opm-common
IntervalTabulated2DFunction.hpp
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  This file is part of the Open Porous Media project (OPM).
5 
6  OPM 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 2 of the License, or
9  (at your option) any later version.
10 
11  OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
28 #ifndef OPM_INTERVAL_TABULATED_2D_FUNCTION_HPP
29 #define OPM_INTERVAL_TABULATED_2D_FUNCTION_HPP
30 
32 
35 
36 #include <algorithm>
37 #include <cassert>
38 #include <cstddef>
39 #include <limits>
40 #include <string>
41 #include <type_traits>
42 #include <vector>
43 
44 namespace Opm {
45 
52 template <class Scalar>
54 {
55 public:
57  { }
58 
59  template <class DataContainer>
60  IntervalTabulated2DFunction(const std::vector<Scalar>& xPos,
61  const std::vector<Scalar>& yPos,
62  const DataContainer& data,
63  const bool xExtrapolate = false,
64  const bool yExtrapolate = false)
65  : xPos_(xPos)
66  , yPos_(yPos)
67  , samples_(data)
68  , xExtrapolate_(xExtrapolate)
69  , yExtrapolate_(yExtrapolate)
70  {
71 #ifndef NDEBUG
72  // in debug mode, ensure that the x and y positions arrays are strictly
73  // mononically increasing.
74  for (unsigned i = 0; i < xPos.size() - 1; ++ i) {
75  if (xPos[i + 1] <= xPos[i])
76  throw std::runtime_error("The array for the x-positions is not strictly increasing!");
77  }
78 
79  for (unsigned i = 0; i < yPos.size() - 1; ++ i) {
80  if (yPos[i + 1] <= yPos[i])
81  throw std::runtime_error("The array for the y-positions is not strictly increasing!");
82  }
83 #endif
84 
85  // make sure the size is correct
86  if (numX() != samples_.size())
87  throw std::runtime_error("numX() is not equal to the number of rows of the sampling points");
88 
89  for (unsigned xIdx = 0; xIdx < numX(); ++xIdx) {
90  if (samples_[xIdx].size() != numY()) {
91  throw std::runtime_error("The " + std::to_string(xIdx) +
92  "-th row of the sampling points has "
93  "different size than numY() ");
94  }
95  }
96  }
97 
101  std::size_t numX() const
102  { return xPos_.size(); }
103 
107  std::size_t numY() const
108  { return yPos_.size(); }
109 
113  Scalar xMin() const
114  { return xPos_.front(); }
115 
119  Scalar xMax() const
120  { return xPos_.back(); }
121 
125  Scalar yMin() const
126  { return yPos_.front(); }
127 
131  Scalar yMax() const
132  { return yPos_.back(); }
133 
134  const std::vector<Scalar>& xPos() const
135  { return xPos_; }
136 
137  const std::vector<Scalar>& yPos() const
138  { return yPos_; }
139 
140  const std::vector<std::vector<Scalar>>& samples() const
141  { return samples_; }
142 
143  bool xExtrapolate() const
144  { return xExtrapolate_; }
145 
146  bool yExtrapolate() const
147  { return yExtrapolate_; }
148 
149  bool operator==(const IntervalTabulated2DFunction<Scalar>& data) const {
150  return this->xPos() == data.xPos() &&
151  this->yPos() == data.yPos() &&
152  this->samples() == data.samples() &&
153  this->xExtrapolate() == data.xExtrapolate() &&
154  this->yExtrapolate() == data.yExtrapolate();
155  }
156 
160  Scalar valueAt(std::size_t i, std::size_t j) const
161  { return samples_[i][j]; }
162 
166  template <class Evaluation>
167  bool applies(const Evaluation& x, const Evaluation& y) const
168  { return appliesX(x) && appliesY(y); }
169 
173  template <class Evaluation>
174  bool appliesX(const Evaluation& x) const
175  { return xMin() <= x && x <= xMax(); }
176 
180  template <class Evaluation>
181  bool appliesY(const Evaluation& y) const
182  { return yMin() <= y && y <= yMax(); }
183 
184 
192  template <typename Evaluation>
193  Evaluation eval(const Evaluation& x, const Evaluation& y) const
194  {
195  if ((!xExtrapolate_ && !appliesX(x)) || (!yExtrapolate_ && !appliesY(y))) {
196  if constexpr (std::is_floating_point_v<Evaluation>) {
197  throw NumericalProblem("Attempt to get undefined table value (" +
198  std::to_string(x) + ", " +
199  std::to_string(y) + ")");
200  } else {
201  throw NumericalProblem("Attempt to get undefined table value (" +
202  std::to_string(x.value()) + ", " +
203  std::to_string(y.value()) + ")");
204  }
205  };
206 
207  // bi-linear interpolation: first, calculate the x and y indices in the lookup
208  // table ...
209  const unsigned i = xSegmentIndex_(x);
210  const unsigned j = ySegmentIndex_(y);
211 
212  // bi-linear interpolation / extrapolation
213  const Evaluation alpha = xToAlpha(x, i);
214  const Evaluation beta = yToBeta(y, j);
215 
216  const Evaluation s1 = valueAt(i, j) * (1.0 - beta) + valueAt(i, j + 1) * beta;
217  const Evaluation s2 = valueAt(i + 1, j) * (1.0 - beta) + valueAt(i + 1, j + 1) * beta;
218 
219  Valgrind::CheckDefined(s1);
220  Valgrind::CheckDefined(s2);
221 
222  // ... and combine them using the x position
223  return s1*(1.0 - alpha) + s2*alpha;
224  }
225 
226 private:
227  // the sampling points in the x-drection
228  std::vector<Scalar> xPos_;
229  // the sampling points in the y-drection
230  std::vector<Scalar> yPos_;
231  // data at the sampling points
232  std::vector<std::vector<Scalar> > samples_;
233 
234  bool xExtrapolate_ = false;
235  bool yExtrapolate_ = false;
236 
240  template <class Evaluation>
241  unsigned xSegmentIndex_(const Evaluation& x) const
242  {
243  assert(xExtrapolate_ || appliesX(x) );
244 
245  return segmentIndex_(x, xPos_);
246  }
247 
251  template <class Evaluation>
252  unsigned ySegmentIndex_(const Evaluation& y) const
253  {
254  assert(yExtrapolate_ || appliesY(y) );
255 
256  return segmentIndex_(y, yPos_);
257  }
258 
259 
260  template <class Evaluation>
261  static unsigned segmentIndex_(const Evaluation& v, const std::vector<Scalar>& vPos)
262  {
263  const unsigned n = vPos.size();
264  assert(n >= 2);
265 
266  if (v <= vPos.front() || n == 2)
267  return 0;
268  else if (v >= vPos.back())
269  return n - 2;
270 
271  assert(n > 2 && v > vPos.front() && v < vPos.back());
272 
273  // bisection. this assumes that the vPos array is strictly mononically
274  // increasing.
275  std::size_t lowerIdx = 0;
276  std::size_t upperIdx = vPos.size() - 1;
277  while (lowerIdx + 1 < upperIdx) {
278  std::size_t pivotIdx = (lowerIdx + upperIdx) / 2;
279  if (v < vPos[pivotIdx])
280  upperIdx = pivotIdx;
281  else
282  lowerIdx = pivotIdx;
283  }
284 
285  assert(vPos[lowerIdx] <= v);
286  assert(v <= vPos[lowerIdx + 1]);
287  return lowerIdx;
288  }
289 
296  template <class Evaluation>
297  Evaluation xToAlpha(const Evaluation& x, unsigned xSegmentIdx) const
298  {
299  Scalar x1 = xPos_[xSegmentIdx];
300  Scalar x2 = xPos_[xSegmentIdx + 1];
301  return (x - x1)/(x2 - x1);
302  }
303 
310  template <class Evaluation>
311  Evaluation yToBeta(const Evaluation& y, unsigned ySegmentIdx) const
312  {
313  Scalar y1 = yPos_[ySegmentIdx];
314  Scalar y2 = yPos_[ySegmentIdx + 1];
315  return (y - y1)/(y2 - y1);
316  }
317 
318 };
319 } // namespace Opm
320 
321 #endif
bool applies(const Evaluation &x, const Evaluation &y) const
Returns true if a coordinate lies in the tabulated range.
Definition: IntervalTabulated2DFunction.hpp:167
Scalar valueAt(std::size_t i, std::size_t j) const
Returns the value of a sampling point.
Definition: IntervalTabulated2DFunction.hpp:160
Definition: Exceptions.hpp:39
A traits class which provides basic mathematical functions for arbitrary scalar floating point values...
Provides the OPM specific exception classes.
std::size_t numX() const
Returns the number of sampling points in X direction.
Definition: IntervalTabulated2DFunction.hpp:101
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
bool appliesX(const Evaluation &x) const
Returns true if a coordinate lies in the tabulated range on the x direction.
Definition: IntervalTabulated2DFunction.hpp:174
Scalar xMin() const
Returns the minimum of the X coordinate of the sampling points.
Definition: IntervalTabulated2DFunction.hpp:113
std::size_t numY() const
Returns the number of sampling points in Y direction.
Definition: IntervalTabulated2DFunction.hpp:107
Evaluation eval(const Evaluation &x, const Evaluation &y) const
Evaluate the function at a given (x,y) position.
Definition: IntervalTabulated2DFunction.hpp:193
Scalar yMin() const
Returns the minimum of the Y coordinate of the sampling points.
Definition: IntervalTabulated2DFunction.hpp:125
Scalar xMax() const
Returns the maximum of the X coordinate of the sampling points.
Definition: IntervalTabulated2DFunction.hpp:119
Some templates to wrap the valgrind client request macros.
Implements a function that depends on two variables.
Definition: IntervalTabulated2DFunction.hpp:53
Scalar yMax() const
Returns the maximum of the Y coordinate of the sampling points.
Definition: IntervalTabulated2DFunction.hpp:131
bool appliesY(const Evaluation &y) const
Returns true if a coordinate lies in the tabulated range on the y direction.
Definition: IntervalTabulated2DFunction.hpp:181