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 "ParallelAlgorithms/Interpolation/Actions/TryToInterpolate.hpp" 14 : #include "ParallelAlgorithms/Interpolation/InterpolatedVars.hpp" 15 : #include "Utilities/ErrorHandling/Error.hpp" 16 : #include "Utilities/Gsl.hpp" 17 : #include "Utilities/Requires.hpp" 18 : #include "Utilities/TaggedTuple.hpp" 19 : 20 : /// \cond 21 : // IWYU pragma: no_forward_declare db::DataBox 22 : namespace Parallel { 23 : template <typename Metavariables> 24 : class GlobalCache; 25 : } // namespace Parallel 26 : namespace domain { 27 : class BlockId; 28 : } // namespace domain 29 : template <typename IdType, typename DataType> 30 : class IdPair; 31 : namespace intrp { 32 : namespace Tags { 33 : struct NumberOfElements; 34 : template <typename Metavariables> 35 : struct InterpolatedVarsHolders; 36 : } // namespace Tags 37 : } // namespace intrp 38 : /// \endcond 39 : 40 : namespace intrp { 41 : namespace Actions { 42 : 43 : /// \ingroup ActionsGroup 44 : /// \brief Receives target points from an InterpolationTarget. 45 : /// 46 : /// After receiving the points, interpolates volume data onto them 47 : /// if it already has all the volume data. 48 : /// 49 : /// The `iteration` parameter is used to order receives of 50 : /// `block_logical_coords`. Because of the asynchronous nature of communication, 51 : /// it is possible that a more recent set of points arrives before an older set. 52 : /// It is assumed that if a more recent set arrives, then the old set is no 53 : /// longer needed. This `iteration` parameter tags each communication as "more 54 : /// recent" or "older" so if we receive an older set of points after a more 55 : /// recent set, we don't overwrite the more recent set. 56 : /// 57 : /// \note If the interpolator receives points with the same iteration, an ERROR 58 : /// will occur. 59 : /// 60 : /// Uses: 61 : /// - Databox: 62 : /// - `Tags::NumberOfElements` 63 : /// - `Tags::InterpolatedVarsHolders<Metavariables>` 64 : /// - `Tags::VolumeVarsInfo<Metavariables>` 65 : /// 66 : /// DataBox changes: 67 : /// - Adds: nothing 68 : /// - Removes: nothing 69 : /// - Modifies: 70 : /// - `Tags::InterpolatedVarsHolders<Metavariables>` 71 : /// 72 : /// For requirements on InterpolationTargetTag, see InterpolationTarget 73 : template <typename InterpolationTargetTag> 74 1 : struct ReceivePoints { 75 : template <typename ParallelComponent, typename DbTags, typename Metavariables, 76 : typename ArrayIndex, size_t VolumeDim> 77 0 : static void apply( 78 : db::DataBox<DbTags>& box, Parallel::GlobalCache<Metavariables>& cache, 79 : const ArrayIndex& /*array_index*/, 80 : const typename InterpolationTargetTag::temporal_id::type& temporal_id, 81 : std::vector<std::optional< 82 : IdPair<domain::BlockId, 83 : tnsr::I<double, VolumeDim, typename ::Frame::BlockLogical>>>>&& 84 : block_logical_coords, 85 : const size_t iteration = 0_st) { 86 : db::mutate<intrp::Tags::InterpolatedVarsHolders<Metavariables>>( 87 : [&temporal_id, &block_logical_coords, &iteration]( 88 : const gsl::not_null<typename intrp::Tags::InterpolatedVarsHolders< 89 : Metavariables>::type*> 90 : vars_holders) { 91 : auto& vars_infos = 92 : get<intrp::Vars::HolderTag<InterpolationTargetTag, 93 : Metavariables>>(*vars_holders) 94 : .infos; 95 : 96 : // Add the new target interpolation points at this temporal_id. There 97 : // are two conditions that allow us to overwrite the current target 98 : // points. Either 99 : // 100 : // 1. There are no current target points at the temporal_id, OR 101 : // 2. There are target points already at this temporal_id, but the 102 : // iteration of the new target points is greater than the 103 : // iteration of the current target points. 104 : // 105 : // If we already have target points and the iteration of the new 106 : // points is less than or equal to the iteration of the current target 107 : // points, then we ignore the new points. The new points are outdated 108 : // and we definitely didn't have any of the new target points in our 109 : // element by the fact that we have already received the next 110 : // iteration of points. 111 : // 112 : // Whenever we overwrite the target points, we also empty the 113 : // `interpolation_is_done_for_these_elements` (by virtue of a default 114 : // constructed `intrp::Vars::Info`) so that we always check every 115 : // element for this new set of target points. 116 : if (vars_infos.count(temporal_id) == 0 or 117 : vars_infos.at(temporal_id).iteration < iteration) { 118 : vars_infos.insert_or_assign( 119 : temporal_id, 120 : intrp::Vars::Info<VolumeDim, typename InterpolationTargetTag:: 121 : vars_to_interpolate_to_target>{ 122 : std::move(block_logical_coords), iteration}); 123 : } else if (vars_infos.at(temporal_id).iteration == iteration) { 124 : ERROR( 125 : "Interpolator received target points at iteration " 126 : << iteration 127 : << " twice. Only one set of points per iteration is allowed."); 128 : } 129 : }, 130 : make_not_null(&box)); 131 : 132 : try_to_interpolate<InterpolationTargetTag>( 133 : make_not_null(&box), make_not_null(&cache), temporal_id); 134 : } 135 : }; 136 : 137 : } // namespace Actions 138 : } // namespace intrp