ampsci
High-precision calculations for one- and two-valence atomic systems
Interpolator.hpp
1#pragma once
2#include <cassert>
3#include <gsl/gsl_errno.h>
4#include <gsl/gsl_spline.h>
5#include <gsl/gsl_version.h>
6#include <iostream>
7#include <map>
8#include <vector>
9
10// This should make code work with old versions of GSL
11#ifdef GSL_MAJOR_VERSION
12#if GSL_MAJOR_VERSION == 1
13#define GSL_VERSION_1
14#endif
15#endif
16
17/*!
18 @brief 1D interpolation using GSL splines.
19 @details
20 Wraps the GSL interpolation library
21 (https://www.gnu.org/software/gsl/doc/html/interp.html).
22 Provides a stateful `Interp` class and a convenience `interpolate()`
23 function. Several interpolation methods are available via `Method`.
24 Does not extrapolate: values outside [xmin, xmax] are returned as zero.
25*/
26namespace Interpolator {
27
28/*!
29 @brief Interpolation method.
30 @details
31 See https://www.gnu.org/software/gsl/doc/html/interp.html for full details.
32*/
33enum class Method {
34 //! Linear interpolation; no additional memory required
35 linear,
36 //! Polynomial interpolation; only suitable for small numbers of points
38 //! Cubic spline with natural boundary conditions (zero second derivative at endpoints)
39 cspline,
40 //! Cubic spline with periodic boundary conditions; first and last y-values must match
42 //! Akima spline with natural boundary conditions (Wodicka non-rounded corner algorithm)
43 akima,
44 //! Akima spline with periodic boundary conditions
46 //! Steffen's monotone spline: no spurious oscillations between data points. GSL v2+ only.
48};
49
50//! Maps Interpolator::Method to the corresponding GSL interpolation type
51static const std::map<Method, const gsl_interp_type *> interp_method{
52 {Method::linear, gsl_interp_linear},
53 {Method::polynomial, gsl_interp_polynomial},
54 {Method::cspline, gsl_interp_cspline},
55 {Method::cspline_periodic, gsl_interp_cspline_periodic},
56 {Method::akima, gsl_interp_akima},
57 {Method::akima_periodic, gsl_interp_akima_periodic}
58#ifndef GSL_VERSION_1
59 ,
60 {Method::steffen, gsl_interp_steffen}
61#endif
62};
63
64//==============================================================================
65
66/*!
67 @brief Stateful 1D interpolation object using GSL.
68 @details
69 Constructed from data vectors x and y (interpreted as samples of y(x)).
70 Once constructed, evaluates the interpolated function at arbitrary points
71 via `interp()` or `operator()`.
72
73 Does not extrapolate: returns 0.0 for x outside [x.front(), x.back()].
74
75 Copy construction and copy assignment are deleted.
76
77 @note x and y are copied into GSL internal storage during construction;
78 the input vectors do not need to outlive the `Interp` object.
79*/
80class Interp {
81
82private:
83 gsl_interp_accel *acc;
84 gsl_spline *spline;
85 double x0, xmax;
86
87public:
88 /*!
89 @brief Construct interpolation object from data points.
90 @param x Strictly increasing x values (abscissae).
91 @param y Function values y(x); must satisfy `y.size() == x.size()`.
92 @param method Interpolation method (default: cspline).
93 */
94 Interp(const std::vector<double> &x, const std::vector<double> &y,
95 Method method = Method::cspline)
96 : acc(gsl_interp_accel_alloc()),
97 spline(gsl_spline_alloc(interp_method.at(method), x.size())),
98 x0(x.front()),
99 xmax(x.back()) {
100 assert(x.size() == y.size() &&
101 "In Interp, input vectors x and y must have same size");
102 assert(x.size() >= gsl_interp_type_min_size(interp_method.at(method)) &&
103 "In Interp, certain interpolation methods require a minimum number "
104 "of points");
105 gsl_spline_init(spline, x.data(), y.data(), x.size());
106 }
107
108 ~Interp() {
109 gsl_spline_free(spline);
110 gsl_interp_accel_free(acc);
111 }
112
113 //! Copy construction deleted
114 Interp(const Interpolator::Interp &) = delete;
115 //! Copy assignment deleted
117
118 //! Returns interpolated y(x). Returns 0.0 if x is outside [x0, xmax].
119 double interp(double x) const {
120 if (x < x0 || x > xmax)
121 return 0.0;
122 else
123 return gsl_spline_eval(spline, x, acc);
124 }
125
126 //! Returns interpolated y(x) for each point in x. Returns 0.0 outside range.
127 std::vector<double> interp(const std::vector<double> &x) const {
128 std::vector<double> y;
129 y.reserve(x.size());
130 for (auto xi : x)
131 y.push_back(interp(xi));
132 return y;
133 }
134
135 //! Returns interpolated y(x). Returns 0.0 if x is outside [x0, xmax].
136 double operator()(double x) const { return interp(x); }
137
138 //! Returns interpolated y(x) for each point in x. Returns 0.0 outside range.
139 std::vector<double> operator()(const std::vector<double> &x) const {
140 return interp(x);
141 }
142};
143
144//==============================================================================
145
146/*!
147 @brief Convenience wrapper: interpolates y_in(x_in) and evaluates at x_out.
148 @param x_in Input x values (strictly increasing).
149 @param y_in Input y values; must satisfy `y_in.size() == x_in.size()`.
150 @param x_out Points at which to evaluate the interpolant.
151 @param method Interpolation method (default: cspline).
152 @returns Vector of interpolated values at each point in x_out.
153*/
154inline std::vector<double> interpolate(const std::vector<double> &x_in,
155 const std::vector<double> &y_in,
156 const std::vector<double> &x_out,
157 Method method = Method::cspline) {
158 Interp i_func(x_in, y_in, method);
159 return i_func(x_out);
160}
161
162//==============================================================================
163
164//! Returns true if the Steffen interpolation method is available (GSL v2+)
165static constexpr bool has_steffen_method() {
166#ifndef GSL_VERSION_1
167 return true;
168#else
169 return false;
170#endif
171}
172
173} // namespace Interpolator
Stateful 1D interpolation object using GSL.
Definition Interpolator.hpp:80
double interp(double x) const
Returns interpolated y(x). Returns 0.0 if x is outside [x0, xmax].
Definition Interpolator.hpp:119
double operator()(double x) const
Returns interpolated y(x). Returns 0.0 if x is outside [x0, xmax].
Definition Interpolator.hpp:136
Interp(const Interpolator::Interp &)=delete
Copy construction deleted.
Interp(const std::vector< double > &x, const std::vector< double > &y, Method method=Method::cspline)
Construct interpolation object from data points.
Definition Interpolator.hpp:94
std::vector< double > operator()(const std::vector< double > &x) const
Returns interpolated y(x) for each point in x. Returns 0.0 outside range.
Definition Interpolator.hpp:139
std::vector< double > interp(const std::vector< double > &x) const
Returns interpolated y(x) for each point in x. Returns 0.0 outside range.
Definition Interpolator.hpp:127
Interp & operator=(const Interpolator::Interp &)=delete
Copy assignment deleted.
1D interpolation using GSL splines.
Definition Interpolator.hpp:26
std::vector< double > interpolate(const std::vector< double > &x_in, const std::vector< double > &y_in, const std::vector< double > &x_out, Method method=Method::cspline)
Convenience wrapper: interpolates y_in(x_in) and evaluates at x_out.
Definition Interpolator.hpp:154
Method
Interpolation method.
Definition Interpolator.hpp:33
@ polynomial
Polynomial interpolation; only suitable for small numbers of points.
@ akima_periodic
Akima spline with periodic boundary conditions.
@ cspline_periodic
Cubic spline with periodic boundary conditions; first and last y-values must match.
@ linear
Linear interpolation; no additional memory required.
@ cspline
Cubic spline with natural boundary conditions (zero second derivative at endpoints)
@ steffen
Steffen's monotone spline: no spurious oscillations between data points. GSL v2+ only.
@ akima
Akima spline with natural boundary conditions (Wodicka non-rounded corner algorithm)