From 4cf23e770b966a286daf9b9c3d63f26dfa471634 Mon Sep 17 00:00:00 2001
From: Wenqing Wang <wenqing.wang@ufz.de>
Date: Fri, 4 Nov 2016 16:04:52 +0100
Subject: [PATCH] [Alg] Added a function to get inverse value from curve

---
 .../PiecewiseLinearInterpolation.h            | 28 ++++++++++++++++++-
 .../TestPiecewiseLinearInterpolation.cpp      | 27 ++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/MathLib/InterpolationAlgorithms/PiecewiseLinearInterpolation.h b/MathLib/InterpolationAlgorithms/PiecewiseLinearInterpolation.h
index 643c87061c1..03f134c69c7 100644
--- a/MathLib/InterpolationAlgorithms/PiecewiseLinearInterpolation.h
+++ b/MathLib/InterpolationAlgorithms/PiecewiseLinearInterpolation.h
@@ -58,7 +58,26 @@ public:
      * this interval are set to \f$x_{\min}\f$ or \f$x_{\max}\f$.
      * @return The interpolated value.
      */
-    double getValue(double pnt_to_interpolate) const;
+    double getValue(double const pnt_to_interpolate) const;
+
+    /**
+     * \brief Calculates the interpolation of the variable by a known
+     *        value of the piece wise linear curve. The curve must be
+     *        monotonically increase or decrease. The monotonicity can be
+     *        checked after create an instance of this class.
+     *
+     * @param value The variable for a point should be located within the range
+     * \f$[f(x_{\min}), f(x_{\max})]\f$, where \f$x_{\min} = \min_{1 \le j \le n}
+     * x_j\f$ and
+     * \f$x_{\max} = \max_{1 \le j \le n} x_j\f$. Points outside of this
+     * interval are
+     * set to f(x_{\min}) or f(x_{\max}).
+     * @return The interpolated value, \f$x\f$.
+     *
+     * \attention Check the monotonicity of the data beforehand if this function
+     *            is used.
+     */
+    double getInverseValue(double const value) const;
 
     /**
      * \brief Calculates derivative using quadratic interpolation
@@ -76,9 +95,16 @@ public:
     double getSupportMax() const;
     double getSupportMin() const;
 
+    bool isMonotonic() const;
+
 private:
     std::vector<double> _supp_pnts;
     std::vector<double> _values_at_supp_pnts;
+
+    double interpolate(std::vector<double> const& supp_pnts,
+                       std::vector<double> const& values_at_supp_pnts,
+                       std::size_t const interval_idx,
+                       double const pnt_to_interpolate) const;
 };
 }  // end namespace MathLib
 
diff --git a/Tests/MathLib/TestPiecewiseLinearInterpolation.cpp b/Tests/MathLib/TestPiecewiseLinearInterpolation.cpp
index 7a0517a368b..6d241be594d 100644
--- a/Tests/MathLib/TestPiecewiseLinearInterpolation.cpp
+++ b/Tests/MathLib/TestPiecewiseLinearInterpolation.cpp
@@ -156,3 +156,30 @@ TEST(MathLibInterpolationAlgorithms, PiecewiseLinearInterpolationDerivative)
     ASSERT_NEAR(0, interpolation.getDerivative(1001),
                 std::numeric_limits<double>::epsilon());
 }
+
+TEST(MathLibInterpolationAlgorithms, PiecewiseLinearInterpolationGetInverseValue)
+{
+    const std::size_t size = 1000;
+    std::vector<double> variables, values;
+    for (std::size_t k=0; k < size; ++k)
+    {
+        variables.push_back(static_cast<double>(k));
+        values.push_back(static_cast<double>(2*k));
+    }
+
+    std::vector<double> variables_cpy = variables;
+    std::vector<double> values_cpy = values;
+
+    MathLib::PiecewiseLinearInterpolation
+                                       interpolation{std::move(variables_cpy),
+                                                     std::move(values_cpy)};
+
+    ASSERT_EQ(true, interpolation.isMonotonic());
+
+    // Get inverse values and compare them
+    for (std::size_t k=0; k < size; ++k)
+    {
+        ASSERT_NEAR(variables[k], interpolation.getInverseValue(values[k]),
+                    std::numeric_limits<double>::epsilon());
+    }
+}
-- 
GitLab