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-2019 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  writeEntry(os, "file", fileName_);
232  writeEntry(os, "outOfBounds", boundsHandlingToWord(boundsHandling_));
233  if (reader_.valid())
234  {
235  reader_->write(os);
236  }
237 }
238 
239 
240 template<class Type>
241 Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
242 {
243  label n = this->size();
244 
245  if (n <= 1)
246  {
247  // There are not enough entries to provide a rate of change
248  return 0;
249  }
250 
251  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
252  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
253  scalar lookupValue = value;
254 
255  if (lookupValue < minLimit)
256  {
257  switch (boundsHandling_)
258  {
259  case interpolationTable::ERROR:
260  {
262  << "value (" << lookupValue << ") underflow" << nl
263  << exit(FatalError);
264  break;
265  }
266  case interpolationTable::WARN:
267  {
269  << "value (" << lookupValue << ") underflow" << nl
270  << " Zero rate of change."
271  << endl;
272  // fall-through to 'CLAMP'
273  [[fallthrough]];
274  }
275  case interpolationTable::CLAMP:
276  {
277  return 0;
278  break;
279  }
280  case interpolationTable::REPEAT:
281  {
282  // adjust lookupValue to >= minLimit
283  scalar span = maxLimit-minLimit;
284  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
285  break;
286  }
287  }
288  }
289  else if (lookupValue >= maxLimit)
290  {
291  switch (boundsHandling_)
292  {
293  case interpolationTable::ERROR:
294  {
296  << "value (" << lookupValue << ") overflow" << nl
297  << exit(FatalError);
298  break;
299  }
300  case interpolationTable::WARN:
301  {
303  << "value (" << lookupValue << ") overflow" << nl
304  << " Zero rate of change."
305  << endl;
306  // fall-through to 'CLAMP'
307  [[fallthrough]];
308  }
309  case interpolationTable::CLAMP:
310  {
311  return 0;
312  break;
313  }
314  case interpolationTable::REPEAT:
315  {
316  // adjust lookupValue <= maxLimit
317  scalar span = maxLimit-minLimit;
318  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
319  break;
320  }
321  }
322  }
323 
324  label lo = 0;
325  label hi = 0;
326 
327  // look for the correct range
328  for (label i = 0; i < n; ++i)
329  {
330  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
331  {
332  lo = hi = i;
333  }
334  else
335  {
336  hi = i;
337  break;
338  }
339  }
340 
341  if (lo == hi)
342  {
343  // we are at the end of the table - or there is only a single entry
344  return 0;
345  }
346  else if (hi == 0)
347  {
348  // this treatment should should only occur under these conditions:
349  // -> the 'REPEAT' treatment
350  // -> (0 <= value <= minLimit)
351  // -> minLimit > 0
352  // Use the value at maxLimit as the value for value=0
353  lo = n - 1;
354 
355  return
356  (
357  (
358  List<Tuple2<scalar, Type>>::operator[](hi).second()
359  - List<Tuple2<scalar, Type>>::operator[](lo).second()
360  )
361  /(
362  List<Tuple2<scalar, Type>>::operator[](hi).first()
363  + minLimit
364  - List<Tuple2<scalar, Type>>::operator[](lo).first()
365  )
366  );
367  }
368  else
369  {
370  // normal rate of change
371  return
372  (
373  (
374  List<Tuple2<scalar, Type>>::operator[](hi).second()
375  - List<Tuple2<scalar, Type>>::operator[](lo).second()
376  )
377  /(
378  List<Tuple2<scalar, Type>>::operator[](hi).first()
379  - List<Tuple2<scalar, Type>>::operator[](lo).first()
380  )
381  );
382  }
383 }
384 
385 
386 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
387 
388 template<class Type>
389 void Foam::interpolationTable<Type>::operator=
390 (
391  const interpolationTable& interpTable
392 )
393 {
394  List<Tuple2<scalar, Type>>::operator=(interpTable);
395  boundsHandling_ = interpTable.boundsHandling_;
396  fileName_ = interpTable.fileName_;
397  reader_ = interpTable.reader_; // note: steals reader. Used in write().
398 }
399 
400 
401 template<class Type>
404 {
405  label ii = i;
406  label n = this->size();
407 
408  if (n <= 1)
409  {
410  ii = 0;
411  }
412  else if (ii < 0)
413  {
414  switch (boundsHandling_)
415  {
416  case interpolationTable::ERROR:
417  {
419  << "index (" << ii << ") underflow" << nl
420  << exit(FatalError);
421  break;
422  }
423  case interpolationTable::WARN:
424  {
426  << "index (" << ii << ") underflow" << nl
427  << " Continuing with the first entry"
428  << endl;
429  // fall-through to 'CLAMP'
430  [[fallthrough]];
431  }
432  case interpolationTable::CLAMP:
433  {
434  ii = 0;
435  break;
436  }
437  case interpolationTable::REPEAT:
438  {
439  while (ii < 0)
440  {
441  ii += n;
442  }
443  break;
444  }
445  }
446  }
447  else if (ii >= n)
448  {
449  switch (boundsHandling_)
450  {
451  case interpolationTable::ERROR:
452  {
454  << "index (" << ii << ") overflow" << nl
455  << exit(FatalError);
456  break;
457  }
458  case interpolationTable::WARN:
459  {
461  << "index (" << ii << ") overflow" << nl
462  << " Continuing with the last entry"
463  << endl;
464  // fall-through to 'CLAMP'
465  [[fallthrough]];
466  }
467  case interpolationTable::CLAMP:
468  {
469  ii = n - 1;
470  break;
471  }
472  case interpolationTable::REPEAT:
473  {
474  while (ii >= n)
475  {
476  ii -= n;
477  }
478  break;
479  }
480  }
481  }
482 
483  return List<Tuple2<scalar, Type>>::operator[](ii);
484 }
485 
486 
487 template<class Type>
488 Type Foam::interpolationTable<Type>::operator()(const scalar value) const
489 {
490  label n = this->size();
491 
492  if (n <= 1)
493  {
494  return List<Tuple2<scalar, Type>>::operator[](0).second();
495  }
496 
497  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
498  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
499  scalar lookupValue = value;
500 
501  if (lookupValue < minLimit)
502  {
503  switch (boundsHandling_)
504  {
505  case interpolationTable::ERROR:
506  {
508  << "value (" << lookupValue << ") underflow" << nl
509  << exit(FatalError);
510  break;
511  }
512  case interpolationTable::WARN:
513  {
515  << "value (" << lookupValue << ") underflow" << nl
516  << " Continuing with the first entry"
517  << endl;
518  // fall-through to 'CLAMP'
519  [[fallthrough]];
520  }
521  case interpolationTable::CLAMP:
522  {
523  return List<Tuple2<scalar, Type>>::operator[](0).second();
524  break;
525  }
526  case interpolationTable::REPEAT:
527  {
528  // adjust lookupValue to >= minLimit
529  scalar span = maxLimit-minLimit;
530  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
531  break;
532  }
533  }
534  }
535  else if (lookupValue >= maxLimit)
536  {
537  switch (boundsHandling_)
538  {
539  case interpolationTable::ERROR:
540  {
542  << "value (" << lookupValue << ") overflow" << nl
543  << exit(FatalError);
544  break;
545  }
546  case interpolationTable::WARN:
547  {
549  << "value (" << lookupValue << ") overflow" << nl
550  << " Continuing with the last entry"
551  << endl;
552  // fall-through to 'CLAMP'
553  [[fallthrough]];
554  }
555  case interpolationTable::CLAMP:
556  {
557  return List<Tuple2<scalar, Type>>::operator[](n-1).second();
558  break;
559  }
560  case interpolationTable::REPEAT:
561  {
562  // adjust lookupValue <= maxLimit
563  scalar span = maxLimit-minLimit;
564  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
565  break;
566  }
567  }
568  }
569 
570  label lo = 0;
571  label hi = 0;
572 
573  // look for the correct range
574  for (label i = 0; i < n; ++i)
575  {
576  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
577  {
578  lo = hi = i;
579  }
580  else
581  {
582  hi = i;
583  break;
584  }
585  }
586 
587  if (lo == hi)
588  {
589  // we are at the end of the table - or there is only a single entry
590  return List<Tuple2<scalar, Type>>::operator[](hi).second();
591  }
592  else if (hi == 0)
593  {
594  // this treatment should should only occur under these conditions:
595  // -> the 'REPEAT' treatment
596  // -> (0 <= value <= minLimit)
597  // -> minLimit > 0
598  // Use the value at maxLimit as the value for value=0
599  lo = n - 1;
600 
601  return
602  (
603  List<Tuple2<scalar, Type>>::operator[](lo).second()
604  + (
605  List<Tuple2<scalar, Type>>::operator[](hi).second()
606  - List<Tuple2<scalar, Type>>::operator[](lo).second()
607  )
608  *(lookupValue / minLimit)
609  );
610  }
611  else
612  {
613  // normal interpolation
614  return
615  (
616  List<Tuple2<scalar, Type>>::operator[](lo).second()
617  + (
618  List<Tuple2<scalar, Type>>::operator[](hi).second()
619  - List<Tuple2<scalar, Type>>::operator[](lo).second()
620  )
621  *(
622  lookupValue
623  - List<Tuple2<scalar, Type>>::operator[](lo).first()
624  )
625  /(
626  List<Tuple2<scalar, Type>>::operator[](hi).first()
627  - List<Tuple2<scalar, Type>>::operator[](lo).first()
628  )
629  );
630  }
631 }
632 
633 
634 // ************************************************************************* //
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:79
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:158
#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:65
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
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
void writeEntry(Ostream &os, const HashTable< T, Key, Hash > &ht)
Definition: HashTableIO.C:96
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.