SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Initialization - Evolution.hpp Hit Total Coverage
Commit: c3e43f8d41800b0ecefb9d1393f1de1d5a280c8f Lines: 14 42 33.3 %
Date: 2026-07-24 22:09:25
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <algorithm>
       7             : #include <cstddef>
       8             : #include <cstdint>
       9             : #include <optional>
      10             : #include <type_traits>
      11             : #include <unordered_map>
      12             : #include <utility>
      13             : 
      14             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      15             : #include "DataStructures/DataBox/Prefixes.hpp"
      16             : #include "DataStructures/TaggedTuple.hpp"
      17             : #include "DataStructures/TaggedVariant.hpp"
      18             : #include "Domain/Amr/Helpers.hpp"
      19             : #include "Domain/Structure/ChildSize.hpp"
      20             : #include "Domain/Structure/DirectionalIdMap.hpp"
      21             : #include "Domain/Structure/Element.hpp"
      22             : #include "Domain/Structure/ElementId.hpp"
      23             : #include "Evolution/DiscontinuousGalerkin/MortarInfo.hpp"
      24             : #include "Evolution/DiscontinuousGalerkin/TimeSteppingPolicy.hpp"
      25             : #include "Evolution/Initialization/Tags.hpp"
      26             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      27             : #include "NumericalAlgorithms/Spectral/Projection.hpp"
      28             : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
      29             : #include "Time/AdaptiveSteppingDiagnostics.hpp"
      30             : #include "Time/ChangeSlabSize/Tags.hpp"
      31             : #include "Time/ChooseLtsStepSize.hpp"
      32             : #include "Time/History.hpp"
      33             : #include "Time/LtsMode.hpp"
      34             : #include "Time/Slab.hpp"
      35             : #include "Time/StepChoosers/StepChooser.hpp"
      36             : #include "Time/Tags/AdaptiveSteppingDiagnostics.hpp"
      37             : #include "Time/Tags/HistoryEvolvedVariables.hpp"
      38             : #include "Time/Tags/LtsMode.hpp"
      39             : #include "Time/Tags/StepNumberWithinSlab.hpp"
      40             : #include "Time/Tags/Time.hpp"
      41             : #include "Time/Tags/TimeStep.hpp"
      42             : #include "Time/Tags/TimeStepId.hpp"
      43             : #include "Time/Tags/TimeStepper.hpp"
      44             : #include "Time/Time.hpp"
      45             : #include "Time/TimeStepId.hpp"
      46             : #include "Time/TimeSteppers/LtsTimeStepper.hpp"
      47             : #include "Time/TimeSteppers/TimeStepper.hpp"
      48             : #include "Utilities/Algorithm.hpp"
      49             : #include "Utilities/ErrorHandling/Assert.hpp"
      50             : #include "Utilities/ErrorHandling/Error.hpp"
      51             : #include "Utilities/Gsl.hpp"
      52             : #include "Utilities/Literals.hpp"
      53             : #include "Utilities/MakeArray.hpp"
      54             : #include "Utilities/ProtocolHelpers.hpp"
      55             : #include "Utilities/TMPL.hpp"
      56             : 
      57             : /// \cond
      58             : namespace Parallel::Tags {
      59             : template <typename Index>
      60             : struct ArrayIndex;
      61             : }  // namespace Parallel::Tags
      62             : namespace Tags {
      63             : template <typename Tag>
      64             : struct StepperErrors;
      65             : }  // namespace Tags
      66             : namespace amr::Tags {
      67             : template <size_t VolumeDim>
      68             : struct Info;
      69             : }  // namespace amr::Tags
      70             : namespace domain::Tags {
      71             : template <size_t VolumeDim>
      72             : struct Element;
      73             : template <size_t VolumeDim>
      74             : struct Mesh;
      75             : }  // namespace domain::Tags
      76             : namespace evolution::dg::Tags {
      77             : template <size_t Dim>
      78             : struct MortarInfo;
      79             : }  // namespace evolution::dg::Tags
      80             : /// \endcond
      81             : 
      82             : namespace Initialization {
      83             : 
      84             : namespace detail {
      85             : inline Time initial_time(const bool time_runs_forward,
      86             :                          const double initial_time_value,
      87             :                          const double initial_slab_size) {
      88             :   const Slab initial_slab =
      89             :       time_runs_forward
      90             :           ? Slab::with_duration_from_start(initial_time_value,
      91             :                                            initial_slab_size)
      92             :           : Slab::with_duration_to_end(initial_time_value, initial_slab_size);
      93             :   return time_runs_forward ? initial_slab.start() : initial_slab.end();
      94             : }
      95             : 
      96             : template <typename TimeStepper>
      97             : void set_next_time_step_id(const gsl::not_null<TimeStepId*> next_time_step_id,
      98             :                            const Time& initial_time,
      99             :                            const bool time_runs_forward,
     100             :                            const TimeStepper& time_stepper) {
     101             :   *next_time_step_id = TimeStepId(
     102             :       time_runs_forward,
     103             :       -static_cast<int64_t>(time_stepper.number_of_past_steps()), initial_time);
     104             : }
     105             : }  // namespace detail
     106             : 
     107             : /// \ingroup InitializationGroup
     108             : /// \brief Initialize items related to time stepping
     109             : ///
     110             : /// \details See the type aliases defined below for what items are added to the
     111             : /// GlobalCache and DataBox and how they are initialized
     112             : ///
     113             : /// Since the evolution has not started yet, initialize the state
     114             : /// _before_ the initial time. So `Tags::TimeStepId` is undefined at this point,
     115             : /// and `Tags::Next<Tags::TimeStepId>` is the initial time.
     116             : template <typename Metavariables, typename TimeStepperBase,
     117             :           bool WithControlSystems, bool AllowLocalTimeStepping>
     118           1 : struct TimeStepping {
     119             :   /// Tags for constant items added to the GlobalCache.  These items are
     120             :   /// initialized from input file options.
     121           1 :   using const_global_cache_tags = tmpl::list<
     122             :       ::Tags::ConcreteTimeStepper<TimeStepperBase, WithControlSystems>,
     123             :       tmpl::conditional_t<AllowLocalTimeStepping, ::Tags::LtsMode,
     124             :                           ::Tags::LtsModeForced<LtsMode::Off>>>;
     125             : 
     126             :   /// Tags for mutable items added to the GlobalCache.  These items are
     127             :   /// initialized from input file options.
     128           1 :   using mutable_global_cache_tags = tmpl::list<>;
     129             : 
     130             :   /// Tags for items fetched by the DataBox and passed to the apply function
     131           1 :   using argument_tags =
     132             :       tmpl::list<::Tags::Time, Tags::InitialTimeDelta,
     133             :                  Tags::InitialSlabSize<AllowLocalTimeStepping>,
     134             :                  ::Tags::TimeStepper<TimeStepperBase>>;
     135             : 
     136             :   /// Tags for simple DataBox items that are initialized from input file options
     137           1 :   using simple_tags_from_options =
     138             :       tmpl::list<::Tags::Time, Tags::InitialTimeDelta,
     139             :                  Tags::InitialSlabSize<AllowLocalTimeStepping>>;
     140             : 
     141             :   /// Tags for simple DataBox items that are default initialized.
     142           1 :   using default_initialized_simple_tags =
     143             :       tmpl::push_back<StepChoosers::step_chooser_simple_tags<Metavariables>,
     144             :                       ::Tags::TimeStepId, ::Tags::StepNumberWithinSlab,
     145             :                       ::Tags::AdaptiveSteppingDiagnostics>;
     146             : 
     147             :   /// Tags for items in the DataBox that are mutated by the apply function
     148           1 :   using return_tags =
     149             :       tmpl::list<::Tags::Next<::Tags::TimeStepId>, ::Tags::TimeStep,
     150             :                  ::Tags::ChangeSlabSize::SlabSizeGoal>;
     151             : 
     152             :   /// Tags for mutable DataBox items that are either default initialized or
     153             :   /// initialized by the apply function
     154           1 :   using simple_tags =
     155             :       tmpl::append<default_initialized_simple_tags, return_tags>;
     156             : 
     157             :   /// Tags for immutable DataBox items (compute items or reference items) added
     158             :   /// to the DataBox.
     159           1 :   using compute_tags =
     160             :       time_stepper_ref_tags<TimeStepperBase, WithControlSystems>;
     161             : 
     162             :   /// Given the items fetched from a DataBox by the argument_tags when using
     163             :   /// LTS, mutate the items in the DataBox corresponding to return_tags
     164           1 :   static void apply(const gsl::not_null<TimeStepId*> next_time_step_id,
     165             :                     const gsl::not_null<TimeDelta*> time_step,
     166             :                     const gsl::not_null<double*> slab_size_goal,
     167             :                     const double initial_time_value,
     168             :                     const double initial_dt_value,
     169             :                     const double initial_slab_size,
     170             :                     const LtsTimeStepper& time_stepper) {
     171             :     const bool time_runs_forward = initial_dt_value > 0.0;
     172             :     const Time initial_time = detail::initial_time(
     173             :         time_runs_forward, initial_time_value, initial_slab_size);
     174             :     detail::set_next_time_step_id(next_time_step_id, initial_time,
     175             :                                   time_runs_forward, time_stepper);
     176             :     *time_step = choose_lts_step_size(initial_time, initial_dt_value);
     177             :     *slab_size_goal =
     178             :         time_runs_forward ? initial_slab_size : -initial_slab_size;
     179             :   }
     180             : 
     181             :   /// Given the items fetched from a DataBox by the argument_tags, when not
     182             :   /// using LTS, mutate the items in the DataBox corresponding to return_tags
     183           1 :   static void apply(const gsl::not_null<TimeStepId*> next_time_step_id,
     184             :                     const gsl::not_null<TimeDelta*> time_step,
     185             :                     const gsl::not_null<double*> slab_size_goal,
     186             :                     const double initial_time_value,
     187             :                     const double initial_dt_value,
     188             :                     const double initial_slab_size,
     189             :                     const TimeStepper& time_stepper) {
     190             :     const bool time_runs_forward = initial_dt_value > 0.0;
     191             :     const Time initial_time = detail::initial_time(
     192             :         time_runs_forward, initial_time_value, initial_slab_size);
     193             :     detail::set_next_time_step_id(next_time_step_id, initial_time,
     194             :                                   time_runs_forward, time_stepper);
     195             :     *time_step = (time_runs_forward ? 1 : -1) * initial_time.slab().duration();
     196             :     *slab_size_goal =
     197             :         time_runs_forward ? initial_slab_size : -initial_slab_size;
     198             :   }
     199             : };
     200             : 
     201             : /// \brief Initialize/update items related to time stepping after an AMR change
     202             : template <size_t Dim>
     203           1 : struct ProjectTimeStepping : tt::ConformsTo<amr::protocols::Projector> {
     204           0 :   using return_tags =
     205             :       tmpl::list<::Tags::TimeStepId, ::Tags::Next<::Tags::TimeStepId>,
     206             :                  ::Tags::TimeStep, ::Tags::Time, ::Tags::StepNumberWithinSlab,
     207             :                  ::Tags::AdaptiveSteppingDiagnostics,
     208             :                  ::Tags::ChangeSlabSize::SlabSizeGoal>;
     209           0 :   using argument_tags = tmpl::list<Parallel::Tags::ArrayIndex<ElementId<Dim>>>;
     210             : 
     211           0 :   static void apply(
     212             :       const gsl::not_null<TimeStepId*> /*time_step_id*/,
     213             :       const gsl::not_null<TimeStepId*> /*next_time_step_id*/,
     214             :       const gsl::not_null<TimeDelta*> /*time_step*/,
     215             :       const gsl::not_null<double*> /*time*/,
     216             :       const gsl::not_null<uint64_t*> /*step_number_within_slab*/,
     217             :       const gsl::not_null<AdaptiveSteppingDiagnostics*>
     218             :       /*adaptive_stepping_diagnostics*/,
     219             :       const gsl::not_null<double*> /*slab_size_goal*/,
     220             :       const ElementId<Dim>& /*element_id*/,
     221             :       const std::pair<Mesh<Dim>, Element<Dim>>& /*old_mesh_and_element*/) {
     222             :     // Do not change anything for p-refinement
     223             :   }
     224             : 
     225             :   template <typename... Tags>
     226           0 :   static void apply(const gsl::not_null<TimeStepId*> time_step_id,
     227             :                     const gsl::not_null<TimeStepId*> next_time_step_id,
     228             :                     const gsl::not_null<TimeDelta*> time_step,
     229             :                     const gsl::not_null<double*> time,
     230             :                     const gsl::not_null<uint64_t*> step_number_within_slab,
     231             :                     const gsl::not_null<AdaptiveSteppingDiagnostics*>
     232             :                         adaptive_stepping_diagnostics,
     233             :                     const gsl::not_null<double*> slab_size_goal,
     234             :                     const ElementId<Dim>& element_id,
     235             :                     const tuples::TaggedTuple<Tags...>& parent_items) {
     236             :     *time_step_id = get<::Tags::TimeStepId>(parent_items);
     237             :     *next_time_step_id = get<::Tags::Next<::Tags::TimeStepId>>(parent_items);
     238             :     *time_step = get<::Tags::TimeStep>(parent_items);
     239             :     *time = get<::Tags::Time>(parent_items);
     240             :     *slab_size_goal = get<::Tags::ChangeSlabSize::SlabSizeGoal>(parent_items);
     241             :     *step_number_within_slab = get<::Tags::StepNumberWithinSlab>(parent_items);
     242             : 
     243             :     // Since AdaptiveSteppingDiagnostics are reduced over all elements, we
     244             :     // set the slab quantities to the same value over all children, and the
     245             :     // step quantities to belong to the first child
     246             :     const auto& parent_diagnostics =
     247             :         get<::Tags::AdaptiveSteppingDiagnostics>(parent_items);
     248             :     const auto& parent_amr_flags =
     249             :         get<amr::Tags::Info<Dim>>(parent_items).flags;
     250             :     const auto& parent_id =
     251             :         get<Parallel::Tags::ArrayIndex<ElementId<Dim>>>(parent_items);
     252             :     auto children_ids = amr::ids_of_children(parent_id, parent_amr_flags);
     253             :     if (element_id == children_ids.front()) {
     254             :       *adaptive_stepping_diagnostics = parent_diagnostics;
     255             :     } else {
     256             :       adaptive_stepping_diagnostics->number_of_slabs =
     257             :           parent_diagnostics.number_of_slabs;
     258             :       adaptive_stepping_diagnostics->number_of_slab_size_changes =
     259             :           parent_diagnostics.number_of_slab_size_changes;
     260             :     }
     261             :   }
     262             : 
     263             :   template <typename... Tags>
     264           0 :   static void apply(
     265             :       const gsl::not_null<TimeStepId*> time_step_id,
     266             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     267             :       const gsl::not_null<TimeDelta*> time_step,
     268             :       const gsl::not_null<double*> time,
     269             :       const gsl::not_null<uint64_t*> step_number_within_slab,
     270             :       const gsl::not_null<AdaptiveSteppingDiagnostics*>
     271             :           adaptive_stepping_diagnostics,
     272             :       const gsl::not_null<double*> slab_size_goal,
     273             :       const ElementId<Dim>& /*element_id*/,
     274             :       const std::unordered_map<ElementId<Dim>, tuples::TaggedTuple<Tags...>>&
     275             :           children_items) {
     276             :     const auto slowest_child =
     277             :         alg::min_element(children_items, [](const auto& a, const auto& b) {
     278             :           const auto& time_step_a = get<::Tags::TimeStep>(a.second);
     279             :           const auto& time_step_b = get<::Tags::TimeStep>(b.second);
     280             :           ASSERT(time_step_a.is_positive() == time_step_b.is_positive(),
     281             :                  "Elements are not taking time steps in the same direction!");
     282             :           return time_step_a.is_positive() ? (time_step_a < time_step_b)
     283             :                                            : (time_step_a > time_step_b);
     284             :         });
     285             :     const auto& slowest_child_items = (*slowest_child).second;
     286             :     *time_step_id = get<::Tags::TimeStepId>(slowest_child_items);
     287             :     *next_time_step_id =
     288             :         get<::Tags::Next<::Tags::TimeStepId>>(slowest_child_items);
     289             :     *time_step = get<::Tags::TimeStep>(slowest_child_items);
     290             :     *time = get<::Tags::Time>(slowest_child_items);
     291             :     *slab_size_goal =
     292             :         get<::Tags::ChangeSlabSize::SlabSizeGoal>(slowest_child_items);
     293             :     *step_number_within_slab =
     294             :         get<::Tags::StepNumberWithinSlab>(slowest_child_items);
     295             :     const auto& slowest_child_diagnostics =
     296             :         get<::Tags::AdaptiveSteppingDiagnostics>(slowest_child_items);
     297             : 
     298             :     adaptive_stepping_diagnostics->number_of_slabs =
     299             :         slowest_child_diagnostics.number_of_slabs;
     300             :     adaptive_stepping_diagnostics->number_of_slab_size_changes =
     301             :         slowest_child_diagnostics.number_of_slab_size_changes;
     302             :     for (const auto& [_, child_items] : children_items) {
     303             :       *adaptive_stepping_diagnostics +=
     304             :           get<::Tags::AdaptiveSteppingDiagnostics>(child_items);
     305             :     }
     306             :   }
     307             : };
     308             : 
     309             : /// \ingroup InitializationGroup
     310             : /// \brief Initialize time-stepper items
     311             : ///
     312             : /// DataBox changes:
     313             : /// - Adds:
     314             : ///   * `db::add_tag_prefix<Tags::dt, variables_tag>`
     315             : ///   * `Tags::HistoryEvolvedVariables<variables_tag>`
     316             : /// - Removes: nothing
     317             : /// - Modifies: nothing
     318             : ///
     319             : /// \note HistoryEvolvedVariables is allocated, but needs to be initialized
     320             : template <typename Metavariables>
     321           1 : struct TimeStepperHistory {
     322           0 :   static constexpr size_t dim = Metavariables::volume_dim;
     323           0 :   using variables_tag = typename Metavariables::system::variables_tag;
     324           0 :   using dt_variables_tag = db::add_tag_prefix<::Tags::dt, variables_tag>;
     325             : 
     326           0 :   using const_global_cache_tags = tmpl::list<>;
     327           0 :   using mutable_global_cache_tags = tmpl::list<>;
     328           0 :   using simple_tags_from_options = tmpl::list<>;
     329           0 :   using simple_tags =
     330             :       tmpl::list<dt_variables_tag,
     331             :                  ::Tags::HistoryEvolvedVariables<variables_tag>>;
     332           0 :   using compute_tags = tmpl::list<>;
     333             : 
     334           0 :   using argument_tags =
     335             :       tmpl::list<::Tags::TimeStepper<TimeStepper>, domain::Tags::Mesh<dim>>;
     336           0 :   using return_tags = simple_tags;
     337             : 
     338           0 :   static void apply(
     339             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     340             :       const gsl::not_null<TimeSteppers::History<typename variables_tag::type>*>
     341             :           history,
     342             :       const TimeStepper& time_stepper, const Mesh<dim>& mesh) {
     343             :     // Will be overwritten before use
     344             :     dt_vars->initialize(mesh.number_of_grid_points());
     345             : 
     346             :     // All steppers we have that need to start at low order require
     347             :     // one additional point per order, so this is the order that
     348             :     // requires no initial past steps.
     349             :     const size_t starting_order =
     350             :         visit(
     351             :             []<typename Tag>(
     352             :                 const std::pair<tmpl::type_<Tag>, typename Tag::type&&> order) {
     353             :               if constexpr (std::is_same_v<Tag,
     354             :                                            TimeSteppers::Tags::FixedOrder>) {
     355             :                 return order.second;
     356             :               } else {
     357             :                 return order.second.minimum;
     358             :               }
     359             :             },
     360             :             time_stepper.order()) -
     361             :         time_stepper.number_of_past_steps();
     362             :     history->integration_order(starting_order);
     363             :   }
     364             : };
     365             : 
     366             : /// \brief Initialize/update items related to time stepper history after an AMR
     367             : /// change
     368             : ///
     369             : /// \note `Tags::TimeStep` and `Tags::Next<Tags::TimeStepId>` are not
     370             : /// initially set by this projector.  They are only updated if the
     371             : /// time stepper must be restarted because of LTS h-refinement.
     372             : template <typename Metavariables>
     373           1 : struct ProjectTimeStepperHistory : tt::ConformsTo<amr::protocols::Projector> {
     374           0 :   static constexpr size_t dim = Metavariables::volume_dim;
     375           0 :   using variables_tag = typename Metavariables::system::variables_tag;
     376           0 :   using dt_variables_tag = db::add_tag_prefix<::Tags::dt, variables_tag>;
     377           0 :   using history_tag = ::Tags::HistoryEvolvedVariables<variables_tag>;
     378             : 
     379           0 :   using return_tags =
     380             :       tmpl::list<dt_variables_tag, history_tag,
     381             :                  ::Tags::Next<::Tags::TimeStepId>, ::Tags::TimeStep>;
     382           0 :   using argument_tags = tmpl::list<
     383             :       domain::Tags::Mesh<dim>, Parallel::Tags::ArrayIndex<ElementId<dim>>,
     384             :       ::Tags::TimeStepper<TimeStepper>, evolution::dg::Tags::MortarInfo<dim>>;
     385             : 
     386           0 :   static void apply(
     387             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     388             :       const gsl::not_null<typename history_tag::type*> history,
     389             :       const gsl::not_null<TimeStepId*> /*next_time_step_id*/,
     390             :       const gsl::not_null<TimeDelta*> /*time_step*/, const Mesh<dim>& new_mesh,
     391             :       const ElementId<dim>& /*element_id*/, const TimeStepper& /*time_stepper*/,
     392             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>&
     393             :       /*mortar_info*/,
     394             :       const std::pair<Mesh<dim>, Element<dim>>& old_mesh_and_element) {
     395             :     const auto& old_mesh = old_mesh_and_element.first;
     396             :     if (old_mesh == new_mesh) {
     397             :       return;  // mesh was not refined, so no projection needed
     398             :     }
     399             :     history->map_entries([&old_mesh, &new_mesh](const auto entry) {
     400             :       *entry = Spectral::project(*entry, old_mesh, new_mesh,
     401             :                                  make_array<dim>(Spectral::SegmentSize::Full),
     402             :                                  make_array<dim>(Spectral::SegmentSize::Full));
     403             :     });
     404             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     405             :   }
     406             : 
     407             :   template <typename... Tags>
     408           0 :   static void apply(
     409             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     410             :       const gsl::not_null<typename history_tag::type*> history,
     411             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     412             :       const gsl::not_null<TimeDelta*> time_step, const Mesh<dim>& new_mesh,
     413             :       const ElementId<dim>& element_id, const TimeStepper& time_stepper,
     414             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>& mortar_info,
     415             :       const tuples::TaggedTuple<Tags...>& parent_items) {
     416             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     417             :     ASSERT(element_id.refinement_levels() == make_array<dim>(0_st) or
     418             :                not mortar_info.empty(),
     419             :            "Element has no neighbors but is not a full block");
     420             :     const auto time_stepping_policy = time_stepping_policy_for_h_refinement(
     421             :         mortar_info, &get<evolution::dg::Tags::MortarInfo<dim>>(parent_items),
     422             :         {});
     423             :     switch (time_stepping_policy) {
     424             :       case evolution::dg::TimeSteppingPolicy::Conservative: {
     425             :         if (time_stepper.number_of_past_steps() != 0) {
     426             :           ERROR_NO_TRACE(
     427             :               "Cannot perform h-refinement with LTS steppers requiring "
     428             :               "initialization.");
     429             :         }
     430             :         const auto integrator_order = time_stepper.order();
     431             :         if (variants::holds_alternative<TimeSteppers::Tags::FixedOrder>(
     432             :                 integrator_order)) {
     433             :           *history = typename history_tag::type{
     434             :               get<TimeSteppers::Tags::FixedOrder>(integrator_order)};
     435             :           return;
     436             :         }
     437             :         const auto start_order =
     438             :             get<TimeSteppers::Tags::VariableOrder>(integrator_order).minimum;
     439             :         *history = typename history_tag::type{start_order};
     440             : 
     441             :         const auto reduced_step = restart_time_step(parent_items, start_order);
     442             :         if (abs(reduced_step) < abs(*time_step)) {
     443             :           *time_step = reduced_step;
     444             :           *next_time_step_id = time_stepper.next_time_id(
     445             :               get<::Tags::TimeStepId>(parent_items), *time_step);
     446             :         }
     447             :         break;
     448             :       }
     449             :       case evolution::dg::TimeSteppingPolicy::EqualRate: {
     450             :         const auto& parent_id =
     451             :             get<domain::Tags::Element<dim>>(parent_items).id();
     452             :         const auto& parent_mesh = get<domain::Tags::Mesh<dim>>(parent_items);
     453             :         const auto child_sizes = domain::child_size(element_id.segment_ids(),
     454             :                                                     parent_id.segment_ids());
     455             :         transform(history, get<history_tag>(parent_items),
     456             :                   [&](const auto& source_entry) {
     457             :                     return Spectral::project(
     458             :                         source_entry, parent_mesh, new_mesh,
     459             :                         make_array<dim>(Spectral::SegmentSize::Full),
     460             :                         child_sizes);
     461             :                   });
     462             :         break;
     463             :       }
     464             :       default:
     465             :         ERROR("Unhandled time-stepping policy: " << time_stepping_policy);
     466             :     }
     467             :   }
     468             : 
     469             :   template <typename... Tags>
     470           0 :   static void apply(
     471             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     472             :       const gsl::not_null<typename history_tag::type*> history,
     473             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     474             :       const gsl::not_null<TimeDelta*> time_step, const Mesh<dim>& new_mesh,
     475             :       const ElementId<dim>& element_id, const TimeStepper& time_stepper,
     476             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>& mortar_info,
     477             :       const std::unordered_map<ElementId<dim>, tuples::TaggedTuple<Tags...>>&
     478             :           children_items) {
     479             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     480             :     ASSERT(element_id.refinement_levels() == make_array<dim>(0_st) or
     481             :                not mortar_info.empty(),
     482             :            "Element has no neighbors but is not a full block");
     483             :     const auto time_stepping_policy =
     484             :         time_stepping_policy_for_h_refinement<Tags...>(mortar_info, {},
     485             :                                                        {&children_items});
     486             :     switch (time_stepping_policy) {
     487             :       case evolution::dg::TimeSteppingPolicy::Conservative: {
     488             :         if (time_stepper.number_of_past_steps() != 0) {
     489             :           ERROR_NO_TRACE(
     490             :               "Cannot perform h-refinement with LTS steppers requiring "
     491             :               "initialization.");
     492             :         }
     493             :         const auto integrator_order = time_stepper.order();
     494             :         if (variants::holds_alternative<TimeSteppers::Tags::FixedOrder>(
     495             :                 integrator_order)) {
     496             :           *history = typename history_tag::type{
     497             :               get<TimeSteppers::Tags::FixedOrder>(integrator_order)};
     498             :           return;
     499             :         }
     500             :         const auto start_order =
     501             :             get<TimeSteppers::Tags::VariableOrder>(integrator_order).minimum;
     502             :         *history = typename history_tag::type{start_order};
     503             : 
     504             :         for (const auto& [child, child_items] : children_items) {
     505             :           const auto reduced_step = restart_time_step(child_items, start_order);
     506             :           if (abs(reduced_step) < abs(*time_step)) {
     507             :             *time_step = reduced_step;
     508             :             *next_time_step_id = time_stepper.next_time_id(
     509             :                 get<::Tags::TimeStepId>(children_items.begin()->second),
     510             :                 *time_step);
     511             :           }
     512             :         }
     513             :         break;
     514             :       }
     515             :       case evolution::dg::TimeSteppingPolicy::EqualRate: {
     516             :         bool first_child = true;
     517             :         for (const auto& [child_id, child_items] : children_items) {
     518             :           const auto& child_mesh = get<domain::Tags::Mesh<dim>>(child_items);
     519             :           const auto child_sizes = domain::child_size(child_id.segment_ids(),
     520             :                                                       element_id.segment_ids());
     521             :           if (first_child) {
     522             :             transform(history, get<history_tag>(child_items),
     523             :                       [&](const auto& source_entry) {
     524             :                         return Spectral::project(
     525             :                             source_entry, child_mesh, new_mesh, child_sizes,
     526             :                             make_array<dim>(Spectral::SegmentSize::Full));
     527             :                       });
     528             :             first_child = false;
     529             :           } else {
     530             :             transform_mutate(
     531             :                 history, get<history_tag>(child_items),
     532             :                 [&](const auto dest_entry, const auto& source_entry) {
     533             :                   *dest_entry += Spectral::project(
     534             :                       source_entry, child_mesh, new_mesh, child_sizes,
     535             :                       make_array<dim>(Spectral::SegmentSize::Full));
     536             :                 });
     537             :           }
     538             :         }
     539             :         break;
     540             :       }
     541             :       default:
     542             :         ERROR("Unhandled time-stepping policy: " << time_stepping_policy);
     543             :     }
     544             :   }
     545             : 
     546             :  private:
     547             :   template <typename... Tags>
     548             :   static evolution::dg::TimeSteppingPolicy
     549           0 :   time_stepping_policy_for_h_refinement(
     550             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>&
     551             :           element_infos,
     552             :       const std::optional<gsl::not_null<
     553             :           const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>*>>&
     554             :           parent_infos,
     555             :       const std::optional<gsl::not_null<const std::unordered_map<
     556             :           ElementId<dim>, tuples::TaggedTuple<Tags...>>*>>& children_items) {
     557             :     std::optional<evolution::dg::TimeSteppingPolicy> policy{};
     558             :     const auto process_infos =
     559             :         [&policy](const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>&
     560             :                       infos) {
     561             :           for (const auto& info : infos) {
     562             :             const auto mortar_policy = info.second.time_stepping_policy();
     563             :             ASSERT(not policy.has_value() or *policy == mortar_policy,
     564             :                    "Inconsistent policies: "
     565             :                        << *policy << " and " << mortar_policy
     566             :                        << "\nWe currently require all mortars to have the "
     567             :                           "same policy when doing h-refinement.  This might "
     568             :                           "be relaxed when we add an LTS policy other than "
     569             :                           "Conservative.");
     570             :             policy.emplace(mortar_policy);
     571             :           }
     572             :         };
     573             : 
     574             :     process_infos(element_infos);
     575             :     if (parent_infos.has_value()) {
     576             :       process_infos(**parent_infos);
     577             :     }
     578             :     if (children_items.has_value()) {
     579             :       if constexpr (sizeof...(Tags) > 0) {
     580             :         for (const auto& child : **children_items) {
     581             :           process_infos(
     582             :               get<evolution::dg::Tags::MortarInfo<dim>>(child.second));
     583             :         }
     584             :       } else {
     585             :         ERROR("Children but no child data");
     586             :       }
     587             :     }
     588             : 
     589             :     ASSERT(policy.has_value(),
     590             :            "Found no mortars, either before or after h-refinement.  A mortar "
     591             :            "should have been created or destroyed, so this is not possible.");
     592             :     return *policy;
     593             :   }
     594             : 
     595             :   template <typename... Tags>
     596           0 :   static TimeDelta restart_time_step(
     597             :       const tuples::TaggedTuple<Tags...>& old_items, const size_t start_order) {
     598             :     const auto& old_history = get<history_tag>(old_items);
     599             :     if (old_history.integration_order() == start_order) {
     600             :       return get<::Tags::TimeStep>(old_items);
     601             :     }
     602             : 
     603             :     const auto& time_step_id = get<::Tags::TimeStepId>(old_items);
     604             :     const auto& errors = get<::Tags::StepperErrors<variables_tag>>(old_items);
     605             :     if (not errors[1].has_value()) {
     606             :       ERROR_NO_TRACE(
     607             :           "Evolutions performing h-refinement with variable-order local "
     608             :           "time-stepping must use ErrorControl for step size choosing.");
     609             :     }
     610             :     ASSERT(errors[1]->errors[start_order - 1].has_value(),
     611             :            "Start-order estimate not available.");
     612             : 
     613             :     // At this low an order, we are almost certainly step-size-limited
     614             :     // by accuracy rather than stability, so ignore things like the
     615             :     // change to the grid spacing.
     616             :     return choose_lts_step_size(
     617             :         time_step_id.step_time(),
     618             :         errors[1]->step_size.value() *
     619             :             pow(1.0 / std::max(*errors[1]->errors[start_order - 1], 1e-14),
     620             :                 1.0 / static_cast<double>(start_order)));
     621             :   }
     622             : };
     623             : }  // namespace Initialization

Generated by: LCOV version 1.14