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-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 "FoamTableReader.H"
27 
28 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
29 
30 template<class Type>
32 :
33  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
34  boundsHandling_(interpolation2DTable::WARN),
35  fileName_(fileName::null),
36  reader_(nullptr)
37 {}
38 
39 
40 template<class Type>
42 (
43  const List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>& values,
44  const boundsHandling bounds,
45  const fileName& fName
46 )
47 :
49  boundsHandling_(bounds),
50  fileName_(fName),
51  reader_(nullptr)
52 {}
53 
54 
55 template<class Type>
57 :
58  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
59  boundsHandling_(interpolation2DTable::WARN),
60  fileName_(fName),
61  reader_(new TableReaders::Foam<Type>(dictionary()))
62 {
63  reader_()(fileName_, *this);
64  checkOrder();
65 }
66 
67 
68 template<class Type>
70 :
71  List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
72  boundsHandling_(wordToBoundsHandling(dict.lookup("outOfBounds"))),
73  fileName_(dict.lookup("file")),
74  reader_(new TableReaders::Foam<Type>(dictionary()))
75 {
76  reader_()(fileName_, *this);
77  checkOrder();
78 }
79 
80 
81 template<class Type>
83 (
84  const interpolation2DTable& interpTable
85 )
86 :
88  boundsHandling_(interpTable.boundsHandling_),
89  fileName_(interpTable.fileName_)
90 {}
91 
92 
93 
94 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
95 
96 template<class Type>
98 (
100  const scalar lookupValue
101 ) const
102 {
103  label n = data.size();
104 
105  scalar minLimit = data.first().first();
106  scalar maxLimit = data.last().first();
107 
108  if (lookupValue < minLimit)
109  {
110  switch (boundsHandling_)
111  {
112  case interpolation2DTable::ERROR:
113  {
115  << "value (" << lookupValue << ") less than lower "
116  << "bound (" << minLimit << ")" << nl
117  << exit(FatalError);
118  break;
119  }
120  case interpolation2DTable::WARN:
121  {
123  << "value (" << lookupValue << ") less than lower "
124  << "bound (" << minLimit << ")" << nl
125  << " Continuing with the first entry"
126  << endl;
127  // fall-through to 'CLAMP'
128  [[fallthrough]];
129  }
130  case interpolation2DTable::CLAMP:
131  {
132  return data.first().second();
133  break;
134  }
135  }
136  }
137  else if (lookupValue >= maxLimit)
138  {
139  switch (boundsHandling_)
140  {
141  case interpolation2DTable::ERROR:
142  {
144  << "value (" << lookupValue << ") greater than upper "
145  << "bound (" << maxLimit << ")" << nl
146  << exit(FatalError);
147  break;
148  }
149  case interpolation2DTable::WARN:
150  {
152  << "value (" << lookupValue << ") greater than upper "
153  << "bound (" << maxLimit << ")" << nl
154  << " Continuing with the last entry"
155  << endl;
156  // fall-through to 'CLAMP'
157  [[fallthrough]];
158  }
159  case interpolation2DTable::CLAMP:
160  {
161  return data.last().second();
162  break;
163  }
164  }
165  }
166 
167  // look for the correct range in X
168  label lo = 0;
169  label hi = 0;
170 
171  for (label i = 0; i < n; ++i)
172  {
173  if (lookupValue >= data[i].first())
174  {
175  lo = hi = i;
176  }
177  else
178  {
179  hi = i;
180  break;
181  }
182  }
183 
184  if (lo == hi)
185  {
186  return data[lo].second();
187  }
188  else
189  {
190  Type m =
191  (data[hi].second() - data[lo].second())
192  /(data[hi].first() - data[lo].first());
193 
194  // normal interpolation
195  return data[lo].second() + m*(lookupValue - data[lo].first());
196  }
197 }
198 
199 
200 template<class Type>
201 template<class BinaryOp>
203 (
204  const BinaryOp& bop,
205  const scalar valueX,
206  const bool reverse
207 ) const
208 {
209  const table& t = *this;
210 
211  label limitI = 0;
212  if (reverse)
213  {
214  limitI = t.size() - 1;
215  }
216 
217  if (bop(valueX, t[limitI].first()))
218  {
219  switch (boundsHandling_)
220  {
221  case interpolation2DTable::ERROR:
222  {
224  << "value (" << valueX << ") out of bounds"
225  << exit(FatalError);
226  break;
227  }
228  case interpolation2DTable::WARN:
229  {
231  << "value (" << valueX << ") out of bounds"
232  << endl;
233  // fall-through to 'CLAMP'
234  [[fallthrough]];
235  }
236  case interpolation2DTable::CLAMP:
237  {
238  return limitI;
239  }
240  default:
241  {
243  << "Un-handled enumeration " << boundsHandling_
244  << abort(FatalError);
245  }
246  }
247  }
248 
249  label i = 0;
250  if (reverse)
251  {
252  label nX = t.size();
253  i = 0;
254  while ((i < nX) && (valueX > t[i].first()))
255  {
256  i++;
257  }
258  }
259  else
260  {
261  i = t.size() - 1;
262  while ((i > 0) && (valueX < t[i].first()))
263  {
264  i--;
265  }
266  }
267 
268  return i;
269 }
270 
271 
272 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
273 
274 template<class Type>
276 (
277  const scalar valueX,
278  const scalar valueY
279 ) const
280 {
281  // Considers all of the list in Y being equal
282  label nX = this->size();
283 
284  const table& t = *this;
285 
286  if (nX == 0)
287  {
289  << "cannot interpolate a zero-sized table - returning zero" << endl;
290 
291  return Zero;
292  }
293  else if (nX == 1)
294  {
295  // only 1 column (in X) - interpolate to find Y value
296  return interpolateValue(t.first().second(), valueY);
297  }
298  else
299  {
300  // have 2-D data, interpolate
301 
302  // find low and high indices in the X range that bound valueX
303  label x0i = Xi(lessOp<scalar>(), valueX, false);
304  label x1i = Xi(greaterOp<scalar>(), valueX, true);
305 
306  if (x0i == x1i)
307  {
308  return interpolateValue(t[x0i].second(), valueY);
309  }
310  else
311  {
312  Type y0(interpolateValue(t[x0i].second(), valueY));
313  Type y1(interpolateValue(t[x1i].second(), valueY));
314 
315  // gradient in X
316  scalar x0 = t[x0i].first();
317  scalar x1 = t[x1i].first();
318  Type mX = (y1 - y0)/(x1 - x0);
319 
320  // interpolate
321  return y0 + mX*(valueX - x0);
322  }
323  }
324 }
325 
326 
327 template<class Type>
329 (
330  const boundsHandling& bound
331 ) const
332 {
333  word enumName("warn");
334 
335  switch (bound)
336  {
337  case interpolation2DTable::ERROR:
338  {
339  enumName = "error";
340  break;
341  }
342  case interpolation2DTable::WARN:
343  {
344  enumName = "warn";
345  break;
346  }
347  case interpolation2DTable::CLAMP:
348  {
349  enumName = "clamp";
350  break;
351  }
352  }
353 
354  return enumName;
355 }
356 
357 
358 template<class Type>
361 (
362  const word& bound
363 ) const
364 {
365  if (bound == "error")
366  {
367  return interpolation2DTable::ERROR;
368  }
369  else if (bound == "warn")
370  {
371  return interpolation2DTable::WARN;
372  }
373  else if (bound == "clamp")
374  {
375  return interpolation2DTable::CLAMP;
376  }
377  else
378  {
380  << "bad outOfBounds specifier " << bound << " using 'warn'" << endl;
381 
382  return interpolation2DTable::WARN;
383  }
384 }
385 
386 
387 template<class Type>
390 (
391  const boundsHandling& bound
392 )
393 {
394  boundsHandling prev = boundsHandling_;
395  boundsHandling_ = bound;
396  return prev;
397 }
398 
399 
400 template<class Type>
402 {
403  label n = this->size();
404  const table& t = *this;
405 
406  scalar prevValue = t[0].first();
407 
408  for (label i=1; i<n; ++i)
409  {
410  const scalar currValue = t[i].first();
411 
412  // avoid duplicate values (divide-by-zero error)
413  if (currValue <= prevValue)
414  {
416  << "out-of-order value: "
417  << currValue << " at index " << i << nl
418  << exit(FatalError);
419  }
420  prevValue = currValue;
421  }
422 }
423 
424 
425 template<class Type>
427 {
428  writeEntry(os, "file", fileName_);
429  writeEntry(os, "outOfBounds", boundsHandlingToWord(boundsHandling_));
430  reader_.write(os);
431 
432  *this >> os;
433 }
434 
435 
436 // ************************************************************************* //
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:79
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: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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
2D table interpolation. The data must be in ascending order in both dimensions x and y...
dimensionedScalar y0(const dimensionedScalar &ds)
T * last()
Return the last entry.
Definition: UILList.H:121
T & first()
Return the first element of the list.
Definition: UListI.H:114
word boundsHandlingToWord(const boundsHandling &bound) const
Return the out-of-bounds handling as a word.
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:54
void reverse(UList< T > &, const label n)
Definition: UListI.H:322
static const char nl
Definition: Ostream.H:260
void write(Ostream &os) const
Write.
Database for solution and other reduced data.
Definition: data.H:51
void writeEntry(Ostream &os, const HashTable< T, Key, Hash > &ht)
Definition: HashTableIO.C:96
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.
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:109
Namespace for OpenFOAM.