integrator.h Source File

CPP API: integrator.h Source File
integrator.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2020-2026 MEmilio
3 *
4 * Authors: Daniel Abele
5 *
6 * Contact: Martin J. Kuehn <Martin.Kuehn@DLR.de>
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 #ifndef INTEGRATOR_H
21 #define INTEGRATOR_H
22 
23 #include "memilio/config.h"
26 #include "memilio/utils/logging.h"
27 #include <memory>
28 #include <functional>
29 
30 namespace mio
31 {
32 
37 template <typename FP>
39  std::function<void(Eigen::Ref<const Eigen::VectorX<FP>> y, FP t, Eigen::Ref<Eigen::VectorX<FP>> dydt)>;
40 
46 template <typename FP, class... Integrands>
48 {
49 public:
57  IntegratorCore(const FP& dt_min, const FP& dt_max)
58  : m_dt_min(dt_min)
59  , m_dt_max(dt_max)
60  {
61  }
62 
63  virtual ~IntegratorCore() {};
64 
65  virtual std::unique_ptr<IntegratorCore<FP, Integrands...>> clone() const = 0;
66 
92  virtual bool step(const Integrands&... fs, Eigen::Ref<const Eigen::VectorX<FP>> yt, FP& t, FP& dt,
93  Eigen::Ref<Eigen::VectorX<FP>> ytp1) const = 0;
94 
102  {
103  return m_dt_min;
104  }
105  const FP& get_dt_min() const
106  {
107  return m_dt_min;
108  }
118  {
119  return m_dt_max;
120  }
121  const FP& get_dt_max() const
122  {
123  return m_dt_max;
124  }
127 private:
129 };
130 
132 template <class FP>
134 
136 template <class FP>
138 
145 template <typename FP, class... Integrands>
147 {
148 public:
149  using Core = IntegratorCore<FP, Integrands...>;
154  SystemIntegrator(std::unique_ptr<Core>&& core)
155  : m_core(std::move(core))
156  , m_is_adaptive(false)
157  {
158  }
159 
161  : m_core(other.m_core->clone())
163  {
164  }
165 
167  {
168  if (this != &other) {
169  m_core = other.m_core->clone();
171  }
172  return *this;
173  }
174 
184  Eigen::Ref<Eigen::VectorX<FP>> advance(const Integrands&... fs, const FP tmax, FP& dt, TimeSeries<FP>& results)
185  {
186  // hint at std functions for ADL
187  using std::ceil;
188  using std::fabs;
189  using std::max;
190  using std::min;
191  const FP t0 = results.get_last_time();
192  const FP eps = Limits<FP>::zero_tolerance();
193  assert(tmax > t0);
194  assert(dt > 0);
195 
196  const auto num_steps =
197  static_cast<size_t>(ceil((tmax - t0) / dt)); // estimated number of time steps (if equidistant)
198 
199  results.reserve(results.get_num_time_points() + num_steps);
200 
201  bool step_okay = true;
202 
203  FP dt_copy; // used to check whether step sizing is adaptive
204  FP dt_restore = 0.0; // used to restore dt, if dt was decreased to reach tmax
205  FP dt_min_restore = m_core->get_dt_min(); // used to restore dt_min, if it was decreased to reach tmax
206  FP t = t0;
207 
208  for (size_t i = results.get_num_time_points() - 1; fabs((tmax - t) / (tmax - t0)) > eps; ++i) {
209  // We don't make time steps too small as the error estimator of an adaptive integrator
210  //may not be able to handle it. this is very conservative and maybe unnecessary,
211  //but also unlikely to happen. may need to be reevaluated.
212 
213  if (dt > tmax - t) {
214  dt_restore = dt;
215  dt = tmax - t;
216  // if necessary, also reduce minimal step size such that we do not step past tmax
217  m_core->get_dt_min() = min<FP>(tmax - t, m_core->get_dt_min());
218  // if dt_min was reduced, the following step will be the last due to dt == dt_min (see step method)
219  // dt_min must be restored after this loop
220  }
221 
222  dt_copy = dt;
223 
224  results.add_time_point();
225  step_okay &= m_core->step(fs..., results[i], t, dt, results[i + 1]);
226  results.get_last_time() = t;
227 
228  // if dt has been changed by step, register the current m_core as adaptive.
229  m_is_adaptive |= !floating_point_equal<FP>(dt, dt_copy, eps);
230  }
231  m_core->get_dt_min() = dt_min_restore; // restore dt_min
232  // if dt was decreased to reach tmax in the last time iteration,
233  // we restore it as it is now probably smaller than required for tolerances
234  dt = max<FP>(dt, dt_restore);
235 
236  if (m_is_adaptive) {
237  if (!step_okay) {
238  log_warning("Adaptive step sizing failed. Forcing an integration step of size dt_min.");
239  }
240  else if (fabs((tmax - t) / (tmax - t0)) > eps) {
241  log_warning("Last time step too small. Could not reach tmax exactly.");
242  }
243  else {
244  log_info("Adaptive step sizing successful to tolerances.");
245  }
246  }
247 
248  return results.get_last_value();
249  }
250 
255  void set_integrator_core(std::unique_ptr<Core>&& core)
256  {
257  m_core.swap(core);
258  m_is_adaptive = false;
259  }
260 
267  {
268  return *m_core;
269  }
270  const Core& get_integrator_core() const
271  {
272  return *m_core;
273  }
274 
275 private:
276  std::unique_ptr<Core> m_core;
278 };
279 
284 template <typename FP>
286 
292 template <typename FP>
294 
295 } // namespace mio
296 
297 #endif // INTEGRATOR_H
Interface class defining the integration step used in a SystemIntegrator.
Definition: integrator.h:48
FP m_dt_max
Definition: integrator.h:128
FP & get_dt_min()
Access lower bound to the step size dt.
Definition: integrator.h:101
FP m_dt_min
Definition: integrator.h:128
const FP & get_dt_max() const
Access upper bound to the step size dt.
Definition: integrator.h:121
const FP & get_dt_min() const
Access lower bound to the step size dt.
Definition: integrator.h:105
virtual bool step(const Integrands &... fs, Eigen::Ref< const Eigen::VectorX< FP >> yt, FP &t, FP &dt, Eigen::Ref< Eigen::VectorX< FP >> ytp1) const =0
Make a single integration step.
IntegratorCore(const FP &dt_min, const FP &dt_max)
Initialize an IntegratorCore.
Definition: integrator.h:57
virtual std::unique_ptr< IntegratorCore< FP, Integrands... > > clone() const =0
FP & get_dt_max()
Access upper bound to the step size dt.
Definition: integrator.h:117
virtual ~IntegratorCore()
Definition: integrator.h:63
Integrate a system of equations over time.
Definition: integrator.h:147
SystemIntegrator(const SystemIntegrator &other)
Definition: integrator.h:160
Eigen::Ref< Eigen::VectorX< FP > > advance(const Integrands &... fs, const FP tmax, FP &dt, TimeSeries< FP > &results)
Advance the integrator.
Definition: integrator.h:184
SystemIntegrator(std::unique_ptr< Core > &&core)
Create an integrator for a specific IVP.
Definition: integrator.h:154
Core & get_integrator_core()
Access the IntegratorCore used for integration.
Definition: integrator.h:266
void set_integrator_core(std::unique_ptr< Core > &&core)
Change the IntegratorCore used for integration.
Definition: integrator.h:255
const Core & get_integrator_core() const
Access the IntegratorCore used for integration.
Definition: integrator.h:270
std::unique_ptr< Core > m_core
Access the IntegratorCore used for integration.
Definition: integrator.h:276
SystemIntegrator & operator=(const SystemIntegrator &other)
Definition: integrator.h:166
bool m_is_adaptive
Access the IntegratorCore used for integration.
Definition: integrator.h:277
stores vectors of values at time points (or some other abstract variable) the value at each time poin...
Definition: time_series.h:58
void reserve(Eigen::Index n)
reserve capacity for n time points
Definition: time_series.h:332
FP & get_last_time()
time of time point at index num_time_points - 1
Definition: time_series.h:286
Eigen::Index get_num_time_points() const
number of time points in the series
Definition: time_series.h:197
Eigen::Ref< Vector > add_time_point()
add one uninitialized time point
Definition: time_series.h:221
Eigen::Ref< const Vector > get_last_value() const
reference to value vector at time point (num_timepoints - 1)
Definition: time_series.h:320
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type min(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2599
static min_max_return_type< ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > >::type max(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &a, const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &b)
Definition: ad.hpp:2596
static double ceil(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x)
Definition: ad.hpp:2449
ad::internal::unary_intermediate< AD_TAPE_REAL, ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 >, ad::operations::ad_fabs< AD_TAPE_REAL > > fabs(const ad::internal::active_type< AD_TAPE_REAL, DATA_HANDLER_1 > &x1)
Definition: ad.hpp:1133
A collection of classes to simplify handling of matrix shapes in meta programming.
Definition: models/abm/analyze_result.h:30
auto i
Definition: io.h:809
void log_warning(spdlog::string_view_t fmt, const Args &... args)
Definition: logging.h:112
void log_info(spdlog::string_view_t fmt, const Args &... args)
Definition: logging.h:94
std::function< void(Eigen::Ref< const Eigen::VectorX< FP > > y, FP t, Eigen::Ref< Eigen::VectorX< FP > > dydt)> DerivFunction
Function template to be integrated.
Definition: integrator.h:39
Definition: io.h:94
static constexpr FP zero_tolerance()=delete