MARLEY (Model of Argon Reaction Low Energy Yields) v2.0.0
A Monte Carlo event generator for tens-of-MeV neutrino interactions
Loading...
Searching...
No Matches
cmd_convert.cc
1
4//
5// This file is part of MARLEY (Model of Argon Reaction Low Energy Yields)
6//
7// MARLEY is free software: you can redistribute it and/or modify it under the
8// terms of version 3 of the GNU General Public License as published by the
9// Free Software Foundation.
10//
11// For the full text of the license please see COPYING or
12// visit http://opensource.org/licenses/GPL-3.0
13//
14// Please respect the MCnet academic usage guidelines. See GUIDELINES
15// or visit https://www.montecarlonet.org/GUIDELINES for details.
16
17// Standard library includes
18#include <fstream>
19#include <iomanip>
20#include <iostream>
21#include <limits>
22#include <memory>
23#include <sstream>
24#include <string>
25#include <vector>
26
27// HepMC3 includes
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"
34
35// MARLEY includes
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"
44
45namespace {
46
47 std::shared_ptr<HepMC3::GenRunInfo> make_cleaned_run_info(
48 std::shared_ptr<HepMC3::GenRunInfo> original)
49 {
50 auto cleaned = std::make_shared<HepMC3::GenRunInfo>(*original);
51 cleaned->remove_attribute("MARLEY.RNGseed");
52 return cleaned;
53 }
54
55 std::shared_ptr<HepMC3::GenParticle> find_legacy_residue(
56 std::shared_ptr<HepMC3::GenParticle> residue )
57 {
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;
63 if ( out->status()
64 != marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS )
65 {
66 daughter = out;
67 break;
68 }
69 if ( !daughter ) daughter = out;
70 }
71 if ( !daughter ) break;
72 current = daughter;
73 }
74 return current;
75 }
76
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;
83 double Ex = 0.;
84 int twoJ = 0;
85 int parity = 1;
86 std::vector< std::shared_ptr< HepMC3::GenParticle > > final_state_particles;
87 };
88
89 LegacyEventView extract_legacy_event_view( HepMC3::GenEvent& ev ) {
90 LegacyEventView v;
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 );
95
96 if ( v.residue ) {
97 auto Ex_a
98 = v.residue->attribute< HepMC3::DoubleAttribute >( "Ex" );
99 if ( Ex_a ) v.Ex = Ex_a->value();
100 auto twoJ_a
101 = v.residue->attribute< HepMC3::IntAttribute >( "twoJ" );
102 if ( twoJ_a ) v.twoJ = twoJ_a->value();
103 auto par_a
104 = v.residue->attribute< HepMC3::IntAttribute >( "parity" );
105 if ( par_a ) v.parity = par_a->value();
106 }
107
108 if ( v.residue ) v.legacy_residue = find_legacy_residue( v.residue );
109
110 v.final_state_particles
111 = marley_hepmc3::get_particles_with_status(
112 marley_hepmc3::NUHEPMC_FINAL_STATE_STATUS, ev );
113
114 return v;
115 }
116
117 void write_old_ascii_event( std::ostream& os,
118 const LegacyEventView& v )
119 {
120 int num_final = 2;
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;
124 ++num_final;
125 }
126
127 std::ostringstream tmp;
128 tmp << std::scientific
129 << std::setprecision( std::numeric_limits< double >::max_digits10 );
130
131 tmp << "2 " << num_final << ' '
132 << v.Ex << ' ' << v.twoJ << ' ' << ( v.parity >= 0 ? '+' : '-' )
133 << '\n';
134
135 auto write_part = [ &tmp ]( const HepMC3::GenParticle& p ) {
136 const auto& m = p.momentum();
137 int q = marley_hepmc3::get_particle_charge(
138 const_cast< HepMC3::GenParticle& >( p ) );
139 tmp << p.pid() << ' ' << m.e() << ' ' << m.px() << ' '
140 << m.py() << ' ' << m.pz() << ' '
141 << p.generated_mass() << ' ' << q << '\n';
142 };
143
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;
151 write_part( *p );
152 }
153
154 os << tmp.str();
155 }
156
157 void write_hepevt_event( std::ostream& os,
158 const LegacyEventView& v, unsigned long event_num,
159 double flux_avg_xsec_natural )
160 {
161 int nhep = 5;
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;
165 ++nhep;
166 }
167
168 constexpr double MEV2GEV = 0.001;
169
170 std::ostringstream tmp;
171 tmp << std::scientific
172 << std::setprecision( std::numeric_limits< double >::max_digits10 );
173
174 tmp << event_num << ' ' << nhep << '\n';
175
176 auto dump_line = [ &tmp ]( const HepMC3::GenParticle& p,
177 int status, int jmo1 = 0, int jmo2 = 0 )
178 {
179 const auto& m = p.momentum();
180 tmp << status << ' ' << p.pid() << ' ' << jmo1 << ' ' << jmo2
181 << " 0 0 "
182 << m.px() * MEV2GEV << ' ' << m.py() * MEV2GEV << ' '
183 << m.pz() * MEV2GEV << ' ' << m.e() * MEV2GEV << ' '
184 << p.generated_mass() * MEV2GEV
185 << " 0. 0. 0. 0." << '\n';
186 };
187
188 if ( v.projectile ) dump_line( *v.projectile, 3 );
189 if ( v.target ) dump_line( *v.target, 3 );
190
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';
194
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;
200 dump_line( *p, 1 );
201 }
202
203 os << tmp.str();
204 }
205
206 void convert_to_legacy(
207 const std::vector< std::string >& input_files,
208 const std::string& output_path )
209 {
210 std::ofstream out( output_path );
211 if ( !out ) throw marley::Error( "Could not open output file \""
212 + output_path + "\" for writing" );
213
214 out << std::scientific
215 << std::setprecision( std::numeric_limits< double >::max_digits10 );
216
217 bool header_written = false;
218 for_each_event( input_files,
219 [ & ]( HepMC3::GenEvent& ev, bool, double xsec, const auto& ) {
220 if ( !header_written ) {
221 out << xsec << '\n';
222 header_written = true;
223 }
224 write_old_ascii_event( out,
225 extract_legacy_event_view( ev ) );
226 } );
227 }
228
229 void convert_to_hepevt(
230 const std::vector< std::string >& input_files,
231 const std::string& output_path )
232 {
233 std::ofstream out( output_path );
234 if ( !out ) throw marley::Error( "Could not open output file \""
235 + output_path + "\" for writing" );
236
237 unsigned long ev_num = 0;
238 for_each_event( input_files,
239 [ & ]( HepMC3::GenEvent& ev, bool, double xsec, const auto& ) {
240 write_hepevt_event( out,
241 extract_legacy_event_view( ev ), ev_num, xsec );
242 ++ev_num;
243 } );
244 }
245
246}
247
248bool marley::CommandHandler::cmd_convert( std::deque< std::string >& args ) {
249
250 std::string output_path;
251 std::string output_format;
252 bool force = false;
253 std::vector< std::string > input_files;
254
255 while ( !args.empty() ) {
256 std::string arg = args.front();
257 args.pop_front();
258
259 if ( arg == "-o" || arg == "--output" ) {
260 if ( args.empty() ) {
261 std::cerr << "marley convert: missing argument after '" << arg
262 << "'\n";
263 return false;
264 }
265 output_path = args.front();
266 args.pop_front();
267 }
268 else if ( arg == "--output-format" ) {
269 if ( args.empty() ) {
270 std::cerr << "marley convert: missing argument after '"
271 << "--output-format'\n";
272 return false;
273 }
274 output_format = args.front();
275 args.pop_front();
276 }
277 else if ( arg == "--force" || arg == "-f" ) {
278 force = true;
279 }
280 else if ( arg == "--help" || arg == "-h" ) {
281 args.clear();
282 args.push_front( "convert" );
284 }
285 else if ( arg.front() == '-' ) {
286 std::cerr << "marley convert: unrecognized option '" << arg << "'\n";
287 return false;
288 }
289 else {
290 input_files.push_back( arg );
291 }
292 }
293
294 if ( output_path.empty() ) {
295 std::cerr << "marley convert: missing required option -o OUTPUT_FILE\n";
296 args.push_front( "convert" );
298 return false;
299 }
300
301 if ( input_files.empty() ) {
302 std::cerr << "marley convert: no input files specified\n";
303 args.push_front( "convert" );
305 return false;
306 }
307
308 if ( output_format.empty() ) {
309 if ( output_path.size() >= 5
310 && output_path.substr( output_path.size() - 5 ) == ".root" )
311 {
312 output_format = "root";
313 }
314 else {
315 output_format = "ascii";
316 }
317 }
318
319 if ( output_format != "ascii" && output_format != "root"
320 && output_format != "legacy" && output_format != "hepevt" )
321 {
322 std::cerr << "marley convert: invalid output format '"
323 << output_format << "'. Supported formats:"
324 " ascii, root, legacy, hepevt\n";
325 return false;
326 }
327
328#ifndef USE_ROOT
329 if ( output_format == "root" ) {
330 std::cerr << "marley convert: ROOT output format requires a"
331 " ROOT-enabled build of MARLEY.\n";
332 return false;
333 }
334#endif
335
336 if ( !force ) {
337 std::ifstream test( output_path );
338 if ( test ) {
339 bool overwrite = marley_utils::prompt_yes_no(
340 "Really overwrite " + output_path + "?" );
341 if ( !overwrite ) {
342 std::cout << "Action aborted.\n";
343 return true;
344 }
345 }
346 }
347
348 if ( output_format == "legacy" ) {
349 convert_to_legacy( input_files, output_path );
350 return true;
351 }
352
353 if ( output_format == "hepevt" ) {
354 convert_to_hepevt( input_files, output_path );
355 return true;
356 }
357
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 );
363
364 bool multi_file = (input_files.size() > 1);
365 std::shared_ptr< HepMC3::GenRunInfo > cleaned_run_info;
366 for_each_event( input_files,
367 [ & ]( HepMC3::GenEvent& ev, bool first_event, double,
368 const auto& first_info )
369 {
370 if ( first_event && multi_file ) {
371 cleaned_run_info = make_cleaned_run_info( first_info );
372 }
373 if ( cleaned_run_info ) {
374 ev.set_run_info( cleaned_run_info );
375 }
376 output_file->write_event( &ev );
377 } );
378
379 return true;
380}
Attribute that holds a real number as a double.
Definition Attribute.h:245
Stores event-related information.
Definition GenEvent.h:47
void set_run_info(std::shared_ptr< GenRunInfo > run)
Set the GenRunInfo object by smart pointer.
Definition GenEvent.h:148
Stores particle-related information.
Definition GenParticle.h:34
int id() const
Get the particle ID number (not PDG ID)
Definition GenParticle.h:68
const FourVector & momentum() const
Get momentum.
Definition GenParticle.h:97
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.
Definition GenParticle.h:94
Attribute that holds an Integer implemented as an int.
Definition Attribute.h:157
static bool cmd_help(std::deque< std::string > &args)
Display top-level or command-specific help messages.
Definition cmd_help.cc:24
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.
Definition Error.hh:26