Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <sstream>
7 : #include <string>
8 : #include <unordered_map>
9 : #include <utility>
10 : #include <vector>
11 :
12 : #include "DataStructures/DataBox/DataBox.hpp"
13 : #include "DataStructures/Variables.hpp"
14 : #include "Domain/BlockLogicalCoordinates.hpp"
15 : #include "ParallelAlgorithms/Actions/FunctionsOfTimeAreReady.hpp"
16 : #include "ParallelAlgorithms/Interpolation/InterpolationTargetDetail.hpp"
17 : #include "ParallelAlgorithms/Interpolation/Tags.hpp"
18 : #include "Utilities/Gsl.hpp"
19 : #include "Utilities/TMPL.hpp"
20 :
21 : /// \cond
22 : namespace domain::Tags {
23 : struct FunctionsOfTime;
24 : } // namespace domain::Tags
25 : namespace Parallel {
26 : template <typename Metavariables>
27 : class GlobalCache;
28 : } // namespace Parallel
29 : /// \endcond
30 :
31 : namespace intrp {
32 : namespace Actions {
33 : /// \ingroup ActionsGroup
34 : /// \brief Receives interpolated variables from an `Element` on a subset
35 : /// of the target points.
36 : ///
37 : /// If interpolated variables for all target points have been received, then
38 : /// - Checks if functions of time are ready (if there are any). If they are not
39 : /// ready, register a simple action callback with the GlobalCache to this
40 : /// action.
41 : /// - Calls `InterpolationTargetTag::post_interpolation_callbacks`
42 : /// - Removes the finished `temporal_id` from `Tags::TemporalIds<TemporalId>`
43 : /// and adds it to `Tags::CompletedTemporalIds<TemporalId>`
44 : /// - Removes `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`,
45 : /// `Tags::IndicesOfFilledInterpPoints`, and
46 : /// `Tags::IndicesOfInvalidInterpPoints` for the finished `temporal_id`.
47 : ///
48 : /// Uses:
49 : /// - DataBox:
50 : /// - `Tags::TemporalIds<TemporalId>`
51 : /// - `Tags::IndicesOfFilledInterpPoints<TemporalId>`
52 : /// - `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`
53 : /// - `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`
54 : /// - `::Tags::Variables<typename
55 : /// InterpolationTargetTag::vars_to_interpolate_to_target>`
56 : ///
57 : /// DataBox changes:
58 : /// - Adds: nothing
59 : /// - Removes: nothing
60 : /// - Modifies:
61 : /// - `Tags::TemporalIds<TemporalId>`
62 : /// - `Tags::CompletedTemporalIds<TemporalId>`
63 : /// - `Tags::IndicesOfFilledInterpPoints<TemporalId>`
64 : /// - `Tags::InterpolatedVars<InterpolationTargetTag,TemporalId>`
65 : /// - `::Tags::Variables<typename
66 : /// InterpolationTargetTag::vars_to_interpolate_to_target>`
67 : ///
68 : /// For requirements on InterpolationTargetTag, see InterpolationTarget
69 : /// and intrp::protocols::InterpolationTargetTag
70 : ///
71 : /// \note This action can be used only with InterpolationTargets that are
72 : /// non-sequential.
73 : template <typename InterpolationTargetTag>
74 1 : struct InterpolationTargetVarsFromElement {
75 : /// For requirements on Metavariables, see InterpolationTarget
76 : template <typename ParallelComponent, typename DbTags, typename Metavariables,
77 : typename ArrayIndex, typename TemporalId>
78 1 : static void apply(
79 : db::DataBox<DbTags>& box, Parallel::GlobalCache<Metavariables>& cache,
80 : const ArrayIndex& array_index,
81 : const std::vector<Variables<
82 : typename InterpolationTargetTag::vars_to_interpolate_to_target>>&
83 : vars_src,
84 : const std::vector<BlockLogicalCoords<Metavariables::volume_dim>>&
85 : block_logical_coords,
86 : const std::vector<std::vector<size_t>>& global_offsets,
87 : const TemporalId& temporal_id,
88 : const bool vars_have_already_been_received = false) {
89 : static_assert(
90 : not InterpolationTargetTag::compute_target_points::is_sequential::value,
91 : "Use InterpolationTargetGetVarsFromElement only with non-sequential"
92 : " compute_target_points");
93 : std::stringstream ss{};
94 : const ::Verbosity& verbosity = Parallel::get<intrp::Tags::Verbosity>(cache);
95 : const bool debug_print = verbosity >= ::Verbosity::Debug;
96 : const bool verbose_print = verbosity >= ::Verbosity::Verbose;
97 : if (verbose_print) {
98 : ss << InterpolationTarget_detail::target_output_prefix<
99 : InterpolationTargetVarsFromElement, InterpolationTargetTag>(
100 : temporal_id)
101 : << ", ";
102 : }
103 : // Check if we already have completed interpolation at this
104 : // temporal_id.
105 : const auto& completed_ids =
106 : db::get<Tags::CompletedTemporalIds<TemporalId>>(box);
107 : // (Search from the end because temporal_id is more likely to be
108 : // at the end of the list then at the beginning.)
109 : if (UNLIKELY(std::find(completed_ids.rbegin(), completed_ids.rend(),
110 : temporal_id) != completed_ids.rend())) {
111 : // The code will get into this 'if' statement in the following
112 : // scenario:
113 : // - There is at least one interpolation point exactly on the
114 : // boundary of two or more Elements, so that
115 : // InterpolationTargetVarsFromElement is called more than once
116 : // with data for the same interpolation point (this is ok,
117 : // and add_received_variables handles this).
118 : // - The only Elements that have not yet called
119 : // InterpolationTargetVarsFromElement for this temporal_id are
120 : // those that have data only for duplicated interpolation
121 : // points, and the InterpolationTarget has already received
122 : // that data from other Elements.
123 : // In this case, the InterpolationTarget proceeds to do its
124 : // work because it has all the data it needs. There is now
125 : // one more condition needed for the scenario that gets
126 : // us inside this 'if':
127 : // - The InterpolationTarget has already completed its work at
128 : // this temporal_id, and it has cleaned up its data structures
129 : // for this temporal_id before all of the remaining calls to
130 : // InterpolationTargetVarsFromElement have occurred at this
131 : // temporal_id, and now we are in one of those remaining
132 : // calls.
133 : //
134 : // If this scenario occurs, we just return. This is because the
135 : // InterpolationTarget is done and there is nothing left to do
136 : // at this temporal_id. Note that if there were extra work to
137 : // do at this temporal_id, then CompletedTemporalIds would not
138 : // have an entry for this temporal_id.
139 : return;
140 : }
141 :
142 : // Call set_up_interpolation only if it has not been called for this
143 : // temporal_id.
144 : // If flag_temporal_ids_for_interpolation returns an empty list, then
145 : // flag_temporal_ids_for_interpolation has already been called for the
146 : // same temporal_id (by an invocation of InterpolationTargetVarsFromElement
147 : // by a different Element) and hence set_up_interpolation has already
148 : // been called.
149 : if (InterpolationTarget_detail::flag_temporal_id_for_interpolation<
150 : InterpolationTargetTag>(make_not_null(&box), temporal_id)) {
151 : InterpolationTarget_detail::set_up_interpolation<InterpolationTargetTag>(
152 : make_not_null(&box), temporal_id, block_logical_coords);
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 :
161 : if (InterpolationTarget_detail::have_data_at_all_points<
162 : InterpolationTargetTag>(box, temporal_id, verbosity)) {
163 : // Check if functions of time are ready on this component. Since this
164 : // simple action has already been called, we don't need to resend the
165 : // data, so we just pass empty vectors for vars_src and
166 : // block_logical_coords
167 : if (not domain::functions_of_time_are_ready_simple_action_callback<
168 : domain::Tags::FunctionsOfTime,
169 : InterpolationTargetVarsFromElement>(
170 : cache, array_index,
171 : std::add_pointer_t<ParallelComponent>{nullptr},
172 : InterpolationTarget_detail::get_temporal_id_value(temporal_id),
173 : std::nullopt, std::decay_t<decltype(vars_src)>{},
174 : std::decay_t<decltype(block_logical_coords)>{}, global_offsets,
175 : temporal_id, true)) {
176 : return;
177 : }
178 : // All the valid points have been interpolated.
179 : // We throw away the return value of call_callbacks in this case
180 : // (it is known to be always true; it can be false only for
181 : // sequential interpolations, which is static-asserted against above).
182 : InterpolationTarget_detail::call_callbacks<InterpolationTargetTag>(
183 : make_not_null(&box), make_not_null(&cache), temporal_id);
184 : InterpolationTarget_detail::clean_up_interpolation_target<
185 : InterpolationTargetTag>(make_not_null(&box), temporal_id);
186 : if (verbose_print) {
187 : ss << "calling callbacks and cleaning up target.";
188 : Parallel::printf("%s\n", ss.str());
189 : }
190 : } else if (debug_print) {
191 : ss << "not enough data. Waiting. See Total/valid/invalid points line.";
192 : Parallel::printf("%s\n", ss.str());
193 : }
194 : }
195 : };
196 : } // namespace Actions
197 : } // namespace intrp
|