ATLAS Offline Software
PunchThroughTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // class header
6 #include "PunchThroughTool.h"
7 
8 // standard C++ libraries
9 #include <iostream>
10 #include <sstream>
11 #include <string>
12 #include <algorithm>
13 #include <vector>
14 #include <numeric>
15 #include <string_view>
16 #include <charconv>
17 
18 // standard C libraries
19 #include <cmath>
20 
21 // Control
23 
24 // HepMC
26 #include "AtlasHepMC/GenVertex.h"
27 #include "AtlasHepMC/GenParticle.h"
28 #include "AtlasHepMC/GenEvent.h"
29 #include "HepPDT/ParticleDataTable.hh"
31 
32 // CLHEP
33 #include "CLHEP/Random/RandFlat.h"
34 
35 // ROOT
36 #include "TFile.h"
37 #include "TH2F.h"
38 #include "TAxis.h"
39 #include "TH1.h"
40 #include "TMath.h"
41 #include "TROOT.h"
42 #include "TKey.h"
43 #include "TClass.h"
44 
45 // PathResolver
47 
48 //ISF
49 #include "ISF_Event/ISFParticle.h"
50 #include "PDFcreator.h"
51 #include "PunchThroughParticle.h"
52 
53 //Amg
55 
56 
57 /*=========================================================================
58  * DESCRIPTION OF FUNCTION:
59  * ==> see headerfile
60  *=======================================================================*/
61 
63  const std::string& name,
64  const IInterface* parent )
65 : base_class(type, name, parent)
66 {
67 }
68 
69 /*=========================================================================
70  * DESCRIPTION OF FUNCTION:
71  * ==> see headerfile
72  *=======================================================================*/
73 
75 {
76  ATH_MSG_DEBUG( "initialize()" );
77 
78  // initialise punch through classifier
79  if (m_punchThroughClassifier.retrieve().isFailure() )
80  {
81  ATH_MSG_ERROR (m_punchThroughClassifier.propertyName() << ": Failed to retrieve tool " << m_punchThroughClassifier.type());
82  return StatusCode::FAILURE;
83  }
84 
85  // resolving lookuptable file
86  std::string resolvedFileName = PathResolverFindCalibFile (m_filenameLookupTable);
87  if (resolvedFileName.empty()) {
88  ATH_MSG_ERROR( "[ punchthrough ] Parametrisation file '" << m_filenameLookupTable << "' not found" );
89  return StatusCode::FAILURE;
90  }
91  ATH_MSG_INFO( "[ punchthrough ] Parametrisation file found: " << resolvedFileName );
92 
93  // open the LookupTable file
94  m_fileLookupTable = new TFile( resolvedFileName.c_str(), "READ");
95  if (!m_fileLookupTable) {
96  ATH_MSG_WARNING("[ punchthrough ] unable to open the lookup-table for the punch-through simulation (file does not exist)");
97  return StatusCode::FAILURE;
98  }
99 
100  if (!m_fileLookupTable->IsOpen()) {
101  ATH_MSG_WARNING("[ punchthrough ] unable to open the lookup-table for the punch-through simulation (wrong or empty file?)");
102  return StatusCode::FAILURE;
103  }
104 
105  //retrieve inverse CDF config file
106  if (!initializeInverseCDF(PathResolverFindCalibFile(m_filenameInverseCDF)))
107  {
108  ATH_MSG_WARNING("[ punchthrough ] unable to open or read the inverse CDF config");
109  return StatusCode::FAILURE;
110  }
111 
112  //retrieve inverse PCA config file
113  if (!initializeInversePCA(PathResolverFindCalibFile(m_filenameInversePCA)))
114  {
115  ATH_MSG_WARNING("[ punchthrough ] unable to open or read the inverse PCA config");
116  return StatusCode::FAILURE;
117  }
118 
119  //check first the size of infoMap for both PCA and CDF, they should be equal
120  if (!(m_xml_info_pca.size() == m_xml_info_cdf.size()))
121  {
122  ATH_MSG_WARNING("[ punchthrough ] size of infoMap for PCA and CDF differs! Something is wrong with input xml files.");
123  return StatusCode::FAILURE;
124  }
125 
126  // retrieve the ParticleProperties handle
127  ATH_CHECK( m_particlePropSvc.retrieve() );
128 
129  // and the particle data table
130  m_particleDataTable = m_particlePropSvc->PDT();
131  if (!m_particleDataTable)
132  {
133  ATH_MSG_FATAL( " [ punchthrough ] Could not get ParticleDataTable! Cannot associate pdg code with charge! Abort. " );
134  return StatusCode::FAILURE;
135  }
136 
137  // Geometry identifier service
138  if ( !m_geoIDSvc.empty() && m_geoIDSvc.retrieve().isFailure())
139  {
140  ATH_MSG_FATAL ( "[ punchthrough ] Could not retrieve GeometryIdentifier Service. Abort");
141  return StatusCode::FAILURE;
142  }
143 
144  //envelope definition service
145  if (m_envDefSvc.retrieve().isFailure() )
146  {
147  ATH_MSG_ERROR( "[ punchthrough ] Could not retrieve " << m_envDefSvc );
148  return StatusCode::FAILURE;
149  }
150 
151  //--------------------------------------------------------------------------------
152  // register all the punch-through particles which will be simulated
153  for ( unsigned int num = 0; num < m_punchThroughParticles.size(); num++ )
154  {
155  const int pdg = m_punchThroughParticles[num];
156  // if no information is given on the creation of anti-particles -> do not simulate anti-particles
157  const bool doAnti = ( num < m_doAntiParticles.size() ) ? m_doAntiParticles[num] : false;
158  // if no information is given on the minimum energy -> take 50. MeV as default
159  const double minEnergy = ( num < m_minEnergy.size() ) ? m_minEnergy[num] : 50.;
160  // if no information is given on the maximum number of punch-through particles -> take -1 as default
161  const int maxNum = ( num < m_minEnergy.size() ) ? m_maxNumParticles[num] : -1;
162  // if no information is given on the scale factor for the number of particles -> take 1. as defaulft
163  const double numFactor = ( num < m_numParticlesFactor.size() ) ? m_numParticlesFactor[num] : 1.;
164  // if no information is given on the position angle factor -> take 1.
165  const double posAngleFactor = ( num < m_posAngleFactor.size() ) ? m_posAngleFactor[num] : 1.;
166  // if no information is given on the momentum angle factor -> take 1.
167  const double momAngleFactor = ( num < m_momAngleFactor.size() ) ? m_momAngleFactor[num] : 1.;
168  // if no information is given on the scale factor for the energy -> take 1. as default
169  const double energyFactor = ( num < m_energyFactor.size() ) ? m_energyFactor[num] : 1.;
170 
171  // register the particle
172  ATH_MSG_VERBOSE("[ punchthrough ] registering punch-through particle type with pdg = " << pdg );
173  if ( registerParticle( pdg, doAnti, minEnergy, maxNum, numFactor, energyFactor, posAngleFactor, momAngleFactor )
174  != StatusCode::SUCCESS)
175  {
176  ATH_MSG_ERROR("[ punchthrough ] unable to register punch-through particle type with pdg = " << pdg);
177  }
178  }
179 
180  // TODO: implement punch-through parameters for different m_pdgInitiators
181  // currently m_pdgInitiators is only used to filter out particles
182 
183  // check if more correlations were given than particle types were registered
184  unsigned int numCorrelations = m_correlatedParticle.size();
185  if ( numCorrelations > m_punchThroughParticles.size() )
186  {
187  ATH_MSG_WARNING("[ punchthrough ] more punch-through particle correlations are given, than punch-through particle types are registered (skipping the last ones)");
188  numCorrelations = m_punchThroughParticles.size();
189  }
190 
191  // now register correlation between particles
192  for ( unsigned int num = 0; num < numCorrelations; num++ )
193  {
194  const int pdg1 = m_punchThroughParticles[num];
195  const int pdg2 = m_correlatedParticle[num];
196  const double fullCorrEnergy = ( num < m_fullCorrEnergy.size() ) ? m_fullCorrEnergy[num] : 0.;
197  const double minCorrEnergy = ( num < m_minCorrEnergy.size() ) ? m_minCorrEnergy[num] : 0.;
198 
199  // if correlatedParticle==0 is given -> no correlation
200  if ( ! pdg2) continue;
201  // register it
202  if ( registerCorrelation(pdg1, pdg2, minCorrEnergy, fullCorrEnergy) != StatusCode::SUCCESS )
203  {
204  ATH_MSG_ERROR("[ punchthrough ] unable to register punch-through particle correlation for pdg1=" << pdg1 << " pdg2=" << pdg2 );
205  }
206  }
207 
208  // get the calo-MS border coordinates. Look at calo and MS geometry definitions, if same R and Z -> boundary surface
209 
210  const RZPairVector* rzMS = &(m_envDefSvc->getMuonRZBoundary());
211  const RZPairVector* rzCalo = &(m_envDefSvc->getCaloRZBoundary());
212 
213  bool found1, found2;
214  found1=false; found2=false;
215 
216  for ( size_t i=0; i<rzCalo->size();++i)
217  {
218  const double r_tempCalo = rzCalo->at(i).first;
219  const double z_tempCalo = rzCalo->at(i).second;
220 
221  if (r_tempCalo> m_beamPipe)
222  {
223  for ( size_t j=0; j<rzMS->size();++j)
224  {
225  const double r_tempMS =rzMS->at(j).first;
226  const double z_tempMS =rzMS->at(j).second;
227 
228  if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && found1==false )
229  {
230  m_R1=r_tempMS;
231  m_z1=std::fabs(z_tempMS);
232  found1=true;
233  continue;
234  }
235  else if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && r_tempCalo!=m_R1 && std::fabs(z_tempCalo)!=m_z1)
236  {
237  m_R2=r_tempMS;
238  m_z2=std::fabs(z_tempMS);
239  found2=true;
240  }
241  }
242 
243  if (found1==true && found2==true) break;
244  }
245  }
246 
247  //in case geometry description changes
248  if (found1 == false) ATH_MSG_ERROR ("first coordinate of calo-MS border not found");
249  if (found2 == false) ATH_MSG_ERROR ("second coordinate of calo-MS border not found; first one is: R1 ="<<m_R1<<" z1 ="<<m_z1);
250 
251  //now order the found values
252  double r_temp, z_temp;
253  if (m_R1>m_R2) { r_temp=m_R1; m_R1=m_R2; m_R2=r_temp; } //m_R1 - smaller one
254  if (m_z1<m_z2) { z_temp=m_z1; m_z1=m_z2; m_z2=z_temp; } //m_z1 - bigger one
255 
256  if (m_R1==m_R2 || m_z1==m_z2) ATH_MSG_ERROR ("[punch-though] Bug in propagation calculation! R1="<<m_R1<<" R2 = "<<m_R2<<" z1="<<m_z1<<" z2= "<<m_z2 );
257  else ATH_MSG_DEBUG ("calo-MS boundary coordinates: R1="<<m_R1<<" R2 = "<<m_R2<<" z1="<<m_z1<<" z2= "<<m_z2);
258 
259  // close the file with the lookuptable
260  m_fileLookupTable->Close();
261 
262  ATH_MSG_INFO( "punchthrough initialization is successful" );
263  return StatusCode::SUCCESS;
264 }
265 
266 /*=========================================================================
267  * DESCRIPTION OF FUNCTION:
268  * ==> see headerfile
269  *=======================================================================*/
270 
272 {
273  ATH_MSG_DEBUG( "[punchthrough] finalize() starting" );
274  for(auto & each : m_particles) {
275  delete each.second;
276  }
277 
278  ATH_MSG_DEBUG( "[punchthrough] finalize() successful" );
279 
280  return StatusCode::SUCCESS;
281 }
282 
283 /*=========================================================================
284  * DESCRIPTION OF FUNCTION:
285  * ==> see headerfile
286  *=======================================================================*/
287 
288 const ISF::ISFParticleVector* ISF::PunchThroughTool::computePunchThroughParticles(const ISF::ISFParticle &isfp, const TFCSSimulationState& simulstate, CLHEP::HepRandomEngine* rndmEngine) const
289 {
290  ATH_MSG_DEBUG( "[ punchthrough ] starting punch-through simulation");
291 
292  // create output particle collection
293  auto isfpCont = std::make_unique<ISF::ISFParticleVector>();
294 
295  ATH_MSG_VERBOSE("[ punchthrough ] position of the input particle: r"<<isfp.position().perp()<<" z= "<<isfp.position().z() );
296 
297  //check if it points to the calorimeter - if not, don't simulate
298 
299  if ( m_geoIDSvc->identifyNextGeoID(isfp) != AtlasDetDescr::fAtlasCalo)
300  {
301  ATH_MSG_VERBOSE ("[ GeoIDSvc ] input particle doesn't point to calorimeter"<< "Next GeoID: "<<m_geoIDSvc->identifyNextGeoID(isfp) );
302  return nullptr;
303  }
304 
305 
306  // check if the particle's pdg is registered as a punch-through-causing type
307  {
308  std::vector<int>::const_iterator pdgIt = m_pdgInitiators.begin();
309  std::vector<int>::const_iterator pdgItEnd = m_pdgInitiators.end();
310 
311  std::vector<int>::const_iterator minEnergyIt = m_initiatorsMinEnergy.begin();
312  // loop over all known punch-through initiators
313  for ( ; pdgIt != pdgItEnd; ++pdgIt, ++minEnergyIt)
314  {
315  if (std::abs(isfp.pdgCode()) == *pdgIt){
316  if(std::sqrt( isfp.momentum().mag2() + isfp.mass()*isfp.mass() ) < *minEnergyIt){
317  ATH_MSG_DEBUG("[ punchthrough ] particle does not meet initiator min energy requirement. Dropping it in the calo.");
318  return nullptr;
319  }
320  break;
321  }
322  }
323 
324  // particle will not cause punch-through -> bail out
325  if (pdgIt == pdgItEnd)
326  {
327  ATH_MSG_DEBUG("[ punchthrough ] particle is not registered as punch-through initiator. Dropping it in the calo.");
328  return nullptr;
329  }
330  }
331 
332  if(isfp.position().eta() < m_initiatorsEtaRange.value().at(0) || isfp.position().eta() > m_initiatorsEtaRange.value().at(1) ){
333  ATH_MSG_DEBUG("[ punchthrough ] particle does not meet initiator eta range requirement. Dropping it in the calo.");
334  return nullptr;
335  }
336 
337  //Calculate probability of punch through using punchThroughClassifier
338  double punchThroughProbability = m_punchThroughClassifier->computePunchThroughProbability(isfp, simulstate);
339 
340  //Draw random number to compare to probability
341  double punchThroughClassifierRand = CLHEP::RandFlat::shoot(rndmEngine);
342 
343  ATH_MSG_DEBUG("[ punchthrough ] punchThroughProbability output: " << punchThroughProbability << " RandFlat: " << punchThroughClassifierRand );
344 
345  //If probability < random number then don't simulate punch through
346  if( punchThroughClassifierRand > punchThroughProbability){
347  ATH_MSG_DEBUG("[ punchthrough ] particle not classified to create punch through. Dropping it in the calo.");
348  return nullptr;
349  }
350 
351  //if initial particle is on ID surface, points to the calorimeter, is a punch-through initiator, meets initiator min enery and eta range
352 
353  // this is the place where the magic is done:
354  // test for each registered punch-through pdg if a punch-through
355  // occures and create these particles
356  // -> therefore loop over all registered pdg ids
357  // to keep track of the correlated particles which were already simulated:
358  // first int is pdg, second int is number of particles created
359 
360  // calculate incoming energy and eta
361  const double initEnergy = std::sqrt( isfp.momentum().mag2() + isfp.mass()*isfp.mass() );
362  const double initEta = isfp.position().eta();
363 
364  // interpolate energy and eta
365  const double interpEnergy = interpolateEnergy(initEnergy, rndmEngine);
366  const double interpEta = interpolateEta(initEta, rndmEngine);
367 
368  std::map<int, int> corrPdgNumDone;
369 
370  int maxTries = 10;
371  int nTries = 0;
372 
373  // loop over all particle pdgs
374  while(isfpCont->empty() && nTries < maxTries) { //ensure we always create at least one punch through particle, maxTries to catch very rare cases
375 
376  for (const auto& currentParticle : m_particles)
377  {
378  // the pdg that is currently treated
379  int doPdg = currentParticle.first;
380  // get the current particle's correlated pdg
381  int corrPdg = currentParticle.second->getCorrelatedPdg();
382 
383  // if there is a correlated particle type to this one
384  if (corrPdg)
385  {
386  // find out if the current pdg was already simulated
387  std::map<int,int>::iterator pos = corrPdgNumDone.find(doPdg);
388  // if the current pdg was not simulated yet, find out if
389  // it's correlated one was simulated
390  if ( pos == corrPdgNumDone.end() ) pos = corrPdgNumDone.find(corrPdg);
391 
392  // neither this nor the correlated particle type was simulated
393  // so far:
394  if ( pos == corrPdgNumDone.end() )
395  {
396  // -> roll a dice if we create this particle or its correlated one
397  if ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) doPdg = corrPdg;
398  // now create the particles with the given pdg and note how many
399  // particles of this pdg are created
400  corrPdgNumDone[doPdg] = getAllParticles(isfp, *isfpCont, rndmEngine, doPdg, interpEnergy, interpEta);
401  }
402 
403  // one of the two correlated particle types was already simulated
404  // 'pos' points to the already simulated one
405  else
406  {
407  // get the pdg of the already simulated particle and the number
408  // of these particles that were created
409  const int donePdg = pos->first;
410  const int doneNumPart = pos->second;
411  // set the pdg of the particle type that will be done
412  if (donePdg == doPdg) doPdg = corrPdg;
413 
414  // now create the correlated particles
415  getCorrelatedParticles(isfp, *isfpCont, doPdg, doneNumPart, rndmEngine, interpEnergy, interpEta);
416  // note: no need to take note, that this particle type is now simulated,
417  // since this is the second of two correlated particles, which is
418  // simulated and we do not have correlations of more than two particles.
419  }
420 
421  // if no correlation for this particle
422  // -> directly create all particles with the current pdg
423  }
424  else getAllParticles(isfp, *isfpCont, rndmEngine, doPdg, interpEnergy, interpEta);
425 
426  } // for-loop over all particle pdgs
427 
428  nTries++;
429  }
430 
431  if (!isfpCont->empty()) ATH_MSG_DEBUG( "[ punchthrough ] returning ISFparticle vector , size: "<<isfpCont->size() );
432 
433  for (ISF::ISFParticle *particle : *isfpCont) {
434  ATH_MSG_DEBUG("codes of produced punch through particle: pdg = "<< particle->pdgCode());
435  Amg::Vector3D position = particle->position();
436  ATH_MSG_DEBUG("position of produced punch-through particle: x = "<< position.x() <<" y = "<< position.y() <<" z = "<< position.z());
437  Amg::Vector3D momentum = particle->momentum();
438  ATH_MSG_DEBUG("momentum of produced punch-through particle: px = "<< momentum.x() <<" py = "<< momentum.x() <<" pz = "<< momentum.x() <<" e = "<< particle->ekin() << " mass = " << particle->mass());
439  }
440 
441  return isfpCont.release();
442 }
443 
444 /*=========================================================================
445  * DESCRIPTION OF FUNCTION:
446  * ==> see headerfile
447  *=======================================================================*/
448 int ISF::PunchThroughTool::getAllParticles(const ISF::ISFParticle &isfp, ISFParticleVector& isfpCont, CLHEP::HepRandomEngine* rndmEngine, int pdg, double interpEnergy, double interpEta, int numParticles) const
449 {
450 
451  // get the current particle
452  PunchThroughParticle *p = m_particles.at(pdg);
453 
454  // if no number of particles (=-1) was handed over as an argument
455  // -> get the number of particles from the pdf
456  if ( numParticles < 0 )
457  {
458  // prepare the function arguments for the PDFcreator class
459  std::vector<int> parameters;
460  parameters.push_back( std::round(interpEnergy) );
461  parameters.push_back( std::round(interpEta*100) );
462  // the maximum number of particles which should be produced
463  // if no maximum number is given, this is -1
464  int maxParticles = p->getMaxNumParticles();
465 
466  // get the right number of punch-through particles
467  // and ensure that we do not create too many particles
468  do
469  {
470  numParticles = int( p->getNumParticlesPDF()->getRand(rndmEngine, parameters) );
471 
472  // scale the number of particles if requested
473  numParticles = lround( numParticles *= p->getNumParticlesFactor() );
474  }
475  while ( (maxParticles >= 0.) && (numParticles > maxParticles) );
476  }
477 
478  ATH_MSG_VERBOSE("[ punchthrough ] adding " << numParticles << " punch-through particles with pdg " << pdg);
479 
480  // now create the exact number of particles which was just computed before
481  double energyRest = std::sqrt( isfp.momentum().mag2() + isfp.mass()*isfp.mass() );
482  double minEnergy = p->getMinEnergy();
483  int numCreated = 0;
484 
485  for ( numCreated = 0; (numCreated < numParticles) && (energyRest > minEnergy); numCreated++ )
486  {
487  // create one particle which fullfills the right energy distribution
488  ISF::ISFParticle *par = getOneParticle(isfp, pdg, rndmEngine, interpEnergy, interpEta);
489 
490  // if something went wrong
491  if (!par)
492  {
493  ATH_MSG_ERROR("[ punchthrough ] something went wrong while creating punch-through particles");
494  return 0;
495  }
496 
497  // get the energy of the particle which was just created
498  const double restMass = m_particleDataTable->particle(std::abs(pdg))->mass();
499  double curEnergy = std::sqrt(par->momentum().mag2() + restMass*restMass);
500 
501  // calculate the maximum energy to be available for all
502  // following punch-through particles created
503  energyRest -= curEnergy;
504 
505  // add this ISFparticle to the vector
506  isfpCont.push_back( par );
507  }
508 
509  // the number of particles which was created is numCreated
510  return (numCreated);
511 }
512 
513 /*=========================================================================
514  * DESCRIPTION OF FUNCTION:
515  * ==> see headerfile
516  *=======================================================================*/
517 
518 int ISF::PunchThroughTool::getCorrelatedParticles(const ISF::ISFParticle &isfp, ISFParticleVector& isfpCont, int pdg, int corrParticles, CLHEP::HepRandomEngine* rndmEngine, double interpEnergy, double interpEta) const
519 {
520  // get the PunchThroughParticle class
521  PunchThroughParticle *p = m_particles.at(pdg);
522 
523  const double initEnergy = std::sqrt( isfp.momentum().mag2() + isfp.mass()*isfp.mass() );
524 
525  // (1.) decide if we do correlation or not
526  double rand = CLHEP::RandFlat::shoot(rndmEngine)
527  *(p->getFullCorrelationEnergy()-p->getMinCorrelationEnergy())
528  + p->getMinCorrelationEnergy();
529  if ( initEnergy < rand )
530  {
531  // here we do not do correlation
532  return getAllParticles(isfp, isfpCont, rndmEngine, pdg, interpEnergy, interpEta);
533  }
534 
535  // (2.) if this point is reached, we do correlation
536  // decide which 2d correlation histogram to use
537  double *histDomains = p->getCorrelationHistDomains();
538  TH2F *hist2d = nullptr;
539  // compute the center values of the lowE and highE
540  // correlation histogram domains
541  if ( initEnergy < histDomains[1])
542  {
543  // initial energy lower than border between lowEnergy and highEnergy histogram domain
544  // --> choose lowEnergy correlation histogram
545  hist2d = p->getCorrelationLowEHist();
546  }
547  else
548  {
549  double rand = CLHEP::RandFlat::shoot(rndmEngine)*(histDomains[2]-histDomains[1])
550  + histDomains[1];
551  hist2d = ( initEnergy < rand) ? p->getCorrelationLowEHist()
552  : p->getCorrelationHighEHist();
553  }
554 
555  // get the correlation 2d histogram
556 
557  // now find out where on the x-axis the the bin for number of
558  // correlated particles is
559  Int_t xbin = hist2d->GetXaxis()->FindFixBin(corrParticles);
560  int numParticles = 0;
561  int maxParticles = p->getMaxNumParticles();
562  // now the distribution along the y-axis is a PDF for the number
563  // of 'pdg' particles
564  do
565  {
566  double rand = CLHEP::RandFlat::shoot(rndmEngine);
567  double sum = 0.;
568  for ( int ybin = 1; ybin <= hist2d->GetNbinsY(); ybin++ )
569  {
570  sum += hist2d->GetBinContent(xbin, ybin);
571  // check if we choose the current bin or not
572  if ( sum >= rand )
573  {
574  numParticles = ybin - 1;
575  break;
576  }
577  }
578  // scale the number of particles is requested
579  numParticles = lround( numParticles * p->getNumParticlesFactor() );
580  }
581  while ( (maxParticles >= 0.) && (numParticles > maxParticles) );
582 
583  // finally create this exact number of particles
584  return getAllParticles(isfp, isfpCont, rndmEngine, pdg, interpEnergy, interpEta, numParticles);
585 }
586 
587 /*=========================================================================
588  * DESCRIPTION OF FUNCTION:
589  * ==> see headerfile
590  *=======================================================================*/
591 
592 ISF::ISFParticle *ISF::PunchThroughTool::getOneParticle(const ISF::ISFParticle &isfp, int pdg, CLHEP::HepRandomEngine* rndmEngine, double interpEnergy, double interpEta) const
593 {
594  // get a local copy of the needed punch-through particle class
595  PunchThroughParticle *p = m_particles.at(pdg);
596 
597  // (0.) get the pca / cdf group based on pdgId and eta, eta times 100, e.g eta -4 to 4 is from eta -400 to 400
598  int pcaCdfIterator = passedParamIterator(pdg, interpEta*100, m_xml_info_pca); //pca and cdf info should be of same size
599 
600  ATH_MSG_DEBUG("[ punchthrough ] passedPCAIterator ==> pcaCdfIterator = "<< pcaCdfIterator <<" , pdg = "<< pdg <<" , interpEnergy = "<< interpEnergy <<" MeV, interpEta(*100) = "<< interpEta*100);
601 
602  // (1.) decide if we create a particle or an anti-particle
603  int anti = 1;
604  if ( p->getdoAnti() )
605  {
606  // get a random-value
607  double rand = CLHEP::RandFlat::shoot(rndmEngine);
608  // 50/50 chance to be a particle or its anti-particle
609  if (rand > 0.5) anti = -1;
610  }
611 
612  // (2.) get the right punch-through distributions
613  // prepare the function arguments for the PDFcreator class
614  std::vector<int> parInitEnergyEta;
615  parInitEnergyEta.push_back( std::round(interpEnergy) );
616  parInitEnergyEta.push_back( std::round(interpEta*100) );
617 
618  //initialise variables to store punch through particle kinematics
619  double energy = 0.;
620  double deltaTheta = 0.;
621  double deltaPhi = 0.;
622  double momDeltaTheta = 0.;
623  double momDeltaPhi = 0.;
624 
625  double principal_component_0 = 0.;
626  double principal_component_1 = 0.;
627  double principal_component_2 = 0.;
628  double principal_component_3 = 0.;
629  double principal_component_4 = 0.;
630  std::vector<double> transformed_variables;
631 
632 
633  principal_component_0 = p->getPCA0PDF()->getRand(rndmEngine, parInitEnergyEta);
634  principal_component_1 = p->getPCA1PDF()->getRand(rndmEngine, parInitEnergyEta);
635  principal_component_2 = p->getPCA2PDF()->getRand(rndmEngine, parInitEnergyEta);
636  principal_component_3 = p->getPCA3PDF()->getRand(rndmEngine, parInitEnergyEta);
637  principal_component_4 = p->getPCA4PDF()->getRand(rndmEngine, parInitEnergyEta);
638 
639  ATH_MSG_DEBUG("Drawn punch through kinematics PCA components: PCA0 = "<< principal_component_0 <<" PCA1 = "<< principal_component_1 <<" PCA2 = "<< principal_component_2 <<" PCA3 = "<< principal_component_3 <<" PCA4 = "<< principal_component_4 );
640 
641  std::vector<double> principal_components {
642  principal_component_0,
643  principal_component_1,
644  principal_component_2,
645  principal_component_3,
646  principal_component_4
647  };
648 
649  transformed_variables = inversePCA(pcaCdfIterator,principal_components);
650 
651  energy = inverseCdfTransform(transformed_variables.at(0), m_variable0_inverse_cdf[pcaCdfIterator]);
652  deltaTheta = inverseCdfTransform(transformed_variables.at(1), m_variable1_inverse_cdf[pcaCdfIterator]);
653  deltaPhi = inverseCdfTransform(transformed_variables.at(2), m_variable2_inverse_cdf[pcaCdfIterator]);
654  momDeltaTheta = inverseCdfTransform(transformed_variables.at(3), m_variable3_inverse_cdf[pcaCdfIterator]);
655  momDeltaPhi = inverseCdfTransform(transformed_variables.at(4), m_variable4_inverse_cdf[pcaCdfIterator]);
656 
657  ATH_MSG_DEBUG("Transformed punch through kinematics: energy = "<< energy <<" MeV deltaTheta = "<< deltaTheta <<" deltaPhi = "<< deltaPhi <<" momDeltaTheta = "<< momDeltaTheta <<" momDeltaPhi = "<< momDeltaPhi );
658 
659  energy *= p->getEnergyFactor(); // scale the energy if requested
660  if (energy < p->getMinEnergy()) {
661  energy = p->getMinEnergy() + 10;
662  }
663 
664 
665  // (2.2) get the particles delta theta relative to the incoming particle
666  double theta = 0;
667  // loop to keep theta within range [0,PI]
668  do
669  {
670  // decide if delta positive/negative
671  deltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
672  // calculate the exact theta value of the later created
673  // punch-through particle
674  theta = isfp.position().theta() + deltaTheta*p->getPosAngleFactor();
675 
676  }
677  while ( (theta > M_PI) || (theta < 0.) );
678  // (2.3) get the particle's delta phi relative to the incoming particle
679 
680  deltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
681 
682  // keep phi within range [-PI,PI]
683  double phi = isfp.position().phi() + deltaPhi*p->getPosAngleFactor();
684  while ( std::fabs(phi) > 2*M_PI) phi /= 2.;
685  while (phi > M_PI) phi -= 2*M_PI;
686  while (phi < -M_PI) phi += 2*M_PI;
687 
688  // (2.4) get the particle momentum delta theta, relative to its position
689  //
690  // loop to keep momTheta within range [0,PI]
691 
692  double momTheta = 0.;
693  do
694  {
695  // decide if delta positive/negative
696  momDeltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
697  // calculate the exact momentum theta value of the later created
698  // punch-through particle
699  momTheta = theta + momDeltaTheta*p->getMomAngleFactor();
700 
701  }
702  while ( (momTheta > M_PI) || (momTheta < 0.) );
703 
704  // (2.5) get the particle momentum delta phi, relative to its position
705 
706  momDeltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
707 
708  double momPhi = phi + momDeltaPhi*p->getMomAngleFactor();
709  // keep momPhi within range [-PI,PI]
710  while ( std::fabs(momPhi) > 2*M_PI) momPhi /= 2.;
711  while (momPhi > M_PI) momPhi -= 2*M_PI;
712  while (momPhi < -M_PI) momPhi += 2*M_PI;
713 
714  // (**) finally create the punch-through particle as a ISFParticle
715 
716  ATH_MSG_DEBUG("createExitPs input parameters: doAnti? = "<< pdg*anti <<" energy = "<< energy <<" theta = "<< theta <<" phi = "<< phi <<" momTheta = "<< momTheta << " momPhi " << momPhi );
717 
718 
719  ISF::ISFParticle *par = createExitPs( isfp, pdg*anti, energy, theta, phi, momTheta, momPhi);
720 
721  return par;
722 }
723 
725 
726  return 0.5 * TMath::Erfc(-x * M_SQRT1_2);
727 }
728 
729 std::vector<double> ISF::PunchThroughTool::dotProduct(const std::vector<std::vector<double>> &m, const std::vector<double> &v)
730 {
731  std::vector<double> result;
732  result.reserve(m.size());
733  for (const auto& r : m){
734  result.push_back(std::inner_product(v.begin(), v.end(), r.begin(), 0.0));
735  }
736 
737  return result;
738 }
739 
740 template<typename T>
741 std::vector<T> str_to_list(const std::string_view str)
742 {
743  constexpr char delimiters = ',';
744  std::vector<T> tokens;
745  // Skip delimiters at beginning.
746  std::string_view::size_type lastPos = str.find_first_not_of(delimiters, 0);
747  // Find first "non-delimiter".
748  std::string_view::size_type pos = str.find_first_of(delimiters, lastPos);
749 
750  while (std::string_view::npos != pos || std::string_view::npos != lastPos) {
751  // Found a token, add it to the vector.
752  std::string_view numbStr = str.substr(lastPos, pos - lastPos);
753  T num = -9999;
754  std::from_chars(numbStr.data(), numbStr.data() + numbStr.size(), num);
755  tokens.push_back(num);
756  // Skip delimiters. Note the "not_of"
757  lastPos = str.find_first_not_of(delimiters, pos);
758  // Find next "non-delimiter"
759  pos = str.find_first_of(delimiters, lastPos);
760  }
761  return tokens;
762 }
763 
764 int ISF::PunchThroughTool::passedParamIterator(int pid, double eta, const std::vector<std::map<std::string, std::string>> &mapvect) const
765 {
766  //convert the pid to absolute value and string for query
767  int pidStrSingle = std::abs(pid);
768  //STEP 1
769  //filter items matching pid first
770 
771  for (unsigned int i = 0; i < mapvect.size(); i++){
772  const std::string &pidStr = mapvect[i].at("pidStr");
773  auto v = str_to_list<int>(pidStr);
774  if(std::find(v.begin(), v.end(),pidStrSingle)==v.end()) continue;
775  const std::string &etaMinsStr = mapvect[i].at("etaMins");
776  const std::string &etaMaxsStr = mapvect[i].at("etaMaxs");
777  std::vector<double> etaMinsVect = str_to_list<double>(etaMinsStr);
778  std::vector<double> etaMaxsVect = str_to_list<double>(etaMaxsStr);
779  assert(etaMaxsVect.size() == etaMinsVect.size());
780  for (unsigned int j = 0; j < etaMinsVect.size(); j++){ // assume size etaMinsVect == etaMaxsVect
781  double etaMinToCompare = etaMinsVect[j];
782  double etaMaxToCompare = etaMaxsVect[j];
783  if((eta >= etaMinToCompare) && (eta < etaMaxToCompare)){
784  //PASS CONDITION
785  //then choose the passing one and note it's iterator
786  return (i); //in case more than 1 match (ambiguous case)
787  }
788  }
789  }
790  return 0;
791 }
792 
793 std::vector<std::map<std::string, std::string>> ISF::PunchThroughTool::getInfoMap(const std::string& mainNode, const std::string &xmlFilePath){
794  std::vector<std::map<std::string, std::string>> xml_info;
795  xmlDocPtr doc = xmlParseFile( xmlFilePath.c_str() );
796 
797  //check info first
798  for( xmlNodePtr nodeRoot = doc->children; nodeRoot != nullptr; nodeRoot = nodeRoot->next) {
799  if (xmlStrEqual( nodeRoot->name, BAD_CAST mainNode.c_str() )) {
800  for( xmlNodePtr nodeRootChild = nodeRoot->children; nodeRootChild != nullptr; nodeRootChild = nodeRootChild->next ) {
801  if (xmlStrEqual( nodeRootChild->name, BAD_CAST "info" )) {
802  if (nodeRootChild->children != NULL) {
803  for( xmlNodePtr infoNode = nodeRootChild->children; infoNode != nullptr; infoNode = infoNode->next) {
804  if(xmlStrEqual( infoNode->name, BAD_CAST "item" )){
805  std::map<std::string, std::string> xml_info_item;
806  xml_info_item.insert({ "name", (const char*) xmlGetProp( infoNode, BAD_CAST "name" ) });
807  xml_info_item.insert({ "etaMins", (const char*) xmlGetProp( infoNode, BAD_CAST "etaMins" ) });
808  xml_info_item.insert({ "etaMaxs", (const char*) xmlGetProp( infoNode, BAD_CAST "etaMaxs" ) });
809  xml_info_item.insert({ "pidStr", (const char*) xmlGetProp( infoNode, BAD_CAST "pidStr" ) });
810  xml_info.push_back(xml_info_item);
811  }
812  }
813  }
814  }
815  }
816  }
817  }
818  return xml_info;
819 }
820 
821 std::vector<double> ISF::PunchThroughTool::inversePCA(int pcaCdfIterator, std::vector<double> &variables) const
822 {
823  std::vector<double> transformed_variables = dotProduct(m_inverse_PCA_matrix[pcaCdfIterator], variables);
824 
825  std::transform (transformed_variables.begin(), transformed_variables.end(), m_PCA_means[pcaCdfIterator].begin(), transformed_variables.begin(), std::plus<double>()); // + means
826 
827  return transformed_variables;
828 }
829 
830 StatusCode ISF::PunchThroughTool::initializeInversePCA(const std::string & inversePCAConfigFile){
831 
832  xmlDocPtr doc = xmlParseFile( inversePCAConfigFile.c_str() );
833 
834  ATH_MSG_INFO( "[ punchthrough ] Loading inversePCA: " << inversePCAConfigFile);
835 
836  //check info first
837  m_xml_info_pca = getInfoMap("PCAinverse",inversePCAConfigFile);
838 
839  //do the saving
840  for (unsigned int i = 0; i < m_xml_info_pca.size(); i++) {
841  std::vector<std::vector<double>> PCA_matrix;
842  ATH_MSG_DEBUG( "[ punchthrough ] m_xml_info_pca[" << i << "].at('name') = " << m_xml_info_pca[i].at("name"));
843 
844  for( xmlNodePtr nodeRoot = doc->children; nodeRoot != nullptr; nodeRoot = nodeRoot->next) {
845  if (xmlStrEqual( nodeRoot->name, BAD_CAST "PCAinverse" )) {
846  for( xmlNodePtr nodePCAinverse = nodeRoot->children; nodePCAinverse != nullptr; nodePCAinverse = nodePCAinverse->next ) {
847 
848  if (xmlStrEqual( nodePCAinverse->name, BAD_CAST m_xml_info_pca[i].at("name").c_str() )) {
849  if (nodePCAinverse->children != NULL) {
850  for( xmlNodePtr pcaNode = nodePCAinverse->children; pcaNode != nullptr; pcaNode = pcaNode->next) {
851 
852  if (xmlStrEqual( pcaNode->name, BAD_CAST "PCAmatrix" )) {
853  std::vector<double> PCA_matrix_row;
854  PCA_matrix_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "comp_0" ) ) );
855  PCA_matrix_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "comp_1" ) ) );
856  PCA_matrix_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "comp_2" ) ) );
857  PCA_matrix_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "comp_3" ) ) );
858  PCA_matrix_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "comp_4" ) ) );
859  PCA_matrix.push_back(PCA_matrix_row);
860  }
861  else if (xmlStrEqual( pcaNode->name, BAD_CAST "PCAmeans" )) {
862  std::vector<double> PCA_means_row;
863  PCA_means_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "mean_0" ) ) );
864  PCA_means_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "mean_1" ) ) );
865  PCA_means_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "mean_2" ) ) );
866  PCA_means_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "mean_3" ) ) );
867  PCA_means_row.push_back( atof( (const char*) xmlGetProp( pcaNode, BAD_CAST "mean_4" ) ) );
868  m_PCA_means.push_back(PCA_means_row);
869  }
870 
871  }
872 
873  }
874  }
875 
876  }
877  }
878  }
879  m_inverse_PCA_matrix.push_back(PCA_matrix);
880  }
881 
882  return StatusCode::SUCCESS;
883 }
884 
885 StatusCode ISF::PunchThroughTool::initializeInverseCDF(const std::string & inverseCdfConfigFile){
886  std::map<double, double> variable0_inverse_cdf_row;
887  std::map<double, double> variable1_inverse_cdf_row;
888  std::map<double, double> variable2_inverse_cdf_row;
889  std::map<double, double> variable3_inverse_cdf_row;
890  std::map<double, double> variable4_inverse_cdf_row;
891 
892  //parse xml that contains config for inverse CDF for each of punch through particle kinematics
893 
894  xmlDocPtr doc = xmlParseFile( inverseCdfConfigFile.c_str() );
895 
896  ATH_MSG_INFO( "[ punchthrough ] Loading inverse CDF: " << inverseCdfConfigFile);
897 
898  //check info first
899  m_xml_info_cdf = getInfoMap("CDFMappings",inverseCdfConfigFile);
900 
901  //do the saving
902  for (unsigned int i = 0; i < m_xml_info_cdf.size(); i++) {
903  ATH_MSG_DEBUG( "[ punchthrough ] m_xml_info_cdf[" << i << "].at('name') = " << m_xml_info_cdf[i].at("name"));
904 
905  for( xmlNodePtr nodeRoot = doc->children; nodeRoot != nullptr; nodeRoot = nodeRoot->next) {
906  if (xmlStrEqual( nodeRoot->name, BAD_CAST "CDFMappings" )) {
907  for( xmlNodePtr typeMappings = nodeRoot->children; typeMappings != nullptr; typeMappings = typeMappings->next ) {
908  if (xmlStrEqual( typeMappings->name, BAD_CAST m_xml_info_cdf[i].at("name").c_str() )) {
909  if (typeMappings->children != NULL) {
910  for( xmlNodePtr nodeMappings = typeMappings->children; nodeMappings != nullptr; nodeMappings = nodeMappings->next) {
911 
912  if (xmlStrEqual( nodeMappings->name, BAD_CAST "variable0" )) {
913  variable0_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
914  }
915  else if (xmlStrEqual( nodeMappings->name, BAD_CAST "variable1" )) {
916  variable1_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
917  }
918  else if (xmlStrEqual( nodeMappings->name, BAD_CAST "variable2" )) {
919  variable2_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
920  }
921  else if (xmlStrEqual( nodeMappings->name, BAD_CAST "variable3" )) {
922  variable3_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
923  }
924  else if (xmlStrEqual( nodeMappings->name, BAD_CAST "variable4" )) {
925  variable4_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
926  }
927  }
928 
929  }
930  }
931  }
932  }
933  }
934  m_variable0_inverse_cdf.push_back(variable0_inverse_cdf_row);
935  m_variable1_inverse_cdf.push_back(variable1_inverse_cdf_row);
936  m_variable2_inverse_cdf.push_back(variable2_inverse_cdf_row);
937  m_variable3_inverse_cdf.push_back(variable3_inverse_cdf_row);
938  m_variable4_inverse_cdf.push_back(variable4_inverse_cdf_row);
939  }
940 
941  return StatusCode::SUCCESS;
942 }
943 
944 std::map<double, double> ISF::PunchThroughTool::getVariableCDFmappings(xmlNodePtr& nodeParent){
945 
946  std::map<double, double> mappings;
947 
948  for( xmlNodePtr node = nodeParent->children; node != nullptr; node = node->next ) {
949  //Get min and max values that we normalise values to
950  if (xmlStrEqual( node->name, BAD_CAST "CDFmap" )) {
951  double ref = atof( (const char*) xmlGetProp( node, BAD_CAST "ref" ) );
952  double quant = atof( (const char*) xmlGetProp( node, BAD_CAST "quant" ) );
953 
954  mappings.insert(std::pair<double, double>(ref, quant) );
955 
956  }
957  }
958 
959  return mappings;
960 }
961 
962 double ISF::PunchThroughTool::inverseCdfTransform(double variable, const std::map<double, double>& inverse_cdf_map) {
963 
964  double norm_cdf = normal_cdf(variable);
965 
966  auto upper = inverse_cdf_map.upper_bound(norm_cdf);
967  auto lower = upper--;
968 
969  double m = (upper->second - lower->second)/(upper->first - lower->first);
970  double c = lower->second - m * lower->first;
971  double transformed = m * norm_cdf + c;
972 
973  return transformed;
974 
975 }
976 
977 double ISF::PunchThroughTool::interpolateEnergy(const double &energy, CLHEP::HepRandomEngine* rndmEngine) const{
978 
979  ATH_MSG_DEBUG("[ punchthrough ] interpolating incoming energy: " << energy);
980 
981  std::string energyPointsString;
982  for (auto element:m_energyPoints){
983  energyPointsString += std::to_string(element) + " ";
984  }
985 
986  ATH_MSG_DEBUG("[ punchthrough ] available energy points: " << energyPointsString);
987 
988  auto const upperEnergy = std::upper_bound(m_energyPoints.begin(), m_energyPoints.end(), energy);
989 
990  if(upperEnergy == m_etaPoints.end()){ //if no energy greater than input energy, choose greatest energy
991  ATH_MSG_DEBUG("[ punchthrough ] incoming energy > largest energy point, returning greatest energy point: " << m_energyPoints.back());
992  return m_energyPoints.back();
993  }
994  else if(upperEnergy == m_etaPoints.begin()){ //if smallest energy greater than input energy, choose smallest energy
995  ATH_MSG_DEBUG("[ punchthrough ] incoming energy < smallest energy point, returning smallest energy point: " << *upperEnergy);
996  return *upperEnergy;
997  }
998 
999  ATH_MSG_DEBUG("[ punchthrough ] energy points upper_bound: "<< *upperEnergy);
1000 
1001  double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1002 
1003  ATH_MSG_DEBUG("[ punchthrough ] Shooting random number: "<< randomShoot);
1004 
1005  double midPoint = *std::prev(upperEnergy)*M_SQRT2;
1006 
1007  if(energy < midPoint){ //if energy smaller than mid point in log(energy)
1008 
1009  double distance = std::abs(energy - *std::prev(upperEnergy))/((midPoint) - *std::prev(upperEnergy));
1010 
1011  ATH_MSG_DEBUG( "[ punchthrough ] incoming energy is closest to prev(upper_bound) in log(energy), distance: " << distance );
1012 
1013  if(randomShoot < distance){
1014  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot < distance, returning upper_bound " << *upperEnergy );
1015  return *upperEnergy;
1016  }
1017  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot > distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1018 
1019  return *std::prev(upperEnergy);
1020  }
1021  else if(energy > midPoint){ //if energy greater than mid point in log(energy)
1022 
1023  double distance = std::abs(energy - *upperEnergy)/((*upperEnergy - midPoint));
1024 
1025  ATH_MSG_DEBUG( "[ punchthrough ] incoming energy is closest to upper_bound in log(energy), distance: " << distance );
1026 
1027  if(randomShoot < distance){
1028  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1029  return *std::prev(upperEnergy);
1030  }
1031  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot > distance, returning upper_bound " << *upperEnergy );
1032  return *upperEnergy;
1033  }
1034 
1035  return *upperEnergy;
1036 }
1037 
1038 double ISF::PunchThroughTool::interpolateEta(const double &eta, CLHEP::HepRandomEngine* rndmEngine) const{
1039 
1040  double absEta = std::abs(eta);
1041 
1042  ATH_MSG_DEBUG("[ punchthrough ] interpolating incoming abs(eta): " << absEta);
1043 
1044  std::string etaPointsString;
1045  for (auto element:m_etaPoints){
1046  etaPointsString += std::to_string(element) + " ";
1047  }
1048 
1049  ATH_MSG_DEBUG("[ punchthrough ] available eta points: " << etaPointsString);
1050 
1051  auto const upperEta = std::upper_bound(m_etaPoints.begin(), m_etaPoints.end(), absEta);
1052 
1053  if(upperEta == m_etaPoints.end()){
1054  ATH_MSG_DEBUG("[ punchthrough ] incoming abs(eta) > largest eta point, returning greatest eta point: " << m_etaPoints.back());
1055  return m_etaPoints.back();
1056  }
1057 
1058 
1059  ATH_MSG_DEBUG("[ punchthrough ] eta points upper_bound: "<< *upperEta);
1060 
1061  double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1062 
1063  ATH_MSG_DEBUG("[ punchthrough ] Shooting random number: "<< randomShoot);
1064 
1065  if(std::abs(absEta - *upperEta) < std::abs(absEta - *std::prev(upperEta))){
1066 
1067  double distance = std::abs(absEta - *upperEta)/((*upperEta - *std::prev(upperEta))/2);
1068 
1069  ATH_MSG_DEBUG( "[ punchthrough ] abs(eta) is closer to eta points upper_bound, distance: " << distance );
1070 
1071  if(randomShoot > distance){
1072  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot > distance, returning upper_bound " << *upperEta );
1073  return *upperEta;
1074  }
1075 
1076  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1077 
1078  return *std::prev(upperEta);
1079  }
1080  else if(std::abs(absEta - *std::prev(upperEta)) < std::abs(absEta - *upperEta)){
1081 
1082  if(std::prev(upperEta) == m_etaPoints.begin()){
1083  ATH_MSG_DEBUG( "[ punchthrough ] prev of upper bound is begin, returning that: " << *std::prev(upperEta) );
1084  return *std::prev(upperEta);
1085  }
1086 
1087  double distance = std::abs(absEta - *std::prev(upperEta))/((*std::prev(upperEta) - *std::prev(std::prev(upperEta)))/2);
1088 
1089  ATH_MSG_DEBUG( "[ punchthrough ] abs(eta) is closer to eta points prev(upper_bound), distance: " << distance );
1090 
1091  if(randomShoot > distance){
1092  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot > distance, returning prev(prev(upper_bound)) " << *std::prev(std::prev(upperEta)) );
1093 
1094  return *std::prev(std::prev(upperEta));
1095  }
1096  ATH_MSG_DEBUG( "[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1097 
1098  return *std::prev(upperEta);
1099  }
1100 
1101  return *std::prev(upperEta);
1102 }
1103 
1104 /*=========================================================================
1105  * DESCRIPTION OF FUNCTION:
1106  * ==> see headerfile
1107  *=======================================================================*/
1108 
1109 StatusCode
1110 ISF::PunchThroughTool::registerParticle(int pdg, bool doAntiparticle,
1111  double minEnergy, int maxNumParticles, double numParticlesFactor,
1112  double energyFactor, double posAngleFactor, double momAngleFactor)
1113 {
1114  // read in the data needed to construct the distributions for the number of punch-through particles
1115 
1116  // (1.) get the distribution function for the number of punch-through particles
1117  std::unique_ptr<ISF::PDFcreator> pdf_num(readLookuptablePDF(pdg, "FREQ_PDG"));
1118  if (!pdf_num ) return StatusCode::FAILURE; // return error if something went wrong
1119 
1120  // (2.) get the PDF for the punch-through energy
1121  std::unique_ptr<PDFcreator> pdf_pca0 (readLookuptablePDF(pdg, "PCA0_PDG"));
1122  if (!pdf_pca0)
1123  {
1124  return StatusCode::FAILURE; // return error if something went wrong
1125  }
1126 
1127  // (3.) get the PDF for the punch-through particles difference in
1128  // theta compared to the incoming particle
1129  std::unique_ptr<PDFcreator> pdf_pca1 (readLookuptablePDF(pdg, "PCA1_PDG"));
1130  if (!pdf_pca1)
1131  {
1132  return StatusCode::FAILURE;
1133  }
1134 
1135  // (4.) get the PDF for the punch-through particles difference in
1136  // phi compared to the incoming particle
1137  std::unique_ptr<PDFcreator> pdf_pca2 (readLookuptablePDF(pdg, "PCA2_PDG"));
1138  if (!pdf_pca2)
1139  {
1140  return StatusCode::FAILURE;
1141  }
1142 
1143  // (5.) get the PDF for the punch-through particle momentum delta theta angle
1144  std::unique_ptr<PDFcreator> pdf_pca3 (readLookuptablePDF(pdg, "PCA3_PDG"));
1145  if (!pdf_pca3)
1146  {
1147  return StatusCode::FAILURE;
1148  }
1149 
1150  // (6.) get the PDF for the punch-through particle momentum delta phi angle
1151  std::unique_ptr<PDFcreator> pdf_pca4 (readLookuptablePDF(pdg, "PCA4_PDG"));
1152  if (!pdf_pca4)
1153  {
1154  return StatusCode::FAILURE;
1155  }
1156 
1157  // (7.) now finally store all this in the right std::map
1158  PunchThroughParticle *particle = new PunchThroughParticle(pdg, doAntiparticle);
1159  particle->setNumParticlesPDF(std::move(pdf_num));
1160  particle->setPCA0PDF(std::move(pdf_pca0));
1161  particle->setPCA1PDF(std::move(pdf_pca1));
1162  particle->setPCA2PDF(std::move(pdf_pca2));
1163  particle->setPCA3PDF(std::move(pdf_pca3));
1164  particle->setPCA4PDF(std::move(pdf_pca4));
1165 
1166  // (8.) set some additional particle and simulation properties
1167  const double restMass = m_particleDataTable->particle(std::abs(pdg))->mass();
1168  minEnergy = ( minEnergy > restMass ) ? minEnergy : restMass;
1169  particle->setMinEnergy(minEnergy);
1170  particle->setMaxNumParticles(maxNumParticles);
1171  particle->setNumParticlesFactor(numParticlesFactor);
1172  particle->setEnergyFactor(energyFactor);
1173  particle->setPosAngleFactor(posAngleFactor);
1174  particle->setMomAngleFactor(momAngleFactor);
1175 
1176  // (9.) insert this PunchThroughParticle instance into the std::map class member
1177  m_particles[pdg] = particle;
1178 
1179  return StatusCode::SUCCESS;
1180 }
1181 
1182 /*=========================================================================
1183  * DESCRIPTION OF FUNCTION:
1184  * ==> see headerfile
1185  *=======================================================================*/
1186 
1188  double minCorrEnergy, double fullCorrEnergy)
1189 {
1190  // find the given pdgs in the registered particle ids
1191  std::map<int, PunchThroughParticle*>::iterator location1 = m_particles.find(pdgID1);
1192  std::map<int, PunchThroughParticle*>::iterator location2 = m_particles.find(pdgID2);
1193 
1194  // if at least one of the given pdgs was not registered yet -> return an error
1195  if ( (location1 == m_particles.end()) || (location2 == m_particles.end()) )
1196  return StatusCode::FAILURE;
1197 
1198  // now look for the correlation histograms
1199  std::stringstream name;
1200  name << "NumExitCorrelations/x_PDG" << std::abs(pdgID1) << "__y_PDG" << std::abs(pdgID2) << "__lowE";
1201  TH2F *hist1_2_lowE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
1202  name.str("");
1203  name << "NumExitCorrelations/x_PDG" << std::abs(pdgID1) << "__y_PDG" << std::abs(pdgID2) << "__highE";
1204  TH2F *hist1_2_highE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
1205  name.str("");
1206  name << "NumExitCorrelations/x_PDG" << std::abs(pdgID2) << "__y_PDG" << std::abs(pdgID1) << "__lowE";
1207  TH2F *hist2_1_lowE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
1208  name.str("");
1209  name << "NumExitCorrelations/x_PDG" << std::abs(pdgID2) << "__y_PDG" << std::abs(pdgID1) << "__highE";
1210  TH2F *hist2_1_highE = (TH2F*)m_fileLookupTable->Get(name.str().c_str());
1211  // check if the histograms exist
1212  if ( (!hist1_2_lowE) || (!hist2_1_lowE) || (!hist1_2_highE) || (!hist2_1_highE) )
1213  {
1214  ATH_MSG_ERROR("[ punchthrough ] unable to retrieve the correlation data for PDG IDs " << pdgID1 << " and " << pdgID2);
1215  return StatusCode::FAILURE;
1216  }
1217 
1218  // TODO: if only one of the two histograms exists, create the other one
1219  // by mirroring the data
1220 
1221  const double lowE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "elow_");
1222  const double midE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "ehigh_");
1223  //TODO: check if the same:
1224  // double midE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(), "elow_");
1225  const double upperE = getFloatAfterPatternInStr( hist1_2_highE->GetTitle(), "ehigh_");
1226  // now store the correlation either way id1->id2 and id2->id1
1227  m_particles[pdgID1]->setCorrelation(pdgID2, hist2_1_lowE, hist2_1_highE,
1228  minCorrEnergy, fullCorrEnergy,
1229  lowE, midE, upperE);
1230 
1231  m_particles[pdgID2]->setCorrelation(pdgID1, hist1_2_lowE, hist1_2_highE,
1232  minCorrEnergy, fullCorrEnergy,
1233  lowE, midE, upperE);
1234  return StatusCode::SUCCESS;
1235 }
1236 
1237 /*=========================================================================
1238  * DESCRIPTION OF FUNCTION:
1239  * ==> see headerfile
1240  *======================================================================*/
1241 
1242 std::unique_ptr<ISF::PDFcreator> ISF::PunchThroughTool::readLookuptablePDF(int pdg, const std::string& folderName)
1243 {
1244 
1245  // will hold the PDFcreator class which will be returned at the end
1246  // this will store the distributions for the punch through particles
1247  // (as map of energy & eta of the incoming particle)
1248  //PDFcreator *pdf = new PDFcreator();
1249  std::unique_ptr<ISF::PDFcreator> pdf = std::make_unique<ISF::PDFcreator>();
1250 
1251  //Get directory object
1252  std::stringstream dirName;
1253  dirName << folderName << pdg;
1254  pdf->setName(dirName.str().c_str());
1255 
1256  TDirectory * dir = (TDirectory*)m_fileLookupTable->Get(dirName.str().c_str());
1257  if(! dir)
1258  {
1259  ATH_MSG_ERROR( "[ punchthrough ] unable to retrieve directory object ("<< folderName << pdg << ")" );
1260  return nullptr;
1261  }
1262 
1263 
1264 
1265  //Get list of all objects in directory
1266  TIter keyList(dir->GetListOfKeys());
1267  TKey *key;
1268 
1269  while ((key = (TKey*)keyList())) {
1270 
1271  //Get histogram object from key and its name
1272  TH1* hist = nullptr;
1273 
1274  std::string histName;
1275  if(strcmp(key->GetClassName(), "TH1F") == 0){
1276  hist = (TH1*)key->ReadObj();
1277  histName = hist->GetName();
1278  }
1279 
1280  //extract energy and eta from hist name 6 and 1 to position delimeters correctly
1281  std::string strEnergy = histName.substr( histName.find_first_of('E') + 1, histName.find_first_of('_')-histName.find_first_of('E') - 1 );
1282  histName.erase(0, histName.find_first_of('_') + 1);
1283  std::string strEtaMin = histName.substr( histName.find("etaMin") + 6, histName.find_first_of('_') - histName.find("etaMin") - 6 );
1284  histName.erase(0, histName.find('_') + 1);
1285  std::string strEtaMax = histName.substr( histName.find("etaMax") + 6, histName.length());
1286 
1287  //create integers to store in map
1288  const int energy = std::stoi(strEnergy);
1289  const int etaMin = std::stoi(strEtaMin);
1290 
1291  //Add entry to pdf map
1292  pdf->addToEnergyEtaHist1DMap(energy, etaMin, hist);
1293 
1294  //create doubles to store energy and eta points for interpolation
1295  const double energyDbl = static_cast<double>(energy);
1296  const double etaDbl = static_cast<double>(etaMin)/100.;
1297 
1298  //create vectors to store the eta and energy points, this allows us to interpolate
1299  if (std::find(m_energyPoints.begin(), m_energyPoints.end(), energyDbl) == m_energyPoints.end()) {
1300  m_energyPoints.push_back(energyDbl);
1301  }
1302  if (std::find(m_etaPoints.begin(), m_etaPoints.end(), etaDbl) == m_etaPoints.end()) {
1303  m_etaPoints.push_back(etaDbl);
1304  }
1305 
1306  }
1307 
1308 
1309 
1310  return pdf;
1311 }
1312 
1313 /* =========================================================================
1314  * DESCRIPTION OF FUNCTION:
1315  * ==> see headerfile
1316  *=========================================================================*/
1317 
1319  double energy, double theta, double phi,double momTheta, double momPhi) const
1320 {
1321  // the intersection point with Calo-MS surface
1322 
1323  const Amg::Vector3D pos = propagator(theta,phi);
1324 
1325  // set up the real punch-through particle at this position
1326  // set up the momentum vector of this particle as a GlobalMomentum
1327  // by using the given energy and mass of the particle and also using
1328  // the given theta and phi
1329 
1331  double mass = m_particleDataTable->particle(std::abs(pdg))->mass();
1332  Amg::setRThetaPhi( mom, std::sqrt(energy*energy - mass*mass), momTheta, momPhi);
1333  ATH_MSG_DEBUG("setRThetaPhi pre input parameters: energy = "<< energy <<" mass = "<< mass);
1334  ATH_MSG_DEBUG("setRThetaPhi input parameters: std::sqrt(energy*energy - mass*mass) = "<< std::sqrt(energy*energy - mass*mass) <<" momTheta = "<< momTheta <<" momPhi = "<< momPhi);
1335 
1336 
1337  double charge = m_particleDataTable->particle(std::abs(pdg))->charge();
1338  // since the PDT table only has abs(PID) values for the charge
1339  charge *= (pdg > 0.) ? 1. : -1.;
1340 
1341  const double pTime = 0;
1342  const int status = 1 + HepMC::SIM_STATUS_THRESHOLD;
1343  const int id = HepMC::UNDEFINED_ID;
1344  // NB we are not considering the possibility that the punch-through
1345  // particle is the incoming particle having survived an interaction.
1346  ISF::ISFParticle* finalPar = new ISF::ISFParticle ( pos, mom, mass, charge, pdg, status, pTime, isfp, id);
1348 
1349  // return the punch-through particle
1350  return finalPar;
1351 }
1352 
1353 /*=========================================================================
1354  * DESCRIPTION OF FUNCTION:
1355  * ==> see headerfile
1356  *=======================================================================*/
1357 
1358 double ISF::PunchThroughTool::getFloatAfterPatternInStr(const char *cstr, const char *cpattern)
1359 {
1360  double num = 0.;
1361 
1362  const std::string_view str( cstr);
1363  const std::string_view pattern( cpattern);
1364  const size_t pos = str.find(pattern);
1365 
1366  if ( pos == std::string::npos)
1367  {
1368  ATH_MSG_WARNING("[ punchthrough ] unable to retrieve floating point number from string");
1369  return -999999999999.;
1370  }
1371  const std::string_view substring = str.substr(pos+pattern.length());
1372  std::from_chars(substring.data(), substring.data() + substring.size(), num);
1373  return num;
1374 }
1375 
1377 {
1378  // phi, theta - direction of the punch-through particle coming into calo
1379  //particle propagates inside the calorimeter along the straight line
1380  //coordinates of this particles when exiting the calo (on calo-MS boundary)
1381 
1382  double x, y, z, r;
1383 
1384  // cylinders border angles
1385  const double theta1 = atan (m_R1/m_z1);
1386  const double theta2 = atan (m_R1/m_z2);
1387  const double theta3 = atan (m_R2/m_z2);
1388  //where is the particle
1389 
1390  if (theta >= 0 && theta < theta1)
1391  {
1392  z = m_z1;
1393  r = std::fabs (m_z1*tan(theta));
1394  }
1395  else if (theta >= theta1 && theta < theta2)
1396  {
1397  z = m_R1/tan(theta);
1398  r = m_R1;
1399  }
1400  else if (theta >= theta2 && theta < theta3)
1401  {
1402  z = m_z2;
1403  r = std::fabs(m_z2*tan(theta));;
1404  }
1405  else if (theta >= theta3 && theta < (TMath::Pi()-theta3) )
1406  {
1407  z = m_R2/tan(theta);
1408  r = m_R2;
1409  }
1410  else if (theta >= (TMath::Pi()-theta3) && theta < (TMath::Pi()-theta2) )
1411  {
1412  z = -m_z2;
1413  r = std::fabs(m_z2*tan(theta));
1414  }
1415  else if (theta >= (TMath::Pi()-theta2) && theta < (TMath::Pi()-theta1) )
1416  {
1417  z = m_R1/tan(theta);
1418  r = m_R1;
1419  }
1420  else if (theta >= (TMath::Pi()-theta1) && theta <= TMath::Pi() )
1421  {
1422  z = -m_z1;
1423  r = std::fabs(m_z1*tan(theta));
1424  }
1425 
1426  //parallel universe
1427  else
1428  {
1429  ATH_MSG_WARNING ( "Given theta angle is incorrect, setting particle position to (0, 0, 0)");
1430  x = 0.0; y = 0.0; z = 0.0; r = 0.0;
1431  }
1432 
1433  x = r*cos(phi);
1434  y = r*sin(phi);
1435  Amg::Vector3D pos(x, y, z);
1436 
1437  ATH_MSG_DEBUG("position of produced punch-through particle: x = "<< x <<" y = "<< y <<" z = "<< z<<" r = "<< pos.perp() <<"std::sqrt(x^2+y^2) = "<< std::sqrt(x*x+y*y) );
1438  ATH_MSG_DEBUG("GeoID thinks: Calo: "<< m_geoIDSvc->inside(pos, AtlasDetDescr::fAtlasCalo) <<" MS: "<< m_geoIDSvc->inside(pos,AtlasDetDescr::fAtlasMS));
1439 
1440  return pos;
1441 }
ISF::PunchThroughTool::PunchThroughTool
PunchThroughTool(const std::string &, const std::string &, const IInterface *)
Constructor.
Definition: PunchThroughTool.cxx:62
xAOD::iterator
JetConstituentVector::iterator iterator
Definition: JetConstituentVector.cxx:68
ISF::PunchThroughTool::inverseCdfTransform
static double inverseCdfTransform(double variable, const std::map< double, double > &inverse_cdf_map)
Definition: PunchThroughTool.cxx:962
mergePhysValFiles.pattern
pattern
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:26
beamspotman.r
def r
Definition: beamspotman.py:676
ISF::PunchThroughTool::getInfoMap
std::vector< std::map< std::string, std::string > > getInfoMap(const std::string &mainNode, const std::string &xmlFilePath)
Definition: PunchThroughTool.cxx:793
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
ISF::PunchThroughTool::initialize
virtual StatusCode initialize()
AlgTool initialize method.
Definition: PunchThroughTool.cxx:74
GenEvent.h
get_generator_info.result
result
Definition: get_generator_info.py:21
python.SystemOfUnits.m
int m
Definition: SystemOfUnits.py:91
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
checkCoolLatestUpdate.variables
variables
Definition: checkCoolLatestUpdate.py:13
ISF::ISFParticle::setNextGeoID
void setNextGeoID(AtlasDetDescr::AtlasRegion geoID)
register the next AtlasDetDescr::AtlasRegion
AddEmptyComponent.histName
string histName
Definition: AddEmptyComponent.py:64
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
str_to_list
std::vector< T > str_to_list(const std::string_view str)
Definition: PunchThroughTool.cxx:741
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
ISF::PunchThroughTool::readLookuptablePDF
std::unique_ptr< ISF::PDFcreator > readLookuptablePDF(int pdgID, const std::string &folderName)
reads out the lookuptable for the given type of particle
Definition: PunchThroughTool.cxx:1242
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
PunchThroughParticle.h
TH2F
Definition: rootspy.cxx:420
RZPairVector
std::vector< RZPair > RZPairVector
Definition: RZPair.h:18
eta
Scalar eta() const
pseudorapidity method
Definition: AmgMatrixBasePlugin.h:79
xAOD::deltaPhi
setSAddress setEtaMS setDirPhiMS setDirZMS setBarrelRadius setEndcapAlpha setEndcapRadius setInterceptInner setEtaMap setEtaBin setIsTgcFailure setDeltaPt deltaPhi
Definition: L2StandAloneMuon_v1.cxx:160
plotmaker.hist
hist
Definition: plotmaker.py:148
GenVertex.h
theta
Scalar theta() const
theta method
Definition: AmgMatrixBasePlugin.h:71
ISF::PunchThroughTool::finalize
virtual StatusCode finalize()
AlgTool finalize method.
Definition: PunchThroughTool.cxx:271
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
ISF::PunchThroughTool::registerCorrelation
StatusCode registerCorrelation(int pdgID1, int pdgID2, double minCorrEnergy=0., double fullCorrEnergy=0.)
register a correlation for the two given types of punch-through particles with a given energy thresho...
Definition: PunchThroughTool.cxx:1187
ISF::ISFParticle
Definition: ISFParticle.h:42
M_PI
#define M_PI
Definition: ActiveFraction.h:11
ISF::ISFParticle::pdgCode
int pdgCode() const
PDG value.
upper
int upper(int c)
Definition: LArBadChannelParser.cxx:49
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
beamspotman.tokens
tokens
Definition: beamspotman.py:1284
x
#define x
GenParticle.h
ISF::PunchThroughTool::interpolateEnergy
double interpolateEnergy(const double &energy, CLHEP::HepRandomEngine *rndmEngine) const
Definition: PunchThroughTool.cxx:977
dqt_zlumi_pandas.mass
mass
Definition: dqt_zlumi_pandas.py:170
drawFromPickle.atan
atan
Definition: drawFromPickle.py:36
plotting.efficiency.substring
string substring
Definition: efficiency.py:21
ISF::ISFParticle::position
const Amg::Vector3D & position() const
The current position of the ISFParticle.
ISF::PunchThroughTool::getOneParticle
ISF::ISFParticle * getOneParticle(const ISF::ISFParticle &isfp, int pdg, CLHEP::HepRandomEngine *rndmEngine, double interpEnergy, double interpEta) const
create exactly one punch-through particle with the given pdg and the given max energy
Definition: PunchThroughTool.cxx:592
ISF::PunchThroughTool::getVariableCDFmappings
static std::map< double, double > getVariableCDFmappings(xmlNodePtr &nodeParent)
Definition: PunchThroughTool.cxx:944
ISFParticle.h
ParticleGun_EoverP_Config.mom
mom
Definition: ParticleGun_EoverP_Config.py:63
SimpleVector.h
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
convertTimingResiduals.sum
sum
Definition: convertTimingResiduals.py:55
LArG4FSStartPointFilter.rand
rand
Definition: LArG4FSStartPointFilter.py:80
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
PunchThroughTool.h
ParticleGun_EoverP_Config.momentum
momentum
Definition: ParticleGun_EoverP_Config.py:63
AtlasDetDescr::fAtlasMS
@ fAtlasMS
Definition: AtlasRegion.h:36
lumiFormat.i
int i
Definition: lumiFormat.py:92
z
#define z
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
ISF::PunchThroughTool::inversePCA
std::vector< double > inversePCA(int pcaCdfIterator, std::vector< double > &variables) const
Definition: PunchThroughTool.cxx:821
ISF::ISFParticleVector
std::vector< ISF::ISFParticle * > ISFParticleVector
ISFParticle vector.
Definition: ISFParticleContainer.h:26
Amg::transform
Amg::Vector3D transform(Amg::Vector3D &v, Amg::Transform3D &tr)
Transform a point from a Trasformation3D.
Definition: GeoPrimitivesHelpers.h:156
ISF::PunchThroughTool::propagator
Amg::Vector3D propagator(double theta, double phi) const
get particle through the calorimeter
Definition: PunchThroughTool.cxx:1376
ParticleGun_EoverP_Config.pid
pid
Definition: ParticleGun_EoverP_Config.py:62
test_pyathena.parent
parent
Definition: test_pyathena.py:15
ISF::PunchThroughTool::getCorrelatedParticles
int getCorrelatedParticles(const ISF::ISFParticle &isfp, ISFParticleVector &isfpCont, int doPdg, int corrParticles, CLHEP::HepRandomEngine *rndmEngine, double interpEnergy, double interpEta) const
get the right number of particles for the given pdg while considering the correlation to an other par...
Definition: PunchThroughTool.cxx:518
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
python.selection.variable
variable
Definition: selection.py:33
drawFromPickle.tan
tan
Definition: drawFromPickle.py:36
ISF::PunchThroughTool::passedParamIterator
int passedParamIterator(int pid, double eta, const std::vector< std::map< std::string, std::string >> &mapvect) const
Definition: PunchThroughTool.cxx:764
TH2F::GetBinContent
double GetBinContent(int) const
Definition: rootspy.cxx:425
beamspotman.dir
string dir
Definition: beamspotman.py:623
CxxUtils::atof
double atof(std::string_view str)
Converts a string into a double / float.
Definition: Control/CxxUtils/Root/StringUtils.cxx:91
HepMC::UNDEFINED_ID
constexpr int UNDEFINED_ID
Definition: MagicNumbers.h:55
ISF::PunchThroughTool::getAllParticles
int getAllParticles(const ISF::ISFParticle &isfp, ISFParticleVector &isfpCont, CLHEP::HepRandomEngine *rndmEngine, int pdg, double interpEnergy, double interpEta, int numParticles=-1) const
create the right number of punch-through particles for the given pdg and return the number of particl...
Definition: PunchThroughTool.cxx:448
trigbs_pickEvents.num
num
Definition: trigbs_pickEvents.py:76
node::name
void name(const std::string &n)
Definition: node.h:38
PathResolver.h
HepMC::SIM_STATUS_THRESHOLD
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
Definition: MagicNumbers.h:38
CaloCellTimeCorrFiller.folderName
string folderName
Definition: CaloCellTimeCorrFiller.py:20
merge_scale_histograms.doc
string doc
Definition: merge_scale_histograms.py:9
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
createCoolChannelIdFile.par
par
Definition: createCoolChannelIdFile.py:29
MagicNumbers.h
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
ISF::ISFParticle::momentum
const Amg::Vector3D & momentum() const
The current momentum vector of the ISFParticle.
ISF::PunchThroughTool::initializeInverseCDF
StatusCode initializeInverseCDF(const std::string &quantileTransformerConfigFile)
Definition: PunchThroughTool.cxx:885
charge
double charge(const T &p)
Definition: AtlasPID.h:494
FakeBkgTools::maxParticles
constexpr uint8_t maxParticles()
Definition: FakeBkgInternals.h:93
Amg::Vector3D
Eigen::Matrix< double, 3, 1 > Vector3D
Definition: GeoPrimitives.h:47
PDFcreator.h
ISF::PunchThroughTool::normal_cdf
static double normal_cdf(double x)
Definition: PunchThroughTool.cxx:724
python.LumiBlobConversion.pos
pos
Definition: LumiBlobConversion.py:18
PathResolverFindCalibFile
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:431
AtlasDetDescr::fAtlasCalo
@ fAtlasCalo
Definition: AtlasRegion.h:35
ISF::PunchThroughTool::createExitPs
ISF::ISFParticle * createExitPs(const ISF::ISFParticle &isfp, int PDGcode, double energy, double theta, double phi, double momTheta, double momPhi) const
create a ISF Particle state at the MS entrace containing a particle with the given properties
Definition: PunchThroughTool.cxx:1318
python.PyAthena.v
v
Definition: PyAthena.py:157
DataVector.h
An STL vector of pointers that by default owns its pointed-to elements.
ISF::PunchThroughTool::initializeInversePCA
StatusCode initializeInversePCA(const std::string &inversePCAConfigFile)
Definition: PunchThroughTool.cxx:830
LArCellBinning.etaMin
etaMin
Definition: LArCellBinning.py:84
y
#define y
python.CaloScaleNoiseConfig.str
str
Definition: CaloScaleNoiseConfig.py:78
ISF::PunchThroughTool::computePunchThroughParticles
const ISF::ISFParticleVector * computePunchThroughParticles(const ISF::ISFParticle &isfp, const TFCSSimulationState &simulstate, CLHEP::HepRandomEngine *rndmEngine) const
interface function: fill a vector with the punch-through particles
Definition: PunchThroughTool.cxx:288
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
ref
const boost::regex ref(r_ef)
GeoPrimitivesHelpers.h
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
TH1
Definition: rootspy.cxx:268
Amg::setRThetaPhi
void setRThetaPhi(Amg::Vector3D &v, double r, double theta, double phi)
sets radius, the theta and phi angle of a vector.
Definition: GeoPrimitivesHelpers.h:80
PowhegPythia8EvtGen_jetjet.pdf
pdf
Definition: PowhegPythia8EvtGen_jetjet.py:4
TauGNNUtils::Variables::absEta
bool absEta(const xAOD::TauJet &tau, double &out)
Definition: TauGNNUtils.cxx:232
ISF::PunchThroughTool::getFloatAfterPatternInStr
double getFloatAfterPatternInStr(const char *str, const char *pattern)
get the floating point number in a string, after the given pattern
Definition: PunchThroughTool.cxx:1358
physics_parameters.parameters
parameters
Definition: physics_parameters.py:144
ISF::PunchThroughTool::interpolateEta
double interpolateEta(const double &eta, CLHEP::HepRandomEngine *rndmEngine) const
Definition: PunchThroughTool.cxx:1038
ISF::PunchThroughParticle
Definition: PunchThroughParticle.h:33
str
Definition: BTagTrackIpAccessor.cxx:11
merge.status
status
Definition: merge.py:17
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
python.compressB64.c
def c
Definition: compressB64.py:93
ISF::PunchThroughTool::registerParticle
StatusCode registerParticle(int pdgID, bool doAntiparticle=false, double minEnergy=0., int maxNumParticles=-1, double numParticlesFactor=1., double energyFactor=1., double posAngleFactor=1., double momAngleFactor=1.)
registers a type of punch-through particles which will be simulated
Definition: PunchThroughTool.cxx:1110
TFCSSimulationState
Definition: TFCSSimulationState.h:32
node
Definition: memory_hooks-stdcmalloc.h:74
ISF::PunchThroughTool::dotProduct
static std::vector< double > dotProduct(const std::vector< std::vector< double >> &m, const std::vector< double > &v)
Definition: PunchThroughTool.cxx:729
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
ISF::ISFParticle::mass
double mass() const
mass of the particle