Version: SMASH-2.2
rootoutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2022
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/rootoutput.h"
11 #include "TFile.h"
12 #include "TTree.h"
13 #include "smash/action.h"
14 #include "smash/clock.h"
16 #include "smash/particles.h"
17 
18 namespace smash {
19 static constexpr int LHyperSurfaceCrossing = LogArea::HyperSurfaceCrossing::id;
20 
21 const int RootOutput::max_buffer_size_ = 500000;
22 
230 RootOutput::RootOutput(const bf::path &path, const std::string &name,
231  const OutputParameters &out_par)
232  : OutputInterface(name),
233  filename_(path / (name + ".root")),
234  write_collisions_(name == "Collisions" || name == "Dileptons" ||
235  name == "Photons"),
236  write_particles_(name == "Particles"),
237  write_initial_conditions_(name == "SMASH_IC"),
238  particles_only_final_(out_par.part_only_final),
239  autosave_frequency_(1000),
240  part_extended_(out_par.part_extended),
241  coll_extended_(out_par.coll_extended),
242  ic_extended_(out_par.ic_extended) {
244  filename_unfinished_ += ".unfinished";
246  make_unique<TFile>(filename_unfinished_.native().c_str(), "NEW");
247  init_trees();
248 }
249 
252  particles_tree_ = new TTree("particles", "particles");
253 
254  particles_tree_->Branch("ev", &ev_, "ev/I");
255  particles_tree_->Branch("tcounter", &tcounter_, "tcounter/I");
256  particles_tree_->Branch("npart", &npart_, "npart/I");
257  particles_tree_->Branch("test_p", &test_p_, "test_p/I");
258  particles_tree_->Branch("modus_l", &modus_l_, "modus_l/D");
259  particles_tree_->Branch("current_t", &current_t_, "current_t/D");
260  particles_tree_->Branch("impact_b", &impact_b_, "impact_b/D");
261  particles_tree_->Branch("empty_event", &empty_event_, "empty_event/O");
262 
263  particles_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
264  particles_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
265 
266  particles_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
267  particles_tree_->Branch("px", &px_[0], "px[npart]/D");
268  particles_tree_->Branch("py", &py_[0], "py[npart]/D");
269  particles_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
270 
271  particles_tree_->Branch("t", &t_[0], "t[npart]/D");
272  particles_tree_->Branch("x", &x_[0], "x[npart]/D");
273  particles_tree_->Branch("y", &y_[0], "y[npart]/D");
274  particles_tree_->Branch("z", &z_[0], "z[npart]/D");
275 
276  particles_tree_->Branch("E_kinetic_tot", &E_kinetic_tot_,
277  "E_kinetic_tot/D");
278  particles_tree_->Branch("E_fields_tot", &E_fields_tot_, "E_fields_tot/D");
279  particles_tree_->Branch("E_tot", &E_tot_, "E_tot/D");
280 
281  if (part_extended_ || ic_extended_) {
282  particles_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
283  particles_tree_->Branch("form_time", &formation_time_[0],
284  "form_time[npart]/D");
285  particles_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
286  particles_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
287  "proc_id_origin[npart]/I");
288  particles_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
289  "proc_type_origin[npart]/I");
290  particles_tree_->Branch("time_last_coll", &time_last_coll_[0],
291  "time_last_coll[npart]/D");
292  particles_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
293  "pdg_mother1[npart]/I");
294  particles_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
295  "pdg_mother2[npart]/I");
296  }
297  }
298 
299  if (write_collisions_) {
300  collisions_tree_ = new TTree("collisions", "collisions");
301 
302  collisions_tree_->Branch("nin", &nin_, "nin/I");
303  collisions_tree_->Branch("nout", &nout_, "nout/I");
304  collisions_tree_->Branch("npart", &npart_, "npart/I");
305  collisions_tree_->Branch("ev", &ev_, "ev/I");
306  collisions_tree_->Branch("weight", &wgt_, "weight/D");
307  collisions_tree_->Branch("partial_weight", &par_wgt_, "partial_weight/D");
308 
309  collisions_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
310  collisions_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
311 
312  collisions_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
313  collisions_tree_->Branch("px", &px_[0], "px[npart]/D");
314  collisions_tree_->Branch("py", &py_[0], "py[npart]/D");
315  collisions_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
316 
317  collisions_tree_->Branch("t", &t_[0], "t[npart]/D");
318  collisions_tree_->Branch("x", &x_[0], "x[npart]/D");
319  collisions_tree_->Branch("y", &y_[0], "y[npart]/D");
320  collisions_tree_->Branch("z", &z_[0], "z[npart]/D");
321 
322  if (coll_extended_) {
323  collisions_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
324  collisions_tree_->Branch("form_time", &formation_time_[0],
325  "form_time[npart]/D");
326  collisions_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
327  collisions_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
328  "proc_id_origin[npart]/I");
329  collisions_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
330  "proc_type_origin[npart]/I");
331  collisions_tree_->Branch("time_last_coll", &time_last_coll_[0],
332  "time_last_coll[npart]/D");
333  collisions_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
334  "pdg_mother1[npart]/I");
335  collisions_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
336  "pdg_mother2[npart]/I");
337  }
338  }
339 }
340 
346  // kOverwrite option prevents from writing extra TKey objects into root file
347  root_out_file_->Write("", TObject::kOverwrite);
348  root_out_file_->Close();
349  bf::rename(filename_unfinished_, filename_);
350 }
351 
352 void RootOutput::at_eventstart(const Particles &particles,
353  const int event_number, const EventInfo &event) {
354  // save event number
355  current_event_ = event_number;
356 
357  modus_l_ = event.modus_length;
358  test_p_ = event.test_particles;
359  current_t_ = event.current_time;
360  E_kinetic_tot_ = event.total_kinetic_energy;
361  E_fields_tot_ = event.total_mean_field_energy;
362  E_tot_ = event.total_energy;
363 
365  output_counter_ = 0;
366  // This is to have only one output of positive impact parameter per event
367  impact_b_ = -1.0;
368  empty_event_ = false;
369  particles_to_tree(particles);
370  output_counter_++;
371  }
372 }
373 
375  const std::unique_ptr<Clock> &,
376  const DensityParameters &,
377  const EventInfo &event) {
378  modus_l_ = event.modus_length;
379  test_p_ = event.test_particles;
380  current_t_ = event.current_time;
381  E_kinetic_tot_ = event.total_kinetic_energy;
382  E_fields_tot_ = event.total_mean_field_energy;
383  E_tot_ = event.total_energy;
384 
386  particles_to_tree(particles);
387  output_counter_++;
388  }
389 }
390 
391 void RootOutput::at_eventend(const Particles &particles,
392  const int /*event_number*/,
393  const EventInfo &event) {
394  modus_l_ = event.modus_length;
395  test_p_ = event.test_particles;
396  current_t_ = event.current_time;
397  E_kinetic_tot_ = event.total_kinetic_energy;
398  E_fields_tot_ = event.total_mean_field_energy;
399  E_tot_ = event.total_energy;
400 
401  impact_b_ = event.impact_parameter;
402  empty_event_ = event.empty_event;
403  if (write_particles_ &&
404  !(event.empty_event &&
406  particles_to_tree(particles);
407  }
408  /* Forced regular dump from operational memory to disk. Very demanding!
409  * If program crashes written data will NOT be lost. */
412  particles_tree_->AutoSave("SaveSelf");
413  }
414  if (write_collisions_) {
415  collisions_tree_->AutoSave("SaveSelf");
416  }
417  }
418 
420  // If the runtime is too short some particles might not yet have
421  // reached the hypersurface. Warning is printed.
422  if (particles.size() != 0 && !event.impose_kinematic_cut_for_SMASH_IC) {
424  "End time might be too small for initial conditions output. "
425  "Hypersurface has not yet been crossed by ",
426  particles.size(), " particle(s).");
427  }
428  }
429 }
430 
432  const double /*density*/) {
433  if (write_collisions_) {
435  action.get_total_weight(), action.get_partial_weight());
436  }
437 
441  }
442 }
443 
444 template <typename T>
445 void RootOutput::particles_to_tree(T &particles) {
446  int i = 0;
447 
450  bool exceeded_buffer_message = true;
451 
452  for (const auto &p : particles) {
453  // Buffer full - flush to tree, else fill with particles
454  if (i >= max_buffer_size_) {
455  if (exceeded_buffer_message) {
456  logg[LOutput].warn()
457  << "\nThe number of particles N = " << particles.size()
458  << " exceeds the maximum buffer size B = " << max_buffer_size_
459  << ".\nceil(N/B) = "
460  << std::ceil(particles.size() /
461  static_cast<double>(max_buffer_size_))
462  << " separate ROOT Tree entries will be created at this output."
463  << "\nMaximum buffer size (max_buffer_size_) can be changed in "
464  << "rootoutput.h\n\n";
465  exceeded_buffer_message = false;
466  }
468  i = 0;
469  particles_tree_->Fill();
470  } else {
471  pdgcode_[i] = p.pdgcode().get_decimal();
472  charge_[i] = p.type().charge();
473 
474  p0_[i] = p.momentum().x0();
475  px_[i] = p.momentum().x1();
476  py_[i] = p.momentum().x2();
477  pz_[i] = p.momentum().x3();
478 
479  t_[i] = p.position().x0();
480  x_[i] = p.position().x1();
481  y_[i] = p.position().x2();
482  z_[i] = p.position().x3();
483 
484  if (part_extended_ || ic_extended_) {
485  const auto h = p.get_history();
486  formation_time_[i] = p.formation_time();
487  xsec_factor_[i] = p.xsec_scaling_factor();
488  time_last_coll_[i] = h.time_last_collision;
489  coll_per_part_[i] = h.collisions_per_particle;
490  proc_id_origin_[i] = h.id_process;
491  proc_type_origin_[i] = static_cast<int>(h.process_type);
492  pdg_mother1_[i] = h.p1.get_decimal();
493  pdg_mother2_[i] = h.p2.get_decimal();
494  }
495 
496  i++;
497  }
498  }
499  // Flush rest to tree
500  if (i > 0) {
501  npart_ = i;
502  particles_tree_->Fill();
503  }
504 }
505 
506 void RootOutput::collisions_to_tree(const ParticleList &incoming,
507  const ParticleList &outgoing,
508  const double weight,
509  const double partial_weight) {
511  nin_ = incoming.size();
512  nout_ = outgoing.size();
513  npart_ = nin_ + nout_;
514  wgt_ = weight;
515  par_wgt_ = partial_weight;
516 
517  int i = 0;
518 
519  /* It is assumed that nin + nout < max_buffer_size_
520  * This is true for any possible reaction for current buffer size: 10000
521  * But if one wants initial/final particles written to collisions
522  * then implementation should be updated. */
523 
524  for (const ParticleList &plist : {incoming, outgoing}) {
525  for (const auto &p : plist) {
526  pdgcode_[i] = p.pdgcode().get_decimal();
527  charge_[i] = p.type().charge();
528 
529  p0_[i] = p.momentum().x0();
530  px_[i] = p.momentum().x1();
531  py_[i] = p.momentum().x2();
532  pz_[i] = p.momentum().x3();
533 
534  t_[i] = p.position().x0();
535  x_[i] = p.position().x1();
536  y_[i] = p.position().x2();
537  z_[i] = p.position().x3();
538 
539  if (coll_extended_) {
540  const auto h = p.get_history();
541  formation_time_[i] = p.formation_time();
542  xsec_factor_[i] = p.xsec_scaling_factor();
543  time_last_coll_[i] = h.time_last_collision;
544  coll_per_part_[i] = h.collisions_per_particle;
545  proc_id_origin_[i] = h.id_process;
546  proc_type_origin_[i] = static_cast<int>(h.process_type);
547  pdg_mother1_[i] = h.p1.get_decimal();
548  pdg_mother2_[i] = h.p2.get_decimal();
549  }
550 
551  i++;
552  }
553  }
554 
555  collisions_tree_->Fill();
556 }
557 } // namespace smash
Action is the base class for a generic process that takes a number of incoming particles and transfor...
Definition: action.h:35
virtual ProcessType get_type() const
Get the process type.
Definition: action.h:131
virtual double get_total_weight() const =0
Return the total weight value, which is mainly used for the weight output entry.
const ParticleList & incoming_particles() const
Get the list of particles that go into the action.
Definition: action.cc:57
virtual double get_partial_weight() const =0
Return the specific weight for the chosen outgoing channel, which is mainly used for the partial weig...
const ParticleList & outgoing_particles() const
Get the list of particles that resulted from the action.
Definition: action.h:245
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:108
Abstraction of generic output.
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
size_t size() const
Definition: particles.h:87
void at_interaction(const Action &action, const double density) override
Writes collisions to a tree defined by treename.
Definition: rootoutput.cc:431
std::vector< double > t_
Property that is written to ROOT output.
Definition: rootoutput.h:190
std::vector< double > y_
Property that is written to ROOT output.
Definition: rootoutput.h:192
double current_t_
Property that is written to ROOT output.
Definition: rootoutput.h:207
OutputOnlyFinal particles_only_final_
Print only final particles in the event, no intermediate output.
Definition: rootoutput.h:222
int current_event_
Number of current event.
Definition: rootoutput.h:171
TTree * collisions_tree_
TTree for collision output.
Definition: rootoutput.h:151
~RootOutput()
Destructor.
Definition: rootoutput.cc:345
double E_kinetic_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:208
int test_p_
Property that is written to ROOT output.
Definition: rootoutput.h:206
void collisions_to_tree(const ParticleList &incoming, const ParticleList &outgoing, const double weight, const double partial_weight)
Writes collisions to a tree defined by treename.
Definition: rootoutput.cc:506
int autosave_frequency_
Root file cannot be read if it was not properly closed and finalized.
Definition: rootoutput.h:233
std::vector< int > proc_type_origin_
Property that is written to ROOT output.
Definition: rootoutput.h:203
double modus_l_
Property that is written to ROOT output.
Definition: rootoutput.h:207
std::vector< double > time_last_coll_
Property that is written to ROOT output.
Definition: rootoutput.h:197
std::vector< int > coll_per_part_
Property that is written to ROOT output.
Definition: rootoutput.h:201
int tcounter_
Property that is written to ROOT output.
Definition: rootoutput.h:206
const bf::path filename_
Filename of output.
Definition: rootoutput.h:133
int npart_
Property that is written to ROOT output.
Definition: rootoutput.h:206
std::vector< int > pdg_mother1_
Property that is written to ROOT output.
Definition: rootoutput.h:204
int nin_
Property that is written to ROOT output.
Definition: rootoutput.h:206
int ev_
Property that is written to ROOT output.
Definition: rootoutput.h:206
bool write_collisions_
Option to write collisions tree.
Definition: rootoutput.h:213
std::vector< int > charge_
Property that is written to ROOT output.
Definition: rootoutput.h:200
std::vector< double > px_
Property that is written to ROOT output.
Definition: rootoutput.h:187
bf::path filename_unfinished_
Filename of output as long as simulation is still running.
Definition: rootoutput.h:135
bool write_initial_conditions_
Option to write particles tree for initial conditions.
Definition: rootoutput.h:219
double wgt_
Property that is written to ROOT output.
Definition: rootoutput.h:207
std::vector< double > py_
Property that is written to ROOT output.
Definition: rootoutput.h:188
std::vector< int > proc_id_origin_
Property that is written to ROOT output.
Definition: rootoutput.h:202
void particles_to_tree(T &particles)
Writes particles to a tree defined by treename.
Definition: rootoutput.cc:445
const bool part_extended_
Whether extended particle output is on.
Definition: rootoutput.h:236
void at_eventstart(const Particles &particles, const int event_number, const EventInfo &event) override
update event number and writes intermediate particles to a tree.
Definition: rootoutput.cc:352
double impact_b_
Property that is written to ROOT output.
Definition: rootoutput.h:207
std::vector< double > z_
Property that is written to ROOT output.
Definition: rootoutput.h:193
std::vector< double > formation_time_
Property that is written to ROOT output.
Definition: rootoutput.h:194
void at_eventend(const Particles &particles, const int event_number, const EventInfo &event) override
update event number and impact parameter, and writes intermediate particles to a tree.
Definition: rootoutput.cc:391
std::vector< double > x_
Property that is written to ROOT output.
Definition: rootoutput.h:191
std::vector< double > p0_
Property that is written to ROOT output.
Definition: rootoutput.h:186
bool empty_event_
Property that is written to ROOT output.
Definition: rootoutput.h:209
static const int max_buffer_size_
Maximal buffer size.
Definition: rootoutput.h:179
std::unique_ptr< TFile > root_out_file_
Pointer to root output file.
Definition: rootoutput.h:137
std::vector< double > xsec_factor_
Property that is written to ROOT output.
Definition: rootoutput.h:196
double E_fields_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:208
const bool coll_extended_
Whether extended collisions output is on.
Definition: rootoutput.h:238
double par_wgt_
Property that is written to ROOT output.
Definition: rootoutput.h:207
void init_trees()
Basic initialization routine, creating the TTree objects for particles and collisions.
Definition: rootoutput.cc:250
int output_counter_
Number of output in a given event.
Definition: rootoutput.h:169
RootOutput(const bf::path &path, const std::string &name, const OutputParameters &out_par)
Construct ROOT output.
Definition: rootoutput.cc:230
void at_intermediate_time(const Particles &particles, const std::unique_ptr< Clock > &clock, const DensityParameters &dens_param, const EventInfo &event) override
Writes intermediate particles to a tree defined by treename, if it is allowed (i.e....
Definition: rootoutput.cc:374
double E_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:208
TTree * particles_tree_
TTree for particles output.
Definition: rootoutput.h:144
std::vector< double > pz_
Property that is written to ROOT output.
Definition: rootoutput.h:189
int nout_
Property that is written to ROOT output.
Definition: rootoutput.h:206
const bool ic_extended_
Whether extended ic output is on.
Definition: rootoutput.h:240
bool write_particles_
Option to write particles tree.
Definition: rootoutput.h:216
std::vector< int > pdgcode_
Property that is written to ROOT output.
Definition: rootoutput.h:199
std::vector< int > pdg_mother2_
Property that is written to ROOT output.
Definition: rootoutput.h:205
@ IfNotEmpty
Print only final-state particles, and those only if the event is not empty.
@ No
Print initial, intermediate and final-state particles.
std::array< einhard::Logger<>, std::tuple_size< LogArea::AreaTuple >::value > logg
An array that stores all pre-configured Logger objects.
Definition: logging.cc:39
constexpr int p
Proton.
Definition: action.h:24
static constexpr int LHyperSurfaceCrossing
@ HyperSurfaceCrossing
Hypersurface crossing Particles are removed from the evolution and printed to a separate output to se...
static constexpr int LOutput
Structure to contain custom data for output.
bool empty_event
True if no collisions happened.
bool impose_kinematic_cut_for_SMASH_IC
Whether or not kinematic cuts are employed for SMASH IC.
Helper structure for Experiment to hold output options and parameters.