interpolation2DTable.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 "IFstream.H"
27 #include "openFoamTableReader.H"
28 
29 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
30 
31 template<class Type>
33 {
34  fileName fName(fileName_);
35  fName.expand();
36 
37  // Read data from file
38  reader_()(fName, *this);
39 
40  if (this->empty())
41  {
43  << "table read from " << fName << " is empty" << nl
44  << exit(FatalError);
45  }
46 
47  // Check that the data are in ascending order
48  checkOrder();
49 }
50 
51 
52 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
53 
54 template<class Type>
56 :
57  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
58  boundsHandling_(interpolation2DTable::WARN),
59  fileName_("fileNameIsUndefined"),
60  reader_(nullptr)
61 {}
62 
63 
64 template<class Type>
66 (
67  const List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>& values,
68  const boundsHandling bounds,
69  const fileName& fName
70 )
71 :
73  boundsHandling_(bounds),
74  fileName_(fName),
75  reader_(nullptr)
76 {}
77 
78 
79 template<class Type>
81 :
82  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
83  boundsHandling_(interpolation2DTable::WARN),
84  fileName_(fName),
85  reader_(new openFoamTableReader<Type>(dictionary()))
86 {
87  readTable();
88 }
89 
90 
91 template<class Type>
93 :
94  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
95  boundsHandling_(wordToBoundsHandling(dict.lookup("outOfBounds"))),
96  fileName_(dict.lookup("file")),
97  reader_(tableReader<Type>::New(dict))
98 {
99  readTable();
100 }
101 
102 
103 template<class Type>
105 (
106  const interpolation2DTable& interpTable
107 )
108 :
110  boundsHandling_(interpTable.boundsHandling_),
111  fileName_(interpTable.fileName_),
112  reader_(interpTable.reader_) // note: steals reader. Used in write().
113 {}
114 
115 
116 
117 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
118 
119 template<class Type>
121 (
123  const scalar lookupValue
124 ) const
125 {
126  label n = data.size();
127 
128  scalar minLimit = data.first().first();
129  scalar maxLimit = data.last().first();
130 
131  if (lookupValue < minLimit)
132  {
133  switch (boundsHandling_)
134  {
135  case interpolation2DTable::ERROR:
136  {
138  << "value (" << lookupValue << ") less than lower "
139  << "bound (" << minLimit << ")" << nl
140  << exit(FatalError);
141  break;
142  }
143  case interpolation2DTable::WARN:
144  {
146  << "value (" << lookupValue << ") less than lower "
147  << "bound (" << minLimit << ")" << nl
148  << " Continuing with the first entry"
149  << endl;
150  // fall-through to 'CLAMP'
151  [[fallthrough]];
152  }
153  case interpolation2DTable::CLAMP:
154  {
155  return data.first().second();
156  break;
157  }
158  }
159  }
160  else if (lookupValue >= maxLimit)
161  {
162  switch (boundsHandling_)
163  {
164  case interpolation2DTable::ERROR:
165  {
167  << "value (" << lookupValue << ") greater than upper "
168  << "bound (" << maxLimit << ")" << nl
169  << exit(FatalError);
170  break;
171  }
172  case interpolation2DTable::WARN:
173  {
175  << "value (" << lookupValue << ") greater than upper "
176  << "bound (" << maxLimit << ")" << nl
177  << " Continuing with the last entry"
178  << endl;
179  // fall-through to 'CLAMP'
180  [[fallthrough]];
181  }
182  case interpolation2DTable::CLAMP:
183  {
184  return data.last().second();
185  break;
186  }
187  }
188  }
189 
190  // look for the correct range in X
191  label lo = 0;
192  label hi = 0;
193 
194  for (label i = 0; i < n; ++i)
195  {
196  if (lookupValue >= data[i].first())
197  {
198  lo = hi = i;
199  }
200  else
201  {
202  hi = i;
203  break;
204  }
205  }
206 
207  if (lo == hi)
208  {
209  return data[lo].second();
210  }
211  else
212  {
213  Type m =
214  (data[hi].second() - data[lo].second())
215  /(data[hi].first() - data[lo].first());
216 
217  // normal interpolation
218  return data[lo].second() + m*(lookupValue - data[lo].first());
219  }
220 }
221 
222 
223 template<class Type>
224 template<class BinaryOp>
226 (
227  const BinaryOp& bop,
228  const scalar valueX,
229  const bool reverse
230 ) const
231 {
232  const table& t = *this;
233 
234  label limitI = 0;
235  if (reverse)
236  {
237  limitI = t.size() - 1;
238  }
239 
240  if (bop(valueX, t[limitI].first()))
241  {
242  switch (boundsHandling_)
243  {
244  case interpolation2DTable::ERROR:
245  {
247  << "value (" << valueX << ") out of bounds"
248  << exit(FatalError);
249  break;
250  }
251  case interpolation2DTable::WARN:
252  {
254  << "value (" << valueX << ") out of bounds"
255  << endl;
256  // fall-through to 'CLAMP'
257  [[fallthrough]];
258  }
259  case interpolation2DTable::CLAMP:
260  {
261  return limitI;
262  }
263  default:
264  {
266  << "Un-handled enumeration " << boundsHandling_
267  << abort(FatalError);
268  }
269  }
270  }
271 
272  label i = 0;
273  if (reverse)
274  {
275  label nX = t.size();
276  i = 0;
277  while ((i < nX) && (valueX > t[i].first()))
278  {
279  i++;
280  }
281  }
282  else
283  {
284  i = t.size() - 1;
285  while ((i > 0) && (valueX < t[i].first()))
286  {
287  i--;
288  }
289  }
290 
291  return i;
292 }
293 
294 
295 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
296 
297 template<class Type>
299 (
300  const scalar valueX,
301  const scalar valueY
302 ) const
303 {
304  // Considers all of the list in Y being equal
305  label nX = this->size();
306 
307  const table& t = *this;
308 
309  if (nX == 0)
310  {
312  << "cannot interpolate a zero-sized table - returning zero" << endl;
313 
314  return Zero;
315  }
316  else if (nX == 1)
317  {
318  // only 1 column (in X) - interpolate to find Y value
319  return interpolateValue(t.first().second(), valueY);
320  }
321  else
322  {
323  // have 2-D data, interpolate
324 
325  // find low and high indices in the X range that bound valueX
326  label x0i = Xi(lessOp<scalar>(), valueX, false);
327  label x1i = Xi(greaterOp<scalar>(), valueX, true);
328 
329  if (x0i == x1i)
330  {
331  return interpolateValue(t[x0i].second(), valueY);
332  }
333  else
334  {
335  Type y0(interpolateValue(t[x0i].second(), valueY));
336  Type y1(interpolateValue(t[x1i].second(), valueY));
337 
338  // gradient in X
339  scalar x0 = t[x0i].first();
340  scalar x1 = t[x1i].first();
341  Type mX = (y1 - y0)/(x1 - x0);
342 
343  // interpolate
344  return y0 + mX*(valueX - x0);
345  }
346  }
347 }
348 
349 
350 template<class Type>
352 (
353  const boundsHandling& bound
354 ) const
355 {
356  word enumName("warn");
357 
358  switch (bound)
359  {
360  case interpolation2DTable::ERROR:
361  {
362  enumName = "error";
363  break;
364  }
365  case interpolation2DTable::WARN:
366  {
367  enumName = "warn";
368  break;
369  }
370  case interpolation2DTable::CLAMP:
371  {
372  enumName = "clamp";
373  break;
374  }
375  }
376 
377  return enumName;
378 }
379 
380 
381 template<class Type>
384 (
385  const word& bound
386 ) const
387 {
388  if (bound == "error")
389  {
390  return interpolation2DTable::ERROR;
391  }
392  else if (bound == "warn")
393  {
394  return interpolation2DTable::WARN;
395  }
396  else if (bound == "clamp")
397  {
398  return interpolation2DTable::CLAMP;
399  }
400  else
401  {
403  << "bad outOfBounds specifier " << bound << " using 'warn'" << endl;
404 
405  return interpolation2DTable::WARN;
406  }
407 }
408 
409 
410 template<class Type>
413 (
414  const boundsHandling& bound
415 )
416 {
417  boundsHandling prev = boundsHandling_;
418  boundsHandling_ = bound;
419  return prev;
420 }
421 
422 
423 template<class Type>
425 {
426  label n = this->size();
427  const table& t = *this;
428 
429  scalar prevValue = t[0].first();
430 
431  for (label i=1; i<n; ++i)
432  {
433  const scalar currValue = t[i].first();
434 
435  // avoid duplicate values (divide-by-zero error)
436  if (currValue <= prevValue)
437  {
439  << "out-of-order value: "
440  << currValue << " at index " << i << nl
441  << exit(FatalError);
442  }
443  prevValue = currValue;
444  }
445 }
446 
447 
448 template<class Type>
450 {
451  os.writeKeyword("file")
452  << fileName_ << token::END_STATEMENT << nl;
453  os.writeKeyword("outOfBounds")
454  << boundsHandlingToWord(boundsHandling_) << token::END_STATEMENT << nl;
455 
456  *this >> os;
457 }
458 
459 
460 // ************************************************************************* //
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 > &)
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
2D table interpolation. The data must be in ascending order in both dimensions x and y...
dimensionedScalar y0(const dimensionedScalar &ds)
Reads an interpolation table from a file - OpenFOAM-format.
T * last()
Return the last entry.
Definition: UILList.H:118
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
word boundsHandlingToWord(const boundsHandling &bound) const
Return the out-of-bounds handling as a word.
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
stressControl lookup("compactNormalStress") >> compactNormalStress
interpolation2DTable()
Construct null.
A class for handling words, derived from string.
Definition: word.H:59
static const zero Zero
Definition: zero.H:97
errorManip< error > abort(error &err)
Definition: errorManip.H:131
dimensionedScalar y1(const dimensionedScalar &ds)
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
void reverse(UList< T > &, const label n)
Definition: UListI.H:322
static const char nl
Definition: Ostream.H:265
void write(Ostream &os) const
Write.
Database for solution data, solver performance and other reduced data.
Definition: data.H:52
Ostream & writeKeyword(const keyType &)
Write the keyword followed by an appropriate indentation.
Definition: Ostream.C:54
boundsHandling outOfBounds(const boundsHandling &bound)
Set the out-of-bounds handling from enum, return previous setting.
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
void checkOrder() const
Check that list is monotonically increasing.
boundsHandling wordToBoundsHandling(const word &bound) const
Return the out-of-bounds handling as an enumeration.
boundsHandling
Enumeration for handling out-of-bound values.
label n
T * first()
Return the first entry.
Definition: UILList.H:106