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 <unordered_map> 10 : 11 : #include "DataStructures/DataBox/DataBox.hpp" 12 : #include "Domain/Amr/Flag.hpp" 13 : #include "Domain/Amr/Tags/Flags.hpp" 14 : #include "Domain/Amr/Tags/NeighborFlags.hpp" 15 : #include "Domain/Amr/UpdateAmrDecision.hpp" 16 : #include "Domain/Structure/Element.hpp" 17 : #include "Domain/Structure/ElementId.hpp" 18 : #include "Domain/Structure/Neighbors.hpp" 19 : #include "Domain/Tags.hpp" 20 : #include "Parallel/GlobalCache.hpp" 21 : #include "Parallel/Invoke.hpp" 22 : #include "ParallelAlgorithms/Amr/Projectors/Mesh.hpp" 23 : #include "Utilities/Algorithm.hpp" 24 : #include "Utilities/ErrorHandling/Error.hpp" 25 : #include "Utilities/Gsl.hpp" 26 : #include "Utilities/PrettyType.hpp" 27 : #include "Utilities/TMPL.hpp" 28 : 29 : namespace amr::Actions { 30 : /// \brief Given the AMR decision of a neighboring Element, potentially update 31 : /// the AMR decision of the target Element. 32 : /// 33 : /// DataBox: 34 : /// - Uses: 35 : /// * domain::Tags::Element<volume_dim> 36 : /// - Modifies: 37 : /// * amr::Tags::NeighborInfo 38 : /// * amr::Tags::Info (if AMR decision is updated) 39 : /// 40 : /// Invokes: 41 : /// - amr::Actions::UpdateAmrDecision on all neighboring Element%s (if AMR 42 : /// decision is updated) 43 : /// 44 : /// \details This Element calls amr::update_amr_decision to see if its 45 : /// AMR decision needs to be updated. If it does, the Element will call 46 : /// amr::Actions::UpdateAmrDecision on its neighbors. 47 : /// 48 1 : struct UpdateAmrDecision { 49 : template <typename ParallelComponent, typename DbTagList, 50 : typename Metavariables> 51 0 : static void apply(db::DataBox<DbTagList>& box, 52 : Parallel::GlobalCache<Metavariables>& cache, 53 : const ElementId<Metavariables::volume_dim>& /*element_id*/, 54 : const ElementId<Metavariables::volume_dim>& neighbor_id, 55 : const Info<Metavariables::volume_dim>& neighbor_amr_info) { 56 : constexpr size_t volume_dim = Metavariables::volume_dim; 57 : auto& my_amr_info = db::get_mutable_reference<amr::Tags::Info<volume_dim>>( 58 : make_not_null(&box)); 59 : auto& my_neighbors_amr_info = 60 : db::get_mutable_reference<amr::Tags::NeighborInfo<volume_dim>>( 61 : make_not_null(&box)); 62 : 63 : // Actions can be executed in any order. Therefore we need to check: 64 : // - If we received info from a neighbor multiple times, but not in the 65 : // order they were sent. Neighbor info should only be sent again if 66 : // the flags have changed to a higher priority (i.e. higher integral value 67 : // of the flag) or the new mesh has a larger number of grid points. 68 : if (1 == my_neighbors_amr_info.count(neighbor_id)) { 69 : const auto& previously_received_info = 70 : my_neighbors_amr_info.at(neighbor_id); 71 : if (previously_received_info.new_mesh.number_of_grid_points() >= 72 : neighbor_amr_info.new_mesh.number_of_grid_points() and 73 : not std::lexicographical_compare( 74 : previously_received_info.flags.begin(), 75 : previously_received_info.flags.end(), 76 : neighbor_amr_info.flags.begin(), neighbor_amr_info.flags.end())) { 77 : return; 78 : } 79 : } 80 : 81 : my_neighbors_amr_info.insert_or_assign(neighbor_id, neighbor_amr_info); 82 : 83 : auto& my_amr_flags = my_amr_info.flags; 84 : // Actions can be executed in any order. Therefore we need to check: 85 : // - If we have evaluated our own AMR decision. If not, return. 86 : if (amr::Flag::Undefined == my_amr_flags[0]) { 87 : using ::operator<<; 88 : ASSERT(volume_dim == alg::count(my_amr_flags, amr::Flag::Undefined), 89 : "Flags should be all Undefined, not " << my_amr_flags); 90 : return; 91 : } 92 : 93 : const auto& element = get<::domain::Tags::Element<volume_dim>>(box); 94 : const auto my_initial_new_mesh = my_amr_info.new_mesh; 95 : 96 : const bool my_amr_decision_changed = 97 : amr::update_amr_decision(make_not_null(&my_amr_flags), element, 98 : neighbor_id, neighbor_amr_info.flags); 99 : 100 : auto& my_new_mesh = my_amr_info.new_mesh; 101 : my_new_mesh = 102 : amr::projectors::new_mesh(get<::domain::Tags::Mesh<volume_dim>>(box), 103 : my_amr_flags, element, my_neighbors_amr_info); 104 : 105 : if (my_amr_decision_changed or my_new_mesh != my_initial_new_mesh) { 106 : auto& amr_element_array = 107 : Parallel::get_parallel_component<ParallelComponent>(cache); 108 : for (const auto& direction_neighbors : element.neighbors()) { 109 : for (const auto& id : direction_neighbors.second.ids()) { 110 : Parallel::simple_action<UpdateAmrDecision>(amr_element_array[id], 111 : element.id(), my_amr_info); 112 : } 113 : } 114 : } 115 : } 116 : }; 117 : } // namespace amr::Actions