unitConversionIO.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-2025 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 "unitConversion.H"
27 #include "dictionary.H"
28 #include "symbols.H"
29 
30 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
31 
33 :
34  dimensions_(dimless),
35  multiplier_(NaN)
36 {
37  is >> *this;
38 }
39 
40 
41 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
42 
43 void Foam::unitConversion::read(const word& keyword, const dictionary& dict)
44 {
45  const unitConversion units(dict.lookup(keyword));
46 
47  if (!compare(*this, units, false))
48  {
50  << "The units " << units.info() << " of " << keyword
51  << " in dictionary " << dict.name() << " do not match "
52  << "the required units " << info()
53  << abort(FatalIOError);
54  }
55 
56  reset(units);
57 }
58 
59 
61 {
62  const unitConversion units(is);
63 
64  if (!compare(*this, units, false))
65  {
67  << "The units " << units.info() << " provided do not match "
68  << "the required units " << info()
69  << abort(FatalIOError);
70  }
71 
72  reset(units);
73 }
74 
75 
77 (
78  const word& keyword,
79  const dictionary& dict,
80  Istream& is
81 )
82 {
83  const unitConversion units(is);
84 
85  if (!compare(*this, units, false))
86  {
88  << "The units " << units.info() << " of " << keyword
89  << " in dictionary " << dict.name() << " do not match "
90  << "the required units " << info()
91  << abort(FatalIOError);
92  }
93 
94  reset(units);
95 }
96 
97 
99 (
100  const word& keyword,
101  const dictionary& dict
102 )
103 {
104  const entry* entryPtr = dict.lookupEntryPtr(keyword, false, true);
105 
106  if (entryPtr)
107  {
108  const unitConversion units(entryPtr->stream());
109 
110  if (!compare(*this, units, false))
111  {
113  << "The units " << units.info() << " of " << keyword
114  << " in dictionary " << dict.name() << " do not match "
115  << "the required units " << info()
116  << abort(FatalIOError);
117  }
118 
119  reset(units);
120 
121  return true;
122  }
123  else
124  {
126  {
128  << "Optional entry '" << keyword << "' is not present,"
129  << " the default value '" << info() << "' will be used."
130  << endl;
131  }
132 
133  return false;
134  }
135 }
136 
137 
139 {
140  token nextToken(is);
141  is.putBack(nextToken);
142 
143  if (nextToken != token::BEGIN_SQR) return false;
144 
145  const unitConversion units(is);
146 
147  if (!unitConversion::compare(units, *this, false))
148  {
150  << "The units " << units.info() << " provided do not match "
151  << "the required units " << info()
152  << abort(FatalIOError);
153  }
154 
155  if (debug && (any() || !unitConversion::compare(units, *this, true)))
156  {
157  Info<< "Unit conversion at line " << is.lineNumber()
158  << " of file " << is.name()
159  << " with factor " << units.multiplier_ << endl;
160  }
161 
162  reset(units);
163 
164  return true;
165 }
166 
167 
169 (
170  const word& keyword,
171  const dictionary& dict,
172  Istream& is
173 )
174 {
175  token nextToken(is);
176  is.putBack(nextToken);
177 
178  if (nextToken != token::BEGIN_SQR) return false;
179 
180  const unitConversion units(is);
181 
182  if (!unitConversion::compare(units, *this, false))
183  {
185  << "The units " << units.info() << " of " << keyword
186  << " in dictionary " << dict.name() << " do not match "
187  << "the required units " << info()
188  << abort(FatalIOError);
189  }
190 
191  if (debug && (any() || !unitConversion::compare(units, *this, true)))
192  {
193  Info<< "Unit conversion of " << keyword
194  << " in dictionary " << dict.name()
195  << " with factor " << units.multiplier_ << endl;
196  }
197 
198  reset(units);
199 
200  return true;
201 }
202 
203 
204 // * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * * //
205 
207 {
208  token nextToken;
209 
210  // Read the next delimiting token. This must be the start bracket.
211  is >> nextToken;
212  if (nextToken != token::BEGIN_SQR)
213  {
215  << "expected a " << token::BEGIN_SQR << " in unitConversion"
216  << endl << "in stream " << is.info() << ", got a "
217  << nextToken << exit(FatalIOError);
218  }
219 
220  // Peek at the next token
221  is >> nextToken;
222  is.putBack(nextToken);
223 
224  // If not a number or separator, then these are named units. Parse.
225  if (!nextToken.isNumber() && nextToken != token::COLON)
226  {
227  // Named units. Parse. Note: Use an explicit construction of the
228  // identity unit instead of 'unitless' because this function may be
229  // used in a static context before 'unitless' is available.
230  units.reset
231  (
233  (
234  is,
235  unitConversion(dimless, 0, 0, 1),
236  Foam::units()
237  )
238  );
239 
240  // Read the next delimiting token. This must be the end bracket.
241  is >> nextToken;
242  if (nextToken != token::END_SQR)
243  {
245  << "expected a " << token::END_SQR << " in unitConversion "
246  << endl << "in stream " << is.info() << ", got a "
247  << nextToken << exit(FatalIOError);
248  }
249 
250  // Check state of Istream
251  is.check("Istream& operator>>(Istream&, unitConversion&)");
252 
253  return is;
254  }
255 
256  // Otherwise these are numbered units. Read directly...
257 
258  // Read the dimensions
259  units.dimensions_.readNoBeginOrEnd(is);
260 
261  // Read the next delimiting token. If a separator, then there are
262  // dimensionless units and a multiplier to read. If it is an end bracket,
263  // then the dimensionless units are zero and the multiplier is one and the
264  // parsing is finished. Otherwise the parsing has failed.
265  is >> nextToken;
266  if (nextToken == token::COLON)
267  {
268  // Peek at the next token
269  is >> nextToken;
270  is.putBack(nextToken);
271 
272  // Read the dimensionless units if present, or set to zero
273  if (!nextToken.isNumber())
274  {
275  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
276  {
277  units.exponents_[i] = 0;
278  }
279  }
280  else
281  {
282  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
283  {
284  is >> units.exponents_[i];
285  }
286  }
287 
288  // Read the next delimiting token. If a separator then there is a
289  // multiplier to read. If it is an end bracket then the multiplier is
290  // one and the parsing is finished. Otherwise the parsing has failed.
291  is >> nextToken;
292  if (nextToken == token::COLON)
293  {
294  // Peek at the next token
295  is >> nextToken;
296  is.putBack(nextToken);
297 
298  // Read the multiplier if present, or set to unity
299  if (!nextToken.isNumber())
300  {
301  units.multiplier_ = 1;
302  }
303  else
304  {
305  is >> units.multiplier_;
306  }
307 
308  // Read the next delimiting token. This must be the end bracket.
309  is >> nextToken;
310  if (nextToken != token::END_SQR)
311  {
313  << "expected a " << token::END_SQR << " in unitConversion "
314  << endl << "in stream " << is.info() << ", got a "
315  << nextToken << exit(FatalIOError);
316  }
317  }
318  else if (nextToken == token::END_SQR)
319  {
320  units.multiplier_ = 1;
321  }
322  else
323  {
325  << "expected a " << token::END_SQR << " or a " << token::COLON
326  << " in unitConversion " << endl << "in stream " << is.info()
327  << ", got a " << nextToken << exit(FatalIOError);
328  }
329  }
330  else if (nextToken == token::END_SQR)
331  {
332  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
333  {
334  units.exponents_[i] = 0;
335  }
336 
337  units.multiplier_ = 1;
338  }
339  else
340  {
342  << "expected a " << token::END_SQR << " or a " << token::COLON
343  << " in unitConversion " << endl << "in stream " << is.info()
344  << ", got a " << nextToken << exit(FatalIOError);
345  }
346 
347  // Check state of Istream
348  is.check("Istream& operator>>(Istream&, unitConversion&)");
349 
350  return is;
351 }
352 
353 
355 {
356  // Write the start
357  os << token::BEGIN_SQR;
358 
359  // Write the dimensions
360  units.dimensions_.writeNoBeginOrEnd(os);
361 
362  // Determine if any dimensionless units are non-zero
363  bool nonZeroDimlessUnits = false;
364  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
365  {
366  nonZeroDimlessUnits =
367  nonZeroDimlessUnits
368  || mag(units.exponents_[i]) > unitConversion::smallExponent;
369  }
370 
371  // Determine if the multiplier is non-unity
372  bool nonUnityMultiplier = units.multiplier_ != 1;
373 
374  // Write a separator if there is anything to follow
375  if (nonZeroDimlessUnits || nonUnityMultiplier)
376  {
377  os << token::SPACE << token::COLON;
378  }
379 
380  // Write the dimensionless units if any are non-zero
381  if (nonZeroDimlessUnits)
382  {
383  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
384  {
385  os << token::SPACE << units.exponents_[i];
386  }
387  }
388 
389  // Write a separator if there is anything to follow
390  if (nonUnityMultiplier)
391  {
392  os << token::SPACE << token::COLON;
393  }
394 
395  // Write the multiplier if it is non-unity
396  if (nonUnityMultiplier)
397  {
398  os << token::SPACE << units.multiplier_;
399  }
400 
401  // Write the end
402  os << token::END_SQR;
403 
404  // Check state of Ostream
405  os.check("Ostream& operator<<(Ostream&, const unitConversion&)");
406 
407  return os;
408 }
409 
410 
411 Foam::Ostream& Foam::operator<<
412 (
413  Ostream& os,
414  const InfoProxy<unitConversion>& ip
415 )
416 {
417  const unitConversion& units = ip.t_;
418 
419  // Filter out special cases
420  if (units.any())
421  {
422  return os << token::BEGIN_SQR << "<any>" << token::END_SQR;
423  }
424  if (units.none())
425  {
426  return os << token::BEGIN_SQR << "<none>" << token::END_SQR;
427  }
428 
429  // Write the start
430  os << token::BEGIN_SQR;
431 
432  // Write the dimensions
433  units.dimensions_.writeInfoNoBeginOrEnd(os);
434 
435  // Determine if any dimensionless units are non-zero
436  bool nonZeroDimlessUnits = false;
437  for (int i = 0; i < unitConversion::nDimlessUnits; ++ i)
438  {
439  nonZeroDimlessUnits =
440  nonZeroDimlessUnits
441  || mag(units.exponents_[i]) > unitConversion::smallExponent;
442  }
443 
444  // Determine if the multiplier is non-unity
445  bool nonUnityMultiplier = units.multiplier_ != 1;
446 
447  // Write a separator if there is anything to follow
448  if (nonZeroDimlessUnits || nonUnityMultiplier)
449  {
450  os << token::SPACE << token::COLON;
451  }
452 
453  // Write the dimensionless units if any are non-zero
454  if (nonZeroDimlessUnits)
455  {
456  for (int i=0; i<unitConversion::nDimlessUnits; i++)
457  {
458  if (mag(units.exponents_[i]) > unitConversion::smallExponent)
459  {
461  [static_cast<unitConversion::dimlessUnitType>(i)];
462 
463  if (units.exponents_[i] != 1)
464  {
465  os << '^' << units.exponents_[i];
466  }
467  }
468  }
469  }
470 
471  // Write a separator if there is anything to follow
472  if (nonUnityMultiplier)
473  {
474  os << token::SPACE << token::COLON;
475  }
476 
477  // Write the multiplier if it is non-unity
478  if (nonUnityMultiplier)
479  {
480  os << token::SPACE << units.multiplier_;
481  }
482 
483  // Write the end
484  os << token::END_SQR;
485 
486  // Check state of Ostream
487  os.check("Ostream& operator<<(Ostream&, const InfoProxy<unitConversion>&)");
488 
489  return os;
490 }
491 
492 
493 // ************************************************************************* //
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:92
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:543
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
static int writeOptionalEntries
If true write optional keywords and values.
Definition: dictionary.H:277
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:578
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
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:73
bool isNumber() const
Definition: tokenI.H:745
@ BEGIN_SQR
Definition: token.H:111
@ END_SQR
Definition: token.H:112
Unit conversion structure. Contains the associated dimensions and the multiplier with which to conver...
bool readIfPresent(const word &keyword, const dictionary &)
Update if found in the dictionary.
static const NamedEnum< dimlessUnitType, 2 > dimlessUnitTypeNames_
Names of the dimensionless units.
static const scalar smallExponent
A small exponent with which to perform inexact comparisons.
unitConversion(const dimensionSet &, const scalar fraction, const scalar angle, const scalar multiplier)
Construct from components.
void read(const word &keyword, const dictionary &)
Update.
dimlessUnitType
Define an enumeration for the names of the dimensionless unit.
A class for handling words, derived from string.
Definition: word.H:62
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define IOInfoInFunction(ios)
Report an IO information message using Foam::Info.
Type parseNoBeginOrEnd(Istream &is, const Type &identity, const HashTable< Type > &table)
Parse tokens into a dimension set or unit conversion, assuming that the '['.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const dimensionSet dimless
messageStream Info
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
const HashTable< unitConversion > & units()
Get the table of unit conversions.
Istream & operator>>(Istream &, pistonPointEdgeData &)
IOerror FatalIOError
bool any(const boolList &l)
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
dictionary dict