opm-common
Spline.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 */
27 #ifndef OPM_SPLINE_HPP
28 #define OPM_SPLINE_HPP
29 
31 
34 
35 #include <cstddef>
36 #include <iosfwd>
37 #include <vector>
38 
39 namespace Opm
40 {
90 template<class Scalar>
91 class Spline
92 {
94  typedef std::vector<Scalar> Vector;
95 
96 public:
102  enum SplineType {
103  Full,
104  Natural,
105  Periodic,
106  Monotonic
107  };
108 
115  { }
116 
127  Spline(Scalar x0, Scalar x1,
128  Scalar y0, Scalar y1,
129  Scalar m0, Scalar m1)
130  { set(x0, x1, y0, y1, m0, m1); }
131 
141  template <class ScalarArrayX, class ScalarArrayY>
142  Spline(std::size_t nSamples,
143  const ScalarArrayX& x,
144  const ScalarArrayY& y,
145  SplineType splineType = Natural,
146  bool sortInputs = true)
147  { this->setXYArrays(nSamples, x, y, splineType, sortInputs); }
148 
157  template <class PointArray>
158  Spline(std::size_t nSamples,
159  const PointArray& points,
160  SplineType splineType = Natural,
161  bool sortInputs = true)
162  { this->setArrayOfPoints(nSamples, points, splineType, sortInputs); }
163 
172  template <class ScalarContainer>
173  Spline(const ScalarContainer& x,
174  const ScalarContainer& y,
175  SplineType splineType = Natural,
176  bool sortInputs = true)
177  { this->setXYContainers(x, y, splineType, sortInputs); }
178 
186  template <class PointContainer>
187  explicit Spline(const PointContainer& points,
188  SplineType splineType = Natural,
189  bool sortInputs = true)
190  { this->setContainerOfPoints(points, splineType, sortInputs); }
191 
202  template <class ScalarArray>
203  Spline(std::size_t nSamples,
204  const ScalarArray& x,
205  const ScalarArray& y,
206  Scalar m0,
207  Scalar m1,
208  bool sortInputs = true)
209  { this->setXYArrays(nSamples, x, y, m0, m1, sortInputs); }
210 
220  template <class PointArray>
221  Spline(std::size_t nSamples,
222  const PointArray& points,
223  Scalar m0,
224  Scalar m1,
225  bool sortInputs = true)
226  { this->setArrayOfPoints(nSamples, points, m0, m1, sortInputs); }
227 
237  template <class ScalarContainerX, class ScalarContainerY>
238  Spline(const ScalarContainerX& x,
239  const ScalarContainerY& y,
240  Scalar m0,
241  Scalar m1,
242  bool sortInputs = true)
243  { this->setXYContainers(x, y, m0, m1, sortInputs); }
244 
253  template <class PointContainer>
254  Spline(const PointContainer& points,
255  Scalar m0,
256  Scalar m1,
257  bool sortInputs = true)
258  { this->setContainerOfPoints(points, m0, m1, sortInputs); }
259 
271  void set(Scalar x0, Scalar x1,
272  Scalar y0, Scalar y1,
273  Scalar m0, Scalar m1)
274  {
275  slopeVec_.resize(2);
276  xPos_.resize(2);
277  yPos_.resize(2);
278 
279  if (x0 > x1) {
280  xPos_[0] = x1;
281  xPos_[1] = x0;
282  yPos_[0] = y1;
283  yPos_[1] = y0;
284  }
285  else {
286  xPos_[0] = x0;
287  xPos_[1] = x1;
288  yPos_[0] = y0;
289  yPos_[1] = y1;
290  }
291 
292  slopeVec_[0] = m0;
293  slopeVec_[1] = m1;
294 
295  Matrix M(numSamples());
296  Vector d(numSamples());
297  Vector moments(numSamples());
298  this->makeFullSystem_(M, d, m0, m1);
299 
300  // solve for the moments
301  M.solve(moments, d);
302 
303  this->setSlopesFromMoments_(slopeVec_, moments);
304  }
305 
309  // Full splines //
313 
325  template <class ScalarArrayX, class ScalarArrayY>
326  void setXYArrays(std::size_t nSamples,
327  const ScalarArrayX& x,
328  const ScalarArrayY& y,
329  Scalar m0, Scalar m1,
330  bool sortInputs = true)
331  {
332  assert(nSamples > 1);
333 
334  setNumSamples_(nSamples);
335  for (std::size_t i = 0; i < nSamples; ++i) {
336  xPos_[i] = x[i];
337  yPos_[i] = y[i];
338  }
339 
340  if (sortInputs)
341  sortInput_();
342  else if (xPos_[0] > xPos_[numSamples() - 1])
344 
345  makeFullSpline_(m0, m1);
346  }
347 
359  template <class ScalarContainerX, class ScalarContainerY>
360  void setXYContainers(const ScalarContainerX& x,
361  const ScalarContainerY& y,
362  Scalar m0, Scalar m1,
363  bool sortInputs = true)
364  {
365  assert(x.size() == y.size());
366  assert(x.size() > 1);
367 
368  setNumSamples_(x.size());
369 
370  std::ranges::copy(x, xPos_.begin());
371  std::ranges::copy(y, yPos_.begin());
372 
373  if (sortInputs)
374  sortInput_();
375  else if (xPos_[0] > xPos_[numSamples() - 1])
377 
378  makeFullSpline_(m0, m1);
379  }
380 
393  template <class PointArray>
394  void setArrayOfPoints(std::size_t nSamples,
395  const PointArray& points,
396  Scalar m0,
397  Scalar m1,
398  bool sortInputs = true)
399  {
400  // a spline with no or just one sampling points? what an
401  // incredible bad idea!
402  assert(nSamples > 1);
403 
404  setNumSamples_(nSamples);
405  for (std::size_t i = 0; i < nSamples; ++i) {
406  xPos_[i] = points[i][0];
407  yPos_[i] = points[i][1];
408  }
409 
410  if (sortInputs)
411  sortInput_();
412  else if (xPos_[0] > xPos_[numSamples() - 1])
414 
415  makeFullSpline_(m0, m1);
416  }
417 
430  template <class XYContainer>
431  void setContainerOfPoints(const XYContainer& points,
432  Scalar m0,
433  Scalar m1,
434  bool sortInputs = true)
435  {
436  // a spline with no or just one sampling points? what an
437  // incredible bad idea!
438  assert(points.size() > 1);
439 
440  setNumSamples_(points.size());
441  typename XYContainer::const_iterator it = points.begin();
442  typename XYContainer::const_iterator endIt = points.end();
443  for (std::size_t i = 0; it != endIt; ++i, ++it) {
444  xPos_[i] = (*it)[0];
445  yPos_[i] = (*it)[1];
446  }
447 
448  if (sortInputs)
449  sortInput_();
450  else if (xPos_[0] > xPos_[numSamples() - 1])
452 
453  // make a full spline
454  makeFullSpline_(m0, m1);
455  }
456 
472  template <class XYContainer>
473  void setContainerOfTuples(const XYContainer& points,
474  Scalar m0,
475  Scalar m1,
476  bool sortInputs = true)
477  {
478  // resize internal arrays
479  setNumSamples_(points.size());
480  typename XYContainer::const_iterator it = points.begin();
481  typename XYContainer::const_iterator endIt = points.end();
482  for (unsigned i = 0; it != endIt; ++i, ++it) {
483  xPos_[i] = std::get<0>(*it);
484  yPos_[i] = std::get<1>(*it);
485  }
486 
487  if (sortInputs)
488  sortInput_();
489  else if (xPos_[0] > xPos_[numSamples() - 1])
491 
492  // make a full spline
493  makeFullSpline_(m0, m1);
494  }
495 
499  // Natural/Periodic splines //
503 
513  template <class ScalarArrayX, class ScalarArrayY>
514  void setXYArrays(std::size_t nSamples,
515  const ScalarArrayX& x,
516  const ScalarArrayY& y,
517  SplineType splineType = Natural,
518  bool sortInputs = true)
519  {
520  assert(nSamples > 1);
521 
522  setNumSamples_(nSamples);
523  for (std::size_t i = 0; i < nSamples; ++i) {
524  xPos_[i] = x[i];
525  yPos_[i] = y[i];
526  }
527 
528  if (sortInputs)
529  sortInput_();
530  else if (xPos_[0] > xPos_[numSamples() - 1])
532 
533  if (splineType == Periodic)
535  else if (splineType == Natural)
537  else if (splineType == Monotonic)
538  this->makeMonotonicSpline_(slopeVec_);
539  else
540  throw std::runtime_error("Spline type "+std::to_string(int(splineType))+" not supported at this place");
541  }
542 
554  template <class ScalarContainerX, class ScalarContainerY>
555  void setXYContainers(const ScalarContainerX& x,
556  const ScalarContainerY& y,
557  SplineType splineType = Natural,
558  bool sortInputs = true)
559  {
560  assert(x.size() == y.size());
561  assert(x.size() > 1);
562 
563  setNumSamples_(x.size());
564  std::ranges::copy(x, xPos_.begin());
565  std::ranges::copy(y, yPos_.begin());
566 
567  if (sortInputs)
568  sortInput_();
569  else if (xPos_[0] > xPos_[numSamples() - 1])
571 
572  if (splineType == Periodic)
574  else if (splineType == Natural)
576  else if (splineType == Monotonic)
577  this->makeMonotonicSpline_(slopeVec_);
578  else
579  throw std::runtime_error("Spline type "+std::to_string(int(splineType))+" not supported at this place");
580  }
581 
594  template <class PointArray>
595  void setArrayOfPoints(std::size_t nSamples,
596  const PointArray& points,
597  SplineType splineType = Natural,
598  bool sortInputs = true)
599  {
600  // a spline with no or just one sampling points? what an
601  // incredible bad idea!
602  assert(nSamples > 1);
603 
604  setNumSamples_(nSamples);
605  for (std::size_t i = 0; i < nSamples; ++i) {
606  xPos_[i] = points[i][0];
607  yPos_[i] = points[i][1];
608  }
609 
610  if (sortInputs)
611  sortInput_();
612  else if (xPos_[0] > xPos_[numSamples() - 1])
614 
615  if (splineType == Periodic)
617  else if (splineType == Natural)
619  else if (splineType == Monotonic)
620  this->makeMonotonicSpline_(slopeVec_);
621  else
622  throw std::runtime_error("Spline type "+std::to_string(int(splineType))+" not supported at this place");
623  }
624 
636  template <class XYContainer>
637  void setContainerOfPoints(const XYContainer& points,
638  SplineType splineType = Natural,
639  bool sortInputs = true)
640  {
641  // a spline with no or just one sampling points? what an
642  // incredible bad idea!
643  assert(points.size() > 1);
644 
645  setNumSamples_(points.size());
646  typename XYContainer::const_iterator it = points.begin();
647  typename XYContainer::const_iterator endIt = points.end();
648  for (std::size_t i = 0; it != endIt; ++ i, ++it) {
649  xPos_[i] = (*it)[0];
650  yPos_[i] = (*it)[1];
651  }
652 
653  if (sortInputs)
654  sortInput_();
655  else if (xPos_[0] > xPos_[numSamples() - 1])
657 
658  if (splineType == Periodic)
660  else if (splineType == Natural)
662  else if (splineType == Monotonic)
663  this->makeMonotonicSpline_(slopeVec_);
664  else
665  throw std::runtime_error("Spline type "+std::to_string(int(splineType))+" not supported at this place");
666  }
667 
682  template <class XYContainer>
683  void setContainerOfTuples(const XYContainer& points,
684  SplineType splineType = Natural,
685  bool sortInputs = true)
686  {
687  // resize internal arrays
688  setNumSamples_(points.size());
689  typename XYContainer::const_iterator it = points.begin();
690  typename XYContainer::const_iterator endIt = points.end();
691  for (unsigned i = 0; it != endIt; ++i, ++it) {
692  xPos_[i] = std::get<0>(*it);
693  yPos_[i] = std::get<1>(*it);
694  }
695 
696  if (sortInputs)
697  sortInput_();
698  else if (xPos_[0] > xPos_[numSamples() - 1])
700 
701  if (splineType == Periodic)
703  else if (splineType == Natural)
705  else if (splineType == Monotonic)
706  this->makeMonotonicSpline_(slopeVec_);
707  else
708  throw std::runtime_error("Spline type "+std::to_string(int(splineType))+" not supported at this place");
709  }
710 
714  template <class Evaluation>
715  bool applies(const Evaluation& x) const
716  { return x_(0) <= x && x <= x_(numSamples() - 1); }
717 
721  std::size_t numSamples() const
722  { return xPos_.size(); }
723 
727  Scalar xAt(std::size_t sampleIdx) const
728  { return x_(sampleIdx); }
729 
733  Scalar valueAt(std::size_t sampleIdx) const
734  { return y_(sampleIdx); }
735 
753  void printCSV(Scalar xi0, Scalar xi1, std::size_t k, std::ostream& os) const;
754 
766  template <class Evaluation>
767  Evaluation eval(const Evaluation& x, bool extrapolate = false) const
768  {
769  if (!extrapolate && !applies(x))
770  throw NumericalProblem("Tried to evaluate a spline outside of its range");
771 
772  // handle extrapolation
773  if (extrapolate) {
774  if (x < xAt(0)) {
775  Scalar m = evalDerivative_(xAt(0), /*segmentIdx=*/0);
776  Scalar y0 = y_(0);
777  return y0 + m*(x - xAt(0));
778  }
779  else if (x > xAt(static_cast<std::size_t>(static_cast<long int>(numSamples()) - 1))) {
780  Scalar m = evalDerivative_(xAt(static_cast<std::size_t>(numSamples() - 1)),
781  /*segmentIdx=*/static_cast<std::size_t>(numSamples()-2));
782  Scalar y0 = y_(static_cast<std::size_t>(numSamples() - 1));
783  return y0 + m*(x - xAt(static_cast<std::size_t>(numSamples() - 1)));
784  }
785  }
786 
787  return eval_(x, segmentIdx_(scalarValue(x)));
788  }
789 
802  template <class Evaluation>
803  Evaluation evalDerivative(const Evaluation& x, bool extrapolate = false) const
804  {
805  if (!extrapolate && !applies(x))
806  throw NumericalProblem("Tried to evaluate the derivative of a spline outside of its range");
807 
808  // handle extrapolation
809  if (extrapolate) {
810  if (x < xAt(0))
811  return evalDerivative_(xAt(0), /*segmentIdx=*/0);
812  else if (x > xAt(numSamples() - 1))
813  return evalDerivative_(xAt(numSamples() - 1), /*segmentIdx=*/numSamples() - 2);
814  }
815 
816  return evalDerivative_(x, segmentIdx_(scalarValue(x)));
817  }
818 
831  template <class Evaluation>
832  Evaluation evalSecondDerivative(const Evaluation& x, bool extrapolate = false) const
833  {
834  if (!extrapolate && !applies(x))
835  throw NumericalProblem("Tried to evaluate the second derivative of a spline outside of its range");
836  else if (extrapolate)
837  return 0.0;
838 
839  return evalDerivative2_(x, segmentIdx_(scalarValue(x)));
840  }
841 
854  template <class Evaluation>
855  Evaluation evalThirdDerivative(const Evaluation& x, bool extrapolate = false) const
856  {
857  if (!extrapolate && !applies(x))
858  throw NumericalProblem("Tried to evaluate the third derivative of a spline outside of its range");
859  else if (extrapolate)
860  return 0.0;
861 
862  return evalDerivative3_(x, segmentIdx_(scalarValue(x)));
863  }
864 
871  template <class Evaluation>
872  Evaluation intersect(const Evaluation& a,
873  const Evaluation& b,
874  const Evaluation& c,
875  const Evaluation& d) const
876  {
877  return intersectInterval(xAt(0), xAt(numSamples() - 1), a, b, c, d);
878  }
879 
886  template <class Evaluation>
887  Evaluation intersectInterval(Scalar x0, Scalar x1,
888  const Evaluation& a,
889  const Evaluation& b,
890  const Evaluation& c,
891  const Evaluation& d) const
892  {
893  assert(applies(x0) && applies(x1));
894 
895  Evaluation tmpSol[3], sol = 0;
896  std::size_t nSol = 0;
897  std::size_t iFirst = segmentIdx_(x0);
898  std::size_t iLast = segmentIdx_(x1);
899  for (std::size_t i = iFirst; i <= iLast; ++i)
900  {
901  std::size_t nCur = intersectSegment_(tmpSol, i, a, b, c, d, x0, x1);
902  if (nCur == 1)
903  sol = tmpSol[0];
904 
905  nSol += nCur;
906  if (nSol > 1) {
907  throw std::runtime_error("Spline has more than one intersection"); //<<a<<"x^3 + "<<b<"x^2 + "<<c<"x + "<<d);
908  }
909  }
910 
911  if (nSol != 1)
912  throw std::runtime_error("Spline has no intersection"); //<<a<"x^3 + " <<b<"x^2 + "<<c<"x + "<<d<<"!");
913 
914  return sol;
915  }
916 
925  int monotonic(Scalar x0, Scalar x1,
926  [[maybe_unused]] bool extrapolate = false) const
927  {
928  assert(std::abs(x0 - x1) > 1e-30);
929 
930  // make sure that x0 is smaller than x1
931  if (x0 > x1)
932  std::swap(x0, x1);
933 
934  assert(x0 < x1);
935 
936  int r = 3;
937  if (x0 < xAt(0)) {
938  assert(extrapolate);
939  Scalar m = evalDerivative_(xAt(0), /*segmentIdx=*/0);
940  if (std::abs(m) < 1e-20)
941  r = (m < 0)?-1:1;
942  x0 = xAt(0);
943  };
944 
945  std::size_t i = segmentIdx_(x0);
946  if (x_(i + 1) >= x1) {
947  // interval is fully contained within a single spline
948  // segment
949  monotonic_(i, x0, x1, r);
950  return r;
951  }
952 
953  // the first segment overlaps with the specified interval
954  // partially
955  monotonic_(i, x0, x_(i+1), r);
956  ++ i;
957 
958  // make sure that the segments which are completly in the
959  // interval [x0, x1] all exhibit the same monotonicity.
960  std::size_t iEnd = segmentIdx_(x1);
961  for (; i < iEnd - 1; ++i) {
962  monotonic_(i, x_(i), x_(i + 1), r);
963  if (!r)
964  return 0;
965  }
966 
967  // if the user asked for a part of the spline which is
968  // extrapolated, we need to check the slope at the spline's
969  // endpoint
970  if (x1 > xAt(numSamples() - 1)) {
971  assert(extrapolate);
972 
973  Scalar m = evalDerivative_(xAt(numSamples() - 1), /*segmentIdx=*/numSamples() - 2);
974  if (m < 0)
975  return (r < 0 || r==3) ? -1 : 0;
976  else if (m > 0)
977  return r > 0 ? 1 : 0;
978 
979  return r;
980  }
981 
982  // check for the last segment
983  monotonic_(iEnd, x_(iEnd), x1, r);
984 
985  return r;
986  }
987 
992  int monotonic() const
993  { return monotonic(xAt(0), xAt(numSamples() - 1)); }
994 
995 protected:
1000  {
1001  explicit ComparatorX_(const std::vector<Scalar>& x)
1002  : x_(x)
1003  {}
1004 
1005  bool operator ()(unsigned idxA, unsigned idxB) const
1006  { return x_.at(idxA) < x_.at(idxB); }
1007 
1008  const std::vector<Scalar>& x_;
1009  };
1010 
1014  void sortInput_()
1015  {
1016  std::size_t n = numSamples();
1017 
1018  // create a vector containing 0...n-1
1019  std::vector<unsigned> idxVector(n);
1020  for (unsigned i = 0; i < n; ++i)
1021  idxVector[i] = i;
1022 
1023  // sort the indices according to the x values of the sample
1024  // points
1025  ComparatorX_ cmp(xPos_);
1026  std::ranges::sort(idxVector, cmp);
1027 
1028  // reorder the sample points
1029  std::vector<Scalar> tmpX(n), tmpY(n);
1030  for (std::size_t i = 0; i < idxVector.size(); ++ i) {
1031  tmpX[i] = xPos_[idxVector[i]];
1032  tmpY[i] = yPos_[idxVector[i]];
1033  }
1034  xPos_ = tmpX;
1035  yPos_ = tmpY;
1036  }
1037 
1043  {
1044  // reverse the arrays
1045  std::size_t n = numSamples();
1046  for (unsigned i = 0; i <= (n - 1)/2; ++i) {
1047  std::swap(xPos_[i], xPos_[n - i - 1]);
1048  std::swap(yPos_[i], yPos_[n - i - 1]);
1049  }
1050  }
1051 
1055  void setNumSamples_(std::size_t nSamples)
1056  {
1057  xPos_.resize(nSamples);
1058  yPos_.resize(nSamples);
1059  slopeVec_.resize(nSamples);
1060  }
1061 
1067  void makeFullSpline_(Scalar m0, Scalar m1)
1068  {
1069  Matrix M(numSamples());
1070  std::vector<Scalar> d(numSamples());
1071  std::vector<Scalar> moments(numSamples());
1072 
1073  // create linear system of equations
1074  this->makeFullSystem_(M, d, m0, m1);
1075 
1076  // solve for the moments (-> second derivatives)
1077  M.solve(moments, d);
1078 
1079  // convert the moments to slopes at the sample points
1080  this->setSlopesFromMoments_(slopeVec_, moments);
1081  }
1082 
1089  {
1090  Matrix M(numSamples(), numSamples());
1091  Vector d(numSamples());
1092  Vector moments(numSamples());
1093 
1094  // create linear system of equations
1095  this->makeNaturalSystem_(M, d);
1096 
1097  // solve for the moments (-> second derivatives)
1098  M.solve(moments, d);
1099 
1100  // convert the moments to slopes at the sample points
1101  this->setSlopesFromMoments_(slopeVec_, moments);
1102  }
1103 
1110  {
1111  Matrix M(numSamples() - 1);
1112  Vector d(numSamples() - 1);
1113  Vector moments(numSamples() - 1);
1114 
1115  // create linear system of equations. This is a bit hacky,
1116  // because it assumes that std::vector internally stores its
1117  // data as a big C-style array, but it saves us from yet
1118  // another copy operation
1119  this->makePeriodicSystem_(M, d);
1120 
1121  // solve for the moments (-> second derivatives)
1122  M.solve(moments, d);
1123 
1124  moments.resize(numSamples());
1125  for (int i = static_cast<int>(numSamples()) - 2; i >= 0; --i) {
1126  unsigned ui = static_cast<unsigned>(i);
1127  moments[ui+1] = moments[ui];
1128  }
1129  moments[0] = moments[numSamples() - 1];
1130 
1131  // convert the moments to slopes at the sample points
1132  this->setSlopesFromMoments_(slopeVec_, moments);
1133  }
1134 
1141  template <class DestVector, class SourceVector>
1142  void assignSamplingPoints_(DestVector& destX,
1143  DestVector& destY,
1144  const SourceVector& srcX,
1145  const SourceVector& srcY,
1146  unsigned nSamples)
1147  {
1148  assert(nSamples >= 2);
1149 
1150  // copy sample points, make sure that the first x value is
1151  // smaller than the last one
1152  for (unsigned i = 0; i < nSamples; ++i) {
1153  unsigned idx = i;
1154  if (srcX[0] > srcX[nSamples - 1])
1155  idx = nSamples - i - 1;
1156  destX[i] = srcX[idx];
1157  destY[i] = srcY[idx];
1158  }
1159  }
1160 
1161  template <class DestVector, class ListIterator>
1162  void assignFromArrayList_(DestVector& destX,
1163  DestVector& destY,
1164  const ListIterator& srcBegin,
1165  const ListIterator& srcEnd,
1166  unsigned nSamples)
1167  {
1168  assert(nSamples >= 2);
1169 
1170  // find out wether the x values are in reverse order
1171  ListIterator it = srcBegin;
1172  ++it;
1173  bool reverse = false;
1174  if ((*srcBegin)[0] > (*it)[0])
1175  reverse = true;
1176  --it;
1177 
1178  // loop over all sampling points
1179  for (unsigned i = 0; it != srcEnd; ++i, ++it) {
1180  unsigned idx = i;
1181  if (reverse)
1182  idx = nSamples - i - 1;
1183  destX[idx] = (*it)[0];
1184  destY[idx] = (*it)[1];
1185  }
1186  }
1187 
1195  template <class DestVector, class ListIterator>
1196  void assignFromTupleList_(DestVector& destX,
1197  DestVector& destY,
1198  ListIterator srcBegin,
1199  ListIterator srcEnd,
1200  unsigned nSamples)
1201  {
1202  assert(nSamples >= 2);
1203 
1204  // copy sample points, make sure that the first x value is
1205  // smaller than the last one
1206 
1207  // find out wether the x values are in reverse order
1208  ListIterator it = srcBegin;
1209  ++it;
1210  bool reverse = false;
1211  if (std::get<0>(*srcBegin) > std::get<0>(*it))
1212  reverse = true;
1213  --it;
1214 
1215  // loop over all sampling points
1216  for (unsigned i = 0; it != srcEnd; ++i, ++it) {
1217  unsigned idx = i;
1218  if (reverse)
1219  idx = nSamples - i - 1;
1220  destX[idx] = std::get<0>(*it);
1221  destY[idx] = std::get<1>(*it);
1222  }
1223  }
1224 
1229  template <class Vector, class Matrix>
1230  void makeFullSystem_(Matrix& M, Vector& d, Scalar m0, Scalar m1)
1231  {
1232  makeNaturalSystem_(M, d);
1233 
1234  std::size_t n = numSamples() - 1;
1235  // first row
1236  M[0][1] = 1;
1237  d[0] = 6/h_(1) * ( (y_(1) - y_(0))/h_(1) - m0);
1238 
1239  // last row
1240  M[n][n - 1] = 1;
1241 
1242  // right hand side
1243  d[n] =
1244  6/h_(n)
1245  *
1246  (m1 - (y_(n) - y_(n - 1))/h_(n));
1247  }
1248 
1253  template <class Vector, class Matrix>
1254  void makeNaturalSystem_(Matrix& M, Vector& d)
1255  {
1256  M = 0.0;
1257 
1258  // See: J. Stoer: "Numerische Mathematik 1", 9th edition,
1259  // Springer, 2005, p. 111
1260  std::size_t n = numSamples() - 1;
1261 
1262  // second to next to last rows
1263  for (std::size_t i = 1; i < n; ++i) {
1264  Scalar lambda_i = h_(i + 1) / (h_(i) + h_(i + 1));
1265  Scalar mu_i = 1 - lambda_i;
1266  Scalar d_i =
1267  6 / (h_(i) + h_(i + 1))
1268  *
1269  ( (y_(i + 1) - y_(i))/h_(i + 1) - (y_(i) - y_(i - 1))/h_(i));
1270 
1271  M[i][i-1] = mu_i;
1272  M[i][i] = 2;
1273  M[i][i + 1] = lambda_i;
1274  d[i] = d_i;
1275  };
1276 
1277  // See Stroer, equation (2.5.2.7)
1278  Scalar lambda_0 = 0;
1279  Scalar d_0 = 0;
1280 
1281  Scalar mu_n = 0;
1282  Scalar d_n = 0;
1283 
1284  // first row
1285  M[0][0] = 2;
1286  M[0][1] = lambda_0;
1287  d[0] = d_0;
1288 
1289  // last row
1290  M[n][n-1] = mu_n;
1291  M[n][n] = 2;
1292  d[n] = d_n;
1293  }
1294 
1299  template <class Matrix, class Vector>
1300  void makePeriodicSystem_(Matrix& M, Vector& d)
1301  {
1302  M = 0.0;
1303 
1304  // See: J. Stoer: "Numerische Mathematik 1", 9th edition,
1305  // Springer, 2005, p. 111
1306  std::size_t n = numSamples() - 1;
1307 
1308  assert(M.rows() == n);
1309 
1310  // second to next to last rows
1311  for (std::size_t i = 2; i < n; ++i) {
1312  Scalar lambda_i = h_(i + 1) / (h_(i) + h_(i + 1));
1313  Scalar mu_i = 1 - lambda_i;
1314  Scalar d_i =
1315  6 / (h_(i) + h_(i + 1))
1316  *
1317  ( (y_(i + 1) - y_(i))/h_(i + 1) - (y_(i) - y_(i - 1))/h_(i));
1318 
1319  M[i-1][i-2] = mu_i;
1320  M[i-1][i-1] = 2;
1321  M[i-1][i] = lambda_i;
1322  d[i-1] = d_i;
1323  };
1324 
1325  Scalar lambda_n = h_(1) / (h_(n) + h_(1));
1326  Scalar lambda_1 = h_(2) / (h_(1) + h_(2));;
1327  Scalar mu_1 = 1 - lambda_1;
1328  Scalar mu_n = 1 - lambda_n;
1329 
1330  Scalar d_1 =
1331  6 / (h_(1) + h_(2))
1332  *
1333  ( (y_(2) - y_(1))/h_(2) - (y_(1) - y_(0))/h_(1));
1334  Scalar d_n =
1335  6 / (h_(n) + h_(1))
1336  *
1337  ( (y_(1) - y_(n))/h_(1) - (y_(n) - y_(n-1))/h_(n));
1338 
1339  // first row
1340  M[0][0] = 2;
1341  M[0][1] = lambda_1;
1342  M[0][n-1] = mu_1;
1343  d[0] = d_1;
1344 
1345  // last row
1346  M[n-1][0] = lambda_n;
1347  M[n-1][n-2] = mu_n;
1348  M[n-1][n-1] = 2;
1349  d[n-1] = d_n;
1350  }
1351 
1360  template <class Vector>
1361  void makeMonotonicSpline_(Vector& slopes)
1362  {
1363  auto n = numSamples();
1364 
1365  // calculate the slopes of the secant lines
1366  std::vector<Scalar> delta(n);
1367  for (std::size_t k = 0; k < n - 1; ++k)
1368  delta[k] = (y_(k + 1) - y_(k))/(x_(k + 1) - x_(k));
1369 
1370  // calculate the "raw" slopes at the sample points
1371  for (std::size_t k = 1; k < n - 1; ++k)
1372  slopes[k] = (delta[k - 1] + delta[k])/2;
1373  slopes[0] = delta[0];
1374  slopes[n - 1] = delta[n - 2];
1375 
1376  // post-process the "raw" slopes at the sample points
1377  for (std::size_t k = 0; k < n - 1; ++k) {
1378  if (std::abs(delta[k]) < 1e-50) {
1379  // make the spline flat if the inputs are equal
1380  slopes[k] = 0;
1381  slopes[k + 1] = 0;
1382  ++ k;
1383  continue;
1384  }
1385  else {
1386  Scalar alpha = slopes[k] / delta[k];
1387  Scalar beta = slopes[k + 1] / delta[k];
1388 
1389  if (alpha < 0 || (k > 0 && slopes[k] / delta[k - 1] < 0)) {
1390  slopes[k] = 0;
1391  }
1392  // limit (alpha, beta) to a circle of radius 3
1393  else if (alpha*alpha + beta*beta > 3*3) {
1394  Scalar tau = 3.0/std::sqrt(alpha*alpha + beta*beta);
1395  slopes[k] = tau*alpha*delta[k];
1396  slopes[k + 1] = tau*beta*delta[k];
1397  }
1398  }
1399  }
1400  }
1401 
1409  template <class MomentsVector, class SlopeVector>
1410  void setSlopesFromMoments_(SlopeVector& slopes, const MomentsVector& moments)
1411  {
1412  std::size_t n = numSamples();
1413 
1414  // evaluate slope at the rightmost point.
1415  // See: J. Stoer: "Numerische Mathematik 1", 9th edition,
1416  // Springer, 2005, p. 109
1417  Scalar mRight;
1418 
1419  {
1420  Scalar h = this->h_(n - 1);
1421  Scalar x = h;
1422  //Scalar x_1 = 0;
1423 
1424  Scalar A =
1425  (y_(n - 1) - y_(n - 2))/h
1426  -
1427  h/6*(moments[n-1] - moments[n - 2]);
1428 
1429  mRight =
1430  //- moments[n - 2] * x_1*x_1 / (2 * h)
1431  //+
1432  moments[n - 1] * x*x / (2 * h)
1433  +
1434  A;
1435  }
1436 
1437  // evaluate the slope for the first n-1 sample points
1438  for (std::size_t i = 0; i < n - 1; ++ i) {
1439  // See: J. Stoer: "Numerische Mathematik 1", 9th edition,
1440  // Springer, 2005, p. 109
1441  Scalar h_i = this->h_(i + 1);
1442  //Scalar x_i = 0;
1443  Scalar x_i1 = h_i;
1444 
1445  Scalar A_i =
1446  (y_(i+1) - y_(i))/h_i
1447  -
1448  h_i/6*(moments[i+1] - moments[i]);
1449 
1450  slopes[i] =
1451  - moments[i] * x_i1*x_i1 / (2 * h_i)
1452  +
1453  //moments[i + 1] * x_i*x_i / (2 * h_i)
1454  //+
1455  A_i;
1456 
1457  }
1458  slopes[n - 1] = mRight;
1459  }
1460 
1461  // evaluate the spline at a given the position and given the
1462  // segment index
1463  template <class Evaluation>
1464  Evaluation eval_(const Evaluation& x, std::size_t i) const
1465  {
1466  // See http://en.wikipedia.org/wiki/Cubic_Hermite_spline
1467  Scalar delta = h_(i + 1);
1468  Evaluation t = (x - x_(i))/delta;
1469 
1470  return
1471  h00_(t) * y_(i)
1472  + h10_(t) * slope_(i)*delta
1473  + h01_(t) * y_(i + 1)
1474  + h11_(t) * slope_(i + 1)*delta;
1475  }
1476 
1477  // evaluate the derivative of a spline given the actual position
1478  // and the segment index
1479  template <class Evaluation>
1480  Evaluation evalDerivative_(const Evaluation& x, std::size_t i) const
1481  {
1482  // See http://en.wikipedia.org/wiki/Cubic_Hermite_spline
1483  Scalar delta = h_(i + 1);
1484  Evaluation t = (x - x_(i))/delta;
1485  Evaluation alpha = 1 / delta;
1486 
1487  return
1488  alpha *
1489  (h00_prime_(t) * y_(i)
1490  + h10_prime_(t) * slope_(i)*delta
1491  + h01_prime_(t) * y_(i + 1)
1492  + h11_prime_(t) * slope_(i + 1)*delta);
1493  }
1494 
1495  // evaluate the second derivative of a spline given the actual
1496  // position and the segment index
1497  template <class Evaluation>
1498  Evaluation evalDerivative2_(const Evaluation& x, std::size_t i) const
1499  {
1500  // See http://en.wikipedia.org/wiki/Cubic_Hermite_spline
1501  Scalar delta = h_(i + 1);
1502  Evaluation t = (x - x_(i))/delta;
1503  Evaluation alpha = 1 / delta;
1504 
1505  return
1506  alpha*alpha
1507  *(h00_prime2_(t) * y_(i)
1508  + h10_prime2_(t) * slope_(i)*delta
1509  + h01_prime2_(t) * y_(i + 1)
1510  + h11_prime2_(t) * slope_(i + 1)*delta);
1511  }
1512 
1513  // evaluate the third derivative of a spline given the actual
1514  // position and the segment index
1515  template <class Evaluation>
1516  Evaluation evalDerivative3_(const Evaluation& x, std::size_t i) const
1517  {
1518  // See http://en.wikipedia.org/wiki/Cubic_Hermite_spline
1519  Scalar delta = h_(i + 1);
1520  Evaluation t = (x - x_(i))/delta;
1521  Evaluation alpha = 1 / delta;
1522 
1523  return
1524  alpha*alpha*alpha
1525  *(h00_prime3_(t)*y_(i)
1526  + h10_prime3_(t)*slope_(i)*delta
1527  + h01_prime3_(t)*y_(i + 1)
1528  + h11_prime3_(t)*slope_(i + 1)*delta);
1529  }
1530 
1531  // hermite basis functions
1532  template <class Evaluation>
1533  Evaluation h00_(const Evaluation& t) const
1534  { return (2*t - 3)*t*t + 1; }
1535 
1536  template <class Evaluation>
1537  Evaluation h10_(const Evaluation& t) const
1538  { return ((t - 2)*t + 1)*t; }
1539 
1540  template <class Evaluation>
1541  Evaluation h01_(const Evaluation& t) const
1542  { return (-2*t + 3)*t*t; }
1543 
1544  template <class Evaluation>
1545  Evaluation h11_(const Evaluation& t) const
1546  { return (t - 1)*t*t; }
1547 
1548  // first derivative of the hermite basis functions
1549  template <class Evaluation>
1550  Evaluation h00_prime_(const Evaluation& t) const
1551  { return (3*2*t - 2*3)*t; }
1552 
1553  template <class Evaluation>
1554  Evaluation h10_prime_(const Evaluation& t) const
1555  { return (3*t - 2*2)*t + 1; }
1556 
1557  template <class Evaluation>
1558  Evaluation h01_prime_(const Evaluation& t) const
1559  { return (-3*2*t + 2*3)*t; }
1560 
1561  template <class Evaluation>
1562  Evaluation h11_prime_(const Evaluation& t) const
1563  { return (3*t - 2)*t; }
1564 
1565  // second derivative of the hermite basis functions
1566  template <class Evaluation>
1567  Evaluation h00_prime2_(const Evaluation& t) const
1568  { return 2*3*2*t - 2*3; }
1569 
1570  template <class Evaluation>
1571  Evaluation h10_prime2_(const Evaluation& t) const
1572  { return 2*3*t - 2*2; }
1573 
1574  template <class Evaluation>
1575  Evaluation h01_prime2_(const Evaluation& t) const
1576  { return -2*3*2*t + 2*3; }
1577 
1578  template <class Evaluation>
1579  Evaluation h11_prime2_(const Evaluation& t) const
1580  { return 2*3*t - 2; }
1581 
1582  // third derivative of the hermite basis functions
1583  template <class Evaluation>
1584  Scalar h00_prime3_(const Evaluation&) const
1585  { return 2*3*2; }
1586 
1587  template <class Evaluation>
1588  Scalar h10_prime3_(const Evaluation&) const
1589  { return 2*3; }
1590 
1591  template <class Evaluation>
1592  Scalar h01_prime3_(const Evaluation&) const
1593  { return -2*3*2; }
1594 
1595  template <class Evaluation>
1596  Scalar h11_prime3_(const Evaluation&) const
1597  { return 2*3; }
1598 
1599  // returns the monotonicality of an interval of a spline segment
1600  //
1601  // The return value have the following meaning:
1602  //
1603  // 3: spline is constant within interval [x0, x1]
1604  // 1: spline is monotonously increasing in the specified interval
1605  // 0: spline is not monotonic (or constant) in the specified interval
1606  // -1: spline is monotonously decreasing in the specified interval
1607  int monotonic_(std::size_t i, Scalar x0, Scalar x1, int& r) const
1608  {
1609  // coefficients of derivative in monomial basis
1610  Scalar a = 3*a_(i);
1611  Scalar b = 2*b_(i);
1612  Scalar c = c_(i);
1613 
1614  if (std::abs(a) < 1e-20 && std::abs(b) < 1e-20 && std::abs(c) < 1e-20)
1615  return 3; // constant in interval, r stays unchanged!
1616 
1617  Scalar disc = b*b - 4*a*c;
1618  if (disc < 0) {
1619  // discriminant of derivative is smaller than 0, i.e. the
1620  // segment's derivative does not exhibit any extrema.
1621  if (x0*(x0*a + b) + c > 0) {
1622  r = (r==3 || r == 1)?1:0;
1623  return 1;
1624  }
1625  else {
1626  r = (r==3 || r == -1)?-1:0;
1627  return -1;
1628  }
1629  }
1630  disc = std::sqrt(disc);
1631  Scalar xE1 = (-b + disc)/(2*a);
1632  Scalar xE2 = (-b - disc)/(2*a);
1633 
1634  if (std::abs(disc) < 1e-30) {
1635  // saddle point -> no extrema
1636  if (std::abs(xE1 - x0) < 1e-30)
1637  // make sure that we're not picking the saddle point
1638  // to determine whether we're monotonically increasing
1639  // or decreasing
1640  x0 = x1;
1641  if (x0*(x0*a + b) + c > 0) {
1642  r = (r==3 || r == 1)?1:0;
1643  return 1;
1644  }
1645  else {
1646  r = (r==3 || r == -1)?-1:0;
1647  return -1;
1648  }
1649  };
1650  if ((x0 < xE1 && xE1 < x1) ||
1651  (x0 < xE2 && xE2 < x1))
1652  {
1653  // there is an extremum in the range (x0, x1)
1654  r = 0;
1655  return 0;
1656  }
1657  // no extremum in range (x0, x1)
1658  x0 = (x0 + x1)/2; // pick point in the middle of the interval
1659  // to avoid extrema on the boundaries
1660  if (x0*(x0*a + b) + c > 0) {
1661  r = (r==3 || r == 1)?1:0;
1662  return 1;
1663  }
1664  else {
1665  r = (r==3 || r == -1)?-1:0;
1666  return -1;
1667  }
1668  }
1669 
1674  template <class Evaluation>
1675  std::size_t intersectSegment_(Evaluation* sol,
1676  std::size_t segIdx,
1677  const Evaluation& a,
1678  const Evaluation& b,
1679  const Evaluation& c,
1680  const Evaluation& d,
1681  Scalar x0 = -1e30, Scalar x1 = 1e30) const
1682  {
1683  unsigned n =
1685  a_(segIdx) - a,
1686  b_(segIdx) - b,
1687  c_(segIdx) - c,
1688  d_(segIdx) - d);
1689  x0 = std::max(x_(segIdx), x0);
1690  x1 = std::min(x_(segIdx+1), x1);
1691 
1692  // filter the intersections outside of the specified interval
1693  std::size_t k = 0;
1694  for (unsigned j = 0; j < n; ++j) {
1695  if (x0 <= sol[j] && sol[j] <= x1) {
1696  sol[k] = sol[j];
1697  ++k;
1698  }
1699  }
1700  return k;
1701  }
1702 
1703  // find the segment index for a given x coordinate
1704  std::size_t segmentIdx_(Scalar x) const
1705  {
1706  // bisection
1707  std::size_t iLow = 0;
1708  std::size_t iHigh = numSamples() - 1;
1709 
1710  while (iLow + 1 < iHigh) {
1711  std::size_t i = (iLow + iHigh) / 2;
1712  if (x_(i) > x)
1713  iHigh = i;
1714  else
1715  iLow = i;
1716  };
1717  return iLow;
1718  }
1719 
1723  Scalar h_(std::size_t i) const
1724  {
1725  assert(x_(i) > x_(i-1)); // the sampling points must be given
1726  // in ascending order
1727  return x_(i) - x_(i - 1);
1728  }
1729 
1733  Scalar x_(std::size_t i) const
1734  { return xPos_[i]; }
1735 
1739  Scalar y_(std::size_t i) const
1740  { return yPos_[i]; }
1741 
1746  Scalar slope_(std::size_t i) const
1747  { return slopeVec_[i]; }
1748 
1749  // returns the coefficient in front of the x^3 term. In Stoer this
1750  // is delta.
1751  Scalar a_(std::size_t i) const
1752  { return evalDerivative3_(/*x=*/Scalar(0.0), i)/6.0; }
1753 
1754  // returns the coefficient in front of the x^2 term In Stoer this
1755  // is gamma.
1756  Scalar b_(std::size_t i) const
1757  { return evalDerivative2_(/*x=*/Scalar(0.0), i)/2.0; }
1758 
1759  // returns the coefficient in front of the x^1 term. In Stoer this
1760  // is beta.
1761  Scalar c_(std::size_t i) const
1762  { return evalDerivative_(/*x=*/Scalar(0.0), i); }
1763 
1764  // returns the coefficient in front of the x^0 term. In Stoer this
1765  // is alpha.
1766  Scalar d_(std::size_t i) const
1767  { return eval_(/*x=*/Scalar(0.0), i); }
1768 
1769  Vector xPos_;
1770  Vector yPos_;
1771  Vector slopeVec_;
1772 };
1773 }
1774 
1775 #endif
Scalar xAt(std::size_t sampleIdx) const
Return the x value of a given sampling point.
Definition: Spline.hpp:727
Definition: Exceptions.hpp:39
void assignSamplingPoints_(DestVector &destX, DestVector &destY, const SourceVector &srcX, const SourceVector &srcY, unsigned nSamples)
Set the sampling point vectors.
Definition: Spline.hpp:1142
Scalar y_(std::size_t i) const
Returns the y coordinate of the i-th sampling point.
Definition: Spline.hpp:1739
void setXYArrays(std::size_t nSamples, const ScalarArrayX &x, const ScalarArrayY &y, SplineType splineType=Natural, bool sortInputs=true)
Set the sampling points natural spline using C-style arrays.
Definition: Spline.hpp:514
Scalar h_(std::size_t i) const
Returns x[i] - x[i - 1].
Definition: Spline.hpp:1723
void makeMonotonicSpline_(Vector &slopes)
Create a monotonic spline from the already set sampling points.
Definition: Spline.hpp:1361
Evaluation evalDerivative(const Evaluation &x, bool extrapolate=false) const
Evaluate the spline&#39;s derivative at a given position.
Definition: Spline.hpp:803
void sortInput_()
Sort the sample points in ascending order of their x value.
Definition: Spline.hpp:1014
SplineType
The type of the spline to be created.
Definition: Spline.hpp:102
Helper class needed to sort the input sampling points.
Definition: Spline.hpp:999
void makeFullSpline_(Scalar m0, Scalar m1)
Create a natural spline from the already set sampling points.
Definition: Spline.hpp:1067
Scalar slope_(std::size_t i) const
Returns the slope (i.e.
Definition: Spline.hpp:1746
Spline()
Default constructor for a spline.
Definition: Spline.hpp:114
Evaluation evalThirdDerivative(const Evaluation &x, bool extrapolate=false) const
Evaluate the spline&#39;s third derivative at a given position.
Definition: Spline.hpp:855
Provides free functions to invert polynomials of degree 1, 2 and 3.
void setXYContainers(const ScalarContainerX &x, const ScalarContainerY &y, Scalar m0, Scalar m1, bool sortInputs=true)
Set the sampling points and the boundary slopes of a full spline using STL-compatible containers...
Definition: Spline.hpp:360
Provides the OPM specific exception classes.
void setArrayOfPoints(std::size_t nSamples, const PointArray &points, SplineType splineType=Natural, bool sortInputs=true)
Set the sampling points of a natural spline using a C-style array.
Definition: Spline.hpp:595
std::size_t numSamples() const
Return the number of (x, y) values.
Definition: Spline.hpp:721
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
Spline(std::size_t nSamples, const PointArray &points, SplineType splineType=Natural, bool sortInputs=true)
Convenience constructor for a natural or a periodic spline.
Definition: Spline.hpp:158
int monotonic() const
Same as monotonic(x0, x1), but with the entire range of the spline as interval.
Definition: Spline.hpp:992
int monotonic(Scalar x0, Scalar x1, [[maybe_unused]] bool extrapolate=false) const
Returns 1 if the spline is monotonically increasing, -1 if the spline is mononously decreasing and 0 ...
Definition: Spline.hpp:925
Spline(const PointContainer &points, SplineType splineType=Natural, bool sortInputs=true)
Convenience constructor for a natural or a periodic spline.
Definition: Spline.hpp:187
void setNumSamples_(std::size_t nSamples)
Resizes the internal vectors to store the sample points.
Definition: Spline.hpp:1055
bool applies(const Evaluation &x) const
Return true iff the given x is in range [x1, xn].
Definition: Spline.hpp:715
void reverseSamplingPoints_()
Reverse order of the elements in the arrays which contain the sampling points.
Definition: Spline.hpp:1042
Spline(const ScalarContainer &x, const ScalarContainer &y, SplineType splineType=Natural, bool sortInputs=true)
Convenience constructor for a natural or a periodic spline.
Definition: Spline.hpp:173
Scalar x_(std::size_t i) const
Returns the y coordinate of the i-th sampling point.
Definition: Spline.hpp:1733
Evaluation intersectInterval(Scalar x0, Scalar x1, const Evaluation &a, const Evaluation &b, const Evaluation &c, const Evaluation &d) const
Find the intersections of the spline with a cubic polynomial in a sub-interval of the spline...
Definition: Spline.hpp:887
void setArrayOfPoints(std::size_t nSamples, const PointArray &points, Scalar m0, Scalar m1, bool sortInputs=true)
Set the sampling points and the boundary slopes of a full spline using a C-style array.
Definition: Spline.hpp:394
Evaluation evalSecondDerivative(const Evaluation &x, bool extrapolate=false) const
Evaluate the spline&#39;s second derivative at a given position.
Definition: Spline.hpp:832
void setXYContainers(const ScalarContainerX &x, const ScalarContainerY &y, SplineType splineType=Natural, bool sortInputs=true)
Set the sampling points of a natural spline using STL-compatible containers.
Definition: Spline.hpp:555
Spline(std::size_t nSamples, const ScalarArray &x, const ScalarArray &y, Scalar m0, Scalar m1, bool sortInputs=true)
Convenience constructor for a full spline.
Definition: Spline.hpp:203
Provides a tridiagonal matrix that also supports non-zero entries in the upper right and lower left...
std::size_t intersectSegment_(Evaluation *sol, std::size_t segIdx, const Evaluation &a, const Evaluation &b, const Evaluation &c, const Evaluation &d, Scalar x0=-1e30, Scalar x1=1e30) const
Find all the intersections of a segment of the spline with a cubic polynomial within a specified inte...
Definition: Spline.hpp:1675
void setContainerOfPoints(const XYContainer &points, SplineType splineType=Natural, bool sortInputs=true)
Set the sampling points of a natural spline using a STL-compatible container of array-like objects...
Definition: Spline.hpp:637
void makePeriodicSpline_()
Create a periodic spline from the already set sampling points.
Definition: Spline.hpp:1109
Scalar valueAt(std::size_t sampleIdx) const
Return the x value of a given sampling point.
Definition: Spline.hpp:733
unsigned invertCubicPolynomial(SolContainer *sol, Scalar a, Scalar b, Scalar c, Scalar d)
Invert a cubic polynomial analytically.
Definition: PolynomialUtils.hpp:149
Evaluation eval(const Evaluation &x, bool extrapolate=false) const
Evaluate the spline at a given position.
Definition: Spline.hpp:767
Provides a tridiagonal matrix that also supports non-zero entries in the upper right and lower left...
Definition: TridiagonalMatrix.hpp:50
void setXYArrays(std::size_t nSamples, const ScalarArrayX &x, const ScalarArrayY &y, Scalar m0, Scalar m1, bool sortInputs=true)
Set the sampling points and the boundary slopes of a full spline using C-style arrays.
Definition: Spline.hpp:326
Spline(const PointContainer &points, Scalar m0, Scalar m1, bool sortInputs=true)
Convenience constructor for a full spline.
Definition: Spline.hpp:254
Spline(const ScalarContainerX &x, const ScalarContainerY &y, Scalar m0, Scalar m1, bool sortInputs=true)
Convenience constructor for a full spline.
Definition: Spline.hpp:238
Spline(Scalar x0, Scalar x1, Scalar y0, Scalar y1, Scalar m0, Scalar m1)
Convenience constructor for a full spline with just two sampling points.
Definition: Spline.hpp:127
void makeFullSystem_(Matrix &M, Vector &d, Scalar m0, Scalar m1)
Make the linear system of equations Mx = d which results in the moments of the full spline...
Definition: Spline.hpp:1230
Spline(std::size_t nSamples, const PointArray &points, Scalar m0, Scalar m1, bool sortInputs=true)
Convenience constructor for a full spline.
Definition: Spline.hpp:221
void printCSV(Scalar xi0, Scalar xi1, std::size_t k, std::ostream &os) const
Prints k tuples of the format (x, y, dx/dy, isMonotonic) to stdout.
Definition: Spline.cpp:35
void setContainerOfTuples(const XYContainer &points, Scalar m0, Scalar m1, bool sortInputs=true)
Set the sampling points and the boundary slopes of a full spline using a STL-compatible container of ...
Definition: Spline.hpp:473
void setContainerOfTuples(const XYContainer &points, SplineType splineType=Natural, bool sortInputs=true)
Set the sampling points of a natural spline using a STL-compatible container of tuple-like objects...
Definition: Spline.hpp:683
Evaluation intersect(const Evaluation &a, const Evaluation &b, const Evaluation &c, const Evaluation &d) const
Find the intersections of the spline with a cubic polynomial in the whole interval, throws Opm::MathError exception if there is more or less than one solution.
Definition: Spline.hpp:872
void assignFromTupleList_(DestVector &destX, DestVector &destY, ListIterator srcBegin, ListIterator srcEnd, unsigned nSamples)
Set the sampling points.
Definition: Spline.hpp:1196
void makePeriodicSystem_(Matrix &M, Vector &d)
Make the linear system of equations Mx = d which results in the moments of the periodic spline...
Definition: Spline.hpp:1300
void makeNaturalSpline_()
Create a natural spline from the already set sampling points.
Definition: Spline.hpp:1088
Class implementing cubic splines.
Definition: Spline.hpp:91
void setSlopesFromMoments_(SlopeVector &slopes, const MomentsVector &moments)
Convert the moments at the sample points to slopes.
Definition: Spline.hpp:1410
void setContainerOfPoints(const XYContainer &points, Scalar m0, Scalar m1, bool sortInputs=true)
Set the sampling points and the boundary slopes of a full spline using a STL-compatible container of ...
Definition: Spline.hpp:431
Spline(std::size_t nSamples, const ScalarArrayX &x, const ScalarArrayY &y, SplineType splineType=Natural, bool sortInputs=true)
Convenience constructor for a natural or a periodic spline.
Definition: Spline.hpp:142
void makeNaturalSystem_(Matrix &M, Vector &d)
Make the linear system of equations Mx = d which results in the moments of the natural spline...
Definition: Spline.hpp:1254