interpolationTable.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2016 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 "IFstream.H"
28 #include "openFoamTableReader.H"
29 
30 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
31 
32 template<class Type>
34 {
35  // preserve the original (unexpanded) fileName to avoid absolute paths
36  // appearing subsequently in the write() method
37  fileName fName(fileName_);
38 
39  fName.expand();
40 
41  // Read data from file
42  reader_()(fName, *this);
43 
44  if (this->empty())
45  {
47  << "table read from " << fName << " is empty" << nl
48  << exit(FatalError);
49  }
50 
51  // Check that the data are okay
52  check();
53 }
54 
55 
56 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
57 
58 template<class Type>
60 :
61  List<Tuple2<scalar, Type>>(),
62  boundsHandling_(interpolationTable::WARN),
63  fileName_("fileNameIsUndefined"),
64  reader_(NULL)
65 {}
66 
67 
68 template<class Type>
70 (
71  const List<Tuple2<scalar, Type>>& values,
72  const boundsHandling bounds,
73  const fileName& fName
74 )
75 :
77  boundsHandling_(bounds),
78  fileName_(fName),
79  reader_(NULL)
80 {}
81 
82 
83 template<class Type>
85 :
86  List<Tuple2<scalar, Type>>(),
87  boundsHandling_(interpolationTable::WARN),
88  fileName_(fName),
89  reader_(new openFoamTableReader<Type>(dictionary()))
90 {
91  readTable();
92 }
93 
94 
95 template<class Type>
97 :
98  List<Tuple2<scalar, Type>>(),
99  boundsHandling_(wordToBoundsHandling(dict.lookup("outOfBounds"))),
100  fileName_(dict.lookup("fileName")),
101  reader_(tableReader<Type>::New(dict))
102 {
103  readTable();
104 }
105 
106 
107 template<class Type>
109 (
110  const interpolationTable& interpTable
111 )
112 :
113  List<Tuple2<scalar, Type>>(interpTable),
114  boundsHandling_(interpTable.boundsHandling_),
115  fileName_(interpTable.fileName_),
116  reader_(interpTable.reader_) // note: steals reader. Used in write().
117 {}
118 
119 
120 
121 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122 
123 template<class Type>
125 (
126  const boundsHandling& bound
127 ) const
128 {
129  word enumName("warn");
130 
131  switch (bound)
132  {
134  {
135  enumName = "error";
136  break;
137  }
139  {
140  enumName = "warn";
141  break;
142  }
144  {
145  enumName = "clamp";
146  break;
147  }
149  {
150  enumName = "repeat";
151  break;
152  }
153  }
154 
155  return enumName;
156 }
157 
158 
159 template<class Type>
162 (
163  const word& bound
164 ) const
165 {
166  if (bound == "error")
167  {
169  }
170  else if (bound == "warn")
171  {
173  }
174  else if (bound == "clamp")
175  {
177  }
178  else if (bound == "repeat")
179  {
181  }
182  else
183  {
185  << "bad outOfBounds specifier " << bound << " using 'warn'" << endl;
186 
188  }
189 }
190 
191 
192 template<class Type>
195 (
196  const boundsHandling& bound
197 )
198 {
199  boundsHandling prev = boundsHandling_;
200  boundsHandling_ = bound;
201  return prev;
202 }
203 
204 
205 template<class Type>
207 {
208  label n = this->size();
209  scalar prevValue = List<Tuple2<scalar, Type>>::operator[](0).first();
210 
211  for (label i=1; i<n; ++i)
212  {
213  const scalar currValue =
214  List<Tuple2<scalar, Type>>::operator[](i).first();
215 
216  // avoid duplicate values (divide-by-zero error)
217  if (currValue <= prevValue)
218  {
220  << "out-of-order value: "
221  << currValue << " at index " << i << nl
222  << exit(FatalError);
223  }
224  prevValue = currValue;
225  }
226 }
227 
228 
229 template<class Type>
231 {
232  os.writeKeyword("fileName")
233  << fileName_ << token::END_STATEMENT << nl;
234  os.writeKeyword("outOfBounds")
235  << boundsHandlingToWord(boundsHandling_) << token::END_STATEMENT << nl;
236  if (reader_.valid())
237  {
238  reader_->write(os);
239  }
240 }
241 
242 
243 template<class Type>
244 Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
245 {
246  label n = this->size();
247 
248  if (n <= 1)
249  {
250  // There are not enough entries to provide a rate of change
251  return 0;
252  }
253 
254  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
255  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
256  scalar lookupValue = value;
257 
258  if (lookupValue < minLimit)
259  {
260  switch (boundsHandling_)
261  {
263  {
265  << "value (" << lookupValue << ") underflow" << nl
266  << exit(FatalError);
267  break;
268  }
270  {
272  << "value (" << lookupValue << ") underflow" << nl
273  << " Zero rate of change."
274  << endl;
275  // fall-through to 'CLAMP'
276  }
278  {
279  return 0;
280  break;
281  }
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  {
296  {
298  << "value (" << lookupValue << ") overflow" << nl
299  << exit(FatalError);
300  break;
301  }
303  {
305  << "value (" << lookupValue << ") overflow" << nl
306  << " Zero rate of change."
307  << endl;
308  // fall-through to 'CLAMP'
309  }
311  {
312  return 0;
313  break;
314  }
316  {
317  // adjust lookupValue <= maxLimit
318  scalar span = maxLimit-minLimit;
319  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
320  break;
321  }
322  }
323  }
324 
325  label lo = 0;
326  label hi = 0;
327 
328  // look for the correct range
329  for (label i = 0; i < n; ++i)
330  {
331  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
332  {
333  lo = hi = i;
334  }
335  else
336  {
337  hi = i;
338  break;
339  }
340  }
341 
342  if (lo == hi)
343  {
344  // we are at the end of the table - or there is only a single entry
345  return 0;
346  }
347  else if (hi == 0)
348  {
349  // this treatment should should only occur under these conditions:
350  // -> the 'REPEAT' treatment
351  // -> (0 <= value <= minLimit)
352  // -> minLimit > 0
353  // Use the value at maxLimit as the value for value=0
354  lo = n - 1;
355 
356  return
357  (
358  (
359  List<Tuple2<scalar, Type>>::operator[](hi).second()
360  - List<Tuple2<scalar, Type>>::operator[](lo).second()
361  )
362  /(
363  List<Tuple2<scalar, Type>>::operator[](hi).first()
364  + minLimit
365  - List<Tuple2<scalar, Type>>::operator[](lo).first()
366  )
367  );
368  }
369  else
370  {
371  // normal rate of change
372  return
373  (
374  (
375  List<Tuple2<scalar, Type>>::operator[](hi).second()
376  - List<Tuple2<scalar, Type>>::operator[](lo).second()
377  )
378  /(
379  List<Tuple2<scalar, Type>>::operator[](hi).first()
380  - List<Tuple2<scalar, Type>>::operator[](lo).first()
381  )
382  );
383  }
384 }
385 
386 
387 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
388 
389 template<class Type>
392 {
393  label ii = i;
394  label n = this->size();
395 
396  if (n <= 1)
397  {
398  ii = 0;
399  }
400  else if (ii < 0)
401  {
402  switch (boundsHandling_)
403  {
405  {
407  << "index (" << ii << ") underflow" << nl
408  << exit(FatalError);
409  break;
410  }
412  {
414  << "index (" << ii << ") underflow" << nl
415  << " Continuing with the first entry"
416  << endl;
417  // fall-through to 'CLAMP'
418  }
420  {
421  ii = 0;
422  break;
423  }
425  {
426  while (ii < 0)
427  {
428  ii += n;
429  }
430  break;
431  }
432  }
433  }
434  else if (ii >= n)
435  {
436  switch (boundsHandling_)
437  {
439  {
441  << "index (" << ii << ") overflow" << nl
442  << exit(FatalError);
443  break;
444  }
446  {
448  << "index (" << ii << ") overflow" << nl
449  << " Continuing with the last entry"
450  << endl;
451  // fall-through to 'CLAMP'
452  }
454  {
455  ii = n - 1;
456  break;
457  }
459  {
460  while (ii >= n)
461  {
462  ii -= n;
463  }
464  break;
465  }
466  }
467  }
468 
470 }
471 
472 
473 template<class Type>
474 Type Foam::interpolationTable<Type>::operator()(const scalar value) const
475 {
476  label n = this->size();
477 
478  if (n <= 1)
479  {
480  return List<Tuple2<scalar, Type>>::operator[](0).second();
481  }
482 
483  scalar minLimit = List<Tuple2<scalar, Type>>::operator[](0).first();
484  scalar maxLimit = List<Tuple2<scalar, Type>>::operator[](n-1).first();
485  scalar lookupValue = value;
486 
487  if (lookupValue < minLimit)
488  {
489  switch (boundsHandling_)
490  {
492  {
494  << "value (" << lookupValue << ") underflow" << nl
495  << exit(FatalError);
496  break;
497  }
499  {
501  << "value (" << lookupValue << ") underflow" << nl
502  << " Continuing with the first entry"
503  << endl;
504  // fall-through to 'CLAMP'
505  }
507  {
508  return List<Tuple2<scalar, Type>>::operator[](0).second();
509  break;
510  }
512  {
513  // adjust lookupValue to >= minLimit
514  scalar span = maxLimit-minLimit;
515  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
516  break;
517  }
518  }
519  }
520  else if (lookupValue >= maxLimit)
521  {
522  switch (boundsHandling_)
523  {
525  {
527  << "value (" << lookupValue << ") overflow" << nl
528  << exit(FatalError);
529  break;
530  }
532  {
534  << "value (" << lookupValue << ") overflow" << nl
535  << " Continuing with the last entry"
536  << endl;
537  // fall-through to 'CLAMP'
538  }
540  {
541  return List<Tuple2<scalar, Type>>::operator[](n-1).second();
542  break;
543  }
545  {
546  // adjust lookupValue <= maxLimit
547  scalar span = maxLimit-minLimit;
548  lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
549  break;
550  }
551  }
552  }
553 
554  label lo = 0;
555  label hi = 0;
556 
557  // look for the correct range
558  for (label i = 0; i < n; ++i)
559  {
560  if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
561  {
562  lo = hi = i;
563  }
564  else
565  {
566  hi = i;
567  break;
568  }
569  }
570 
571  if (lo == hi)
572  {
573  // we are at the end of the table - or there is only a single entry
574  return List<Tuple2<scalar, Type>>::operator[](hi).second();
575  }
576  else if (hi == 0)
577  {
578  // this treatment should should only occur under these conditions:
579  // -> the 'REPEAT' treatment
580  // -> (0 <= value <= minLimit)
581  // -> minLimit > 0
582  // Use the value at maxLimit as the value for value=0
583  lo = n - 1;
584 
585  return
586  (
587  List<Tuple2<scalar, Type>>::operator[](lo).second()
588  + (
589  List<Tuple2<scalar, Type>>::operator[](hi).second()
590  - List<Tuple2<scalar, Type>>::operator[](lo).second()
591  )
592  *(lookupValue / minLimit)
593  );
594  }
595  else
596  {
597  // normal interpolation
598  return
599  (
600  List<Tuple2<scalar, Type>>::operator[](lo).second()
601  + (
602  List<Tuple2<scalar, Type>>::operator[](hi).second()
603  - List<Tuple2<scalar, Type>>::operator[](lo).second()
604  )
605  *(
606  lookupValue
607  - List<Tuple2<scalar, Type>>::operator[](lo).first()
608  )
609  /(
610  List<Tuple2<scalar, Type>>::operator[](hi).first()
611  - List<Tuple2<scalar, Type>>::operator[](lo).first()
612  )
613  );
614  }
615 }
616 
617 
618 // ************************************************************************* //
Type rateOfChange(const scalar) const
Return the rate of change at the interpolation location.
word boundsHandlingToWord(const boundsHandling &bound) const
Return the out-of-bounds handling as a word.
void check() const
Check that list is monotonically increasing.
dictionary dict
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
friend Ostream & operator(Ostream &, const UList< T > &)
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: Tuple2.H:47
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
const Tuple2< scalar, Type > & operator[](const label) const
Return an element of constant Tuple2<scalar, Type>
Reads an interpolation table from a file - OpenFOAM-format.
T & first()
Return the first element of the list.
Definition: UListI.H:114
Base class to read table data for the interpolationTable.
Definition: tableReader.H:57
Type operator()(const scalar) const
Return an interpolated value.
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
Clamp value to the start/end value.
An interpolation/look-up table of scalar vs <Type> values. The reference scalar values must be monoto...
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
Exit with a FatalError.
static const char nl
Definition: Ostream.H:262
Ostream & writeKeyword(const keyType &)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:54
label size() const
Return the number of elements in the UList.
Issue warning and clamp value (default)
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 occurences of environment variables.
Definition: string.C:95
Treat as a repeating list.
label n
boundsHandling wordToBoundsHandling(const word &bound) const
Return the out-of-bounds handling as an enumeration.
void write(Ostream &os) const
Write.