ATLAS Offline Software
Loading...
Searching...
No Matches
G4RunAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Local includes
6#include "G4RunAlg.h"
7
8// Geant4 includes
9#include "G4Event.hh"
10#include "G4EventManager.hh"
11#include "G4GDMLParser.hh"
12#include "G4TrackingManager.hh"
13#include "G4PhysicalVolumeStore.hh"
14#include "G4GeometryManager.hh"
15
16// Athena includes
25
26// standard library
27#include <memory>
28#include <mutex>
29
30static std::once_flag releaseGeoModelOnceFlag;
31
32// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
33
34StatusCode G4RunAlg::initialize ATLAS_NOT_THREAD_SAFE ()
35{
36 ATH_MSG_DEBUG("Start of G4RunAlg::initialize()");
37
38 // Read the simplified geometry for FastCaloSim track transportation if requested
39 // TODO: should be moved to Geant4 main thread (detector construction)
40 if(!m_simplifiedGeoPath.empty()) {
41 std::string geoFile = PathResolverFindCalibFile(m_simplifiedGeoPath);
42 if (geoFile.empty()) {
43 ATH_MSG_FATAL("Could not find simplified geometry file: " << m_simplifiedGeoPath);
44 return StatusCode::FAILURE;
45 }
46 G4GDMLParser parser;
47 parser.Read(geoFile, false);
48 }
49
50 // Truth service
51 ATH_CHECK(m_truthRecordSvc.retrieve());
52 ATH_MSG_INFO("- Using ISF TruthRecordSvc : " << m_truthRecordSvc.typeAndName());
53
54 // Retrieve the G4RunTool. This will start the G4 main thread
55 ATH_CHECK(m_g4RunTool.retrieve());
56 ATH_MSG_INFO("Waiting on G4RunTool to be ready for run");
57 // We have to wait on the Geant4 main thread to finish initializing.
58 // Wait has to be done here because Gaudi tool initialization are protected by a recursive mutex
59 // which would lead to a deadlock between the Geant4 main thread and the Athena thread
60 ATH_CHECK(m_g4RunTool->WaitBeginRun());
61
62 // Initialize algorithm-specific services
63 ATH_CHECK(m_rndmGenSvc.retrieve());
64 ATH_CHECK(m_userActionSvc.retrieve());
65 // These have already been initialized by G4RunTool, just populate the handles
66 ATH_CHECK(m_senDetTool.retrieve());
67 ATH_CHECK(m_fastSimTool.retrieve());
68
69 // I/O
70 ATH_CHECK(m_inputTruthCollectionKey.initialize());
71 ATH_CHECK(m_outputTruthCollectionKey.initialize());
72 ATH_CHECK(m_eventInfoKey.initialize());
73
74 ATH_CHECK(m_inputConverter.retrieve());
75 if (!m_truthPreselectionTool.empty()) {
76 ATH_CHECK(m_truthPreselectionTool.retrieve());
77 }
78
79 if (!m_qspatcher.empty()) {
80 ATH_CHECK(m_qspatcher.retrieve());
81 }
82
83 ATH_MSG_DEBUG("End of G4RunAlg::initialize()");
84 return StatusCode::SUCCESS;
85}
86
87// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
88
89StatusCode G4RunAlg::execute(const EventContext& ctx)
90{
91 static std::atomic<unsigned int> n_Event=0;
92 ATH_MSG_DEBUG("++++++++++++ G4RunAlg execute ++++++++++++");
93
94 n_Event += 1;
95
96 if (n_Event<=10 || (n_Event%100) == 0) {
97 ATH_MSG_ALWAYS("Event num. " << n_Event << " start processing");
98 }
99
100 // Release GeoModel Geometry if necessary
101 // TODO: should be moved to Geant4 main thread after run initialization
102 if (m_releaseGeoModel) {
103 try {
105 }
106 catch(const std::exception& e) {
107 ATH_MSG_ERROR("Failure in G4RunAlg::releaseGeoModel: " << e.what());
108 return StatusCode::FAILURE;
109 }
110 }
111
112 // Set the RNG to use for this event. We need to reset it for MT jobs
113 // because of the mismatch between Gaudi slot-local and G4 thread-local RNG.
114 ATHRNG::RNGWrapper* rngWrapper = m_rndmGenSvc->getEngine(this, m_randomStreamName);
115 rngWrapper->setSeed( m_randomStreamName, ctx);
116
118 if (!inputTruthCollection.isValid()) {
119 ATH_MSG_FATAL("Unable to read input GenEvent collection " << inputTruthCollection.name() << " in store " << inputTruthCollection.store());
120 return StatusCode::FAILURE;
121 }
122 ATH_MSG_DEBUG("Found input GenEvent collection " << inputTruthCollection.name() << " in store " << inputTruthCollection.store());
123 // create the output Truth collection
125 std::unique_ptr<McEventCollection> shadowTruth{};
126 if (m_useShadowEvent) {
127 outputTruthCollection = std::make_unique<McEventCollection>();
128 // copy input Evgen collection to shadow Truth collection
129 shadowTruth = std::make_unique<McEventCollection>(*inputTruthCollection);
130 for (HepMC::GenEvent* currentGenEvent : *shadowTruth ) {
131 // Apply QS patch if required
132 if ( not m_qspatcher.empty() ) {
133 ATH_CHECK(m_qspatcher->applyWorkaround(*currentGenEvent));
134 }
135 // Copy GenEvent and remove daughters of quasi-stable particles to be simulated
136 std::unique_ptr<HepMC::GenEvent> outputEvent = m_truthPreselectionTool->filterGenEvent(*currentGenEvent);
137 outputTruthCollection->push_back(outputEvent.release());
138 }
139 }
140 else {
141 // copy input Evgen collection to output Truth collection
142 outputTruthCollection = std::make_unique<McEventCollection>(*inputTruthCollection);
143 // empty shadow Truth collection
144 shadowTruth = std::make_unique<McEventCollection>();
145 // Apply QS patch if required
146 if ( not m_qspatcher.empty() ) {
147 for (HepMC::GenEvent* currentGenEvent : *outputTruthCollection ) {
148 ATH_CHECK(m_qspatcher->applyWorkaround(*currentGenEvent));
149 }
150 }
151 }
152
153 ATH_MSG_DEBUG("Recorded output GenEvent collection " << outputTruthCollection.name() << " in store " << outputTruthCollection.store());
154
155 const int largestGeneratedParticleBC = (outputTruthCollection->empty()) ? HepMC::UNDEFINED_ID
156 : HepMC::maxGeneratedParticleBarcode(outputTruthCollection->at(0)); // TODO make this more robust
157 const int largestGeneratedVertexBC = (outputTruthCollection->empty()) ? HepMC::UNDEFINED_ID
158 : HepMC::maxGeneratedVertexBarcode(outputTruthCollection->at(0)); // TODO make this more robust
160 EventOutcome eventOutcome = EventOutcome::Success;
161 {
162
163 // called by the Geant4 PrimaryGeneratorAction because primary vertices must be instantiated by Geant4 threads
164 auto prepare_event = [this, &outputTruthCollection, &shadowTruth, largestGeneratedParticleBC, largestGeneratedVertexBC](G4Event& event) -> StatusCode {
165 // tell TruthService we're starting a new event
166 ATH_CHECK( m_truthRecordSvc->initializeTruthCollection(largestGeneratedParticleBC, largestGeneratedVertexBC) );
167 ATH_CHECK(m_inputConverter->convertHepMCToG4Event(
168 *outputTruthCollection, event, *shadowTruth));
169 return StatusCode::SUCCESS;
170 };
171
172 auto eventInfo = std::make_unique<AtlasG4SyncEventUserInfo>(rngWrapper->getEngine(ctx), std::move(prepare_event), ctx);
173
174 // get a shared pointer to the hit collection map because we will need it after the G4Event is destroyed
175 std::shared_ptr<HitCollectionMap> hitCollections = eventInfo->GetHitCollectionMap();
176
177 ATH_CHECK(m_senDetTool->BeginOfAthenaEvent(*hitCollections));
178 ATH_CHECK(m_userActionSvc->BeginOfAthenaEvent(*hitCollections));
179 ATH_CHECK(m_fastSimTool->BeginOfAthenaEvent(*hitCollections));
180
181 auto syncInterface = eventInfo->SyncInterface();
182
183 ATH_MSG_DEBUG("Pushing Athena event " << ctx.eventID().event_number() << " onto event buffer");
184 m_g4RunTool->PushEvent(std::move(eventInfo));
185 ATH_MSG_DEBUG("Buffer size=" << m_g4RunTool->Size() << ", waiting for event to finish");
186 // G4 tells Athena after the worker run manager has terminated the event.
187 syncInterface->WaitStatusDone();
188 eventOutcome = syncInterface->Outcome();
189
190 if (eventOutcome == EventOutcome::Aborted) {
191 ATH_MSG_WARNING("Event was aborted !! ");
192 ATH_MSG_WARNING("Simulation will now go on to the next event ");
194 ATH_MSG_WARNING("setFilterPassed is now False");
195 setFilterPassed(false, ctx);
196 }
199 if (!eventInfo.isValid()) {
201 "Failed to retrieve xAOD::EventInfo while trying to update the "
202 "error state!");
203 return StatusCode::FAILURE;
204 } else {
205 eventInfo->updateErrorState(xAOD::EventInfo::Core,
207 ATH_MSG_WARNING("Set error state in xAOD::EventInfo!");
208 }
209 }
210 }
211
212 ATH_CHECK(m_senDetTool->EndOfAthenaEvent(*hitCollections));
213 ATH_CHECK(m_userActionSvc->EndOfAthenaEvent(*hitCollections));
214 ATH_CHECK(m_fastSimTool->EndOfAthenaEvent(*hitCollections));
215
216 ATH_CHECK(m_truthRecordSvc->releaseEvent());
217 }
218 // Remove QS patch if required
219 if(!m_qspatcher.empty()) {
220 for (HepMC::GenEvent* currentGenEvent : *outputTruthCollection ) {
221 ATH_CHECK(m_qspatcher->removeWorkaround(*currentGenEvent));
222 }
223 }
224
225 if (eventOutcome == EventOutcome::PreparationFailed) {
226 ATH_MSG_ERROR("Failed to prepare Geant4 event");
227 return StatusCode::FAILURE;
228 }
229 if (eventOutcome == EventOutcome::RunTerminated) {
230 ATH_MSG_ERROR("Geant4 terminated before completing this event");
231 return StatusCode::FAILURE;
232 }
233
234 return StatusCode::SUCCESS;
235}
236
237// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
238
240{
241 SmartIF<IGeoModelSvc> geoModel{Gaudi::svcLocator()->service("GeoModelSvc")};
242 if (!geoModel) {
243 ATH_MSG_WARNING( " ----> Unable to retrieve GeoModelSvc" );
244 }
245 else {
246 if (geoModel->clear().isFailure()) {
247 ATH_MSG_WARNING( " ----> GeoModelSvc::clear() failed" );
248 }
249 else {
250 ATH_MSG_INFO( " ----> GeoModelSvc::clear() succeeded " );
251 }
252 }
253 m_releaseGeoModel=false; // Don't do that again...
254 return;
255}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_ALWAYS(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
static std::once_flag releaseGeoModelOnceFlag
StatusCode G4RunAlg::initialize ATLAS_NOT_THREAD_SAFE()
Install fatal handler with default options.
Definition G4RunAlg.cxx:34
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
void setSeed(const std::string &algName, const EventContext &ctx)
Set the random seed using a string (e.g.
Definition RNGWrapper.h:154
CLHEP::HepRandomEngine * getEngine(const EventContext &ctx) const
Retrieve the random engine corresponding to the provided EventContext.
Definition RNGWrapper.h:108
virtual void setFilterPassed(bool state, const EventContext &ctx) const
Gaudi::Property< bool > m_releaseGeoModel
Definition G4RunAlg.h:79
ToolHandle< ISF::IGenEventFilter > m_truthPreselectionTool
Tool for filtering out quasi-stable particle daughters.
Definition G4RunAlg.h:107
ServiceHandle< Simulation::IZeroLifetimePatcher > m_qspatcher
Quasi-Stable Particle Simulation Patcher.
Definition G4RunAlg.h:94
ServiceHandle< IAthRNGSvc > m_rndmGenSvc
Random number service.
Definition G4RunAlg.h:96
PublicToolHandle< IG4RunTool > m_g4RunTool
G4Atlas Tool for thread management and data interface.
Definition G4RunAlg.h:103
void releaseGeoModel()
Releases the GeoModel geometry from memory once it has been used to build the G4 geometry and is no-l...
Definition G4RunAlg.cxx:239
Gaudi::Property< bool > m_useShadowEvent
Definition G4RunAlg.h:80
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfoKey
Definition G4RunAlg.h:85
PublicToolHandle< ISensitiveDetectorMasterTool > m_senDetTool
Sensitive Detector Master Tool.
Definition G4RunAlg.h:105
ServiceHandle< G4UA::IUserActionSvc > m_userActionSvc
User Action Service.
Definition G4RunAlg.h:98
ServiceHandle< ISF::ITruthSvc > m_truthRecordSvc
Central Truth Service.
Definition G4RunAlg.h:92
virtual StatusCode execute(const EventContext &ctx) override
Simulate one Athena event.
Definition G4RunAlg.cxx:89
Gaudi::Property< bool > m_killAbortedEvents
Definition G4RunAlg.h:78
Gaudi::Property< std::string > m_randomStreamName
Definition G4RunAlg.h:81
PublicToolHandle< IFastSimulationMasterTool > m_fastSimTool
Fast Simulation Master Tool.
Definition G4RunAlg.h:101
SG::WriteHandleKey< McEventCollection > m_outputTruthCollectionKey
Definition G4RunAlg.h:87
ServiceHandle< ISF::IInputConverter > m_inputConverter
Service to convert ISF_Particles into a G4Event.
Definition G4RunAlg.h:90
SG::ReadHandleKey< McEventCollection > m_inputTruthCollectionKey
Definition G4RunAlg.h:86
Gaudi::Property< bool > m_flagAbortedEvents
Definition G4RunAlg.h:77
virtual bool isValid() override final
Can the handle be successfully dereferenced?
std::string store() const
Return the name of the store holding the object we are proxying.
const std::string & name() const
Return the StoreGate ID for the referenced object.
@ Core
Core flags describing the event.
@ Error
The sub-detector issued an error.
int maxGeneratedVertexBarcode(const HepMC::GenEvent *genEvent)
Get the maximal absolute value of barcode of vertex present in the event. Returns a negative number.
constexpr int UNDEFINED_ID
int maxGeneratedParticleBarcode(const HepMC::GenEvent *genEvent)
Get the maximal value of barcode of particle present in the event.
HepMC3::GenEvent GenEvent
Definition GenEvent.h:39