Line | Branch | Exec | Source |
---|---|---|---|
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 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup Core | ||
10 | * \brief Implements tabulation for a two-dimensional function. | ||
11 | */ | ||
12 | #ifndef DUMUX_TABULATED_2D_FUNCTION_HH | ||
13 | #define DUMUX_TABULATED_2D_FUNCTION_HH | ||
14 | |||
15 | #include <vector> | ||
16 | #include <cassert> | ||
17 | #include <algorithm> | ||
18 | |||
19 | namespace Dumux { | ||
20 | |||
21 | /*! | ||
22 | * \ingroup Core | ||
23 | * \brief Implements tabulation for a two-dimensional function. | ||
24 | * | ||
25 | * This class can be used to tabulate a two dimensional function | ||
26 | * \f$f(x, y)\f$ over the range \f$[x_{min}, x_{max}] \times [y_{min}, | ||
27 | * y_{max}]\f$. For this, the ranges of the \f$x\f$ and \f$y\f$ axes are | ||
28 | * divided into \f$m\f$ and \f$n\f$ sub-intervals and the values of | ||
29 | * \f$f(x_i, y_j)\f$ need to be provided. Here, \f$x_i\f$ and | ||
30 | * \f$y_j\f$ are the largest positions of the \f$i\f$-th and | ||
31 | * \f$j\f$-th interval. Between these sampling points this tabulation | ||
32 | * class uses linear interpolation. | ||
33 | */ | ||
34 | template<class Scalar> | ||
35 | class Tabulated2DFunction | ||
36 | { | ||
37 | public: | ||
38 | /*! | ||
39 | * \brief Default constructor. | ||
40 | */ | ||
41 | Tabulated2DFunction() | ||
42 | { }; | ||
43 | |||
44 | /*! | ||
45 | * \brief Constructor where the tabulation parameters are already | ||
46 | * provided. | ||
47 | */ | ||
48 | Tabulated2DFunction(Scalar xMin, Scalar xMax, int m, | ||
49 | Scalar yMin, Scalar yMax, int n) | ||
50 | { | ||
51 | resize(xMin, xMax, m, yMin, yMax, n); | ||
52 | }; | ||
53 | |||
54 | /*! | ||
55 | * \brief Resize the tabulation to a new range. | ||
56 | * | ||
57 | * \note _All_ previously specified sampling points become invalid | ||
58 | * after calling this method. You have to supply new ones. | ||
59 | */ | ||
60 | void resize(Scalar xMin, Scalar xMax, int m, | ||
61 | Scalar yMin, Scalar yMax, int n) | ||
62 | { | ||
63 | 2 | samples_.resize(m*n); | |
64 | |||
65 | 6 | m_ = m; | |
66 | 6 | n_ = n; | |
67 | |||
68 | 6 | xMin_ = xMin; | |
69 | 6 | xMax_ = xMax; | |
70 | |||
71 | 6 | yMin_ = yMin; | |
72 | 2 | yMax_ = yMax; | |
73 | } | ||
74 | |||
75 | /*! | ||
76 | * \brief Return the position on the x-axis of the i-th interval. | ||
77 | */ | ||
78 | 200 | Scalar iToX(int i) const | |
79 | { | ||
80 |
2/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200 times.
|
200 | assert(0 <= i && i < m_); |
81 | |||
82 | 200 | return xMin_ + i*(xMax_ - xMin_)/(m_ - 1); | |
83 | } | ||
84 | |||
85 | /*! | ||
86 | * \brief Return the position on the y-axis of the j-th interval. | ||
87 | */ | ||
88 | 40000 | Scalar jToY(int j) const | |
89 | { | ||
90 |
2/4✓ Branch 0 taken 40000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40000 times.
|
40000 | assert(0 <= j && j < n_); |
91 | |||
92 | 40000 | return yMin_ + j*(yMax_ - yMin_)/(n_ - 1); | |
93 | } | ||
94 | |||
95 | /*! | ||
96 | * \brief Return the interval index of a given position on the x-axis. | ||
97 | * | ||
98 | * This method returns a *floating point* number. The integer part | ||
99 | * should be interpreted as interval, the decimal places are the | ||
100 | * position of the x value between the i-th and the (i+1)-th | ||
101 | * sample point. | ||
102 | */ | ||
103 | Scalar xToI(Scalar x) const | ||
104 | { | ||
105 | 44292 | return (x - xMin_)/(xMax_ - xMin_)*(m_ - 1); | |
106 | } | ||
107 | |||
108 | |||
109 | /*! | ||
110 | * \brief Return the interval index of a given position on the y-axis. | ||
111 | * | ||
112 | * This method returns a *floating point* number. The integer part | ||
113 | * should be interpreted as interval, the decimal places are the | ||
114 | * position of the y value between the j-th and the (j+1)-th | ||
115 | * sample point. | ||
116 | */ | ||
117 | Scalar yToJ(Scalar y) const | ||
118 | { | ||
119 | 44292 | return (y - yMin_)/(yMax_ - yMin_)*(n_ - 1); | |
120 | } | ||
121 | |||
122 | |||
123 | /*! | ||
124 | * \brief Get the value of the sample point which is at the | ||
125 | * intersection of the \f$i\f$-th interval of the x-Axis | ||
126 | * and the \f$j\f$-th of the y-Axis. | ||
127 | */ | ||
128 | 177168 | Scalar getSamplePoint(int i, int j) const | |
129 | { | ||
130 |
2/4✓ Branch 0 taken 177168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 177168 times.
|
177168 | assert(0 <= i && i < m_); |
131 |
2/4✓ Branch 0 taken 177168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 177168 times.
|
177168 | assert(0 <= j && j < n_); |
132 | |||
133 | 354336 | return samples_[j*m_ + i]; | |
134 | } | ||
135 | |||
136 | /*! | ||
137 | * \brief Set the value of the sample point which is at the | ||
138 | * intersection of the \f$i\f$-th interval of the x-Axis | ||
139 | * and the \f$j\f$-th of the y-Axis. | ||
140 | */ | ||
141 | 120000 | void setSamplePoint(int i, int j, Scalar value) | |
142 | { | ||
143 |
2/4✓ Branch 0 taken 120000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120000 times.
|
120000 | assert(0 <= i && i < m_); |
144 |
2/4✓ Branch 0 taken 120000 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120000 times.
|
120000 | assert(0 <= j && j < n_); |
145 | |||
146 | 240000 | samples_[j*m_ + i] = value; | |
147 | 120000 | } | |
148 | |||
149 | /*! | ||
150 | * \brief Return an interpolated value. | ||
151 | */ | ||
152 | 44292 | Scalar get(Scalar x, Scalar y) const | |
153 | { | ||
154 | 88584 | Scalar alpha = xToI(x); | |
155 | 88584 | Scalar beta = yToJ(y); | |
156 | |||
157 | using std::clamp; | ||
158 |
1/2✓ Branch 0 taken 44292 times.
✗ Branch 1 not taken.
|
44292 | int i = clamp(static_cast<int>(alpha), 0, m_ - 2); |
159 |
1/2✓ Branch 0 taken 44292 times.
✗ Branch 1 not taken.
|
44292 | int j = clamp(static_cast<int>(beta), 0, n_ - 2); |
160 | |||
161 | 44292 | alpha -= i; | |
162 | 44292 | beta -= j; | |
163 | |||
164 | // bi-linear interpolation | ||
165 | 44292 | Scalar s1 = getSamplePoint(i, j)*(1.0 - alpha) + getSamplePoint(i + 1, j)*alpha; | |
166 | 44292 | Scalar s2 = getSamplePoint(i, j + 1)*(1.0 - alpha) + getSamplePoint(i + 1, j + 1)*alpha; | |
167 | 44292 | return s1*(1.0 - beta) + s2*beta; | |
168 | } | ||
169 | |||
170 | /*! | ||
171 | * \brief The () operator | ||
172 | * | ||
173 | * This is just a convenience alias for get(x,y); | ||
174 | */ | ||
175 | Scalar operator()(Scalar x, Scalar y) const | ||
176 | 44292 | { return get(x, y); } | |
177 | |||
178 | private: | ||
179 | // the vector which contains the values of the sample points | ||
180 | // f(x_i, y_j). don't use this directly, use getSamplePoint(i,j) | ||
181 | // instead! | ||
182 | std::vector<Scalar> samples_; | ||
183 | |||
184 | // the number of sample points in x direction | ||
185 | int m_; | ||
186 | |||
187 | // the number of sample points in y direction | ||
188 | int n_; | ||
189 | |||
190 | // the range of the tabulation on the x axis | ||
191 | Scalar xMin_; | ||
192 | Scalar xMax_; | ||
193 | |||
194 | // the range of the tabulation on the y axis | ||
195 | Scalar yMin_; | ||
196 | Scalar yMax_; | ||
197 | |||
198 | }; | ||
199 | |||
200 | } // end namespace Dumux | ||
201 | |||
202 | #endif | ||
203 |