ATLAS Offline Software
Loading...
Searching...
No Matches
LArFastShower.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#include "LArFastShower.h"
6
7#include "GaudiKernel/Bootstrap.h"
8#include "GaudiKernel/ISvcLocator.h"
10
11#include "AtlasHepMC/GenEvent.h"
15#include "CLHEP/Random/RandFlat.h"
16
17#include <stdexcept>
18
19#include "G4Electron.hh"
20#include "G4Gamma.hh"
21#include "G4Positron.hh"
22#include "G4Neutron.hh"
23#include "G4PionPlus.hh"
24#include "G4PionMinus.hh"
25#include "G4VSensitiveDetector.hh"
26#include "G4EventManager.hh"
28#include "IFastSimDedicatedSD.h"
29
30#include "GaudiKernel/ConcurrencyFlags.h"
31
32#undef _TRACE_FSM_
33#undef _TRACE_DOIT_
34#undef _TRACE_POSITION_
35#undef _INFO_FSM_
36
37
38LArFastShower::LArFastShower(const std::string& name, G4Region* region, const FastShowerConfigStruct& config,
39 IFastSimDedicatedSD* fastSimDedicatedSD):
40 G4VFastSimulationModel(name, region),
41 m_configuration(config),
42 m_fastSimDedicatedSD(fastSimDedicatedSD),
43 m_showerLibSvc(nullptr),
46 m_eventNum(0)
47{
48 /* Starting points, i.e. vertex coordinates, are needed to create
49 * the Frozen Shower library, so they are saved in a hepmc file.
50 * Frozen showers are then simulated from these starting points
51 * in a separate job. To speed up the simulation,
52 * showers will be read from the library instead of being simulated.*/
53 m_generate_starting_points = (!m_configuration.m_generated_starting_points_file.empty());
55 std::string hepmcFileName = m_configuration.m_generated_starting_points_file;
56
57 // In multi-thread run, multiple hepmc files are created.
58 // To distinguish between them we add thread_id in their name.
59 if (Gaudi::Concurrency::ConcurrencyFlags::numThreads() > 1)
60 {
61 auto threadId = std::this_thread::get_id();
62 std::stringstream ss;
63 ss << threadId;
64 hepmcFileName += "."+ss.str();
65 }
66 m_starting_points_file = std::make_shared<HepMC3::WriterAscii>(hepmcFileName);
67 }
68
69 enum DETECTOR { EMB=100000, EMEC=200000, FCAL1=300000, FCAL2=400000,
70 FCAL3=500000, HECLOC=600000, HEC=700000 };
71
72 m_detmap["EMB"]=EMB;
73 m_detmap["EMEC"]=EMEC;
74 m_detmap["FCAL1"]=FCAL1;
75 m_detmap["FCAL2"]=FCAL2;
76 m_detmap["FCAL3"]=FCAL3;
77 m_detmap["HECLOC"]=HECLOC;
78 m_detmap["HEC"]=HEC;
79}
80
82{
83 if ( !m_fastSimDedicatedSD ) {
84 throw std::runtime_error("LArFastShower: no pointer to IFastSimDedicatedSD!");
85 }
87}
88
89
91{
92 if ( !m_showerLibSvc ) {
93 SmartIF<ILArG4ShowerLibSvc> smartShowerLibSvc{Gaudi::svcLocator()->service(m_configuration.m_showerLibSvcName)};
94 if ( smartShowerLibSvc ) { m_showerLibSvc = smartShowerLibSvc.get(); }
95 if ( !m_showerLibSvc ) {
96 throw std::runtime_error("LArFastShower: cannot retrieve LArG4ShowerLibSvc");
97 }
98 }
99 return m_showerLibSvc;
100}
101
102
103G4bool LArFastShower::IsApplicable(const G4ParticleDefinition& particleType)
104{
105#ifdef _TRACE_FSM_
106 G4cout << "LArFastShower::IsApplicable" << G4endl;
107#endif
108
109 /*
110 * if ( flag to parameterize is set )
111 * && ( (we want to record SPs) || (ShowerLibSvc has a library for this particle) )
112 */
113 if (m_applicableMap.find(particleType.GetPDGEncoding()) != m_applicableMap.end()) {
114 return m_applicableMap.find(particleType.GetPDGEncoding())->second;
115 }
116 bool rez = false;
119 showerLibSvc()->checkLibrary( particleType.GetPDGEncoding(),
120 m_configuration.m_detector_tag ) ))
121 rez = true;
122 m_applicableMap[particleType.GetPDGEncoding()] = rez;
123 return rez;
124}
125
126G4bool LArFastShower::ModelTrigger(const G4FastTrack& fastTrack)
127{
128 /* ==========================================================================
129 Determine if the particle is to be returned to full Geant4 simulation.
130 In the event where the particle is EITHER killed and parameterised OR
131 simply killed, this must be done in the appropriate LArFastShower DoIt method.
132 This method Checks: 1) Geometry; 2) Energy; 3) (for e+/e-) Containment
133 ========================================================================== */
134
135#ifdef _TRACE_FSM_
136 G4cout << "LArFastShower::commonTrigger" << G4endl;
137#endif
138
139 // We are in a parameterized volume
140
141 // Check if the particle is within energy bounds
142 G4double particleEnergy = fastTrack.GetPrimaryTrack()->GetKineticEnergy();
143 const G4ParticleDefinition& particleType = *(fastTrack.GetPrimaryTrack()->GetDefinition());
144
145 if ( flagToShowerLib(particleType) == true &&
146 particleEnergy > minEneToShowerLib(particleType) &&
147 particleEnergy < maxEneToShowerLib(particleType) ) {
148
149#ifdef _TRACE_FSM_
150 G4cout << "Particle has energy (" << particleEnergy << ") for shower lib and shower lib is on! Accept particle!" << G4endl;
151#endif
152 } else {
153
154#ifdef _TRACE_FSM_
155 G4cout << "Particle has energy (" << particleEnergy << ") outside killing, shower lib and parametrisation "
156 << "or some features are switched off ... returning it to Geant " << G4endl;
157#endif
158
159 return false;
160 }
161
162 if (ForcedAccept(fastTrack)) return true;
163 if (ForcedDeny(fastTrack)) return false;
164
165 if (CheckContainment(fastTrack)==false) {
166#ifdef _TRACE_FSM_
167 G4cout << "LArFastShower::ModelTrigger() particle failed CheckContainment()... will not be parameterised: " << G4endl;
168#endif
169 return false;
170 }
171
172#ifdef _TRACE_FSM_
173 G4cout << "LArFastShower::ModelTrigger() direction: " << fastTrack.GetPrimaryTrackLocalDirection() << G4endl;
174 G4cout << "LArFastShower::ModelTrigger() mom dir: " << fastTrack.GetPrimaryTrack()->GetMomentumDirection() << G4endl;
175#endif
176
177 return true;
178}
179
180
181void LArFastShower::DoIt(const G4FastTrack& fastTrack, G4FastStep& fastStep)
182{
183#ifdef _TRACE_FSM_
184 G4cout << "LArFastShower::Doit()" << G4endl;
185#endif
186
188 if (CLHEP::RandFlat::shoot(G4Random::getTheEngine()) <= m_configuration.m_generated_starting_points_ratio) {
189 std::unique_ptr<const HepMC::GenEvent> ge = GetGenEvent(fastTrack);
191 }
192 KillParticle( fastTrack, fastStep );
193 return;
194 }
195 this->UseShowerLib( fastTrack, fastStep );
196
197#ifdef _TRACE_FSM_
198 G4cout << "LArFastShower::Doit() done" << G4endl;
199#endif
200
201}
202
203#ifdef _TRACE_DOIT_
204void LArFastShower::KillParticle(const G4FastTrack& fastTrack, G4FastStep& fastStep)
205#else
206void LArFastShower::KillParticle(const G4FastTrack&, G4FastStep& fastStep)
207#endif
208{
209
210#ifdef _TRACE_DOIT_
211 G4cout << "Low energy particle is being killed: " << fastTrack.GetPrimaryTrack()->GetKineticEnergy() << G4endl;
212#endif
213
214 // Kill the particle
215 fastStep.KillPrimaryTrack();
216 fastStep.ProposePrimaryTrackPathLength(0.0);
217
218 return;
219}
220
221void LArFastShower::UseShowerLib(const G4FastTrack& fastTrack, G4FastStep& fastStep)
222{
223 try {
224#ifdef _TRACE_DOIT_
225 G4cout << "LArFastShower::UseShowerLib()" << G4endl;
226#endif
227
228 // kill the electron to be parametrised
229 KillParticle(fastTrack, fastStep);
230
231 // -----------------------------
232 // Get Shower from ShowerLibSvc
233 // -----------------------------
234 const std::vector<EnergySpot> shower =
235 showerLibSvc()->getShower(fastTrack, m_configuration.m_detector_tag);
236
237#ifdef _TRACE_DOIT_
238 G4cout << "Got shower (" << shower.size() << ") from shower lib" << G4endl;
239#endif
240 const double weight = (m_configuration.m_applyRRWeights) ? fastTrack.GetPrimaryTrack()->GetWeight() : 1.0;
241 // loop over hits in shower
242 for (const auto& a_spot : shower) {
243
244#ifdef _TRACE_DOIT_
245 G4cout << "Make Spot: " << a_spot.GetPosition().x() << " "
246 << a_spot.GetPosition().y() << " " << a_spot.GetPosition().z()
247 << " " << a_spot.GetEnergy() << " " << a_spot.GetTime() << G4endl;
248#endif
249 fastShowerSD()->ProcessSpot(a_spot, weight);
250
251#ifdef _TRACE_DOIT_
252 G4cout << "Made Spot" << G4endl;
253#endif
254
255 }
256
257#ifdef _TRACE_FSM_
258 G4cout << "LArFastShower::UseShowerLib() Done" << G4endl;
259#endif
260
261 return;
262 }
263
264 // FIXME: Catching all exceptions and suppressing them? That's awful!!
265 catch (const std::exception & e) {
266 G4cout << "FastShower::UseShowerLib ERROR Handling an exception in LArFastShower::" << e.what() << G4endl;
267 return;
268 }
269
270}
271
272G4bool LArFastShower::CheckContainment(const G4FastTrack &fastTrack)
273{
274
275 G4ThreeVector showerDirection = fastTrack.GetPrimaryTrack()->GetMomentumDirection();
276 G4ThreeVector initialShowerPosition = fastTrack.GetPrimaryTrack()->GetPosition();
277 G4ThreeVector orthoShower = showerDirection.orthogonal();
278 G4ThreeVector crossShower = showerDirection.cross(orthoShower);
279
280#ifdef _TRACE_FSM_
281 G4cout << "LArFastShower::CheckContainment() orthoShower: " << orthoShower << G4endl;
282 G4cout << "LArFastShower::CheckContainment() crossShower: " << crossShower << G4endl;
283#endif
284
285 //Build 5 points at the shower max. edges and far end
286 //this picks the points where 99% of the particle energy was already deposited
287 /* Short history of containment check:
288 * First, it was magic numbers from ShowerParams class
289 G4double Zmx = myParameterisation()->GetAveZmx();
290 G4double R = myParameterisation()->GetAveR90(); // Easy - just multiply
291 G4double Z = myParameterisation()->GetAveZ90(); // More convoluted
292 * Then, after ShowerParams class was sent to code heaven, the magic numbers were saved from it
293 * and stored right here:
294 G4double Zmx = 22*mm;
295 G4double R = 1.5*4*cm;
296 G4double Z = 22*2.5*mm;
297 * Now, we take it directly from the library
298 */
299 G4double Z = showerLibSvc()->getContainmentZ(fastTrack,m_configuration.m_detector_tag);
300 G4double R = showerLibSvc()->getContainmentR(fastTrack,m_configuration.m_detector_tag);
301
302 if (Z == 0.0 && R == 0.0) {
303 // no containment check
304 return true;
305 }
306
307 // Here is OUR magic number. Looking on the hit distribution plot,
308 // it seems that that way most of hits will be inside
309 G4double Zmx = Z / 3;
310
311 G4int cosPhi[4] = {1,0,-1,0};
312 G4int sinPhi[4] = {0,1,0,-1};
313
314#ifdef _TRACE_FSM_
315 G4cout << "LArFastShower::CheckContainment() R = " << R << G4endl;
316 G4cout << "LArFastShower::CheckContainment() Z = " << Z << G4endl;
317#endif
318
319 G4ThreeVector position;
320
321 G4VSolid* caloSolid = fastTrack.GetEnvelopeSolid();
322 const G4AffineTransform* affineTransformation = fastTrack.GetAffineTransformation();
323
324 //Startpoint
325 position = initialShowerPosition;
326 affineTransformation->ApplyPointTransform(position);
327 if(caloSolid->Inside(position) == kOutside)
328 return false;
329
330 //Longitudinal Endpoint
331 position = initialShowerPosition + Z*showerDirection;
332 affineTransformation->ApplyPointTransform(position);
333 if(caloSolid->Inside(position) == kOutside)
334 return false;
335
336 //Lateral Spread
337 for(int i=0; i<4 ;i++)
338 {
339 position = initialShowerPosition + Zmx*showerDirection +
340 R*cosPhi[i]*orthoShower + R*sinPhi[i]*crossShower;
341 affineTransformation->ApplyPointTransform(position);
342 if(caloSolid->Inside(position) == kOutside)
343 return false;
344 }
345
346#ifdef _TRACE_FSM_
347 G4cout << "LArFastShower::CheckContainment() Shower is contained " << G4endl;
348#endif
349
350 return true;
351
352}
353
354std::unique_ptr<const HepMC::GenEvent> LArFastShower::GetGenEvent(const G4FastTrack &fastTrack)
355{
356 const G4ThreeVector showerPos = fastTrack.GetPrimaryTrack()->GetPosition();
357 const G4ThreeVector showerMom = fastTrack.GetPrimaryTrack()->GetMomentum();
358 const G4double energy = fastTrack.GetPrimaryTrack()->GetKineticEnergy();
359
360 G4int pdgcode = fastTrack.GetPrimaryTrack()->GetDefinition()->GetPDGEncoding();
361 if (pdgcode < 0) pdgcode = -pdgcode; // hack for positrons. let it be electrons.
362
363 HepMC3::Units::MomentumUnit momentumUnit = HepMC3::Units::MEV;
364 HepMC3::Units::LengthUnit lengthUnit = HepMC3::Units::MM;
365 // new event. Signal processing = 0, event number "next"
366 std::unique_ptr<HepMC::GenEvent> ge = std::make_unique<HepMC::GenEvent>(momentumUnit,lengthUnit);
367
368 ge->set_event_number(++m_eventNum);
369
370 // starting point from which the shower develops, time = 0.
372 HepMC::FourVector(showerPos.x(), showerPos.y(), showerPos.z(), 0) );
373 ge->add_vertex(gv);
374
375 // input particle (status=4) is always required by HepMC.
376 // make it a dummy geantino with 4-mom=0. pdg_id=999.
378 HepMC::FourVector(0.,0.,0.,0.),
379 999, 4 );
380 gv->add_particle_in(std::move(gpi));
381
382 // output particle (status=1) is the FourVector of the shower.
384 HepMC::FourVector(showerMom.x(), showerMom.y(), showerMom.z(), energy),
385 pdgcode, 1 );
386 gv->add_particle_out(std::move(gpo));
387
388 // return auto_pointer. will be deleted automatically
389 return ge;
390}
391
392// Helper methods
393bool LArFastShower::flagToShowerLib( const G4ParticleDefinition& particleType ) const
394{
395 if ( &particleType == G4Electron::ElectronDefinition() ||
396 &particleType == G4Positron::PositronDefinition() ) {
397 return m_configuration.m_e_FlagShowerLib;
398 } else if ( &particleType == G4Gamma::GammaDefinition() ) {
399 return m_configuration.m_g_FlagShowerLib;
400 } else if ( &particleType == G4Neutron::NeutronDefinition() ) {
401 return m_configuration.m_Neut_FlagShowerLib;
402 } else if ( &particleType == G4PionPlus::PionPlusDefinition() ||
403 &particleType == G4PionMinus::PionMinusDefinition() ) {
404 return m_configuration.m_Pion_FlagShowerLib;
405 }
406 return false;
407}
408double LArFastShower::minEneToShowerLib( const G4ParticleDefinition& particleType ) const
409{
410 if ( &particleType == G4Electron::ElectronDefinition() ||
411 &particleType == G4Positron::PositronDefinition() ) {
412 return m_configuration.m_e_MinEneShowerLib;
413 } else if ( &particleType == G4Gamma::GammaDefinition() ) {
414 return m_configuration.m_g_MinEneShowerLib;
415 } else if ( &particleType == G4Neutron::NeutronDefinition() ) {
416 return m_configuration.m_Neut_MinEneShowerLib;
417 } else if ( &particleType == G4PionPlus::PionPlusDefinition() ||
418 &particleType == G4PionMinus::PionMinusDefinition() ) {
419 return m_configuration.m_Pion_MinEneShowerLib;
420 }
421 return 0.0;
422}
423
424double LArFastShower::maxEneToShowerLib( const G4ParticleDefinition& particleType ) const
425{
426 if ( &particleType == G4Electron::ElectronDefinition() ||
427 &particleType == G4Positron::PositronDefinition() ) {
428 return m_configuration.m_e_MaxEneShowerLib;
429 } else if ( &particleType == G4Gamma::GammaDefinition() ) {
430 return m_configuration.m_g_MaxEneShowerLib;
431 } else if ( &particleType == G4Neutron::NeutronDefinition() ) {
432 return m_configuration.m_Neut_MaxEneShowerLib;
433 } else if ( &particleType == G4PionPlus::PionPlusDefinition() ||
434 &particleType == G4PionMinus::PionMinusDefinition() ) {
435 return m_configuration.m_Pion_MaxEneShowerLib;
436 }
437 return 0.0;
438}
439bool LArFastShower::generateFSStartingPoint( std::unique_ptr<const HepMC::GenEvent> &ge ) const
440{
442 return false;
443 m_starting_points_file->write_event(*ge);
444 return true;
445}
446G4bool LArFastShower::ForcedAccept(const G4FastTrack & fastTrack)
447{
448 G4ThreeVector initialShowerPosition = fastTrack.GetPrimaryTrack()->GetPosition();
449
450 // if ( !m_configuration.m_containHigh &&
451 // ( initialShowerPosition.eta()>=m_configuration.m_absHighEta ||
452 // initialShowerPosition.eta()<=-m_configuration.m_absHighEta ) ) return true;
453
454 if ( !m_configuration.m_containHigh &&
455 ( initialShowerPosition.eta()>m_configuration.m_absHighEta ||
456 initialShowerPosition.eta()<-m_configuration.m_absHighEta ) ) return true;
457
458 if ( !m_configuration.m_containCrack &&
459 ( ( initialShowerPosition.eta()>m_configuration.m_absCrackEta1 &&
460 initialShowerPosition.eta()<m_configuration.m_absCrackEta2 ) ||
461 ( initialShowerPosition.eta()<-m_configuration.m_absCrackEta1 &&
462 initialShowerPosition.eta()>-m_configuration.m_absCrackEta2 ) ) ) return true;
463
464 if ( !m_configuration.m_containLow &&
465 ( initialShowerPosition.eta()<m_configuration.m_absLowEta ||
466 initialShowerPosition.eta()>-m_configuration.m_absLowEta ) ) return true;
467 return false;
468}
469
470G4bool LArFastShower::ForcedDeny (const G4FastTrack &)
471{
472 return false;
473}
static Double_t ss
This is the interface for the fast simulation dedicated sensitive detector.
virtual void ProcessSpot(const EnergySpot &spot, double weight)=0
ProcessHitsMethod.
virtual double getContainmentZ(const G4FastTrack &, int)=0
virtual std::vector< EnergySpot > getShower(const G4FastTrack &, int) const =0
virtual double getContainmentR(const G4FastTrack &, int)=0
ILArG4ShowerLibSvc * showerLibSvc()
void KillParticle(const G4FastTrack &, G4FastStep &)
Method to kill a particle and deposit its energy using exponential decay function.
ILArG4ShowerLibSvc * m_showerLibSvc
Pointer to the shower library service.
IFastSimDedicatedSD * fastShowerSD()
virtual G4bool ForcedAccept(const G4FastTrack &)
If it returns true, the particle will be parameterized without further checks.
std::shared_ptr< HepMC3::WriterAscii > m_starting_points_file
void UseShowerLib(const G4FastTrack &, G4FastStep &)
Function for the application of shower library.
LArFastShower(const std::string &name, G4Region *region, const FastShowerConfigStruct &config, IFastSimDedicatedSD *fastSimDedicatedSD)
Constructor.
virtual G4bool ForcedDeny(const G4FastTrack &)
If it returns true, the particle will be returned to G4 without further checks.
bool generateFSStartingPoint(std::unique_ptr< const HepMC::GenEvent > &ge) const
bool flagToShowerLib(const G4ParticleDefinition &particleType) const
get switch for frozen showers
double minEneToShowerLib(const G4ParticleDefinition &particleType) const
get upper energy limit for frozen showers
double maxEneToShowerLib(const G4ParticleDefinition &particleType) const
get lower energy limit for frozen showers
std::map< int, bool > m_applicableMap
virtual G4bool ModelTrigger(const G4FastTrack &) override
Determines the applicability of the fast sim model to this particular track.
std::unique_ptr< const HepMC::GenEvent > GetGenEvent(const G4FastTrack &fastTrack)
bool m_generate_starting_points
G4bool IsApplicable(const G4ParticleDefinition &) override
Determines the applicability of the fast sim model to this particle type Called once for each track p...
const FastShowerConfigStruct m_configuration
void DoIt(const G4FastTrack &, G4FastStep &) override
Assigns the track to the appropriate method for application of the fast simulation.
virtual G4bool CheckContainment(const G4FastTrack &fastTrack)
Function to check the containment of a shower within a regular detector region.
std::map< std::string, int > m_detmap
IFastSimDedicatedSD * m_fastSimDedicatedSD
Shower library sensitive detector for this shower.
HepMC3::FourVector FourVector
GenParticlePtr newGenParticlePtr(const HepMC3::FourVector &mom=HepMC3::FourVector::ZERO_VECTOR(), int pid=0, int status=0)
Definition GenParticle.h:21
HepMC3::GenParticlePtr GenParticlePtr
Definition GenParticle.h:19
GenVertexPtr newGenVertexPtr(const HepMC3::FourVector &pos=HepMC3::FourVector::ZERO_VECTOR(), const int i=0)
Definition GenVertex.h:25
HepMC3::GenVertexPtr GenVertexPtr
Definition GenVertex.h:23