SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Amr/Actions - EvaluateRefinementCriteria.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 33.3 % 3 1
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 <algorithm>
       7              : #include <array>
       8              : #include <cstddef>
       9              : #include <tuple>
      10              : #include <utility>
      11              : 
      12              : #include "DataStructures/DataBox/DataBox.hpp"
      13              : #include "DataStructures/DataBox/ObservationBox.hpp"
      14              : #include "DataStructures/DataBox/TagTraits.hpp"
      15              : #include "Domain/Amr/Flag.hpp"
      16              : #include "Domain/Amr/Helpers.hpp"
      17              : #include "Domain/Amr/Tags/Flags.hpp"
      18              : #include "Domain/Structure/Element.hpp"
      19              : #include "Domain/Structure/ElementId.hpp"
      20              : #include "Domain/Structure/Neighbors.hpp"
      21              : #include "Domain/Tags.hpp"
      22              : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
      23              : #include "Parallel/ArrayCollection/SimpleActionOnElement.hpp"
      24              : #include "Parallel/GlobalCache.hpp"
      25              : #include "Parallel/Invoke.hpp"
      26              : #include "Parallel/Tags/Section.hpp"
      27              : #include "ParallelAlgorithms/Actions/GetItemFromDistributedObject.hpp"
      28              : #include "ParallelAlgorithms/Amr/Actions/UpdateAmrDecision.hpp"
      29              : #include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp"
      30              : #include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp"
      31              : #include "ParallelAlgorithms/Amr/Policies/EnforcePolicies.hpp"
      32              : #include "ParallelAlgorithms/Amr/Policies/Policies.hpp"
      33              : #include "ParallelAlgorithms/Amr/Policies/Tags.hpp"
      34              : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp"
      35              : #include "ParallelAlgorithms/Amr/Tags.hpp"
      36              : #include "Utilities/ErrorHandling/Assert.hpp"
      37              : #include "Utilities/ErrorHandling/Error.hpp"
      38              : #include "Utilities/Gsl.hpp"
      39              : #include "Utilities/MakeArray.hpp"
      40              : #include "Utilities/PrettyType.hpp"
      41              : #include "Utilities/TMPL.hpp"
      42              : 
      43              : /// \cond
      44              : namespace tuples {
      45              : template <class... Tags>
      46              : class TaggedTuple;
      47              : }  // namespace tuples
      48              : /// \endcond
      49              : 
      50              : namespace detail {
      51              : template <typename Criterion>
      52              : struct get_tags {
      53              :   using type = typename Criterion::compute_tags_for_observation_box;
      54              : };
      55              : 
      56              : }  // namespace detail
      57              : 
      58              : namespace amr::Actions {
      59              : /// \brief Evaluates the refinement criteria in order to set the amr::Info of an
      60              : /// Element and sends this information to the neighbors of the Element.
      61              : ///
      62              : /// DataBox:
      63              : /// - Uses:
      64              : ///   * domain::Tags::Element<volume_dim>
      65              : ///   * amr::Tags::NeighborInfo<volume_dim>
      66              : ///   * amr::Criteria::Tags::Criteria (from GlobalCache)
      67              : ///   * amr::Tags::Policies (from GlobalCache)
      68              : ///   * any tags requested by the refinement criteria
      69              : /// - Modifies:
      70              : ///   * amr::Tags::Info<volume_dim>
      71              : ///
      72              : /// Invokes:
      73              : /// - UpdateAmrDecision on all neighboring Element%s
      74              : ///
      75              : /// \details
      76              : /// - Evaluates each refinement criteria held by amr::Criteria::Tags::Criteria,
      77              : ///   and in each dimension selects the amr::Flag with the highest
      78              : ///   priority (i.e the highest integral value).  If
      79              : ///   Metavariables::amr::p_refine_only_in_event is true, only h-refinement
      80              : ///   criteria will be evaluated
      81              : /// - If necessary, changes the refinement decision in order to satisfy the
      82              : ///   amr::Policies
      83              : /// - An Element that is splitting in one dimension is not allowed to join
      84              : ///   in another dimension.  If this is requested by the refinement critiera,
      85              : ///   the decision to join is changed to do nothing
      86              : /// - Checks if any neighbors have sent their AMR decision, and if so, calls
      87              : ///   amr:::update_amr_decision with the decision of each neighbor in
      88              : ///   order to see if the current decision needs to be updated
      89              : /// - Sends the (possibly updated) decision to all of the neighboring Elements
      90            1 : struct EvaluateRefinementCriteria {
      91              :   template <typename ParallelComponent, typename DbTagList,
      92              :             typename Metavariables, size_t Dim>
      93            0 :   static void apply(db::DataBox<DbTagList>& box,
      94              :                     Parallel::GlobalCache<Metavariables>& cache,
      95              :                     const ElementId<Dim>& element_id) {
      96              :     if constexpr (Metavariables::amr::keep_coarse_grids) {
      97              :       // Only evaluate the criteria on the finest grid. The other elements keep
      98              :       // their flags as Undefined and will therefore be skipped by AdjustDomain.
      99              :       const bool is_finest_grid =
     100              :           db::get<amr::Tags::ChildIds<Dim>>(box).empty();
     101              :       if (not is_finest_grid) {
     102              :         return;
     103              :       }
     104              :     }
     105              : 
     106              :     constexpr size_t volume_dim = Metavariables::volume_dim;
     107              :     auto overall_decision = make_array<volume_dim>(amr::Flag::Undefined);
     108              : 
     109              :     // Evaluate criteria on blocks that have AMR enabled, and "do nothing" on
     110              :     // the other blocks.
     111              :     // Note that blocks that do not have AMR enabled can still be refined to
     112              :     // satisfy 2:1 balance. When this happens, they won't coarsen back since "do
     113              :     // nothing" has higher priority than coarsening. This behavior can be
     114              :     // changed if needed.
     115              :     const auto& amr_blocks = db::get<amr::Tags::AmrBlocks<volume_dim>>(box);
     116              :     if (not amr_blocks.has_value() or
     117              :         alg::found(amr_blocks.value(), element_id.block_id())) {
     118              :       using compute_tags =
     119              :           tmpl::remove_duplicates<tmpl::flatten<tmpl::transform<
     120              :               tmpl::at<
     121              :                   typename Metavariables::factory_creation::factory_classes,
     122              :                   Criterion>,
     123              :               detail::get_tags<tmpl::_1>>>>;
     124              :       auto observation_box =
     125              :           make_observation_box<compute_tags>(make_not_null(&box));
     126              : 
     127              :       const auto& refinement_criteria =
     128              :           db::get<amr::Criteria::Tags::Criteria>(box);
     129              :       for (const auto& criterion : refinement_criteria) {
     130              :         const auto refinement_type = criterion->type();
     131              :         if (Metavariables::amr::p_refine_only_in_event and
     132              :             refinement_type == amr::Criteria::Type::p) {
     133              :           continue;
     134              :         }
     135              :         auto decision = criterion->evaluate(observation_box, cache, element_id);
     136              :         if constexpr (Metavariables::amr::p_refine_only_in_event) {
     137              :           ASSERT(alg::none_of(decision,
     138              :                               [](amr::Flag flag) {
     139              :                                 return flag == amr::Flag::IncreaseResolution or
     140              :                                        flag == amr::Flag::DecreaseResolution;
     141              :                               }),
     142              :                  "The criterion '"
     143              :                      << typeid(*criterion).name()
     144              :                      << "' requested p-refinement, but claims to be "
     145              :                         "for h-refinement.");
     146              :         }
     147              : 
     148              :         // Enforce restrictions from the topologies of the Element
     149              :         const auto& topologies =
     150              :             db::get<domain::Tags::Element<Dim>>(box).topologies();
     151              :         if (refinement_type == amr::Criteria::Type::p) {
     152              :           enforce_p_refinement_topology_restrictions(make_not_null(&decision),
     153              :                                                      topologies);
     154              :         } else if (refinement_type == amr::Criteria::Type::h) {
     155              :           enforce_h_refinement_topology_restrictions(make_not_null(&decision),
     156              :                                                      topologies);
     157              :         } else {
     158              :           ERROR("Bad refinement type " << refinement_type);
     159              :         }
     160              :         for (size_t d = 0; d < volume_dim; ++d) {
     161              :           overall_decision[d] = std::max(overall_decision[d], decision[d]);
     162              :         }
     163              :       }
     164              :     }  // amr_blocks.contains(element_id.block_id())
     165              : 
     166              :     // If no refinement criteria were called, then set flag to do nothing
     167              :     for (size_t d = 0; d < volume_dim; ++d) {
     168              :       if (overall_decision[d] == amr::Flag::Undefined) {
     169              :         overall_decision[d] = amr::Flag::DoNothing;
     170              :       }
     171              :     }
     172              : 
     173              :     const auto& policies = db::get<amr::Tags::Policies>(box);
     174              :     amr::enforce_policies(make_not_null(&overall_decision), policies,
     175              :                           element_id,
     176              :                           get<::domain::Tags::Mesh<volume_dim>>(box));
     177              : 
     178              :     // An element cannot join if it is splitting in another dimension.
     179              :     // Update the flags now before sending to neighbors as each time
     180              :     // a flag is changed by UpdateAmrDecision, it sends the new flags
     181              :     // to its neighbors.  So updating now will save some commmunication.
     182              :     amr::prevent_element_from_joining_while_splitting(
     183              :         make_not_null(&overall_decision));
     184              : 
     185              :     // Check if we received any neighbor flags prior to determining our own
     186              :     // flags.  If yes, then possible update our flags (e.g. sibling doesn't want
     187              :     // to join, maintain 2:1 balance, etc.)
     188              :     const auto& my_element = get<::domain::Tags::Element<volume_dim>>(box);
     189              :     const auto& my_neighbors_amr_info =
     190              :         get<amr::Tags::NeighborInfo<volume_dim>>(box);
     191              :     if (not my_neighbors_amr_info.empty()) {
     192              :       for (const auto& [neighbor_id, neighbor_amr_info] :
     193              :            my_neighbors_amr_info) {
     194              :         amr::update_amr_decision(
     195              :             make_not_null(&overall_decision), my_element, neighbor_id,
     196              :             neighbor_amr_info.flags,
     197              :             policies.enforce_two_to_one_balance_in_normal_direction());
     198              :       }
     199              :     }
     200              : 
     201              :     const auto new_mesh = amr::projectors::new_mesh_to_communicate_to_neighbors(
     202              :         get<::domain::Tags::Mesh<volume_dim>>(box), overall_decision,
     203              :         my_element, my_neighbors_amr_info);
     204              : 
     205              :     db::mutate<amr::Tags::Info<Metavariables::volume_dim>>(
     206              :         [&overall_decision,
     207              :          &new_mesh](const gsl::not_null<amr::Info<volume_dim>*> amr_info) {
     208              :           amr_info->flags = overall_decision;
     209              :           amr_info->new_mesh = new_mesh;
     210              :         },
     211              :         make_not_null(&box));
     212              : 
     213              :     auto& amr_element_array =
     214              :         Parallel::get_parallel_component<ParallelComponent>(cache);
     215              : 
     216              :     const amr::Info<Metavariables::volume_dim>& my_info =
     217              :         get<amr::Tags::Info<volume_dim>>(box);
     218              :     for (const auto& [direction, neighbors] : my_element.neighbors()) {
     219              :       (void)direction;
     220              :       for (const auto& neighbor_id : neighbors.ids()) {
     221              :         if constexpr (Parallel::is_dg_element_collection_v<ParallelComponent>) {
     222              :           const auto neighbor_location = static_cast<int>(
     223              :               Parallel::local_synchronous_action<
     224              :                   Parallel::Actions::GetItemFromDistributedOject<
     225              :                       Parallel::Tags::ElementLocations<volume_dim>>>(
     226              :                   Parallel::get_parallel_component<ParallelComponent>(cache))
     227              :                   ->at(neighbor_id));
     228              :           Parallel::threaded_action<Parallel::Actions::SimpleActionOnElement<
     229              :               UpdateAmrDecision, true>>(amr_element_array[neighbor_location],
     230              :                                         neighbor_id, element_id, my_info);
     231              :         } else {
     232              :           Parallel::simple_action<UpdateAmrDecision>(
     233              :               amr_element_array[neighbor_id], element_id, my_info);
     234              :         }
     235              :       }
     236              :     }
     237              :   }
     238              : };
     239              : }  // namespace amr::Actions
        

Generated by: LCOV version 2.0-1