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))