SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Amr/Actions - AdjustDomain.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 1 3 33.3 %
Date: 2025-12-05 05:03:31
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <array>
       7             : #include <cstddef>
       8             : #include <unordered_set>
       9             : 
      10             : #include "DataStructures/DataBox/DataBox.hpp"
      11             : #include "Domain/Amr/Flag.hpp"
      12             : #include "Domain/Amr/Helpers.hpp"
      13             : #include "Domain/Amr/NewNeighborIds.hpp"
      14             : #include "Domain/Amr/Tags/Flags.hpp"
      15             : #include "Domain/Amr/Tags/NeighborFlags.hpp"
      16             : #include "Domain/Structure/Direction.hpp"
      17             : #include "Domain/Structure/DirectionMap.hpp"
      18             : #include "Domain/Structure/DirectionalIdMap.hpp"
      19             : #include "Domain/Structure/Element.hpp"
      20             : #include "Domain/Structure/ElementId.hpp"
      21             : #include "Domain/Structure/Neighbors.hpp"
      22             : #include "Domain/Tags.hpp"
      23             : #include "Domain/Tags/NeighborMesh.hpp"
      24             : #include "IO/Logging/Tags.hpp"
      25             : #include "IO/Logging/Verbosity.hpp"
      26             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      27             : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
      28             : #include "Parallel/GlobalCache.hpp"
      29             : #include "Parallel/Invoke.hpp"
      30             : #include "Parallel/Phase.hpp"
      31             : #include "Parallel/Printf/Printf.hpp"
      32             : #include "Parallel/Tags/DistributedObjectTags.hpp"
      33             : #include "Parallel/Tags/Section.hpp"
      34             : #include "ParallelAlgorithms/Amr/Actions/CreateChild.hpp"
      35             : #include "ParallelAlgorithms/Amr/Actions/CreateParent.hpp"
      36             : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp"
      37             : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
      38             : #include "ParallelAlgorithms/Amr/Tags.hpp"
      39             : #include "Utilities/Algorithm.hpp"
      40             : #include "Utilities/ErrorHandling/Assert.hpp"
      41             : #include "Utilities/Gsl.hpp"
      42             : #include "Utilities/Literals.hpp"
      43             : #include "Utilities/PrettyType.hpp"
      44             : #include "Utilities/ProtocolHelpers.hpp"
      45             : #include "Utilities/TMPL.hpp"
      46             : 
      47             : namespace amr {
      48             : /// \cond
      49             : template <class Metavariables>
      50             : struct Component;
      51             : /// \endcond
      52             : }  // namespace amr
      53             : 
      54             : namespace detail {
      55             : template <typename ListOfProjectors>
      56             : struct GetMutatedTags;
      57             : 
      58             : template <typename... Projectors>
      59             : struct GetMutatedTags<tmpl::list<Projectors...>> {
      60             :   using type = tmpl::remove_duplicates<
      61             :       tmpl::flatten<tmpl::append<typename Projectors::return_tags...>>>;
      62             : };
      63             : }  // namespace detail
      64             : 
      65             : namespace amr::Actions {
      66             : /// \brief Adjusts the domain given the refinement criteria
      67             : ///
      68             : /// \details
      69             : /// - Checks if an Element wants to split in any dimension; if yes, determines
      70             : ///   the ElementId%s of the new children Element%s and calls
      71             : ///   amr::Actions::CreateChild on the amr::Component, then exits the action.
      72             : /// - Checks if an Element wants to join in any dimension; if yes, either calls
      73             : ///   amr::Actions::CreateParent on the amr::Component if this is the child
      74             : ///   Element that should create the parent Element or does nothing, and then
      75             : ///   exits the action.
      76             : /// - Checks if an Element wants to increase or decrease its resolution, if yes,
      77             : ///   mutates the Mesh
      78             : /// - Updates the Neighbors of the Element
      79             : /// - Resets amr::Tags::Flag%s to amr::Flag::Undefined
      80             : /// - Resets amr::Tags::NeighborInfo to an empty map
      81             : /// - Mutates all return_tags of Metavariables::amr::projectors
      82           1 : struct AdjustDomain {
      83             :   template <typename ParallelComponent, typename DbTagList,
      84             :             typename Metavariables>
      85           0 :   static void apply(db::DataBox<DbTagList>& box,
      86             :                     Parallel::GlobalCache<Metavariables>& cache,
      87             :                     const ElementId<Metavariables::volume_dim>& element_id) {
      88             :     if constexpr (Parallel::is_dg_element_collection_v<ParallelComponent>) {
      89             :       ERROR("Can't adjust the domain for DG elements running on nodegroups.");
      90             :     } else {
      91             :       constexpr size_t volume_dim = Metavariables::volume_dim;
      92             :       using amr_projectors = typename Metavariables::amr::projectors;
      93             :       static_assert(
      94             :           tmpl::all<amr_projectors,
      95             :                     tt::assert_conforms_to<tmpl::_1,
      96             :                                            amr::protocols::Projector>>::value,
      97             :           "All AMR projectors must conform to 'amr::protocols::Projector'.");
      98             : 
      99             :       // To prevent bugs when new mutable items are added to a DataBox, we
     100             :       // require that all mutable_item_creation_tags of box are either:
     101             :       // - mutated by one of the projectors in Metavariables::amr::projectors
     102             :       // - in the list of distributed_object_tags
     103             :       // - or in the list of tags mutated by this action
     104             :       using distributed_object_tags =
     105             :           typename ::Parallel::Tags::distributed_object_tags<
     106             :               Metavariables, ElementId<volume_dim>>;
     107             :       using tags_mutated_by_this_action = tmpl::list<
     108             :           ::domain::Tags::Element<volume_dim>, ::domain::Tags::Mesh<volume_dim>,
     109             :           ::domain::Tags::NeighborMesh<volume_dim>, amr::Tags::Info<volume_dim>,
     110             :           amr::Tags::NeighborInfo<volume_dim>, amr::Tags::ParentId<volume_dim>,
     111             :           amr::Tags::ChildIds<volume_dim>, amr::Tags::ParentMesh<volume_dim>,
     112             :           Parallel::Tags::Section<ParallelComponent, amr::Tags::GridIndex>,
     113             :           Parallel::Tags::Section<ParallelComponent, amr::Tags::IsFinestGrid>>;
     114             :       using mutated_tags =
     115             :           tmpl::append<distributed_object_tags, tags_mutated_by_this_action,
     116             :                        typename detail::GetMutatedTags<amr_projectors>::type>;
     117             :       using mutable_tags =
     118             :           typename db::DataBox<DbTagList>::mutable_item_creation_tags;
     119             :       using mutable_tags_not_mutated =
     120             :           tmpl::list_difference<mutable_tags, mutated_tags>;
     121             :       static_assert(
     122             :           std::is_same_v<mutable_tags_not_mutated, tmpl::list<>>,
     123             :           "All mutable tags in the DataBox must be explicitly mutated "
     124             :           "by an amr::projector.  Default initialized objects can use "
     125             :           "amr::projector::DefaultInitialize.");
     126             : 
     127             :       const auto& my_amr_info = db::get<amr::Tags::Info<volume_dim>>(box);
     128             :       const auto& my_amr_flags = my_amr_info.flags;
     129             :       auto& element_array =
     130             :           Parallel::get_parallel_component<ParallelComponent>(cache);
     131             :       auto& amr_component =
     132             :           Parallel::get_parallel_component<amr::Component<Metavariables>>(
     133             :               cache);
     134             :       const auto& phase_bookmarks =
     135             :           Parallel::local(element_array[element_id])->phase_bookmarks();
     136             :       const auto& verbosity =
     137             :           db::get<logging::Tags::Verbosity<amr::OptionTags::AmrGroup>>(box);
     138             : 
     139             :       if (alg::all_of(my_amr_flags, [](amr::Flag flag) {
     140             :             return flag == amr::Flag::Undefined;
     141             :           })) {
     142             :         // AMR flags are undefined. This state can be reached when the AMR
     143             :         // component broadcasts the `AdjustDomain` simple action to the entire
     144             :         // element array, then some of those elements run the simple action and
     145             :         // create new child elements, and then the broadcast also arrives at
     146             :         // these new elements for some reason (seems like a Charm++ bug). The
     147             :         // AMR flags will be undefined in this case, so we just ignore the
     148             :         // broadcast and return early here.
     149             :         return;
     150             :       } else if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     151             :                    return flag == amr::Flag::Split;
     152             :                  })) {
     153             :         // h-refinement
     154             :         using ::operator<<;
     155             :         ASSERT(alg::count(my_amr_flags, amr::Flag::Join) == 0,
     156             :                "Element " << element_id
     157             :                           << " cannot both split and join, but had AMR flags "
     158             :                           << my_amr_flags << "\n");
     159             :         const size_t child_grid_index = Metavariables::amr::keep_coarse_grids
     160             :                                             ? element_id.grid_index() + 1
     161             :                                             : element_id.grid_index();
     162             :         auto children_ids =
     163             :             amr::ids_of_children(element_id, my_amr_flags, child_grid_index);
     164             :         if (verbosity >= Verbosity::Debug) {
     165             :           Parallel::printf("Splitting element %s into %zu: %s\n", element_id,
     166             :                            children_ids.size(), children_ids);
     167             :         }
     168             :         Parallel::simple_action<CreateChild>(amr_component, element_array,
     169             :                                              element_id, children_ids, 0_st,
     170             :                                              phase_bookmarks);
     171             :         return;
     172             :       } else if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     173             :                    return flag == amr::Flag::Join;
     174             :                  })) {
     175             :         // h-coarsening
     176             :         if (Metavariables::amr::keep_coarse_grids) {
     177             :           ERROR(
     178             :               "When AMR keeps coarse grids then no h-coarsening during AMR is "
     179             :               "allowed, but element "
     180             :               << element_id
     181             :               << " requested h-coarsening. Set the 'AllowCoarsening' policy to "
     182             :                  "false to disable coarsening.");
     183             :           // Note: this restriction could be relaxed if ever needed.
     184             :           return;
     185             :         }
     186             :         // Only one element should create the new parent
     187             :         if (amr::is_child_that_creates_parent(element_id, my_amr_flags)) {
     188             :           auto parent_id = amr::id_of_parent(element_id, my_amr_flags);
     189             :           const auto& element =
     190             :               db::get<::domain::Tags::Element<volume_dim>>(box);
     191             :           auto ids_to_join =
     192             :               amr::ids_of_joining_neighbors(element, my_amr_flags);
     193             :           if (verbosity >= Verbosity::Debug) {
     194             :             Parallel::printf("Joining %zu elements: %s -> %s\n",
     195             :                              ids_to_join.size(), ids_to_join, parent_id);
     196             :           }
     197             :           Parallel::simple_action<CreateParent>(
     198             :               amr_component, element_array, std::move(parent_id), element_id,
     199             :               std::move(ids_to_join), phase_bookmarks);
     200             :         }
     201             :         return;
     202             :       }
     203             : 
     204             :       // Neither h-refinement nor h-coarsening. This element will remain.
     205             : 
     206             :       if constexpr (Metavariables::amr::keep_coarse_grids) {
     207             :         // Create new element that covers this one with an incremented grid
     208             :         // index. p-refinement will be handled by the newly created element.
     209             :         ElementId<volume_dim> new_element_id{element_id.block_id(),
     210             :                                              element_id.segment_ids(),
     211             :                                              element_id.grid_index() + 1};
     212             :         Parallel::simple_action<CreateChild>(
     213             :             amr_component, element_array, element_id,
     214             :             std::vector<ElementId<volume_dim>>{new_element_id}, 0_st,
     215             :             phase_bookmarks);
     216             :         return;
     217             :       }
     218             : 
     219             :       const auto old_mesh_and_element =
     220             :           std::make_pair(db::get<::domain::Tags::Mesh<volume_dim>>(box),
     221             :                          db::get<::domain::Tags::Element<volume_dim>>(box));
     222             :       const auto& old_mesh = old_mesh_and_element.first;
     223             : 
     224             :       // Determine new neighbors and update the Element
     225             :       const auto& amr_info_of_neighbors =
     226             :           db::get<amr::Tags::NeighborInfo<volume_dim>>(box);
     227             :       auto [new_neighbors, new_neighbor_meshes] =
     228             :           neighbors_of_child(old_mesh_and_element.second, my_amr_info,
     229             :                              amr_info_of_neighbors, element_id);
     230             :       ::Initialization::mutate_assign<
     231             :           tmpl::list<::domain::Tags::Element<volume_dim>,
     232             :                      ::domain::Tags::NeighborMesh<volume_dim>>>(
     233             :           make_not_null(&box),
     234             :           Element<volume_dim>(element_id, std::move(new_neighbors)),
     235             :           std::move(new_neighbor_meshes));
     236             : 
     237             :       // Check for p-refinement
     238             :       if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     239             :             return (flag == amr::Flag::IncreaseResolution or
     240             :                     flag == amr::Flag::DecreaseResolution);
     241             :           })) {
     242             :         db::mutate<::domain::Tags::Mesh<volume_dim>>(
     243             :             [&old_mesh,
     244             :              &my_amr_flags](const gsl::not_null<Mesh<volume_dim>*> mesh) {
     245             :               *mesh = amr::projectors::mesh(old_mesh, my_amr_flags);
     246             :             },
     247             :             make_not_null(&box));
     248             : 
     249             :         if (verbosity >= Verbosity::Debug) {
     250             :           Parallel::printf(
     251             :               "Increasing order of element %s: %s -> %s\n", element_id,
     252             :               old_mesh.extents(),
     253             :               db::get<::domain::Tags::Mesh<volume_dim>>(box).extents());
     254             :         }
     255             :       }
     256             : 
     257             :       // Run the projectors on all elements, even if they did no p-refinement.
     258             :       // This allows projectors to update mutable items that depend upon the
     259             :       // neighbors of the element.
     260             :       tmpl::for_each<amr_projectors>(
     261             :           [&box, &old_mesh_and_element](auto projector_v) {
     262             :             using projector = typename decltype(projector_v)::type;
     263             :             try {
     264             :               db::mutate_apply<projector>(make_not_null(&box),
     265             :                                           old_mesh_and_element);
     266             :             } catch (std::exception& e) {
     267             :               ERROR("Error in AMR projector '"
     268             :                     << pretty_type::get_name<projector>() << "':\n"
     269             :                     << e.what());
     270             :             }
     271             :           });
     272             : 
     273             :       // Reset the AMR flags
     274             :       db::mutate<amr::Tags::Info<volume_dim>,
     275             :                  amr::Tags::NeighborInfo<volume_dim>>(
     276             :           [](const gsl::not_null<amr::Info<volume_dim>*> amr_info,
     277             :              const gsl::not_null<std::unordered_map<ElementId<volume_dim>,
     278             :                                                     amr::Info<volume_dim>>*>
     279             :                  local_amr_info_of_neighbors) {
     280             :             local_amr_info_of_neighbors->clear();
     281             :             for (size_t d = 0; d < volume_dim; ++d) {
     282             :               amr_info->flags[d] = amr::Flag::Undefined;
     283             :             }
     284             :           },
     285             :           make_not_null(&box));
     286             :     }
     287             :   }
     288             : };
     289             : }  // namespace amr::Actions

Generated by: LCOV version 1.14