28 #ifndef OPM_UNIFORM_X_TABULATED_2D_FUNCTION_HPP 29 #define OPM_UNIFORM_X_TABULATED_2D_FUNCTION_HPP 42 #include <type_traits> 54 template <
class Scalar>
58 typedef std::tuple<Scalar, Scalar, Scalar> SamplePoint;
77 : interpolationGuide_(interpolationGuide)
80 UniformXTabulated2DFunction(
const std::vector<Scalar>& xPos,
81 const std::vector<Scalar>& yPos,
82 const std::vector<std::vector<SamplePoint>>& samples,
87 , interpolationGuide_(interpolationGuide)
94 {
return xPos_.front(); }
100 {
return xPos_.back(); }
105 Scalar
xAt(std::size_t i)
const 111 Scalar
yAt(std::size_t i, std::size_t j)
const 112 {
return std::get<1>(samples_[i][j]); }
117 Scalar
valueAt(std::size_t i, std::size_t j)
const 118 {
return std::get<2>(samples_[i][j]); }
124 {
return xPos_.size(); }
130 {
return std::get<1>(samples_.at(i).front()); }
136 {
return std::get<1>(samples_.at(i).back()); }
141 std::size_t
numY(
unsigned i)
const 142 {
return samples_.at(i).size(); }
154 const std::vector<std::vector<SamplePoint>>& samples()
const 159 const std::vector<Scalar>& xPos()
const 164 const std::vector<Scalar>& yPos()
const 171 return interpolationGuide_;
177 Scalar
jToY(
unsigned i,
unsigned j)
const 180 assert(std::size_t(j) < samples_[i].size());
182 return std::get<1>(samples_.at(i).at(j));
188 template <
class Evaluation>
190 [[maybe_unused]]
bool extrapolate =
false)
const 192 assert(extrapolate || (
xMin() <= x && x <=
xMax()));
195 assert(xPos_.size() >= 2);
199 else if (x >= xPos_[xPos_.size() - 2])
200 return xPos_.size() - 2;
202 assert(xPos_.size() >= 3);
205 unsigned lowerIdx = 1;
206 unsigned upperIdx = xPos_.size() - 2;
207 while (lowerIdx + 1 < upperIdx) {
208 unsigned pivotIdx = (lowerIdx + upperIdx) / 2;
209 if (x < xPos_[pivotIdx])
225 template <
class Evaluation>
226 Evaluation
xToAlpha(
const Evaluation& x,
unsigned segmentIdx)
const 228 Scalar x1 = xPos_[segmentIdx];
229 Scalar x2 = xPos_[segmentIdx + 1];
230 return (x - x1)/(x2 - x1);
236 template <
class Evaluation>
238 [[maybe_unused]]
bool extrapolate =
false)
const 240 assert(xSampleIdx <
numX());
241 const auto& colSamplePoints = samples_.at(xSampleIdx);
243 assert(colSamplePoints.size() >= 2);
244 assert(extrapolate || (
yMin(xSampleIdx) <= y && y <=
yMax(xSampleIdx)));
246 if (y <= std::get<1>(colSamplePoints[1]))
248 else if (y >= std::get<1>(colSamplePoints[colSamplePoints.size() - 2]))
249 return colSamplePoints.size() - 2;
251 assert(colSamplePoints.size() >= 3);
254 unsigned lowerIdx = 1;
255 unsigned upperIdx = colSamplePoints.size() - 2;
256 while (lowerIdx + 1 < upperIdx) {
257 unsigned pivotIdx = (lowerIdx + upperIdx) / 2;
258 if (y < std::get<1>(colSamplePoints[pivotIdx]))
274 template <
class Evaluation>
275 Evaluation
yToBeta(
const Evaluation& y,
unsigned xSampleIdx,
unsigned ySegmentIdx)
const 277 assert(xSampleIdx <
numX());
278 assert(ySegmentIdx <
numY(xSampleIdx) - 1);
280 const auto& colSamplePoints = samples_.at(xSampleIdx);
282 Scalar y1 = std::get<1>(colSamplePoints[ySegmentIdx]);
283 Scalar y2 = std::get<1>(colSamplePoints[ySegmentIdx + 1]);
285 return (y - y1)/(y2 - y1);
291 template <
class Evaluation>
292 bool applies(
const Evaluation& x,
const Evaluation& y)
const 298 Scalar alpha =
xToAlpha(decay<Scalar>(x), i);
300 const auto& col1SamplePoints = samples_.at(i);
301 const auto& col2SamplePoints = samples_.at(i + 1);
304 alpha*std::get<1>(col1SamplePoints.front()) +
305 (1 - alpha)*std::get<1>(col2SamplePoints.front());
308 alpha*std::get<1>(col1SamplePoints.back()) +
309 (1 - alpha)*std::get<1>(col2SamplePoints.back());
311 return minY <= y && y <= maxY;
319 template <
class Evaluation>
320 Evaluation
eval(
const Evaluation& x,
const Evaluation& y,
bool extrapolate=
false)
const 322 Evaluation alpha, beta1, beta2;
324 findPoints(i, j1, j2, alpha, beta1, beta2, x, y, extrapolate);
325 return eval(i, j1, j2, alpha, beta1, beta2);
328 template <
class Evaluation>
329 void findPoints(
unsigned& i,
337 bool extrapolate)
const 340 if (!extrapolate && !
applies(x, y)) {
341 if constexpr (std::is_floating_point_v<Evaluation>) {
343 std::to_string(x) +
", " +
344 std::to_string(y) +
")");
346 throw NumericalProblem(
"Attempt to get undefined table value (" +
347 std::to_string(x.value()) +
", " +
348 std::to_string(y.value()) +
")");
362 Evaluation shift = 0.0;
363 if (interpolationGuide_ == InterpolationPolicy::Vertical) {
367 if (interpolationGuide_ == InterpolationPolicy::LeftExtreme) {
370 shift = yPos_[i+1] - yPos_[i];
372 assert(interpolationGuide_ == InterpolationPolicy::RightExtreme);
378 shift = yPos_[i+1] - yPos_[i];
379 auto yEnd = yPos_[i]*(1.0 - alpha) + yPos_[i+1]*alpha;
381 shift = shift * y / yEnd;
387 auto yLower = y - alpha*shift;
388 auto yUpper = y + (1-alpha)*shift;
392 beta1 =
yToBeta(yLower, i, j1);
393 beta2 =
yToBeta(yUpper, i + 1, j2);
396 template <
class Evaluation>
397 Evaluation
eval(
const unsigned& i,
const unsigned& j1,
const unsigned& j2,
const Evaluation& alpha,
const Evaluation& beta1,
const Evaluation& beta2)
const 400 const Evaluation& s1 =
valueAt(i, j1)*(1.0 - beta1) +
valueAt(i, j1 + 1)*beta1;
401 const Evaluation& s2 =
valueAt(i + 1, j2)*(1.0 - beta2) +
valueAt(i + 1, j2 + 1)*beta2;
403 Valgrind::CheckDefined(s1);
404 Valgrind::CheckDefined(s2);
407 const Evaluation& result = s1*(1.0 - alpha) + s2*alpha;
408 Valgrind::CheckDefined(result);
420 if (xPos_.empty() || xPos_.back() < nextX) {
421 xPos_.push_back(nextX);
422 yPos_.push_back(std::numeric_limits<Scalar>::lowest() / 2);
423 samples_.push_back({});
424 return xPos_.size() - 1;
426 else if (xPos_.front() > nextX) {
428 xPos_.insert(xPos_.begin(), nextX);
429 yPos_.insert(yPos_.begin(), std::numeric_limits<Scalar>::lowest() / 2);
430 samples_.insert(samples_.begin(), std::vector<SamplePoint>());
433 throw std::invalid_argument(
"Sampling points should be specified either monotonically " 434 "ascending or descending.");
446 if (samples_[i].empty()) {
447 samples_[i].emplace_back(x, y,
value);
451 else if (std::get<1>(samples_[i].back()) < y) {
452 samples_[i].emplace_back(x, y,
value);
453 if (interpolationGuide_ == InterpolationPolicy::RightExtreme) {
456 return samples_[i].size() - 1;
458 else if (std::get<1>(samples_[i].front()) > y) {
460 samples_[i].emplace(samples_[i].begin(), x, y,
value);
461 if (interpolationGuide_ == InterpolationPolicy::LeftExtreme) {
467 throw std::invalid_argument(
"Sampling points must be specified in either monotonically " 468 "ascending or descending order.");
477 void print(std::ostream& os)
const;
480 return this->xPos() == data.xPos() &&
481 this->yPos() == data.yPos() &&
482 this->samples() == data.samples() &&
483 this->interpolationGuide() == data.interpolationGuide();
490 std::vector<std::vector<SamplePoint> > samples_;
493 std::vector<Scalar> xPos_;
495 std::vector<Scalar> yPos_;
Definition: Exceptions.hpp:39
Provides the OPM specific exception classes.
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Some templates to wrap the valgrind client request macros.