Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <optional>
8 :
9 : #include "DataStructures/DataBox/DataBox.hpp"
10 : #include "Domain/Creators/Tags/Domain.hpp"
11 : #include "Parallel/AlgorithmExecution.hpp"
12 : #include "Parallel/ArrayCollection/IsDgElementCollection.hpp"
13 : #include "Parallel/GlobalCache.hpp"
14 : #include "Parallel/Info.hpp"
15 : #include "Parallel/Invoke.hpp"
16 : #include "Parallel/Local.hpp"
17 : #include "Parallel/Protocols/ElementRegistrar.hpp"
18 : #include "ParallelAlgorithms/Actions/GetItemFromDistributedObject.hpp"
19 : #include "ParallelAlgorithms/Interpolation/InterpolationTargetDetail.hpp"
20 : #include "ParallelAlgorithms/Interpolation/Tags.hpp"
21 : #include "Utilities/Gsl.hpp"
22 : #include "Utilities/PrettyType.hpp"
23 : #include "Utilities/ProtocolHelpers.hpp"
24 : #include "Utilities/Requires.hpp"
25 : #include "Utilities/StdHelpers.hpp"
26 : #include "Utilities/TMPL.hpp"
27 : #include "Utilities/TaggedTuple.hpp"
28 :
29 : /// \cond
30 : namespace ah::Tags {
31 : struct BlocksForInterpolation;
32 : } // namespace ah::Tags
33 : namespace db {
34 : template <typename TagsList>
35 : class DataBox;
36 : } // namespace db
37 : namespace intrp {
38 : template <typename Metavariables>
39 : struct Interpolator;
40 : } // namespace intrp
41 : /// \endcond
42 :
43 : namespace intrp {
44 : namespace Actions {
45 :
46 : /// \ingroup ActionsGroup
47 : /// \brief Invoked on the `Interpolator` ParallelComponent to register an
48 : /// element with the `Interpolator`.
49 : ///
50 : /// This is called by `RegisterElementWithInterpolator` below.
51 : ///
52 : /// Uses: nothing
53 : ///
54 : /// DataBox changes:
55 : /// - Adds: nothing
56 : /// - Removes: nothing
57 : /// - Modifies:
58 : /// - `Tags::NumberOfElements`
59 : ///
60 : /// For requirements on Metavariables, see `InterpolationTarget`.
61 1 : struct RegisterElement {
62 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
63 : typename ArrayIndex>
64 0 : static void apply(db::DataBox<DbTags>& box,
65 : const Parallel::GlobalCache<Metavariables>& cache,
66 : const ArrayIndex& /*array_index*/,
67 : const ElementId<Metavariables::volume_dim>& element_id) {
68 : using sequential_targets =
69 : intrp::InterpolationTarget_detail::get_sequential_target_tags<
70 : Metavariables>;
71 : const auto& blocks_to_interpolate =
72 : Parallel::get<ah::Tags::BlocksForInterpolation>(cache);
73 : const auto& blocks =
74 : Parallel::get<domain::Tags::Domain<Metavariables::volume_dim>>(cache)
75 : .blocks();
76 : db::mutate<Tags::NumberOfElements<Metavariables::volume_dim>>(
77 : [&](const gsl::not_null<std::unordered_map<
78 : std::string,
79 : std::unordered_set<ElementId<Metavariables::volume_dim>>>*>
80 : num_elements) {
81 : const auto& block_name = blocks[element_id.block_id()].name();
82 :
83 : tmpl::for_each<sequential_targets>([&](auto target_v) {
84 : using target = tmpl::type_from<decltype(target_v)>;
85 : const std::string& target_name = pretty_type::name<target>();
86 : if (not blocks_to_interpolate.contains(target_name)) {
87 : ERROR("Target " << target_name
88 : << " not in blocks to interpolate: "
89 : << keys_of(blocks_to_interpolate));
90 : }
91 :
92 : if (blocks_to_interpolate.at(target_name).contains(block_name)) {
93 : (*num_elements)[target_name].insert(element_id);
94 : }
95 : });
96 : },
97 : make_not_null(&box));
98 : }
99 : };
100 :
101 : /// \ingroup ActionsGroup
102 : /// \brief Invoked on the `Interpolator` ParallelComponent to deregister an
103 : /// element with the `Interpolator`.
104 : ///
105 : /// This is called by `RegisterElementWithInterpolator` below.
106 : ///
107 : /// Uses: nothing
108 : ///
109 : /// DataBox changes:
110 : /// - Adds: nothing
111 : /// - Removes: nothing
112 : /// - Modifies:
113 : /// - `Tags::NumberOfElements`
114 : ///
115 : /// For requirements on Metavariables, see `InterpolationTarget`.
116 1 : struct DeregisterElement {
117 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
118 : typename ArrayIndex>
119 0 : static void apply(db::DataBox<DbTags>& box,
120 : const Parallel::GlobalCache<Metavariables>& cache,
121 : const ArrayIndex& /*array_index*/,
122 : const ElementId<Metavariables::volume_dim>& element_id) {
123 : using sequential_targets =
124 : intrp::InterpolationTarget_detail::get_sequential_target_tags<
125 : Metavariables>;
126 : const auto& blocks_to_interpolate =
127 : Parallel::get<ah::Tags::BlocksForInterpolation>(cache);
128 : const auto& blocks =
129 : Parallel::get<domain::Tags::Domain<Metavariables::volume_dim>>(cache)
130 : .blocks();
131 : db::mutate<Tags::NumberOfElements<Metavariables::volume_dim>>(
132 : [&](const gsl::not_null<std::unordered_map<
133 : std::string,
134 : std::unordered_set<ElementId<Metavariables::volume_dim>>>*>
135 : num_elements) {
136 : const auto& block_name = blocks[element_id.block_id()].name();
137 :
138 : tmpl::for_each<sequential_targets>([&](auto target_v) {
139 : using target = tmpl::type_from<decltype(target_v)>;
140 : const std::string& target_name = pretty_type::name<target>();
141 : if (not blocks_to_interpolate.contains(target_name)) {
142 : ERROR("Target " << target_name
143 : << " not in blocks to interpolate: "
144 : << keys_of(blocks_to_interpolate));
145 : }
146 :
147 : if (blocks_to_interpolate.at(target_name).contains(block_name)) {
148 : const size_t num_elements_removed =
149 : (*num_elements)[target_name].erase(element_id);
150 : if (num_elements_removed == 0) {
151 : ERROR("Unable to remove element "
152 : << element_id << " from interpolator core "
153 : << Parallel::my_proc<size_t>(cache) << " for target "
154 : << target_name);
155 : }
156 : }
157 : });
158 : },
159 : make_not_null(&box));
160 : }
161 : };
162 :
163 : /// \ingroup ActionsGroup
164 : /// \brief Invoked on `DgElementArray` to register all its elements with the
165 : /// `Interpolator`.
166 : ///
167 : /// Uses: nothing
168 : ///
169 : /// DataBox changes:
170 : /// - Adds: nothing
171 : /// - Removes: nothing
172 : /// - Modifies: nothing
173 : ///
174 : /// When this struct is used as an action, the `apply` function will perform the
175 : /// registration with the interpolator. However, this struct also offers the
176 : /// static member functions `perform_registration` and `perform_deregistration`
177 : /// that are needed for either registering when an element is added to a core
178 : /// outside of initialization or deregistering when an element is being
179 : /// eliminated from a core. The use of separate functions is necessary to
180 : /// provide an interface usable outside of iterable actions, e.g. in specialized
181 : /// `pup` functions.
182 1 : struct RegisterElementWithInterpolator
183 : : tt::ConformsTo<Parallel::protocols::ElementRegistrar> {
184 : private:
185 : template <typename ParallelComponent, typename RegisterOrDeregisterAction,
186 : typename Metavariables, typename ArrayIndex>
187 0 : static void register_or_deregister_impl(
188 : Parallel::GlobalCache<Metavariables>& cache,
189 : const ArrayIndex& array_index) {
190 : if constexpr (Parallel::is_dg_element_collection_v<ParallelComponent>) {
191 : const auto core_id = static_cast<int>(
192 : Parallel::local_synchronous_action<
193 : Parallel::Actions::GetItemFromDistributedOject<
194 : typename ParallelComponent::element_collection_tag>>(
195 : Parallel::get_parallel_component<ParallelComponent>(cache))
196 : ->at(array_index)
197 : .get_core());
198 : auto interpolator = Parallel::get_parallel_component<
199 : ::intrp::Interpolator<Metavariables>>(cache)[core_id];
200 : Parallel::simple_action<RegisterOrDeregisterAction>(interpolator,
201 : array_index);
202 : } else {
203 : auto& interpolator =
204 : *Parallel::local_branch(Parallel::get_parallel_component<
205 : ::intrp::Interpolator<Metavariables>>(cache));
206 : Parallel::simple_action<RegisterOrDeregisterAction>(interpolator,
207 : array_index);
208 : }
209 : }
210 :
211 : public: // ElementRegistrar protocol
212 : template <typename ParallelComponent, typename DbTagList,
213 : typename Metavariables, typename ArrayIndex>
214 0 : static void perform_registration(const db::DataBox<DbTagList>& /*box*/,
215 : Parallel::GlobalCache<Metavariables>& cache,
216 : const ArrayIndex& array_index) {
217 : register_or_deregister_impl<ParallelComponent, RegisterElement>(
218 : cache, array_index);
219 : }
220 :
221 : template <typename ParallelComponent, typename DbTagList,
222 : typename Metavariables, typename ArrayIndex>
223 0 : static void perform_deregistration(
224 : const db::DataBox<DbTagList>& /*box*/,
225 : Parallel::GlobalCache<Metavariables>& cache,
226 : const ArrayIndex& array_index) {
227 : register_or_deregister_impl<ParallelComponent, DeregisterElement>(
228 : cache, array_index);
229 : }
230 :
231 : public: // Iterable action
232 : template <typename DbTagList, typename... InboxTags, typename Metavariables,
233 : typename ArrayIndex, typename ActionList,
234 : typename ParallelComponent>
235 0 : static Parallel::iterable_action_return_t apply(
236 : db::DataBox<DbTagList>& box,
237 : const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
238 : Parallel::GlobalCache<Metavariables>& cache,
239 : const ArrayIndex& array_index, const ActionList /*meta*/,
240 : const ParallelComponent* const /*meta*/) {
241 : perform_registration<ParallelComponent>(box, cache, array_index);
242 : return {Parallel::AlgorithmExecution::Continue, std::nullopt};
243 : }
244 : };
245 :
246 : } // namespace Actions
247 : } // namespace intrp
|