SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Amr/Actions - AdjustDomain.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 1 3 33.3 %
Date: 2024-04-23 20:50:18
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/GlobalCache.hpp"
      28             : #include "Parallel/Invoke.hpp"
      29             : #include "Parallel/Phase.hpp"
      30             : #include "Parallel/Printf/Printf.hpp"
      31             : #include "Parallel/Tags/DistributedObjectTags.hpp"
      32             : #include "ParallelAlgorithms/Amr/Actions/CreateChild.hpp"
      33             : #include "ParallelAlgorithms/Amr/Actions/CreateParent.hpp"
      34             : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp"
      35             : #include "ParallelAlgorithms/Amr/Protocols/Projector.hpp"
      36             : #include "ParallelAlgorithms/Amr/Tags.hpp"
      37             : #include "Utilities/Algorithm.hpp"
      38             : #include "Utilities/ErrorHandling/Assert.hpp"
      39             : #include "Utilities/Gsl.hpp"
      40             : #include "Utilities/Literals.hpp"
      41             : #include "Utilities/PrettyType.hpp"
      42             : #include "Utilities/ProtocolHelpers.hpp"
      43             : #include "Utilities/TMPL.hpp"
      44             : 
      45             : namespace amr {
      46             : /// \cond
      47             : template <class Metavariables>
      48             : struct Component;
      49             : /// \endcond
      50             : }  // namespace amr
      51             : 
      52             : namespace detail {
      53             : template <typename ListOfProjectors>
      54             : struct GetMutatedTags;
      55             : 
      56             : template <typename... Projectors>
      57             : struct GetMutatedTags<tmpl::list<Projectors...>> {
      58             :   using type = tmpl::remove_duplicates<
      59             :       tmpl::flatten<tmpl::append<typename Projectors::return_tags...>>>;
      60             : };
      61             : }  // namespace detail
      62             : 
      63             : namespace amr::Actions {
      64             : /// \brief Adjusts the domain given the refinement criteria
      65             : ///
      66             : /// \details
      67             : /// - Checks if an Element wants to split in any dimension; if yes, determines
      68             : ///   the ElementId%s of the new children Element%s and calls
      69             : ///   amr::Actions::CreateChild on the amr::Component, then exits the action.
      70             : /// - Checks if an Element wants to join in any dimension; if yes, either calls
      71             : ///   amr::Actions::CreateParent on the amr::Component if this is the child
      72             : ///   Element that should create the parent Element or does nothing, and then
      73             : ///   exits the action.
      74             : /// - Checks if an Element wants to increase or decrease its resolution, if yes,
      75             : ///   mutates the Mesh
      76             : /// - Updates the Neighbors of the Element
      77             : /// - Resets amr::Tags::Flag%s to amr::Flag::Undefined
      78             : /// - Resets amr::Tags::NeighborInfo to an empty map
      79             : /// - Mutates all return_tags of Metavariables::amr::projectors
      80           1 : struct AdjustDomain {
      81             :   template <typename ParallelComponent, typename DbTagList,
      82             :             typename Metavariables>
      83           0 :   static void apply(db::DataBox<DbTagList>& box,
      84             :                     Parallel::GlobalCache<Metavariables>& cache,
      85             :                     const ElementId<Metavariables::volume_dim>& element_id) {
      86             :     constexpr size_t volume_dim = Metavariables::volume_dim;
      87             :     using amr_projectors = typename Metavariables::amr::projectors;
      88             :     static_assert(
      89             :         tmpl::all<
      90             :             amr_projectors,
      91             :             tt::assert_conforms_to<tmpl::_1, amr::protocols::Projector>>::value,
      92             :         "All AMR projectors must conform to 'amr::protocols::Projector'.");
      93             : 
      94             :     // To prevent bugs when new mutable items are added to a DataBox, we require
      95             :     // that all mutable_item_creation_tags of box are either:
      96             :     // - mutated by one of the projectors in Metavariables::amr::projectors
      97             :     // - in the list of distributed_object_tags
      98             :     // - or in the list of tags mutated by this action
      99             :     using distributed_object_tags =
     100             :         typename ::Parallel::Tags::distributed_object_tags<
     101             :             Metavariables, ElementId<volume_dim>>;
     102             :     using tags_mutated_by_this_action = tmpl::list<
     103             :         ::domain::Tags::Element<volume_dim>, ::domain::Tags::Mesh<volume_dim>,
     104             :         ::domain::Tags::NeighborMesh<volume_dim>, amr::Tags::Info<volume_dim>,
     105             :         amr::Tags::NeighborInfo<volume_dim>>;
     106             :     using mutated_tags =
     107             :         tmpl::append<distributed_object_tags, tags_mutated_by_this_action,
     108             :                      typename detail::GetMutatedTags<amr_projectors>::type>;
     109             :     using mutable_tags =
     110             :         typename db::DataBox<DbTagList>::mutable_item_creation_tags;
     111             :     using mutable_tags_not_mutated =
     112             :         tmpl::list_difference<mutable_tags, mutated_tags>;
     113             :     static_assert(std::is_same_v<mutable_tags_not_mutated, tmpl::list<>>,
     114             :                   "All mutable tags in the DataBox must be explicitly mutated "
     115             :                   "by an amr::projector.  Default initialized objects can use "
     116             :                   "amr::projector::DefaultInitialize.");
     117             : 
     118             :     const auto& my_amr_info = db::get<amr::Tags::Info<volume_dim>>(box);
     119             :     const auto& my_amr_flags = my_amr_info.flags;
     120             :     auto& element_array =
     121             :         Parallel::get_parallel_component<ParallelComponent>(cache);
     122             :     const auto& phase_bookmarks =
     123             :         Parallel::local(element_array[element_id])->phase_bookmarks();
     124             :     const auto& verbosity =
     125             :         db::get<logging::Tags::Verbosity<amr::OptionTags::AmrGroup>>(box);
     126             : 
     127             :     if (alg::all_of(my_amr_flags, [](amr::Flag flag) {
     128             :           return flag == amr::Flag::Undefined;
     129             :         })) {
     130             :       // AMR flags are undefined. This state can be reached when the AMR
     131             :       // component broadcasts the `AdjustDomain` simple action to the entire
     132             :       // element array, then some of those elements run the simple action and
     133             :       // create new child elements, and then the broadcast also arrives at these
     134             :       // new elements for some reason (seems like a Charm++ bug). The AMR flags
     135             :       // will be undefined in this case, so we just ignore the broadcast and
     136             :       // return early here.
     137             :       return;
     138             :     } else if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     139             :                  return flag == amr::Flag::Split;
     140             :                })) {
     141             :       // h-refinement
     142             :       using ::operator<<;
     143             :       ASSERT(alg::count(my_amr_flags, amr::Flag::Join) == 0,
     144             :              "Element " << element_id
     145             :                         << " cannot both split and join, but had AMR flags "
     146             :                         << my_amr_flags << "\n");
     147             :       auto children_ids = amr::ids_of_children(element_id, my_amr_flags);
     148             :       auto& amr_component =
     149             :           Parallel::get_parallel_component<amr::Component<Metavariables>>(
     150             :               cache);
     151             :       if (verbosity >= Verbosity::Debug) {
     152             :         Parallel::printf("Splitting element %s into %zu: %s\n", element_id,
     153             :                          children_ids.size(), children_ids);
     154             :       }
     155             :       Parallel::simple_action<CreateChild>(amr_component, element_array,
     156             :                                            element_id, children_ids, 0_st,
     157             :                                            phase_bookmarks);
     158             : 
     159             :     } else if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     160             :                  return flag == amr::Flag::Join;
     161             :                })) {
     162             :       // h-coarsening
     163             :       // Only one element should create the new parent
     164             :       if (amr::is_child_that_creates_parent(element_id, my_amr_flags)) {
     165             :         auto parent_id = amr::id_of_parent(element_id, my_amr_flags);
     166             :         const auto& element = db::get<::domain::Tags::Element<volume_dim>>(box);
     167             :         auto ids_to_join = amr::ids_of_joining_neighbors(element, my_amr_flags);
     168             :         auto& amr_component =
     169             :             Parallel::get_parallel_component<amr::Component<Metavariables>>(
     170             :                 cache);
     171             :         if (verbosity >= Verbosity::Debug) {
     172             :           Parallel::printf("Joining %zu elements: %s -> %s\n",
     173             :                            ids_to_join.size(), ids_to_join, parent_id);
     174             :         }
     175             :         Parallel::simple_action<CreateParent>(
     176             :             amr_component, element_array, std::move(parent_id), element_id,
     177             :             std::move(ids_to_join), phase_bookmarks);
     178             :       }
     179             : 
     180             :     } else {
     181             :       // Neither h-refinement nor h-coarsening. This element will remain.
     182             :       const auto old_mesh_and_element =
     183             :           std::make_pair(db::get<::domain::Tags::Mesh<volume_dim>>(box),
     184             :                          db::get<::domain::Tags::Element<volume_dim>>(box));
     185             :       const auto& old_mesh = old_mesh_and_element.first;
     186             : 
     187             :       // Determine new neighbors and update the Element
     188             :       {  // avoid shadowing when mutating flags below
     189             :         using NeighborMeshType =
     190             :             DirectionalIdMap<volume_dim, ::Mesh<volume_dim>>;
     191             :         const auto& amr_info_of_neighbors =
     192             :             db::get<amr::Tags::NeighborInfo<volume_dim>>(box);
     193             :         db::mutate<::domain::Tags::Element<volume_dim>,
     194             :                    ::domain::Tags::NeighborMesh<volume_dim>>(
     195             :             [&element_id, &amr_info_of_neighbors](
     196             :                 const gsl::not_null<Element<volume_dim>*> element,
     197             :                 const gsl::not_null<NeighborMeshType*> neighbor_meshes) {
     198             :               auto new_neighbors = element->neighbors();
     199             :               neighbor_meshes->clear();
     200             :               for (auto& [direction, neighbors] : new_neighbors) {
     201             :                 const auto new_neighbor_ids_and_meshes = amr::new_neighbor_ids(
     202             :                     element_id, direction, neighbors, amr_info_of_neighbors);
     203             :                 std::unordered_set<ElementId<volume_dim>> new_neighbor_ids;
     204             :                 for (const auto& [id, mesh] : new_neighbor_ids_and_meshes) {
     205             :                   neighbor_meshes->insert({{direction, id}, mesh});
     206             :                   new_neighbor_ids.insert(id);
     207             :                 }
     208             :                 neighbors.set_ids_to(new_neighbor_ids);
     209             :               }
     210             :               *element =
     211             :                   Element<volume_dim>(element_id, std::move(new_neighbors));
     212             :             },
     213             :             make_not_null(&box));
     214             :       }
     215             : 
     216             :       // Check for p-refinement
     217             :       if (alg::any_of(my_amr_flags, [](amr::Flag flag) {
     218             :             return (flag == amr::Flag::IncreaseResolution or
     219             :                     flag == amr::Flag::DecreaseResolution);
     220             :           })) {
     221             :         db::mutate<::domain::Tags::Mesh<volume_dim>>(
     222             :             [&old_mesh,
     223             :              &my_amr_flags](const gsl::not_null<Mesh<volume_dim>*> mesh) {
     224             :               *mesh = amr::projectors::mesh(old_mesh, my_amr_flags);
     225             :             },
     226             :             make_not_null(&box));
     227             : 
     228             :         if (verbosity >= Verbosity::Debug) {
     229             :           Parallel::printf(
     230             :               "Increasing order of element %s: %s -> %s\n", element_id,
     231             :               old_mesh.extents(),
     232             :               db::get<::domain::Tags::Mesh<volume_dim>>(box).extents());
     233             :         }
     234             :       }
     235             : 
     236             :       // Run the projectors on all elements, even if they did no h-refinement.
     237             :       // This allows projectors to update mutable items that depend upon the
     238             :       // neighbors of the element.
     239             :       tmpl::for_each<amr_projectors>(
     240             :           [&box, &old_mesh_and_element](auto projector_v) {
     241             :             using projector = typename decltype(projector_v)::type;
     242             :             try {
     243             :               db::mutate_apply<projector>(make_not_null(&box),
     244             :                                           old_mesh_and_element);
     245             :             } catch (std::exception& e) {
     246             :               ERROR("Error in AMR projector '"
     247             :                     << pretty_type::get_name<projector>() << "':\n"
     248             :                     << e.what());
     249             :             }
     250             :           });
     251             : 
     252             :       // Reset the AMR flags
     253             :       db::mutate<amr::Tags::Info<volume_dim>,
     254             :                  amr::Tags::NeighborInfo<volume_dim>>(
     255             :           [](const gsl::not_null<amr::Info<volume_dim>*> amr_info,
     256             :              const gsl::not_null<std::unordered_map<ElementId<volume_dim>,
     257             :                                                     amr::Info<volume_dim>>*>
     258             :                  amr_info_of_neighbors) {
     259             :             amr_info_of_neighbors->clear();
     260             :             for (size_t d = 0; d < volume_dim; ++d) {
     261             :               amr_info->flags[d] = amr::Flag::Undefined;
     262             :             }
     263             :           },
     264             :           make_not_null(&box));
     265             :     }
     266             :   }
     267             : };
     268             : }  // namespace amr::Actions

Generated by: LCOV version 1.14