SpECTRE Documentation Coverage Report
Current view: top level - Evolution/DgSubcell/Actions - Initialize.hpp Coverage Total Hit
Commit: a37d7b3c1803b88b537d2aef1c27ca5e6b499398 Lines: 28.6 % 14 4
Test Date: 2026-11-12 04:47:19
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 <tuple>
       9              : #include <type_traits>
      10              : #include <utility>
      11              : 
      12              : #include "DataStructures/DataBox/DataBox.hpp"
      13              : #include "DataStructures/TaggedTuple.hpp"
      14              : #include "Domain/Structure/DirectionalId.hpp"
      15              : #include "Domain/Structure/Element.hpp"
      16              : #include "Domain/Structure/FaceType.hpp"
      17              : #include "Domain/Tags.hpp"
      18              : #include "Evolution/DgSubcell/ActiveGrid.hpp"
      19              : #include "Evolution/DgSubcell/GhostData.hpp"
      20              : #include "Evolution/DgSubcell/Mesh.hpp"
      21              : #include "Evolution/DgSubcell/Projection.hpp"
      22              : #include "Evolution/DgSubcell/RdmpTciData.hpp"
      23              : #include "Evolution/DgSubcell/Reconstruction.hpp"
      24              : #include "Evolution/DgSubcell/ReconstructionMethod.hpp"
      25              : #include "Evolution/DgSubcell/Tags/ActiveGrid.hpp"
      26              : #include "Evolution/DgSubcell/Tags/CellCenteredFlux.hpp"
      27              : #include "Evolution/DgSubcell/Tags/Coordinates.hpp"
      28              : #include "Evolution/DgSubcell/Tags/DataForRdmpTci.hpp"
      29              : #include "Evolution/DgSubcell/Tags/DidRollback.hpp"
      30              : #include "Evolution/DgSubcell/Tags/GhostDataForReconstruction.hpp"
      31              : #include "Evolution/DgSubcell/Tags/GhostZoneInverseJacobian.hpp"
      32              : #include "Evolution/DgSubcell/Tags/InitialTciData.hpp"
      33              : #include "Evolution/DgSubcell/Tags/Interpolators.hpp"
      34              : #include "Evolution/DgSubcell/Tags/Jacobians.hpp"
      35              : #include "Evolution/DgSubcell/Tags/Mesh.hpp"
      36              : #include "Evolution/DgSubcell/Tags/MeshForGhostData.hpp"
      37              : #include "Evolution/DgSubcell/Tags/ReconstructionOrder.hpp"
      38              : #include "Evolution/DgSubcell/Tags/StepsSinceTciCall.hpp"
      39              : #include "Evolution/DgSubcell/Tags/SubcellOptions.hpp"
      40              : #include "Evolution/DgSubcell/Tags/TciCallsSinceRollback.hpp"
      41              : #include "Evolution/DgSubcell/Tags/TciGridHistory.hpp"
      42              : #include "Evolution/DgSubcell/Tags/TciStatus.hpp"
      43              : #include "Evolution/DiscontinuousGalerkin/OnlyDgBlockIds.hpp"
      44              : #include "Evolution/Initialization/SetVariables.hpp"
      45              : #include "NumericalAlgorithms/Interpolation/IrregularInterpolant.hpp"
      46              : #include "NumericalAlgorithms/Spectral/Basis.hpp"
      47              : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      48              : #include "Parallel/AlgorithmExecution.hpp"
      49              : #include "Parallel/GlobalCache.hpp"
      50              : #include "Utilities/Algorithm.hpp"
      51              : #include "Utilities/CallWithDynamicType.hpp"
      52              : #include "Utilities/ContainerHelpers.hpp"
      53              : #include "Utilities/ErrorHandling/Error.hpp"
      54              : #include "Utilities/TMPL.hpp"
      55              : 
      56              : /// \cond
      57              : namespace Tags {
      58              : template <typename Tag>
      59              : struct HistoryEvolvedVariables;
      60              : }  // namespace Tags
      61              : /// \endcond
      62              : 
      63              : namespace evolution::dg::subcell::Actions {
      64              : /*!
      65              :  * \brief Initialize the subcell grid, including the size of the evolved
      66              :  * `Variables` and, if present, primitive `Variables`.
      67              :  *
      68              :  * By default sets the element to `subcell::ActiveGrid::Subcell` unless it
      69              :  * is not allowed to use subcell either because it is at an external boundary
      70              :  * or because it or one of its neighbors has been marked as DG-only.
      71              :  *
      72              :  * GlobalCache:
      73              :  * - Uses:
      74              :  *   - `subcell::Tags::SubcellOptions`
      75              :  *
      76              :  * DataBox:
      77              :  * - Uses:
      78              :  *   - `domain::Tags::Mesh<Dim>`
      79              :  *   - `domain::Tags::Element<Dim>`
      80              :  *   - `System::variables_tag`
      81              :  * - Adds:
      82              :  *   - `subcell::Tags::Mesh<Dim>`
      83              :  *   - `subcell::Tags::MeshForGhostData<Dim>`
      84              :  *   - `subcell::Tags::ActiveGrid`
      85              :  *   - `subcell::Tags::DidRollback`
      86              :  *   - `subcell::Tags::TciGridHistory`
      87              :  *   - `subcell::Tags::TciCallsSinceRollback`
      88              :  *   - `subcell::Tags::GhostDataForReconstruction<Dim>`
      89              :  *   - `subcell::Tags::GhostZoneInverseJacobian<Dim>`
      90              :  *   - `subcell::Tags::TciDecision`
      91              :  *   - `subcell::Tags::DataForRdmpTci`
      92              :  *   - `subcell::fd::Tags::InverseJacobianLogicalToGrid<Dim>`
      93              :  *   - `subcell::fd::Tags::DetInverseJacobianLogicalToGrid`
      94              :  *   - `subcell::Tags::LogicalCoordinates<Dim>`
      95              :  *   - `subcell::Tags::ReconstructionOrder<Dim>` (set as `std::nullopt`)
      96              :  *   - `subcell::Tags::Coordinates<Dim, Frame::Grid>` (as compute tag)
      97              :  *   - `subcell::Tags::Coordinates<Dim, Frame::Inertial>` (as compute tag)
      98              :  * - Removes: nothing
      99              :  * - Modifies:
     100              :  *   - `System::variables_tag` and `System::primitive_variables_tag` if the cell
     101              :  *     is troubled
     102              :  *   - `Tags::dt<System::variables_tag>` if the cell is troubled
     103              :  */
     104              : template <size_t Dim, typename System, bool UseNumericInitialData>
     105            1 : struct SetSubcellGrid {
     106            0 :   using const_global_cache_tags =
     107              :       tmpl::list<Tags::SubcellOptions<Dim>,
     108              :                  evolution::dg::Tags::OnlyDgBlockIds<Dim>>;
     109              : 
     110            0 :   using simple_tags = tmpl::list<
     111              :       Tags::ActiveGrid, Tags::DidRollback, Tags::TciGridHistory,
     112              :       Tags::TciCallsSinceRollback, Tags::StepsSinceTciCall,
     113              :       evolution::dg::subcell::Tags::MeshForGhostData<Dim>,
     114              :       Tags::GhostDataForReconstruction<Dim>,
     115              :       Tags::GhostZoneInverseJacobian<Dim>, Tags::TciDecision,
     116              :       Tags::NeighborTciDecisions<Dim>, Tags::DataForRdmpTci,
     117              :       subcell::Tags::CellCenteredFlux<typename System::flux_variables, Dim>,
     118              :       subcell::Tags::ReconstructionOrder<Dim>,
     119              :       evolution::dg::subcell::Tags::InterpolatorsFromFdToNeighborFd<Dim>,
     120              :       evolution::dg::subcell::Tags::InterpolatorsFromDgToNeighborFd<Dim>,
     121              :       evolution::dg::subcell::Tags::InterpolatorsFromNeighborDgToFd<Dim>,
     122              :       typename System::variables_tag,
     123              :       evolution::dg::subcell::Tags::ExtensionDirections<Dim>>;
     124            0 :   using compute_tags =
     125              :       tmpl::list<Tags::MeshCompute<Dim>, Tags::LogicalCoordinatesCompute<Dim>,
     126              :                  ::domain::Tags::MappedCoordinates<
     127              :                      ::domain::Tags::ElementMap<Dim, Frame::Grid>,
     128              :                      subcell::Tags::Coordinates<Dim, Frame::ElementLogical>,
     129              :                      subcell::Tags::Coordinates>,
     130              :                  Tags::InertialCoordinatesCompute<
     131              :                      ::domain::CoordinateMaps::Tags::CoordinateMap<
     132              :                          Dim, Frame::Grid, Frame::Inertial>>,
     133              :                  fd::Tags::InverseJacobianLogicalToGridCompute<
     134              :                      ::domain::Tags::ElementMap<Dim, Frame::Grid>, Dim>,
     135              :                  fd::Tags::DetInverseJacobianLogicalToGridCompute<Dim>,
     136              :                  fd::Tags::InverseJacobianLogicalToInertialCompute<
     137              :                      ::domain::CoordinateMaps::Tags::CoordinateMap<
     138              :                          Dim, Frame::Grid, Frame::Inertial>,
     139              :                      Dim>,
     140              :                  fd::Tags::DetInverseJacobianLogicalToInertialCompute<
     141              :                      ::domain::CoordinateMaps::Tags::CoordinateMap<
     142              :                          Dim, Frame::Grid, Frame::Inertial>,
     143              :                      Dim>>;
     144              : 
     145              :   template <typename DbTagsList, typename... InboxTags, typename ArrayIndex,
     146              :             typename ActionList, typename ParallelComponent,
     147              :             typename Metavariables>
     148            0 :   static Parallel::iterable_action_return_t apply(
     149              :       db::DataBox<DbTagsList>& box,
     150              :       [[maybe_unused]] const tuples::TaggedTuple<InboxTags...>& inboxes,
     151              :       [[maybe_unused]] const Parallel::GlobalCache<Metavariables>& cache,
     152              :       [[maybe_unused]] const ArrayIndex& array_index, ActionList /*meta*/,
     153              :       const ParallelComponent* const /*meta*/) {
     154              :     const SubcellOptions& subcell_options =
     155              :         db::get<Tags::SubcellOptions<Dim>>(box);
     156              :     const std::vector<size_t>& only_dg_block_ids =
     157              :         db::get<evolution::dg::Tags::OnlyDgBlockIds<Dim>>(box);
     158              :     const Mesh<Dim>& dg_mesh = db::get<::domain::Tags::Mesh<Dim>>(box);
     159              :     const Mesh<Dim>& subcell_mesh = db::get<subcell::Tags::Mesh<Dim>>(box);
     160              :     const Element<Dim>& element = db::get<::domain::Tags::Element<Dim>>(box);
     161              : 
     162              :     for (size_t d = 0; d < Dim; ++d) {
     163              :       if (subcell_options.persson_num_highest_modes() >= dg_mesh.extents(d) and
     164              :           dg_mesh.basis(d) != Spectral::Basis::Cartoon) {
     165              :         ERROR("Number of the highest modes to be monitored by the Persson TCI ("
     166              :               << subcell_options.persson_num_highest_modes()
     167              :               << ") must be smaller than the extent of the DG mesh ("
     168              :               << dg_mesh.extents(d) << ").");
     169              :       }
     170              :     }
     171              : 
     172              :     const bool bordering_dg_block =
     173              :         evolution::dg::borders_only_dg_block(element, only_dg_block_ids);
     174              : 
     175              :     // Non-hypercube topologies (e.g. spherical shells) can never use subcell
     176              :     // and are automatically treated as DG-only.
     177              :     const bool subcell_allowed_in_element =
     178              :         fd::dg_mesh_supports_subcell(dg_mesh) and
     179              :         not alg::found(only_dg_block_ids, element.id().block_id()) and
     180              :         not bordering_dg_block;
     181              :     const bool cell_is_not_on_external_boundary =
     182              :         db::get<::domain::Tags::Element<Dim>>(box)
     183              :             .external_boundaries()
     184              :             .empty();
     185              : 
     186              :     constexpr bool subcell_enabled_at_external_boundary =
     187              :         Metavariables::SubcellOptions::subcell_enabled_at_external_boundary;
     188              : 
     189              :     // Non-hypercube elements (e.g. spherical shells) cannot use subcell and may
     190              :     // have > 24 neighbors, which would overflow the fixed-size
     191              :     // DirectionalIdMap, so their map is left empty. Hypercube elements that
     192              :     // are forced to DG (e.g. because they border a DG-only block) still have
     193              :     // a bounded neighbor count and continue to track TCI decisions normally.
     194              :     //
     195              :     // Within a hypercube element, also skip MultipleNonconforming directions.
     196              :     // These arise on the "one" side of a many-to-one interface where
     197              :     // bordering a non-hypercube element
     198              :     if (fd::dg_mesh_supports_subcell(dg_mesh)) {
     199              :       db::mutate<Tags::NeighborTciDecisions<Dim>>(
     200              :           [&element](const auto neighbor_decisions_ptr) {
     201              :             neighbor_decisions_ptr->clear();
     202              :             for (const auto& [direction, neighbors_in_direction] :
     203              :                  element.neighbors()) {
     204              :               if (element.face_types().at(direction) ==
     205              :                   ::domain::FaceType::MultipleNonconforming) {
     206              :                 continue;
     207              :               }
     208              :               for (const auto& neighbor : neighbors_in_direction.ids()) {
     209              :                 neighbor_decisions_ptr->insert(
     210              :                     std::pair{DirectionalId<Dim>{direction, neighbor}, 0});
     211              :               }
     212              :             }
     213              :           },
     214              :           make_not_null(&box));
     215              :     }
     216              : 
     217              :     db::mutate_apply<
     218              :         tmpl::list<Tags::ActiveGrid, Tags::DidRollback,
     219              :                    typename System::variables_tag, subcell::Tags::TciDecision,
     220              :                    subcell::Tags::TciCallsSinceRollback,
     221              :                    subcell::Tags::StepsSinceTciCall>,
     222              :         tmpl::list<>>(
     223              :         [&cell_is_not_on_external_boundary, &dg_mesh,
     224              :          subcell_allowed_in_element, &subcell_mesh](
     225              :             const gsl::not_null<ActiveGrid*> active_grid_ptr,
     226              :             const gsl::not_null<bool*> did_rollback_ptr,
     227              :             const auto active_vars_ptr,
     228              :             const gsl::not_null<int*> tci_decision_ptr,
     229              :             const gsl::not_null<size_t*> tci_calls_since_rollback_ptr,
     230              :             const gsl::not_null<size_t*> steps_since_tci_call_ptr) {
     231              :           // We don't consider setting the initial grid to subcell as rolling
     232              :           // back. Since no time step is undone, we just continue on the
     233              :           // subcells as a normal solve.
     234              :           *did_rollback_ptr = false;
     235              : 
     236              :           if ((cell_is_not_on_external_boundary or
     237              :                subcell_enabled_at_external_boundary) and
     238              :               subcell_allowed_in_element) {
     239              :             *active_grid_ptr = ActiveGrid::Subcell;
     240              :             active_vars_ptr->initialize(subcell_mesh.number_of_grid_points());
     241              :           } else {
     242              :             *active_grid_ptr = ActiveGrid::Dg;
     243              :             active_vars_ptr->initialize(dg_mesh.number_of_grid_points());
     244              :           }
     245              : 
     246              :           *tci_decision_ptr = 0;
     247              :           *tci_calls_since_rollback_ptr = 0;
     248              :           *steps_since_tci_call_ptr = 0;
     249              :         },
     250              :         make_not_null(&box));
     251              :     if constexpr (System::has_primitive_and_conservative_vars) {
     252              :       db::mutate<typename System::primitive_variables_tag>(
     253              :           [&dg_mesh, &subcell_mesh](const auto prim_vars_ptr,
     254              :                                     const auto active_grid) {
     255              :             if (active_grid == ActiveGrid::Dg) {
     256              :               prim_vars_ptr->initialize(dg_mesh.number_of_grid_points());
     257              :             } else {
     258              :               prim_vars_ptr->initialize(subcell_mesh.number_of_grid_points());
     259              :             }
     260              :           },
     261              :           make_not_null(&box), db::get<Tags::ActiveGrid>(box));
     262              :     }
     263              :     if constexpr (not UseNumericInitialData) {
     264              :       if (db::get<Tags::ActiveGrid>(box) ==
     265              :           evolution::dg::subcell::ActiveGrid::Dg) {
     266              :         evolution::Initialization::Actions::SetVariables<
     267              :             ::domain::Tags::Coordinates<Dim, Frame::ElementLogical>>::
     268              :             apply(box, inboxes, cache, array_index, ActionList{},
     269              :                   std::add_pointer_t<ParallelComponent>{nullptr});
     270              :       } else {
     271              :         evolution::Initialization::Actions::
     272              :             SetVariables<Tags::Coordinates<Dim, Frame::ElementLogical>>::apply(
     273              :                 box, inboxes, cache, array_index, ActionList{},
     274              :                 std::add_pointer_t<ParallelComponent>{nullptr});
     275              :       }
     276              :     }
     277              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     278              :   }
     279              : };
     280              : 
     281              : /*!
     282              :  * \brief Sets the RDMP data from the initial data and sends it to neighboring
     283              :  * elements.
     284              :  *
     285              :  * GlobalCache:
     286              :  * - Uses:
     287              :  *   - `ParallelComponent` proxy
     288              :  *
     289              :  * DataBox:
     290              :  * - Uses:
     291              :  *   - `domain::Tags::Element<Dim>`
     292              :  *   - `subcell::Tags::DataForRdmpTci`
     293              :  *   - `subcell::Tags::InitialTciData`
     294              :  *   - whatever `SetInitialRdmpData` uses
     295              :  * - Adds: nothing
     296              :  * - Removes: nothing
     297              :  * - Modifies:
     298              :  *   - whatever `SetInitialRdmpData` mutates
     299              :  */
     300              : template <size_t Dim, typename SetInitialRdmpData>
     301            1 : struct SetAndCommunicateInitialRdmpData {
     302            0 :   using inbox_tags =
     303              :       tmpl::list<evolution::dg::subcell::Tags::InitialTciData<Dim>>;
     304              : 
     305              :   template <typename DbTagsList, typename... InboxTags, typename ArrayIndex,
     306              :             typename ActionList, typename ParallelComponent,
     307              :             typename Metavariables>
     308            0 :   static Parallel::iterable_action_return_t apply(
     309              :       db::DataBox<DbTagsList>& box,
     310              :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     311              :       Parallel::GlobalCache<Metavariables>& cache,
     312              :       const ArrayIndex& /*array_index*/, ActionList /*meta*/,
     313              :       const ParallelComponent* const /*meta*/) {
     314              :     // Get the RDMP data on this element and then initialize it.
     315              :     db::mutate_apply<SetInitialRdmpData>(make_not_null(&box));
     316              : 
     317              :     // Send RDMP data to neighbors
     318              :     const auto& element = db::get<domain::Tags::Element<Dim>>(box);
     319              :     const auto& rdmp_data =
     320              :         db::get<evolution::dg::subcell::Tags::DataForRdmpTci>(box);
     321              :     auto& receiver_proxy =
     322              :         Parallel::get_parallel_component<ParallelComponent>(cache);
     323              :     for (const auto& [direction, neighbors] : element.neighbors()) {
     324              :       for (const auto& neighbor : neighbors) {
     325              :         const auto& orientation = neighbors.orientation(neighbor);
     326              :         const auto direction_from_neighbor = orientation(direction.opposite());
     327              :         evolution::dg::subcell::InitialTciData data{{}, rdmp_data};
     328              :         // We use temporal ID 0 for sending RDMP data
     329              :         const int temporal_id = 0;
     330              :         Parallel::receive_data<
     331              :             evolution::dg::subcell::Tags::InitialTciData<Dim>>(
     332              :             receiver_proxy[neighbor], temporal_id,
     333              :             std::make_pair(
     334              :                 DirectionalId<Dim>{direction_from_neighbor, element.id()},
     335              :                 std::move(data)));
     336              :       }
     337              :     }
     338              : 
     339              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     340              :   }
     341              : };
     342              : 
     343              : /*!
     344              :  * \brief Apply the TCI on the FD grid to the initial data and send the TCI
     345              :  * decision to neighboring elements.
     346              :  *
     347              :  * GlobalCache:
     348              :  * - Uses:
     349              :  *   - `ParallelComponent` proxy
     350              :  *
     351              :  * DataBox:
     352              :  * - Uses:
     353              :  *   - `domain::Tags::Element<Dim>`
     354              :  *   - `subcell::Tags::DataForRdmpTci`
     355              :  *   - `subcell::Tags::InitialTciData`
     356              :  *   - `subcell::Tags::SubcellOptions`
     357              :  *   - `subcell::Tags::ActiveGrid`
     358              :  *   - whatever `TciOnFdGridMutator` uses
     359              :  * - Adds: nothing
     360              :  * - Removes: nothing
     361              :  * - Modifies:
     362              :  *   - `subcell::Tags::DataForRdmpTci`
     363              :  *   - `subcell::Tags::TciDecision`
     364              :  */
     365              : template <size_t Dim, typename System, typename TciOnFdGridMutator>
     366            1 : struct ComputeAndSendTciOnInitialGrid {
     367            0 :   using inbox_tags =
     368              :       tmpl::list<evolution::dg::subcell::Tags::InitialTciData<Dim>>;
     369              : 
     370              :   template <typename DbTagsList, typename... InboxTags, typename ArrayIndex,
     371              :             typename ActionList, typename ParallelComponent,
     372              :             typename Metavariables>
     373            0 :   static Parallel::iterable_action_return_t apply(
     374              :       db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
     375              :       Parallel::GlobalCache<Metavariables>& cache,
     376              :       const ArrayIndex& /*array_index*/, ActionList /*meta*/,
     377              :       const ParallelComponent* const /*meta*/) {
     378              :     const Element<Dim>& element = db::get<::domain::Tags::Element<Dim>>(box);
     379              : 
     380              :     // Check if we have received all RDMP data.
     381              :     if (LIKELY(element.number_of_neighbors() != 0)) {
     382              :       auto& inbox =
     383              :           tuples::get<evolution::dg::subcell::Tags::InitialTciData<Dim>>(
     384              :               inboxes);
     385              :       const auto& received = inbox.find(0);
     386              :       if (received == inbox.end() or
     387              :           received->second.size() != element.number_of_neighbors()) {
     388              :         return {Parallel::AlgorithmExecution::Retry, std::nullopt};
     389              :       }
     390              : 
     391              :       db::mutate<evolution::dg::subcell::Tags::DataForRdmpTci>(
     392              :           [&element, &received](const auto rdmp_tci_data_ptr) {
     393              :             (void)element;
     394              :             const size_t number_of_rdmp_vars =
     395              :                 rdmp_tci_data_ptr->max_variables_values.size();
     396              :             ASSERT(rdmp_tci_data_ptr->max_variables_values.size() ==
     397              :                        number_of_rdmp_vars,
     398              :                    "The number of local max vars is "
     399              :                        << number_of_rdmp_vars
     400              :                        << " while the number of local min vars is "
     401              :                        << rdmp_tci_data_ptr->max_variables_values.size()
     402              :                        << " the local element ID is " << element.id());
     403              :             for (const auto& [direction_and_neighbor_element_id,
     404              :                               neighbor_initial_tci_data] : received->second) {
     405              :               ASSERT(neighbor_initial_tci_data.initial_rdmp_data.has_value(),
     406              :                      "Neighbor in direction "
     407              :                          << direction_and_neighbor_element_id.direction()
     408              :                          << " with element ID "
     409              :                          << direction_and_neighbor_element_id.id() << " of "
     410              :                          << element.id()
     411              :                          << " didn't send initial TCI data correctly");
     412              :               ASSERT(
     413              :                   neighbor_initial_tci_data.initial_rdmp_data.value()
     414              :                           .max_variables_values.size() == number_of_rdmp_vars,
     415              :                   "The number of local RDMP vars is "
     416              :                       << number_of_rdmp_vars
     417              :                       << " while the number of remote max vars is "
     418              :                       << neighbor_initial_tci_data.initial_rdmp_data.value()
     419              :                              .max_variables_values.size()
     420              :                       << " the local element ID is " << element.id()
     421              :                       << " and the remote id is "
     422              :                       << direction_and_neighbor_element_id.id());
     423              :               ASSERT(
     424              :                   neighbor_initial_tci_data.initial_rdmp_data.value()
     425              :                           .min_variables_values.size() == number_of_rdmp_vars,
     426              :                   "The number of local RDMP vars is "
     427              :                       << number_of_rdmp_vars
     428              :                       << " while the number of remote min vars is "
     429              :                       << neighbor_initial_tci_data.initial_rdmp_data.value()
     430              :                              .min_variables_values.size()
     431              :                       << " the local element ID is " << element.id()
     432              :                       << " and the remote id is "
     433              :                       << direction_and_neighbor_element_id.id());
     434              :               for (size_t var_index = 0; var_index < number_of_rdmp_vars;
     435              :                    ++var_index) {
     436              :                 rdmp_tci_data_ptr->max_variables_values[var_index] =
     437              :                     std::max(rdmp_tci_data_ptr->max_variables_values[var_index],
     438              :                              neighbor_initial_tci_data.initial_rdmp_data.value()
     439              :                                  .max_variables_values[var_index]);
     440              :                 rdmp_tci_data_ptr->min_variables_values[var_index] =
     441              :                     std::min(rdmp_tci_data_ptr->min_variables_values[var_index],
     442              :                              neighbor_initial_tci_data.initial_rdmp_data.value()
     443              :                                  .min_variables_values[var_index]);
     444              :               }
     445              :             }
     446              :           },
     447              :           make_not_null(&box));
     448              :       inbox.erase(received);
     449              :     }
     450              : 
     451              :     const auto send_tci_decision = [&cache, &element](const int tci_decision) {
     452              :       if (UNLIKELY(element.number_of_neighbors() == 0)) {
     453              :         return;
     454              :       }
     455              :       auto& receiver_proxy =
     456              :           Parallel::get_parallel_component<ParallelComponent>(cache);
     457              :       for (const auto& [direction, neighbors] : element.neighbors()) {
     458              :         for (const auto& neighbor : neighbors) {
     459              :           const auto& orientation = neighbors.orientation(neighbor);
     460              :           const auto direction_from_neighbor =
     461              :               orientation(direction.opposite());
     462              :           evolution::dg::subcell::InitialTciData data{tci_decision, {}};
     463              :           // We use temporal ID 1 for ending the TCI decision.
     464              :           const int temporal_id = 1;
     465              :           Parallel::receive_data<
     466              :               evolution::dg::subcell::Tags::InitialTciData<Dim>>(
     467              :               receiver_proxy[neighbor], temporal_id,
     468              :               std::make_pair(
     469              :                   DirectionalId<Dim>{direction_from_neighbor, element.id()},
     470              :                   std::move(data)));
     471              :         }
     472              :       }
     473              :     };
     474              : 
     475              :     const SubcellOptions& subcell_options =
     476              :         db::get<Tags::SubcellOptions<Dim>>(box);
     477              : 
     478              :     if (subcell_options.always_use_subcells() or
     479              :         get<Tags::ActiveGrid>(box) == ActiveGrid::Dg) {
     480              :       db::mutate<Tags::TciDecision>(
     481              :           [](const gsl::not_null<int*> tci_decision_ptr) {
     482              :             *tci_decision_ptr = 0;
     483              :           },
     484              :           make_not_null(&box));
     485              :       send_tci_decision(0);
     486              :       return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     487              :     }
     488              : 
     489              :     // Now run the TCI to see if we could switch back to DG.
     490              :     const std::tuple<int, evolution::dg::subcell::RdmpTciData> tci_result =
     491              :         db::mutate_apply<TciOnFdGridMutator>(
     492              :             make_not_null(&box), subcell_options.persson_exponent() + 1.0,
     493              :             false);
     494              : 
     495              :     db::mutate<Tags::TciDecision>(
     496              :         [&tci_result](const gsl::not_null<int*> tci_decision_ptr) {
     497              :           *tci_decision_ptr = std::get<0>(tci_result);
     498              :         },
     499              :         make_not_null(&box));
     500              :     send_tci_decision(std::get<0>(tci_result));
     501              : 
     502              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     503              :   }
     504              : };
     505              : 
     506              : /*!
     507              :  * \brief Using the local and neighboring TCI decisions, switches the element to
     508              :  * DG if the DG solution was determined to be admissible.
     509              :  *
     510              :  * GlobalCache:
     511              :  * - Uses:
     512              :  *   - `ParallelComponent` proxy
     513              :  *
     514              :  * DataBox:
     515              :  * - Uses:
     516              :  *   - `domain::Tags::Element<Dim>`
     517              :  *   - `subcell::Tags::DataForRdmpTci`
     518              :  *   - `subcell::Tags::InitialTciData`
     519              :  *   - `subcell::Tags::SubcellOptions`
     520              :  *   - `subcell::Tags::ActiveGrid`
     521              :  *   - whatever `TciOnFdGridMutator` uses
     522              :  * - Adds: nothing
     523              :  * - Removes: nothing
     524              :  * - Modifies:
     525              :  *   - `subcell::Tags::NeighborTciDecisions`
     526              :  *   - `System::variables_tag`
     527              :  *   - `Tags::HistoryEvolvedVariables<System::variables_tag>`
     528              :  *   - `subcell::Tags::GhostDataForReconstruction`
     529              :  *   - `subcell::Tags::TciGridHistory`
     530              :  *   - `subcell::Tags::CellCenteredFlux`
     531              :  */
     532              : template <size_t Dim, typename System>
     533            1 : struct SetInitialGridFromTciData {
     534              :   template <typename DbTagsList, typename... InboxTags, typename ArrayIndex,
     535              :             typename ActionList, typename ParallelComponent,
     536              :             typename Metavariables>
     537            0 :   static Parallel::iterable_action_return_t apply(
     538              :       db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
     539              :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     540              :       const ArrayIndex& /*array_index*/, ActionList /*meta*/,
     541              :       const ParallelComponent* const /*meta*/) {
     542              :     const Element<Dim>& element = db::get<::domain::Tags::Element<Dim>>(box);
     543              :     if (LIKELY(element.number_of_neighbors() != 0)) {
     544              :       auto& inbox =
     545              :           tuples::get<evolution::dg::subcell::Tags::InitialTciData<Dim>>(
     546              :               inboxes);
     547              :       const auto& received = inbox.find(1);
     548              :       // Check if we have received all TCI decisions.
     549              :       if (received == inbox.end() or
     550              :           received->second.size() != element.number_of_neighbors()) {
     551              :         return {Parallel::AlgorithmExecution::Retry, std::nullopt};
     552              :       }
     553              : 
     554              :       db::mutate<evolution::dg::subcell::Tags::NeighborTciDecisions<Dim>>(
     555              :           [&element, &received](const auto neighbor_tci_decisions_ptr) {
     556              :             // Non-hypercube elements (e.g. spherical shells) have an empty
     557              :             // NeighborTciDecisions map (see SetSubcellGrid) and will remain
     558              :             // on DG regardless of neighbor TCI decisions.
     559              :             if (neighbor_tci_decisions_ptr->empty()) {
     560              :               return;
     561              :             }
     562              :             for (const auto& [directional_element_id,
     563              :                               neighbor_initial_tci_data] : received->second) {
     564              :               ASSERT(neighbor_initial_tci_data.tci_status.has_value(),
     565              :                      "Neighbor in direction "
     566              :                          << directional_element_id.direction()
     567              :                          << " with element ID " << directional_element_id.id()
     568              :                          << " of " << element.id()
     569              :                          << " didn't send initial TCI decision correctly");
     570              :               if (not neighbor_tci_decisions_ptr->contains(
     571              :                       directional_element_id)) {
     572              :                 // TCI decisions for MultipleNonconforming neighbors are not
     573              :                 // tracked because those elements are forced to remain on DG.
     574              :                 ASSERT(element.face_types().at(
     575              :                            directional_element_id.direction()) ==
     576              :                            ::domain::FaceType::MultipleNonconforming,
     577              :                        "NeighborTciDecisions does not contain the neighbor "
     578              :                            << directional_element_id
     579              :                            << " but the face is not MultipleNonconforming. "
     580              :                               "This indicates a bug in the initialization of "
     581              :                               "NeighborTciDecisions.");
     582              :                 continue;
     583              :               }
     584              :               neighbor_tci_decisions_ptr->at(directional_element_id) =
     585              :                   neighbor_initial_tci_data.tci_status.value();
     586              :             }
     587              :           },
     588              :           make_not_null(&box));
     589              :       inbox.erase(received);
     590              :     }
     591              : 
     592              :     if (get<Tags::ActiveGrid>(box) == ActiveGrid::Dg) {
     593              :       // In this case we are allowed to only do DG in this element. No need to
     594              :       // even do any checks.
     595              :       return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     596              :     }
     597              : 
     598              :     const SubcellOptions& subcell_options =
     599              :         db::get<Tags::SubcellOptions<Dim>>(box);
     600              : 
     601              :     bool cell_is_troubled =
     602              :         subcell_options.always_use_subcells() or
     603              :         (subcell_options.use_halo() and [&box]() -> bool {
     604              :           for (const auto& [_, neighbor_decision] :
     605              :                db::get<evolution::dg::subcell::Tags::NeighborTciDecisions<Dim>>(
     606              :                    box)) {
     607              :             if (neighbor_decision != 0) {
     608              :               return true;
     609              :             }
     610              :           }
     611              :           return false;
     612              :         }()) or
     613              :         (db::get<Tags::TciDecision>(box) != 0);
     614              : 
     615              :     if (not cell_is_troubled) {
     616              :       using variables_tag = typename System::variables_tag;
     617              :       using flux_variables = typename System::flux_variables;
     618              : 
     619              :       const Mesh<Dim>& dg_mesh = db::get<::domain::Tags::Mesh<Dim>>(box);
     620              :       const Mesh<Dim>& subcell_mesh = db::get<subcell::Tags::Mesh<Dim>>(box);
     621              :       db::mutate<
     622              :           variables_tag, ::Tags::HistoryEvolvedVariables<variables_tag>,
     623              :           Tags::ActiveGrid, subcell::Tags::GhostDataForReconstruction<Dim>,
     624              :           evolution::dg::subcell::Tags::TciGridHistory,
     625              :           evolution::dg::subcell::Tags::CellCenteredFlux<flux_variables, Dim>>(
     626              :           [&dg_mesh, &subcell_mesh, &subcell_options](
     627              :               const auto active_vars_ptr, const auto active_history_ptr,
     628              :               const gsl::not_null<ActiveGrid*> active_grid_ptr,
     629              :               const auto subcell_ghost_data_ptr,
     630              :               const gsl::not_null<
     631              :                   std::deque<evolution::dg::subcell::ActiveGrid>*>
     632              :                   tci_grid_history_ptr,
     633              :               const auto subcell_cell_centered_fluxes) {
     634              :             // Note: strictly speaking, to be conservative this should
     635              :             // reconstruct uJ instead of u.
     636              :             *active_vars_ptr = fd::reconstruct(
     637              :                 *active_vars_ptr, dg_mesh, subcell_mesh.extents(),
     638              :                 subcell_options.reconstruction_method());
     639              : 
     640              :             // Reconstruct the DG solution for each time in the time stepper
     641              :             // history
     642              :             active_history_ptr->map_entries(
     643              :                 [&dg_mesh, &subcell_mesh, &subcell_options](const auto entry) {
     644              :                   *entry =
     645              :                       fd::reconstruct(*entry, dg_mesh, subcell_mesh.extents(),
     646              :                                       subcell_options.reconstruction_method());
     647              :                 });
     648              :             *active_grid_ptr = ActiveGrid::Dg;
     649              : 
     650              :             // Clear the neighbor data needed for subcell reconstruction since
     651              :             // we have now completed the time step.
     652              :             subcell_ghost_data_ptr->clear();
     653              : 
     654              :             // Clear the TCI grid history since we don't need to use it when on
     655              :             // the DG grid.
     656              :             tci_grid_history_ptr->clear();
     657              : 
     658              :             // Clear the allocation for the cell-centered fluxes.
     659              :             *subcell_cell_centered_fluxes = std::nullopt;
     660              :           },
     661              :           make_not_null(&box));
     662              :     }
     663              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     664              :   }
     665              : };
     666              : }  // namespace evolution::dg::subcell::Actions
        

Generated by: LCOV version 2.0-1