FML
Spline.h
Go to the documentation of this file.
1#ifndef SPLINE_HEADER
2#define SPLINE_HEADER
3#include <cassert>
4#include <cmath>
5#include <gsl/gsl_errno.h>
6#include <gsl/gsl_interp2d.h>
7#include <gsl/gsl_spline.h>
8#include <gsl/gsl_spline2d.h>
9#include <iostream>
10#include <vector>
11#ifdef USE_OMP
12#include <omp.h>
13#endif
14#ifdef USE_MPI
15#include <mpi.h>
16#endif
17
18namespace FML {
19 namespace INTERPOLATION {
20
21 /// This namespace deals with creating and using splines
22 namespace SPLINE {
23
24 // Type aliases
25 class GSLSpline;
26 class GSLSpline2D;
29 using DVector = std::vector<double>;
30 using DVector2D = std::vector<DVector>;
31
32#ifndef SPLINE_FIDUCIAL_INTERPOL_TYPE
33#define SPLINE_FIDUCIAL_INTERPOL_TYPE gsl_interp_cspline
34#endif
35#ifndef SPLINE_FIDUCIAL_INTERPOL_TYPE_2D
36#define SPLINE_FIDUCIAL_INTERPOL_TYPE_2D gsl_interp2d_bicubic
37#endif
38#ifndef SPLINE_FIDUCIAL_SPLINE_WARNING
39#define SPLINE_FIDUCIAL_SPLINE_WARNING false
40#endif
41
42 //====================================================
43 ///
44 /// This is a wrapper class for easy use of GSL splines
45 /// It is (OpenMP) thread safe as long as splines are
46 /// not created by a subthread and later tried to be used
47 /// by more than that thread!
48 ///
49 /// The fiducial splines are cubic splines for 1D and
50 /// bicubic for 2D assuming natural (y''=0) boundary
51 /// conditions at the end-points
52 ///
53 /// The fiducial choice allows to get the function value
54 /// and up to second order derivatives. NB: if you change
55 /// the fiducial choice to a lower order spline,
56 /// e.g to gsl_interp_linear, then the second derivative
57 /// deriv_xx etc. will not work
58 ///
59 /// If evaluating out of bounds it will return the closest
60 /// value. To get a warning when this happens call
61 /// set_out_of_bounds_warning(true) before using the spline
62 /// or set the define SPLINE_FIDUCIAL_SPLINE_WARNING to be true
63 ///
64 /// Errors are handled via the throw_error function
65 ///
66 /// Compile time defines:
67 ///
68 /// USE_MPI : Use MPI (only effect is in on how errors are handled)
69 ///
70 /// USE_OMP : Use OpenMP
71 ///
72 /// SPLINE_FIDUCIAL_INTERPOL_TYPE : Cubic spline is the fiducial choice
73 ///
74 /// SPLINE_FIDUCIAL_INTERPOL_TYPE_2D : Bicubic is the fiducial choice
75 ///
76 /// SPLINE_FIDUCIAL_SPLINE_WARNING : Show warnings if we evaluate out of bounds
77 ///
78 //====================================================
79
80 class GSLSpline {
81 private:
82 // GSL spline
83 gsl_spline * spline{nullptr};
84
85 // If we use threads then we must have a unique accelerator per thread
86#ifdef USE_OMP
87 std::vector<gsl_interp_accel *> xaccs{};
88#else
89 gsl_interp_accel * xacc{nullptr};
90#endif
91
92 const gsl_interp_type * interpoltype_used = SPLINE_FIDUCIAL_INTERPOL_TYPE;
93
94 // Info about the spline
95 int size_x{};
96 double xmin{};
97 double xmax{};
98 double dx_min{};
99 double dx_max{};
100 std::string name{"NoName"};
101
102 // Print warnings if out of bounds if wanted
103 bool out_of_bounds_warning = SPLINE_FIDUCIAL_SPLINE_WARNING;
104 void out_of_bounds_check(double x) const;
105
106 // Handle errors
107 void throw_error(std::string errormessage) const;
108
109 public:
110 GSLSpline() = default;
111
112 /// Construct giving the spline a name (useful for error/warning messages)
113 GSLSpline(std::string name);
114
115 /// Construct a spline from pointers to x and y. Both must have nx elements.
116 GSLSpline(double * x,
117 double * y,
118 int nx,
119 std::string splinename = "NoName",
120 const gsl_interp_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE);
121 /// Construct a spline from vectors x and y. Both must have the same size.
122 GSLSpline(const DVector & x,
123 const DVector & y,
124 std::string splinename = "NoName",
125 const gsl_interp_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE);
126 GSLSpline(const GSLSpline & rhs);
127 GSLSpline & operator=(const GSLSpline & rhs);
128 ~GSLSpline();
129
130 /// Is the spline created or not?
131 explicit operator bool() const;
132
133 /// Create a spline from pointers to x and y. Both must have nx elements.
134 void create(const double * x,
135 const double * y,
136 int nx,
137 std::string splinename = "NoName",
138 const gsl_interp_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE);
139 /// Create a spline from vectors x and y. Both must have the same size.
140 void create(const DVector & x,
141 const DVector & y,
142 std::string splinename = "NoName",
143 const gsl_interp_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE);
144
145 // Methods for spline lookup of function and its derivatives
146 /// Overload of the () operator for easy evaluation of the spline
147 double operator()(double x) const;
148 /// Get the value of the spline (if out of bounds we use the closest value)
149 double eval(double x) const;
150 double eval_deriv(double x, int deriv) const;
151 /// Get the value of the first derivative of the spline
152 double deriv_x(double x) const;
153 /// Get the value of the second derivative of the spline
154 double deriv_xx(double x) const;
155
156 // Some useful info
157 /// Get the range the spline was created on
158 std::pair<double, double> get_xrange() const;
159 /// Get the name of the spline
160 std::string get_name() const;
161 /// Turn on/off warnings if we try to evaluate out of bounds (we use closest value in that case)
162 void set_out_of_bounds_warning(bool v);
163
164 /// Get the raw GSL data for x used to create the spline
165 DVector get_x_data() { return DVector(spline->x, spline->x + spline->size); }
166 /// Get the raw GSL data for y=f(x) used to create the spline
167 DVector get_y_data() { return DVector(spline->y, spline->y + spline->size); }
168
169 /// Free up memory associated with the spline
170 void free();
171 };
172
173 /// Create 2D splines
175 private:
176 // GSL spline
177 gsl_spline2d * spline{nullptr};
178
179 // If we use threads then we must have a unique accelerator per thread
180#ifdef USE_OMP
181 std::vector<gsl_interp_accel *> xaccs{};
182 std::vector<gsl_interp_accel *> yaccs{};
183#else
184 gsl_interp_accel * xacc{nullptr};
185 gsl_interp_accel * yacc{nullptr};
186#endif
187 const gsl_interp2d_type * interpoltype_used = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D;
188
189 // Info about the spline
190 int size_x{};
191 int size_y{};
192 double xmin{};
193 double xmax{};
194 double ymin{};
195 double ymax{};
196 double dx_min{};
197 double dx_max{};
198 double dy_min{};
199 double dy_max{};
200 std::string name{"NoName"};
201
202 // Print warnings if out of bounds if wanted
203 bool out_of_bounds_warning = SPLINE_FIDUCIAL_SPLINE_WARNING;
204 void out_of_bounds_check(double x, double y) const;
205
206 // A list of all the (up to second order) derivative functions in GSL,
207 // We map Dx^nx Dy^ny f => nx + 3*ny in the list for use in eval_deriv
208 typedef double (
209 *evalfunc)(const gsl_spline2d *, double, double, gsl_interp_accel *, gsl_interp_accel *);
210
211 std::vector<evalfunc> derivfunc{gsl_spline2d_eval,
212 gsl_spline2d_eval_deriv_x,
213 gsl_spline2d_eval_deriv_xx,
214 gsl_spline2d_eval_deriv_y,
215 gsl_spline2d_eval_deriv_xy,
216 nullptr,
217 gsl_spline2d_eval_deriv_yy};
218
219 // Handle errors
220 void throw_error(std::string errormessage) const;
221
222 public:
223 GSLSpline2D() = default;
224 GSLSpline2D(std::string name);
225 GSLSpline2D(const double * x,
226 const double * y,
227 const double * z,
228 int nx,
229 int ny,
230 std::string splinename = "NoName",
231 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
232 GSLSpline2D(const DVector & x,
233 const DVector & y,
234 const DVector & z,
235 std::string splinename = "NoName",
236 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
237 GSLSpline2D(const DVector & x,
238 const DVector & y,
239 const DVector2D & z,
240 std::string splinename = "NoName",
241 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
242 GSLSpline2D(const GSLSpline2D & rhs);
243 GSLSpline2D & operator=(const GSLSpline2D & rhs);
244 ~GSLSpline2D();
245
246 /// Is the spline created or not?
247 explicit operator bool() const;
248
249 /// Create a spline from pointers to x, y and z. z must have nx * ny elements.
250 void create(const double * x,
251 const double * y,
252 const double * z,
253 int nx,
254 int ny,
255 std::string splinename = "NoName",
256 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
257 /// Create a spline from vectors to x, y and z. Size of z must be nx * ny.
258 void create(const DVector & x,
259 const DVector & y,
260 const DVector & z,
261 std::string splinename = "NoName",
262 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
263 /// Create a spline from vectors to x, y and z. Size of z must be (nx, ny).
264 void create(const DVector & x,
265 const DVector & y,
266 const DVector2D & z,
267 std::string splinename = "NoName",
268 const gsl_interp2d_type * interpoltype = SPLINE_FIDUCIAL_INTERPOL_TYPE_2D);
269
270 // Methods for spline lookup of function and its derivatives
271 /// Overload of the () operator for easy evaluation of the spline
272 double operator()(double x, double y) const;
273 /// Get the value of the spline (if out of bounds we use the closest value)
274 double eval(double x, double y) const;
275 /// General method to fetch derivatives. derivx is the number of x-derivatives and derivy is the number
276 /// of y-derivatives (how many are availiable depends on the spline method).
277 double eval_deriv(double x, double y, int derivx, int derivy) const;
278 /// Get the value of the x-derivative of the spline
279 double deriv_x(double x, double y) const;
280 /// Get the value of the second x-derivative of the spline
281 double deriv_xx(double x, double y) const;
282 /// Get the value of the x,y-derivative of the spline
283 double deriv_xy(double x, double y) const;
284 /// Get the value of the y-derivative of the spline
285 double deriv_y(double x, double y) const;
286 /// Get the value of the second y-derivative of the spline
287 double deriv_yy(double x, double y) const;
288
289 // Some useful info
290 /// Get the x-range the spline was created on
291 std::pair<double, double> get_xrange() const;
292 /// Get the y-range the spline was created on
293 std::pair<double, double> get_yrange() const;
294 /// Get the name of the spline
295 std::string get_name() const;
296 /// Turn on/off warnings if we try to evaluate out of bounds (we use closest value in that case)
297 void set_out_of_bounds_warning(bool v);
298
299 /// Get the raw GSL data for x used to create the spline
300 DVector get_x_data() { return DVector(spline->xarr, spline->xarr + size_x); }
301 /// Get the raw GSL data for y used to create the spline
302 DVector get_y_data() { return DVector(spline->yarr, spline->yarr + size_y); }
303 /// Get the raw GSL data for z=f(x,y) used to create the spline
304 DVector get_z_data() { return DVector(spline->zarr, spline->zarr + size_x * size_y); }
305
306 /// Free up memory associated with the spline
307 void free();
308 };
309 } // namespace SPLINE
310 } // namespace INTERPOLATION
311} // namespace FML
312#endif
double deriv_xy(double x, double y) const
Get the value of the x,y-derivative of the spline.
Definition: Spline.cpp:594
GSLSpline2D & operator=(const GSLSpline2D &rhs)
Definition: Spline.cpp:327
void create(const double *x, const double *y, const double *z, int nx, int ny, std::string splinename="NoName", const gsl_interp2d_type *interpoltype=SPLINE_FIDUCIAL_INTERPOL_TYPE_2D)
Create a spline from pointers to x, y and z. z must have nx * ny elements.
Definition: Spline.cpp:371
double eval(double x, double y) const
Get the value of the spline (if out of bounds we use the closest value)
Definition: Spline.cpp:477
double eval_deriv(double x, double y, int derivx, int derivy) const
General method to fetch derivatives.
Definition: Spline.cpp:499
void free()
Free up memory associated with the spline.
Definition: Spline.cpp:537
double operator()(double x, double y) const
Overload of the () operator for easy evaluation of the spline.
Definition: Spline.cpp:364
double deriv_x(double x, double y) const
Get the value of the x-derivative of the spline.
Definition: Spline.cpp:590
double deriv_yy(double x, double y) const
Get the value of the second y-derivative of the spline.
Definition: Spline.cpp:593
DVector get_z_data()
Get the raw GSL data for z=f(x,y) used to create the spline.
Definition: Spline.h:304
std::pair< double, double > get_xrange() const
Get the x-range the spline was created on.
Definition: Spline.cpp:595
DVector get_y_data()
Get the raw GSL data for y used to create the spline.
Definition: Spline.h:302
double deriv_y(double x, double y) const
Get the value of the y-derivative of the spline.
Definition: Spline.cpp:592
void set_out_of_bounds_warning(bool v)
Turn on/off warnings if we try to evaluate out of bounds (we use closest value in that case)
Definition: Spline.cpp:598
std::string get_name() const
Get the name of the spline.
Definition: Spline.cpp:597
double deriv_xx(double x, double y) const
Get the value of the second x-derivative of the spline.
Definition: Spline.cpp:591
DVector get_x_data()
Get the raw GSL data for x used to create the spline.
Definition: Spline.h:300
std::pair< double, double > get_yrange() const
Get the y-range the spline was created on.
Definition: Spline.cpp:596
This is a wrapper class for easy use of GSL splines It is (OpenMP) thread safe as long as splines are...
Definition: Spline.h:80
DVector get_y_data()
Get the raw GSL data for y=f(x) used to create the spline.
Definition: Spline.h:167
double eval(double x) const
Get the value of the spline (if out of bounds we use the closest value)
Definition: Spline.cpp:183
void create(const double *x, const double *y, int nx, std::string splinename="NoName", const gsl_interp_type *interpoltype=SPLINE_FIDUCIAL_INTERPOL_TYPE)
Create a spline from pointers to x and y. Both must have nx elements.
Definition: Spline.cpp:89
double eval_deriv(double x, int deriv) const
Definition: Spline.cpp:203
double deriv_x(double x) const
Get the value of the first derivative of the spline.
Definition: Spline.cpp:275
double operator()(double x) const
Overload of the () operator for easy evaluation of the spline.
Definition: Spline.cpp:181
DVector get_x_data()
Get the raw GSL data for x used to create the spline.
Definition: Spline.h:165
GSLSpline & operator=(const GSLSpline &rhs)
Definition: Spline.cpp:60
std::string get_name() const
Get the name of the spline.
Definition: Spline.cpp:278
void free()
Free up memory associated with the spline.
Definition: Spline.cpp:240
void set_out_of_bounds_warning(bool v)
Turn on/off warnings if we try to evaluate out of bounds (we use closest value in that case)
Definition: Spline.cpp:279
double deriv_xx(double x) const
Get the value of the second derivative of the spline.
Definition: Spline.cpp:276
std::pair< double, double > get_xrange() const
Get the range the spline was created on.
Definition: Spline.cpp:277
std::vector< DVector > DVector2D
Definition: Spline.h:30
std::vector< double > DVector
Definition: Spline.h:29
Definition: CAMBReader.h:10
return y
Definition: Global.h:265
float z
Definition: example.py:56
x
Definition: test.py:18