00001 #include "RecoEcal/EgammaClusterAlgos/interface/PFECALSuperClusterAlgo.h"
00002 #include "RecoParticleFlow/PFClusterTools/interface/PFClusterWidthAlgo.h"
00003 #include "RecoParticleFlow/PFClusterTools/interface/LinkByRecHit.h"
00004 #include "DataFormats/ParticleFlowReco/interface/PFLayer.h"
00005 #include "DataFormats/HcalDetId/interface/HcalDetId.h"
00006 #include "RecoEcal/EgammaCoreTools/interface/Mustache.h"
00007 #include "Math/GenVector/VectorUtil.h"
00008 #include "TFile.h"
00009 #include "TH2F.h"
00010 #include "TROOT.h"
00011 #include "TMath.h"
00012
00013 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00014
00015 #include <stdexcept>
00016 #include <string>
00017 #include <sstream>
00018 #include <cmath>
00019
00020 using namespace std;
00021 namespace MK = reco::MustacheKernel;
00022
00023
00024 namespace {
00025 typedef edm::View<reco::PFCluster> PFClusterView;
00026 typedef edm::Ptr<reco::PFCluster> PFClusterPtr;
00027 typedef edm::PtrVector<reco::PFCluster> PFClusterPtrVector;
00028 typedef PFECALSuperClusterAlgo::CalibratedClusterPtr CalibClusterPtr;
00029 typedef PFECALSuperClusterAlgo::CalibratedClusterPtrVector CalibClusterPtrVector;
00030
00031 typedef std::binary_function<const CalibClusterPtr&,
00032 const CalibClusterPtr&,
00033 bool> ClusBinaryFunction;
00034
00035 typedef std::unary_function<const CalibClusterPtr&,
00036 bool> ClusUnaryFunction;
00037
00038 struct SumPSEnergy : public std::binary_function<double,
00039 const PFClusterPtr&,
00040 double> {
00041 PFLayer::Layer _thelayer;
00042 SumPSEnergy(PFLayer::Layer layer) : _thelayer(layer) {}
00043 double operator()(double a,
00044 const PFClusterPtr& b) {
00045 return a + (_thelayer == b->layer())*b->energy();
00046 }
00047 };
00048
00049 struct GreaterByE : public ClusBinaryFunction {
00050 bool operator()(const CalibClusterPtr& x,
00051 const CalibClusterPtr& y) {
00052 return x->energy() > y->energy() ;
00053 }
00054 };
00055
00056 struct GreaterByEt : public ClusBinaryFunction {
00057 bool operator()(const CalibClusterPtr& x,
00058 const CalibClusterPtr& y) {
00059 return x->energy()/std::cosh(x->eta()) > y->energy()/std::cosh(y->eta());
00060 }
00061 };
00062
00063 struct IsASeed : public ClusUnaryFunction {
00064 double threshold;
00065 IsASeed(double thresh) : threshold(thresh) {}
00066 bool operator()(const CalibClusterPtr& x) {
00067 return x->energy() > threshold;
00068 }
00069 };
00070
00071 struct IsLinkedByRecHit : public ClusUnaryFunction {
00072 const CalibClusterPtr the_seed;
00073 const double _threshold, _majority;
00074 const double _maxSatelliteDEta, _maxSatelliteDPhi;
00075 double x_rechits_tot, x_rechits_match;
00076 IsLinkedByRecHit(const CalibClusterPtr& s, const double threshold,
00077 const double majority, const double maxDEta,
00078 const double maxDPhi) :
00079 the_seed(s),_threshold(threshold),_majority(majority),
00080 _maxSatelliteDEta(maxDEta), _maxSatelliteDPhi(maxDPhi) {}
00081 bool operator()(const CalibClusterPtr& x) {
00082 if( the_seed->energy_nocalib() < _threshold ) return false;
00083 const double dEta = std::abs(the_seed->eta()-x->eta());
00084 const double dPhi =
00085 std::abs(TVector2::Phi_mpi_pi(the_seed->phi() - x->phi()));
00086 if( _maxSatelliteDEta < dEta || _maxSatelliteDPhi < dPhi) return false;
00087
00088 const auto& seedHitsAndFractions =
00089 the_seed->the_ptr()->hitsAndFractions();
00090 const auto& xHitsAndFractions =
00091 x->the_ptr()->hitsAndFractions();
00092 x_rechits_tot = xHitsAndFractions.size();
00093 x_rechits_match = 0.0;
00094 for( const std::pair<DetId, float>& seedHit : seedHitsAndFractions ) {
00095 for( const std::pair<DetId, float>& xHit : xHitsAndFractions ) {
00096 if( seedHit.first == xHit.first ) {
00097 x_rechits_match += 1.0;
00098 }
00099 }
00100 }
00101 return x_rechits_match/x_rechits_tot > _majority;
00102 }
00103 };
00104
00105 struct IsClustered : public ClusUnaryFunction {
00106 const CalibClusterPtr the_seed;
00107 PFECALSuperClusterAlgo::clustering_type _type;
00108 bool dynamic_dphi;
00109 double etawidthSuperCluster_, phiwidthSuperCluster_;
00110 IsClustered(const CalibClusterPtr s,
00111 PFECALSuperClusterAlgo::clustering_type ct,
00112 const bool dyn_dphi) :
00113 the_seed(s), _type(ct), dynamic_dphi(dyn_dphi) {}
00114 bool operator()(const CalibClusterPtr& x) {
00115 const double dphi =
00116 std::abs(TVector2::Phi_mpi_pi(the_seed->phi() - x->phi()));
00117 const bool isEB = ( PFLayer::ECAL_BARREL == x->the_ptr()->layer() );
00118 const bool passes_dphi =
00119 ( (!dynamic_dphi && dphi < phiwidthSuperCluster_ ) ||
00120 (dynamic_dphi && MK::inDynamicDPhiWindow(isEB,the_seed->phi(),
00121 x->energy_nocalib(),
00122 x->eta(),
00123 x->phi()) ) );
00124
00125 switch( _type ) {
00126 case PFECALSuperClusterAlgo::kBOX:
00127 return ( std::abs(the_seed->eta()-x->eta())<etawidthSuperCluster_ &&
00128 passes_dphi );
00129 break;
00130 case PFECALSuperClusterAlgo::kMustache:
00131 return ( passes_dphi &&
00132 MK::inMustache(the_seed->eta(),
00133 the_seed->phi(),
00134 x->energy_nocalib(),
00135 x->eta(),
00136 x->phi() ));
00137 break;
00138 default:
00139 return false;
00140 }
00141 return false;
00142 }
00143 };
00144
00145 double testPreshowerDistance(const edm::Ptr<reco::PFCluster>& eeclus,
00146 const edm::Ptr<reco::PFCluster>& psclus) {
00147 if( psclus.isNull() || eeclus.isNull() ) return -1.0;
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 const reco::PFCluster::REPPoint& pspos = psclus->positionREP();
00160 const reco::PFCluster::REPPoint& eepos = eeclus->positionREP();
00161
00162 if( eeclus->z()*psclus->z() < 0 ) return -1.0;
00163 const double dphi= std::abs(TVector2::Phi_mpi_pi(eepos.phi() -
00164 pspos.phi()));
00165 if( dphi > 0.6 ) return -1.0;
00166 const double deta= std::abs(eepos.eta() - pspos.eta());
00167 if( deta > 0.3 ) return -1.0;
00168 return LinkByRecHit::testECALAndPSByRecHit(*eeclus,*psclus,false);
00169 }
00170 }
00171
00172 PFECALSuperClusterAlgo::PFECALSuperClusterAlgo() { }
00173
00174 void PFECALSuperClusterAlgo::
00175 setPFClusterCalibration(const std::shared_ptr<PFEnergyCalibration>& calib) {
00176 _pfEnergyCalibration = calib;
00177 }
00178
00179 void PFECALSuperClusterAlgo::
00180 loadAndSortPFClusters(const PFClusterView& clusters,
00181 const PFClusterView& psclusters) {
00182
00183 superClustersEB_.reset(new reco::SuperClusterCollection);
00184 _clustersEB.clear();
00185 superClustersEE_.reset(new reco::SuperClusterCollection);
00186 _clustersEE.clear();
00187 _psclustersforee.clear();
00188
00189 auto clusterPtrs = clusters.ptrVector();
00190
00191 for ( auto& cluster : clusterPtrs ){
00192 LogDebug("PFClustering")
00193 << "Loading PFCluster i="<<cluster.key()
00194 <<" energy="<<cluster->energy()<<std::endl;
00195
00196 double Ecorr = _pfEnergyCalibration->energyEm(*cluster,
00197 0.0,0.0,
00198 applyCrackCorrections_);
00199 CalibratedClusterPtr calib_cluster(new CalibratedPFCluster(cluster,Ecorr));
00200 switch( cluster->layer() ) {
00201 case PFLayer::ECAL_BARREL:
00202 if( calib_cluster->energy() > threshPFClusterBarrel_ ) {
00203 _clustersEB.push_back(calib_cluster);
00204 }
00205 break;
00206 case PFLayer::ECAL_ENDCAP:
00207 if( calib_cluster->energy() > threshPFClusterEndcap_ ) {
00208 _clustersEE.push_back(calib_cluster);
00209 _psclustersforee.emplace(calib_cluster->the_ptr(),
00210 edm::PtrVector<reco::PFCluster>());
00211 }
00212 break;
00213 default:
00214 break;
00215 }
00216 }
00217
00218 edm::PtrVector<reco::PFCluster> clusterPtrsPS = psclusters.ptrVector();
00219 double dist = -1.0, min_dist = -1.0;
00220
00221
00222 for( const auto& psclus : clusterPtrsPS ) {
00223 if( psclus->energy() < threshPFClusterES_ ) continue;
00224 switch( psclus->layer() ) {
00225 case PFLayer::PS1:
00226 case PFLayer::PS2:
00227 break;
00228 default:
00229 continue;
00230 }
00231 edm::Ptr<reco::PFCluster> eematch;
00232 dist = min_dist = -1.0;
00233 for( const auto& eeclus : _clustersEE ) {
00234 dist = testPreshowerDistance(eeclus->the_ptr(),psclus);
00235 if( dist == -1.0 || (min_dist != -1.0 && dist > min_dist) ) continue;
00236 if( dist < min_dist || min_dist == -1.0 ) {
00237 eematch = eeclus->the_ptr();
00238 min_dist = dist;
00239 }
00240 }
00241 if( eematch.isNonnull() ) _psclustersforee[eematch].push_back(psclus);
00242 }
00243
00244
00245
00246 GreaterByEt greater;
00247 std::sort(_clustersEB.begin(), _clustersEB.end(), greater);
00248 std::sort(_clustersEE.begin(), _clustersEE.end(), greater);
00249 }
00250
00251 void PFECALSuperClusterAlgo::run() {
00252
00253 buildAllSuperClusters(_clustersEB, threshPFClusterSeedBarrel_);
00254
00255 buildAllSuperClusters(_clustersEE, threshPFClusterSeedEndcap_);
00256 }
00257
00258 void PFECALSuperClusterAlgo::
00259 buildAllSuperClusters(CalibClusterPtrVector& clusters,
00260 double seedthresh) {
00261 IsASeed seedable(seedthresh);
00262
00263 std::stable_partition(clusters.begin(),clusters.end(),seedable);
00264
00265
00266
00267
00268 while( std::any_of(clusters.cbegin(), clusters.cend(), seedable) ) {
00269 buildSuperCluster(clusters.front(),clusters);
00270 }
00271 }
00272
00273 void PFECALSuperClusterAlgo::
00274 buildSuperCluster(CalibClusterPtr& seed,
00275 CalibClusterPtrVector& clusters) {
00276 IsClustered IsClusteredWithSeed(seed,_clustype,_useDynamicDPhi);
00277 IsLinkedByRecHit MatchesSeedByRecHit(seed,satelliteThreshold_,
00278 fractionForMajority_,0.1,0.2);
00279 bool isEE = false;
00280 SumPSEnergy sumps1(PFLayer::PS1), sumps2(PFLayer::PS2);
00281 switch( seed->the_ptr()->layer() ) {
00282 case PFLayer::ECAL_BARREL:
00283 IsClusteredWithSeed.phiwidthSuperCluster_ = phiwidthSuperClusterBarrel_;
00284 IsClusteredWithSeed.etawidthSuperCluster_ = etawidthSuperClusterBarrel_;
00285 edm::LogInfo("PFClustering") << "Building SC number "
00286 << superClustersEB_->size() + 1
00287 << " in the ECAL barrel!";
00288 break;
00289 case PFLayer::ECAL_ENDCAP:
00290 IsClusteredWithSeed.phiwidthSuperCluster_ = phiwidthSuperClusterEndcap_;
00291 IsClusteredWithSeed.etawidthSuperCluster_ = etawidthSuperClusterEndcap_;
00292 edm::LogInfo("PFClustering") << "Building SC number "
00293 << superClustersEE_->size() + 1
00294 << " in the ECAL endcap!" << std::endl;
00295 isEE = true;
00296 break;
00297 default:
00298 break;
00299 }
00300
00301
00302
00303
00304
00305
00306 auto not_clustered = std::stable_partition(clusters.begin(),clusters.end(),
00307 IsClusteredWithSeed);
00308
00309
00310 if( doSatelliteClusterMerge_ ) {
00311 not_clustered = std::stable_partition(not_clustered,clusters.end(),
00312 MatchesSeedByRecHit);
00313 }
00314
00315 if(verbose_) {
00316 edm::LogInfo("PFClustering") << "Dumping cluster detail";
00317 edm::LogVerbatim("PFClustering")
00318 << "\tPassed seed: e = " << seed->energy_nocalib()
00319 << " eta = " << seed->eta() << " phi = " << seed->phi()
00320 << std::endl;
00321 for( auto clus = clusters.cbegin(); clus != not_clustered; ++clus ) {
00322 edm::LogVerbatim("PFClustering")
00323 << "\t\tClustered cluster: e = " << (*clus)->energy_nocalib()
00324 << " eta = " << (*clus)->eta() << " phi = " << (*clus)->phi()
00325 << std::endl;
00326 }
00327 for( auto clus = not_clustered; clus != clusters.end(); ++clus ) {
00328 edm::LogVerbatim("PFClustering")
00329 << "\tNon-Clustered cluster: e = " << (*clus)->energy_nocalib()
00330 << " eta = " << (*clus)->eta() << " phi = " << (*clus)->phi()
00331 << std::endl;
00332 }
00333 }
00334
00335
00336 CalibratedClusterPtrVector clustered(clusters.begin(),not_clustered);
00337 clusters.erase(clusters.begin(),not_clustered);
00338
00339 std::vector<const reco::PFCluster*> bare_ptrs;
00340
00341 double posX(0), posY(0), posZ(0),
00342 rawSCEnergy(0), corrSCEnergy(0), clusterCorrEE(0),
00343 PS1_clus_sum(0), PS2_clus_sum(0);
00344 for( auto& clus : clustered ) {
00345 bare_ptrs.push_back(clus->the_ptr().get());
00346
00347 const double cluseraw = clus->energy_nocalib();
00348 const math::XYZPoint& cluspos = clus->the_ptr()->position();
00349 posX += cluseraw * cluspos.X();
00350 posY += cluseraw * cluspos.Y();
00351 posZ += cluseraw * cluspos.Z();
00352
00353 if( isEE ) {
00354 const auto& psclusters = _psclustersforee[clus->the_ptr()];
00355 PS1_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
00356 0.0,sumps1);
00357 PS2_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
00358 0.0,sumps2);
00359 clusterCorrEE =
00360 _pfEnergyCalibration->energyEm(*(clus->the_ptr()),
00361 PS1_clus_sum,PS2_clus_sum,
00362 applyCrackCorrections_);
00363 clus->resetCalibratedEnergy(clusterCorrEE);
00364 }
00365
00366 rawSCEnergy += cluseraw;
00367 corrSCEnergy += clus->energy();
00368 }
00369 posX /= rawSCEnergy;
00370 posY /= rawSCEnergy;
00371 posZ /= rawSCEnergy;
00372
00373
00374 reco::SuperCluster new_sc(corrSCEnergy,math::XYZPoint(posX,posY,posZ));
00375 double ps1_energy(0.0), ps2_energy(0.0), ps_energy(0.0);
00376 new_sc.setSeed(clustered.front()->the_ptr());
00377 for( const auto& clus : clustered ) {
00378 new_sc.addCluster(clus->the_ptr());
00379 auto& hits_and_fractions = clus->the_ptr()->hitsAndFractions();
00380 for( auto& hit_and_fraction : hits_and_fractions ) {
00381 new_sc.addHitAndFraction(hit_and_fraction.first,hit_and_fraction.second);
00382 }
00383 const auto& cluspsassociation = _psclustersforee[clus->the_ptr()];
00384
00385
00386 for( const auto& psclus : cluspsassociation ) {
00387 auto found_pscluster = std::find(new_sc.preshowerClustersBegin(),
00388 new_sc.preshowerClustersEnd(),
00389 reco::CaloClusterPtr(psclus));
00390 if( found_pscluster == new_sc.preshowerClustersEnd() ) {
00391 const double psenergy = psclus->energy();
00392 new_sc.addPreshowerCluster(psclus);
00393 ps1_energy += (PFLayer::PS1 == psclus->layer())*psenergy;
00394 ps2_energy += (PFLayer::PS2 == psclus->layer())*psenergy;
00395 ps_energy += psenergy;
00396 } else {
00397 throw cms::Exception("PFECALSuperClusterAlgo::buildSuperCluster")
00398 << "Found a PS cluster matched to more than one EE cluster!"
00399 << std::endl << std::hex << psclus.get() << " == "
00400 << found_pscluster->get() << std::dec << std::endl;
00401 }
00402 }
00403 }
00404 new_sc.setPreshowerEnergy(ps_energy);
00405 new_sc.setPreshowerEnergyPlane1(ps1_energy);
00406 new_sc.setPreshowerEnergyPlane2(ps2_energy);
00407
00408
00409 PFClusterWidthAlgo pfwidth(bare_ptrs);
00410 new_sc.setEtaWidth(pfwidth.pflowEtaWidth());
00411 new_sc.setPhiWidth(pfwidth.pflowPhiWidth());
00412
00413
00414 new_sc.rawEnergy();
00415
00416
00417 switch( seed->the_ptr()->layer() ) {
00418 case PFLayer::ECAL_BARREL:
00419 superClustersEB_->push_back(new_sc);
00420 break;
00421 case PFLayer::ECAL_ENDCAP:
00422 superClustersEE_->push_back(new_sc);
00423 break;
00424 default:
00425 break;
00426 }
00427 }