22#include "HepMC3/Attribute.h"
23#include "HepMC3/GenEvent.h"
24#include "HepMC3/GenVertex.h"
25#include "HepMC3/GenParticle.h"
28#include "marley/DiscreteNuclearReaction.hh"
29#include "marley/ElectronReaction.hh"
30#include "marley/HauserFeshbachDecay.hh"
31#include "marley/JSON.hh"
32#include "marley/Logger.hh"
33#include "marley/MatrixElement.hh"
34#include "marley/Reaction.hh"
35#include "marley/StructureDatabase.hh"
36#include "marley/hepmc3_utils.hh"
37#include "marley/ContinuumNuclearReaction.hh"
38#include "marley/marley_kinematics.hh"
39#include "marley/marley_utils.hh"
46 using namespace marley_utils;
48 std::map<ProcType, std::string> proc_type_to_string_map {
49 { ProcType::Unknown,
"Unknown" },
50 { ProcType::NeutrinoCC_Discrete,
"\u03BD CC (Discrete)" },
51 { ProcType::AntiNeutrinoCC_Discrete,
"anti-\u03BD CC (Discrete)" },
52 { ProcType::NC_Discrete,
"NC (Discrete)" },
53 { ProcType::NuElectronElastic,
"(anti-)\u03BD + e- ES" },
54 { ProcType::NeutrinoCC_Continuum,
"\u03BD CC (Continuum)" },
55 { ProcType::AntiNeutrinoCC_Continuum,
"anti-\u03BD CC (Continuum)" },
56 { ProcType::NC_Continuum,
"NC (Continuum)" },
57 { ProcType::StandaloneDecay,
"Standalone Decay" },
62 std::map<ProcType, std::vector<int> > proc_type_to_nu_pdg = {
64 { ProcType::NeutrinoCC_Discrete,
65 { ELECTRON_NEUTRINO, MUON_NEUTRINO, TAU_NEUTRINO }
68 { ProcType::AntiNeutrinoCC_Discrete,
69 { ELECTRON_ANTINEUTRINO, MUON_ANTINEUTRINO, TAU_ANTINEUTRINO }
72 { ProcType::NC_Discrete,
73 { ELECTRON_NEUTRINO, MUON_NEUTRINO, TAU_NEUTRINO,
74 ELECTRON_ANTINEUTRINO, MUON_ANTINEUTRINO, TAU_ANTINEUTRINO }
77 { ProcType::NuElectronElastic,
78 { ELECTRON_NEUTRINO, MUON_NEUTRINO, TAU_NEUTRINO,
79 ELECTRON_ANTINEUTRINO, MUON_ANTINEUTRINO, TAU_ANTINEUTRINO }
82 { ProcType::NeutrinoCC_Continuum,
83 { ELECTRON_NEUTRINO, MUON_NEUTRINO, TAU_NEUTRINO }
86 { ProcType::AntiNeutrinoCC_Continuum,
87 { ELECTRON_ANTINEUTRINO, MUON_ANTINEUTRINO, TAU_ANTINEUTRINO }
90 { ProcType::NC_Continuum,
91 { ELECTRON_NEUTRINO, MUON_NEUTRINO, TAU_NEUTRINO,
92 ELECTRON_ANTINEUTRINO, MUON_ANTINEUTRINO, TAU_ANTINEUTRINO }
99 void set_level_ptrs(std::vector<marley::MatrixElement>& matrix_elements,
114 int scheme_pdg = marley_utils::get_nucleus_pid( ds->
Z(), ds->
A() );
115 if ( pdg_d != scheme_pdg )
throw marley::Error(
"Nuclear data mismatch:"
116 " attempted to associate a decay scheme object that has PDG code "
117 + std::to_string(scheme_pdg) +
" with a reaction object that has"
118 " PDG code " + std::to_string(pdg_d) );
123 double unbound_threshold = mt.unbound_threshold( pdg_d );
133 for (
auto& mat_el : matrix_elements ) {
140 double en = mat_el.tabulated_level_energy();
146 if ( en > unbound_threshold ) {
147 mat_el.set_level(
nullptr);
154 MARLEY_LOG( DEBUG,
"physics.reaction" ) <<
"reaction level at " << en
155 <<
" MeV was matched to the decay scheme level at "
156 << plevel->
energy() <<
" MeV";
163 int twoJf = plevel->
twoJ();
167 bool rules_ok =
true;
168 ME_Type mtype = mat_el.type();
169 if ( mtype == ME_Type::FERMI ) {
170 if ( twoJi != twoJf || Pi != Pf ) rules_ok =
false;
172 else if ( mtype == ME_Type::GAMOW_TELLER ) {
173 if ( Pi != Pf ) rules_ok =
false;
174 int twoJf_min = std::abs( twoJi - 2 );
175 int twoJf_max = twoJi + 2;
176 if ( twoJf < twoJf_min || twoJf > twoJf_max ) rules_ok =
false;
186 MARLEY_LOG( WARN,
"physics.reaction" )
187 <<
"The tabulated " << nuc_d <<
" level at "
188 << plevel->
energy() <<
" MeV does not satisfy the selection rules"
189 <<
" for a " << mat_el.type_str() <<
" transition from the " << nuc_b
190 <<
" ground state.\n Initial J\u03C0 = "
191 <<
static_cast<double>( twoJi ) / 2. << Pi
192 <<
"\n Final J\u03C0 = " <<
static_cast<double>( twoJf ) / 2.
198 const auto begin = matrix_elements.cbegin();
199 const auto end = matrix_elements.cend();
200 const auto found = std::find_if(begin, end,
202 {
return plevel == me.
level(); });
207 throw marley::Error(
"Reaction dataset gives two level energies that"
208 " refer to the same DecayScheme level at "
209 + std::to_string( plevel->
energy() ) +
" MeV");
217 mat_el.set_level( plevel );
227 double& pc_cm,
double& Ed_cm)
const
230 double Ea = KEa +
ma_;
234 double sqrt_s = std::sqrt(s);
238 pc_cm = real_sqrt(std::pow(Ec_cm, 2) -
mc_*
mc_);
244 Ed_cm = std::max(sqrt_s - Ec_cm,
md_);
248 double KEa,
double pc_cm,
double cos_theta_c_cm,
double phi_c_cm,
249 double Ec_cm,
double Ed_cm,
int residue_status )
const
252 double sin_theta_c_cm = real_sqrt( 1. - std::pow(cos_theta_c_cm, 2) );
254 double pc_cm_x = sin_theta_c_cm * std::cos( phi_c_cm ) * pc_cm;
255 double pc_cm_y = sin_theta_c_cm * std::sin( phi_c_cm ) * pc_cm;
256 double pc_cm_z = cos_theta_c_cm * pc_cm;
260 auto ejectile = marley_hepmc3::make_particle(
pdg_c_, pc_cm_x, pc_cm_y,
261 pc_cm_z, Ec_cm, marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS,
mc_ );
263 auto residue = marley_hepmc3::make_particle(
pdg_d_, -pc_cm_x, -pc_cm_y,
264 -pc_cm_z, Ed_cm, residue_status,
md_ );
267 double Ea = KEa +
ma_;
270 double pa = real_sqrt( KEa * (KEa + 2.*
ma_) );
273 double beta_z = pa / (Ea +
mb_);
274 marley_kinematics::lorentz_boost( 0., 0., -beta_z, *ejectile );
275 marley_kinematics::lorentz_boost( 0., 0., -beta_z, *residue );
284 double KEa,
const std::shared_ptr< HepMC3::GenParticle >& ejectile,
285 const std::shared_ptr< HepMC3::GenParticle >& residue )
const
288 auto event = std::make_shared< HepMC3::GenEvent >( HepMC3::Units::MEV,
292 int signal_process_id = marley_hepmc3::get_nuhepmc_proc_id(
process_type_ );
293 event->add_attribute(
"signal_process_id",
294 std::make_shared< HepMC3::IntAttribute >( signal_process_id )
299 auto prim_vtx = std::make_shared< HepMC3::GenVertex >();
300 prim_vtx->set_status( marley_hepmc3::NUHEPMC_PRIMARY_VERTEX );
302 event->add_vertex( prim_vtx );
305 double Ea = KEa +
ma_;
308 double pa = real_sqrt( KEa * (KEa + 2.*
ma_) );
313 auto projectile = marley_hepmc3::make_particle(
pdg_a_, 0., 0., pa, Ea,
314 marley_hepmc3::NUHEPMC_PROJECTILE_STATUS,
ma_ );
316 auto target = marley_hepmc3::make_particle(
pdg_b_,
317 marley_hepmc3::NUHEPMC_TARGET_STATUS,
mb_ );
320 prim_vtx->add_particle_in( projectile );
321 prim_vtx->add_particle_in( target );
323 prim_vtx->add_particle_out( ejectile );
324 prim_vtx->add_particle_out( residue );
334 const auto& vec = proc_type_to_nu_pdg.at( proc_type );
335 if ( std::find(vec.cbegin(), vec.cend(),
pdg_a) != vec.end() ) {
336 if ( proc_type == ProcType::NeutrinoCC_Discrete ||
337 proc_type == ProcType::NeutrinoCC_Continuum ) pdg_c =
pdg_a - 1;
338 else if ( proc_type == ProcType::AntiNeutrinoCC_Discrete ||
339 proc_type == ProcType::AntiNeutrinoCC_Continuum ) pdg_c =
pdg_a + 1;
340 else if ( proc_type == ProcType::NC_Discrete ||
341 proc_type == ProcType::NC_Continuum ) pdg_c =
pdg_a;
343 else if ( proc_type == ProcType::NuElectronElastic ) pdg_c =
pdg_a;
344 else throw marley::Error(
"Unrecognized ProcessType encountered in"
345 " marley::Reaction::get_ejectile_pdg()");
348 + std::to_string(
pdg_a) +
" cannot participate in reactions of type "
349 + proc_type_to_string_map.at(proc_type));
354std::string marley::Reaction::proc_type_to_string(
const ProcType& pt) {
355 return proc_type_to_string_map.at( pt );
359 return proc_type_to_nu_pdg.at( pt );
365std::vector< std::unique_ptr<marley::Reaction> >
371 std::vector< std::unique_ptr<marley::Reaction> > loaded_reactions;
373 std::regex rx_comment(
"#.*");
376 std::ifstream file_in( filename );
380 if ( !file_in.good() ) {
381 throw marley::Error(
"Could not read from the file " + filename);
388 line = marley_utils::get_next_line( file_in, rx_comment,
false );
391 std::istringstream iss( line );
392 int integer_proc_type;
393 iss >> integer_proc_type;
395 auto proc_type =
static_cast<ProcType
>( integer_proc_type );
406 while ( iss >> target_pdg ) {
409 loaded_reactions.emplace_back(
410 std::make_unique<marley::ElectronReaction>(
pdg_a, target_pdg,
415 line = marley_utils::get_next_line( file_in, rx_comment,
false );
424 }
while ( !line.empty() );
426 return loaded_reactions;
436 int integer_data_format;
437 iss >> integer_data_format;
438 auto df =
static_cast< DataFormat >( integer_data_format );
449 auto matrix_elements = std::make_shared<std::vector<
455 double old_energy = std::numeric_limits<double>::lowest();
456 while (line = marley_utils::get_next_line(file_in, rx_comment,
false),
468 double energy, strength;
470 iss >> energy >> strength >> integer_me_type;
471 if ( old_energy >= energy )
throw marley::Error(
"Invalid reaction"
472 " dataset. Level energies must be unique and must be given in"
473 " ascending order." );
479 double err_low = 0., err_high = 0.;
480 if ( iss >> err_low ) {
491 matrix_elements->emplace_back( energy, strength,
492 static_cast<ME_Type
>(integer_me_type), err_low, err_high,
507 set_level_ptrs( *matrix_elements,
pdg_b, pdg_d, db );
515 loaded_reactions.emplace_back(
516 std::make_unique< marley::DiscreteNuclearReaction >( proc_type,
517 pdg_a,
pdg_b, pdg_c, pdg_d, q_d, matrix_elements, coulomb_mode,
518 ff_config, filename )
534 auto txsec = std::make_shared< marley::TabulatedXSec >(
535 pdg_b, proc_type, coulomb_mode, delta_ias );
540 std::string table_file_name;
541 while ( table_file_name = marley_utils::get_next_line(file_in,
542 rx_comment,
false), file_in.good() )
544 txsec->add_table( table_file_name );
558 txsec->optimize(
pdg_a, 100. );
560 loaded_reactions.emplace_back(
561 std::make_unique< marley::ContinuumNuclearReaction >( proc_type,
pdg_a,
562 pdg_b, pdg_c, pdg_d, q_d, txsec, filename )
567 else throw marley::Error(
"Unrecognized reaction data format"
568 " encountered in marley::Reaction::load_from_file()" );
570 return loaded_reactions;
578 int Zi = marley_utils::get_particle_Z(
pdg_b );
579 int A = marley_utils::get_particle_A(
pdg_b );
594 if ( Ni <= 0 )
throw marley::Error(
"A NeutrinoCC process requires"
595 " a target nucleus with N > 0");
597 pdg_d = marley_utils::get_nucleus_pid(Zf, A);
606 if ( Zi <= 0 )
throw marley::Error(
"An AntiNeutrinoCC process requires"
607 " a target nucleus with Z > 0");
609 pdg_d = marley_utils::get_nucleus_pid(Zf, A);
613 else throw marley::Error(
"Unrecognized ProcessType encountered in"
614 " marley::Reaction::get_residue_pdg_and_charge()" );
CoulombMode
Enumerated type used to set the method for handling Coulomb corrections for CC nuclear reactions.
Discrete level and γ-ray data for a specific nuclide.
int A() const
Get the mass number.
int Z() const
Get the atomic number.
marley::Level * get_pointer_to_closest_level(double E_level)
Gets a pointer to the Level in the DecayScheme whose excitation energy is closest to E_level.
Base class for all exceptions thrown by MARLEY functions.
A discrete nuclear energy level.
marley::Parity parity() const
Get the level parity.
int twoJ() const
Get two times the level spin.
double energy() const
Get the excitation energy of this level (MeV)
static const MassTable & Instance()
Get a const reference to the singleton instance of the MassTable.
A reduced nuclear matrix element that represents a transition caused by a neutrino-nucleus reaction.
TransitionType
Enumerated type that represents the possible kinds of nuclear transitions recognized by MARLEY.
const marley::Level * level() const
Get a pointer to the final-state nuclear Level accessed by the matrix element, or nullptr if it is a ...
Type-safe representation of a parity value (either +1 or -1)
Reaction(const std::string &source_file)
Construct a Reaction with the resolved path of the data file.
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)
static int get_ejectile_pdg(int pdg_a, ProcessType proc_type)
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_Continuum
Nuclear matrix elements contain for a transition to a continuum of nuclear levels.
@ 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.
@ NuElectronElastic
Neutrino-electron elastic scattering.
@ NeutrinoCC_Discrete
Nuclear matrix elements contain for a transition to a discrete nuclear level.
@ AntiNeutrinoCC_Continuum
Nuclear matrix elements contain for a transition to a continuum of nuclear levels.
@ NeutrinoCC_Continuum
Nuclear matrix elements contain for a transition to a continuum of nuclear levels.
DataFormat
Enumerated type describing the file format for reaction data.
@ MultipoleResponses
Continuum nuclear responses are given for one or more multipoles.
static const std::vector< int > & get_projectiles(ProcessType proc_type)
const std::string & source_file() const
Get the resolved path of the reaction data file used to construct this Reaction.
static void get_residue_pdg_and_charge(ProcessType proc_type, int pdg_b, int &pdg_d, int &q_d)
virtual std::shared_ptr< HepMC3::GenEvent > make_event_object(double KEa, double pc_cm, double cos_theta_c_cm, double phi_c_cm, double Ec_cm, double Ed_cm, int residue_status) const
Helper function that makes an event object.
static std::vector< std::unique_ptr< Reaction > > load_from_file(const std::string &filename, StructureDatabase &db, CoulombCorrector::CoulombMode coulomb_mode, const JSON &ff_config)
int pdg_c_
PDG code for the ejectile.
const std::string source_file_
Resolved path of the reaction data file.
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)
Container for nuclear structure information organized by nuclide.
static void get_gs_spin_parity(int nuc_pdg, int &twoJ, marley::Parity &Pi)
Looks up the ground-state spin-parity for a particular nuclide.
marley::DecayScheme * get_decay_scheme(const int particle_id)
Retrieves discrete level data from the database.
An atomic target for a lepton scattering reaction.