3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
monotonecubicspline.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_COMMON_MONOTONE_CUBIC_SPLINE_HH
25#define DUMUX_COMMON_MONOTONE_CUBIC_SPLINE_HH
26
27#include <cmath>
28#include <cassert>
29#include <iterator>
30#include <vector>
31#include <algorithm>
32
33#include <dune/common/float_cmp.hh>
34
35// Hermite basis functions
37
38// for inversion
40
41namespace Dumux {
42
49template<class Scalar = double>
51{
53public:
58
65 MonotoneCubicSpline(const std::vector<Scalar>& x, const std::vector<Scalar>& y)
66 {
67 updatePoints(x, y);
68 }
69
75 void updatePoints(const std::vector<Scalar>& x, const std::vector<Scalar>& y)
76 {
77 // check some requirements
78 assert (x.size() == y.size());
79 assert (x.size() >=2);
80 assert (std::is_sorted(x.begin(), x.end()) || std::is_sorted(x.rbegin(), x.rend()));
81
82 // save a copy of the control points
83 x_ = x;
84 y_ = y;
85
86 // the number of control points
87 numPoints_ = x.size();
88
89 // whether we are increasing
90 increasingX_ = x_.back() > x_.front();
91 increasingY_ = y_.back() > y_.front();
92
93 // the slope at every control point
94 m_.resize(numPoints_);
95
96 // compute slopes (see Fritsch & Butland (1984), Eq. (5))
97 Scalar deltaX = (x[1]-x[0]);
98 Scalar secant = m_.front() = (y[1]-y[0])/deltaX;
99 Scalar prevDeltaX = deltaX;
100 Scalar prevSecant = secant;
101 for (int i = 1; i < numPoints_-1; ++i, prevSecant = secant, prevDeltaX = deltaX)
102 {
103 deltaX = (x[i+1]-x[i]);
104 secant = (y[i+1]-y[i])/deltaX;
105 const auto alpha = (prevDeltaX + 2*deltaX)/(3*(prevDeltaX + deltaX));
106 m_[i] = prevSecant*secant > 0.0 ? prevSecant*secant/(alpha*secant + (1.0-alpha)*prevSecant) : 0.0;
107 }
108 m_.back() = secant;
109 }
110
116 Scalar eval(const Scalar x) const
117 {
118 if ((x <= x_.front() && increasingX_) || (x >= x_.front() && !increasingX_))
119 return y_.front() + m_.front()*(x - x_.front());
120 else if ((x > x_.back() && increasingX_) || (x < x_.back() && !increasingX_))
121 return y_.back() + m_.back()*(x - x_.back());
122
123 return eval_(x);
124 }
125
131 Scalar evalDerivative(const Scalar x) const
132 {
133 if ((x <= x_.front() && increasingX_) || (x >= x_.front() && !increasingX_))
134 return m_.front();
135 else if ((x > x_.back() && increasingX_) || (x < x_.back() && !increasingX_))
136 return m_.back();
137
138 return evalDerivative_(x);
139 }
140
147 Scalar evalInverse(const Scalar y) const
148 {
149 if ((y <= y_.front() && increasingY_) || (y >= y_.front() && !increasingY_))
150 return x_.front() + (y - y_.front())/m_.front();
151 else if ((y > y_.back() && increasingY_) || (y < y_.back() && !increasingY_))
152 return x_.back() + (y - y_.back())/m_.back();
153
154 return evalInverse_(y);
155 }
156
157private:
158 Scalar eval_(const Scalar x) const
159 {
160 // interpolate parametrization parameter t in [0,1]
161 const auto lookUpIndex = lookUpIndex_(x_, x, increasingX_);
162 const auto h = (x_[lookUpIndex] - x_[lookUpIndex-1]);
163 const auto t = (x - x_[lookUpIndex-1])/h;
164 return y_[lookUpIndex-1]*Basis::h00(t) + h*m_[lookUpIndex-1]*Basis::h10(t)
165 + y_[lookUpIndex]*Basis::h01(t) + h*m_[lookUpIndex]*Basis::h11(t);
166 }
167
168 Scalar evalDerivative_(const Scalar x) const
169 {
170 // interpolate parametrization parameter t in [0,1]
171 const auto lookUpIndex = lookUpIndex_(x_, x, increasingX_);
172 const auto h = (x_[lookUpIndex] - x_[lookUpIndex-1]);
173 const auto t = (x - x_[lookUpIndex-1])/h;
174 const auto dtdx = 1.0/h;
175 return y_[lookUpIndex-1]*Basis::dh00(t)*dtdx + m_[lookUpIndex-1]*Basis::dh10(t)
176 + y_[lookUpIndex]*Basis::dh01(t)*dtdx + m_[lookUpIndex]*Basis::dh11(t);
177 }
178
179 Scalar evalInverse_(const Scalar y) const
180 {
181 const auto lookUpIndex = lookUpIndex_(y_, y, increasingY_);
182 auto localPolynomial = [&](const auto x) {
183 // interpolate parametrization parameter t in [0,1]
184 const auto h = (x_[lookUpIndex] - x_[lookUpIndex-1]);
185 const auto t = (x - x_[lookUpIndex-1])/h;
186 return y - (y_[lookUpIndex-1]*Basis::h00(t) + h*m_[lookUpIndex-1]*Basis::h10(t)
187 + y_[lookUpIndex]*Basis::h01(t) + h*m_[lookUpIndex]*Basis::h11(t));
188 };
189
190 // use an epsilon for the bracket
191 const auto eps = (x_[lookUpIndex]-x_[lookUpIndex-1])*1e-5;
192 return findScalarRootBrent(x_[lookUpIndex-1]-eps, x_[lookUpIndex]+eps, localPolynomial);
193 }
194
195 auto lookUpIndex_(const std::vector<Scalar>& vec, const Scalar v, bool increasing) const
196 {
197 return increasing ? lookUpIndexIncreasing_(vec, v) : lookUpIndexDecreasing_(vec, v);
198 }
199
200 auto lookUpIndexIncreasing_(const std::vector<Scalar>& vec, const Scalar v) const
201 {
202 const auto lookUpIndex = std::distance(vec.begin(), std::lower_bound(vec.begin(), vec.end(), v));
203 assert(lookUpIndex != 0 && lookUpIndex < vec.size());
204 return lookUpIndex;
205 }
206
207 auto lookUpIndexDecreasing_(const std::vector<Scalar>& vec, const Scalar v) const
208 {
209 const auto lookUpIndex = vec.size() - std::distance(vec.rbegin(), std::upper_bound(vec.rbegin(), vec.rend(), v));
210 assert(lookUpIndex != 0 && lookUpIndex < vec.size());
211 return lookUpIndex;
212 }
213
214 std::vector<Scalar> x_;
215 std::vector<Scalar> y_;
216 std::vector<Scalar> m_;
217 std::size_t numPoints_;
218 bool increasingX_;
219 bool increasingY_;
220};
221
222} // end namespace Dumux
223
224#endif
The cubic hermite spline basis.
Root finding algorithms for scalar functions.
ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: geometry/distance.hh:138
Scalar findScalarRootBrent(Scalar a, Scalar b, const ResFunc &residual, const Scalar tol=1e-13, const int maxIter=200)
Brent's root finding algorithm for scalar functions.
Definition: findscalarroot.hh:111
Definition: adapt.hh:29
The cubic spline hermite basis.
Definition: cubicsplinehermitebasis.hh:36
static constexpr Scalar h01(const Scalar t)
Definition: cubicsplinehermitebasis.hh:43
static constexpr Scalar dh01(const Scalar t)
Definition: cubicsplinehermitebasis.hh:55
static constexpr Scalar dh11(const Scalar t)
Definition: cubicsplinehermitebasis.hh:58
static constexpr Scalar h11(const Scalar t)
Definition: cubicsplinehermitebasis.hh:46
static constexpr Scalar h00(const Scalar t)
Definition: cubicsplinehermitebasis.hh:37
static constexpr Scalar dh10(const Scalar t)
Definition: cubicsplinehermitebasis.hh:52
static constexpr Scalar h10(const Scalar t)
Definition: cubicsplinehermitebasis.hh:40
static constexpr Scalar dh00(const Scalar t)
Definition: cubicsplinehermitebasis.hh:49
A monotone cubic spline.
Definition: monotonecubicspline.hh:51
MonotoneCubicSpline()=default
Default constructor.
void updatePoints(const std::vector< Scalar > &x, const std::vector< Scalar > &y)
Create a monotone cubic spline from the control points (x[i], y[i])
Definition: monotonecubicspline.hh:75
Scalar evalInverse(const Scalar y) const
Evaluate the inverse function.
Definition: monotonecubicspline.hh:147
Scalar eval(const Scalar x) const
Evaluate the y value at a given x value.
Definition: monotonecubicspline.hh:116
Scalar evalDerivative(const Scalar x) const
Evaluate the first derivative dy/dx at a given x value.
Definition: monotonecubicspline.hh:131
MonotoneCubicSpline(const std::vector< Scalar > &x, const std::vector< Scalar > &y)
Construct a monotone cubic spline from the control points (x[i], y[i])
Definition: monotonecubicspline.hh:65