15 #include <string_view>
29 #include "HepPDT/ParticleDataTable.hh"
33 #include "CLHEP/Random/RandFlat.h"
63 const std::string&
name,
79 if (m_punchThroughClassifier.retrieve().isFailure() )
81 ATH_MSG_ERROR (m_punchThroughClassifier.propertyName() <<
": Failed to retrieve tool " << m_punchThroughClassifier.type());
82 return StatusCode::FAILURE;
87 if (resolvedFileName.empty()) {
88 ATH_MSG_ERROR(
"[ punchthrough ] Parametrisation file '" << m_filenameLookupTable <<
"' not found" );
89 return StatusCode::FAILURE;
91 ATH_MSG_INFO(
"[ punchthrough ] Parametrisation file found: " << resolvedFileName );
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;
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;
108 ATH_MSG_WARNING(
"[ punchthrough ] unable to open or read the inverse CDF config");
109 return StatusCode::FAILURE;
115 ATH_MSG_WARNING(
"[ punchthrough ] unable to open or read the inverse PCA config");
116 return StatusCode::FAILURE;
120 if (!(m_xml_info_pca.size() == m_xml_info_cdf.size()))
122 ATH_MSG_WARNING(
"[ punchthrough ] size of infoMap for PCA and CDF differs! Something is wrong with input xml files.");
123 return StatusCode::FAILURE;
127 ATH_CHECK( m_particlePropSvc.retrieve() );
130 m_particleDataTable = m_particlePropSvc->PDT();
131 if (!m_particleDataTable)
133 ATH_MSG_FATAL(
" [ punchthrough ] Could not get ParticleDataTable! Cannot associate pdg code with charge! Abort. " );
134 return StatusCode::FAILURE;
138 if ( !m_geoIDSvc.empty() && m_geoIDSvc.retrieve().isFailure())
140 ATH_MSG_FATAL (
"[ punchthrough ] Could not retrieve GeometryIdentifier Service. Abort");
141 return StatusCode::FAILURE;
145 if (m_envDefSvc.retrieve().isFailure() )
147 ATH_MSG_ERROR(
"[ punchthrough ] Could not retrieve " << m_envDefSvc );
148 return StatusCode::FAILURE;
153 for (
unsigned int num = 0;
num < m_punchThroughParticles.size();
num++ )
155 const int pdg = m_punchThroughParticles[
num];
157 const bool doAnti = (
num < m_doAntiParticles.size() ) ? m_doAntiParticles[
num] :
false;
159 const double minEnergy = (
num < m_minEnergy.size() ) ? m_minEnergy[
num] : 50.;
161 const int maxNum = (
num < m_minEnergy.size() ) ? m_maxNumParticles[
num] : -1;
163 const double numFactor = (
num < m_numParticlesFactor.size() ) ? m_numParticlesFactor[
num] : 1.;
165 const double posAngleFactor = (
num < m_posAngleFactor.size() ) ? m_posAngleFactor[
num] : 1.;
167 const double momAngleFactor = (
num < m_momAngleFactor.size() ) ? m_momAngleFactor[
num] : 1.;
169 const double energyFactor = (
num < m_energyFactor.size() ) ? m_energyFactor[
num] : 1.;
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)
176 ATH_MSG_ERROR(
"[ punchthrough ] unable to register punch-through particle type with pdg = " << pdg);
184 unsigned int numCorrelations = m_correlatedParticle.size();
185 if ( numCorrelations > m_punchThroughParticles.size() )
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();
192 for (
unsigned int num = 0;
num < numCorrelations;
num++ )
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.;
200 if ( ! pdg2)
continue;
202 if ( registerCorrelation(pdg1, pdg2, minCorrEnergy, fullCorrEnergy) != StatusCode::SUCCESS )
204 ATH_MSG_ERROR(
"[ punchthrough ] unable to register punch-through particle correlation for pdg1=" << pdg1 <<
" pdg2=" << pdg2 );
210 const RZPairVector* rzMS = &(m_envDefSvc->getMuonRZBoundary());
211 const RZPairVector* rzCalo = &(m_envDefSvc->getCaloRZBoundary());
214 found1=
false; found2=
false;
216 for (
size_t i=0;
i<rzCalo->size();++
i)
218 const double r_tempCalo = rzCalo->at(
i).first;
219 const double z_tempCalo = rzCalo->at(
i).second;
221 if (r_tempCalo> m_beamPipe)
223 for (
size_t j=0; j<rzMS->size();++j)
225 const double r_tempMS =rzMS->at(j).first;
226 const double z_tempMS =rzMS->at(j).second;
228 if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && found1==
false )
231 m_z1=std::fabs(z_tempMS);
235 else if (r_tempCalo==r_tempMS && z_tempCalo==z_tempMS && r_tempCalo!=m_R1 && std::fabs(z_tempCalo)!=m_z1)
238 m_z2=std::fabs(z_tempMS);
243 if (found1==
true && found2==
true)
break;
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);
252 double r_temp, z_temp;
253 if (m_R1>m_R2) { r_temp=m_R1; m_R1=m_R2; m_R2=r_temp; }
254 if (m_z1<m_z2) { z_temp=m_z1; m_z1=m_z2; m_z2=z_temp; }
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);
260 m_fileLookupTable->Close();
262 ATH_MSG_INFO(
"punchthrough initialization is successful" );
263 return StatusCode::SUCCESS;
274 for(
auto & each : m_particles) {
280 return StatusCode::SUCCESS;
290 ATH_MSG_DEBUG(
"[ punchthrough ] starting punch-through simulation");
293 auto isfpCont = std::make_unique<ISF::ISFParticleVector>();
301 ATH_MSG_VERBOSE (
"[ GeoIDSvc ] input particle doesn't point to calorimeter"<<
"Next GeoID: "<<m_geoIDSvc->identifyNextGeoID(isfp) );
308 std::vector<int>::const_iterator pdgIt = m_pdgInitiators.begin();
309 std::vector<int>::const_iterator pdgItEnd = m_pdgInitiators.end();
311 std::vector<int>::const_iterator minEnergyIt = m_initiatorsMinEnergy.begin();
313 for ( ; pdgIt != pdgItEnd; ++pdgIt, ++minEnergyIt)
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.");
325 if (pdgIt == pdgItEnd)
327 ATH_MSG_DEBUG(
"[ punchthrough ] particle is not registered as punch-through initiator. Dropping it in the calo.");
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.");
338 double punchThroughProbability = m_punchThroughClassifier->computePunchThroughProbability(isfp, simulstate);
341 double punchThroughClassifierRand = CLHEP::RandFlat::shoot(rndmEngine);
343 ATH_MSG_DEBUG(
"[ punchthrough ] punchThroughProbability output: " << punchThroughProbability <<
" RandFlat: " << punchThroughClassifierRand );
346 if( punchThroughClassifierRand > punchThroughProbability){
347 ATH_MSG_DEBUG(
"[ punchthrough ] particle not classified to create punch through. Dropping it in the calo.");
361 const double initEnergy = std::sqrt( isfp.
momentum().mag2() + isfp.
mass()*isfp.
mass() );
362 const double initEta = isfp.
position().eta();
365 const double interpEnergy = interpolateEnergy(initEnergy, rndmEngine);
366 const double interpEta = interpolateEta(initEta, rndmEngine);
368 std::map<int, int> corrPdgNumDone;
374 while(isfpCont->empty() && nTries < maxTries) {
376 for (
const auto& currentParticle : m_particles)
379 int doPdg = currentParticle.first;
381 int corrPdg = currentParticle.second->getCorrelatedPdg();
390 if (
pos == corrPdgNumDone.end() )
pos = corrPdgNumDone.find(corrPdg);
394 if (
pos == corrPdgNumDone.end() )
397 if ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) doPdg = corrPdg;
400 corrPdgNumDone[doPdg] = getAllParticles(isfp, *isfpCont, rndmEngine, doPdg, interpEnergy, interpEta);
409 const int donePdg =
pos->first;
410 const int doneNumPart =
pos->second;
412 if (donePdg == doPdg) doPdg = corrPdg;
415 getCorrelatedParticles(isfp, *isfpCont, doPdg, doneNumPart, rndmEngine, interpEnergy, interpEta);
424 else getAllParticles(isfp, *isfpCont, rndmEngine, doPdg, interpEnergy, interpEta);
431 if (!isfpCont->empty())
ATH_MSG_DEBUG(
"[ punchthrough ] returning ISFparticle vector , size: "<<isfpCont->size() );
436 ATH_MSG_DEBUG(
"position of produced punch-through particle: x = "<< position.x() <<
" y = "<< position.y() <<
" z = "<< position.z());
441 return isfpCont.release();
456 if ( numParticles < 0 )
470 numParticles =
int(
p->getNumParticlesPDF()->getRand(rndmEngine,
parameters) );
473 numParticles = lround( numParticles *=
p->getNumParticlesFactor() );
478 ATH_MSG_VERBOSE(
"[ punchthrough ] adding " << numParticles <<
" punch-through particles with pdg " << pdg);
481 double energyRest = std::sqrt( isfp.
momentum().mag2() + isfp.
mass()*isfp.
mass() );
482 double minEnergy =
p->getMinEnergy();
485 for ( numCreated = 0; (numCreated < numParticles) && (energyRest > minEnergy); numCreated++ )
493 ATH_MSG_ERROR(
"[ punchthrough ] something went wrong while creating punch-through particles");
498 const double restMass = m_particleDataTable->particle(std::abs(pdg))->mass();
499 double curEnergy = std::sqrt(
par->momentum().mag2() + restMass*restMass);
503 energyRest -= curEnergy;
506 isfpCont.push_back(
par );
523 const double initEnergy = std::sqrt( isfp.
momentum().mag2() + isfp.
mass()*isfp.
mass() );
526 double rand = CLHEP::RandFlat::shoot(rndmEngine)
527 *(
p->getFullCorrelationEnergy()-
p->getMinCorrelationEnergy())
528 +
p->getMinCorrelationEnergy();
529 if ( initEnergy <
rand )
532 return getAllParticles(isfp, isfpCont, rndmEngine, pdg, interpEnergy, interpEta);
537 double *histDomains =
p->getCorrelationHistDomains();
538 TH2F *hist2d =
nullptr;
541 if ( initEnergy < histDomains[1])
545 hist2d =
p->getCorrelationLowEHist();
549 double rand = CLHEP::RandFlat::shoot(rndmEngine)*(histDomains[2]-histDomains[1])
551 hist2d = ( initEnergy <
rand) ?
p->getCorrelationLowEHist()
552 :
p->getCorrelationHighEHist();
559 Int_t xbin = hist2d->GetXaxis()->FindFixBin(corrParticles);
560 int numParticles = 0;
566 double rand = CLHEP::RandFlat::shoot(rndmEngine);
568 for (
int ybin = 1; ybin <= hist2d->GetNbinsY(); ybin++ )
570 sum += hist2d->GetBinContent(xbin, ybin);
574 numParticles = ybin - 1;
579 numParticles = lround( numParticles *
p->getNumParticlesFactor() );
584 return getAllParticles(isfp, isfpCont, rndmEngine, pdg, interpEnergy, interpEta, numParticles);
598 int pcaCdfIterator = passedParamIterator(pdg, interpEta*100, m_xml_info_pca);
600 ATH_MSG_DEBUG(
"[ punchthrough ] passedPCAIterator ==> pcaCdfIterator = "<< pcaCdfIterator <<
" , pdg = "<< pdg <<
" , interpEnergy = "<< interpEnergy <<
" MeV, interpEta(*100) = "<< interpEta*100);
604 if (
p->getdoAnti() )
607 double rand = CLHEP::RandFlat::shoot(rndmEngine);
609 if (
rand > 0.5) anti = -1;
614 std::vector<int> parInitEnergyEta;
615 parInitEnergyEta.push_back(
std::round(interpEnergy) );
616 parInitEnergyEta.push_back(
std::round(interpEta*100) );
620 double deltaTheta = 0.;
622 double momDeltaTheta = 0.;
623 double momDeltaPhi = 0.;
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;
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);
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 );
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
649 transformed_variables = inversePCA(pcaCdfIterator,principal_components);
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]);
657 ATH_MSG_DEBUG(
"Transformed punch through kinematics: energy = "<<
energy <<
" MeV deltaTheta = "<< deltaTheta <<
" deltaPhi = "<<
deltaPhi <<
" momDeltaTheta = "<< momDeltaTheta <<
" momDeltaPhi = "<< momDeltaPhi );
659 energy *=
p->getEnergyFactor();
660 if (energy < p->getMinEnergy()) {
661 energy =
p->getMinEnergy() + 10;
671 deltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
674 theta = isfp.
position().theta() + deltaTheta*
p->getPosAngleFactor();
677 while ( (theta >
M_PI) || (theta < 0.) );
680 deltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
684 while ( std::fabs(phi) > 2*
M_PI) phi /= 2.;
692 double momTheta = 0.;
696 momDeltaTheta *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
699 momTheta = theta + momDeltaTheta*
p->getMomAngleFactor();
702 while ( (momTheta >
M_PI) || (momTheta < 0.) );
706 momDeltaPhi *= ( CLHEP::RandFlat::shoot(rndmEngine) > 0.5 ) ? 1. : -1.;
708 double momPhi = phi + momDeltaPhi*
p->getMomAngleFactor();
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;
716 ATH_MSG_DEBUG(
"createExitPs input parameters: doAnti? = "<< pdg*anti <<
" energy = "<<
energy <<
" theta = "<< theta <<
" phi = "<< phi <<
" momTheta = "<< momTheta <<
" momPhi " << momPhi );
726 return 0.5 * TMath::Erfc(-
x * M_SQRT1_2);
731 std::vector<double>
result;
733 for (
const auto&
r :
m){
734 result.push_back(std::inner_product(
v.begin(),
v.end(),
r.begin(), 0.0));
743 constexpr
char delimiters =
',';
746 std::string_view::size_type lastPos =
str.find_first_not_of(delimiters, 0);
748 std::string_view::size_type
pos =
str.find_first_of(delimiters, lastPos);
750 while (std::string_view::npos !=
pos || std::string_view::npos != lastPos) {
752 std::string_view numbStr =
str.substr(lastPos,
pos - lastPos);
754 std::from_chars(numbStr.data(), numbStr.data() + numbStr.size(),
num);
757 lastPos =
str.find_first_not_of(delimiters,
pos);
759 pos =
str.find_first_of(delimiters, lastPos);
767 int pidStrSingle = std::abs(
pid);
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++){
781 double etaMinToCompare = etaMinsVect[j];
782 double etaMaxToCompare = etaMaxsVect[j];
783 if((eta >= etaMinToCompare) && (eta < etaMaxToCompare)){
794 std::vector<std::map<std::string, std::string>> xml_info;
795 xmlDocPtr
doc = xmlParseFile( xmlFilePath.c_str() );
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);
823 std::vector<double> transformed_variables = dotProduct(m_inverse_PCA_matrix[pcaCdfIterator],
variables);
825 std::transform (transformed_variables.begin(), transformed_variables.end(), m_PCA_means[pcaCdfIterator].begin(), transformed_variables.begin(), std::plus<double>());
827 return transformed_variables;
832 xmlDocPtr
doc = xmlParseFile( inversePCAConfigFile.c_str() );
834 ATH_MSG_INFO(
"[ punchthrough ] Loading inversePCA: " << inversePCAConfigFile);
837 m_xml_info_pca = getInfoMap(
"PCAinverse",inversePCAConfigFile);
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"));
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 ) {
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) {
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);
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);
879 m_inverse_PCA_matrix.push_back(PCA_matrix);
882 return StatusCode::SUCCESS;
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;
894 xmlDocPtr
doc = xmlParseFile( inverseCdfConfigFile.c_str() );
896 ATH_MSG_INFO(
"[ punchthrough ] Loading inverse CDF: " << inverseCdfConfigFile);
899 m_xml_info_cdf = getInfoMap(
"CDFMappings",inverseCdfConfigFile);
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"));
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) {
912 if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable0" )) {
913 variable0_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
915 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable1" )) {
916 variable1_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
918 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable2" )) {
919 variable2_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
921 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable3" )) {
922 variable3_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
924 else if (xmlStrEqual( nodeMappings->name, BAD_CAST
"variable4" )) {
925 variable4_inverse_cdf_row = getVariableCDFmappings(nodeMappings);
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);
941 return StatusCode::SUCCESS;
946 std::map<double, double> mappings;
948 for( xmlNodePtr
node = nodeParent->children;
node !=
nullptr;
node =
node->next ) {
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" ) );
954 mappings.insert(std::pair<double, double>(
ref, quant) );
964 double norm_cdf = normal_cdf(
variable);
966 auto upper = inverse_cdf_map.upper_bound(norm_cdf);
967 auto lower =
upper--;
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;
981 std::string energyPointsString;
982 for (
auto element:m_energyPoints){
986 ATH_MSG_DEBUG(
"[ punchthrough ] available energy points: " << energyPointsString);
988 auto const upperEnergy = std::upper_bound(m_energyPoints.begin(), m_energyPoints.end(),
energy);
990 if(upperEnergy == m_etaPoints.end()){
991 ATH_MSG_DEBUG(
"[ punchthrough ] incoming energy > largest energy point, returning greatest energy point: " << m_energyPoints.back());
992 return m_energyPoints.back();
994 else if(upperEnergy == m_etaPoints.begin()){
995 ATH_MSG_DEBUG(
"[ punchthrough ] incoming energy < smallest energy point, returning smallest energy point: " << *upperEnergy);
999 ATH_MSG_DEBUG(
"[ punchthrough ] energy points upper_bound: "<< *upperEnergy);
1001 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1003 ATH_MSG_DEBUG(
"[ punchthrough ] Shooting random number: "<< randomShoot);
1005 double midPoint = *std::prev(upperEnergy)*M_SQRT2;
1009 double distance = std::abs(
energy - *std::prev(upperEnergy))/((midPoint) - *std::prev(upperEnergy));
1011 ATH_MSG_DEBUG(
"[ punchthrough ] incoming energy is closest to prev(upper_bound) in log(energy), distance: " <<
distance );
1014 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot < distance, returning upper_bound " << *upperEnergy );
1015 return *upperEnergy;
1017 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot > distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1019 return *std::prev(upperEnergy);
1021 else if(
energy > midPoint){
1023 double distance = std::abs(
energy - *upperEnergy)/((*upperEnergy - midPoint));
1025 ATH_MSG_DEBUG(
"[ punchthrough ] incoming energy is closest to upper_bound in log(energy), distance: " <<
distance );
1028 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEnergy) );
1029 return *std::prev(upperEnergy);
1031 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot > distance, returning upper_bound " << *upperEnergy );
1032 return *upperEnergy;
1035 return *upperEnergy;
1040 double absEta = std::abs(eta);
1044 std::string etaPointsString;
1045 for (
auto element:m_etaPoints){
1049 ATH_MSG_DEBUG(
"[ punchthrough ] available eta points: " << etaPointsString);
1051 auto const upperEta = std::upper_bound(m_etaPoints.begin(), m_etaPoints.end(),
absEta);
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();
1059 ATH_MSG_DEBUG(
"[ punchthrough ] eta points upper_bound: "<< *upperEta);
1061 double randomShoot = CLHEP::RandFlat::shoot(rndmEngine);
1063 ATH_MSG_DEBUG(
"[ punchthrough ] Shooting random number: "<< randomShoot);
1065 if(std::abs(
absEta - *upperEta) < std::abs(
absEta - *std::prev(upperEta))){
1067 double distance = std::abs(
absEta - *upperEta)/((*upperEta - *std::prev(upperEta))/2);
1069 ATH_MSG_DEBUG(
"[ punchthrough ] abs(eta) is closer to eta points upper_bound, distance: " <<
distance );
1072 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot > distance, returning upper_bound " << *upperEta );
1076 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1078 return *std::prev(upperEta);
1080 else if(std::abs(
absEta - *std::prev(upperEta)) < std::abs(
absEta - *upperEta)){
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);
1087 double distance = std::abs(
absEta - *std::prev(upperEta))/((*std::prev(upperEta) - *std::prev(std::prev(upperEta)))/2);
1089 ATH_MSG_DEBUG(
"[ punchthrough ] abs(eta) is closer to eta points prev(upper_bound), distance: " <<
distance );
1092 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot > distance, returning prev(prev(upper_bound)) " << *std::prev(std::prev(upperEta)) );
1094 return *std::prev(std::prev(upperEta));
1096 ATH_MSG_DEBUG(
"[ punchthrough ] randomShoot < distance, returning prev(upper_bound) " << *std::prev(upperEta) );
1098 return *std::prev(upperEta);
1101 return *std::prev(upperEta);
1111 double minEnergy,
int maxNumParticles,
double numParticlesFactor,
1112 double energyFactor,
double posAngleFactor,
double momAngleFactor)
1117 std::unique_ptr<ISF::PDFcreator> pdf_num(readLookuptablePDF(pdg,
"FREQ_PDG"));
1118 if (!pdf_num )
return StatusCode::FAILURE;
1121 std::unique_ptr<PDFcreator> pdf_pca0 (readLookuptablePDF(pdg,
"PCA0_PDG"));
1124 return StatusCode::FAILURE;
1129 std::unique_ptr<PDFcreator> pdf_pca1 (readLookuptablePDF(pdg,
"PCA1_PDG"));
1132 return StatusCode::FAILURE;
1137 std::unique_ptr<PDFcreator> pdf_pca2 (readLookuptablePDF(pdg,
"PCA2_PDG"));
1140 return StatusCode::FAILURE;
1144 std::unique_ptr<PDFcreator> pdf_pca3 (readLookuptablePDF(pdg,
"PCA3_PDG"));
1147 return StatusCode::FAILURE;
1151 std::unique_ptr<PDFcreator> pdf_pca4 (readLookuptablePDF(pdg,
"PCA4_PDG"));
1154 return StatusCode::FAILURE;
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));
1167 const double restMass = m_particleDataTable->particle(std::abs(pdg))->mass();
1168 minEnergy = ( minEnergy > restMass ) ? minEnergy : restMass;
1170 particle->setMaxNumParticles(maxNumParticles);
1171 particle->setNumParticlesFactor(numParticlesFactor);
1172 particle->setEnergyFactor(energyFactor);
1173 particle->setPosAngleFactor(posAngleFactor);
1174 particle->setMomAngleFactor(momAngleFactor);
1179 return StatusCode::SUCCESS;
1188 double minCorrEnergy,
double fullCorrEnergy)
1195 if ( (location1 == m_particles.end()) || (location2 == m_particles.end()) )
1196 return StatusCode::FAILURE;
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());
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());
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());
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());
1212 if ( (!hist1_2_lowE) || (!hist2_1_lowE) || (!hist1_2_highE) || (!hist2_1_highE) )
1214 ATH_MSG_ERROR(
"[ punchthrough ] unable to retrieve the correlation data for PDG IDs " << pdgID1 <<
" and " << pdgID2);
1215 return StatusCode::FAILURE;
1221 const double lowE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(),
"elow_");
1222 const double midE = getFloatAfterPatternInStr( hist1_2_lowE->GetTitle(),
"ehigh_");
1225 const double upperE = getFloatAfterPatternInStr( hist1_2_highE->GetTitle(),
"ehigh_");
1227 m_particles[pdgID1]->setCorrelation(pdgID2, hist2_1_lowE, hist2_1_highE,
1228 minCorrEnergy, fullCorrEnergy,
1229 lowE, midE, upperE);
1231 m_particles[pdgID2]->setCorrelation(pdgID1, hist1_2_lowE, hist1_2_highE,
1232 minCorrEnergy, fullCorrEnergy,
1233 lowE, midE, upperE);
1234 return StatusCode::SUCCESS;
1249 std::unique_ptr<ISF::PDFcreator>
pdf = std::make_unique<ISF::PDFcreator>();
1252 std::stringstream dirName;
1254 pdf->setName(dirName.str().c_str());
1256 TDirectory *
dir = (TDirectory*)m_fileLookupTable->Get(dirName.str().c_str());
1266 TIter keyList(
dir->GetListOfKeys());
1269 while ((
key = (TKey*)keyList())) {
1272 TH1*
hist =
nullptr;
1275 if(strcmp(
key->GetClassName(),
"TH1F") == 0){
1288 const int energy = std::stoi(strEnergy);
1289 const int etaMin = std::stoi(strEtaMin);
1295 const double energyDbl =
static_cast<double>(
energy);
1296 const double etaDbl =
static_cast<double>(
etaMin)/100.;
1299 if (
std::find(m_energyPoints.begin(), m_energyPoints.end(), energyDbl) == m_energyPoints.end()) {
1300 m_energyPoints.push_back(energyDbl);
1302 if (
std::find(m_etaPoints.begin(), m_etaPoints.end(), etaDbl) == m_etaPoints.end()) {
1303 m_etaPoints.push_back(etaDbl);
1319 double energy,
double theta,
double phi,
double momTheta,
double momPhi)
const
1331 double mass = m_particleDataTable->particle(std::abs(pdg))->mass();
1334 ATH_MSG_DEBUG(
"setRThetaPhi input parameters: std::sqrt(energy*energy - mass*mass) = "<< std::sqrt(
energy*
energy -
mass*
mass) <<
" momTheta = "<< momTheta <<
" momPhi = "<< momPhi);
1337 double charge = m_particleDataTable->particle(std::abs(pdg))->charge();
1339 charge *= (pdg > 0.) ? 1. : -1.;
1341 const double pTime = 0;
1362 const std::string_view
str( cstr);
1363 const std::string_view
pattern( cpattern);
1366 if (
pos == std::string::npos)
1368 ATH_MSG_WARNING(
"[ punchthrough ] unable to retrieve floating point number from string");
1369 return -999999999999.;
1371 const std::string_view substring =
str.substr(
pos+
pattern.length());
1372 std::from_chars(substring.data(), substring.data() + substring.size(),
num);
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);
1390 if (theta >= 0 && theta < theta1)
1393 r = std::fabs (m_z1*
tan(theta));
1395 else if (theta >= theta1 && theta < theta2)
1397 z = m_R1/
tan(theta);
1400 else if (theta >= theta2 && theta < theta3)
1403 r = std::fabs(m_z2*
tan(theta));;
1405 else if (theta >= theta3 && theta < (TMath::Pi()-theta3) )
1407 z = m_R2/
tan(theta);
1410 else if (theta >= (TMath::Pi()-theta3) && theta < (TMath::Pi()-theta2) )
1413 r = std::fabs(m_z2*
tan(theta));
1415 else if (theta >= (TMath::Pi()-theta2) && theta < (TMath::Pi()-theta1) )
1417 z = m_R1/
tan(theta);
1420 else if (theta >= (TMath::Pi()-theta1) && theta <= TMath::Pi() )
1423 r = std::fabs(m_z1*
tan(theta));
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;
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) );