BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
general_fubini.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 
34 #include "error.hpp"
35 #include "field_profiles.hpp"
38 #include "gsl_root_finder.hpp"
39 #include "kink_profile_guesser.hpp"
40 #include "logging_manager.hpp"
42 #include "shooting.hpp"
43 
44 #include <fstream>
45 #include <iomanip>
46 #include <iostream>
47 #include <string>
48 #include <tuple>
49 #include <vector>
50 
51 namespace BubbleProfiler {
52 
54  double u{1.};
55  double v{1.};
56  double m{3.};
57  bool calculate_profile{false};
58  double global_min{-1.};
59  std::string output_file{""};
60  std::string perturbations_file{""};
61  bool use_perturbative{false};
62  bool verbose{false};
63 };
64 
66 {
67  std::cout <<
68  "Usage: fubini [OPTION] <u> <v> <m>\n\n"
69  "Calculate action and field profile for one-dimensional binomial\n"
70  "potential characterized by the parameters u, v, and m.\n\n"
71  "Example: fubini -c -o 'output.txt' 1 1 3\n\n"
72  "Options:\n"
73  " -c, --calculate-profile calculate field profile as well\n"
74  " -g, --global-minimum=MIN use MIN as location of true vacuum\n"
75  " -h, --help print this help message\n"
76  " -o, --output-file=FILE write results to FILE\n"
77  " -P, --perturbations-file=FILE write perturbations to FILE\n"
78  " -p, --perturbative use the perturbative algorithm\n"
79  " -v, --verbose produce verbose output"
80  << std::endl;
81 }
82 
83 bool starts_with(const std::string& option, const std::string& prefix)
84 {
85  return !option.compare(0, prefix.size(), prefix);
86 }
87 
88 std::string get_option_value(const std::string& option,
89  const std::string& sep = "=")
90 {
91  std::string value{""};
92  const auto prefix_end = option.find(sep);
93 
94  if (prefix_end != std::string::npos) {
95  value = option.substr(prefix_end + 1);
96  }
97 
98  return value;
99 }
100 
101 void parse_positional_args(const std::vector<std::string>& args,
102  Fubini_options& options)
103 {
104  const auto n_positional_args = args.size();
105 
106  if (n_positional_args == 0) {
107  throw Setup_error(
108  "value of u must be provided");
109  } else if (n_positional_args == 1) {
110  throw Setup_error(
111  "value of v must be provided");
112  } else if (n_positional_args == 2) {
113  throw Setup_error(
114  "value of m must be provided");
115  } else if (n_positional_args > 3) {
116  throw Setup_error(
117  "unrecognized command line argument '"
118  + args[3] + "'");
119  }
120 
121  try {
122  options.u = std::stod(args[0]);
123  } catch (const std::invalid_argument& e) {
124  throw Setup_error(
125  "invalid value of u, '" + args[0] + "'");
126  }
127 
128  try {
129  options.v = std::stod(args[1]);
130  } catch (const std::invalid_argument& e) {
131  throw Setup_error(
132  "invalid value for v, '" + args[1] + "'");
133  }
134 
135  try {
136  options.m = std::stod(args[2]);
137  } catch (const std::invalid_argument& e) {
138  throw Setup_error(
139  "invalid value for m, '" + args[2] + "'");
140  }
141 }
142 
143 double parse_global_min(const std::string& value)
144 {
145  if (value.empty()) {
146  throw Setup_error(
147  "'-g' or '--global-minimum' given but no value specified");
148  }
149 
150  double global_min = 0.;
151  try {
152  global_min = std::stod(value);
153  } catch (const std::invalid_argument& e) {
154  throw Setup_error(
155  "invalid global minimum location '" + value + "'");
156  }
157 
158  if (global_min <= 0.) {
159  throw Setup_error(
160  "explicitly specified true vacuum must be positive");
161  }
162 
163  return global_min;
164 }
165 
166 Fubini_options parse_cmd_line_args(int argc, const char* argv[])
167 {
168  Fubini_options options;
169 
170  std::vector<std::string> positional_args;
171  int i = 1;
172  while (i < argc) {
173  const std::string opt(argv[i++]);
174 
175  if (!starts_with(opt, "-")) {
176  positional_args.push_back(opt);
177  continue;
178  }
179 
180  if (opt == "-c" || opt == "--calculate-profile") {
181  options.calculate_profile = true;
182  continue;
183  }
184 
185  if (opt == "-g") {
186  if (i == argc) {
187  throw Setup_error(
188  "'-g' given but no value for true vacuum provided");
189  }
190  const std::string value(argv[i++]);
191  options.global_min = parse_global_min(value);
192  continue;
193  }
194 
195  if (starts_with(opt, "--global-minimum=")) {
196  const std::string value = get_option_value(opt);
197  options.global_min = parse_global_min(value);
198  continue;
199  }
200 
201  if (opt == "-h" || opt == "--help") {
202  print_usage();
203  exit(EXIT_SUCCESS);
204  }
205 
206  if (opt == "-o") {
207  if (i == argc) {
208  throw Setup_error(
209  "'-o' given but no output file name provided");
210  }
211  const std::string filename(argv[i++]);
212  if (starts_with(filename, "-") && filename != "-") {
213  throw Setup_error(
214  "'-o' given but no output file name provided");
215  }
216  options.output_file = filename;
217  continue;
218  }
219 
220  if (starts_with(opt, "--output-file=")) {
221  const std::string filename = get_option_value(opt);
222  if (filename.empty()) {
223  throw Setup_error(
224  "'--output-file=' given but no output file name provided");
225  }
226  options.output_file = filename;
227  continue;
228  }
229 
230  if (opt == "-P") {
231  if (i == argc) {
232  throw Setup_error(
233  "'-P' given but no file name provided");
234  }
235  const std::string filename(argv[i++]);
236  if (starts_with(filename, "-") && filename != "-") {
237  throw Setup_error(
238  "'-P' given but no file name provided");
239  }
240  options.perturbations_file = filename;
241  continue;
242  }
243 
244  if (starts_with(opt, "--perturbations-file=")) {
245  const std::string filename = get_option_value(opt);
246  if (filename.empty()) {
247  throw Setup_error(
248  "'--perturbations-file=' given but no file name provided");
249  }
250  options.perturbations_file = filename;
251  continue;
252  }
253 
254  if (opt == "-p" || opt == "--perturbative") {
255  options.use_perturbative = true;
256  continue;
257  }
258 
259  if (opt == "-v" || opt == "--verbose") {
260  options.verbose = true;
261  continue;
262  }
263 
264  throw Setup_error(
265  "unrecognized command line argument '" + opt + "'");
266  }
267 
268  parse_positional_args(positional_args, options);
269 
270  return options;
271 }
272 
273 std::tuple<double, Field_profiles> solve_shooting(
274  const Generalized_fubini_potential& potential, double true_min,
275  bool calculate_profile)
276 {
277  const double false_min = potential.get_local_minimum_location();
278  const double barrier = potential.get_local_maximum_location();
279 
280  const int dim = 4;
281 
282  unsigned int options
283  = calculate_profile ?
284  (Shooting::Solver_options::Compute_action |
285  Shooting::Solver_options::Compute_profile)
286  : Shooting::Solver_options::Compute_action;
287 
288  double action = 0.;
289  Field_profiles profile;
290 
291  Shooting profiler;
292  profiler.solve(potential, false_min, true_min, barrier, dim,
293  options);
294 
295  if ((options & Shooting::Solver_options::Compute_action) != 0) {
296  action = profiler.get_euclidean_action();
297  }
298 
299  if ((options & Shooting::Solver_options::Compute_profile) != 0) {
300  profile = profiler.get_bubble_profile();
301  }
302 
303  return std::make_tuple(action, profile);
304 }
305 
306 std::tuple<double, Field_profiles> solve_perturbative(
307  Generalized_fubini_potential& potential, double true_min,
308  const std::string& observer_file)
309 {
311 
312  RK4_perturbative_profiler profiler;
313 
314  profiler.set_initial_step_size(1.e-3);
315 
316  profiler.set_initial_guesser(std::make_shared<Kink_profile_guesser>());
317 
318  const double action_tol = 1.e-3;
319  const double fields_tol = 1.e-3;
320  profiler.set_convergence_tester(
321  std::make_shared<Relative_convergence_tester>(
322  action_tol, fields_tol));
323 
324  auto root_finder = std::make_shared<Root_finder>();
325  profiler.set_root_finder(root_finder);
326 
327  const int dim = 4;
328 
329  Eigen::VectorXd true_vacuum(1);
330  true_vacuum << true_min;
331 
332  Eigen::VectorXd false_vacuum(1);
333  false_vacuum << potential.get_local_minimum_location();
334 
335  profiler.set_number_of_dimensions(dim);
336  profiler.set_true_vacuum_loc(true_vacuum);
337  profiler.set_false_vacuum_loc(false_vacuum);
338 
339  double action = 0.;
340  Field_profiles profile;
341 
342  if (observer_file.empty()) {
343  profiler.calculate_bubble_profile(potential);
344  } else {
345  Generalized_fubini_observer observer(potential, observer_file);
346  profiler.calculate_bubble_profile(potential, observer);
347  }
348  action = profiler.get_euclidean_action();
349  profile = profiler.get_bubble_profile();
350 
351  return std::make_tuple(action, profile);
352 }
353 
354 void write_profile(std::ostream& ostr, const Field_profiles& numerical_profile,
355  const Field_profiles& exact_profile)
356 {
357  ostr << "# "
358  << std::setw(16) << "rho" << ' '
359  << std::setw(16) << "numeric" << ' '
360  << std::setw(16) << "exact" << std::endl;
361 
362  const auto n_grid_points = numerical_profile.get_number_of_grid_points();
363  if (n_grid_points != exact_profile.get_number_of_grid_points()) {
364  throw Setup_error(
365  "number of grid points do not match in numerical and exact solution");
366  }
367 
368  const auto rho_values = numerical_profile.get_spatial_grid();
369  const auto numerical_values = numerical_profile.get_field_profiles();
370  const auto exact_values = exact_profile.get_field_profiles();
371 
372  for (int i = 0; i < n_grid_points; ++i) {
373  ostr << " "
374  << std::setw(16) << std::setprecision(8)
375  << std::scientific << rho_values(i) << ' '
376  << std::setw(16) << std::setprecision(8)
377  << std::scientific << numerical_values(i, 0) << ' '
378  << std::setw(16) << std::setprecision(8)
379  << std::scientific << exact_values(i, 0) << std::endl;
380  }
381 }
382 
383 void write_action(std::ostream& ostr, double numerical_action,
384  double exact_action)
385 {
386  const double rel_diff = (numerical_action - exact_action)
387  / (0.5 * (numerical_action + exact_action));
388 
389  ostr << "# Numerical action = "
390  << std::setprecision(8) << std::scientific << numerical_action
391  << std::endl;
392  ostr << "# Exact action = "
393  << std::setprecision(8) << std::scientific << exact_action
394  << std::endl;
395  ostr << "# Relative error = "
396  << std::setprecision(8) << std::scientific << rel_diff
397  << std::endl;
398 }
399 
400 } // namespace BubbleProfiler
401 
402 int main(int argc, const char* argv[])
403 {
404  using namespace BubbleProfiler;
405 
406  if (argc == 1) {
407  std::cerr << "Usage: fubini [OPTION] <u> <v> <m>\n"
408  << "Try 'fubini --help' for more information."
409  << std::endl;
410  return EXIT_FAILURE;
411  }
412 
413  int exit_code = 0;
414  try {
415  Fubini_options options = parse_cmd_line_args(argc, argv);
416 
417  if (options.global_min <= 0.) {
418  options.global_min = 2.;
419  }
420 
421  if (options.verbose) {
424  }
425 
426  Generalized_fubini_potential potential(options.u, options.v, options.m);
427 
428  // Sanity check on potential
429  const double local_min = potential.get_local_minimum_location();
430  if (potential(options.global_min) > potential(local_min)) {
431  throw Setup_error(
432  "true minimum of potential greater than false minimum");
433  }
434 
435  std::tuple<double, Field_profiles> result;
436  if (options.use_perturbative) {
437  result = solve_perturbative(potential, options.global_min,
438  options.perturbations_file);
439  } else {
440  result = solve_shooting(potential, options.global_min,
441  options.calculate_profile);
442  }
443 
444  std::ofstream output_file;
445  if (!options.output_file.empty()) {
446  output_file.open(options.output_file, std::ios::out);
447  }
448 
449  std::ostream& output_stream
450  = (options.output_file.empty() ? std::cout : output_file);
451 
452  if (options.calculate_profile) {
453  const Field_profiles profiles = std::get<1>(result);
454  const Field_profiles exact_profile
455  = potential.get_profile(profiles.get_spatial_grid());
456  write_profile(output_stream, std::get<1>(result), exact_profile);
457  }
458 
459  const double exact_action = potential.get_action();
460  write_action(output_stream, std::get<0>(result), exact_action);
461  } catch (const Setup_error& e) {
462  std::cerr << "Error: " << e.what() << std::endl;
463  exit_code = EXIT_FAILURE;
464  } catch (const BVP_solver_error& e) {
465  std::cerr << "Error: " << e.what() << std::endl;
466  exit_code = EXIT_FAILURE;
467  } catch (const Numerical_error& e) {
468  std::cerr << "Error: " << e.what() << std::endl;
469  exit_code = EXIT_FAILURE;
470  } catch (const Error& e) {
471  std::cerr << "Error: " << e.what() << std::endl;
472  exit_code = EXIT_FAILURE;
473  } catch (...) {
474  std::cerr << "Error: unrecognized error occurred."
475  << std::endl;
476  exit_code = EXIT_FAILURE;
477  }
478 
479  return exit_code;
480 }
contains the definition of the Field_profiles clas
Exception indicating failure to integrate BVP.
Definition: error.hpp:44
void parse_positional_args(const std::vector< std::string > &args, Fubini_options &options)
std::tuple< double, Field_profiles > solve_perturbative(Generalized_fubini_potential &potential, double true_min, const std::string &observer_file)
void set_initial_guesser(std::shared_ptr< Profile_guesser > g)
const Eigen::VectorXd & get_spatial_grid() const
Get a vector of the grid point coordinates.
void set_false_vacuum_loc(const Eigen::VectorXd &fv)
Bubble_profiler_inputs parse_cmd_line_args(int argc, const char *argv[])
void solve(const std::function< double(double)> &potential_, const std::function< double(double)> &potential_first_, const std::function< double(double)> &potential_second_, double false_min_, double true_min_, double barrier_, int dim_=3, unsigned int options=(Solver_options::Compute_action|Solver_options::Compute_profile))
Definition: shooting.cpp:81
void set_root_finder(std::shared_ptr< Root_finder< Eigen::VectorXd > > rf)
double get_euclidean_action() const
Retrieve the action after running calculate_bubble_profile.
std::string get_option_value(const std::string &option, const std::string &sep="=")
void write_profile(std::ostream &ostr, const Field_profiles &numerical_profile, const Field_profiles &exact_profile)
void set_convergence_tester(std::shared_ptr< Profile_convergence_tester > ct)
static Logging_manager & get_manager()
const Field_profiles & get_bubble_profile() const
Definition: shooting.cpp:48
double get_euclidean_action() const
Definition: shooting.cpp:40
std::tuple< double, Field_profiles > solve_shooting(const Generalized_fubini_potential &potential, double true_min, bool calculate_profile)
int main(int argc, const char *argv[])
void write_action(double action, std::ostream &ostr)
Write the value of the action to requested output stream.
double parse_global_min(const std::string &value)
Solve the one-dimensional problem using the shooting method.
Definition: shooting.hpp:44
Exception indicating general setup error.
Definition: error.hpp:32
One-dimensional shooting method.
bool starts_with(const std::string &option, const std::string &prefix)
Exception indicating generic numerical error.
Definition: error.hpp:116
const Field_profiles & get_bubble_profile() const
Retrieve the field profiles after running calculate_bubble_profile.
Discretized set of field profiles.
Bounce solver using perturbative method.
const Eigen::MatrixXd & get_field_profiles() const
Get the field profile data in matrix form.
Field_profiles get_profile(const Eigen::VectorXd &) const