48#include "math/CubicSpline.hpp"
58 CubicSpline::CubicSpline() : isUniform(true), generated(false) {
63 void CubicSpline::addPoint(
const RealType xp,
const RealType yp) {
68 void CubicSpline::addPoints(
const std::vector<RealType>& xps,
69 const std::vector<RealType>& yps) {
70 assert(xps.size() == yps.size());
72 for (
unsigned int i = 0; i < xps.size(); i++) {
78 void CubicSpline::generate() {
104 for (
int i = 1; i < n; i++) {
105 if ((x_[i] - x_[i - 1]) <= 0.0) sorted =
false;
111 std::vector<int> p = sort_permutation(x_);
112 x_ = apply_permutation(x_, p);
113 y_ = apply_permutation(y_, p);
119 b[0] = x_[1] - x_[0];
120 c[0] = (y_[1] - y_[0]) / b[0];
129 c[0] = -3.0 * pow((y_[1] - y_[0]) / (x_[1] - x_[0]), 2);
130 d[0] = -2.0 * pow((y_[1] - y_[0]) / (x_[1] - x_[0]), 3);
134 dx = 1.0 / (x_[1] - x_[0]);
142 for (
int i = 1; i < n - 1; i++) {
143 b[i] = x_[i + 1] - x_[i];
144 if (fabs(b[i] - b[0]) / b[0] > 1.0e-5) isUniform =
false;
145 c[i] = (y_[i + 1] - y_[i]) / b[i];
146 d[i] = 2.0 * (b[i] + b[i - 1]);
149 d[n - 1] = 2.0 * b[n - 2];
154 fp1 = c[0] - b[0] * (c[1] - c[0]) / (b[0] + b[1]);
158 ((b[0] + b[1]) * (c[2] - c[1]) / (b[1] + b[2]) - c[1] + c[0]) /
161 fpn = c[n - 2] + b[n - 2] * (c[n - 2] - c[n - 3]) / (b[n - 3] + b[n - 2]);
164 fpn = fpn + b[n - 2] *
165 (c[n - 2] - c[n - 3] -
166 (b[n - 3] + b[n - 2]) * (c[n - 3] - c[n - 4]) /
167 (b[n - 3] + b[n - 4])) /
168 (x_[n - 1] - x_[n - 4]);
172 c[n - 1] = 3.0 * (fpn - c[n - 2]);
173 for (
int i = n - 2; i > 0; i--)
174 c[i] = 3.0 * (c[i] - c[i - 1]);
175 c[0] = 3.0 * (c[0] - fp1);
179 for (
int k = 1; k < n; k++) {
180 p = b[k - 1] / d[k - 1];
181 d[k] = d[k] - p * b[k - 1];
182 c[k] = c[k] - p * c[k - 1];
185 c[n - 1] = c[n - 1] / d[n - 1];
187 for (
int k = n - 2; k >= 0; k--)
188 c[k] = (c[k] - b[k] * c[k + 1]) / d[k];
192 for (
int i = 0; i < n - 1; i++) {
193 h = x_[i + 1] - x_[i];
194 d[i] = (c[i + 1] - c[i]) / (3.0 * h);
195 b[i] = (y_[i + 1] - y_[i]) / h - h * (c[i] + h * d[i]);
198 b[n - 1] = b[n - 2] + h * (2.0 * c[n - 2] + h * 3.0 * d[n - 2]);
200 if (isUniform) dx = 1.0 / (x_[1] - x_[0]);
206 RealType CubicSpline::getValueAt(
const RealType& t) {
207 if (!generated) generate();
214 j = int((t - x_[0]) * dx);
217 for (
int i = 0; i < n; i++) {
225 j = std::clamp(j, 0, n - 1);
228 return y_[j] + dt * (b[j] + dt * (c[j] + dt * d[j]));
231 void CubicSpline::getValueAt(
const RealType& t, RealType& v) {
232 if (!generated) generate();
239 j = int((t - x_[0]) * dx);
242 for (
int i = 0; i < n; i++) {
250 j = std::clamp(j, 0, n - 1);
253 v = y_[j] + dt * (b[j] + dt * (c[j] + dt * d[j]));
256 std::pair<RealType, RealType> CubicSpline::getLimits() {
257 if (!generated) generate();
258 return make_pair(x_.front(), x_.back());
261 RealType CubicSpline::getSpacing() {
262 if (!generated) generate();
270 void CubicSpline::getValueAndDerivativeAt(
const RealType& t, RealType& v,
272 if (!generated) generate();
279 j = int((t - x_[0]) * dx);
282 for (
int i = 0; i < n; i++) {
290 j = std::clamp(j, 0, n - 1);
293 v = y_[j] + dt * (b[j] + dt * (c[j] + dt * d[j]));
294 dv = b[j] + dt * (2.0 * c[j] + 3.0 * dt * d[j]);
297 std::vector<int> CubicSpline::sort_permutation(
298 const std::vector<double>& v)
const {
299 std::vector<int> p(v.size());
301 std::iota(p.begin(), p.end(), 0);
302 std::sort(p.begin(), p.end(), [&v](
int a,
int b) { return (v[a] < v[b]); });
307 std::vector<RealType> CubicSpline::apply_permutation(
308 const std::vector<RealType>& v,
const std::vector<int>& p)
const {
309 std::size_t n = p.size();
310 std::vector<RealType> sorted_vec(n);
312 for (std::size_t i = 0; i < n; ++i) {
313 sorted_vec[i] = v[p[i]];
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.