File indexing completed on 2024-04-06 12:24:40
0001 #include "RecoEcal/EgammaClusterAlgos/interface/SCEnergyCorrectorSemiParm.h"
0002
0003 #include "FWCore/Utilities/interface/isFinite.h"
0004 #include "FWCore/Utilities/interface/Transition.h"
0005 #include "DataFormats/EcalDetId/interface/EcalSubdetector.h"
0006 #include "DataFormats/VertexReco/interface/Vertex.h"
0007 #include "DataFormats/Math/interface/deltaPhi.h"
0008 #include "RecoEcal/EgammaCoreTools/interface/EcalTools.h"
0009 #include "RecoEcal/EgammaCoreTools/interface/EcalClusterTools.h"
0010 #include "RecoEgamma/EgammaTools/interface/EgammaHGCALIDParamDefaults.h"
0011
0012 #include <vdt/vdtMath.h>
0013
0014 using namespace reco;
0015
0016 namespace {
0017
0018 std::pair<bool, float> getMaxDRNonSeedCluster(const reco::SuperCluster& sc) {
0019 float maxDR2 = 0.;
0020 const edm::Ptr<reco::CaloCluster>& seedClus = sc.seed();
0021
0022 for (const auto& clus : sc.clusters()) {
0023 if (clus == seedClus) {
0024 continue;
0025 }
0026
0027
0028 const double dr2 = reco::deltaR2(*clus, *seedClus);
0029 if (dr2 > maxDR2) {
0030 maxDR2 = dr2;
0031 }
0032 }
0033 return {sc.clustersSize() != 1, sc.clustersSize() != 1 ? std::sqrt(maxDR2) : 999.};
0034 }
0035 template <typename T>
0036 int countRecHits(const T& recHitHandle, float threshold) {
0037 int count = 0;
0038 if (recHitHandle.isValid()) {
0039 for (const auto& recHit : *recHitHandle) {
0040 if (recHit.energy() > threshold) {
0041 count++;
0042 }
0043 }
0044 }
0045 return count;
0046 }
0047 }
0048
0049 SCEnergyCorrectorSemiParm::SCEnergyCorrectorSemiParm()
0050 : caloTopo_(nullptr),
0051 caloGeom_(nullptr),
0052 isHLT_(false),
0053 isPhaseII_(false),
0054 regTrainedWithPS_(true),
0055 applySigmaIetaIphiBug_(false),
0056 nHitsAboveThresholdEB_(0),
0057 nHitsAboveThresholdEE_(0),
0058 nHitsAboveThresholdHG_(0),
0059 hitsEnergyThreshold_(-1.),
0060 hgcalCylinderR_(0.) {}
0061
0062 SCEnergyCorrectorSemiParm::SCEnergyCorrectorSemiParm(const edm::ParameterSet& iConfig, edm::ConsumesCollector cc)
0063 : SCEnergyCorrectorSemiParm() {
0064 setTokens(iConfig, cc);
0065 }
0066
0067 void SCEnergyCorrectorSemiParm::fillPSetDescription(edm::ParameterSetDescription& desc) {
0068 desc.add<bool>("isHLT", false);
0069 desc.add<bool>("isPhaseII", false);
0070 desc.add<bool>("regTrainedWithPS", true);
0071 desc.add<bool>("applySigmaIetaIphiBug", false);
0072 desc.add<edm::InputTag>("ecalRecHitsEE", edm::InputTag("ecalRecHit", "EcalRecHitsEE"));
0073 desc.add<edm::InputTag>("ecalRecHitsEB", edm::InputTag("ecalRecHit", "EcalRecHitsEB"));
0074 desc.add<std::string>("regressionKeyEB", "pfscecal_EBCorrection_offline_v2");
0075 desc.add<std::string>("regressionKeyEE", "pfscecal_EECorrection_offline_v2");
0076 desc.add<std::string>("uncertaintyKeyEB", "pfscecal_EBUncertainty_offline_v2");
0077 desc.add<std::string>("uncertaintyKeyEE", "pfscecal_EEUncertainty_offline_v2");
0078 desc.add<double>("regressionMinEB", 0.2);
0079 desc.add<double>("regressionMaxEB", 2.0);
0080 desc.add<double>("regressionMinEE", 0.2);
0081 desc.add<double>("regressionMaxEE", 2.0);
0082 desc.add<double>("uncertaintyMinEB", 0.0002);
0083 desc.add<double>("uncertaintyMaxEB", 0.5);
0084 desc.add<double>("uncertaintyMinEE", 0.0002);
0085 desc.add<double>("uncertaintyMaxEE", 0.5);
0086 desc.add<edm::InputTag>("vertexCollection", edm::InputTag("offlinePrimaryVertices"));
0087 desc.add<double>("eRecHitThreshold", 1.);
0088 desc.add<edm::InputTag>("hgcalRecHits", edm::InputTag());
0089 desc.add<double>("hgcalCylinderR", EgammaHGCALIDParamDefaults::kRCylinder);
0090 }
0091
0092 edm::ParameterSetDescription SCEnergyCorrectorSemiParm::makePSetDescription() {
0093 edm::ParameterSetDescription desc;
0094 fillPSetDescription(desc);
0095 return desc;
0096 }
0097
0098 void SCEnergyCorrectorSemiParm::setEventSetup(const edm::EventSetup& es) {
0099 caloTopo_ = &es.getData(caloTopoToken_);
0100 caloGeom_ = &es.getData(caloGeomToken_);
0101
0102 regParamBarrel_.setForests(es);
0103 regParamEndcap_.setForests(es);
0104
0105 if (isPhaseII_) {
0106 hgcalShowerShapes_.initPerSetup(es);
0107 }
0108 }
0109
0110 void SCEnergyCorrectorSemiParm::setEvent(const edm::Event& event) {
0111 event.getByToken(tokenEBRecHits_, recHitsEB_);
0112 if (!isPhaseII_) {
0113 event.getByToken(tokenEERecHits_, recHitsEE_);
0114 } else {
0115 event.getByToken(tokenHgcalRecHits_, recHitsHgcal_);
0116 hgcalShowerShapes_.initPerEvent(*recHitsHgcal_);
0117 }
0118 if (isHLT_ || isPhaseII_) {
0119
0120
0121 nHitsAboveThresholdEB_ = countRecHits(recHitsEB_, hitsEnergyThreshold_);
0122 nHitsAboveThresholdEE_ = countRecHits(recHitsEE_, hitsEnergyThreshold_);
0123 nHitsAboveThresholdHG_ = countRecHits(recHitsHgcal_, hitsEnergyThreshold_);
0124 }
0125 if (!isHLT_) {
0126 event.getByToken(tokenVertices_, vertices_);
0127 }
0128 }
0129
0130 std::pair<double, double> SCEnergyCorrectorSemiParm::getCorrections(const reco::SuperCluster& sc) const {
0131 std::pair<double, double> corrEnergyAndRes = {-1, -1};
0132
0133 const auto regData = getRegData(sc);
0134 if (regData.empty()) {
0135
0136 return corrEnergyAndRes;
0137 }
0138 DetId seedId = sc.seed()->seed();
0139 const auto& regParam = getRegParam(seedId);
0140
0141 double mean = regParam.mean(regData);
0142 double sigma = regParam.sigma(regData);
0143
0144 double energyCorr = mean * sc.rawEnergy();
0145 if (isHLT_ && sc.seed()->seed().det() == DetId::Ecal && seedId.subdetId() == EcalEndcap && !regTrainedWithPS_) {
0146 energyCorr += sc.preshowerEnergy();
0147 }
0148 double resolutionEst = sigma * energyCorr;
0149
0150 corrEnergyAndRes.first = energyCorr;
0151 corrEnergyAndRes.second = resolutionEst;
0152
0153 return corrEnergyAndRes;
0154 }
0155
0156 void SCEnergyCorrectorSemiParm::modifyObject(reco::SuperCluster& sc) const {
0157 std::pair<double, double> cor = getCorrections(sc);
0158 if (cor.first < 0)
0159 return;
0160 sc.setEnergy(cor.first);
0161 sc.setCorrectedEnergy(cor.first);
0162 if (cor.second >= 0) {
0163 sc.setCorrectedEnergyUncertainty(cor.second);
0164 }
0165 }
0166
0167 std::vector<float> SCEnergyCorrectorSemiParm::getRegData(const reco::SuperCluster& sc) const {
0168 switch (sc.seed()->seed().det()) {
0169 case DetId::Ecal:
0170 if (isPhaseII_ && sc.seed()->seed().subdetId() == EcalEndcap) {
0171 throw cms::Exception("ConfigError") << " Error in SCEnergyCorrectorSemiParm: "
0172 << " running over events with EcalEndcap clusters while enabling "
0173 "isPhaseII, please set isPhaseII = False in regression config";
0174 }
0175 return isHLT_ ? getRegDataECALHLTV1(sc) : getRegDataECALV1(sc);
0176 case DetId::HGCalEE:
0177 if (!isPhaseII_) {
0178 throw cms::Exception("ConfigError") << " Error in SCEnergyCorrectorSemiParm: "
0179 << " running over PhaseII events without enabling isPhaseII, please set "
0180 "isPhaseII = True in regression config";
0181 }
0182 return isHLT_ ? getRegDataHGCALHLTV1(sc) : getRegDataHGCALV1(sc);
0183 default:
0184 return std::vector<float>();
0185 }
0186 }
0187
0188 void SCEnergyCorrectorSemiParm::RegParam::setForests(const edm::EventSetup& setup) {
0189 meanForest_ = &setup.getData(meanForestToken_);
0190 sigmaForest_ = &setup.getData(sigmaForestToken_);
0191 }
0192
0193 double SCEnergyCorrectorSemiParm::RegParam::mean(const std::vector<float>& data) const {
0194 return meanForest_ ? meanOutTrans_(meanForest_->GetResponse(data.data())) : -1;
0195 }
0196
0197 double SCEnergyCorrectorSemiParm::RegParam::sigma(const std::vector<float>& data) const {
0198 return sigmaForest_ ? sigmaOutTrans_(sigmaForest_->GetResponse(data.data())) : -1;
0199 }
0200
0201 std::vector<float> SCEnergyCorrectorSemiParm::getRegDataECALV1(const reco::SuperCluster& sc) const {
0202 std::vector<float> eval(30, 0.);
0203
0204 const reco::CaloCluster& seedCluster = *(sc.seed());
0205 const bool iseb = seedCluster.hitsAndFractions()[0].first.subdetId() == EcalBarrel;
0206 const EcalRecHitCollection* recHits = iseb ? recHitsEB_.product() : recHitsEE_.product();
0207
0208 const double raw_energy = sc.rawEnergy();
0209 const int numberOfClusters = sc.clusters().size();
0210
0211 const auto& localCovariances = EcalClusterTools::localCovariances(seedCluster, recHits, caloTopo_);
0212
0213 const float eLeft = EcalClusterTools::eLeft(seedCluster, recHits, caloTopo_);
0214 const float eRight = EcalClusterTools::eRight(seedCluster, recHits, caloTopo_);
0215 const float eTop = EcalClusterTools::eTop(seedCluster, recHits, caloTopo_);
0216 const float eBottom = EcalClusterTools::eBottom(seedCluster, recHits, caloTopo_);
0217
0218 float sigmaIetaIeta = sqrt(localCovariances[0]);
0219 float sigmaIetaIphi = std::numeric_limits<float>::max();
0220 float sigmaIphiIphi = std::numeric_limits<float>::max();
0221
0222 if (!edm::isNotFinite(localCovariances[2]))
0223 sigmaIphiIphi = sqrt(localCovariances[2]);
0224
0225
0226 const float see_by_spp = sigmaIetaIeta * (applySigmaIetaIphiBug_ ? std::numeric_limits<float>::max() : sigmaIphiIphi);
0227 if (see_by_spp > 0) {
0228 sigmaIetaIphi = localCovariances[1] / see_by_spp;
0229 } else if (localCovariances[1] > 0) {
0230 sigmaIetaIphi = 1.f;
0231 } else {
0232 sigmaIetaIphi = -1.f;
0233 }
0234
0235
0236 std::vector<float> clusterRawEnergy;
0237 clusterRawEnergy.resize(std::max(3, numberOfClusters), 0);
0238 std::vector<float> clusterDEtaToSeed;
0239 clusterDEtaToSeed.resize(std::max(3, numberOfClusters), 0);
0240 std::vector<float> clusterDPhiToSeed;
0241 clusterDPhiToSeed.resize(std::max(3, numberOfClusters), 0);
0242 float clusterMaxDR = 999.;
0243 float clusterMaxDRDPhi = 999.;
0244 float clusterMaxDRDEta = 999.;
0245 float clusterMaxDRRawEnergy = 0.;
0246
0247 size_t iclus = 0;
0248 float maxDR = 0;
0249 edm::Ptr<reco::CaloCluster> pclus;
0250 const edm::Ptr<reco::CaloCluster>& theseed = sc.seed();
0251
0252 auto clusend = sc.clustersEnd();
0253 for (auto clus = sc.clustersBegin(); clus != clusend; ++clus) {
0254 pclus = *clus;
0255
0256 if (theseed == pclus)
0257 continue;
0258 clusterRawEnergy[iclus] = pclus->energy();
0259 clusterDPhiToSeed[iclus] = reco::deltaPhi(pclus->phi(), theseed->phi());
0260 clusterDEtaToSeed[iclus] = pclus->eta() - theseed->eta();
0261
0262
0263 const auto the_dr = reco::deltaR(*pclus, *theseed);
0264 if (the_dr > maxDR) {
0265 maxDR = the_dr;
0266 clusterMaxDR = maxDR;
0267 clusterMaxDRDPhi = clusterDPhiToSeed[iclus];
0268 clusterMaxDRDEta = clusterDEtaToSeed[iclus];
0269 clusterMaxDRRawEnergy = clusterRawEnergy[iclus];
0270 }
0271 ++iclus;
0272 }
0273
0274 eval[0] = vertices_->size();
0275 eval[1] = raw_energy;
0276 eval[2] = sc.etaWidth();
0277 eval[3] = sc.phiWidth();
0278 eval[4] = EcalClusterTools::e3x3(seedCluster, recHits, caloTopo_) / raw_energy;
0279 eval[5] = seedCluster.energy() / raw_energy;
0280 eval[6] = EcalClusterTools::eMax(seedCluster, recHits) / raw_energy;
0281 eval[7] = EcalClusterTools::e2nd(seedCluster, recHits) / raw_energy;
0282 eval[8] = (eLeft + eRight != 0.f ? (eLeft - eRight) / (eLeft + eRight) : 0.f);
0283 eval[9] = (eTop + eBottom != 0.f ? (eTop - eBottom) / (eTop + eBottom) : 0.f);
0284 eval[10] = sigmaIetaIeta;
0285 eval[11] = sigmaIetaIphi;
0286 eval[12] = sigmaIphiIphi;
0287 eval[13] = std::max(0, numberOfClusters - 1);
0288 eval[14] = clusterMaxDR;
0289 eval[15] = clusterMaxDRDPhi;
0290 eval[16] = clusterMaxDRDEta;
0291 eval[17] = clusterMaxDRRawEnergy / raw_energy;
0292 eval[18] = clusterRawEnergy[0] / raw_energy;
0293 eval[19] = clusterRawEnergy[1] / raw_energy;
0294 eval[20] = clusterRawEnergy[2] / raw_energy;
0295 eval[21] = clusterDPhiToSeed[0];
0296 eval[22] = clusterDPhiToSeed[1];
0297 eval[23] = clusterDPhiToSeed[2];
0298 eval[24] = clusterDEtaToSeed[0];
0299 eval[25] = clusterDEtaToSeed[1];
0300 eval[26] = clusterDEtaToSeed[2];
0301 if (iseb) {
0302 EBDetId ebseedid(seedCluster.seed());
0303 eval[27] = ebseedid.ieta();
0304 eval[28] = ebseedid.iphi();
0305 } else {
0306 EEDetId eeseedid(seedCluster.seed());
0307 eval[27] = eeseedid.ix();
0308 eval[28] = eeseedid.iy();
0309
0310
0311
0312 eval[29] = seedCluster.eta();
0313 }
0314 return eval;
0315 }
0316
0317 std::vector<float> SCEnergyCorrectorSemiParm::getRegDataECALHLTV1(const reco::SuperCluster& sc) const {
0318 std::vector<float> eval(7, 0.);
0319 auto maxDRNonSeedClus = getMaxDRNonSeedCluster(sc);
0320 const float clusterMaxDR = maxDRNonSeedClus.first ? maxDRNonSeedClus.second : 999.;
0321
0322 const reco::CaloCluster& seedCluster = *(sc.seed());
0323 const bool iseb = seedCluster.hitsAndFractions()[0].first.subdetId() == EcalBarrel;
0324 const EcalRecHitCollection* recHits = iseb ? recHitsEB_.product() : recHitsEE_.product();
0325
0326 eval[0] = nHitsAboveThresholdEB_ + nHitsAboveThresholdEE_;
0327 eval[1] = sc.eta();
0328 eval[2] = sc.phiWidth();
0329 eval[3] = EcalClusterTools::e3x3(seedCluster, recHits, caloTopo_) / sc.rawEnergy();
0330 eval[4] = std::max(0, static_cast<int>(sc.clusters().size()) - 1);
0331 eval[5] = clusterMaxDR;
0332 eval[6] = sc.rawEnergy();
0333
0334 return eval;
0335 }
0336
0337 std::vector<float> SCEnergyCorrectorSemiParm::getRegDataHGCALV1(const reco::SuperCluster& sc) const {
0338 std::vector<float> eval(17, 0.);
0339
0340 auto ssCalc = hgcalShowerShapes_.createCalc(sc);
0341 auto pcaWidths = ssCalc.getPCAWidths(hgcalCylinderR_);
0342 auto energyHighestHits = ssCalc.getEnergyHighestHits(2);
0343
0344 auto maxDRNonSeedClus = getMaxDRNonSeedCluster(sc);
0345 const float clusterMaxDR = maxDRNonSeedClus.first ? maxDRNonSeedClus.second : 999.;
0346
0347 eval[0] = sc.rawEnergy();
0348 eval[1] = sc.eta();
0349 eval[2] = sc.etaWidth();
0350 eval[3] = sc.phiWidth();
0351 eval[4] = sc.clusters().size();
0352 eval[5] = sc.hitsAndFractions().size();
0353 eval[6] = clusterMaxDR;
0354 eval[7] = sc.eta() - sc.seed()->eta();
0355 eval[8] = reco::deltaPhi(sc.phi(), sc.seed()->phi());
0356 eval[9] = energyHighestHits[0] / sc.rawEnergy();
0357 eval[10] = energyHighestHits[1] / sc.rawEnergy();
0358 eval[11] = std::sqrt(pcaWidths.sigma2uu);
0359 eval[12] = std::sqrt(pcaWidths.sigma2vv);
0360 eval[13] = std::sqrt(pcaWidths.sigma2ww);
0361 eval[14] = ssCalc.getRvar(hgcalCylinderR_, sc.rawEnergy());
0362 eval[15] = sc.seed()->energy() / sc.rawEnergy();
0363 eval[16] = nHitsAboveThresholdEB_ + nHitsAboveThresholdHG_;
0364
0365 return eval;
0366 }
0367
0368 std::vector<float> SCEnergyCorrectorSemiParm::getRegDataHGCALHLTV1(const reco::SuperCluster& sc) const {
0369 std::vector<float> eval(7, 0.);
0370 const float clusterMaxDR = getMaxDRNonSeedCluster(sc).second;
0371
0372 auto ssCalc = hgcalShowerShapes_.createCalc(sc);
0373
0374 eval[0] = sc.rawEnergy();
0375 eval[1] = sc.eta();
0376 eval[2] = sc.phiWidth();
0377 eval[3] = std::max(0, static_cast<int>(sc.clusters().size()) - 1);
0378 eval[4] = ssCalc.getRvar(hgcalCylinderR_);
0379 eval[5] = clusterMaxDR;
0380 eval[6] = nHitsAboveThresholdEB_ + nHitsAboveThresholdHG_;
0381
0382 return eval;
0383 }