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 <memory>
8 : #include <optional>
9 : #include <sstream>
10 : #include <string>
11 : #include <type_traits>
12 : #include <unordered_set>
13 : #include <utility>
14 : #include <vector>
15 :
16 : #include "DataStructures/DataBox/DataBox.hpp"
17 : #include "DataStructures/LinkedMessageId.hpp"
18 : #include "DataStructures/VariablesTag.hpp"
19 : #include "IO/Logging/Verbosity.hpp"
20 : #include "Parallel/GlobalCache.hpp"
21 : #include "Parallel/Invoke.hpp"
22 : #include "Parallel/Printf/Printf.hpp"
23 : #include "ParallelAlgorithms/Actions/FunctionsOfTimeAreReady.hpp"
24 : #include "ParallelAlgorithms/Interpolation/Actions/SendPointsToInterpolator.hpp"
25 : #include "ParallelAlgorithms/Interpolation/Actions/VerifyTemporalIdsAndSendPoints.hpp"
26 : #include "ParallelAlgorithms/Interpolation/InterpolationTargetDetail.hpp"
27 : #include "ParallelAlgorithms/Interpolation/Tags.hpp"
28 : #include "Utilities/Gsl.hpp"
29 : #include "Utilities/Literals.hpp"
30 : #include "Utilities/PrettyType.hpp"
31 : #include "Utilities/Requires.hpp"
32 : #include "Utilities/TMPL.hpp"
33 : #include "Utilities/TaggedTuple.hpp"
34 : #include "Utilities/TypeTraits.hpp"
35 :
36 : /// \cond
37 : namespace domain::Tags {
38 : struct FunctionsOfTime;
39 : } // namespace domain::Tags
40 : namespace intrp::Tags {
41 : template <typename TemporalId>
42 : struct CompletedTemporalIds;
43 : template <typename TemporalId>
44 : struct PendingTemporalIds;
45 : template <typename TemporalId>
46 : struct TemporalIds;
47 : } // namespace intrp::Tags
48 : template <typename TagsList>
49 : struct Variables;
50 : /// \endcond
51 :
52 : namespace intrp::Actions {
53 : /// \ingroup ActionsGroup
54 : /// \brief Receives interpolated variables from an `Interpolator` on a subset
55 : /// of the target points.
56 : ///
57 : /// If interpolated variables for all target points have been received, then
58 : /// - Checks if functions of time are ready (if there are any). If they are not
59 : /// ready, register a simple action callback with the GlobalCache to this
60 : /// action.
61 : /// - Calls `InterpolationTargetTag::post_interpolation_callbacks`
62 : /// - Tells `Interpolator`s that the interpolation is complete
63 : /// (by calling
64 : /// `Actions::CleanUpInterpolator<InterpolationTargetTag>`)
65 : /// - Removes the current id from `Tags::CurrentTemporalId<TemporalId>`
66 : /// - If there are more `temporal_id`s, begins interpolation at the next
67 : /// `temporal_id` (by calling `Actions::VerifyTemporalIdsAndSendPoints`)
68 : ///
69 : /// Uses:
70 : /// - DataBox:
71 : /// - `Tags::CurrentTemporalId<TemporalId>`
72 : /// - `Tags::IndicesOfFilledInterpPoints<TemporalId>`
73 : /// - `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`
74 : ///
75 : /// DataBox changes:
76 : /// - Adds: nothing
77 : /// - Removes: nothing
78 : /// - Modifies:
79 : /// - `Tags::CurrentTemporalId<TemporalId>`
80 : /// - `Tags::CompletedTemporalIds<TemporalId>`
81 : /// - `Tags::IndicesOfFilledInterpPoints<TemporalId>`
82 : /// - `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`
83 : /// - `::Tags::Variables<typename
84 : /// InterpolationTargetTag::vars_to_interpolate_to_target>`
85 : ///
86 : /// For requirements on InterpolationTargetTag, see InterpolationTarget
87 : template <typename InterpolationTargetTag>
88 1 : struct InterpolationTargetReceiveVars {
89 : static_assert(
90 : InterpolationTargetTag::compute_target_points::is_sequential::value,
91 : "Actions::InterpolationTargetReceiveVars can be used only with "
92 : "sequential targets.");
93 : /// For requirements on Metavariables, see InterpolationTarget
94 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
95 : typename ArrayIndex, typename TemporalId>
96 1 : static void apply(
97 : db::DataBox<DbTags>& box, Parallel::GlobalCache<Metavariables>& cache,
98 : const ArrayIndex& array_index,
99 : const std::vector<Variables<
100 : typename InterpolationTargetTag::vars_to_interpolate_to_target>>&
101 : vars_src,
102 : const std::vector<std::vector<size_t>>& global_offsets,
103 : const TemporalId& temporal_id,
104 : const bool vars_have_already_been_received = false) {
105 : // Check if we already have completed interpolation at this
106 : // temporal_id.
107 : const auto& completed_ids =
108 : db::get<Tags::CompletedTemporalIds<TemporalId>>(box);
109 : std::stringstream ss{};
110 : const ::Verbosity& verbosity = Parallel::get<intrp::Tags::Verbosity>(cache);
111 : const bool debug_print = verbosity >= ::Verbosity::Debug;
112 : const bool verbose_print = verbosity >= ::Verbosity::Verbose;
113 : if (verbose_print) {
114 : ss << InterpolationTarget_detail::target_output_prefix<
115 : InterpolationTargetReceiveVars, InterpolationTargetTag>(
116 : temporal_id)
117 : << ", ";
118 : }
119 :
120 : // (Search from the end because temporal_id is more likely to be
121 : // at the end of the list then at the beginning.)
122 : if (UNLIKELY(std::find(completed_ids.rbegin(), completed_ids.rend(),
123 : temporal_id) != completed_ids.rend())) {
124 : // The code will get into this 'if' statement in the following
125 : // scenario:
126 : // - There is at least one interpolation point exactly on the
127 : // boundary of two or more Elements, so that
128 : // InterpolationTargetReceiveVars is called more than once
129 : // with data for the same interpolation point (this is ok,
130 : // and add_received_variables handles this).
131 : // - The only Interpolator elements that have not yet called
132 : // InterpolationTargetReceiveVars for this temporal_id are
133 : // those that have data only for duplicated interpolation
134 : // points, and the InterpolationTarget has already received
135 : // that data from other Interpolator elements.
136 : // In this case, the InterpolationTarget proceeds to do its
137 : // work because it has all the data it needs. There is now
138 : // one more condition needed for the scenario that gets
139 : // us inside this 'if':
140 : // - The InterpolationTarget has already completed its work at
141 : // this temporal_id, and it has cleaned up its data structures
142 : // for this temporal_id before all of the remaining calls to
143 : // InterpolationTargetReceiveVars have occurred at this
144 : // temporal_id, and now we are in one of those remaining
145 : // calls.
146 : //
147 : // If this scenario occurs, we just return. This is because the
148 : // InterpolationTarget is done and there is nothing left to do
149 : // at this temporal_id. Note that if there were extra work to
150 : // do at this temporal_id, then CompletedTemporalIds would not
151 : // have an entry for this temporal_id.
152 : return;
153 : }
154 :
155 : if (not vars_have_already_been_received) {
156 : InterpolationTarget_detail::add_received_variables<
157 : InterpolationTargetTag>(make_not_null(&box), vars_src, global_offsets,
158 : temporal_id);
159 : }
160 : if (InterpolationTarget_detail::have_data_at_all_points<
161 : InterpolationTargetTag>(box, temporal_id, verbosity)) {
162 : if (verbose_print) {
163 : ss << "calling callbacks ";
164 : }
165 : // All the valid points have been interpolated.
166 :
167 : // Check if functions of time are ready on this component. Since this
168 : // simple action has already been called, we don't need to resend the
169 : // data, so we just pass empty vectors for vars_src and global_offsets
170 : if (not domain::functions_of_time_are_ready_simple_action_callback<
171 : domain::Tags::FunctionsOfTime, InterpolationTargetReceiveVars>(
172 : cache, array_index,
173 : std::add_pointer_t<ParallelComponent>{nullptr},
174 : InterpolationTarget_detail::get_temporal_id_value(temporal_id),
175 : std::nullopt, std::decay_t<decltype(vars_src)>{},
176 : std::decay_t<decltype(global_offsets)>{}, temporal_id, true)) {
177 : return;
178 : }
179 :
180 : if (InterpolationTarget_detail::call_callbacks<InterpolationTargetTag>(
181 : make_not_null(&box), make_not_null(&cache), temporal_id)) {
182 : if (verbose_print) {
183 : ss << "and cleaning up target.";
184 : }
185 : InterpolationTarget_detail::clean_up_interpolation_target<
186 : InterpolationTargetTag>(make_not_null(&box), temporal_id);
187 : auto& interpolator_proxy =
188 : Parallel::get_parallel_component<Interpolator<Metavariables>>(
189 : cache);
190 : Parallel::simple_action<
191 : Actions::CleanUpInterpolator<InterpolationTargetTag>>(
192 : interpolator_proxy, temporal_id);
193 :
194 : // If there are further pending_temporal_ids, begin interpolation for
195 : // the next one.
196 : const auto& current_id =
197 : db::get<Tags::CurrentTemporalId<TemporalId>>(box);
198 : using ::operator<<;
199 : ASSERT(not current_id.has_value(),
200 : "After a serial interpolation (horizon find) is finished, the "
201 : "current temporal id shouldn't have a value, but it does "
202 : << current_id.value());
203 : if (not db::get<Tags::PendingTemporalIds<TemporalId>>(box).empty()) {
204 : if (verbose_print) {
205 : using ::operator<<;
206 : ss << " Verifying next pending temporal id out of "
207 : << db::get<Tags::PendingTemporalIds<TemporalId>>(box).empty();
208 : }
209 : // Call directly
210 : Actions::VerifyTemporalIdsAndSendPoints<InterpolationTargetTag>::
211 : template apply<ParallelComponent>(box, cache, array_index);
212 : } else if (verbose_print) {
213 : ss << " No pending temporal ids to verify.";
214 : }
215 :
216 : if (verbose_print) {
217 : Parallel::printf("%s\n", ss.str());
218 : }
219 : } else if (debug_print) {
220 : ss << "and NOT cleaning up target.";
221 : Parallel::printf("%s\n", ss.str());
222 : }
223 : } else if (debug_print) {
224 : ss << "not enough data. Waiting. See Total/valid/invalid points line.";
225 : Parallel::printf("%s\n", ss.str());
226 : }
227 : }
228 : };
229 : } // namespace intrp::Actions
|