SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem/Measurements - BNSCenterOfMass.hpp Hit Total Coverage
Commit: 1d64892952139ddfbae7cdbdcd87dce73af8d9fe Lines: 11 30 36.7 %
Date: 2025-12-12 21:49:13
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 <string>
       8             : #include <tuple>
       9             : #include <vector>
      10             : 
      11             : #include "ControlSystem/Component.hpp"
      12             : #include "ControlSystem/Protocols/Measurement.hpp"
      13             : #include "ControlSystem/Protocols/Submeasurement.hpp"
      14             : #include "ControlSystem/RunCallbacks.hpp"
      15             : #include "DataStructures/DataBox/Tag.hpp"
      16             : #include "DataStructures/LinkedMessageId.hpp"
      17             : #include "DataStructures/Tensor/TypeAliases.hpp"
      18             : #include "Domain/BlockLogicalCoordinates.hpp"
      19             : #include "Domain/Creators/Tags/Domain.hpp"
      20             : #include "Domain/FunctionsOfTime/FunctionOfTime.hpp"
      21             : #include "Domain/FunctionsOfTime/Tags.hpp"
      22             : #include "Domain/Structure/ObjectLabel.hpp"
      23             : #include "IO/Logging/Verbosity.hpp"
      24             : #include "IO/Observer/ObserverComponent.hpp"
      25             : #include "IO/Observer/ReductionActions.hpp"
      26             : #include "NumericalAlgorithms/LinearOperators/DefiniteIntegral.hpp"
      27             : #include "Parallel/GlobalCache.hpp"
      28             : #include "Parallel/Invoke.hpp"
      29             : #include "Parallel/Reduction.hpp"
      30             : #include "ParallelAlgorithms/Actions/FunctionsOfTimeAreReady.hpp"
      31             : #include "ParallelAlgorithms/Events/Tags.hpp"
      32             : #include "ParallelAlgorithms/EventsAndTriggers/Event.hpp"
      33             : #include "Utilities/Algorithm.hpp"
      34             : #include "Utilities/GetOutput.hpp"
      35             : #include "Utilities/ProtocolHelpers.hpp"
      36             : #include "Utilities/Serialization/CharmPupable.hpp"
      37             : #include "Utilities/StdArrayHelpers.hpp"
      38             : #include "Utilities/TMPL.hpp"
      39             : 
      40             : /// \cond
      41             : class DataVector;
      42             : template <size_t VolumeDim>
      43             : class ElementId;
      44             : template <size_t Dim>
      45             : class Mesh;
      46             : namespace control_system::Tags {
      47             : struct WriteDataToDisk;
      48             : }  // namespace control_system::Tags
      49             : namespace Parallel {
      50             : template <typename Metavariables>
      51             : class GlobalCache;
      52             : }  // namespace Parallel
      53             : namespace domain::Tags {
      54             : template <size_t Dim>
      55             : struct Mesh;
      56             : template <size_t Dim, typename Frame>
      57             : struct Coordinates;
      58             : }  // namespace domain::Tags
      59             : namespace grmhd::ValenciaDivClean::Tags {
      60             : struct TildeD;
      61             : }  // namespace grmhd::ValenciaDivClean::Tags
      62             : namespace Tags {
      63             : struct PreviousTriggerTime;
      64             : }  // namespace Tags
      65             : /// \endcond
      66             : 
      67             : namespace control_system {
      68           1 : namespace measurements {
      69             : /// \cond
      70             : template <typename ControlSystems>
      71             : struct PostReductionSendBNSStarCentersToControlSystem;
      72             : /// \endcond
      73             : 
      74             : /*!
      75             :  * \brief  Factored Center of Mass calculation (for easier testing)
      76             :  *
      77             :  * \details This function computes the integral of tildeD (assumed to be the
      78             :  * conservative baryon density in the inertial frame), as well as its first
      79             :  * moment in the grid frame. The integrals are limited to \f$x>0\f$ (label A) or
      80             :  * \f$x<0\f$ (label B).
      81             :  *
      82             :  * \param mass_a Integral of tildeD (x > 0)
      83             :  * \param mass_b Integral of tildeD (x < 0)
      84             :  * \param first_moment_A First moment of integral of tildeD (x > 0)
      85             :  * \param first_moment_B First moment of integral of tildeD (x < 0)
      86             :  * \param mesh The mesh
      87             :  * \param inv_det_jacobian The inverse determinant of the jacobian of the map
      88             :  * between logical and inertial coordinates \param tilde_d TildeD on the mesh
      89             :  * \param x_grid The coordinates in the grid frame
      90             :  */
      91           1 : void center_of_mass_integral_on_element(
      92             :     const gsl::not_null<double*> mass_a, const gsl::not_null<double*> mass_b,
      93             :     const gsl::not_null<std::array<double, 3>*> first_moment_A,
      94             :     const gsl::not_null<std::array<double, 3>*> first_moment_B,
      95             :     const Mesh<3>& mesh, const Scalar<DataVector>& inv_det_jacobian,
      96             :     const Scalar<DataVector>& tilde_d,
      97             :     const tnsr::I<DataVector, 3, Frame::Grid>& x_grid);
      98             : }  // namespace measurements
      99             : 
     100             : /*!
     101             :  * \brief An `::Event` that computes the center of mass for $x > 0$ and $x < 0$
     102             :  * where $x$ is the in the `Frame::Grid`.
     103             :  *
     104             :  * \details See
     105             :  * `control_system::measurements::grid_center_of_mass_integral_on_element` for
     106             :  * the calculation of the CoM. This event then does a reduction and calls
     107             :  * `control_system::PostReductionSendBNSStarCentersToControlSystem` as a post
     108             :  * reduction callback.
     109             :  *
     110             :  * \tparam ControlSystems `tmpl::list` of all control systems that use this
     111             :  * event.
     112             :  */
     113             : template <typename ControlSystems>
     114           1 : class BNSEvent : public ::Event {
     115             :  public:
     116             :   /// \cond
     117             :   // LCOV_EXCL_START
     118             :   explicit BNSEvent(CkMigrateMessage* /*unused*/) {}
     119             :   using PUP::able::register_constructor;
     120             :   WRAPPED_PUPable_decl_template(BNSEvent);  // NOLINT
     121             :   // LCOV_EXCL_STOP
     122             :   /// \endcond
     123             : 
     124             :   // This event is created during control system initialization, not
     125             :   // from the input file.
     126           0 :   static constexpr bool factory_creatable = false;
     127           0 :   BNSEvent() = default;
     128             : 
     129           0 :   using compute_tags_for_observation_box = tmpl::list<>;
     130             : 
     131           0 :   using return_tags = tmpl::list<>;
     132           0 :   using argument_tags =
     133             :       tmpl::list<::Tags::Time, ::Tags::PreviousTriggerTime,
     134             :                  ::Events::Tags::ObserverMesh<3>,
     135             :                  ::Events::Tags::ObserverDetInvJacobian<Frame::ElementLogical,
     136             :                                                         Frame::Inertial>,
     137             :                  grmhd::ValenciaDivClean::Tags::TildeD,
     138             :                  ::Events::Tags::ObserverCoordinates<3, Frame::Grid>>;
     139             : 
     140             :   template <typename Metavariables, typename ArrayIndex,
     141             :             typename ParallelComponent>
     142           0 :   void operator()(const double time, const std::optional<double>& previous_time,
     143             :                   const Mesh<3>& mesh,
     144             :                   const Scalar<DataVector>& inv_det_jacobian,
     145             :                   const Scalar<DataVector>& tilde_d,
     146             :                   const tnsr::I<DataVector, 3, Frame::Grid>& x_grid,
     147             :                   Parallel::GlobalCache<Metavariables>& cache,
     148             :                   const ArrayIndex& array_index,
     149             :                   const ParallelComponent* const /*meta*/,
     150             :                   const ObservationValue& /*observation_value*/) const {
     151             :     const LinkedMessageId<double> measurement_id{time, previous_time};
     152             : 
     153             :     // Initialize integrals and perform local calculations
     154             :     double mass_a = 0.;
     155             :     double mass_b = 0.;
     156             :     std::array<double, 3> first_moment_a = {0., 0., 0.};
     157             :     std::array<double, 3> first_moment_b = {0., 0., 0.};
     158             :     measurements::center_of_mass_integral_on_element(
     159             :         &mass_a, &mass_b, &first_moment_a, &first_moment_b, mesh,
     160             :         inv_det_jacobian, tilde_d, x_grid);
     161             : 
     162             :     // Reduction
     163             :     auto my_proxy =
     164             :         Parallel::get_parallel_component<ParallelComponent>(cache)[array_index];
     165             :     // We need a place to run RunCallback on... this does not need to be
     166             :     // the control system using the CoM data.
     167             :     auto& reduction_target_proxy = Parallel::get_parallel_component<
     168             :         ControlComponent<Metavariables, tmpl::front<ControlSystems>>>(cache);
     169             :     Parallel::ReductionData<
     170             :         Parallel::ReductionDatum<LinkedMessageId<double>, funcl::AssertEqual<>>,
     171             :         Parallel::ReductionDatum<double, funcl::Plus<>>,
     172             :         Parallel::ReductionDatum<double, funcl::Plus<>>,
     173             :         Parallel::ReductionDatum<std::array<double, 3>, funcl::Plus<>>,
     174             :         Parallel::ReductionDatum<std::array<double, 3>, funcl::Plus<>>>
     175             :         reduction_data{measurement_id, mass_a, mass_b, first_moment_a,
     176             :                        first_moment_b};
     177             :     Parallel::contribute_to_reduction<
     178             :         measurements::PostReductionSendBNSStarCentersToControlSystem<
     179             :             ControlSystems>>(std::move(reduction_data), my_proxy,
     180             :                              reduction_target_proxy);
     181             :   }
     182             : 
     183           0 :   using is_ready_argument_tags = tmpl::list<>;
     184             : 
     185             :   template <typename Metavariables, typename ArrayIndex, typename Component>
     186           0 :   bool is_ready(Parallel::GlobalCache<Metavariables>& /*cache*/,
     187             :                 const ArrayIndex& /*array_index*/,
     188             :                 const Component* const /*component*/) const {
     189             :     return true;
     190             :   }
     191             : 
     192           1 :   bool needs_evolved_variables() const override { return true; }
     193             : };
     194             : 
     195             : /// \cond
     196             : template <typename ControlSystems>
     197             : PUP::able::PUP_ID BNSEvent<ControlSystems>::my_PUP_ID = 0;  // NOLINT
     198             : /// \endcond
     199             : 
     200             : namespace measurements {
     201           1 : namespace Tags {
     202             : /// \ingroup DataBoxTagsGroup
     203             : /// \ingroup ControlSystemGroup
     204             : /// DataBox tag for location of neutron star center (or more accurately, center
     205             : /// of mass of the matter in the x>0 (label A) or x<0 (label B) region, in grid
     206             : /// coordinates).
     207             : template <::domain::ObjectLabel Center, typename Fr>
     208           1 : struct NeutronStarCenter : db::SimpleTag {
     209           0 :   using type = std::array<double, 3>;
     210             : };
     211             : 
     212             : /// \ingroup DataBoxTagsGroup
     213             : /// \ingroup ControlSystemGroup
     214             : /// DataBox tag for location of center of mass of all of the matter.
     215             : template <typename Fr>
     216           1 : struct SystemCenterOfMass : db::SimpleTag {
     217           0 :   using type = std::array<double, 3>;
     218             : };
     219             : }  // namespace Tags
     220             : 
     221             : /*!
     222             :  * \brief Measurement providing the location of the center of mass of the matter
     223             :  * in the \f$x>0\f$ and \f$x<0\f$ regions (assumed to correspond to the center
     224             :  * of mass of the two neutron stars in a BNS merger).
     225             :  *
     226             :  * \details We use Events::Tags::ObserverXXX for tags that might need to be
     227             :  * retrieved from either the Subcell or DG grid.
     228             :  */
     229           1 : struct BothNSCenters : tt::ConformsTo<protocols::Measurement> {
     230           0 :   struct FindTwoCenters : tt::ConformsTo<protocols::Submeasurement> {
     231           0 :     static std::string name() { return "BothNSCenters::FindTwoCenters"; }
     232             :     /// Unused aliases needed to conform to the submeasurement protocol.
     233             :     template <typename ControlSystems>
     234           1 :     using interpolation_target_tag = void;
     235             :     template <typename ControlSystems>
     236           0 :     using horizon_metavars = void;
     237             : 
     238             :     template <typename ControlSystems>
     239           0 :     using event = BNSEvent<ControlSystems>;
     240             :   };
     241             :   /// List of submeasurements used by this measurement -- only FindTwoCenters
     242             :   /// here.
     243           1 :   using submeasurements = tmpl::list<FindTwoCenters>;
     244             : };
     245             : 
     246             : /*!
     247             :  * \brief Simple action called after reduction of the center of mass data.
     248             :  *
     249             :  * \details `mass_a`, `mass_b`, `first_moment_a`, and `first_moment_b` will
     250             :  * contain the reduced data for the integral of the density (and its first
     251             :  * moment) in the x>=0 (A label) and x<0 (B label) regions. This action
     252             :  * calculates the center of mass in each region, and sends the result to the
     253             :  * control system.
     254             :  *
     255             :  * If the `control_system::Tags::WriteDataToDisk` tag is true, then this will
     256             :  * also write the centers of mass to the `/ControlSystems/BnsCenters` subfile of
     257             :  * the reductions h5 file. The columns of the file are
     258             :  *
     259             :  * - %Time
     260             :  * - Center_A_x
     261             :  * - Center_A_y
     262             :  * - Center_A_z
     263             :  * - Center_B_x
     264             :  * - Center_B_y
     265             :  * - Center_B_z
     266             :  */
     267             : template <typename ControlSystems>
     268           1 : struct PostReductionSendBNSStarCentersToControlSystem {
     269             :   template <typename ParallelComponent, typename DbTags, typename Metavariables,
     270             :             typename ArrayIndex>
     271           0 :   static void apply(db::DataBox<DbTags>& /*box*/,
     272             :                     Parallel::GlobalCache<Metavariables>& cache,
     273             :                     const ArrayIndex& /*array_index*/,
     274             :                     const LinkedMessageId<double>& measurement_id,
     275             :                     const double& mass_a, const double& mass_b,
     276             :                     const std::array<double, 3>& first_moment_a,
     277             :                     const std::array<double, 3>& first_moment_b) {
     278             :     // Function called after reduction of the CoM data.
     279             :     // Calculate CoM from integrals
     280             :     std::array<double, 3> grid_center_a = first_moment_a / mass_a;
     281             :     std::array<double, 3> grid_center_b = first_moment_b / mass_b;
     282             :     std::array<double, 3> grid_center_total =
     283             :         (first_moment_a + first_moment_b) / (mass_a + mass_b);
     284             : 
     285             :     // To convert grid coords to inertial coords, we must find the block that
     286             :     // these coords are in and use that grid to inertial map
     287             :     const Domain<3>& domain = Parallel::get<domain::Tags::Domain<3>>(cache);
     288             :     const domain::FunctionsOfTimeMap& functions_of_time =
     289             :         Parallel::get<domain::Tags::FunctionsOfTime>(cache);
     290             :     tnsr::I<DataVector, 3, Frame::Grid> grid_tnsr_center{};
     291             :     for (size_t i = 0; i < 3; i++) {
     292             :       grid_tnsr_center.get(i) =
     293             :           DataVector{gsl::at(grid_center_a, i), gsl::at(grid_center_b, i),
     294             :                      gsl::at(grid_center_total, i)};
     295             :     }
     296             : 
     297             :     const auto block_logical_coords = block_logical_coordinates(
     298             :         domain, grid_tnsr_center, measurement_id.id, functions_of_time);
     299             : 
     300             :     ASSERT(alg::all_of(block_logical_coords,
     301             :                        [](const auto& logical_coord_holder) {
     302             :                          return logical_coord_holder.has_value();
     303             :                        }),
     304             :            "Grid centers of BNS ("
     305             :                << grid_center_a << ", " << grid_center_b << ", "
     306             :                << grid_center_total
     307             :                << ") could not be mapped to the logical frame.");
     308             : 
     309             :     const auto& blocks = domain.blocks();
     310             : 
     311             :     ASSERT(block_logical_coords.size() == 3,
     312             :            "There should be exactly 3 block logical coordinates for the two "
     313             :            "centers of the BNS plus the system COM, but instead there are "
     314             :                << block_logical_coords.size());
     315             : 
     316             :     std::array<double, 3> inertial_center_a{};
     317             :     std::array<double, 3> inertial_center_b{};
     318             :     std::array<double, 3> inertial_center_total{};
     319             : 
     320             :     for (size_t n = 0; n < block_logical_coords.size(); n++) {
     321             :       const auto& logical_coord_holder = block_logical_coords[n];
     322             :       const auto& block_id = logical_coord_holder.value().id;
     323             : 
     324             :       const auto& block = blocks[block_id.get_index()];
     325             :       const auto& grid_to_inertial_map =
     326             :           block.moving_mesh_grid_to_inertial_map();
     327             : 
     328             :       const auto inertial_center = grid_to_inertial_map(
     329             :           tnsr::I<double, 3, Frame::Grid>{
     330             :               n == 0 ? grid_center_a
     331             :                      : (n == 1 ? grid_center_b : grid_center_total)},
     332             :           measurement_id.id, functions_of_time);
     333             : 
     334             :       auto& center_to_set =
     335             :           n == 0 ? inertial_center_a
     336             :                  : (n == 1 ? inertial_center_b : inertial_center_total);
     337             :       for (size_t i = 0; i < 3; i++) {
     338             :         gsl::at(center_to_set, i) = inertial_center.get(i);
     339             :       }
     340             :     }
     341             : 
     342             :     const auto center_databox = db::create<db::AddSimpleTags<
     343             :         Tags::NeutronStarCenter<::domain::ObjectLabel::A, Frame::Grid>,
     344             :         Tags::NeutronStarCenter<::domain::ObjectLabel::B, Frame::Grid>,
     345             :         Tags::NeutronStarCenter<::domain::ObjectLabel::A, Frame::Inertial>,
     346             :         Tags::NeutronStarCenter<::domain::ObjectLabel::B, Frame::Inertial>,
     347             :         Tags::SystemCenterOfMass<Frame::Grid>,
     348             :         Tags::SystemCenterOfMass<Frame::Inertial>>>(
     349             :         grid_center_a, grid_center_b, inertial_center_a, inertial_center_b,
     350             :         grid_center_total, inertial_center_total);
     351             : 
     352             :     // Send results to the control system(s)
     353             :     RunCallbacks<BothNSCenters::FindTwoCenters, ControlSystems>::apply(
     354             :         center_databox, cache, measurement_id);
     355             : 
     356             :     if (Parallel::get<control_system::Tags::WriteDataToDisk>(cache)) {
     357             :       std::vector<double> grid_data_to_write{
     358             :           measurement_id.id,   grid_center_a[0],     grid_center_a[1],
     359             :           grid_center_a[2],    grid_center_b[0],     grid_center_b[1],
     360             :           grid_center_b[2],    grid_center_total[0], grid_center_total[1],
     361             :           grid_center_total[2]};
     362             : 
     363             :       std::vector<double> inertial_data_to_write{measurement_id.id};
     364             :       inertial_data_to_write.insert(inertial_data_to_write.end(),
     365             :                                     inertial_center_a.begin(),
     366             :                                     inertial_center_a.end());
     367             :       inertial_data_to_write.insert(inertial_data_to_write.end(),
     368             :                                     inertial_center_b.begin(),
     369             :                                     inertial_center_b.end());
     370             :       inertial_data_to_write.insert(inertial_data_to_write.end(),
     371             :                                     inertial_center_total.begin(),
     372             :                                     inertial_center_total.end());
     373             : 
     374             :       auto& writer_proxy = Parallel::get_parallel_component<
     375             :           observers::ObserverWriter<Metavariables>>(cache);
     376             : 
     377             :       Parallel::threaded_action<
     378             :           observers::ThreadedActions::WriteReductionDataRow>(
     379             :           // Node 0 is always the writer
     380             :           writer_proxy[0], grid_subfile_path_, legend_,
     381             :           std::make_tuple(std::move(grid_data_to_write)));
     382             :       Parallel::threaded_action<
     383             :           observers::ThreadedActions::WriteReductionDataRow>(
     384             :           // Node 0 is always the writer
     385             :           writer_proxy[0], inertial_subfile_path_, legend_,
     386             :           std::make_tuple(std::move(inertial_data_to_write)));
     387             :     }
     388             :   }
     389             : 
     390             :  private:
     391           0 :   const static inline std::vector<std::string> legend_{
     392             :       "Time",           "Center_A_x",      "Center_A_y",
     393             :       "Center_A_z",     "Center_B_x",      "Center_B_y",
     394             :       "Center_B_z",     "Center_System_x", "Center_System_y",
     395             :       "Center_System_z"};
     396           0 :   const static inline std::string grid_subfile_path_{
     397             :       "/ControlSystems/BnsGridCenters"};
     398           0 :   const static inline std::string inertial_subfile_path_{
     399             :       "/ControlSystems/BnsInertialCenters"};
     400             : };
     401             : }  // namespace measurements
     402             : }  // namespace control_system

Generated by: LCOV version 1.14