units.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) 2011-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 "demandDrivenData.H"
28 #include "dictionary.H"
29 #include "symbols.H"
30 #include "mathematicalConstants.H"
31 
32 using namespace Foam::constant::mathematical;
33 
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 
40 
42 {
43  if (!unitsDictPtr_)
44  {
45  dictionary* cachedPtr = nullptr;
46 
48  (
50  (
51  debug::configDict().found("units")
52  ? "units"
53  : debug::configDict().found("UnitSets")
54  ? "UnitSets"
55  : debug::configDict().found("DimensionSets")
56  ? "DimensionSets"
57  : "units",
58  cachedPtr
59  )
60  );
61  }
62 
63  return *unitsDictPtr_;
64 }
65 
68 
69 // Delete the above data at the end of the run
71 {
73  {
77  }
78 };
79 
81 
82 }
83 
84 
85 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
86 
87 namespace Foam
88 {
89 namespace units
90 {
91 
93 {
94  return unitSet(dimensionSet(0, 0, 0, 0, 0), 1, 0, 1);
95 }
96 
98 {
99  return unitSet(dimensionSet(0, 0, 0, 0, 0), 1, 0, 0.01);
100 }
101 
103 {
104  return unitSet(dimensionSet(0, 0, 0, 0, 0), 0, 1, 1);
105 }
106 
108 {
109  return unitSet(dimensionSet(0, 0, 0, 0, 0), 0, 1, 2*pi);
110 }
111 
113 {
114  return unitSet(dimensionSet(0, 0, 0, 0, 0), 0, 1, pi/180);
115 }
116 
117 unitSet length_(dimensionSet(0, 1, 0, 0, 0), 0, 0, 1);
118 
119 }
120 }
121 
122 
123 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
124 
126 
129 
132 
136 
138 
139 
140 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
141 
143 {
144  if (!unitsPtr_)
145  {
147 
148  unitsPtr_->insert("%", newPercent());
149 
150  unitsPtr_->insert("rad", newRadians());
151  unitsPtr_->insert("rot", newRotations());
152  unitsPtr_->insert("deg", newDegrees());
153 
154  // Get the relevant part of the control dictionary
155  const dictionary& unitSetDict =
156  unitsDict().subDict(unitsDict().lookup<word>("set"));
157 
158  // Read fundamental units
159  HashTable<label> fundamentalUnits;
160  forAllConstIter(dictionary, unitSetDict, iter)
161  {
162  ITstream& is = iter().stream();
163 
164  const dimensionSet units(is);
165 
166  // Check that this is unique
167  if (fundamentalUnits.found(iter().keyword()))
168  {
170  << "Duplicate-fundamental unit specified"
171  << exit(FatalIOError);
172  }
173 
174  // Get the index of the dimension of this fundamental unit
175  label i = -1;
176  for (label j = 0; j < dimensionSet::nDimensions; ++ j)
177  {
178  if (units[j] == 0);
179  else if (units[j] == 1 && i == -1) i = j;
180  else i = -2;
181  }
182  if (i < 0)
183  {
185  << "Non-fundamental unit specified" << units
186  << exit(FatalIOError);
187  }
188 
189  // Store the name
190  fundamentalUnits.insert(iter().keyword(), i);
191 
192  // Add to the table
193  unitsPtr_->insert
194  (
195  iter().keyword(),
196  units*unitSet(dimless, 0, 0, scalar(1))
197  );
198  }
199 
200  // Local function to add a unit to the table with checking
201  auto addUnit = []
202  (
203  const word& name,
204  const unitSet& units,
205  const scalar multiplier
206  )
207  {
208  const bool ok =
209  unitsPtr_->insert
210  (
211  name,
212  units*unitSet(dimless, 0, 0, multiplier)
213  );
214 
215  if (!ok)
216  {
218  << "Duplicate unit " << name
219  << " read from dictionary"
220  << exit(FatalIOError);
221  }
222  };
223 
224  // Read conversions to fundamental units. These are defined the wrong
225  // way around relative to the chosen unit set, so we have to parse them
226  // and then add the reverse conversion to the table.
227  forAllConstIter(HashTable<label>, fundamentalUnits, iter)
228  {
229  if (!unitsDict().found(iter.key())) continue;
230 
231  auto readPunctuation = [](symbols::tokeniser& tis, const char p)
232  {
233  token t(tis.nextToken());
234  if (!t.isPunctuation() || t.pToken() != p)
235  {
237  << "Illegal token " << t
238  << ". Expected character '" << p << "'."
239  << exit(FatalIOError);
240  }
241  };
242 
243  ITstream& is = unitsDict().lookup(iter.key());
244  symbols::tokeniser tis(is);
245 
246  // Read the name and the multiplier, in whatever order
247  token t(tis.nextToken());
248  tis.putBack(t);
249  word derivedUnitName;
250  scalar multiplier;
251  if (!t.isNumber())
252  {
253  readPunctuation(tis, token::BEGIN_SQR);
254  derivedUnitName = tis.nextToken().wordToken();
255  readPunctuation(tis, token::END_SQR);
256  multiplier = tis.nextToken().number();
257  }
258  else
259  {
260  multiplier = tis.nextToken().number();
261  readPunctuation(tis, token::BEGIN_SQR);
262  derivedUnitName = tis.nextToken().wordToken();
263  readPunctuation(tis, token::END_SQR);
264  }
265 
266  // Now we have the name and the multiplier, we can add the
267  // inverse conversion to the table; i.e., flip the names, and
268  // use the reciprocal of the multiplier
269  addUnit
270  (
271  derivedUnitName,
272  unitsPtr_->operator[](iter.key()),
273  1/multiplier
274  );
275  }
276 
277  // Read other units
279  {
280  if
281  (
282  iter().isDict()
283  || iter().keyword() == "set"
284  || iter().keyword() == "unitSet"
285  || fundamentalUnits.found(iter().keyword())
286  ) continue;
287 
288  // Read the units and the multiplier, in whatever order
289  ITstream& is = iter().stream();
290  token t(is);
291  is.putBack(t);
292  unitSet units(units::any);
293  scalar multiplier;
294  if (!t.isNumber())
295  {
296  is >> units;
297  multiplier = pTraits<scalar>(is);
298  }
299  else
300  {
301  multiplier = pTraits<scalar>(is);
302  is >> units;
303  }
304 
305  // Add the conversion to the table
306  addUnit(iter().keyword(), units, multiplier);
307  }
308 
309  // Add programmatically defined units
310  if (addedUnitsPtr_)
311  {
313  {
314  const bool ok = unitsPtr_->insert(iter.key(), iter());
315 
316  if (!ok)
317  {
319  << "Duplicate unit " << iter.key()
320  << " added to dictionary"
321  << exit(FatalIOError);
322  }
323  }
324  }
325  }
326 
327  return *unitsPtr_;
328 }
329 
330 
331 void Foam::units::add(const word& name, const unitSet& units)
332 {
334 
335  if (!addedUnitsPtr_)
336  {
338  }
339 
340  addedUnitsPtr_->insert(name, units);
341 
343 }
344 
345 
346 const Foam::unitSet& Foam::units::lookup(const word& unitName)
347 {
348  return table()[unitName];
349 }
350 
351 
353 {
355 }
356 
357 
358 void Foam::units::setLength(const scalar length)
359 {
361 }
362 
363 
364 Foam::scalar Foam::degToRad(const scalar deg)
365 {
366  return units::degrees.toStandard(deg);
367 }
368 
369 
370 Foam::scalar Foam::radToDeg(const scalar rad)
371 {
372  return units::degrees.toUser(rad);
373 }
374 
375 
376 // ************************************************************************* //
bool found
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
An STL-conforming hash table.
Definition: HashTable.H:127
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:138
Input token stream.
Definition: ITstream.H:56
void putBack(const token &)
Put back token.
Definition: Istream.C:30
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:778
Dimension set for the base types.
Definition: dimensionSet.H:125
Traits class for primitives.
Definition: pTraits.H:53
token nextToken()
...
Definition: symbols.C:88
Istream & stream()
Access the stream.
Definition: symbols.C:76
void putBack(const token &)
...
Definition: symbols.C:111
A token holds items read from Istream.
Definition: token.H:74
bool isNumber() const
Definition: tokenI.H:789
bool isPunctuation() const
Definition: tokenI.H:324
@ BEGIN_SQR
Definition: token.H:112
@ END_SQR
Definition: token.H:113
punctuationToken pToken() const
Definition: tokenI.H:329
const word & wordToken() const
Definition: tokenI.H:347
scalar number() const
Definition: tokenI.H:799
Unit conversion structure. Contains the associated dimensions and the multiplier with which to conver...
Definition: unitSet.H:68
static unitSet newAny()
Return a new "any" unit set.
Definition: unitSetI.H:36
T toUser(const T &) const
Convert a value to user units.
static unitSet newNone()
Return a new "none" unit set.
Definition: unitSetI.H:42
static unitSet newUnitless()
Return a new "unitless" unit set.
Definition: unitSetI.H:30
T toStandard(const T &) const
Convert a value to standard units.
void reset(const unitSet &)
Reset the unit conversion.
Definition: unitSet.C:117
A class for handling words, derived from string.
Definition: word.H:63
Template functions to aid in the implementation of demand driven data.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
mathematical constants.
dictionary & switchSet(const char *subDictName, dictionary *&subDictPtr)
Internal function to lookup a sub-dictionary from configDict.
Definition: debug.C:196
dictionary & configDict()
The central control dictionary.
Definition: debug.C:117
const HashTable< dimensionSet > table
Table of dimensions.
Definition: dimensions.C:74
const dimensionSet length
const unitSet & length
Definition: units.C:137
const unitSet percent
unitSet newRadians()
Definition: units.C:102
unitSet newRotations()
Definition: units.C:107
unitSet newPercent()
Definition: units.C:97
const unitSet radians
const unitSet unitless
unitSet newFraction()
Definition: units.C:92
unitSet length_(dimensionSet(0, 1, 0, 0, 0), 0, 0, 1)
void add(const word &name, const unitSet &unit)
Add a unit conversion.
Definition: units.C:331
const HashTable< unitSet > & table()
Get the table of unit conversions.
Definition: units.C:142
const unitSet none
void setLength(const unitSet &length)
Set the length scale to the given unit set.
Definition: units.C:352
unitSet newDegrees()
Definition: units.C:112
const unitSet any
const unitSet fraction
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
const unitSet degrees
const unitSet rotations
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
scalar radToDeg(const scalar rad)
Convert radians to degrees.
Definition: units.C:370
const dimensionSet & dimless
Definition: dimensions.C:138
scalar degToRad(const scalar deg)
Convert degrees to radians.
Definition: units.C:364
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
const dimensionSet & dimLength
Definition: dimensions.C:141
void deleteDemandDrivenData(DataType *&dataPtr)
HashTable< unitSet > * addedUnitsPtr_(nullptr)
HashTable< unitSet > * unitsPtr_(nullptr)
const dictionary & unitsDict()
Definition: units.C:41
IOerror FatalIOError
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
dictionary * unitsDictPtr_(nullptr)
deleteUnitsPtr deleteUnitsPtr_
Definition: units.C:80
volScalarField & p
Useful unit conversions.