ENH: interpolationTable improvements

- reduce code duplication, support returning multiple interpolations
  as a Field
This commit is contained in:
Mark Olesen
2019-08-23 15:57:22 +02:00
committed by Andrew Heather
parent 784d3ad5d4
commit 87330972d8
7 changed files with 444 additions and 482 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016 OpenCFD Ltd.
Copyright (C) 2016-2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -47,7 +47,7 @@ void Foam::interpolation2DTable<Type>::readTable()
}
// Check that the data are in ascending order
checkOrder();
check();
}
@ -56,7 +56,7 @@ void Foam::interpolation2DTable<Type>::readTable()
template<class Type>
Foam::interpolation2DTable<Type>::interpolation2DTable()
:
List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
List<value_type>(),
bounding_(bounds::normalBounding::WARN),
fileName_("fileNameIsUndefined"),
reader_(nullptr)
@ -71,7 +71,7 @@ Foam::interpolation2DTable<Type>::interpolation2DTable
const fileName& fName
)
:
List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(values),
List<value_type>(values),
bounding_(bounding),
fileName_(fName),
reader_(nullptr)
@ -81,7 +81,7 @@ Foam::interpolation2DTable<Type>::interpolation2DTable
template<class Type>
Foam::interpolation2DTable<Type>::interpolation2DTable(const fileName& fName)
:
List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
List<value_type>(),
bounding_(bounds::normalBounding::WARN),
fileName_(fName),
reader_(new openFoamTableReader<Type>(dictionary()))
@ -93,7 +93,7 @@ Foam::interpolation2DTable<Type>::interpolation2DTable(const fileName& fName)
template<class Type>
Foam::interpolation2DTable<Type>::interpolation2DTable(const dictionary& dict)
:
List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(),
List<value_type>(),
bounding_
(
bounds::normalBoundingNames.lookupOrDefault
@ -104,7 +104,7 @@ Foam::interpolation2DTable<Type>::interpolation2DTable(const dictionary& dict)
true // Failsafe behaviour
)
),
fileName_(dict.lookup("file")),
fileName_(dict.get<fileName>("file")),
reader_(tableReader<Type>::New(dict))
{
readTable();
@ -117,121 +117,28 @@ Foam::interpolation2DTable<Type>::interpolation2DTable
const interpolation2DTable& interpTable
)
:
List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>(interpTable),
List<value_type>(interpTable),
bounding_(interpTable.bounding_),
fileName_(interpTable.fileName_),
reader_(interpTable.reader_) // note: steals reader. Used in write().
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Type Foam::interpolation2DTable<Type>::interpolateValue
(
const List<Tuple2<scalar, Type>>& data,
const scalar lookupValue
const List<Tuple2<scalar, Type>>& list,
scalar lookupValue
) const
{
const label n = data.size();
const scalar minLimit = data.first().first();
const scalar maxLimit = data.last().first();
if (lookupValue < minLimit)
{
switch (bounding_)
{
case bounds::normalBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::normalBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< " Continuing with the first entry"
<< endl;
// Behaviour as per CLAMP
return data.first().second();
break;
}
case bounds::normalBounding::CLAMP:
{
return data.first().second();
break;
}
}
}
else if (lookupValue >= maxLimit)
{
switch (bounding_)
{
case bounds::normalBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::normalBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< " Continuing with the last entry"
<< endl;
// Behaviour as per CLAMP
return data.last().second();
break;
}
case bounds::normalBounding::CLAMP:
{
return data.last().second();
break;
}
}
}
// look for the correct range in X
label lo = 0;
label hi = 0;
for (label i = 0; i < n; ++i)
{
if (lookupValue >= data[i].first())
{
lo = hi = i;
}
else
{
hi = i;
break;
}
}
if (lo == hi)
{
return data[lo].second();
}
else
{
Type m =
(data[hi].second() - data[lo].second())
/(data[hi].first() - data[lo].first());
// normal interpolation
return data[lo].second() + m*(lookupValue - data[lo].first());
}
return interpolationTable<Type>::interpolateValue
(
list,
lookupValue,
bounds::repeatableBounding(bounding_)
);
}
@ -244,7 +151,7 @@ Foam::label Foam::interpolation2DTable<Type>::Xi
const bool reverse
) const
{
const table& t = *this;
const List<value_type>& t = *this;
label limitI = 0;
if (reverse)
@ -259,15 +166,14 @@ Foam::label Foam::interpolation2DTable<Type>::Xi
case bounds::normalBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << valueX << ") out of bounds"
<< "value (" << valueX << ") out of bounds" << nl
<< exit(FatalError);
break;
}
case bounds::normalBounding::WARN:
{
WarningInFunction
<< "value (" << valueX << ") out of bounds"
<< endl;
<< "value (" << valueX << ") out of bounds" << nl;
// Behaviour as per CLAMP
return limitI;
@ -290,11 +196,11 @@ Foam::label Foam::interpolation2DTable<Type>::Xi
label i = 0;
if (reverse)
{
label nX = t.size();
const label nX = t.size();
i = 0;
while ((i < nX) && (valueX > t[i].first()))
{
i++;
++i;
}
}
else
@ -302,7 +208,7 @@ Foam::label Foam::interpolation2DTable<Type>::Xi
i = t.size() - 1;
while ((i > 0) && (valueX < t[i].first()))
{
i--;
--i;
}
}
@ -319,66 +225,61 @@ Type Foam::interpolation2DTable<Type>::operator()
const scalar valueY
) const
{
// Considers all of the list in Y being equal
const label nX = this->size();
const List<value_type>& t = *this;
const table& t = *this;
// Assumes all of the list in Y being equal length
const label nX = t.size();
if (nX == 0)
{
WarningInFunction
<< "cannot interpolate a zero-sized table - returning zero" << endl;
<< "Cannot interpolate zero-sized table - returning zero" << nl;
return Zero;
}
else if (nX == 1)
{
// only 1 column (in X) - interpolate to find Y value
// Only 1 column (in X) - simply interpolate to find Y value
return interpolateValue(t.first().second(), valueY);
}
else
// Find low and high indices in the X range that bound valueX
const label lo = Xi(lessOp<scalar>(), valueX, false);
const label hi = Xi(greaterOp<scalar>(), valueX, true);
if (lo == hi)
{
// have 2-D data, interpolate
// find low and high indices in the X range that bound valueX
const label x0i = Xi(lessOp<scalar>(), valueX, false);
const label x1i = Xi(greaterOp<scalar>(), valueX, true);
if (x0i == x1i)
{
return interpolateValue(t[x0i].second(), valueY);
}
else
{
Type y0(interpolateValue(t[x0i].second(), valueY));
Type y1(interpolateValue(t[x1i].second(), valueY));
// gradient in X
const scalar x0 = t[x0i].first();
const scalar x1 = t[x1i].first();
Type mX = (y1 - y0)/(x1 - x0);
// interpolate
return y0 + mX*(valueX - x0);
}
return interpolateValue(t[lo].second(), valueY);
}
// Normal interpolation
const Type y0(interpolateValue(t[lo].second(), valueY));
const Type y1(interpolateValue(t[hi].second(), valueY));
const scalar& x0 = t[lo].first();
const scalar& x1 = t[hi].first();
return (y0 + (y1 - y0)*(valueX - x0)/(x1 - x0));
}
template<class Type>
void Foam::interpolation2DTable<Type>::checkOrder() const
void Foam::interpolation2DTable<Type>::check() const
{
const label n = this->size();
const table& t = *this;
const List<value_type>& list = *this;
scalar prevValue = t[0].first();
scalar prevValue(0);
for (label i=1; i<n; ++i)
label i = 0;
for (const auto& item : list)
{
const scalar currValue = t[i].first();
const scalar& currValue = item.first();
// avoid duplicate values (divide-by-zero error)
if (currValue <= prevValue)
// Avoid duplicate values (divide-by-zero error)
if (i && currValue <= prevValue)
{
FatalErrorInFunction
<< "out-of-order value: "
@ -386,6 +287,7 @@ void Foam::interpolation2DTable<Type>::checkOrder() const
<< exit(FatalError);
}
prevValue = currValue;
++i;
}
}

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,8 +28,8 @@ Class
Foam::interpolation2DTable
Description
2D table interpolation. The data must be in ascending order in both
dimensions x and y.
2D table interpolation.
The data must be in ascending order in both dimensions x and y.
SourceFiles
interpolation2DTable.C
@ -38,10 +39,7 @@ SourceFiles
#ifndef interpolation2DTable_H
#define interpolation2DTable_H
#include "List.H"
#include "Tuple2.H"
#include "tableBounds.H"
#include "tableReader.H"
#include "interpolationTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -57,17 +55,7 @@ class interpolation2DTable
:
public List<Tuple2<scalar, List<Tuple2<scalar, Type>>>>
{
public:
// Public data types
//- Convenience typedef
typedef List<Tuple2<scalar, List<Tuple2<scalar, Type>>>> table;
private:
// Private data
// Private Data
//- Handling for out-of-bound values
bounds::normalBounding bounding_;
@ -84,11 +72,11 @@ private:
//- Read the table of data from file
void readTable();
//- Return interpolated value in List
//- Interpolated value within 1-D list
Type interpolateValue
(
const List<Tuple2<scalar, Type>>& data,
const scalar
const List<Tuple2<scalar, Type>>& list,
scalar lookupValue
) const;
//- Return an X index from the matrix
@ -103,6 +91,15 @@ private:
public:
// Public Data Types
//- The element data type
typedef Tuple2<scalar, List<Tuple2<scalar, Type>>> value_type;
//- Convenience typedef
typedef List<Tuple2<scalar, List<Tuple2<scalar, Type>>>> table;
// Constructors
//- Construct null
@ -117,12 +114,12 @@ public:
);
//- Construct given the name of the file containing the table of data
interpolation2DTable(const fileName& fName);
explicit interpolation2DTable(const fileName& fName);
//- Construct by reading file name and outOfBounds from dictionary
interpolation2DTable(const dictionary& dict);
explicit interpolation2DTable(const dictionary& dict);
//- Construct copy
//- Copy construct
interpolation2DTable(const interpolation2DTable& interpTable);
@ -130,7 +127,7 @@ public:
//- Check that list is monotonically increasing
// Exit with a FatalError if there is a problem
void checkOrder() const;
void check() const;
//- Write
void write(Ostream& os) const;
@ -138,11 +135,15 @@ public:
// Member Operators
//- Return an element of constant List<Tuple2<scalar, Type>>
const List<Tuple2<scalar, Type>>& operator[](const label) const;
//- Return an interpolated value
Type operator()(const scalar valueX, const scalar valueY) const;
// Housekeeping
//- Deprecated(2019-08) check list is monotonically increasing
// \deprecated(2019-08) - older name for check() method
void checkOrder() const { check(); }
};

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -59,7 +60,7 @@ void Foam::interpolationTable<Type>::readTable()
template<class Type>
Foam::interpolationTable<Type>::interpolationTable()
:
List<Tuple2<scalar, Type>>(),
List<value_type>(),
bounding_(bounds::repeatableBounding::WARN),
fileName_("fileNameIsUndefined"),
reader_(nullptr)
@ -74,7 +75,7 @@ Foam::interpolationTable<Type>::interpolationTable
const fileName& fName
)
:
List<Tuple2<scalar, Type>>(values),
List<value_type>(values),
bounding_(bounding),
fileName_(fName),
reader_(nullptr)
@ -84,7 +85,7 @@ Foam::interpolationTable<Type>::interpolationTable
template<class Type>
Foam::interpolationTable<Type>::interpolationTable(const fileName& fName)
:
List<Tuple2<scalar, Type>>(),
List<value_type>(),
bounding_(bounds::repeatableBounding::WARN),
fileName_(fName),
reader_(new openFoamTableReader<Type>(dictionary()))
@ -96,7 +97,7 @@ Foam::interpolationTable<Type>::interpolationTable(const fileName& fName)
template<class Type>
Foam::interpolationTable<Type>::interpolationTable(const dictionary& dict)
:
List<Tuple2<scalar, Type>>(),
List<value_type>(),
bounding_
(
bounds::repeatableBoundingNames.lookupOrDefault
@ -107,7 +108,7 @@ Foam::interpolationTable<Type>::interpolationTable(const dictionary& dict)
true // Failsafe behaviour
)
),
fileName_(dict.lookup("file")),
fileName_(dict.get<fileName>("file")),
reader_(tableReader<Type>::New(dict))
{
readTable();
@ -120,7 +121,7 @@ Foam::interpolationTable<Type>::interpolationTable
const interpolationTable& interpTable
)
:
List<Tuple2<scalar, Type>>(interpTable),
List<value_type>(interpTable),
bounding_(interpTable.bounding_),
fileName_(interpTable.fileName_),
reader_(interpTable.reader_) // note: steals reader. Used in write().
@ -133,16 +134,17 @@ Foam::interpolationTable<Type>::interpolationTable
template<class Type>
void Foam::interpolationTable<Type>::check() const
{
const label n = this->size();
scalar prevValue = this->first().first();
const List<value_type>& list = *this;
for (label i=1; i<n; ++i)
scalar prevValue(0);
label i = 0;
for (const auto& item : list)
{
const scalar currValue =
List<Tuple2<scalar, Type>>::operator[](i).first();
const scalar& currValue = item.first();
// avoid duplicate values (divide-by-zero error)
if (currValue <= prevValue)
// Avoid duplicate values (divide-by-zero error)
if (i && currValue <= prevValue)
{
FatalErrorInFunction
<< "out-of-order value: "
@ -150,6 +152,7 @@ void Foam::interpolationTable<Type>::check() const
<< exit(FatalError);
}
prevValue = currValue;
++i;
}
}
@ -167,19 +170,20 @@ void Foam::interpolationTable<Type>::write(Ostream& os) const
template<class Type>
Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
Type Foam::interpolationTable<Type>::rateOfChange(scalar lookupValue) const
{
label n = this->size();
const List<value_type>& list = *this;
const label n = list.size();
if (n <= 1)
{
// There are not enough entries to provide a rate of change
return 0;
// Not enough entries for a rate of change
return Zero;
}
const scalar minLimit = this->first().first();
const scalar maxLimit = this->last().first();
scalar lookupValue = value;
const scalar minLimit = list.first().first();
const scalar maxLimit = list.last().first();
if (lookupValue < minLimit)
{
@ -188,31 +192,32 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") underflow" << nl
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") underflow" << nl
<< " Zero rate of change."
<< endl;
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< " Zero rate of change." << endl;
// Behaviour as per CLAMP
return 0;
return Zero;
break;
}
case bounds::repeatableBounding::CLAMP:
{
return 0;
return Zero;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// Adjust lookupValue to >= minLimit
scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
@ -224,31 +229,32 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") overflow" << nl
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") overflow" << nl
<< " Zero rate of change."
<< endl;
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< " Zero rate of change." << endl;
// Behaviour as per CLAMP
return 0;
return Zero;
break;
}
case bounds::repeatableBounding::CLAMP:
{
return 0;
return Zero;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// Adjust lookupValue <= maxLimit
scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
@ -257,10 +263,10 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
label lo = 0;
label hi = 0;
// look for the correct range
// Look for the correct range
for (label i = 0; i < n; ++i)
{
if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
if (lookupValue >= list[i].first())
{
lo = hi = i;
}
@ -273,12 +279,11 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
if (lo == hi)
{
// we are at the end of the table - or there is only a single entry
return 0;
return Zero;
}
else if (hi == 0)
{
// this treatment should only occur under these conditions:
// This treatment should only occur under these conditions:
// -> the 'REPEAT' treatment
// -> (0 <= value <= minLimit)
// -> minLimit > 0
@ -287,32 +292,200 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
return
(
(
List<Tuple2<scalar, Type>>::operator[](hi).second()
- List<Tuple2<scalar, Type>>::operator[](lo).second()
)
/(
List<Tuple2<scalar, Type>>::operator[](hi).first()
+ minLimit
- List<Tuple2<scalar, Type>>::operator[](lo).first()
)
(list[hi].second() - list[lo].second())
/ (list[hi].first() + minLimit - list[lo].first())
);
}
else
// Normal rate of change
return
(
(list[hi].second() - list[lo].second())
/ (list[hi].first() - list[lo].first())
);
}
template<class Type>
Type Foam::interpolationTable<Type>::interpolateValue
(
const List<Tuple2<scalar, Type>>& list,
scalar lookupValue,
bounds::repeatableBounding bounding
)
{
const label n = list.size();
if (n <= 1)
{
// normal rate of change
#ifdef FULLDEBUG
if (!n)
{
FatalErrorInFunction
<< "Cannot interpolate from zero-sized table" << nl
<< exit(FatalError);
}
#endif
return list.first().second();
}
const scalar minLimit = list.first().first();
const scalar maxLimit = list.last().first();
if (lookupValue < minLimit)
{
switch (bounding)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< " Continuing with the first entry" << endl;
// Behaviour as per CLAMP
return list.first().second();
break;
}
case bounds::repeatableBounding::CLAMP:
{
return list.first().second();
break;
}
case bounds::repeatableBounding::REPEAT:
{
// adjust lookupValue to >= minLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
}
else if (lookupValue >= maxLimit)
{
switch (bounding)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< " Continuing with the last entry" << endl;
// Behaviour as per 'CLAMP'
return list.last().second();
break;
}
case bounds::repeatableBounding::CLAMP:
{
return list.last().second();
break;
}
case bounds::repeatableBounding::REPEAT:
{
// Adjust lookupValue <= maxLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
}
label lo = 0;
label hi = 0;
// Look for the correct range
for (label i = 0; i < n; ++i)
{
if (lookupValue >= list[i].first())
{
lo = hi = i;
}
else
{
hi = i;
break;
}
}
if (lo == hi)
{
return list[hi].second();
}
else if (hi == 0)
{
// This treatment should only occur under these conditions:
// -> the 'REPEAT' treatment
// -> (0 <= value <= minLimit)
// -> minLimit > 0
// Use the value at maxLimit as the value for value=0
lo = n - 1;
return
(
(
List<Tuple2<scalar, Type>>::operator[](hi).second()
- List<Tuple2<scalar, Type>>::operator[](lo).second()
)
/(
List<Tuple2<scalar, Type>>::operator[](hi).first()
- List<Tuple2<scalar, Type>>::operator[](lo).first()
)
list[lo].second()
+ (list[hi].second() - list[lo].second())
* (lookupValue / minLimit)
);
}
// Normal interpolation
return
(
list[lo].second()
+ (list[hi].second() - list[lo].second())
* (lookupValue - list[lo].first())
/ (list[hi].first() - list[lo].first())
);
}
template<class Type>
Type Foam::interpolationTable<Type>::interpolateValue
(
scalar lookupValue
) const
{
return interpolateValue(*this, lookupValue, bounding_);
}
template<class Type>
Foam::tmp<Foam::Field<Type>>
Foam::interpolationTable<Type>::interpolateValues
(
const UList<scalar>& vals
) const
{
auto tfld = tmp<Field<Type>>::New(vals.size());
auto& fld = tfld.ref();
forAll(fld, i)
{
fld[i] = interpolateValue(vals[i]);
}
return tfld;
}
@ -320,242 +493,105 @@ Type Foam::interpolationTable<Type>::rateOfChange(const scalar value) const
template<class Type>
const Foam::Tuple2<Foam::scalar, Type>&
Foam::interpolationTable<Type>::operator[](const label i) const
Foam::interpolationTable<Type>::operator[](label idx) const
{
label ii = i;
label n = this->size();
const List<value_type>& list = *this;
const label n = list.size();
if (n <= 1)
{
ii = 0;
idx = 0;
#ifdef FULLDEBUG
if (!n)
{
FatalErrorInFunction
<< "Cannot interpolate from zero-sized table" << nl
<< exit(FatalError);
}
#endif
}
else if (ii < 0)
else if (idx < 0)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "index (" << ii << ") underflow" << nl
<< "index (" << idx << ") underflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "index (" << ii << ") underflow" << nl
<< " Continuing with the first entry"
<< endl;
<< "index (" << idx << ") underflow" << nl
<< " Continuing with the first entry" << nl;
// Behaviour as per 'CLAMP'
ii = 0;
idx = 0;
break;
}
case bounds::repeatableBounding::CLAMP:
{
ii = 0;
idx = 0;
break;
}
case bounds::repeatableBounding::REPEAT:
{
while (ii < 0)
while (idx < 0)
{
ii += n;
idx += n;
}
break;
}
}
}
else if (ii >= n)
else if (idx >= n)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "index (" << ii << ") overflow" << nl
<< "index (" << idx << ") overflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "index (" << ii << ") overflow" << nl
<< " Continuing with the last entry"
<< endl;
<< "index (" << idx << ") overflow" << nl
<< " Continuing with the last entry" << nl;
// Behaviour as per 'CLAMP'
ii = n - 1;
idx = n - 1;
break;
}
case bounds::repeatableBounding::CLAMP:
{
ii = n - 1;
idx = n - 1;
break;
}
case bounds::repeatableBounding::REPEAT:
{
while (ii >= n)
while (idx >= n)
{
ii -= n;
idx -= n;
}
break;
}
}
}
return List<Tuple2<scalar, Type>>::operator[](ii);
return list[idx];
}
template<class Type>
Type Foam::interpolationTable<Type>::operator()(const scalar value) const
Type Foam::interpolationTable<Type>::operator()(scalar lookupValue) const
{
label n = this->size();
if (n <= 1)
{
return this->first().second();
}
const scalar minLimit = this->first().first();
const scalar maxLimit = this->last().first();
scalar lookupValue = value;
if (lookupValue < minLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") underflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") underflow" << nl
<< " Continuing with the first entry"
<< endl;
// Behaviour as per CLAMP
return this->first().second();
break;
}
case bounds::repeatableBounding::CLAMP:
{
return this->first().second();
break;
}
case bounds::repeatableBounding::REPEAT:
{
// adjust lookupValue to >= minLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
break;
}
}
}
else if (lookupValue >= maxLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << lookupValue << ") overflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << lookupValue << ") overflow" << nl
<< " Continuing with the last entry"
<< endl;
// Behaviour as per 'CLAMP'
return this->last().second();
break;
}
case bounds::repeatableBounding::CLAMP:
{
return this->last().second();
break;
}
case bounds::repeatableBounding::REPEAT:
{
// adjust lookupValue <= maxLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue-minLimit, span) + minLimit;
break;
}
}
}
label lo = 0;
label hi = 0;
// look for the correct range
for (label i = 0; i < n; ++i)
{
if (lookupValue >= List<Tuple2<scalar, Type>>::operator[](i).first())
{
lo = hi = i;
}
else
{
hi = i;
break;
}
}
if (lo == hi)
{
// we are at the end of the table - or there is only a single entry
return List<Tuple2<scalar, Type>>::operator[](hi).second();
}
else if (hi == 0)
{
// this treatment should only occur under these conditions:
// -> the 'REPEAT' treatment
// -> (0 <= value <= minLimit)
// -> minLimit > 0
// Use the value at maxLimit as the value for value=0
lo = n - 1;
return
(
List<Tuple2<scalar, Type>>::operator[](lo).second()
+ (
List<Tuple2<scalar, Type>>::operator[](hi).second()
- List<Tuple2<scalar, Type>>::operator[](lo).second()
)
*(lookupValue / minLimit)
);
}
else
{
// normal interpolation
return
(
List<Tuple2<scalar, Type>>::operator[](lo).second()
+ (
List<Tuple2<scalar, Type>>::operator[](hi).second()
- List<Tuple2<scalar, Type>>::operator[](lo).second()
)
*(
lookupValue
- List<Tuple2<scalar, Type>>::operator[](lo).first()
)
/(
List<Tuple2<scalar, Type>>::operator[](hi).first()
- List<Tuple2<scalar, Type>>::operator[](lo).first()
)
);
}
return interpolateValue(*this, lookupValue, bounding_);
}

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -36,7 +37,6 @@ Description
If \c repeat is chosen for the out-of-bounds handling, the final time
value is treated as being equivalent to time=0 for the following periods.
The construct from dictionary reads a filename from a dictionary and
has an optional readerType. Default is to read OpenFOAM format. The only
other format is csv (comma separated values):
@ -65,10 +65,10 @@ SourceFiles
#include "List.H"
#include "Tuple2.H"
#include "tableBounds.H"
#include "tableReader.H"
#include "autoPtr.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -84,7 +84,7 @@ class interpolationTable
:
public List<Tuple2<scalar, Type>>
{
// Private data
// Private Data
//- Handling for out-of-bound values
bounds::repeatableBounding bounding_;
@ -104,6 +104,15 @@ class interpolationTable
public:
// Public Data Types
//- The element data type
typedef Tuple2<scalar, Type> value_type;
//- The mapped data type
typedef Type mapped_type;
// Constructors
//- Construct null
@ -118,19 +127,28 @@ public:
);
//- Construct given the name of the file containing the table of data
interpolationTable(const fileName& fName);
explicit interpolationTable(const fileName& fName);
//- Construct by reading file name and outOfBounds from dictionary
// and read the table from that file.
//- and read the table from that file.
// This is a specialised constructor used by patchFields
interpolationTable(const dictionary& dict);
explicit interpolationTable(const dictionary& dict);
//- Construct copy
//- Copy construct
interpolationTable(const interpolationTable& interpTable);
// Member Functions
//- Return an interpolated value in List
static Type interpolateValue
(
const List<Tuple2<scalar, Type>>& list,
scalar lookupValue,
bounds::repeatableBounding = bounds::repeatableBounding::CLAMP
);
//- Check that list is monotonically increasing
// Exit with a FatalError if there is a problem
void check() const;
@ -139,17 +157,26 @@ public:
void write(Ostream& os) const;
//- Return the rate of change at the interpolation location
// for the give value
Type rateOfChange(const scalar) const;
//- for the given lookup value
Type rateOfChange(scalar lookupValue) const;
//- Return an interpolated value
Type interpolateValue(scalar lookupValue) const;
//- Return multiple interpolated values
tmp<Field<Type>> interpolateValues
(
const UList<scalar>& vals
) const;
// Member Operators
//- Return an element of constant Tuple2<scalar, Type>
const Tuple2<scalar, Type>& operator[](const label) const;
const Tuple2<scalar, Type>& operator[](label idx) const;
//- Return an interpolated value
Type operator()(const scalar) const;
Type operator()(scalar lookupValue) const;
};

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -38,7 +39,7 @@ Foam::Function1Types::Table<Type>::Table
:
TableBase<Type>(entryName, dict)
{
Istream& is(dict.lookup(entryName));
Istream& is = dict.lookup(entryName);
word entryType(is);
is >> this->table_;
TableBase<Type>::check();
@ -52,11 +53,4 @@ Foam::Function1Types::Table<Type>::Table(const Table<Type>& tbl)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class Type>
Foam::Function1Types::Table<Type>::~Table()
{}
// ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -72,7 +73,6 @@ class Table
//- No copy assignment
void operator=(const Table<Type>&) = delete;
public:
//- Runtime type information
@ -81,7 +81,7 @@ public:
// Constructors
//- Construct from entry name and Istream
//- Construct from entry name and dictionary
Table(const word& entryName, const dictionary& dict);
//- Copy constructor
@ -95,7 +95,7 @@ public:
//- Destructor
virtual ~Table();
virtual ~Table() = default;
};

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,15 +40,15 @@ Foam::Function1Types::TableBase<Type>::interpolator() const
{
// Re-work table into linear list
tableSamplesPtr_.reset(new scalarField(table_.size()));
scalarField& tableSamples = tableSamplesPtr_();
scalarField& samples = *tableSamplesPtr_;
forAll(table_, i)
{
tableSamples[i] = table_[i].first();
samples[i] = table_[i].first();
}
interpolatorPtr_ = interpolationWeights::New
(
interpolationScheme_,
tableSamples
samples
);
}
@ -116,21 +117,23 @@ void Foam::Function1Types::TableBase<Type>::check() const
<< nl << exit(FatalError);
}
const label n = table_.size();
scalar prevValue = table_[0].first();
scalar prevValue(0);
for (label i = 1; i < n; ++i)
label i = 0;
for (const auto& item : table_)
{
const scalar currValue = table_[i].first();
const scalar& currValue = item.first();
// avoid duplicate values (divide-by-zero error)
if (currValue <= prevValue)
// Avoid duplicate values (divide-by-zero error)
if (i && currValue <= prevValue)
{
FatalErrorInFunction
<< "out-of-order value: " << currValue << " at index " << i
<< "out-of-order value: "
<< currValue << " at index " << i << nl
<< exit(FatalError);
}
prevValue = currValue;
++i;
}
}
@ -142,45 +145,44 @@ bool Foam::Function1Types::TableBase<Type>::checkMinBounds
scalar& xDash
) const
{
if (x < table_.first().first())
const scalar minLimit = table_.first().first();
const scalar maxLimit = table_.last().first();
if (x < minLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << x << ") underflow"
<< "value (" << x << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << x << ") underflow" << nl
<< endl;
<< "value (" << x << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< " Continuing with the first entry" << endl;
// Behaviour as per CLAMP
xDash = table_.first().first();
xDash = minLimit;
return true;
break;
}
case bounds::repeatableBounding::CLAMP:
{
xDash = table_.first().first();
xDash = minLimit;
return true;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// adjust x to >= minX
const scalar span =
table_.last().first() - table_.first().first();
xDash =
(
fmod(x - table_.first().first(), span)
+ table_.first().first()
);
// Adjust x to >= minX
const scalar span = maxLimit - minLimit;
xDash = fmod(x - minLimit, span) + minLimit;
break;
}
}
@ -201,45 +203,44 @@ bool Foam::Function1Types::TableBase<Type>::checkMaxBounds
scalar& xDash
) const
{
if (x > table_.last().first())
const scalar minLimit = table_.first().first();
const scalar maxLimit = table_.last().first();
if (x > maxLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << x << ") overflow"
<< "value (" << x << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << x << ") overflow" << nl
<< endl;
<< "value (" << x << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< " Continuing with the last entry" << endl;
// Behaviour as per CLAMP
xDash = table_.last().first();
xDash = maxLimit;
return true;
break;
}
case bounds::repeatableBounding::CLAMP:
{
xDash = table_.last().first();
xDash = maxLimit;
return true;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// adjust x to >= minX
const scalar span =
table_.last().first() - table_.first().first();
xDash =
(
fmod(x - table_.first().first(), span)
+ table_.first().first()
);
// Adjust x to >= minX
const scalar span = maxLimit - minLimit;
xDash = fmod(x - minLimit, span) + minLimit;
break;
}
}
@ -256,10 +257,9 @@ bool Foam::Function1Types::TableBase<Type>::checkMaxBounds
template<class Type>
void Foam::Function1Types::TableBase<Type>::convertTimeBase(const Time& t)
{
forAll(table_, i)
for (auto& item : table_)
{
scalar value = table_[i].first();
table_[i].first() = t.userTimeToTime(value);
item.first() = t.userTimeToTime(item.first());
}
tableSamplesPtr_.clear();
@ -318,8 +318,8 @@ Type Foam::Function1Types::TableBase<Type>::integrate
template<class Type>
Foam::tmp<Foam::scalarField> Foam::Function1Types::TableBase<Type>::x() const
{
tmp<scalarField> tfld(new scalarField(table_.size(), Zero));
scalarField& fld = tfld.ref();
auto tfld = tmp<scalarField>::New(table_.size(), Zero);
auto& fld = tfld.ref();
forAll(table_, i)
{
@ -333,8 +333,8 @@ Foam::tmp<Foam::scalarField> Foam::Function1Types::TableBase<Type>::x() const
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::Function1Types::TableBase<Type>::y() const
{
tmp<Field<Type>> tfld(new Field<Type>(table_.size(), Zero));
Field<Type>& fld = tfld.ref();
auto tfld = tmp<Field<Type>>::New(table_.size(), Zero);
auto& fld = tfld.ref();
forAll(table_, i)
{
@ -348,12 +348,14 @@ Foam::tmp<Foam::Field<Type>> Foam::Function1Types::TableBase<Type>::y() const
template<class Type>
void Foam::Function1Types::TableBase<Type>::writeEntries(Ostream& os) const
{
os.writeEntryIfDifferent<word>
(
"outOfBounds",
bounds::repeatableBoundingNames[bounds::repeatableBounding::CLAMP],
bounds::repeatableBoundingNames[bounding_]
);
if (bounds::repeatableBounding::CLAMP != bounding_)
{
os.writeEntry
(
"outOfBounds",
bounds::repeatableBoundingNames[bounding_]
);
}
os.writeEntryIfDifferent<word>
(