BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
relative_convergence_tester.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 "euclidean_action.hpp"
26 #include "field_profiles.hpp"
27 #include "math_wrappers.hpp"
28 #include "potential.hpp"
29 
30 #include <algorithm>
31 #include <cmath>
32 #include <limits>
33 #include <sstream>
34 #include <string>
35 
36 namespace BubbleProfiler {
37 
39  double action_tol_, double fields_tol_)
40  : action_relative_tol(action_tol_)
41  , field_vals_relative_tol(fields_tol_)
42 {
44 }
45 
47  : Relative_convergence_tester(tol, tol)
48 {
49 }
50 
52  const Potential& potential, const Field_profiles& profiles)
53 {
54  bool converged = false;
55  const double current_action = calculate_action(potential, profiles);
56  const double domain_start = profiles.get_domain_start();
57  const Eigen::VectorXd current_field_vals = profiles.evaluate_at(domain_start);
58 
59  if (iteration_count > 0) {
60  converged = check_action_converged(current_action) &&
61  check_fields_converged(domain_start, current_field_vals);
62  }
63 
64  old_action = current_action;
65  old_field_vals = current_field_vals;
67 
68  if (converged) {
70  logger.log_message(logging::Log_level::Trace, "Relative change in action < "
71  + std::to_string(action_relative_tol));
72  logger.log_message(logging::Log_level::Trace, "Relative changes in fields at (r = "
73  + std::to_string(domain_start) + ") < "
74  + std::to_string(field_vals_relative_tol));
75  }
76 
77  return converged;
78 }
79 
81 {
82  const auto min_tol = std::min(action_relative_tol, field_vals_relative_tol);
83  return static_cast<int>(-std::log10(min_tol) * 10);
84 }
85 
87  double x, double y) const
88 {
89  const double ax = Abs(x);
90  const double ay = Abs(y);
91  const double largest = std::max(ax, ay);
92 
93  const double underflow = std::numeric_limits<double>::min();
94 
95  if (largest < underflow) {
96  return 0.;
97  }
98 
99  return Abs(x - y) / largest;
100 }
101 
103 {
104  const double action_diff = relative_difference(action, old_action);
105 
106  logger.log_message(logging::Log_level::Trace, "Relative change in action = "
107  + std::to_string(action_diff));
108 
109  const bool action_converged = action_diff < action_relative_tol;
110 
111  std::stringstream log_str;
112  log_str << "Action converged = " << (action_converged ? "true" : "false");
114 
115  return action_converged;
116 }
117 
119  double domain_start, const Eigen::VectorXd& field_vals) const
120 {
121  const int n_fields = field_vals.size();
122 
123  if (n_fields != old_field_vals.size()) {
124  throw Setup_error(
125  "Relative_convergence_tester::check_fields_converged: "
126  "number of field values does not match previous number");
127  }
128 
129  std::vector<double> field_diffs(n_fields);
130  for (int i = 0; i < n_fields; ++i) {
131  field_diffs[i] = relative_difference(field_vals(i), old_field_vals(i));
132  logger.log_message(logging::Log_level::Trace, "Field_" + std::to_string(i)
133  + "(r = " + std::to_string(domain_start) + ") = "
134  + std::to_string(field_vals(i)));
135  }
136  const double max_diff = *std::max_element(field_diffs.cbegin(), field_diffs.cend());
137 
138  logger.log_message(logging::Log_level::Trace, "Maximum relative change in fields (at r = 0) = "
139  + std::to_string(max_diff));
140 
141  const bool fields_converged = max_diff < field_vals_relative_tol;
142  std::stringstream log_str;
143  log_str << "Fields converged = " << + (fields_converged ? "true" : "false");
145 
146 
147  return fields_converged;
148 }
149 
151 {
152  iteration_count = 0.;
153  old_action = 0.;
154  old_field_vals = Eigen::VectorXd::Zero(old_field_vals.size());
155 }
156 
157 } // namespace BubbleProfiler
contains the definition of the Field_profiles clas
contains helper functions for calculating the Euclidean action
T Abs(T x) noexcept
virtual bool is_converged(const Potential &potential, const Field_profiles &profiles) override
Check whether the candidate bubble solution has converged.
bool check_fields_converged(double, const Eigen::VectorXd &) const
virtual void restart() override
Restart the convergence tester to the start of the iteration.
void log_message(Log_level level, const std::string &msg) const
Relative_convergence_tester()=default
Construct relative convergence tester with default tolerances.
Eigen::VectorXd evaluate_at(double rho) const
Get all field values at a given radius.
Exception indicating general setup error.
Definition: error.hpp:32
Abstract base class for a generic potential.
Definition: potential.hpp:36
double calculate_action(const Potential &potential, const Field_profiles &profiles, std::size_t max_intervals=1000, double rel_tol=1.e-4, double abs_tol=1.e-4, Integration_rule rule=Integration_rule::GK31, bool use_kinetic=true)
Calculates the action using either the kinetic or potential terms.
Discretized set of field profiles.