SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Systems/Cce/Actions - ScriObserveInterpolated.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 1 5 20.0 %
Date: 2025-12-05 05:03:31
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 <cstddef>
       7             : #include <optional>
       8             : #include <string>
       9             : #include <tuple>
      10             : #include <unordered_map>
      11             : #include <utility>
      12             : #include <vector>
      13             : 
      14             : #include "DataStructures/ComplexDataVector.hpp"
      15             : #include "DataStructures/DataBox/DataBox.hpp"
      16             : #include "DataStructures/SpinWeighted.hpp"
      17             : #include "Evolution/Systems/Cce/Actions/WriteScriBondiQuantities.hpp"
      18             : #include "Evolution/Systems/Cce/OptionTags.hpp"
      19             : #include "Evolution/Systems/Cce/ScriPlusInterpolationManager.hpp"
      20             : #include "Evolution/Systems/Cce/Tags.hpp"
      21             : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshCoefficients.hpp"
      22             : #include "NumericalAlgorithms/SpinWeightedSphericalHarmonics/SwshTransform.hpp"
      23             : #include "Parallel/AlgorithmExecution.hpp"
      24             : #include "Parallel/GlobalCache.hpp"
      25             : #include "Parallel/Invoke.hpp"
      26             : #include "Parallel/Local.hpp"
      27             : #include "Utilities/Gsl.hpp"
      28             : #include "Utilities/MakeString.hpp"
      29             : #include "Utilities/System/ParallelInfo.hpp"
      30             : #include "Utilities/TMPL.hpp"
      31             : 
      32             : namespace Cce {
      33             : /// \cond
      34             : template <typename Metavariables>
      35             : struct AnalyticWorldtubeBoundary;
      36             : /// \endcond
      37             : namespace Actions {
      38             : namespace detail {
      39             : // Provide a nicer name for the output h5 files for some of the uglier
      40             : // combinations we need
      41             : template <typename Tag>
      42             : struct ScriOutput {
      43             :   static std::string name() { return db::tag_name<Tag>(); }
      44             : };
      45             : template <typename Tag>
      46             : struct ScriOutput<Tags::ScriPlus<Tag>> {
      47             :   static std::string name() { return pretty_type::short_name<Tag>(); }
      48             : };
      49             : template <>
      50             : struct ScriOutput<Tags::Du<Tags::TimeIntegral<Tags::ScriPlus<Tags::Psi4>>>> {
      51             :   static std::string name() { return "Psi4"; }
      52             : };
      53             : 
      54             : using weyl_correction_list =
      55             :     tmpl::list<Tags::Du<Tags::TimeIntegral<Tags::ScriPlus<Tags::Psi4>>>,
      56             :                Tags::ScriPlus<Tags::Psi3>, Tags::ScriPlus<Tags::Psi2>,
      57             :                Tags::ScriPlus<Tags::Psi1>, Tags::ScriPlus<Tags::Psi0>,
      58             :                Tags::EthInertialRetardedTime>;
      59             : 
      60             : void correct_weyl_scalars_for_inertial_time(
      61             :     gsl::not_null<Variables<weyl_correction_list>*> weyl_correction_variables);
      62             : }  // namespace detail
      63             : 
      64             : /*!
      65             :  * \ingroup ActionsGroup
      66             :  * \brief Checks the interpolation managers and if they are ready, performs the
      67             :  * interpolation and sends the data to file.
      68             :  *
      69             :  * \details This uses the `ScriPlusInterpolationManager` to perform the
      70             :  * interpolations of all requested scri quantities (determined by
      71             :  * `scri_values_to_observe` in the metavariables), and write them to disk using
      72             :  * `observers::threadedActions::WriteSimpleData`. When using an analytic
      73             :  * worldtube solution, this action also uses the `AnalyticBoundaryDataManager`
      74             :  * to output the expected News value at the appropriate asymptotically inertial
      75             :  * time.
      76             :  *
      77             :  * \note This action also uses the `Tags::EthInertialRetardedTime`, interpolated
      78             :  * to the inertial frame, to perform the coordinate transformations presented in
      79             :  * \cite Boyle:2015nqa to the Weyl scalars after interpolation. For our
      80             :  * formulas, we need to adjust the signs and factors of two to be compatible
      81             :  * with our definitions of \f$\eth\f$ and choice of Newman-Penrose tetrad.
      82             :  *
      83             :  * \f{align*}{
      84             :  * \Psi_0^{\prime (5)}
      85             :  * =&  \Psi_0^{(5)} + 2 \eth u^\prime \Psi_1^{(4)}
      86             :  * + \frac{3}{4} \left(\eth u^\prime\right)^2 \Psi_2^{(3)}
      87             :  * + \frac{1}{2} \left( \eth u^\prime\right)^3  \Psi_3^{(2)}
      88             :  * + \frac{1}{16} \left(\eth u^\prime\right)^4 \Psi_4^{(1)}, \\
      89             :  * \Psi_1^{\prime (4)}
      90             :  * =&  \Psi_1^{(4)} + \frac{3}{2} \eth u^\prime \Psi_2^{(3)}
      91             :  * + \frac{3}{4} \left(\eth u^\prime\right)^2  \Psi_3^{(2)}
      92             :  * + \frac{1}{8} \left(\eth u^\prime\right)^3 \Psi_4^{(1)}, \\
      93             :  * \Psi_2^{\prime (3)}
      94             :  * =&  \Psi_2^{(3)}
      95             :  * + \eth u^\prime  \Psi_3^{(2)}
      96             :  * + \frac{1}{4} \left(\eth  u^\prime\right)^2 \Psi_4^{(1)}, \\
      97             :  * \Psi_3^{\prime (2)}
      98             :  * =& \Psi_3^{(2)} + \frac{1}{2} \eth u^{\prime} \Psi_4^{ (1)}, \\
      99             :  * \Psi_4^{\prime (1)}
     100             :  * =& \Psi_4^{(1)}.
     101             :  * \f}
     102             :  *
     103             :  * \note If \p WriteSynchronously is true, then a local synchronous action will
     104             :  * be used to write the News value rather than a threaded action.
     105             :  *
     106             :  * \ref DataBoxGroup changes:
     107             :  * - Adds: nothing
     108             :  * - Removes: nothing
     109             :  * - Modifies: `InterpolagionManager<ComplexDataVector, Tag>` for each `Tag` in
     110             :  * `Metavariables::scri_values_to_observe`
     111             :  */
     112             : template <typename ObserverWriterComponent, typename BoundaryComponent,
     113             :           bool WriteSynchronously = true>
     114           1 : struct ScriObserveInterpolated {
     115           0 :   using const_global_cache_tags = tmpl::flatten<
     116             :       tmpl::list<Tags::ObservationLMax,
     117             :                  std::conditional_t<
     118             :                      tt::is_a_v<AnalyticWorldtubeBoundary, BoundaryComponent>,
     119             :                      tmpl::list<Tags::OutputNoninertialNews>, tmpl::list<>>>>;
     120             :   template <typename DbTags, typename... InboxTags, typename Metavariables,
     121             :             typename ArrayIndex, typename ActionList,
     122             :             typename ParallelComponent>
     123           0 :   static Parallel::iterable_action_return_t apply(
     124             :       db::DataBox<DbTags>& box,
     125             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     126             :       Parallel::GlobalCache<Metavariables>& cache,
     127             :       const ArrayIndex& /*array_index*/, const ActionList /*meta*/,
     128             :       const ParallelComponent* const /*meta*/) {
     129             :     const size_t observation_l_max = db::get<Tags::ObservationLMax>(box);
     130             :     const size_t l_max = db::get<Tags::LMax>(box);
     131             :     const double extraction_radius =
     132             :         Parallel::get<Tags::ExtractionRadius>(cache);
     133             :     const std::string subfile_name =
     134             :         MakeString{} << "SpectreR" << std::setfill('0') << std::setw(4)
     135             :                      << std::lround(extraction_radius);
     136             :     ComplexModalVector goldberg_modes{square(l_max + 1)};
     137             : 
     138             :     // alternative for the coordinate transformation getting scri+ values of the
     139             :     // weyl scalars:
     140             :     // need to obtain the eth of the inertial retarded time, each of the Weyl
     141             :     // scalars, and then we'll perform a transformation on that temporary
     142             :     // variables object, then output.
     143             :     // it won't be as general, but that's largely fine. The main frustration is
     144             :     // the loss of precision.
     145             :     Variables<detail::weyl_correction_list> corrected_scri_plus_weyl{
     146             :         Spectral::Swsh::number_of_swsh_collocation_points(l_max)};
     147             : 
     148             :     while (
     149             :         db::get<Tags::InterpolationManager<
     150             :             ComplexDataVector,
     151             :             tmpl::front<typename Metavariables::scri_values_to_observe>>>(box)
     152             :             .first_time_is_ready_to_interpolate()) {
     153             :       // first get the weyl scalars and correct them
     154             :       double interpolation_time = 0.0;
     155             :       tmpl::for_each<detail::weyl_correction_list>(
     156             :           [&interpolation_time, &corrected_scri_plus_weyl, &box](auto tag_v) {
     157             :             using tag = typename decltype(tag_v)::type;
     158             :             std::pair<double, ComplexDataVector> interpolation;
     159             :             db::mutate<Tags::InterpolationManager<ComplexDataVector, tag>>(
     160             :                 [&interpolation](
     161             :                     const gsl::not_null<
     162             :                         ScriPlusInterpolationManager<ComplexDataVector, tag>*>
     163             :                         interpolation_manager) {
     164             :                   interpolation =
     165             :                       interpolation_manager->interpolate_and_pop_first_time();
     166             :                 },
     167             :                 make_not_null(&box));
     168             :             interpolation_time = interpolation.first;
     169             :             get(get<tag>(corrected_scri_plus_weyl)).data() =
     170             :                 interpolation.second;
     171             :           });
     172             : 
     173             :       detail::correct_weyl_scalars_for_inertial_time(
     174             :           make_not_null(&corrected_scri_plus_weyl));
     175             : 
     176             :       // add them to the data to write
     177             :       std::unordered_map<std::string, std::vector<double>> data_to_write{};
     178             :       tmpl::for_each<detail::weyl_correction_list>(
     179             :           [&data_to_write, &corrected_scri_plus_weyl, &interpolation_time,
     180             :            &observation_l_max, &l_max, &goldberg_modes](auto tag_v) {
     181             :             using tag = typename decltype(tag_v)::type;
     182             :             if constexpr (tmpl::list_contains_v<
     183             :                               typename Metavariables::scri_values_to_observe,
     184             :                               tag>) {
     185             :               data_to_write[detail::ScriOutput<tag>::name()] =
     186             :                   transform_nodal_data(
     187             :                       make_not_null(&goldberg_modes),
     188             :                       get(get<tag>(corrected_scri_plus_weyl)).data(),
     189             :                       interpolation_time, l_max, observation_l_max, tag{});
     190             :             }
     191             :           });
     192             : 
     193             :       // then do the interpolation and add the rest of the tags.
     194             :       tmpl::for_each<
     195             :           tmpl::list_difference<typename Metavariables::scri_values_to_observe,
     196             :                                 detail::weyl_correction_list>>(
     197             :           [&box, &data_to_write, &observation_l_max, &l_max,
     198             :            &goldberg_modes](auto tag_v) {
     199             :             using tag = typename decltype(tag_v)::type;
     200             :             std::pair<double, ComplexDataVector> interpolation;
     201             :             db::mutate<Tags::InterpolationManager<ComplexDataVector, tag>>(
     202             :                 [&interpolation](
     203             :                     const gsl::not_null<
     204             :                         ScriPlusInterpolationManager<ComplexDataVector, tag>*>
     205             :                         interpolation_manager) {
     206             :                   interpolation =
     207             :                       interpolation_manager->interpolate_and_pop_first_time();
     208             :                 },
     209             :                 make_not_null(&box));
     210             :             data_to_write[detail::ScriOutput<tag>::name()] =
     211             :                 transform_nodal_data(make_not_null(&goldberg_modes),
     212             :                                      interpolation.second, interpolation.first,
     213             :                                      l_max, observation_l_max, tag{});
     214             :           });
     215             : 
     216             :       auto observer_proxy =
     217             :           Parallel::get_parallel_component<ObserverWriterComponent>(cache)[0];
     218             :       if constexpr (WriteSynchronously) {
     219             :         Parallel::local_synchronous_action<
     220             :             Cce::Actions::WriteScriBondiQuantities>(
     221             :             observer_proxy, cache, subfile_name, observation_l_max,
     222             :             std::move(data_to_write));
     223             :       } else {
     224             :         Parallel::threaded_action<Cce::Actions::WriteScriBondiQuantities>(
     225             :             observer_proxy, subfile_name, observation_l_max,
     226             :             std::move(data_to_write));
     227             :       }
     228             : 
     229             :       // output the expected news associated with the time value interpolated at
     230             :       // scri+.
     231             :       if constexpr (tmpl::list_contains_v<DbTags,
     232             :                                           Tags::AnalyticBoundaryDataManager>) {
     233             :         if (not db::get<Tags::OutputNoninertialNews>(box)) {
     234             :           db::get<Tags::AnalyticBoundaryDataManager>(box)
     235             :               .template write_news<ParallelComponent>(cache,
     236             :                                                       interpolation_time);
     237             :         }
     238             :       }
     239             :     }
     240             :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     241             :   }
     242             : 
     243             :  private:
     244             :   template <typename Tag>
     245           0 :   static std::vector<double> transform_nodal_data(
     246             :       const gsl::not_null<ComplexModalVector*> goldberg_mode_buffer,
     247             :       const ComplexDataVector& data, const double time, const size_t l_max,
     248             :       const size_t observation_l_max, const Tag& /*meta*/) {
     249             :     constexpr int Spin = Tag::type::type::spin;
     250             :     const SpinWeighted<ComplexDataVector, Spin> to_transform;
     251             :     make_const_view(make_not_null(&to_transform.data()), data, 0, data.size());
     252             :     SpinWeighted<ComplexModalVector, Spin> goldberg_modes;
     253             :     goldberg_modes.set_data_ref(goldberg_mode_buffer);
     254             :     Spectral::Swsh::libsharp_to_goldberg_modes(
     255             :         make_not_null(&goldberg_modes),
     256             :         Spectral::Swsh::swsh_transform(l_max, 1, to_transform), l_max);
     257             : 
     258             :     std::vector<double> modal_data(2 * square(observation_l_max + 1) + 1);
     259             : 
     260             :     modal_data[0] = time;
     261             :     for (size_t i = 0; i < square(observation_l_max + 1); ++i) {
     262             :       modal_data[2 * i + 1] = real(goldberg_modes.data()[i]);
     263             :       modal_data[2 * i + 2] = imag(goldberg_modes.data()[i]);
     264             :     }
     265             : 
     266             :     return modal_data;
     267             :   }
     268             : };
     269             : }  // namespace Actions
     270             : }  // namespace Cce

Generated by: LCOV version 1.14