25#include <unordered_map>
131 return StatusCode::FAILURE;
135 if (configFile.empty()){
137 return StatusCode::FAILURE;
143 env.ReadFile(configFile.c_str(), kEnvLocal);
145 std::string modelFilename(
"");
146 std::string quantileFilename(
"");
156 modelFilename = env.GetValue(
"inputModelFileName",
"ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNNetwork.json");
157 ATH_MSG_DEBUG(
"Getting the input Model from: " << modelFilename );
160 if (filename.empty()){
161 ATH_MSG_ERROR(
"Could not find model file " << modelFilename);
162 return StatusCode::FAILURE;
173 quantileFilename = env.GetValue(
"inputQuantileFileName",
"ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNQuantileTransformer.root");
174 ATH_MSG_DEBUG(
"Getting the input QuantileTransformer from: " << quantileFilename);
177 if (qfilename.empty()){
178 ATH_MSG_ERROR(
"Could not find QuantileTransformer file " << quantileFilename);
179 return StatusCode::FAILURE;
183 std::stringstream vars(env.GetValue(
"Variables",
""));
187 std::getline(vars, substr,
',');
190 ATH_MSG_ERROR(
"Unsupported variable " << substr <<
" found in the config.");
191 return StatusCode::FAILURE;
220 unsigned int numberOfExpectedBinCombinedMVA ;
225 ATH_MSG_ERROR(
"Configuration issue : cutSelector expected size " << numberOfExpectedBinCombinedMVA <<
227 return StatusCode::FAILURE;
233 ATH_MSG_ERROR(
"Configuration issue : cutSelectorCF expected size " << numberOfExpectedBinCombinedMVA <<
235 return StatusCode::FAILURE;
238 ATH_MSG_ERROR(
"Configuration issue : CF rejection is only defined "
239 "for multiClass: TRUE");
240 return StatusCode::FAILURE;
252 if (
m_fractions.size() != numberOfExpectedEtaBins * 5){
254 return StatusCode::FAILURE;
259 if (
m_cutSCT.size() != numberOfExpectedEtaBins){
260 ATH_MSG_ERROR(
"Configuration issue : cutSCT expected size " << numberOfExpectedEtaBins <<
262 return StatusCode::FAILURE;
267 if (
m_cutPi.size() != numberOfExpectedEtaBins){
268 ATH_MSG_ERROR(
"Configuration issue : cutPi expected size " << numberOfExpectedEtaBins <<
269 " input size " <<
m_cutPi.size());
270 return StatusCode::FAILURE;
275 if (
m_cutBL.size() != numberOfExpectedEtaBins){
276 ATH_MSG_ERROR(
"Configuration issue : cutBL expected size " << numberOfExpectedEtaBins <<
277 " input size " <<
m_cutBL.size());
278 return StatusCode::FAILURE;
284 ATH_MSG_ERROR(
"Configuration issue : cutAmbiguity expected size " << numberOfExpectedEtaBins <<
286 return StatusCode::FAILURE;
323 ATH_MSG_ERROR(
"ERROR: Something went wrong with the setup of the decision objects...");
324 return StatusCode::FAILURE;
338 return StatusCode::SUCCESS;
356 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
362 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed");
367 ATH_MSG_DEBUG(
"exiting because cluster is NULL " << cluster);
371 if(!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
372 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2");
376 const double energy = cluster->
e();
377 const float eta = cluster->
etaBE(2);
380 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
391 double et = (std::cosh(track->eta()) != 0.) ? energy / std::cosh(track->eta()) : 0.;
394 uint8_t nSiHitsPlusDeadSensors(0);
395 uint8_t nPixHitsPlusDeadSensors(0);
396 bool passBLayerRequirement(
false);
397 uint8_t ambiguityBit(0);
399 bool allFound =
true;
400 std::string notFoundList =
"";
406 ambiguityBit = ambiguityTypeAcc(*eg);
410 notFoundList +=
"ambiguityType ";
422 ATH_MSG_VERBOSE(Form(
"PassVars: MVA=%8.5f, eta=%8.5f, et=%8.5f, nSiHitsPlusDeadSensors=%i, nHitsPlusPixDeadSensors=%i, passBLayerRequirement=%i, ambiguityBit=%i, mu=%8.5f",
424 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
425 passBLayerRequirement,
427 double mvaScoreCF = 0;
430 ATH_MSG_VERBOSE(Form(
"PassVars: MVA=%8.5f, eta=%8.5f, et=%8.5f, nSiHitsPlusDeadSensors=%i, nHitsPlusPixDeadSensors=%i, passBLayerRequirement=%i, ambiguityBit=%i, mu=%8.5f",
432 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
433 passBLayerRequirement,
438 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for the decision are found. The following variables are missing: " + notFoundList );
443 bool passNSilicon(
true);
444 bool passNPixel(
true);
445 bool passNBlayer(
true);
446 bool passAmbiguity(
true);
449 if (std::abs(
eta) > 2.47){
450 ATH_MSG_DEBUG(
"This electron is fabs(eta)>2.47 Returning False.");
459 ATH_MSG_DEBUG(
"Cannot evaluate model for Et " <<
et <<
". Returning false..");
465 if (!passKine){
return acceptData;}
471 passAmbiguity =
false;
477 if(
m_cutBL[etaBin] == 1 && !passBLayerRequirement){
484 if (nPixHitsPlusDeadSensors <
m_cutPi[etaBin]){
491 if (nSiHitsPlusDeadSensors <
m_cutSCT[etaBin]){
493 passNSilicon =
false;
502 double cutDiscriminantCF;
505 throw std::runtime_error(
"AsgElectronSelectorTool: The desired eta/pt bin is outside of the range specified by the input. This should never happen! This indicates a mismatch between the binning in the configuration file and the tool implementation." );
515 if (mvaScoreCF < cutDiscriminantCF){
523 double cutDiscriminant;
526 throw std::runtime_error(
"AsgElectronSelectorTool: The desired eta/pt bin is outside of the range specified by the input. This should never happen! This indicates a mismatch between the binning in the configuration file and the tool implementation." );
536 if (mvaScore < cutDiscriminant){
566 double discriminant = 0;
573 const float eta = cluster->
etaBE(2);
584 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculateMultipleOutputs( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
586 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed" );
596 if (!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
597 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2.");
602 const double energy = cluster->
e();
603 const float eta = cluster->
etaBE(2);
606 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
619 const double et = energy / std::cosh(track->eta());
623 double SCTWeightedCharge(0.0);
624 uint8_t nSCTHitsPlusDeadSensors(0);
625 uint8_t nPixHitsPlusDeadSensors(0);
626 float d0(0.0), d0sigma(0.0), d0significance(0.0), qd0(0.0);
627 float trackqoverp(0.0);
630 double trans_TRTPID(0.0);
633 float deltaEta1(0), deltaPhiRescaled2(0), EoverP(0);
636 float Reta(0), Rphi(0), Rhad1(0), Rhad(0), w2(0), f1(0), Eratio(0), f3(0), wtots1(0);
638 bool allFound =
true;
639 std::string notFoundList =
"";
642 trackqoverp = track->qOverP();
644 qd0 = (eg->charge())*track->d0();
645 float vard0 = track->definingParametersCovMatrix()(0, 0);
647 d0sigma = std::sqrt(vard0);
649 d0significance = std::abs(d0 / d0sigma);
657 notFoundList +=
"eProbabilityHT ";
661 const double tau = 15.0;
662 const double fEpsilon = 1.0e-30;
663 double pid_tmp = TRT_PID;
665 pid_tmp = 1.0 - 1.0e-15;
666 else if (pid_tmp <= fEpsilon)
668 trans_TRTPID = -std::log(1.0 / pid_tmp - 1.0) * (1. / tau);
675 trans_TRTPID = trans_TRT_PID_acc(*eg);
679 if ((std::abs(trans_TRTPID) < 1.0e-6) && (std::abs(
eta) > 2.01)){
685 double refittedTrack_LMqoverp = track->charge() / std::sqrt(std::pow(track->parameterPX(
index), 2) +
686 std::pow(track->parameterPY(
index), 2) +
687 std::pow(track->parameterPZ(
index), 2));
689 dPOverP = 1 - trackqoverp / (refittedTrack_LMqoverp);
693 notFoundList +=
"deltaPoverP ";
696 EoverP = energy * std::abs(trackqoverp);
703 for (
unsigned TPit = 0; TPit < eg->nTrackParticles(); TPit++) {
704 uint8_t temp_NSCTHits = 0;
705 if (eg->trackParticle(TPit)) {
707 SCT += temp_NSCTHits;
708 charge += temp_NSCTHits*(eg->trackParticle(TPit)->
charge());
712 SCTWeightedCharge = (eg->charge()*
charge/
SCT);
714 ATH_MSG_WARNING(
"No SCT hit for any track associated to electron ! nTP = " << eg->nTrackParticles());
721 notFoundList +=
"Reta ";
726 notFoundList +=
"Rphi ";
731 notFoundList +=
"Rhad1 ";
736 notFoundList +=
"Rhad ";
741 notFoundList +=
"weta2 ";
746 notFoundList +=
"f1 ";
751 notFoundList +=
"Eratio ";
756 notFoundList +=
"f3 ";
760 if (std::abs(
eta) > 2.01) {
767 notFoundList +=
"wtots1 ";
774 notFoundList +=
"deltaEta1 ";
779 notFoundList +=
"deltaPhiRescaled2 ";
783 ATH_MSG_VERBOSE(Form(
"Vars: eta=%8.5f, et=%8.5f, f3=%8.5f, rHad==%8.5f, rHad1=%8.5f, Reta=%8.5f, w2=%8.5f, f1=%8.5f, Emaxs1=%8.5f, deltaEta1=%8.5f, d0=%8.5f, qd0=%8.5f, d0significance=%8.5f, Rphi=%8.5f, dPOverP=%8.5f, deltaPhiRescaled2=%8.5f, TRT_PID=%8.5f, trans_TRTPID=%8.5f, mu=%8.5f, wtots1=%8.5f, EoverP=%8.5f, nPixHitsPlusDeadSensors=%2df, nSCTHitsPlusDeadSensors=%2df, SCTWeightedCharge=%8.5f",
784 eta,
et, f3, Rhad, Rhad1, Reta,
788 Rphi, dPOverP, deltaPhiRescaled2,
789 TRT_PID, trans_TRTPID,
791 wtots1, EoverP,
int(nPixHitsPlusDeadSensors),
int(nSCTHitsPlusDeadSensors), SCTWeightedCharge));
794 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for MVA calculation are found. The following variables are missing: " + notFoundList );
797 std::vector<double> variableValues;
803 variableValues.push_back(std::abs(
eta));
break;
805 variableValues.push_back(
et);
break;
807 variableValues.push_back(f3);
break;
809 variableValues.push_back(Rhad);
break;
811 variableValues.push_back(Rhad1);
break;
813 variableValues.push_back(Reta);
break;
815 variableValues.push_back(w2);
break;
817 variableValues.push_back(f1);
break;
819 variableValues.push_back(Eratio);
break;
821 variableValues.push_back(deltaEta1);
break;
823 variableValues.push_back(d0);
break;
825 variableValues.push_back(qd0);
break;
827 variableValues.push_back(d0significance);
break;
829 variableValues.push_back(Rphi);
break;
831 variableValues.push_back(dPOverP);
break;
833 variableValues.push_back(deltaPhiRescaled2);
break;
835 variableValues.push_back(trans_TRTPID);
break;
837 variableValues.push_back(wtots1);
break;
839 variableValues.push_back(EoverP);
break;
841 variableValues.push_back(nPixHitsPlusDeadSensors);
break;
843 variableValues.push_back(nSCTHitsPlusDeadSensors);
break;
845 variableValues.push_back(SCTWeightedCharge);
break;
848 throw std::runtime_error(
"AsgElectronSelectorTool: unknown variable "
849 "index, something went wrong in initialization!" );
854 Eigen::Matrix<float, -1, 1> mvaScores =
m_mvaTool->calculate(variableValues);
857 std::vector<float> mvaOutputs;
858 mvaOutputs.reserve(mvaScores.rows());
859 for (
int i = 0; i < mvaScores.rows(); i++) {
860 mvaOutputs.push_back(mvaScores(i, 0));
877 return accept(Gaudi::Hive::currentContext(), part);
881 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *part= "<<(&ctx)<<
", "<<part<<
" )");
887 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
896 return calculate(Gaudi::Hive::currentContext(), part);
901 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *part"<<(&ctx)<<
", "<<part<<
" )");
907 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
915 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
918 return accept(ctx, ele, mu);
921 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
930 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
936 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
949 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
955 if (std::abs(
eta) > 2.5){
956 ATH_MSG_DEBUG(
"Failed, cluster->etaBE(2) range due to " <<
eta <<
" seems like a fwd electron" );
968 constexpr double oneOverTau = 1. / 10;
969 constexpr double fEpsilon = 1.0e-30;
970 if (score >= 1.0) score = 1.0 - 1.0e-15;
971 else if (score <= fEpsilon) score = fEpsilon;
973 score = -std::log(1.0 / score - 1.0) * oneOverTau;
987 disc = (mvaScores.at(0) * (1 -
m_fractions.at(5 * etaBin + 0)) +
988 (mvaScores.at(1) *
m_fractions.at(5 * etaBin + 0))) /
989 ((mvaScores.at(2) *
m_fractions.at(5 * etaBin + 1)) +
990 (mvaScores.at(3) *
m_fractions.at(5 * etaBin + 2)) +
991 (mvaScores.at(4) *
m_fractions.at(5 * etaBin + 3)) +
992 (mvaScores.at(5) *
m_fractions.at(5 * etaBin + 4)));
996 disc = mvaScores.at(0) /
997 ((mvaScores.at(1) *
m_fractions.at(5 * etaBin + 0)) +
998 (mvaScores.at(2) *
m_fractions.at(5 * etaBin + 1)) +
999 (mvaScores.at(3) *
m_fractions.at(5 * etaBin + 2)) +
1000 (mvaScores.at(4) *
m_fractions.at(5 * etaBin + 3)) +
1001 (mvaScores.at(5) *
m_fractions.at(5 * etaBin + 4)));
1005 return std::log(disc);
1011 disc = mvaScores.at(0) / mvaScores.at(1);
1013 return std::log(disc);
1021 const double etaBins[nEtaBins] = {0.1, 0.6, 0.8, 1.15, 1.37, 1.52, 1.81, 2.01, 2.37, 2.47};
1022 for (
unsigned int etaBin = 0; etaBin < nEtaBins; ++etaBin){
1023 if (std::abs(
eta) < etaBins[etaBin])
return etaBin;
1025 return (nEtaBins-1);
1031 static const double GeV = 1000;
1034 for (
unsigned int etBin = 0; etBin < nEtBins; ++etBin){
1035 if (
et < etBins[etBin])
return etBin;
1048 double cut = cuts.at(ibin_combinedML);
1049 const double GeV = 1000;
1052 if (
et >= eTBins[9])
return cut;
1053 if (
et <= eTBins[0])
return cut;
1061 double etLow = eTBins[
bin-1];
1062 double etUp = eTBins[
bin];
1066 double gradient = ( discUp - discLow ) / ( etUp - etLow );
1068 return discLow + (
et - etLow) * gradient;
Scalar eta() const
pseudorapidity method
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
double charge(const T &p)
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
SG::ConstAccessor< T, ALLOC > ConstAccessor
SG::Accessor< T, ALLOC > Accessor
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
void setCutResult(const std::string &cutName, bool cutResult)
Set the result of a cut, based on the cut name (safer)
virtual double e() const
The total energy of the particle.
bool hasSampling(const CaloSample s) const
Checks if certain smapling contributes to cluster.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
Class providing the definition of the 4-vector interface.
bool contains(const std::string &s, const std::string ®x)
does a string contain the substring
@ nPixHitsPlusDeadSensors
@ nSCTHitsPlusDeadSensors
const std::unordered_map< std::string, int > variableMap
std::vector< int > HelperInt(const std::string &input, TEnv &env)
std::vector< double > HelperDouble(const std::string &input, TEnv &env)
std::string findConfigFile(const std::string &input, const std::map< std::string, std::string > &configmap)
const std::map< std::string, std::string > ElectronDNNPointToConfFile
bool passAmbiguity(xAOD::AmbiguityTool::AmbiguityType type, const uint16_t criterion)
return true if the ambiguity type is one of several that are stored in a bitmask
std::size_t numberOfPixelHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of Pixel hits plus dead sensors in the track particle
std::size_t numberOfSCTHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of SCT hits plus dead sensors in the track particle
bool passBLayerRequirement(const xAOD::TrackParticle &tp)
return true if effective number of BL hits + outliers is at least one
std::size_t numberOfSiliconHitsAndDeadSensors(const xAOD::TrackParticle &tp)
return the number of Silicon hits plus dead sensors in the track particle
@ deltaPhiRescaled2
difference between the cluster phi (second sampling) and the phi of the track extrapolated to the sec...
@ deltaEta1
difference between the cluster eta (first sampling) and the eta of the track extrapolated to the firs...
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
@ wtots1
shower width is determined in a window detaxdphi = 0,0625 ×~0,2, corresponding typically to 20 strips...
@ f3
fraction of energy reconstructed in 3rd sampling
@ f1
E1/E = fraction of energy reconstructed in the first sampling, where E1 is energy in all strips belon...
@ Eratio
(emaxs1-e2tsts1)/(emaxs1+e2tsts1)
@ weta2
the lateral width is calculated with a window of 3x5 cells using the energy weighted sum over all cel...
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Egamma_v1 Egamma
Definition of the current "egamma version".
@ eProbabilityHT
Electron probability from High Threshold (HT) information [float].
@ numberOfSCTHits
number of hits in SCT [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".
@ LastMeasurement
Parameter defined at the position of the last measurement.
Extra patterns decribing particle interation process.