DD4hep  1.37.0
Detector Description Toolkit for High Energy Physics
Geant4Output2ROOT.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #include <DD4hep/Printout.h>
16 #include <DD4hep/InstanceCount.h>
18 #include <DDG4/Geant4Output2ROOT.h>
19 #include <DDG4/Geant4Kernel.h>
20 #include <DDG4/Geant4Particle.h>
21 #include <DDG4/Geant4Data.h>
22 
23 // Geant4 include files
24 #include <G4Event.hh>
25 #include <G4HCofThisEvent.hh>
26 #include <G4ParticleTable.hh>
27 #include <G4Run.hh>
28 
29 // ROOT include files
30 #include <TFile.h>
31 #include <TTree.h>
32 #include <TBranch.h>
33 #include <TSystem.h>
34 
35 using namespace dd4hep::sim;
36 
39 
42  : Geant4OutputAction(ctxt, nam) {
43  declareProperty("Section", m_section = "EVENT");
44  declareProperty("HandleMCTruth", m_handleMCTruth);
45  declareProperty("DisabledCollections", m_disabledCollections);
46  declareProperty("DisableParticles", m_disableParticles);
47  declareProperty("FilesByRun", m_filesByRun);
49 }
50 
53  closeOutput();
55 }
56 
59 void Geant4Output2ROOT::endRun(const G4Run* run) {
60  const int nThreads = context()->kernel().master().numThreads();
61  // ST: nThreads==0, close immediately
62  // MT: wait until every worker has called endRun before closing
63  int done = ++m_endRunCount;
64  if (nThreads == 0 || done >= nThreads) {
65  closeOutput();
66  }
68 }
69 
72  if (!m_file) return;
73  TDirectory::TContext ctxt(m_file.get());
74  info("+++ Closing ROOT output file %s", m_file->GetName());
75  m_branches.clear();
76  for (const auto& [name, tree] : m_sections) {
77  if (tree != m_tree) tree->Write();
78  }
79  m_sections.clear();
80  m_tree->Write();
81  m_file->Close();
82  m_tree = nullptr;
83  m_file.reset();
84 }
85 
88  std::lock_guard<std::mutex> lock(s_rootMutex);
90 }
91 
93 TTree* Geant4Output2ROOT::section(const std::string& nam) {
94  auto i = m_sections.find(nam);
95  if (i == m_sections.end()) {
96  TDirectory::TContext ctxt(m_file.get());
97  TTree* t = new TTree(nam.c_str(), ("Geant4 " + nam + " information").c_str());
98  m_sections.emplace(nam, t);
99  return t;
100  }
101  return i->second;
102 }
103 
105 void Geant4Output2ROOT::beginRun(const G4Run* run) {
106  std::unique_lock<std::mutex> lock(s_rootMutex);
107  // Reset per-run counter here, before any events, so a new run never sees
108  // stale counts from the previous run.
109  m_endRunCount = 0;
110  std::string fname = m_output;
111  if ( m_filesByRun ) {
112  size_t idx = m_output.rfind(".");
113  if ( m_file ) {
115  }
116  fname = m_output.substr(0, idx);
117  fname += _toString(run->GetRunID(), ".run%08d");
118  if ( idx != std::string::npos )
119  fname += m_output.substr(idx);
120  }
121  if ( !m_file && !fname.empty() ) {
122  TDirectory::TContext ctxt(TDirectory::CurrentDirectory());
123  if ( !gSystem->AccessPathName(fname.c_str()) ) {
124  gSystem->Unlink(fname.c_str());
125  }
126  std::unique_ptr<TFile> file(TFile::Open(fname.c_str(), "RECREATE", "dd4hep Simulation data"));
127  if ( !file ) {
128  file.reset(TFile::Open((fname+".1").c_str(), "RECREATE", "dd4hep Simulation data"));
129  }
130  if ( !file ) {
131  except("Failed to create ROOT output file:'%s'", fname.c_str());
132  }
133  if (file->IsZombie()) {
134  except("Failed to open ROOT output file:'%s'", fname.c_str());
135  }
136  m_file = std::move(file);
138  }
140 }
141 
143 int Geant4Output2ROOT::fill(const std::string& nam, const ComponentCast& type, void* ptr) {
144  std::lock_guard<std::mutex> lock(s_rootMutex);
145  if (!m_file) return 0;
146  TBranch* b = nullptr;
147  auto i = m_branches.find(nam);
148  if (i == m_branches.end()) {
149  const std::type_info& typ = type.type();
150  if (auto* cl = TBuffer::GetClass(typ)) {
151  b = m_tree->Branch(nam.c_str(), cl->GetName(), static_cast<void*>(nullptr));
152  b->SetAutoDelete(false);
153  m_branches.emplace(nam, b);
154  }
155  else {
156  throw std::runtime_error("No ROOT TClass object available for object type:" + typeName(typ));
157  }
158  }
159  else {
160  b = i->second;
161  }
162  const Long64_t evt = b->GetEntries();
163  const Long64_t nevt = b->GetTree()->GetEntries();
164  if (nevt > evt) {
165  b->SetAddress(nullptr);
166  for (Long64_t num = nevt - evt; num > 0; --num)
167  b->Fill();
168  }
169  b->SetAddress(&ptr);
170  const int nbytes = b->Fill();
171  if (nbytes < 0) {
172  throw std::runtime_error("Failed to write ROOT collection:" + nam + "!");
173  }
174  return nbytes;
175 }
176 
179  std::lock_guard<std::mutex> lock(s_rootMutex);
180  if (m_file) {
181  Int_t evtid = ctxt.context->GetEventID();
182  TTree* id_tree = section("G4EventIDs");
183  TBranch* br = id_tree->GetBranch("G4EventID");
184  if (!br) {
185  br = id_tree->Branch("G4EventID", &evtid, "G4EventID/I");
186  }
187  else {
188  br->SetAddress(&evtid);
189  }
190  id_tree->Fill();
191 
192  auto* a = m_tree->GetListOfBranches();
193  const Long64_t evt = m_tree->GetEntries() + 1;
194  const Int_t nb = a->GetEntriesFast();
196  for (Int_t i = 0; i < nb; ++i) {
197  auto* br_ptr = static_cast<TBranch*>(a->UncheckedAt(i));
198  const Long64_t br_evt = br_ptr->GetEntries();
199  if (br_evt < evt) {
200  br_ptr->SetAddress(nullptr);
201  for (Long64_t num = evt - br_evt; num > 0; --num)
202  br_ptr->Fill();
203  }
204  }
205  m_tree->SetEntries(evt);
206  }
208 }
209 
212  if (m_disableParticles) return;
213  auto* parts = context()->event().extension<Geant4ParticleMap>();
214  if (!parts) return;
215  Geant4HitWrapper::HitManipulator* manipulator = Geant4HitWrapper::manipulator<Geant4Particle>();
216  G4ParticleTable* table = G4ParticleTable::GetParticleTable();
217  const Geant4ParticleMap::ParticleMap pm = parts->particles();
218  std::vector<void*> particles;
219  particles.reserve(pm.size());
220  for ( const auto& i : pm ) {
221  auto* p = i.second;
222  G4ParticleDefinition* def = table->FindParticle(p->pdgID);
223  p->charge = static_cast<char>(3.0 * (def ? def->GetPDGCharge() : -1.0)); // Assume e-/pi-
224  particles.emplace_back(p);
225  }
226  fill("MCParticles",manipulator->vec_type,&particles);
227 }
228 
231  auto* coll = dynamic_cast<Geant4HitCollection*>(collection);
232  if (!coll) return;
233  const std::string hc_nam = collection->GetName();
234  for(const auto& n : m_disabledCollections) {
235  if ( n == hc_nam ) {
236  return;
237  }
238  }
239  const size_t nhits = coll->GetSize();
240  std::vector<void*> hits;
241  hits.reserve(nhits);
242  coll->getHitsUnchecked(hits);
243  if ( m_handleMCTruth && m_truth && nhits > 0 ) {
244  try {
245  for(size_t i=0; i<nhits; ++i) {
246  Geant4HitData* h = coll->hit(i);
247  if (auto* trk_hit = dynamic_cast<Geant4Tracker::Hit*>(h)) {
248  Geant4HitData::Contribution& t = trk_hit->truth;
250  }
251  if (auto* cal_hit = dynamic_cast<Geant4Calorimeter::Hit*>(h)) {
252  for(auto& t : cal_hit->truth)
253  t.trackID = m_truth->particleID(t.trackID);
254  }
255  }
256  }
257  catch(...) {
258  error("+++ Exception while saving collection %s.",hc_nam.c_str());
259  }
260  }
261  fill(hc_nam, coll->vector_type(), &hits);
262 }
dd4hep::sim::Geant4OutputAction::endRun
virtual void endRun(const G4Run *run)
Callback to store the Geant4 run information.
Definition: Geant4OutputAction.cpp:112
Geant4HitCollection.h
dd4hep::sim::Geant4Output2ROOT::closeOutputLocked
void closeOutputLocked()
Close the current output file. Must be called with s_rootMutex held.
Definition: Geant4Output2ROOT.cpp:71
dd4hep::sim::Geant4Output2ROOT::saveEvent
void saveEvent(OutputContext< G4Event > &ctxt) override
Callback to store the Geant4 event.
Definition: Geant4Output2ROOT.cpp:211
dd4hep::sim::Geant4Output2ROOT::s_rootMutex
static std::mutex s_rootMutex
Static mutex to protect ROOT I/O operations in multi-threaded mode.
Definition: Geant4Output2ROOT.h:66
dd4hep::sim::Geant4HitCollection
Generic hit container class using Geant4HitWrapper objects.
Definition: Geant4HitCollection.h:201
dd4hep::_toString
std::string _toString(bool value)
String conversions: boolean value to string.
Definition: Handle.cpp:332
G4VHitsCollection
Class of the Geant4 toolkit. See http://www-geant4.kek.jp/Reference.
Definition: Geant4Classes.h:47
dd4hep::sim::Geant4OutputAction
Base class to output Geant4 event data to persistent media.
Definition: Geant4OutputAction.h:40
dd4hep::InstanceCount::increment
static void increment(T *)
Increment count according to type information.
Definition: InstanceCount.h:98
Geant4Data.h
dd4hep::sim::Geant4Context::event
Geant4Event & event() const
Access the geant4 event – valid only between BeginEvent() and EndEvent()!
Definition: Geant4Context.cpp:84
dd4hep::sim::Geant4Output2ROOT::m_handleMCTruth
bool m_handleMCTruth
Property: Flag if Monte-Carlo truth should be followed and checked.
Definition: Geant4Output2ROOT.h:60
dd4hep::sim::Geant4Output2ROOT::commit
void commit(OutputContext< G4Event > &ctxt) override
Commit data at end of filling procedure.
Definition: Geant4Output2ROOT.cpp:178
dd4hep::sim::Geant4OutputAction::OutputContext
Helper class for thread savety.
Definition: Geant4OutputAction.h:43
dd4hep::sim::Geant4ParticleMap
Data structure to map particles produced during the generation and the simulation.
Definition: Geant4Particle.h:339
dd4hep::sim::Geant4Action::info
void info(const char *fmt,...) const
Support of info messages.
Definition: Geant4Action.cpp:215
dd4hep::sim::Geant4Event::extension
T * extension(bool alert=true)
Access to type safe extension object. Exception is thrown if the object is invalid.
Definition: Geant4Context.h:151
dd4hep::sim::Geant4Output2ROOT::Geant4Output2ROOT
Geant4Output2ROOT(Geant4Context *context, const std::string &nam)
Standard constructor.
Definition: Geant4Output2ROOT.cpp:41
dd4hep::sim::Geant4Action::except
void except(const char *fmt,...) const
Support of exceptions: Print fatal message and throw runtime_error.
Definition: Geant4Action.cpp:256
dd4hep::sim::Geant4Output2ROOT::m_tree
TTree * m_tree
Reference to the event data tree (owned by m_file)
Definition: Geant4Output2ROOT.h:52
dd4hep::sim::Geant4Output2ROOT::m_endRunCount
std::atomic< int > m_endRunCount
Counter of worker endRun calls so that closeOutput fires only after all workers are done.
Definition: Geant4Output2ROOT.h:64
dd4hep::sim::Geant4Output2ROOT::fill
int fill(const std::string &nam, const ComponentCast &type, void *ptr)
Fill single EVENT branch entry (Geant4 collection data)
Definition: Geant4Output2ROOT.cpp:143
dd4hep::sim::Geant4OutputAction::commit
virtual void commit(OutputContext< G4Event > &ctxt)
Commit data at end of filling procedure.
Definition: Geant4OutputAction.cpp:104
dd4hep::sim::Geant4Action::error
void error(const char *fmt,...) const
Support of error messages.
Definition: Geant4Action.cpp:231
dd4hep::sim::Geant4Tracker::Hit
DDG4 tracker hit class used by the generic DDG4 tracker sensitive detector.
Definition: Geant4Data.h:263
dd4hep::sim::Geant4ParticleMap::ParticleMap
std::map< int, Particle * > ParticleMap
Definition: Geant4Particle.h:342
dd4hep::sim::Geant4HitData
Base class for geant4 hit structures used by the default DDG4 sensitive detector implementations.
Definition: Geant4Data.h:110
dd4hep::sim::Geant4OutputAction::m_truth
Geant4ParticleMap * m_truth
Reference to MC truth object.
Definition: Geant4OutputAction.h:60
dd4hep::sim::Geant4Action::declareProperty
Geant4Action & declareProperty(const std::string &nam, T &val)
Declare property.
Definition: Geant4Action.h:366
dd4hep::InstanceCount::decrement
static void decrement(T *)
Decrement count according to type information.
Definition: InstanceCount.h:102
dd4hep::sim::Geant4Kernel::numThreads
int numThreads() const
Definition: Geant4Kernel.h:162
dd4hep::sim::Geant4OutputAction::beginRun
virtual void beginRun(const G4Run *run)
Callback to initialize storing the Geant4 information.
Definition: Geant4OutputAction.cpp:108
dd4hep::sim::Geant4Output2ROOT::m_file
std::unique_ptr< TFile > m_file
Reference to the ROOT file to open.
Definition: Geant4Output2ROOT.h:50
dd4hep::sim::Geant4Output2ROOT::m_branches
Branches m_branches
Branches in the event tree.
Definition: Geant4Output2ROOT.h:48
dd4hep::sim::Geant4Action::name
const std::string & name() const
Access name of the action.
Definition: Geant4Action.h:280
dd4hep::sim::Geant4Calorimeter::Hit
DDG4 calorimeter hit class used by the generic DDG4 calorimeter sensitive detector.
Definition: Geant4Data.h:323
dd4hep::sim::Geant4Output2ROOT::section
TTree * section(const std::string &nam)
Create/access tree by name for non collection user data.
Definition: Geant4Output2ROOT.cpp:93
dd4hep::sim::Geant4ParticleMap::particleID
int particleID(int track, bool throw_if_not_found=true) const
Access the equivalent track id (shortcut to the usage of TrackEquivalents)
Definition: Geant4Particle.cpp:537
dd4hep::sim::Geant4HitData::MonteCarloContrib::trackID
int trackID
Geant 4 Track identifier.
Definition: Geant4Data.h:141
dd4hep::sim::Geant4HitWrapper::HitManipulator::vec_type
const ComponentCast & vec_type
Definition: Geant4HitCollection.h:73
dd4hep::sim::Geant4Output2ROOT::saveCollection
void saveCollection(OutputContext< G4Event > &ctxt, G4VHitsCollection *collection) override
Callback to store each Geant4 hit collection.
Definition: Geant4Output2ROOT.cpp:230
dd4hep::sim::Geant4Output2ROOT::m_sections
Sections m_sections
Known file sections.
Definition: Geant4Output2ROOT.h:46
dd4hep::sim::Geant4Output2ROOT::m_disabledCollections
std::vector< std::string > m_disabledCollections
Property: vector with disabled collections.
Definition: Geant4Output2ROOT.h:56
dd4hep::sim::Geant4OutputAction::m_output
std::string m_output
Property: "Output" output destination.
Definition: Geant4OutputAction.h:56
dd4hep::sim
Namespace for the Geant4 based simulation part of the AIDA detector description toolkit.
Definition: EDM4hepFileReader.cpp:46
dd4hep::sim::Geant4Output2ROOT::beginRun
void beginRun(const G4Run *run) override
Callback to store the Geant4 run information.
Definition: Geant4Output2ROOT.cpp:105
dd4hep::sim::Geant4Context::kernel
Geant4Kernel & kernel() const
Access to the kernel object.
Definition: Geant4Context.h:233
dd4hep::sim::Geant4Output2ROOT::m_section
std::string m_section
Property: name of the event tree.
Definition: Geant4Output2ROOT.h:54
dd4hep::sim::Geant4Output2ROOT::m_disableParticles
bool m_disableParticles
Property: vector with disabled collections.
Definition: Geant4Output2ROOT.h:58
dd4hep::sim::Geant4HitWrapper::HitManipulator
Generic type manipulation class for generic hit structures created in Geant4 sensitive detectors.
Definition: Geant4HitCollection.h:65
dd4hep::sim::Geant4OutputAction::OutputContext::context
const T * context
Definition: Geant4OutputAction.h:45
dd4hep::sim::Geant4Output2ROOT::m_filesByRun
bool m_filesByRun
Property: Flag to create a new output file for each run.
Definition: Geant4Output2ROOT.h:62
Geant4Particle.h
dd4hep::sim::Geant4HitData::MonteCarloContrib
Utility class describing the monte carlo contribution of a given particle to a hit.
Definition: Geant4Data.h:138
dd4hep::sim::Geant4Output2ROOT::closeOutput
virtual void closeOutput()
Close current output file.
Definition: Geant4Output2ROOT.cpp:87
Geant4Kernel.h
InstanceCount.h
dd4hep::sim::Geant4Output2ROOT::~Geant4Output2ROOT
~Geant4Output2ROOT() override
Default destructor.
Definition: Geant4Output2ROOT.cpp:52
dd4hep::sim::Geant4Kernel::master
Geant4Kernel & master() const
Thread's master context.
Definition: Geant4Kernel.h:158
dd4hep::sim::Geant4Output2ROOT::endRun
void endRun(const G4Run *run) override
Callback at end of run: write and close the output file while DDG4 is still alive.
Definition: Geant4Output2ROOT.cpp:59
Printout.h
Geant4Output2ROOT.h
dd4hep::sim::Geant4Context
Generic context to extend user, run and event information.
Definition: Geant4Context.h:201
dd4hep::sim::Geant4Action::context
Geant4Context * context() const
Access the context.
Definition: Geant4Action.h:270