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

Generated by: LCOV version 2.0-1