diff --git a/DataFormats/EgammaCandidates/interface/Photon.h b/DataFormats/EgammaCandidates/interface/Photon.h index f1daf95615eb4..ddae30524c9b7 100644 --- a/DataFormats/EgammaCandidates/interface/Photon.h +++ b/DataFormats/EgammaCandidates/interface/Photon.h @@ -579,6 +579,12 @@ namespace reco { // go back to run2-like 2 effective depths if desired - depth 1 is the normal depth 1, depth 2 is the sum over the rest void hcalToRun2EffDepth(); + ///MVA based beam halo tagger - trained for EE and for pT > 200 GeV + float haloTaggerMVAVal() const { return haloTaggerMVAVal_; } + + ///set the haloTaggerMVAVal here + void setHaloTaggerMVAVal(float x) { haloTaggerMVAVal_ = x; } + private: /// check overlap with another candidate bool overlap(const Candidate&) const override; @@ -599,6 +605,7 @@ namespace reco { MIPVariables mipVariableBlock_; PflowIsolationVariables pfIsolation_; PflowIDVariables pfID_; + float haloTaggerMVAVal_; }; } // namespace reco diff --git a/DataFormats/EgammaCandidates/src/Photon.cc b/DataFormats/EgammaCandidates/src/Photon.cc index f1ac9770a17fe..7633e35a966f5 100644 --- a/DataFormats/EgammaCandidates/src/Photon.cc +++ b/DataFormats/EgammaCandidates/src/Photon.cc @@ -4,7 +4,11 @@ using namespace reco; Photon::Photon(const LorentzVector& p4, const Point& caloPos, const PhotonCoreRef& core, const Point& vtx) - : RecoCandidate(0, p4, vtx, 22), caloPosition_(caloPos), photonCore_(core), pixelSeed_(false) {} + : RecoCandidate(0, p4, vtx, 22), + caloPosition_(caloPos), + photonCore_(core), + pixelSeed_(false), + haloTaggerMVAVal_(-999) {} Photon::Photon(const Photon& rhs) : RecoCandidate(rhs), @@ -19,7 +23,8 @@ Photon::Photon(const Photon& rhs) saturationInfo_(rhs.saturationInfo_), eCorrections_(rhs.eCorrections_), mipVariableBlock_(rhs.mipVariableBlock_), - pfIsolation_(rhs.pfIsolation_) {} + pfIsolation_(rhs.pfIsolation_), + haloTaggerMVAVal_(rhs.haloTaggerMVAVal_) {} Photon::~Photon() {} diff --git a/DataFormats/EgammaCandidates/src/classes_def.xml b/DataFormats/EgammaCandidates/src/classes_def.xml index 9432329160786..20137d71f63d4 100644 --- a/DataFormats/EgammaCandidates/src/classes_def.xml +++ b/DataFormats/EgammaCandidates/src/classes_def.xml @@ -9,7 +9,8 @@ - + + diff --git a/DataFormats/PatCandidates/src/classes_def_objects.xml b/DataFormats/PatCandidates/src/classes_def_objects.xml index 2b98aef02aab2..b4a6802919c71 100644 --- a/DataFormats/PatCandidates/src/classes_def_objects.xml +++ b/DataFormats/PatCandidates/src/classes_def_objects.xml @@ -222,7 +222,8 @@ - + + diff --git a/RecoEgamma/EgammaPhotonProducers/python/gedPhotons_cfi.py b/RecoEgamma/EgammaPhotonProducers/python/gedPhotons_cfi.py index d8d6f7b86e32f..cf6dfa5e5ebf5 100644 --- a/RecoEgamma/EgammaPhotonProducers/python/gedPhotons_cfi.py +++ b/RecoEgamma/EgammaPhotonProducers/python/gedPhotons_cfi.py @@ -3,6 +3,7 @@ from RecoEgamma.PhotonIdentification.pfIsolationCalculator_cfi import * from RecoEgamma.PhotonIdentification.isolationCalculator_cfi import * from RecoEgamma.PhotonIdentification.mipVariable_cfi import * +from RecoEgamma.PhotonIdentification.mvaHaloVariable_cfi import * from RecoEcal.EgammaClusterProducers.hybridSuperClusters_cfi import * from RecoEcal.EgammaClusterProducers.multi5x5BasicClusters_cfi import * @@ -39,6 +40,7 @@ isolationSumsCalculatorSet = cms.PSet(isolationSumsCalculator), PFIsolationCalculatorSet = cms.PSet(pfIsolationCalculator), mipVariableSet = cms.PSet(mipVariable), + mvaBasedHaloVariableSet = cms.PSet(mvaHaloVariable), usePrimaryVertex = cms.bool(True), primaryVertexProducer = cms.InputTag('offlinePrimaryVerticesWithBS'), posCalc_t0_endcPresh = cms.double(3.6), @@ -51,6 +53,7 @@ endcapEcalHits = cms.InputTag("ecalRecHit","EcalRecHitsEE"), preshowerHits = cms.InputTag("ecalPreshowerRecHit","EcalRecHitsES"), runMIPTagger = cms.bool(True), + runMVABasedHaloTagger = cms.bool(True), highEt = cms.double(100.), minR9Barrel = cms.double(0.94), minR9Endcap = cms.double(0.95), diff --git a/RecoEgamma/EgammaPhotonProducers/python/photons_cfi.py b/RecoEgamma/EgammaPhotonProducers/python/photons_cfi.py index 1ffac6650827f..615aa535e9607 100644 --- a/RecoEgamma/EgammaPhotonProducers/python/photons_cfi.py +++ b/RecoEgamma/EgammaPhotonProducers/python/photons_cfi.py @@ -2,6 +2,7 @@ from RecoEgamma.PhotonIdentification.isolationCalculator_cfi import * from RecoEgamma.PhotonIdentification.mipVariable_cfi import * +from RecoEgamma.PhotonIdentification.mvaHaloVariable_cfi import * from RecoEcal.EgammaClusterProducers.hybridSuperClusters_cfi import * from RecoEcal.EgammaClusterProducers.multi5x5BasicClusters_cfi import * from RecoEgamma.EgammaIsolationAlgos.egammaHBHERecHitThreshold_cff import egammaHBHERecHit @@ -30,6 +31,7 @@ candidateP4type = cms.string("fromEcalEnergy"), isolationSumsCalculatorSet = cms.PSet(isolationSumsCalculator), mipVariableSet = cms.PSet(mipVariable), + mvaBasedHaloVariableSet = cms.PSet(mvaHaloVariable), usePrimaryVertex = cms.bool(True), primaryVertexProducer = cms.InputTag('offlinePrimaryVerticesWithBS'), posCalc_t0_endcPresh = cms.double(3.6), @@ -42,6 +44,7 @@ endcapEcalHits = cms.InputTag("ecalRecHit","EcalRecHitsEE"), preshowerHits = cms.InputTag("ecalPreshowerRecHit","EcalRecHitsES"), runMIPTagger = cms.bool(True), + runMVABasedHaloTagger = cms.bool(False), highEt = cms.double(100.), minR9Barrel = cms.double(0.94), minR9Endcap = cms.double(0.95), @@ -161,6 +164,7 @@ hbheModule = cms.string('hbhereco'), endcapEcalHits = cms.InputTag("ecalRecHit","EcalRecHitsEE"), runMIPTagger = cms.bool(True), + runMVABasedHaloTagger = cms.bool(False), highEt = cms.double(100.), minR9Barrel = cms.double(10.0), minR9Endcap = cms.double(10.0), diff --git a/RecoEgamma/EgammaPhotonProducers/src/GEDPhotonProducer.cc b/RecoEgamma/EgammaPhotonProducers/src/GEDPhotonProducer.cc index 337cea3032416..e2cad868ccab1 100644 --- a/RecoEgamma/EgammaPhotonProducers/src/GEDPhotonProducer.cc +++ b/RecoEgamma/EgammaPhotonProducers/src/GEDPhotonProducer.cc @@ -40,6 +40,7 @@ #include "RecoEgamma/EgammaPhotonAlgos/interface/PhotonEnergyCorrector.h" #include "RecoEgamma/PhotonIdentification/interface/PhotonIsolationCalculator.h" #include "RecoEgamma/PhotonIdentification/interface/PhotonMIPHaloTagger.h" +#include "RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h" #include "RecoLocalCalo/EcalRecAlgos/interface/EcalSeverityLevelAlgo.h" #include "RecoLocalCalo/EcalRecAlgos/interface/EcalSeverityLevelAlgoRcd.h" #include "CondFormats/EcalObjects/interface/EcalPFRecHitThresholds.h" @@ -50,6 +51,8 @@ #include "PhysicsTools/TensorFlow/interface/TensorFlow.h" #include "RecoEgamma/EgammaIsolationAlgos/interface/EcalPFClusterIsolation.h" #include "RecoEgamma/EgammaIsolationAlgos/interface/HcalPFClusterIsolation.h" +#include "CondFormats/GBRForest/interface/GBRForest.h" +#include "CommonTools/MVAUtils/interface/GBRForestTools.h" class CacheData { public: @@ -67,8 +70,16 @@ class CacheData { const auto useEBModelInGap = pset_dnn.getParameter("useEBModelInGap"); photonDNNEstimator = std::make_unique(config, useEBModelInGap); } + ///for MVA based beam halo tagger in the EE + const auto runMVABasedHaloTagger = conf.getParameter("runMVABasedHaloTagger"); + edm::ParameterSet mvaBasedHaloVariableSet = conf.getParameter("mvaBasedHaloVariableSet"); + auto trainingFileName_ = mvaBasedHaloVariableSet.getParameter(("trainingFileName")).fullPath(); + if (runMVABasedHaloTagger) { + haloTaggerGBR = createGBRForest(trainingFileName_); + } } std::unique_ptr photonDNNEstimator; + std::unique_ptr haloTaggerGBR; }; class GEDPhotonProducer : public edm::stream::EDProducer> { @@ -174,6 +185,7 @@ class GEDPhotonProducer : public edm::stream::EDProducer photonMIPHaloTagger_ = nullptr; + //MVA based Halo tagger for the EE photons + std::unique_ptr photonMVABasedHaloTagger_ = nullptr; std::vector preselCutValuesBarrel_; std::vector preselCutValuesEndcap_; @@ -318,6 +332,7 @@ GEDPhotonProducer::GEDPhotonProducer(const edm::ParameterSet& config, const Cach minR9Endcap_ = config.getParameter("minR9Endcap"); usePrimaryVertex_ = config.getParameter("usePrimaryVertex"); runMIPTagger_ = config.getParameter("runMIPTagger"); + runMVABasedHaloTagger_ = config.getParameter("runMVABasedHaloTagger"); candidateP4type_ = config.getParameter("candidateP4type"); valueMapPFCandPhoton_ = config.getParameter("valueMapPhotons"); @@ -411,6 +426,12 @@ GEDPhotonProducer::GEDPhotonProducer(const edm::ParameterSet& config, const Cach photonMIPHaloTagger_->setup(mipVariableSet, consumesCollector()); } + if (recoStep_.isFinal() && runMVABasedHaloTagger_) { + edm::ParameterSet mvaBasedHaloVariableSet = config.getParameter("mvaBasedHaloVariableSet"); + photonMVABasedHaloTagger_ = + std::make_unique(mvaBasedHaloVariableSet, consumesCollector()); + } + ///Get the set for PF cluster isolation calculator const edm::ParameterSet& pfECALClusIsolCfg = config.getParameter("pfECALClusIsolCfg"); pfClusterProducer_ = @@ -1057,6 +1078,11 @@ void GEDPhotonProducer::fillPhotonCollection(edm::Event& evt, reco::Photon newCandidate(*phoRef); iSC++; + if (runMVABasedHaloTagger_) { ///sets values only for EE, for EB it always returns 1 + float BHmva = photonMVABasedHaloTagger_->calculateMVA(&newCandidate, globalCache()->haloTaggerGBR.get(), evt, es); + newCandidate.setHaloTaggerMVAVal(BHmva); + } + // Calculate the PF isolation reco::Photon::PflowIsolationVariables pfIso; // The PFID are not recomputed since they have been already computed in the first loop with the DNN diff --git a/RecoEgamma/EgammaPhotonProducers/src/PhotonProducer.cc b/RecoEgamma/EgammaPhotonProducers/src/PhotonProducer.cc index 8fdf6f536cbe2..8544ca0f260ca 100644 --- a/RecoEgamma/EgammaPhotonProducers/src/PhotonProducer.cc +++ b/RecoEgamma/EgammaPhotonProducers/src/PhotonProducer.cc @@ -34,6 +34,7 @@ #include "RecoEgamma/EgammaPhotonAlgos/interface/PhotonEnergyCorrector.h" #include "RecoEgamma/PhotonIdentification/interface/PhotonIsolationCalculator.h" #include "RecoEgamma/PhotonIdentification/interface/PhotonMIPHaloTagger.h" +#include "RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h" #include "RecoLocalCalo/EcalRecAlgos/interface/EcalSeverityLevelAlgo.h" #include "RecoLocalCalo/EcalRecAlgos/interface/EcalSeverityLevelAlgoRcd.h" #include "RecoEgamma/EgammaElectronAlgos/interface/ElectronHcalHelper.h" @@ -83,6 +84,7 @@ class PhotonProducer : public edm::stream::EDProducer<> { double minR9Barrel_; double minR9Endcap_; bool runMIPTagger_; + bool runMVABasedHaloTagger_; bool validConversions_; @@ -95,6 +97,8 @@ class PhotonProducer : public edm::stream::EDProducer<> { //MIP PhotonMIPHaloTagger photonMIPHaloTagger_; + //MVA based Halo tagger for the EE photons + std::unique_ptr photonMVABasedHaloTagger_ = nullptr; std::vector preselCutValuesBarrel_; std::vector preselCutValuesEndcap_; @@ -127,6 +131,7 @@ PhotonProducer::PhotonProducer(const edm::ParameterSet& config) minR9Endcap_ = config.getParameter("minR9Endcap"); usePrimaryVertex_ = config.getParameter("usePrimaryVertex"); runMIPTagger_ = config.getParameter("runMIPTagger"); + runMVABasedHaloTagger_ = config.getParameter("runMVABasedHaloTagger"); candidateP4type_ = config.getParameter("candidateP4type"); diff --git a/RecoEgamma/PhotonIdentification/BuildFile.xml b/RecoEgamma/PhotonIdentification/BuildFile.xml index 02e53c5fd2adf..1aeb92479f3cf 100644 --- a/RecoEgamma/PhotonIdentification/BuildFile.xml +++ b/RecoEgamma/PhotonIdentification/BuildFile.xml @@ -24,6 +24,7 @@ + diff --git a/RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h b/RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h new file mode 100644 index 0000000000000..935bd9e5fead4 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h @@ -0,0 +1,90 @@ +/** \class PhotonMVABasedHaloTagger + * \author Shilpi Jain (University of Minnesota) + * Links to the presentation: + 1. ECAL DPG: https://indico.cern.ch/event/991261/contributions/4283096/attachments/2219229/3757719/beamHalo_31march_v1.pdf + 2. JetMET POG: https://indico.cern.ch/event/1027614/contributions/4314949/attachments/2224472/3767396/beamHalo_12April.pdf + */ + +#ifndef RecoEgamma_PhotonIdentification_PhotonMVABasedHaloTagger_h +#define RecoEgamma_PhotonIdentification_PhotonMVABasedHaloTagger_h + +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "DataFormats/EcalRecHit/interface/EcalRecHitCollections.h" +#include "DataFormats/EgammaCandidates/interface/Photon.h" +#include "FWCore/Framework/interface/ConsumesCollector.h" +#include "Geometry/CaloGeometry/interface/CaloGeometry.h" +#include "Geometry/Records/interface/CaloGeometryRecord.h" +#include "DataFormats/HcalRecHit/interface/HcalRecHitCollections.h" +#include "CondFormats/GBRForest/interface/GBRForest.h" +#include "RecoEcal/EgammaCoreTools/interface/EcalClusterLazyTools.h" +#include "RecoEgamma/EgammaIsolationAlgos/interface/EgammaHcalIsolation.h" +#include "CondFormats/EcalObjects/interface/EcalPFRecHitThresholds.h" +#include "CondFormats/DataRecord/interface/EcalPFRecHitThresholdsRcd.h" +#include + +class PhotonMVABasedHaloTagger { +public: + PhotonMVABasedHaloTagger(const edm::ParameterSet& conf, edm::ConsumesCollector&& iC); + + double calculateMVA(const reco::Photon* pho, + const GBRForest* gbr_, + const edm::Event& iEvent, + const edm::EventSetup& es); + +private: + void calphoClusCoordinECAL(const CaloGeometry* geo, + const reco::Photon*, + const EcalPFRecHitThresholds* thresholds, + const EcalRecHitCollection& ecalRecHits); + + void calmatchedHBHECoordForBothHypothesis(const CaloGeometry* geo, + const reco::Photon*, + const HBHERecHitCollection& HBHERecHits); + + void calmatchedESCoordForBothHypothesis(const CaloGeometry* geo, + const reco::Photon*, + const EcalRecHitCollection& ESRecHits); + + double calAngleBetweenEEAndSubDet(int nhits, double subdetClusX, double subdetClusY, double subdetClusZ); + + int hcalClusNhits_samedPhi_, hcalClusNhits_samedR_; + int ecalClusNhits_, preshowerNhits_samedPhi_, preshowerNhits_samedR_; + double hcalClusX_samedPhi_, hcalClusY_samedPhi_, hcalClusZ_samedPhi_, hcalClusX_samedR_, hcalClusY_samedR_, + hcalClusZ_samedR_; + double hcalClusE_samedPhi_, hcalClusE_samedR_; + + double ecalClusX_, ecalClusY_, ecalClusZ_; + double preshowerX_samedPhi_, preshowerY_samedPhi_, preshowerZ_samedPhi_, preshowerX_samedR_, preshowerY_samedR_, + preshowerZ_samedR_; + double ecalClusE_, preshowerE_samedPhi_, preshowerE_samedR_; + double noiseThrES_; + + EgammaHcalIsolation::arrayHB recHitEThresholdHB_; + EgammaHcalIsolation::arrayHE recHitEThresholdHE_; + + const edm::ESGetToken geometryToken_; + const edm::ESGetToken ecalPFRechitThresholdsToken_; + const EcalClusterLazyTools::ESGetTokens ecalClusterToolsESGetTokens_; + + edm::ESHandle pG_; + edm::EDGetTokenT rhoLabel_; + edm::EDGetTokenT EBecalCollection_; + edm::EDGetTokenT EEecalCollection_; + edm::EDGetTokenT ESCollection_; + edm::EDGetTokenT HBHERecHitsCollection_; + + ///values of dR etc to cluster the hits in various sub-detectors + static constexpr float dr2Max_ECALClus_ = 0.2 * 0.2; + static constexpr float rho2Min_ECALpos_ = 31 * 31; //cm + static constexpr float rho2Max_ECALpos_ = 172 * 172; //cm + static constexpr float dRho2Max_HCALClus_SamePhi_ = 26 * 26; //cm + static constexpr float dPhiMax_HCALClus_SamePhi_ = 0.15; + static constexpr float dR2Max_HCALClus_SamePhi_ = 0.15 * 0.15; + static constexpr float dRho2Max_ESClus_ = 2.2 * 2.2; //cm + static constexpr float dXY_ESClus_SamePhi_ = 1; ///cm + static constexpr float dXY_ESClus_SamedR_ = 1; ///cm +}; + +#endif // PhotonMVABasedHaloTagger_H diff --git a/RecoEgamma/PhotonIdentification/python/mvaHaloVariable_cfi.py b/RecoEgamma/PhotonIdentification/python/mvaHaloVariable_cfi.py new file mode 100644 index 0000000000000..b0e1cb278a953 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/python/mvaHaloVariable_cfi.py @@ -0,0 +1,20 @@ +import FWCore.ParameterSet.Config as cms +from RecoEgamma.EgammaIsolationAlgos.egammaHBHERecHitThreshold_cff import egammaHBHERecHit + +pathToHaloMVATrainingFile = "RecoEgamma/PhotonIdentification/data/beamHaloTaggerID/xgboostToTMVA_BHtagger.root" +mvaHaloVariable = cms.PSet( + #required inputs + trainingFileName = cms.FileInPath(pathToHaloMVATrainingFile), + rhoLabel = cms.InputTag("fixedGridRhoFastjetAllTmp"), + barrelEcalRecHitCollection = cms.InputTag("ecalRecHit","EcalRecHitsEB"), + endcapEcalRecHitCollection = cms.InputTag("ecalRecHit","EcalRecHitsEE"), + esRecHitCollection = cms.InputTag("ecalPreshowerRecHit","EcalRecHitsES"), + HBHERecHitsCollection = egammaHBHERecHit.hbheRecHits, + recHitEThresholdHB = egammaHBHERecHit.recHitEThresholdHB, + recHitEThresholdHE = egammaHBHERecHit.recHitEThresholdHE, + noiseThrES = cms.double(0.0) + + +) + + diff --git a/RecoEgamma/PhotonIdentification/src/PhotonMVABasedHaloTagger.cc b/RecoEgamma/PhotonIdentification/src/PhotonMVABasedHaloTagger.cc new file mode 100644 index 0000000000000..afaffacd73b56 --- /dev/null +++ b/RecoEgamma/PhotonIdentification/src/PhotonMVABasedHaloTagger.cc @@ -0,0 +1,427 @@ +/** \class PhotonMVABasedHaloTagger + * \author Shilpi Jain (University of Minnesota) + * * Links to the presentation: + 1. ECAL DPG: https://indico.cern.ch/event/991261/contributions/4283096/attachments/2219229/3757719/beamHalo_31march_v1.pdf + 2. JetMET POG: https://indico.cern.ch/event/1027614/contributions/4314949/attachments/2224472/3767396/beamHalo_12April.pdf + */ + +#include "RecoEgamma/PhotonIdentification/interface/PhotonMVABasedHaloTagger.h" +#include "DataFormats/DetId/interface/DetId.h" +#include "DataFormats/EcalDetId/interface/EBDetId.h" +#include "DataFormats/EcalRecHit/interface/EcalRecHit.h" + +#include "FWCore/MessageLogger/interface/MessageLogger.h" +#include "RecoEcal/EgammaCoreTools/interface/EcalClusterTools.h" +#include +#include "CommonTools/MVAUtils/interface/GBRForestTools.h" + +PhotonMVABasedHaloTagger::PhotonMVABasedHaloTagger(const edm::ParameterSet& conf, edm::ConsumesCollector&& iC) + : geometryToken_(iC.esConsumes()), + ecalPFRechitThresholdsToken_(iC.esConsumes()), + ecalClusterToolsESGetTokens_(std::move(iC)) { + rhoLabel_ = iC.consumes(conf.getParameter("rhoLabel")); + + EBecalCollection_ = iC.consumes(conf.getParameter("barrelEcalRecHitCollection")); + EEecalCollection_ = iC.consumes(conf.getParameter("endcapEcalRecHitCollection")); + ESCollection_ = iC.consumes(conf.getParameter("esRecHitCollection")); + HBHERecHitsCollection_ = iC.consumes(conf.getParameter("HBHERecHitsCollection")); + recHitEThresholdHB_ = conf.getParameter("recHitEThresholdHB"); + recHitEThresholdHE_ = conf.getParameter("recHitEThresholdHE"); + + noiseThrES_ = conf.getParameter("noiseThrES"); +} + +double PhotonMVABasedHaloTagger::calculateMVA(const reco::Photon* pho, + const GBRForest* gbr_, + const edm::Event& iEvent, + const edm::EventSetup& es) { + bool isEB = pho->isEB(); + + if (isEB) + return 1.0; /// this MVA is useful and trained only for the EE photons. For EB, there are a lot of other useful handles which can reject beam halo efficiently + + //rho handle + double rho_ = iEvent.get(rhoLabel_); + + // Get all the RecHits + const auto& ecalRecHitsBarrel = iEvent.get(EBecalCollection_); + const auto& ecalRecHitsEndcap = iEvent.get(EEecalCollection_); + const auto& esRecHits = iEvent.get(ESCollection_); + const auto& hbheRecHits = iEvent.get(HBHERecHitsCollection_); + + //gets geometry + pG_ = es.getHandle(geometryToken_); + const CaloGeometry* geo = pG_.product(); + + ///ECAL PF rechit thresholds + auto const& thresholds = es.getData(ecalPFRechitThresholdsToken_); + + noZS::EcalClusterLazyTools lazyToolnoZS( + iEvent, ecalClusterToolsESGetTokens_.get(es), EBecalCollection_, EEecalCollection_); + + ///calculate the energy weighted X, Y and Z position of the photon cluster + if (isEB) + calphoClusCoordinECAL(geo, pho, &thresholds, ecalRecHitsBarrel); + else + calphoClusCoordinECAL(geo, pho, &thresholds, ecalRecHitsEndcap); + + ///calculate the HBHE cluster position hypothesis + calmatchedHBHECoordForBothHypothesis(geo, pho, hbheRecHits); + calmatchedESCoordForBothHypothesis(geo, pho, esRecHits); + + ///this function works for EE only. Above ones work for EB as well in case later one wants to put a similar function for EB without returning 1 + + double angle_EE_HE_samedPhi = calAngleBetweenEEAndSubDet( + hcalClusNhits_samedPhi_, + hcalClusX_samedPhi_, + hcalClusY_samedPhi_, + hcalClusZ_samedPhi_); //essentially caculates the angle and energy variables in the two hypothesis between EE and HE + + double angle_EE_HE_samedR = + calAngleBetweenEEAndSubDet(hcalClusNhits_samedR_, hcalClusX_samedR_, hcalClusY_samedR_, hcalClusZ_samedR_); + + double angle_EE_ES_samedPhi = calAngleBetweenEEAndSubDet( + preshowerNhits_samedPhi_, preshowerX_samedPhi_, preshowerY_samedPhi_, preshowerZ_samedPhi_); + + double angle_EE_ES_samedR = + calAngleBetweenEEAndSubDet(preshowerNhits_samedR_, preshowerX_samedR_, preshowerY_samedR_, preshowerZ_samedR_); + + ////set all the above calculated variables as input to the MVA + + const auto& vCov = lazyToolnoZS.localCovariances(*(pho->superCluster()->seed())); + double spp = (isnan(vCov[2]) ? 0. : sqrt(vCov[2])); + + ///https://cmssdt.cern.ch/lxr/source/RecoEgamma/ElectronIdentification/src/ElectronMVAEstimator.cc + + float vars[15]; + + vars[0] = preshowerE_samedPhi_; + vars[1] = hcalClusE_samedPhi_; + vars[2] = preshowerE_samedR_; + vars[3] = hcalClusE_samedR_; + vars[4] = pho->full5x5_r9(); + vars[5] = pho->superCluster()->etaWidth(); + vars[6] = pho->superCluster()->phiWidth(); + vars[7] = pho->full5x5_sigmaIetaIeta(); + vars[8] = spp; + vars[9] = angle_EE_ES_samedR; + vars[10] = angle_EE_HE_samedR; + vars[11] = angle_EE_ES_samedPhi; + vars[12] = angle_EE_HE_samedPhi; + vars[13] = (pho->superCluster()->preshowerEnergyPlane1() + pho->superCluster()->preshowerEnergyPlane2()) / + pho->superCluster()->rawEnergy(); + vars[14] = rho_; + + double BHmva = gbr_->GetGradBoostClassifier(vars); + return BHmva; +} + +void PhotonMVABasedHaloTagger::calphoClusCoordinECAL(const CaloGeometry* geo, + const reco::Photon* pho, + const EcalPFRecHitThresholds* thresholds, + const EcalRecHitCollection& ecalRecHits) { + ecalClusX_ = 0; + ecalClusY_ = 0; + ecalClusZ_ = 0; + ecalClusNhits_ = 0; + ecalClusE_ = 0; + + double phoSCEta = pho->superCluster()->eta(); + double phoSCPhi = pho->superCluster()->phi(); + + for (const auto& ecalrechit : ecalRecHits) { + auto const det = ecalrechit.id(); + double rhE = ecalrechit.energy(); + const GlobalPoint& rechitPoint = geo->getPosition(det); + + double rhEta = rechitPoint.eta(); + double rhPhi = rechitPoint.phi(); + double rhX = rechitPoint.x(); + double rhY = rechitPoint.y(); + double rhZ = rechitPoint.z(); + + if (thresholds == nullptr) { + throw cms::Exception("EmptyPFRechHitThresCollection") + << "In PhotonMVABasedHaloTagger::calphoClusCoordinECAL, EcalPFRecHitThresholds cannot be = nulptr"; + } + + float rhThres = (*thresholds)[det]; + + if (rhE <= rhThres) + continue; + + if (phoSCEta * rhEta < 0) + continue; + + double dR2 = reco::deltaR2(rhEta, rhPhi, phoSCEta, phoSCPhi); + + if (dR2 < dr2Max_ECALClus_) { + ecalClusX_ += rhX * rhE; + ecalClusY_ += rhY * rhE; + ecalClusZ_ += rhZ * rhE; + ecalClusE_ += rhE; + ecalClusNhits_++; + } + } //for(int ih=0; ih 0) { //should always be > 0 for an EM cluster + ecalClusX_ = ecalClusX_ / ecalClusE_; + ecalClusY_ = ecalClusY_ / ecalClusE_; + ecalClusZ_ = ecalClusZ_ / ecalClusE_; + } //if(ecalClusNhits_>0) +} + +void PhotonMVABasedHaloTagger::calmatchedHBHECoordForBothHypothesis(const CaloGeometry* geo, + const reco::Photon* pho, + const HBHERecHitCollection& HBHERecHits) { + hcalClusX_samedPhi_ = 0; + hcalClusY_samedPhi_ = 0; + hcalClusZ_samedPhi_ = 0; + + hcalClusNhits_samedPhi_ = 0; + hcalClusE_samedPhi_ = 0; + + hcalClusX_samedR_ = 0; + hcalClusY_samedR_ = 0; + hcalClusZ_samedR_ = 0; + hcalClusNhits_samedR_ = 0; + hcalClusE_samedR_ = 0; + + double phoSCEta = pho->superCluster()->eta(); + double phoSCPhi = pho->superCluster()->phi(); + + // Loop over HBHERecHit's + for (const auto& hbherechit : HBHERecHits) { + HcalDetId det = hbherechit.id(); + const GlobalPoint& rechitPoint = geo->getPosition(det); + + double rhEta = rechitPoint.eta(); + double rhPhi = rechitPoint.phi(); + double rhX = rechitPoint.x(); + double rhY = rechitPoint.y(); + double rhZ = rechitPoint.z(); + double rhE = hbherechit.energy(); + + int depth = det.depth(); + + if ((det.subdet() == HcalBarrel and (depth < 1 or depth > int(recHitEThresholdHB_.size()))) or + (det.subdet() == HcalEndcap and (depth < 1 or depth > int(recHitEThresholdHE_.size())))) { + edm::LogWarning("PhotonMVABasedHaloTagger") + << " hit in subdet " << det.subdet() << " has an unaccounted for depth of " << depth + << "!! Leaving this hit!!"; + continue; + } + + const bool goodHBe = det.subdet() == HcalBarrel and rhE > recHitEThresholdHB_[depth - 1]; + const bool goodHEe = det.subdet() == HcalEndcap and rhE > recHitEThresholdHE_[depth - 1]; + if (!(goodHBe or goodHEe)) + continue; + + if (phoSCEta * rhEta < 0) + continue; ///Should be on the same side of Z + + double dPhi = deltaPhi(phoSCPhi, rhPhi); + + ///only valid for the EE; this is 26 cm; hit within 3x3 of HCAL centered at the EECAL xtal + bool isRHBehindECAL = std::abs(dPhi) < dPhiMax_HCALClus_SamePhi_; + if (isRHBehindECAL) { + double rho2 = pow(rhX, 2) + pow(rhY, 2); + isRHBehindECAL &= (rho2 >= rho2Min_ECALpos_ && rho2 <= rho2Max_ECALpos_); + if (isRHBehindECAL) { + double dRho2 = pow(rhX - ecalClusX_, 2) + pow(rhY - ecalClusY_, 2); + isRHBehindECAL &= dRho2 <= dRho2Max_HCALClus_SamePhi_; + if (isRHBehindECAL) { + hcalClusX_samedPhi_ += rhX * rhE; + hcalClusY_samedPhi_ += rhY * rhE; + hcalClusZ_samedPhi_ += rhZ * rhE; + hcalClusE_samedPhi_ += rhE; + hcalClusNhits_samedPhi_++; + } + } + } //if(rho>=31 && rho<=172) + + ///dont use hits which are just behind the ECAL in the same phi region + if (!isRHBehindECAL) { + double dR2 = reco::deltaR2(phoSCEta, phoSCPhi, rhEta, rhPhi); + if (dR2 < dR2Max_HCALClus_SamePhi_) { + hcalClusX_samedR_ += rhX * rhE; + hcalClusY_samedR_ += rhY * rhE; + hcalClusZ_samedR_ += rhZ * rhE; + hcalClusE_samedR_ += rhE; + hcalClusNhits_samedR_++; + } + } + } //for(int ih=0; ih 0) { + hcalClusX_samedPhi_ = hcalClusX_samedPhi_ / hcalClusE_samedPhi_; + hcalClusY_samedPhi_ = hcalClusY_samedPhi_ / hcalClusE_samedPhi_; + hcalClusZ_samedPhi_ = hcalClusZ_samedPhi_ / hcalClusE_samedPhi_; + } //if(hcalClusNhits_samedPhi_>0) + + if (hcalClusNhits_samedR_ > 0) { + hcalClusX_samedR_ = hcalClusX_samedR_ / hcalClusE_samedR_; + hcalClusY_samedR_ = hcalClusY_samedR_ / hcalClusE_samedR_; + hcalClusZ_samedR_ = hcalClusZ_samedR_ / hcalClusE_samedR_; + } //if(hcalClusNhits_samedR_>0) +} + +void PhotonMVABasedHaloTagger::calmatchedESCoordForBothHypothesis(const CaloGeometry* geo, + const reco::Photon* pho, + const EcalRecHitCollection& ESRecHits) { + preshowerX_samedPhi_ = 0; + preshowerY_samedPhi_ = 0; + preshowerZ_samedPhi_ = 0; + preshowerNhits_samedPhi_ = 0; + preshowerE_samedPhi_ = 0; + + preshowerX_samedR_ = 0; + preshowerY_samedR_ = 0; + preshowerZ_samedR_ = 0; + preshowerNhits_samedR_ = 0; + preshowerE_samedR_ = 0; + + double phoSCEta = pho->superCluster()->eta(); + double phoSCPhi = pho->superCluster()->phi(); + + double tmpDiffdRho = 999; + double matchX_samephi = -999; + double matchY_samephi = -999; + bool foundESRH_samephi = false; + + double tmpDiffdRho_samedR = 999; + double matchX_samedR = -999; + double matchY_samedR = -999; + bool foundESRH_samedR = false; + + ///get theta and phi of the coordinates of photon + double tan_theta = 1. / sinh(phoSCEta); + + double cos_phi = cos(phoSCPhi); + double sin_phi = sin(phoSCPhi); + + for (const auto& esrechit : ESRecHits) { + const GlobalPoint& rechitPoint = geo->getPosition(esrechit.id()); + + double rhEta = rechitPoint.eta(); + double rhX = rechitPoint.x(); + double rhY = rechitPoint.y(); + double rhZ = rechitPoint.z(); + double rhE = esrechit.energy(); + + if (phoSCEta * rhEta < 0) + continue; + + if (rhE < noiseThrES_) + continue; + + ////try to include RH according to the strips, 11 in X and 11 in Y + /////////First calculate RH nearest in phi and eta to that of the photon SC + + //////same phi ----> the X and Y should be similar + ////i.e. hit is required to be within the ----> seems better match with the data compared to 2.47 + double dRho2 = pow(rhX - ecalClusX_, 2) + pow(rhY - ecalClusY_, 2); + + if (dRho2 < tmpDiffdRho && dRho2 < dRho2Max_ESClus_) { + tmpDiffdRho = dRho2; + matchX_samephi = rhX; + matchY_samephi = rhY; + foundESRH_samephi = true; + } + + ////////same eta + ///calculate the expected x and y at the position of hte rechit + double exp_ESRho = rhZ * tan_theta; + double exp_ESX = cos_phi * exp_ESRho; + double exp_ESY = sin_phi * exp_ESRho; + + double dRho_samedR2 = pow(rhX - exp_ESX, 2) + pow(rhY - exp_ESY, 2); + + if (dRho_samedR2 < tmpDiffdRho_samedR) { + tmpDiffdRho_samedR = dRho_samedR2; + matchX_samedR = rhX; + matchY_samedR = rhY; + foundESRH_samedR = true; + } + + } /// for (const auto& esrechit : ESRecHits) + + ////Now calculate the sum in +/- 5 strips in X and y around the matched RH + //+/5 strips mean = 5*~2mm = +/-10 mm = 1 cm + + for (const auto& esrechit : ESRecHits) { + const GlobalPoint& rechitPoint = geo->getPosition(esrechit.id()); + + double rhEta = rechitPoint.eta(); + double rhX = rechitPoint.x(); + double rhY = rechitPoint.y(); + double rhZ = rechitPoint.z(); + double rhE = esrechit.energy(); + + if (phoSCEta * rhEta < 0) + continue; + if (rhE < noiseThrES_) + continue; + + ///same phi + bool isRHBehindECAL = foundESRH_samephi; + if (isRHBehindECAL) { + double dX_samephi = std::abs(matchX_samephi - rhX); + double dY_samephi = std::abs(matchY_samephi - rhY); + isRHBehindECAL &= (dX_samephi < dXY_ESClus_SamePhi_ && dY_samephi < dXY_ESClus_SamePhi_); + if (isRHBehindECAL) { + preshowerX_samedPhi_ += rhX * rhE; + preshowerY_samedPhi_ += rhY * rhE; + preshowerZ_samedPhi_ += rhZ * rhE; + preshowerE_samedPhi_ += rhE; + preshowerNhits_samedPhi_++; + } + } + + ///same dR + if (!isRHBehindECAL && foundESRH_samedR) { + double dX_samedR = std::abs(matchX_samedR - rhX); + double dY_samedR = std::abs(matchY_samedR - rhY); + + if (dX_samedR < dXY_ESClus_SamedR_ && dY_samedR < dXY_ESClus_SamedR_) { + preshowerX_samedR_ += rhX * rhE; + preshowerY_samedR_ += rhY * rhE; + preshowerZ_samedR_ += rhZ * rhE; + preshowerE_samedR_ += rhE; + preshowerNhits_samedR_++; + } + } + } ///for(int ih=0; ih 0) { + preshowerX_samedPhi_ = preshowerX_samedPhi_ / preshowerE_samedPhi_; + preshowerY_samedPhi_ = preshowerY_samedPhi_ / preshowerE_samedPhi_; + preshowerZ_samedPhi_ = preshowerZ_samedPhi_ / preshowerE_samedPhi_; + } //if(preshowerNhits_samedPhi_>0) + + if (preshowerNhits_samedR_ > 0) { + preshowerX_samedR_ = preshowerX_samedR_ / preshowerE_samedR_; + preshowerY_samedR_ = preshowerY_samedR_ / preshowerE_samedR_; + preshowerZ_samedR_ = preshowerZ_samedR_ / preshowerE_samedR_; + } //if(preshowerNhits_samedR_>0) +} + +double PhotonMVABasedHaloTagger::calAngleBetweenEEAndSubDet(int nhits, + double subdetClusX, + double subdetClusY, + double subdetClusZ) { + ////get the angle of the line joining the ECAL cluster and the subdetector wrt Z axis for any hypothesis + + double angle = -999; + + if (ecalClusNhits_ > 0 && nhits > 0) { + double dR = + sqrt(pow(subdetClusX - ecalClusX_, 2) + pow(subdetClusY - ecalClusY_, 2) + pow(subdetClusZ - ecalClusZ_, 2)); + + double cosTheta = std::abs(subdetClusZ - ecalClusZ_) / dR; + + angle = acos(cosTheta); + } + + return angle; +}