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