20 #include <string_view>
27 #include "CLHEP/Random/RandFlat.h"
51 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open or read the inverse CDF config");
52 return StatusCode::FAILURE;
58 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open or read the inverse PCA config");
59 return StatusCode::FAILURE;
65 ATH_MSG_WARNING(
"[PunchThroughG4Tool] size of infoMap for PCA and CDF differs! Something is wrong with input xml files.");
66 return StatusCode::FAILURE;
69 ATH_MSG_INFO(
"[PunchThroughG4Tool] initialization is successful" );
70 return StatusCode::SUCCESS;
74 G4ParticleTable *ptable = G4ParticleTable::GetParticleTable();
94 ATH_MSG_VERBOSE(
"VERBOSE: [PunchThroughG4Tool] registering punch-through particle type with pdg = " << pdg );
95 if (
registerPunchThroughParticle( *ptable, pdg, doAnti, minEnergy, maxNum, numFactor, energyFactor, posAngleFactor, momAngleFactor ) != StatusCode::SUCCESS)
97 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to register punch-through particle type with pdg = " << pdg);
98 return StatusCode::FAILURE;
102 return StatusCode::SUCCESS;
108 ATH_MSG_INFO(
"[PunchThroughG4Tool] PunchThroughG4Tool::initializePhysics() called");
110 if (resolvedFileName.empty()) {
112 return StatusCode::FAILURE;
114 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Parametrisation file found: " << resolvedFileName );
118 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open the lookup-table for the punch-through simulation (file does not exist)");
119 return StatusCode::FAILURE;
123 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to open the lookup-table for the punch-through simulation (wrong or empty file?)");
124 return StatusCode::FAILURE;
142 ATH_MSG_FATAL (
"[PunchThroughG4Tool] Could not retrieve GeometryIdentifier Service. Abort");
143 return StatusCode::FAILURE;
150 return StatusCode::FAILURE;
156 const std::vector<std::pair<double, double>>* rzMS = &(
m_envDefSvc->getMuonRZBoundary());
157 const std::vector<std::pair<double, double>>* rzCalo = &(
m_envDefSvc->getCaloRZBoundary());
159 return StatusCode::SUCCESS;
172 ATH_MSG_WARNING(
"[PunchThroughG4Tool] more punch-through particle correlations are given, than punch-through particle types are registered (skipping the last ones)");
177 for (
unsigned int num = 0;
num < numCorrelations;
num++ )
185 if ( ! pdg2)
continue;
187 if (
registerCorrelation(pdg1, pdg2, minCorrEnergy, fullCorrEnergy) != StatusCode::SUCCESS )
189 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to register punch-through particle correlation for pdg1=" << pdg1 <<
" pdg2=" << pdg2 );
190 return StatusCode::FAILURE;
194 return StatusCode::SUCCESS;
200 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] getCaloMSVars()==> m_R1 = "<< caloMSVarsVect[0] <<
", m_R2 = " << caloMSVarsVect[1] <<
", m_z1 = " << caloMSVarsVect[2] <<
", m_z2 = " << caloMSVarsVect[3]);
202 return caloMSVarsVect;
206 const std::vector<std::pair<double, double>>* rzCalo)
209 found1=
false; found2=
false;
213 for (
const auto & [r_tempCalo , z_tempCalo] : *rzCalo )
218 for (
const auto & [r_tempMS , z_tempMS] : *rzMS )
221 if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && found1==
false )
224 m_z1=std::fabs(z_tempMS);
229 else if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && r_tempCalo!=
m_R1 && std::fabs(z_tempCalo)!=
m_z1)
232 m_z2=std::fabs(z_tempMS);
237 if (found1==
true && found2==
true)
break;
242 if (found1 ==
false){
243 ATH_MSG_ERROR (
"[PunchThroughG4Tool] first coordinate of calo-MS border not found");
244 return StatusCode::FAILURE;
246 if (found2 ==
false){
247 ATH_MSG_ERROR (
"[PunchThroughG4Tool] second coordinate of calo-MS border not found; first one is: R1 ="<<
m_R1<<
" z1 ="<<
m_z1);
248 return StatusCode::FAILURE;
257 return StatusCode::FAILURE;
262 return StatusCode::SUCCESS;
272 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] finalize() successful" );
274 return StatusCode::SUCCESS;
279 G4ParticleDefinition* secG4Particle = ptable.FindParticle(secondarySignedPDG);
280 double mass = secG4Particle->GetPDGMass();
281 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkParticleTable] secondarySignedPDG = " << secondarySignedPDG <<
", mass = "<<
mass);
286 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] starting punch-through simulation");
289 std::vector<std::map<std::string, double>> secKinematicsMapVect;
292 const G4Track * g4PrimaryTrack = fastTrack.GetPrimaryTrack();
295 const G4ParticleDefinition * mainG4Particle = g4PrimaryTrack->GetDefinition();
298 int pdgID = mainG4Particle->GetPDGEncoding();
299 float mainPartMass = mainG4Particle->GetPDGMass();
300 float mainMomMag2 = g4PrimaryTrack->GetMomentum().mag2();
301 float mainPartEta = g4PrimaryTrack->GetPosition().eta();
303 const G4ThreeVector mainMomentumDir = g4PrimaryTrack->GetMomentumDirection();
304 const G4ThreeVector mainMomentum = g4PrimaryTrack->GetMomentum();
305 const G4ThreeVector mainPosition = g4PrimaryTrack->GetPosition();
308 const double initEnergy = std::sqrt( mainMomMag2 + mainPartMass*mainPartMass );
309 const double initEta = mainPartEta;
311 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] position of the input particle: r"<<mainPosition.perp()<<
" z= "<<mainPosition.z() );
315 const Amg::Vector3D amg3DPosVec(mainPosition.x(), mainPosition.y(), mainPosition.z());
316 const Amg::Vector3D amg3DMomDirVec(mainMomentumDir.x(), mainMomentumDir.y(), mainMomentumDir.z());
317 const Amg::Vector3D amg3DMomVec(mainMomentum.x(), mainMomentum.y(), mainMomentum.z());
322 ATH_MSG_DEBUG(
"[PunchThroughG4Tool](GeoIDSvc) input particle doesn't point to calorimeter"<<
"Next GeoID: "<< nextGeoID );
334 for ( ; pdgIt != pdgItEnd; ++pdgIt, ++minEnergyIt)
336 if (std::abs(pdgID) == *pdgIt){
337 if(initEnergy < *minEnergyIt){
338 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle does not meet initiator min energy requirement. Dropping it in the calo.");
347 if (pdgIt == pdgItEnd)
349 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle is not registered as punch-through initiator. Dropping it in the calo.");
356 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle does not meet initiator eta range requirement. Dropping it in the calo.");
361 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] punchThroughProbability output: " << punchThroughProbability <<
" RandFlat: " << punchThroughClassifierRand );
364 if( punchThroughClassifierRand > punchThroughProbability){
365 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] particle not classified to create punch through. Dropping it in the calo.");
383 std::map<int, int> corrPdgNumDone;
389 while(secKinematicsMapVect.empty() && nTries < maxTries) {
394 int doPdg = currentParticle.first;
396 int corrPdg = currentParticle.second->getCorrelatedPdg();
405 if ( itPdgPos == corrPdgNumDone.end() ) itPdgPos = corrPdgNumDone.find(corrPdg);
409 if ( itPdgPos == corrPdgNumDone.end() )
412 if ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) doPdg = corrPdg;
415 corrPdgNumDone[doPdg] =
getAllParticles(*g4PrimaryTrack, secKinematicsMapVect, rndmEngine, doPdg, interpEnergy, interpEta);
424 const int donePdg = itPdgPos->first;
425 const int doneNumPart = itPdgPos->second;
427 if (donePdg == doPdg) doPdg = corrPdg;
430 getCorrelatedParticles(*g4PrimaryTrack, secKinematicsMapVect, doPdg, doneNumPart, rndmEngine, interpEnergy, interpEta);
440 getAllParticles(*g4PrimaryTrack, secKinematicsMapVect, rndmEngine, doPdg, interpEnergy, interpEta);
445 return secKinematicsMapVect;
448 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)
451 float initParticleTheta = g4PrimaryTrack.GetPosition().theta();
452 float initParticlePhi = g4PrimaryTrack.GetPosition().phi();
456 double minAllowedEnergy =
p->getMinEnergy();
460 if ( numParticles < 0 )
474 numParticles =
int(
p->getNumParticlesPDF()->getRand(rndmEngine,
parameters) );
477 numParticles = lround( numParticles *=
p->getNumParticlesFactor() );
482 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] adding " << numParticles <<
" punch-through particles with pdg code: " << pdg);
485 for (
int numCreated = 0; numCreated < numParticles; numCreated++ )
488 std::map<std::string, double> secondaryKinematicsMap =
getOneParticleKinematics(rndmEngine, pdg, initParticleTheta, initParticlePhi, interpEnergy, interpEta);
491 double energy = secondaryKinematicsMap.at(
"energy");
492 if(
energy > minAllowedEnergy){
494 secKinematicsMapVect.push_back(secondaryKinematicsMap);
499 std::size_t numSecondaries = secKinematicsMapVect.size();
502 return (numSecondaries);
505 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)
508 const G4ParticleDefinition * mainG4Particle = g4PrimaryTrack.GetDefinition();
510 float mainMomMag2 = g4PrimaryTrack.GetMomentum().mag2();
511 float mainPartMass = mainG4Particle->GetPDGMass();
516 const double initEnergy = std::sqrt( mainMomMag2 + mainPartMass*mainPartMass );
519 double rand = CLHEP::RandFlat::shoot(rndmEngine)
520 *(
p->getFullCorrelationEnergy() -
p->getMinCorrelationEnergy())
521 +
p->getMinCorrelationEnergy();
524 if ( initEnergy <
rand )
527 return getAllParticles(g4PrimaryTrack, secKinematicsMapVect, rndmEngine, pdg, interpEnergy, interpEta);
532 double *histDomains =
p->getCorrelationHistDomains();
533 TH2F *hist2d =
nullptr;
536 if ( initEnergy < histDomains[1])
540 hist2d =
p->getCorrelationLowEHist();
544 double rand = CLHEP::RandFlat::shoot(rndmEngine)*(histDomains[2]-histDomains[1]) + histDomains[1];
545 hist2d = ( initEnergy <
rand) ?
p->getCorrelationLowEHist() :
p->getCorrelationHighEHist();
551 Int_t xbin = hist2d->GetXaxis()->FindFixBin(corrParticles);
552 int numParticles = 0;
558 double rand = CLHEP::RandFlat::shoot(rndmEngine);
560 for (
int ybin = 1; ybin <= hist2d->GetNbinsY(); ybin++ )
562 sum += hist2d->GetBinContent(xbin, ybin);
566 numParticles = ybin - 1;
571 numParticles = lround( numParticles *
p->getNumParticlesFactor() );
576 return getAllParticles(g4PrimaryTrack, secKinematicsMapVect, rndmEngine, pdg, interpEnergy, interpEta, numParticles);
587 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] passedPCAIterator ==> pcaCdfIterator = "<< pcaCdfIterator <<
" , pdg = "<< secondaryPDG <<
" , interpEnergy = "<< interpEnergy <<
" MeV, interpEta(*100) = "<< interpEta*100);
592 if (
p->getdoAnti() )
595 double rand = CLHEP::RandFlat::shoot(rndmEngine);
597 if (
rand > 0.5) anti = -1;
602 std::vector<int> parInitEnergyEta;
603 parInitEnergyEta.push_back(
std::round(interpEnergy) );
604 parInitEnergyEta.push_back(
std::round(interpEta*100) );
608 double deltaTheta = 0.;
610 double momDeltaTheta = 0.;
611 double momDeltaPhi = 0.;
613 double principal_component_0 = 0.;
614 double principal_component_1 = 0.;
615 double principal_component_2 = 0.;
616 double principal_component_3 = 0.;
617 double principal_component_4 = 0.;
618 std::vector<double> transformed_variables;
620 principal_component_0 =
p->getPCA0PDF()->getRand(rndmEngine, parInitEnergyEta);
621 principal_component_1 =
p->getPCA1PDF()->getRand(rndmEngine, parInitEnergyEta);
622 principal_component_2 =
p->getPCA2PDF()->getRand(rndmEngine, parInitEnergyEta);
623 principal_component_3 =
p->getPCA3PDF()->getRand(rndmEngine, parInitEnergyEta);
624 principal_component_4 =
p->getPCA4PDF()->getRand(rndmEngine, parInitEnergyEta);
626 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 );
628 std::vector<double> principal_components {
629 principal_component_0,
630 principal_component_1,
631 principal_component_2,
632 principal_component_3,
633 principal_component_4
636 transformed_variables =
inversePCA(pcaCdfIterator,principal_components);
644 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Transformed punch through kinematics: energy = "<<
energy <<
" MeV deltaTheta = "<< deltaTheta <<
" deltaPhi = "<<
deltaPhi <<
" momDeltaTheta = "<< momDeltaTheta <<
" momDeltaPhi = "<< momDeltaPhi );
646 energy *=
p->getEnergyFactor();
649 if (energy < p->getMinEnergy()) {
650 energy =
p->getMinEnergy() + 10;
659 deltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
663 theta = initParticleTheta + deltaTheta*
p->getPosAngleFactor();
668 deltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
671 double phi = initParticlePhi +
deltaPhi*
p->getPosAngleFactor();
679 double momTheta = 0.;
683 momDeltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
686 momTheta =
theta + momDeltaTheta*
p->getMomAngleFactor();
688 while ( (momTheta >
M_PI) || (momTheta < 0.) );
691 momDeltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
693 double momPhi =
phi + momDeltaPhi*
p->getMomAngleFactor();
695 while ( std::fabs(momPhi) > 2*
M_PI) momPhi /= 2.;
696 while (momPhi >
M_PI) momPhi -= 2*
M_PI;
697 while (momPhi < -
M_PI) momPhi += 2*
M_PI;
700 std::map<std::string, double> secondaryKinematicsMap;
701 secondaryKinematicsMap.insert({
"anti" , anti });
702 secondaryKinematicsMap.insert({
"secondaryPDG" , secondaryPDG });
703 secondaryKinematicsMap.insert({
"energy" ,
energy });
704 secondaryKinematicsMap.insert({
"theta" ,
theta });
705 secondaryKinematicsMap.insert({
"phi" ,
phi });
706 secondaryKinematicsMap.insert({
"momTheta" , momTheta });
707 secondaryKinematicsMap.insert({
"momPhi" , momPhi });
709 return secondaryKinematicsMap;
715 double totEnergySecondaries = 0;
719 for (std::size_t
i = 0;
i < secKinematicsMapVect.size();
i++) {
720 energy = secKinematicsMapVect[
i].at(
"energy");
721 totEnergySecondaries +=
energy;
726 secKinematicsMapVect.begin(),
727 secKinematicsMapVect.end(),
728 [](
const std::map<std::string, double>& lhs,
const std::map<std::string, double>& rhs) {
729 return lhs.at(
"energy") > rhs.at(
"energy");
734 if(totEnergySecondaries > mainEnergyInit){
735 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkEnergySumFromSecondaries] Case where energy of created secondaries more than parent track identified! ");
736 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::checkEnergySumFromSecondaries] ==> TotalSecondariesEnergy = " << totEnergySecondaries <<
", ParentEnergy = "<< mainEnergyInit);
740 while (totEnergySecondaries > mainEnergyInit && !secKinematicsMapVect.empty()) {
742 std::map<std::string, double> lastMap = secKinematicsMapVect.back();
745 double lastEnergy = lastMap.at(
"energy");
748 secKinematicsMapVect.pop_back();
751 totEnergySecondaries -= lastEnergy;
755 return secKinematicsMapVect;
758 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){
760 const G4ParticleDefinition* mainG4Particle = g4PrimaryTrack.GetDefinition();
761 float mainMomMag2 = g4PrimaryTrack.GetMomentum().mag2();
762 float mainPartMass = mainG4Particle->GetPDGMass();
763 double mainEnergyInit = std::sqrt(mainMomMag2 + mainPartMass * mainPartMass);
769 int numSecondaries = secKinematicsMapVect.size();
771 if(numSecondaries>0){
773 fastStep.SetNumberOfSecondaryTracks(numSecondaries);
776 double currentTime = g4PrimaryTrack.GetGlobalTime();
779 for(
int i=0;
i < numSecondaries;
i++){
780 int anti = (
int)(secKinematicsMapVect[
i].at(
"anti"));
781 int secondaryPDG = (
int)(secKinematicsMapVect[
i].at(
"secondaryPDG"));
782 int signedPDG = secondaryPDG*anti;
783 double energy = secKinematicsMapVect[
i].at(
"energy");
784 double theta = secKinematicsMapVect[
i].at(
"theta");
785 double phi = secKinematicsMapVect[
i].at(
"phi");
786 double momTheta = secKinematicsMapVect[
i].at(
"momTheta");
787 double momPhi = secKinematicsMapVect[
i].at(
"momPhi");
790 ATH_MSG_DEBUG(
"[PunchThroughG4Tool::createAllSecondaryTracks] createSecondaryTrack input parameters: currentTime = " << currentTime <<
" anti? = "<< anti <<
" signedPDG = "<< signedPDG <<
" energy = "<<
energy <<
" theta = "<<
theta <<
" phi = "<<
phi <<
" momTheta = "<< momTheta <<
" momPhi " << momPhi);
796 G4Exception(
"[PunchThroughG4Tool::createAllSecondaryTracks]",
"ExceptionError", FatalException,
"something went wrong while creating punch-through particle tracks");
801 secTrackCont.push_back( newSecTrack );
809 double energy,
double theta,
double phi,
double momTheta,
double momPhi,
const std::vector<double> &caloMSVars)
812 G4Track *newSecTrack =
nullptr;
814 G4ParticleDefinition* secG4Particle = ptable.FindParticle(secondarySignedPDG);
815 double mass = secG4Particle->GetPDGMass();
824 G4ThreeVector momVec;
826 momVec.setRThetaPhi(momMag,momTheta,momPhi);
827 ATH_MSG_DEBUG(
"[PunchThroughG4Tool]::createSecondaryTrack] setRThetaPhi pre input parameters: energy = " <<
energy <<
" mass = "<<
mass);
828 ATH_MSG_DEBUG(
"[PunchThroughG4Tool]::createSecondaryTrack] setRThetaPhi input parameters: std::sqrt(energy*energy - mass*mass) = " << std::sqrt(
energy*
energy -
mass*
mass) <<
" momTheta = "<< momTheta <<
" momPhi = "<< momPhi);
831 G4DynamicParticle dynParticle(secG4Particle,momVec);
832 newSecTrack = fastStep.CreateSecondaryTrack(dynParticle, posVec, currentTime,
false);
838 return 0.5 * TMath::Erfc(-
x * M_SQRT1_2);
843 std::vector<double>
result;
845 for (
const auto&
r :
m){
846 result.push_back(std::inner_product(
v.begin(),
v.end(),
r.begin(), 0.0));
855 constexpr
char delimiters =
',';
858 std::string_view::size_type lastPos =
str.find_first_not_of(delimiters, 0);
860 std::string_view::size_type
pos =
str.find_first_of(delimiters, lastPos);
862 while (std::string_view::npos !=
pos || std::string_view::npos != lastPos) {
864 std::string_view numbStr =
str.substr(lastPos,
pos - lastPos);
866 std::from_chars(numbStr.data(), numbStr.data() + numbStr.size(),
num);
869 lastPos =
str.find_first_not_of(delimiters,
pos);
871 pos =
str.find_first_of(delimiters, lastPos);
879 int pidStrSingle = std::abs(
pid);
883 for (
unsigned int i = 0;
i < mapvect.size();
i++){
884 const std::string &pidStr = mapvect[
i].at(
"pidStr");
885 auto v = str_to_list<int>(pidStr);
886 if(
std::find(
v.begin(),
v.end(),pidStrSingle)==
v.end())
continue;
887 const std::string &etaMinsStr = mapvect[
i].at(
"etaMins");
888 const std::string &etaMaxsStr = mapvect[
i].at(
"etaMaxs");
889 std::vector<double> etaMinsVect = str_to_list<double>(etaMinsStr);
890 std::vector<double> etaMaxsVect = str_to_list<double>(etaMaxsStr);
891 assert(etaMaxsVect.size() == etaMinsVect.size());
892 for (
unsigned int j = 0; j < etaMinsVect.size(); j++){
893 double etaMinToCompare = etaMinsVect[j];
894 double etaMaxToCompare = etaMaxsVect[j];
895 if((
eta >= etaMinToCompare) && (
eta < etaMaxToCompare)){
910 std::vector<std::map<std::string, std::string>> xml_info;
911 doc = xmlParseFile( xmlFilePath.c_str() );
914 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
915 if (xmlStrEqual( nodeRoot->name, BAD_CAST mainNode.c_str() )) {
916 for( xmlNodePtr nodeRootChild = nodeRoot->children; nodeRootChild !=
nullptr; nodeRootChild = nodeRootChild->next ) {
917 if (xmlStrEqual( nodeRootChild->name, BAD_CAST
"info" )) {
918 if (nodeRootChild->children != NULL) {
919 for( xmlNodePtr infoNode = nodeRootChild->children; infoNode !=
nullptr; infoNode = infoNode->next) {
920 if(xmlStrEqual( infoNode->name, BAD_CAST
"item" )){
921 std::map<std::string, std::string> xml_info_item;
923 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"name")) !=
nullptr) {
924 xml_info_item.insert({
"name",
reinterpret_cast<const char*
>(xmlBuff)});
926 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"etaMins")) !=
nullptr) {
927 xml_info_item.insert({
"etaMins",
reinterpret_cast<const char*
>(xmlBuff)});
929 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"etaMaxs")) !=
nullptr) {
930 xml_info_item.insert({
"etaMaxs",
reinterpret_cast<const char*
>(xmlBuff)});
932 if ((xmlBuff = xmlGetProp(infoNode, BAD_CAST
"pidStr")) !=
nullptr) {
933 xml_info_item.insert({
"pidStr",
reinterpret_cast<const char*
>(xmlBuff)});
936 xml_info.push_back(xml_info_item);
955 std::transform (transformed_variables.begin(), transformed_variables.end(),
m_PCA_means[pcaCdfIterator].begin(), transformed_variables.begin(), std::plus<double>());
957 return transformed_variables;
965 doc = xmlParseFile( inversePCAConfigFile.c_str() );
967 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Loading inversePCA: " << inversePCAConfigFile);
974 std::vector<std::vector<double>> PCA_matrix;
977 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
978 if (xmlStrEqual( nodeRoot->name, BAD_CAST
"PCAinverse" )) {
979 for( xmlNodePtr nodePCAinverse = nodeRoot->children; nodePCAinverse !=
nullptr; nodePCAinverse = nodePCAinverse->next ) {
981 if (xmlStrEqual( nodePCAinverse->name, BAD_CAST
m_xml_info_pca[
i].at(
"name").c_str() )) {
982 if (nodePCAinverse->children != NULL) {
983 for( xmlNodePtr pcaNode = nodePCAinverse->children; pcaNode !=
nullptr; pcaNode = pcaNode->next) {
985 if (xmlStrEqual( pcaNode->name, BAD_CAST
"PCAmatrix" )) {
986 std::vector<double> PCA_matrix_row;
987 for (
int i = 0;
i <= 4; ++
i) {
989 if ((xmlBuff = xmlGetProp(pcaNode, BAD_CAST
propName.c_str())) !=
nullptr) {
990 PCA_matrix_row.push_back(
atof(
reinterpret_cast<const char*
>(xmlBuff)));
993 PCA_matrix.push_back(PCA_matrix_row);
995 else if (xmlStrEqual( pcaNode->name, BAD_CAST
"PCAmeans" )) {
996 std::vector<double> PCA_means_row;
997 for (
int i = 0;
i <= 4; ++
i) {
999 if ((xmlBuff = xmlGetProp(pcaNode, BAD_CAST
propName.c_str())) !=
nullptr) {
1000 PCA_means_row.push_back(
atof(
reinterpret_cast<const char*
>(xmlBuff)));
1020 return StatusCode::SUCCESS;
1024 std::map<double, double> variable0_inverse_cdf_row;
1025 std::map<double, double> variable1_inverse_cdf_row;
1026 std::map<double, double> variable2_inverse_cdf_row;
1027 std::map<double, double> variable3_inverse_cdf_row;
1028 std::map<double, double> variable4_inverse_cdf_row;
1035 doc = xmlParseFile( inverseCdfConfigFile.c_str() );
1037 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Loading inverse CDF: " << inverseCdfConfigFile);
1046 for( xmlNodePtr nodeRoot =
doc->children; nodeRoot !=
nullptr; nodeRoot = nodeRoot->next) {
1047 if (xmlStrEqual( nodeRoot->name, BAD_CAST
"CDFMappings" )) {
1048 for( xmlNodePtr typeMappings = nodeRoot->children; typeMappings !=
nullptr; typeMappings = typeMappings->next ) {
1049 if (xmlStrEqual( typeMappings->name, BAD_CAST
m_xml_info_cdf[
i].at(
"name").c_str() )) {
1050 if (typeMappings->children != NULL) {
1051 for( xmlNodePtr nodeMappings = typeMappings->children; nodeMappings !=
nullptr; nodeMappings = nodeMappings->next) {
1053 if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable0" )) {
1056 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable1" )) {
1059 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable2" )) {
1062 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable3" )) {
1065 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable4" )) {
1085 return StatusCode::SUCCESS;
1089 std::map<double, double> mappings;
1093 for( xmlNodePtr
node = nodeParent->children;
node !=
nullptr;
node =
node->next ) {
1095 if (xmlStrEqual(
node->
name, BAD_CAST
"CDFmap" )) {
1096 if ((xmlBuff = xmlGetProp(
node, BAD_CAST
"ref")) !=
nullptr) {
1097 ref =
atof(
reinterpret_cast<const char*
> (xmlBuff) );
1099 if ((xmlBuff = xmlGetProp(
node, BAD_CAST
"quant")) !=
nullptr) {
1100 quant =
atof(
reinterpret_cast<const char*
> (xmlBuff) );
1102 mappings.insert(std::pair<double, double>(
ref, quant) );
1113 auto upper = inverse_cdf_map.upper_bound(norm_cdf);
1114 auto lower =
upper--;
1116 double m = (
upper->second - lower->second)/(
upper->first - lower->first);
1117 double c = lower->second -
m * lower->first;
1118 double transformed =
m * norm_cdf +
c;
1128 std::string energyPointsString;
1133 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] available energy points: " << energyPointsString);
1138 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy > largest energy point, returning greatest energy point: " <<
m_energyPoints.back());
1142 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy < smallest energy point, returning smallest energy point: " << *upperEnergy);
1143 return *upperEnergy;
1146 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] energy points upper_bound: "<< *upperEnergy);
1148 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1150 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Shooting random number: "<< randomShoot);
1152 double midPoint = *std::prev(upperEnergy)*M_SQRT2;
1156 double distance = std::abs(
energy - *std::prev(upperEnergy))/((midPoint) - *std::prev(upperEnergy));
1158 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy is closest to prev(upper_bound) in log(energy), distance: " <<
distance );
1161 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning upper_bound " << *upperEnergy );
1162 return *upperEnergy;
1164 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1166 return *std::prev(upperEnergy);
1168 else if(
energy > midPoint){
1170 double distance = std::abs(
energy - *upperEnergy)/((*upperEnergy - midPoint));
1172 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming energy is closest to upper_bound in log(energy), distance: " <<
distance );
1175 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1176 return *std::prev(upperEnergy);
1178 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning upper_bound " << *upperEnergy );
1179 return *upperEnergy;
1182 return *upperEnergy;
1191 std::string etaPointsString;
1196 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] available eta points: " << etaPointsString);
1201 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] incoming abs(eta) > largest eta point, returning greatest eta point: " <<
m_etaPoints.back());
1206 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] eta points upper_bound: "<< *upperEta);
1208 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1210 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] Shooting random number: "<< randomShoot);
1212 if(std::abs(
absEta - *upperEta) < std::abs(
absEta - *std::prev(upperEta))){
1214 double distance = std::abs(
absEta - *upperEta)/((*upperEta - *std::prev(upperEta))/2);
1216 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] abs(eta) is closer to eta points upper_bound, distance: " <<
distance );
1219 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning upper_bound " << *upperEta );
1223 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1225 return *std::prev(upperEta);
1227 else if(std::abs(
absEta - *std::prev(upperEta)) < std::abs(
absEta - *upperEta)){
1230 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] prev of upper bound is begin, returning that: " << *std::prev(upperEta) );
1231 return *std::prev(upperEta);
1234 double distance = std::abs(
absEta - *std::prev(upperEta))/((*std::prev(upperEta) - *std::prev(std::prev(upperEta)))/2);
1236 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] abs(eta) is closer to eta points prev(upper_bound), distance: " <<
distance );
1239 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot > distance, returning prev(prev(upper_bound)) " << *std::prev(std::prev(upperEta)) );
1241 return *std::prev(std::prev(upperEta));
1243 ATH_MSG_DEBUG(
"[PunchThroughG4Tool] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1245 return *std::prev(upperEta);
1248 return *std::prev(upperEta);
1253 double minEnergy,
int maxNumParticles,
double numParticlesFactor,
1254 double energyFactor,
double posAngleFactor,
double momAngleFactor)
1256 G4ParticleDefinition* secG4Particle = ptable.FindParticle(std::abs(pdg));
1257 double restMass = secG4Particle->GetPDGMass();
1262 if (!pdf_num )
return StatusCode::FAILURE;
1268 return StatusCode::FAILURE;
1276 return StatusCode::FAILURE;
1284 return StatusCode::FAILURE;
1291 return StatusCode::FAILURE;
1298 return StatusCode::FAILURE;
1303 particle->setNumParticlesPDF(std::move(pdf_num));
1304 particle->setPCA0PDF(std::move(pdf_pca0));
1305 particle->setPCA1PDF(std::move(pdf_pca1));
1306 particle->setPCA2PDF(std::move(pdf_pca2));
1307 particle->setPCA3PDF(std::move(pdf_pca3));
1308 particle->setPCA4PDF(std::move(pdf_pca4));
1311 minEnergy = ( minEnergy > restMass ) ? minEnergy : restMass;
1313 particle->setMaxNumParticles(maxNumParticles);
1314 particle->setNumParticlesFactor(numParticlesFactor);
1315 particle->setEnergyFactor(energyFactor);
1316 particle->setPosAngleFactor(posAngleFactor);
1317 particle->setMomAngleFactor(momAngleFactor);
1322 return StatusCode::SUCCESS;
1326 double minCorrEnergy,
double fullCorrEnergy)
1334 return StatusCode::FAILURE;
1337 std::stringstream
name;
1338 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID1) <<
"__y_PDG" << std::abs(pdgID2) <<
"__lowE";
1341 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID1) <<
"__y_PDG" << std::abs(pdgID2) <<
"__highE";
1344 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID2) <<
"__y_PDG" << std::abs(pdgID1) <<
"__lowE";
1347 name <<
"NumExitCorrelations/x_PDG" << std::abs(pdgID2) <<
"__y_PDG" << std::abs(pdgID1) <<
"__highE";
1350 if ( (!hist1_2_lowE) || (!hist2_1_lowE) || (!hist1_2_highE) || (!hist2_1_highE) )
1352 ATH_MSG_ERROR(
"[PunchThroughG4Tool] unable to retrieve the correlation data for PDG IDs " << pdgID1 <<
" and " << pdgID2);
1353 return StatusCode::FAILURE;
1364 m_particles[pdgID1]->setCorrelation(pdgID2, hist2_1_lowE, hist2_1_highE,
1365 minCorrEnergy, fullCorrEnergy,
1366 lowE, midE, upperE);
1367 m_particles[pdgID2]->setCorrelation(pdgID1, hist1_2_lowE, hist1_2_highE,
1368 minCorrEnergy, fullCorrEnergy,
1369 lowE, midE, upperE);
1370 return StatusCode::SUCCESS;
1380 std::unique_ptr<PunchThroughPDFCreator>
pdf = std::make_unique<PunchThroughPDFCreator>();
1387 TDirectory *
dir = (TDirectory*)fileLookupTable->Get(
dirName.str().c_str());
1395 TIter keyList(
dir->GetListOfKeys());
1398 while ((
key = (TKey*)keyList())) {
1401 TH1*
hist =
nullptr;
1404 if(strcmp(
key->GetClassName(),
"TH1F") == 0){
1417 const int energy = std::stoi(strEnergy);
1418 const int etaMin = std::stoi(strEtaMin);
1424 const double energyDbl =
static_cast<double>(
energy);
1425 const double etaDbl =
static_cast<double>(
etaMin)/100.;
1444 const std::string_view
str( cstr);
1445 const std::string_view
pattern( cpattern);
1448 if (
pos == std::string::npos)
1450 ATH_MSG_WARNING(
"[PunchThroughG4Tool] unable to retrieve floating point number from string");
1451 return -999999999999.;
1453 const std::string_view substring =
str.substr(
pos+
pattern.length());
1454 std::from_chars(substring.data(), substring.data() + substring.size(),
num);
1468 const double theta1 =
atan (R1 / z1);
1469 const double theta2 =
atan (R1 / z2);
1470 const double theta3 =
atan (R2 / z2);
1488 else if (
theta >= theta3 &&
theta < (TMath::Pi() - theta3) )
1493 else if (
theta >= (TMath::Pi() - theta3) &&
theta < (TMath::Pi() - theta2) )
1498 else if (
theta >= (TMath::Pi() - theta2) &&
theta < (TMath::Pi() - theta1) )
1503 else if (
theta >= (TMath::Pi() - theta1) &&
theta <= TMath::Pi() )
1512 ATH_MSG_WARNING(
"[PunchThroughG4Tool::punchTroughPosPropagator] Given theta angle is incorrect, setting particle position to (0, 0, 0)");
1513 x = 0.0;
y = 0.0;
z = 0.0;
r = 0.0;
1518 G4ThreeVector posVec(
x,
y,
z);
1520 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));