27#include "HepMC3/Attribute.h"
28#include "HepMC3/FourVector.h"
29#include "HepMC3/GenCrossSection.h"
30#include "HepMC3/GenEvent.h"
31#include "HepMC3/GenRunInfo.h"
32#include "HepMC3/GenVertex.h"
33#include "HepMC3/GenParticle.h"
36#include "marley/marley_utils.hh"
37#include "marley/hepmc3_utils.hh"
38#include "marley/Error.hh"
39#include "marley/Generator.hh"
40#include "marley/JSON.hh"
41#include "marley/Reaction.hh"
45 constexpr int DUMMY_NUHEPMC_PROC_ID = 0;
48 struct NuHepMCProcess {
49 NuHepMCProcess(
int procID, std::string name, std::string description )
50 : id_( procID ), name_( name ), desc_( description ) {}
58 const std::map< marley::Reaction::ProcessType, NuHepMCProcess >
59 ptype_to_nuhepmc_proc =
62 { 100,
"vCC-discrete",
"charged-current neutrino-nucleus"
63 " scattering via discrete transitions" } },
65 { 110,
"anti-vCC-discrete",
"charged-current antineutrino-nucleus"
66 " scattering via discrete transitions" } },
68 { 150,
"NC-discrete",
"neutral-current (anti)neutrino-nucleus"
69 " scattering via discrete transitions" } },
71 { 700,
"v-e",
"(anti)neutrino-electron elastic scattering" } },
73 { 101,
"vCC-continuum",
"charged-current neutrino-nucleus"
74 " scattering via continuum transitions" } },
76 { 111,
"anti-vCC-continuum",
"charged-current antineutrino-nucleus"
77 " scattering via continuum transitions" } },
79 { 151,
"NC-continuum",
"neutral-current (anti)neutrino-nucleus"
80 " scattering via continuum transitions" } },
82 { 800,
"standalone-decay",
"standalone nuclear de-excitation"
83 " with no simulated primary reaction" } },
87 std::map< int, std::pair< std::string, std::string > >
91 { marley_hepmc3::NUHEPMC_PRIMARY_VERTEX, {
"Primary",
92 "Represents the primary interaction" } },
94 { marley_hepmc3::NUHEPMC_HF_DECAY_VERTEX, {
"HFDecay",
95 "Represents a nuclear de-excitation step simulated using the"
96 " Hauser-Feshbach treatment" } },
98 { marley_hepmc3::NUHEPMC_GAMMA_DECAY_VERTEX, {
"GammaDecay",
99 "Represents a nuclear de-excitation step simulated using tabulated"
100 " gamma-ray branching ratios" } },
105 std::map< int, std::pair< std::string, std::string > >
106 particle_status_map =
109 { marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS, {
"Final-state",
110 "Undecayed physical particle" } },
112 { marley_hepmc3::NUHEPMC_PROJECTILE_STATUS, {
"Projectile",
113 "Incoming beam particle" } },
115 { marley_hepmc3::NUHEPMC_TARGET_STATUS, {
"Target",
116 "Target particle struck by incoming beam particle in"
117 " the primary interaction" } },
119 { marley_hepmc3::NUHEPMC_UNDECAYED_RESIDUE_STATUS, {
"UndecayedRemnant",
120 "Nuclear remnant before simulation of nuclear de-excitations" } },
122 { marley_hepmc3::NUHEPMC_INTERMEDIATE_RESIDUE_STATUS,
123 {
"IntermediateRemnant",
124 "Nuclear remnant during simulation of nuclear de-excitations" } },
129 std::vector< std::string > nuhepmc_convention_vec = {
139namespace marley_hepmc3 {
142 auto itr = ptype_to_nuhepmc_proc.find( pt );
143 if ( itr != ptype_to_nuhepmc_proc.end() ) {
144 return itr->second.id_;
146 return DUMMY_NUHEPMC_PROC_ID;
151 auto itr = std::find_if( ptype_to_nuhepmc_proc.cbegin(),
152 ptype_to_nuhepmc_proc.cend(), [ proc_id ](
auto& pair ) ->
bool
153 { return pair.second.id_ == proc_id; }
155 if ( itr != ptype_to_nuhepmc_proc.end() ) {
161 void set_particle_charge( HepMC3::GenParticle& particle,
int charge ) {
163 std::make_shared< HepMC3::IntAttribute >(charge) );
165 throw marley::Error(
"Failed to set particle charge in marley_hepmc3"
166 "::set_particle_charge()" );
170 int get_particle_charge( HepMC3::GenParticle& particle ) {
172 auto* q_ptr = particle.
attribute< HepMC3::IntAttribute >(
"charge" ).get();
173 if ( q_ptr )
return q_ptr->value();
175 return marley_utils::get_particle_charge( particle.
pid() );
178 std::shared_ptr< HepMC3::GenParticle > make_particle(
179 const HepMC3::FourVector& mom4,
int pdg,
int status,
182 auto particle = std::make_shared< HepMC3::GenParticle >(
184 if ( mass != DUMMY_PARTICLE_MASS ) {
190 std::shared_ptr< HepMC3::GenParticle > make_particle(
191 int pdg,
double px,
double py,
double pz,
double E,
int status,
194 HepMC3::FourVector mom4( px, py, pz, E );
195 return make_particle( mom4, pdg, status, mass );
198 std::shared_ptr< HepMC3::GenParticle > make_particle(
199 int pdg,
double px,
double py,
double pz,
int status,
202 double E = marley_utils::real_sqrt( px*px + py*py + pz*pz + mass*mass );
203 HepMC3::FourVector mom4( px, py, pz, E );
204 return make_particle( mom4, pdg, status, mass );
207 std::shared_ptr< HepMC3::GenParticle > make_particle(
208 int pdg,
int status,
double mass )
210 HepMC3::FourVector mom4;
211 if ( mass != DUMMY_PARTICLE_MASS ) {
214 return make_particle( mom4, pdg, status, mass );
219 std::vector< std::shared_ptr< HepMC3::GenParticle > >
220 get_particles_with_status(
int status, HepMC3::GenEvent& ev )
223 std::vector< std::shared_ptr< HepMC3::GenParticle > > found_particles;
224 for (
auto& p : particles ) {
225 if ( p->status() == status ) {
226 found_particles.push_back( p );
229 return found_particles;
232 std::vector< std::shared_ptr< HepMC3::GenVertex > >
233 get_vertices_with_status(
int status, HepMC3::GenEvent& ev )
235 const auto& vertices = ev.
vertices();
236 std::vector< std::shared_ptr< HepMC3::GenVertex > > found_vertices;
237 for (
auto& v : vertices ) {
238 if ( v->status() == status ) {
239 found_vertices.push_back( v );
242 return found_vertices;
245 std::shared_ptr< HepMC3::GenParticle >
246 get_first_particle_with_status(
int status, HepMC3::GenEvent& ev )
248 auto particle_ptrs = get_particles_with_status( status, ev );
249 if ( !particle_ptrs.empty() )
return particle_ptrs.front();
253 std::shared_ptr< HepMC3::GenParticle > get_projectile(
254 HepMC3::GenEvent& ev )
256 return get_first_particle_with_status(
257 marley_hepmc3::NUHEPMC_PROJECTILE_STATUS, ev );
260 std::shared_ptr< HepMC3::GenParticle > get_target(
261 HepMC3::GenEvent& ev )
263 return get_first_particle_with_status(
264 marley_hepmc3::NUHEPMC_TARGET_STATUS, ev );
267 std::shared_ptr< HepMC3::GenParticle > get_ejectile(
268 HepMC3::GenEvent& ev )
270 return get_first_particle_with_status(
271 marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS, ev );
274 std::shared_ptr< HepMC3::GenParticle > get_residue(
275 HepMC3::GenEvent& ev )
277 return get_first_particle_with_status(
278 marley_hepmc3::NUHEPMC_UNDECAYED_RESIDUE_STATUS, ev );
282 void prepare_process_metadata( HepMC3::GenRunInfo& run_info ) {
283 std::vector< int > proc_id_vec;
284 for (
const auto& pair : ptype_to_nuhepmc_proc ) {
285 int proc_id = pair.second.id_;
286 proc_id_vec.push_back( proc_id );
288 std::string attr_prefix =
"NuHepMC.ProcessInfo["
289 + std::to_string( proc_id ) +
"].";
292 std::make_shared< HepMC3::StringAttribute >(pair.second.name_) );
295 std::make_shared< HepMC3::StringAttribute >(pair.second.desc_) );
299 std::make_shared< HepMC3::VectorIntAttribute >(proc_id_vec) );
303 void prepare_vertex_status_metadata( HepMC3::GenRunInfo& run_info ) {
304 std::vector< int > status_vec;
305 for (
const auto& pair : vertex_status_map ) {
306 int status = pair.first;
307 status_vec.push_back( status );
309 std::string attr_prefix =
"NuHepMC.VertexStatusInfo["
310 + std::to_string( status ) +
"].";
313 std::make_shared< HepMC3::StringAttribute >(pair.second.first) );
316 std::make_shared< HepMC3::StringAttribute >(pair.second.second) );
320 std::make_shared< HepMC3::VectorIntAttribute >(status_vec) );
324 void prepare_particle_status_metadata( HepMC3::GenRunInfo& run_info ) {
325 std::vector< int > status_vec;
326 for (
const auto& pair : particle_status_map ) {
327 int status = pair.first;
328 status_vec.push_back( status );
330 std::string attr_prefix =
"NuHepMC.ParticleStatusInfo["
331 + std::to_string( status ) +
"].";
334 std::make_shared< HepMC3::StringAttribute >(pair.second.first) );
337 std::make_shared< HepMC3::StringAttribute >(pair.second.second) );
341 std::make_shared< HepMC3::VectorIntAttribute >(status_vec) );
345 void prepare_non_standard_pdg_code_metadata( HepMC3::GenRunInfo& run_info )
349 const std::vector< int > non_standard_PDGs = { 0 };
351 std::make_shared< HepMC3::VectorIntAttribute >(non_standard_PDGs) );
353 run_info.
add_attribute(
"NuHepMC.AdditionalParticleNumbers[0].Name",
354 std::make_shared< HepMC3::StringAttribute >(
"Absent" ) );
356 run_info.
add_attribute(
"NuHepMC.AdditionalParticleNumbers[0].Description",
357 std::make_shared< HepMC3::StringAttribute >(
"Dummy particle"
358 " representing an absent projectile in a standalone nuclear"
359 " de-excitation event (used by \"marley decay\")" ) );
364 void apply_nuhepmc_runinfo_conventions( HepMC3::GenRunInfo& run_info,
365 const double flux_avg_xsec )
370 std::make_shared< HepMC3::VectorStringAttribute >(
371 nuhepmc_convention_vec )
376 std::make_shared< HepMC3::StringAttribute >(
"pb" )
379 run_info.
add_attribute(
"NuHepMC.Units.CrossSection.TargetScale",
380 std::make_shared< HepMC3::StringAttribute >(
"PerAtom" )
384 double xsec_picobarn = flux_avg_xsec * marley_utils::hbar_c2
385 * marley_utils::fm2_to_picobarn;
386 run_info.
add_attribute(
"NuHepMC.FluxAveragedTotalCrossSection",
387 std::make_shared< HepMC3::DoubleAttribute >( xsec_picobarn )
391 std::vector< std::string > marley_DOIs = {
392 "10.1103/PhysRevC.103.044604",
393 "10.1016/j.cpc.2021.108123"
397 std::make_shared< HepMC3::VectorStringAttribute >( marley_DOIs )
400 std::vector< std::string > marley_arXivs = {
407 std::make_shared< HepMC3::VectorStringAttribute >( marley_arXivs )
410 std::vector< std::string > marley_INSPIREs = {
415 run_info.
add_attribute(
"NuHepMC.Citations.Generator.InspireHEP",
416 std::make_shared< HepMC3::VectorStringAttribute >( marley_INSPIREs )
421 std::string check_run_info_compatibility(
422 const HepMC3::GenRunInfo& ref,
423 const HepMC3::GenRunInfo& candidate )
426 return "weight names differ between files";
429 auto ref_attr = ref.
attribute< HepMC3::StringAttribute >(
430 "MARLEY.JSONconfig" );
431 auto cand_attr = candidate.
attribute< HepMC3::StringAttribute >(
432 "MARLEY.JSONconfig" );
434 if ( ref_attr && cand_attr ) {
436 marley::JSON ref_json = marley::JSON::load( ref_attr->value() );
437 marley::JSON cand_json = marley::JSON::load( cand_attr->
value() );
439 auto strip_run_keys = []( marley::JSON& j ) -> marley::JSON {
440 marley::JSON result = marley::JSON::object();
441 for (
const auto& [key, value] : j.object_range() ) {
442 if ( key !=
"seed" && key !=
"generate" ) {
449 marley::JSON ref_stripped = strip_run_keys( ref_json );
450 marley::JSON cand_stripped = strip_run_keys( cand_json );
452 if ( ref_stripped.dump_string() != cand_stripped.dump_string() ) {
453 return "MARLEY JSON configuration differs between files";
455 }
catch (
const std::exception& e ) {
456 return "failed to parse MARLEY JSON configuration: "
457 + std::string( e.what() );
459 }
else if (
static_cast< bool >( ref_attr )
460 !=
static_cast< bool >( cand_attr ) )
462 return "one file has MARLEY JSON configuration and the other does not";
471void marley_hepmc3::store_decay_time(
double partial_width,
473 const std::shared_ptr< HepMC3::GenParticle >& parent )
477 MARLEY_LOG( TRACE,
"physics.deexcitation.gamma" ) <<
"decay_time = "
478 << marley_utils::hbar * decay_time <<
" s";
482 decay_time *= marley_utils::hbar_c * marley_utils::fm_to_cm;
488 double E2_parent = std::pow( mom4_parent.
e(), 2 );
489 double beta2_parent = mom4_parent.
length2() / E2_parent;
490 double gamma_parent = 1. / marley_utils::real_sqrt( 1. - beta2_parent );
491 decay_time *= gamma_parent;
495 if ( !parent_prod_vtx )
throw marley::Error(
"Could not access parent"
496 " particle production vertex in marley_hepmc3::store_decay_time()" );
497 double old_time = parent_prod_vtx->position().t();
501 double new_time = old_time + decay_time;
503 decay_pos4.
set_t( new_time );
505 decay_vtx->set_position( decay_pos4 );
515 const std::string BOX_HEAVY =
"━";
516 const std::string THIN_CHAR =
"─";
517 const std::string ARROW_RIGHT =
"►";
518 const std::string BOX_VERT =
"│";
521 const std::string THICK_SEP = []() {
524 for (
int k = 0; k < 71; ++k ) s += BOX_HEAVY;
531 int utf8_display_width(
const std::string& s ) {
534 while ( i < s.size() ) {
535 auto c =
static_cast< unsigned char >( s[i] );
540 }
else if ( c < 0xE0u ) {
541 cp =
static_cast< uint32_t
>( c & 0x1Fu ) << 6;
542 if ( i + 1 < s.size() )
543 cp |=
static_cast< unsigned char >( s[i+1] ) & 0x3Fu;
545 }
else if ( c < 0xF0u ) {
546 cp =
static_cast< uint32_t
>( c & 0x0Fu ) << 12;
547 if ( i + 1 < s.size() )
548 cp |=
static_cast< uint32_t
>(
549 static_cast< unsigned char >( s[i+1] ) & 0x3Fu ) << 6;
550 if ( i + 2 < s.size() )
551 cp |=
static_cast< unsigned char >( s[i+2] ) & 0x3Fu;
555 cp =
static_cast< uint32_t
>( c & 0x07u ) << 18;
556 if ( i + 1 < s.size() )
557 cp |=
static_cast< uint32_t
>(
558 static_cast< unsigned char >( s[i+1] ) & 0x3Fu ) << 12;
559 if ( i + 2 < s.size() )
560 cp |=
static_cast< uint32_t
>(
561 static_cast< unsigned char >( s[i+2] ) & 0x3Fu ) << 6;
562 if ( i + 3 < s.size() )
563 cp |=
static_cast< unsigned char >( s[i+3] ) & 0x3Fu;
568 if ( cp < 0x0300u || cp > 0x036Fu ) ++w;
575 std::string make_thin_sep(
const std::string& prefix,
int total = 71 ) {
576 std::string s = prefix;
577 int fill = total - utf8_display_width( prefix );
578 for (
int k = 0; k < fill; ++k ) s += THIN_CHAR;
584 std::string left_pad(
const std::string& s,
int target ) {
585 int dw = utf8_display_width( s );
586 int pad = ( target > dw ) ? ( target - dw ) : 0;
587 return s + std::string(
static_cast< size_t >( pad ),
' ' );
591 std::string format_jp(
int twoJ,
int par ) {
593 if ( twoJ % 2 == 0 ) j = std::to_string( twoJ / 2 );
594 else j = std::to_string( twoJ ) +
"/2";
595 return j + ( par >= 0 ?
"+" :
"-" );
603 std::string tag = marley_utils::get_particle_symbol( proj_pdg );
627 bool get_double_attr(
const HepMC3::ConstGenParticlePtr& p,
628 const std::string& name,
double& val )
631 if ( !attr )
return false;
637 bool get_double_attr_vtx(
const HepMC3::ConstGenVertexPtr& v,
638 const std::string& name,
double& val )
641 if ( !attr )
return false;
647 bool get_int_attr(
const HepMC3::ConstGenParticlePtr& p,
648 const std::string& name,
int& val )
651 if ( !attr )
return false;
657 bool get_int_attr_vtx(
const HepMC3::ConstGenVertexPtr& v,
658 const std::string& name,
int& val )
661 if ( !attr )
return false;
667 std::string fmtpm(
double v ) {
668 std::ostringstream ss;
669 ss << std::showpos << std::fixed << std::setprecision( 3 ) << v;
694 void print_particle_line( std::ostream& os,
695 const HepMC3::ConstGenParticlePtr& p,
699 int vtx_multipolarity )
706 bool has_ex = get_double_attr( p,
"Ex", Ex );
707 get_int_attr( p,
"twoJ", twoJ );
708 get_int_attr( p,
"parity", par );
709 bool excited = has_ex && ( Ex > 0. );
711 std::string name = marley_utils::get_particle_symbol( pdg, excited );
714 if ( is_in_block && has_ex ) {
715 os <<
" " << left_pad( name, 11 )
716 <<
"Ex = " << std::fixed << std::setprecision( 2 ) << Ex <<
" MeV";
718 os <<
" Jπ = " << format_jp( twoJ, par );
726 double px = mom.
px();
727 double py = mom.
py();
728 double pz = mom.
pz();
729 double p3mag = std::sqrt( px*px + py*py + pz*pz );
731 std::ostringstream line;
732 line <<
" " << left_pad( name, 11 )
733 <<
"E = " << std::fixed << std::setprecision( 3 )
734 << std::setw( 9 ) << E <<
" MeV ";
745 bool is_nuclear = ( pdg > 1000000000 );
746 bool is_final_state_particle =
747 ( p->status() == marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS );
748 bool ground_state_nucleus = is_nuclear && !is_in_block && is_deex_vtx
749 && ( !has_ex || Ex == 0. )
750 && ( is_gamma_vtx || !is_final_state_particle );
752 if ( ground_state_nucleus ) {
754 line <<
"[ground state]";
755 }
else if ( p3mag < 1e-6 ) {
758 }
else if ( std::abs(px) < 1e-6 && std::abs(py) < 1e-6 ) {
760 line <<
"pz = " << std::showpos << std::fixed << std::setprecision( 3 )
761 << pz << std::noshowpos;
762 }
else if ( pdg == 22 && is_gamma_vtx && vtx_multipolarity > 0 ) {
764 line <<
"M" << vtx_multipolarity
765 <<
" (l = " << vtx_multipolarity <<
")";
768 line <<
"p = (" << fmtpm(px) <<
", " << fmtpm(py) <<
", "
769 << fmtpm(pz) <<
") MeV/c";
772 os << line.str() <<
"\n";
776 if ( !is_in_block && excited && !ground_state_nucleus
777 && !( pdg == 22 && is_gamma_vtx ) && twoJ >= 0 )
780 << std::fixed << std::setprecision( 2 ) << Ex
781 <<
" MeV Jπ = " << format_jp( twoJ, par ) <<
"\n";
787 std::string chain_particle_name(
const HepMC3::ConstGenParticlePtr& p ) {
790 bool excited = get_double_attr( p,
"Ex", Ex ) && ( Ex > 0. );
791 return marley_utils::get_particle_symbol( pdg, excited );
799 if ( verts.empty() )
return;
802 const auto& pv = verts.front();
803 const auto& pv_in = pv->particles_in();
804 const auto& pv_out = pv->particles_out();
807 HepMC3::ConstGenParticlePtr proj =
nullptr;
808 HepMC3::ConstGenParticlePtr target =
nullptr;
809 if ( pv_in.size() == 2u ) {
810 const auto& pv_in1 = pv_in.front();
811 const auto& pv_in2 = pv_in.back();
812 if ( pv_in1->status() == marley_hepmc3::NUHEPMC_PROJECTILE_STATUS ) {
821 else throw marley::Error(
"Primary vertex without two incoming particles"
822 " encountered in marley_hepmc3::print_event()" );
825 HepMC3::ConstGenParticlePtr ejectile =
nullptr;
826 HepMC3::ConstGenParticlePtr residue =
nullptr;
827 if ( pv_out.size() == 2u ) {
828 const auto& pv_out1 = pv_out.front();
829 const auto& pv_out2 = pv_out.back();
831 if ( pv_out1->status()
832 == marley_hepmc3::NUHEPMC_UNDECAYED_RESIDUE_STATUS )
842 else throw marley::Error(
"Primary vertex without two outgoing particles"
843 " encountered in marley_hepmc3::print_event()" );
846 std::string tag = chain_tag_primary( proc_type, proj->pid() );
849 std::ostringstream pline;
850 pline <<
" " << chain_particle_name( proj )
851 <<
" (" << std::fixed << std::setprecision( 2 )
852 << proj->momentum().e() <<
" MeV)";
853 pline <<
" + " << chain_particle_name( target );
855 pline <<
" " << THIN_CHAR << THIN_CHAR <<
"[" << tag
856 <<
"]" << THIN_CHAR << THIN_CHAR << ARROW_RIGHT <<
" ";
857 pline << chain_particle_name( ejectile );
858 pline <<
" + " << chain_particle_name( residue );
862 double Ex = 0.;
int twoJ = -1;
int par = 1;
863 bool has_ex = get_double_attr( residue,
"Ex", Ex );
864 get_int_attr( residue,
"twoJ", twoJ );
865 get_int_attr( residue,
"parity", par );
866 if ( has_ex && Ex > 0. ) {
867 pline <<
" [Ex=" << std::fixed << std::setprecision( 2 ) << Ex
868 <<
" MeV, " << format_jp( twoJ, par ) <<
"]";
871 os << pline.str() <<
"\n";
874 for (
size_t vi = 1; vi < verts.size(); ++vi ) {
875 const auto& vtx = verts[vi];
876 int vstatus = vtx->status();
877 const auto& vin = vtx->particles_in();
878 const auto& vout = vtx->particles_out();
883 if ( vstatus == marley_hepmc3::NUHEPMC_HF_DECAY_VERTEX ) {
886 else if ( vstatus == marley_hepmc3::NUHEPMC_GAMMA_DECAY_VERTEX ) {
894 HepMC3::ConstGenParticlePtr dec_in = vin.front();
897 HepMC3::ConstGenParticlePtr frag =
nullptr;
898 HepMC3::ConstGenParticlePtr daughter =
nullptr;
899 if ( vout.size() != 2u ) {
900 throw marley::Error(
"Binary decay vertex does not have exactly"
901 " two outgoing particles" );
904 auto prod1 = vout.front();
905 auto prod2 = vout.back();
907 if ( prod1->generated_mass() <= prod2->generated_mass() ) {
916 std::ostringstream dline;
918 if ( dec_in ) dline << chain_particle_name( dec_in );
919 dline <<
" " << THIN_CHAR << THIN_CHAR <<
"[" << dtag
920 <<
"]" << THIN_CHAR << THIN_CHAR << ARROW_RIGHT <<
" ";
921 if ( frag ) dline << chain_particle_name( frag );
923 if ( daughter ) dline << chain_particle_name( daughter );
927 double Ex = 0.;
int twoJ = -1;
int par = 1;
928 bool has_ex = get_double_attr( daughter,
"Ex", Ex );
929 get_int_attr( daughter,
"twoJ", twoJ );
930 get_int_attr( daughter,
"parity", par );
931 if ( has_ex && Ex > 0. ) {
932 dline <<
" [Ex=" << std::fixed << std::setprecision( 2 ) << Ex
933 <<
" MeV, " << format_jp( twoJ, par ) <<
"]";
934 }
else if ( daughter->pid() > 1000000000 ) {
935 dline <<
" [ground state]";
938 os << dline.str() <<
"\n";
951 std::string compute_gamma_multipolarity_string(
952 const HepMC3::ConstGenVertexPtr& vtx )
954 const auto& in_particles = vtx->particles_in();
955 if ( in_particles.empty() )
return {};
957 int twoJ_i = 0, Pi = 0;
958 if ( !get_int_attr( in_particles.front(),
"twoJ", twoJ_i ) )
return {};
959 if ( !get_int_attr( in_particles.front(),
"parity", Pi ) )
return {};
962 const auto& out_particles = vtx->particles_out();
963 HepMC3::ConstGenParticlePtr daughter =
nullptr;
964 for (
const auto& p : out_particles ) {
965 if ( p->pid() != 22 ) { daughter = p;
break; }
967 if ( !daughter )
return {};
969 int twoJ_f = 0, Pf = 0;
970 if ( !get_int_attr( daughter,
"twoJ", twoJ_f ) )
return {};
971 if ( !get_int_attr( daughter,
"parity", Pf ) )
return {};
974 int ell = std::abs( twoJ_i - twoJ_f ) / 2;
975 if ( ell < 1 ) ell = 1;
977 int phase = ( ell % 2 == 0 ) ? 1 : -1;
978 char type = ( Pi == phase * Pf ) ?
'E' :
'M';
980 return type + std::to_string( ell );
984 void print_vertex_block( std::ostream& os,
985 const HepMC3::ConstGenVertexPtr& vtx,
int vtx_index )
987 int vstatus = vtx->status();
988 bool is_deex = ( vstatus == marley_hepmc3::NUHEPMC_HF_DECAY_VERTEX
989 || vstatus == marley_hepmc3::NUHEPMC_GAMMA_DECAY_VERTEX );
990 bool is_gamma = ( vstatus == marley_hepmc3::NUHEPMC_GAMMA_DECAY_VERTEX );
993 std::string type_name;
994 if ( vstatus == marley_hepmc3::NUHEPMC_PRIMARY_VERTEX )
995 type_name =
"PRIMARY INTERACTION";
996 else if ( vstatus == marley_hepmc3::NUHEPMC_HF_DECAY_VERTEX )
997 type_name =
"HAUSER-FESHBACH";
998 else if ( vstatus == marley_hepmc3::NUHEPMC_GAMMA_DECAY_VERTEX )
999 type_name =
"GAMMA CASCADE";
1001 type_name =
"VERTEX (status " + std::to_string( vstatus ) +
")";
1003 std::ostringstream hdr;
1004 hdr <<
" [V" << vtx_index <<
"] " << type_name;
1007 if ( vstatus == marley_hepmc3::NUHEPMC_HF_DECAY_VERTEX ) {
1008 double width_tot = 0., width_ec = 0.;
1009 bool has_tot = get_double_attr_vtx( vtx,
"TotalWidth", width_tot );
1010 bool has_ec = get_double_attr_vtx( vtx,
"ECWidth", width_ec );
1011 if ( has_tot && has_ec ) {
1013 << std::scientific << std::setprecision( 2 ) << width_ec
1015 << std::scientific << std::setprecision( 2 ) << width_tot
1020 else if ( is_gamma ) {
1022 std::string xl = compute_gamma_multipolarity_string( vtx );
1023 if ( !xl.empty() ) hdr <<
" " << xl;
1026 if ( get_double_attr_vtx( vtx,
"GammaBranchingRatio", br ) ) {
1027 hdr <<
" BR = " << std::scientific << std::setprecision( 2 ) << br;
1029 double width_tot = 0.;
1030 if ( get_double_attr_vtx( vtx,
"TotalWidth", width_tot ) ) {
1032 << std::scientific << std::setprecision( 2 ) << width_tot
1036 os << hdr.str() <<
"\n";
1041 if ( is_gamma ) get_int_attr_vtx( vtx,
"multipolarity", multi );
1044 os << make_thin_sep( THIN_CHAR + THIN_CHAR +
" IN " ) <<
"\n";
1045 for (
const auto& p : vtx->particles_in() ) {
1046 print_particle_line( os, p,
1047 true, is_deex, is_gamma, multi );
1051 os << make_thin_sep( THIN_CHAR + THIN_CHAR +
" OUT " ) <<
"\n";
1052 for (
const auto& p : vtx->particles_out() ) {
1053 print_particle_line( os, p,
1054 false, is_deex, is_gamma, multi );
1068 if ( attr ) proc_type = marley_hepmc3::from_nuhepmc_proc_id( attr->value() );
1069 std::string proc_name = marley::Reaction::proc_type_to_string( proc_type );
1072 os << THICK_SEP <<
"\n";
1075 os <<
" MARLEY " << BOX_VERT <<
" Event #" << ev.
event_number()
1076 <<
" " << BOX_VERT <<
" " << proc_name <<
"\n";
1079 os << THICK_SEP <<
"\n";
1082 os <<
" INTERACTION CHAIN\n";
1083 print_interaction_chain( os, ev, proc_type );
1087 for (
const auto& vtx : ev.
vertices() ) {
1088 os << THICK_SEP <<
"\n";
1089 print_vertex_block( os, vtx, vtx_idx++ );
1093 os << THICK_SEP <<
"\n";
1094 os <<
" FINAL STATE\n";
1095 for (
const auto& p : ev.
particles() ) {
1096 if ( p->status() == marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS ) {
1099 print_particle_line( os, p,
1109 os << THICK_SEP <<
"\n";
1113 double proc_xs = proc_attr ? proc_attr->
value() : 0.;
1114 double tot_xs = tot_attr ? tot_attr->
value() : 0.;
1115 os <<
" σ[" << proc_name <<
"] = "
1116 << std::scientific << std::setprecision( 3 ) << proc_xs
1118 << std::scientific << std::setprecision( 3 ) << tot_xs <<
" pb\n";
1122 os << THICK_SEP <<
"\n";
Attribute that holds a real number as a double.
double value() const
get the value associated to this Attribute.
void set_t(double tt)
Set time component of position/displacement.
double px() const
x-component of momentum
double py() const
y-component of momentum
double pz() const
z-component of momentum
double e() const
Energy component of momentum.
void set_e(double ee)
Set energy component of momentum.
double length2() const
Squared magnitude of (x, y, z) 3-vector.
Stores event-related information.
const std::vector< ConstGenParticlePtr > & particles() const
Get list of particles (const)
int event_number() const
Get event number.
std::shared_ptr< T > attribute(const std::string &name, const int &id=0) const
Get attribute of type T.
const std::vector< ConstGenVertexPtr > & vertices() const
Get list of vertices (const)
bool add_attribute(const std::string &name, std::shared_ptr< Attribute > att)
Add an attribute to this particle.
const FourVector & momentum() const
Get momentum.
std::shared_ptr< T > attribute(const std::string &name) const
Get attribute of type T.
void set_generated_mass(double m)
Set generated mass.
ConstGenVertexPtr production_vertex() const
Get production vertex (const version)
int pid() const
Get PDG ID.
void add_attribute(const std::string &name, const std::shared_ptr< Attribute > &att)
add an attribute This will overwrite existing attribute if an attribute with the same name is present
const std::vector< std::string > & weight_names() const
Get the vector of weight names.
std::shared_ptr< T > attribute(const std::string &name) const
Get attribute of type T.
Attribute that holds an Integer implemented as an int.
int value() const
get the value associated to this Attribute.
std::string value() const
get the value associated to this Attribute.
Base class for all exceptions thrown by MARLEY functions.
The MARLEY Event generator.
double sample_decay_time(double partial_width)
Sample a random decay time given a partial decay width.
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.
@ Unknown
Dummy value used for error handling.
@ StandaloneDecay
Standalone nuclear de-excitation with no simulated primary reaction (used by "marley decay")
@ 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.