Version: SMASH-2.1
rootoutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2021
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 
224 RootOutput::RootOutput(const bf::path &path, const std::string &name,
225  const OutputParameters &out_par)
226  : OutputInterface(name),
227  filename_(path / (name + ".root")),
228  write_collisions_(name == "Collisions" || name == "Dileptons" ||
229  name == "Photons"),
230  write_particles_(name == "Particles"),
231  write_initial_conditions_(name == "SMASH_IC"),
232  particles_only_final_(out_par.part_only_final),
233  autosave_frequency_(1000),
234  part_extended_(out_par.part_extended),
235  coll_extended_(out_par.coll_extended),
236  ic_extended_(out_par.ic_extended) {
238  filename_unfinished_ += ".unfinished";
240  make_unique<TFile>(filename_unfinished_.native().c_str(), "NEW");
241  init_trees();
242 }
243 
246  particles_tree_ = new TTree("particles", "particles");
247 
248  particles_tree_->Branch("ev", &ev_, "ev/I");
249  particles_tree_->Branch("tcounter", &tcounter_, "tcounter/I");
250  particles_tree_->Branch("npart", &npart_, "npart/I");
251  particles_tree_->Branch("test_p", &test_p_, "test_p/I");
252  particles_tree_->Branch("modus_l", &modus_l_, "modus_l/D");
253  particles_tree_->Branch("current_t", &current_t_, "current_t/D");
254  particles_tree_->Branch("impact_b", &impact_b_, "impact_b/D");
255  particles_tree_->Branch("empty_event", &empty_event_, "empty_event/O");
256 
257  particles_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
258  particles_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
259 
260  particles_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
261  particles_tree_->Branch("px", &px_[0], "px[npart]/D");
262  particles_tree_->Branch("py", &py_[0], "py[npart]/D");
263  particles_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
264 
265  particles_tree_->Branch("t", &t_[0], "t[npart]/D");
266  particles_tree_->Branch("x", &x_[0], "x[npart]/D");
267  particles_tree_->Branch("y", &y_[0], "y[npart]/D");
268  particles_tree_->Branch("z", &z_[0], "z[npart]/D");
269 
270  particles_tree_->Branch("E_kinetic_tot", &E_kinetic_tot_,
271  "E_kinetic_tot/D");
272  particles_tree_->Branch("E_fields_tot", &E_fields_tot_, "E_fields_tot/D");
273  particles_tree_->Branch("E_tot", &E_tot_, "E_tot/D");
274 
275  if (part_extended_ || ic_extended_) {
276  particles_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
277  particles_tree_->Branch("form_time", &formation_time_[0],
278  "form_time[npart]/D");
279  particles_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
280  particles_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
281  "proc_id_origin[npart]/I");
282  particles_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
283  "proc_type_origin[npart]/I");
284  particles_tree_->Branch("time_last_coll", &time_last_coll_[0],
285  "time_last_coll[npart]/D");
286  particles_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
287  "pdg_mother1[npart]/I");
288  particles_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
289  "pdg_mother2[npart]/I");
290  }
291  }
292 
293  if (write_collisions_) {
294  collisions_tree_ = new TTree("collisions", "collisions");
295 
296  collisions_tree_->Branch("nin", &nin_, "nin/I");
297  collisions_tree_->Branch("nout", &nout_, "nout/I");
298  collisions_tree_->Branch("npart", &npart_, "npart/I");
299  collisions_tree_->Branch("ev", &ev_, "ev/I");
300  collisions_tree_->Branch("weight", &wgt_, "weight/D");
301  collisions_tree_->Branch("partial_weight", &par_wgt_, "partial_weight/D");
302 
303  collisions_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
304  collisions_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
305 
306  collisions_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
307  collisions_tree_->Branch("px", &px_[0], "px[npart]/D");
308  collisions_tree_->Branch("py", &py_[0], "py[npart]/D");
309  collisions_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
310 
311  collisions_tree_->Branch("t", &t_[0], "t[npart]/D");
312  collisions_tree_->Branch("x", &x_[0], "x[npart]/D");
313  collisions_tree_->Branch("y", &y_[0], "y[npart]/D");
314  collisions_tree_->Branch("z", &z_[0], "z[npart]/D");
315 
316  if (coll_extended_) {
317  collisions_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
318  collisions_tree_->Branch("form_time", &formation_time_[0],
319  "form_time[npart]/D");
320  collisions_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
321  collisions_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
322  "proc_id_origin[npart]/I");
323  collisions_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
324  "proc_type_origin[npart]/I");
325  collisions_tree_->Branch("time_last_coll", &time_last_coll_[0],
326  "time_last_coll[npart]/D");
327  collisions_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
328  "pdg_mother1[npart]/I");
329  collisions_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
330  "pdg_mother2[npart]/I");
331  }
332  }
333 }
334 
340  // kOverwrite option prevents from writing extra TKey objects into root file
341  root_out_file_->Write("", TObject::kOverwrite);
342  root_out_file_->Close();
343  bf::rename(filename_unfinished_, filename_);
344 }
345 
346 void RootOutput::at_eventstart(const Particles &particles,
347  const int event_number, const EventInfo &event) {
348  // save event number
349  current_event_ = event_number;
350 
351  modus_l_ = event.modus_length;
352  test_p_ = event.test_particles;
353  current_t_ = event.current_time;
354  E_kinetic_tot_ = event.total_kinetic_energy;
355  E_fields_tot_ = event.total_mean_field_energy;
356  E_tot_ = event.total_energy;
357 
359  output_counter_ = 0;
360  // This is to have only one output of positive impact parameter per event
361  impact_b_ = -1.0;
362  empty_event_ = false;
363  particles_to_tree(particles);
364  output_counter_++;
365  }
366 }
367 
369  const std::unique_ptr<Clock> &,
370  const DensityParameters &,
371  const EventInfo &event) {
372  modus_l_ = event.modus_length;
373  test_p_ = event.test_particles;
374  current_t_ = event.current_time;
375  E_kinetic_tot_ = event.total_kinetic_energy;
376  E_fields_tot_ = event.total_mean_field_energy;
377  E_tot_ = event.total_energy;
378 
380  particles_to_tree(particles);
381  output_counter_++;
382  }
383 }
384 
385 void RootOutput::at_eventend(const Particles &particles,
386  const int /*event_number*/,
387  const EventInfo &event) {
388  modus_l_ = event.modus_length;
389  test_p_ = event.test_particles;
390  current_t_ = event.current_time;
391  E_kinetic_tot_ = event.total_kinetic_energy;
392  E_fields_tot_ = event.total_mean_field_energy;
393  E_tot_ = event.total_energy;
394 
395  impact_b_ = event.impact_parameter;
396  empty_event_ = event.empty_event;
397  if (write_particles_ &&
398  !(event.empty_event &&
400  particles_to_tree(particles);
401  }
402  /* Forced regular dump from operational memory to disk. Very demanding!
403  * If program crashes written data will NOT be lost. */
406  particles_tree_->AutoSave("SaveSelf");
407  }
408  if (write_collisions_) {
409  collisions_tree_->AutoSave("SaveSelf");
410  }
411  }
412 
414  // If the runtime is too short some particles might not yet have
415  // reached the hypersurface. Warning is printed.
416  if (particles.size() != 0) {
418  "End time might be too small for initial conditions output. "
419  "Hypersurface has not yet been crossed by ",
420  particles.size(), " particle(s).");
421  }
422  }
423 }
424 
426  const double /*density*/) {
427  if (write_collisions_) {
429  action.get_total_weight(), action.get_partial_weight());
430  }
431 
435  }
436 }
437 
438 template <typename T>
439 void RootOutput::particles_to_tree(T &particles) {
440  int i = 0;
441 
444  bool exceeded_buffer_message = true;
445 
446  for (const auto &p : particles) {
447  // Buffer full - flush to tree, else fill with particles
448  if (i >= max_buffer_size_) {
449  if (exceeded_buffer_message) {
450  logg[LOutput].warn()
451  << "\nThe number of particles N = " << particles.size()
452  << " exceeds the maximum buffer size B = " << max_buffer_size_
453  << ".\nceil(N/B) = "
454  << std::ceil(particles.size() /
455  static_cast<double>(max_buffer_size_))
456  << " separate ROOT Tree entries will be created at this output."
457  << "\nMaximum buffer size (max_buffer_size_) can be changed in "
458  << "rootoutput.h\n\n";
459  exceeded_buffer_message = false;
460  }
462  i = 0;
463  particles_tree_->Fill();
464  } else {
465  pdgcode_[i] = p.pdgcode().get_decimal();
466  charge_[i] = p.type().charge();
467 
468  p0_[i] = p.momentum().x0();
469  px_[i] = p.momentum().x1();
470  py_[i] = p.momentum().x2();
471  pz_[i] = p.momentum().x3();
472 
473  t_[i] = p.position().x0();
474  x_[i] = p.position().x1();
475  y_[i] = p.position().x2();
476  z_[i] = p.position().x3();
477 
478  if (part_extended_ || ic_extended_) {
479  const auto h = p.get_history();
480  formation_time_[i] = p.formation_time();
481  xsec_factor_[i] = p.xsec_scaling_factor();
482  time_last_coll_[i] = h.time_last_collision;
483  coll_per_part_[i] = h.collisions_per_particle;
484  proc_id_origin_[i] = h.id_process;
485  proc_type_origin_[i] = static_cast<int>(h.process_type);
486  pdg_mother1_[i] = h.p1.get_decimal();
487  pdg_mother2_[i] = h.p2.get_decimal();
488  }
489 
490  i++;
491  }
492  }
493  // Flush rest to tree
494  if (i > 0) {
495  npart_ = i;
496  particles_tree_->Fill();
497  }
498 }
499 
500 void RootOutput::collisions_to_tree(const ParticleList &incoming,
501  const ParticleList &outgoing,
502  const double weight,
503  const double partial_weight) {
505  nin_ = incoming.size();
506  nout_ = outgoing.size();
507  npart_ = nin_ + nout_;
508  wgt_ = weight;
509  par_wgt_ = partial_weight;
510 
511  int i = 0;
512 
513  /* It is assumed that nin + nout < max_buffer_size_
514  * This is true for any possible reaction for current buffer size: 10000
515  * But if one wants initial/final particles written to collisions
516  * then implementation should be updated. */
517 
518  for (const ParticleList &plist : {incoming, outgoing}) {
519  for (const auto &p : plist) {
520  pdgcode_[i] = p.pdgcode().get_decimal();
521  charge_[i] = p.type().charge();
522 
523  p0_[i] = p.momentum().x0();
524  px_[i] = p.momentum().x1();
525  py_[i] = p.momentum().x2();
526  pz_[i] = p.momentum().x3();
527 
528  t_[i] = p.position().x0();
529  x_[i] = p.position().x1();
530  y_[i] = p.position().x2();
531  z_[i] = p.position().x3();
532 
533  if (coll_extended_) {
534  const auto h = p.get_history();
535  formation_time_[i] = p.formation_time();
536  xsec_factor_[i] = p.xsec_scaling_factor();
537  time_last_coll_[i] = h.time_last_collision;
538  coll_per_part_[i] = h.collisions_per_particle;
539  proc_id_origin_[i] = h.id_process;
540  proc_type_origin_[i] = static_cast<int>(h.process_type);
541  pdg_mother1_[i] = h.p1.get_decimal();
542  pdg_mother2_[i] = h.p2.get_decimal();
543  }
544 
545  i++;
546  }
547  }
548 
549  collisions_tree_->Fill();
550 }
551 } // 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:425
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:339
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:500
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:439
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:346
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:385
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:244
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:224
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:368
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.
Helper structure for Experiment to hold output options and parameters.