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 <deque> 9 : #include <unordered_map> 10 : #include <utility> 11 : 12 : #include "DataStructures/DataBox/DataBox.hpp" 13 : #include "Domain/Amr/Flag.hpp" 14 : #include "Domain/Amr/Helpers.hpp" 15 : #include "Domain/Amr/Tags/Flags.hpp" 16 : #include "Domain/Structure/Element.hpp" 17 : #include "Domain/Structure/ElementId.hpp" 18 : #include "Domain/Tags.hpp" 19 : #include "Parallel/ElementRegistration.hpp" 20 : #include "Parallel/GlobalCache.hpp" 21 : #include "Parallel/Invoke.hpp" 22 : #include "ParallelAlgorithms/Amr/Actions/InitializeParent.hpp" 23 : #include "Utilities/Algorithm.hpp" 24 : #include "Utilities/TMPL.hpp" 25 : #include "Utilities/TaggedTuple.hpp" 26 : 27 : namespace amr::Actions { 28 : /// \brief Collects data from child elements to send to their parent element 29 : /// during adaptive mesh refinement 30 1 : struct CollectDataFromChildren { 31 : /// \brief This function should be called after the parent element has been 32 : /// created by amr::Actions::CreateParent. 33 : /// 34 : /// \details This function sends a copy of all items corresponding to the 35 : /// mutable_item_creation_tags of `box` of `child_id` to the first sibling in 36 : /// `sibling_ids_to_collect` by invoking this action. Finally, the child 37 : /// element destroys itself. 38 : template <typename ParallelComponent, typename DbTagList, 39 : typename Metavariables> 40 1 : static void apply( 41 : db::DataBox<DbTagList>& box, Parallel::GlobalCache<Metavariables>& cache, 42 : const ElementId<Metavariables::volume_dim>& child_id, 43 : const ElementId<Metavariables::volume_dim>& parent_id, 44 : std::deque<ElementId<Metavariables::volume_dim>> sibling_ids_to_collect) { 45 : std::unordered_map<ElementId<Metavariables::volume_dim>, 46 : tuples::tagged_tuple_from_typelist<typename db::DataBox< 47 : DbTagList>::mutable_item_creation_tags>> 48 : children_data{}; 49 : children_data.emplace( 50 : child_id, 51 : db::copy_items< 52 : typename db::DataBox<DbTagList>::mutable_item_creation_tags>(box)); 53 : const auto next_child_id = sibling_ids_to_collect.front(); 54 : sibling_ids_to_collect.pop_front(); 55 : auto& array_proxy = 56 : Parallel::get_parallel_component<ParallelComponent>(cache); 57 : Parallel::simple_action<CollectDataFromChildren>( 58 : array_proxy[next_child_id], parent_id, sibling_ids_to_collect, 59 : std::move(children_data)); 60 : 61 : Parallel::deregister_element<ParallelComponent>(box, cache, child_id); 62 : array_proxy[child_id].ckDestroy(); 63 : } 64 : 65 : /// \brief This function should be called after a child element has added its 66 : /// data to `children_data` by a previous invocation of this action. 67 : /// 68 : /// \details This function adds a copy of all items corresponding to the 69 : /// mutable_item_creation_tags of `box` of `child_id` to `children_data`. 70 : /// In addition, it checks if there are additional siblings that need to be 71 : /// added to `sibiling_ids_to_collect`. (This is necessary as not all 72 : /// siblings share a face.) If `sibling_ids_to_collect` is not empty, this 73 : /// action is invoked again on the first sibling in `sibling_ids_to_collect`. 74 : /// If it is empty, the data is sent to the parent element by calling 75 : /// amr::Actions::InitializeParent. Finally, the child element destroys 76 : /// itself. 77 : template <typename ParallelComponent, typename DbTagList, 78 : typename Metavariables> 79 1 : static void apply( 80 : db::DataBox<DbTagList>& box, Parallel::GlobalCache<Metavariables>& cache, 81 : const ElementId<Metavariables::volume_dim>& child_id, 82 : const ElementId<Metavariables::volume_dim>& parent_id, 83 : std::deque<ElementId<Metavariables::volume_dim>> sibling_ids_to_collect, 84 : std::unordered_map< 85 : ElementId<Metavariables::volume_dim>, 86 : tuples::tagged_tuple_from_typelist< 87 : typename db::DataBox<DbTagList>::mutable_item_creation_tags>> 88 : children_data) { 89 : constexpr size_t volume_dim = Metavariables::volume_dim; 90 : 91 : // Determine if there are additional siblings that are joining 92 : // This is necessary because AMR flags are only communicated to face 93 : // neighbors. 94 : const auto& element = db::get<::domain::Tags::Element<volume_dim>>(box); 95 : const auto& my_amr_flags = db::get<amr::Tags::Info<volume_dim>>(box).flags; 96 : auto ids_to_join = amr::ids_of_joining_neighbors(element, my_amr_flags); 97 : for (const auto& id_to_check : ids_to_join) { 98 : if (alg::count(sibling_ids_to_collect, id_to_check) == 0 and 99 : children_data.count(id_to_check) == 0) { 100 : sibling_ids_to_collect.emplace_back(id_to_check); 101 : } 102 : } 103 : 104 : children_data.emplace( 105 : child_id, 106 : db::copy_items< 107 : typename db::DataBox<DbTagList>::mutable_item_creation_tags>(box)); 108 : auto& array_proxy = 109 : Parallel::get_parallel_component<ParallelComponent>(cache); 110 : 111 : if (sibling_ids_to_collect.empty()) { 112 : Parallel::simple_action<InitializeParent>(array_proxy[parent_id], 113 : std::move(children_data)); 114 : } else { 115 : const auto next_child_id = sibling_ids_to_collect.front(); 116 : sibling_ids_to_collect.pop_front(); 117 : Parallel::simple_action<CollectDataFromChildren>( 118 : array_proxy[next_child_id], parent_id, sibling_ids_to_collect, 119 : std::move(children_data)); 120 : } 121 : 122 : Parallel::deregister_element<ParallelComponent>(box, cache, child_id); 123 : array_proxy[child_id].ckDestroy(); 124 : } 125 : }; 126 : } // namespace amr::Actions