SpECTRE Documentation Coverage Report
Current view: top level - Evolution/Particles/MonteCarlo - TemplatedLocalFunctions.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 75.0 % 8 6
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 <array>
       7              : #include <optional>
       8              : #include <random>
       9              : #include <vector>
      10              : 
      11              : #include "DataStructures/Tensor/TypeAliases.hpp"
      12              : 
      13              : /// \cond
      14              : class DataVector;
      15              : 
      16              : template <size_t Dim, typename T>
      17              : class DirectionalIdMap;
      18              : 
      19              : namespace Frame {
      20              : struct Fluid;
      21              : }  // namespace Frame
      22              : 
      23              : namespace gsl {
      24              :   template <typename T>
      25              :   class not_null;
      26              : }  // namespace gsl
      27              : 
      28              : template<size_t Dim>
      29              : class Mesh;
      30              : 
      31              : namespace Particles::MonteCarlo {
      32              : template<size_t EnergyBins,size_t NeutrinoSpecies>
      33              : class NeutrinoInteractionTable;
      34              : 
      35              : struct Packet;
      36              : }  // namespace Particles::MonteCarlo
      37              : 
      38              : namespace EquationsOfState {
      39              : template <bool IsRelativistic, size_t ThermodynamicDim>
      40              : class EquationOfState;
      41              : }  // namespace EquationsOfState
      42              : /// \endcond
      43              : 
      44              : /// Items related to the evolution of particles
      45              : /// Items related to Monte-Carlo radiation transport
      46              : namespace Particles::MonteCarlo {
      47              : 
      48              : namespace detail {
      49              : 
      50              : void draw_single_packet(gsl::not_null<double*> time,
      51              :                         gsl::not_null<std::array<double, 3>*> coord,
      52              :                         gsl::not_null<std::array<double, 3>*> momentum,
      53              :                         gsl::not_null<std::mt19937*> random_number_generator);
      54              : }  // namespace detail
      55              : 
      56              : 
      57              : /// Structure containing Monte-Carlo function templated on EnergyBins
      58              : /// and/or NeutrinoSpecies
      59              : template <size_t EnergyBins, size_t NeutrinoSpecies>
      60            1 : struct TemplatedLocalFunctions {
      61              :   /*!
      62              :    * \brief Function to take a single Monte Carlo time step on a
      63              :    * finite difference element.
      64              :    */
      65            1 :   void take_time_step_on_element(
      66              :       gsl::not_null<std::vector<Packet>*> packets,
      67              :       gsl::not_null<Scalar<DataVector>*> coupling_tilde_tau,
      68              :       gsl::not_null<Scalar<DataVector>*> coupling_tilde_ye,
      69              :       gsl::not_null<tnsr::i<DataVector, 3>*> coupling_tilde_s,
      70              :       gsl::not_null<std::mt19937*> random_number_generator,
      71              :       gsl::not_null<std::array<DataVector, NeutrinoSpecies>*>
      72              :           single_packet_energy,
      73              : 
      74              :       double start_time, double target_end_time,
      75              :       const EquationsOfState::EquationOfState<true, 3>& equation_of_state,
      76              :       const NeutrinoInteractionTable<EnergyBins, NeutrinoSpecies>&
      77              :           interaction_table,
      78              :       const Scalar<DataVector>& electron_fraction,
      79              :       const Scalar<DataVector>& rest_mass_density,
      80              :       const Scalar<DataVector>& temperature,
      81              :       const Scalar<DataVector>& lorentz_factor,
      82              :       const tnsr::i<DataVector, 3, Frame::Inertial>&
      83              :           lower_spatial_four_velocity,
      84              :       const Scalar<DataVector>& lapse,
      85              :       const tnsr::I<DataVector, 3, Frame::Inertial>& shift,
      86              :       const tnsr::i<DataVector, 3, Frame::Inertial>& d_lapse,
      87              :       const tnsr::iJ<DataVector, 3, Frame::Inertial>& d_shift,
      88              :       const tnsr::iJJ<DataVector, 3, Frame::Inertial>& d_inv_spatial_metric,
      89              :       const tnsr::ii<DataVector, 3, Frame::Inertial>& spatial_metric,
      90              :       const tnsr::II<DataVector, 3, Frame::Inertial>& inv_spatial_metric,
      91              :       const Scalar<DataVector>& sqrt_determinant_spatial_metric,
      92              :       const Scalar<DataVector>& cell_light_crossing_time, const Mesh<3>& mesh,
      93              :       const tnsr::I<DataVector, 3, Frame::ElementLogical>& mesh_coordinates,
      94              :       size_t num_ghost_zones,
      95              :       const std::optional<tnsr::I<DataVector, 3, Frame::Inertial>>&
      96              :           mesh_velocity,
      97              :       const InverseJacobian<DataVector, 3, Frame::ElementLogical,
      98              :                             Frame::Inertial>&
      99              :           inverse_jacobian_logical_to_inertial,
     100              :       const Scalar<DataVector>& det_jacobian_logical_to_inertial,
     101              :       const Jacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     102              :           inertial_to_fluid_jacobian,
     103              :       const InverseJacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     104              :           inertial_to_fluid_inverse_jacobian,
     105              :       const DirectionalIdMap<3, std::optional<DataVector>>&
     106              :           electron_fraction_ghost,
     107              :       const DirectionalIdMap<3, std::optional<DataVector>>&
     108              :           baryon_density_ghost,
     109              :       const DirectionalIdMap<3, std::optional<DataVector>>& temperature_ghost,
     110              :       const DirectionalIdMap<3, std::optional<DataVector>>&
     111              :           cell_light_crossing_time_ghost);
     112              : 
     113              :   /*!
     114              :    * \brief Function emitting Monte Carlo packets
     115              :    *
     116              :    * We emit a total energy emissivity_in_cell * cell_proper_four_volume
     117              :    * for each grid
     118              :    * cell, neutrino species, and neutrino energy bin. We aim for packets of
     119              :    * energy single_packet_energy in the fluid frame. The number of packets
     120              :    * is, in each bin b and for each species s,
     121              :    * `N = emission_in_cell[s][b] / single_packet_energy[s]`
     122              :    * and randomly rounded up or down to get integer number of packets (i.e.
     123              :    * if we want N=2.6 packets, there is a 60 percent chance of creating a 3rd
     124              :    * packet). The position of the packets is drawn from a homogeneous
     125              :    * distribution in the logical frame, and the direction of propagation of the
     126              :    * neutrinos is drawn from an isotropic distribution in the fluid frame.
     127              :    * Specifically, the 4-momentum of a packet of energy nu in the fluid frame
     128              :    * is
     129              :    * \f{align}
     130              :    * p^t &= \nu \\
     131              :    * p^x &= \nu * sin(\theta) * cos(\phi) \\
     132              :    * p^y &= \nu * sin(\theta) * sin(\phi) \\
     133              :    * p^z &= \nu * cos(theta)
     134              :    * \f}
     135              :    * with \f$cos(\theta)\f$ drawn from a uniform distribution in [-1,1] and
     136              :    * \f$\phi\f$ from a uniform distribution in \f$[0,2*\pi]\f$. We
     137              :    * transform to the inertial frame \f$p_t\f$ and \f$p^x,p^y,p^z\f$ using the
     138              :    * jacobian/inverse jacobian passed as option. The number of neutrinos in
     139              :    * each packet is defined as
     140              :    * `n = single_packet_energy[s] / energy_at_bin_center[b]`
     141              :    * Note that the packet energy is in code units and energy of a bin in MeV.
     142              :    *
     143              :    * All tensors are assumed to correspond to live points only, except for
     144              :    * the coupling terms and emissivity, which include ghost zones.
     145              :    */
     146            1 :   void emit_packets(
     147              :       gsl::not_null<std::vector<Packet>*> packets,
     148              :       gsl::not_null<std::mt19937*> random_number_generator,
     149              :       gsl::not_null<Scalar<DataVector>*> coupling_tilde_tau,
     150              :       gsl::not_null<tnsr::i<DataVector, 3, Frame::Inertial>*> coupling_tilde_s,
     151              :       gsl::not_null<Scalar<DataVector>*> coupling_rho_ye,
     152              :       const double& time_start_step, const double& time_step,
     153              :       const Mesh<3>& mesh, size_t num_ghost_zones,
     154              :       const std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>&
     155              :           emissivity_in_cell,
     156              :       const std::array<DataVector, NeutrinoSpecies>& single_packet_energy,
     157              :       const std::array<double, EnergyBins>& energy_at_bin_center,
     158              :       const Scalar<DataVector>& lorentz_factor,
     159              :       const tnsr::i<DataVector, 3, Frame::Inertial>&
     160              :           lower_spatial_four_velocity,
     161              :       const Jacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     162              :           inertial_to_fluid_jacobian,
     163              :       const InverseJacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     164              :         inertial_to_fluid_inverse_jacobian,
     165              :       const Scalar<DataVector>& cell_proper_four_volume);
     166              : 
     167              :   /*!
     168              :    * \brief Evolve Monte-Carlo packets within an element.
     169              :    *
     170              :    * Evolve packets until (approximately) the provided final time
     171              :    * following the methods of \cite Foucart2021mcb.
     172              :    * The vector of Packets should contain all MC packets that we wish
     173              :    * to advance in time. Note that this function only handles
     174              :    * propagation / absorption / scattering of packets, but not
     175              :    * emission. The final time of the packet may differ from the
     176              :    * desired final time by up to 5 percent, due to the fact that when
     177              :    * using the diffusion approximation (for large scattering
     178              :    * opacities) we take fixed time steps in the fluid frame,
     179              :    * leading to unpredictable time steps in the inertial frame.
     180              :    *
     181              :    * The absorption and scattering opacity tables include ghost
     182              :    * zones, and so do the coupling terms. Other variables are
     183              :    * only using live points.
     184              :    */
     185            1 :   void evolve_packets(
     186              :       gsl::not_null<std::vector<Packet>*> packets,
     187              :       gsl::not_null<std::mt19937*> random_number_generator,
     188              :       gsl::not_null<Scalar<DataVector>*> coupling_tilde_tau,
     189              :       gsl::not_null<tnsr::i<DataVector, 3, Frame::Inertial>*> coupling_tilde_s,
     190              :       gsl::not_null<Scalar<DataVector>*> coupling_rho_ye, double final_time,
     191              :       const Mesh<3>& mesh,
     192              :       const tnsr::I<DataVector, 3, Frame::ElementLogical>& mesh_coordinates,
     193              :       size_t num_ghost_zones,
     194              :       const std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>&
     195              :           absorption_opacity_table,
     196              :       const std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>&
     197              :           scattering_opacity_table,
     198              :       const std::array<double, EnergyBins>& energy_at_bin_center,
     199              :       const Scalar<DataVector>& lorentz_factor,
     200              :       const tnsr::i<DataVector, 3, Frame::Inertial>&
     201              :           lower_spatial_four_velocity,
     202              :       const Scalar<DataVector>& lapse,
     203              :       const tnsr::I<DataVector, 3, Frame::Inertial>& shift,
     204              :       const tnsr::i<DataVector, 3, Frame::Inertial>& d_lapse,
     205              :       const tnsr::iJ<DataVector, 3, Frame::Inertial>& d_shift,
     206              :       const tnsr::iJJ<DataVector, 3, Frame::Inertial>& d_inv_spatial_metric,
     207              :       const tnsr::ii<DataVector, 3, Frame::Inertial>& spatial_metric,
     208              :       const tnsr::II<DataVector, 3, Frame::Inertial>& inv_spatial_metric,
     209              :       const Scalar<DataVector>& cell_light_crossing_time,
     210              :       const std::optional<tnsr::I<DataVector, 3, Frame::Inertial>>&
     211              :           mesh_velocity,
     212              :       const InverseJacobian<DataVector, 3, Frame::ElementLogical,
     213              :                             Frame::Inertial>&
     214              :           inverse_jacobian_logical_to_inertial,
     215              :       const Jacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     216              :           inertial_to_fluid_jacobian,
     217              :       const InverseJacobian<DataVector, 4, Frame::Inertial, Frame::Fluid>&
     218              :           inertial_to_fluid_inverse_jacobian);
     219              : 
     220              :   /// Interpolate the opacities from values tabulated as a function of
     221              :   /// neutrino energy in the fluid frame, to the value at the given
     222              :   /// fluid frame energy.
     223              :   /// We interpolate the logarithm of the opacity, linearly in fluid
     224              :   /// frame energy.
     225            1 :   void interpolate_opacities_at_fluid_energy(
     226              :       gsl::not_null<double*> absorption_opacity_packet,
     227              :       gsl::not_null<double*> scattering_opacity_packet,
     228              :       double fluid_frame_energy, size_t species, size_t index,
     229              :       const std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>&
     230              :           absorption_opacity_table,
     231              :       const std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>&
     232              :           scattering_opacity_table,
     233              :       const std::array<double, EnergyBins>& energy_at_bin_center);
     234              : 
     235              :   /// Function responsible to correct emissivity, absorption, and scattering
     236              :   /// rates in regions where there is a stiff coupling between the neutrinos
     237              :   /// and the fluid. This is done by transferring a fraction
     238              :   /// fraction_ka_to_ks of the absorption opacity to scattering opacity,
     239              :   /// while multiplying the emissivity by ( 1 - fraction_ka_to_ks ) to
     240              :   /// keep the equilibrium energy density constant.
     241            1 :   void implicit_monte_carlo_interaction_rates(
     242              :       gsl::not_null<
     243              :           std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>*>
     244              :           emissivity_in_cell,
     245              :       gsl::not_null<
     246              :           std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>*>
     247              :           absorption_opacity,
     248              :       gsl::not_null<
     249              :           std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>*>
     250              :           scattering_opacity,
     251              :       gsl::not_null<
     252              :           std::array<std::array<DataVector, EnergyBins>, NeutrinoSpecies>*>
     253              :           fraction_ka_to_ks,
     254              :       const Scalar<DataVector>& cell_light_crossing_time,
     255              :       const Scalar<DataVector>& electron_fraction,
     256              :       const Scalar<DataVector>& rest_mass_density,
     257              :       const Scalar<DataVector>& temperature, double minimum_temperature,
     258              :       const NeutrinoInteractionTable<EnergyBins, NeutrinoSpecies>&
     259              :           interaction_table,
     260              :       const EquationsOfState::EquationOfState<true, 3>& equation_of_state);
     261              : 
     262              :   // Floor for opacity values (absorption or scattering).
     263              :   // This is used in two places. First, when interpolating opacities
     264              :   // in energy space, we interpolate log(max(kappa,opacity_floor)),
     265              :   // with kappa the tabulated value. Second, if kappa = opacity_floor
     266              :   // for some interaction, we assume that the interaction never happens.
     267            0 :   const double opacity_floor = 1.e-100;
     268              : };
     269              : 
     270              : }  // namespace Particles::MonteCarlo
        

Generated by: LCOV version 2.0-1