SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Initialization - Evolution.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 14 42 33.3 %
Date: 2026-03-03 02:01:44
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/ApplyMatrices.hpp"
      15             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      16             : #include "DataStructures/DataBox/Prefixes.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/Slab.hpp"
      34             : #include "Time/StepChoosers/StepChooser.hpp"
      35             : #include "Time/Tags/AdaptiveSteppingDiagnostics.hpp"
      36             : #include "Time/Tags/HistoryEvolvedVariables.hpp"
      37             : #include "Time/Tags/StepNumberWithinSlab.hpp"
      38             : #include "Time/Tags/Time.hpp"
      39             : #include "Time/Tags/TimeStep.hpp"
      40             : #include "Time/Tags/TimeStepId.hpp"
      41             : #include "Time/Tags/TimeStepper.hpp"
      42             : #include "Time/Time.hpp"
      43             : #include "Time/TimeStepId.hpp"
      44             : #include "Time/TimeSteppers/LtsTimeStepper.hpp"
      45             : #include "Time/TimeSteppers/TimeStepper.hpp"
      46             : #include "Utilities/Algorithm.hpp"
      47             : #include "Utilities/ErrorHandling/Assert.hpp"
      48             : #include "Utilities/ErrorHandling/Error.hpp"
      49             : #include "Utilities/Gsl.hpp"
      50             : #include "Utilities/Literals.hpp"
      51             : #include "Utilities/MakeArray.hpp"
      52             : #include "Utilities/ProtocolHelpers.hpp"
      53             : #include "Utilities/TMPL.hpp"
      54             : #include "Utilities/TaggedTuple.hpp"
      55             : 
      56             : /// \cond
      57             : namespace Parallel::Tags {
      58             : template <typename Index>
      59             : struct ArrayIndex;
      60             : }  // namespace Parallel::Tags
      61             : namespace Tags {
      62             : template <typename Tag>
      63             : struct StepperErrors;
      64             : }  // namespace Tags
      65             : namespace amr::Tags {
      66             : template <size_t VolumeDim>
      67             : struct Info;
      68             : }  // namespace amr::Tags
      69             : namespace domain::Tags {
      70             : template <size_t VolumeDim>
      71             : struct Element;
      72             : template <size_t VolumeDim>
      73             : struct Mesh;
      74             : }  // namespace domain::Tags
      75             : namespace evolution::dg::Tags {
      76             : template <size_t Dim>
      77             : struct MortarInfo;
      78             : }  // namespace evolution::dg::Tags
      79             : /// \endcond
      80             : 
      81             : namespace Initialization {
      82             : 
      83             : namespace detail {
      84             : inline Time initial_time(const bool time_runs_forward,
      85             :                          const double initial_time_value,
      86             :                          const double initial_slab_size) {
      87             :   const Slab initial_slab =
      88             :       time_runs_forward
      89             :           ? Slab::with_duration_from_start(initial_time_value,
      90             :                                            initial_slab_size)
      91             :           : Slab::with_duration_to_end(initial_time_value, initial_slab_size);
      92             :   return time_runs_forward ? initial_slab.start() : initial_slab.end();
      93             : }
      94             : 
      95             : template <typename TimeStepper>
      96             : void set_next_time_step_id(const gsl::not_null<TimeStepId*> next_time_step_id,
      97             :                            const Time& initial_time,
      98             :                            const bool time_runs_forward,
      99             :                            const TimeStepper& time_stepper) {
     100             :   *next_time_step_id = TimeStepId(
     101             :       time_runs_forward,
     102             :       -static_cast<int64_t>(time_stepper.number_of_past_steps()), initial_time);
     103             : }
     104             : }  // namespace detail
     105             : 
     106             : /// \ingroup InitializationGroup
     107             : /// \brief Initialize items related to time stepping
     108             : ///
     109             : /// \details See the type aliases defined below for what items are added to the
     110             : /// GlobalCache and DataBox and how they are initialized
     111             : ///
     112             : /// Since the evolution has not started yet, initialize the state
     113             : /// _before_ the initial time. So `Tags::TimeStepId` is undefined at this point,
     114             : /// and `Tags::Next<Tags::TimeStepId>` is the initial time.
     115             : template <typename Metavariables, typename TimeStepperBase>
     116           1 : struct TimeStepping {
     117             :   /// Tags for constant items added to the GlobalCache.  These items are
     118             :   /// initialized from input file options.
     119           1 :   using const_global_cache_tags =
     120             :       tmpl::list<::Tags::ConcreteTimeStepper<TimeStepperBase>>;
     121             : 
     122             :   /// Tags for mutable items added to the GlobalCache.  These items are
     123             :   /// initialized from input file options.
     124           1 :   using mutable_global_cache_tags = tmpl::list<>;
     125             : 
     126             :   /// Tags for items fetched by the DataBox and passed to the apply function
     127           1 :   using argument_tags =
     128             :       tmpl::list<::Tags::Time, Tags::InitialTimeDelta,
     129             :                  Tags::InitialSlabSize<TimeStepperBase::local_time_stepping>,
     130             :                  ::Tags::ConcreteTimeStepper<TimeStepperBase>>;
     131             : 
     132             :   /// Tags for simple DataBox items that are initialized from input file options
     133           1 :   using simple_tags_from_options =
     134             :       tmpl::list<::Tags::Time, Tags::InitialTimeDelta,
     135             :                  Tags::InitialSlabSize<TimeStepperBase::local_time_stepping>>;
     136             : 
     137             :   /// Tags for simple DataBox items that are default initialized.
     138           1 :   using default_initialized_simple_tags =
     139             :       tmpl::push_back<StepChoosers::step_chooser_simple_tags<
     140             :                           Metavariables, TimeStepperBase::local_time_stepping>,
     141             :                       ::Tags::TimeStepId, ::Tags::StepNumberWithinSlab,
     142             :                       ::Tags::AdaptiveSteppingDiagnostics>;
     143             : 
     144             :   /// Tags for items in the DataBox that are mutated by the apply function
     145           1 :   using return_tags =
     146             :       tmpl::list<::Tags::Next<::Tags::TimeStepId>, ::Tags::TimeStep,
     147             :                  ::Tags::ChangeSlabSize::SlabSizeGoal>;
     148             : 
     149             :   /// Tags for mutable DataBox items that are either default initialized or
     150             :   /// initialized by the apply function
     151           1 :   using simple_tags =
     152             :       tmpl::append<default_initialized_simple_tags, return_tags>;
     153             : 
     154             :   /// Tags for immutable DataBox items (compute items or reference items) added
     155             :   /// to the DataBox.
     156           1 :   using compute_tags = time_stepper_ref_tags<TimeStepperBase>;
     157             : 
     158             :   /// Given the items fetched from a DataBox by the argument_tags when using
     159             :   /// LTS, mutate the items in the DataBox corresponding to return_tags
     160           1 :   static void apply(const gsl::not_null<TimeStepId*> next_time_step_id,
     161             :                     const gsl::not_null<TimeDelta*> time_step,
     162             :                     const gsl::not_null<double*> slab_size_goal,
     163             :                     const double initial_time_value,
     164             :                     const double initial_dt_value,
     165             :                     const double initial_slab_size,
     166             :                     const LtsTimeStepper& time_stepper) {
     167             :     const bool time_runs_forward = initial_dt_value > 0.0;
     168             :     const Time initial_time = detail::initial_time(
     169             :         time_runs_forward, initial_time_value, initial_slab_size);
     170             :     detail::set_next_time_step_id(next_time_step_id, initial_time,
     171             :                                   time_runs_forward, time_stepper);
     172             :     *time_step = choose_lts_step_size(initial_time, initial_dt_value);
     173             :     *slab_size_goal =
     174             :         time_runs_forward ? initial_slab_size : -initial_slab_size;
     175             :   }
     176             : 
     177             :   /// Given the items fetched from a DataBox by the argument_tags, when not
     178             :   /// using LTS, mutate the items in the DataBox corresponding to return_tags
     179           1 :   static void apply(const gsl::not_null<TimeStepId*> next_time_step_id,
     180             :                     const gsl::not_null<TimeDelta*> time_step,
     181             :                     const gsl::not_null<double*> slab_size_goal,
     182             :                     const double initial_time_value,
     183             :                     const double initial_dt_value,
     184             :                     const double initial_slab_size,
     185             :                     const TimeStepper& time_stepper) {
     186             :     const bool time_runs_forward = initial_dt_value > 0.0;
     187             :     const Time initial_time = detail::initial_time(
     188             :         time_runs_forward, initial_time_value, initial_slab_size);
     189             :     detail::set_next_time_step_id(next_time_step_id, initial_time,
     190             :                                   time_runs_forward, time_stepper);
     191             :     *time_step = (time_runs_forward ? 1 : -1) * initial_time.slab().duration();
     192             :     *slab_size_goal =
     193             :         time_runs_forward ? initial_slab_size : -initial_slab_size;
     194             :   }
     195             : };
     196             : 
     197             : /// \brief Initialize/update items related to time stepping after an AMR change
     198             : template <size_t Dim>
     199           1 : struct ProjectTimeStepping : tt::ConformsTo<amr::protocols::Projector> {
     200           0 :   using return_tags =
     201             :       tmpl::list<::Tags::TimeStepId, ::Tags::Next<::Tags::TimeStepId>,
     202             :                  ::Tags::TimeStep, ::Tags::Time, ::Tags::StepNumberWithinSlab,
     203             :                  ::Tags::AdaptiveSteppingDiagnostics,
     204             :                  ::Tags::ChangeSlabSize::SlabSizeGoal>;
     205           0 :   using argument_tags = tmpl::list<Parallel::Tags::ArrayIndex<ElementId<Dim>>>;
     206             : 
     207           0 :   static void apply(
     208             :       const gsl::not_null<TimeStepId*> /*time_step_id*/,
     209             :       const gsl::not_null<TimeStepId*> /*next_time_step_id*/,
     210             :       const gsl::not_null<TimeDelta*> /*time_step*/,
     211             :       const gsl::not_null<double*> /*time*/,
     212             :       const gsl::not_null<uint64_t*> /*step_number_within_slab*/,
     213             :       const gsl::not_null<AdaptiveSteppingDiagnostics*>
     214             :       /*adaptive_stepping_diagnostics*/,
     215             :       const gsl::not_null<double*> /*slab_size_goal*/,
     216             :       const ElementId<Dim>& /*element_id*/,
     217             :       const std::pair<Mesh<Dim>, Element<Dim>>& /*old_mesh_and_element*/) {
     218             :     // Do not change anything for p-refinement
     219             :   }
     220             : 
     221             :   template <typename... Tags>
     222           0 :   static void apply(const gsl::not_null<TimeStepId*> time_step_id,
     223             :                     const gsl::not_null<TimeStepId*> next_time_step_id,
     224             :                     const gsl::not_null<TimeDelta*> time_step,
     225             :                     const gsl::not_null<double*> time,
     226             :                     const gsl::not_null<uint64_t*> step_number_within_slab,
     227             :                     const gsl::not_null<AdaptiveSteppingDiagnostics*>
     228             :                         adaptive_stepping_diagnostics,
     229             :                     const gsl::not_null<double*> slab_size_goal,
     230             :                     const ElementId<Dim>& element_id,
     231             :                     const tuples::TaggedTuple<Tags...>& parent_items) {
     232             :     *time_step_id = get<::Tags::TimeStepId>(parent_items);
     233             :     *next_time_step_id = get<::Tags::Next<::Tags::TimeStepId>>(parent_items);
     234             :     *time_step = get<::Tags::TimeStep>(parent_items);
     235             :     *time = get<::Tags::Time>(parent_items);
     236             :     *slab_size_goal = get<::Tags::ChangeSlabSize::SlabSizeGoal>(parent_items);
     237             :     *step_number_within_slab = get<::Tags::StepNumberWithinSlab>(parent_items);
     238             : 
     239             :     // Since AdaptiveSteppingDiagnostics are reduced over all elements, we
     240             :     // set the slab quantities to the same value over all children, and the
     241             :     // step quantities to belong to the first child
     242             :     const auto& parent_diagnostics =
     243             :         get<::Tags::AdaptiveSteppingDiagnostics>(parent_items);
     244             :     const auto& parent_amr_flags =
     245             :         get<amr::Tags::Info<Dim>>(parent_items).flags;
     246             :     const auto& parent_id =
     247             :         get<Parallel::Tags::ArrayIndex<ElementId<Dim>>>(parent_items);
     248             :     auto children_ids = amr::ids_of_children(parent_id, parent_amr_flags);
     249             :     if (element_id == children_ids.front()) {
     250             :       *adaptive_stepping_diagnostics = parent_diagnostics;
     251             :     } else {
     252             :       adaptive_stepping_diagnostics->number_of_slabs =
     253             :           parent_diagnostics.number_of_slabs;
     254             :       adaptive_stepping_diagnostics->number_of_slab_size_changes =
     255             :           parent_diagnostics.number_of_slab_size_changes;
     256             :     }
     257             :   }
     258             : 
     259             :   template <typename... Tags>
     260           0 :   static void apply(
     261             :       const gsl::not_null<TimeStepId*> time_step_id,
     262             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     263             :       const gsl::not_null<TimeDelta*> time_step,
     264             :       const gsl::not_null<double*> time,
     265             :       const gsl::not_null<uint64_t*> step_number_within_slab,
     266             :       const gsl::not_null<AdaptiveSteppingDiagnostics*>
     267             :           adaptive_stepping_diagnostics,
     268             :       const gsl::not_null<double*> slab_size_goal,
     269             :       const ElementId<Dim>& /*element_id*/,
     270             :       const std::unordered_map<ElementId<Dim>, tuples::TaggedTuple<Tags...>>&
     271             :           children_items) {
     272             :     const auto slowest_child =
     273             :         alg::min_element(children_items, [](const auto& a, const auto& b) {
     274             :           const auto& time_step_a = get<::Tags::TimeStep>(a.second);
     275             :           const auto& time_step_b = get<::Tags::TimeStep>(b.second);
     276             :           ASSERT(time_step_a.is_positive() == time_step_b.is_positive(),
     277             :                  "Elements are not taking time steps in the same direction!");
     278             :           return time_step_a.is_positive() ? (time_step_a < time_step_b)
     279             :                                            : (time_step_a > time_step_b);
     280             :         });
     281             :     const auto& slowest_child_items = (*slowest_child).second;
     282             :     *time_step_id = get<::Tags::TimeStepId>(slowest_child_items);
     283             :     *next_time_step_id =
     284             :         get<::Tags::Next<::Tags::TimeStepId>>(slowest_child_items);
     285             :     *time_step = get<::Tags::TimeStep>(slowest_child_items);
     286             :     *time = get<::Tags::Time>(slowest_child_items);
     287             :     *slab_size_goal =
     288             :         get<::Tags::ChangeSlabSize::SlabSizeGoal>(slowest_child_items);
     289             :     *step_number_within_slab =
     290             :         get<::Tags::StepNumberWithinSlab>(slowest_child_items);
     291             :     const auto& slowest_child_diagnostics =
     292             :         get<::Tags::AdaptiveSteppingDiagnostics>(slowest_child_items);
     293             : 
     294             :     adaptive_stepping_diagnostics->number_of_slabs =
     295             :         slowest_child_diagnostics.number_of_slabs;
     296             :     adaptive_stepping_diagnostics->number_of_slab_size_changes =
     297             :         slowest_child_diagnostics.number_of_slab_size_changes;
     298             :     for (const auto& [_, child_items] : children_items) {
     299             :       *adaptive_stepping_diagnostics +=
     300             :           get<::Tags::AdaptiveSteppingDiagnostics>(child_items);
     301             :     }
     302             :   }
     303             : };
     304             : 
     305             : /// \ingroup InitializationGroup
     306             : /// \brief Initialize time-stepper items
     307             : ///
     308             : /// DataBox changes:
     309             : /// - Adds:
     310             : ///   * `db::add_tag_prefix<Tags::dt, variables_tag>`
     311             : ///   * `Tags::HistoryEvolvedVariables<variables_tag>`
     312             : /// - Removes: nothing
     313             : /// - Modifies: nothing
     314             : ///
     315             : /// \note HistoryEvolvedVariables is allocated, but needs to be initialized
     316             : template <typename Metavariables>
     317           1 : struct TimeStepperHistory {
     318           0 :   static constexpr size_t dim = Metavariables::volume_dim;
     319           0 :   using variables_tag = typename Metavariables::system::variables_tag;
     320           0 :   using dt_variables_tag = db::add_tag_prefix<::Tags::dt, variables_tag>;
     321             : 
     322           0 :   using const_global_cache_tags = tmpl::list<>;
     323           0 :   using mutable_global_cache_tags = tmpl::list<>;
     324           0 :   using simple_tags_from_options = tmpl::list<>;
     325           0 :   using simple_tags =
     326             :       tmpl::list<dt_variables_tag,
     327             :                  ::Tags::HistoryEvolvedVariables<variables_tag>>;
     328           0 :   using compute_tags = tmpl::list<>;
     329             : 
     330           0 :   using argument_tags =
     331             :       tmpl::list<::Tags::TimeStepper<TimeStepper>, domain::Tags::Mesh<dim>>;
     332           0 :   using return_tags = simple_tags;
     333             : 
     334           0 :   static void apply(
     335             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     336             :       const gsl::not_null<TimeSteppers::History<typename variables_tag::type>*>
     337             :           history,
     338             :       const TimeStepper& time_stepper, const Mesh<dim>& mesh) {
     339             :     // Will be overwritten before use
     340             :     dt_vars->initialize(mesh.number_of_grid_points());
     341             : 
     342             :     // All steppers we have that need to start at low order require
     343             :     // one additional point per order, so this is the order that
     344             :     // requires no initial past steps.
     345             :     const size_t starting_order =
     346             :         visit(
     347             :             []<typename Tag>(
     348             :                 const std::pair<tmpl::type_<Tag>, typename Tag::type&&> order) {
     349             :               if constexpr (std::is_same_v<Tag,
     350             :                                            TimeSteppers::Tags::FixedOrder>) {
     351             :                 return order.second;
     352             :               } else {
     353             :                 return order.second.minimum;
     354             :               }
     355             :             },
     356             :             time_stepper.order()) -
     357             :         time_stepper.number_of_past_steps();
     358             :     history->integration_order(starting_order);
     359             :   }
     360             : };
     361             : 
     362             : /// \brief Initialize/update items related to time stepper history after an AMR
     363             : /// change
     364             : ///
     365             : /// \note `Tags::TimeStep` and `Tags::Next<Tags::TimeStepId>` are not
     366             : /// initially set by this projector.  They are only updated if the
     367             : /// time stepper must be restarted because of LTS h-refinement.
     368             : template <typename Metavariables>
     369           1 : struct ProjectTimeStepperHistory : tt::ConformsTo<amr::protocols::Projector> {
     370           0 :   static constexpr size_t dim = Metavariables::volume_dim;
     371           0 :   using variables_tag = typename Metavariables::system::variables_tag;
     372           0 :   using dt_variables_tag = db::add_tag_prefix<::Tags::dt, variables_tag>;
     373           0 :   using history_tag = ::Tags::HistoryEvolvedVariables<variables_tag>;
     374             : 
     375           0 :   using return_tags =
     376             :       tmpl::list<dt_variables_tag, history_tag,
     377             :                  ::Tags::Next<::Tags::TimeStepId>, ::Tags::TimeStep>;
     378           0 :   using argument_tags = tmpl::list<
     379             :       domain::Tags::Mesh<dim>, Parallel::Tags::ArrayIndex<ElementId<dim>>,
     380             :       ::Tags::TimeStepper<TimeStepper>, evolution::dg::Tags::MortarInfo<dim>>;
     381             : 
     382           0 :   static void apply(
     383             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     384             :       const gsl::not_null<typename history_tag::type*> history,
     385             :       const gsl::not_null<TimeStepId*> /*next_time_step_id*/,
     386             :       const gsl::not_null<TimeDelta*> /*time_step*/, const Mesh<dim>& new_mesh,
     387             :       const ElementId<dim>& /*element_id*/, const TimeStepper& /*time_stepper*/,
     388             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>&
     389             :       /*mortar_info*/,
     390             :       const std::pair<Mesh<dim>, Element<dim>>& old_mesh_and_element) {
     391             :     const auto& old_mesh = old_mesh_and_element.first;
     392             :     if (old_mesh == new_mesh) {
     393             :       return;  // mesh was not refined, so no projection needed
     394             :     }
     395             :     const auto projection_matrices =
     396             :         Spectral::p_projection_matrices(old_mesh, new_mesh);
     397             :     const auto& old_extents = old_mesh.extents();
     398             :     history->map_entries(
     399             :         [&projection_matrices, &old_extents](const auto entry) {
     400             :           *entry = apply_matrices(projection_matrices, *entry, old_extents);
     401             :         });
     402             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     403             :   }
     404             : 
     405             :   template <typename... Tags>
     406           0 :   static void apply(
     407             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     408             :       const gsl::not_null<typename history_tag::type*> history,
     409             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     410             :       const gsl::not_null<TimeDelta*> time_step, const Mesh<dim>& new_mesh,
     411             :       const ElementId<dim>& element_id, const TimeStepper& time_stepper,
     412             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>& mortar_info,
     413             :       const tuples::TaggedTuple<Tags...>& parent_items) {
     414             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     415             :     ASSERT(element_id.refinement_levels() == make_array<dim>(0_st) or
     416             :                not mortar_info.empty(),
     417             :            "Element has no neighbors but is not a full block");
     418             :     const auto time_stepping_policy = time_stepping_policy_for_h_refinement(
     419             :         mortar_info, &get<evolution::dg::Tags::MortarInfo<dim>>(parent_items),
     420             :         {});
     421             :     switch (time_stepping_policy) {
     422             :       case evolution::dg::TimeSteppingPolicy::Conservative: {
     423             :         if (time_stepper.number_of_past_steps() != 0) {
     424             :           ERROR_NO_TRACE(
     425             :               "Cannot perform h-refinement with LTS steppers requiring "
     426             :               "initialization.");
     427             :         }
     428             :         const auto integrator_order = time_stepper.order();
     429             :         if (variants::holds_alternative<TimeSteppers::Tags::FixedOrder>(
     430             :                 integrator_order)) {
     431             :           *history = typename history_tag::type{
     432             :               get<TimeSteppers::Tags::FixedOrder>(integrator_order)};
     433             :           return;
     434             :         }
     435             :         const auto start_order =
     436             :             get<TimeSteppers::Tags::VariableOrder>(integrator_order).minimum;
     437             :         *history = typename history_tag::type{start_order};
     438             : 
     439             :         const auto reduced_step = restart_time_step(parent_items, start_order);
     440             :         if (abs(reduced_step) < abs(*time_step)) {
     441             :           *time_step = reduced_step;
     442             :           *next_time_step_id = time_stepper.next_time_id(
     443             :               get<::Tags::TimeStepId>(parent_items), *time_step);
     444             :         }
     445             :         break;
     446             :       }
     447             :       case evolution::dg::TimeSteppingPolicy::EqualRate: {
     448             :         const auto& parent_id =
     449             :             get<domain::Tags::Element<dim>>(parent_items).id();
     450             :         const auto& parent_mesh = get<domain::Tags::Mesh<dim>>(parent_items);
     451             :         const auto child_sizes = domain::child_size(element_id.segment_ids(),
     452             :                                                     parent_id.segment_ids());
     453             :         const auto projection_matrices =
     454             :             Spectral::projection_matrix_parent_to_child(parent_mesh, new_mesh,
     455             :                                                         child_sizes);
     456             :         transform(history, get<history_tag>(parent_items),
     457             :                   [&](const auto& source_entry) {
     458             :                     return apply_matrices(projection_matrices, source_entry,
     459             :                                           parent_mesh.extents());
     460             :                   });
     461             :         break;
     462             :       }
     463             :       default:
     464             :         ERROR("Unhandled time-stepping policy: " << time_stepping_policy);
     465             :     }
     466             :   }
     467             : 
     468             :   template <typename... Tags>
     469           0 :   static void apply(
     470             :       const gsl::not_null<typename dt_variables_tag::type*> dt_vars,
     471             :       const gsl::not_null<typename history_tag::type*> history,
     472             :       const gsl::not_null<TimeStepId*> next_time_step_id,
     473             :       const gsl::not_null<TimeDelta*> time_step, const Mesh<dim>& new_mesh,
     474             :       const ElementId<dim>& element_id, const TimeStepper& time_stepper,
     475             :       const DirectionalIdMap<dim, evolution::dg::MortarInfo<dim>>& mortar_info,
     476             :       const std::unordered_map<ElementId<dim>, tuples::TaggedTuple<Tags...>>&
     477             :           children_items) {
     478             :     dt_vars->initialize(new_mesh.number_of_grid_points());
     479             :     ASSERT(element_id.refinement_levels() == make_array<dim>(0_st) or
     480             :                not mortar_info.empty(),
     481             :            "Element has no neighbors but is not a full block");
     482             :     const auto time_stepping_policy =
     483             :         time_stepping_policy_for_h_refinement<Tags...>(mortar_info, {},
     484             :                                                        {&children_items});
     485             :     switch (time_stepping_policy) {
     486             :       case evolution::dg::TimeSteppingPolicy::Conservative: {
     487             :         if (time_stepper.number_of_past_steps() != 0) {
     488             :           ERROR_NO_TRACE(
     489             :               "Cannot perform h-refinement with LTS steppers requiring "
     490             :               "initialization.");
     491             :         }
     492             :         const auto integrator_order = time_stepper.order();
     493             :         if (variants::holds_alternative<TimeSteppers::Tags::FixedOrder>(
     494             :                 integrator_order)) {
     495             :           *history = typename history_tag::type{
     496             :               get<TimeSteppers::Tags::FixedOrder>(integrator_order)};
     497             :           return;
     498             :         }
     499             :         const auto start_order =
     500             :             get<TimeSteppers::Tags::VariableOrder>(integrator_order).minimum;
     501             :         *history = typename history_tag::type{start_order};
     502             : 
     503             :         for (const auto& [child, child_items] : children_items) {
     504             :           const auto reduced_step = restart_time_step(child_items, start_order);
     505             :           if (abs(reduced_step) < abs(*time_step)) {
     506             :             *time_step = reduced_step;
     507             :             *next_time_step_id = time_stepper.next_time_id(
     508             :                 get<::Tags::TimeStepId>(children_items.begin()->second),
     509             :                 *time_step);
     510             :           }
     511             :         }
     512             :         break;
     513             :       }
     514             :       case evolution::dg::TimeSteppingPolicy::EqualRate: {
     515             :         bool first_child = true;
     516             :         for (const auto& [child_id, child_items] : children_items) {
     517             :           const auto& child_mesh = get<domain::Tags::Mesh<dim>>(child_items);
     518             :           const auto child_sizes = domain::child_size(child_id.segment_ids(),
     519             :                                                       element_id.segment_ids());
     520             :           const auto projection_matrices =
     521             :               Spectral::projection_matrix_child_to_parent(child_mesh, new_mesh,
     522             :                                                           child_sizes);
     523             :           if (first_child) {
     524             :             transform(history, get<history_tag>(child_items),
     525             :                       [&](const auto& source_entry) {
     526             :                         return apply_matrices(projection_matrices, source_entry,
     527             :                                               child_mesh.extents());
     528             :                       });
     529             :             first_child = false;
     530             :           } else {
     531             :             transform_mutate(
     532             :                 history, get<history_tag>(child_items),
     533             :                 [&](const auto dest_entry, const auto& source_entry) {
     534             :                   *dest_entry += apply_matrices(
     535             :                       projection_matrices, source_entry, child_mesh.extents());
     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