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