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