ATLAS Offline Software
Loading...
Searching...
No Matches
LArG4GenShowerLib.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
15
16// class header
17#include "LArG4GenShowerLib.h"
18
19// local include(s):
22
23// athena includes
24#include "GeneratorObjects/McEventCollection.h" // For MC Truth information:
26#include "GaudiKernel/IToolSvc.h"
30
31// geant includes
32#include "G4Version.hh"
33
34// ROOT includes
35#include "TFile.h"
36
37// STL include(s):
38#include <sstream>
39#include <cstdlib>
40
41using CLHEP::Hep3Vector;
42
43// definition for helper struct
44class Dist {
45public:
46 Dist(ShowerLib::StepInfo* the_h1, ShowerLib::StepInfo* the_h2) : h1(the_h1), h2(the_h2) {}
50 {
52 h1->setValid(false);
53 h2->setValid(false);
54 return newStep;
55 }
56};
57
59public:
62 bool operator()( const ShowerLib::StepInfo * first, const ShowerLib::StepInfo * second) const {
63 return sortFunction(first, second, m_type );
64 }
65private:
67 //returns true if first is closer to the origin. this should sort from closest to farest
68 bool sortFunction ( const ShowerLib::StepInfo* first, const ShowerLib::StepInfo* second, const CompareType type) const {
69 if (type == RHO) {
70 if (first->position().mag2() < second->position().mag2()) return true;
71 return false;
72 } else if (type == R) {
73 if (first->position().perp2() < second->position().perp2()) return true;
74 return false;
75 } else if (type == Z) {
76 if (first->position().z() < second->position().z()) return true;
77 return false;
78 }
79 return true; //it's here just to avoid warnings
80 }
81};
82
84{
85 ATH_MSG_DEBUG ( "Initializing" );
86
87 ShowerLib::IShowerLib* library = nullptr;
88
89 std::vector< std::string >::const_iterator nameiter;
90
91 ATH_MSG_DEBUG ( "Starting struct files iteration" );
92 for (nameiter = m_lib_struct_files.value().begin(); nameiter != m_lib_struct_files.value().end(); ++nameiter ) {
93
94 ATH_MSG_DEBUG ( "Struct file: " << (*nameiter) );
95
96 library = ShowerLib::iterateStruct(*nameiter);
97
98 if (library == nullptr) {
99 ATH_MSG_WARNING ( "Library structure file " << (*nameiter) << " doesn't describe a valid library" );
100 continue;
101 }
102
103 std::stringstream location;
104 location << library->detector() << "/" << library->particle_id();
105 m_libraries[location.str()] = library;
106 m_libraries_by_filename[(*nameiter)+".root"] = library;
107 m_stat_lib_saved[library]=0;
108 m_stat_lib_notsaved[library]=0;
109
110 ATH_MSG_VERBOSE ( "Library named " << (*nameiter)+".root" << "is stored at the location " << location.str() );
111
112 }
113
114 if (m_libraries.empty()) {
115 ATH_MSG_ERROR ( "No valid library structure files found. Further execution is pointless." );
116 return StatusCode::FAILURE;
117 }
118
119 ATH_MSG_DEBUG ( "LArG4GenShowerLib " << this->name() << " initialized" );
120
121 return StatusCode::SUCCESS;
122}
123
124StatusCode LArG4GenShowerLib::execute(const EventContext& /*ctx*/)
125{
126 const ShowerLib::StepInfoCollection* eventStepsES = getStepInfo();
127
128 auto theParticle = getParticleFromMC();
129 if (!theParticle) {
130 ATH_MSG_ERROR ( "Couldn't get truth particle" );
131 return StatusCode::FAILURE;
132 }
133
135
136 double fraction = eventStepsES->invalid_energy/theParticle->momentum().e();
137 if (fraction > m_energyFraction) {
138 ATH_MSG_WARNING ( "Shower deposited too much energy outside the calorimeter region (" << (int)(fraction*100) << "%), ignoring" );
139 m_stat_invalid += 1;
140 return StatusCode::SUCCESS;
141 }
142 //otherwise shower is valid. even if it ultimately wont go to any library
143 m_stat_valid += 1;
144
145 ShowerLib::StepInfoList* eventSteps;
146
147 if (eventStepsES->size()>500) {
148 eventSteps = copyStepInfoZeroCleanup(eventStepsES);
149 } else {
150 eventSteps = copyStepInfo(eventStepsES);
151 }
152
153 double etot = 0.;
154 for (ShowerLib::StepInfoList::const_iterator iter = eventSteps->begin();iter != eventSteps->end();++iter) {
155 etot += (*iter)->dep();
156 }
157
158 std::stringstream location;
159
160 location << eventStepsES->detector << "/" << theParticle->pdg_id();
161
162 if (m_libraries.find(location.str()) == m_libraries.end()) {
163 ATH_MSG_WARNING ( "No library structure for " << location.str() );
164
165 for (ShowerLib::StepInfoList::iterator i(eventSteps->begin());i != eventSteps->end(); ++i) {
166 delete (*i);
167 }
168 delete eventSteps;
169 m_stat_nolib += 1;
170 return StatusCode::SUCCESS; //not really an error, just lost time
171 }
172
173 Hep3Vector origin(theParticle->production_vertex()->position().x(),
174 theParticle->production_vertex()->position().y(),
175 theParticle->production_vertex()->position().z());
176
177 // Also save direction vector. By default shower lib is created in
178 // the direction of the input particle.
179 Hep3Vector DirectionShower(theParticle->momentum().px(),
180 theParticle->momentum().py(),
181 theParticle->momentum().pz());
182 DirectionShower /= DirectionShower.mag();
183 Hep3Vector OrthoShower = DirectionShower.orthogonal();
184 OrthoShower /= OrthoShower.mag();
185 Hep3Vector CrossShower = DirectionShower.cross(OrthoShower);
186 CrossShower /= CrossShower.mag();
187
188 // Rotate the hit such that Z direction is along the shower direction
189 for (ShowerLib::StepInfoList::iterator i(eventSteps->begin()); i != eventSteps->end(); ++i) {
190 Hep3Vector HitDir = (*i)->position() - origin;
191
192 (*i)->setX(HitDir*OrthoShower);
193 (*i)->setY(HitDir*CrossShower);
194 (*i)->setZ(HitDir*DirectionShower);
195 }
196
197 ATH_MSG_VERBOSE ( "Size of input shower: " << eventSteps->size() );
198
199 clusterize(eventSteps);
200
201 ATH_MSG_VERBOSE ( "Size after clusterization: " << eventSteps->size() );
202
203 if (eventSteps->size() > 10) {
204 truncate(eventSteps);
205 ATH_MSG_VERBOSE ( "Size after truncation: " << eventSteps->size() );
206 }
207
208 double maxZ = 0, maxR = 0;
209 double edep = 0.;
210
211 double containmentEnergy = m_containmentEnergy * etot;
212
213 // sort the hits by R, make the border where 95% is deposited
215 ShowerLib::StepInfoList::const_iterator iter = eventSteps->begin();
216 for (;(iter != eventSteps->end()) && (edep < containmentEnergy);++iter) {
217 edep += (*iter)->dep();
218 maxR = (*iter)->position().r();
219 }
220
221 edep = 0.;
222 // sort the hits by Z, make the border where 95% is deposited
224 iter = eventSteps->begin();
225 for (;(iter != eventSteps->end()) && (edep < containmentEnergy);++iter) {
226 edep += (*iter)->dep();
227 maxZ = (*iter)->position().z();
228 }
229
230 ShowerLib::Shower* shower = new ShowerLib::Shower();
231 shower->setZSize(maxZ);
232 shower->setRSize(maxR);
233
234 for (ShowerLib::StepInfoList::iterator i(eventSteps->begin());i != eventSteps->end(); ++i) {
235
236 shower->push_back(new ShowerLib::ShowerEnergySpot(G4ThreeVector((*i)->x(), (*i)->y(), (*i)->z()),(*i)->dep(),(*i)->time()));
237
238 delete (*i);
239 }
240
241 delete eventSteps;
242
243 if ((*m_libraries.find(location.str())).second->storeShower(std::move(theParticle), shower)) {
244 m_stat_lib_saved[(*m_libraries.find(location.str())).second] += 1;
245 } else {
246 ATH_MSG_WARNING ( "Wasn't able to store shower (" << location.str() << ")" );
247 m_stat_lib_notsaved[(*m_libraries.find(location.str())).second] += 1;
248 }
249
250 ATH_MSG_VERBOSE ( "Successfully finished" );
251
252 return StatusCode::SUCCESS;
253}
254
256{
257 const McEventCollection* mcEvent;
258 if (evtStore()->retrieve(mcEvent,"GEN_EVENT").isFailure()) return nullptr;
259
260 // Return the last particle of the event.
261 if (mcEvent)
262 return !mcEvent->at(0)->particles().empty() ? mcEvent->at(0)->particles().back() : nullptr;
263
264 return nullptr;
265}
266
268{
269 const ShowerLib::StepInfoCollection* eventStepsES;
270 if (evtStore()->retrieve(eventStepsES, "EventSteps").isFailure()) return nullptr;
271
272 return eventStepsES;
273
274}
275
277{
279 ShowerLib::StepInfo *copy = nullptr;
280
281 for (ShowerLib::StepInfoCollection::const_iterator iter = stepinfo->begin(); iter!=stepinfo->end(); ++iter) {
282 copy = new ShowerLib::StepInfo(*(*iter));
283 rez->push_back(copy);
284 }
285
286 return rez;
287}
288
290{
292
293 const double dsame = 1.; // 1mm^2
294 ShowerLib::StepInfo *i1 = nullptr;
295 ShowerLib::StepInfo *i2 = nullptr;
296
297 for (ShowerLib::StepInfoCollection::const_iterator i = stepinfo->begin(); i!=stepinfo->end(); ++i) {
298 if(i1 == nullptr) {
299 i1 = new ShowerLib::StepInfo(*(*i));
300 rez->push_back(i1);
301 }
302 else {
303 i2 = new ShowerLib::StepInfo(*(*i));
304 // if distance below cut off, combined and erase
305 if ( (i1)->diff2(*i2) < dsame) {
306 *i1 += *i2;
307 delete i2;
308 } else {
309 rez->push_back(i2);
310 i1 = i2;
311 }
312 }
313 }
314
315 return rez;
316}
317
319{
320 typedef std::multimap<double,Dist> distMap;
321
322 distMap distances;
323
324 //fill the map
325 for (ShowerLib::StepInfoList::iterator i_h1(stepinfo->begin()); i_h1 != stepinfo->end(); ++i_h1) {
326 //iterate only the upper triangle of N*N matrix, since we do not want to create every distance twice
327 for (ShowerLib::StepInfoList::reverse_iterator i_h2(stepinfo->rbegin()); (*i_h2) != (*i_h1); ++i_h2) {
328 distances.insert(distMap::value_type((*i_h1)->diff2(**i_h2),Dist(*i_h1, *i_h2)));
329 }
330 }
331
332 const double rmin = m_maxRadius;
333
334 int cursize = stepinfo->size();
335
336
337 while (cursize > 1) {
338 distMap::iterator iter = distances.begin();
339 while ( !( (*iter).second.h1->valid() && (*iter).second.h2->valid() ) ) {
340 distances.erase(iter++); //find the first (i.e. closest) valid pair of hits, removing invalid
341 }
342
343 if ((*iter).first > rmin ) break; //if the closest already far enough - stop
344
345 ShowerLib::StepInfo* mergedHit = (*iter).second.merge(); //merge two closest hits
346
347 for (ShowerLib::StepInfoList::iterator i_h1(stepinfo->begin()); i_h1 != stepinfo->end(); ++i_h1) {
348 if ((*i_h1)->valid()){ //only for valid hits
349 distances.insert(distMap::value_type((*i_h1)->diff2(*mergedHit),Dist(*i_h1, mergedHit))); //calculate and store distances
350 }
351 }
352
353 stepinfo->push_back(mergedHit); //store the merged hit
354 cursize--; //merging == -1 valid hit
355 }
356
357 // remove invalid
358 for (ShowerLib::StepInfoList::iterator i = stepinfo->begin(); i != stepinfo->end();) {
359 if ((*i)->valid()) {
360 ++i;
361 } else {
362 delete (*i);
363 i = stepinfo->erase(i);
364 }
365 }
366
367}
368
370{
371 double etot = 0;
373
374 for (ShowerLib::StepInfoList::const_iterator i(stepinfo->begin()); i != stepinfo->end(); ++i) {
375 etot += (*i)->dep();
376 }
377
378 double minEnergy = m_minEnergy * etot;
379 double rsum = 0.;
380 ShowerLib::StepInfoList::iterator iterCut;
381 //we're continuing our cycle if (we're not at the end yet) && ( (the current hit is still inside maxDistance radius) || (the total energy still less then the threshold) )
382 for (iterCut = stepinfo->begin(); (iterCut != stepinfo->end()) && (((*iterCut)->position().mag2() < m_maxDistance) || (rsum < minEnergy));++iterCut) {
383 rsum += (*iterCut)->dep();
384 }
385
386 if (iterCut == stepinfo->end()) {
387 return;
388 }
389
390 stepinfo->erase(iterCut,stepinfo->end());
391
392 if (rsum == 0) { //WTF?
393 return;
394 }
395
396 const double inv_rsum = 1. / rsum;
397 for (iterCut = stepinfo->begin(); iterCut != stepinfo->end(); ++iterCut){
398 (*iterCut)->setE((*iterCut)->dep() * etot*inv_rsum);
399 }
400
401}
402
404{
405 char* atlasProject = getenv("AtlasProject");
406 char* atlasVersion = getenv("AtlasVersion");
407 std::string atlasReleaseTag = (atlasProject? std::string(atlasProject)+std::string("-") : std::string("Unknown-"));
408 if(atlasVersion) {
409 atlasReleaseTag += std::string(atlasVersion);
410 }
411 else {
412 atlasReleaseTag += std::string("Unknown");
413 }
414
415 // get geometry version
416 ServiceHandle<IGeoModelSvc> geoModelSvc("GeoModelSvc", this->name());
417 const auto & version = geoModelSvc->atlasVersion();
418 //
419 // get geant4 version and strip off CVS Name tag
420 std::string g4Version = G4Version;
421 size_t pos = g4Version.find("$Name: ");
422 if (pos != std::string::npos) {
423 g4Version.erase(pos, 7);
424 }
425 pos = g4Version.find(" $");
426 if (pos != std::string::npos) {
427 g4Version.erase(pos, 2);
428 }
429 libMap::iterator itr;
430 for (itr = m_libraries.begin();itr != m_libraries.end();++itr){
431 // release
432 (*itr).second->release(atlasReleaseTag);
433 (*itr).second->geometry(version);
434 // get Physics list
435 (*itr).second->physicsList(m_physicslist_name);
436 //
437 (*itr).second->geantVersion(g4Version);
438 }
439}
440
441
443{
444
445 // add condition tags
447
448 libMap::iterator itr;
449 for (itr = m_libraries_by_filename.begin();itr != m_libraries_by_filename.end();++itr){
450 ATH_MSG_DEBUG ( "Writing shower library to file " << (*itr).first );
451
452 TFile libr((*itr).first.c_str(),"RECREATE");
453
454 if (!(*itr).second->writeToROOT(&libr)) {
455 ATH_MSG_ERROR ( "Wasn't able to write " << (*itr).first << ". Probably empty lib." );
456 }
457
458 libr.Close();
459 }
460 if (m_stat_numshowers> 0) {
461 ATH_MSG_DEBUG ( "********Statistics for GenShowerLib********" );
462 ATH_MSG_DEBUG ( "Total number of showers: " << m_stat_numshowers
463 << ", valid: "<< m_stat_valid << " (" << (m_stat_valid*100)/m_stat_numshowers << "%)"
464 << ", invalid: " << m_stat_invalid << " (" << (m_stat_invalid*100)/m_stat_numshowers << "%)" );
465 for (itr = m_libraries.begin();itr != m_libraries.end();++itr){
466 ATH_MSG_DEBUG ( "*******************************************" );
467 std::stringstream ss((*itr).second->statistics());
468 for(std::string line; std::getline(ss,line);)
469 ATH_MSG_DEBUG ( line );
470 ATH_MSG_DEBUG ( "Saved: " << m_stat_lib_saved[(*itr).second] << " Rejected: " << m_stat_lib_notsaved[(*itr).second] );
471 }
472 ATH_MSG_DEBUG ( "*******************************************" );
473 ATH_MSG_DEBUG ( "Showers with no corresponding library: " << m_stat_nolib << " (" << (m_stat_nolib*100)/m_stat_numshowers << "%)" );
474 }
475 ATH_MSG_DEBUG ( "Finalized." );
476
477 return StatusCode::SUCCESS;
478}
479
480
482 double& weights, double& xavfra, double& yavfra, double& ravfra)
483{
484 double escal(0.);
485 double xav(0.), yav(0.), xav2(0.), yav2(0.);
486
487 for (ShowerLib::StepInfoCollection::const_iterator i=eventSteps.begin();i<eventSteps.end(); ++i) {
488 escal += (*i)->dep();
489 xav += (*i)->x()*(*i)->dep();
490 yav += (*i)->y()*(*i)->dep();
491 xav2 += (*i)->x()*(*i)->x()*(*i)->dep();
492 yav2 += (*i)->y()*(*i)->y()*(*i)->dep();
493 }
494
495 // Center of gravity:
496 const double inv_escal = escal == 0 ? 1 : 1. / escal;
497 xavfra = xav*inv_escal;
498 yavfra = yav*inv_escal;
499 // Second momentum:
500 ravfra = std::sqrt(std::abs((xav2*inv_escal-xavfra*xavfra) +
501 (yav2*inv_escal-yavfra*yavfra)));
502 // energy is used as weights
503 weights = escal;
504
505 return;
506}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t ss
ServiceHandle< StoreGateSvc > & evtStore()
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
const T * at(size_type n) const
Access an element, as an rvalue.
const_iterator end() const noexcept
Return a const_iterator pointing past the end of the collection.
const_iterator begin() const noexcept
Return a const_iterator pointing at the beginning of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
ShowerLib::StepInfo * merge()
ShowerLib::StepInfo * h1
ShowerLib::StepInfo * h2
Dist(ShowerLib::StepInfo *the_h1, ShowerLib::StepInfo *the_h2)
virtual StatusCode initialize() override
StringArrayProperty m_lib_struct_files
void addingTagsToLibrary()
adding tag information (release, detector description, ...) to library comment
libMap m_libraries
pointer to shower library
DoubleProperty m_containmentEnergy
property, see LArG4GenShowerLib::LArG4GenShowerLib
DoubleProperty m_energyFraction
property, see LArG4GenShowerLib::LArG4GenShowerLib
StringProperty m_physicslist_name
std::map< ShowerLib::IShowerLib *, int > m_stat_lib_notsaved
void truncate(ShowerLib::StepInfoList *stepinfo)
std::map< ShowerLib::IShowerLib *, int > m_stat_lib_saved
void clusterize(ShowerLib::StepInfoList *stepinfo)
DoubleProperty m_maxDistance
property, see LArG4GenShowerLib::LArG4GenShowerLib
void calculateMoments(const ShowerLib::StepInfoCollection &eventSteps, double &weights, double &xavfra, double &yavfra, double &ravfra)
calculate moments from StepInfoCollection
DoubleProperty m_minEnergy
property, see LArG4GenShowerLib::LArG4GenShowerLib
ShowerLib::StepInfoList * copyStepInfo(const ShowerLib::StepInfoCollection *stepinfo)
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
DoubleProperty m_maxRadius
property, see LArG4GenShowerLib::LArG4GenShowerLib
HepMC::ConstGenParticlePtr getParticleFromMC()
return first MC truth particle for event
virtual StatusCode finalize() override
const ShowerLib::StepInfoCollection * getStepInfo()
ShowerLib::StepInfoList * copyStepInfoZeroCleanup(const ShowerLib::StepInfoCollection *stepinfo)
This defines the McEventCollection, which is really just an ObjectVector of McEvent objectsFile: Gene...
Class for shower library shower lib interface.
Definition IShowerLib.h:40
virtual int particle_id() const
get particle tag
Definition IShowerLib.h:124
virtual const std::string detector() const
get detector tag
Definition IShowerLib.h:121
Class for shower library shower.
Definition Shower.h:36
void setZSize(const float zsize)
Definition Shower.h:64
void setRSize(const float rsize)
Definition Shower.h:65
Class for collection of StepInfo class (G4 hits).
Class to collect information about G4 steps.
Definition StepInfo.h:35
bool sortFunction(const ShowerLib::StepInfo *first, const ShowerLib::StepInfo *second, const CompareType type) const
stepInfoDistCompare(const CompareType type)
bool operator()(const ShowerLib::StepInfo *first, const ShowerLib::StepInfo *second) const
HepMC3::ConstGenParticlePtr ConstGenParticlePtr
Definition GenParticle.h:20
IShowerLib * iterateStruct(const std::string &fname)
std::list< StepInfo * > StepInfoList