Version: SMASH-3.4
rootoutput.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2014-2025
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/rootoutput.h"
11 
12 #include "TFile.h"
13 #include "TTree.h"
14 #include "smash/action.h"
15 #include "smash/clock.h"
17 #include "smash/particles.h"
18 
19 namespace smash {
20 
21 const int RootOutput::max_buffer_size_ = 500000;
22 
23 /*!\Userguide
24  * \page doxypage_output_root
25  * SMASH ROOT output is a fast and disk-space efficient, but not human-readable
26  * output. It is a custom format making information about the SMASH calculation
27  * accessible with ROOT, mostly mirroring the information of the
28  * \ref doxypage_output_oscar "OSCAR output" formats. This output is distinct
29  * from the standarized \ref doxypage_output_hepmc "HepMC output" that is also
30  * available in a ROOT format and more widely adopted.
31  *
32  * SMASH ROOT output files can be viewed using ROOT's TBrowser. One can also
33  * access them using ROOT functions. The full memory structure of the ROOT
34  * files can be found here: http://root.cern.ch/root/html/TFile.html. We only
35  * describe the logical structure of the SMASH ROOT output. Knowing the logical
36  * structure is enough to read and write ROOT files, be able to view them in
37  * TBrowser, or write a ROOT macro to analyze them.
38  *
39  * Producing ROOT output requires ROOT installed (see http://root.cern.ch).
40  *
41  * Depending on configuration (see \ref doxypage_output "Output"), SMASH can
42  * produce two ROOT files per run: \c Particles.root and \c Collisions.root.
43  * These files contain a TTree called \c particles and a TTree called
44  * \c collisions, respectively. The \c particles tree contains information about
45  * the parameters of the run (such as the number of testparticles and event
46  * number), information relating to individual particles (such as their position
47  * or charge), and information about bulk observables in the system (kinetic
48  * energy, mean field energy, and total energy). The \c collisions tree contains
49  * information about each collision, such as number of incoming and outgoing
50  * particles. It also has the full information about the incoming and outgoing\
51  * particles of each collision.
52  *
53  * In case that the ROOT format is used for dilepton output
54  * (see \ref doxypage_output_dileptons "Dileption output"), the ROOT file is
55  * called \c Dileptons.root and only contains a \c collisions tree with all the
56  * dilepton decays.
57  *
58  * Output is divided into ROOT entries (output blocks). In a ROOT entry,
59  * information is stored in TBranches, where every physical quantity corresponds
60  * to a separate TBranch. One entry (output block) in the \c particles TTree is
61  * comprised of:
62  * \code
63  * ev ens tcounter npart test_p modus_l current_t impact_b empty_event
64  * id[npart] pdgcode[npart] charge[npart] formation_time[npart]
65  * time_last_collision[npart] t[npart] x[npart] y[npart] z[npart] p0[npart]
66  * px[npart] py[npart] pz[npart] E_kinetic_tot E_fields_tot E_tot
67  * \endcode
68  * All particles in a ROOT entry (output block) are at the same time and in the
69  * same event. The maximal number of particles in one entry is limited to
70  * 500000. This is done to limit the buffer size needed for ROOT output. If the
71  * number of particles in one ROOT entry (output block) exceeds 500000, then
72  * they are written in separate entries with the same \c tcounter and \c ev.
73  *
74  * Each ROOT entry (output block) contains TBranches with overall information
75  * about the event and the output block:
76  * \li \c ev is event number
77  * \li \c ens is ensemble number
78  * \li \c tcounter is number of the output block in a given event
79  * \li \c npart is number of particles in the block
80  * \li \c test_p is number of testparticles per particle
81  * \li \c modus_l is modus length
82  * \li \c current_t is time associated with the output block, in fm
83  * \li \c impact_b is the impact parameter of the event
84  * \li \c empty_event indicates whether the projectile did not interact with the
85  * target
86  *
87  * Then, each ROOT entry (output block) contains information about all particles
88  * in the block. Particle characteristics such as position or charge are stored
89  * in arrays which belong to separate TBranches. There are TBranches containing
90  * arrays with information on the following quantities:
91  * \li \c id is unique integer identifier of the particle
92  * \li \c pdgcode is PDG id
93  * \li \c charge is the electric charge
94  * \li \c formation_time is particle formation time
95  * \li \c time_last_collision is time of the last collision
96  * \li \c p0, \c px, \c py, \c pz are components of particle 4-momentum
97  * \li \c t, \c x, \c y, \c z are components of particle 4-position
98  *
99  * Finally, each ROOT entry (output block) contains information about some of
100  * the bulk properties of the system:
101  * \li \c E_kinetic_tot is total kinetic energy in the system
102  * \li \c E_fields_tot is total mean field energy * test_p
103  * \li \c E_tot is the sum of E_kinetic_tot and E_fields_tot
104  *
105  * In case of extended output
106  * (see \ref input_output_content_specific_ "extended output") more fields are
107  * added. Their description is the same that in case of OSCAR format, see
108  * \ref extended_output_format_ "extended OSCAR format".
109  * \note In contrast to the OSCAR format, the ROOT output includes
110  * \c formation_time and \c time_last_collision in the standard (not extended)
111  * output.
112  *
113  * If "Collisions:" section is present in the config file, then in addition to a
114  * file Particles.root with particles TTree, another file Collisions.root is
115  * created. Collisions.root contains information about each collision, written
116  * as one leaf. Similarly to Particles.root, this includes global information
117  * about the event:
118  * \code
119  * ev ens
120  * \endcode
121  * and information about particles participating in a collision:
122  * \code
123  * id[npart] pdgcode[npart] charge[npart] formation_time[npart]
124  * time_last_collision[npart] p0[npart] px[npart] py[npart] pz[npart] t[npart]
125  * x[npart] y[npart] z[npart]
126  * \endcode
127  * where all arrays are now of dimension nin+nout = npart.
128  * Beyond these, Collisions.root contains a few additional fields:
129  * \li \c nin is the number of incoming particles in the reaction,
130  * \li \c nout is the number of outgoing particles in the reaction,
131  * \li \c wgt is an action weight, whose meaning depends on the type of action:
132  * for collisions it is the total cross section, for decays it is the total
133  * decay width, and for dilepton decays it is the shining weight,
134  * \li \c par_wgt is partial weight of the collision.
135  *
136  * Currently writing initial and final configurations to collisions tree is not
137  * supported.
138  *
139  * See also \ref doxypage_output_collisions_box_modus.
140  *
141  * Here is an example of a basic ROOT macro to read the ROOT output of SMASH:
142  * \code
143  * // file name: basic_macro.C
144  *
145  * #include <TFile.h>
146  * #include <TTree.h>
147  *
148  * int rootfile_basic_example() {
149  * // open SMASH output file to be read in
150  * TFile *input_file = TFile::Open("../build/data/0/Particles.root");
151  * if (input_file->IsOpen()) {
152  * printf("Successfully opened file %s\n", input_file->GetName());
153  * } else {
154  * printf("Error at opening file %s\n", input_file->GetName());
155  * }
156  *
157  * // Get a tree from file
158  * TTree *tree = static_cast<TTree*>(input_file->Get("particles"));
159  *
160  * // Get number of entries in a tree
161  * Int_t nentries = tree->GetEntries();
162  * printf("Number of entries in a tree is %d\n", nentries);
163  *
164  * // This draws p_T distribution at initialization
165  * // tree->Draw("sqrt(px*px + py*py)","tcounter==0");
166  *
167  * // This draws 3D momentum space distribution at initialization
168  * tree->Draw("px:py:pz","tcounter==0");
169  *
170  * return 0;
171  * }
172  * \endcode
173  * To execute this macro:
174  * \code
175  * root -l
176  * .L basic_macro.C+
177  * rootfile_basic_example()
178  * \endcode
179  *
180  * To generate a ROOT macro for a more involved analysis:
181  * \code
182  * root -l Particles.root
183  * particles->MakeClass("analysis")
184  * \endcode
185  * This creates analysis.h and analysis.C, the latter of which provides an
186  * example of a basic loop over entries. The user can modify the Loop() function
187  * and build a more complicated analysis. The following is an example of a macro
188  * using an array of histograms to obtain the radial momentum distribution for
189  * each of the entries in the Particles.root:
190  * \code
191  * #define analysis_cxx
192  * #include "analysis.h"
193  * #include <TH2.h>
194  * #include <TStyle.h>
195  * #include <TCanvas.h>
196  * #include <iostream>
197  *
198  * void analysis::Loop()
199  * {
200  * if (fChain == 0) return;
201  * Long64_t n_entries = fChain->GetEntriesFast();
202  *
203  * // an array of histograms
204  * TH1D *h_p_avg[n_entries];
205  * // Each histogram needs to be declared with a unique name and title
206  * for (int i = 0; i < n_entries; i++){
207  * char h_p_avg_name[256];
208  * char h_p_avg_title[256];
209  *
210  * sprintf(h_p_avg_name, "h_p_avg_entry_%d", i);
211  * sprintf(h_p_avg_title, "momentum distribution at entry %d", i);
212  * h_p_avg[i] = new TH1D(h_p_avg_name, h_p_avg_title, 50, 0, 1.0);
213  * h_p_avg[i]->Sumw2();
214  * h_p_avg[i]->SetStats(1);
215  * }
216  *
217  * Long64_t nb = 0;
218  * // A loop over all entries
219  * for (Long64_t j_entry = 0; j_entry < n_entries; j_entry++){
220  * //Load the TTree data for that entry
221  * Long64_t i_entry = LoadTree(j_entry);
222  * if (i_entry < 0){
223  * std::cout << "Failed to load the TTree at j_entry = "
224  * << j_entry << std::endl;
225  * break;
226  * }
227  * nb = fChain->GetEntry(j_entry);
228  *
229  * // A loop over all particles in the entry
230  * for (int i = 0; i < npart; i++) {
231  * const double p = sqrt( px[i] * px[i] + py[i] * py[i] + pz[i] * pz[i]
232  * );
233  * // filling the j_entry-th histogram
234  * h_p_avg[j_entry]->Fill(p, 1.0/(p*p));
235  * }
236  * }
237  *
238  * // drawing the histogram corresponding to the j_entry = 0 entry
239  * h_p_avg[0]->Draw();
240  * }
241  * /endcode
242  * To run this analysis:
243  * \code
244  * root -l
245  * .L analysis.C+
246  * analysis t
247  * t.Loop()
248  * \endcode
249  *
250  * To quickly view a ROOT file from the command line:
251  * \code
252  * root -l Particles.root // attaches the .root file
253  * .ls // lists objects contained in the .root file; here: particles
254  * particles->Draw("p0", "tcounter == 0")
255  * \endcode
256  *
257  * Viewing a ROOT file can be also done in a TBrowser:
258  * \code
259  * root -l
260  * new TBrowser
261  * \endcode
262  *
263  * For more examples of extracting info from .root file see root.cern.ch
264  *
265  */
266 RootOutput::RootOutput(const std::filesystem::path &path,
267  const std::string &name, const OutputParameters &out_par)
268  : OutputInterface(name),
269  filename_(path / (name + ".root")),
270  write_collisions_(name == "Collisions" || name == "Dileptons" ||
271  name == "Photons"),
272  write_particles_(name == "Particles"),
273  write_initial_conditions_(name == "SMASH_IC"),
274  particles_only_final_(out_par.part_only_final),
275  part_extended_(out_par.part_extended),
276  coll_extended_(out_par.coll_extended),
277  ic_extended_(out_par.ic_extended) {
279  filename_unfinished_ += ".unfinished";
281  std::make_unique<TFile>(filename_unfinished_.native().c_str(), "NEW");
282  init_trees();
283 }
284 
287  particles_tree_ = new TTree("particles", "particles");
288 
289  particles_tree_->Branch("ev", &ev_, "ev/I");
290  particles_tree_->Branch("ens", &ens_, "ens/I");
291  particles_tree_->Branch("tcounter", &tcounter_, "tcounter/I");
292  particles_tree_->Branch("npart", &npart_, "npart/I");
293  particles_tree_->Branch("test_p", &test_p_, "test_p/I");
294  particles_tree_->Branch("modus_l", &modus_l_, "modus_l/D");
295  particles_tree_->Branch("current_t", &current_t_, "current_t/D");
296  particles_tree_->Branch("impact_b", &impact_b_, "impact_b/D");
297  particles_tree_->Branch("empty_event", &empty_event_, "empty_event/O");
298 
299  particles_tree_->Branch("id", &id_[0], "id[npart]/I");
300  particles_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
301  particles_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
302  particles_tree_->Branch("formation_time", &formation_time_[0],
303  "formation_time[npart]/D");
304  particles_tree_->Branch("time_last_collision", &time_last_collision_[0],
305  "time_last_collision[npart]/D");
306 
307  particles_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
308  particles_tree_->Branch("px", &px_[0], "px[npart]/D");
309  particles_tree_->Branch("py", &py_[0], "py[npart]/D");
310  particles_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
311 
312  particles_tree_->Branch("t", &t_[0], "t[npart]/D");
313  particles_tree_->Branch("x", &x_[0], "x[npart]/D");
314  particles_tree_->Branch("y", &y_[0], "y[npart]/D");
315  particles_tree_->Branch("z", &z_[0], "z[npart]/D");
316 
317  particles_tree_->Branch("E_kinetic_tot", &E_kinetic_tot_,
318  "E_kinetic_tot/D");
319  particles_tree_->Branch("E_fields_tot", &E_fields_tot_, "E_fields_tot/D");
320  particles_tree_->Branch("E_tot", &E_tot_, "E_tot/D");
321 
322  if (part_extended_ || ic_extended_) {
323  particles_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
324  particles_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
325  particles_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
326  "proc_id_origin[npart]/I");
327  particles_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
328  "proc_type_origin[npart]/I");
329  particles_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
330  "pdg_mother1[npart]/I");
331  particles_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
332  "pdg_mother2[npart]/I");
333  particles_tree_->Branch("baryon_number", &baryon_number_[0],
334  "baryon_number[npart]/I");
335  particles_tree_->Branch("strangeness", &strangeness_[0],
336  "strangeness[npart]/I");
337  }
338  }
339 
340  if (write_collisions_) {
341  collisions_tree_ = new TTree("collisions", "collisions");
342 
343  collisions_tree_->Branch("ev", &ev_, "ev/I");
344  collisions_tree_->Branch("ens", &ens_, "ens/I");
345 
346  collisions_tree_->Branch("nin", &nin_, "nin/I");
347  collisions_tree_->Branch("nout", &nout_, "nout/I");
348  collisions_tree_->Branch("npart", &npart_, "npart/I");
349  collisions_tree_->Branch("weight", &wgt_, "weight/D");
350  collisions_tree_->Branch("partial_weight", &par_wgt_, "partial_weight/D");
351 
352  collisions_tree_->Branch("id", &id_[0], "id[npart]/I");
353  collisions_tree_->Branch("pdgcode", &pdgcode_[0], "pdgcode[npart]/I");
354  collisions_tree_->Branch("charge", &charge_[0], "charge[npart]/I");
355  collisions_tree_->Branch("formation_time", &formation_time_[0],
356  "formation_time[npart]/D");
357  collisions_tree_->Branch("time_last_collision", &time_last_collision_[0],
358  "time_last_collision[npart]/D");
359 
360  collisions_tree_->Branch("p0", &p0_[0], "p0[npart]/D");
361  collisions_tree_->Branch("px", &px_[0], "px[npart]/D");
362  collisions_tree_->Branch("py", &py_[0], "py[npart]/D");
363  collisions_tree_->Branch("pz", &pz_[0], "pz[npart]/D");
364 
365  collisions_tree_->Branch("t", &t_[0], "t[npart]/D");
366  collisions_tree_->Branch("x", &x_[0], "x[npart]/D");
367  collisions_tree_->Branch("y", &y_[0], "y[npart]/D");
368  collisions_tree_->Branch("z", &z_[0], "z[npart]/D");
369 
370  if (coll_extended_) {
371  collisions_tree_->Branch("ncoll", &coll_per_part_[0], "ncoll[npart]/I");
372  collisions_tree_->Branch("xsecfac", &xsec_factor_[0], "xsecfac[npart]/D");
373  collisions_tree_->Branch("proc_id_origin", &proc_id_origin_[0],
374  "proc_id_origin[npart]/I");
375  collisions_tree_->Branch("proc_type_origin", &proc_type_origin_[0],
376  "proc_type_origin[npart]/I");
377  collisions_tree_->Branch("pdg_mother1", &pdg_mother1_[0],
378  "pdg_mother1[npart]/I");
379  collisions_tree_->Branch("pdg_mother2", &pdg_mother2_[0],
380  "pdg_mother2[npart]/I");
381  collisions_tree_->Branch("baryon_number", &baryon_number_[0],
382  "baryon_number[npart]/I");
383  collisions_tree_->Branch("strangeness", &strangeness_[0],
384  "strangeness[npart]/I");
385  }
386  }
387 }
388 
389 /**
390  * RootOutput destructor. Writes root objects (here TTrees) to file and closes
391  * it.
392  */
394  // kOverwrite option prevents from writing extra TKey objects into root file
395  root_out_file_->Write("", TObject::kOverwrite);
396  root_out_file_->Close();
397  std::filesystem::rename(filename_unfinished_, filename_);
398 }
399 
400 void RootOutput::at_eventstart(const Particles &particles,
401  const EventLabel &event_label,
402  const EventInfo &event) {
403  // save event and ensemble numbers
404  current_event_ = event_label.event_number;
405  current_ensemble_ = event_label.ensemble_number;
406 
407  modus_l_ = event.modus_length;
408  test_p_ = event.test_particles;
409  current_t_ = event.current_time;
410  E_kinetic_tot_ = event.total_kinetic_energy;
411  E_fields_tot_ = event.total_mean_field_energy;
412  E_tot_ = event.total_energy;
413 
415  output_counter_ = 0;
416  // This is to have only one output of positive impact parameter per event
417  impact_b_ = -1.0;
418  empty_event_ = false;
419  particles_to_tree(particles);
420  output_counter_++;
421  }
422 }
423 
425  const std::unique_ptr<Clock> &,
426  const DensityParameters &,
427  const EventLabel &event_label,
428  const EventInfo &event) {
429  current_ensemble_ = event_label.ensemble_number;
430  modus_l_ = event.modus_length;
431  test_p_ = event.test_particles;
432  current_t_ = event.current_time;
433  E_kinetic_tot_ = event.total_kinetic_energy;
434  E_fields_tot_ = event.total_mean_field_energy;
435  E_tot_ = event.total_energy;
436 
438  particles_to_tree(particles);
439  output_counter_++;
440  }
441 }
442 
443 void RootOutput::at_eventend(const Particles &particles,
444  const EventLabel &event_label,
445  const EventInfo &event) {
446  current_ensemble_ = event_label.ensemble_number;
447  test_p_ = event.test_particles;
448  modus_l_ = event.modus_length;
449  current_t_ = event.current_time;
450  impact_b_ = event.impact_parameter;
451  empty_event_ = event.empty_event;
452 
453  E_kinetic_tot_ = event.total_kinetic_energy;
454  E_fields_tot_ = event.total_mean_field_energy;
455  E_tot_ = event.total_energy;
456 
457  if (write_particles_ &&
458  !(event.empty_event &&
460  particles_to_tree(particles);
461  }
462  /* Calculate the autosave frequency to be used. In case multiple ensembles are
463  * used this has to be at least 1, so set it to 1 if the number of ensembles
464  * is larger than the initial value of the autosave frequency. The evaluation
465  * of the actual frequency to be used has to be done only once, i.e. when the
466  * autosave_frequency_ has still its meaningless initial negative value. */
467  if (autosave_frequency_ < 0) {
468  autosave_frequency_ = 1000 / event.n_ensembles;
469  if (autosave_frequency_ == 0) {
471  }
472  }
473  /* Forced regular dump from operational memory to disk. Very demanding!
474  * If program crashes written data will NOT be lost. */
477  particles_tree_->AutoSave("SaveSelf");
478  }
479  if (write_collisions_) {
480  collisions_tree_->AutoSave("SaveSelf");
481  }
482  }
483 }
484 
486  const double /*density*/) {
487  if (write_collisions_) {
489  action.get_total_weight(), action.get_partial_weight());
490  }
491 
493  (action.get_type() == ProcessType::Fluidization ||
496  }
497 }
498 
499 template <typename T>
500 void RootOutput::particles_to_tree(T &particles) {
501  int i = 0;
502 
506  bool exceeded_buffer_message = true;
507 
508  for (const auto &p : particles) {
509  // Buffer full - flush to tree, else fill with particles
510  if (i >= max_buffer_size_) {
511  if (exceeded_buffer_message) {
512  logg[LOutput].warn()
513  << "\nThe number of particles N = " << particles.size()
514  << " exceeds the maximum buffer size B = " << max_buffer_size_
515  << ".\nceil(N/B) = "
516  << std::ceil(particles.size() /
517  static_cast<double>(max_buffer_size_))
518  << " separate ROOT Tree entries will be created at this output."
519  << "\nMaximum buffer size (max_buffer_size_) can be changed in "
520  << "rootoutput.h\n\n";
521  exceeded_buffer_message = false;
522  }
524  i = 0;
525  particles_tree_->Fill();
526  } else {
527  id_[i] = p.id();
528  pdgcode_[i] = p.pdgcode().get_decimal();
529  charge_[i] = p.type().charge();
530  formation_time_[i] = p.formation_time();
531  time_last_collision_[i] = p.get_history().time_last_collision;
532 
533  p0_[i] = p.momentum().x0();
534  px_[i] = p.momentum().x1();
535  py_[i] = p.momentum().x2();
536  pz_[i] = p.momentum().x3();
537 
538  t_[i] = p.position().x0();
539  x_[i] = p.position().x1();
540  y_[i] = p.position().x2();
541  z_[i] = p.position().x3();
542 
543  if (part_extended_ || ic_extended_) {
544  const auto h = p.get_history();
545  coll_per_part_[i] = h.collisions_per_particle;
546  xsec_factor_[i] = p.xsec_scaling_factor();
547  proc_id_origin_[i] = h.id_process;
548  proc_type_origin_[i] = static_cast<int>(h.process_type);
549  pdg_mother1_[i] = h.p1.get_decimal();
550  pdg_mother2_[i] = h.p2.get_decimal();
551  baryon_number_[i] = p.type().baryon_number();
552  strangeness_[i] = p.type().strangeness();
553  }
554 
555  i++;
556  }
557  }
558  // Flush rest to tree
559  if (i > 0) {
560  npart_ = i;
561  particles_tree_->Fill();
562  }
563 }
564 
565 void RootOutput::collisions_to_tree(const ParticleList &incoming,
566  const ParticleList &outgoing,
567  const double weight,
568  const double partial_weight) {
571  nin_ = incoming.size();
572  nout_ = outgoing.size();
573  npart_ = nin_ + nout_;
574  wgt_ = weight;
575  par_wgt_ = partial_weight;
576 
577  int i = 0;
578 
579  /* It is assumed that nin + nout < max_buffer_size_
580  * This is true for any possible reaction for current buffer size
581  * But if one wants initial/final particles written to collisions
582  * then implementation should be updated. */
583 
584  for (const ParticleList &plist : {incoming, outgoing}) {
585  for (const auto &p : plist) {
586  id_[i] = p.id();
587  pdgcode_[i] = p.pdgcode().get_decimal();
588  charge_[i] = p.type().charge();
589  formation_time_[i] = p.formation_time();
590  time_last_collision_[i] = p.get_history().time_last_collision;
591 
592  p0_[i] = p.momentum().x0();
593  px_[i] = p.momentum().x1();
594  py_[i] = p.momentum().x2();
595  pz_[i] = p.momentum().x3();
596 
597  t_[i] = p.position().x0();
598  x_[i] = p.position().x1();
599  y_[i] = p.position().x2();
600  z_[i] = p.position().x3();
601 
602  if (coll_extended_) {
603  const auto h = p.get_history();
604  coll_per_part_[i] = h.collisions_per_particle;
605  xsec_factor_[i] = p.xsec_scaling_factor();
606  proc_id_origin_[i] = h.id_process;
607  proc_type_origin_[i] = static_cast<int>(h.process_type);
608  pdg_mother1_[i] = h.p1.get_decimal();
609  pdg_mother2_[i] = h.p2.get_decimal();
610  baryon_number_[i] = p.type().baryon_number();
611  strangeness_[i] = p.type().strangeness();
612  }
613 
614  i++;
615  }
616  }
617 
618  collisions_tree_->Fill();
619 }
620 } // 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:61
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:247
A class to pre-calculate and store parameters relevant for density calculation.
Definition: density.h:92
Abstraction of generic output.
The Particles class abstracts the storage and manipulation of particles.
Definition: particles.h:33
void at_interaction(const Action &action, const double density) override
Writes collisions to a tree defined by treename.
Definition: rootoutput.cc:485
std::vector< double > t_
Property that is written to ROOT output.
Definition: rootoutput.h:176
std::vector< double > y_
Property that is written to ROOT output.
Definition: rootoutput.h:178
void at_intermediate_time(const Particles &particles, const std::unique_ptr< Clock > &clock, const DensityParameters &dens_param, const EventLabel &event_label, const EventInfo &event) override
Writes intermediate particles to a tree defined by treename, if it is allowed (i.e....
Definition: rootoutput.cc:424
double current_t_
Property that is written to ROOT output.
Definition: rootoutput.h:162
OutputOnlyFinal particles_only_final_
Print only final particles in the event (no intermediate output).
Definition: rootoutput.h:207
int current_event_
Number of current event.
Definition: rootoutput.h:139
TTree * collisions_tree_
TTree for collision output.
Definition: rootoutput.h:119
~RootOutput()
Destructor.
Definition: rootoutput.cc:393
double E_kinetic_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:180
int test_p_
Property that is written to ROOT output.
Definition: rootoutput.h:160
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:565
void at_eventstart(const Particles &particles, const EventLabel &event_label, const EventInfo &event) override
update event number and writes intermediate particles to a tree.
Definition: rootoutput.cc:400
int autosave_frequency_
ROOT file cannot be read if it was not properly closed and finalized.
Definition: rootoutput.h:221
std::vector< int > proc_type_origin_
Property that is written to ROOT output.
Definition: rootoutput.h:186
double modus_l_
Property that is written to ROOT output.
Definition: rootoutput.h:161
std::vector< int > coll_per_part_
Property that is written to ROOT output.
Definition: rootoutput.h:183
int tcounter_
Property that is written to ROOT output.
Definition: rootoutput.h:158
std::vector< int > baryon_number_
Property that is written to ROOT output.
Definition: rootoutput.h:189
int npart_
Property that is written to ROOT output.
Definition: rootoutput.h:159
std::vector< int > pdg_mother1_
Property that is written to ROOT output.
Definition: rootoutput.h:187
int nin_
Property that is written to ROOT output.
Definition: rootoutput.h:191
int ev_
Property that is written to ROOT output.
Definition: rootoutput.h:156
bool write_collisions_
Option to write collisions tree.
Definition: rootoutput.h:198
std::vector< int > charge_
Property that is written to ROOT output.
Definition: rootoutput.h:167
std::vector< double > px_
Property that is written to ROOT output.
Definition: rootoutput.h:173
const std::filesystem::path filename_
Filename of output.
Definition: rootoutput.h:101
std::vector< int > strangeness_
Property that is written to ROOT output.
Definition: rootoutput.h:190
bool write_initial_conditions_
Option to write particles tree for initial conditions.
Definition: rootoutput.h:204
double wgt_
Property that is written to ROOT output.
Definition: rootoutput.h:193
std::vector< double > py_
Property that is written to ROOT output.
Definition: rootoutput.h:174
std::vector< int > proc_id_origin_
Property that is written to ROOT output.
Definition: rootoutput.h:185
void particles_to_tree(T &particles)
Writes particles to a tree defined by treename.
Definition: rootoutput.cc:500
const bool part_extended_
Whether extended particle output is on.
Definition: rootoutput.h:224
double impact_b_
Property that is written to ROOT output.
Definition: rootoutput.h:163
RootOutput(const std::filesystem::path &path, const std::string &name, const OutputParameters &out_par)
Construct ROOT output.
Definition: rootoutput.cc:266
std::vector< double > z_
Property that is written to ROOT output.
Definition: rootoutput.h:179
std::vector< int > id_
Property that is written to ROOT output.
Definition: rootoutput.h:165
std::vector< double > formation_time_
Property that is written to ROOT output.
Definition: rootoutput.h:168
int current_ensemble_
Number of current ensemble.
Definition: rootoutput.h:141
void at_eventend(const Particles &particles, const EventLabel &event_label, const EventInfo &event) override
update event number and impact parameter, and writes intermediate particles to a tree.
Definition: rootoutput.cc:443
std::vector< double > x_
Property that is written to ROOT output.
Definition: rootoutput.h:177
std::vector< double > p0_
Property that is written to ROOT output.
Definition: rootoutput.h:172
bool empty_event_
Property that is written to ROOT output.
Definition: rootoutput.h:164
static const int max_buffer_size_
Maximal buffer size.
Definition: rootoutput.h:149
std::unique_ptr< TFile > root_out_file_
Pointer to root output file.
Definition: rootoutput.h:105
std::vector< double > xsec_factor_
Property that is written to ROOT output.
Definition: rootoutput.h:184
double E_fields_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:181
std::filesystem::path filename_unfinished_
Filename of output as long as simulation is still running.
Definition: rootoutput.h:103
const bool coll_extended_
Whether extended collisions output is on.
Definition: rootoutput.h:226
std::vector< double > time_last_collision_
Property that is written to ROOT output.
Definition: rootoutput.h:170
double par_wgt_
Property that is written to ROOT output.
Definition: rootoutput.h:194
void init_trees()
Basic initialization routine, creating the TTree objects for particles and collisions.
Definition: rootoutput.cc:285
int output_counter_
Number of output in a given event.
Definition: rootoutput.h:137
double E_tot_
Property that is written to ROOT output.
Definition: rootoutput.h:182
TTree * particles_tree_
TTree for particles output.
Definition: rootoutput.h:112
int ens_
Property that is written to ROOT output.
Definition: rootoutput.h:157
std::vector< double > pz_
Property that is written to ROOT output.
Definition: rootoutput.h:175
int nout_
Property that is written to ROOT output.
Definition: rootoutput.h:192
const bool ic_extended_
Whether extended ic output is on.
Definition: rootoutput.h:228
bool write_particles_
Option to write particles tree.
Definition: rootoutput.h:201
std::vector< int > pdgcode_
Property that is written to ROOT output.
Definition: rootoutput.h:166
std::vector< int > pdg_mother2_
Property that is written to ROOT output.
Definition: rootoutput.h:188
@ 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.h:245
constexpr int p
Proton.
Definition: action.h:24
@ FluidizationNoRemoval
See here for a short description.
@ Fluidization
See here for a short description.
static constexpr int LOutput
Structure to contain custom data for output.
bool empty_event
True if no collisions happened.
Structure to contain information about the event and ensemble numbers.
int32_t ensemble_number
The number of the ensemble.
int32_t event_number
The number of the event.
Helper structure for Experiment to hold output options and parameters.