CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
PFECALSuperClusterAlgo.cc
Go to the documentation of this file.
7 #include "Math/GenVector/VectorUtil.h"
8 #include "TFile.h"
9 #include "TH2F.h"
10 #include "TROOT.h"
11 #include "TMath.h"
12 
14 
15 #include <stdexcept>
16 #include <string>
17 #include <sstream>
18 #include <cmath>
19 
20 using namespace std;
21 namespace MK = reco::MustacheKernel;
22 
23 
24 namespace {
25  typedef edm::View<reco::PFCluster> PFClusterView;
26  typedef edm::Ptr<reco::PFCluster> PFClusterPtr;
27  typedef edm::PtrVector<reco::PFCluster> PFClusterPtrVector;
28  typedef PFECALSuperClusterAlgo::CalibratedClusterPtr CalibClusterPtr;
29  typedef PFECALSuperClusterAlgo::CalibratedClusterPtrVector CalibClusterPtrVector;
30 
31  typedef std::binary_function<const CalibClusterPtr&,
32  const CalibClusterPtr&,
33  bool> ClusBinaryFunction;
34 
35  typedef std::unary_function<const CalibClusterPtr&,
36  bool> ClusUnaryFunction;
37 
38  struct SumPSEnergy : public std::binary_function<double,
39  const PFClusterPtr&,
40  double> {
41  PFLayer::Layer _thelayer;
42  SumPSEnergy(PFLayer::Layer layer) : _thelayer(layer) {}
43  double operator()(double a,
44  const PFClusterPtr& b) {
45  return a + (_thelayer == b->layer())*b->energy();
46  }
47  };
48 
49  struct GreaterByE : public ClusBinaryFunction {
50  bool operator()(const CalibClusterPtr& x,
51  const CalibClusterPtr& y) {
52  return x->energy() > y->energy() ;
53  }
54  };
55 
56  struct GreaterByEt : public ClusBinaryFunction {
57  bool operator()(const CalibClusterPtr& x,
58  const CalibClusterPtr& y) {
59  return x->energy()/std::cosh(x->eta()) > y->energy()/std::cosh(y->eta());
60  }
61  };
62 
63  struct IsASeed : public ClusUnaryFunction {
64  double threshold;
65  IsASeed(double thresh) : threshold(thresh) {}
66  bool operator()(const CalibClusterPtr& x) {
67  return x->energy() > threshold;
68  }
69  };
70 
71  struct IsLinkedByRecHit : public ClusUnaryFunction {
72  const CalibClusterPtr the_seed;
73  const double _threshold, _majority;
74  const double _maxSatelliteDEta, _maxSatelliteDPhi;
75  double x_rechits_tot, x_rechits_match;
76  IsLinkedByRecHit(const CalibClusterPtr& s, const double threshold,
77  const double majority, const double maxDEta,
78  const double maxDPhi) :
79  the_seed(s),_threshold(threshold),_majority(majority),
80  _maxSatelliteDEta(maxDEta), _maxSatelliteDPhi(maxDPhi) {}
81  bool operator()(const CalibClusterPtr& x) {
82  if( the_seed->energy_nocalib() < _threshold ) return false;
83  const double dEta = std::abs(the_seed->eta()-x->eta());
84  const double dPhi =
85  std::abs(TVector2::Phi_mpi_pi(the_seed->phi() - x->phi()));
86  if( _maxSatelliteDEta < dEta || _maxSatelliteDPhi < dPhi) return false;
87  // now see if the clusters overlap in rechits
88  const auto& seedHitsAndFractions =
89  the_seed->the_ptr()->hitsAndFractions();
90  const auto& xHitsAndFractions =
91  x->the_ptr()->hitsAndFractions();
92  x_rechits_tot = xHitsAndFractions.size();
93  x_rechits_match = 0.0;
94  for( const std::pair<DetId, float>& seedHit : seedHitsAndFractions ) {
95  for( const std::pair<DetId, float>& xHit : xHitsAndFractions ) {
96  if( seedHit.first == xHit.first ) {
97  x_rechits_match += 1.0;
98  }
99  }
100  }
101  return x_rechits_match/x_rechits_tot > _majority;
102  }
103  };
104 
105  struct IsClustered : public ClusUnaryFunction {
106  const CalibClusterPtr the_seed;
108  bool dynamic_dphi;
109  double etawidthSuperCluster_, phiwidthSuperCluster_;
110  IsClustered(const CalibClusterPtr s,
112  const bool dyn_dphi) :
113  the_seed(s), _type(ct), dynamic_dphi(dyn_dphi) {}
114  bool operator()(const CalibClusterPtr& x) {
115  const double dphi =
116  std::abs(TVector2::Phi_mpi_pi(the_seed->phi() - x->phi()));
117  const bool isEB = ( PFLayer::ECAL_BARREL == x->the_ptr()->layer() );
118  const bool passes_dphi =
119  ( (!dynamic_dphi && dphi < phiwidthSuperCluster_ ) ||
120  (dynamic_dphi && MK::inDynamicDPhiWindow(isEB,the_seed->phi(),
121  x->energy_nocalib(),
122  x->eta(),
123  x->phi()) ) );
124 
125  switch( _type ) {
127  return ( std::abs(the_seed->eta()-x->eta())<etawidthSuperCluster_ &&
128  passes_dphi );
129  break;
131  return ( passes_dphi &&
132  MK::inMustache(the_seed->eta(),
133  the_seed->phi(),
134  x->energy_nocalib(),
135  x->eta(),
136  x->phi() ));
137  break;
138  default:
139  return false;
140  }
141  return false;
142  }
143  };
144 
145  double testPreshowerDistance(const edm::Ptr<reco::PFCluster>& eeclus,
146  const edm::Ptr<reco::PFCluster>& psclus) {
147  if( psclus.isNull() || eeclus.isNull() ) return -1.0;
148  /*
149  // commented out since PFCluster::layer() uses a lot of CPU
150  // and since
151  if( PFLayer::ECAL_ENDCAP != eeclus->layer() ) return -1.0;
152  if( PFLayer::PS1 != psclus->layer() &&
153  PFLayer::PS2 != psclus->layer() ) {
154  throw cms::Exception("testPreshowerDistance")
155  << "The second argument passed to this function was "
156  << "not a preshower cluster!" << std::endl;
157  }
158  */
159  const reco::PFCluster::REPPoint& pspos = psclus->positionREP();
160  const reco::PFCluster::REPPoint& eepos = eeclus->positionREP();
161  // lazy continue based on geometry
162  if( eeclus->z()*psclus->z() < 0 ) return -1.0;
163  const double dphi= std::abs(TVector2::Phi_mpi_pi(eepos.phi() -
164  pspos.phi()));
165  if( dphi > 0.6 ) return -1.0;
166  const double deta= std::abs(eepos.eta() - pspos.eta());
167  if( deta > 0.3 ) return -1.0;
168  return LinkByRecHit::testECALAndPSByRecHit(*eeclus,*psclus,false);
169  }
170 }
171 
173 
175 setPFClusterCalibration(const std::shared_ptr<PFEnergyCalibration>& calib) {
176  _pfEnergyCalibration = calib;
177 }
178 
180 loadAndSortPFClusters(const PFClusterView& clusters,
181  const PFClusterView& psclusters) {
182  // reset the system for running
183  superClustersEB_.reset(new reco::SuperClusterCollection);
184  _clustersEB.clear();
185  superClustersEE_.reset(new reco::SuperClusterCollection);
186  _clustersEE.clear();
187  _psclustersforee.clear();
188 
189  auto clusterPtrs = clusters.ptrVector();
190  //Select PF clusters available for the clustering
191  for ( auto& cluster : clusterPtrs ){
192  LogDebug("PFClustering")
193  << "Loading PFCluster i="<<cluster.key()
194  <<" energy="<<cluster->energy()<<std::endl;
195 
196  double Ecorr = _pfEnergyCalibration->energyEm(*cluster,
197  0.0,0.0,
198  applyCrackCorrections_);
199  CalibratedClusterPtr calib_cluster(new CalibratedPFCluster(cluster,Ecorr));
200  switch( cluster->layer() ) {
202  if( calib_cluster->energy() > threshPFClusterBarrel_ ) {
203  _clustersEB.push_back(calib_cluster);
204  }
205  break;
207  if( calib_cluster->energy() > threshPFClusterEndcap_ ) {
208  _clustersEE.push_back(calib_cluster);
209  _psclustersforee.emplace(calib_cluster->the_ptr(),
211  }
212  break;
213  default:
214  break;
215  }
216  }
217  // make the association map of ECAL clusters to preshower clusters
218  edm::PtrVector<reco::PFCluster> clusterPtrsPS = psclusters.ptrVector();
219  double dist = -1.0, min_dist = -1.0;
220  // match PS clusters to EE clusters, minimum distance to EE is ensured
221  // since the inner loop is over the EE clusters
222  for( const auto& psclus : clusterPtrsPS ) {
223  if( psclus->energy() < threshPFClusterES_ ) continue;
224  switch( psclus->layer() ) { // just in case this isn't the ES...
225  case PFLayer::PS1:
226  case PFLayer::PS2:
227  break;
228  default:
229  continue;
230  }
232  dist = min_dist = -1.0; // reset
233  for( const auto& eeclus : _clustersEE ) {
234  dist = testPreshowerDistance(eeclus->the_ptr(),psclus);
235  if( dist == -1.0 || (min_dist != -1.0 && dist > min_dist) ) continue;
236  if( dist < min_dist || min_dist == -1.0 ) {
237  eematch = eeclus->the_ptr();
238  min_dist = dist;
239  }
240  } // loop on EE clusters
241  if( eematch.isNonnull() ) _psclustersforee[eematch].push_back(psclus);
242  } // loop on PS clusters
243 
244  // sort full cluster collections by their calibrated energy
245  // this will put all the seeds first by construction
246  GreaterByEt greater;
247  std::sort(_clustersEB.begin(), _clustersEB.end(), greater);
248  std::sort(_clustersEE.begin(), _clustersEE.end(), greater);
249 }
250 
252  // clusterize the EB
253  buildAllSuperClusters(_clustersEB, threshPFClusterSeedBarrel_);
254  // clusterize the EE
255  buildAllSuperClusters(_clustersEE, threshPFClusterSeedEndcap_);
256 }
257 
259 buildAllSuperClusters(CalibClusterPtrVector& clusters,
260  double seedthresh) {
261  IsASeed seedable(seedthresh);
262  // make sure only seeds appear at the front of the list of clusters
263  std::stable_partition(clusters.begin(),clusters.end(),seedable);
264  // in each iteration we are working on a list that is already sorted
265  // in the cluster energy and remains so through each iteration
266  // NB: since clusters is sorted in loadClusters any_of has O(1)
267  // timing until you run out of seeds!
268  while( std::any_of(clusters.cbegin(), clusters.cend(), seedable) ) {
269  buildSuperCluster(clusters.front(),clusters);
270  }
271 }
272 
274 buildSuperCluster(CalibClusterPtr& seed,
275  CalibClusterPtrVector& clusters) {
276  IsClustered IsClusteredWithSeed(seed,_clustype,_useDynamicDPhi);
277  IsLinkedByRecHit MatchesSeedByRecHit(seed,satelliteThreshold_,
278  fractionForMajority_,0.1,0.2);
279  bool isEE = false;
280  SumPSEnergy sumps1(PFLayer::PS1), sumps2(PFLayer::PS2);
281  switch( seed->the_ptr()->layer() ) {
283  IsClusteredWithSeed.phiwidthSuperCluster_ = phiwidthSuperClusterBarrel_;
284  IsClusteredWithSeed.etawidthSuperCluster_ = etawidthSuperClusterBarrel_;
285  edm::LogInfo("PFClustering") << "Building SC number "
286  << superClustersEB_->size() + 1
287  << " in the ECAL barrel!";
288  break;
289  case PFLayer::ECAL_ENDCAP:
290  IsClusteredWithSeed.phiwidthSuperCluster_ = phiwidthSuperClusterEndcap_;
291  IsClusteredWithSeed.etawidthSuperCluster_ = etawidthSuperClusterEndcap_;
292  edm::LogInfo("PFClustering") << "Building SC number "
293  << superClustersEE_->size() + 1
294  << " in the ECAL endcap!" << std::endl;
295  isEE = true;
296  break;
297  default:
298  break;
299  }
300 
301  // this function shuffles the list of clusters into a list
302  // where all clustered sub-clusters are at the front
303  // and returns a pointer to the first unclustered cluster.
304  // The relative ordering of clusters is preserved
305  // (i.e. both resulting sub-lists are sorted by energy).
306  auto not_clustered = std::stable_partition(clusters.begin(),clusters.end(),
307  IsClusteredWithSeed);
308  // satellite cluster merging
309  // it was found that large clusters can split!
310  if( doSatelliteClusterMerge_ ) {
311  not_clustered = std::stable_partition(not_clustered,clusters.end(),
312  MatchesSeedByRecHit);
313  }
314 
315  if(verbose_) {
316  edm::LogInfo("PFClustering") << "Dumping cluster detail";
317  edm::LogVerbatim("PFClustering")
318  << "\tPassed seed: e = " << seed->energy_nocalib()
319  << " eta = " << seed->eta() << " phi = " << seed->phi()
320  << std::endl;
321  for( auto clus = clusters.cbegin(); clus != not_clustered; ++clus ) {
322  edm::LogVerbatim("PFClustering")
323  << "\t\tClustered cluster: e = " << (*clus)->energy_nocalib()
324  << " eta = " << (*clus)->eta() << " phi = " << (*clus)->phi()
325  << std::endl;
326  }
327  for( auto clus = not_clustered; clus != clusters.end(); ++clus ) {
328  edm::LogVerbatim("PFClustering")
329  << "\tNon-Clustered cluster: e = " << (*clus)->energy_nocalib()
330  << " eta = " << (*clus)->eta() << " phi = " << (*clus)->phi()
331  << std::endl;
332  }
333  }
334  // move the clustered clusters out of available cluster list
335  // and into a temporary vector for building the SC
336  CalibratedClusterPtrVector clustered(clusters.begin(),not_clustered);
337  clusters.erase(clusters.begin(),not_clustered);
338  // need the vector of raw pointers for a PF width class
339  std::vector<const reco::PFCluster*> bare_ptrs;
340  // calculate necessary parameters and build the SC
341  double posX(0), posY(0), posZ(0),
342  rawSCEnergy(0), corrSCEnergy(0), clusterCorrEE(0),
343  PS1_clus_sum(0), PS2_clus_sum(0);
344  for( auto& clus : clustered ) {
345  bare_ptrs.push_back(clus->the_ptr().get());
346 
347  const double cluseraw = clus->energy_nocalib();
348  const math::XYZPoint& cluspos = clus->the_ptr()->position();
349  posX += cluseraw * cluspos.X();
350  posY += cluseraw * cluspos.Y();
351  posZ += cluseraw * cluspos.Z();
352  // update EE calibrated super cluster energies
353  if( isEE ) {
354  const auto& psclusters = _psclustersforee[clus->the_ptr()];
355  PS1_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
356  0.0,sumps1);
357  PS2_clus_sum = std::accumulate(psclusters.begin(),psclusters.end(),
358  0.0,sumps2);
359  clusterCorrEE =
360  _pfEnergyCalibration->energyEm(*(clus->the_ptr()),
361  PS1_clus_sum,PS2_clus_sum,
362  applyCrackCorrections_);
363  clus->resetCalibratedEnergy(clusterCorrEE);
364  }
365 
366  rawSCEnergy += cluseraw;
367  corrSCEnergy += clus->energy();
368  }
369  posX /= rawSCEnergy;
370  posY /= rawSCEnergy;
371  posZ /= rawSCEnergy;
372 
373  // now build the supercluster
374  reco::SuperCluster new_sc(corrSCEnergy,math::XYZPoint(posX,posY,posZ));
375  double ps1_energy(0.0), ps2_energy(0.0), ps_energy(0.0);
376  new_sc.setSeed(clustered.front()->the_ptr());
377  for( const auto& clus : clustered ) {
378  new_sc.addCluster(clus->the_ptr());
379  auto& hits_and_fractions = clus->the_ptr()->hitsAndFractions();
380  for( auto& hit_and_fraction : hits_and_fractions ) {
381  new_sc.addHitAndFraction(hit_and_fraction.first,hit_and_fraction.second);
382  }
383  const auto& cluspsassociation = _psclustersforee[clus->the_ptr()];
384  // EE rechits should be uniquely matched to sets of pre-shower
385  // clusters at this point, so we throw an exception if otherwise
386  for( const auto& psclus : cluspsassociation ) {
387  auto found_pscluster = std::find(new_sc.preshowerClustersBegin(),
388  new_sc.preshowerClustersEnd(),
389  reco::CaloClusterPtr(psclus));
390  if( found_pscluster == new_sc.preshowerClustersEnd() ) {
391  const double psenergy = psclus->energy();
392  new_sc.addPreshowerCluster(psclus);
393  ps1_energy += (PFLayer::PS1 == psclus->layer())*psenergy;
394  ps2_energy += (PFLayer::PS2 == psclus->layer())*psenergy;
395  ps_energy += psenergy;
396  } else {
397  throw cms::Exception("PFECALSuperClusterAlgo::buildSuperCluster")
398  << "Found a PS cluster matched to more than one EE cluster!"
399  << std::endl << std::hex << psclus.get() << " == "
400  << found_pscluster->get() << std::dec << std::endl;
401  }
402  }
403  }
404  new_sc.setPreshowerEnergy(ps_energy);
405  new_sc.setPreshowerEnergyPlane1(ps1_energy);
406  new_sc.setPreshowerEnergyPlane2(ps2_energy);
407 
408  // calculate linearly weighted cluster widths
409  PFClusterWidthAlgo pfwidth(bare_ptrs);
410  new_sc.setEtaWidth(pfwidth.pflowEtaWidth());
411  new_sc.setPhiWidth(pfwidth.pflowPhiWidth());
412 
413  // cache the value of the raw energy
414  new_sc.rawEnergy();
415 
416  // save the super cluster to the appropriate list
417  switch( seed->the_ptr()->layer() ) {
419  superClustersEB_->push_back(new_sc);
420  break;
421  case PFLayer::ECAL_ENDCAP:
422  superClustersEE_->push_back(new_sc);
423  break;
424  default:
425  break;
426  }
427 }
#define LogDebug(id)
CaloCluster_iterator preshowerClustersBegin() const
fist iterator over PreshowerCluster constituents
Definition: SuperCluster.h:77
void addHitAndFraction(DetId id, float fraction)
Definition: CaloCluster.h:182
bool inDynamicDPhiWindow(const bool isEE, const float seedPhi, const float ClustE, const float ClusEta, const float clusPhi)
Definition: Mustache.cc:74
static double testECALAndPSByRecHit(const reco::PFCluster &clusterECAL, const reco::PFCluster &clusterPS, bool debug=false)
void setPreshowerEnergyPlane2(double preshowerEnergy2)
Definition: SuperCluster.h:63
ROOT::Math::PositionVector3D< ROOT::Math::CylindricalEta3D< Double32_t > > REPPoint
Definition: PFCluster.h:46
double pflowPhiWidth() const
#define abs(x)
Definition: mlp_lapack.h:159
double Phi_mpi_pi(double x)
Definition: JetUtil.h:24
void setSeed(const CaloClusterPtr &r)
list of used xtals by DetId // now inherited by CaloCluster
Definition: SuperCluster.h:89
edm::Ptr< CaloCluster > CaloClusterPtr
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:7
void setPhiWidth(double pw)
Definition: SuperCluster.h:64
double pflowEtaWidth() const
void setEtaWidth(double ew)
Definition: SuperCluster.h:65
std::vector< CalibratedClusterPtr > CalibratedClusterPtrVector
std::shared_ptr< CalibratedPFCluster > CalibratedClusterPtr
bool isNonnull() const
Checks for non-null.
Definition: Ptr.h:152
MVATrainerComputer * calib
Definition: MVATrainer.cc:64
void buildAllSuperClusters(CalibratedClusterPtrVector &, double seedthresh)
T const * get() const
Returns C++ pointer to the item.
Definition: Ptr.h:143
double dPhi(double phi1, double phi2)
Definition: JetUtil.h:30
std::vector< SuperCluster > SuperClusterCollection
collection of SuperCluser objectr
void loadAndSortPFClusters(const edm::View< reco::PFCluster > &ecalclusters, const edm::View< reco::PFCluster > &psclusters)
Layer
layer definition
Definition: PFLayer.h:31
double rawEnergy() const
raw uncorrected energy (sum of energies of component BasicClusters)
Definition: SuperCluster.h:49
XYZPointD XYZPoint
point in space with cartesian internal representation
Definition: Point3D.h:13
void addPreshowerCluster(const CaloClusterPtr &r)
add reference to constituent BasicCluster
Definition: SuperCluster.h:98
double b
Definition: hdecay.h:120
void buildSuperCluster(CalibratedClusterPtr &, CalibratedClusterPtrVector &)
bool GreaterByE(const T &a1, const T &a2)
void addCluster(const CaloClusterPtr &r)
add reference to constituent BasicCluster
Definition: SuperCluster.h:92
bool isNull() const
Checks for null.
Definition: Ptr.h:148
double a
Definition: hdecay.h:121
Definition: DDAxes.h:10
void setPreshowerEnergyPlane1(double preshowerEnergy1)
Definition: SuperCluster.h:62
void setPFClusterCalibration(const std::shared_ptr< PFEnergyCalibration > &)
bool inMustache(const float maxEta, const float maxPhi, const float ClustE, const float ClusEta, const float ClusPhi)
Definition: Mustache.cc:9
CaloCluster_iterator preshowerClustersEnd() const
last iterator over PreshowerCluster constituents
Definition: SuperCluster.h:80
void setPreshowerEnergy(double preshowerEnergy)
Definition: SuperCluster.h:61