25#include "HepMC3/Attribute.h"
26#include "HepMC3/GenEvent.h"
29#include "marley/DiscreteNuclearReaction.hh"
30#include "marley/Error.hh"
31#include "marley/Generator.hh"
32#include "marley/JSON.hh"
33#include "marley/JSONConfig.hh"
34#include "marley/LeptonFactors.hh"
35#include "marley/Level.hh"
36#include "marley/Logger.hh"
37#include "marley/MatrixElement.hh"
38#include "marley/NuclearFormFactor.hh"
39#include "marley/NucleonFormFactors.hh"
40#include "marley/NuclearResponses.hh"
41#include "marley/Integrator.hh"
42#include "marley/marley_utils.hh"
48 constexpr int BOGUS_TWO_J_VALUE = -99999;
52 ProcType pt,
int pdg_a,
int pdg_b,
int pdg_c,
int pdg_d,
int q_d,
53 const std::shared_ptr< std::vector<marley::MatrixElement> >& mat_els,
62 int Zb = marley_utils::get_particle_Z(
pdg_b_ );
64 int Ab = marley_utils::get_particle_A(
pdg_b_ );
73 ::check_for_allowed_approximation( ff_config );
78std::shared_ptr< HepMC3::GenEvent > marley::DiscreteNuclearReaction
84 " The requested projectile particle ID, " + std::to_string(
pdg_a )
85 +
", does not match the projectile particle ID, " + std::to_string(
pdg_a_ )
86 +
", in the reaction dataset." );
90 if ( KEa <
KEa_threshold_ )
throw std::range_error(
"Could not create"
91 " this event. Projectile kinetic energy " + std::to_string( KEa )
92 +
" MeV is below the threshold value " + std::to_string(
KEa_threshold_ )
100 std::vector<double> level_weights;
106 static std::discrete_distribution< size_t > ldist;
117 &level_weights,
false );
127 if ( level_weights.empty() ) {
128 throw marley::Error(
"Could not create this event. The DecayScheme object"
129 " associated with this reaction does not contain data for any"
130 " kinematically accessible levels for a projectile kinetic energy of "
131 + std::to_string( KEa ) +
" MeV (max E_level = "
138 if ( sum_of_xsecs <= 0. ) {
139 throw marley::Error(
"Could not create this event. All kinematically"
140 " accessible levels for a projectile kinetic energy of "
141 + std::to_string( KEa ) +
" MeV (max E_level = "
143 +
" MeV) have vanishing matrix elements." );
148 std::discrete_distribution<size_t>::param_type params( level_weights.begin(),
149 level_weights.end() );
158 double E_level = sampled_matrix_el.level_energy();
167 double s, Ec_cm, pc_cm, Ed_cm;
171 double beta_c_cm = pc_cm / Ec_cm;
180 marley_utils::two_pi,
false );
185 int twoJ = BOGUS_TWO_J_VALUE;
195 sdb.get_gs_spin_parity(
pdg_b_, twoJ_gs, P_gs );
201 twoJ = final_lev->
twoJ();
215 if ( sampled_matrix_el.type() == ME_Type::FERMI ) {
219 else if ( sampled_matrix_el.type() == ME_Type::GAMOW_TELLER ) {
226 if ( twoJ_gs == 0 ) twoJ = 2;
233 std::vector<int> allowed_twoJs;
234 std::vector<double> ld_weights;
236 auto& ldm = sdb.get_level_density_model(
pdg_d_ );
238 for (
int myTwoJ = std::abs(twoJ_gs - 2); myTwoJ <= twoJ_gs + 2;
241 allowed_twoJs.push_back( myTwoJ );
242 ld_weights.push_back( ldm.level_density(E_level, myTwoJ, P) );
245 std::discrete_distribution<size_t> my_twoJ_dist( ld_weights.begin(),
249 twoJ = allowed_twoJs.at( my_index );
252 else throw marley::Error(
"Unrecognized matrix element type encountered"
253 " in marley::DiscreteNuclearReaction::create_event()" );
256 MARLEY_LOG( DEBUG,
"physics.reaction" ) <<
"Sampled a "
257 << sampled_matrix_el.type_str()
259 <<
" ground state (with spin-parity " <<
static_cast<double>( twoJ_gs ) / 2.
261 <<
" level with Ex = " << E_level <<
" MeV and spin-parity "
262 <<
static_cast<double>( twoJ ) / 2. << P;
267 phi_c_cm, Ec_cm, Ed_cm, E_level, twoJ, P );
270 event->add_attribute(
"me_index",
271 std::make_shared< HepMC3::IntAttribute >(
272 static_cast<int>( me_index ) ) );
284 double dummy_cos_theta = 0.;
292 ME_Type mat_el_type )
const
294 double dummy_cos_theta = 0.;
295 std::vector< double > level_xsecs;
303 for (
size_t j = 0u; j < level_xsecs.size(); ++j ) {
305 if ( ml.type() == mat_el_type ) {
306 xsec += level_xsecs.at( j );
316 double cos_theta_c_cm )
const
326 double& beta_c_cm,
bool check_max_E_level )
const
329 if ( std::abs(cos_theta_c_cm) > 1. )
return 0.;
332 if ( mat_el.
strength() == 0. )
return 0.;
338 if ( check_max_E_level ) {
351 double s = std::pow(
ma_ +
mb_, 2 ) + 2.*
mb_*KEa;
352 double sqrt_s = std::sqrt( s );
355 double Eb_cm = ( s +
mb_*
mb_ -
ma_*
ma_ ) / ( 2. * sqrt_s );
357 double Ea_cm = sqrt_s - Eb_cm;
358 double pa_cm = marley_utils::real_sqrt( std::pow(Ea_cm, 2) -
ma_*
ma_ );
360 double Ec_cm = ( s +
mc_*
mc_ - md2 ) / ( 2. * sqrt_s );
361 double pc_cm = marley_utils::real_sqrt( std::pow(Ec_cm, 2) -
mc_*
mc_ );
364 double omega_cm = Ea_cm - Ec_cm;
367 double kappa_cm = marley_utils::real_sqrt( std::pow( pa_cm, 2 )
368 + std::pow( pc_cm, 2 ) - 2. * pa_cm * pc_cm * cos_theta_c_cm );
371 double Q2 = kappa_cm*kappa_cm - omega_cm*omega_cm;
374 beta_c_cm = pc_cm / Ec_cm;
377 double Ed_cm = sqrt_s - Ec_cm;
381 double diff_xsec_prefactor = ( marley_utils::GF2 / ( 2 * marley_utils::pi ) )
382 * ( Eb_cm * Ed_cm / s ) * Ec_cm * pc_cm;
389 double pc_dot_pd = Ed_cm*Ec_cm + std::pow( pc_cm, 2 );
393 double beta_rel_cd = marley_utils::real_sqrt(
394 std::pow(pc_dot_pd, 2) -
mc_*
mc_*md2 ) / pc_dot_pd;
400 diff_xsec_prefactor *= marley_utils::Vud2 * factor_C;
406 if ( mat_el.
type() == ME_Type::FERMI ) {
408 diff_xsec_prefactor *= 0.25*std::pow( Q_w, 2 );
411 else throw marley::Error(
"Unrecognized or invalid process type encountered"
412 " in marley::DiscreteNuclearReaction::diff_xs()" );
419 int helicity = marley_utils::get_particle_helicity(
pdg_a_ );
420 double sin2_theta_c_cm = 1. - cos_theta_c_cm*cos_theta_c_cm;
421 double vcc = 1. + beta_c_cm * cos_theta_c_cm;
422 double vll = vcc - 2.*Ea_cm*Ec_cm*sin2_theta_c_cm
423 * beta_c_cm*beta_c_cm/kappa_cm/kappa_cm;
424 double vcl = -1.* ( omega_cm*vcc/kappa_cm +
mc_*
mc_/Ec_cm/kappa_cm );
425 double vT = 1. - beta_c_cm*cos_theta_c_cm + Ea_cm*Ec_cm
426 * beta_c_cm*beta_c_cm*sin2_theta_c_cm/kappa_cm/kappa_cm;
427 double vTprime = helicity * ( (Ea_cm + Ec_cm)
428 * (1. - beta_c_cm*cos_theta_c_cm)/kappa_cm -
mc_*
mc_/kappa_cm/Ec_cm );
439 double strength_eff = mat_el.
strength();
440 strength_eff *= std::pow(
nuclear_ff_->F( kappa_cm_eff ), 2 );
445 double rCC, rCL, rLL, rTvv, rTaa, rTprime;
446 const double kM = kappa_cm_eff / marley_utils::m_nucleon;
447 const double k2M = kappa_cm_eff * kappa_cm_eff / marley_utils::m_nucleon;
449 if ( mat_el.
type() == ME_Type::FERMI ) {
451 strength_eff *= F1*F1 / marley_utils::g_V2;
454 rCL = strength_eff * kM;
455 rLL = strength_eff * kM * kM / 4.;
460 else if ( mat_el.
type() == ME_Type::GAMOW_TELLER ) {
462 strength_eff *= FA*FA / marley_utils::g_A2;
468 double FPA = FP / FA;
469 double F12A = ( F1 + 2. * marley_utils::m_nucleon * F2 ) / FA;
471 rCC = strength_eff * kM * kM / 12. * ( 1. - 2.*omega_cm_eff*FPA
472 + omega_cm_eff*omega_cm_eff*FPA*FPA );
473 rCL = strength_eff * kM / 3. * ( 1. - (omega_cm_eff + 0.5*k2M)*FPA
474 + 0.5*omega_cm_eff*k2M*FPA*FPA );
475 rLL = strength_eff * ( 1./3. - k2M/3.*FPA + k2M*k2M/12.*FPA*FPA );
477 rTaa = strength_eff * ( 2./3. + kM*kM/6.*F12A*F12A );
478 rTprime = -1. * strength_eff * 2./3. * kM * F12A;
480 else throw marley::Error(
"Unrecognized matrix element type encountered in"
481 " marley::DiscreteNuclearReaction::diff_xs()" );
485 double diff_xsec = diff_xsec_prefactor * ( lf * nr );
493 bool check_max_E_level )
const
502 if ( mat_el.
strength() == 0. )
return 0.;
506 [ &mat_el, KEa, &beta_c_cm, check_max_E_level,
this ](
507 double cos_theta_cm ) ->
double
508 {
return this->
diff_xs( mat_el, KEa, cos_theta_cm, beta_c_cm,
509 check_max_E_level ); }, -1., 1.
512 MARLEY_LOG( DEBUG,
"physics.reaction.xsec" ) <<
"total xsec " <<
description_
513 <<
" to level with energy " << mat_el.
level_energy() <<
" MeV is "
514 << total_xsec <<
" MeV^(-2).";
521 double KEa,
double cos_theta_c_cm, std::vector<double>* level_xsecs,
522 bool differential )
const
533 if ( differential && std::abs(cos_theta_c_cm) > 1. )
return 0.;
537 if ( KEa <= 0. )
return 0.;
541 if ( level_xsecs ) level_xsecs->clear();
548 double level_energy = mat_el.level_energy();
551 if ( level_energy > max_E_level )
break;
556 double partial_xsec = 0.;
557 if ( mat_el.strength() != 0. ) {
563 double beta_c_cm = 0.;
567 if ( differential ) {
568 partial_xsec =
diff_xs( mat_el, KEa, cos_theta_c_cm, beta_c_cm,
false );
570 partial_xsec =
total_xs( mat_el, KEa, beta_c_cm,
false );
573 if ( std::isnan(partial_xsec) ) {
574 MARLEY_LOG( WARN,
"physics.reaction.xsec" )
575 <<
"Partial cross section for reaction "
577 MARLEY_LOG( DEBUG,
"physics.reaction.xsec" )
578 <<
"Parameters were level energy = "
579 << mat_el.level_energy() <<
" MeV, projectile kinetic energy = "
580 << KEa <<
" MeV, and reduced matrix element = " << mat_el.strength()
581 <<
". Differential was set to " << differential <<
".";
582 MARLEY_LOG( DEBUG,
"physics.reaction.xsec" )
583 <<
"The partial cross section to this level"
584 <<
" will be set to zero.";
588 xsec += partial_xsec;
597 if ( level_xsecs ) level_xsecs->push_back( partial_xsec );
611 double max = marley_utils::UNKNOWN_MAX;
615 if ( mat_el.
type() == ME_Type::FERMI ) {
616 max = this->
diff_xs( mat_el, KEa, 1., beta_c_cm,
false );
618 else if ( mat_el.
type() == ME_Type::GAMOW_TELLER ) {
619 max = this->
diff_xs( mat_el, KEa, -1., beta_c_cm,
false );
621 else throw marley::Error(
"Unrecognized matrix element type encountered"
622 " in marley::DiscreteNuclearReaction::sample_cos_theta_c_cm()" );
626 [ &mat_el, KEa, &beta_c_cm,
this ](
double cos_theta_cm ) ->
double
627 {
return this->
diff_xs( mat_el, KEa, cos_theta_cm, beta_c_cm,
false ); },
639 bool has_excited_state =
false;
641 if ( me.level_energy() > 0. ) {
642 has_excited_state =
true;
CoulombMode
Enumerated type used to set the method for handling Coulomb corrections for CC nuclear reactions.
double summed_xs_helper(int pdg_a, double KEa, double cos_theta_c_cm, std::vector< double > *level_xsecs, bool differential) const
NucleonFormFactors nucleon_form_factors_
Object that handles calculations of nucleon form factors.
bool allowed_approx_
Flag that indicates whether to include aditional terms beyond the q->0 limit.
std::shared_ptr< NuclearFormFactor > nuclear_ff_
Object that handles calculations of the nuclear form factor.
virtual double total_xs(int pdg_a, double KEa) const override
Total reaction cross section (MeV -2) including all kinematically-allowed final nuclear levels.
double diff_xs(const marley::MatrixElement &mat_el, double KEa, double cos_theta_c_cm, double &beta_c_cm, bool check_max_E_level) const
Differential cross section (MeV -2) evaluated in the center-of-momentum frame for a transition to a ...
CoulombCorrector coulomb_corrector_
Object that handles calculations of Coulomb correction factors.
DiscreteNuclearReaction(ProcessType pt, int pdg_a, int pdg_b, int pdg_c, int pdg_d, int q_d, const std::shared_ptr< std::vector< marley::MatrixElement > > &mat_els, CoulombCorrector::CoulombMode mode, const JSON &ff_config, const std::string &source_file)
std::shared_ptr< std::vector< marley::MatrixElement > > matrix_elements_
Matrix elements representing all of the possible nuclear transitions that may be caused by this react...
virtual void set_description() override
Creates the description string based on the PDG code values for the initial and final particles.
double sample_cos_theta_c_cm(const marley::MatrixElement &matrix_el, double KEa, double beta_c_cm, marley::Generator &gen) const
Samples a polar angle cosine for the ejectile using the relevant portion of the reaction nuclear matr...
Base class for all exceptions thrown by MARLEY functions.
The MARLEY Event generator.
double uniform_random_double(double min, double max, bool inclusive)
Sample a random number uniformly on either [min, max) or [min, max].
marley::StructureDatabase & get_structure_db()
Get a reference to the StructureDatabase owned by this Generator.
double rejection_sample(const std::function< double(double)> &f, double xmin, double xmax, double &fmax, double safety_factor=1.01, double max_search_tolerance=DEFAULT_REJECTION_SAMPLING_TOLERANCE_)
Sample from a given 1D probability density function f(x) on the interval [xmin, xmax] using a simple ...
auto sample_from_distribution(RandomNumberDistribution &rnd) -> decltype(std::declval< RandomNumberDistribution & >().operator()(std::declval< std::mt19937_64 & >()))
Sample from an arbitrary probability distribution (defined here as any object that implements an oper...
Numerical integrator that uses Clenshaw-Curtis quadrature
double num_integrate(const std::function< double(double)> &f, double a, double b) const
Numerically integrate an arbitrary 1D function.
A discrete nuclear energy level.
marley::Parity parity() const
Get the level parity.
int twoJ() const
Get two times the level spin.
A reduced nuclear matrix element that represents a transition caused by a neutrino-nucleus reaction.
TransitionType type() const
Get the kind of nuclear transition (e.g., Fermi, Gamow-Teller) represented by the matrix element.
double strength() const
Get the numerical value (dimensionless) of the matrix element.
double level_energy() const
Get the excitation energy (MeV) of the final-state nuclear level accessed by the matrix element.
TransitionType
Enumerated type that represents the possible kinds of nuclear transitions recognized by MARLEY.
double weak_nuclear_charge() const
virtual std::shared_ptr< HepMC3::GenEvent > make_nuclear_event_object(double KEa, double pc_cm, double cos_theta_c_cm, double phi_c_cm, double Ec_cm, double Ed_cm, double E_level, int twoJ, const marley::Parity &P) const
Helper function that makes a complete event object for a nuclear reaction.
virtual void set_description()
Creates the description string based on the PDG code values for the initial and final particles.
double max_level_energy(double KEa) const
Get the maximum possible excitation energy (MeV) of the final-state residue that is kinematically all...
NuclearReaction(ProcessType pt, int pdg_a, int pdg_b, int pdg_c, int pdg_d, int q_d, const std::string &source_file)
double KEa_threshold_
Lab-frame kinetic energy of the projectile at threshold for this reaction (i.e., the residue is produ...
double md_gs_
Ground state mass (MeV) of the residue.
Type-safe representation of a parity value (either +1 or -1)
int pdg_a_
PDG code for the projectile.
double md_
Residue mass (MeV)
ProcessType process_type_
Type of scattering process (CC, NC) represented by this reaction.
double mc_
Ejectile mass (MeV)
void two_two_scatter(double KEa, double &s, double &Ec_cm, double &pc_cm, double &Ed_cm) const
Helper function that handles CM frame kinematics for the reaction.
ProcessType
Enumerated type describing the kind of scattering process represented by a Reaction.
@ NC_Discrete
Nuclear matrix elements contain for a transition to a discrete nuclear level.
@ AntiNeutrinoCC_Discrete
Nuclear matrix elements contain for a transition to a discrete nuclear level.
@ NeutrinoCC_Discrete
Nuclear matrix elements contain for a transition to a discrete nuclear level.
const std::string & source_file() const
Get the resolved path of the reaction data file used to construct this Reaction.
std::string description_
String that contains a formula describing the reaction.
int pdg_d_
PDG code for the residue.
int pdg_a() const
Get the projectile PDG code.
int pdg_b_
PDG code for the target.
double ma_
Projectile mass (MeV)
int pdg_b() const
Get the target PDG code.
double mb_
Target mass (MeV)
An atomic target for a lepton scattering reaction.