BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
instream_profile_guesser.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 
24 #include "error.hpp"
25 #include "field_profiles.hpp"
26 #include "math_wrappers.hpp"
27 #include "potential.hpp"
28 
29 #include <boost/algorithm/string/classification.hpp>
30 #include <boost/algorithm/string/split.hpp>
31 #include <boost/algorithm/string/trim.hpp>
32 #include <boost/lexical_cast.hpp>
33 
34 namespace BubbleProfiler {
35 
37  std::istream& input_stream_)
38 {
39  read_profiles(input_stream_);
40 }
41 
43  std::istream& input_stream_, const std::string& delimiters_)
44  : delimiters(delimiters_)
45 {
46  read_profiles(input_stream_);
47 }
48 
50  std::istream& input_stream_, const std::string& delimiters_,
51  const std::string& line_comment_start_)
52  : delimiters(delimiters_)
53  , line_comment_start(line_comment_start_)
54 {
55  read_profiles(input_stream_);
56 }
57 
59 {
60  has_n_fields = false;
61  spatial_grid.clear();
62  field_values.clear();
63 }
64 
65 void Instream_profile_guesser::read_profiles(std::istream& input_stream)
66 {
67  reset();
68 
69  if (!input_stream.good()) {
70  throw IO_error("cannot read from provided stream");
71  }
72 
73  logger.log_message(logging::Log_level::Trace, "Reading from input stream");
74 
75  std::string line;
76  has_n_fields = false;
77  while (std::getline(input_stream, line)) {
78  strip_comments(line);
79  boost::trim(line);
80  if (line.empty()) {
81  continue;
82  }
83  process_line(line);
84  }
85 
86  if (spatial_grid.empty()) {
87  throw IO_error("no valid grid points found");
88  }
89 
91  "Read " + std::to_string(spatial_grid.size())
92  + " points from input stream");
94  "Found values for " + std::to_string(n_fields)
95  + " fields");
96 }
97 
98 void Instream_profile_guesser::strip_comments(std::string& line) const
99 {
100  const auto pos = line.find(line_comment_start);
101  if (pos != std::string::npos) {
102  line = line.substr(0, pos);
103  }
104 }
105 
106 void Instream_profile_guesser::process_line(const std::string& line)
107 {
108  std::vector<std::string> fields;
109  boost::split(fields, line, boost::is_any_of(delimiters),
110  boost::token_compress_on);
111 
112  if (fields.empty()) {
113  throw IO_error("no valid fields found in line: " + line);
114  }
115 
116  const std::size_t current_n_fields = fields.size() - 1;
117  if (current_n_fields == 0) {
118  throw IO_error("no field values given in line: " + line);
119  }
120 
121  if (has_n_fields) {
122  if (current_n_fields != n_fields) {
123  throw IO_error("incorrect number of fields in line: " + line);
124  }
125  } else {
126  n_fields = current_n_fields;
127  has_n_fields = true;
128  field_values = std::vector<std::vector<double> >(n_fields);
129  }
130 
131  try {
132  const double grid_value = boost::lexical_cast<double>(fields[0]);
133  spatial_grid.push_back(grid_value);
134 
135  for (std::size_t i = 0; i < n_fields; ++i) {
136  const double field_value = boost::lexical_cast<double>(fields[i + 1]);
137  field_values[i].push_back(field_value);
138  }
139  } catch (const boost::bad_lexical_cast& error) {
140  throw IO_error("unable to read input data in line: " + line);
141  }
142 }
143 
145  const Potential& potential,
146  const Eigen::VectorXd& /* true_vacuum */,
147  int n_dimensions, double domain_start, double domain_end,
148  double initial_step_size, double interpolation_points_fraction)
149 {
150  const std::size_t required_n_fields = potential.get_number_of_fields();
151  if (required_n_fields != n_fields || !has_n_fields) {
152  throw Setup_error(
153  "number of fields in guess does not match number in potential");
154  }
155 
156  const double stored_domain_start = spatial_grid.front();
157  const double stored_domain_end = spatial_grid.back();
158 
159  if (domain_start >= 0.) {
160  if (Abs(stored_domain_start - domain_start) > tolerance) {
161  throw Setup_error(
162  "stored domain start does not match requested domain start");
163  }
164  }
165 
166  if (domain_end >= 0.) {
167  if (Abs(stored_domain_end - domain_end) > tolerance) {
168  throw Setup_error(
169  "stored domain end does not match requested domain end");
170  }
171  }
172 
173  // If definite values for the domain start and end, and the grid step
174  // size are given, require that the calculated grid matches that read
175  // from the stream. This is imposed for simplicity, but could be
176  // removed if the guessed profile is constructed by interpolating the
177  // read in values at the desired grid points.
178  if (domain_start >= 0. && domain_end >= 0.) {
179  const std::size_t requested_n_grid_points = 1 + static_cast<std::size_t>(
180  std::ceil((domain_end - domain_start) / initial_step_size));
181  if (requested_n_grid_points != spatial_grid.size()) {
182  throw Setup_error(
183  "number of stored grid points does not match desired grid size");
184  }
185  const double rho_incr = (domain_end - domain_start) /
186  (requested_n_grid_points - 1.);
187  for (std::size_t i = 0; i < requested_n_grid_points; ++i) {
188  const double current_rho = domain_start + i * rho_incr;
189  if (Abs(spatial_grid[i] - current_rho) > tolerance) {
190  throw Setup_error("spatial coordinate at grid point "
191  + std::to_string(i)
192  + " does not match required value");
193  }
194  }
195  }
196 
197  Eigen::VectorXd grid(get_spatial_grid());
198  Eigen::MatrixXd profiles(get_field_values());
199 
200  Field_profiles profile_guess(grid, profiles, interpolation_points_fraction);
201  profile_guess.set_number_of_dimensions(n_dimensions);
202 
203  return profile_guess;
204 }
205 
207 {
208  Eigen::VectorXd grid(
209  Eigen::VectorXd::Map(spatial_grid.data(), spatial_grid.size()));
210  return grid;
211 }
212 
214 {
215  const auto n_grid_points = spatial_grid.size();
216  Eigen::MatrixXd profiles(n_grid_points, n_fields);
217  for (std::size_t i = 0; i < n_fields; ++i) {
218  profiles.col(i) =
219  Eigen::VectorXd::Map(field_values[i].data(), field_values[i].size());
220  }
221  return profiles;
222 }
223 
224 } // namespace BubbleProfiler
contains the definition of the Field_profiles clas
T Abs(T x) noexcept
contains the definition of the Instream_profile_guesser class
void log_message(Log_level level, const std::string &msg) const
Eigen::MatrixXd get_field_values() const
returns the values of the fields read from the stream
Eigen::VectorXd get_spatial_grid() const
returns the values of the spacetime coordinate read from the stream
Exception indicating generic input/output error.
Definition: error.hpp:122
std::vector< std::vector< double > > field_values
void read_profiles(std::istream &)
read a profile guess from the given stream
virtual Field_profiles get_profile_guess(const Potential &, const Eigen::VectorXd &, int, double, double, double, double) override
Calculate an initial guess for the bubble profile.
virtual std::size_t get_number_of_fields() const =0
Exception indicating general setup error.
Definition: error.hpp:32
Abstract base class for a generic potential.
Definition: potential.hpp:36
Discretized set of field profiles.
Instream_profile_guesser(std::istream &)
reads a profile guess from the given input stream