Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include "DataStructures/DataBox/PrefixHelpers.hpp"
7 : #include "DataStructures/DataBox/Prefixes.hpp"
8 : #include "DataStructures/MathWrapper.hpp"
9 : #include "Time/History.hpp"
10 : #include "Time/Time.hpp"
11 : #include "Time/TimeSteppers/TimeStepper.hpp"
12 : #include "Utilities/GenerateInstantiations.hpp"
13 : #include "Utilities/Gsl.hpp"
14 : #include "Utilities/Serialization/CharmPupable.hpp"
15 :
16 : /// \cond
17 : #define IMEX_TIME_STEPPER_WRAPPED_TYPE(data) BOOST_PP_TUPLE_ELEM(0, data)
18 : #define IMEX_TIME_STEPPER_DERIVED_CLASS(data) BOOST_PP_TUPLE_ELEM(1, data)
19 : /// \endcond
20 :
21 : /*!
22 : * \ingroup TimeSteppersGroup
23 : *
24 : * Base class for TimeSteppers with IMEX support, derived from
25 : * TimeStepper.
26 : *
27 : * All supported time-stepping algorithms (both implicit and
28 : * explicit) consist of substeps that add linear combinations of
29 : * derivative values. For implicit substeps, it is convenient to
30 : * split out the contribution of the final implicit term from
31 : * contributions from the history. We therefore write an implicit
32 : * substep as
33 : *
34 : * \f{equation}{
35 : * Y_{n+1} =
36 : * Y_{n,\text{explicit}} + Y_{n,\text{inhomogeneous}} + w_n S(Y_{n+1})
37 : * \f}
38 : *
39 : * Here \f$Y_{n,\text{explicit}}\f$ is the value of the evolved
40 : * variables before the implicit substep is applied,
41 : * \f$Y_{n,\text{inhomogeneous}}\f$ is the contribution of the past
42 : * values from the implicit derivative history, and \f$S(\cdot)\f$ is
43 : * the implicit portion of the right-hand-side (generally source
44 : * terms for PDEs). We call \f$w_n\f$ the *implicit weight*.
45 : * This split form is convenient for most consumers of this class, so
46 : * we present methods for calculating
47 : * \f$Y_{n,\text{inhomogeneous}}\f$ and \f$w_n\f$ individually
48 : * instead of a method to perform a full step update.
49 : *
50 : * History cleanup is the same for the explicit and implicit parts,
51 : * and should be done together.
52 : *
53 : * Dense output formulae are the same for the explicit and implicit
54 : * parts of any conservative IMEX stepper. To evaluate dense output,
55 : * call `dense_update_u` with the implicit history after a successful
56 : * call to `dense_update_u` with the explicit history.
57 : *
58 : * Several of the member functions of this class are templated and
59 : * perform type erasure before forwarding their arguments to the
60 : * derived classes. This is implemented using the macros \ref
61 : * IMEX_TIME_STEPPER_DECLARE_OVERLOADS, which must be placed in a
62 : * private section of the class body, and
63 : * IMEX_TIME_STEPPER_DEFINE_OVERLOADS(derived_class), which must be
64 : * placed in the cpp file.
65 : */
66 1 : class ImexTimeStepper : public virtual TimeStepper {
67 : public:
68 0 : static constexpr bool imex = true;
69 0 : using provided_time_stepper_interfaces =
70 : tmpl::list<ImexTimeStepper, TimeStepper>;
71 :
72 0 : WRAPPED_PUPable_abstract(ImexTimeStepper); // NOLINT
73 :
74 : /// \cond
75 : #define IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL(_, data) \
76 : virtual void add_inhomogeneous_implicit_terms_forward( \
77 : gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
78 : const TimeSteppers::ConstUntypedHistory<IMEX_TIME_STEPPER_WRAPPED_TYPE( \
79 : data)>& implicit_history, \
80 : const TimeDelta& time_step) const = 0; \
81 : virtual double implicit_weight_forward( \
82 : const TimeSteppers::ConstUntypedHistory<IMEX_TIME_STEPPER_WRAPPED_TYPE( \
83 : data)>& implicit_history, \
84 : const TimeDelta& time_step) const = 0;
85 :
86 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL,
87 : (MATH_WRAPPER_TYPES))
88 : #undef IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL
89 : /// \endcond
90 :
91 : /// Convergence order of the integrator when used in IMEX mode.
92 1 : virtual size_t imex_order() const = 0;
93 :
94 : /// Add the change for the current implicit substep,
95 : /// \f$Y_{n,\text{inhomogeneous}}\f$, to u, given a past history of
96 : /// the implicit derivatives.
97 : ///
98 : /// Derived classes must implement this as a function with signature
99 : ///
100 : /// ```
101 : /// template <typename T>
102 : /// void add_inhomogeneous_implicit_terms_impl(
103 : /// gsl::not_null<T*> u,
104 : /// const ConstUntypedHistory<T>& implicit_history,
105 : /// const TimeDelta& time_step) const;
106 : /// ```
107 : ///
108 : /// \note
109 : /// Unlike the `update_u` methods, which overwrite their result
110 : /// arguments, this function adds the result to the existing value.
111 : template <typename Vars>
112 1 : void add_inhomogeneous_implicit_terms(
113 : const gsl::not_null<Vars*> u,
114 : const TimeSteppers::History<Vars>& implicit_history,
115 : const TimeDelta& time_step) const {
116 : return add_inhomogeneous_implicit_terms_forward(
117 : &*make_math_wrapper(u), implicit_history.untyped(), time_step);
118 : }
119 :
120 : /// The coefficient \f$w_n\f$ of the implicit derivative for the
121 : /// current substep. For a Runge-Kutta method, this is the
122 : /// coefficient on the diagonal of the Butcher tableau.
123 : ///
124 : /// Derived classes must implement this as a function with signature
125 : ///
126 : /// ```
127 : /// template <typename T>
128 : /// double implicit_weight_impl(
129 : /// const ConstUntypedHistory<T>& implicit_history,
130 : /// const TimeDelta& time_step) const;
131 : /// ```
132 : template <typename Vars>
133 1 : double implicit_weight(const TimeSteppers::History<Vars>& implicit_history,
134 : const TimeDelta& time_step) const {
135 : return implicit_weight_forward(implicit_history.untyped(), time_step);
136 : }
137 : };
138 :
139 : /// \cond
140 : #define IMEX_TIME_STEPPER_DECLARE_OVERLOADS_IMPL(_, data) \
141 : void add_inhomogeneous_implicit_terms_forward( \
142 : gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
143 : const TimeSteppers::ConstUntypedHistory<IMEX_TIME_STEPPER_WRAPPED_TYPE( \
144 : data)>& implicit_history, \
145 : const TimeDelta& time_step) const override; \
146 : double implicit_weight_forward( \
147 : const TimeSteppers::ConstUntypedHistory<IMEX_TIME_STEPPER_WRAPPED_TYPE( \
148 : data)>& implicit_history, \
149 : const TimeDelta& time_step) const override;
150 :
151 : #define IMEX_TIME_STEPPER_DEFINE_OVERLOADS_IMPL(_, data) \
152 : void IMEX_TIME_STEPPER_DERIVED_CLASS(data):: \
153 : add_inhomogeneous_implicit_terms_forward( \
154 : const gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \
155 : const TimeSteppers::ConstUntypedHistory< \
156 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \
157 : const TimeDelta& time_step) const { \
158 : return add_inhomogeneous_implicit_terms_impl(u, implicit_history, \
159 : time_step); \
160 : } \
161 : double IMEX_TIME_STEPPER_DERIVED_CLASS(data)::implicit_weight_forward( \
162 : const TimeSteppers::ConstUntypedHistory<IMEX_TIME_STEPPER_WRAPPED_TYPE( \
163 : data)>& implicit_history, \
164 : const TimeDelta& time_step) const { \
165 : return implicit_weight_impl(implicit_history, time_step); \
166 : }
167 : /// \endcond
168 :
169 : /// \ingroup TimeSteppersGroup
170 : /// Macro declaring overloaded detail methods in classes derived from
171 : /// ImexTimeStepper. Must be placed in a private section of the class
172 : /// body.
173 1 : #define IMEX_TIME_STEPPER_DECLARE_OVERLOADS \
174 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DECLARE_OVERLOADS_IMPL, \
175 : (MATH_WRAPPER_TYPES))
176 :
177 : /// \ingroup TimeSteppersGroup
178 : /// Macro defining overloaded detail methods in classes derived from
179 : /// ImexTimeStepper. Must be placed in the cpp file for the derived
180 : /// class.
181 1 : #define IMEX_TIME_STEPPER_DEFINE_OVERLOADS(derived_class) \
182 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DEFINE_OVERLOADS_IMPL, \
183 : (MATH_WRAPPER_TYPES), (derived_class))
|