34#include <unordered_map>
132 return StatusCode::FAILURE;
138 return StatusCode::FAILURE;
146 std::string modelFilename(
"");
147 std::string quantileFilename(
"");
157 modelFilename = env.GetValue(
"inputModelFileName",
"ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNNetwork.json");
158 ATH_MSG_DEBUG(
"Getting the input Model from: " << modelFilename );
161 if (filename.empty()){
162 ATH_MSG_ERROR(
"Could not find model file " << modelFilename);
163 return StatusCode::FAILURE;
174 quantileFilename = env.GetValue(
"inputQuantileFileName",
"ElectronPhotonSelectorTools/offline/mc16_20210204/ElectronDNNQuantileTransformer.root");
175 ATH_MSG_DEBUG(
"Getting the input QuantileTransformer from: " << quantileFilename);
178 if (qfilename.empty()){
179 ATH_MSG_ERROR(
"Could not find QuantileTransformer file " << quantileFilename);
180 return StatusCode::FAILURE;
184 std::stringstream vars(env.GetValue(
"Variables",
""));
188 std::getline(vars, substr,
',');
191 ATH_MSG_ERROR(
"Unsupported variable " << substr <<
" found in the config.");
192 return StatusCode::FAILURE;
221 unsigned int numberOfExpectedBinCombinedMVA ;
226 ATH_MSG_ERROR(
"Configuration issue : cutSelector expected size " << numberOfExpectedBinCombinedMVA <<
228 return StatusCode::FAILURE;
234 ATH_MSG_ERROR(
"Configuration issue : cutSelectorCF expected size " << numberOfExpectedBinCombinedMVA <<
236 return StatusCode::FAILURE;
239 ATH_MSG_ERROR(
"Configuration issue : CF rejection is only defined "
240 "for multiClass: TRUE");
241 return StatusCode::FAILURE;
253 if (
m_fractions.size() != numberOfExpectedEtaBins * 5){
255 return StatusCode::FAILURE;
260 if (
m_cutSCT.size() != numberOfExpectedEtaBins){
261 ATH_MSG_ERROR(
"Configuration issue : cutSCT expected size " << numberOfExpectedEtaBins <<
263 return StatusCode::FAILURE;
268 if (
m_cutPi.size() != numberOfExpectedEtaBins){
269 ATH_MSG_ERROR(
"Configuration issue : cutPi expected size " << numberOfExpectedEtaBins <<
270 " input size " <<
m_cutPi.size());
271 return StatusCode::FAILURE;
276 if (
m_cutBL.size() != numberOfExpectedEtaBins){
277 ATH_MSG_ERROR(
"Configuration issue : cutBL expected size " << numberOfExpectedEtaBins <<
278 " input size " <<
m_cutBL.size());
279 return StatusCode::FAILURE;
285 ATH_MSG_ERROR(
"Configuration issue : cutAmbiguity expected size " << numberOfExpectedEtaBins <<
287 return StatusCode::FAILURE;
324 ATH_MSG_ERROR(
"ERROR: Something went wrong with the setup of the decision objects...");
325 return StatusCode::FAILURE;
339 return StatusCode::SUCCESS;
357 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
363 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed");
368 ATH_MSG_DEBUG(
"exiting because cluster is NULL " << cluster);
372 if(!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
373 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2");
377 const double energy = cluster->
e();
378 const float eta = cluster->
etaBE(2);
381 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
392 double et = (std::cosh(track->eta()) != 0.) ? energy / std::cosh(track->eta()) : 0.;
395 uint8_t nSiHitsPlusDeadSensors(0);
396 uint8_t nPixHitsPlusDeadSensors(0);
397 bool passBLayerRequirement(
false);
398 uint8_t ambiguityBit(0);
400 bool allFound =
true;
401 std::string notFoundList =
"";
405 static const SG::AuxElement::Accessor<uint8_t> ambiguityTypeAcc(
"ambiguityType");
406 if (ambiguityTypeAcc.isAvailable(*eg)) {
407 ambiguityBit = ambiguityTypeAcc(*eg);
411 notFoundList +=
"ambiguityType ";
423 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",
425 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
426 passBLayerRequirement,
428 double mvaScoreCF = 0;
431 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",
433 nSiHitsPlusDeadSensors, nPixHitsPlusDeadSensors,
434 passBLayerRequirement,
439 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for the decision are found. The following variables are missing: " + notFoundList );
444 bool passNSilicon(
true);
445 bool passNPixel(
true);
446 bool passNBlayer(
true);
447 bool passAmbiguity(
true);
450 if (std::abs(
eta) > 2.47){
451 ATH_MSG_DEBUG(
"This electron is fabs(eta)>2.47 Returning False.");
460 ATH_MSG_DEBUG(
"Cannot evaluate model for Et " <<
et <<
". Returning false..");
466 if (!passKine){
return acceptData;}
472 passAmbiguity =
false;
478 if(
m_cutBL[etaBin] == 1 && !passBLayerRequirement){
485 if (nPixHitsPlusDeadSensors <
m_cutPi[etaBin]){
492 if (nSiHitsPlusDeadSensors <
m_cutSCT[etaBin]){
494 passNSilicon =
false;
503 double cutDiscriminantCF;
506 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." );
516 if (mvaScoreCF < cutDiscriminantCF){
524 double cutDiscriminant;
527 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." );
537 if (mvaScore < cutDiscriminant){
567 double discriminant = 0;
574 const float eta = cluster->
etaBE(2);
585 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculateMultipleOutputs( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
587 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed" );
597 if (!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
598 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2.");
603 const double energy = cluster->
e();
604 const float eta = cluster->
etaBE(2);
607 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
620 const double et = energy / std::cosh(track->eta());
624 double SCTWeightedCharge(0.0);
625 uint8_t nSCTHitsPlusDeadSensors(0);
626 uint8_t nPixHitsPlusDeadSensors(0);
627 float d0(0.0), d0sigma(0.0), d0significance(0.0), qd0(0.0);
628 float trackqoverp(0.0);
631 double trans_TRTPID(0.0);
634 float deltaEta1(0), deltaPhiRescaled2(0), EoverP(0);
637 float Reta(0), Rphi(0), Rhad1(0), Rhad(0), w2(0), f1(0), Eratio(0), f3(0), wtots1(0);
639 bool allFound =
true;
640 std::string notFoundList =
"";
643 trackqoverp = track->qOverP();
645 qd0 = (eg->
charge())*track->d0();
646 float vard0 = track->definingParametersCovMatrix()(0, 0);
648 d0sigma = std::sqrt(vard0);
650 d0significance = (d0sigma == 0.) ? -99999. : std::abs(d0 / d0sigma);
652 const static SG::AuxElement::Accessor<float> trans_TRT_PID_acc(
"transformed_e_probability_ht");
653 if (!trans_TRT_PID_acc.isAvailable(*eg)) {
658 notFoundList +=
"eProbabilityHT ";
662 const double tau = 15.0;
663 const double fEpsilon = 1.0e-30;
664 double pid_tmp = TRT_PID;
666 pid_tmp = 1.0 - 1.0e-15;
667 else if (pid_tmp <= fEpsilon)
669 trans_TRTPID = -std::log(1.0 / pid_tmp - 1.0) * (1. / tau);
676 trans_TRTPID = trans_TRT_PID_acc(*eg);
680 if ((std::abs(trans_TRTPID) < 1.0e-6) && (std::abs(
eta) > 2.01)){
686 double refittedTrack_LMqoverp = track->charge() / std::sqrt(std::pow(track->parameterPX(
index), 2) +
687 std::pow(track->parameterPY(
index), 2) +
688 std::pow(track->parameterPZ(
index), 2));
690 dPOverP = 1 - trackqoverp / (refittedTrack_LMqoverp);
694 notFoundList +=
"deltaPoverP ";
697 EoverP = energy * std::abs(trackqoverp);
705 uint8_t temp_NSCTHits = 0;
708 SCT += temp_NSCTHits;
722 notFoundList +=
"Reta ";
727 notFoundList +=
"Rphi ";
732 notFoundList +=
"Rhad1 ";
737 notFoundList +=
"Rhad ";
742 notFoundList +=
"weta2 ";
747 notFoundList +=
"f1 ";
752 notFoundList +=
"Eratio ";
757 notFoundList +=
"f3 ";
761 if (std::abs(
eta) > 2.01) {
768 notFoundList +=
"wtots1 ";
775 notFoundList +=
"deltaEta1 ";
780 notFoundList +=
"deltaPhiRescaled2 ";
784 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",
785 eta,
et, f3, Rhad, Rhad1, Reta,
789 Rphi, dPOverP, deltaPhiRescaled2,
790 TRT_PID, trans_TRTPID,
792 wtots1, EoverP,
int(nPixHitsPlusDeadSensors),
int(nSCTHitsPlusDeadSensors), SCTWeightedCharge));
795 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for MVA calculation are found. The following variables are missing: " + notFoundList );
798 std::vector<double> variableValues;
804 variableValues.push_back(std::abs(
eta));
break;
806 variableValues.push_back(
et);
break;
808 variableValues.push_back(f3);
break;
810 variableValues.push_back(Rhad);
break;
812 variableValues.push_back(Rhad1);
break;
814 variableValues.push_back(Reta);
break;
816 variableValues.push_back(w2);
break;
818 variableValues.push_back(f1);
break;
820 variableValues.push_back(Eratio);
break;
822 variableValues.push_back(deltaEta1);
break;
824 variableValues.push_back(d0);
break;
826 variableValues.push_back(qd0);
break;
828 variableValues.push_back(d0significance);
break;
830 variableValues.push_back(Rphi);
break;
832 variableValues.push_back(dPOverP);
break;
834 variableValues.push_back(deltaPhiRescaled2);
break;
836 variableValues.push_back(trans_TRTPID);
break;
838 variableValues.push_back(wtots1);
break;
840 variableValues.push_back(EoverP);
break;
842 variableValues.push_back(nPixHitsPlusDeadSensors);
break;
844 variableValues.push_back(nSCTHitsPlusDeadSensors);
break;
846 variableValues.push_back(SCTWeightedCharge);
break;
849 throw std::runtime_error(
"AsgElectronSelectorTool: unknown variable "
850 "index, something went wrong in initialization!" );
855 Eigen::Matrix<float, -1, 1> mvaScores =
m_mvaTool->calculate(variableValues);
858 std::vector<float> mvaOutputs;
859 mvaOutputs.reserve(mvaScores.rows());
860 for (
int i = 0; i < mvaScores.rows(); i++) {
861 mvaOutputs.push_back(mvaScores(i, 0));
878 return accept(Gaudi::Hive::currentContext(), part);
882 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *part= "<<(&ctx)<<
", "<<part<<
" )");
888 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
897 return calculate(Gaudi::Hive::currentContext(), part);
902 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *part"<<(&ctx)<<
", "<<part<<
" )");
908 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
916 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
919 return accept(ctx, ele, mu);
922 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
931 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
937 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
944 static const SG::AuxElement::ConstAccessor< uint16_t > accAuthor(
"author" );
946 if (accAuthor.isAvailable(*eg)){
950 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
956 if (std::abs(
eta) > 2.5){
957 ATH_MSG_DEBUG(
"Failed, cluster->etaBE(2) range due to " <<
eta <<
" seems like a fwd electron" );
969 constexpr double oneOverTau = 1. / 10;
970 constexpr double fEpsilon = 1.0e-30;
971 if (score >= 1.0) score = 1.0 - 1.0e-15;
972 else if (score <= fEpsilon) score = fEpsilon;
974 score = -std::log(1.0 / score - 1.0) * oneOverTau;
988 disc = (mvaScores.at(0) * (1 -
m_fractions.at(5 * etaBin + 0)) +
989 (mvaScores.at(1) *
m_fractions.at(5 * etaBin + 0))) /
990 ((mvaScores.at(2) *
m_fractions.at(5 * etaBin + 1)) +
991 (mvaScores.at(3) *
m_fractions.at(5 * etaBin + 2)) +
992 (mvaScores.at(4) *
m_fractions.at(5 * etaBin + 3)) +
993 (mvaScores.at(5) *
m_fractions.at(5 * etaBin + 4)));
997 disc = mvaScores.at(0) /
998 ((mvaScores.at(1) *
m_fractions.at(5 * etaBin + 0)) +
999 (mvaScores.at(2) *
m_fractions.at(5 * etaBin + 1)) +
1000 (mvaScores.at(3) *
m_fractions.at(5 * etaBin + 2)) +
1001 (mvaScores.at(4) *
m_fractions.at(5 * etaBin + 3)) +
1002 (mvaScores.at(5) *
m_fractions.at(5 * etaBin + 4)));
1006 return std::log(disc);
1012 disc = mvaScores.at(0) / mvaScores.at(1);
1014 return std::log(disc);
1022 const double etaBins[nEtaBins] = {0.1, 0.6, 0.8, 1.15, 1.37, 1.52, 1.81, 2.01, 2.37, 2.47};
1023 for (
unsigned int etaBin = 0; etaBin < nEtaBins; ++etaBin){
1024 if (std::abs(
eta) < etaBins[etaBin])
return etaBin;
1026 return (nEtaBins-1);
1032 static const double GeV = 1000;
1035 for (
unsigned int etBin = 0; etBin < nEtBins; ++etBin){
1036 if (
et < etBins[etBin])
return etBin;
1049 double cut = cuts.at(ibin_combinedML);
1050 const double GeV = 1000;
1053 if (
et >= eTBins[9])
return cut;
1054 if (
et <= eTBins[0])
return cut;
1062 double etLow = eTBins[
bin-1];
1063 double etUp = eTBins[
bin];
1067 double gradient = ( discUp - discLow ) / ( etUp - etLow );
1069 return discLow + (
et - etLow) * gradient;
Scalar eta() const
pseudorapidity method
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
#define ATH_MSG_INFO(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)
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.
bool showerShapeValue(float &value, const EgammaParameters::ShowerShapeType information) const
Accessor for ShowerShape values.
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
bool trackCaloMatchValue(float &value, const EgammaParameters::TrackCaloMatchType information) const
Accessor for Track to Calo Match Values.
float charge() const
Obtain the charge of the object.
const xAOD::TrackParticle * trackParticle(size_t index=0) const
Pointer to the xAOD::TrackParticle/s that match the electron candidate.
size_t nTrackParticles() const
Return the number xAOD::TrackParticles that match the electron candidate.
Class providing the definition of the 4-vector interface.
bool summaryValue(uint8_t &value, const SummaryType &information) const
Accessor for TrackSummary values.
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.