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 : * Dense output formulae are the same for the explicit and implicit 51 : * parts of any conservative IMEX stepper. To evaluate dense output, 52 : * call `dense_update_u` with the implicit history after a successful 53 : * call to `dense_update_u` with the explicit history. 54 : * 55 : * Several of the member functions of this class are templated and 56 : * perform type erasure before forwarding their arguments to the 57 : * derived classes. This is implemented using the macros \ref 58 : * IMEX_TIME_STEPPER_DECLARE_OVERLOADS, which must be placed in a 59 : * private section of the class body, and 60 : * IMEX_TIME_STEPPER_DEFINE_OVERLOADS(derived_class), which must be 61 : * placed in the cpp file. 62 : */ 63 1 : class ImexTimeStepper : public virtual TimeStepper { 64 : public: 65 0 : static constexpr bool imex = true; 66 0 : using provided_time_stepper_interfaces = 67 : tmpl::list<ImexTimeStepper, TimeStepper>; 68 : 69 0 : WRAPPED_PUPable_abstract(ImexTimeStepper); // NOLINT 70 : 71 : /// \cond 72 : #define IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL(_, data) \ 73 : virtual void add_inhomogeneous_implicit_terms_forward( \ 74 : gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \ 75 : const TimeSteppers::MutableUntypedHistory< \ 76 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 77 : const TimeDelta& time_step) const = 0; \ 78 : virtual double implicit_weight_forward( \ 79 : const TimeSteppers::MutableUntypedHistory< \ 80 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 81 : const TimeDelta& time_step) const = 0; 82 : 83 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL, 84 : (MATH_WRAPPER_TYPES)) 85 : #undef IMEX_TIME_STEPPER_DECLARE_VIRTUALS_IMPL 86 : /// \endcond 87 : 88 : /// Convergence order of the integrator when used in IMEX mode. 89 1 : virtual size_t imex_order() const = 0; 90 : 91 : /// Add the change for the current implicit substep, 92 : /// \f$Y_{n,\text{inhomogeneous}}\f$, to u, given a past history of 93 : /// the implicit derivatives. 94 : /// 95 : /// Derived classes must implement this as a function with signature 96 : /// 97 : /// ``` 98 : /// template <typename T> 99 : /// void add_inhomogeneous_implicit_terms_impl( 100 : /// gsl::not_null<T*> u, 101 : /// const MutableUntypedHistory<T>& implicit_history, 102 : /// const TimeDelta& time_step) const; 103 : /// ``` 104 : /// 105 : /// \note 106 : /// Unlike the `update_u` methods, which overwrite their result 107 : /// arguments, this function adds the result to the existing value. 108 : template <typename Vars> 109 1 : void add_inhomogeneous_implicit_terms( 110 : const gsl::not_null<Vars*> u, 111 : const gsl::not_null<TimeSteppers::History<Vars>*> implicit_history, 112 : const TimeDelta& time_step) const { 113 : return add_inhomogeneous_implicit_terms_forward( 114 : &*make_math_wrapper(u), implicit_history->untyped(), time_step); 115 : } 116 : 117 : /// The coefficient \f$w_n\f$ of the implicit derivative for the 118 : /// current substep. For a Runge-Kutta method, this is the 119 : /// coefficient on the diagonal of the Butcher tableau. 120 : /// 121 : /// Derived classes must implement this as a function with signature 122 : /// 123 : /// ``` 124 : /// template <typename T> 125 : /// double implicit_weight_impl( 126 : /// const MutableUntypedHistory<T>& implicit_history, 127 : /// const TimeDelta& time_step) const; 128 : /// ``` 129 : template <typename Vars> 130 1 : double implicit_weight( 131 : const gsl::not_null<TimeSteppers::History<Vars>*> implicit_history, 132 : const TimeDelta& time_step) const { 133 : return implicit_weight_forward(implicit_history->untyped(), time_step); 134 : } 135 : }; 136 : 137 : /// \cond 138 : #define IMEX_TIME_STEPPER_DECLARE_OVERLOADS_IMPL(_, data) \ 139 : void add_inhomogeneous_implicit_terms_forward( \ 140 : gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \ 141 : const TimeSteppers::MutableUntypedHistory< \ 142 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 143 : const TimeDelta& time_step) const override; \ 144 : double implicit_weight_forward( \ 145 : const TimeSteppers::MutableUntypedHistory< \ 146 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 147 : const TimeDelta& time_step) const override; 148 : 149 : #define IMEX_TIME_STEPPER_DEFINE_OVERLOADS_IMPL(_, data) \ 150 : void IMEX_TIME_STEPPER_DERIVED_CLASS(data):: \ 151 : add_inhomogeneous_implicit_terms_forward( \ 152 : const gsl::not_null<IMEX_TIME_STEPPER_WRAPPED_TYPE(data)*> u, \ 153 : const TimeSteppers::MutableUntypedHistory< \ 154 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 155 : const TimeDelta& time_step) const { \ 156 : return add_inhomogeneous_implicit_terms_impl(u, implicit_history, \ 157 : time_step); \ 158 : } \ 159 : double IMEX_TIME_STEPPER_DERIVED_CLASS(data)::implicit_weight_forward( \ 160 : const TimeSteppers::MutableUntypedHistory< \ 161 : IMEX_TIME_STEPPER_WRAPPED_TYPE(data)>& implicit_history, \ 162 : const TimeDelta& time_step) const { \ 163 : return implicit_weight_impl(implicit_history, time_step); \ 164 : } 165 : /// \endcond 166 : 167 : /// \ingroup TimeSteppersGroup 168 : /// Macro declaring overloaded detail methods in classes derived from 169 : /// ImexTimeStepper. Must be placed in a private section of the class 170 : /// body. 171 1 : #define IMEX_TIME_STEPPER_DECLARE_OVERLOADS \ 172 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DECLARE_OVERLOADS_IMPL, \ 173 : (MATH_WRAPPER_TYPES)) 174 : 175 : /// \ingroup TimeSteppersGroup 176 : /// Macro defining overloaded detail methods in classes derived from 177 : /// ImexTimeStepper. Must be placed in the cpp file for the derived 178 : /// class. 179 1 : #define IMEX_TIME_STEPPER_DEFINE_OVERLOADS(derived_class) \ 180 : GENERATE_INSTANTIATIONS(IMEX_TIME_STEPPER_DEFINE_OVERLOADS_IMPL, \ 181 : (MATH_WRAPPER_TYPES), (derived_class))