-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
scalar_initial_value_problem.h
143 lines (129 loc) Β· 6.31 KB
/
scalar_initial_value_problem.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#pragma once
#include <memory>
#include <optional>
#include <utility>
#include "drake/common/default_scalars.h"
#include "drake/common/drake_copyable.h"
#include "drake/common/eigen_types.h"
#include "drake/systems/analysis/initial_value_problem.h"
#include "drake/systems/analysis/scalar_view_dense_output.h"
namespace drake {
namespace systems {
/// A thin wrapper of the InitialValueProblem class to provide a simple
/// interface when solving scalar initial value problems i.e. when evaluating
/// the x(t; π€) solution function to the given ODE dx/dt = f(t, x; π€),
/// where f : t β¨― x β β , t β β, x β β, π€ β βα΅, along with an initial
/// condition x(tβ; π€) = xβ. The parameter vector π€ allows for generic IVP
/// definitions, which can later be solved for any instance of said vector.
///
/// Note the distinction from general initial value problems where
/// f : t β¨― π± β ββΏ and π± β ββΏ, addressed by the class being wrapped. While
/// every scalar initial value problem could be written in vector form, this
/// wrapper keeps both problem definition and solution in their scalar form
/// with almost zero overhead, leading to clearer code if applicable.
/// Moreover, this scalar form facilitates single-dimensional quadrature
/// using methods for solving initial value problems.
///
/// See InitialValueProblem class documentation for information on caching
/// support and dense output usage for improved efficiency in scalar IVP
/// solving.
///
/// For further insight into its use, consider the following examples of scalar
/// IVPs:
///
/// - The population growth of an hypothetical bacteria colony is described
/// by dN/dt = r * N. The colony has Nβ subjects at time tβ. In this
/// context, x β N, xβ β Nβ, π€ β [r], dx/dt = f(t, x; π€) = π€β * x.
///
/// - The charge Q stored in the capacitor of a (potentially equivalent) series
/// RC circuit driven by a time varying voltage source E(t) can be described
/// by dQ/dt = (E(t) - Q / Cs) / Rs, where Rs refers to the resistor's
/// resistance and Cs refers to the capacitor's capacitance. In this context,
/// and assuming an initial stored charge Qβ at time tβ, x β Q, π€ β [Rs, Cs],
/// xβ β Qβ, dx/dt = f(t, x; π€) = (E(t) - x / π€β) / π€β.
///
/// @tparam_nonsymbolic_scalar
template <typename T>
class ScalarInitialValueProblem {
public:
DRAKE_NO_COPY_NO_MOVE_NO_ASSIGN(ScalarInitialValueProblem);
/// Scalar ODE dx/dt = f(t, x; π€) function type.
///
/// @param t The independent variable t β β .
/// @param x The dependent variable x β β .
/// @param k The parameter vector π€ β βα΅.
/// @return The derivative dx/dt β β.
using ScalarOdeFunction =
std::function<T(const T& t, const T& x, const VectorX<T>& k)>;
/// Constructs a scalar IVP described by the given @p scalar_ode_function,
/// using given @p x0 as initial conditions, and parameterized with @p k.
///
/// @param scalar_ode_function The ODE function f(t, π±; π€) that describes
/// the state evolution over time. @param x0 The initial state π±β β β.
/// @param k The parameter vector π€ β βα΅. By default m=0 (no parameters).
ScalarInitialValueProblem(
const ScalarOdeFunction& scalar_ode_function, const T& x0,
const Eigen::Ref<const VectorX<T>>& k = Vector0<T>{});
/// Solves the IVP from time @p t0 up to time @p tf, using the initial state
/// π±β and parameter vector π€ provided in the constructor.
/// @throws std::exception if t0 > tf.
T Solve(const T& t0, const T& tf) const;
/// Solves and yields an approximation of the IVP solution x(t; π€) for the
/// closed time interval between the initial time @p t0 and the final time @p
/// tf, using initial state π±β and parameter vector π€ provided in the
/// constructor.
///
/// To this end, the wrapped IntegratorBase instance solves this IVP,
/// advancing time and state from tβ and π±β = π±(@p t0) to @p tf and π±(@p
/// tf), creating a dense output over that [@p t0, @p tf] interval along the
/// way.
///
/// @param tf The IVP will be solved up to this time, which must be β₯ @p t0.
/// Usually, @p t0 < @p tf as an empty dense output would result if @p t0 =
/// @p tf.
/// @returns A dense approximation to π±(t; π€) with π±(t0; π€) = π±β,
/// defined for t0 β€ t β€ tf.
/// @note The larger the given @p tf value is, the larger the approximated
/// interval will be. See documentation of the specific dense output
/// technique in use for reference on performance impact as this
/// interval grows.
/// @throws std::exception if t0 > tf.
std::unique_ptr<ScalarDenseOutput<T>> DenseSolve(const T& t0,
const T& tf) const;
/// Resets the internal integrator instance by in-place
/// construction of the given integrator type.
///
/// A usage example is shown below.
/// @code{.cpp}
/// scalar_ivp.reset_integrator<RungeKutta2Integrator<T>>(max_step);
/// @endcode
///
/// @param args The integrator type-specific arguments.
/// @returns The new integrator instance.
/// @tparam Integrator The integrator type, which must be an
/// IntegratorBase subclass.
/// @tparam Args The integrator specific argument types.
/// @warning This operation invalidates pointers returned by
/// ScalarInitialValueProblem::get_integrator() and
/// ScalarInitialValueProblem::get_mutable_integrator().
template <typename Integrator, typename... Args>
Integrator* reset_integrator(Args&&... args) {
return vector_ivp_->template reset_integrator<Integrator>(
std::forward<Args>(args)...);
}
/// Gets a reference to the internal integrator instance.
const IntegratorBase<T>& get_integrator() const {
return vector_ivp_->get_integrator();
}
/// Gets a mutable reference to the internal integrator instance.
IntegratorBase<T>& get_mutable_integrator() {
return vector_ivp_->get_mutable_integrator();
}
private:
// Vector IVP representation of this scalar IVP.
std::unique_ptr<InitialValueProblem<T>> vector_ivp_;
};
} // namespace systems
} // namespace drake
DRAKE_DECLARE_CLASS_TEMPLATE_INSTANTIATIONS_ON_DEFAULT_NONSYMBOLIC_SCALARS(
class drake::systems::ScalarInitialValueProblem)