34#include <unordered_map>
91 const std::string& prefixName,
92 const std::string& layerName,
93 const std::string& userModelFileName,
94 const std::string& userQuantileFileName,
102 std::string modelFile = !userModelFileName.empty()
104 : env.GetValue((
prefix +
"inputModelFileName").c_str(),
"");
106 std::string quantileFile = !userQuantileFileName.empty()
107 ? userQuantileFileName
108 : env.GetValue((
prefix +
"inputQuantileFileName").c_str(),
"");
113 if (modelPath.empty() || quantilePath.empty()) {
124 std::string varStr = env.GetValue((
prefix +
"Variables").c_str(),
"");
125 std::stringstream varsStream(varStr);
128 std::vector<std::string> tempVariables;
131 while (std::getline(varsStream, substr,
',')) {
132 if (substr.empty())
continue;
134 substr = substr.substr(
prefix.length());
139 tempVariables.push_back(substr);
143 if (tempVariables.empty())
return false;
156 parentTool->
msg(MSG::ERROR) <<
"Configuration issue : cutSelector expected size " << numberOfExpectedBinCombinedMVA <<
163 parentTool->
msg(MSG::ERROR) <<
"Configuration issue : cutSelectorCF expected size " << numberOfExpectedBinCombinedMVA <<
168 parentTool->
msg(MSG::ERROR) <<
"Configuration issue : CF rejection is only defined "
169 "for multiClass: TRUE";
177 unsigned int nFractionsPerBin =
m_nOutputs - 1;
178 unsigned int expectedFractionsSize = numberOfExpectedEtaBins * nFractionsPerBin;
181 parentTool->
msg(MSG::ERROR) <<
"Configuration issue: multiclass is TRUE, but the number of fractions ("
183 << expectedFractionsSize <<
" fractions expected).";
188 m_mvaTool = std::make_unique<ElectronDNNCalculator>(
191 quantilePath.c_str(),
203 for (
int i = 0; i <
scores.rows(); ++i) {
257 return StatusCode::FAILURE;
266 return StatusCode::FAILURE;
273 int nLayers = env.GetValue(
"nSelectionLayers", 1);
275 const std::vector<std::string> defaultPrefixes = {
283 for (
int i = 0; i < nLayers; ++i) {
284 std::string prefix = (i < static_cast<int>(defaultPrefixes.size()))
286 : (
"Layer" + std::to_string(i + 1) +
".");
288 std::string layerName = (i == 0) ?
"FirstSelection"
289 : (i == 1) ?
"SecondSelection"
290 : (
"Layer" + std::to_string(i + 1));
296 if (!layer.initialize(env, prefix, layerName, userModel, userQuantile,
this)) {
297 ATH_MSG_ERROR(
"Error initializing layer " << i <<
" with prefix: " << prefix);
298 return StatusCode::FAILURE;
300 m_layers.push_back(std::move(layer));
339 ATH_MSG_ERROR(
"ERROR: Something went wrong with the setup of the decision objects...");
340 return StatusCode::FAILURE;
344 return StatusCode::SUCCESS;
362 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
368 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed");
373 ATH_MSG_DEBUG(
"exiting because cluster is NULL " << cluster);
377 if(!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
378 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2");
382 const double energy = cluster->
e();
383 const float eta = cluster->
etaBE(2);
386 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
397 double et = (std::cosh(track->eta()) != 0.) ? energy / std::cosh(track->eta()) : 0.;
400 uint8_t nSiHitsPlusDeadSensors(0);
401 uint8_t nPixHitsPlusDeadSensors(0);
402 bool passBLayerRequirement(
false);
403 uint8_t ambiguityBit(0);
405 bool allFound =
true;
406 std::string notFoundList =
"";
412 ambiguityBit = ambiguityTypeAcc(*eg);
416 notFoundList +=
"ambiguityType ";
428 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for the decision are found. The following variables are missing: " + notFoundList );
433 bool passNSilicon(
true);
434 bool passNPixel(
true);
435 bool passNBlayer(
true);
436 bool passAmbiguity(
true);
440 if (std::abs(
eta) > 2.47){
441 ATH_MSG_DEBUG(
"This electron is fabs(eta)>2.47 Returning False.");
450 ATH_MSG_DEBUG(
"Cannot evaluate model for Et " <<
et <<
". Returning false..");
456 if (!passKine){
return acceptData;}
458for (
size_t idx = 0; idx <
m_layers.size(); ++idx) {
463 if (!layer.m_cutAmbiguity.empty()){
466 passAmbiguity =
false;
471 if (!layer.m_cutBL.empty()) {
472 if(layer.m_cutBL[etaBin] == 1 && !passBLayerRequirement){
478 if (!layer.m_cutPi.empty()){
479 if (nPixHitsPlusDeadSensors < layer.m_cutPi[etaBin]){
485 if (!layer.m_cutSCT.empty()){
486 if (nSiHitsPlusDeadSensors < layer.m_cutSCT[etaBin]){
488 passNSilicon =
false;
495 if (!layer.m_cutSelectorCF.empty()){
496 double cutDiscriminantCF;
498 if (ibin_combinedMVA >= layer.m_cutSelectorCF.size()){
499 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." );
505 cutDiscriminantCF = layer.m_cutSelectorCF.at(ibin_combinedMVA);
510 if (mvaScoreCF < cutDiscriminantCF){
517 if (!layer.m_cutSelector.empty()) {
518 double cutDiscriminant;
520 if (ibin_combinedMVA >= layer.m_cutSelector.size()){
521 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." );
527 cutDiscriminant = layer.m_cutSelector.at(ibin_combinedMVA);
532 double disc = layer.m_multiClass
536 if (disc < cutDiscriminant) {
537 ATH_MSG_DEBUG(
"MVA macro: Prompt cut failed in layer " << layer.name);
541 if (!passMVA || !passNSilicon || !passNPixel || !passNBlayer || !passAmbiguity) {
566 return discScores.empty() ? -999.0 : discScores.back();
571 std::vector<double> discriminants;
573 const float eta = cluster->
etaBE(2);
576 for (
size_t i = 0; i < mvaOutputs.
layerOutputs.size(); ++i) {
578 if (
scores.empty())
continue;
581 double disc = layer.m_multiClass
585 discriminants.push_back(disc);
588 return discriminants;
604 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculateMultipleOutputs( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
606 throw std::runtime_error(
"AsgElectronSelectorTool: Failed, no electron object was passed" );
617 if (!cluster->
hasSampling(CaloSampling::CaloSample::EMB2) && !cluster->
hasSampling(CaloSampling::CaloSample::EME2)){
618 ATH_MSG_DEBUG(
"Failed, cluster is missing samplings EMB2 and EME2.");
624 const double energy = cluster->
e();
625 const float eta = cluster->
etaBE(2);
628 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
643 const double et = energy / std::cosh(track->eta());
647 double SCTWeightedCharge(0.0);
648 uint8_t nSCTHitsPlusDeadSensors(0);
649 uint8_t nPixHitsPlusDeadSensors(0);
650 float d0(0.0), d0sigma(0.0), d0significance(0.0), qd0(0.0);
651 float trackqoverp(0.0);
654 double trans_TRTPID(0.0);
657 float deltaEta1(0), deltaPhiRescaled2(0), EoverP(0);
660 float Reta(0), Rphi(0), Rhad1(0), Rhad(0), w2(0), f1(0), Eratio(0), f3(0), wtots1(0);
662 bool allFound =
true;
663 std::string notFoundList =
"";
666 trackqoverp = track->qOverP();
668 qd0 = (eg->
charge())*track->d0();
669 float vard0 = track->definingParametersCovMatrix()(0, 0);
671 d0sigma = std::sqrt(vard0);
673 d0significance = (d0sigma == 0.) ? -99999. : std::abs(d0 / d0sigma);
681 notFoundList +=
"eProbabilityHT ";
685 const double tau = 15.0;
686 const double fEpsilon = 1.0e-30;
687 double pid_tmp = TRT_PID;
689 pid_tmp = 1.0 - 1.0e-15;
690 else if (pid_tmp <= fEpsilon)
692 trans_TRTPID = -std::log(1.0 / pid_tmp - 1.0) * (1. / tau);
699 trans_TRTPID = trans_TRT_PID_acc(*eg);
703 if ((std::abs(trans_TRTPID) < 1.0e-6) && (std::abs(
eta) > 2.01)){
709 double refittedTrack_LMqoverp = track->charge() / std::sqrt(std::pow(track->parameterPX(
index), 2) +
710 std::pow(track->parameterPY(
index), 2) +
711 std::pow(track->parameterPZ(
index), 2));
713 dPOverP = 1 - trackqoverp / (refittedTrack_LMqoverp);
717 notFoundList +=
"deltaPoverP ";
720 EoverP = energy * std::abs(trackqoverp);
728 uint8_t temp_NSCTHits = 0;
731 SCT += temp_NSCTHits;
745 notFoundList +=
"Reta ";
750 notFoundList +=
"Rphi ";
755 notFoundList +=
"Rhad1 ";
760 notFoundList +=
"Rhad ";
765 notFoundList +=
"weta2 ";
770 notFoundList +=
"f1 ";
775 notFoundList +=
"Eratio ";
780 notFoundList +=
"f3 ";
784 if (std::abs(
eta) > 2.01) {
791 notFoundList +=
"wtots1 ";
798 notFoundList +=
"deltaEta1 ";
803 notFoundList +=
"deltaPhiRescaled2 ";
807 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",
808 eta,
et, f3, Rhad, Rhad1, Reta,
812 Rphi, dPOverP, deltaPhiRescaled2,
813 TRT_PID, trans_TRTPID,
815 wtots1, EoverP,
int(nPixHitsPlusDeadSensors),
int(nSCTHitsPlusDeadSensors), SCTWeightedCharge));
818 throw std::runtime_error(
"AsgElectronSelectorTool: Not all variables needed for MVA calculation are found. The following variables are missing: " + notFoundList );
823 for (
const auto& layer :
m_layers) {
824 std::vector<double> variableValues;
825 variableValues.reserve(layer.m_enum_variables.size());
826 for (
const auto varID : layer.m_enum_variables) {
831 variableValues.push_back(std::abs(
eta));
break;
833 variableValues.push_back(
et);
break;
835 variableValues.push_back(f3);
break;
837 variableValues.push_back(Rhad);
break;
839 variableValues.push_back(Rhad1);
break;
841 variableValues.push_back(Reta);
break;
843 variableValues.push_back(w2);
break;
845 variableValues.push_back(f1);
break;
847 variableValues.push_back(Eratio);
break;
849 variableValues.push_back(deltaEta1);
break;
851 variableValues.push_back(d0);
break;
853 variableValues.push_back(qd0);
break;
855 variableValues.push_back(d0significance);
break;
857 variableValues.push_back(Rphi);
break;
859 variableValues.push_back(dPOverP);
break;
861 variableValues.push_back(deltaPhiRescaled2);
break;
863 variableValues.push_back(trans_TRTPID);
break;
865 variableValues.push_back(wtots1);
break;
867 variableValues.push_back(EoverP);
break;
869 variableValues.push_back(nPixHitsPlusDeadSensors);
break;
871 variableValues.push_back(nSCTHitsPlusDeadSensors);
break;
873 variableValues.push_back(SCTWeightedCharge);
break;
876 throw std::runtime_error(
"AsgElectronSelectorTool: unknown variable "
877 "index, something went wrong in initialization!" );
883 mvaOutputs.
layerOutputs.push_back(layer.evaluate(variableValues));
900 return accept(Gaudi::Hive::currentContext(), part);
904 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *part= "<<(&ctx)<<
", "<<part<<
" )");
910 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
919 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *part"<<(&ctx)<<
", "<<part<<
" )");
925 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
933 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::accept( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
936 return accept(ctx, ele, mu);
939 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
948 ATH_MSG_VERBOSE(
"\t AsgElectronSelectorTool::calculate( &ctx, *eg, mu= "<<(&ctx)<<
", "<<eg<<
", "<<mu<<
" )");
954 ATH_MSG_DEBUG(
"AsgElectronSelectorTool::could not cast to const Electron");
967 ATH_MSG_DEBUG(
"Failed, this is a forward electron! The AsgElectronSelectorTool is only suitable for central electrons!");
973 if (std::abs(
eta) > 2.5){
974 ATH_MSG_DEBUG(
"Failed, cluster->etaBE(2) range due to " <<
eta <<
" seems like a fwd electron" );
986 constexpr double oneOverTau = 1 ;
987 constexpr double fEpsilon = 1.0e-30;
988 if (score >= 1.0) score = 1.0 - 1.0e-15;
989 else if (score <= fEpsilon) score = fEpsilon;
991 score = -std::log(1.0 / score - 1.0) * oneOverTau;
1001 size_t nClasses = mvaScores.size();
1002 size_t nFractionsPerBin = nClasses - 1;
1004 if (cfSignal && nClasses >= 3) {
1006 double numerator = mvaScores.at(0) * (1.0 - fractions.at(nFractionsPerBin * etaBin + 0)) +
1007 mvaScores.at(1) * fractions.at(nFractionsPerBin * etaBin + 0);
1009 double denominator = 0.0;
1010 for (
size_t i = 2; i < nClasses; ++i) {
1011 denominator += mvaScores.at(i) * fractions.at(nFractionsPerBin * etaBin + i - 1);
1013 if (denominator != 0.0) {
1014 disc = numerator / denominator;
1019 double numerator = mvaScores.at(0);
1020 double denominator = 0.0;
1022 for (
size_t i = 1; i < nClasses; ++i) {
1023 denominator += mvaScores.at(i) * fractions.at(nFractionsPerBin * etaBin + i - 1);
1025 if (denominator != 0.0) {
1026 disc = numerator / denominator;
1030 return std::log(disc);
1036 disc = mvaScores.at(0) / mvaScores.at(1);
1038 return std::log(disc);
1046 const double etaBins[nEtaBins] = {0.1, 0.6, 0.8, 1.15, 1.37, 1.52, 1.81, 2.01, 2.37, 2.47};
1047 for (
unsigned int etaBin = 0; etaBin < nEtaBins; ++etaBin){
1048 if (std::abs(
eta) < etaBins[etaBin])
return etaBin;
1050 return (nEtaBins-1);
1056 static const double GeV = 1000;
1059 for (
unsigned int etBin = 0; etBin < nEtBins; ++etBin){
1060 if (
et < etBins[etBin])
return etBin;
1073 double cut = cuts.at(ibin_combinedML);
1074 const double GeV = 1000;
1077 if (
et >= eTBins[9])
return cut;
1078 if (
et <= eTBins[0])
return cut;
1086 double etLow = eTBins[
bin-1];
1087 double etUp = eTBins[
bin];
1091 double gradient = ( discUp - discLow ) / ( etUp - etLow );
1093 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::vector< std::vector< float > > scores
std::pair< std::vector< unsigned int >, bool > res
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Helper class to provide type-safe access to aux data.
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.
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.