20 #include <string_view>
27 #include "CLHEP/Random/RandFlat.h"
50 if (resolvedFileName.empty()) {
52 return StatusCode::FAILURE;
54 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Parametrisation file found: " << resolvedFileName );
59 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open or read the inverse CDF config");
60 return StatusCode::FAILURE;
66 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open or read the inverse PCA config");
67 return StatusCode::FAILURE;
73 ATH_MSG_WARNING(
"[PunchThroughG4Tool] size of infoMap for PCA and CDF differs! Something is wrong with input xml files.");
74 return StatusCode::FAILURE;
80 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open the lookup-table for the punch-through simulation (file does not exist)");
81 return StatusCode::FAILURE;
85 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open the lookup-table for the punch-through simulation (wrong or empty file?)");
86 return StatusCode::FAILURE;
104 ATH_MSG_FATAL (
"[PunchThroughG4Tool] Could not retrieve GeometryIdentifier Service. Abort");
105 return StatusCode::FAILURE;
112 return StatusCode::FAILURE;
118 const std::vector<std::pair<double, double>>* rzMS = &(
m_envDefSvc->getMuonRZBoundary());
119 const std::vector<std::pair<double, double>>* rzCalo = &(
m_envDefSvc->getCaloRZBoundary());
122 ATH_MSG_INFO(
"[PunchThroughG4Tool] initialization is successful" );
123 return StatusCode::SUCCESS;
127 G4ParticleTable *ptable = G4ParticleTable::GetParticleTable();
147 ATH_MSG_VERBOSE(
"VERBOSE: [PunchThroughG4Tool] registering punch-through particle type with pdg = " << pdg );
148 if (
registerPunchThroughParticle( *ptable, pdg, doAnti, minEnergy, maxNum, numFactor, energyFactor, posAngleFactor, momAngleFactor ) != StatusCode::SUCCESS)
150 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to register punch-through particle type with pdg = " << pdg);
151 return StatusCode::FAILURE;
155 return StatusCode::SUCCESS;
168 ATH_MSG_WARNING(
"[PunchThroughG4Tool] more punch-through particle correlations are given, than punch-through particle types are registered (skipping the last ones)");
173 for (
unsigned int num = 0;
num < numCorrelations;
num++ )
181 if ( ! pdg2)
continue;
183 if (
registerCorrelation(pdg1, pdg2, minCorrEnergy, fullCorrEnergy) != StatusCode::SUCCESS )
185 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to register punch-through particle correlation for pdg1=" << pdg1 <<
" pdg2=" << pdg2 );
186 return StatusCode::FAILURE;
190 return StatusCode::SUCCESS;
196 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] getCaloMSVars()==> m_R1 = "<< caloMSVarsVect[0] <<
", m_R2 = " << caloMSVarsVect[1] <<
", m_z1 = " << caloMSVarsVect[2] <<
", m_z2 = " << caloMSVarsVect[3]);
198 return caloMSVarsVect;
202 const std::vector<std::pair<double, double>>* rzCalo)
205 found1=
false; found2=
false;
209 for (
const auto & [r_tempCalo , z_tempCalo] : *rzCalo )
214 for (
const auto & [r_tempMS , z_tempMS] : *rzMS )
217 if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && found1==
false )
220 m_z1=std::fabs(z_tempMS);
225 else if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && r_tempCalo!=
m_R1 && std::fabs(z_tempCalo)!=
m_z1)
228 m_z2=std::fabs(z_tempMS);
233 if (found1==
true && found2==
true)
break;
238 if (found1 ==
false){
239 ATH_MSG_ERROR (
"[PunchThroughG4Tool] first coordinate of calo-MS border not found");
240 return StatusCode::FAILURE;
242 if (found2 ==
false){
243 ATH_MSG_ERROR (
"[PunchThroughG4Tool] second coordinate of calo-MS border not found; first one is: R1 ="<<
m_R1<<
" z1 ="<<
m_z1);
244 return StatusCode::FAILURE;
253 return StatusCode::FAILURE;
258 return StatusCode::SUCCESS;
268 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] finalize() successful" );
270 return StatusCode::SUCCESS;
275 G4ParticleDefinition* secG4Particle = ptable.FindParticle(secondarySignedPDG);
276 double mass = secG4Particle->GetPDGMass();
277 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkParticleTable] secondarySignedPDG = " << secondarySignedPDG <<
", mass = "<<
mass);
282 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] starting punch-through simulation");
285 std::vector<std::map<std::string, double>> secKinematicsMapVect;
288 const G4Track * g4PrimaryTrack = fastTrack.GetPrimaryTrack();
291 const G4ParticleDefinition * mainG4Particle = g4PrimaryTrack->GetDefinition();
294 int pdgID = mainG4Particle->GetPDGEncoding();
295 float mainPartMass = mainG4Particle->GetPDGMass();
296 float mainMomMag2 = g4PrimaryTrack->GetMomentum().mag2();
297 float mainPartEta = g4PrimaryTrack->GetPosition().eta();
299 const G4ThreeVector mainMomentumDir = g4PrimaryTrack->GetMomentumDirection();
300 const G4ThreeVector mainMomentum = g4PrimaryTrack->GetMomentum();
301 const G4ThreeVector mainPosition = g4PrimaryTrack->GetPosition();
304 const double initEnergy = std::sqrt( mainMomMag2 + mainPartMass*mainPartMass );
305 const double initEta = mainPartEta;
307 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] position of the input particle: r"<<mainPosition.perp()<<
" z= "<<mainPosition.z() );
311 const Amg::Vector3D amg3DPosVec(mainPosition.x(), mainPosition.y(), mainPosition.z());
312 const Amg::Vector3D amg3DMomDirVec(mainMomentumDir.x(), mainMomentumDir.y(), mainMomentumDir.z());
313 const Amg::Vector3D amg3DMomVec(mainMomentum.x(), mainMomentum.y(), mainMomentum.z());
318 ATH_MSG_DEBUG(
"[PunchThroughG4Tool](GeoIDSvc) input particle doesn't point to calorimeter"<<
"Next GeoID: "<< nextGeoID );
330 for ( ; pdgIt != pdgItEnd; ++pdgIt, ++minEnergyIt)
332 if (std::abs(pdgID) == *pdgIt){
333 if(initEnergy < *minEnergyIt){
334 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle does not meet initiator min energy requirement. Dropping it in the calo.");
343 if (pdgIt == pdgItEnd)
345 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle is not registered as punch-through initiator. Dropping it in the calo.");
352 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle does not meet initiator eta range requirement. Dropping it in the calo.");
357 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] punchThroughProbability output: " << punchThroughProbability <<
" RandFlat: " << punchThroughClassifierRand );
360 if( punchThroughClassifierRand > punchThroughProbability){
361 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle not classified to create punch through. Dropping it in the calo.");
379 std::map<int, int> corrPdgNumDone;
385 while(secKinematicsMapVect.empty() && nTries < maxTries) {
390 int doPdg = currentParticle.first;
392 int corrPdg = currentParticle.second->getCorrelatedPdg();
401 if ( itPdgPos == corrPdgNumDone.end() ) itPdgPos = corrPdgNumDone.find(corrPdg);
405 if ( itPdgPos == corrPdgNumDone.end() )
408 if ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) doPdg = corrPdg;
411 corrPdgNumDone[doPdg] =
getAllParticles(*g4PrimaryTrack, secKinematicsMapVect, rndmEngine, doPdg, interpEnergy, interpEta);
420 const int donePdg = itPdgPos->first;
421 const int doneNumPart = itPdgPos->second;
423 if (donePdg == doPdg) doPdg = corrPdg;
426 getCorrelatedParticles(*g4PrimaryTrack, secKinematicsMapVect, doPdg, doneNumPart, rndmEngine, interpEnergy, interpEta);
436 getAllParticles(*g4PrimaryTrack, secKinematicsMapVect, rndmEngine, doPdg, interpEnergy, interpEta);
441 return secKinematicsMapVect;
444 int PunchThroughG4Tool::getAllParticles(
const G4Track& g4PrimaryTrack, std::vector<std::map<std::string, double>> &secKinematicsMapVect, CLHEP::HepRandomEngine* rndmEngine,
int pdg,
double interpEnergy,
double interpEta,
int numParticles)
447 float initParticleTheta = g4PrimaryTrack.GetPosition().theta();
448 float initParticlePhi = g4PrimaryTrack.GetPosition().phi();
452 double minAllowedEnergy =
p->getMinEnergy();
456 if ( numParticles < 0 )
470 numParticles =
int(
p->getNumParticlesPDF()->getRand(rndmEngine,
parameters) );
473 numParticles = lround( numParticles *=
p->getNumParticlesFactor() );
478 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] adding " << numParticles <<
" punch-through particles with pdg code: " << pdg);
481 for (
int numCreated = 0; numCreated < numParticles; numCreated++ )
484 std::map<std::string, double> secondaryKinematicsMap =
getOneParticleKinematics(rndmEngine, pdg, initParticleTheta, initParticlePhi, interpEnergy, interpEta);
487 double energy = secondaryKinematicsMap.at(
"energy");
488 if(
energy > minAllowedEnergy){
490 secKinematicsMapVect.push_back(secondaryKinematicsMap);
495 std::size_t numSecondaries = secKinematicsMapVect.size();
498 return (numSecondaries);
501 int PunchThroughG4Tool::getCorrelatedParticles(
const G4Track& g4PrimaryTrack, std::vector<std::map<std::string, double>> &secKinematicsMapVect,
int pdg,
int corrParticles, CLHEP::HepRandomEngine* rndmEngine,
double interpEnergy,
double interpEta)
504 const G4ParticleDefinition * mainG4Particle = g4PrimaryTrack.GetDefinition();
506 float mainMomMag2 = g4PrimaryTrack.GetMomentum().mag2();
507 float mainPartMass = mainG4Particle->GetPDGMass();
512 const double initEnergy = std::sqrt( mainMomMag2 + mainPartMass*mainPartMass );
515 double rand = CLHEP::RandFlat::shoot(rndmEngine)
516 *(
p->getFullCorrelationEnergy() -
p->getMinCorrelationEnergy())
517 +
p->getMinCorrelationEnergy();
520 if ( initEnergy <
rand )
523 return getAllParticles(g4PrimaryTrack, secKinematicsMapVect, rndmEngine, pdg, interpEnergy, interpEta);
528 double *histDomains =
p->getCorrelationHistDomains();
529 TH2F *hist2d =
nullptr;
532 if ( initEnergy < histDomains[1])
536 hist2d =
p->getCorrelationLowEHist();
540 double rand = CLHEP::RandFlat::shoot(rndmEngine)*(histDomains[2]-histDomains[1]) + histDomains[1];
541 hist2d = ( initEnergy <
rand) ?
p->getCorrelationLowEHist() :
p->getCorrelationHighEHist();
547 Int_t xbin = hist2d->GetXaxis()->FindFixBin(corrParticles);
548 int numParticles = 0;
554 double rand = CLHEP::RandFlat::shoot(rndmEngine);
556 for (
int ybin = 1; ybin <= hist2d->GetNbinsY(); ybin++ )
558 sum += hist2d->GetBinContent(xbin, ybin);
562 numParticles = ybin - 1;
567 numParticles = lround( numParticles *
p->getNumParticlesFactor() );
572 return getAllParticles(g4PrimaryTrack, secKinematicsMapVect, rndmEngine, pdg, interpEnergy, interpEta, numParticles);
583 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] passedPCAIterator ==> pcaCdfIterator = "<< pcaCdfIterator <<
" , pdg = "<< secondaryPDG <<
" , interpEnergy = "<< interpEnergy <<
" MeV, interpEta(*100) = "<< interpEta*100);
588 if (
p->getdoAnti() )
591 double rand = CLHEP::RandFlat::shoot(rndmEngine);
593 if (
rand > 0.5) anti = -1;
598 std::vector<int> parInitEnergyEta;
599 parInitEnergyEta.push_back(
std::round(interpEnergy) );
600 parInitEnergyEta.push_back(
std::round(interpEta*100) );
604 double deltaTheta = 0.;
606 double momDeltaTheta = 0.;
607 double momDeltaPhi = 0.;
609 double principal_component_0 = 0.;
610 double principal_component_1 = 0.;
611 double principal_component_2 = 0.;
612 double principal_component_3 = 0.;
613 double principal_component_4 = 0.;
614 std::vector<double> transformed_variables;
616 principal_component_0 =
p->getPCA0PDF()->getRand(rndmEngine, parInitEnergyEta);
617 principal_component_1 =
p->getPCA1PDF()->getRand(rndmEngine, parInitEnergyEta);
618 principal_component_2 =
p->getPCA2PDF()->getRand(rndmEngine, parInitEnergyEta);
619 principal_component_3 =
p->getPCA3PDF()->getRand(rndmEngine, parInitEnergyEta);
620 principal_component_4 =
p->getPCA4PDF()->getRand(rndmEngine, parInitEnergyEta);
622 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] 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 );
624 std::vector<double> principal_components {
625 principal_component_0,
626 principal_component_1,
627 principal_component_2,
628 principal_component_3,
629 principal_component_4
632 transformed_variables =
inversePCA(pcaCdfIterator,principal_components);
640 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Transformed punch through kinematics: energy = "<<
energy <<
" MeV deltaTheta = "<< deltaTheta <<
" deltaPhi = "<<
deltaPhi <<
" momDeltaTheta = "<< momDeltaTheta <<
" momDeltaPhi = "<< momDeltaPhi );
642 energy *=
p->getEnergyFactor();
645 if (energy < p->getMinEnergy()) {
646 energy =
p->getMinEnergy() + 10;
655 deltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
659 theta = initParticleTheta + deltaTheta*
p->getPosAngleFactor();
664 deltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
667 double phi = initParticlePhi +
deltaPhi*
p->getPosAngleFactor();
675 double momTheta = 0.;
679 momDeltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
682 momTheta =
theta + momDeltaTheta*
p->getMomAngleFactor();
684 while ( (momTheta >
M_PI) || (momTheta < 0.) );
687 momDeltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
689 double momPhi =
phi + momDeltaPhi*
p->getMomAngleFactor();
691 while ( std::fabs(momPhi) > 2*
M_PI) momPhi /= 2.;
692 while (momPhi >
M_PI) momPhi -= 2*
M_PI;
693 while (momPhi < -
M_PI) momPhi += 2*
M_PI;
696 std::map<std::string, double> secondaryKinematicsMap;
697 secondaryKinematicsMap.insert({
"anti" , anti });
698 secondaryKinematicsMap.insert({
"secondaryPDG" , secondaryPDG });
699 secondaryKinematicsMap.insert({
"energy" ,
energy });
700 secondaryKinematicsMap.insert({
"theta" ,
theta });
701 secondaryKinematicsMap.insert({
"phi" ,
phi });
702 secondaryKinematicsMap.insert({
"momTheta" , momTheta });
703 secondaryKinematicsMap.insert({
"momPhi" , momPhi });
705 return secondaryKinematicsMap;
711 double totEnergySecondaries = 0;
715 for (std::size_t
i = 0;
i < secKinematicsMapVect.size();
i++) {
716 energy = secKinematicsMapVect[
i].at(
"energy");
717 totEnergySecondaries +=
energy;
722 secKinematicsMapVect.begin(),
723 secKinematicsMapVect.end(),
724 [](
const std::map<std::string, double>& lhs,
const std::map<std::string, double>& rhs) {
725 return lhs.at(
"energy") > rhs.at(
"energy");
730 if(totEnergySecondaries > mainEnergyInit){
731 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkEnergySumFromSecondaries] Case where energy of created secondaries more than parent track identified! ");
732 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkEnergySumFromSecondaries] ==> TotalSecondariesEnergy = " << totEnergySecondaries <<
", ParentEnergy = "<< mainEnergyInit);
736 while (totEnergySecondaries > mainEnergyInit && !secKinematicsMapVect.empty()) {
738 std::map<std::string, double> lastMap = secKinematicsMapVect.back();
741 double lastEnergy = lastMap.at(
"energy");
744 secKinematicsMapVect.pop_back();
747 totEnergySecondaries -= lastEnergy;
751 return secKinematicsMapVect;
754 void PunchThroughG4Tool::createAllSecondaryTracks(G4ParticleTable &ptable, G4FastStep& fastStep,
const G4Track& g4PrimaryTrack, std::vector<std::map<std::string, double>> &secKinematicsMapVect, G4TrackVector& secTrackCont,
const std::vector<double> &caloMSVars){
756 const G4ParticleDefinition* mainG4Particle = g4PrimaryTrack.GetDefinition();
757 float mainMomMag2 = g4PrimaryTrack.GetMomentum().mag2();
758 float mainPartMass = mainG4Particle->GetPDGMass();
759 double mainEnergyInit = std::sqrt(mainMomMag2 + mainPartMass * mainPartMass);
765 int numSecondaries = secKinematicsMapVect.size();
767 if(numSecondaries>0){
769 fastStep.SetNumberOfSecondaryTracks(numSecondaries);
772 double currentTime = g4PrimaryTrack.GetGlobalTime();
775 for(
int i=0;
i < numSecondaries;
i++){
776 int anti = (
int)(secKinematicsMapVect[
i].at(
"anti"));
777 int secondaryPDG = (
int)(secKinematicsMapVect[
i].at(
"secondaryPDG"));
778 int signedPDG = secondaryPDG*anti;
779 double energy = secKinematicsMapVect[
i].at(
"energy");
780 double theta = secKinematicsMapVect[
i].at(
"theta");
781 double phi = secKinematicsMapVect[
i].at(
"phi");
782 double momTheta = secKinematicsMapVect[
i].at(
"momTheta");
783 double momPhi = secKinematicsMapVect[
i].at(
"momPhi");
786 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::createAllSecondaryTracks] createSecondaryTrack input parameters: currentTime = " << currentTime <<
" anti? = "<< anti <<
" signedPDG = "<< signedPDG <<
" energy = "<<
energy <<
" theta = "<<
theta <<
" phi = "<<
phi <<
" momTheta = "<< momTheta <<
" momPhi " << momPhi);
792 G4Exception(
"[PunchThroughG4Tool::createAllSecondaryTracks]",
"ExceptionError", FatalException,
"something went wrong while creating punch-through particle tracks");
797 secTrackCont.push_back( newSecTrack );
805 double energy,
double theta,
double phi,
double momTheta,
double momPhi,
const std::vector<double> &caloMSVars)
808 G4Track *newSecTrack =
nullptr;
810 G4ParticleDefinition* secG4Particle = ptable.FindParticle(secondarySignedPDG);
811 double mass = secG4Particle->GetPDGMass();
820 G4ThreeVector momVec;
822 momVec.setRThetaPhi(momMag,momTheta,momPhi);
823 ATH_MSG_DEBUG(
"[PunchThroughG4Tool]::createSecondaryTrack] setRThetaPhi pre input parameters: energy = " <<
energy <<
" mass = "<<
mass);
824 ATH_MSG_DEBUG(
"[PunchThroughG4Tool]::createSecondaryTrack] setRThetaPhi input parameters: std::sqrt(energy*energy - mass*mass) = " << std::sqrt(
energy*
energy -
mass*
mass) <<
" momTheta = "<< momTheta <<
" momPhi = "<< momPhi);
827 G4DynamicParticle dynParticle(secG4Particle,momVec);
828 newSecTrack = fastStep.CreateSecondaryTrack(dynParticle, posVec, currentTime,
false);
834 return 0.5 * TMath::Erfc(-
x * M_SQRT1_2);
839 std::vector<double>
result;
841 for (
const auto&
r :
m){
842 result.push_back(std::inner_product(
v.begin(),
v.end(),
r.begin(), 0.0));
851 constexpr
char delimiters =
',';
854 std::string_view::size_type lastPos =
str.find_first_not_of(delimiters, 0);
856 std::string_view::size_type
pos =
str.find_first_of(delimiters, lastPos);
858 while (std::string_view::npos !=
pos || std::string_view::npos != lastPos) {
860 std::string_view numbStr =
str.substr(lastPos,
pos - lastPos);
862 std::from_chars(numbStr.data(), numbStr.data() + numbStr.size(),
num);
865 lastPos =
str.find_first_not_of(delimiters,
pos);
867 pos =
str.find_first_of(delimiters, lastPos);
875 int pidStrSingle = std::abs(
pid);
879 for (
unsigned int i = 0;
i < mapvect.size();
i++){
880 const std::string &pidStr = mapvect[
i].at(
"pidStr");
881 auto v = str_to_list<int>(pidStr);
882 if(
std::find(
v.begin(),
v.end(),pidStrSingle)==
v.end())
continue;
883 const std::string &etaMinsStr = mapvect[
i].at(
"etaMins");
884 const std::string &etaMaxsStr = mapvect[
i].at(
"etaMaxs");
885 std::vector<double> etaMinsVect = str_to_list<double>(etaMinsStr);
886 std::vector<double> etaMaxsVect = str_to_list<double>(etaMaxsStr);
887 assert(etaMaxsVect.size() == etaMinsVect.size());
888 for (
unsigned int j = 0; j < etaMinsVect.size(); j++){
889 double etaMinToCompare = etaMinsVect[j];
890 double etaMaxToCompare = etaMaxsVect[j];
891 if((
eta >= etaMinToCompare) && (
eta < etaMaxToCompare)){
906 std::vector<std::map<std::string, std::string>> xml_info;
907 doc = xmlParseFile( xmlFilePath.c_str() );
910 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
911 if (xmlStrEqual( nodeRoot->name, BAD_CAST mainNode.c_str() )) {
912 for( xmlNodePtr nodeRootChild = nodeRoot->children; nodeRootChild !=
nullptr; nodeRootChild = nodeRootChild->next ) {
913 if (xmlStrEqual( nodeRootChild->name, BAD_CAST
"info" )) {
914 if (nodeRootChild->children != NULL) {
915 for( xmlNodePtr infoNode = nodeRootChild->children; infoNode !=
nullptr; infoNode = infoNode->next) {
916 if(xmlStrEqual( infoNode->name, BAD_CAST
"item" )){
917 std::map<std::string, std::string> xml_info_item;
919 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"name")) !=
nullptr) {
920 xml_info_item.insert({
"name", (
const char*)xmlBuff});
922 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"etaMins")) !=
nullptr) {
923 xml_info_item.insert({
"etaMins", (
const char*)xmlBuff});
925 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"etaMaxs")) !=
nullptr) {
926 xml_info_item.insert({
"etaMaxs", (
const char*)xmlBuff});
928 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"pidStr")) !=
nullptr) {
929 xml_info_item.insert({
"pidStr", (
const char*)xmlBuff});
932 xml_info.push_back(xml_info_item);
951 std::transform (transformed_variables.begin(), transformed_variables.end(),
m_PCA_means[pcaCdfIterator].begin(), transformed_variables.begin(), std::plus<double>());
953 return transformed_variables;
961 doc = xmlParseFile( inversePCAConfigFile.c_str() );
963 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Loading inversePCA: " << inversePCAConfigFile);
970 std::vector<std::vector<double>> PCA_matrix;
973 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
974 if (xmlStrEqual( nodeRoot->name, BAD_CAST
"PCAinverse" )) {
975 for( xmlNodePtr nodePCAinverse = nodeRoot->children; nodePCAinverse !=
nullptr; nodePCAinverse = nodePCAinverse->next ) {
977 if (xmlStrEqual( nodePCAinverse->name, BAD_CAST
m_xml_info_pca[
i].at(
"name").c_str() )) {
978 if (nodePCAinverse->children != NULL) {
979 for( xmlNodePtr pcaNode = nodePCAinverse->children; pcaNode !=
nullptr; pcaNode = pcaNode->next) {
981 if (xmlStrEqual( pcaNode->name, BAD_CAST
"PCAmatrix" )) {
982 std::vector<double> PCA_matrix_row;
983 for (
int i = 0;
i <= 4; ++
i) {
985 if ((xmlBuff = xmlGetProp(pcaNode, BAD_CAST
propName.c_str())) !=
nullptr) {
986 PCA_matrix_row.push_back(
atof((
const char*)xmlBuff));
989 PCA_matrix.push_back(PCA_matrix_row);
991 else if (xmlStrEqual( pcaNode->name, BAD_CAST
"PCAmeans" )) {
992 std::vector<double> PCA_means_row;
993 for (
int i = 0;
i <= 4; ++
i) {
995 if ((xmlBuff = xmlGetProp(pcaNode, BAD_CAST
propName.c_str())) !=
nullptr) {
996 PCA_means_row.push_back(
atof((
const char*)xmlBuff));
1016 return StatusCode::SUCCESS;
1020 std::map<double, double> variable0_inverse_cdf_row;
1021 std::map<double, double> variable1_inverse_cdf_row;
1022 std::map<double, double> variable2_inverse_cdf_row;
1023 std::map<double, double> variable3_inverse_cdf_row;
1024 std::map<double, double> variable4_inverse_cdf_row;
1031 doc = xmlParseFile( inverseCdfConfigFile.c_str() );
1033 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Loading inverse CDF: " << inverseCdfConfigFile);
1042 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
1043 if (xmlStrEqual( nodeRoot->name, BAD_CAST
"CDFMappings" )) {
1044 for( xmlNodePtr typeMappings = nodeRoot->children; typeMappings !=
nullptr; typeMappings = typeMappings->next ) {
1045 if (xmlStrEqual( typeMappings->name, BAD_CAST
m_xml_info_cdf[
i].at(
"name").c_str() )) {
1046 if (typeMappings->children != NULL) {
1047 for( xmlNodePtr nodeMappings = typeMappings->children; nodeMappings !=
nullptr; nodeMappings = nodeMappings->next) {
1049 if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable0" )) {
1052 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable1" )) {
1055 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable2" )) {
1058 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable3" )) {
1061 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable4" )) {
1081 return StatusCode::SUCCESS;
1085 std::map<double, double> mappings;
1089 for( xmlNodePtr
node = nodeParent->children;
node !=
nullptr;
node =
node->next ) {
1091 if (xmlStrEqual(
node->
name, BAD_CAST
"CDFmap" )) {
1092 if ((xmlBuff = xmlGetProp(
node, BAD_CAST
"ref")) !=
nullptr) {
1093 ref =
atof( (
const char*) xmlBuff );
1095 if ((xmlBuff = xmlGetProp(
node, BAD_CAST
"quant")) !=
nullptr) {
1096 quant =
atof( (
const char*) xmlBuff );
1098 mappings.insert(std::pair<double, double>(
ref, quant) );
1109 auto upper = inverse_cdf_map.upper_bound(norm_cdf);
1110 auto lower =
upper--;
1112 double m = (
upper->second - lower->second)/(
upper->first - lower->first);
1113 double c = lower->second -
m * lower->first;
1114 double transformed =
m * norm_cdf +
c;
1124 std::string energyPointsString;
1129 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] available energy points: " << energyPointsString);
1134 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy > largest energy point, returning greatest energy point: " <<
m_energyPoints.back());
1138 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy < smallest energy point, returning smallest energy point: " << *upperEnergy);
1139 return *upperEnergy;
1142 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] energy points upper_bound: "<< *upperEnergy);
1144 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1146 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Shooting random number: "<< randomShoot);
1148 double midPoint = *std::prev(upperEnergy)*M_SQRT2;
1152 double distance = std::abs(
energy - *std::prev(upperEnergy))/((midPoint) - *std::prev(upperEnergy));
1154 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy is closest to prev(upper_bound) in log(energy), distance: " <<
distance );
1157 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning upper_bound " << *upperEnergy );
1158 return *upperEnergy;
1160 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1162 return *std::prev(upperEnergy);
1164 else if(
energy > midPoint){
1166 double distance = std::abs(
energy - *upperEnergy)/((*upperEnergy - midPoint));
1168 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy is closest to upper_bound in log(energy), distance: " <<
distance );
1171 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1172 return *std::prev(upperEnergy);
1174 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning upper_bound " << *upperEnergy );
1175 return *upperEnergy;
1178 return *upperEnergy;
1187 std::string etaPointsString;
1192 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] available eta points: " << etaPointsString);
1197 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming abs(eta) > largest eta point, returning greatest eta point: " <<
m_etaPoints.back());
1202 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] eta points upper_bound: "<< *upperEta);
1204 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1206 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Shooting random number: "<< randomShoot);
1208 if(std::abs(
absEta - *upperEta) < std::abs(
absEta - *std::prev(upperEta))){
1210 double distance = std::abs(
absEta - *upperEta)/((*upperEta - *std::prev(upperEta))/2);
1212 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] abs(eta) is closer to eta points upper_bound, distance: " <<
distance );
1215 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning upper_bound " << *upperEta );
1219 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1221 return *std::prev(upperEta);
1223 else if(std::abs(
absEta - *std::prev(upperEta)) < std::abs(
absEta - *upperEta)){
1226 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] prev of upper bound is begin, returning that: " << *std::prev(upperEta) );
1227 return *std::prev(upperEta);
1230 double distance = std::abs(
absEta - *std::prev(upperEta))/((*std::prev(upperEta) - *std::prev(std::prev(upperEta)))/2);
1232 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] abs(eta) is closer to eta points prev(upper_bound), distance: " <<
distance );
1235 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning prev(prev(upper_bound)) " << *std::prev(std::prev(upperEta)) );
1237 return *std::prev(std::prev(upperEta));
1239 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1241 return *std::prev(upperEta);
1244 return *std::prev(upperEta);
1249 double minEnergy,
int maxNumParticles,
double numParticlesFactor,
1250 double energyFactor,
double posAngleFactor,
double momAngleFactor)
1252 G4ParticleDefinition* secG4Particle = ptable.FindParticle(std::abs(pdg));
1253 double restMass = secG4Particle->GetPDGMass();
1258 if (!pdf_num )
return StatusCode::FAILURE;
1264 return StatusCode::FAILURE;
1272 return StatusCode::FAILURE;
1280 return StatusCode::FAILURE;
1287 return StatusCode::FAILURE;
1294 return StatusCode::FAILURE;
1299 particle->setNumParticlesPDF(std::move(pdf_num));
1300 particle->setPCA0PDF(std::move(pdf_pca0));
1301 particle->setPCA1PDF(std::move(pdf_pca1));
1302 particle->setPCA2PDF(std::move(pdf_pca2));
1303 particle->setPCA3PDF(std::move(pdf_pca3));
1304 particle->setPCA4PDF(std::move(pdf_pca4));
1307 minEnergy = ( minEnergy > restMass ) ? minEnergy : restMass;
1309 particle->setMaxNumParticles(maxNumParticles);
1310 particle->setNumParticlesFactor(numParticlesFactor);
1311 particle->setEnergyFactor(energyFactor);
1312 particle->setPosAngleFactor(posAngleFactor);
1313 particle->setMomAngleFactor(momAngleFactor);
1318 return StatusCode::SUCCESS;
1322 double minCorrEnergy,
double fullCorrEnergy)
1330 return StatusCode::FAILURE;
1333 std::stringstream
name;
1334 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID1) <<
"__y_PDG" << std::abs(pdgID2) <<
"__lowE";
1337 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID1) <<
"__y_PDG" << std::abs(pdgID2) <<
"__highE";
1340 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID2) <<
"__y_PDG" << std::abs(pdgID1) <<
"__lowE";
1343 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID2) <<
"__y_PDG" << std::abs(pdgID1) <<
"__highE";
1346 if ( (!hist1_2_lowE) || (!hist2_1_lowE) || (!hist1_2_highE) || (!hist2_1_highE) )
1348 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to retrieve the correlation data for PDG IDs " << pdgID1 <<
" and " << pdgID2);
1349 return StatusCode::FAILURE;
1360 m_particles[pdgID1]->setCorrelation(pdgID2, hist2_1_lowE, hist2_1_highE,
1361 minCorrEnergy, fullCorrEnergy,
1362 lowE, midE, upperE);
1363 m_particles[pdgID2]->setCorrelation(pdgID1, hist1_2_lowE, hist1_2_highE,
1364 minCorrEnergy, fullCorrEnergy,
1365 lowE, midE, upperE);
1366 return StatusCode::SUCCESS;
1376 std::unique_ptr<PunchThroughPDFCreator>
pdf = std::make_unique<PunchThroughPDFCreator>();
1383 TDirectory *
dir = (TDirectory*)fileLookupTable->Get(
dirName.str().c_str());
1391 TIter keyList(
dir->GetListOfKeys());
1394 while ((
key = (TKey*)keyList())) {
1397 TH1*
hist =
nullptr;
1400 if(strcmp(
key->GetClassName(),
"TH1F") == 0){
1413 const int energy = std::stoi(strEnergy);
1414 const int etaMin = std::stoi(strEtaMin);
1420 const double energyDbl =
static_cast<double>(
energy);
1421 const double etaDbl =
static_cast<double>(
etaMin)/100.;
1440 const std::string_view
str( cstr);
1441 const std::string_view
pattern( cpattern);
1444 if (
pos == std::string::npos)
1446 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to retrieve floating point number from string");
1447 return -999999999999.;
1449 const std::string_view substring =
str.substr(
pos+
pattern.length());
1450 std::from_chars(substring.data(), substring.data() + substring.size(),
num);
1464 const double theta1 =
atan (R1 / z1);
1465 const double theta2 =
atan (R1 / z2);
1466 const double theta3 =
atan (R2 / z2);
1484 else if (
theta >= theta3 &&
theta < (TMath::Pi() - theta3) )
1489 else if (
theta >= (TMath::Pi() - theta3) &&
theta < (TMath::Pi() - theta2) )
1494 else if (
theta >= (TMath::Pi() - theta2) &&
theta < (TMath::Pi() - theta1) )
1499 else if (
theta >= (TMath::Pi() - theta1) &&
theta <= TMath::Pi() )
1508 ATH_MSG_WARNING(
"[PunchThroughG4Tool::punchTroughPosPropagator] Given theta angle is incorrect, setting particle position to (0, 0, 0)");
1509 x = 0.0;
y = 0.0;
z = 0.0;
r = 0.0;
1514 G4ThreeVector posVec(
x,
y,
z);
1516 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::punchTroughPosPropagator] position of produced punch-through particle: x = " <<
x <<
" y = "<<
y <<
" z = "<<
z<<
" r = "<< posVec.perp() <<
"std::sqrt(x^2+y^2) = "<< std::sqrt(
x *
x +
y *
y));