Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <cstdint>
8 : #include <pup.h>
9 : #include <type_traits>
10 :
11 : #include "DataStructures/MathWrapper.hpp"
12 : #include "Time/History.hpp"
13 : #include "Utilities/GenerateInstantiations.hpp"
14 : #include "Utilities/Gsl.hpp"
15 : #include "Utilities/Serialization/CharmPupable.hpp"
16 :
17 : /// \cond
18 : class TimeDelta;
19 : class TimeStepId;
20 : /// \endcond
21 :
22 : /// \ingroup TimeSteppersGroup
23 : ///
24 : /// Holds classes that take time steps.
25 : namespace TimeSteppers {}
26 :
27 : /// \cond
28 : #define TIME_STEPPER_WRAPPED_TYPE(data) BOOST_PP_TUPLE_ELEM(0, data)
29 : #define TIME_STEPPER_DERIVED_CLASS(data) BOOST_PP_TUPLE_ELEM(1, data)
30 : /// \endcond
31 :
32 : /// \ingroup TimeSteppersGroup
33 : ///
34 : /// Abstract base class for TimeSteppers.
35 : ///
36 : /// Several of the member functions of this class are templated and
37 : /// perform type erasure before forwarding their arguments to the
38 : /// derived classes. This is implemented using the macros \ref
39 : /// TIME_STEPPER_DECLARE_OVERLOADS, which must be placed in a private
40 : /// section of the class body, and
41 : /// TIME_STEPPER_DEFINE_OVERLOADS(derived_class), which must be placed
42 : /// in the cpp file.
43 1 : class TimeStepper : public PUP::able {
44 : public:
45 0 : WRAPPED_PUPable_abstract(TimeStepper); // NOLINT
46 :
47 : /// \cond
48 : #define TIME_STEPPER_DECLARE_VIRTUALS_IMPL(_, data) \
49 : virtual void update_u_forward( \
50 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
51 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
52 : data)>& history, \
53 : const TimeDelta& time_step) const = 0; \
54 : virtual bool update_u_forward( \
55 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
56 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u_error, \
57 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
58 : data)>& history, \
59 : const TimeDelta& time_step) const = 0; \
60 : virtual bool dense_update_u_forward( \
61 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
62 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
63 : data)>& history, \
64 : const double time) const = 0; \
65 : virtual bool can_change_step_size_forward( \
66 : const TimeStepId& time_id, \
67 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
68 : data)>& history) const = 0;
69 :
70 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DECLARE_VIRTUALS_IMPL,
71 : (MATH_WRAPPER_TYPES))
72 : #undef TIME_STEPPER_DECLARE_VIRTUALS_IMPL
73 : /// \endcond
74 :
75 : /// Set \p u to the value at the end of the current substep.
76 : ///
77 : /// Derived classes must implement this as a function with signature
78 : ///
79 : /// ```
80 : /// template <typename T>
81 : /// void update_u_impl(gsl::not_null<T*> u,
82 : /// const MutableUntypedHistory<T>& history,
83 : /// const TimeDelta& time_step) const;
84 : /// ```
85 : template <typename Vars>
86 1 : void update_u(const gsl::not_null<Vars*> u,
87 : const gsl::not_null<TimeSteppers::History<Vars>*> history,
88 : const TimeDelta& time_step) const {
89 : return update_u_forward(&*make_math_wrapper(u), history->untyped(),
90 : time_step);
91 : }
92 :
93 : /// Set \p u to the value at the end of the current substep; report the error
94 : /// measure when available.
95 : ///
96 : /// For a substep method, the error measure will only be available on full
97 : /// steps. For a multistep method, the error measure will only be available
98 : /// when a sufficient number of steps are available in the `history` to
99 : /// compare two orders of step. Whenever the error measure is unavailable,
100 : /// `u_error` is unchanged and the function return is `false`.
101 : ///
102 : /// Derived classes must implement this as a function with signature
103 : ///
104 : /// ```
105 : /// template <typename T>
106 : /// bool update_u_impl(gsl::not_null<T*> u, gsl::not_null<T*> u_error,
107 : /// const MutableUntypedHistory<T>& history,
108 : /// const TimeDelta& time_step) const;
109 : /// ```
110 : template <typename Vars, typename ErrVars>
111 1 : bool update_u(const gsl::not_null<Vars*> u,
112 : const gsl::not_null<ErrVars*> u_error,
113 : const gsl::not_null<TimeSteppers::History<Vars>*> history,
114 : const TimeDelta& time_step) const {
115 : static_assert(
116 : std::is_same_v<math_wrapper_type<Vars>, math_wrapper_type<ErrVars>>);
117 : return update_u_forward(&*make_math_wrapper(u),
118 : &*make_math_wrapper(u_error), history->untyped(),
119 : time_step);
120 : }
121 :
122 : /// Compute the solution value at a time between steps. To evaluate
123 : /// at a time within a given step, call this method at the start of
124 : /// the step containing the time. The function returns true on
125 : /// success, otherwise the call should be retried after the next
126 : /// substep.
127 : ///
128 : /// Derived classes must implement this as a function with signature
129 : ///
130 : /// ```
131 : /// template <typename T>
132 : /// bool dense_update_u_impl(
133 : /// gsl::not_null<T*> u, const ConstUntypedHistory<T>& history,
134 : /// double time) const;
135 : /// ```
136 : template <typename Vars>
137 1 : bool dense_update_u(const gsl::not_null<Vars*> u,
138 : const TimeSteppers::History<Vars>& history,
139 : const double time) const {
140 : return dense_update_u_forward(&*make_math_wrapper(u), history.untyped(),
141 : time);
142 : }
143 :
144 : /// The convergence order of the stepper
145 1 : virtual size_t order() const = 0;
146 :
147 : /// The convergence order of the stepper error measure
148 1 : virtual size_t error_estimate_order() const = 0;
149 :
150 : /// Number of substeps in this TimeStepper
151 1 : virtual uint64_t number_of_substeps() const = 0;
152 :
153 : /// Number of substeps in this TimeStepper when providing an error measure for
154 : /// adaptive time-stepping
155 : ///
156 : /// \details Certain substep methods (e.g. embedded RK4(3)) require additional
157 : /// steps when providing an error measure of the integration.
158 1 : virtual uint64_t number_of_substeps_for_error() const = 0;
159 :
160 : /// Number of past time steps needed for multi-step method
161 1 : virtual size_t number_of_past_steps() const = 0;
162 :
163 : /// Rough estimate of the maximum step size this method can take
164 : /// stably as a multiple of the step for Euler's method.
165 1 : virtual double stable_step() const = 0;
166 :
167 : /// The TimeStepId after the current substep
168 1 : virtual TimeStepId next_time_id(const TimeStepId& current_id,
169 : const TimeDelta& time_step) const = 0;
170 :
171 : /// The TimeStepId after the current substep when providing an error measure
172 : /// for adaptive time-stepping.
173 : ///
174 : /// Certain substep methods (e.g. embedded RK4(3)) require additional
175 : /// steps when providing an error measure of the integration.
176 1 : virtual TimeStepId next_time_id_for_error(
177 : const TimeStepId& current_id, const TimeDelta& time_step) const = 0;
178 :
179 : /// Whether a change in the step size is allowed before taking
180 : /// a step.
181 : ///
182 : /// Derived classes must implement this as a function with signature
183 : ///
184 : /// ```
185 : /// template <typename T>
186 : /// bool can_change_step_size_impl(
187 : /// const TimeStepId& time_id,
188 : /// const ConstUntypedHistory<T>& history) const;
189 : /// ```
190 : template <typename Vars>
191 1 : bool can_change_step_size(const TimeStepId& time_id,
192 : const TimeSteppers::History<Vars>& history) const {
193 : return can_change_step_size_forward(time_id, history.untyped());
194 : }
195 : };
196 :
197 : /// \cond
198 : #define TIME_STEPPER_DECLARE_OVERLOADS_IMPL(_, data) \
199 : void update_u_forward( \
200 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
201 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
202 : data)>& history, \
203 : const TimeDelta& time_step) const override; \
204 : bool update_u_forward( \
205 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
206 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u_error, \
207 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
208 : data)>& history, \
209 : const TimeDelta& time_step) const override; \
210 : bool dense_update_u_forward( \
211 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
212 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
213 : data)>& history, \
214 : double time) const override; \
215 : bool can_change_step_size_forward( \
216 : const TimeStepId& time_id, \
217 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
218 : data)>& history) const override;
219 :
220 : #define TIME_STEPPER_DEFINE_OVERLOADS_IMPL(_, data) \
221 : void TIME_STEPPER_DERIVED_CLASS(data)::update_u_forward( \
222 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
223 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
224 : data)>& history, \
225 : const TimeDelta& time_step) const { \
226 : return update_u_impl(u, history, time_step); \
227 : } \
228 : bool TIME_STEPPER_DERIVED_CLASS(data)::update_u_forward( \
229 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
230 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u_error, \
231 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
232 : data)>& history, \
233 : const TimeDelta& time_step) const { \
234 : return update_u_impl(u, u_error, history, time_step); \
235 : } \
236 : bool TIME_STEPPER_DERIVED_CLASS(data)::dense_update_u_forward( \
237 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
238 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
239 : data)>& history, \
240 : const double time) const { \
241 : return dense_update_u_impl(u, history, time); \
242 : } \
243 : bool TIME_STEPPER_DERIVED_CLASS(data)::can_change_step_size_forward( \
244 : const TimeStepId& time_id, \
245 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
246 : data)>& history) const { \
247 : return can_change_step_size_impl(time_id, history); \
248 : }
249 : /// \endcond
250 :
251 : /// \ingroup TimeSteppersGroup
252 : /// Macro declaring overloaded detail methods in classes derived from
253 : /// TimeStepper. Must be placed in a private section of the class
254 : /// body.
255 1 : #define TIME_STEPPER_DECLARE_OVERLOADS \
256 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DECLARE_OVERLOADS_IMPL, \
257 : (MATH_WRAPPER_TYPES))
258 :
259 : /// \ingroup TimeSteppersGroup
260 : /// Macro defining overloaded detail methods in classes derived from
261 : /// TimeStepper. Must be placed in the cpp file for the derived
262 : /// class.
263 1 : #define TIME_STEPPER_DEFINE_OVERLOADS(derived_class) \
264 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DEFINE_OVERLOADS_IMPL, \
265 : (MATH_WRAPPER_TYPES), (derived_class))
|