OGS
PiecewiseLinearInterpolation.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <algorithm>
7#include <cmath>
8#include <limits>
9#include <range/v3/range/conversion.hpp>
10#include <utility>
11
12#include "BaseLib/Error.h"
13#include "BaseLib/quicksort.h"
14
15namespace MathLib
16{
18 std::vector<double> supporting_points,
19 std::vector<double>
20 values_at_supp_pnts,
21 bool supp_pnts_sorted)
22 : supp_pnts_(std::move(supporting_points)),
23 values_at_supp_pnts_(std::move(values_at_supp_pnts))
24{
25 if (!supp_pnts_sorted)
26 {
28 supp_pnts_, static_cast<std::size_t>(0), supp_pnts_.size(),
30 }
31
32 const auto it = std::adjacent_find(supp_pnts_.begin(), supp_pnts_.end());
33 if (it != supp_pnts_.end())
34 {
35 const std::size_t i = std::distance(supp_pnts_.begin(), it);
37 "Variable {:d} and variable {:d} are the same. Piecewise linear "
38 "interpolation is not possible\n",
39 i, i + 1);
40 }
41}
42
44 std::vector<int> const& supporting_points,
45 std::vector<double> const& values_at_supp_pnts,
46 bool supp_pnts_sorted)
47 : supp_pnts_(supporting_points | ranges::to<std::vector<double>>()),
48 values_at_supp_pnts_(values_at_supp_pnts)
49{
50 if (!supp_pnts_sorted)
51 {
53 supp_pnts_, static_cast<std::size_t>(0), supp_pnts_.size(),
55 }
56
57 const auto it = std::adjacent_find(supp_pnts_.begin(), supp_pnts_.end());
58 if (it != supp_pnts_.end())
59 {
60 const std::size_t i = std::distance(supp_pnts_.begin(), it);
62 "Variable {:d} and variable {:d} are the same. Piecewise linear "
63 "interpolation is not possible\n",
64 i, i + 1);
65 }
66}
67
68double PiecewiseLinearInterpolation::getValue(double pnt_to_interpolate) const
69{
70 // search interval that has the point inside
71 if (pnt_to_interpolate <= supp_pnts_.front())
72 {
73 return values_at_supp_pnts_[0];
74 }
75
76 if (supp_pnts_.back() <= pnt_to_interpolate)
77 {
78 return values_at_supp_pnts_[supp_pnts_.size() - 1];
79 }
80
81 auto const& it(std::lower_bound(supp_pnts_.begin(), supp_pnts_.end(),
82 pnt_to_interpolate));
83 std::size_t const interval_idx = std::distance(supp_pnts_.begin(), it) - 1;
84
85 // support points.
86 double const x = supp_pnts_[interval_idx];
87 double const x_r = supp_pnts_[interval_idx + 1];
88
89 // values.
90 double const f = values_at_supp_pnts_[interval_idx];
91 double const f_r = values_at_supp_pnts_[interval_idx + 1];
92
93 // compute linear interpolation polynom: y = m * (x - support[i]) + value[i]
94 const double t = (pnt_to_interpolate - x) / (x_r - x);
95 return std::lerp(f, f_r, t);
96}
97
99 double const pnt_to_interpolate) const
100{
101 if (pnt_to_interpolate < supp_pnts_.front() ||
102 supp_pnts_.back() < pnt_to_interpolate)
103 {
104 return 0;
105 }
106
107 auto const& it(std::lower_bound(supp_pnts_.begin(), supp_pnts_.end(),
108 pnt_to_interpolate));
109 std::size_t interval_idx = std::distance(supp_pnts_.begin(), it);
110
111 if (pnt_to_interpolate == supp_pnts_.front())
112 {
113 interval_idx = 1;
114 }
115
116 if (interval_idx > 1 && interval_idx < supp_pnts_.size() - 2)
117 {
118 // left and right support points.
119 double const x_ll = supp_pnts_[interval_idx - 2];
120 double const x_l = supp_pnts_[interval_idx - 1];
121 double const x = supp_pnts_[interval_idx];
122 double const x_r = supp_pnts_[interval_idx + 1];
123
124 // left and right values.
125 double const f_ll = values_at_supp_pnts_[interval_idx - 2];
126 double const f_l = values_at_supp_pnts_[interval_idx - 1];
127 double const f = values_at_supp_pnts_[interval_idx];
128 double const f_r = values_at_supp_pnts_[interval_idx + 1];
129
130 double const tangent_right = (f_l - f_r) / (x_l - x_r);
131 double const tangent_left = (f_ll - f) / (x_ll - x);
132 double const w = (pnt_to_interpolate - x) / (x_l - x);
133 return (1. - w) * tangent_right + w * tangent_left;
134 }
135
136 return (values_at_supp_pnts_[interval_idx] -
137 values_at_supp_pnts_[interval_idx - 1]) /
138 (supp_pnts_[interval_idx] - supp_pnts_[interval_idx - 1]);
139}
140
142{
143 assert(!supp_pnts_.empty());
144 return supp_pnts_.back();
145}
147{
148 assert(!supp_pnts_.empty());
149 return supp_pnts_.front();
150}
151} // namespace MathLib
#define OGS_FATAL(...)
Definition Error.h:19
PiecewiseLinearInterpolation(std::vector< double > supporting_points, std::vector< double > values_at_supp_pnts, bool supp_pnts_sorted=false)
double getDerivative(double const pnt_to_interpolate) const
Calculates derivative using quadratic interpolation and central difference quotient.
double getValue(double pnt_to_interpolate) const
Calculates the interpolation value.
void quicksort(It1 first1, It1 last1, It2 first2, Comparator compare)
Definition quicksort.h:17
static const double t