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/GlobalCache.hpp" 23 : #include "Parallel/Invoke.hpp" 24 : #include "ParallelAlgorithms/Amr/Actions/UpdateAmrDecision.hpp" 25 : #include "ParallelAlgorithms/Amr/Criteria/Criterion.hpp" 26 : #include "ParallelAlgorithms/Amr/Criteria/Tags/Criteria.hpp" 27 : #include "Utilities/ErrorHandling/Error.hpp" 28 : #include "Utilities/Gsl.hpp" 29 : #include "Utilities/MakeArray.hpp" 30 : #include "Utilities/PrettyType.hpp" 31 : #include "Utilities/TMPL.hpp" 32 : 33 : /// \cond 34 : namespace tuples { 35 : template <class... Tags> 36 : class TaggedTuple; 37 : } // namespace tuples 38 : /// \endcond 39 : 40 : namespace detail { 41 : template <typename Criterion> 42 : struct get_tags { 43 : using type = typename Criterion::compute_tags_for_observation_box; 44 : }; 45 : 46 : } // namespace detail 47 : 48 : namespace amr::Actions { 49 : /// \brief Evaluates the refinement criteria in order to set the 50 : /// amr::Flag%s of an Element and sends this information to the 51 : /// neighbors of the Element. 52 : /// 53 : /// DataBox: 54 : /// - Uses: 55 : /// * domain::Tags::Element<volume_dim> 56 : /// * amr::Tags::NeighborFlags<volume_dim> 57 : /// * amr::Criteria::Tags::Criteria (from GlobalCache) 58 : /// * any tags requested by the refinement criteria 59 : /// - Modifies: 60 : /// * amr::Tags::Flags<volume_dim> 61 : /// 62 : /// Invokes: 63 : /// - UpdateAmrDecision on all neighboring Element%s 64 : /// 65 : /// \details 66 : /// - Evaluates each refinement criteria held by amr::Criteria::Tags::Criteria, 67 : /// and in each dimension selects the amr::Flag with the highest 68 : /// priority (i.e the highest integral value). 69 : /// - An Element that is splitting in one dimension is not allowed to join 70 : /// in another dimension. If this is requested by the refinement critiera, 71 : /// the decision to join is changed to do nothing 72 : /// - Checks if any neighbors have sent their AMR decision, and if so, calls 73 : /// amr:::update_amr_decision with the decision of each neighbor in 74 : /// order to see if the current decision needs to be updated 75 : /// - Sends the (possibly updated) decision to all of the neighboring Elements 76 1 : struct EvaluateRefinementCriteria { 77 : template <typename ParallelComponent, typename DbTagList, 78 : typename Metavariables> 79 0 : static void apply(db::DataBox<DbTagList>& box, 80 : Parallel::GlobalCache<Metavariables>& cache, 81 : const ElementId<Metavariables::volume_dim>& element_id) { 82 : constexpr size_t volume_dim = Metavariables::volume_dim; 83 : auto overall_decision = make_array<volume_dim>(amr::Flag::Undefined); 84 : 85 : using compute_tags = tmpl::remove_duplicates<tmpl::filter< 86 : tmpl::flatten<tmpl::transform< 87 : tmpl::at<typename Metavariables::factory_creation::factory_classes, 88 : Criterion>, 89 : detail::get_tags<tmpl::_1>>>, 90 : db::is_compute_tag<tmpl::_1>>>; 91 : auto observation_box = make_observation_box<compute_tags>(box); 92 : 93 : const auto& refinement_criteria = 94 : db::get<amr::Criteria::Tags::Criteria>(box); 95 : for (const auto& criterion : refinement_criteria) { 96 : auto decision = criterion->evaluate(observation_box, cache, element_id); 97 : for (size_t d = 0; d < volume_dim; ++d) { 98 : overall_decision[d] = std::max(overall_decision[d], decision[d]); 99 : } 100 : } 101 : 102 : // An element cannot join if it is splitting in another dimension. 103 : // Update the flags now before sending to neighbors as each time 104 : // a flag is changed by UpdateAmrDecision, it sends the new flags 105 : // to its neighbors. So updating now will save some commmunication. 106 : amr::prevent_element_from_joining_while_splitting( 107 : make_not_null(&overall_decision)); 108 : 109 : // Check if we received any neighbor flags prior to determining our own 110 : // flags. If yes, then possible update our flags (e.g. sibling doesn't want 111 : // to join, maintain 2:1 balance, etc.) 112 : const auto& my_element = get<::domain::Tags::Element<volume_dim>>(box); 113 : const auto& my_neighbors_amr_flags = 114 : get<amr::Tags::NeighborFlags<volume_dim>>(box); 115 : if (not my_neighbors_amr_flags.empty()) { 116 : for (const auto& [neighbor_id, neighbor_amr_flags] : 117 : my_neighbors_amr_flags) { 118 : amr::update_amr_decision(make_not_null(&overall_decision), my_element, 119 : neighbor_id, neighbor_amr_flags); 120 : } 121 : } 122 : 123 : db::mutate<amr::Tags::Flags<Metavariables::volume_dim>>( 124 : make_not_null(&box), 125 : [&overall_decision]( 126 : const gsl::not_null<std::array<amr::Flag, volume_dim>*> amr_flags) { 127 : *amr_flags = overall_decision; 128 : }); 129 : 130 : auto& amr_element_array = 131 : Parallel::get_parallel_component<ParallelComponent>(cache); 132 : 133 : const std::array<amr::Flag, Metavariables::volume_dim>& my_flags = 134 : get<amr::Tags::Flags<volume_dim>>(box); 135 : for (const auto& [direction, neighbors] : my_element.neighbors()) { 136 : (void)direction; 137 : for (const auto& neighbor_id : neighbors.ids()) { 138 : Parallel::simple_action<UpdateAmrDecision>( 139 : amr_element_array[neighbor_id], element_id, my_flags); 140 : } 141 : } 142 : } 143 : }; 144 : } // namespace amr::Actions