Skip to content

Commit aefb2f8

Browse files
committed
Replace Odeint with in-house RK4
1 parent 8de5101 commit aefb2f8

17 files changed

+568
-594
lines changed

.gitattributes

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ src/utils/*.cpp licensefile=.githooks/LICENSE-C++
5151
src/utils/cnpy.hpp !licensefile
5252
src/utils/cnpy.cpp !licensefile
5353
src/utils/Legendre.hpp !licensefile
54-
src/utils/RungeKutta4.* !licensefile
54+
src/utils/RungeKutta.hpp !licensefile
5555

5656
# tests
5757
tests/unit_tests.cpp licensefile=.githooks/LICENSE-C++

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- The implementation of the `RadialSolution` for the second order ODE
1717
associated with the spherical diffuse Green's function is less heavily
1818
`template`-d.
19+
- The dependency on Boost.Odeint has been dropped.
1920

2021
## [Version 1.2.0-rc1] - 2018-03-02
2122

src/green/InterfacesImpl.hpp

+52-45
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
#include <cmath>
2727
#include <fstream>
28+
#include <iomanip>
2829
#include <vector>
2930

3031
#include "Config.hpp"
@@ -34,37 +35,39 @@
3435
#ifndef HAS_CXX11
3536
#include <boost/foreach.hpp>
3637
#endif
37-
// Boost.Odeint includes
38-
#include <boost/numeric/odeint.hpp>
3938

4039
#include "utils/MathUtils.hpp"
41-
#include "utils/RungeKutta4.hpp"
40+
#include "utils/RungeKutta.hpp"
41+
#include "utils/SplineFunction.hpp"
4242

4343
/*! \file InterfacesImpl.hpp */
4444

4545
namespace pcm {
4646
namespace green {
4747
namespace detail {
48+
/*! \brief Abstract class for an system of ordinary differential equations
49+
* \tparam Order The order of the ordinary differential equation
50+
* \author Roberto Di Remigio
51+
* \date 2018
52+
*/
53+
template <size_t Order = 1> class ODESystem {
54+
public:
55+
typedef pcm::array<double, Order> StateType;
56+
size_t ODEorder() const { return Order; }
57+
void operator()(const StateType & f, StateType & dfdx, const double t) const {
58+
RHS(f, dfdx, t);
59+
}
60+
virtual ~ODESystem() {}
61+
62+
private:
63+
virtual void RHS(const StateType & f, StateType & dfdx, const double t) const = 0;
64+
};
4865

4966
/*! \typedef ProfileEvaluator
5067
* \brief sort of a function pointer to the dielectric profile evaluation function
5168
*/
5269
typedef pcm::function<pcm::tuple<double, double>(const double)> ProfileEvaluator;
5370

54-
/*! \struct IntegratorParameters
55-
* \brief holds parameters for the integrator
56-
*/
57-
struct IntegratorParameters {
58-
/*! Lower bound of the integration interval */
59-
double r_0_;
60-
/*! Upper bound of the integration interval */
61-
double r_infinity_;
62-
/*! Time step between observer calls */
63-
double observer_step_;
64-
IntegratorParameters(double r0, double rinf, double step)
65-
: r_0_(r0), r_infinity_(rinf), observer_step_(step) {}
66-
};
67-
6871
/*! \class LnTransformedRadial
6972
* \brief system of ln-transformed first-order radial differential equations
7073
* \author Roberto Di Remigio
@@ -73,25 +76,25 @@ struct IntegratorParameters {
7376
* Provides a handle to the system of differential equations for the integrator.
7477
* The dielectric profile comes in as a boost::function object.
7578
*/
76-
class LnTransformedRadial __final : public pcm::utils::detail::ODESystem<2> {
79+
class LnTransformedRadial __final : public pcm::green::detail::ODESystem<2> {
7780
public:
7881
/*! Type of the state vector of the ODE */
79-
typedef pcm::utils::detail::ODESystem<2>::StateType StateType;
82+
typedef pcm::green::detail::ODESystem<2>::StateType StateType;
8083
/*! Constructor from profile evaluator and angular momentum */
8184
LnTransformedRadial(const ProfileEvaluator & e, int lval) : eval_(e), l_(lval) {}
8285

8386
private:
8487
/*! Dielectric profile function and derivative evaluation */
85-
ProfileEvaluator eval_;
88+
const ProfileEvaluator eval_;
8689
/*! Angular momentum */
87-
int l_;
88-
/*! Provides a functor for the evaluation of the system
89-
* of first-order ODEs needed by Boost.Odeint
90-
* The second-order ODE and the system of first-order ODEs
91-
* are reported in the manuscript.
90+
const int l_;
91+
/*! \brief Provides a functor for the evaluation of the system of first-order ODEs.
9292
* \param[in] rho state vector holding the function and its first derivative
9393
* \param[out] drhodr state vector holding the first and second derivative
9494
* \param[in] y logarithmic position on the integration grid
95+
*
96+
* The second-order ODE and the system of first-order ODEs
97+
* are reported in the manuscript.
9598
*/
9699
virtual void RHS(const StateType & rho, StateType & drhodr, const double y) const {
97100
// Evaluate the dielectric profile
@@ -107,7 +110,6 @@ class LnTransformedRadial __final : public pcm::utils::detail::ODESystem<2> {
107110
};
108111
} // namespace detail
109112

110-
using detail::IntegratorParameters;
111113
using detail::ProfileEvaluator;
112114

113115
/*! \class RadialFunction
@@ -138,21 +140,25 @@ template <typename ODE> class RadialFunction __final {
138140
RadialFunction(int l,
139141
double ymin,
140142
double ymax,
141-
const ProfileEvaluator & eval,
142-
const IntegratorParameters & parms)
143+
double ystep,
144+
const ProfileEvaluator & eval)
143145
: L_(l),
144146
y_min_(ymin),
145147
y_max_(ymax),
146148
y_sign_(pcm::utils::sign(y_max_ - y_min_)) {
147-
compute(eval, parms);
149+
compute(ystep, eval);
148150
}
149151
pcm::tuple<double, double> operator()(double point) const {
150152
return pcm::make_tuple(function_impl(point), derivative_impl(point));
151153
}
152154
friend std::ostream & operator<<(std::ostream & os, RadialFunction & obj) {
153155
for (size_t i = 0; i < obj.function_[0].size(); ++i) {
154-
os << obj.function_[0][i] << " " << obj.function_[1][i] << " "
156+
// clang-format off
157+
os << std::fixed << std::left << std::setprecision(14)
158+
<< obj.function_[0][i] << " "
159+
<< obj.function_[1][i] << " "
155160
<< obj.function_[2][i] << std::endl;
161+
// clang-format on
156162
}
157163
return os;
158164
}
@@ -176,36 +182,36 @@ template <typename ODE> class RadialFunction __final {
176182
function_[2].push_back(x[1]);
177183
}
178184
/*! \brief Calculates radial solution
179-
* \param[in] eval dielectric profile evaluator function object
180-
* \param[in] parms parameters for the integrator
185+
* \param[in] step ODE integrator step
186+
* \param[in] eval dielectric profile evaluator function object
187+
* \return the number of integration steps
181188
*
182-
* This function discriminates between the first, i.e. the one with r^l
183-
* behavior, and the second radial solution, i.e. the one with r^(-l-1)
184-
* behavior, based on the sign of the integration interval y_sign_.
189+
* This function discriminates between the first (zeta-type), i.e. the one
190+
* with r^l behavior, and the second (omega-type) radial solution, i.e. the
191+
* one with r^(-l-1) behavior, based on the sign of the integration interval
192+
* y_sign_.
185193
*/
186-
void compute(const ProfileEvaluator & eval, const IntegratorParameters & parms) {
187-
namespace odeint = boost::numeric::odeint;
188-
odeint::runge_kutta4<StateType> stepper;
189-
194+
size_t compute(const double step, const ProfileEvaluator & eval) {
190195
ODE system(eval, L_);
191-
// Holds the initial conditions
192-
StateType init;
193196
// Set initial conditions
197+
StateType init;
194198
if (y_sign_ > 0.0) { // zeta-type solution
195199
init[0] = y_sign_ * L_ * y_min_;
196200
init[1] = y_sign_ * L_;
197201
} else { // omega-type solution
198202
init[0] = y_sign_ * (L_ + 1) * y_min_;
199203
init[1] = y_sign_ * (L_ + 1);
200204
}
201-
odeint::integrate_const(
205+
pcm::utils::RungeKutta4<StateType> stepper;
206+
size_t nSteps = pcm::utils::integrate_const(
202207
stepper,
203208
system,
204209
init,
205210
y_min_,
206211
y_max_,
207-
y_sign_ * parms.observer_step_,
212+
y_sign_ * step,
208213
pcm::bind(&RadialFunction<ODE>::push_back, this, pcm::_1, pcm::_2));
214+
209215
// clang-format off
210216
// Reverse order of function_ if omega-type solution was computed
211217
// this ensures that they are in ascending order, as later expected by
@@ -218,9 +224,10 @@ template <typename ODE> class RadialFunction __final {
218224
#endif /* HAS_CXX11 */
219225
std::reverse(comp.begin(), comp.end());
220226
}
221-
}
227+
// clang-format on
222228
}
223-
// clang-format on
229+
return nSteps;
230+
}
224231
/*! \brief Returns value of function at given point
225232
* \param[in] point evaluation point
226233
*

src/green/SphericalDiffuse.cpp

+16-19
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,10 @@ void SphericalDiffuse<ProfilePolicy>::toFile(const std::string & prefix) {
129129
writeToFile(zetaC_, tmp + "zetaC.dat");
130130
writeToFile(omegaC_, tmp + "omegaC.dat");
131131
for (int L = 1; L <= maxLGreen_; ++L) {
132-
writeToFile(zeta_[L], tmp + "zeta_" + pcm::to_string(L) + ".dat");
133-
writeToFile(omega_[L], tmp + "omega_" + pcm::to_string(L) + ".dat");
132+
std::ostringstream Llabel;
133+
Llabel << std::setw(4) << std::setfill('0') << L;
134+
writeToFile(zeta_[L], tmp + "zeta_" + Llabel.str() + ".dat");
135+
writeToFile(omega_[L], tmp + "omega_" + Llabel.str() + ".dat");
134136
}
135137
}
136138

@@ -240,35 +242,30 @@ void SphericalDiffuse<ProfilePolicy>::initSphericalDiffuse() {
240242
using namespace detail;
241243

242244
// Parameters for the numerical solution of the radial differential equation
243-
double r_0_ = 0.1; /*! Lower bound of the integration interval */
244-
double r_infinity_ = this->profile_.upperLimit() +
245-
30.0; /*! Upper bound of the integration interval */
246-
245+
/*! Lower bound of the integration interval */
246+
double r_0_ = 0.1;
247247
double y_0_ = std::log(r_0_);
248+
/*! Upper bound of the integration interval */
249+
double r_infinity_ = this->profile_.upperLimit() + 30.0;
248250
double y_infinity_ = std::log(r_infinity_);
249251
double relative_width = this->profile_.relativeWidth();
250-
double observer_step_ =
251-
1.0e-2 * relative_width; /*! Time step between observer calls */
252+
/*! Time step between observer calls */
253+
double step_ = 1.0e-2 * relative_width;
252254

253-
IntegratorParameters params_(y_0_, y_infinity_, observer_step_);
254255
ProfileEvaluator eval_ =
255256
pcm::bind(&ProfilePolicy::operator(), this->profile_, pcm::_1);
256257

257258
zetaC_ =
258-
RadialFunction<LnTransformedRadial>(maxLC_, y_0_, y_infinity_, eval_, params_);
259+
RadialFunction<LnTransformedRadial>(maxLC_, y_0_, y_infinity_, step_, eval_);
259260
omegaC_ =
260-
RadialFunction<LnTransformedRadial>(maxLC_, y_infinity_, y_0_, eval_, params_);
261+
RadialFunction<LnTransformedRadial>(maxLC_, y_infinity_, y_0_, step_, eval_);
261262
zeta_.reserve(maxLGreen_ + 1);
262263
omega_.reserve(maxLGreen_ + 1);
263264
for (int L = 0; L <= maxLGreen_; ++L) {
264-
RadialFunction<LnTransformedRadial> tmp_zeta_(
265-
L, y_0_, y_infinity_, eval_, params_);
266-
zeta_.push_back(tmp_zeta_);
267-
}
268-
for (int L = 0; L <= maxLGreen_; ++L) {
269-
RadialFunction<LnTransformedRadial> tmp_omega_(
270-
L, y_infinity_, y_0_, eval_, params_);
271-
omega_.push_back(tmp_omega_);
265+
zeta_.push_back(
266+
RadialFunction<LnTransformedRadial>(L, y_0_, y_infinity_, step_, eval_));
267+
omega_.push_back(
268+
RadialFunction<LnTransformedRadial>(L, y_infinity_, y_0_, step_, eval_));
272269
}
273270
}
274271

src/interface/Meddle.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ void Meddle::initInput(int nr_nuclei,
439439
Eigen::Matrix3Xd centers = Eigen::Map<Eigen::Matrix3Xd>(coordinates, 3, nr_nuclei);
440440

441441
if (input_.mode() != "EXPLICIT") {
442-
Symmetry pg = buildGroup(
442+
Symmetry pg(
443443
symmetry_info[0], symmetry_info[1], symmetry_info[2], symmetry_info[3]);
444444
input_.molecule(detail::initMolecule(input_, pg, nr_nuclei, chg, centers));
445445
}

src/utils/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ LoggerImpl.hpp
99
MathUtils.hpp
1010
Molecule.hpp
1111
QuadratureRules.hpp
12+
RungeKutta.hpp
1213
Solvent.hpp
1314
Sphere.hpp
1415
SplineFunction.hpp

0 commit comments

Comments
 (0)