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 "DataStructures/TaggedTuple.hpp"
14 : #include "Domain/Amr/Flag.hpp"
15 : #include "Domain/Amr/Helpers.hpp"
16 : #include "Domain/Amr/Tags/Flags.hpp"
17 : #include "Domain/Structure/Element.hpp"
18 : #include "Domain/Structure/ElementId.hpp"
19 : #include "Domain/Tags.hpp"
20 : #include "Parallel/ElementRegistration.hpp"
21 : #include "Parallel/GlobalCache.hpp"
22 : #include "Parallel/Invoke.hpp"
23 : #include "ParallelAlgorithms/Amr/Actions/InitializeParent.hpp"
24 : #include "Utilities/Algorithm.hpp"
25 : #include "Utilities/TMPL.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
|