From 96763bb06bcd1c235c2966343b9afde2aa85c0b6 Mon Sep 17 00:00:00 2001
From: Andrew Heather <>
Date: Fri, 11 Sep 2020 20:33:06 +0100
Subject: [PATCH] ENH: Added optional limits to Function1 (#1924)

To apply limits to the input values, use the dictionary format to include the
optional keywords 'minLimit' and/or 'maxLimit', e.g.

    limitedPolyTest        polynomial;
    limitedPolyTestCoeffs
    {
        limitedPolyTest coeffs
        (
            (5 1)
            (-2 2)
            (-2 3)
            (1 4)
        );

        minLimit    0.4;
        maxLimit    1.4;
    }

    limitedTableFileTest   tableFile;
    limitedTableFileTestCoeffs
    {
        file            "<system>/fanCurve.txt";
        minLimit        0.4;
        maxLimit        1.4;
    }
---
 .../Function1/Function1Expression.C           |  2 +-
 .../functions/Function1/Function1/Function1.C | 22 ++++++++++
 .../functions/Function1/Function1/Function1.H |  8 ++++
 .../Function1/Function1/function1Base.C       | 37 ++++++++++++++--
 .../Function1/Function1/function1Base.H       |  9 ++++
 .../PolynomialEntry/PolynomialEntry.C         | 13 ++++--
 .../PolynomialEntry/PolynomialEntry.H         |  7 +++
 .../functions/Function1/Scale/ScaleI.H        |  5 ++-
 .../functions/Function1/Sine/SineI.H          | 12 ++++--
 .../functions/Function1/Table/TableBase.C     | 43 ++++++++++++-------
 .../functions/Function1/Table/TableBase.H     |  2 +-
 .../halfCosineRamp/halfCosineRampI.H          |  5 ++-
 .../Function1/linearRamp/linearRampI.H        |  3 +-
 .../Function1/quadraticRamp/quadraticRampI.H  |  3 +-
 .../quarterCosineRamp/quarterCosineRampI.H    |  4 +-
 .../quarterSineRamp/quarterSineRampI.H        |  3 +-
 .../functions/Function1/step/stepFunctionI.H  |  4 +-
 17 files changed, 147 insertions(+), 35 deletions(-)

diff --git a/src/OpenFOAM/expressions/Function1/Function1Expression.C b/src/OpenFOAM/expressions/Function1/Function1Expression.C
index 2575e0cb014..82e0cc9fd79 100644
--- a/src/OpenFOAM/expressions/Function1/Function1Expression.C
+++ b/src/OpenFOAM/expressions/Function1/Function1Expression.C
@@ -86,7 +86,7 @@ Type Foam::Function1Types::Function1Expression<Type>::value
     // Expression evaluation
     driver_.clearVariables();
 
-    driver_.setArgument(x);
+    driver_.setArgument(this->limitValue(x));
 
     driver_.parse(this->valueExpr_);
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.C b/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.C
index f635078a468..38185c12840 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.C
+++ b/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.C
@@ -31,6 +31,28 @@ License
 // Required by clang 5 for correct instantiation of Function1::New
 #include "Constant.H"
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class Type>
+void Foam::Function1<Type>::addLimitedAreaToSum
+(
+    const scalar x1,
+    const scalar x2,
+    Type& sum
+) const
+{
+    if (x1 < minLimit_)
+    {
+        sum += (min(minLimit_, x2) - x1)*this->value(minLimit_);
+    }
+
+    if (x2 > maxLimit_)
+    {
+        sum += (x2 - max(maxLimit_, x1))*this->value(maxLimit_);
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
 
 template<class Type>
diff --git a/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.H b/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.H
index 5ff592788bc..465aa714947 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.H
+++ b/src/OpenFOAM/primitives/functions/Function1/Function1/Function1.H
@@ -116,6 +116,14 @@ protected:
         //- No copy assignment
         void operator=(const Function1<Type>&) = delete;
 
+        //- Helper function for integrate() function to add limited contribution
+        void addLimitedAreaToSum
+        (
+            const scalar x1,
+            const scalar x2,
+            Type& sum
+        ) const;
+
 
 public:
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.C b/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.C
index c4a6e0a1940..423c4a2611c 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.C
+++ b/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.C
@@ -33,7 +33,9 @@ License
 Foam::function1Base::function1Base(const word& entryName)
 :
     refCount(),
-    name_(entryName)
+    name_(entryName),
+    minLimit_(-GREAT),
+    maxLimit_(GREAT)
 {}
 
 
@@ -44,21 +46,48 @@ Foam::function1Base::function1Base
 )
 :
     refCount(),
-    name_(entryName)
+    name_(entryName),
+    minLimit_(dict.getOrDefault<scalar>("minLimit", -GREAT)),
+    maxLimit_(dict.getOrDefault<scalar>("maxLimit", GREAT))
 {}
 
 
 Foam::function1Base::function1Base(const function1Base& rhs)
 :
     refCount(),
-    name_(rhs.name_)
+    name_(rhs.name_),
+    minLimit_(rhs.minLimit_),
+    maxLimit_(rhs.maxLimit_)
 {}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::function1Base::convertTimeBase(const Time& t)
-{}
+{
+    minLimit_ = t.userTimeToTime(minLimit_);
+    maxLimit_ = t.userTimeToTime(maxLimit_);
+}
+
+
+Foam::scalar Foam::function1Base::limitValue(const scalar x) const
+{
+    return min(max(minLimit_, x), maxLimit_);
+}
+
+
+// TBD
+// void Foam::function1Base::writeEntries(Ostream& os) const
+// {
+//     if (minLimit_ > -ROOTGREAT)
+//     {
+//         os.writeEntry("minLimit", minLimit_);
+//     }
+//     if (maxLimit_ < ROOTGREAT)
+//     {
+//         os.writeEntry("maxLimit", maxLimit_);
+//     }
+// }
 
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.H b/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.H
index 4aa9bf68ea2..462882af019 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.H
+++ b/src/OpenFOAM/primitives/functions/Function1/Function1/function1Base.H
@@ -67,6 +67,12 @@ protected:
         //- Name of entry
         const word name_;
 
+        //- Optional minimum limit (x)
+        scalar minLimit_;
+
+        //- Optional maximum limit (x)
+        scalar maxLimit_;
+
 
     // Protected Member Functions
 
@@ -107,6 +113,9 @@ public:
 
         //- Convert time
         virtual void convertTimeBase(const Time& t);
+
+        //- Apply min|max limit to the input value
+        virtual scalar limitValue(const scalar x) const;
 };
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.C b/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.C
index a2197035569..b6e29177411 100644
--- a/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.C
+++ b/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.C
@@ -144,13 +144,15 @@ void Foam::Function1Types::Polynomial<Type>::convertTimeBase(const Time& t)
 template<class Type>
 Type Foam::Function1Types::Polynomial<Type>::value(const scalar x) const
 {
+    const scalar xlim = this->limitValue(x);
+
     Type y(Zero);
     forAll(coeffs_, i)
     {
         y += cmptMultiply
         (
             coeffs_[i].first(),
-            cmptPow(pTraits<Type>::one*x, coeffs_[i].second())
+            cmptPow(pTraits<Type>::one*xlim, coeffs_[i].second())
         );
     }
 
@@ -167,6 +169,11 @@ Type Foam::Function1Types::Polynomial<Type>::integrate
 {
     Type intx(Zero);
 
+    this->addLimitedAreaToSum(x1, x2, intx);
+
+    const scalar x1lim = this->limitValue(x1);
+    const scalar x2lim = this->limitValue(x2);
+
     if (canIntegrate_)
     {
         forAll(coeffs_, i)
@@ -180,12 +187,12 @@ Type Foam::Function1Types::Polynomial<Type>::integrate
                 ),
                 cmptPow
                 (
-                    pTraits<Type>::one*x2,
+                    pTraits<Type>::one*x2lim,
                     coeffs_[i].second() + pTraits<Type>::one
                 )
               - cmptPow
                 (
-                    pTraits<Type>::one*x1,
+                    pTraits<Type>::one*x1lim,
                     coeffs_[i].second() + pTraits<Type>::one
                 )
             );
diff --git a/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.H b/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.H
index 06d778c0c6c..5f41d7ab46f 100644
--- a/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.H
+++ b/src/OpenFOAM/primitives/functions/Function1/PolynomialEntry/PolynomialEntry.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -103,6 +104,12 @@ public:
         //- Copy constructor
         explicit Polynomial(const Polynomial& poly);
 
+        //- Construct and return a clone
+        virtual tmp<Function1<Type>> clone() const
+        {
+            return tmp<Function1<Type>>(new Polynomial<Type>(*this));
+        }
+
 
     //- Destructor
     virtual ~Polynomial() = default;
diff --git a/src/OpenFOAM/primitives/functions/Function1/Scale/ScaleI.H b/src/OpenFOAM/primitives/functions/Function1/Scale/ScaleI.H
index fe201a48108..515307be29c 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Scale/ScaleI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/Scale/ScaleI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -32,7 +33,9 @@ License
 template<class Type>
 inline Type Foam::Function1Types::Scale<Type>::value(const scalar t) const
 {
-    return scale_->value(t)*value_->value(t);
+    const scalar tlim = this->limitValue(t);
+
+    return scale_->value(tlim)*value_->value(tlim);
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/Sine/SineI.H b/src/OpenFOAM/primitives/functions/Function1/Sine/SineI.H
index be03d62ddce..722562c5c94 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Sine/SineI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/Sine/SineI.H
@@ -92,9 +92,11 @@ Foam::Function1Types::Sine<Type>::squareForm
 template<class Type>
 inline Type Foam::Function1Types::Sine<Type>::cosValue(const scalar t) const
 {
+    const scalar tlim = this->limitValue(t);
+
     return
     (
-        cosForm(t) * scale_->value(t) + level_->value(t)
+        cosForm(tlim) * scale_->value(tlim) + level_->value(tlim)
     );
 }
 
@@ -102,9 +104,11 @@ inline Type Foam::Function1Types::Sine<Type>::cosValue(const scalar t) const
 template<class Type>
 inline Type Foam::Function1Types::Sine<Type>::sinValue(const scalar t) const
 {
+    const scalar tlim = this->limitValue(t);
+
     return
     (
-        sinForm(t) * scale_->value(t) + level_->value(t)
+        sinForm(tlim) * scale_->value(tlim) + level_->value(tlim)
     );
 }
 
@@ -116,9 +120,11 @@ inline Type Foam::Function1Types::Sine<Type>::squareValue
     const scalar posFrac
 ) const
 {
+    const scalar tlim = this->limitValue(t);
+
     return
     (
-        squareForm(t, posFrac) * scale_->value(t) + level_->value(t)
+        squareForm(tlim, posFrac) * scale_->value(tlim) + level_->value(tlim)
     );
 }
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.C b/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.C
index 8c1fdb25957..715df68417d 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.C
+++ b/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.C
@@ -98,13 +98,6 @@ Foam::Function1Types::TableBase<Type>::TableBase(const TableBase<Type>& tbl)
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-template<class Type>
-Foam::Function1Types::TableBase<Type>::~TableBase()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class Type>
@@ -270,9 +263,11 @@ void Foam::Function1Types::TableBase<Type>::convertTimeBase(const Time& t)
 template<class Type>
 Type Foam::Function1Types::TableBase<Type>::value(const scalar x) const
 {
-    scalar xDash = x;
+    const scalar xlim = this->limitValue(x);
+
+    scalar xDash = xlim;
 
-    if (checkMinBounds(x, xDash))
+    if (checkMinBounds(xlim, xDash))
     {
         return table_.first().second();
     }
@@ -286,7 +281,7 @@ Type Foam::Function1Types::TableBase<Type>::value(const scalar x) const
     interpolator().valueWeights(xDash, currentIndices_, currentWeights_);
 
     Type t = currentWeights_[0]*table_[currentIndices_[0]].second();
-    for (label i = 1; i < currentIndices_.size(); i++)
+    for (label i = 1; i < currentIndices_.size(); ++i)
     {
         t += currentWeights_[i]*table_[currentIndices_[i]].second();
     }
@@ -302,15 +297,31 @@ Type Foam::Function1Types::TableBase<Type>::integrate
     const scalar x2
 ) const
 {
-    // Use interpolator
-    interpolator().integrationWeights(x1, x2, currentIndices_, currentWeights_);
+    scalar x1lim = this->limitValue(x1);
+    scalar x2lim = this->limitValue(x2);
 
-    Type sum = currentWeights_[0]*table_[currentIndices_[0]].second();
-    for (label i = 1; i < currentIndices_.size(); i++)
+    Type sum = Zero;
+
+    if (mag(x2lim - x1lim) > ROOTVSMALL)
     {
-       sum += currentWeights_[i]*table_[currentIndices_[i]].second();
+        // Use interpolator
+        interpolator().integrationWeights
+        (
+            this->limitValue(x1),
+            this->limitValue(x2),
+            currentIndices_,
+            currentWeights_
+        );
+
+        sum += currentWeights_[0]*table_[currentIndices_[0]].second();
+        for (label i = 1; i < currentIndices_.size(); ++i)
+        {
+            sum += currentWeights_[i]*table_[currentIndices_[i]].second();
+        }
     }
 
+    this->addLimitedAreaToSum(x1, x2, sum);
+
     return sum;
 }
 
@@ -323,7 +334,7 @@ Foam::tmp<Foam::scalarField> Foam::Function1Types::TableBase<Type>::x() const
 
     forAll(table_, i)
     {
-        fld[i] = table_[i].first();
+        fld[i] = this->limitValue(table_[i].first());
     }
 
     return tfld;
diff --git a/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.H b/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.H
index 82361382bd2..704230be74f 100644
--- a/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.H
+++ b/src/OpenFOAM/primitives/functions/Function1/Table/TableBase.H
@@ -108,7 +108,7 @@ public:
 
 
     //- Destructor
-    virtual ~TableBase();
+    virtual ~TableBase() = default;
 
 
     // Member Functions
diff --git a/src/OpenFOAM/primitives/functions/Function1/halfCosineRamp/halfCosineRampI.H b/src/OpenFOAM/primitives/functions/Function1/halfCosineRamp/halfCosineRampI.H
index 1f50e6c8680..641bacb6e02 100644
--- a/src/OpenFOAM/primitives/functions/Function1/halfCosineRamp/halfCosineRampI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/halfCosineRamp/halfCosineRampI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,7 +36,9 @@ inline Foam::scalar Foam::Function1Types::halfCosineRamp::value
     const scalar t
 ) const
 {
-    return 0.5*(1 - cos(constant::mathematical::pi*linearRamp(t)));
+    return
+        0.5
+       *(1 - cos(constant::mathematical::pi*linearRamp(this->limitValue(t))));
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/linearRamp/linearRampI.H b/src/OpenFOAM/primitives/functions/Function1/linearRamp/linearRampI.H
index 318323c3427..3670f60fe06 100644
--- a/src/OpenFOAM/primitives/functions/Function1/linearRamp/linearRampI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/linearRamp/linearRampI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,7 +35,7 @@ inline Foam::scalar Foam::Function1Types::linearRamp::value
     const scalar t
 ) const
 {
-    return ramp::linearRamp(t);
+    return ramp::linearRamp(this->limitValue(t));
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/quadraticRamp/quadraticRampI.H b/src/OpenFOAM/primitives/functions/Function1/quadraticRamp/quadraticRampI.H
index 14a850ac65f..f0b2ea02a52 100644
--- a/src/OpenFOAM/primitives/functions/Function1/quadraticRamp/quadraticRampI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/quadraticRamp/quadraticRampI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,7 +35,7 @@ inline Foam::scalar Foam::Function1Types::quadraticRamp::value
     const scalar t
 ) const
 {
-    return sqr(linearRamp(t));
+    return sqr(linearRamp(this->limitValue(t)));
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/quarterCosineRamp/quarterCosineRampI.H b/src/OpenFOAM/primitives/functions/Function1/quarterCosineRamp/quarterCosineRampI.H
index 4b5b2fabc5b..582e209cda5 100644
--- a/src/OpenFOAM/primitives/functions/Function1/quarterCosineRamp/quarterCosineRampI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/quarterCosineRamp/quarterCosineRampI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,7 +36,8 @@ inline Foam::scalar Foam::Function1Types::quarterCosineRamp::value
     const scalar t
 ) const
 {
-    return 1 - cos(0.5*constant::mathematical::pi*linearRamp(t));
+    return
+        1 - cos(0.5*constant::mathematical::pi*linearRamp(this->limitValue(t)));
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/quarterSineRamp/quarterSineRampI.H b/src/OpenFOAM/primitives/functions/Function1/quarterSineRamp/quarterSineRampI.H
index ea7d9a9a49a..002482fd530 100644
--- a/src/OpenFOAM/primitives/functions/Function1/quarterSineRamp/quarterSineRampI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/quarterSineRamp/quarterSineRampI.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,7 +36,7 @@ inline Foam::scalar Foam::Function1Types::quarterSineRamp::value
     const scalar t
 ) const
 {
-    return sin(0.5*constant::mathematical::pi*linearRamp(t));
+    return sin(0.5*constant::mathematical::pi*linearRamp(this->limitValue(t)));
 }
 
 
diff --git a/src/OpenFOAM/primitives/functions/Function1/step/stepFunctionI.H b/src/OpenFOAM/primitives/functions/Function1/step/stepFunctionI.H
index c3016813892..49850779287 100644
--- a/src/OpenFOAM/primitives/functions/Function1/step/stepFunctionI.H
+++ b/src/OpenFOAM/primitives/functions/Function1/step/stepFunctionI.H
@@ -34,7 +34,9 @@ inline Foam::scalar Foam::Function1Types::stepFunction::value
     const scalar t
 ) const
 {
-    if (t < start_ || t > start_ + duration_)
+    const scalar tlim = this->limitValue(t);
+
+    if (tlim < start_ || tlim > start_ + duration_)
     {
         return 0;
     }
-- 
GitLab