OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
LinearSpline.cpp
Go to the documentation of this file.
1//
2// Linear Spline Interpolation to replace GSL spline
3//
4// Copyright (c) 2023, Paul Scherrer Institute, Villigen PSI, Switzerland
5// All rights reserved
6//
7// This file is part of OPAL.
8//
9// OPAL is free software: you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation, either version 3 of the License, or
12// (at your option) any later version.
13//
14// You should have received a copy of the GNU General License
15// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
16//
17
18#include "LinearSpline.h"
19#include <stdexcept>
20
21LinearSpline::LinearSpline(const std::vector<double>& x, const std::vector<double>& y) {
23}
24
25void LinearSpline::init(const std::vector<double>& x, const std::vector<double>& y) {
26 // Base class handles the x and y points
28 // The gradients of each interval
30 // And the integrals over each interval
32}
33
34double LinearSpline::eval(const double x, Accelerator& accel) const {
35 double result{};
36 if (x_.empty()) {
37 throw std::runtime_error("LinearSpline: not initialized");
38 }
39 if (x <= x_.front()) {
40 result = extrapolateLeft(x);
41 } else if (x >= x_.back()) {
42 result = extrapolateRight(x);
43 } else {
44 const size_t i = findInterval(x, accel.last_index_);
45 result = m_[i] * x + c_[i];
46 }
47 return result;
48}
49
50double LinearSpline::evalIntegral(double xa, double xb, Accelerator& accel) const {
51 double result{};
52 // Verify parameters
53 if (x_.empty()) {
54 throw std::runtime_error("LinearSpline: not initialized");
55 }
56 if (xb < xa) {
57 std::swap(xa, xb);
58 }
59 // Linear extrapolation below the defined intervals
60 if (xa < x_.front()) {
61 const auto y = extrapolateLeft(xa);
62 const auto dx = x_.front() - xa;
63 const auto dy = y_.front() - y;
64 result += dx * y_.front() - dx * dy / 2.0;
65 xa = x_.front();
66 }
67 // Linear extrapolation above the defined intervals
68 if (xb > x_.back()) {
69 const auto y = extrapolateRight(xb);
70 const auto dx = xb - x_.back();
71 const auto dy = y - y_.back();
72 result += dx * y_.back() + dx * dy / 2.0;
73 xb = x_.back();
74 }
75 // Find the intervals
76 const size_t ia = findInterval(xa, accel.last_index_);
77 const size_t ib = findInterval(xb, accel.last_upper_index_);
78 // The first partial interval
79 result -= integral(ia, xa - x_[ia]);
80 // All the full interval integrals
81 for (size_t m = ia; m < ib; ++m) {
82 result += integrals_[m];
83 }
84 // The last partial interval
85 result += integral(ib, xb - x_[ib]);
86 return result;
87}
88
90 m_.resize(x_.size() - 1);
91 c_.resize(x_.size() - 1);
92 for (size_t i = 0; i < x_.size() - 1; ++i) {
93 m_[i] = (y_[i + 1] - y_[i]) / (x_[i + 1] - x_[i]);
94 c_[i] = y_[i] - m_[i] * x_[i];
95 }
96}
97
99 integrals_.resize(x_.size() - 1);
100 for (size_t i = 0; i < x_.size() - 1; ++i) {
101 integrals_[i] = integral(i, x_[i + 1] - x_[i]);
102 }
103}
104
105double LinearSpline::integral(const size_t i, const double dx) const {
106 const auto x2 = x_[i] + dx;
107 return m_[i] * (x2 * x2 - x_[i] * x_[i]) / 2.0 + c_[i] * (x2 - x_[i]);
108}
109
110double LinearSpline::extrapolateLeft(const double x) const { return m_.front() * x + c_.front(); }
111
112double LinearSpline::extrapolateRight(const double x) const { return m_.back() * x + c_.back(); }
Accelerator caching last interval indices.
virtual void init(const std::vector< double > &x, const std::vector< double > &y)
Initialize from tabulated data (natural spline).
size_t findInterval(double x, size_t &intervalCache) const
Return the interval index for the given x-coordinate, using the supplied cached value if possible.
std::vector< double > x_
std::vector< double > y_
std::vector< double > integrals_
LinearSpline()=default
Default constructor.
std::vector< double > m_
double evalIntegral(double xa, double xb, Accelerator &accel) const override
Evaluate the integral of the spline at x.
double extrapolateRight(double x) const
Linear extrapolation to the right of the data range.
double extrapolateLeft(double x) const
Linear extrapolation to the left of the data range.
void computeCoefficients()
Compute linear spline coefficients.
std::vector< double > c_
double integral(size_t i, double dx) const
Calculate the integral from x_[i] to x_[i]+dx.
void computeIntegrals()
Compute the integrals of the intervals.
void init(const std::vector< double > &x, const std::vector< double > &y) override
Initialize from tabulated data (natural spline).
double eval(double x, Accelerator &accel) const override
Evaluate the spline at x using an accelerator.