|
| 1 | +#ifndef PHARE_CORE_NUMERICS_SSPRK4_5_INTEGRATOR_HPP |
| 2 | +#define PHARE_CORE_NUMERICS_SSPRK4_5_INTEGRATOR_HPP |
| 3 | + |
| 4 | +#include "initializer/data_provider.hpp" |
| 5 | +#include "amr/solvers/time_integrator/base_mhd_timestepper.hpp" |
| 6 | +#include "amr/solvers/time_integrator/compute_fluxes.hpp" |
| 7 | +#include "amr/solvers/time_integrator/euler_using_computed_flux.hpp" |
| 8 | +#include "amr/solvers/solver_mhd_model_view.hpp" |
| 9 | +#include "amr/solvers/time_integrator/euler.hpp" |
| 10 | +#include "core/numerics/time_integrator_utils.hpp" |
| 11 | + |
| 12 | +namespace PHARE::solver |
| 13 | +{ |
| 14 | +template<template<typename> typename FVMethodStrategy, typename MHDModel> |
| 15 | +class SSPRK4_5Integrator : public BaseMHDTimestepper<MHDModel> |
| 16 | +{ |
| 17 | + using Super = BaseMHDTimestepper<MHDModel>; |
| 18 | + |
| 19 | + using level_t = typename MHDModel::level_t; |
| 20 | + using FieldT = typename MHDModel::field_type; |
| 21 | + using VecFieldT = typename MHDModel::vecfield_type; |
| 22 | + using GridLayoutT = typename MHDModel::gridlayout_type; |
| 23 | + using MHDStateT = typename MHDModel::state_type; |
| 24 | + |
| 25 | + using Dispatchers_t = Dispatchers<GridLayoutT>; |
| 26 | + using RKUtils_t = Dispatchers_t::RKUtils_t; |
| 27 | + |
| 28 | + using RKPair_t = core::RKPair<typename VecFieldT::value_type, MHDStateT>; |
| 29 | + |
| 30 | +public: |
| 31 | + SSPRK4_5Integrator(PHARE::initializer::PHAREDict const& dict) |
| 32 | + : Super{dict} |
| 33 | + , euler_{dict} |
| 34 | + , compute_fluxes_{dict} |
| 35 | + { |
| 36 | + } |
| 37 | + |
| 38 | + // Butcher fluxes are used to accumulate fluxes over multiple stages, the corresponding buffer |
| 39 | + // should only contain the fluxes over one time step. The accumulation over all substeps is |
| 40 | + // delegated to the solver. |
| 41 | + void operator()(MHDModel& model, auto& state, auto& fluxes, auto& bc, level_t& level, |
| 42 | + double const currentTime, double const newTime) |
| 43 | + { |
| 44 | + this->resetButcherFluxes_(model, level); |
| 45 | + |
| 46 | + auto const dt = newTime - currentTime; |
| 47 | + |
| 48 | + // U1 = Un + w0_*dt*F(Un) |
| 49 | + euler_(model, state, state1_, fluxes, bc, level, currentTime, newTime, w0_ * dt); |
| 50 | + |
| 51 | + this->accumulateButcherFluxes_( |
| 52 | + model, state.E, fluxes, level, |
| 53 | + (w0_ * w11_ * w21_ * w31_ * w43_ + w0_ * w11_ * w21_ * w41_ + w0_ * w11_)); |
| 54 | + |
| 55 | + // U2 = w10_*Un + w11_*U1 + w12_*dt*F(U1) |
| 56 | + // |
| 57 | + // U2 = w10_Un + w11_*U1 |
| 58 | + rk_step_(level, model, newTime, state2_, RKPair_t{w10_, state}, RKPair_t{w11_, state1_}); |
| 59 | + |
| 60 | + // U2 = U2 + w12_*dt*F(U1) |
| 61 | + compute_fluxes_(model, state1_, fluxes, bc, level, newTime); |
| 62 | + |
| 63 | + euler_using_butcher_fluxes_(model, state2_, state2_, state1_.E, fluxes, bc, level, newTime, |
| 64 | + w12_ * dt); |
| 65 | + |
| 66 | + this->accumulateButcherFluxes_( |
| 67 | + model, state1_.E, fluxes, level, |
| 68 | + (w12_ * w21_ * w31_ * w43_ + w12_ * w21_ * w41_ + w12_ * w40_)); |
| 69 | + |
| 70 | + // U3 = w20_*Un + w21_*U2 + w22_*dt*F(U2) |
| 71 | + // |
| 72 | + // U3 = w20_*Un + w21_*U2 |
| 73 | + rk_step_(level, model, newTime, state3_, RKPair_t{w20_, state}, RKPair_t{w21_, state2_}); |
| 74 | + |
| 75 | + // U3 = U3 + w22_*dt*F(U2) |
| 76 | + compute_fluxes_(model, state2_, fluxes, bc, level, newTime); |
| 77 | + |
| 78 | + euler_using_butcher_fluxes_(model, state3_, state3_, state2_.E, fluxes, bc, level, newTime, |
| 79 | + w22_ * dt); |
| 80 | + |
| 81 | + this->accumulateButcherFluxes_(model, state2_.E, fluxes, level, |
| 82 | + (w22_ * w31_ * w43_ + w22_ * w41_)); |
| 83 | + |
| 84 | + // U4 = w30_*Un + w31_*U3 + w32_*dt*F(U3) |
| 85 | + // |
| 86 | + // U4 = w30_*Un + w31_*U3 |
| 87 | + rk_step_(level, model, newTime, state4_, RKPair_t{w30_, state}, RKPair_t{w31_, state3_}); |
| 88 | + |
| 89 | + // U4 = U4 + w32_*dt*F(U3) |
| 90 | + // if we were not using butcher formulation, we would need a separate flux buffer for F(U3) |
| 91 | + // for the final step |
| 92 | + compute_fluxes_(model, state3_, fluxes, bc, level, newTime); |
| 93 | + |
| 94 | + euler_using_butcher_fluxes_(model, state4_, state4_, state3_.E, fluxes, bc, level, newTime, |
| 95 | + w32_ * dt); |
| 96 | + |
| 97 | + this->accumulateButcherFluxes_(model, state3_.E, fluxes, level, (w32_ * w43_ + w42_)); |
| 98 | + |
| 99 | + compute_fluxes_(model, state4_, fluxes, bc, level, newTime); |
| 100 | + |
| 101 | + this->accumulateButcherFluxes_(model, state4_.E, fluxes, level, w44_); |
| 102 | + |
| 103 | + euler_using_butcher_fluxes_(model, state, state, this->butcherE_, this->butcherFluxes_, bc, |
| 104 | + level, newTime, dt); |
| 105 | + |
| 106 | + // Un+1 = w40_*U2 + w41_*U3 + w42_*F(U3) + w43_*U4 + w44_*dt*F(U4) |
| 107 | + } |
| 108 | + |
| 109 | + void registerResources(MHDModel& model) |
| 110 | + { |
| 111 | + Super::registerResources(model); |
| 112 | + model.resourcesManager->registerResources(state1_); |
| 113 | + model.resourcesManager->registerResources(state2_); |
| 114 | + } |
| 115 | + |
| 116 | + void allocate(MHDModel& model, auto& patch, double const allocateTime) const |
| 117 | + { |
| 118 | + Super::allocate(model, patch, allocateTime); |
| 119 | + model.resourcesManager->allocate(state1_, patch, allocateTime); |
| 120 | + model.resourcesManager->allocate(state2_, patch, allocateTime); |
| 121 | + } |
| 122 | + |
| 123 | + void fillMessengerInfo(auto& info) const |
| 124 | + { |
| 125 | + info.ghostDensity.push_back(state1_.rho.name()); |
| 126 | + info.ghostMomentum.push_back(state1_.rhoV.name()); |
| 127 | + info.ghostTotalEnergy.push_back(state1_.Etot.name()); |
| 128 | + info.ghostElectric.push_back(state1_.E.name()); |
| 129 | + info.ghostCurrent.push_back(state1_.J.name()); |
| 130 | + |
| 131 | + info.ghostDensity.push_back(state2_.rho.name()); |
| 132 | + info.ghostMomentum.push_back(state2_.rhoV.name()); |
| 133 | + info.ghostTotalEnergy.push_back(state2_.Etot.name()); |
| 134 | + info.ghostElectric.push_back(state2_.E.name()); |
| 135 | + info.ghostCurrent.push_back(state2_.J.name()); |
| 136 | + } |
| 137 | + |
| 138 | + NO_DISCARD auto getCompileTimeResourcesViewList() |
| 139 | + { |
| 140 | + return std::tuple_cat(Super::getCompileTimeResourcesViewList(), |
| 141 | + std::forward_as_tuple(state1_, state2_)); |
| 142 | + } |
| 143 | + |
| 144 | + NO_DISCARD auto getCompileTimeResourcesViewList() const |
| 145 | + { |
| 146 | + return std::tuple_cat(Super::getCompileTimeResourcesViewList(), |
| 147 | + std::forward_as_tuple(state1_, state2_)); |
| 148 | + } |
| 149 | + |
| 150 | + using Super::exposeFluxes; |
| 151 | + |
| 152 | +private: |
| 153 | + static constexpr auto w0_{0.391752226571890}; |
| 154 | + static constexpr auto w10_{0.444370493651235}; |
| 155 | + static constexpr auto w11_{0.555629506348765}; |
| 156 | + static constexpr auto w12_{0.368410593050371}; |
| 157 | + static constexpr auto w20_{0.620101851488403}; |
| 158 | + static constexpr auto w21_{0.379898148511597}; |
| 159 | + static constexpr auto w22_{0.251891774271694}; |
| 160 | + static constexpr auto w30_{0.178079954393132}; |
| 161 | + static constexpr auto w31_{0.821920045606868}; |
| 162 | + static constexpr auto w32_{0.544974750228521}; |
| 163 | + static constexpr auto w40_{0.517231671970585}; |
| 164 | + static constexpr auto w41_{0.096059710526147}; |
| 165 | + static constexpr auto w42_{0.063692468666290}; |
| 166 | + static constexpr auto w43_{0.386708617503268}; |
| 167 | + static constexpr auto w44_{0.226007483236906}; |
| 168 | + |
| 169 | + Euler<FVMethodStrategy, MHDModel> euler_; |
| 170 | + ComputeFluxes<FVMethodStrategy, MHDModel> compute_fluxes_; |
| 171 | + EulerUsingComputedFlux<MHDModel> euler_using_butcher_fluxes_; |
| 172 | + RKUtils_t rk_step_; |
| 173 | + |
| 174 | + MHDStateT state1_{"state1"}; |
| 175 | + MHDStateT state2_{"state2"}; |
| 176 | + MHDStateT state3_{"state2"}; |
| 177 | + MHDStateT state4_{"state2"}; |
| 178 | +}; |
| 179 | + |
| 180 | +} // namespace PHARE::solver |
| 181 | + |
| 182 | +#endif |
0 commit comments