votca 2024.2-dev
Loading...
Searching...
No Matches
cubicspline.cc
Go to the documentation of this file.
1/*
2 * Copyright 2009-2020 The VOTCA Development Team (http://www.votca.org)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18// Standard includes
19#include <cmath>
20#include <iostream>
21
22// Local VOTCA includes
24#include "votca/tools/linalg.h"
25
26namespace votca {
27namespace tools {
28
29using namespace std;
30
31void CubicSpline::Interpolate(const Eigen::VectorXd &x,
32 const Eigen::VectorXd &y) {
33 if (x.size() != y.size()) {
34 throw std::invalid_argument(
35 "error in CubicSpline::Interpolate : sizes of vectors x and y do not "
36 "match");
37 }
38
39 if (x.size() < 3) {
40 throw std::invalid_argument(
41 "error in CubicSpline::Interpolate : vectors x and y have to contain "
42 "at least 3 points");
43 }
44
45 const Index N = x.size();
46
47 // copy the grid points into f
48 r_ = x;
49 f_ = y;
50 Eigen::VectorXd temp = Eigen::VectorXd::Zero(N);
51
52 Eigen::MatrixXd A = Eigen::MatrixXd::Zero(N, N);
53
54 for (Index i = 0; i < N - 2; ++i) {
55 temp(i + 1) =
56 -(A_prime_l(i) * f_(i) + (B_prime_l(i) - A_prime_r(i)) * f_(i + 1) -
57 B_prime_r(i) * f_(i + 2));
58
59 A(i + 1, i) = C_prime_l(i);
60 A(i + 1, i + 1) = D_prime_l(i) - C_prime_r(i);
61 A(i + 1, i + 2) = -D_prime_r(i);
62 }
63
64 switch (boundaries_) {
65 case splineNormal:
66 A(0, 0) = 1;
67 A(N - 1, N - 1) = 1;
68 break;
69 case splinePeriodic:
70 A(0, 0) = 1;
71 A(0, N - 1) = -1;
72 A(N - 1, 0) = 1;
73 A(N - 1, N - 1) = -1;
74 break;
76 throw std::runtime_error(
77 "erro in CubicSpline::Interpolate: case splineDerivativeZero not "
78 "implemented yet");
79 break;
80 }
81
82 Eigen::HouseholderQR<Eigen::MatrixXd> QR(A);
83 f2_ = QR.solve(temp);
84}
85
86void CubicSpline::Fit(const Eigen::VectorXd &x, const Eigen::VectorXd &y) {
87 if (x.size() != y.size()) {
88 throw std::invalid_argument(
89 "error in CubicSpline::Fit : sizes of vectors x and y do not match");
90 }
91
92 const Index N = x.size();
93 const Index ngrid = r_.size();
94
95 // construct the equation
96 // A*u = b
97 // where u = { {f[i]}, {f''[i]} }
98 // and b[i] = y[i] for 0<=i<N
99 // and b[i]=0 for i>=N (for smoothing condition)
100 // A[i,j] contains the data fitting + the spline smoothing conditions
101
102 Eigen::MatrixXd A = Eigen::MatrixXd::Zero(N, 2 * ngrid);
103 Eigen::MatrixXd B = Eigen::MatrixXd::Zero(
104 ngrid, 2 * ngrid); // Matrix with smoothing conditions
105
106 // Construct smoothing matrix
108 // construct the matrix to fit the points and the vector b
109 AddToFitMatrix(A, x, 0);
110 // now do a constrained qr solve
111 Eigen::VectorXd sol = linalg_constrained_qrsolve(A, y, B);
112
113#ifndef __INTEL_LLVM_COMPILER
114 /* isnan/isinf is always false in fast floating point modes on intel */
115 // check vector "sol" for nan's
116 for (Index i = 0; i < 2 * ngrid; i++) {
117 if ((std::isinf(sol(i))) || (std::isnan(sol(i)))) {
118 throw std::runtime_error(
119 "error in CubicSpline::Fit : value nan occurred due to wrong fitgrid "
120 "boundaries");
121 }
122 }
123#endif
124
125 f_ = sol.segment(0, ngrid);
126 f2_ = sol.segment(ngrid, ngrid);
127}
128
129double CubicSpline::Calculate(double r) {
130 Index interval = getInterval(r);
131 return A(r) * f_[interval] + B(r) * f_[interval + 1] + C(r) * f2_[interval] +
132 D(r) * f2_[interval + 1];
133}
134
136 Index interval = getInterval(r);
137 return Aprime(r) * f_[interval] + Bprime(r) * f_[interval + 1] +
138 Cprime(r) * f2_[interval] + Dprime(r) * f2_[interval + 1];
139}
140
141double CubicSpline::A(double r) {
142 return (1.0 - (r - r_[getInterval(r)]) /
143 (r_[getInterval(r) + 1] - r_[getInterval(r)]));
144}
145
146double CubicSpline::Aprime(double r) {
147 return -1.0 / (r_[getInterval(r) + 1] - r_[getInterval(r)]);
148}
149
150double CubicSpline::B(double r) {
151 return (r - r_[getInterval(r)]) /
152 (r_[getInterval(r) + 1] - r_[getInterval(r)]);
153}
154
155double CubicSpline::Bprime(double r) {
156 return 1.0 / (r_[getInterval(r) + 1] - r_[getInterval(r)]);
157}
158
159double CubicSpline::C(double r) {
160
161 double xxi = r - r_[getInterval(r)];
162 double h = r_[getInterval(r) + 1] - r_[getInterval(r)];
163
164 return (0.5 * xxi * xxi - (1.0 / 6.0) * xxi * xxi * xxi / h -
165 (1.0 / 3.0) * xxi * h);
166}
167
168double CubicSpline::Cprime(double r) {
169 double xxi = r - r_[getInterval(r)];
170 double h = r_[getInterval(r) + 1] - r_[getInterval(r)];
171
172 return (xxi - 0.5 * xxi * xxi / h - h / 3);
173}
174
175double CubicSpline::D(double r) {
176
177 double xxi = r - r_[getInterval(r)];
178 double h = r_[getInterval(r) + 1] - r_[getInterval(r)];
179
180 return ((1.0 / 6.0) * xxi * xxi * xxi / h - (1.0 / 6.0) * xxi * h);
181}
182
183double CubicSpline::Dprime(double r) {
184 double xxi = r - r_[getInterval(r)];
185 double h = r_[getInterval(r) + 1] - r_[getInterval(r)];
186
187 return (0.5 * xxi * xxi / h - (1.0 / 6.0) * h);
188}
189
190double CubicSpline::A_prime_l(Index i) { return -1.0 / (r_[i + 1] - r_[i]); }
191
192double CubicSpline::B_prime_l(Index i) { return 1.0 / (r_[i + 1] - r_[i]); }
193
195 return (1.0 / 6.0) * (r_[i + 1] - r_[i]);
196}
197
199 return (1.0 / 3.0) * (r_[i + 1] - r_[i]);
200}
201
203 return -1.0 / (r_[i + 2] - r_[i + 1]);
204}
205
206double CubicSpline::B_prime_r(Index i) { return 1.0 / (r_[i + 2] - r_[i + 1]); }
207
209 return -(1.0 / 3.0) * (r_[i + 2] - r_[i + 1]);
210}
211
213 return -(1.0 / 6.0) * (r_[i + 2] - r_[i + 1]);
214}
215
216} // namespace tools
217} // namespace votca
double Cprime(double r)
void Interpolate(const Eigen::VectorXd &x, const Eigen::VectorXd &y) override
Calculate interpolating spline for given (x,y) values. Points on resulting spline can be obtained via...
double C_prime_l(Index i)
void AddToFitMatrix(matrix_type &M, double x, Index offset1, Index offset2=0, double scale=1)
Add a point (one entry) to fitting matrix.
double Aprime(double r)
double Dprime(double r)
void Fit(const Eigen::VectorXd &x, const Eigen::VectorXd &y) override
Fit spline through noisy (x,y) values. Points on resulting fitted spline can be obtained via Calculat...
double D_prime_l(Index i)
double D_prime_r(Index i)
double B_prime_r(Index i)
double B_prime_l(Index i)
double Calculate(double r) override
Calculate spline function value for a given x value on the spline created by Interpolate() or Fit()
double A_prime_r(Index i)
double CalculateDerivative(double r) override
Calculate y value for a given x value on the derivative of the spline created by function Interpolate...
void AddBCToFitMatrix(matrix_type &M, Index offset1, Index offset2=0)
Add boundary conditions to fitting matrix.
double Bprime(double r)
double C_prime_r(Index i)
double A_prime_l(Index i)
Eigen::VectorXd r_
Definition spline.h:173
eBoundary boundaries_
Get the spline data f_.
Definition spline.h:171
Index getInterval(double r)
Determine the index of the interval containing value r.
Definition spline.cc:62
@ splineDerivativeZero
derivatives and end-points are zero.
Definition spline.h:76
@ splinePeriodic
periodic boundary conditions:
Definition spline.h:75
@ splineNormal
normal boundary conditions:
Definition spline.h:74
STL namespace.
Eigen::VectorXd linalg_constrained_qrsolve(const Eigen::MatrixXd &A, const Eigen::VectorXd &b, const Eigen::MatrixXd &constr)
solves A*x=b under the constraint B*x = 0
Definition linalg.cc:28
base class for all analysis tools
Definition basebead.h:33
Eigen::Index Index
Definition types.h:26