Version: SMASH-3.1
rootsolver.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2023
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_SMASH_ROOTSOLVER_H_
11 #define SRC_INCLUDE_SMASH_ROOTSOLVER_H_
12 
13 #include <functional>
14 #include <memory>
15 #include <optional>
16 #include <string>
17 
18 #include "gsl/gsl_errno.h"
19 #include "gsl/gsl_math.h"
20 #include "gsl/gsl_roots.h"
21 
22 #include "logging.h"
23 
24 namespace smash {
25 static constexpr int LRootSolver = LogArea::RootSolver::id;
30 class RootSolver1D {
31  public:
37  explicit RootSolver1D(std::function<double(double)> eq) {
38  root_eq_ = std::make_unique<std::function<double(double)>>(eq);
39  }
40 
41  ~RootSolver1D() { root_eq_ = nullptr; }
42 
51  std::optional<double> try_find_root(double initial_guess_low,
52  double initial_guess_high,
53  size_t itermax) {
54  // check if root is in the given interval
55  if ((*root_eq_)(initial_guess_low) * (*root_eq_)(initial_guess_high) > 0) {
56  logg[LRootSolver].debug()
57  << "Function has same sign at both ends of the interval ["
58  << initial_guess_low << ", " << initial_guess_high
59  << "]. Root can't be found in this interval.";
60  return std::nullopt;
61  }
62  gsl_function function_GSL = {&(gsl_func), nullptr};
63  int status = GSL_CONTINUE;
64  size_t iter = 0;
65  Root_finder_ = gsl_root_fsolver_alloc(Solver_name_);
66  gsl_root_fsolver_set(Root_finder_, &function_GSL, initial_guess_low,
67  initial_guess_high);
68  do {
69  iter++;
70  status = gsl_root_fsolver_iterate(Root_finder_);
71  if (status != GSL_SUCCESS) {
72  logg[LRootSolver].debug("GSL ERROR in root finding: " +
73  static_cast<std::string>(gsl_strerror(status)));
74  break;
75  }
76  double xlow = gsl_root_fsolver_x_lower(Root_finder_);
77  double xhigh = gsl_root_fsolver_x_upper(Root_finder_);
78  status = gsl_root_test_interval(xlow, xhigh, 0, solution_precision_);
79  if (status == GSL_SUCCESS) {
80  double root = 0.5 * (xlow + xhigh);
81  gsl_root_fsolver_free(Root_finder_);
82  return root;
83  }
84  } while (status == GSL_CONTINUE && iter < itermax);
85  gsl_root_fsolver_free(Root_finder_);
86  return std::nullopt;
87  }
88 
89  private:
91  const gsl_root_fsolver_type *Solver_name_ = gsl_root_fsolver_brent;
92 
94  gsl_root_fsolver *Root_finder_ = nullptr;
95 
103  static inline std::unique_ptr<std::function<double(double)>> root_eq_ =
104  nullptr;
105 
107  double solution_precision_ = 1e-7;
108 
125  static double gsl_func(const double x, void *) { return (*root_eq_)(x); }
126 };
127 
128 } // namespace smash
129 
130 #endif // SRC_INCLUDE_SMASH_ROOTSOLVER_H_
A class used for calculating the root of a one-dimensional equation.
Definition: rootsolver.h:30
RootSolver1D(std::function< double(double)> eq)
Construct a new Root Solver 1D object.
Definition: rootsolver.h:37
double solution_precision_
Expected precision of the root.
Definition: rootsolver.h:107
gsl_root_fsolver * Root_finder_
GSL root finding object to take care of root finding.
Definition: rootsolver.h:94
const gsl_root_fsolver_type * Solver_name_
GSL solver to use for root finding.
Definition: rootsolver.h:91
static double gsl_func(const double x, void *)
The function of which a root should be found in the form that GSL expects.
Definition: rootsolver.h:125
std::optional< double > try_find_root(double initial_guess_low, double initial_guess_high, size_t itermax)
Attempt to find a root in a given interval.
Definition: rootsolver.h:51
static std::unique_ptr< std::function< double(double)> > root_eq_
Static pointer to the function to solve.
Definition: rootsolver.h:103
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
Definition: action.h:24
static constexpr int LRootSolver
Definition: rootsolver.h:25