/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019-2021 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 .
\*---------------------------------------------------------------------------*/
#include "TableBase.H"
#include "Time.H"
#include "interpolationWeights.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template
const Foam::interpolationWeights&
Foam::Function1Types::TableBase::interpolator() const
{
if (!interpolatorPtr_)
{
// Re-work table into linear list
tableSamplesPtr_.reset(new scalarField(table_.size()));
auto& samples = *tableSamplesPtr_;
forAll(table_, i)
{
samples[i] = table_[i].first();
}
interpolatorPtr_ = interpolationWeights::New
(
interpolationScheme_,
samples
);
}
return *interpolatorPtr_;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::Function1Types::TableBase::TableBase
(
const word& name,
const dictionary& dict,
const objectRegistry* obrPtr
)
:
Function1(name, dict, obrPtr),
bounding_
(
bounds::repeatableBoundingNames.getOrDefault
(
"outOfBounds",
dict,
bounds::repeatableBounding::CLAMP,
true // Failsafe behaviour
)
),
interpolationScheme_
(
dict.getOrDefault
(
"interpolationScheme",
"linear",
keyType::LITERAL
)
),
table_(),
tableSamplesPtr_(nullptr),
interpolatorPtr_(nullptr)
{}
template
Foam::Function1Types::TableBase::TableBase(const TableBase& tbl)
:
Function1(tbl),
bounding_(tbl.bounding_),
interpolationScheme_(tbl.interpolationScheme_),
table_(tbl.table_),
tableSamplesPtr_(nullptr),
interpolatorPtr_(nullptr)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template
void Foam::Function1Types::TableBase::initialise()
{
if (!table_.size())
{
FatalErrorInFunction
<< "Table for entry " << this->name() << " is invalid (empty)"
<< nl << exit(FatalError);
}
scalar prevValue(0);
label i = 0;
for (const auto& item : table_)
{
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;
++i;
}
}
template
bool Foam::Function1Types::TableBase::checkMinBounds
(
const scalar x,
scalar& xDash
) const
{
const scalar minLimit = table_.first().first();
const scalar maxLimit = table_.last().first();
if (x < minLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << x << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << x << ") less than lower "
<< "bound (" << minLimit << ")" << nl
<< " Continuing with the first entry" << endl;
// Behaviour as per CLAMP
xDash = minLimit;
return true;
break;
}
case bounds::repeatableBounding::CLAMP:
{
xDash = minLimit;
return true;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// Adjust x to >= minX
const scalar span = maxLimit - minLimit;
xDash = fmod(x - minLimit, span) + minLimit;
break;
}
}
}
else
{
xDash = x;
}
return false;
}
template
bool Foam::Function1Types::TableBase::checkMaxBounds
(
const scalar x,
scalar& xDash
) const
{
const scalar minLimit = table_.first().first();
const scalar maxLimit = table_.last().first();
if (x > maxLimit)
{
switch (bounding_)
{
case bounds::repeatableBounding::ERROR:
{
FatalErrorInFunction
<< "value (" << x << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< exit(FatalError);
break;
}
case bounds::repeatableBounding::WARN:
{
WarningInFunction
<< "value (" << x << ") greater than upper "
<< "bound (" << maxLimit << ")" << nl
<< " Continuing with the last entry" << endl;
// Behaviour as per CLAMP
xDash = maxLimit;
return true;
break;
}
case bounds::repeatableBounding::CLAMP:
{
xDash = maxLimit;
return true;
break;
}
case bounds::repeatableBounding::REPEAT:
{
// Adjust x to >= minX
const scalar span = maxLimit - minLimit;
xDash = fmod(x - minLimit, span) + minLimit;
break;
}
}
}
else
{
xDash = x;
}
return false;
}
template
void Foam::Function1Types::TableBase::userTimeToTime(const Time& t)
{
for (auto& item : table_)
{
item.first() = t.userTimeToTime(item.first());
}
tableSamplesPtr_.clear();
interpolatorPtr_.clear();
}
template
Type Foam::Function1Types::TableBase::value(const scalar x) const
{
scalar xDash = x;
if (checkMinBounds(x, xDash))
{
return table_.first().second();
}
if (checkMaxBounds(xDash, xDash))
{
return table_.last().second();
}
// Use interpolator
interpolator().valueWeights(xDash, currentIndices_, currentWeights_);
Type t(currentWeights_[0]*table_[currentIndices_[0]].second());
for (label i = 1; i < currentIndices_.size(); i++)
{
t += currentWeights_[i]*table_[currentIndices_[i]].second();
}
return t;
}
template
Type Foam::Function1Types::TableBase::integrate
(
const scalar x1,
const scalar x2
) const
{
// Use interpolator
interpolator().integrationWeights(x1, x2, currentIndices_, currentWeights_);
Type sum(currentWeights_[0]*table_[currentIndices_[0]].second());
for (label i = 1; i < currentIndices_.size(); i++)
{
sum += currentWeights_[i]*table_[currentIndices_[i]].second();
}
return sum;
}
template
Foam::tmp Foam::Function1Types::TableBase::x() const
{
auto tfld = tmp::New(table_.size(), Zero);
auto& fld = tfld.ref();
forAll(table_, i)
{
fld[i] = table_[i].first();
}
return tfld;
}
template
Foam::tmp> Foam::Function1Types::TableBase::y() const
{
auto tfld = tmp>::New(table_.size(), Zero);
auto& fld = tfld.ref();
forAll(table_, i)
{
fld[i] = table_[i].second();
}
return tfld;
}
template
void Foam::Function1Types::TableBase::writeEntries(Ostream& os) const
{
if (bounds::repeatableBounding::CLAMP != bounding_)
{
os.writeEntry
(
"outOfBounds",
bounds::repeatableBoundingNames[bounding_]
);
}
os.writeEntryIfDifferent
(
"interpolationScheme",
"linear",
interpolationScheme_
);
}
template
void Foam::Function1Types::TableBase::writeData(Ostream& os) const
{
Function1::writeData(os);
os << nl << indent << table_;
os.endEntry();
writeEntries(os);
}
// ************************************************************************* //