SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DiscontinuousGalerkin/Initialization - Mortars.hpp Hit Total Coverage
Commit: 3ffcbc8ecf43797401b60bcca17d6040ee06f013 Lines: 3 19 15.8 %
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 <array>
       7             : #include <cstddef>
       8             : #include <optional>
       9             : #include <tuple>
      10             : #include <unordered_map>
      11             : #include <utility>
      12             : #include <vector>
      13             : 
      14             : #include "DataStructures/ApplyMatrices.hpp"
      15             : #include "DataStructures/DataBox/DataBox.hpp"
      16             : #include "DataStructures/DataBox/DataBoxTag.hpp"
      17             : #include "DataStructures/DataBox/PrefixHelpers.hpp"
      18             : #include "DataStructures/DataBox/Prefixes.hpp"
      19             : #include "DataStructures/Variables.hpp"
      20             : #include "Domain/Creators/Tags/Domain.hpp"
      21             : #include "Domain/Structure/ChildSize.hpp"
      22             : #include "Domain/Structure/Direction.hpp"
      23             : #include "Domain/Structure/Element.hpp"
      24             : #include "Domain/Structure/Neighbors.hpp"
      25             : #include "Domain/Structure/OrientationMap.hpp"
      26             : #include "Domain/Structure/TrimMap.hpp"
      27             : #include "Domain/Tags.hpp"
      28             : #include "Domain/Tags/NeighborMesh.hpp"
      29             : #include "Evolution/DiscontinuousGalerkin/InboxTags.hpp"
      30             : #include "Evolution/DiscontinuousGalerkin/Initialization/QuadratureTag.hpp"
      31             : #include "Evolution/DiscontinuousGalerkin/MortarData.hpp"
      32             : #include "Evolution/DiscontinuousGalerkin/MortarDataHolder.hpp"
      33             : #include "Evolution/DiscontinuousGalerkin/MortarInfo.hpp"
      34             : #include "Evolution/DiscontinuousGalerkin/MortarTags.hpp"
      35             : #include "Evolution/DiscontinuousGalerkin/NormalVectorTags.hpp"
      36             : #include "Evolution/DiscontinuousGalerkin/TimeSteppingPolicy.hpp"
      37             : #include "NumericalAlgorithms/DiscontinuousGalerkin/MortarHelpers.hpp"
      38             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      39             : #include "NumericalAlgorithms/Spectral/SegmentSize.hpp"
      40             : #include "Parallel/AlgorithmExecution.hpp"
      41             : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
      42             : #include "ParallelAlgorithms/Initialization/MutateAssign.hpp"
      43             : #include "Time/BoundaryHistory.hpp"
      44             : #include "Time/TimeStepId.hpp"
      45             : #include "Utilities/ErrorHandling/Assert.hpp"
      46             : #include "Utilities/Gsl.hpp"
      47             : #include "Utilities/MakeArray.hpp"
      48             : #include "Utilities/TMPL.hpp"
      49             : 
      50             : /// \cond
      51             : template <size_t Dim>
      52             : class Domain;
      53             : namespace Parallel {
      54             : template <typename Metavariables>
      55             : class GlobalCache;
      56             : }  // namespace Parallel
      57             : namespace Spectral {
      58             : enum class Quadrature : uint8_t;
      59             : }  // namespace Spectral
      60             : namespace Tags {
      61             : struct TimeStepId;
      62             : }  // namespace Tags
      63             : namespace tuples {
      64             : template <class... Tags>
      65             : class TaggedTuple;
      66             : }  // namespace tuples
      67             : /// \endcond
      68             : 
      69           1 : namespace evolution::dg::Initialization {
      70             : namespace detail {
      71             : template <size_t Dim>
      72             : ::dg::MortarMap<Dim, evolution::dg::MortarDataHolder<Dim>> empty_mortar_data(
      73             :     const Element<Dim>& element);
      74             : 
      75             : template <size_t Dim>
      76             : ::dg::MortarMap<Dim, MortarInfo<Dim>> mortar_infos(
      77             :     const Domain<Dim>& domain, const Element<Dim>& element,
      78             :     const Mesh<Dim>& volume_mesh,
      79             :     const ::dg::MortarMap<Dim, Mesh<Dim>>& neighbor_mesh,
      80             :     bool local_time_stepping);
      81             : 
      82             : template <size_t Dim>
      83             : std::tuple<::dg::MortarMap<Dim, Mesh<Dim - 1>>,
      84             :            ::dg::MortarMap<Dim, TimeStepId>,
      85             :            DirectionMap<Dim, std::optional<Variables<tmpl::list<
      86             :                                  evolution::dg::Tags::MagnitudeOfNormal,
      87             :                                  evolution::dg::Tags::NormalCovector<Dim>>>>>>
      88             : mortars_apply_impl(const Element<Dim>& element,
      89             :                    const TimeStepId& next_temporal_id,
      90             :                    const Mesh<Dim>& volume_mesh,
      91             :                    const ::dg::MortarMap<Dim, Mesh<Dim>>& neighbor_mesh);
      92             : 
      93             : template <size_t Dim>
      94             : void h_refine_structure(
      95             :     gsl::not_null<::dg::MortarMap<Dim, evolution::dg::MortarDataHolder<Dim>>*>
      96             :         mortar_data,
      97             :     gsl::not_null<::dg::MortarMap<Dim, Mesh<Dim - 1>>*> mortar_mesh,
      98             :     gsl::not_null<::dg::MortarMap<Dim, MortarInfo<Dim>>*> mortar_infos,
      99             :     gsl::not_null<::dg::MortarMap<Dim, TimeStepId>*> mortar_next_temporal_id,
     100             :     gsl::not_null<
     101             :         DirectionMap<Dim, std::optional<::Variables<tmpl::list<
     102             :                               ::evolution::dg::Tags::MagnitudeOfNormal,
     103             :                               ::evolution::dg::Tags::NormalCovector<Dim>>>>>*>
     104             :         normal_covector_and_magnitude,
     105             :     const Domain<Dim>& domain, const Mesh<Dim>& new_mesh,
     106             :     const Element<Dim>& new_element,
     107             :     const ::dg::MortarMap<Dim, Mesh<Dim>>& neighbor_mesh,
     108             :     const TimeStepId& current_temporal_id, bool local_time_stepping);
     109             : }  // namespace detail
     110             : 
     111             : /*!
     112             :  * \brief Initialize mortars between elements for exchanging boundary correction
     113             :  * terms.
     114             :  *
     115             :  * Uses:
     116             :  * - DataBox:
     117             :  *   - `Tags::Element<Dim>`
     118             :  *   - `Tags::Mesh<Dim>`
     119             :  *   - `BoundaryScheme::receive_temporal_id`
     120             :  *
     121             :  * DataBox changes:
     122             :  * - Adds:
     123             :  *   - `Tags::MortarData<Dim>`
     124             :  *   - `Tags::MortarMesh<Dim>`
     125             :  *   - `Tags::MortarInfo<Dim>`
     126             :  *   - `Tags::MortarNextTemporalId<Dim>`
     127             :  *   - `evolution::dg::Tags::NormalCovectorAndMagnitude<Dim>`
     128             :  * - Removes: nothing
     129             :  * - Modifies: nothing
     130             :  */
     131             : template <size_t Dim, typename System>
     132           1 : struct Mortars {
     133             :  public:
     134           0 :   using const_global_cache_tags = tmpl::list<domain::Tags::Domain<Dim>>;
     135           0 :   using simple_tags_from_options = tmpl::list<>;
     136             : 
     137           0 :   using simple_tags = tmpl::list<
     138             :       Tags::MortarData<Dim>, Tags::MortarMesh<Dim>, Tags::MortarInfo<Dim>,
     139             :       Tags::MortarNextTemporalId<Dim>,
     140             :       evolution::dg::Tags::NormalCovectorAndMagnitude<Dim>,
     141             :       Tags::MortarDataHistory<
     142             :           Dim, typename db::add_tag_prefix<
     143             :                    ::Tags::dt, typename System::variables_tag>::type>>;
     144           0 :   using compute_tags = tmpl::list<>;
     145             : 
     146             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     147             :             typename ArrayIndex, typename ActionList,
     148             :             typename ParallelComponent>
     149           0 :   static Parallel::iterable_action_return_t apply(
     150             :       db::DataBox<DbTagsList>& box,
     151             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     152             :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     153             :       const ArrayIndex& /*array_index*/, ActionList /*meta*/,
     154             :       const ParallelComponent* const /*meta*/) {
     155             :     const auto& domain = db::get<domain::Tags::Domain<Dim>>(box);
     156             :     const auto& element = db::get<::domain::Tags::Element<Dim>>(box);
     157             :     const auto& volume_mesh = db::get<domain::Tags::Mesh<Dim>>(box);
     158             :     const auto& neighbor_mesh = db::get<domain::Tags::NeighborMesh<Dim>>(box);
     159             :     auto mortar_data = detail::empty_mortar_data(element);
     160             :     auto mortar_infos =
     161             :         detail::mortar_infos(domain, element, volume_mesh, neighbor_mesh,
     162             :                              Metavariables::local_time_stepping);
     163             :     auto [mortar_meshes, mortar_next_temporal_ids, normal_covector_quantities] =
     164             :         detail::mortars_apply_impl(
     165             :             element, db::get<::Tags::Next<::Tags::TimeStepId>>(box),
     166             :             db::get<::domain::Tags::Mesh<Dim>>(box),
     167             :             db::get<::domain::Tags::NeighborMesh<Dim>>(box));
     168             :     typename Tags::MortarDataHistory<
     169             :         Dim, typename db::add_tag_prefix<
     170             :                  ::Tags::dt, typename System::variables_tag>::type>::type
     171             :         boundary_data_history{};
     172             :     for (const auto& mortar_id_and_data : mortar_data) {
     173             :       if (mortar_infos.at(mortar_id_and_data.first).time_stepping_policy() ==
     174             :           TimeSteppingPolicy::Conservative) {
     175             :         // default initialize data
     176             :         boundary_data_history[mortar_id_and_data.first];
     177             :       }
     178             :     }
     179             :     ::Initialization::mutate_assign<simple_tags>(
     180             :         make_not_null(&box), std::move(mortar_data), std::move(mortar_meshes),
     181             :         std::move(mortar_infos), std::move(mortar_next_temporal_ids),
     182             :         std::move(normal_covector_quantities),
     183             :         std::move(boundary_data_history));
     184             :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     185             :   }
     186             : };
     187             : 
     188             : /// \brief Initialize/update items related to mortars after an AMR change
     189             : ///
     190             : /// Mutates:
     191             : ///   - Tags::MortarData<dim>
     192             : ///   - Tags::MortarMesh<dim>
     193             : ///   - Tags::MortarInfo<dim>
     194             : ///   - Tags::MortarNextTemporalId<dim>
     195             : ///   - evolution::dg::Tags::NormalCovectorAndMagnitude<dim>
     196             : ///   - Tags::MortarDataHistory<dim, typename dt_variables_tag::type>>
     197             : ///
     198             : /// For p-refined interfaces:
     199             : ///   - Regenerates MortarData and MortarInfo (should have no effect)
     200             : ///   - Sets the NormalCovectorAndMagnitude to std::nullopt if the face mesh
     201             : ///     changed
     202             : ///   - Projects the local geometric data (but not the data on the mortar-mesh)
     203             : ///     in the MortarDataHistory, if present
     204             : ///   - Does nothing to MortarMesh and MortarNextTemporalId
     205             : ///
     206             : /// For h-refined interfaces:
     207             : ///   - Regenerates MortarData and MortarInfo
     208             : ///   - Sets the NormalCovectorAndMagnitude to std::nullopt
     209             : ///   - Calculates MortarMesh
     210             : ///   - Sets MortarNextTemporalId to the current temporal id
     211             : ///   - For local time-stepping:
     212             : ///     - Removes MortarDataHistory data corresponding to split or joined
     213             : ///       elements
     214             : ///     - Projects MortarDataHistory data corresponding to non-h-refined
     215             : ///       elements onto refined mortars (both geometric and mortar-mesh data)
     216             : ///     - Creates empty histories for new mortars between two h-refined
     217             : ///       elements
     218             : template <typename Metavariables>
     219           1 : struct ProjectMortars : tt::ConformsTo<amr::protocols::Projector> {
     220             :  private:
     221           0 :   using magnitude_and_normal_type = ::Variables<tmpl::list<
     222             :       ::evolution::dg::Tags::MagnitudeOfNormal,
     223             :       ::evolution::dg::Tags::NormalCovector<Metavariables::volume_dim>>>;
     224             : 
     225             :  public:
     226           0 :   static constexpr size_t dim = Metavariables::volume_dim;
     227           0 :   using dt_variables_tag = typename db::add_tag_prefix<
     228             :       ::Tags::dt, typename Metavariables::system::variables_tag>;
     229           0 :   using mortar_data_history_tag =
     230             :       Tags::MortarDataHistory<dim, typename dt_variables_tag::type>;
     231           0 :   using mortar_data_history_type = typename mortar_data_history_tag::type;
     232             : 
     233           0 :   using return_tags =
     234             :       tmpl::list<Tags::MortarData<dim>, Tags::MortarMesh<dim>,
     235             :                  Tags::MortarInfo<dim>, Tags::MortarNextTemporalId<dim>,
     236             :                  evolution::dg::Tags::NormalCovectorAndMagnitude<dim>,
     237             :                  Tags::MortarDataHistory<dim, typename dt_variables_tag::type>>;
     238           0 :   using argument_tags =
     239             :       tmpl::list<domain::Tags::Domain<dim>, domain::Tags::Mesh<dim>,
     240             :                  domain::Tags::Element<dim>, domain::Tags::NeighborMesh<dim>,
     241             :                  ::Tags::TimeStepId>;
     242             : 
     243           0 :   static void apply(
     244             :       const gsl::not_null<
     245             :           ::dg::MortarMap<dim, evolution::dg::MortarDataHolder<dim>>*>
     246             :           mortar_data,
     247             :       const gsl::not_null<::dg::MortarMap<dim, Mesh<dim - 1>>*> mortar_mesh,
     248             :       const gsl::not_null<::dg::MortarMap<dim, MortarInfo<dim>>*> mortar_infos,
     249             :       const gsl::not_null<::dg::MortarMap<dim, TimeStepId>*>
     250             :           mortar_next_temporal_id,
     251             :       const gsl::not_null<
     252             :           DirectionMap<dim, std::optional<magnitude_and_normal_type>>*>
     253             :           normal_covector_and_magnitude,
     254             :       const gsl::not_null<mortar_data_history_type*> mortar_data_history,
     255             :       const Domain<dim>& domain, const Mesh<dim>& new_mesh,
     256             :       const Element<dim>& new_element,
     257             :       const ::dg::MortarMap<dim, Mesh<dim>>& neighbor_mesh,
     258             :       const TimeStepId& current_temporal_id,
     259             :       const std::pair<Mesh<dim>, Element<dim>>& old_mesh_and_element) {
     260             :     const auto& [old_mesh, old_element] = old_mesh_and_element;
     261             :     ASSERT(old_element.id() == new_element.id(),
     262             :            "p-refinement should not have changed the element id");
     263             : 
     264             :     const bool mesh_changed = old_mesh != new_mesh;
     265             : 
     266             :     auto new_mortar_infos =
     267             :         detail::mortar_infos(domain, new_element, new_mesh, neighbor_mesh,
     268             :                              Metavariables::local_time_stepping);
     269             : 
     270             :     // The old mortars must be removed from the MortarMaps before the
     271             :     // new ones can be added to avoid potentially exceeding the
     272             :     // MortarMap capacity, so we collect the new data and add it at
     273             :     // the end.
     274             :     using NewMortarEntry = std::tuple<
     275             :         DirectionalId<dim>, Mesh<dim - 1>,
     276             :         std::optional<typename mortar_data_history_type::mapped_type>>;
     277             :     std::vector<NewMortarEntry> new_mortars{};
     278             : 
     279             :     for (const auto& [direction, neighbors] : new_element.neighbors()) {
     280             :       const auto sliced_away_dimension = direction.dimension();
     281             :       const auto old_face_mesh = old_mesh.slice_away(sliced_away_dimension);
     282             :       const auto new_face_mesh = new_mesh.slice_away(sliced_away_dimension);
     283             :       const bool face_mesh_changed = old_face_mesh != new_face_mesh;
     284             :       if (face_mesh_changed) {
     285             :         (*normal_covector_and_magnitude)[direction] = std::nullopt;
     286             :       }
     287             :       for (const auto& neighbor : neighbors) {
     288             :         const DirectionalId<dim> mortar_id{direction, neighbor};
     289             :         const auto& new_neighbor_mesh = neighbor_mesh.at(mortar_id);
     290             :         const auto new_mortar_mesh = ::dg::mortar_mesh(
     291             :             new_face_mesh, new_neighbor_mesh.slice_away(sliced_away_dimension));
     292             :         if (mortar_mesh->contains(mortar_id)) {
     293             :           // Set the mortar mesh, but do not project any existing mesh
     294             :           // data.  The mesh needs to have a valid value in order to
     295             :           // project data when we send to our neighbors.  If the mesh
     296             :           // resolution needs to be changed afterwards because of a
     297             :           // change in the neighbor, that's fine, because
     298             :           // element-to-mortar projections are lossless.  Projecting
     299             :           // existing data would be bad, because we might erroneously
     300             :           // decrease the mesh resolution, losing the high-order
     301             :           // modes.
     302             :           mortar_mesh->at(mortar_id) = new_mortar_mesh;
     303             :           // mortar_data does not need projecting as it has already been used
     304             :           // and will be resized automatically
     305             :           if (mesh_changed and not mortar_data_history->empty()) {
     306             :             auto& boundary_history = mortar_data_history->at(mortar_id);
     307             :             auto local_history = boundary_history.local();
     308             :             const auto project_local_boundary_data =
     309             :                 [&new_face_mesh, &new_mesh](
     310             :                     const TimeStepId& /* id */,
     311             :                     const gsl::not_null<::evolution::dg::MortarData<dim>*>
     312             :                         data) {
     313             :                   return p_project_geometric_data(data, new_face_mesh,
     314             :                                                   new_mesh);
     315             :                 };
     316             :             local_history.for_each(project_local_boundary_data);
     317             :           }
     318             :         } else {
     319             :           const auto& new_mortar_size =
     320             :               new_mortar_infos.at(mortar_id).mortar_size();
     321             : 
     322             :           std::optional<typename mortar_data_history_type::mapped_type>
     323             :               new_history{};
     324             :           for (const auto& [old_mortar_id, old_history] :
     325             :                *mortar_data_history) {
     326             :             if (old_mortar_id.direction() != direction or
     327             :                 not overlapping(old_mortar_id.id(), neighbor)) {
     328             :               continue;
     329             :             }
     330             :             const auto& old_mortar_size =
     331             :                 mortar_infos->at(old_mortar_id).mortar_size();
     332             :             if (not new_history.has_value()) {
     333             :               new_history.emplace(old_history);
     334             :               new_history->remote().clear();
     335             :               auto local_history = new_history->local();
     336             :               if (mesh_changed) {
     337             :                 const auto project_face_data =
     338             :                     [&new_face_mesh, &new_mesh](
     339             :                         const TimeStepId& /* id */,
     340             :                         const gsl::not_null<::evolution::dg::MortarData<dim>*>
     341             :                             data) {
     342             :                       return p_project_geometric_data(data, new_face_mesh,
     343             :                                                       new_mesh);
     344             :                     };
     345             :                 local_history.for_each(project_face_data);
     346             :               }
     347             :               const auto project_mortar_data =
     348             :                   [&new_mortar_mesh, &new_mortar_size, &old_mortar_size](
     349             :                       const TimeStepId& /* id */,
     350             :                       const gsl::not_null<::evolution::dg::MortarData<dim>*>
     351             :                           data) {
     352             :                     const auto& old_mortar_mesh = data->mortar_mesh.value();
     353             :                     const auto mortar_projection_matrices =
     354             :                         Spectral::projection_matrices(
     355             :                             old_mortar_mesh, new_mortar_mesh, old_mortar_size,
     356             :                             new_mortar_size);
     357             :                     DataVector& vars = data->mortar_data.value();
     358             :                     vars = apply_matrices(mortar_projection_matrices, vars,
     359             :                                           old_mortar_mesh.extents());
     360             :                     data->mortar_mesh = new_mortar_mesh;
     361             :                     return true;
     362             :                   };
     363             :               local_history.for_each(project_mortar_data);
     364             :             } else {
     365             :               auto local_history = new_history->local();
     366             :               const auto old_local_history = old_history.local();
     367             :               const auto project_local_mortar_data =
     368             :                   [&new_mortar_mesh, &new_mortar_size, &old_local_history,
     369             :                    &old_mortar_size](
     370             :                       const TimeStepId& id,
     371             :                       const gsl::not_null<::evolution::dg::MortarData<dim>*>
     372             :                           data) {
     373             :                     const auto& old_data = old_local_history.data(id);
     374             :                     const auto& old_mortar_mesh = old_data.mortar_mesh.value();
     375             :                     const auto mortar_projection_matrices =
     376             :                         Spectral::projection_matrices(
     377             :                             old_mortar_mesh, new_mortar_mesh, old_mortar_size,
     378             :                             new_mortar_size);
     379             :                     data->mortar_data.value() +=
     380             :                         apply_matrices(mortar_projection_matrices,
     381             :                                        old_data.mortar_data.value(),
     382             :                                        old_mortar_mesh.extents());
     383             :                     return true;
     384             :                   };
     385             :               local_history.for_each(project_local_mortar_data);
     386             :             }
     387             :           }
     388             : 
     389             :           new_mortars.emplace_back(mortar_id, new_mortar_mesh, new_history);
     390             :         }
     391             :       }
     392             :     }
     393             : 
     394             :     if (not new_mortars.empty()) {
     395             :       domain::remove_nonexistent_neighbors(mortar_mesh, new_element);
     396             :       domain::remove_nonexistent_neighbors(mortar_next_temporal_id,
     397             :                                            new_element);
     398             :       domain::remove_nonexistent_neighbors(mortar_data_history, new_element);
     399             :       for (auto& [mortar_id, new_mortar_mesh, new_history] : new_mortars) {
     400             :         mortar_mesh->emplace(mortar_id, std::move(new_mortar_mesh));
     401             :         // We only do h refinement at a slab boundary, so we know all
     402             :         // the neighbors are aligned with us temporally.
     403             :         mortar_next_temporal_id->emplace(mortar_id, current_temporal_id);
     404             :         if (new_history.has_value()) {
     405             :           mortar_data_history->emplace(mortar_id, *new_history);
     406             :         }
     407             :       }
     408             :     }
     409             : 
     410             :     *mortar_data = detail::empty_mortar_data(new_element);
     411             :     *mortar_infos = std::move(new_mortar_infos);
     412             : 
     413             :     for (const auto& direction : new_element.external_boundaries()) {
     414             :       const auto sliced_away_dimension = direction.dimension();
     415             :       const auto old_face_mesh = old_mesh.slice_away(sliced_away_dimension);
     416             :       const auto new_face_mesh = new_mesh.slice_away(sliced_away_dimension);
     417             :       const bool face_mesh_changed = old_face_mesh != new_face_mesh;
     418             :       if (face_mesh_changed) {
     419             :         (*normal_covector_and_magnitude)[direction] = std::nullopt;
     420             :       }
     421             :     }
     422             :   }
     423             : 
     424             :   template <typename... ParentTags>
     425           0 :   static void apply(
     426             :       const gsl::not_null<
     427             :           ::dg::MortarMap<dim, evolution::dg::MortarDataHolder<dim>>*>
     428             :           mortar_data,
     429             :       const gsl::not_null<::dg::MortarMap<dim, Mesh<dim - 1>>*> mortar_mesh,
     430             :       const gsl::not_null<::dg::MortarMap<dim, MortarInfo<dim>>*> mortar_infos,
     431             :       const gsl::not_null<::dg::MortarMap<dim, TimeStepId>*>
     432             :           mortar_next_temporal_id,
     433             :       const gsl::not_null<
     434             :           DirectionMap<dim, std::optional<magnitude_and_normal_type>>*>
     435             :           normal_covector_and_magnitude,
     436             :       const gsl::not_null<mortar_data_history_type*> mortar_data_history,
     437             :       const Domain<dim>& domain, const Mesh<dim>& new_mesh,
     438             :       const Element<dim>& new_element,
     439             :       const ::dg::MortarMap<dim, Mesh<dim>>& neighbor_mesh,
     440             :       const TimeStepId& /*possibly_unset*/,
     441             :       const tuples::TaggedTuple<ParentTags...>& parent_items) {
     442             :     detail::h_refine_structure(
     443             :         mortar_data, mortar_mesh, mortar_infos, mortar_next_temporal_id,
     444             :         normal_covector_and_magnitude, domain, new_mesh, new_element,
     445             :         neighbor_mesh, get<::Tags::TimeStepId>(parent_items),
     446             :         Metavariables::local_time_stepping);
     447             : 
     448             :     const auto& old_element = get<domain::Tags::Element<dim>>(parent_items);
     449             :     const auto& old_histories = get<mortar_data_history_tag>(parent_items);
     450             :     for (const auto& [direction, neighbors] : new_element.neighbors()) {
     451             :       for (const auto& neighbor : neighbors) {
     452             :         const DirectionalId<dim> mortar_id{direction, neighbor};
     453             :         if (mortar_infos->at(mortar_id).time_stepping_policy() !=
     454             :             TimeSteppingPolicy::Conservative) {
     455             :           continue;
     456             :         }
     457             :         if (const auto old_history = old_histories.find(mortar_id);
     458             :             old_history != old_histories.end()) {
     459             :           // The neighbor did not h-refine, so we have to project
     460             :           // its mortar data from our parent.
     461             :           auto& new_history =
     462             :               mortar_data_history->emplace(mortar_id, old_history->second)
     463             :                   .first->second;
     464             :           new_history.local().clear();
     465             :           auto remote_history = new_history.remote();
     466             :           const auto& new_mortar_mesh = mortar_mesh->at(mortar_id);
     467             :           const auto& orientation = neighbors.orientation(neighbor);
     468             :           const auto new_mortar_size = domain::child_size(
     469             :               ::dg::mortar_segments(new_element.id(), neighbor,
     470             :                                     direction.dimension(), orientation),
     471             :               ::dg::mortar_segments(old_element.id(), neighbor,
     472             :                                     direction.dimension(), orientation));
     473             :           const auto project_mortar_data =
     474             :               [&new_mortar_mesh, &new_mortar_size](
     475             :                   const TimeStepId& /* id */,
     476             :                   const gsl::not_null<::evolution::dg::MortarData<dim>*> data) {
     477             :                 const auto& old_mortar_mesh = data->mortar_mesh.value();
     478             :                 const auto mortar_projection_matrices =
     479             :                     Spectral::projection_matrices(
     480             :                         old_mortar_mesh, new_mortar_mesh,
     481             :                         make_array<dim - 1>(Spectral::SegmentSize::Full),
     482             :                         new_mortar_size);
     483             :                 DataVector& vars = data->mortar_data.value();
     484             :                 vars = apply_matrices(mortar_projection_matrices, vars,
     485             :                                       old_mortar_mesh.extents());
     486             :                 data->mortar_mesh = new_mortar_mesh;
     487             :                 return true;
     488             :               };
     489             :           remote_history.for_each(project_mortar_data);
     490             :         } else {
     491             :           // Neither this element nor the neighbor existed before
     492             :           // refinement.
     493             :           mortar_data_history->emplace(
     494             :               mortar_id, typename mortar_data_history_type::mapped_type{});
     495             :         }
     496             :       }
     497             :     }
     498             :   }
     499             : 
     500             :   template <typename... ChildTags>
     501           0 :   static void apply(
     502             :       const gsl::not_null<
     503             :           ::dg::MortarMap<dim, evolution::dg::MortarDataHolder<dim>>*>
     504             :           mortar_data,
     505             :       const gsl::not_null<::dg::MortarMap<dim, Mesh<dim - 1>>*> mortar_mesh,
     506             :       const gsl::not_null<::dg::MortarMap<dim, MortarInfo<dim>>*> mortar_infos,
     507             :       const gsl::not_null<::dg::MortarMap<dim, TimeStepId>*>
     508             :           mortar_next_temporal_id,
     509             :       const gsl::not_null<
     510             :           DirectionMap<dim, std::optional<magnitude_and_normal_type>>*>
     511             :           normal_covector_and_magnitude,
     512             :       const gsl::not_null<mortar_data_history_type*> mortar_data_history,
     513             :       const Domain<dim>& domain, const Mesh<dim>& new_mesh,
     514             :       const Element<dim>& new_element,
     515             :       const ::dg::MortarMap<dim, Mesh<dim>>& neighbor_mesh,
     516             :       const TimeStepId& /*possibly_unset*/,
     517             :       const std::unordered_map<
     518             :           ElementId<dim>, tuples::TaggedTuple<ChildTags...>>& children_items) {
     519             :     detail::h_refine_structure(
     520             :         mortar_data, mortar_mesh, mortar_infos, mortar_next_temporal_id,
     521             :         normal_covector_and_magnitude, domain, new_mesh, new_element,
     522             :         neighbor_mesh, get<::Tags::TimeStepId>(children_items.begin()->second),
     523             :         Metavariables::local_time_stepping);
     524             : 
     525             :     for (const auto& [direction, neighbors] : new_element.neighbors()) {
     526             :       for (const auto& neighbor : neighbors) {
     527             :         const DirectionalId<dim> mortar_id{direction, neighbor};
     528             :         if (mortar_infos->at(mortar_id).time_stepping_policy() !=
     529             :             TimeSteppingPolicy::Conservative) {
     530             :           continue;
     531             :         }
     532             :         std::optional<typename mortar_data_history_type::mapped_type>
     533             :             new_history{};
     534             :         for (const auto& [child, child_items] : children_items) {
     535             :           const auto& old_histories =
     536             :               get<mortar_data_history_tag>(child_items);
     537             :           if (const auto old_history = old_histories.find(mortar_id);
     538             :               old_history != old_histories.end()) {
     539             :             // The neighbor did not h-refine, so we have to project
     540             :             // its mortar data from our children.
     541             :             const auto& new_mortar_mesh = mortar_mesh->at(mortar_id);
     542             :             const auto& orientation = neighbors.orientation(neighbor);
     543             :             const auto old_mortar_size = domain::child_size(
     544             :                 ::dg::mortar_segments(child, neighbor, direction.dimension(),
     545             :                                       orientation),
     546             :                 ::dg::mortar_segments(new_element.id(), neighbor,
     547             :                                       direction.dimension(), orientation));
     548             :             if (not new_history.has_value()) {
     549             :               new_history.emplace(old_history->second);
     550             :               new_history->local().clear();
     551             :               auto remote_history = new_history->remote();
     552             :               const auto project_mortar_data =
     553             :                   [&new_mortar_mesh, &old_mortar_size](
     554             :                       const TimeStepId& /* id */,
     555             :                       const gsl::not_null<::evolution::dg::MortarData<dim>*>
     556             :                           data) {
     557             :                     const auto& old_mortar_mesh = data->mortar_mesh.value();
     558             :                     const auto mortar_projection_matrices =
     559             :                         Spectral::projection_matrices(
     560             :                             old_mortar_mesh, new_mortar_mesh, old_mortar_size,
     561             :                             make_array<dim - 1>(Spectral::SegmentSize::Full));
     562             :                     DataVector& vars = data->mortar_data.value();
     563             :                     vars = apply_matrices(mortar_projection_matrices, vars,
     564             :                                           old_mortar_mesh.extents());
     565             :                     data->mortar_mesh = new_mortar_mesh;
     566             :                     return true;
     567             :                   };
     568             :               remote_history.for_each(project_mortar_data);
     569             :             } else {
     570             :               auto remote_history = new_history->remote();
     571             :               const auto old_remote_history = old_history->second.remote();
     572             :               const auto project_mortar_data =
     573             :                   [&new_mortar_mesh, &old_mortar_size, &old_remote_history](
     574             :                       const TimeStepId& id,
     575             :                       const gsl::not_null<::evolution::dg::MortarData<dim>*>
     576             :                           data) {
     577             :                     const auto& old_data = old_remote_history.data(id);
     578             :                     const auto& old_mortar_mesh =
     579             :                         old_data.mortar_mesh.value();
     580             :                     const auto mortar_projection_matrices =
     581             :                         Spectral::projection_matrices(
     582             :                             old_mortar_mesh, new_mortar_mesh, old_mortar_size,
     583             :                             make_array<dim - 1>(Spectral::SegmentSize::Full));
     584             :                     data->mortar_data.value() +=
     585             :                         apply_matrices(mortar_projection_matrices,
     586             :                                        old_data.mortar_data.value(),
     587             :                                        old_mortar_mesh.extents());
     588             :                     return true;
     589             :                   };
     590             :               remote_history.for_each(project_mortar_data);
     591             :             }
     592             :           }
     593             :         }
     594             : 
     595             :         if (new_history.has_value()) {
     596             :           mortar_data_history->emplace(mortar_id, std::move(*new_history));
     597             :         } else {
     598             :           // Neither this element nor the neighbor existed before
     599             :           // refinement.
     600             :           mortar_data_history->emplace(
     601             :               mortar_id, typename mortar_data_history_type::mapped_type{});
     602             :         }
     603             :       }
     604             :     }
     605             :   }
     606             : };
     607             : }  // namespace evolution::dg::Initialization

Generated by: LCOV version 1.14