unitSetIO.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2024-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "units.H"
27 #include "dictionary.H"
28 #include "NamedEnum.H"
29 #include "symbols.H"
30 
31 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
32 
34 :
35  dimensions_(dimless),
36  multiplier_(NaN)
37 {
38  is >> *this;
39 }
40 
41 
42 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
43 
44 void Foam::unitSet::read(const word& keyword, const dictionary& dict)
45 {
46  const unitSet units(dict.lookup(keyword));
47 
48  if (!compare(*this, units, false))
49  {
50  multiplier_ = scalar(1);
51 
53  << "The units " << units.info() << " of " << keyword
54  << " in dictionary " << dict.name() << " do not have "
55  << "the required dimensions " << info()
56  << abort(FatalIOError);
57  }
58 
59  reset(units);
60 }
61 
62 
64 {
65  const unitSet units(is);
66 
67  if (!compare(*this, units, false))
68  {
69  multiplier_ = scalar(1);
70 
72  << "The units " << units.info() << " provided do not have "
73  << "the required dimensions " << info()
74  << abort(FatalIOError);
75  }
76 
77  reset(units);
78 }
79 
80 
82 (
83  const word& keyword,
84  const dictionary& dict,
85  Istream& is
86 )
87 {
88  const unitSet units(is);
89 
90  if (!compare(*this, units, false))
91  {
92  multiplier_ = scalar(1);
93 
95  << "The units " << units.info() << " of " << keyword
96  << " in dictionary " << dict.name() << " do not have "
97  << "the required dimensions " << info()
98  << abort(FatalIOError);
99  }
100 
101  reset(units);
102 }
103 
104 
106 (
107  const word& keyword,
108  const dictionary& dict
109 )
110 {
111  const entry* entryPtr = dict.lookupEntryPtr(keyword, false, true);
112 
113  if (entryPtr)
114  {
115  const unitSet units(entryPtr->stream());
116 
117  if (!compare(*this, units, false))
118  {
119  multiplier_ = scalar(1);
120 
122  << "The units " << units.info() << " of " << keyword
123  << " in dictionary " << dict.name() << " do not have "
124  << "the required dimensions " << info()
125  << abort(FatalIOError);
126  }
127 
128  reset(units);
129 
130  return true;
131  }
132  else
133  {
134  return false;
135  }
136 }
137 
138 
140 {
141  token nextToken(is);
142  is.putBack(nextToken);
143 
144  if (nextToken != token::BEGIN_SQR) return false;
145 
146  const unitSet units(is);
147 
148  if (!unitSet::compare(units, *this, false))
149  {
150  multiplier_ = scalar(1);
151 
153  << "The units " << units.info() << " provided do not have "
154  << "the required dimensions " << info()
155  << abort(FatalIOError);
156  }
157 
158  if (debug && (any() || !unitSet::compare(units, *this, true)))
159  {
160  Info<< "Unit conversion at line " << is.lineNumber()
161  << " of file " << is.name()
162  << " with factor " << units.multiplier_ << endl;
163  }
164 
165  reset(units);
166 
167  return true;
168 }
169 
170 
172 (
173  const word& keyword,
174  const dictionary& dict,
175  Istream& is
176 )
177 {
178  token nextToken(is);
179  is.putBack(nextToken);
180 
181  if (nextToken != token::BEGIN_SQR) return false;
182 
183  const unitSet units(is);
184 
185  if (!unitSet::compare(units, *this, false))
186  {
187  multiplier_ = scalar(1);
188 
190  << "The units " << units.info() << " of " << keyword
191  << " in dictionary " << dict.name() << " do not have "
192  << "the required dimensions " << info()
193  << abort(FatalIOError);
194  }
195 
196  if (debug && (any() || !unitSet::compare(units, *this, true)))
197  {
198  Info<< "Unit conversion of " << keyword
199  << " in dictionary " << dict.name()
200  << " with factor " << units.multiplier_ << endl;
201  }
202 
203  reset(units);
204 
205  return true;
206 }
207 
208 
209 // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
210 
212 {
213  token nextToken;
214 
215  // Read the next delimiting token. This must be the start bracket.
216  is >> nextToken;
217  if (nextToken != token::BEGIN_SQR)
218  {
220  << "expected a " << token::BEGIN_SQR << " in unitSet"
221  << endl << "in stream " << is.info() << ", got a "
222  << nextToken << exit(FatalIOError);
223  }
224 
225  // Peek at the next token
226  is >> nextToken;
227  is.putBack(nextToken);
228 
229  // If not a number or separator, then these are named units. Parse.
230  if (!nextToken.isNumber() && nextToken != token::COLON)
231  {
232  // Named units. Parse. Note: Use an explicit construction of the
233  // identity unit instead of 'unitless' because this function may be
234  // used in a static context before 'unitless' is available.
235  units.reset
236  (
238  (
239  is,
240  unitSet(dimless, 0, 0, 1),
242  )
243  );
244 
245  // Read the next delimiting token. This must be the end bracket.
246  is >> nextToken;
247  if (nextToken != token::END_SQR)
248  {
250  << "expected a " << token::END_SQR << " in unitSet "
251  << endl << "in stream " << is.info() << ", got a "
252  << nextToken << exit(FatalIOError);
253  }
254 
255  // Check state of Istream
256  is.check("Istream& operator>>(Istream&, unitSet&)");
257 
258  return is;
259  }
260 
261  // Otherwise these are numbered units. Read directly...
262 
263  // Read the dimensions
264  units.dimensions_.readNoBeginOrEnd(is);
265 
266  // Read the next delimiting token. If a separator, then there are
267  // dimensionless units and a multiplier to read. If it is an end bracket,
268  // then the dimensionless units are zero and the multiplier is one and the
269  // parsing is finished. Otherwise the parsing has failed.
270  is >> nextToken;
271  if (nextToken == token::COLON)
272  {
273  // Peek at the next token
274  is >> nextToken;
275  is.putBack(nextToken);
276 
277  // Read the dimensionless units if present, or set to zero
278  if (!nextToken.isNumber())
279  {
280  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
281  {
282  units.exponents_[i] = 0;
283  }
284  }
285  else
286  {
287  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
288  {
289  is >> units.exponents_[i];
290  }
291  }
292 
293  // Read the next delimiting token. If a separator then there is a
294  // multiplier to read. If it is an end bracket then the multiplier is
295  // one and the parsing is finished. Otherwise the parsing has failed.
296  is >> nextToken;
297  if (nextToken == token::COLON)
298  {
299  // Peek at the next token
300  is >> nextToken;
301  is.putBack(nextToken);
302 
303  // Read the multiplier if present, or set to unity
304  if (!nextToken.isNumber())
305  {
306  units.multiplier_ = 1;
307  }
308  else
309  {
310  is >> units.multiplier_;
311  }
312 
313  // Read the next delimiting token. This must be the end bracket.
314  is >> nextToken;
315  if (nextToken != token::END_SQR)
316  {
318  << "expected a " << token::END_SQR << " in unitSet "
319  << endl << "in stream " << is.info() << ", got a "
320  << nextToken << exit(FatalIOError);
321  }
322  }
323  else if (nextToken == token::END_SQR)
324  {
325  units.multiplier_ = 1;
326  }
327  else
328  {
330  << "expected a " << token::END_SQR << " or a " << token::COLON
331  << " in unitSet " << endl << "in stream " << is.info()
332  << ", got a " << nextToken << exit(FatalIOError);
333  }
334  }
335  else if (nextToken == token::END_SQR)
336  {
337  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
338  {
339  units.exponents_[i] = 0;
340  }
341 
342  units.multiplier_ = 1;
343  }
344  else
345  {
347  << "expected a " << token::END_SQR << " or a " << token::COLON
348  << " in unitSet " << endl << "in stream " << is.info()
349  << ", got a " << nextToken << exit(FatalIOError);
350  }
351 
352  // Check state of Istream
353  is.check("Istream& operator>>(Istream&, unitSet&)");
354 
355  return is;
356 }
357 
358 
360 {
361  // Write the start
362  os << token::BEGIN_SQR;
363 
364  // Write the dimensions
365  units.dimensions_.writeNoBeginOrEnd(os);
366 
367  // Determine if any dimensionless units are non-zero
368  bool nonZeroDimlessUnits = false;
369  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
370  {
371  nonZeroDimlessUnits =
372  nonZeroDimlessUnits
373  || mag(units.exponents_[i]) > unitSet::smallExponent;
374  }
375 
376  // Determine if the multiplier is non-unity
377  bool nonUnityMultiplier = units.multiplier_ != 1;
378 
379  // Write a separator if there is anything to follow
380  if (nonZeroDimlessUnits || nonUnityMultiplier)
381  {
382  os << token::SPACE << token::COLON;
383  }
384 
385  // Write the dimensionless units if any are non-zero
386  if (nonZeroDimlessUnits)
387  {
388  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
389  {
390  os << token::SPACE << units.exponents_[i];
391  }
392  }
393 
394  // Write a separator if there is anything to follow
395  if (nonUnityMultiplier)
396  {
397  os << token::SPACE << token::COLON;
398  }
399 
400  // Write the multiplier if it is non-unity
401  if (nonUnityMultiplier)
402  {
403  os << token::SPACE << units.multiplier_;
404  }
405 
406  // Write the end
407  os << token::END_SQR;
408 
409  // Check state of Ostream
410  os.check("Ostream& operator<<(Ostream&, const unitSet&)");
411 
412  return os;
413 }
414 
415 
416 Foam::Ostream& Foam::operator<<
417 (
418  Ostream& os,
419  const InfoProxy<unitSet>& ip
420 )
421 {
422  const unitSet& units = ip.t_;
423 
424  // Filter out special cases
425  if (units.any())
426  {
427  return os << token::BEGIN_SQR << "<any>" << token::END_SQR;
428  }
429  if (units.none())
430  {
431  return os << token::BEGIN_SQR << "<none>" << token::END_SQR;
432  }
433 
434  // Write the start
435  os << token::BEGIN_SQR;
436 
437  // Write the dimensions
438  units.dimensions_.writeInfoNoBeginOrEnd(os);
439 
440  // Determine if any dimensionless units are non-zero
441  bool nonZeroDimlessUnits = false;
442  for (int i = 0; i < unitSet::nDimlessUnits; ++ i)
443  {
444  nonZeroDimlessUnits =
445  nonZeroDimlessUnits
446  || mag(units.exponents_[i]) > unitSet::smallExponent;
447  }
448 
449  // Determine if the multiplier is non-unity
450  bool nonUnityMultiplier = units.multiplier_ != 1;
451 
452  // Write a separator if there is anything to follow
453  if (nonZeroDimlessUnits || nonUnityMultiplier)
454  {
455  os << token::SPACE << token::COLON;
456  }
457 
458  // Write the dimensionless units if any are non-zero
459  if (nonZeroDimlessUnits)
460  {
461  for (int i=0; i<unitSet::nDimlessUnits; i++)
462  {
463  if (mag(units.exponents_[i]) > unitSet::smallExponent)
464  {
466  [static_cast<unitSet::dimlessUnitType>(i)];
467 
468  if (units.exponents_[i] != 1)
469  {
470  os << '^' << units.exponents_[i];
471  }
472  }
473  }
474  }
475 
476  // Write a separator if there is anything to follow
477  if (nonUnityMultiplier)
478  {
479  os << token::SPACE << token::COLON;
480  }
481 
482  // Write the multiplier if it is non-unity
483  if (nonUnityMultiplier)
484  {
485  os << token::SPACE << units.multiplier_;
486  }
487 
488  // Write the end
489  os << token::END_SQR;
490 
491  // Check state of Ostream
492  os.check("Ostream& operator<<(Ostream&, const InfoProxy<unitSet>&)");
493 
494  return os;
495 }
496 
497 
498 // ************************************************************************* //
label lineNumber() const
Return current stream line number.
Definition: IOstream.H:450
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:108
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:297
InfoProxy< IOstream > info() const
Return info proxy.
Definition: IOstream.H:552
A helper class for outputting values to Ostream.
Definition: InfoProxy.H:50
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
void putBack(const token &)
Put back token.
Definition: Istream.C:30
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:111
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:507
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
Ostream & writeInfoNoBeginOrEnd(Ostream &os) const
Write info without the square brackets.
Ostream & writeNoBeginOrEnd(Ostream &os) const
Write without the square brackets.
Istream & readNoBeginOrEnd(Istream &is)
Read without the square brackets.
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:68
virtual ITstream & stream() const =0
Return token stream if this entry is a primitive entry.
A token holds items read from Istream.
Definition: token.H:74
bool isNumber() const
Definition: tokenI.H:789
@ BEGIN_SQR
Definition: token.H:112
@ END_SQR
Definition: token.H:113
Unit conversion structure. Contains the associated dimensions and the multiplier with which to conver...
Definition: unitSet.H:68
bool readIfPresent(const word &keyword, const dictionary &)
Update if found in the dictionary.
Definition: unitSetIO.C:106
bool none() const
Return whether this is the "none" unit. I.e., the case where unit.
Definition: unitSetI.H:68
InfoProxy< unitSet > info() const
Return info proxy.
Definition: unitSet.H:228
void read(const word &keyword, const dictionary &)
Update.
Definition: unitSetIO.C:44
unitSet(const dimensionSet &, const scalar fraction, const scalar angle, const scalar multiplier)
Construct from components.
Definition: unitSet.C:90
static const scalar smallExponent
A small exponent with which to perform inexact comparisons.
Definition: unitSet.H:94
static const NamedEnum< dimlessUnitType, 2 > & dimlessUnitTypeNames_
Names of the dimensionless units.
Definition: unitSet.H:88
@ nDimlessUnits
Definition: unitSet.H:76
dimlessUnitType
Define an enumeration for the names of the dimensionless unit.
Definition: unitSet.H:82
void reset(const unitSet &)
Reset the unit conversion.
Definition: unitSet.C:117
bool any() const
Return whether this is the "any" unit. I.e., the case where.
Definition: unitSetI.H:62
A class for handling words, derived from string.
Definition: word.H:63
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
const dimensionSet dimless
Type parseNoBeginOrEnd(Istream &is, const Type &identity, const HashTable< Type > &table)
Parse tokens into a dimension set or unit conversion, assuming that the '['.
const HashTable< unitSet > & table()
Get the table of unit conversions.
Definition: units.C:142
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Istream & operator>>(Istream &, pointEdgeDist &)
Definition: pointEdgeDist.C:41
const dimensionSet & dimless
Definition: dimensions.C:138
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
errorManip< error > abort(error &err)
Definition: errorManip.H:131
messageStream Info
IOerror FatalIOError
bool any(const boolList &l)
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
dictionary dict
Useful unit conversions.