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 <optional>
9 : #include <pup.h>
10 : #include <type_traits>
11 :
12 : #include "DataStructures/MathWrapper.hpp"
13 : #include "Time/History.hpp"
14 : #include "Time/StepperErrorEstimate.hpp"
15 : #include "Utilities/GenerateInstantiations.hpp"
16 : #include "Utilities/Gsl.hpp"
17 : #include "Utilities/Serialization/CharmPupable.hpp"
18 :
19 : /// \cond
20 : struct StepperErrorTolerances;
21 : class TimeDelta;
22 : class TimeStepId;
23 : /// \endcond
24 :
25 : /// \ingroup TimeSteppersGroup
26 : ///
27 : /// Holds classes that take time steps.
28 : namespace TimeSteppers {}
29 :
30 : /// \cond
31 : #define TIME_STEPPER_WRAPPED_TYPE(data) BOOST_PP_TUPLE_ELEM(0, data)
32 : #define TIME_STEPPER_DERIVED_CLASS(data) BOOST_PP_TUPLE_ELEM(1, data)
33 : #define TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) BOOST_PP_TUPLE_ELEM(2, data)
34 : /// \endcond
35 :
36 : /// \ingroup TimeSteppersGroup
37 : ///
38 : /// Abstract base class for TimeSteppers.
39 : ///
40 : /// Several of the member functions of this class are templated and
41 : /// perform type erasure before forwarding their arguments to the
42 : /// derived classes. This is implemented using the macros \ref
43 : /// TIME_STEPPER_DECLARE_OVERLOADS, which must be placed in a private
44 : /// section of the class body, and
45 : /// TIME_STEPPER_DEFINE_OVERLOADS(derived_class), which must be placed
46 : /// in the cpp file.
47 1 : class TimeStepper : public PUP::able {
48 : public:
49 0 : static constexpr bool local_time_stepping = false;
50 0 : static constexpr bool imex = false;
51 0 : using provided_time_stepper_interfaces = tmpl::list<TimeStepper>;
52 :
53 0 : WRAPPED_PUPable_abstract(TimeStepper); // NOLINT
54 :
55 : /// \cond
56 : #define TIME_STEPPER_DECLARE_VIRTUALS_IMPL(_, data) \
57 : virtual void update_u_forward( \
58 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
59 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
60 : data)>& history, \
61 : const TimeDelta& time_step) const = 0; \
62 : virtual std::optional<StepperErrorEstimate> update_u_forward( \
63 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
64 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
65 : data)>& history, \
66 : const TimeDelta& time_step, \
67 : const std::optional<StepperErrorTolerances>& tolerances) const = 0; \
68 : virtual void clean_history_forward( \
69 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
70 : data)>& history) const = 0; \
71 : virtual bool dense_update_u_forward( \
72 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
73 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
74 : data)>& history, \
75 : double time) const = 0; \
76 : virtual bool can_change_step_size_forward( \
77 : const TimeStepId& time_id, \
78 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
79 : data)>& history) const = 0;
80 :
81 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DECLARE_VIRTUALS_IMPL,
82 : (MATH_WRAPPER_TYPES))
83 : #undef TIME_STEPPER_DECLARE_VIRTUALS_IMPL
84 : /// \endcond
85 :
86 : /// Set \p u to the value at the end of the current substep.
87 : ///
88 : /// Derived classes must implement this as a function with signature
89 : ///
90 : /// ```
91 : /// template <typename T>
92 : /// void update_u_impl(gsl::not_null<T*> u,
93 : /// const ConstUntypedHistory<T>& history,
94 : /// const TimeDelta& time_step) const;
95 : /// ```
96 : template <typename Vars>
97 1 : void update_u(const gsl::not_null<Vars*> u,
98 : const TimeSteppers::History<Vars>& history,
99 : const TimeDelta& time_step) const {
100 : return update_u_forward(&*make_math_wrapper(u), history.untyped(),
101 : time_step);
102 : }
103 :
104 : /// Set \p u to the value at the end of the current substep; report the error
105 : /// measure when available.
106 : ///
107 : /// For a substep method, the error measure will only be available on full
108 : /// steps. For a multistep method, the error measure will only be available
109 : /// when a sufficient number of steps are available in the `history` to
110 : /// compare two orders of step. Whenever the error measure is unavailable,
111 : /// the return value is empty
112 : ///
113 : /// If \p tolerances is empty, no error measures are calculated, but
114 : /// any additional substeps necessary for error estimation are still
115 : /// taken. This is useful when a system integrates multiple
116 : /// variables in separate calls to the TimeStepper, but only uses
117 : /// estimates from some of them.
118 : ///
119 : /// Derived classes must implement this as a function with signature
120 : ///
121 : /// ```
122 : /// template <typename T>
123 : /// std::optional<StepperErrorEstimate> update_u_impl(
124 : /// gsl::not_null<T*> u,
125 : /// const ConstUntypedHistory<T>& history,
126 : /// const TimeDelta& time_step,
127 : /// const std::optional<StepperErrorTolerances>& tolerances) const;
128 : /// ```
129 : template <typename Vars>
130 1 : std::optional<StepperErrorEstimate> update_u(
131 : const gsl::not_null<Vars*> u, const TimeSteppers::History<Vars>& history,
132 : const TimeDelta& time_step,
133 : const std::optional<StepperErrorTolerances>& tolerances) const {
134 : return update_u_forward(&*make_math_wrapper(u), history.untyped(),
135 : time_step, tolerances);
136 : }
137 :
138 : /// Remove old entries from the history.
139 : ///
140 : /// This should be called after update_u and dense output.
141 : /// Afterward, the history will generally require a new entry to be
142 : /// added before it can be used by the TimeStepper.
143 : ///
144 : /// Derived classes must implement this as a function with signature
145 : ///
146 : /// ```
147 : /// template <typename T>
148 : /// void clean_history_impl(const MutableUntypedHistory<T>& history) const;
149 : /// ```
150 : template <typename Vars>
151 1 : void clean_history(
152 : const gsl::not_null<TimeSteppers::History<Vars>*> history) const {
153 : return clean_history_forward(history->untyped());
154 : }
155 :
156 : /// Compute the solution value at a time between steps. To evaluate
157 : /// at a time within a given step, call this method at the start of
158 : /// the step containing the time. The function returns true on
159 : /// success, otherwise the call should be retried after the next
160 : /// substep.
161 : ///
162 : /// The change from the partial step will be added to the initial
163 : /// value, so \p u should generally be initialized to
164 : /// `*history.step_start(time).value`. (TimeStepper
165 : /// implementations are required to keep this value in the history.)
166 : ///
167 : /// Derived classes must implement this as a function with signature
168 : ///
169 : /// ```
170 : /// template <typename T>
171 : /// bool dense_update_u_impl(
172 : /// gsl::not_null<T*> u, const ConstUntypedHistory<T>& history,
173 : /// double time) const;
174 : /// ```
175 : template <typename Vars>
176 1 : bool dense_update_u(const gsl::not_null<Vars*> u,
177 : const TimeSteppers::History<Vars>& history,
178 : const double time) const {
179 : return dense_update_u_forward(&*make_math_wrapper(u), history.untyped(),
180 : time);
181 : }
182 :
183 : /// The convergence order of the stepper
184 1 : virtual size_t order() const = 0;
185 :
186 : /// Number of substeps in this TimeStepper
187 1 : virtual uint64_t number_of_substeps() const = 0;
188 :
189 : /// Number of substeps in this TimeStepper when providing an error measure for
190 : /// adaptive time-stepping
191 : ///
192 : /// \details Certain substep methods (e.g. embedded RK4(3)) require additional
193 : /// steps when providing an error measure of the integration.
194 1 : virtual uint64_t number_of_substeps_for_error() const = 0;
195 :
196 : /// Number of past time steps needed for multi-step method
197 1 : virtual size_t number_of_past_steps() const = 0;
198 :
199 : /// Rough estimate of the maximum step size this method can take
200 : /// stably as a multiple of the step for Euler's method.
201 1 : virtual double stable_step() const = 0;
202 :
203 : /// Whether computational and temporal orderings of operations
204 : /// match.
205 : ///
206 : /// If this method returns true, then, for two time-stepper
207 : /// operations occurring at different simulation times, the
208 : /// temporally earlier operation will be performed first. These
209 : /// operations include RHS evaluation, dense output, and neighbor
210 : /// communication. In particular, dense output never requires
211 : /// performing a RHS evaluation later than the output time, so
212 : /// control systems measurements cannot cause deadlocks.
213 : ///
214 : /// \warning This guarantee only holds if the time steps themselves
215 : /// are monotonic, which can be violated during initialization.
216 1 : virtual bool monotonic() const = 0;
217 :
218 : /// The TimeStepId after the current substep
219 1 : virtual TimeStepId next_time_id(const TimeStepId& current_id,
220 : const TimeDelta& time_step) const = 0;
221 :
222 : /// The TimeStepId after the current substep when providing an error measure
223 : /// for adaptive time-stepping.
224 : ///
225 : /// Certain substep methods (e.g. embedded RK4(3)) require additional
226 : /// steps when providing an error measure of the integration.
227 1 : virtual TimeStepId next_time_id_for_error(
228 : const TimeStepId& current_id, const TimeDelta& time_step) const = 0;
229 :
230 : /// Whether a change in the step size is allowed before taking
231 : /// a step. Step sizes can never be changed on a substep.
232 : ///
233 : /// Derived classes must implement this as a function with signature
234 : ///
235 : /// ```
236 : /// template <typename T>
237 : /// bool can_change_step_size_impl(
238 : /// const TimeStepId& time_id,
239 : /// const ConstUntypedHistory<T>& history) const;
240 : /// ```
241 : template <typename Vars>
242 1 : bool can_change_step_size(const TimeStepId& time_id,
243 : const TimeSteppers::History<Vars>& history) const {
244 : return can_change_step_size_forward(time_id, history.untyped());
245 : }
246 : };
247 :
248 : /// \cond
249 : #define TIME_STEPPER_DECLARE_OVERLOADS_IMPL(_, data) \
250 : void update_u_forward( \
251 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
252 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
253 : data)>& history, \
254 : const TimeDelta& time_step) const override; \
255 : std::optional<StepperErrorEstimate> update_u_forward( \
256 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
257 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
258 : data)>& history, \
259 : const TimeDelta& time_step, \
260 : const std::optional<StepperErrorTolerances>& tolerances) const override; \
261 : void clean_history_forward( \
262 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
263 : data)>& history) const override; \
264 : bool dense_update_u_forward( \
265 : gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
266 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
267 : data)>& history, \
268 : double time) const override; \
269 : bool can_change_step_size_forward( \
270 : const TimeStepId& time_id, \
271 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
272 : data)>& history) const override;
273 :
274 : #define TIME_STEPPER_DEFINE_OVERLOADS_IMPL(_, data) \
275 : TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) \
276 : void TIME_STEPPER_DERIVED_CLASS(data)::update_u_forward( \
277 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
278 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
279 : data)>& history, \
280 : const TimeDelta& time_step) const { \
281 : return update_u_impl(u, history, time_step); \
282 : } \
283 : TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) \
284 : std::optional<StepperErrorEstimate> \
285 : TIME_STEPPER_DERIVED_CLASS(data)::update_u_forward( \
286 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
287 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
288 : data)>& history, \
289 : const TimeDelta& time_step, \
290 : const std::optional<StepperErrorTolerances>& tolerances) const { \
291 : return update_u_impl(u, history, time_step, tolerances); \
292 : } \
293 : TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) \
294 : void TIME_STEPPER_DERIVED_CLASS(data)::clean_history_forward( \
295 : const TimeSteppers::MutableUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
296 : data)>& history) const { \
297 : return clean_history_impl(history); \
298 : } \
299 : TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) \
300 : bool TIME_STEPPER_DERIVED_CLASS(data)::dense_update_u_forward( \
301 : const gsl::not_null<TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
302 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
303 : data)>& history, \
304 : const double time) const { \
305 : return dense_update_u_impl(u, history, time); \
306 : } \
307 : TIME_STEPPER_DERIVED_CLASS_TEMPLATE(data) \
308 : bool TIME_STEPPER_DERIVED_CLASS(data)::can_change_step_size_forward( \
309 : const TimeStepId& time_id, \
310 : const TimeSteppers::ConstUntypedHistory<TIME_STEPPER_WRAPPED_TYPE( \
311 : data)>& history) const { \
312 : return can_change_step_size_impl(time_id, history); \
313 : }
314 : /// \endcond
315 :
316 : /// \ingroup TimeSteppersGroup
317 : /// Macro declaring overloaded detail methods in classes derived from
318 : /// TimeStepper. Must be placed in a private section of the class
319 : /// body.
320 1 : #define TIME_STEPPER_DECLARE_OVERLOADS \
321 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DECLARE_OVERLOADS_IMPL, \
322 : (MATH_WRAPPER_TYPES))
323 :
324 : /// \ingroup TimeSteppersGroup
325 : /// Macro defining overloaded detail methods in classes derived from
326 : /// TimeStepper. Must be placed in the cpp file for the derived
327 : /// class.
328 : /// @{
329 1 : #define TIME_STEPPER_DEFINE_OVERLOADS(derived_class) \
330 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DEFINE_OVERLOADS_IMPL, \
331 : (MATH_WRAPPER_TYPES), (derived_class), ())
332 1 : #define TIME_STEPPER_DEFINE_OVERLOADS_TEMPLATED(derived_class, template_args) \
333 : GENERATE_INSTANTIATIONS(TIME_STEPPER_DEFINE_OVERLOADS_IMPL, \
334 : (MATH_WRAPPER_TYPES), (derived_class), \
335 : (template <template_args>))
336 : /// @}
|