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 : #include <utility> 9 : #include <vector> 10 : 11 : #include "DataStructures/DataBox/DataBox.hpp" 12 : #include "DataStructures/Tensor/TypeAliases.hpp" 13 : #include "Domain/BlockLogicalCoordinates.hpp" 14 : #include "IO/Logging/Verbosity.hpp" 15 : #include "Parallel/Printf/Printf.hpp" 16 : #include "ParallelAlgorithms/Interpolation/Actions/TryToInterpolate.hpp" 17 : #include "ParallelAlgorithms/Interpolation/InterpolatedVars.hpp" 18 : #include "ParallelAlgorithms/Interpolation/Tags.hpp" 19 : #include "Utilities/Algorithm.hpp" 20 : #include "Utilities/ErrorHandling/Error.hpp" 21 : #include "Utilities/Gsl.hpp" 22 : #include "Utilities/PrettyType.hpp" 23 : #include "Utilities/Requires.hpp" 24 : #include "Utilities/TaggedTuple.hpp" 25 : 26 : /// \cond 27 : 28 : namespace Parallel { 29 : template <typename Metavariables> 30 : class GlobalCache; 31 : } // namespace Parallel 32 : namespace domain { 33 : class BlockId; 34 : } // namespace domain 35 : template <typename IdType, typename DataType> 36 : class IdPair; 37 : namespace intrp { 38 : namespace Tags { 39 : template <size_t Dim> 40 : struct NumberOfElements; 41 : template <typename Metavariables> 42 : struct InterpolatedVarsHolders; 43 : } // namespace Tags 44 : } // namespace intrp 45 : /// \endcond 46 : 47 : namespace intrp { 48 : namespace Actions { 49 : 50 : /// \ingroup ActionsGroup 51 : /// \brief Receives target points from an InterpolationTarget. 52 : /// 53 : /// After receiving the points, interpolates volume data onto them 54 : /// if it already has all the volume data. 55 : /// 56 : /// The `iteration` parameter is used to order receives of 57 : /// `block_logical_coords`. Because of the asynchronous nature of communication, 58 : /// it is possible that a more recent set of points arrives before an older set. 59 : /// It is assumed that if a more recent set arrives, then the old set is no 60 : /// longer needed. This `iteration` parameter tags each communication as "more 61 : /// recent" or "older" so if we receive an older set of points after a more 62 : /// recent set, we don't overwrite the more recent set. 63 : /// 64 : /// \note If the interpolator receives points with the same iteration, an ERROR 65 : /// will occur. 66 : /// 67 : /// Uses: 68 : /// - Databox: 69 : /// - `Tags::NumberOfElements` 70 : /// - `Tags::InterpolatedVarsHolders<Metavariables>` 71 : /// - `Tags::VolumeVarsInfo<Metavariables>` 72 : /// 73 : /// DataBox changes: 74 : /// - Adds: nothing 75 : /// - Removes: nothing 76 : /// - Modifies: 77 : /// - `Tags::InterpolatedVarsHolders<Metavariables>` 78 : /// 79 : /// For requirements on InterpolationTargetTag, see InterpolationTarget 80 : template <typename InterpolationTargetTag> 81 1 : struct ReceivePoints { 82 : template <typename ParallelComponent, typename DbTags, typename Metavariables, 83 : typename ArrayIndex, size_t VolumeDim> 84 0 : static void apply( 85 : db::DataBox<DbTags>& box, Parallel::GlobalCache<Metavariables>& cache, 86 : const ArrayIndex& /*array_index*/, 87 : const typename InterpolationTargetTag::temporal_id::type& temporal_id, 88 : std::vector<BlockLogicalCoords<VolumeDim>>&& block_logical_coords, 89 : const size_t iteration = 0_st, 90 : const size_t reinterpolation_iteration = 0_st) { 91 : const auto& finished_ids = 92 : get<intrp::Vars::HolderTag<InterpolationTargetTag, Metavariables>>( 93 : get<intrp::Tags::InterpolatedVarsHolders<Metavariables>>(box)) 94 : .temporal_ids_when_data_has_been_interpolated; 95 : 96 : // If we are receiving points from a target after the interpolation has 97 : // finished, we discard the points and don't do anything 98 : if (alg::found(finished_ids, temporal_id)) { 99 : return; 100 : } 101 : 102 : db::mutate<intrp::Tags::InterpolatedVarsHolders<Metavariables>>( 103 : [&temporal_id, &block_logical_coords, &iteration, 104 : &reinterpolation_iteration]( 105 : const gsl::not_null<typename intrp::Tags::InterpolatedVarsHolders< 106 : Metavariables>::type*> 107 : vars_holders) { 108 : auto& vars_infos = 109 : get<intrp::Vars::HolderTag<InterpolationTargetTag, 110 : Metavariables>>(*vars_holders) 111 : .infos; 112 : 113 : // Add the new target interpolation points at this temporal_id. There 114 : // are three conditions that allow us to overwrite the current target 115 : // points: 116 : // 117 : // 1. There are no current target points at the temporal_id, OR 118 : // 2. There are target points already at this temporal_id, but the 119 : // iteration of the new target points is greater than the 120 : // iteration of the current target points (even if we are retrying 121 : // interpolation). 122 : // 3. There are target points already at this temporal_id, but the 123 : // iteration of the new target points is equal to the iteration of 124 : // the current target points, and the incoming reinterpolation 125 : // iteration is greater than the current reinterpolation 126 : // iteration. 127 : // 128 : // If we already have target points and the iteration of the new 129 : // points is less than or equal to the iteration of the current target 130 : // points (and we aren't retrying an interpolation with new points), 131 : // then we ignore the new points. The new points are outdated and we 132 : // definitely didn't have any of the new target points in our element 133 : // by the fact that we have already received the next iteration of 134 : // points. 135 : // 136 : // However, it occasionally happens where interpolation fails at some 137 : // iteration, and the horizon finder is able to send a new set of 138 : // points to try for the same iteration. 139 : // 140 : // Whenever we overwrite the target points, we also empty the 141 : // `interpolation_is_done_for_these_elements` (by virtue of a default 142 : // constructed `intrp::Vars::Info`) so that we always check every 143 : // element for this new set of target points. 144 : if (vars_infos.count(temporal_id) == 0 or 145 : vars_infos.at(temporal_id).iteration < iteration or 146 : (vars_infos.at(temporal_id).iteration == iteration and 147 : vars_infos.at(temporal_id).reinterpolation_iteration < 148 : reinterpolation_iteration)) { 149 : vars_infos.insert_or_assign( 150 : temporal_id, 151 : intrp::Vars::Info<VolumeDim, typename InterpolationTargetTag:: 152 : vars_to_interpolate_to_target>{ 153 : std::move(block_logical_coords), iteration}); 154 : } else if (vars_infos.at(temporal_id).iteration == iteration and 155 : vars_infos.at(temporal_id).reinterpolation_iteration == 156 : reinterpolation_iteration) { 157 : ERROR("Interpolator received target points at iteration " 158 : << iteration << " (and reinterpolation iteration " 159 : << reinterpolation_iteration << ") twice."); 160 : } 161 : }, 162 : make_not_null(&box)); 163 : 164 : if (Parallel::get<intrp::Tags::Verbosity>(cache) >= ::Verbosity::Debug) { 165 : Parallel::printf("%s, received points.\n", 166 : InterpolationTarget_detail::interpolator_output_prefix< 167 : InterpolationTargetTag>(temporal_id)); 168 : } 169 : 170 : try_to_interpolate<InterpolationTargetTag>( 171 : make_not_null(&box), make_not_null(&cache), temporal_id); 172 : } 173 : }; 174 : 175 : } // namespace Actions 176 : } // namespace intrp