SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/Interpolation - InterpolationTarget.hpp Hit Total Coverage
Commit: 1c32b58340e006addc79befb2cdaa7547247e09c Lines: 1 10 10.0 %
Date: 2024-04-19 07:30:15
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <memory>
       7             : 
       8             : #include "DataStructures/DataBox/DataBox.hpp"
       9             : #include "Parallel/Algorithms/AlgorithmSingleton.hpp"
      10             : #include "Parallel/GlobalCache.hpp"
      11             : #include "Parallel/Local.hpp"
      12             : #include "Parallel/ParallelComponentHelpers.hpp"
      13             : #include "Parallel/Phase.hpp"
      14             : #include "Parallel/PhaseDependentActionList.hpp"
      15             : #include "ParallelAlgorithms/Actions/TerminatePhase.hpp"
      16             : #include "ParallelAlgorithms/Interpolation/Actions/InterpolationTargetSendPoints.hpp"
      17             : #include "ParallelAlgorithms/Interpolation/Protocols/InterpolationTargetTag.hpp"
      18             : #include "Utilities/PrettyType.hpp"
      19             : #include "Utilities/ProtocolHelpers.hpp"
      20             : #include "Utilities/TMPL.hpp"
      21             : #include "Utilities/TypeTraits.hpp"
      22             : 
      23             : /// \cond
      24             : namespace intrp {
      25             : namespace Actions {
      26             : template <typename Metavariables, typename InterpolationTargetTag>
      27             : struct InitializeInterpolationTarget;
      28             : }  // namespace Actions
      29             : }  // namespace intrp
      30             : /// \endcond
      31             : 
      32             : namespace intrp {
      33             : 
      34             : /// \brief ParallelComponent representing a set of points to be interpolated
      35             : /// to and a function to call upon interpolation to those points.
      36             : ///
      37             : /// Each InterpolationTarget will communicate with the `Interpolator`.
      38             : ///
      39             : /// `InterpolationTargetTag` must conform to the
      40             : /// intrp::protocols::InterpolationTargetTag protocol.
      41             : ///
      42             : /// The metavariables must contain the following type aliases:
      43             : /// - interpolator_source_vars:
      44             : ///      A `tmpl::list` of tags that define a `Variables` sent from all
      45             : ///      `Element`s to the local `Interpolator`.
      46             : /// - interpolation_target_tags:
      47             : ///      A `tmpl::list` of all `InterpolationTargetTag`s.
      48             : /// - temporal_id:
      49             : ///      The type held by ::intrp::Tags::TemporalIds.
      50             : ///
      51             : /// `Metavariables` must contain the following static constexpr members:
      52             : /// - size_t volume_dim:
      53             : ///      The dimension of the Domain.
      54             : ///
      55             : /// ### Interpolation with time-dependent CoordinateMaps
      56             : ///
      57             : /// Each set of points to be interpolated onto is labeled by a
      58             : /// `temporal_id`.  If any step of the interpolation procedure ever
      59             : /// uses a time-dependent `CoordinateMap`, then it needs to grab
      60             : /// `FunctionOfTime`s from the `GlobalCache`.  Before doing so, it
      61             : /// must verify that those `FunctionOfTime`s are up-to-date for the
      62             : /// given `temporal_id`.
      63             : ///
      64             : /// Note that once the `FunctionOfTime` has been verified to be
      65             : /// up-to-date for a particular `temporal_id` at one step in the
      66             : /// interpolation procedure, all subsequent steps of the interpolation
      67             : /// procedure for that same `temporal_id` need not worry about
      68             : /// re-verifying the `FunctionOfTime`.  Therefore, we need only focus
      69             : /// on the first step in the interpolation procedure that needs
      70             : /// `FunctionOfTime`s: computing the points on which to interpolate.
      71             : ///
      72             : /// Each `InterpolationTarget` has a function
      73             : /// `InterpolationTargetTag::compute_target_points` that returns the
      74             : /// points to be interpolated onto, expressed in the frame
      75             : /// `InterpolationTargetTag::compute_target_points::frame`.  Then the
      76             : /// function `block_logical_coordinates` (and eventually
      77             : /// `element_logical_coordinates`) is called to convert those points
      78             : /// to the element logical frame to do the interpolation.  If
      79             : /// `InterpolationTargetTag::compute_target_points::frame` is
      80             : /// different from the grid frame, and if the `CoordinateMap` is
      81             : /// time-dependent, then `block_logical_coordinates` grabs
      82             : /// `FunctionOfTime`s from the `GlobalCache`.  So therefore any Action
      83             : /// calling `block_logical_coordinates` must wait until the
      84             : /// `FunctionOfTime`s in the `GlobalCache` are up-to-date for the
      85             : /// `temporal_id` being passed into `block_logical_coordinates`.
      86             : ///
      87             : /// Here we describe the logic used in all the Actions that call
      88             : /// `block_logical_coordinates`.
      89             : ///
      90             : /// #### Interpolation using the Interpolator ParallelComponent
      91             : ///
      92             : /// Recall that `InterpolationTarget` can be used with the
      93             : /// `Interpolator` ParallelComponent (as for the horizon finder), or
      94             : /// by having the `Element`s interpolate directly (as for most
      95             : /// Observers).  Here we discuss the case when the `Interpolator`
      96             : /// is used; the other case is discussed below.
      97             : ///
      98             : /// Ensuring the `FunctionOfTime`s are up-to-date is done via two Tags
      99             : /// in the DataBox and a helper Action.  When interpolation is
     100             : /// requested for a new `temporal_id` (e.g. by
     101             : /// `intrp::Events::Interpolate`), the `temporal_id` is added to
     102             : /// `Tags::PendingTemporalIds`, which holds a
     103             : /// `std::deque<temporal_id>`, and represents `temporal_ids` that we
     104             : /// want to interpolate onto, but for which `FunctionOfTime`s are not
     105             : /// necessarily up-to-date.  We also keep another list of
     106             : /// `temporal_ids`: `Tags::TemporalIds`, for which `FunctionOfTime`s
     107             : /// are guaranteed to be up-to-date.
     108             : ///
     109             : /// The action `Actions::VerifyTemporalIdsAndSendPoints` moves
     110             : /// `temporal_id`s from `PendingTemporalIds` to `TemporalIds` as
     111             : /// appropriate, and if any `temporal_id`s have been so moved, it
     112             : /// generates the `block_logical_coordinates` and sends them to the
     113             : /// `Interpolator` `ParallelComponent`.  The logic is illustrated in
     114             : /// pseudocode below.  Recall that some InterpolationTargets are
     115             : /// sequential, (i.e. you cannot interpolate onto one temporal_id until
     116             : /// interpolation on previous ones are done, like the apparent horizon
     117             : /// finder), and some are non-sequential (i.e. you can interpolate in
     118             : /// any order).
     119             : ///
     120             : /// ```
     121             : /// if (map is time-independent or frame is grid frame) {
     122             : ///   move all PendingTemporalIds to TemporalIds
     123             : ///   if (sequential) {
     124             : ///     call block_logical_coords and interpolate for first temporal_id.
     125             : ///     // when interpolation is complete,
     126             : ///     // Actions::InterpolationTargetReceiveVars will begin interpolation
     127             : ///     // on the next temporal_id.
     128             : ///   } else {
     129             : ///     call block_logical_coords and interpolate for all temporal_ids.
     130             : ///   }
     131             : ///   return;
     132             : /// }
     133             : /// if (FunctionOfTimes are up-to-date for any PendingTemporalIds) {
     134             : ///   move up-to-date PendingTemporalIds to TemporalIds
     135             : ///   if (sequential) {
     136             : ///     call block_logical_coords and interpolate for first temporal_id.
     137             : ///     // when interpolation is complete,
     138             : ///     // Actions::InterpolationTargetReceiveVars will begin interpolation
     139             : ///     // on the next temporal_id.
     140             : ///   } else {
     141             : ///     call block_logical_coords and interpolate for all temporal_ids.
     142             : ///     if (PendingTemporalIds is non-empty) {
     143             : ///       call myself (i.e. execute VerifyTemporalIdsAndSendPoints)
     144             : ///     }
     145             : ///   }
     146             : /// } else {
     147             : ///   set VerifyTemporalIdsAndSendPoints as a callback for the
     148             : ///   `domain::Tags::FunctionsOfTime` in the mutable part of the GlobalCache, so
     149             : ///   that once `FunctionsOfTime` are updated, VerifyTemporalIdsAndSendPoints is
     150             : ///   called.
     151             : /// }
     152             : /// ```
     153             : ///
     154             : /// Note that VerifyTemporalIdsAndSendPoints always exits in one of three
     155             : /// ways:
     156             : /// - It has set itself up as a callback, so it will be called again.
     157             : /// - It started a sequential interpolation that will automatically
     158             : ///   start another sequential interpolation when finished.
     159             : /// - It started non-sequential interpolations on all
     160             : ///   `TemporalIds`, and there are no `PendingTemporalIds` left.
     161             : ///
     162             : /// We now describe the logic of the Actions that use
     163             : /// VerifyTemporalIdsAndSendPoints.
     164             : ///
     165             : /// ##### Actions::AddTemporalIdsToInterpolationTarget
     166             : ///
     167             : /// `Actions::AddTemporalIdsToInterpolationTarget` is called by
     168             : /// `intrp::Events::Interpolate` to trigger interpolation for new
     169             : /// `temporal_id`s. Its logic is as follows, in pseudocode:
     170             : ///
     171             : /// ```
     172             : /// Add passed-in temporal_ids to PendingTemporalIds
     173             : /// if (sequential) {
     174             : ///   if (TemporalIds is empty and
     175             : ///       PendingTemporalIds was empty before it was appended above) {
     176             : ///     call VerifyTemporalIdsAndSendPoints
     177             : ///   } else {
     178             : ///     Do nothing, because there is already a sequential interpolation in
     179             : ///     progress, or there is a callback already waiting.
     180             : ///   }
     181             : /// } else { // not sequential
     182             : ///   if (TemporalIds is non-empty) {
     183             : ///     call block_logical_coordinates and begin interpolating for
     184             : ///     all TemporalIds.
     185             : ///   }
     186             : ///   if (PendingTemporalIds is non-empty) {
     187             : ///     call VerifyTemporalIdsAndSendPoints
     188             : ///   }
     189             : ///}
     190             : ///```
     191             : ///
     192             : /// ##### Actions::InterpolationTargetReceiveVars
     193             : ///
     194             : /// `Actions::InterpolationTargetReceiveVars` is called by the
     195             : /// `Interpolator` when it is finished interpolating the current
     196             : /// `temporal_id`.  For the sequential case, it needs to start
     197             : /// interpolating for the next `temporal_id`.  The logic is, in pseudocode:
     198             : ///
     199             : ///```
     200             : /// if (sequential) {
     201             : ///   if (TemporalIds is not empty) {
     202             : ///     call block_logical_coordinates and interpolate for next temporal_id
     203             : ///   } else if (PendingTemporalIds is not empty) {
     204             : ///     call VerifyTemporalIdsAndSendPoints
     205             : ///   }
     206             : /// }
     207             : ///```
     208             : ///
     209             : /// ##### intrp::callbacks::FindApparentHorizon
     210             : ///
     211             : /// `intrp::callbacks::FindApparentHorizon calls`
     212             : /// `block_logical_coordinates` when it needs to start a new iteration
     213             : /// of the horizon finder at the same `temporal_id`, so one might
     214             : /// think you need to worry about up-to-date `FunctionOfTime`s. But
     215             : /// since `intrp::callbacks::FindApparentHorizon` always works on the same
     216             : /// `temporal_id` for which the `FunctionOfTime`s have already been
     217             : /// verified as up-to-date from the last iteration, no special consideration
     218             : /// of `FunctionOfTime`s need be done here.
     219             : ///
     220             : /// #### Interpolation without using the Interpolator ParallelComponent
     221             : ///
     222             : /// This case is easier than the case with the `Interpolator`, because
     223             : /// the target points are always time-independent in the frame
     224             : /// `compute_target_points::frame`.
     225             : ///
     226             : /// ##### Actions::EnsureFunctionOfTimeUpToDate
     227             : ///
     228             : /// `Actions::EnsureFunctionOfTimeUpToDate` verifies that the
     229             : ///  `FunctionOfTime`s are up-to-date at the `DgElementArray`s current
     230             : ///  time.
     231             : ///
     232             : /// ###### Current logic:
     233             : ///
     234             : /// > `Actions::EnsureFunctionOfTimeUpToDate` is placed in `DgElementArray`s
     235             : /// >  PDAL before any use of interpolation.
     236             : ///
     237             : /// ##### Actions::InterpolationTargetSendTimeIndepPointsToElements
     238             : ///
     239             : /// `Actions::InterpolationTargetSendTimeIndepPointsToElements`
     240             : /// is invoked on `InterpolationTarget` during the Registration PDAL,
     241             : /// to send time-independent point information to `Element`s.
     242             : ///
     243             : /// ###### Current logic:
     244             : ///
     245             : /// > Send the result of `compute_target_points` to all `Element`s.
     246             : ///
     247             : /// Note that this may need to be revisited because every `Element` has
     248             : /// a copy of every target point, which may use a lot of memory.  An
     249             : /// alternative is for each Element to invoke an Action on each
     250             : /// `InterpolationTarget` (presumably from an `Event`) at each time,
     251             : /// and then the InterpolationTarget invokes another Action to send points
     252             : /// to only those `Elements` that contain the points; this alternative
     253             : /// uses less memory but much more communication. Another alternative would
     254             : /// be to place the points in the GlobalCache (one copy per node) since the
     255             : /// points need be computed only once.
     256             : ///
     257             : template <class Metavariables, typename InterpolationTargetTag>
     258           1 : struct InterpolationTarget {
     259           0 :   using interpolation_target_tag = InterpolationTargetTag;
     260             :   static_assert(
     261             :       tt::assert_conforms_to_v<interpolation_target_tag,
     262             :                                intrp::protocols::InterpolationTargetTag>);
     263           0 :   static std::string name() {
     264             :     return pretty_type::name<InterpolationTargetTag>();
     265             :   }
     266           0 :   using chare_type = ::Parallel::Algorithms::Singleton;
     267           0 :   using const_global_cache_tags =
     268             :       Parallel::get_const_global_cache_tags_from_actions<
     269             :           tmpl::flatten<tmpl::list<
     270             :               typename InterpolationTargetTag::compute_target_points,
     271             :               typename InterpolationTargetTag::post_interpolation_callbacks>>>;
     272           0 :   using metavariables = Metavariables;
     273           0 :   using phase_dependent_action_list = tmpl::list<
     274             :       Parallel::PhaseActions<
     275             :           Parallel::Phase::Initialization,
     276             :           tmpl::list<intrp::Actions::InitializeInterpolationTarget<
     277             :                          Metavariables, InterpolationTargetTag>,
     278             :                      Parallel::Actions::TerminatePhase>>,
     279             :       Parallel::PhaseActions<
     280             :           Parallel::Phase::Register,
     281             :           tmpl::list<
     282             :               tmpl::conditional_t<
     283             :                   InterpolationTargetTag::compute_target_points::is_sequential::
     284             :                       value,
     285             :                   tmpl::list<>,
     286             :                   tmpl::list<
     287             :                       Actions::InterpolationTargetSendTimeIndepPointsToElements<
     288             :                           InterpolationTargetTag>>>,
     289             :               Parallel::Actions::TerminatePhase>>>;
     290             : 
     291           0 :   using simple_tags_from_options = Parallel::get_simple_tags_from_options<
     292             :       Parallel::get_initialization_actions_list<phase_dependent_action_list>>;
     293             : 
     294           0 :   static void execute_next_phase(
     295             :       Parallel::Phase next_phase,
     296             :       Parallel::CProxy_GlobalCache<metavariables>& global_cache) {
     297             :     auto& local_cache = *Parallel::local_branch(global_cache);
     298             :     Parallel::get_parallel_component<
     299             :         InterpolationTarget<metavariables, InterpolationTargetTag>>(local_cache)
     300             :         .start_phase(next_phase);
     301             :   };
     302             : };
     303             : }  // namespace intrp

Generated by: LCOV version 1.14