File indexing completed on 2024-11-26 02:34:27
0001
0002 #include "RecoEcal/EgammaClusterAlgos/interface/Multi5x5ClusterAlgo.h"
0003
0004
0005 #include "Geometry/Records/interface/IdealGeometryRecord.h"
0006 #include "Geometry/CaloGeometry/interface/CaloSubdetectorGeometry.h"
0007 #include "Geometry/CaloGeometry/interface/CaloCellGeometry.h"
0008 #include "Geometry/CaloTopology/interface/EcalEndcapTopology.h"
0009 #include "Geometry/CaloTopology/interface/EcalBarrelTopology.h"
0010 #include "RecoEcal/EgammaCoreTools/interface/ClusterEtLess.h"
0011 #include "DataFormats/CaloRecHit/interface/CaloID.h"
0012 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0013
0014
0015 template <class T1, class T2, typename Comp = std::less<T1> >
0016 struct PairSortByFirst {
0017 Comp comp;
0018 bool operator()(const std::pair<T1, T2>& lhs, const std::pair<T1, T2>& rhs) { return comp(lhs.first, rhs.first); }
0019 bool operator()(const T1& lhs, const std::pair<T1, T2>& rhs) { return comp(lhs, rhs.first); }
0020 bool operator()(const std::pair<T1, T2>& lhs, const T1& rhs) { return comp(lhs.first, rhs); }
0021 bool operator()(const T1& lhs, const T1& rhs) { return comp(lhs, rhs); }
0022 };
0023
0024 struct EBDetIdSorter {
0025 bool operator()(const EBDetId& lhs, const EBDetId& rhs) {
0026 if (lhs.ieta() < rhs.ieta())
0027 return true;
0028 else if (lhs.ieta() > rhs.ieta())
0029 return false;
0030 else
0031 return lhs.iphi() < rhs.iphi();
0032 }
0033 };
0034
0035 struct EEDetIdSorter {
0036 bool operator()(const EEDetId& lhs, const EEDetId& rhs) {
0037 if (lhs.zside() < rhs.zside())
0038 return true;
0039 else if (lhs.zside() > rhs.zside())
0040 return false;
0041 else {
0042 if (lhs.ix() < rhs.ix())
0043 return true;
0044 else if (lhs.ix() > rhs.ix())
0045 return false;
0046 else
0047 return lhs.iy() < rhs.iy();
0048 }
0049 }
0050 };
0051
0052
0053
0054 std::vector<reco::BasicCluster> Multi5x5ClusterAlgo::makeClusters(const EcalRecHitCollection* hits,
0055 const CaloSubdetectorGeometry* geometry_p,
0056 const CaloSubdetectorTopology* topology_p,
0057 const CaloSubdetectorGeometry* geometryES_p,
0058 reco::CaloID::Detectors detector,
0059 bool regional,
0060 const std::vector<RectangularEtaPhiRegion>& regions) {
0061 std::vector<EcalRecHit> seeds;
0062
0063 double threshold = 0;
0064 std::string ecalPart_string;
0065 detector_ = reco::CaloID::DET_NONE;
0066 if (detector == reco::CaloID::DET_ECAL_ENDCAP) {
0067 detector_ = reco::CaloID::DET_ECAL_ENDCAP;
0068 threshold = ecalEndcapSeedThreshold_;
0069 ecalPart_string = "EndCap";
0070 }
0071 if (detector == reco::CaloID::DET_ECAL_BARREL) {
0072 detector_ = reco::CaloID::DET_ECAL_BARREL;
0073 threshold = ecalBarrelSeedThreshold_;
0074 ecalPart_string = "Barrel";
0075 }
0076
0077 LogTrace("EcalClusters") << "-------------------------------------------------------------";
0078 LogTrace("EcalClusters") << "Island algorithm invoked for ECAL" << ecalPart_string;
0079 LogTrace("EcalClusters") << "Looking for seeds, energy threshold used = " << threshold << " GeV";
0080
0081 int nregions = 0;
0082 if (regional)
0083 nregions = regions.size();
0084
0085 if (!regional || nregions) {
0086 for (auto const& hit : *hits) {
0087 double energy = hit.energy();
0088 if (energy < threshold)
0089 continue;
0090
0091 auto thisCell = geometry_p->getGeometry(hit.id());
0092
0093
0094 bool withinRegion = false;
0095 if (regional) {
0096 for (auto const& region : regions) {
0097 if (region.inRegion(thisCell->etaPos(), thisCell->phiPos())) {
0098 withinRegion = true;
0099 break;
0100 }
0101 }
0102 }
0103
0104 if (!regional || withinRegion) {
0105 float ET = hit.energy() * thisCell->getPosition().basicVector().unit().perp();
0106 if (ET > threshold)
0107 seeds.push_back(hit);
0108 }
0109 }
0110 }
0111
0112 sort(seeds.begin(), seeds.end(), [](auto const& x, auto const& y) { return (x.energy() > y.energy()); });
0113
0114 LogTrace("EcalClusters") << "Total number of seeds found in event = " << seeds.size();
0115
0116 auto clusters_v = mainSearch(hits, geometry_p, topology_p, geometryES_p, seeds);
0117 sort(clusters_v.rbegin(), clusters_v.rend(), isClusterEtLess);
0118
0119 LogTrace("EcalClusters") << "---------- end of main search. clusters have been sorted ----";
0120
0121 return clusters_v;
0122 }
0123
0124
0125
0126 namespace {
0127 class ProtoClusters {
0128 using ProtoBasicCluster = Multi5x5ClusterAlgo::ProtoBasicCluster;
0129 std::vector<ProtoBasicCluster> clusters_;
0130 std::vector<std::pair<DetId, int> > whichClusCrysBelongsTo_;
0131 bool reassignSeedCrysToClusterItSeeds_;
0132
0133 public:
0134 ProtoClusters(bool reassignSeedCrysToClusterItSeeds)
0135 : reassignSeedCrysToClusterItSeeds_(reassignSeedCrysToClusterItSeeds) {}
0136 void push_back(ProtoBasicCluster&& c) {
0137 clusters_.push_back(std::move(c));
0138 if (reassignSeedCrysToClusterItSeeds_) {
0139 for (auto const& hit : clusters_.back().hits()) {
0140 whichClusCrysBelongsTo_.push_back(std::pair<DetId, int>(hit.first, clusters_.size() - 1));
0141 }
0142 }
0143 }
0144 std::vector<ProtoBasicCluster> finalize() {
0145 if (reassignSeedCrysToClusterItSeeds_) {
0146 std::sort(whichClusCrysBelongsTo_.begin(), whichClusCrysBelongsTo_.end(), PairSortByFirst<DetId, int>());
0147
0148 for (size_t clusNr = 0; clusNr < clusters_.size(); clusNr++) {
0149 if (!clusters_[clusNr].containsSeed()) {
0150 const EcalRecHit& seedHit = clusters_[clusNr].seed();
0151 typedef std::vector<std::pair<DetId, int> >::iterator It;
0152 std::pair<It, It> result = std::equal_range(whichClusCrysBelongsTo_.begin(),
0153 whichClusCrysBelongsTo_.end(),
0154 seedHit.id(),
0155 PairSortByFirst<DetId, int>());
0156
0157 if (result.first != result.second)
0158 clusters_[result.first->second].removeHit(seedHit);
0159 clusters_[clusNr].addSeed();
0160 }
0161 }
0162 }
0163 whichClusCrysBelongsTo_.clear();
0164 return std::move(clusters_);
0165 }
0166 };
0167 }
0168
0169 std::vector<reco::BasicCluster> Multi5x5ClusterAlgo::mainSearch(const EcalRecHitCollection* hits,
0170 const CaloSubdetectorGeometry* geometry_p,
0171 const CaloSubdetectorTopology* topology_p,
0172 const CaloSubdetectorGeometry* geometryES_p,
0173 std::vector<EcalRecHit> const& seeds) {
0174 LogTrace("EcalClusters") << "Building clusters............";
0175
0176
0177 std::vector<reco::BasicCluster> clusters_v;
0178
0179
0180 std::set<DetId> used_s;
0181
0182
0183 std::set<DetId> canSeed_s;
0184
0185 ProtoClusters protoClusters{reassignSeedCrysToClusterItSeeds_};
0186
0187
0188 bool first = true;
0189 for (auto const& seed : seeds) {
0190 struct Guard {
0191 bool& b_;
0192 Guard(bool& b) : b_{b} {};
0193 ~Guard() { b_ = false; }
0194 };
0195 Guard guard(first);
0196
0197
0198 bool usedButCanSeed = false;
0199 if (canSeed_s.find(seed.id()) != canSeed_s.end())
0200 usedButCanSeed = true;
0201
0202
0203 if (!seed.checkFlag(EcalRecHit::kGood)) {
0204 if (seed.checkFlags(v_chstatus_))
0205 continue;
0206 }
0207
0208
0209 if ((used_s.find(seed.id()) != used_s.end()) && (usedButCanSeed == false)) {
0210 if (first) {
0211 LogTrace("EcalClusters") << "##############################################################";
0212 LogTrace("EcalClusters") << "DEBUG ALERT: Highest energy seed already belongs to a cluster!";
0213 LogTrace("EcalClusters") << "##############################################################";
0214 }
0215
0216
0217
0218 continue;
0219 }
0220
0221
0222
0223 CaloNavigator<DetId> navigator(seed.id(), topology_p);
0224 DetId seedId = navigator.pos();
0225 EcalRecHitCollection::const_iterator seedIt = hits->find(seedId);
0226 navigator.setHome(seedId);
0227
0228
0229 bool localMaxima = checkMaxima(navigator, hits);
0230
0231 if (localMaxima) {
0232
0233
0234 auto current_v = prepareCluster(navigator, hits, geometry_p, used_s, canSeed_s);
0235
0236
0237
0238 if (!current_v.empty()) {
0239 auto c = makeCluster(hits, geometry_p, geometryES_p, seedIt, usedButCanSeed, current_v);
0240 if (c) {
0241 protoClusters.push_back(std::move(*c));
0242 } else {
0243 for (auto const& current : current_v) {
0244 used_s.erase(current.first);
0245 }
0246 }
0247 }
0248 }
0249 }
0250
0251 auto finalProtoClusters = protoClusters.finalize();
0252
0253 for (auto const& protoCluster : finalProtoClusters) {
0254 Point position = posCalculator_.Calculate_Location(protoCluster.hits(), hits, geometry_p, geometryES_p);
0255 clusters_v.emplace_back(protoCluster.energy(),
0256 position,
0257 reco::CaloID(detector_),
0258 protoCluster.hits(),
0259 reco::CaloCluster::multi5x5,
0260 protoCluster.seed().id());
0261 }
0262
0263 return clusters_v;
0264 }
0265
0266 std::optional<Multi5x5ClusterAlgo::ProtoBasicCluster> Multi5x5ClusterAlgo::makeCluster(
0267 const EcalRecHitCollection* hits,
0268 const CaloSubdetectorGeometry* geometry,
0269 const CaloSubdetectorGeometry* geometryES,
0270 const EcalRecHitCollection::const_iterator& seedIt,
0271 bool seedOutside,
0272 std::vector<std::pair<DetId, float> >& current_v) {
0273 double energy = 0;
0274
0275 reco::CaloID caloID;
0276 Point position;
0277 position = posCalculator_.Calculate_Location(current_v, hits, geometry, geometryES);
0278
0279 for (auto const& hitInfo : current_v) {
0280 EcalRecHitCollection::const_iterator itt = hits->find(hitInfo.first);
0281 EcalRecHit hit_p = *itt;
0282 energy += hit_p.energy();
0283
0284 if (hitInfo.first.subdetId() == EcalBarrel) {
0285 caloID = reco::CaloID::DET_ECAL_BARREL;
0286 } else {
0287 caloID = reco::CaloID::DET_ECAL_ENDCAP;
0288 }
0289 }
0290
0291
0292 LogTrace("EcalClusters") << "******** NEW CLUSTER ********";
0293 LogTrace("EcalClusters") << "No. of crystals = " << current_v.size();
0294 LogTrace("EcalClusters") << " Energy = " << energy;
0295 LogTrace("EcalClusters") << " Phi = " << position.phi();
0296 LogTrace("EcalClusters") << " Eta " << position.eta();
0297 LogTrace("EcalClusters") << "*****************************";
0298
0299
0300
0301 double seedEnergy = seedIt->energy();
0302 if ((seedOutside && energy >= 0) || (!seedOutside && energy >= seedEnergy)) {
0303 return ProtoBasicCluster(energy, *seedIt, std::move(current_v));
0304
0305
0306
0307
0308
0309 }
0310 return {};
0311 }
0312
0313 bool Multi5x5ClusterAlgo::checkMaxima(CaloNavigator<DetId>& navigator, const EcalRecHitCollection* hits) const {
0314 bool maxima = true;
0315 EcalRecHitCollection::const_iterator thisHit;
0316 EcalRecHitCollection::const_iterator seedHit = hits->find(navigator.pos());
0317 double seedEnergy = seedHit->energy();
0318
0319 std::array<DetId, 4> swissCrossVec;
0320
0321 swissCrossVec[0] = navigator.west();
0322 navigator.home();
0323 swissCrossVec[1] = navigator.east();
0324 navigator.home();
0325 swissCrossVec[2] = navigator.north();
0326 navigator.home();
0327 swissCrossVec[3] = navigator.south();
0328 navigator.home();
0329
0330 for (auto const& det : swissCrossVec) {
0331
0332 thisHit = hits->find(det);
0333
0334
0335 if ((det == DetId(0)) || thisHit == hits->end())
0336 continue;
0337
0338
0339
0340 uint32_t rhFlag = thisHit->recoFlag();
0341 std::vector<int>::const_iterator vit = std::find(v_chstatus_.begin(), v_chstatus_.end(), rhFlag);
0342 if (vit != v_chstatus_.end())
0343 continue;
0344
0345
0346
0347 if (thisHit->energy() > seedEnergy) {
0348 maxima = false;
0349 break;
0350 }
0351 }
0352
0353 return maxima;
0354 }
0355
0356 std::vector<std::pair<DetId, float> > Multi5x5ClusterAlgo::prepareCluster(CaloNavigator<DetId>& navigator,
0357 const EcalRecHitCollection* hits,
0358 const CaloSubdetectorGeometry* geometry,
0359 std::set<DetId>& used_s,
0360 std::set<DetId>& canSeed_s) const {
0361 std::vector<std::pair<DetId, float> > current_v;
0362 DetId thisDet;
0363 std::set<DetId>::iterator setItr;
0364
0365
0366
0367
0368
0369
0370 for (int dx = -2; dx < 3; ++dx) {
0371 for (int dy = -2; dy < 3; ++dy) {
0372
0373
0374 thisDet = navigator.offsetBy(dx, dy);
0375 navigator.home();
0376
0377
0378
0379 if (addCrystal(thisDet, *hits) and (used_s.find(thisDet) == used_s.end())) {
0380 current_v.push_back(std::pair<DetId, float>(thisDet, 1.));
0381 used_s.insert(thisDet);
0382 }
0383
0384
0385
0386 if ((abs(dx) > 1) || (abs(dy) > 1)) {
0387
0388
0389
0390 canSeed_s.insert(thisDet);
0391 }
0392 else {
0393
0394
0395 setItr = canSeed_s.find(thisDet);
0396 if (setItr != canSeed_s.end()) {
0397
0398 canSeed_s.erase(setItr);
0399 }
0400 }
0401
0402 }
0403
0404 }
0405
0406
0407
0408
0409 return current_v;
0410 }
0411
0412 bool Multi5x5ClusterAlgo::addCrystal(const DetId& det, const EcalRecHitCollection& recHits) {
0413 auto thisIt = recHits.find(det);
0414 return ((thisIt != recHits.end()) && (thisIt->id() != DetId(0)));
0415 }
0416
0417 bool Multi5x5ClusterAlgo::ProtoBasicCluster::removeHit(const EcalRecHit& hitToRM) {
0418 std::vector<std::pair<DetId, float> >::iterator hitPos;
0419 for (hitPos = hits_.begin(); hitPos < hits_.end(); hitPos++) {
0420 if (hitToRM.id() == hitPos->first)
0421 break;
0422 }
0423 if (hitPos != hits_.end()) {
0424 hits_.erase(hitPos);
0425 energy_ -= hitToRM.energy();
0426 return true;
0427 }
0428 return false;
0429 }
0430
0431
0432
0433 bool Multi5x5ClusterAlgo::ProtoBasicCluster::addSeed() {
0434 typedef std::vector<std::pair<DetId, float> >::iterator It;
0435 std::pair<It, It> hitPos;
0436
0437 if (seed_.id().subdetId() == EcalBarrel) {
0438 hitPos = std::equal_range(hits_.begin(), hits_.end(), seed_.id(), PairSortByFirst<DetId, float, EBDetIdSorter>());
0439 } else {
0440 hitPos = std::equal_range(hits_.begin(), hits_.end(), seed_.id(), PairSortByFirst<DetId, float, EEDetIdSorter>());
0441 }
0442
0443 if (hitPos.first == hitPos.second) {
0444 hits_.insert(hitPos.first, std::pair<DetId, float>(seed_.id(), 1.));
0445 energy_ += seed_.energy();
0446 containsSeed_ = true;
0447
0448 return true;
0449 } else
0450 return false;
0451 }
0452
0453 bool Multi5x5ClusterAlgo::ProtoBasicCluster::isSeedCrysInHits_() const {
0454 for (auto const& hit : hits_) {
0455 if (seed_.id() == hit.first)
0456 return true;
0457 }
0458 return false;
0459 }