BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
field_profiles.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of BubbleProfiler.
3  *
4  * BubbleProfiler is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * BubbleProfiler is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with BubbleProfiler. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
23 #include "field_profiles.hpp"
24 #include "error.hpp"
25 
26 #include <cmath>
27 
28 namespace BubbleProfiler {
29 
30 Field_profiles::Field_profiles(const Eigen::VectorXd& gridpoints_,
31  const Eigen::MatrixXd& profiles_,
32  double interpolation_points_fraction_)
33  : gridpoints(gridpoints_)
34  , profiles(profiles_)
35  , splines(profiles_.cols())
36 {
37  if (interpolation_points_fraction_ <= 0. ||
38  interpolation_points_fraction_ > 1.) {
39  throw Setup_error(
40  "fraction of points used in interpolation must be between 0 and 1");
41  }
42 
43  build_splines();
44 }
45 
46 Field_profiles::Field_profiles(int num_fields_, double domain_start_,
47  double domain_end_, int n_steps_,
48  double interpolation_points_fraction_)
49  : Field_profiles(Eigen::VectorXd::LinSpaced(
50  n_steps_, domain_start_, domain_end_),
51  Eigen::MatrixXd::Zero(n_steps_, num_fields_),
52  interpolation_points_fraction_)
53 {
54 }
55 
56 Field_profiles::Field_profiles(const Eigen::MatrixXd& profiles_,
57  double domain_start_, double domain_end_,
58  double interpolation_points_fraction_)
59  : Field_profiles(Eigen::VectorXd::LinSpaced(
60  profiles_.rows(), domain_start_, domain_end_),
61  profiles_, interpolation_points_fraction_)
62 {
63 }
64 
66 {
67  if (f <= 0. || f > 1.) {
68  throw Setup_error(
69  "fraction of points used in interpolation must be between 0 and 1");
70  }
71 
73  must_update_coords = true;
74 }
75 
76 void Field_profiles::set_field_profile(int i, const Eigen::VectorXd& p)
77 {
78  if (p.rows() != profiles.rows()) {
79  throw Setup_error("Field_profiles::set_field_profiles: "
80  "number of grid points does not match");
81  }
82 
83  profiles.col(i) = p;
85 }
86 
88 {
89  const int n_steps = gridpoints.size();
90  const int n_knots = static_cast<int>(
91  std::ceil(interpolation_points_fraction * n_steps));
92 
93  if (n_knots > n_steps) {
94  throw Setup_error("Field_profiles::initialize_interpolation_grid_values: "
95  "number of knots cannot exceed number of grid points");
96  }
97 
98  const int stride = (n_steps - 1) / (n_knots - 1);
99 
100  if (interpolation_grid_values.size() != n_knots) {
101  interpolation_grid_values.resize(n_knots);
102  }
103 
105  for (int i = 1; i < n_knots - 1; ++i) {
106  interpolation_grid_values(i) = gridpoints(i * stride);
107  }
108  interpolation_grid_values(n_knots - 1) = gridpoints(n_steps - 1);
109 }
110 
112 {
113  const int n_steps = gridpoints.size();
114  const int n_knots = interpolation_grid_values.size();
115  const int stride = (n_steps - 1) / (n_knots - 1);
116 
117  interpolation_field_values(0, field) = profiles(0, field);
118  for (int i = 1; i < n_knots - 1; ++i) {
119  interpolation_field_values(i, field) = profiles(i * stride, field);
120  }
121  interpolation_field_values(n_knots - 1, field) =
122  profiles(n_steps - 1, field);
123 }
124 
126 {
127  const int n_steps = gridpoints.size();
128  const int n_knots = interpolation_grid_values.size();
129  const int stride = (n_steps - 1) / (n_knots - 1);
130 
131  if (interpolation_field_values.cols() != profiles.cols() ||
132  interpolation_field_values.rows() != n_knots) {
133  interpolation_field_values.resize(n_knots, profiles.cols());
134  }
135 
136  interpolation_field_values.row(0) = profiles.row(0);
137  for (int i = 1; i < n_knots - 1; ++i) {
138  interpolation_field_values.row(i) = profiles.row(i * stride);
139  }
140  interpolation_field_values.row(n_knots - 1) = profiles.row(n_steps - 1);
141 }
142 
144 {
145  if (must_update_coords) {
146  build_splines();
147  } else {
149 
150  splines[field].construct_interpolant(
152  interpolation_field_values.col(field),
154  }
155 }
156 
158 {
159  if (must_update_coords) {
161  must_update_coords = false;
162  }
163 
165 
166  const int n_fields = profiles.cols();
167  for (int i = 0; i < n_fields; ++i) {
168  splines[i].construct_interpolant(interpolation_grid_values,
171  }
172 }
173 
174 double Field_profiles::evaluate_at(int field, double rho) const
175 {
176  if (field < 0 || field >= profiles.cols()) {
177  throw Out_of_bounds_error(
178  field,
179  "Field_profiles::evaluate_at: invalid field index "
180  + std::to_string(field));
181  }
182 
183  return splines[field].evaluate_at(rho);
184 }
185 
186 Eigen::VectorXd Field_profiles::evaluate_at(double rho) const
187 {
188  const int n_fields = profiles.cols();
189  Eigen::VectorXd result(n_fields);
190  for (int i = 0; i < n_fields; ++i) {
191  result(i) = splines[i].evaluate_at(rho);
192  }
193  return result;
194 }
195 
196 
197 double Field_profiles::derivative_at(int field, int order, double rho) const
198 {
199  if (order != 1 && order != 2) {
200  throw Not_implemented_error(
201  "Field_profiles::derivative_at: "
202  "only first or second derivatives may be computed");
203  }
204 
205  if (field < 0 || field >= profiles.cols()) {
206  throw Out_of_bounds_error(
207  field,
208  "Field_profiles::evaluate_at: invalid field index "
209  + std::to_string(field));
210  }
211 
212  return order == 1 ? splines[field].evaluate_deriv_at(rho) :
213  splines[field].evaluate_second_deriv_at(rho);
214 }
215 
216 } // namespace BubbleProfiler
contains the definition of the Field_profiles clas
double derivative_at(int field, int order, double rho) const
Take the radial derivative of a field at a given radius.
void set_interpolation_points_fraction(double f)
void set_field_profile(int i, const Eigen::VectorXd &p)
std::vector< GSL_interpolator > splines
Eigen::MatrixXd interpolation_field_values
Eigen::VectorXd evaluate_at(double rho) const
Get all field values at a given radius.
Exception indicating out of bounds access error.
Definition: error.hpp:75
Exception indicating general setup error.
Definition: error.hpp:32
Eigen::VectorXd interpolation_grid_values
Discretized set of field profiles.