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