28#include "HepMC3/Attribute.h"
29#include "HepMC3/FourVector.h"
30#include "HepMC3/GenEvent.h"
31#include "HepMC3/GenParticle.h"
32#include "HepMC3/GenRunInfo.h"
33#include "HepMC3/GenVertex.h"
36#include "cmd_helpers.hh"
37#include "marley/CommandHandler.hh"
38#include "marley/Error.hh"
39#include "marley/EventFileReader.hh"
40#include "marley/hepmc3_utils.hh"
41#include "marley/JSON.hh"
42#include "marley/OutputFile.hh"
43#include "marley/marley_utils.hh"
47 std::shared_ptr<HepMC3::GenRunInfo> make_cleaned_run_info(
48 std::shared_ptr<HepMC3::GenRunInfo> original)
50 auto cleaned = std::make_shared<HepMC3::GenRunInfo>(*original);
51 cleaned->remove_attribute(
"MARLEY.RNGseed");
55 std::shared_ptr<HepMC3::GenParticle> find_legacy_residue(
56 std::shared_ptr<HepMC3::GenParticle> residue )
58 auto current = residue;
59 while (
auto vtx = current->end_vertex() ) {
60 std::shared_ptr<HepMC3::GenParticle> daughter;
61 for (
const auto& out : vtx->particles_out() ) {
62 if ( !marley_utils::is_ion( out->pid() ) )
continue;
64 != marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS )
69 if ( !daughter ) daughter = out;
71 if ( !daughter )
break;
77 struct LegacyEventView {
78 std::shared_ptr<HepMC3::GenParticle> projectile;
79 std::shared_ptr<HepMC3::GenParticle> target;
80 std::shared_ptr<HepMC3::GenParticle> ejectile;
81 std::shared_ptr<HepMC3::GenParticle> residue;
82 std::shared_ptr<HepMC3::GenParticle> legacy_residue;
86 std::vector< std::shared_ptr< HepMC3::GenParticle > > final_state_particles;
91 v.projectile = marley_hepmc3::get_projectile( ev );
92 v.target = marley_hepmc3::get_target( ev );
93 v.ejectile = marley_hepmc3::get_ejectile( ev );
94 v.residue = marley_hepmc3::get_residue( ev );
99 if ( Ex_a ) v.Ex = Ex_a->value();
102 if ( twoJ_a ) v.twoJ = twoJ_a->value();
105 if ( par_a ) v.parity = par_a->value();
108 if ( v.residue ) v.legacy_residue = find_legacy_residue( v.residue );
110 v.final_state_particles
111 = marley_hepmc3::get_particles_with_status(
112 marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS, ev );
117 void write_old_ascii_event( std::ostream& os,
118 const LegacyEventView& v )
121 for (
const auto& p : v.final_state_particles ) {
122 if ( v.ejectile && p->
id() == v.ejectile->
id() )
continue;
123 if ( v.legacy_residue && p->
id() == v.legacy_residue->
id() )
continue;
127 std::ostringstream tmp;
128 tmp << std::scientific
129 << std::setprecision( std::numeric_limits< double >::max_digits10 );
131 tmp <<
"2 " << num_final <<
' '
132 << v.Ex <<
' ' << v.twoJ <<
' ' << ( v.parity >= 0 ?
'+' :
'-' )
136 const auto& m = p.momentum();
137 int q = marley_hepmc3::get_particle_charge(
139 tmp << p.pid() <<
' ' << m.e() <<
' ' << m.px() <<
' '
140 << m.py() <<
' ' << m.pz() <<
' '
141 << p.generated_mass() <<
' ' << q <<
'\n';
144 if ( v.projectile ) write_part( *v.projectile );
145 if ( v.target ) write_part( *v.target );
146 if ( v.ejectile ) write_part( *v.ejectile );
147 if ( v.legacy_residue ) write_part( *v.legacy_residue );
148 for (
const auto& p : v.final_state_particles ) {
149 if ( v.ejectile && p->
id() == v.ejectile->
id() )
continue;
150 if ( v.legacy_residue && p->
id() == v.legacy_residue->
id() )
continue;
157 void write_hepevt_event( std::ostream& os,
158 const LegacyEventView& v,
unsigned long event_num,
159 double flux_avg_xsec_natural )
162 for (
const auto& p : v.final_state_particles ) {
163 if ( v.ejectile && p->
id() == v.ejectile->
id() )
continue;
164 if ( v.legacy_residue && p->
id() == v.legacy_residue->
id() )
continue;
168 constexpr double MEV2GEV = 0.001;
170 std::ostringstream tmp;
171 tmp << std::scientific
172 << std::setprecision( std::numeric_limits< double >::max_digits10 );
174 tmp << event_num <<
' ' << nhep <<
'\n';
177 int status,
int jmo1 = 0,
int jmo2 = 0 )
180 tmp << status <<
' ' << p.
pid() <<
' ' << jmo1 <<
' ' << jmo2
182 << m.px() * MEV2GEV <<
' ' << m.py() * MEV2GEV <<
' '
183 << m.pz() * MEV2GEV <<
' ' << m.e() * MEV2GEV <<
' '
185 <<
" 0. 0. 0. 0." <<
'\n';
188 if ( v.projectile ) dump_line( *v.projectile, 3 );
189 if ( v.target ) dump_line( *v.target, 3 );
191 tmp <<
"11 0 " << v.twoJ <<
' ' << v.parity <<
" 0 0 "
192 <<
"0. 0. 0. " << v.Ex <<
' ' << flux_avg_xsec_natural
193 <<
" 0. 0. 0. 0." <<
'\n';
195 if ( v.ejectile ) dump_line( *v.ejectile, 1 );
196 if ( v.legacy_residue ) dump_line( *v.legacy_residue, 1 );
197 for (
const auto& p : v.final_state_particles ) {
198 if ( v.ejectile && p->
id() == v.ejectile->
id() )
continue;
199 if ( v.legacy_residue && p->
id() == v.legacy_residue->
id() )
continue;
206 void convert_to_legacy(
207 const std::vector< std::string >& input_files,
208 const std::string& output_path )
210 std::ofstream out( output_path );
211 if ( !out )
throw marley::Error(
"Could not open output file \""
212 + output_path +
"\" for writing" );
214 out << std::scientific
215 << std::setprecision( std::numeric_limits< double >::max_digits10 );
217 bool header_written =
false;
218 for_each_event( input_files,
220 if ( !header_written ) {
222 header_written =
true;
224 write_old_ascii_event( out,
225 extract_legacy_event_view( ev ) );
229 void convert_to_hepevt(
230 const std::vector< std::string >& input_files,
231 const std::string& output_path )
233 std::ofstream out( output_path );
234 if ( !out )
throw marley::Error(
"Could not open output file \""
235 + output_path +
"\" for writing" );
237 unsigned long ev_num = 0;
238 for_each_event( input_files,
240 write_hepevt_event( out,
241 extract_legacy_event_view( ev ), ev_num, xsec );
250 std::string output_path;
251 std::string output_format;
253 std::vector< std::string > input_files;
255 while ( !args.empty() ) {
256 std::string arg = args.front();
259 if ( arg ==
"-o" || arg ==
"--output" ) {
260 if ( args.empty() ) {
261 std::cerr <<
"marley convert: missing argument after '" << arg
265 output_path = args.front();
268 else if ( arg ==
"--output-format" ) {
269 if ( args.empty() ) {
270 std::cerr <<
"marley convert: missing argument after '"
271 <<
"--output-format'\n";
274 output_format = args.front();
277 else if ( arg ==
"--force" || arg ==
"-f" ) {
280 else if ( arg ==
"--help" || arg ==
"-h" ) {
282 args.push_front(
"convert" );
285 else if ( arg.front() ==
'-' ) {
286 std::cerr <<
"marley convert: unrecognized option '" << arg <<
"'\n";
290 input_files.push_back( arg );
294 if ( output_path.empty() ) {
295 std::cerr <<
"marley convert: missing required option -o OUTPUT_FILE\n";
296 args.push_front(
"convert" );
301 if ( input_files.empty() ) {
302 std::cerr <<
"marley convert: no input files specified\n";
303 args.push_front(
"convert" );
308 if ( output_format.empty() ) {
309 if ( output_path.size() >= 5
310 && output_path.substr( output_path.size() - 5 ) ==
".root" )
312 output_format =
"root";
315 output_format =
"ascii";
319 if ( output_format !=
"ascii" && output_format !=
"root"
320 && output_format !=
"legacy" && output_format !=
"hepevt" )
322 std::cerr <<
"marley convert: invalid output format '"
323 << output_format <<
"'. Supported formats:"
324 " ascii, root, legacy, hepevt\n";
329 if ( output_format ==
"root" ) {
330 std::cerr <<
"marley convert: ROOT output format requires a"
331 " ROOT-enabled build of MARLEY.\n";
337 std::ifstream test( output_path );
339 bool overwrite = marley_utils::prompt_yes_no(
340 "Really overwrite " + output_path +
"?" );
342 std::cout <<
"Action aborted.\n";
348 if ( output_format ==
"legacy" ) {
349 convert_to_legacy( input_files, output_path );
353 if ( output_format ==
"hepevt" ) {
354 convert_to_hepevt( input_files, output_path );
358 std::string out_config_str =
"{ format: \"" + output_format
359 +
"\", file: \"" + output_path
360 +
"\", mode: \"overwrite\", force: true }";
361 auto out_config = marley::JSON::load( out_config_str );
362 auto output_file = marley::OutputFile::make_OutputFile( out_config );
364 bool multi_file = (input_files.size() > 1);
365 std::shared_ptr< HepMC3::GenRunInfo > cleaned_run_info;
366 for_each_event( input_files,
368 const auto& first_info )
370 if ( first_event && multi_file ) {
371 cleaned_run_info = make_cleaned_run_info( first_info );
373 if ( cleaned_run_info ) {
376 output_file->write_event( &ev );
Attribute that holds a real number as a double.
Stores event-related information.
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the GenRunInfo object by smart pointer.
Stores particle-related information.
int id() const
Get the particle ID number (not PDG ID)
const FourVector & momentum() const
Get momentum.
std::shared_ptr< T > attribute(const std::string &name) const
Get attribute of type T.
double generated_mass() const
Get generated mass.
int pid() const
Get PDG ID.
Attribute that holds an Integer implemented as an int.
static bool cmd_help(std::deque< std::string > &args)
Display top-level or command-specific help messages.
static bool cmd_convert(std::deque< std::string > &args)
Convert MARLEY event files between supported formats.
Base class for all exceptions thrown by MARLEY functions.