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