GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/common/splinecommon_.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 165 186 88.7%
Functions: 27 30 90.0%
Branches: 273 480 56.9%

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 The common code for all 3rd order polynomial splines.
11 */
12 #ifndef DUMUX_SPLINE_COMMON__HH
13 #define DUMUX_SPLINE_COMMON__HH
14
15 #include <algorithm>
16 #include <iostream>
17 #include <cassert>
18
19 #include <dune/common/exceptions.hh>
20 #include <dune/common/float_cmp.hh>
21
22 #include "math.hh"
23
24 namespace Dumux {
25
26 /*!
27 * \ingroup Core
28 * \brief The common code for all 3rd order polynomial splines.
29 */
30 template<class ScalarT, class ImplementationT>
31 class SplineCommon_
32 {
33 using Scalar = ScalarT;
34 using Implementation = ImplementationT;
35
36 Implementation &asImp_()
37 { return *static_cast<Implementation*>(this); }
38 const Implementation &asImp_() const
39 { return *static_cast<const Implementation*>(this); }
40
41 public:
42 /*!
43 * \brief Return true if the given x is in range [x1, xn].
44 */
45 bool applies(Scalar x) const
46 {
47 123016155 return x_(0) <= x && x <= x_(numSamples_() - 1);
48 }
49
50 /*!
51 * \brief Return the x value of the leftmost sampling point.
52 */
53 Scalar xMin() const
54 8 { return x_(0); }
55
56 /*!
57 * \brief Return the x value of the rightmost sampling point.
58 */
59 Scalar xMax() const
60 9 { return x_(numSamples_() - 1); }
61
62 /*!
63 * \brief Prints k tuples of the format (x, y, dx/dy, isMonotonic)
64 * to stdout.
65 *
66 * If the spline does not apply for parts of [x0, x1] it is
67 * extrapolated using a straight line. The result can be inspected
68 * using the following commands:
69 *
70 ----------- snip -----------
71 ./yourProgramm > spline.csv
72 gnuplot
73
74 gnuplot> plot "spline.csv" using 1:2 w l ti "Curve", \
75 "spline.csv" using 1:3 w l ti "Derivative", \
76 "spline.csv" using 1:4 w p ti "Monotonic"
77 ----------- snap -----------
78 */
79 2 void printCSV(Scalar xi0, Scalar xi1, int k) const
80 {
81 using std::max;
82 using std::min;
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 Scalar x0 = min(xi0, xi1);
84
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 Scalar x1 = max(xi0, xi1);
85 4 const int n = numSamples_() - 1;
86
2/2
✓ Branch 0 taken 2002 times.
✓ Branch 1 taken 2 times.
2004 for (int i = 0; i <= k; ++i) {
87 2002 double x = i*(x1 - x0)/k + x0;
88 2002 double x_p1 = x + (x1 - x0)/k;
89 double y;
90 double dy_dx;
91 2002 double mono = 1;
92 3964 if (!applies(x)) {
93
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (x < 0) {
94 60 dy_dx = evalDerivative(x_(0));
95 60 y = (x - x_(0))*dy_dx + y_(0);
96 20 mono = (dy_dx>0)?1:-1;
97 }
98 40 else if (x > x_(n)) {
99 60 dy_dx = evalDerivative(x_(n));
100 60 y = (x - x_(n))*dy_dx + y_(n);
101 20 mono = (dy_dx>0)?1:-1;
102 }
103 else {
104 std::cerr << "ooops: " << x << "\n";
105 exit(1);
106 }
107 }
108 else {
109 1962 y = eval(x);
110 1962 dy_dx = evalDerivative(x);
111 1962 mono = monotonic(max<Scalar>(x_(0), x), min<Scalar>(x_(n), x_p1));
112 }
113
114 8008 std::cout << x << " " << y << " " << dy_dx << " " << mono << "\n";
115 }
116 2 }
117
118 /*!
119 * \brief Evaluate the spline at a given position.
120 *
121 * \param x The value on the abscissa where the spline ought to be
122 * evaluated
123 * \param extrapolate If this parameter is set to true, the spline
124 * will be extended beyond its range by
125 * straight lines, if false calling extrapolate
126 * for \f$ x \not [x_{min}, x_{max}]\f$ will
127 * cause a failed assertion.
128 */
129 23092768 Scalar eval(Scalar x, bool extrapolate=false) const
130 {
131
2/2
✓ Branch 0 taken 23090568 times.
✓ Branch 1 taken 2 times.
23092768 assert(extrapolate || applies(x));
132
133 // handle extrapolation
134
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23090568 times.
23092768 if (extrapolate) {
135 8 if (x < xMin()) {
136 6 Scalar m = evalDerivative_(xMin(), /*segmentIdx=*/0);
137 4 Scalar y0 = y_(0);
138 4 return y0 + m*(x - xMin());
139 }
140 4 else if (x > xMax()) {
141 8 Scalar m = evalDerivative_(xMax(), /*segmentIdx=*/numSamples_()-2);
142 6 Scalar y0 = y_(numSamples_()-1);
143 4 return y0 + m*(x - xMax());
144 }
145 }
146
147 46181160 return eval_(x, segmentIdx_(x));
148 }
149
150 /*!
151 * \brief Evaluate the spline's derivative at a given position.
152 *
153 * \param x The value on the abscissa where the spline's
154 * derivative ought to be evaluated
155 *
156 * \param extrapolate If this parameter is set to true, the spline
157 * will be extended beyond its range by
158 * straight lines, if false calling extrapolate
159 * for \f$ x \not [x_{min}, x_{max}]\f$ will
160 * cause a failed assertion.
161
162 */
163 1397488 Scalar evalDerivative(Scalar x, bool extrapolate=false) const
164 {
165
1/2
✓ Branch 0 taken 1395197 times.
✗ Branch 1 not taken.
1397488 assert(extrapolate || applies(x));
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1395197 times.
1397488 if (extrapolate) {
167 if (Dune::FloatCmp::le(x, xMin()))
168 return evalDerivative_(xMin(), 0);
169 else if (Dune::FloatCmp::ge(x, xMax()))
170 return evalDerivative_(xMax(), numSamples_() - 2);
171 }
172
173 2790430 return evalDerivative_(x, segmentIdx_(x));
174 }
175
176 /*!
177 * \brief Find the intersections of the spline with a cubic
178 * polynomial in the whole interval, throws
179 * Dune::MathError exception if there is more or less than
180 * one solution.
181 */
182 Scalar intersect(Scalar a, Scalar b, Scalar c, Scalar d) const
183 {
184 return intersectInterval(xMin(), xMax(), a, b, c, d);
185 }
186
187 /*!
188 * \brief Find the intersections of the spline with a cubic
189 * polynomial in a sub-interval of the spline, throws
190 * Dune::MathError exception if there is more or less than
191 * one solution.
192 */
193 55775 Scalar intersectInterval(Scalar x0, Scalar x1,
194 Scalar a, Scalar b, Scalar c, Scalar d) const
195 {
196 assert(applies(x0) && applies(x1));
197
198 Scalar tmpSol[3];
199 int nSol = 0;
200 int iFirst = segmentIdx_(x0);
201 int iLast = segmentIdx_(x1);
202
2/2
✓ Branch 0 taken 55775 times.
✓ Branch 1 taken 55775 times.
111550 for (int i = iFirst; i <= iLast; ++i)
203 {
204 55775 nSol += intersectSegment_(tmpSol, i, a, b, c, d, x0, x1);
205
206
1/2
✓ Branch 0 taken 55775 times.
✗ Branch 1 not taken.
55775 if (nSol > 1) {
207 DUNE_THROW(Dune::MathError,
208 "Spline has more than one intersection"); //<<a<<"x^3 + "<<b<"x^2 + "<<c<"x + "<<d);
209 }
210 }
211
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55775 times.
55775 if (nSol != 1)
213 DUNE_THROW(Dune::MathError,
214 "Spline has no intersection"); //<<a<"x^3 + " <<b<"x^2 + "<<c<"x + "<<d<<"!");
215
216 55775 return tmpSol[0];
217 }
218
219 /*!
220 * \brief Returns 1 if the spline is monotonically increasing, -1
221 * if the spline is monotonously decreasing and 0 if the
222 * spline is not monotonous in the interval (x0, x1).
223 *
224 * In the corner case where the whole spline is flat, it returns
225 * 2.
226 */
227 1963 int monotonic(Scalar x0, Scalar x1) const
228 {
229 assert(applies(x0));
230 assert(applies(x1));
231
2/4
✓ Branch 0 taken 1963 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1963 times.
3926 assert(Dune::FloatCmp::ne<Scalar>(x0, x1));
232
233 // make sure that x0 is smaller than x1
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1963 times.
1963 if (x0 > x1)
235 {
236 using std::swap;
237 swap(x0, x1);
238 }
239
240 // corner case where the whole spline is a constant
241 6870 if (Dune::FloatCmp::eq<Scalar>(moment_(0), 0) &&
242
3/4
✓ Branch 0 taken 981 times.
✓ Branch 1 taken 982 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 981 times.
1963 Dune::FloatCmp::eq<Scalar>(moment_(1), 0) &&
243 Dune::FloatCmp::eq<Scalar>(y_(0), y_(1)))
244 {
245 // actually the is monotonically increasing as well as
246 // monotonously decreasing
247 return 2;
248 }
249
250
251 1963 int i = segmentIdx_(x0);
252 7852 if (x_(i) <= x0 && x1 <= x_(i+1)) {
253 // the interval to check is completely included in a
254 // single segment
255 1956 return monotonic_(i, x0, x1);
256 }
257
258 // make sure that the segments which are completely in the
259 // interval [x0, x1] all exhibit the same monotonicity.
260 7 int iEnd = segmentIdx_(x1);
261 14 int r = monotonic_(i, x0, x_(1));
262
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
9 for (; i < iEnd - 1; ++i)
263
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (r != monotonic_(i, x_(i), x_(i + 1)))
264 return 0;
265
266 // check for the last segment
267
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (x_(iEnd) < x1 && r != monotonic_(iEnd, x_(iEnd), x1))
268 2 { return 0; }
269
270 return r;
271 }
272
273 /*!
274 * \brief Same as monotonic(x0, x1), but with the entire range of the
275 * spline as interval.
276 */
277 int monotonic() const
278 { return monotonic(xMin(), xMax()); }
279
280 protected:
281 // this is an internal class, so everything is protected!
282 SplineCommon_() = default;
283
284 /*!
285 * \brief Set the sampling point vectors.
286 *
287 * This takes care that the order of the x-values is ascending,
288 * although the input must be ordered already!
289 */
290 template <class DestVector, class SourceVector>
291 void assignSamplingPoints_(DestVector &destX,
292 DestVector &destY,
293 const SourceVector &srcX,
294 const SourceVector &srcY,
295 int numSamples)
296 {
297 assert(numSamples >= 2);
298
299 // copy sample points, make sure that the first x value is
300 // smaller than the last one
301 bool reverse = (srcX[0] > srcX[numSamples - 1]);
302
303 for (int i = 0; i < numSamples; ++i) {
304 int idx = i;
305 if (reverse)
306 idx = numSamples - i - 1;
307 destX[i] = srcX[idx];
308 destY[i] = srcY[idx];
309 }
310 }
311
312 /*!
313 * \brief Set the sampling point vectors.
314 *
315 * This takes care that the order of the x-values is ascending,
316 * although the input must be ordered already!
317 */
318 template <class DestVector, class ListIterator>
319 void assignFromArrayList_(DestVector &destX,
320 DestVector &destY,
321 const ListIterator &srcBegin,
322 const ListIterator &srcEnd,
323 int numSamples)
324 {
325 assert(numSamples >= 2);
326
327 // find out whether the x values are in reverse order
328 ListIterator it = srcBegin;
329 ++it;
330 bool reverse = ((*srcBegin)[0] > (*it)[0]);
331 --it;
332
333 // loop over all sampling points
334 for (int i = 0; it != srcEnd; ++i, ++it) {
335 int idx = i;
336 if (reverse)
337 idx = numSamples - i - 1;
338 destX[idx] = (*it)[0];
339 destY[idx] = (*it)[1];
340 }
341 }
342
343 /*!
344 * \brief Set the sampling points.
345 *
346 * Here we assume that the elements of the source vector have an
347 * [] operator where v[0] is the x value and v[1] is the y value
348 * if the sampling point.
349 */
350 template <class DestVector, class ListIterator>
351 void assignFromTupleList_(DestVector &destX,
352 DestVector &destY,
353 ListIterator srcBegin,
354 ListIterator srcEnd,
355 int numSamples)
356 {
357 assert(numSamples >= 2);
358
359 // copy sample points, make sure that the first x value is
360 // smaller than the last one
361
362 // find out whether the x values are in reverse order
363 ListIterator it = srcBegin;
364 ++it;
365 bool reverse = (std::get<0>(*srcBegin) > std::get<0>(*it));
366 --it;
367
368 // loop over all sampling points
369 for (int i = 0; it != srcEnd; ++i, ++it) {
370 int idx = i;
371 if (reverse)
372 idx = numSamples - i - 1;
373 destX[idx] = std::get<0>(*it);
374 destY[idx] = std::get<1>(*it);
375 }
376 }
377
378
379 /*!
380 * \brief Make the linear system of equations Mx = d which results
381 * in the moments of the periodic spline.
382 *
383 * When solving Mx = d, it should be noted that x[0] is trash and
384 * needs to be set to x[n-1]
385 */
386 template <class Vector, class Matrix>
387 void makePeriodicSystem_(Matrix &M, Vector &d)
388 {
389 // a periodic spline only makes sense if the first and the
390 // last sampling point have the same y value
391 assert(y_(0) == y_(numSamples_() - 1));
392
393 makeNaturalSystem(M, d);
394
395 int n = numSamples_() - 1;
396
397 Scalar lambda_n = h_(1)/(h_(n) + h_(1));
398 Scalar lambda_1 = M[1][2];
399 Scalar mu_1 = 1 - lambda_1;
400 Scalar mu_n = 1 - lambda_n;
401
402 Scalar d_n =
403 6 / (h_(n) + h_(1))
404 *
405 ( (y_(1) - y_(n))/h_(1) - (y_(n) - y_(n-1))/h_(n));
406
407 // insert lambda_n and mu_1
408 M[1][n] = mu_1;
409 M[n][1] = lambda_n;
410 M[n][n-1] = mu_n;
411 d[n] = d_n;
412 }
413
414 /*!
415 * \brief Make the linear system of equations Mx = d which results
416 * in the moments of the full spline.
417 */
418 template <class Vector, class Matrix>
419 90666 void makeFullSystem_(Matrix &M, Vector &d, Scalar m0, Scalar m1)
420 {
421 181306 makeNaturalSystem_(M, d);
422
423 181332 int n = numSamples_() - 1;
424 // first row
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90640 times.
90666 M[0][1] = 1;
426 543926 d[0] = 6/h_(1) * ( (y_(1) - y_(0))/h_(1) - m0);
427
428 // last row
429
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 90634 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 90634 times.
181320 M[n][n - 1] = 1;
430
431 // right hand side
432 181346 d[n] =
433 181318 6/h_(n)
434 90666 *
435 362650 (m1 - (y_(n) - y_(n - 1))/h_(n));
436 90666 }
437
438 /*!
439 * \brief Make the linear system of equations Mx = d which results
440 * in the moments of the natural spline.
441 * Stoer2005: Numerische Mathematik 1, p. 111 \cite stoer2005
442 */
443 template <class Vector, class Matrix>
444 52 void makeNaturalSystem_(Matrix &M, Vector &d)
445 {
446 90686 M = 0;
447 90686 d = 0;
448
449 181328 const int n = numSamples_() - 1;
450
451 // second to next to last rows
452
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 26 times.
90842 for (int i = 1; i < n; ++i) {
453 354 const Scalar lambda_i = h_(i + 1) / (h_(i) + h_(i+1));
454 156 const Scalar mu_i = 1 - lambda_i;
455 156 const Scalar d_i =
456 288 6 / (h_(i) + h_(i+1))
457 156 *
458 912 ( (y_(i+1) - y_(i))/h_(i+1) - (y_(i) - y_(i-1))/h_(i));
459
460 156 M[i][i-1] = mu_i;
461 312 M[i][i] = 2;
462 312 M[i][i + 1] = lambda_i;
463 468 d[i] = d_i;
464 }
465
466 // first row
467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90634 times.
90686 M[0][0] = 2;
468
469 // last row
470
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 90634 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90634 times.
181350 M[n][n] = 2;
471 // right hand side
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90634 times.
90738 d[0] = 0.0;
473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90634 times.
90768 d[n] = 0.0;
474 52 }
475
476 // evaluate the spline at a given the position and given the
477 // segment index
478 23092764 Scalar eval_(Scalar x, int i) const
479 {
480 // See: Stoer2005 "Numerische Mathematik 1", 9th edition,
481 // Springer, 2005, p. 109
482 46185266 Scalar h_i1 = h_(i + 1);
483 46185528 Scalar x_i = x - x_(i);
484 46185528 Scalar x_i1 = x_(i+1) - x;
485
486 23092764 Scalar A_i =
487 69278292 (y_(i+1) - y_(i))/h_i1
488 -
489 69278292 h_i1/6*(moment_(i+1) - moment_(i));
490 69278292 Scalar B_i = y_(i) - moment_(i)* (h_i1*h_i1) / 6;
491
492 return
493 46185528 moment_(i)* x_i1*x_i1*x_i1 / (6 * h_i1)
494 23092764 +
495 46185528 moment_(i + 1)* x_i*x_i*x_i / (6 * h_i1)
496 23092764 +
497 23092764 A_i*x_i
498 +
499 23092764 B_i;
500 }
501
502 // evaluate the derivative of a spline given the actual position
503 // and the segment index
504 1397492 Scalar evalDerivative_(Scalar x, int i) const
505 {
506 // See: Stoer2005 "Numerische Mathematik 1", 9th edition,
507 // Springer, 2005, p. 109
508 2794660 Scalar h_i1 = h_(i + 1);
509 2794984 Scalar x_i = x - x_(i);
510 2794984 Scalar x_i1 = x_(i+1) - x;
511
512 1397492 Scalar A_i =
513 4192476 (y_(i+1) - y_(i))/h_i1
514 -
515 4192476 h_i1/6*(moment_(i+1) - moment_(i));
516
517 return
518 2794984 -moment_(i) * x_i1*x_i1 / (2 * h_i1)
519 1397492 +
520 2794984 moment_(i + 1) * x_i*x_i / (2 * h_i1)
521 +
522 1397492 A_i;
523 }
524
525
526 // returns the monotonicality of an interval of a spline segment
527 //
528 // The return value have the following meaning:
529 //
530 // 1: spline is monotonously increasing in the specified interval
531 // 0: spline is not monotonic in the specified interval
532 // -1: spline is monotonously decreasing in the specified interval
533 1972 int monotonic_(int i, Scalar x0, Scalar x1) const
534 {
535 // shift the interval so that it is consistent with the
536 // definitions by Stoer2005
537 3944 x0 = x0 - x_(i);
538 3944 x1 = x1 - x_(i);
539
540 3944 Scalar a = a_(i);
541 3944 Scalar b = b_(i);
542 3944 Scalar c = c_(i);
543
544 1972 Scalar disc = 4*b*b - 12*a*c;
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1972 times.
1972 if (disc < 0) {
546 // discriminant is smaller than 0, i.e. the segment does
547 // not exhibit any extrema.
548 return (x0*(x0*3*a + 2*b) + c > 0) ? 1 : -1;
549 }
550 using std::sqrt;
551 1972 disc = sqrt(disc);
552 1972 Scalar xE1 = (-2*b + disc)/(6*a);
553 1972 Scalar xE2 = (-2*b - disc)/(6*a);
554
555
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1972 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1972 times.
3944 if (Dune::FloatCmp::eq<Scalar>(disc, 0)) {
556 // saddle point -> no extrema
557 if (Dune::FloatCmp::eq<Scalar>(xE1, x0))
558 // make sure that we're not picking the saddle point
559 // to determine whether we're monotonically increasing
560 // or decreasing
561 x0 = x1;
562 return sign(x0*(x0*3*a + 2*b) + c);
563 }
564
6/6
✓ Branch 0 taken 1042 times.
✓ Branch 1 taken 930 times.
✓ Branch 2 taken 1036 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 631 times.
✓ Branch 5 taken 1335 times.
1972 if ((x0 < xE1 && xE1 < x1) ||
565
2/2
✓ Branch 0 taken 625 times.
✓ Branch 1 taken 6 times.
631 (x0 < xE2 && xE2 < x1))
566 {
567 // there is an extremum in the range (x0, x1)
568 return 0;
569 }
570 // no extremum in range (x0, x1)
571 1960 x0 = (x0 + x1)/2; // pick point in the middle of the interval
572 // to avoid extrema on the boundaries
573 1960 return sign(x0*(x0*3*a + 2*b) + c);
574 }
575
576 /*!
577 * \brief Find all the intersections of a segment of the spline
578 * with a cubic polynomial within a specified interval.
579 */
580 55775 int intersectSegment_(Scalar *sol,
581 int segIdx,
582 Scalar a, Scalar b, Scalar c, Scalar d,
583 Scalar x0 = -1e100, Scalar x1 = 1e100) const
584 {
585 55775 int n = invertCubicPolynomial(sol,
586 55775 a_(segIdx) - a,
587 111550 b_(segIdx) - b,
588 55775 c_(segIdx) - c,
589 111550 d_(segIdx) - d);
590 using std::max;
591 167325 x0 = max(x_(segIdx), x0);
592 167325 x1 = max(x_(segIdx+1), x1);
593
594 // filter the intersections outside of the specified interval
595 55775 int k = 0;
596
2/2
✓ Branch 0 taken 128821 times.
✓ Branch 1 taken 55775 times.
184596 for (int j = 0; j < n; ++j) {
597 257642 sol[j] += x_(segIdx); // add the offset of the interval. For details see Stoer2005
598
1/2
✓ Branch 0 taken 55775 times.
✗ Branch 1 not taken.
55775 if (x0 <= sol[j] && sol[j] <= x1) {
599 55775 sol[k] = sol[j];
600 55775 ++k;
601 }
602 }
603 55775 return k;
604 }
605
606 // find the segment index for a given x coordinate
607 int segmentIdx_(Scalar x) const
608 {
609 // bisection
610 24483712 int iLow = 0;
611 48967424 int iHigh = numSamples_() - 1;
612
613
12/12
✓ Branch 0 taken 4106 times.
✓ Branch 1 taken 2053 times.
✓ Branch 2 taken 320 times.
✓ Branch 3 taken 160 times.
✓ Branch 4 taken 4226 times.
✓ Branch 5 taken 2113 times.
✓ Branch 6 taken 3926 times.
✓ Branch 7 taken 1963 times.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 7 times.
✓ Branch 10 taken 262 times.
✓ Branch 11 taken 131 times.
24500559 while (iLow + 1 < iHigh) {
614 12854 int i = (iLow + iHigh) / 2;
615 25708 if (x_(i) > x)
616 iHigh = i;
617 else
618 iLow = i;
619 }
620 return iLow;
621 }
622
623 /*!
624 * \brief Returns x[i] - x[i - 1]
625 */
626 397 Scalar h_(int i) const
627 {
628 assert(x_(i) > x_(i-1)); // the sampling points must be given
629 // in ascending order
630 75065709 return x_(i) - x_(i - 1);
631 }
632
633 /*!
634 * \brief Returns the y coordinate of the i-th sampling point.
635 */
636 Scalar x_(int i) const
637
161/260
✗ Branch 0 not taken.
✓ Branch 1 taken 2121 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2121 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2121 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4081 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4081 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 4081 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4081 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 4162 times.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 4156 times.
✓ Branch 18 taken 6 times.
✓ Branch 19 taken 4156 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 90661 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 90661 times.
✓ Branch 24 taken 1191442 times.
✓ Branch 25 taken 19863633 times.
✓ Branch 26 taken 1191442 times.
✓ Branch 27 taken 19863633 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 21055075 times.
✓ Branch 30 taken 155768 times.
✓ Branch 31 taken 144327 times.
✓ Branch 32 taken 155768 times.
✓ Branch 33 taken 144327 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 300095 times.
✓ Branch 36 taken 19563538 times.
✓ Branch 37 taken 144294 times.
✓ Branch 38 taken 19563538 times.
✓ Branch 39 taken 144294 times.
✓ Branch 40 taken 55769 times.
✓ Branch 41 taken 19725109 times.
✓ Branch 42 taken 55769 times.
✓ Branch 43 taken 161571 times.
✓ Branch 44 taken 162 times.
✓ Branch 45 taken 2132658 times.
✓ Branch 46 taken 201450 times.
✓ Branch 47 taken 2132658 times.
✓ Branch 48 taken 201294 times.
✓ Branch 49 taken 2132814 times.
✓ Branch 50 taken 201294 times.
✓ Branch 51 taken 201288 times.
✓ Branch 52 taken 6 times.
✓ Branch 53 taken 201288 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 6 times.
✓ Branch 56 taken 257077 times.
✓ Branch 57 taken 89889 times.
✓ Branch 58 taken 57902 times.
✓ Branch 59 taken 89889 times.
✓ Branch 60 taken 1204185 times.
✓ Branch 61 taken 89909 times.
✓ Branch 62 taken 1204185 times.
✗ Branch 63 not taken.
✓ Branch 64 taken 1202078 times.
✗ Branch 65 not taken.
✓ Branch 66 taken 1191448 times.
✓ Branch 67 taken 55769 times.
✓ Branch 68 taken 3413995 times.
✗ Branch 69 not taken.
✓ Branch 70 taken 3413989 times.
✗ Branch 71 not taken.
✓ Branch 72 taken 216 times.
✓ Branch 73 taken 2222547 times.
✓ Branch 74 taken 216 times.
✗ Branch 75 not taken.
✓ Branch 76 taken 222 times.
✗ Branch 77 not taken.
✓ Branch 78 taken 182 times.
✗ Branch 79 not taken.
✓ Branch 80 taken 182 times.
✗ Branch 81 not taken.
✓ Branch 82 taken 194 times.
✓ Branch 83 taken 1146519 times.
✓ Branch 84 taken 18 times.
✓ Branch 85 taken 1146519 times.
✓ Branch 86 taken 18 times.
✓ Branch 87 taken 12 times.
✓ Branch 88 taken 1146519 times.
✓ Branch 89 taken 12 times.
✗ Branch 90 not taken.
✗ Branch 91 not taken.
✓ Branch 92 taken 12 times.
✗ Branch 93 not taken.
✗ Branch 94 not taken.
✗ Branch 95 not taken.
✗ Branch 96 not taken.
✗ Branch 97 not taken.
✗ Branch 99 not taken.
✗ Branch 100 not taken.
✗ Branch 102 not taken.
✓ Branch 103 taken 397 times.
✗ Branch 104 not taken.
✓ Branch 105 taken 397 times.
✗ Branch 106 not taken.
✓ Branch 107 taken 397 times.
✓ Branch 111 taken 2053 times.
✗ Branch 112 not taken.
✓ Branch 113 taken 2053 times.
✗ Branch 114 not taken.
✗ Branch 115 not taken.
✓ Branch 116 taken 2053 times.
✗ Branch 117 not taken.
✗ Branch 118 not taken.
✗ Branch 119 not taken.
✗ Branch 120 not taken.
✗ Branch 123 not taken.
✗ Branch 124 not taken.
✓ Branch 126 taken 1146 times.
✓ Branch 127 taken 2960 times.
✓ Branch 128 taken 1146 times.
✓ Branch 129 taken 2960 times.
✓ Branch 130 taken 160 times.
✗ Branch 131 not taken.
✓ Branch 132 taken 160 times.
✗ Branch 133 not taken.
✗ Branch 134 not taken.
✓ Branch 135 taken 160 times.
✗ Branch 136 not taken.
✗ Branch 137 not taken.
✗ Branch 138 not taken.
✗ Branch 139 not taken.
✗ Branch 140 not taken.
✗ Branch 141 not taken.
✓ Branch 145 taken 170 times.
✓ Branch 146 taken 150 times.
✓ Branch 147 taken 170 times.
✓ Branch 148 taken 150 times.
✓ Branch 149 taken 2113 times.
✗ Branch 150 not taken.
✓ Branch 151 taken 2113 times.
✗ Branch 152 not taken.
✗ Branch 153 not taken.
✓ Branch 154 taken 2113 times.
✗ Branch 155 not taken.
✗ Branch 156 not taken.
✗ Branch 157 not taken.
✗ Branch 158 not taken.
✗ Branch 159 not taken.
✗ Branch 160 not taken.
✓ Branch 164 taken 1206 times.
✓ Branch 165 taken 3020 times.
✓ Branch 166 taken 1206 times.
✓ Branch 167 taken 3020 times.
✓ Branch 168 taken 18 times.
✗ Branch 169 not taken.
✓ Branch 170 taken 18 times.
✗ Branch 171 not taken.
✗ Branch 172 not taken.
✓ Branch 173 taken 18 times.
✗ Branch 174 not taken.
✗ Branch 175 not taken.
✗ Branch 176 not taken.
✗ Branch 177 not taken.
✗ Branch 178 not taken.
✗ Branch 179 not taken.
✗ Branch 183 not taken.
✓ Branch 184 taken 6 times.
✗ Branch 185 not taken.
✓ Branch 186 taken 6 times.
✗ Branch 187 not taken.
✓ Branch 188 taken 6 times.
✗ Branch 189 not taken.
✓ Branch 190 taken 6 times.
✗ Branch 191 not taken.
✓ Branch 192 taken 6 times.
✗ Branch 193 not taken.
✓ Branch 194 taken 6 times.
✗ Branch 195 not taken.
✓ Branch 196 taken 6 times.
✗ Branch 197 not taken.
✓ Branch 198 taken 6 times.
✗ Branch 199 not taken.
✓ Branch 200 taken 6 times.
✗ Branch 201 not taken.
✓ Branch 202 taken 6 times.
✗ Branch 203 not taken.
✓ Branch 204 taken 6 times.
✗ Branch 205 not taken.
✓ Branch 206 taken 6 times.
✓ Branch 207 taken 1963 times.
✗ Branch 208 not taken.
✓ Branch 209 taken 1963 times.
✗ Branch 210 not taken.
✓ Branch 211 taken 1963 times.
✗ Branch 212 not taken.
✓ Branch 213 taken 1963 times.
✗ Branch 214 not taken.
✓ Branch 215 taken 1963 times.
✗ Branch 216 not taken.
✓ Branch 217 taken 1963 times.
✗ Branch 218 not taken.
✓ Branch 219 taken 1048 times.
✓ Branch 220 taken 2878 times.
✓ Branch 221 taken 1048 times.
✓ Branch 222 taken 2878 times.
✓ Branch 223 taken 1963 times.
✗ Branch 224 not taken.
✓ Branch 225 taken 1963 times.
✗ Branch 226 not taken.
✓ Branch 227 taken 1956 times.
✓ Branch 228 taken 7 times.
✓ Branch 229 taken 1956 times.
✓ Branch 230 taken 7 times.
✓ Branch 231 taken 10 times.
✓ Branch 232 taken 4 times.
✓ Branch 233 taken 10 times.
✓ Branch 234 taken 4 times.
✓ Branch 240 taken 7 times.
✗ Branch 241 not taken.
✓ Branch 242 taken 7 times.
✗ Branch 243 not taken.
✓ Branch 246 taken 1982 times.
✓ Branch 247 taken 20 times.
✓ Branch 248 taken 1982 times.
✓ Branch 249 taken 20 times.
✓ Branch 250 taken 1962 times.
✓ Branch 251 taken 20 times.
✓ Branch 252 taken 1960 times.
✓ Branch 253 taken 2 times.
✓ Branch 254 taken 1960 times.
✓ Branch 255 taken 2 times.
✓ Branch 258 taken 10 times.
✓ Branch 259 taken 10 times.
✓ Branch 260 taken 20 times.
✗ Branch 261 not taken.
✓ Branch 262 taken 20 times.
✗ Branch 263 not taken.
✓ Branch 266 taken 10 times.
✓ Branch 267 taken 10 times.
✓ Branch 268 taken 1962 times.
✗ Branch 269 not taken.
✓ Branch 270 taken 1962 times.
✗ Branch 271 not taken.
✓ Branch 272 taken 131 times.
✗ Branch 273 not taken.
✓ Branch 274 taken 131 times.
✗ Branch 275 not taken.
✗ Branch 276 not taken.
✓ Branch 277 taken 131 times.
✓ Branch 278 taken 1 times.
✓ Branch 279 taken 1 times.
✓ Branch 280 taken 1 times.
✓ Branch 281 taken 1 times.
✓ Branch 284 taken 1 times.
✗ Branch 285 not taken.
✓ Branch 287 taken 141 times.
✓ Branch 288 taken 121 times.
✓ Branch 289 taken 141 times.
✓ Branch 290 taken 121 times.
123464334 { return asImp_().x_(i); }
638
639 /*!
640 * \brief Returns the y coordinate of the i-th sampling point.
641 */
642 Scalar y_(int i) const
643
14/26
✗ Branch 0 not taken.
✓ Branch 1 taken 90628 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90628 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 90628 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 6 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 6 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 6 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 10 times.
✓ Branch 30 taken 10 times.
✓ Branch 31 taken 10 times.
✓ Branch 32 taken 10 times.
✓ Branch 33 taken 10 times.
✓ Branch 34 taken 10 times.
✓ Branch 35 taken 10 times.
✓ Branch 36 taken 10 times.
272446 { return asImp_().y_(i); }
644
645 /*!
646 * \brief Returns the moment (i.e. second derivative) of the
647 * spline at the i-th sampling point.
648 */
649 Scalar moment_(int i) const
650
6/8
✓ Branch 0 taken 981 times.
✓ Branch 1 taken 982 times.
✓ Branch 2 taken 981 times.
✓ Branch 3 taken 982 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 981 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 981 times.
242588644 { return asImp_().moment_(i); }
651
652 // returns the coefficient in front of the x^0 term. In Stoer2005 this
653 // is delta.
654 57747 Scalar a_(int i) const
655
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 57747 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57747 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57747 times.
173241 { return (moment_(i+1) - moment_(i))/(6*h_(i+1)); }
656
657 // returns the coefficient in front of the x^2 term In Stoer2005 this
658 // is gamma.
659 Scalar b_(int i) const
660 115494 { return moment_(i)/2; }
661
662 // returns the coefficient in front of the x^1 term. In Stoer2005 this
663 // is beta.
664 57747 Scalar c_(int i) const
665
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 57747 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57747 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57747 times.
173241 { return (y_(i+1) - y_(i))/h_(i + 1) - h_(i+1)/6*(2*moment_(i) + moment_(i+1)); }
666
667 // returns the coefficient in front of the x^0 term. In Stoer2005 this
668 // is alpha.
669 Scalar d_(int i) const
670 111550 { return y_(i); }
671
672 /*!
673 * \brief Returns the number of sampling points.
674 */
675 int numSamples_() const
676
22/48
✗ Branch 0 not taken.
✓ Branch 1 taken 90628 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90628 times.
✓ Branch 4 taken 55787 times.
✓ Branch 5 taken 20910904 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 55775 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2222567 times.
✓ Branch 10 taken 2053 times.
✓ Branch 11 taken 201288 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1146679 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 160 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 2113 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✓ Branch 31 taken 18 times.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 36 not taken.
✓ Branch 37 taken 6 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 6 times.
✓ Branch 40 taken 1963 times.
✗ Branch 41 not taken.
✓ Branch 42 taken 1963 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 1962 times.
✓ Branch 45 taken 20 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 131 times.
✗ Branch 48 not taken.
✓ Branch 49 taken 131 times.
✓ Branch 50 taken 1 times.
✗ Branch 51 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
49268839 { return asImp_().numSamples(); }
677 };
678
679 } // end namespace Dumux
680
681 #endif
682