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