DD4hep  1.37.0
Detector Description Toolkit for High Energy Physics
Geant4HepEmTrackingPhysics.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 //==========================================================================
11 
58 #ifndef DDG4_GEANT4HEPEMTRACKINGPHYSICS_H
59 #define DDG4_GEANT4HEPEMTRACKINGPHYSICS_H 1
60 
62 #include <DDG4/Geant4PhysicsList.h>
63 
65 #include <G4Electron.hh>
66 #include <G4EventManager.hh>
67 #include <G4Gamma.hh>
68 #include <G4Positron.hh>
69 #include <G4RegionStore.hh>
70 #include <G4TrackStatus.hh>
71 #include <G4VUserPhysicsList.hh>
72 
74 #include <G4HepEmConfig.hh>
75 #include <G4HepEmTrackingManager.hh>
76 
78 #include <memory>
79 #include <string>
80 #include <unordered_set>
81 #include <utility>
82 #include <vector>
83 
85 namespace dd4hep {
86 
88  namespace sim {
89 
90  namespace {
91 
93  class Geant4RegionSelectiveHepEmTrackingManager : public G4VTrackingManager {
94  public:
95  Geant4RegionSelectiveHepEmTrackingManager(bool trackInAllRegions,
96  std::unordered_set<G4int> hepEmRegionIDs,
97  G4int verbose)
98  : m_trackInAllRegions(trackInAllRegions)
99  , m_hepEmRegionIDs(std::move(hepEmRegionIDs))
100  , m_hepEmTrackingManager(new G4HepEmTrackingManager(verbose)) {}
101 
102  virtual ~Geant4RegionSelectiveHepEmTrackingManager() = default;
103 
104  G4HepEmConfig* GetConfig() { return m_hepEmTrackingManager->GetConfig(); }
105 
106  void BuildPhysicsTable(const G4ParticleDefinition& part) override {
107  m_hepEmTrackingManager->BuildPhysicsTable(part);
108  }
109 
110  void PreparePhysicsTable(const G4ParticleDefinition& part) override {
111  m_hepEmTrackingManager->PreparePhysicsTable(part);
112  }
113 
114  void FlushEvent() override {
115  m_hepEmTrackingManager->FlushEvent();
116  }
117 
118  void HandOverOneTrack(G4Track* aTrack) override {
119  if (useHepEm(aTrack)) {
120  m_hepEmTrackingManager->HandOverOneTrack(aTrack);
121  return;
122  }
123  trackWithGeant4(aTrack);
124  }
125 
126  private:
127  bool useHepEm(const G4Track* aTrack) const {
128  if (m_trackInAllRegions) {
129  return true;
130  }
131  const G4VPhysicalVolume* volume = aTrack->GetVolume();
132  if (volume == nullptr && aTrack->GetTouchableHandle()) {
133  volume = aTrack->GetTouchableHandle()->GetVolume();
134  }
135  if (volume == nullptr) {
136  return false;
137  }
138  const G4LogicalVolume* logical = volume->GetLogicalVolume();
139  if (logical == nullptr) {
140  return false;
141  }
142  const G4Region* region = logical->GetRegion();
143  if (region == nullptr) {
144  return false;
145  }
146  return m_hepEmRegionIDs.find(region->GetInstanceID()) != m_hepEmRegionIDs.end();
147  }
148 
149  void trackWithGeant4(G4Track* track) {
150  // We are inside a custom G4VTrackingManager::HandOverOneTrack() path here,
151  // but with track hand-off to Geant4 after all (since not in a HepEm region).
152  // In this path, G4EventManager does not execute its normal post-ProcessOneTrack()
153  // switch (see G4EventManager::DoProcessing, switch(istop) in the non-custom branch),
154  // so we must mirror that track-status/secondary/trajectory handling here.
155  auto* eventManager = G4EventManager::GetEventManager();
156  auto* trackManager = eventManager->GetTrackingManager();
157  auto* stackManager = eventManager->GetStackManager();
158 
159  trackManager->ProcessOneTrack(track);
160 
161  G4TrackStatus track_status = track->GetTrackStatus();
162  G4VTrajectory* trajectory =
163  trackManager->GetStoreTrajectory() == 0 ? nullptr : trackManager->GimmeTrajectory();
164  G4TrackVector* secondaries = trackManager->GimmeSecondaries();
165 
166  switch (track_status) {
167  case fStopButAlive:
168  case fSuspend:
169  case fSuspendAndWait:
170  stackManager->PushOneTrack(track, trajectory);
171  trajectory = nullptr;
172  eventManager->StackTracks(secondaries);
173  break;
174  case fPostponeToNextEvent:
175  stackManager->PushOneTrack(track);
176  eventManager->StackTracks(secondaries);
177  delete trajectory;
178  break;
179  case fStopAndKill:
180  eventManager->StackTracks(secondaries);
181  delete trajectory;
182  delete track;
183  break;
184  case fKillTrackAndSecondaries:
185  if (secondaries != nullptr) {
186  for (auto& secondary : *secondaries) {
187  delete secondary;
188  }
189  secondaries->clear();
190  }
191  delete trajectory;
192  delete track;
193  break;
194  default:
195  G4cerr << "+++ Geant4RegionSelectiveHepEmTrackingManager: unexpected track status from "
196  "G4TrackingManager, killing track."
197  << G4endl;
198  eventManager->StackTracks(secondaries);
199  delete trajectory;
200  delete track;
201  break;
202  }
203  }
204 
206  std::unordered_set<G4int> m_hepEmRegionIDs;
207  std::unique_ptr<G4HepEmTrackingManager> m_hepEmTrackingManager;
208  };
209 
210  } // namespace
211 
213 
230  protected:
233 
235  std::vector<std::string> m_woodcockRegions;
237  std::vector<std::string> m_hepEmRegions;
239  G4int m_verbosity;
240 
241  public:
244  : Geant4PhysicsList(context, nam) {
245  declareProperty("WoodcockRegions", m_woodcockRegions);
246  declareProperty("HepEmRegions", m_hepEmRegions);
247  declareProperty("VerboseLevel", m_verbosity = 0);
248  }
249 
251  virtual ~Geant4HepEmTrackingPhysics() = default;
252 
254 
264  virtual void constructProcesses(G4VUserPhysicsList* /* physics_list */) override {
265  const bool trackInAllRegions = m_hepEmRegions.empty();
266  std::unordered_set<G4int> hepEmRegionIDs;
267  if (trackInAllRegions) {
268  info("+++ HepEm region selection: all regions");
269  } else {
270  for (const auto& regionName : m_hepEmRegions) {
271  G4Region* region = G4RegionStore::GetInstance()->GetRegion(regionName, false);
272  if (region == nullptr) {
273  warning("+++ HepEm region not found in G4RegionStore: %s", regionName.c_str());
274  continue;
275  }
276  hepEmRegionIDs.insert(region->GetInstanceID());
277  info("+++ HepEm enabled in G4Region: %s", regionName.c_str());
278  }
279  if (hepEmRegionIDs.empty()) {
280  warning("+++ No valid HepEmRegions were resolved; HepEm tracking will be disabled.");
281  }
282  }
283  const std::unordered_set<G4int> resolvedHepEmRegionIDs = hepEmRegionIDs;
284 
285  auto* tm =
286  new Geant4RegionSelectiveHepEmTrackingManager(trackInAllRegions, std::move(hepEmRegionIDs), m_verbosity);
287 
288  G4int configuredWoodcockRegions = 0;
289  for (const auto& region : m_woodcockRegions) {
290  G4Region* woodcockRegion = G4RegionStore::GetInstance()->GetRegion(region, false);
291  if (woodcockRegion == nullptr) {
292  warning("+++ Woodcock region not found in G4RegionStore: %s", region.c_str());
293  continue;
294  }
295  if (!trackInAllRegions
296  && resolvedHepEmRegionIDs.find(woodcockRegion->GetInstanceID()) == resolvedHepEmRegionIDs.end()) {
297  warning("+++ Ignoring Woodcock region '%s': region is outside HepEmRegions selection", region.c_str());
298  continue;
299  }
300  info("+++ Enabling Woodcock photon tracking in G4Region: %s", region.c_str());
301  tm->GetConfig()->SetWoodcockTrackingRegion(region);
302  ++configuredWoodcockRegions;
303  }
304  if (!trackInAllRegions && !m_woodcockRegions.empty() && configuredWoodcockRegions == 0) {
305  warning("+++ No WoodcockRegions remain after applying HepEmRegions intersection.");
306  }
307 
308  // Warn if another custom tracking manager is already installed —
309  // SetTrackingManager() is exclusive and will silently replace it.
310  auto warnIfConflict = [&](G4ParticleDefinition* particle) {
311  if (particle->GetTrackingManager() != nullptr) {
312  warning("+++ Replacing existing tracking manager for %s with G4HepEmTrackingManager",
313  particle->GetParticleName().c_str());
314  }
315  };
316  warnIfConflict(G4Electron::Definition());
317  warnIfConflict(G4Positron::Definition());
318  warnIfConflict(G4Gamma::Definition());
319 
320  G4Electron::Definition()->SetTrackingManager(tm);
321  G4Positron::Definition()->SetTrackingManager(tm);
322  G4Gamma::Definition() ->SetTrackingManager(tm);
323 
324  info("+++ Installed G4HepEmTrackingManager for e-/e+/gamma");
325  }
326  };
327  } // namespace sim
328 } // namespace dd4hep
329 
330 #endif // DDG4_GEANT4HEPEMTRACKINGPHYSICS_H
331 
332 #include <DDG4/Factories.h>
333 using namespace dd4hep::sim;
dd4hep::sim::Geant4HepEmTrackingPhysics::Geant4HepEmTrackingPhysics
Geant4HepEmTrackingPhysics(Geant4Context *context, const std::string &nam)
Standard constructor.
Definition: Geant4HepEmTrackingPhysics.cpp:243
dd4hep::sim::Geant4HepEmTrackingPhysics::constructProcesses
virtual void constructProcesses(G4VUserPhysicsList *) override
Callback to install the G4HepEmTrackingManager on e-, e+ and gamma.
Definition: Geant4HepEmTrackingPhysics.cpp:264
Geant4PhysicsList.h
DECLARE_GEANT4ACTION
#define DECLARE_GEANT4ACTION(name)
Plugin defintion to create Geant4Action objects.
Definition: Factories.h:210
dd4hep::sim::Geant4Action::warning
void warning(const char *fmt,...) const
Support of warning messages.
Definition: Geant4Action.cpp:223
m_hepEmRegionIDs
std::unordered_set< G4int > m_hepEmRegionIDs
Definition: Geant4HepEmTrackingPhysics.cpp:206
dd4hep::sim::Geant4HepEmTrackingPhysics::m_woodcockRegions
std::vector< std::string > m_woodcockRegions
G4Region names in which Woodcock tracking is activated for photons.
Definition: Geant4HepEmTrackingPhysics.cpp:235
dd4hep::sim::Geant4Action::info
void info(const char *fmt,...) const
Support of info messages.
Definition: Geant4Action.cpp:215
dd4hep::sim::Geant4HepEmTrackingPhysics::~Geant4HepEmTrackingPhysics
virtual ~Geant4HepEmTrackingPhysics()=default
Default destructor.
Geant4HepEmTrackingPhysics
PhysicsConstructor enabling G4HepEm vectorised EM tracking for e-/e+/gamma.
dd4hep::sim::Geant4HepEmTrackingPhysics::m_verbosity
G4int m_verbosity
Verbosity forwarded to the underlying G4HepEmTrackingManager.
Definition: Geant4HepEmTrackingPhysics.cpp:239
dd4hep::sim::Geant4HepEmTrackingPhysics::DDG4_DEFINE_ACTION_CONSTRUCTORS
DDG4_DEFINE_ACTION_CONSTRUCTORS(Geant4HepEmTrackingPhysics)
Define standard assignments and constructors.
dd4hep::sim::Geant4Action::declareProperty
Geant4Action & declareProperty(const std::string &nam, T &val)
Declare property.
Definition: Geant4Action.h:366
dd4hep::verbose
std::size_t verbose(const std::string &src, const std::string &msg)
Definition: RootDictionary.h:63
dd4hep::sim::Geant4PhysicsList
Concrete basic implementation of a Geant4 physics list action.
Definition: Geant4PhysicsList.h:41
m_hepEmTrackingManager
std::unique_ptr< G4HepEmTrackingManager > m_hepEmTrackingManager
Definition: Geant4HepEmTrackingPhysics.cpp:207
Factories.h
dd4hep::sim
Namespace for the Geant4 based simulation part of the AIDA detector description toolkit.
Definition: EDM4hepFileReader.cpp:46
dd4hep
Namespace for the AIDA detector description toolkit.
Definition: AlignmentsCalib.h:28
dd4hep::sim::Geant4HepEmTrackingPhysics::m_hepEmRegions
std::vector< std::string > m_hepEmRegions
G4Region names in which HepEm tracking manager is activated.
Definition: Geant4HepEmTrackingPhysics.cpp:237
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
m_trackInAllRegions
bool m_trackInAllRegions
Definition: Geant4HepEmTrackingPhysics.cpp:205