interpolationTable.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-2018 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 "interpolationTable.H"
27 #include "openFoamTableReader.H"
28 
29 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
30 
31 template<class Type>
33 {
34  // preserve the original (unexpanded) fileName to avoid absolute paths
35  // appearing subsequently in the write() method
36  fileName fName(fileName_);
37 
38  fName.expand();
39 
40  // Read data from file
41  reader_()(fName, *this);
42 
43  if (this->empty())
44  {
46  << "table read from " << fName << " is empty" << nl
47  << exit(FatalError);
48  }
49 
50  // Check that the data are okay
51  check();
52 }
53 
54 
55 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
56 
57 template<class Type>
59 :
60  List<Tuple2<scalar, Type>>(),
61  boundsHandling_(interpolationTable::WARN),
62  fileName_("fileNameIsUndefined"),
63  reader_(nullptr)
64 {}
65 
66 
67 template<class Type>
69 (
70  const List<Tuple2<scalar, Type>>& values,
71  const boundsHandling bounds,
72  const fileName& fName
73 )
74 :
76  boundsHandling_(bounds),
77  fileName_(fName),
78  reader_(nullptr)
79 {}
80 
81 
82 template<class Type>
84 :
85  List<Tuple2<scalar, Type>>(),
86  boundsHandling_(interpolationTable::WARN),
87  fileName_(fName),
88  reader_(new openFoamTableReader<Type>(dictionary()))
89 {
90  readTable();
91 }
92 
93 
94 template<class Type>
96 :
97  List<Tuple2<scalar, Type>>(),
98  boundsHandling_(wordToBoundsHandling(dict.lookup("outOfBounds"))),
99  fileName_(dict.lookup("file")),
100  reader_(tableReader<Type>::New(dict))
101 {
102  readTable();
103 }
104 
105 
106 template<class Type>
108 (
109  const interpolationTable& interpTable
110 )
111 :
112  List<Tuple2<scalar, Type>>(interpTable),
113  boundsHandling_(interpTable.boundsHandling_),
114  fileName_(interpTable.fileName_),
115  reader_(interpTable.reader_) // note: steals reader. Used in write().
116 {}
117 
118 
119 
120 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
121 
122 template<class Type>
124 (
125  const boundsHandling& bound
126 ) const
127 {
128  word enumName("warn");
129 
130  switch (bound)
131  {
132  case interpolationTable::ERROR:
133  {
134  enumName = "error";
135  break;
136  }
137  case interpolationTable::WARN:
138  {
139  enumName = "warn";
140  break;
141  }
142  case interpolationTable::CLAMP:
143  {
144  enumName = "clamp";
145  break;
146  }
147  case interpolationTable::REPEAT:
148  {
149  enumName = "repeat";
150  break;
151  }
152  }
153 
154  return enumName;
155 }
156 
157 
158 template<class Type>
161 (
162  const word& bound
163 ) const
164 {
165  if (bound == "error")
166  {
167  return interpolationTable::ERROR;
168  }
169  else if (bound == "warn")
170  {
171  return interpolationTable::WARN;
172  }
173  else if (bound == "clamp")
174  {
175  return interpolationTable::CLAMP;
176  }
177  else if (bound == "repeat")
178  {
179  return interpolationTable::REPEAT;
180  }
181  else
182  {
184  << "bad outOfBounds specifier " << bound << " using 'warn'" << endl;
185 
186  return interpolationTable::WARN;
187  }
188 }
189 
190 
191 template<class Type>
194 (
195  const boundsHandling& bound
196 )
197 {
198  boundsHandling prev = boundsHandling_;
199  boundsHandling_ = bound;
200  return prev;
201 }
202 
203 
204 template<class Type>
206 {
207  label n = this->size();
208  scalar prevValue = List<Tuple2<scalar, Type>>::operator[](0).first();
209 
210  for (label i=1; i<n; ++i)
211  {
212  const scalar currValue =
213  List<Tuple2<scalar, Type>>::operator[](i).first();
214 
215  // avoid duplicate values (divide-by-zero error)
216  if (currValue <= prevValue)
217  {
219  << "out-of-order value: "
220  << currValue << " at index " << i << nl
221  << exit(FatalError);
222  }
223  prevValue = currValue;
224  }
225 }
226 
227 
228 template<class Type>
230 {
231  os.writeKeyword("file")
232  << fileName_ << token::END_STATEMENT << nl;
233  os.writeKeyword("outOfBounds")
234  << boundsHandlingToWord(boundsHandling_) << token::END_STATEMENT << nl;
235  if (reader_.valid())
236  {
237  reader_->write(os);
238  }
239 }
240 
241 
242 template<class Type>
243 Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
244 {
245  label n = this->size();
246 
247  if (n <= 1)
248  {
249  // There are not enough entries to provide a rate of change
250  return 0;
251  }
252 
253  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
254  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
255  scalar lookupValue = value;
256 
257  if (lookupValue < minLimit)
258  {
259  switch (boundsHandling_)
260  {
261  case interpolationTable::ERROR:
262  {
264  << "value (" << lookupValue << ") underflow" << nl
265  << exit(FatalError);
266  break;
267  }
268  case interpolationTable::WARN:
269  {
271  << "value (" << lookupValue << ") underflow" << nl
272  << " Zero rate of change."
273  << endl;
274  // fall-through to 'CLAMP'
275  [[fallthrough]];
276  }
277  case interpolationTable::CLAMP:
278  {
279  return 0;
280  break;
281  }
282  case interpolationTable::REPEAT:
283  {
284  // adjust lookupValue to >= minLimit
285  scalar span = maxLimit-minLimit;
286  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
287  break;
288  }
289  }
290  }
291  else if (lookupValue >= maxLimit)
292  {
293  switch (boundsHandling_)
294  {
295  case interpolationTable::ERROR:
296  {
298  << "value (" << lookupValue << ") overflow" << nl
299  << exit(FatalError);
300  break;
301  }
302  case interpolationTable::WARN:
303  {
305  << "value (" << lookupValue << ") overflow" << nl
306  << " Zero rate of change."
307  << endl;
308  // fall-through to 'CLAMP'
309  [[fallthrough]];
310  }
311  case interpolationTable::CLAMP:
312  {
313  return 0;
314  break;
315  }
316  case interpolationTable::REPEAT:
317  {
318  // adjust lookupValue <= maxLimit
319  scalar span = maxLimit-minLimit;
320  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
321  break;
322  }
323  }
324  }
325 
326  label lo = 0;
327  label hi = 0;
328 
329  // look for the correct range
330  for (label i = 0; i < n; ++i)
331  {
332  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
333  {
334  lo = hi = i;
335  }
336  else
337  {
338  hi = i;
339  break;
340  }
341  }
342 
343  if (lo == hi)
344  {
345  // we are at the end of the table - or there is only a single entry
346  return 0;
347  }
348  else if (hi == 0)
349  {
350  // this treatment should should only occur under these conditions:
351  // -> the 'REPEAT' treatment
352  // -> (0 <= value <= minLimit)
353  // -> minLimit > 0
354  // Use the value at maxLimit as the value for value=0
355  lo = n - 1;
356 
357  return
358  (
359  (
360  List<Tuple2<scalar, Type>>::operator[](hi).second()
361  - List<Tuple2<scalar, Type>>::operator[](lo).second()
362  )
363  /(
364  List<Tuple2<scalar, Type>>::operator[](hi).first()
365  + minLimit
366  - List<Tuple2<scalar, Type>>::operator[](lo).first()
367  )
368  );
369  }
370  else
371  {
372  // normal rate of change
373  return
374  (
375  (
376  List<Tuple2<scalar, Type>>::operator[](hi).second()
377  - List<Tuple2<scalar, Type>>::operator[](lo).second()
378  )
379  /(
380  List<Tuple2<scalar, Type>>::operator[](hi).first()
381  - List<Tuple2<scalar, Type>>::operator[](lo).first()
382  )
383  );
384  }
385 }
386 
387 
388 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
389 
390 template<class Type>
393 {
394  label ii = i;
395  label n = this->size();
396 
397  if (n <= 1)
398  {
399  ii = 0;
400  }
401  else if (ii < 0)
402  {
403  switch (boundsHandling_)
404  {
405  case interpolationTable::ERROR:
406  {
408  << "index (" << ii << ") underflow" << nl
409  << exit(FatalError);
410  break;
411  }
412  case interpolationTable::WARN:
413  {
415  << "index (" << ii << ") underflow" << nl
416  << " Continuing with the first entry"
417  << endl;
418  // fall-through to 'CLAMP'
419  [[fallthrough]];
420  }
421  case interpolationTable::CLAMP:
422  {
423  ii = 0;
424  break;
425  }
426  case interpolationTable::REPEAT:
427  {
428  while (ii < 0)
429  {
430  ii += n;
431  }
432  break;
433  }
434  }
435  }
436  else if (ii >= n)
437  {
438  switch (boundsHandling_)
439  {
440  case interpolationTable::ERROR:
441  {
443  << "index (" << ii << ") overflow" << nl
444  << exit(FatalError);
445  break;
446  }
447  case interpolationTable::WARN:
448  {
450  << "index (" << ii << ") overflow" << nl
451  << " Continuing with the last entry"
452  << endl;
453  // fall-through to 'CLAMP'
454  [[fallthrough]];
455  }
456  case interpolationTable::CLAMP:
457  {
458  ii = n - 1;
459  break;
460  }
461  case interpolationTable::REPEAT:
462  {
463  while (ii >= n)
464  {
465  ii -= n;
466  }
467  break;
468  }
469  }
470  }
471 
472  return List<Tuple2<scalar, Type>>::operator[](ii);
473 }
474 
475 
476 template<class Type>
477 Type Foam::interpolationTable<Type>::operator()(const scalar value) const
478 {
479  label n = this->size();
480 
481  if (n <= 1)
482  {
483  return List<Tuple2<scalar, Type>>::operator[](0).second();
484  }
485 
486  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
487  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
488  scalar lookupValue = value;
489 
490  if (lookupValue < minLimit)
491  {
492  switch (boundsHandling_)
493  {
494  case interpolationTable::ERROR:
495  {
497  << "value (" << lookupValue << ") underflow" << nl
498  << exit(FatalError);
499  break;
500  }
501  case interpolationTable::WARN:
502  {
504  << "value (" << lookupValue << ") underflow" << nl
505  << " Continuing with the first entry"
506  << endl;
507  // fall-through to 'CLAMP'
508  [[fallthrough]];
509  }
510  case interpolationTable::CLAMP:
511  {
512  return List<Tuple2<scalar, Type>>::operator[](0).second();
513  break;
514  }
515  case interpolationTable::REPEAT:
516  {
517  // adjust lookupValue to >= minLimit
518  scalar span = maxLimit-minLimit;
519  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
520  break;
521  }
522  }
523  }
524  else if (lookupValue >= maxLimit)
525  {
526  switch (boundsHandling_)
527  {
528  case interpolationTable::ERROR:
529  {
531  << "value (" << lookupValue << ") overflow" << nl
532  << exit(FatalError);
533  break;
534  }
535  case interpolationTable::WARN:
536  {
538  << "value (" << lookupValue << ") overflow" << nl
539  << " Continuing with the last entry"
540  << endl;
541  // fall-through to 'CLAMP'
542  [[fallthrough]];
543  }
544  case interpolationTable::CLAMP:
545  {
546  return List<Tuple2<scalar, Type>>::operator[](n-1).second();
547  break;
548  }
549  case interpolationTable::REPEAT:
550  {
551  // adjust lookupValue <= maxLimit
552  scalar span = maxLimit-minLimit;
553  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
554  break;
555  }
556  }
557  }
558 
559  label lo = 0;
560  label hi = 0;
561 
562  // look for the correct range
563  for (label i = 0; i < n; ++i)
564  {
565  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
566  {
567  lo = hi = i;
568  }
569  else
570  {
571  hi = i;
572  break;
573  }
574  }
575 
576  if (lo == hi)
577  {
578  // we are at the end of the table - or there is only a single entry
579  return List<Tuple2<scalar, Type>>::operator[](hi).second();
580  }
581  else if (hi == 0)
582  {
583  // this treatment should should only occur under these conditions:
584  // -> the 'REPEAT' treatment
585  // -> (0 <= value <= minLimit)
586  // -> minLimit > 0
587  // Use the value at maxLimit as the value for value=0
588  lo = n - 1;
589 
590  return
591  (
592  List<Tuple2<scalar, Type>>::operator[](lo).second()
593  + (
594  List<Tuple2<scalar, Type>>::operator[](hi).second()
595  - List<Tuple2<scalar, Type>>::operator[](lo).second()
596  )
597  *(lookupValue / minLimit)
598  );
599  }
600  else
601  {
602  // normal interpolation
603  return
604  (
605  List<Tuple2<scalar, Type>>::operator[](lo).second()
606  + (
607  List<Tuple2<scalar, Type>>::operator[](hi).second()
608  - List<Tuple2<scalar, Type>>::operator[](lo).second()
609  )
610  *(
611  lookupValue
612  - List<Tuple2<scalar, Type>>::operator[](lo).first()
613  )
614  /(
615  List<Tuple2<scalar, Type>>::operator[](hi).first()
616  - List<Tuple2<scalar, Type>>::operator[](lo).first()
617  )
618  );
619  }
620 }
621 
622 
623 // ************************************************************************* //
dictionary dict
word boundsHandlingToWord(const boundsHandling &bound) const
Return the out-of-bounds handling as a word.
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
A class for handling file names.
Definition: fileName.H:69
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const Tuple2< scalar, Type > & operator[](const label) const
Return an element of constant Tuple2<scalar, Type>
interpolationTable()
Construct null.
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:66
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:60
Type rateOfChange(const scalar) const
Return the rate of change at the interpolation location.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
Reads an interpolation table from a file - OpenFOAM-format.
Base class to read table data for the interpolationTable.
Definition: tableReader.H:57
boundsHandling outOfBounds(const boundsHandling &bound)
Set the out-of-bounds handling from enum, return previous setting.
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
stressControl lookup("compactNormalStress") >> compactNormalStress
A class for handling words, derived from string.
Definition: word.H:59
void check() const
Check that list is monotonically increasing.
An interpolation/look-up table of scalar vs <Type> values. The reference scalar values must be monoto...
Type operator()(const scalar) const
Return an interpolated value.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
static const char nl
Definition: Ostream.H:265
Ostream & writeKeyword(const keyType &)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:54
void write(Ostream &os) const
Write.
boundsHandling
Enumeration for handling out-of-bound values.
volScalarField & bound(volScalarField &, const dimensionedScalar &lowerBound)
Bound the given scalar field if it has gone unbounded.
Definition: bound.C:33
#define WarningInFunction
Report a warning using Foam::Warning.
string & expand(const bool allowEmpty=false)
Expand initial tildes and all occurrences of environment variables.
Definition: string.C:95
label n
boundsHandling wordToBoundsHandling(const word &bound) const
Return the out-of-bounds handling as an enumeration.