SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Systems/GrMhd/GhValenciaDivClean/Actions - SetInitialData.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 10.3 % 39 4
Test Date: 2026-10-22 17:29:42
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 <variant>
      10              : 
      11              : #include "DataStructures/DataBox/DataBox.hpp"
      12              : #include "DataStructures/DataVector.hpp"
      13              : #include "DataStructures/TaggedTuple.hpp"
      14              : #include "DataStructures/Tensor/EagerMath/DeterminantAndInverse.hpp"
      15              : #include "DataStructures/Tensor/Tensor.hpp"
      16              : #include "Domain/Structure/ElementId.hpp"
      17              : #include "Evolution/DgSubcell/ActiveGrid.hpp"
      18              : #include "Evolution/DgSubcell/Tags/ActiveGrid.hpp"
      19              : #include "Evolution/DgSubcell/Tags/Coordinates.hpp"
      20              : #include "Evolution/DgSubcell/Tags/Jacobians.hpp"
      21              : #include "Evolution/DgSubcell/Tags/Mesh.hpp"
      22              : #include "Evolution/NumericInitialData.hpp"
      23              : #include "Evolution/Systems/GeneralizedHarmonic/Actions/SetInitialData.hpp"
      24              : #include "Evolution/Systems/GeneralizedHarmonic/GaugeSourceFunctions/SetPiAndPhiFromConstraints.hpp"
      25              : #include "Evolution/Systems/GeneralizedHarmonic/Tags.hpp"
      26              : #include "Evolution/Systems/GrMhd/ValenciaDivClean/Actions/NumericInitialData.hpp"
      27              : #include "IO/Importers/Actions/ReadVolumeData.hpp"
      28              : #include "IO/Importers/ElementDataReader.hpp"
      29              : #include "IO/Importers/Tags.hpp"
      30              : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      31              : #include "Options/String.hpp"
      32              : #include "Parallel/AlgorithmExecution.hpp"
      33              : #include "Parallel/GlobalCache.hpp"
      34              : #include "Parallel/Invoke.hpp"
      35              : #include "PointwiseFunctions/GeneralRelativity/SpatialMetric.hpp"
      36              : #include "PointwiseFunctions/GeneralRelativity/Tags.hpp"
      37              : #include "PointwiseFunctions/Hydro/EquationsOfState/EquationOfState.hpp"
      38              : #include "PointwiseFunctions/Hydro/Tags.hpp"
      39              : #include "PointwiseFunctions/InitialDataUtilities/InitialData.hpp"
      40              : #include "PointwiseFunctions/InitialDataUtilities/Tags/InitialData.hpp"
      41              : #include "Utilities/ErrorHandling/Error.hpp"
      42              : #include "Utilities/Gsl.hpp"
      43              : #include "Utilities/TMPL.hpp"
      44              : 
      45              : /// \cond
      46              : namespace Tags {
      47              : struct Time;
      48              : }  // namespace Tags
      49              : /// \endcond
      50              : 
      51            1 : namespace grmhd::GhValenciaDivClean {
      52              : 
      53              : /*!
      54              :  * \brief Numeric initial data loaded from volume data files
      55              :  *
      56              :  * This class can be factory-created in the input file to start an evolution
      57              :  * from numeric initial data. It selects the set of GH variables to load from
      58              :  * the volume data file (ADM or GH variables), the set of hydro variables, and
      59              :  * allows to set constant values for some of the hydro variables. This class
      60              :  * mostly combines the `gh::NumericInitialData` and
      61              :  * `grmhd::ValenciaDivClean::NumericInitialData` classes.
      62              :  */
      63            1 : class NumericInitialData : public evolution::initial_data::InitialData,
      64              :                            public evolution::NumericInitialData {
      65              :  private:
      66            0 :   using GhNumericId = gh::NumericInitialData;
      67            0 :   using HydroNumericId = grmhd::ValenciaDivClean::NumericInitialData;
      68              : 
      69              :  public:
      70            0 :   using all_vars =
      71              :       tmpl::append<GhNumericId::all_vars, HydroNumericId::all_vars>;
      72              : 
      73            0 :   struct GhVariables : GhNumericId::Variables {};
      74            0 :   struct HydroVariables : HydroNumericId::Variables {};
      75              : 
      76            0 :   using options = tmpl::list<importers::OptionTags::VolumeData, GhVariables,
      77              :                              HydroVariables, HydroNumericId::DensityCutoff>;
      78              : 
      79            0 :   static constexpr Options::String help =
      80              :       "Numeric initial data loaded from volume data files";
      81              : 
      82            0 :   NumericInitialData() = default;
      83            0 :   NumericInitialData(const NumericInitialData& rhs) = default;
      84            0 :   NumericInitialData& operator=(const NumericInitialData& rhs) = default;
      85            0 :   NumericInitialData(NumericInitialData&& /*rhs*/) = default;
      86            0 :   NumericInitialData& operator=(NumericInitialData&& /*rhs*/) = default;
      87            0 :   ~NumericInitialData() = default;
      88              : 
      89              :   /// \cond
      90              :   explicit NumericInitialData(CkMigrateMessage* msg);
      91              :   using PUP::able::register_constructor;
      92              :   WRAPPED_PUPable_decl_template(NumericInitialData);
      93              :   /// \endcond
      94              : 
      95            0 :   std::unique_ptr<evolution::initial_data::InitialData> get_clone()
      96              :       const override {
      97              :     return std::make_unique<NumericInitialData>(*this);
      98              :   }
      99              : 
     100            0 :   NumericInitialData(
     101              :       importers::ImporterOptions importer_options,
     102              :       typename GhNumericId::Variables::type gh_selected_variables,
     103              :       typename HydroNumericId::Variables::type hydro_selected_variables,
     104              :       double density_cutoff);
     105              : 
     106            0 :   const importers::ImporterOptions& importer_options() const {
     107              :     return gh_numeric_id_.importer_options();
     108              :   }
     109              : 
     110            0 :   const GhNumericId& gh_numeric_id() const { return gh_numeric_id_; }
     111              : 
     112            0 :   const HydroNumericId& hydro_numeric_id() const { return hydro_numeric_id_; }
     113              : 
     114            0 :   size_t volume_data_id() const;
     115              : 
     116              :   template <typename... AllTags>
     117            0 :   void select_for_import(
     118              :       const gsl::not_null<tuples::TaggedTuple<AllTags...>*> fields) const {
     119              :     gh_numeric_id_.select_for_import(fields);
     120              :     hydro_numeric_id_.select_for_import(fields);
     121              :   }
     122              : 
     123              :   template <typename... AllTags, size_t ThermodynamicDim>
     124            0 :   void set_initial_data(
     125              :       const gsl::not_null<tnsr::aa<DataVector, 3>*> spacetime_metric,
     126              :       const gsl::not_null<tnsr::aa<DataVector, 3>*> pi,
     127              :       const gsl::not_null<tnsr::iaa<DataVector, 3>*> phi,
     128              :       const gsl::not_null<Scalar<DataVector>*> rest_mass_density,
     129              :       const gsl::not_null<Scalar<DataVector>*> electron_fraction,
     130              :       const gsl::not_null<Scalar<DataVector>*> specific_internal_energy,
     131              :       const gsl::not_null<tnsr::I<DataVector, 3>*> spatial_velocity,
     132              :       const gsl::not_null<tnsr::I<DataVector, 3>*> magnetic_field,
     133              :       const gsl::not_null<Scalar<DataVector>*> div_cleaning_field,
     134              :       const gsl::not_null<Scalar<DataVector>*> lorentz_factor,
     135              :       const gsl::not_null<Scalar<DataVector>*> pressure,
     136              :       const gsl::not_null<Scalar<DataVector>*> temperature,
     137              :       const gsl::not_null<tuples::TaggedTuple<AllTags...>*> numeric_data,
     138              :       const Mesh<3>& mesh,
     139              :       const InverseJacobian<DataVector, 3, Frame::ElementLogical,
     140              :                             Frame::Inertial>& inv_jacobian,
     141              :       const tnsr::I<DataVector, 3, Frame::Inertial>& inertial_coords,
     142              :       const EquationsOfState::EquationOfState<true, ThermodynamicDim>&
     143              :           equation_of_state) const {
     144              :     gh_numeric_id_.set_initial_data(spacetime_metric, pi, phi, numeric_data,
     145              :                                     mesh, inv_jacobian, inertial_coords);
     146              :     const auto spatial_metric = gr::spatial_metric(*spacetime_metric);
     147              :     const auto inv_spatial_metric =
     148              :         determinant_and_inverse(spatial_metric).second;
     149              :     hydro_numeric_id_.set_initial_data(
     150              :         rest_mass_density, electron_fraction, specific_internal_energy,
     151              :         spatial_velocity, magnetic_field, div_cleaning_field, lorentz_factor,
     152              :         pressure, temperature, numeric_data, inv_spatial_metric,
     153              :         equation_of_state);
     154              :   }
     155              : 
     156            0 :   void pup(PUP::er& p) override;
     157              : 
     158            0 :   friend bool operator==(const NumericInitialData& lhs,
     159              :                          const NumericInitialData& rhs);
     160              : 
     161              :  private:
     162            0 :   GhNumericId gh_numeric_id_{};
     163            0 :   HydroNumericId hydro_numeric_id_{};
     164              : };
     165              : 
     166            0 : namespace Actions {
     167              : 
     168              : /*!
     169              :  * \brief Dispatch loading numeric initial data from files.
     170              :  *
     171              :  * Place this action before
     172              :  * grmhd::GhValenciaDivClean::Actions::SetNumericInitialData in the action list.
     173              :  * See importers::Actions::ReadAllVolumeDataAndDistribute for details, which is
     174              :  * invoked by this action.
     175              :  */
     176            1 : struct SetInitialData {
     177            0 :   using const_global_cache_tags =
     178              :       tmpl::list<evolution::initial_data::Tags::InitialData>;
     179              : 
     180              :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     181              :             typename ArrayIndex, typename ActionList,
     182              :             typename ParallelComponent>
     183            0 :   static Parallel::iterable_action_return_t apply(
     184              :       db::DataBox<DbTagsList>& box,
     185              :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
     186              :       Parallel::GlobalCache<Metavariables>& cache,
     187              :       const ArrayIndex& array_index, const ActionList /*meta*/,
     188              :       const ParallelComponent* const parallel_component) {
     189              :     // Dispatch to the correct `apply` overload based on type of initial data
     190              :     using initial_data_classes =
     191              :         tmpl::at<typename Metavariables::factory_creation::factory_classes,
     192              :                  evolution::initial_data::InitialData>;
     193              :     return call_with_dynamic_type<Parallel::iterable_action_return_t,
     194              :                                   initial_data_classes>(
     195              :         &db::get<evolution::initial_data::Tags::InitialData>(box),
     196              :         [&box, &cache, &array_index,
     197              :          &parallel_component](const auto* const initial_data) {
     198              :           return apply(make_not_null(&box), *initial_data, cache, array_index,
     199              :                        parallel_component);
     200              :         });
     201              :   }
     202              : 
     203              :  private:
     204            0 :   static constexpr size_t Dim = 3;
     205              : 
     206              :   // Numeric initial data
     207              :   template <typename DbTagsList, typename Metavariables, typename ArrayIndex,
     208              :             typename ParallelComponent>
     209            0 :   static Parallel::iterable_action_return_t apply(
     210              :       const gsl::not_null<db::DataBox<DbTagsList>*> /*box*/,
     211              :       const NumericInitialData& initial_data,
     212              :       Parallel::GlobalCache<Metavariables>& cache,
     213              :       const ArrayIndex& array_index, const ParallelComponent* const /*meta*/) {
     214              :     // If we are using GH Numeric ID, then we don't have to set Pi and Phi since
     215              :     // we are reading them in. Also we only need to mutate this tag once so do
     216              :     // it on the first element.
     217              :     if (is_zeroth_element(array_index) and
     218              :         std::holds_alternative<gh::NumericInitialData::GhVars>(
     219              :             initial_data.gh_numeric_id().selected_variables())) {
     220              :       Parallel::mutate<gh::Tags::SetPiAndPhiFromConstraints,
     221              :                        gh::gauges::SetPiAndPhiFromConstraintsCacheMutator>(
     222              :           cache, false);
     223              :     }
     224              :     // Select the subset of the available variables that we want to read from
     225              :     // the volume data file
     226              :     tuples::tagged_tuple_from_typelist<db::wrap_tags_in<
     227              :         importers::Tags::Selected, NumericInitialData::all_vars>>
     228              :         selected_fields{};
     229              :     initial_data.select_for_import(make_not_null(&selected_fields));
     230              :     // Dispatch loading the variables from the volume data file
     231              :     // - Not using `ckLocalBranch` here to make sure the simple action
     232              :     //   invocation is asynchronous.
     233              :     auto& reader_component = Parallel::get_parallel_component<
     234              :         importers::ElementDataReader<Metavariables>>(cache);
     235              :     Parallel::simple_action<importers::Actions::ReadAllVolumeDataAndDistribute<
     236              :         3, NumericInitialData::all_vars, ParallelComponent>>(
     237              :         reader_component, initial_data.importer_options(),
     238              :         initial_data.volume_data_id(), std::move(selected_fields));
     239              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     240              :   }
     241              : 
     242              :   // "AnalyticData"-type initial data
     243              :   template <typename DbTagsList, typename InitialData, typename Metavariables,
     244              :             typename ArrayIndex, typename ParallelComponent>
     245            0 :   static Parallel::iterable_action_return_t apply(
     246              :       const gsl::not_null<db::DataBox<DbTagsList>*> box,
     247              :       const InitialData& initial_data,
     248              :       Parallel::GlobalCache<Metavariables>& /*cache*/,
     249              :       const ArrayIndex& /*array_index*/,
     250              :       const ParallelComponent* const /*meta*/) {
     251              :     // Get ADM + hydro variables from analytic data / solution
     252              :     const auto& [coords, mesh, inv_jacobian] = [&box]() {
     253              :       if constexpr (db::tag_is_retrievable_v<
     254              :                         evolution::dg::subcell::Tags::ActiveGrid,
     255              :                         db::DataBox<DbTagsList>>) {
     256              :         const bool on_subcell =
     257              :             db::get<evolution::dg::subcell::Tags::ActiveGrid>(*box) ==
     258              :             evolution::dg::subcell::ActiveGrid::Subcell;
     259              :         if (on_subcell) {
     260              :           return std::forward_as_tuple(
     261              :               db::get<evolution::dg::subcell::Tags::Coordinates<
     262              :                   Dim, Frame::Inertial>>(*box),
     263              :               db::get<evolution::dg::subcell::Tags::Mesh<Dim>>(*box),
     264              :               db::get<evolution::dg::subcell::fd::Tags::
     265              :                           InverseJacobianLogicalToInertial<Dim>>(*box));
     266              :         }
     267              :       }
     268              :       return std::forward_as_tuple(
     269              :           db::get<domain::Tags::Coordinates<Dim, Frame::Inertial>>(*box),
     270              :           db::get<domain::Tags::Mesh<Dim>>(*box),
     271              :           db::get<domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
     272              :                                                 Frame::Inertial>>(*box));
     273              :     }();
     274              :     auto vars = evolution::Initialization::initial_data(
     275              :         initial_data, coords, db::get<::Tags::Time>(*box),
     276              :         tmpl::append<tmpl::list<gr::Tags::SpatialMetric<DataVector, 3>,
     277              :                                 gr::Tags::Lapse<DataVector>,
     278              :                                 gr::Tags::Shift<DataVector, 3>,
     279              :                                 gr::Tags::ExtrinsicCurvature<DataVector, 3>>,
     280              :                      hydro::grmhd_tags<DataVector>>{});
     281              :     const auto& spatial_metric =
     282              :         get<gr::Tags::SpatialMetric<DataVector, 3>>(vars);
     283              :     const auto& lapse = get<gr::Tags::Lapse<DataVector>>(vars);
     284              :     const auto& shift = get<gr::Tags::Shift<DataVector, 3>>(vars);
     285              :     const auto& extrinsic_curvature =
     286              :         get<gr::Tags::ExtrinsicCurvature<DataVector, 3>>(vars);
     287              : 
     288              :     // Compute GH vars from ADM vars
     289              :     db::mutate<gr::Tags::SpacetimeMetric<DataVector, 3>,
     290              :                gh::Tags::Pi<DataVector, 3>, gh::Tags::Phi<DataVector, 3>>(
     291              :         &gh::initial_gh_variables_from_adm<3>, box, spatial_metric, lapse,
     292              :         shift, extrinsic_curvature, mesh, inv_jacobian, coords);
     293              : 
     294              :     // Move hydro vars directly into the DataBox
     295              :     tmpl::for_each<hydro::grmhd_tags<DataVector>>(
     296              :         [&box, &vars](const auto tag_v) {
     297              :           using tag = tmpl::type_from<std::decay_t<decltype(tag_v)>>;
     298              :           Initialization::mutate_assign<tmpl::list<tag>>(
     299              :               box, std::move(get<tag>(vars)));
     300              :         });
     301              : 
     302              :     // No need to import numeric initial data, so we terminate the phase by
     303              :     // pausing the algorithm on this element
     304              :     return {Parallel::AlgorithmExecution::Pause, std::nullopt};
     305              :   }
     306              : };
     307              : 
     308              : /*!
     309              :  * \brief Receive numeric initial data loaded by
     310              :  * grmhd::GhValenciaDivClean::Actions::SetInitialData.
     311              :  *
     312              :  * Place this action in the action list after
     313              :  * grmhd::GhValenciaDivClean::Actions::SetInitialData to wait until the
     314              :  * data for this element has arrived, and then compute the GH variables and the
     315              :  * remaining primitive variables and store them in the DataBox to be used as
     316              :  * initial data.
     317              :  *
     318              :  * This action modifies the GH system tags (spacetime metric, pi, phi) and the
     319              :  * tags listed in `hydro::grmhd_tags` in the DataBox (i.e., the hydro
     320              :  * primitives). It does not modify conservative variables, so it relies on a
     321              :  * primitive-to-conservative update in the action list before the evolution can
     322              :  * start.
     323              :  *
     324              :  * \requires This action requires an equation of state, which is retrieved from
     325              :  * the DataBox as `hydro::Tags::GrmhdEquationOfState`.
     326              :  */
     327            1 : struct ReceiveNumericInitialData {
     328            0 :   static constexpr size_t Dim = 3;
     329            0 :   using inbox_tags =
     330              :       tmpl::list<importers::Tags::VolumeData<NumericInitialData::all_vars>>;
     331              : 
     332              :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
     333              :             typename ActionList, typename ParallelComponent>
     334            0 :   static Parallel::iterable_action_return_t apply(
     335              :       db::DataBox<DbTagsList>& box, tuples::TaggedTuple<InboxTags...>& inboxes,
     336              :       const Parallel::GlobalCache<Metavariables>& /*cache*/,
     337              :       const ElementId<Dim>& /*element_id*/, const ActionList /*meta*/,
     338              :       const ParallelComponent* const /*meta*/) {
     339              :     auto& inbox =
     340              :         tuples::get<importers::Tags::VolumeData<NumericInitialData::all_vars>>(
     341              :             inboxes);
     342              :     const auto& initial_data = dynamic_cast<const NumericInitialData&>(
     343              :         db::get<evolution::initial_data::Tags::InitialData>(box));
     344              :     const size_t volume_data_id = initial_data.volume_data_id();
     345              :     if (inbox.find(volume_data_id) == inbox.end()) {
     346              :       return {Parallel::AlgorithmExecution::Retry, std::nullopt};
     347              :     }
     348              :     auto numeric_data = std::move(inbox.extract(volume_data_id).mapped());
     349              : 
     350              :     const auto& [coords, mesh, inv_jacobian] = [&box]() {
     351              :       if constexpr (db::tag_is_retrievable_v<
     352              :                         evolution::dg::subcell::Tags::ActiveGrid,
     353              :                         db::DataBox<DbTagsList>>) {
     354              :         const bool on_subcell =
     355              :             db::get<evolution::dg::subcell::Tags::ActiveGrid>(box) ==
     356              :             evolution::dg::subcell::ActiveGrid::Subcell;
     357              :         if (on_subcell) {
     358              :           return std::forward_as_tuple(
     359              :               db::get<evolution::dg::subcell::Tags::Coordinates<
     360              :                   Dim, Frame::Inertial>>(box),
     361              :               db::get<evolution::dg::subcell::Tags::Mesh<Dim>>(box),
     362              :               db::get<evolution::dg::subcell::fd::Tags::
     363              :                           InverseJacobianLogicalToInertial<Dim>>(box));
     364              :         }
     365              :       }
     366              :       return std::forward_as_tuple(
     367              :           db::get<domain::Tags::Coordinates<Dim, Frame::Inertial>>(box),
     368              :           db::get<domain::Tags::Mesh<Dim>>(box),
     369              :           db::get<domain::Tags::InverseJacobian<Dim, Frame::ElementLogical,
     370              :                                                 Frame::Inertial>>(box));
     371              :     }();
     372              :     const auto& equation_of_state =
     373              :         db::get<hydro::Tags::GrmhdEquationOfState>(box);
     374              : 
     375              :     db::mutate<gr::Tags::SpacetimeMetric<DataVector, 3>,
     376              :                gh::Tags::Pi<DataVector, 3>, gh::Tags::Phi<DataVector, 3>,
     377              :                hydro::Tags::RestMassDensity<DataVector>,
     378              :                hydro::Tags::ElectronFraction<DataVector>,
     379              :                hydro::Tags::SpecificInternalEnergy<DataVector>,
     380              :                hydro::Tags::SpatialVelocity<DataVector, 3>,
     381              :                hydro::Tags::MagneticField<DataVector, 3>,
     382              :                hydro::Tags::DivergenceCleaningField<DataVector>,
     383              :                hydro::Tags::LorentzFactor<DataVector>,
     384              :                hydro::Tags::Pressure<DataVector>,
     385              :                hydro::Tags::Temperature<DataVector>>(
     386              :         [&initial_data, &numeric_data, &equation_of_state](
     387              :             const gsl::not_null<tnsr::aa<DataVector, 3>*> spacetime_metric,
     388              :             const gsl::not_null<tnsr::aa<DataVector, 3>*> pi,
     389              :             const gsl::not_null<tnsr::iaa<DataVector, 3>*> phi,
     390              :             const gsl::not_null<Scalar<DataVector>*> rest_mass_density,
     391              :             const gsl::not_null<Scalar<DataVector>*> electron_fraction,
     392              :             const gsl::not_null<Scalar<DataVector>*> specific_internal_energy,
     393              :             const gsl::not_null<tnsr::I<DataVector, 3>*> spatial_velocity,
     394              :             const gsl::not_null<tnsr::I<DataVector, 3>*> magnetic_field,
     395              :             const gsl::not_null<Scalar<DataVector>*> div_cleaning_field,
     396              :             const gsl::not_null<Scalar<DataVector>*> lorentz_factor,
     397              :             const gsl::not_null<Scalar<DataVector>*> pressure,
     398              :             const gsl::not_null<Scalar<DataVector>*> temperature,
     399              :             const auto& local_mesh, const auto& local_inv_jacobian,
     400              :             const auto& local_inertial_coords) {
     401              :           initial_data.set_initial_data(
     402              :               spacetime_metric, pi, phi, rest_mass_density, electron_fraction,
     403              :               specific_internal_energy, spatial_velocity, magnetic_field,
     404              :               div_cleaning_field, lorentz_factor, pressure, temperature,
     405              :               make_not_null(&numeric_data), local_mesh, local_inv_jacobian,
     406              :               local_inertial_coords, equation_of_state);
     407              :         },
     408              :         make_not_null(&box), mesh, inv_jacobian, coords);
     409              : 
     410              :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     411              :   }
     412              : };
     413              : 
     414              : }  // namespace Actions
     415              : 
     416              : }  // namespace grmhd::GhValenciaDivClean
        

Generated by: LCOV version 2.0-1