Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
-------------------------------------------------------------------------------
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "interpolationTable.H"
#include "openFoamTableReader.H"
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
void Foam::interpolationTable<Type>::readTable()
// preserve the original (unexpanded) fileName to avoid absolute paths
// appearing subsequently in the write() method
fileName fName(fileName_);
fName.expand();
reader_()(fName, *this);
FatalErrorInFunction
<< "table read from " << fName << " is empty" << nl
// Check that the data are okay
check();
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>
Foam::interpolationTable<Type>::interpolationTable()
:
bounding_(bounds::repeatableBounding::WARN),
fileName_("fileNameIsUndefined"),
{}
template<class Type>
Foam::interpolationTable<Type>::interpolationTable
(
Henry Weller
committed
const List<Tuple2<scalar, Type>>& values,
const bounds::repeatableBounding bounding,
fileName_(fName),
{}
template<class Type>
Foam::interpolationTable<Type>::interpolationTable(const fileName& fName)
bounding_(bounds::repeatableBounding::WARN),
fileName_(fName),
reader_(new openFoamTableReader<Type>())
{
readTable();
}
template<class Type>
Foam::interpolationTable<Type>::interpolationTable(const dictionary& dict)
:
bounds::repeatableBoundingNames.getOrDefault
(
"outOfBounds",
dict,
bounds::repeatableBounding::WARN,
true // Failsafe behaviour
fileName_(dict.get<fileName>("file")),
reader_(tableReader<Type>::New(dict))
{
readTable();
}
template<class Type>
Foam::interpolationTable<Type>::interpolationTable
(
const interpolationTable& tbl
List<value_type>(tbl),
bounding_(tbl.bounding_),
fileName_(tbl.fileName_),
reader_(tbl.reader_.clone())
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
void Foam::interpolationTable<Type>::check() const
{
const List<value_type>& list = *this;
scalar prevValue(0);
label i = 0;
for (const auto& item : list)
const scalar& currValue = item.first();
// Avoid duplicate values (divide-by-zero error)
if (i && currValue <= prevValue)
FatalErrorInFunction
<< "out-of-order value: "
<< currValue << " at index " << i << nl
<< exit(FatalError);
}
prevValue = currValue;
}
}
template<class Type>
void Foam::interpolationTable<Type>::write(Ostream& os) const
{
os.writeEntry("file", fileName_);
os.writeEntry("outOfBounds", bounds::repeatableBoundingNames[bounding_]);
{
reader_->write(os);
}
Type Foam::interpolationTable<Type>::rateOfChange(scalar lookupValue) const
const List<value_type>& list = *this;
const label n = list.size();
// Not enough entries for a rate of change
return Zero;
const scalar minLimit = list.first().first();
const scalar maxLimit = list.last().first();
if (lookupValue < minLimit)
{
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< " Zero rate of change." << endl;
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
// Adjust lookupValue to >= minLimit
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
}
else if (lookupValue >= maxLimit)
{
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< " Zero rate of change." << endl;
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
// Adjust lookupValue <= maxLimit
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
break;
}
}
}
label lo = 0;
label hi = 0;
for (label i = 0; i < n; ++i)
{
{
lo = hi = i;
}
else
{
hi = i;
break;
}
}
if (lo == hi)
{
}
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[hi].second() - list[lo].second())
/ (list[hi].first() + minLimit - list[lo].first())
// Normal rate of change
return
(
(list[hi].second() - list[lo].second())
/ (list[hi].first() - list[lo].first())
);
}
Type Foam::interpolationTable<Type>::interpolateValue
(
const List<Tuple2<scalar, Type>>& list,
scalar lookupValue,
bounds::repeatableBounding bounding
)
#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)
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "value (" << lookupValue << ") less than lower "
<< "bound (" << minLimit << ")\n"
<< " Continuing with the first entry" << endl;
// Behaviour as per CLAMP
return list.first().second();
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
// adjust lookupValue to >= minLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "value (" << lookupValue << ") greater than upper "
<< "bound (" << maxLimit << ")\n"
<< " Continuing with the last entry" << endl;
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
// Adjust lookupValue <= maxLimit
const scalar span = maxLimit-minLimit;
lookupValue = fmod(lookupValue - minLimit, span) + minLimit;
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
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[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)
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
template<class Type>
void Foam::interpolationTable<Type>::operator=
(
const interpolationTable<Type>& rhs
)
{
if (this == &rhs)
{
return;
}
static_cast<List<value_type>&>(*this) = rhs;
bounding_ = rhs.bounding_;
fileName_ = rhs.fileName_;
reader_.reset(rhs.reader_.clone());
}
template<class Type>
const Foam::Tuple2<Foam::scalar, Type>&
Foam::interpolationTable<Type>::operator[](label idx) const
{
const List<value_type>& list = *this;
const label n = list.size();
if (n <= 1)
{
idx = 0;
#ifdef FULLDEBUG
if (!n)
{
FatalErrorInFunction
<< "Cannot interpolate from zero-sized table" << nl
<< exit(FatalError);
}
#endif
}
else if (idx < 0)
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "index (" << idx << ") underflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "index (" << idx << ") underflow" << nl
<< " Continuing with the first entry" << nl;
// Behaviour as per 'CLAMP'
idx = 0;
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
while (idx < 0)
{
idx += n;
}
case bounds::repeatableBounding::ERROR:
FatalErrorInFunction
<< "index (" << idx << ") overflow" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
<< "index (" << idx << ") overflow" << nl
<< " Continuing with the last entry" << nl;
case bounds::repeatableBounding::CLAMP:
case bounds::repeatableBounding::REPEAT:
while (idx >= n)
{
idx -= n;
}
template<class Type>
Type Foam::interpolationTable<Type>::operator()(scalar lookupValue) const
{
return interpolateValue(*this, lookupValue, bounding_);
// ************************************************************************* //