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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "interpolationTable.H"
30 #include "openFoamTableReader.H"
31 
32 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
33 
34 template<class Type>
36 {
37  // preserve the original (unexpanded) fileName to avoid absolute paths
38  // appearing subsequently in the write() method
39  fileName fName(fileName_);
40 
41  fName.expand();
42 
43  // Read data from file
44  reader_()(fName, *this);
45 
46  if (this->empty())
47  {
49  << "table read from " << fName << " is empty" << nl
50  << exit(FatalError);
51  }
52 
53  // Check that the data are okay
54  check();
55 }
56 
57 
58 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
59 
60 template<class Type>
62 :
63  List<value_type>(),
64  bounding_(bounds::repeatableBounding::WARN),
65  fileName_("fileNameIsUndefined"),
66  reader_(nullptr)
67 {}
68 
69 
70 template<class Type>
72 (
74  const bounds::repeatableBounding bounding,
75  const fileName& fName
76 )
77 :
79  bounding_(bounding),
80  fileName_(fName),
81  reader_(nullptr)
82 {}
83 
84 
85 template<class Type>
87 :
88  List<value_type>(),
89  bounding_(bounds::repeatableBounding::WARN),
90  fileName_(fName),
91  reader_(new openFoamTableReader<Type>(dictionary()))
92 {
93  readTable();
94 }
95 
96 
97 template<class Type>
99 :
100  List<value_type>(),
101  bounding_
102  (
103  bounds::repeatableBoundingNames.lookupOrDefault
104  (
105  "outOfBounds",
106  dict,
107  bounds::repeatableBounding::WARN,
108  true // Failsafe behaviour
109  )
110  ),
111  fileName_(dict.get<fileName>("file")),
112  reader_(tableReader<Type>::New(dict))
113 {
114  readTable();
115 }
116 
117 
118 template<class Type>
120 (
121  const interpolationTable& interpTable
122 )
123 :
124  List<value_type>(interpTable),
125  bounding_(interpTable.bounding_),
126  fileName_(interpTable.fileName_),
127  reader_(interpTable.reader_) // note: steals reader. Used in write().
128 {}
129 
130 
131 
132 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
133 
134 template<class Type>
136 {
137  const List<value_type>& list = *this;
138 
139  scalar prevValue(0);
140 
141  label i = 0;
142  for (const auto& item : list)
143  {
144  const scalar& currValue = item.first();
145 
146  // Avoid duplicate values (divide-by-zero error)
147  if (i && currValue <= prevValue)
148  {
150  << "out-of-order value: "
151  << currValue << " at index " << i << nl
152  << exit(FatalError);
153  }
154  prevValue = currValue;
155  ++i;
156  }
157 }
158 
159 
160 template<class Type>
162 {
163  os.writeEntry("file", fileName_);
164  os.writeEntry("outOfBounds", bounds::repeatableBoundingNames[bounding_]);
165  if (reader_.valid())
166  {
167  reader_->write(os);
168  }
169 }
170 
171 
172 template<class Type>
173 Type Foam::interpolationTable<Type>::rateOfChange(scalar lookupValue) const
174 {
175  const List<value_type>& list = *this;
176 
177  const label n = list.size();
178 
179  if (n <= 1)
180  {
181  // Not enough entries for a rate of change
182  return Zero;
183  }
184 
185  const scalar minLimit = list.first().first();
186  const scalar maxLimit = list.last().first();
187 
188  if (lookupValue < minLimit)
189  {
190  switch (bounding_)
191  {
192  case bounds::repeatableBounding::ERROR:
193  {
195  << "value (" << lookupValue << ") less than lower "
196  << "bound (" << minLimit << ")\n"
197  << exit(FatalError);
198  break;
199  }
200  case bounds::repeatableBounding::WARN:
201  {
203  << "value (" << lookupValue << ") less than lower "
204  << "bound (" << minLimit << ")\n"
205  << " Zero rate of change." << endl;
206 
207  // Behaviour as per CLAMP
208  return Zero;
209  break;
210  }
211  case bounds::repeatableBounding::CLAMP:
212  {
213  return Zero;
214  break;
215  }
216  case bounds::repeatableBounding::REPEAT:
217  {
218  // Adjust lookupValue to >= minLimit
219  scalar span = maxLimit-minLimit;
220  lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
221  break;
222  }
223  }
224  }
225  else if (lookupValue >= maxLimit)
226  {
227  switch (bounding_)
228  {
229  case bounds::repeatableBounding::ERROR:
230  {
232  << "value (" << lookupValue << ") greater than upper "
233  << "bound (" << maxLimit << ")\n"
234  << exit(FatalError);
235  break;
236  }
237  case bounds::repeatableBounding::WARN:
238  {
240  << "value (" << lookupValue << ") greater than upper "
241  << "bound (" << maxLimit << ")\n"
242  << " Zero rate of change." << endl;
243 
244  // Behaviour as per CLAMP
245  return Zero;
246  break;
247  }
248  case bounds::repeatableBounding::CLAMP:
249  {
250  return Zero;
251  break;
252  }
253  case bounds::repeatableBounding::REPEAT:
254  {
255  // Adjust lookupValue <= maxLimit
256  scalar span = maxLimit-minLimit;
257  lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
258  break;
259  }
260  }
261  }
262 
263  label lo = 0;
264  label hi = 0;
265 
266  // Look for the correct range
267  for (label i = 0; i < n; ++i)
268  {
269  if (lookupValue >= list[i].first())
270  {
271  lo = hi = i;
272  }
273  else
274  {
275  hi = i;
276  break;
277  }
278  }
279 
280  if (lo == hi)
281  {
282  return Zero;
283  }
284  else if (hi == 0)
285  {
286  // This treatment should only occur under these conditions:
287  // -> the 'REPEAT' treatment
288  // -> (0 <= value <= minLimit)
289  // -> minLimit > 0
290  // Use the value at maxLimit as the value for value=0
291  lo = n - 1;
292 
293  return
294  (
295  (list[hi].second() - list[lo].second())
296  / (list[hi].first() + minLimit - list[lo].first())
297  );
298  }
299 
300 
301  // Normal rate of change
302  return
303  (
304  (list[hi].second() - list[lo].second())
305  / (list[hi].first() - list[lo].first())
306  );
307 }
308 
309 
310 template<class Type>
312 (
313  const List<Tuple2<scalar, Type>>& list,
314  scalar lookupValue,
316 )
317 {
318  const label n = list.size();
319 
320  if (n <= 1)
321  {
322  #ifdef FULLDEBUG
323  if (!n)
324  {
326  << "Cannot interpolate from zero-sized table" << nl
327  << exit(FatalError);
328  }
329  #endif
330 
331  return list.first().second();
332  }
333 
334  const scalar minLimit = list.first().first();
335  const scalar maxLimit = list.last().first();
336 
337  if (lookupValue < minLimit)
338  {
339  switch (bounding)
340  {
341  case bounds::repeatableBounding::ERROR:
342  {
344  << "value (" << lookupValue << ") less than lower "
345  << "bound (" << minLimit << ")\n"
346  << exit(FatalError);
347  break;
348  }
349  case bounds::repeatableBounding::WARN:
350  {
352  << "value (" << lookupValue << ") less than lower "
353  << "bound (" << minLimit << ")\n"
354  << " Continuing with the first entry" << endl;
355 
356  // Behaviour as per CLAMP
357  return list.first().second();
358  break;
359  }
360  case bounds::repeatableBounding::CLAMP:
361  {
362  return list.first().second();
363  break;
364  }
365  case bounds::repeatableBounding::REPEAT:
366  {
367  // adjust lookupValue to >= minLimit
368  const scalar span = maxLimit-minLimit;
369  lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
370  break;
371  }
372  }
373  }
374  else if (lookupValue >= maxLimit)
375  {
376  switch (bounding)
377  {
378  case bounds::repeatableBounding::ERROR:
379  {
381  << "value (" << lookupValue << ") greater than upper "
382  << "bound (" << maxLimit << ")\n"
383  << exit(FatalError);
384  break;
385  }
386  case bounds::repeatableBounding::WARN:
387  {
389  << "value (" << lookupValue << ") greater than upper "
390  << "bound (" << maxLimit << ")\n"
391  << " Continuing with the last entry" << endl;
392 
393  // Behaviour as per 'CLAMP'
394  return list.last().second();
395  break;
396  }
397  case bounds::repeatableBounding::CLAMP:
398  {
399  return list.last().second();
400  break;
401  }
402  case bounds::repeatableBounding::REPEAT:
403  {
404  // Adjust lookupValue <= maxLimit
405  const scalar span = maxLimit-minLimit;
406  lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
407  break;
408  }
409  }
410  }
411 
412 
413  label lo = 0;
414  label hi = 0;
415 
416  // Look for the correct range
417  for (label i = 0; i < n; ++i)
418  {
419  if (lookupValue >= list[i].first())
420  {
421  lo = hi = i;
422  }
423  else
424  {
425  hi = i;
426  break;
427  }
428  }
429 
430  if (lo == hi)
431  {
432  return list[hi].second();
433  }
434  else if (hi == 0)
435  {
436  // This treatment should only occur under these conditions:
437  // -> the 'REPEAT' treatment
438  // -> (0 <= value <= minLimit)
439  // -> minLimit > 0
440  // Use the value at maxLimit as the value for value=0
441  lo = n - 1;
442 
443  return
444  (
445  list[lo].second()
446  + (list[hi].second() - list[lo].second())
447  * (lookupValue / minLimit)
448  );
449  }
450 
451 
452  // Normal interpolation
453  return
454  (
455  list[lo].second()
456  + (list[hi].second() - list[lo].second())
457  * (lookupValue - list[lo].first())
458  / (list[hi].first() - list[lo].first())
459  );
460 }
461 
462 
463 template<class Type>
465 (
466  scalar lookupValue
467 ) const
468 {
469  return interpolateValue(*this, lookupValue, bounding_);
470 }
471 
472 
473 template<class Type>
476 (
477  const UList<scalar>& vals
478 ) const
479 {
480  auto tfld = tmp<Field<Type>>::New(vals.size());
481  auto& fld = tfld.ref();
482 
483  forAll(fld, i)
484  {
485  fld[i] = interpolateValue(vals[i]);
486  }
487 
488  return tfld;
489 }
490 
491 
492 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
493 
494 template<class Type>
497 {
498  const List<value_type>& list = *this;
499  const label n = list.size();
500 
501  if (n <= 1)
502  {
503  idx = 0;
504 
505  #ifdef FULLDEBUG
506  if (!n)
507  {
509  << "Cannot interpolate from zero-sized table" << nl
510  << exit(FatalError);
511  }
512  #endif
513  }
514  else if (idx < 0)
515  {
516  switch (bounding_)
517  {
518  case bounds::repeatableBounding::ERROR:
519  {
521  << "index (" << idx << ") underflow" << nl
522  << exit(FatalError);
523  break;
524  }
525  case bounds::repeatableBounding::WARN:
526  {
528  << "index (" << idx << ") underflow" << nl
529  << " Continuing with the first entry" << nl;
530 
531  // Behaviour as per 'CLAMP'
532  idx = 0;
533  break;
534  }
535  case bounds::repeatableBounding::CLAMP:
536  {
537  idx = 0;
538  break;
539  }
540  case bounds::repeatableBounding::REPEAT:
541  {
542  while (idx < 0)
543  {
544  idx += n;
545  }
546  break;
547  }
548  }
549  }
550  else if (idx >= n)
551  {
552  switch (bounding_)
553  {
554  case bounds::repeatableBounding::ERROR:
555  {
557  << "index (" << idx << ") overflow" << nl
558  << exit(FatalError);
559  break;
560  }
561  case bounds::repeatableBounding::WARN:
562  {
564  << "index (" << idx << ") overflow" << nl
565  << " Continuing with the last entry" << nl;
566 
567  // Behaviour as per 'CLAMP'
568  idx = n - 1;
569  break;
570  }
571  case bounds::repeatableBounding::CLAMP:
572  {
573  idx = n - 1;
574  break;
575  }
576  case bounds::repeatableBounding::REPEAT:
577  {
578  while (idx >= n)
579  {
580  idx -= n;
581  }
582  break;
583  }
584  }
585  }
586 
587  return list[idx];
588 }
589 
590 
591 template<class Type>
592 Type Foam::interpolationTable<Type>::operator()(scalar lookupValue) const
593 {
594  return interpolateValue(*this, lookupValue, bounding_);
595 }
596 
597 
598 // ************************************************************************* //
Foam::openFoamTableReader
Reads an interpolation table from a file - OpenFOAM-format.
Definition: openFoamTableReader.H:51
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::Zero
static constexpr const zero Zero
Global zero.
Definition: zero.H:128
Foam::HashTableOps::values
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:149
interpolationTable.H
Foam::tableReader
Base class to read table data for the interpolationTable.
Definition: tableReader.H:59
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::interpolationTable::interpolateValues
tmp< Field< Type > > interpolateValues(const UList< scalar > &vals) const
Return multiple interpolated values.
Definition: interpolationTable.C:476
Foam::bounds::repeatableBounding
repeatableBounding
Enumeration for handling out-of-bound values that are repeatable.
Definition: tableBounds.H:61
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::interpolationTable::operator()
Type operator()(scalar lookupValue) const
Return an interpolated value.
Definition: interpolationTable.C:592
Foam::interpolationTable::write
void write(Ostream &os) const
Write.
Definition: interpolationTable.C:161
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::label
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:62
Foam::interpolationTable::interpolationTable
interpolationTable()
Construct null.
Definition: interpolationTable.C:61
fld
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Definition: gmvOutputLagrangian.H:23
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::interpolationTable::interpolateValue
static Type interpolateValue(const List< Tuple2< scalar, Type >> &list, scalar lookupValue, bounds::repeatableBounding=bounds::repeatableBounding::CLAMP)
Return an interpolated value in List.
Definition: interpolationTable.C:312
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::New
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
Definition: DimensionedFieldReuseFunctions.H:105
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:102
Foam::string::expand
string & expand(const bool allowEmpty=false)
Definition: string.C:159
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
Foam::interpolationTable::check
void check() const
Check that list is monotonically increasing.
Definition: interpolationTable.C:135
Foam::Ostream::writeEntry
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:219
Foam::UList::size
void size(const label n) noexcept
Override size to be inconsistent with allocated storage.
Definition: UListI.H:360
Foam::bounds::repeatableBoundingNames
const Foam::Enum< repeatableBounding > repeatableBoundingNames
Strings corresponding to the repeatableBounding.
Foam::interpolationTable::rateOfChange
Type rateOfChange(scalar lookupValue) const
Definition: interpolationTable.C:173
Foam::interpolationTable
An interpolation/look-up table of scalar vs <Type> values. The reference scalar values must be monoto...
Definition: interpolationTable.H:82
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::Tuple2< scalar, scalar >
Foam::interpolationTable::operator[]
const Tuple2< scalar, Type > & operator[](label idx) const
Return an element of constant Tuple2<scalar, Type>
Definition: interpolationTable.C:496
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
openFoamTableReader.H