SpECTRE Documentation Coverage Report
Current view: top level - Elliptic/DiscontinuousGalerkin/Actions - ApplyOperator.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 41.7 % 12 5
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 <cstddef>
       7              : #include <optional>
       8              : #include <string>
       9              : #include <tuple>
      10              : #include <type_traits>
      11              : #include <utility>
      12              : 
      13              : #include "DataStructures/DataBox/DataBox.hpp"
      14              : #include "DataStructures/DataBox/DataBoxTag.hpp"
      15              : #include "DataStructures/TaggedTuple.hpp"
      16              : #include "DataStructures/Tensor/EagerMath/Magnitude.hpp"
      17              : #include "Domain/Creators/Tags/ExternalBoundaryConditions.hpp"
      18              : #include "Domain/Creators/Tags/InitialExtents.hpp"
      19              : #include "Domain/FaceNormal.hpp"
      20              : #include "Domain/Structure/Direction.hpp"
      21              : #include "Domain/Structure/DirectionMap.hpp"
      22              : #include "Domain/Structure/DirectionalIdMap.hpp"
      23              : #include "Domain/Structure/Element.hpp"
      24              : #include "Domain/Tags.hpp"
      25              : #include "Domain/Tags/FaceNormal.hpp"
      26              : #include "Domain/Tags/Faces.hpp"
      27              : #include "Domain/Tags/SurfaceJacobian.hpp"
      28              : #include "Elliptic/BoundaryConditions/ApplyBoundaryCondition.hpp"
      29              : #include "Elliptic/DiscontinuousGalerkin/DgOperator.hpp"
      30              : #include "Elliptic/DiscontinuousGalerkin/Initialization.hpp"
      31              : #include "Elliptic/DiscontinuousGalerkin/Tags.hpp"
      32              : #include "Elliptic/Systems/GetFluxesComputer.hpp"
      33              : #include "Elliptic/Systems/GetModifyBoundaryData.hpp"
      34              : #include "Elliptic/Systems/GetSourcesComputer.hpp"
      35              : #include "Elliptic/Utilities/ApplyAt.hpp"
      36              : #include "NumericalAlgorithms/Convergence/Tags.hpp"
      37              : #include "NumericalAlgorithms/DiscontinuousGalerkin/HasReceivedFromAllMortars.hpp"
      38              : #include "NumericalAlgorithms/DiscontinuousGalerkin/MortarHelpers.hpp"
      39              : #include "NumericalAlgorithms/DiscontinuousGalerkin/Tags.hpp"
      40              : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      41              : #include "Parallel/AlgorithmExecution.hpp"
      42              : #include "Parallel/GlobalCache.hpp"
      43              : #include "Parallel/InboxInserters.hpp"
      44              : #include "Parallel/Invoke.hpp"
      45              : #include "ParallelAlgorithms/Amr/Projectors/CopyFromCreatorOrLeaveAsIs.hpp"
      46              : #include "ParallelAlgorithms/Amr/Projectors/DefaultInitialize.hpp"
      47              : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
      48              : #include "Utilities/ErrorHandling/Assert.hpp"
      49              : #include "Utilities/GetOutput.hpp"
      50              : #include "Utilities/Gsl.hpp"
      51              : #include "Utilities/Literals.hpp"
      52              : #include "Utilities/TMPL.hpp"
      53              : 
      54              : /// Actions related to elliptic discontinuous Galerkin schemes
      55            1 : namespace elliptic::dg::Actions {
      56              : // The individual actions in this namespace are not exposed publicly because
      57              : // they don't work on their own. Instead, the public interface (defined below)
      58              : // exposes them in action lists.
      59              : namespace detail {
      60              : 
      61              : // This is a global ID that identifies the DG operator application. It
      62              : // increments with each application of the operator.
      63              : struct DgOperatorLabel {};
      64              : using TemporalIdTag = Convergence::Tags::IterationId<DgOperatorLabel>;
      65              : 
      66              : // This tag is used to communicate mortar data across neighbors
      67              : template <size_t Dim, typename TemporalIdTag, typename PrimalFields,
      68              :           typename PrimalFluxes>
      69              : struct MortarDataInboxTag
      70              :     : public Parallel::InboxInserters::Map<
      71              :           MortarDataInboxTag<Dim, TemporalIdTag, PrimalFields, PrimalFluxes>> {
      72              :   using temporal_id = typename TemporalIdTag::type;
      73              :   using type =
      74              :       std::map<temporal_id,
      75              :                DirectionalIdMap<Dim, elliptic::dg::BoundaryData<PrimalFields,
      76              :                                                                 PrimalFluxes>>>;
      77              : };
      78              : 
      79              : // Initializes all quantities the DG operator needs on internal and external
      80              : // faces, as well as the mortars between neighboring elements. Also initializes
      81              : // the variable-independent background fields in the PDEs.
      82              : template <typename System, typename BackgroundTag>
      83              : struct InitializeFacesMortarsAndBackground {
      84              :  private:
      85              :   static constexpr size_t Dim = System::volume_dim;
      86              :   static constexpr bool has_background_fields =
      87              :       not std::is_same_v<typename System::background_fields, tmpl::list<>>;
      88              :   static_assert(
      89              :       not(has_background_fields and std::is_same_v<BackgroundTag, void>),
      90              :       "The system has background fields that need initialization. Supply a "
      91              :       "'BackgroundTag' to 'elliptic::dg::Actions::initialize_operator'.");
      92              : 
      93              :   using InitializeFacesAndMortars = elliptic::dg::InitializeFacesAndMortars<
      94              :       Dim, typename System::inv_metric_tag, BackgroundTag>;
      95              :   using InitializeBackground = elliptic::dg::InitializeBackground<
      96              :       Dim, typename System::background_fields, BackgroundTag>;
      97              : 
      98              :  public:
      99              :   using simple_tags = tmpl::append<
     100              :       typename InitializeFacesAndMortars::return_tags,
     101              :       tmpl::conditional_t<has_background_fields,
     102              :                           typename InitializeBackground::return_tags,
     103              :                           tmpl::list<>>>;
     104              :   using compute_tags = tmpl::list<>;
     105              :   using const_global_cache_tags =
     106              :       tmpl::conditional_t<has_background_fields, tmpl::list<BackgroundTag>,
     107              :                           tmpl::list<>>;
     108              : 
     109              :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     110              :             typename ArrayIndex, typename ActionList,
     111              :             typename ParallelComponent>
     112              :   static Parallel::iterable_action_return_t apply(
     113              :       db::DataBox<DbTagsList>& box,
     114              :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     115              :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     116              :       const ArrayIndex& /*array_index*/, ActionList /*meta*/,
     117              :       const ParallelComponent* const /*meta*/) {
     118              :     // Initialize faces and mortars
     119              :     db::mutate_apply<InitializeFacesAndMortars>(make_not_null(&box));
     120              :     if constexpr (has_background_fields) {
     121              :       // Initialize background fields
     122              :       db::mutate_apply<InitializeBackground>(make_not_null(&box));
     123              :     }
     124              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     125              :   }
     126              : };
     127              : 
     128              : // Compute auxiliary variables and fluxes from the primal variables, prepare the
     129              : // local side of all mortars and send the local mortar data to neighbors. Also
     130              : // handle boundary conditions by preparing the exterior ("ghost") side of
     131              : // external mortars.
     132              : template <typename System, bool Linearized, typename TemporalIdTag,
     133              :           typename PrimalFieldsTag, typename PrimalFluxesTag,
     134              :           typename OperatorAppliedToFieldsTag, typename PrimalMortarFieldsTag,
     135              :           typename PrimalMortarFluxesTag,
     136              :           typename FluxesArgsTags =
     137              :               elliptic::get_fluxes_argument_tags<System, Linearized>,
     138              :           typename SourcesArgsTags =
     139              :               elliptic::get_sources_argument_tags<System, Linearized>>
     140              : struct PrepareAndSendMortarData;
     141              : 
     142              : template <typename System, bool Linearized, typename TemporalIdTag,
     143              :           typename PrimalFieldsTag, typename PrimalFluxesTag,
     144              :           typename OperatorAppliedToFieldsTag, typename PrimalMortarFieldsTag,
     145              :           typename PrimalMortarFluxesTag, typename... FluxesArgsTags,
     146              :           typename... SourcesArgsTags>
     147              : struct PrepareAndSendMortarData<
     148              :     System, Linearized, TemporalIdTag, PrimalFieldsTag, PrimalFluxesTag,
     149              :     OperatorAppliedToFieldsTag, PrimalMortarFieldsTag, PrimalMortarFluxesTag,
     150              :     tmpl::list<FluxesArgsTags...>, tmpl::list<SourcesArgsTags...>> {
     151              :  private:
     152              :   static constexpr size_t Dim = System::volume_dim;
     153              :   using all_mortar_data_tag = ::Tags::Mortars<
     154              :       elliptic::dg::Tags::MortarData<typename TemporalIdTag::type,
     155              :                                      typename PrimalMortarFieldsTag::tags_list,
     156              :                                      typename PrimalMortarFluxesTag::tags_list>,
     157              :       Dim>;
     158              :   using mortar_data_inbox_tag =
     159              :       MortarDataInboxTag<Dim, TemporalIdTag,
     160              :                          typename PrimalMortarFieldsTag::tags_list,
     161              :                          typename PrimalMortarFluxesTag::tags_list>;
     162              :   using BoundaryConditionsBase = typename System::boundary_conditions_base;
     163              :   using DerivFieldsTag = db::add_tag_prefix<::Tags::deriv, PrimalFieldsTag,
     164              :                                             tmpl::size_t<Dim>, Frame::Inertial>;
     165              : 
     166              :  public:
     167              :   // Request these tags be added to the DataBox. We
     168              :   // don't actually need to initialize them, because the
     169              :   // `PrimalFieldsTag` will be set by other actions before applying the operator
     170              :   // and the remaining tags hold output of the operator.
     171              :   using simple_tags = tmpl::list<TemporalIdTag, PrimalFieldsTag, DerivFieldsTag,
     172              :                                  PrimalFluxesTag, OperatorAppliedToFieldsTag,
     173              :                                  all_mortar_data_tag>;
     174              :   using compute_tags = tmpl::list<>;
     175              :   using const_global_cache_tags =
     176              :       tmpl::list<domain::Tags::ExternalBoundaryConditions<Dim>>;
     177              : 
     178              :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     179              :             typename ActionList, typename ParallelComponent>
     180              :   static Parallel::iterable_action_return_t apply(
     181              :       db::DataBox<DbTagsList>& box,
     182              :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     183              :       Parallel::GlobalCache<Metavariables>& cache,
     184              :       const ElementId<Dim>& element_id, const ActionList /*meta*/,
     185              :       const ParallelComponent* const /*meta*/) {
     186              :     const auto& temporal_id = db::get<TemporalIdTag>(box);
     187              :     const auto& element = db::get<domain::Tags::Element<Dim>>(box);
     188              : 
     189              :     const auto& mortar_meshes =
     190              :         db::get<::Tags::Mortars<domain::Tags::Mesh<Dim - 1>, Dim>>(box);
     191              :     const auto& boundary_conditions =
     192              :         db::get<domain::Tags::ExternalBoundaryConditions<Dim>>(box).at(
     193              :             element_id.block_id());
     194              :     const auto apply_boundary_condition = [&box, &boundary_conditions,
     195              :                                            &element_id](
     196              :                                               const Direction<Dim>& direction,
     197              :                                               auto&&... fields_and_fluxes) {
     198              :       ASSERT(boundary_conditions.contains(direction),
     199              :              "No boundary condition is available in block "
     200              :                  << element_id.block_id() << " in direction " << direction
     201              :                  << ". Make sure you are setting up boundary conditions when "
     202              :                     "creating the domain.");
     203              :       ASSERT(dynamic_cast<const BoundaryConditionsBase*>(
     204              :                  boundary_conditions.at(direction).get()) != nullptr,
     205              :              "The boundary condition in block "
     206              :                  << element_id.block_id() << " in direction " << direction
     207              :                  << " has an unexpected type. Make sure it derives off the "
     208              :                     "'boundary_conditions_base' class set in the system.");
     209              :       const auto& boundary_condition =
     210              :           dynamic_cast<const BoundaryConditionsBase&>(
     211              :               *boundary_conditions.at(direction));
     212              :       elliptic::apply_boundary_condition<Linearized>(
     213              :           boundary_condition, box, direction,
     214              :           std::forward<decltype(fields_and_fluxes)>(fields_and_fluxes)...);
     215              :     };
     216              : 
     217              :     // Can't `db::get` the arguments for the boundary conditions within
     218              :     // `db::mutate`, so we extract the data to mutate and move it back in when
     219              :     // we're done.
     220              :     // Possible optimization: also keep memory for the mortar data around in the
     221              :     // DataBox. Currently the mortar data is extracted and erased by
     222              :     // `apply_operator` anyway, so we can just create a new map here to avoid
     223              :     // dealing with AMR resizing the mortars. When we keep the memory around,
     224              :     // its size has to be adjusted when the mesh changes during AMR.
     225              :     typename PrimalFluxesTag::type primal_fluxes;
     226              :     typename DerivFieldsTag::type deriv_fields;
     227              :     typename all_mortar_data_tag::type all_mortar_data{};
     228              :     db::mutate<PrimalFluxesTag, DerivFieldsTag>(
     229              :         [&primal_fluxes, &deriv_fields](const auto local_primal_fluxes,
     230              :                                         const auto local_deriv_fields) {
     231              :           primal_fluxes = std::move(*local_primal_fluxes);
     232              :           deriv_fields = std::move(*local_deriv_fields);
     233              :         },
     234              :         make_not_null(&box));
     235              : 
     236              :     elliptic::dg::prepare_mortar_data<System, Linearized>(
     237              :         make_not_null(&deriv_fields), make_not_null(&primal_fluxes),
     238              :         make_not_null(&all_mortar_data), db::get<PrimalFieldsTag>(box), element,
     239              :         db::get<domain::Tags::Mesh<Dim>>(box),
     240              :         db::get<domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
     241              :                                               Frame::Inertial>>(box),
     242              :         db::get<domain::Tags::Faces<Dim, domain::Tags::FaceNormal<Dim>>>(box),
     243              :         mortar_meshes,
     244              :         db::get<::Tags::Mortars<::Tags::MortarSize<Dim - 1>, Dim>>(box),
     245              :         temporal_id, apply_boundary_condition,
     246              :         std::forward_as_tuple(db::get<FluxesArgsTags>(box)...));
     247              : 
     248              :     // Move the mutated data back into the DataBox
     249              :     db::mutate<PrimalFluxesTag, DerivFieldsTag, all_mortar_data_tag>(
     250              :         [&primal_fluxes, &deriv_fields, &all_mortar_data](
     251              :             const auto local_primal_fluxes, const auto local_deriv_fields,
     252              :             const auto local_all_mortar_data) {
     253              :           *local_primal_fluxes = std::move(primal_fluxes);
     254              :           *local_deriv_fields = std::move(deriv_fields);
     255              :           *local_all_mortar_data = std::move(all_mortar_data);
     256              :         },
     257              :         make_not_null(&box));
     258              : 
     259              :     // Send mortar data to neighbors
     260              :     auto& receiver_proxy =
     261              :         Parallel::get_parallel_component<ParallelComponent>(cache);
     262              :     for (const auto& [direction, neighbors] : element.neighbors()) {
     263              :       const size_t dimension = direction.dimension();
     264              :       for (const auto& neighbor_id : neighbors) {
     265              :         const auto& orientation = neighbors.orientation(neighbor_id);
     266              :         const auto direction_from_neighbor = orientation(direction.opposite());
     267              :         const ::dg::MortarId<Dim> mortar_id{direction, neighbor_id};
     268              :         // Make a copy of the local boundary data on the mortar to send to the
     269              :         // neighbor
     270              :         auto remote_boundary_data_on_mortar =
     271              :             get<all_mortar_data_tag>(box).at(mortar_id).local_data(temporal_id);
     272              :         // Reorient the data to the neighbor orientation if necessary
     273              :         if (not orientation.is_aligned()) {
     274              :           remote_boundary_data_on_mortar.orient_on_slice(
     275              :               mortar_meshes.at(mortar_id).extents(), dimension, orientation);
     276              :         }
     277              :         // Send remote data to neighbor
     278              :         Parallel::receive_data<mortar_data_inbox_tag>(
     279              :             receiver_proxy[neighbor_id], temporal_id,
     280              :             std::make_pair(
     281              :                 ::dg::MortarId<Dim>{direction_from_neighbor, element.id()},
     282              :                 std::move(remote_boundary_data_on_mortar)));
     283              :       }  // loop over neighbors in direction
     284              :     }  // loop over directions
     285              : 
     286              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     287              :   }
     288              : };
     289              : 
     290              : // Wait until all mortar data from neighbors is available. Then add boundary
     291              : // corrections to the primal fluxes, compute their derivatives (i.e. the second
     292              : // derivatives of the primal variables) and add boundary corrections to the
     293              : // result.
     294              : template <typename System, bool Linearized, typename TemporalIdTag,
     295              :           typename PrimalFieldsTag, typename PrimalFluxesTag,
     296              :           typename OperatorAppliedToFieldsTag, typename PrimalMortarFieldsTag,
     297              :           typename PrimalMortarFluxesTag,
     298              :           typename FluxesArgsTags =
     299              :               elliptic::get_fluxes_argument_tags<System, Linearized>,
     300              :           typename SourcesArgsTags =
     301              :               elliptic::get_sources_argument_tags<System, Linearized>,
     302              :           typename ModifyBoundaryDataArgsTags =
     303              :               elliptic::get_modify_boundary_data_args_tags<System, Linearized>>
     304              : struct ReceiveMortarDataAndApplyOperator;
     305              : 
     306              : template <typename System, bool Linearized, typename TemporalIdTag,
     307              :           typename PrimalFieldsTag, typename PrimalFluxesTag,
     308              :           typename OperatorAppliedToFieldsTag, typename PrimalMortarFieldsTag,
     309              :           typename PrimalMortarFluxesTag, typename... FluxesArgsTags,
     310              :           typename... SourcesArgsTags, typename... ModifyBoundaryDataArgsTags>
     311              : struct ReceiveMortarDataAndApplyOperator<
     312              :     System, Linearized, TemporalIdTag, PrimalFieldsTag, PrimalFluxesTag,
     313              :     OperatorAppliedToFieldsTag, PrimalMortarFieldsTag, PrimalMortarFluxesTag,
     314              :     tmpl::list<FluxesArgsTags...>, tmpl::list<SourcesArgsTags...>,
     315              :     tmpl::list<ModifyBoundaryDataArgsTags...>> {
     316              :  private:
     317              :   static constexpr size_t Dim = System::volume_dim;
     318              :   using all_mortar_data_tag = ::Tags::Mortars<
     319              :       elliptic::dg::Tags::MortarData<typename TemporalIdTag::type,
     320              :                                      typename PrimalMortarFieldsTag::tags_list,
     321              :                                      typename PrimalMortarFluxesTag::tags_list>,
     322              :       Dim>;
     323              :   using mortar_data_inbox_tag =
     324              :       MortarDataInboxTag<Dim, TemporalIdTag,
     325              :                          typename PrimalMortarFieldsTag::tags_list,
     326              :                          typename PrimalMortarFluxesTag::tags_list>;
     327              :   using DerivFieldsTag = db::add_tag_prefix<::Tags::deriv, PrimalFieldsTag,
     328              :                                             tmpl::size_t<Dim>, Frame::Inertial>;
     329              :  public:
     330              :   using const_global_cache_tags =
     331              :       tmpl::list<elliptic::dg::Tags::PenaltyParameter,
     332              :                  elliptic::dg::Tags::Massive, elliptic::dg::Tags::Formulation>;
     333              :   using inbox_tags = tmpl::list<mortar_data_inbox_tag>;
     334              : 
     335              :   template <typename DbTags, typename... InboxTags, typename Metavariables,
     336              :             typename ArrayIndex, typename ActionList,
     337              :             typename ParallelComponent>
     338              :   static Parallel::iterable_action_return_t apply(
     339              :       db::DataBox<DbTags>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
     340              :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     341              :       const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
     342              :       const ParallelComponent* const /*meta*/) {
     343              :     const auto& temporal_id = get<TemporalIdTag>(box);
     344              :     const auto& element = get<domain::Tags::Element<Dim>>(box);
     345              : 
     346              :     if (not::dg::has_received_from_all_mortars<mortar_data_inbox_tag>(
     347              :             temporal_id, element, inboxes)) {
     348              :       return {Parallel::AlgorithmExecution::Retry, std::nullopt};
     349              :     }
     350              : 
     351              :     // Move received "remote" mortar data into the DataBox
     352              :     if (LIKELY(element.number_of_neighbors() > 0)) {
     353              :       auto received_mortar_data =
     354              :           std::move(tuples::get<mortar_data_inbox_tag>(inboxes)
     355              :                         .extract(temporal_id)
     356              :                         .mapped());
     357              :       db::mutate<all_mortar_data_tag>(
     358              :           [&received_mortar_data, &temporal_id](const auto all_mortar_data) {
     359              :             for (auto& [mortar_id, mortar_data] : received_mortar_data) {
     360              :               all_mortar_data->at(mortar_id).remote_insert(
     361              :                   temporal_id, std::move(mortar_data));
     362              :             }
     363              :           },
     364              :           make_not_null(&box));
     365              :     }
     366              : 
     367              :     // Used to retrieve items out of the DataBox to forward to functions
     368              :     const auto get_items = [](const auto&... args) {
     369              :       return std::forward_as_tuple(args...);
     370              :     };
     371              : 
     372              :     // Apply DG operator
     373              :     using fluxes_args_tags =
     374              :         typename elliptic::get_fluxes_argument_tags<System, Linearized>;
     375              :     using fluxes_args_volume_tags =
     376              :         typename elliptic::get_fluxes_volume_tags<System, Linearized>;
     377              :     DirectionMap<Dim, std::tuple<decltype(db::get<FluxesArgsTags>(box))...>>
     378              :         fluxes_args_on_faces{};
     379              :     for (const auto& direction : Direction<Dim>::all_directions()) {
     380              :       fluxes_args_on_faces.emplace(
     381              :           direction, elliptic::util::apply_at<
     382              :                          domain::make_faces_tags<Dim, fluxes_args_tags,
     383              :                                                  fluxes_args_volume_tags>,
     384              :                          fluxes_args_volume_tags>(get_items, box, direction));
     385              :     }
     386              :     db::mutate<OperatorAppliedToFieldsTag, all_mortar_data_tag>(
     387              :         [](const auto&... args) {
     388              :           elliptic::dg::apply_operator<System, Linearized>(args...);
     389              :         },
     390              :         make_not_null(&box), db::get<PrimalFieldsTag>(box),
     391              :         db::get<DerivFieldsTag>(box), db::get<PrimalFluxesTag>(box), element,
     392              :         db::get<domain::Tags::Mesh<Dim>>(box),
     393              :         db::get<domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
     394              :                                               Frame::Inertial>>(box),
     395              :         db::get<domain::Tags::DetInvJacobian<Frame::ElementLogical,
     396              :                                              Frame::Inertial>>(box),
     397              :         db::get<
     398              :             domain::Tags::DetJacobian<Frame::ElementLogical, Frame::Inertial>>(
     399              :             box),
     400              :         db::get<domain::Tags::DetTimesInvJacobian<Dim, Frame::ElementLogical,
     401              :                                                   Frame::Inertial>>(box),
     402              :         db::get<domain::Tags::Faces<Dim, domain::Tags::FaceNormal<Dim>>>(box),
     403              :         db::get<domain::Tags::Faces<Dim, domain::Tags::FaceNormalVector<Dim>>>(
     404              :             box),
     405              :         db::get<domain::Tags::Faces<
     406              :             Dim, domain::Tags::UnnormalizedFaceNormalMagnitude<Dim>>>(box),
     407              :         db::get<domain::Tags::Faces<
     408              :             Dim, domain::Tags::DetSurfaceJacobian<Frame::ElementLogical,
     409              :                                                   Frame::Inertial>>>(box),
     410              :         db::get<domain::Tags::Faces<
     411              :             Dim, domain::Tags::DetTimesInvJacobian<Dim, Frame::ElementLogical,
     412              :                                                    Frame::Inertial>>>(box),
     413              :         db::get<::Tags::Mortars<domain::Tags::Mesh<Dim - 1>, Dim>>(box),
     414              :         db::get<::Tags::Mortars<::Tags::MortarSize<Dim - 1>, Dim>>(box),
     415              :         db::get<::Tags::Mortars<domain::Tags::DetSurfaceJacobian<
     416              :                                     Frame::ElementLogical, Frame::Inertial>,
     417              :                                 Dim>>(box),
     418              :         db::get<::Tags::Mortars<elliptic::dg::Tags::PenaltyFactor, Dim>>(box),
     419              :         db::get<elliptic::dg::Tags::Massive>(box),
     420              :         db::get<elliptic::dg::Tags::Formulation>(box), temporal_id,
     421              :         fluxes_args_on_faces,
     422              :         std::forward_as_tuple(db::get<SourcesArgsTags>(box)...),
     423              :         std::forward_as_tuple(db::get<ModifyBoundaryDataArgsTags>(box)...));
     424              : 
     425              :     // Increment temporal ID
     426              :     db::mutate<TemporalIdTag>(
     427              :         [](const gsl::not_null<size_t*> stored_temporal_id) {
     428              :           ++(*stored_temporal_id);
     429              :         },
     430              :         make_not_null(&box));
     431              : 
     432              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     433              :   }
     434              : };
     435              : 
     436              : }  // namespace detail
     437              : 
     438              : /*!
     439              :  * \brief Initialize geometric and background quantities for the elliptic DG
     440              :  * operator
     441              :  *
     442              :  * The geometric and background quantities are initialized together because the
     443              :  * geometry depends on the background metric through the normalization of face
     444              :  * normals. Other examples for background fields are curvature quantities
     445              :  * associated with the background metric, or matter sources such as a
     446              :  * mass-density in the XCTS equations. All `System::background_fields` are
     447              :  * retrieved from the `BackgroundTag` together, to enable re-using cached
     448              :  * temporary quantities in the computations. The `variables` function is invoked
     449              :  * on the `BackgroundTag` with the inertial coordinates, the element's `Mesh`
     450              :  * and the element's inverse Jacobian. These arguments allow computing numeric
     451              :  * derivatives, if necessary. The `BackgroundTag` can be set to `void` (default)
     452              :  * if the `System` has no background fields.
     453              :  *
     454              :  * DataBox:
     455              :  * - Uses:
     456              :  *   - `domain::Tags::InitialExtents<Dim>`
     457              :  *   - `BackgroundTag`
     458              :  * - Adds:
     459              :  *   - `::Tags::Mortars<domain::Tags::Mesh<Dim - 1>, Dim>`
     460              :  *   - `::Tags::Mortars<::Tags::MortarSize<Dim - 1>, Dim>`
     461              :  *   - `::Tags::Variables<background_fields>`
     462              :  * - Adds on internal and external faces:
     463              :  *   - `domain::Tags::Coordinates<Dim, Frame::Inertial>`
     464              :  *   - `::Tags::Normalized<domain::Tags::UnnormalizedFaceNormal<Dim>>`
     465              :  *   - `::Tags::Magnitude<domain::Tags::UnnormalizedFaceNormal<Dim>>`
     466              :  *   - `::Tags::Variables<background_fields>`
     467              :  *
     468              :  * \see elliptic::dg::Actions::apply_operator
     469              :  */
     470              : template <typename System, typename BackgroundTag = void>
     471            1 : using initialize_operator = tmpl::list<
     472              :     detail::InitializeFacesMortarsAndBackground<System, BackgroundTag>>;
     473              : 
     474              : /*!
     475              :  * \brief AMR projectors for the tags added by `initialize_operator`
     476              :  */
     477              : template <typename System, typename BackgroundTag = void>
     478            1 : using amr_projectors = tmpl::append<
     479              :     tmpl::list<elliptic::dg::InitializeFacesAndMortars<
     480              :         System::volume_dim, typename System::inv_metric_tag, BackgroundTag>>,
     481              :     tmpl::conditional_t<
     482              :         std::is_same_v<typename System::background_fields, tmpl::list<>>,
     483              :         tmpl::list<>,
     484              :         tmpl::list<elliptic::dg::InitializeBackground<
     485              :             System::volume_dim, typename System::background_fields,
     486              :             BackgroundTag>>>>;
     487              : 
     488              : /*!
     489              :  * \brief Apply the DG operator to the `PrimalFieldsTag` and write the result to
     490              :  * the `OperatorAppliedToFieldsTag`
     491              :  *
     492              :  * Add the `apply_actions` list to the action list of a parallel component to
     493              :  * compute the elliptic DG operator or its linearization. The operator involves
     494              :  * a communication between nearest-neighbor elements. See `elliptic::dg` for
     495              :  * details on the elliptic DG operator. Make sure to add
     496              :  * `elliptic::dg::Actions::initialize_operator` to the initialization phase of
     497              :  * your parallel component so the required DataBox tags are set up before
     498              :  * applying the operator.
     499              :  *
     500              :  * The result of the computation is written to the `OperatorAppliedToFieldsTag`.
     501              :  * Additionally, the primal fluxes are written to the `PrimalFluxesTag` as an
     502              :  * intermediate result. The auxiliary fields and fluxes are discarded to avoid
     503              :  * inflating the memory usage.
     504              :  *
     505              :  * You can specify the `PrimalMortarFieldsTag` and the `PrimalMortarFluxesTag`
     506              :  * to re-use mortar-data memory buffers from other operator applications, for
     507              :  * example when applying the nonlinear and linearized operator. They default to
     508              :  * the `PrimalFieldsTag` and the `PrimalFluxesTag`, meaning memory buffers
     509              :  * corresponding to these tags are set up in the DataBox.
     510              :  *
     511              :  * \par AMR
     512              :  * Also add the `amr_projectors` to the list of AMR projectors to support AMR.
     513              :  */
     514              : template <typename System, bool Linearized, typename PrimalFieldsTag,
     515              :           typename PrimalFluxesTag, typename OperatorAppliedToFieldsTag,
     516              :           typename PrimalMortarFieldsTag = PrimalFieldsTag,
     517              :           typename PrimalMortarFluxesTag = PrimalFluxesTag>
     518            1 : struct DgOperator {
     519            0 :   using system = System;
     520            0 :   using temporal_id_tag = detail::TemporalIdTag;
     521              : 
     522              :  private:
     523            0 :   static constexpr size_t Dim = System::volume_dim;
     524            0 :   using DerivVarsTag = db::add_tag_prefix<::Tags::deriv, PrimalFieldsTag,
     525              :                                           tmpl::size_t<Dim>, Frame::Inertial>;
     526              :  public:
     527            0 :   using apply_actions =
     528              :       tmpl::list<detail::PrepareAndSendMortarData<
     529              :                      System, Linearized, temporal_id_tag, PrimalFieldsTag,
     530              :                      PrimalFluxesTag, OperatorAppliedToFieldsTag,
     531              :                      PrimalMortarFieldsTag, PrimalMortarFluxesTag>,
     532              :                  detail::ReceiveMortarDataAndApplyOperator<
     533              :                      System, Linearized, temporal_id_tag, PrimalFieldsTag,
     534              :                      PrimalFluxesTag, OperatorAppliedToFieldsTag,
     535              :                      PrimalMortarFieldsTag, PrimalMortarFluxesTag>>;
     536            0 :   using amr_projectors = tmpl::list<
     537              :       ::amr::projectors::DefaultInitialize<
     538              :           DerivVarsTag, PrimalFluxesTag, OperatorAppliedToFieldsTag,
     539              :           ::Tags::Mortars<elliptic::dg::Tags::MortarData<
     540              :                               typename temporal_id_tag::type,
     541              :                               typename PrimalMortarFieldsTag::tags_list,
     542              :                               typename PrimalMortarFluxesTag::tags_list>,
     543              :                           Dim>>,
     544              :       ::amr::projectors::CopyFromCreatorOrLeaveAsIs<temporal_id_tag>>;
     545              : };
     546              : 
     547              : /*!
     548              :  * \brief For linear systems, impose inhomogeneous boundary conditions as
     549              :  * contributions to the fixed sources (i.e. the RHS of the equations).
     550              :  *
     551              :  * \see elliptic::dg::impose_inhomogeneous_boundary_conditions_on_source
     552              :  */
     553              : template <typename System, typename FixedSourcesTag,
     554              :           typename FluxesArgsTags =
     555              :               elliptic::get_fluxes_argument_tags<System, false>,
     556              :           typename SourcesArgsTags =
     557              :               elliptic::get_sources_argument_tags<System, false>,
     558              :           typename ModifyBoundaryDataArgsTags =
     559              :               elliptic::get_modify_boundary_data_args_tags<System, false>>
     560            1 : struct ImposeInhomogeneousBoundaryConditionsOnSource;
     561              : 
     562              : /// \cond
     563              : template <typename System, typename FixedSourcesTag, typename... FluxesArgsTags,
     564              :           typename... SourcesArgsTags, typename... ModifyBoundaryDataArgsTags>
     565              : struct ImposeInhomogeneousBoundaryConditionsOnSource<
     566              :     System, FixedSourcesTag, tmpl::list<FluxesArgsTags...>,
     567              :     tmpl::list<SourcesArgsTags...>, tmpl::list<ModifyBoundaryDataArgsTags...>>
     568              :     : tt::ConformsTo<::amr::protocols::Projector> {
     569              :  private:
     570              :   static constexpr size_t Dim = System::volume_dim;
     571              :   using BoundaryConditionsBase = typename System::boundary_conditions_base;
     572              : 
     573              :  public:  // DataBox mutator, amr::protocols::Projector
     574              :   using const_global_cache_tags =
     575              :       tmpl::list<elliptic::dg::Tags::PenaltyParameter,
     576              :                  elliptic::dg::Tags::Massive, elliptic::dg::Tags::Formulation,
     577              :                  domain::Tags::ExternalBoundaryConditions<Dim>>;
     578              : 
     579              :   using return_tags = tmpl::list<::Tags::DataBox>;
     580              :   using argument_tags = tmpl::list<>;
     581              : 
     582              :   template <typename DbTagsList, typename... AmrData>
     583              :   static void apply(const gsl::not_null<db::DataBox<DbTagsList>*> box_ptr,
     584              :                     const AmrData&... /*amr_data*/) {
     585              :     // Just to get the same semantics as in actions
     586              :     auto& box = *box_ptr;
     587              :     const auto& element_id = db::get<domain::Tags::Element<Dim>>(box).id();
     588              :     // Used to retrieve items out of the DataBox to forward to functions
     589              :     const auto get_items = [](const auto&... args) {
     590              :       return std::forward_as_tuple(args...);
     591              :     };
     592              :     const auto& boundary_conditions =
     593              :         db::get<domain::Tags::ExternalBoundaryConditions<Dim>>(box).at(
     594              :             element_id.block_id());
     595              :     const auto apply_boundary_condition = [&box, &boundary_conditions,
     596              :                                            &element_id](
     597              :                                               const Direction<Dim>& direction,
     598              :                                               auto&&... fields_and_fluxes) {
     599              :       ASSERT(boundary_conditions.contains(direction),
     600              :              "No boundary condition is available in block "
     601              :                  << element_id.block_id() << " in direction " << direction
     602              :                  << ". Make sure you are setting up boundary conditions when "
     603              :                     "creating the domain.");
     604              :       ASSERT(dynamic_cast<const BoundaryConditionsBase*>(
     605              :                  boundary_conditions.at(direction).get()) != nullptr,
     606              :              "The boundary condition in block "
     607              :                  << element_id.block_id() << " in direction " << direction
     608              :                  << " has an unexpected type. Make sure it derives off the "
     609              :                     "'boundary_conditions_base' class set in the system.");
     610              :       const auto& boundary_condition =
     611              :           dynamic_cast<const BoundaryConditionsBase&>(
     612              :               *boundary_conditions.at(direction));
     613              :       elliptic::apply_boundary_condition<false>(
     614              :           boundary_condition, box, direction,
     615              :           std::forward<decltype(fields_and_fluxes)>(fields_and_fluxes)...);
     616              :     };
     617              : 
     618              :     // Can't `db::get` the arguments for the boundary conditions within
     619              :     // `db::mutate`, so we extract the data to mutate and move it back in when
     620              :     // we're done.
     621              :     typename FixedSourcesTag::type fixed_sources;
     622              :     db::mutate<FixedSourcesTag>(
     623              :         [&fixed_sources](const auto local_fixed_sources) {
     624              :           fixed_sources = std::move(*local_fixed_sources);
     625              :         },
     626              :         make_not_null(&box));
     627              : 
     628              :     using fluxes_args_tags =
     629              :         typename elliptic::get_fluxes_argument_tags<System, false>;
     630              :     using fluxes_args_volume_tags =
     631              :         elliptic::get_fluxes_volume_tags<System, false>;
     632              :     DirectionMap<Dim, std::tuple<decltype(db::get<FluxesArgsTags>(box))...>>
     633              :         fluxes_args_on_faces{};
     634              :     for (const auto& direction : Direction<Dim>::all_directions()) {
     635              :       fluxes_args_on_faces.emplace(
     636              :           direction, elliptic::util::apply_at<
     637              :                          domain::make_faces_tags<Dim, fluxes_args_tags,
     638              :                                                  fluxes_args_volume_tags>,
     639              :                          fluxes_args_volume_tags>(get_items, box, direction));
     640              :     }
     641              : 
     642              :     elliptic::dg::impose_inhomogeneous_boundary_conditions_on_source<System>(
     643              :         make_not_null(&fixed_sources), db::get<domain::Tags::Element<Dim>>(box),
     644              :         db::get<domain::Tags::Mesh<Dim>>(box),
     645              :         db::get<domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
     646              :                                               Frame::Inertial>>(box),
     647              :         db::get<domain::Tags::DetInvJacobian<Frame::ElementLogical,
     648              :                                              Frame::Inertial>>(box),
     649              :         db::get<
     650              :             domain::Tags::DetJacobian<Frame::ElementLogical, Frame::Inertial>>(
     651              :             box),
     652              :         db::get<domain::Tags::DetTimesInvJacobian<Dim, Frame::ElementLogical,
     653              :                                                   Frame::Inertial>>(box),
     654              :         db::get<domain::Tags::Faces<Dim, domain::Tags::FaceNormal<Dim>>>(box),
     655              :         db::get<domain::Tags::Faces<Dim, domain::Tags::FaceNormalVector<Dim>>>(
     656              :             box),
     657              :         db::get<domain::Tags::Faces<
     658              :             Dim, domain::Tags::UnnormalizedFaceNormalMagnitude<Dim>>>(box),
     659              :         db::get<domain::Tags::Faces<
     660              :             Dim, domain::Tags::DetSurfaceJacobian<Frame::ElementLogical,
     661              :                                                   Frame::Inertial>>>(box),
     662              :         db::get<domain::Tags::Faces<
     663              :             Dim, domain::Tags::DetTimesInvJacobian<Dim, Frame::ElementLogical,
     664              :                                                    Frame::Inertial>>>(box),
     665              :         db::get<::Tags::Mortars<domain::Tags::Mesh<Dim - 1>, Dim>>(box),
     666              :         db::get<::Tags::Mortars<::Tags::MortarSize<Dim - 1>, Dim>>(box),
     667              :         db::get<::Tags::Mortars<domain::Tags::DetSurfaceJacobian<
     668              :                                     Frame::ElementLogical, Frame::Inertial>,
     669              :                                 Dim>>(box),
     670              :         db::get<::Tags::Mortars<elliptic::dg::Tags::PenaltyFactor, Dim>>(box),
     671              :         db::get<elliptic::dg::Tags::Massive>(box),
     672              :         db::get<elliptic::dg::Tags::Formulation>(box), apply_boundary_condition,
     673              :         std::forward_as_tuple(db::get<FluxesArgsTags>(box)...),
     674              :         std::forward_as_tuple(db::get<SourcesArgsTags>(box)...),
     675              :         fluxes_args_on_faces,
     676              :         std::forward_as_tuple(db::get<ModifyBoundaryDataArgsTags>(box)...));
     677              : 
     678              :     // Move the mutated data back into the DataBox
     679              :     db::mutate<FixedSourcesTag>(
     680              :         [&fixed_sources](const auto local_fixed_sources) {
     681              :           *local_fixed_sources = std::move(fixed_sources);
     682              :         },
     683              :         make_not_null(&box));
     684              :   }
     685              : };
     686              : /// \endcond
     687              : 
     688              : }  // namespace elliptic::dg::Actions
        

Generated by: LCOV version 2.0-1