CMS 3D CMS Logo

EcalClusterTools.h
Go to the documentation of this file.
1 #ifndef RecoEcal_EgammaCoreTools_EcalClusterTools_h
2 #define RecoEcal_EgammaCoreTools_EcalClusterTools_h
3 
34 //#include "DataFormats/Math/interface/Point3D.h"
36 //includes for ShowerShape function to work
37 #include <vector>
38 #include <cmath>
39 #include <TMath.h>
40 #include <TMatrixT.h>
41 #include <TMatrixD.h>
42 #include <TVectorT.h>
43 #include <TVectorD.h>
44 
49 
51 
52 
53 #include "CLHEP/Geometry/Transform3D.h"
54 
59 
60 
61 class DetId;
62 class CaloTopology;
63 class CaloGeometry;
64 
66 
67  // major and minor cluster moments wrt principale axes:
68  float sMaj;
69  float sMin;
70  // angle between sMaj and phi:
71  float alpha;
72  Cluster2ndMoments():sMaj(0.),sMin(0.),alpha(0.){}
73 
74 };
75 
76 template<bool noZS>
78  public:
79  // various energies in the matrix nxn surrounding the maximum energy crystal of the input cluster
80  //we use an eta/phi coordinate system rather than phi/eta
81  //note e3x2 does not have a definate eta/phi geometry, it takes the maximum 3x2 block containing the
82  //seed regardless of whether that 3 in eta or phi
83  static float e1x3( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
84 
85 
86  static float e3x1( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
87 
88 
89  static float e1x5( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
90 
91  static float e5x1( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
92 
93  static float e2x2( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
94 
95  static float e3x2( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
96 
97  static float e3x3( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
98 
99  static float e4x4( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology);
100 
101  static float e5x5( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
102  static int n5x5( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
103 
104  // energy in the 2x5 strip right of the max crystal (does not contain max crystal)
105  // 2 crystals wide in eta, 5 wide in phi.
106  static float e2x5Right( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
107  // energy in the 2x5 strip left of the max crystal (does not contain max crystal)
108 
109  static float e2x5Left( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
110  // energy in the 5x2 strip above the max crystal (does not contain max crystal)
111  // 5 crystals wide in eta, 2 wide in phi.
112 
113  static float e2x5Top( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
114  // energy in the 5x2 strip below the max crystal (does not contain max crystal)
115 
116  static float e2x5Bottom( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
117  // energy in a 2x5 strip containing the seed (max) crystal.
118  // 2 crystals wide in eta, 5 wide in phi.
119  // it is the maximum of either (1x5left + 1x5center) or (1x5right + 1x5center)
120  static float e2x5Max( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
121 
122  // energies in the crystal left, right, top, bottom w.r.t. to the most energetic crystal
123  static float eLeft( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
124 
125  static float eRight( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
126 
127  static float eTop( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
128 
129  static float eBottom( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology );
130  // the energy of the most energetic crystal in the cluster
131 
132  static float eMax( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits );
133 
134  // the energy of the second most energetic crystal in the cluster
135  static float e2nd( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits );
136 
137  // get the DetId and the energy of the maximum energy crystal of the input cluster
138  static std::pair<DetId, float> getMaximum( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits);
139 
140  static std::vector<float> energyBasketFractionEta( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits );
141 
142  static std::vector<float> energyBasketFractionPhi( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits);
143 
144  // return a vector v with v[0] = etaLat, v[1] = phiLat, v[2] = lat
145  static std::vector<float> lat( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW = true, float w0 = 4.7 );
146 
147  // return a vector v with v[0] = covEtaEta, v[1] = covEtaPhi, v[2] = covPhiPhi
148 
149  static std::vector<float> covariances(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits, const CaloTopology *topology, const CaloGeometry* geometry, float w0 = 4.7);
150 
151  // return a vector v with v[0] = covIEtaIEta, v[1] = covIEtaIPhi, v[2] = covIPhiIPhi
152  //this function calculates differences in eta/phi in units of crystals not global eta/phi
153  //this is gives better performance in the crack regions of the calorimeter but gives otherwise identical results to covariances function
154  // except that it doesnt need an eta based correction funtion in the endcap
155  //it is multipled by an approprate crystal size to ensure it gives similar values to covariances(...)
156  //
157  //Warning: covIEtaIEta has been studied by egamma, but so far covIPhiIPhi hasnt been studied extensively so there could be a bug in
158  // the covIPhiIEta or covIPhiIPhi calculations. I dont think there is but as it hasnt been heavily used, there might be one
159  static std::vector<float> localCovariances(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits, const CaloTopology *topology, float w0 = 4.7);
160 
161  static std::vector<float> scLocalCovariances(const reco::SuperCluster &cluster, const EcalRecHitCollection* recHits,const CaloTopology *topology, float w0 = 4.7);
162 
163  // cluster second moments with respect to principal axes:
164  static Cluster2ndMoments cluster2ndMoments( const reco::BasicCluster &basicCluster, const EcalRecHitCollection &recHits, double phiCorrectionFactor=0.8, double w0=4.7, bool useLogWeights=true);
165 
166  static Cluster2ndMoments cluster2ndMoments( const reco::SuperCluster &superCluster, const EcalRecHitCollection &recHits, double phiCorrectionFactor=0.8, double w0=4.7, bool useLogWeights=true);
167  static Cluster2ndMoments cluster2ndMoments( const std::vector<std::pair<const EcalRecHit*, float> >& RH_ptrs_fracs, double phiCorrectionFactor=0.8, double w0=4.7, bool useLogWeights=true);
168 
169  static double zernike20( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0 = 6.6, bool logW = true, float w0 = 4.7 );
170  static double zernike42( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0 = 6.6, bool logW = true, float w0 = 4.7 );
171 
172  // get the detId's of a matrix centered in the maximum energy crystal = (0,0)
173  // the size is specified by ixMin, ixMax, iyMin, iyMax in unit of crystals
174  static std::vector<DetId> matrixDetId( const CaloTopology* topology, DetId id, CaloRectangle rectangle );
175  static std::vector<DetId> matrixDetId( const CaloTopology* topology, DetId id, int size )
176  { return matrixDetId(topology, id, CaloRectangle{-size, size, -size, size}); }
177 
178  // get the energy deposited in a matrix centered in the maximum energy crystal = (0,0)
179  // the size is specified by ixMin, ixMax, iyMin, iyMax in unit of crystals
180  static float matrixEnergy( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology, DetId id, CaloRectangle rectangle );
181  static int matrixSize( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology* topology, DetId id, CaloRectangle rectangle );
182 
183  static float getFraction( const std::vector< std::pair<DetId, float> > &v_id, DetId id);
184  // get the DetId and the energy of the maximum energy crystal in a vector of DetId
185  static std::pair<DetId, float> getMaximum( const std::vector< std::pair<DetId, float> > &v_id, const EcalRecHitCollection *recHits);
186 
187  // get the energy of a DetId, return 0 if the DetId is not in the collection
188  static float recHitEnergy(DetId id, const EcalRecHitCollection *recHits);
189 
190  //Shower shape variables return vector <Roundness, Angle> of a photon
191  static std::vector<float> roundnessBarrelSuperClusters( const reco::SuperCluster &superCluster ,const EcalRecHitCollection &recHits, int weightedPositionMethod = 0, float energyThreshold = 0.0);
192  static std::vector<float> roundnessBarrelSuperClustersUserExtended( const reco::SuperCluster &superCluster ,const EcalRecHitCollection &recHits, int ieta_delta=0, int iphi_delta=0, float energyRHThresh=0.00000, int weightedPositionMethod=0);
193  static std::vector<float> roundnessSelectedBarrelRecHits(const std::vector<std::pair<const EcalRecHit*,float> >&rhVector, int weightedPositionMethod = 0);
194 
195  //works out the number of staturated crystals in 5x5
196  static int nrSaturatedCrysIn5x5(const DetId& id,const EcalRecHitCollection* recHits,const CaloTopology *topology);
197  private:
199  {
201  double r;
202  double phi;
203  };
204 
205  static std::vector<EcalClusterEnergyDeposition> getEnergyDepTopology( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW, float w0 );
206 
207  static math::XYZVector meanClusterPosition( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, const CaloGeometry *geometry );
208 
209  //return energy weighted mean distance from the seed crystal in number of crystals
210  //<iEta,iPhi>, iPhi is not defined for endcap and is returned as zero
211  static std::pair<float,float> mean5x5PositionInLocalCrysCoord(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits,const CaloTopology *topology);
212 
213  static std::pair<float,float> mean5x5PositionInXY(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits,const CaloTopology *topology);
214 
215  static double f00(double r) { return 1; }
216  static double f11(double r) { return r; }
217  static double f20(double r) { return 2.0*r*r-1.0; }
218  static double f22(double r) { return r*r; }
219  static double f31(double r) { return 3.0*r*r*r - 2.0*r; }
220  static double f33(double r) { return r*r*r; }
221  static double f40(double r) { return 6.0*r*r*r*r-6.0*r*r+1.0; }
222  static double f42(double r) { return 4.0*r*r*r*r-3.0*r*r; }
223  static double f44(double r) { return r*r*r*r; }
224  static double f51(double r) { return 10.0*pow(r,5)-12.0*pow(r,3)+3.0*r; }
225  static double f53(double r) { return 5.0*pow(r,5) - 4.0*pow(r,3); }
226  static double f55(double r) { return pow(r,5); }
227 
228  static double absZernikeMoment( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 );
229  static double fast_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 );
230  static double calc_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 );
231 
232  static double factorial(int n) {
233  double res = 1.;
234  for (int i = 2; i <= n; ++i) res *= i;
235  return res;
236  }
237 
238  //useful functions for the localCovariances function
239  static float getIEta(const DetId& id);
240  static float getIPhi(const DetId& id);
241  static float getNormedIX(const DetId& id);
242  static float getNormedIY(const DetId& id);
243  static float getDPhiEndcap(const DetId& crysId,float meanX,float meanY);
244  static float getNrCrysDiffInEta(const DetId& crysId,const DetId& orginId);
245  static float getNrCrysDiffInPhi(const DetId& crysId,const DetId& orginId);
246 
247  //useful functions for showerRoundnessBarrel function
248  static int deltaIEta(int seed_ieta, int rh_ieta);
249  static int deltaIPhi(int seed_iphi, int rh_iphi);
250  static std::vector<int> getSeedPosition(const std::vector<std::pair<const EcalRecHit*,float> >&RH_ptrs);
251  static float getSumEnergy(const std::vector<std::pair<const EcalRecHit*,float> >&RH_ptrs_fracs);
252  static float computeWeight(float eRH, float energyTotal, int weightedPositionMethod);
253 
254 
255 };
256 
257 // implementation
258 template<bool noZS>
259 float EcalClusterToolsT<noZS>::getFraction( const std::vector< std::pair<DetId, float> > &v_id, DetId id)
260 {
261  if(noZS) return 1.0;
262  float frac = 0.0;
263  for ( size_t i = 0; i < v_id.size(); ++i ) {
264  if(v_id[i].first.rawId()==id.rawId()){
265  frac= v_id[i].second;
266  break;
267  }
268  }
269  return frac;
270 }
271 
272 template<bool noZS>
273 std::pair<DetId, float> EcalClusterToolsT<noZS>::getMaximum( const std::vector< std::pair<DetId, float> > &v_id, const EcalRecHitCollection *recHits)
274 {
275  float max = 0;
276  DetId id(0);
277  for ( size_t i = 0; i < v_id.size(); ++i ) {
278  float energy = recHitEnergy( v_id[i].first, recHits ) * (noZS ? 1.0 : v_id[i].second);
279  if ( energy > max ) {
280  max = energy;
281  id = v_id[i].first;
282  }
283  }
284  return std::pair<DetId, float>(id, max);
285 }
286 
287 template<bool noZS>
288 std::pair<DetId, float> EcalClusterToolsT<noZS>::getMaximum( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
289 {
290  return getMaximum( cluster.hitsAndFractions(), recHits );
291 }
292 
293 
294 template<bool noZS>
296 {
297  if ( id == DetId(0) ) {
298  return 0;
299  } else {
300  EcalRecHitCollection::const_iterator it = recHits->find( id );
301  if ( it != recHits->end() ) {
302  if( noZS && ( it->checkFlag(EcalRecHit::kTowerRecovered) ||
303  it->checkFlag(EcalRecHit::kWeird) ||
304  (it->detid().subdetId() == EcalBarrel &&
305  it->checkFlag(EcalRecHit::kDiWeird) ))) return 0.0;
306  else return it->energy();
307  } else {
308  //throw cms::Exception("EcalRecHitNotFound") << "The recHit corresponding to the DetId" << id.rawId() << " not found in the EcalRecHitCollection";
309  // the recHit is not in the collection (hopefully zero suppressed)
310  return 0;
311  }
312  }
313  return 0;
314 }
315 
316 
317 // Returns the energy in a rectangle of crystals
318 // specified in eta by ixMin and ixMax
319 // and in phi by iyMin and iyMax
320 //
321 // Reference picture (X=seed crystal)
322 // iy ___________
323 // 2 |_|_|_|_|_|
324 // 1 |_|_|_|_|_|
325 // 0 |_|_|X|_|_|
326 // -1 |_|_|_|_|_|
327 // -2 |_|_|_|_|_|
328 // -2 -1 0 1 2 ix
329 template<bool noZS>
331 {
332  float energy = 0;
333  auto const& vId = cluster.hitsAndFractions();
334 
335  for (auto const& detId : rectangle(id, *topology)) {
336  energy += recHitEnergy( detId, recHits ) * getFraction(vId, detId);
337  }
338 
339  return energy;
340 }
341 
342 template<bool noZS>
344 {
345  int result = 0;
346 
347  for (auto const& detId : rectangle(id, *topology)) {
348  const float energy = recHitEnergy(detId, recHits);
349  const float frac = getFraction(cluster.hitsAndFractions(), detId);
350  if(energy * frac > 0) result++;
351  }
352  return result;
353 }
354 
355 
356 template<bool noZS>
358 {
359  std::vector<DetId> v;
360  for (auto const& detId : rectangle(id, *topology)) {
361  if ( detId != DetId(0) ) v.push_back(detId);
362  }
363  return v;
364 }
365 
366 
367 template<bool noZS>
369 {
370  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
371  std::list<float> energies;
372  float max_E = matrixEnergy( cluster, recHits, topology, id, {-1, 0, -1, 0} );
373  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-1, 0, 0, 1} ) );
374  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, { 0, 1, 0, 1} ) );
375  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, { 0, 1, -1, 0} ) );
376  return max_E;
377 }
378 
379 template<bool noZS>
381 {
382  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
383  float max_E = matrixEnergy( cluster, recHits, topology, id, {-1, 1, -1, 0} );
384  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {0, 1, -1, 1} ) );
385  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-1, 1, 0, 1} ) );
386  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-1, 0, -1, 1} ) );
387  return max_E;
388 }
389 
390 template<bool noZS>
392 {
393  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
394  return matrixEnergy( cluster, recHits, topology, id, {-1, 1, -1, 1} );
395 }
396 
397 template<bool noZS>
399 {
400  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
401  float max_E = matrixEnergy( cluster, recHits, topology, id, {-1, 2, -2, 1} );
402  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-2, 1, -2, 1} ) );
403  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-2, 1, -1, 2} ) );
404  max_E = std::max( max_E, matrixEnergy( cluster, recHits, topology, id, {-1, 2, -1, 2} ) );
405  return max_E;
406 }
407 
408 template<bool noZS>
410 {
411  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
412  return matrixEnergy( cluster, recHits, topology, id, {-2, 2, -2, 2} );
413 }
414 
415 template<bool noZS>
417 {
418  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
419  return matrixSize( cluster, recHits, topology, id, {-2, 2, -2, 2} );
420 }
421 
422 template<bool noZS>
424 {
425  return getMaximum( cluster.hitsAndFractions(), recHits ).second;
426 }
427 
428 template<bool noZS>
430 {
431  std::vector<float> energies;
432  const std::vector< std::pair<DetId, float> >& v_id = cluster.hitsAndFractions();
433  energies.reserve( v_id.size() );
434  if ( v_id.size() < 2 ) return 0;
435  for ( size_t i = 0; i < v_id.size(); ++i ) {
436  energies.push_back( recHitEnergy( v_id[i].first, recHits ) * (noZS ? 1.0 : v_id[i].second) );
437  }
438  std::partial_sort( energies.begin(), energies.begin()+2, energies.end(), std::greater<float>() );
439  return energies[1];
440 }
441 
442 template<bool noZS>
444 {
445  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
446  return matrixEnergy( cluster, recHits, topology, id, {1, 2, -2, 2} );
447 }
448 
449 template<bool noZS>
451 {
452  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
453  return matrixEnergy( cluster, recHits, topology, id, {-2, -1, -2, 2} );
454 }
455 
456 template<bool noZS>
458 {
459  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
460  return matrixEnergy( cluster, recHits, topology, id, {-2, 2, 1, 2} );
461 }
462 
463 template<bool noZS>
465 {
466  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
467  return matrixEnergy( cluster, recHits, topology, id, {-2, 2, -2, -1} );
468 }
469 
470 // Energy in 2x5 strip containing the max crystal.
471 // Adapted from code by Sam Harper
472 template<bool noZS>
474 {
475  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
476 
477  // 1x5 strip left of seed
478  float left = matrixEnergy( cluster, recHits, topology, id, {-1, -1, -2, 2} );
479  // 1x5 strip right of seed
480  float right = matrixEnergy( cluster, recHits, topology, id, {1, 1, -2, 2} );
481  // 1x5 strip containing seed
482  float centre = matrixEnergy( cluster, recHits, topology, id, {0, 0, -2, 2} );
483 
484  // Return the maximum of (left+center) or (right+center) strip
485  return left > right ? left+centre : right+centre;
486 }
487 
488 template<bool noZS>
490 {
491  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
492  return matrixEnergy( cluster, recHits, topology, id, {0, 0, -2, 2} );
493 }
494 
495 template<bool noZS>
497 {
498  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
499  return matrixEnergy( cluster, recHits, topology, id, {-2, 2, 0, 0} );
500 }
501 
502 template<bool noZS>
504 {
505  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
506  return matrixEnergy( cluster, recHits, topology, id, {0, 0, -1, 1} );
507 }
508 
509 template<bool noZS>
511 {
512  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
513  return matrixEnergy( cluster, recHits, topology, id, {-1, 1, 0, 0} );
514 }
515 
516 template<bool noZS>
518 {
519  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
520  return matrixEnergy( cluster, recHits, topology, id, {-1, -1, 0, 0} );
521 }
522 
523 template<bool noZS>
525 {
526  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
527  return matrixEnergy( cluster, recHits, topology, id, {1, 1, 0, 0} );
528 }
529 
530 template<bool noZS>
532 {
533  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
534  return matrixEnergy( cluster, recHits, topology, id, {0, 0, 1, 1} );
535 }
536 
537 template<bool noZS>
539 {
540  DetId id = getMaximum( cluster.hitsAndFractions(), recHits ).first;
541  return matrixEnergy( cluster, recHits, topology, id, {0, 0, -1, -1} );
542 }
543 
544 template<bool noZS>
546 {
547  std::vector<float> basketFraction( 2 * EBDetId::kModulesPerSM );
548  float clusterEnergy = cluster.energy();
549  const std::vector< std::pair<DetId, float> >& v_id = cluster.hitsAndFractions();
550  if ( v_id[0].first.subdetId() != EcalBarrel ) {
551  edm::LogWarning("EcalClusterToolsT<noZS>::energyBasketFractionEta") << "Trying to get basket fraction for endcap basic-clusters. Basket fractions can be obtained ONLY for barrel basic-clusters. Returning empty vector.";
552  return basketFraction;
553  }
554  for ( size_t i = 0; i < v_id.size(); ++i ) {
555  basketFraction[ EBDetId(v_id[i].first).im()-1 + EBDetId(v_id[i].first).positiveZ()*EBDetId::kModulesPerSM ] += recHitEnergy( v_id[i].first, recHits ) * v_id[i].second / clusterEnergy;
556  }
557  std::sort( basketFraction.rbegin(), basketFraction.rend() );
558  return basketFraction;
559 }
560 
561 template<bool noZS>
563 {
564  std::vector<float> basketFraction( 2 * (EBDetId::MAX_IPHI / EBDetId::kCrystalsInPhi) );
565  float clusterEnergy = cluster.energy();
566  const std::vector< std::pair<DetId, float> >& v_id = cluster.hitsAndFractions();
567  if ( v_id[0].first.subdetId() != EcalBarrel ) {
568  edm::LogWarning("EcalClusterToolsT<noZS>::energyBasketFractionPhi") << "Trying to get basket fraction for endcap basic-clusters. Basket fractions can be obtained ONLY for barrel basic-clusters. Returning empty vector.";
569  return basketFraction;
570  }
571  for ( size_t i = 0; i < v_id.size(); ++i ) {
572  basketFraction[ (EBDetId(v_id[i].first).iphi()-1)/EBDetId::kCrystalsInPhi + EBDetId(v_id[i].first).positiveZ()*EBDetId::kTowersInPhi] += recHitEnergy( v_id[i].first, recHits ) * (noZS ? 1.0 : v_id[i].second) / clusterEnergy;
573  }
574  std::sort( basketFraction.rbegin(), basketFraction.rend() );
575  return basketFraction;
576 }
577 
578 template<bool noZS>
579 std::vector<typename EcalClusterToolsT<noZS>::EcalClusterEnergyDeposition> EcalClusterToolsT<noZS>::getEnergyDepTopology( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW, float w0 )
580 {
581  std::vector<typename EcalClusterToolsT<noZS>::EcalClusterEnergyDeposition> energyDistribution;
582  // init a map of the energy deposition centered on the
583  // cluster centroid. This is for momenta calculation only.
584  CLHEP::Hep3Vector clVect(cluster.position().x(), cluster.position().y(), cluster.position().z());
585  CLHEP::Hep3Vector clDir(clVect);
586  clDir*=1.0/clDir.mag();
587  // in the transverse plane, axis perpendicular to clusterDir
588  CLHEP::Hep3Vector theta_axis(clDir.y(),-clDir.x(),0.0);
589  theta_axis *= 1.0/theta_axis.mag();
590  CLHEP::Hep3Vector phi_axis = theta_axis.cross(clDir);
591 
592  const std::vector< std::pair<DetId, float> >& clusterDetIds = cluster.hitsAndFractions();
593 
595  EcalRecHit testEcalRecHit;
596  std::vector< std::pair<DetId, float> >::const_iterator posCurrent;
597  // loop over crystals
598  for(posCurrent=clusterDetIds.begin(); posCurrent!=clusterDetIds.end(); ++posCurrent) {
599  EcalRecHitCollection::const_iterator itt = recHits->find( (*posCurrent).first );
600  testEcalRecHit=*itt;
601 
602  if(( (*posCurrent).first != DetId(0)) && (recHits->find( (*posCurrent).first ) != recHits->end())) {
603  clEdep.deposited_energy = testEcalRecHit.energy() * (noZS ? 1.0 : (*posCurrent).second);
604  // if logarithmic weight is requested, apply cut on minimum energy of the recHit
605  if(logW) {
606  //double w0 = parameterMap_.find("W0")->second;
607 
608  double weight = std::max(0.0, w0 + log(std::abs(clEdep.deposited_energy)/cluster.energy()) );
609  if(weight==0) {
610  LogDebug("ClusterShapeAlgo") << "Crystal has insufficient energy: E = "
611  << clEdep.deposited_energy << " GeV; skipping... ";
612  continue;
613  }
614  else LogDebug("ClusterShapeAlgo") << "===> got crystal. Energy = " << clEdep.deposited_energy << " GeV. ";
615  }
616  DetId id_ = (*posCurrent).first;
617  const CaloSubdetectorGeometry* geo = geometry->getSubdetectorGeometry(id_);
618  auto this_cell = geo->getGeometry(id_);
619  const GlobalPoint& cellPos = this_cell->getPosition();
620  CLHEP::Hep3Vector gblPos (cellPos.x(),cellPos.y(),cellPos.z()); //surface position?
621  // Evaluate the distance from the cluster centroid
622  CLHEP::Hep3Vector diff = gblPos - clVect;
623  // Important: for the moment calculation, only the "lateral distance" is important
624  // "lateral distance" r_i = distance of the digi position from the axis Origin-Cluster Center
625  // ---> subtract the projection on clDir
626  CLHEP::Hep3Vector DigiVect = diff - diff.dot(clDir)*clDir;
627  clEdep.r = DigiVect.mag();
628  LogDebug("ClusterShapeAlgo") << "E = " << clEdep.deposited_energy
629  << "\tdiff = " << diff.mag()
630  << "\tr = " << clEdep.r;
631  clEdep.phi = DigiVect.angle(theta_axis);
632  if(DigiVect.dot(phi_axis)<0) clEdep.phi = 2 * M_PI - clEdep.phi;
633  energyDistribution.push_back(clEdep);
634  }
635  }
636  return energyDistribution;
637 }
638 
639 template<bool noZS>
640 std::vector<float> EcalClusterToolsT<noZS>::lat( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW, float w0 )
641 {
642  std::vector<EcalClusterToolsT::EcalClusterEnergyDeposition> energyDistribution = getEnergyDepTopology( cluster, recHits, geometry, logW, w0 );
643 
644  std::vector<float> lat;
645  double r, redmoment=0;
646  double phiRedmoment = 0 ;
647  double etaRedmoment = 0 ;
648  int n,n1,n2,tmp;
649  int clusterSize=energyDistribution.size();
650  float etaLat_, phiLat_, lat_;
651  if (clusterSize<3) {
652  etaLat_ = 0.0 ;
653  lat_ = 0.0;
654  lat.push_back(0.);
655  lat.push_back(0.);
656  lat.push_back(0.);
657  return lat;
658  }
659 
660  n1=0; n2=1;
661  if (energyDistribution[1].deposited_energy >
662  energyDistribution[0].deposited_energy)
663  {
664  tmp=n2; n2=n1; n1=tmp;
665  }
666  for (int i=2; i<clusterSize; i++) {
667  n=i;
668  if (energyDistribution[i].deposited_energy >
669  energyDistribution[n1].deposited_energy)
670  {
671  tmp = n2;
672  n2 = n1; n1 = i; n=tmp;
673  } else {
674  if (energyDistribution[i].deposited_energy >
675  energyDistribution[n2].deposited_energy)
676  {
677  tmp=n2; n2=i; n=tmp;
678  }
679  }
680 
681  r = energyDistribution[n].r;
682  redmoment += r*r* energyDistribution[n].deposited_energy;
683  double rphi = r * cos (energyDistribution[n].phi) ;
684  phiRedmoment += rphi * rphi * energyDistribution[n].deposited_energy;
685  double reta = r * sin (energyDistribution[n].phi) ;
686  etaRedmoment += reta * reta * energyDistribution[n].deposited_energy;
687  }
688  double e1 = energyDistribution[n1].deposited_energy;
689  double e2 = energyDistribution[n2].deposited_energy;
690 
691  lat_ = redmoment/(redmoment+2.19*2.19*(e1+e2));
692  phiLat_ = phiRedmoment/(phiRedmoment+2.19*2.19*(e1+e2));
693  etaLat_ = etaRedmoment/(etaRedmoment+2.19*2.19*(e1+e2));
694 
695  lat.push_back(etaLat_);
696  lat.push_back(phiLat_);
697  lat.push_back(lat_);
698  return lat;
699 }
700 
701 template<bool noZS>
703 {
704  // find mean energy position of a 5x5 cluster around the maximum
705  math::XYZVector meanPosition(0.0, 0.0, 0.0);
706  const std::vector<std::pair<DetId,float> >& hsAndFs = cluster.hitsAndFractions();
707  std::vector<DetId> v_id = matrixDetId( topology, getMaximum( cluster, recHits ).first, 2 );
708  for( const std::pair<DetId,float>& hitAndFrac : hsAndFs ) {
709  for( std::vector<DetId>::const_iterator it = v_id.begin(); it != v_id.end(); ++it ) {
710  if( hitAndFrac.first != *it && !noZS) continue;
711  const CaloSubdetectorGeometry* geo = geometry->getSubdetectorGeometry(*it);
712  GlobalPoint positionGP = geo->getGeometry( *it )->getPosition();
713  math::XYZVector position(positionGP.x(),positionGP.y(),positionGP.z());
714  meanPosition = meanPosition + recHitEnergy( *it, recHits ) * position * hitAndFrac.second;
715  }
716  if(noZS) break;
717  }
718  return meanPosition / e5x5( cluster, recHits, topology );
719 }
720 
721 //returns mean energy weighted eta/phi in crystals from the seed
722 //iPhi is not defined for endcap and is returned as zero
723 //return <eta,phi>
724 //we have an issue in working out what to do for negative energies
725 //I (Sam Harper) think it makes sense to ignore crystals with E<0 in the calculation as they are ignored
726 //in the sigmaIEtaIEta calculation (well they arent fully ignored, they do still contribute to the e5x5 sum
727 //in the sigmaIEtaIEta calculation but not here)
728 template<bool noZS>
730 {
731  DetId seedId = getMaximum( cluster, recHits ).first;
732  float meanDEta=0.;
733  float meanDPhi=0.;
734  float energySum=0.;
735 
736  const std::vector<std::pair<DetId,float> >& hsAndFs = cluster.hitsAndFractions();
737  std::vector<DetId> v_id = matrixDetId( topology,seedId, 2 );
738  for( const std::pair<DetId,float>& hAndF : hsAndFs ) {
739  for ( std::vector<DetId>::const_iterator it = v_id.begin(); it != v_id.end(); ++it ) {
740  if( hAndF.first != *it && !noZS ) continue;
741  float energy = recHitEnergy(*it,recHits) * hAndF.second;
742  if(energy<0.) continue;//skipping negative energy crystals
743  meanDEta += energy * getNrCrysDiffInEta(*it,seedId);
744  meanDPhi += energy * getNrCrysDiffInPhi(*it,seedId);
745  energySum +=energy;
746  }
747  if(noZS) break;
748  }
749  meanDEta /=energySum;
750  meanDPhi /=energySum;
751  return std::pair<float,float>(meanDEta,meanDPhi);
752 }
753 
754 //returns mean energy weighted x/y in normalised crystal coordinates
755 //only valid for endcap, returns 0,0 for barrel
756 //we have an issue in working out what to do for negative energies
757 //I (Sam Harper) think it makes sense to ignore crystals with E<0 in the calculation as they are ignored
758 //in the sigmaIEtaIEta calculation (well they arent fully ignored, they do still contribute to the e5x5 sum
759 //in the sigmaIEtaIEta calculation but not here)
760 template<bool noZS>
762 {
763  DetId seedId = getMaximum( cluster, recHits ).first;
764 
765  std::pair<float,float> meanXY(0.,0.);
766  if(seedId.subdetId()==EcalBarrel) return meanXY;
767 
768  float energySum=0.;
769 
770  const std::vector<std::pair<DetId,float> >& hsAndFs = cluster.hitsAndFractions();
771  std::vector<DetId> v_id = matrixDetId( topology,seedId, 2);
772  for( const std::pair<DetId,float>& hAndF : hsAndFs ) {
773  for ( std::vector<DetId>::const_iterator it = v_id.begin(); it != v_id.end(); ++it ) {
774  if( hAndF.first != *it && !noZS) continue;
775  float energy = recHitEnergy(*it,recHits) * hAndF.second;
776  if(energy<0.) continue;//skipping negative energy crystals
777  meanXY.first += energy * getNormedIX(*it);
778  meanXY.second += energy * getNormedIY(*it);
779  energySum +=energy;
780  }
781  if(noZS) break;
782  }
783  meanXY.first/=energySum;
784  meanXY.second/=energySum;
785  return meanXY;
786 }
787 
788 template<bool noZS>
789 std::vector<float> EcalClusterToolsT<noZS>::covariances(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits, const CaloTopology *topology, const CaloGeometry* geometry, float w0)
790 {
791  float e_5x5 = e5x5( cluster, recHits, topology );
792  float covEtaEta, covEtaPhi, covPhiPhi;
793  if (e_5x5 >= 0.) {
794  //double w0_ = parameterMap_.find("W0")->second;
795  const std::vector< std::pair<DetId, float>>& v_id =cluster.hitsAndFractions();
796  math::XYZVector meanPosition = meanClusterPosition( cluster, recHits, topology, geometry );
797 
798  // now we can calculate the covariances
799  double numeratorEtaEta = 0;
800  double numeratorEtaPhi = 0;
801  double numeratorPhiPhi = 0;
802  double denominator = 0;
803 
804  DetId id = getMaximum( v_id, recHits ).first;
805  CaloRectangle rectangle{-2, 2, -2, 2};
806  for (auto const& detId : rectangle(id, *topology)) {
807  float frac=getFraction(v_id,detId);
808  float energy = recHitEnergy( detId, recHits )*frac;
809 
810  if ( energy <= 0 ) continue;
811 
812  const CaloSubdetectorGeometry* geo = geometry->getSubdetectorGeometry(detId);
813  GlobalPoint position = geo->getGeometry(detId)->getPosition();
814 
815  double dPhi = position.phi() - meanPosition.phi();
816  if (dPhi > + Geom::pi()) { dPhi = Geom::twoPi() - dPhi; }
817  if (dPhi < - Geom::pi()) { dPhi = Geom::twoPi() + dPhi; }
818 
819  double dEta = position.eta() - meanPosition.eta();
820  double w = 0.;
821  w = std::max(0.0f, w0 + std::log( energy / e_5x5 ));
822 
823  denominator += w;
824  numeratorEtaEta += w * dEta * dEta;
825  numeratorEtaPhi += w * dEta * dPhi;
826  numeratorPhiPhi += w * dPhi * dPhi;
827  }
828 
829  if (denominator != 0.0) {
830  covEtaEta = numeratorEtaEta / denominator;
831  covEtaPhi = numeratorEtaPhi / denominator;
832  covPhiPhi = numeratorPhiPhi / denominator;
833  } else {
834  covEtaEta = 999.9;
835  covEtaPhi = 999.9;
836  covPhiPhi = 999.9;
837  }
838 
839  } else {
840  // Warn the user if there was no energy in the cells and return zeroes.
841  // std::cout << "\ClusterShapeAlgo::Calculate_Covariances: no energy in supplied cells.\n";
842  covEtaEta = 0;
843  covEtaPhi = 0;
844  covPhiPhi = 0;
845  }
846  std::vector<float> v;
847  v.push_back( covEtaEta );
848  v.push_back( covEtaPhi );
849  v.push_back( covPhiPhi );
850  return v;
851 }
852 
853 //for covIEtaIEta,covIEtaIPhi and covIPhiIPhi are defined but only covIEtaIEta has been actively studied
854 //instead of using absolute eta/phi it counts crystals normalised so that it gives identical results to normal covariances except near the cracks where of course its better
855 //it also does not require any eta correction function in the endcap
856 //it is multipled by an approprate crystal size to ensure it gives similar values to covariances(...)
857 template<bool noZS>
858 std::vector<float> EcalClusterToolsT<noZS>::localCovariances(const reco::BasicCluster &cluster, const EcalRecHitCollection* recHits,const CaloTopology *topology,float w0)
859 {
860 
861  float e_5x5 = e5x5( cluster, recHits, topology );
862  float covEtaEta, covEtaPhi, covPhiPhi;
863 
864  if (e_5x5 >= 0.) {
865  //double w0_ = parameterMap_.find("W0")->second;
866  const std::vector< std::pair<DetId, float> >& v_id = cluster.hitsAndFractions();
867  std::pair<float,float> mean5x5PosInNrCrysFromSeed = mean5x5PositionInLocalCrysCoord( cluster, recHits, topology );
868  std::pair<float,float> mean5x5XYPos = mean5x5PositionInXY(cluster,recHits,topology);
869 
870  // now we can calculate the covariances
871  double numeratorEtaEta = 0;
872  double numeratorEtaPhi = 0;
873  double numeratorPhiPhi = 0;
874  double denominator = 0;
875 
876  //these allow us to scale the localCov by the crystal size
877  //so that the localCovs have the same average value as the normal covs
878  const double barrelCrysSize = 0.01745; //approximate size of crystal in eta,phi in barrel
879  const double endcapCrysSize = 0.0447; //the approximate crystal size sigmaEtaEta was corrected to in the endcap
880 
881  DetId seedId = getMaximum( v_id, recHits ).first;
882 
883  bool isBarrel=seedId.subdetId()==EcalBarrel;
884  const double crysSize = isBarrel ? barrelCrysSize : endcapCrysSize;
885 
886  CaloRectangle rectangle{-2, 2, -2, 2};
887  for (auto const& detId : rectangle(seedId, *topology)) {
888  float frac = getFraction(v_id,detId);
889  float energy = recHitEnergy( detId, recHits )*frac;
890  if ( energy <= 0 ) continue;
891 
892  float dEta = getNrCrysDiffInEta(detId,seedId) - mean5x5PosInNrCrysFromSeed.first;
893  float dPhi = 0;
894 
895  if(isBarrel) dPhi = getNrCrysDiffInPhi(detId,seedId) - mean5x5PosInNrCrysFromSeed.second;
896  else dPhi = getDPhiEndcap(detId,mean5x5XYPos.first,mean5x5XYPos.second);
897 
898 
899  double w = std::max(0.0f,w0 + std::log( energy / e_5x5 ));
900 
901  denominator += w;
902  numeratorEtaEta += w * dEta * dEta;
903  numeratorEtaPhi += w * dEta * dPhi;
904  numeratorPhiPhi += w * dPhi * dPhi;
905  }
906 
907 
908  //multiplying by crysSize to make the values compariable to normal covariances
909  if (denominator != 0.0) {
910  covEtaEta = crysSize*crysSize* numeratorEtaEta / denominator;
911  covEtaPhi = crysSize*crysSize* numeratorEtaPhi / denominator;
912  covPhiPhi = crysSize*crysSize* numeratorPhiPhi / denominator;
913  } else {
914  covEtaEta = 999.9;
915  covEtaPhi = 999.9;
916  covPhiPhi = 999.9;
917  }
918 
919 
920  } else {
921  // Warn the user if there was no energy in the cells and return zeroes.
922  // std::cout << "\ClusterShapeAlgo::Calculate_Covariances: no energy in supplied cells.\n";
923  covEtaEta = 0;
924  covEtaPhi = 0;
925  covPhiPhi = 0;
926  }
927  std::vector<float> v;
928  v.push_back( covEtaEta );
929  v.push_back( covEtaPhi );
930  v.push_back( covPhiPhi );
931  return v;
932 }
933 
934 template<bool noZS>
935 double EcalClusterToolsT<noZS>::zernike20( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0, bool logW, float w0 )
936 {
937  return absZernikeMoment( cluster, recHits, geometry, 2, 0, R0, logW, w0 );
938 }
939 
940 template<bool noZS>
941 double EcalClusterToolsT<noZS>::zernike42( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0, bool logW, float w0 )
942 {
943  return absZernikeMoment( cluster, recHits, geometry, 4, 2, R0, logW, w0 );
944 }
945 
946 template<bool noZS>
947 double EcalClusterToolsT<noZS>::absZernikeMoment( const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 )
948 {
949  // 1. Check if n,m are correctly
950  if ((m>n) || ((n-m)%2 != 0) || (n<0) || (m<0)) return -1;
951 
952  // 2. Check if n,R0 are within validity Range :
953  // n>20 or R0<2.19cm just makes no sense !
954  if ((n>20) || (R0<=2.19)) return -1;
955  if (n<=5) return fast_AbsZernikeMoment(cluster, recHits, geometry, n, m, R0, logW, w0 );
956  else return calc_AbsZernikeMoment(cluster, recHits, geometry, n, m, R0, logW, w0 );
957 }
958 
959 template<bool noZS>
960 double EcalClusterToolsT<noZS>::fast_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 )
961 {
962  double r,ph,e,Re=0,Im=0;
963  double TotalEnergy = cluster.energy();
964  int index = (n/2)*(n/2)+(n/2)+m;
965  std::vector<EcalClusterEnergyDeposition> energyDistribution = getEnergyDepTopology( cluster, recHits, geometry, logW, w0 );
966  int clusterSize = energyDistribution.size();
967  if(clusterSize < 3) return 0.0;
968 
969  for (int i=0; i<clusterSize; i++)
970  {
971  r = energyDistribution[i].r / R0;
972  if (r<1) {
973  std::vector<double> pol;
974  pol.push_back( f00(r) );
975  pol.push_back( f11(r) );
976  pol.push_back( f20(r) );
977  pol.push_back( f22(r) );
978  pol.push_back( f31(r) );
979  pol.push_back( f33(r) );
980  pol.push_back( f40(r) );
981  pol.push_back( f42(r) );
982  pol.push_back( f44(r) );
983  pol.push_back( f51(r) );
984  pol.push_back( f53(r) );
985  pol.push_back( f55(r) );
986  ph = (energyDistribution[i]).phi;
987  e = energyDistribution[i].deposited_energy;
988  Re = Re + e/TotalEnergy * pol[index] * cos( (double) m * ph);
989  Im = Im - e/TotalEnergy * pol[index] * sin( (double) m * ph);
990  }
991  }
992  return sqrt(Re*Re+Im*Im);
993 }
994 
995 template<bool noZS>
996 double EcalClusterToolsT<noZS>::calc_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0 )
997 {
998  double r, ph, e, Re=0, Im=0, f_nm;
999  double TotalEnergy = cluster.energy();
1000  std::vector<EcalClusterEnergyDeposition> energyDistribution = getEnergyDepTopology( cluster, recHits, geometry, logW, w0 );
1001  int clusterSize=energyDistribution.size();
1002  if(clusterSize<3) return 0.0;
1003 
1004  for (int i = 0; i < clusterSize; ++i)
1005  {
1006  r = energyDistribution[i].r / R0;
1007  if (r < 1) {
1008  ph = energyDistribution[i].phi;
1009  e = energyDistribution[i].deposited_energy;
1010  f_nm = 0;
1011  for (int s=0; s<=(n-m)/2; s++) {
1012  if (s%2==0) {
1013  f_nm = f_nm + factorial(n-s)*pow(r,(double) (n-2*s))/(factorial(s)*factorial((n+m)/2-s)*factorial((n-m)/2-s));
1014  } else {
1015  f_nm = f_nm - factorial(n-s)*pow(r,(double) (n-2*s))/(factorial(s)*factorial((n+m)/2-s)*factorial((n-m)/2-s));
1016  }
1017  }
1018  Re = Re + e/TotalEnergy * f_nm * cos( (double) m*ph);
1019  Im = Im - e/TotalEnergy * f_nm * sin( (double) m*ph);
1020  }
1021  }
1022  return sqrt(Re*Re+Im*Im);
1023 }
1024 
1025 //returns the crystal 'eta' from the det id
1026 //it is defined as the number of crystals from the centre in the eta direction
1027 //for the barrel with its eta/phi geometry it is always integer
1028 //for the endcap it is fractional due to the x/y geometry
1029 template<bool noZS>
1031 {
1032  if(id.det()==DetId::Ecal){
1033  if(id.subdetId()==EcalBarrel){
1034  EBDetId ebId(id);
1035  return ebId.ieta();
1036  }else if(id.subdetId()==EcalEndcap){
1037  float iXNorm = getNormedIX(id);
1038  float iYNorm = getNormedIY(id);
1039 
1040  return std::sqrt(iXNorm*iXNorm+iYNorm*iYNorm);
1041  }
1042  }
1043  return 0.;
1044 }
1045 
1046 
1047 //returns the crystal 'phi' from the det id
1048 //it is defined as the number of crystals from the centre in the phi direction
1049 //for the barrel with its eta/phi geometry it is always integer
1050 //for the endcap it is not defined
1051 template<bool noZS>
1053 {
1054  if(id.det()==DetId::Ecal){
1055  if(id.subdetId()==EcalBarrel){
1056  EBDetId ebId(id);
1057  return ebId.iphi();
1058  }
1059  }
1060  return 0.;
1061 }
1062 
1063 //want to map 1=-50,50=-1,51=1 and 100 to 50 so sub off one if zero or neg
1064 template<bool noZS>
1066 {
1067  if(id.det()==DetId::Ecal && id.subdetId()==EcalEndcap){
1068  EEDetId eeId(id);
1069  int iXNorm = eeId.ix()-50;
1070  if(iXNorm<=0) iXNorm--;
1071  return iXNorm;
1072  }
1073  return 0;
1074 }
1075 
1076 //want to map 1=-50,50=-1,51=1 and 100 to 50 so sub off one if zero or neg
1077 template<bool noZS>
1079 {
1080  if(id.det()==DetId::Ecal && id.subdetId()==EcalEndcap){
1081  EEDetId eeId(id);
1082  int iYNorm = eeId.iy()-50;
1083  if(iYNorm<=0) iYNorm--;
1084  return iYNorm;
1085  }
1086  return 0;
1087 }
1088 
1089 //nr crystals crysId is away from orgin id in eta
1090 template<bool noZS>
1091 float EcalClusterToolsT<noZS>::getNrCrysDiffInEta(const DetId& crysId,const DetId& orginId)
1092 {
1093  float crysIEta = getIEta(crysId);
1094  float orginIEta = getIEta(orginId);
1095  bool isBarrel = orginId.subdetId()==EcalBarrel;
1096 
1097  float nrCrysDiff = crysIEta-orginIEta;
1098 
1099  //no iEta=0 in barrel, so if go from positive to negative
1100  //need to reduce abs(detEta) by 1
1101  if(isBarrel){
1102  if(crysIEta*orginIEta<0){ // -1 to 1 transition
1103  if(crysIEta>0) nrCrysDiff--;
1104  else nrCrysDiff++;
1105  }
1106  }
1107  return nrCrysDiff;
1108 }
1109 
1110 //nr crystals crysId is away from orgin id in phi
1111 template<bool noZS>
1112 float EcalClusterToolsT<noZS>::getNrCrysDiffInPhi(const DetId& crysId,const DetId& orginId)
1113 {
1114  float crysIPhi = getIPhi(crysId);
1115  float orginIPhi = getIPhi(orginId);
1116  bool isBarrel = orginId.subdetId()==EcalBarrel;
1117 
1118  float nrCrysDiff = crysIPhi-orginIPhi;
1119 
1120  if(isBarrel){ //if barrel, need to map into 0-180
1121  if (nrCrysDiff > + 180) { nrCrysDiff = nrCrysDiff - 360; }
1122  if (nrCrysDiff < - 180) { nrCrysDiff = nrCrysDiff + 360; }
1123  }
1124  return nrCrysDiff;
1125 }
1126 
1127 //nr crystals crysId is away from mean phi in 5x5 in phi
1128 template<bool noZS>
1129 float EcalClusterToolsT<noZS>::getDPhiEndcap(const DetId& crysId,float meanX,float meanY)
1130 {
1131  float iXNorm = getNormedIX(crysId);
1132  float iYNorm = getNormedIY(crysId);
1133 
1134  float hitLocalR2 = (iXNorm-meanX)*(iXNorm-meanX)+(iYNorm-meanY)*(iYNorm-meanY);
1135  float hitR2 = iXNorm*iXNorm+iYNorm*iYNorm;
1136  float meanR2 = meanX*meanX+meanY*meanY;
1137  float hitR = sqrt(hitR2);
1138  float meanR = sqrt(meanR2);
1139 
1140  float tmp = (hitR2+meanR2-hitLocalR2)/(2*hitR*meanR);
1141  if (tmp<-1) tmp =-1;
1142  if (tmp>1) tmp=1;
1143  float phi = acos(tmp);
1144  float dPhi = hitR*phi;
1145 
1146  return dPhi;
1147 }
1148 
1149 template<bool noZS>
1150 std::vector<float> EcalClusterToolsT<noZS>::scLocalCovariances(const reco::SuperCluster &cluster, const EcalRecHitCollection* recHits,const CaloTopology *topology, float w0)
1151 {
1152  const reco::BasicCluster bcluster = *(cluster.seed());
1153 
1154  float e_5x5 = e5x5(bcluster, recHits, topology);
1155  float covEtaEta, covEtaPhi, covPhiPhi;
1156 
1157  if (e_5x5 >= 0.) {
1158  const std::vector<std::pair<DetId, float> >& v_id = cluster.hitsAndFractions();
1159  std::pair<float,float> mean5x5PosInNrCrysFromSeed = mean5x5PositionInLocalCrysCoord(bcluster, recHits, topology);
1160  std::pair<float,float> mean5x5XYPos = mean5x5PositionInXY(cluster,recHits,topology);
1161  // now we can calculate the covariances
1162  double numeratorEtaEta = 0;
1163  double numeratorEtaPhi = 0;
1164  double numeratorPhiPhi = 0;
1165  double denominator = 0;
1166 
1167  const double barrelCrysSize = 0.01745; //approximate size of crystal in eta,phi in barrel
1168  const double endcapCrysSize = 0.0447; //the approximate crystal size sigmaEtaEta was corrected to in the endcap
1169 
1170  DetId seedId = getMaximum(v_id, recHits).first;
1171  bool isBarrel=seedId.subdetId()==EcalBarrel;
1172 
1173  const double crysSize = isBarrel ? barrelCrysSize : endcapCrysSize;
1174 
1175  for (size_t i = 0; i < v_id.size(); ++i) {
1176  float frac = getFraction(v_id, v_id[i].first);
1177  float energy = recHitEnergy(v_id[i].first, recHits)*frac;
1178 
1179  if (energy <= 0) continue;
1180 
1181  float dEta = getNrCrysDiffInEta(v_id[i].first,seedId) - mean5x5PosInNrCrysFromSeed.first;
1182  float dPhi = 0;
1183  if(isBarrel) dPhi = getNrCrysDiffInPhi(v_id[i].first,seedId) - mean5x5PosInNrCrysFromSeed.second;
1184  else dPhi = getDPhiEndcap(v_id[i].first,mean5x5XYPos.first,mean5x5XYPos.second);
1185 
1186 
1187 
1188  double w = 0.;
1189  w = std::max(0.0f, w0 + std::log( energy / e_5x5 ));
1190 
1191  denominator += w;
1192  numeratorEtaEta += w * dEta * dEta;
1193  numeratorEtaPhi += w * dEta * dPhi;
1194  numeratorPhiPhi += w * dPhi * dPhi;
1195  }
1196 
1197  //multiplying by crysSize to make the values compariable to normal covariances
1198  if (denominator != 0.0) {
1199  covEtaEta = crysSize*crysSize* numeratorEtaEta / denominator;
1200  covEtaPhi = crysSize*crysSize* numeratorEtaPhi / denominator;
1201  covPhiPhi = crysSize*crysSize* numeratorPhiPhi / denominator;
1202  } else {
1203  covEtaEta = 999.9;
1204  covEtaPhi = 999.9;
1205  covPhiPhi = 999.9;
1206  }
1207 
1208  } else {
1209  // Warn the user if there was no energy in the cells and return zeroes.
1210  // std::cout << "\ClusterShapeAlgo::Calculate_Covariances: no energy in supplied cells.\n";
1211  covEtaEta = 0;
1212  covEtaPhi = 0;
1213  covPhiPhi = 0;
1214  }
1215 
1216  std::vector<float> v;
1217  v.push_back( covEtaEta );
1218  v.push_back( covEtaPhi );
1219  v.push_back( covPhiPhi );
1220 
1221  return v;
1222 }
1223 
1224 
1225 // compute cluster second moments with respect to principal axes (eigenvectors of sEtaEta, sPhiPhi, sEtaPhi matrix)
1226 // store also angle alpha between major axis and phi.
1227 // takes into account shower elongation in phi direction due to magnetic field effect:
1228 // default value of 0.8 ensures sMaj = sMin for unconverted photons
1229 // (if phiCorrectionFactor=1 sMaj > sMin and alpha=0 also for unconverted photons)
1230 template<bool noZS>
1231 Cluster2ndMoments EcalClusterToolsT<noZS>::cluster2ndMoments( const reco::BasicCluster &basicCluster, const EcalRecHitCollection &recHits, double phiCorrectionFactor, double w0, bool useLogWeights) {
1232 
1233  if(recHits.empty()) return Cluster2ndMoments();
1234 
1235  std::vector<std::pair<const EcalRecHit*, float> > RH_ptrs_fracs;
1236 
1237  const std::vector< std::pair<DetId, float> >& myHitsPair = basicCluster.hitsAndFractions();
1238 
1239  for(unsigned int i=0; i<myHitsPair.size(); i++){
1240  //get pointer to recHit object
1241  EcalRecHitCollection::const_iterator myRH = recHits.find(myHitsPair[i].first);
1242  if(myRH != recHits.end()){
1243  RH_ptrs_fracs.push_back( std::make_pair(&(*myRH) , myHitsPair[i].second) );
1244  }
1245  }
1246 
1247  return EcalClusterToolsT<noZS>::cluster2ndMoments(RH_ptrs_fracs, phiCorrectionFactor, w0, useLogWeights);
1248 }
1249 
1250 template<bool noZS>
1251 Cluster2ndMoments EcalClusterToolsT<noZS>::cluster2ndMoments( const reco::SuperCluster &superCluster, const EcalRecHitCollection &recHits, double phiCorrectionFactor, double w0, bool useLogWeights) {
1252 
1253  return EcalClusterToolsT<noZS>::cluster2ndMoments( *(superCluster.seed()), recHits, phiCorrectionFactor, w0, useLogWeights);
1254 
1255 }
1256 
1257 template<bool noZS>
1258 Cluster2ndMoments EcalClusterToolsT<noZS>::cluster2ndMoments( const std::vector<std::pair<const EcalRecHit*, float> >& RH_ptrs_fracs, double phiCorrectionFactor, double w0, bool useLogWeights) {
1259 
1260  if(RH_ptrs_fracs.empty()) return Cluster2ndMoments();
1261 
1262  double mid_eta(0),mid_phi(0),mid_x(0),mid_y(0);
1263 
1264  double Etot = EcalClusterToolsT<noZS>::getSumEnergy( RH_ptrs_fracs );
1265 
1266  double max_phi=-10.;
1267  double min_phi=100.;
1268 
1269 
1270  std::vector<double> etaDetId;
1271  std::vector<double> phiDetId;
1272  std::vector<double> xDetId;
1273  std::vector<double> yDetId;
1274  std::vector<double> wiDetId;
1275 
1276  unsigned int nCry=0;
1277  double denominator=0.;
1278  bool isBarrel(true);
1279 
1280  // loop over rechits and compute weights:
1281  for(std::vector<std::pair<const EcalRecHit*, float> >::const_iterator rhf_ptr = RH_ptrs_fracs.begin(); rhf_ptr != RH_ptrs_fracs.end(); rhf_ptr++){
1282  const EcalRecHit* rh_ptr = rhf_ptr->first;
1283 
1284 
1285  //get iEta, iPhi
1286  double temp_eta(0),temp_phi(0),temp_x(0),temp_y(0);
1287  isBarrel = rh_ptr->detid().subdetId()==EcalBarrel;
1288 
1289  if(isBarrel) {
1290  temp_eta = (getIEta(rh_ptr->detid()) > 0. ? getIEta(rh_ptr->detid()) + 84.5 : getIEta(rh_ptr->detid()) + 85.5);
1291  temp_phi= getIPhi(rh_ptr->detid()) - 0.5;
1292  }
1293  else {
1294  temp_eta = getIEta(rh_ptr->detid());
1295  temp_x = getNormedIX(rh_ptr->detid());
1296  temp_y = getNormedIY(rh_ptr->detid());
1297  }
1298 
1299  double temp_ene=rh_ptr->energy() * (noZS ? 1.0 : rhf_ptr->second);
1300 
1301  double temp_wi=((useLogWeights) ?
1302  std::max(0.0, w0 + std::log( std::abs(temp_ene)/Etot ))
1303  : temp_ene);
1304 
1305 
1306  if(temp_phi>max_phi) max_phi=temp_phi;
1307  if(temp_phi<min_phi) min_phi=temp_phi;
1308  etaDetId.push_back(temp_eta);
1309  phiDetId.push_back(temp_phi);
1310  xDetId.push_back(temp_x);
1311  yDetId.push_back(temp_y);
1312  wiDetId.push_back(temp_wi);
1313  denominator+=temp_wi;
1314  nCry++;
1315  }
1316 
1317  if(isBarrel){
1318  // correct phi wrap-around:
1319  if(max_phi==359.5 && min_phi==0.5){
1320  for(unsigned int i=0; i<nCry; i++){
1321  if(phiDetId[i] - 179. > 0.) phiDetId[i]-=360.;
1322  mid_phi+=phiDetId[i]*wiDetId[i];
1323  mid_eta+=etaDetId[i]*wiDetId[i];
1324  }
1325  } else{
1326  for(unsigned int i=0; i<nCry; i++){
1327  mid_phi+=phiDetId[i]*wiDetId[i];
1328  mid_eta+=etaDetId[i]*wiDetId[i];
1329  }
1330  }
1331  }else{
1332  for(unsigned int i=0; i<nCry; i++){
1333  mid_eta+=etaDetId[i]*wiDetId[i];
1334  mid_x+=xDetId[i]*wiDetId[i];
1335  mid_y+=yDetId[i]*wiDetId[i];
1336  }
1337  }
1338 
1339  mid_eta/=denominator;
1340  mid_phi/=denominator;
1341  mid_x/=denominator;
1342  mid_y/=denominator;
1343 
1344 
1345  // See = sigma eta eta
1346  // Spp = (B field corrected) sigma phi phi
1347  // See = (B field corrected) sigma eta phi
1348  double See=0.;
1349  double Spp=0.;
1350  double Sep=0.;
1351  double deta(0),dphi(0);
1352  // compute (phi-corrected) covariance matrix:
1353  for(unsigned int i=0; i<nCry; i++) {
1354  if(isBarrel) {
1355  deta = etaDetId[i]-mid_eta;
1356  dphi = phiDetId[i]-mid_phi;
1357  } else {
1358  deta = etaDetId[i]-mid_eta;
1359  float hitLocalR2 = (xDetId[i]-mid_x)*(xDetId[i]-mid_x)+(yDetId[i]-mid_y)*(yDetId[i]-mid_y);
1360  float hitR2 = xDetId[i]*xDetId[i]+yDetId[i]*yDetId[i];
1361  float meanR2 = mid_x*mid_x+mid_y*mid_y;
1362  float hitR = sqrt(hitR2);
1363  float meanR = sqrt(meanR2);
1364  float phi = acos((hitR2+meanR2-hitLocalR2)/(2*hitR*meanR));
1365  dphi = hitR*phi;
1366 
1367  }
1368  See += (wiDetId[i]* deta * deta) / denominator;
1369  Spp += phiCorrectionFactor*(wiDetId[i]* dphi * dphi) / denominator;
1370  Sep += sqrt(phiCorrectionFactor)*(wiDetId[i]*deta*dphi) / denominator;
1371  }
1372 
1373  Cluster2ndMoments returnMoments;
1374 
1375  // compute matrix eigenvalues:
1376  returnMoments.sMaj = ((See + Spp) + sqrt((See - Spp)*(See - Spp) + 4.*Sep*Sep)) / 2.;
1377  returnMoments.sMin = ((See + Spp) - sqrt((See - Spp)*(See - Spp) + 4.*Sep*Sep)) / 2.;
1378 
1379  returnMoments.alpha = atan( (See - Spp + sqrt( (Spp - See)*(Spp - See) + 4.*Sep*Sep )) / (2.*Sep));
1380 
1381  return returnMoments;
1382 
1383 }
1384 
1385 //compute shower shapes: roundness and angle in a vector. Roundness is 0th element, Angle is 1st element.
1386 //description: uses classical mechanics inertia tensor.
1387 // roundness is smaller_eValue/larger_eValue
1388 // angle is the angle from the iEta axis to the smallest eVector (a.k.a. the shower's elongated axis)
1389 // this function uses only recHits belonging to a SC above energyThreshold (default 0)
1390 // you can select linear weighting = energy_recHit/total_energy (weightedPositionMethod=0) default
1391 // or log weighting = max( 0.0, 4.2 + log(energy_recHit/total_energy) ) (weightedPositionMethod=1)
1392 template<bool noZS>
1393 std::vector<float> EcalClusterToolsT<noZS>::roundnessBarrelSuperClusters( const reco::SuperCluster &superCluster ,const EcalRecHitCollection &recHits, int weightedPositionMethod, float energyThreshold){//int positionWeightingMethod=0){
1394  std::vector<std::pair<const EcalRecHit*, float> > RH_ptrs_fracs;
1395  const std::vector< std::pair<DetId, float> >& myHitsPair = superCluster.hitsAndFractions();
1396  for(unsigned int i=0; i< myHitsPair.size(); ++i){
1397  //get pointer to recHit object
1398  EcalRecHitCollection::const_iterator myRH = recHits.find(myHitsPair[i].first);
1399  if( myRH != recHits.end() && myRH->energy()*(noZS ? 1.0 : myHitsPair[i].second) > energyThreshold){
1400  //require rec hit to have positive energy
1401  RH_ptrs_fracs.push_back( std::make_pair(&(*myRH) , myHitsPair[i].second) );
1402  }
1403  }
1404  std::vector<float> temp = EcalClusterToolsT<noZS>::roundnessSelectedBarrelRecHits(RH_ptrs_fracs,weightedPositionMethod);
1405  return temp;
1406 }
1407 
1408 // this function uses all recHits within specified window ( with default values ieta_delta=2, iphi_delta=5) around SC's highest recHit.
1409 // recHits must pass an energy threshold "energyRHThresh" (default 0)
1410 // you can select linear weighting = energy_recHit/total_energy (weightedPositionMethod=0)
1411 // or log weighting = max( 0.0, 4.2 + log(energy_recHit/total_energy) ) (weightedPositionMethod=1)
1412 template<bool noZS>
1413 std::vector<float> EcalClusterToolsT<noZS>::roundnessBarrelSuperClustersUserExtended( const reco::SuperCluster &superCluster ,const EcalRecHitCollection &recHits, int ieta_delta, int iphi_delta, float energyRHThresh, int weightedPositionMethod){
1414 
1415  std::vector<std::pair<const EcalRecHit*, float> > RH_ptrs_fracs;
1416  const std::vector< std::pair<DetId, float> >& myHitsPair = superCluster.hitsAndFractions();
1417  for(unsigned int i=0; i<myHitsPair.size(); ++i){
1418  //get pointer to recHit object
1419  EcalRecHitCollection::const_iterator myRH = recHits.find(myHitsPair[i].first);
1420  if(myRH != recHits.end() && myRH->energy()*(noZS ? 1.0 : myHitsPair[i].second) > energyRHThresh)
1421  RH_ptrs_fracs.push_back( std::make_pair(&(*myRH) , myHitsPair[i].second) );
1422  }
1423 
1424 
1425  std::vector<int> seedPosition = EcalClusterToolsT<noZS>::getSeedPosition( RH_ptrs_fracs );
1426 
1427  for(EcalRecHitCollection::const_iterator rh = recHits.begin(); rh != recHits.end(); rh++){
1428  EBDetId EBdetIdi( rh->detid() );
1429  float the_fraction = 0;
1430  //if(rh != recHits.end())
1431  bool inEtaWindow = ( abs( deltaIEta(seedPosition[0],EBdetIdi.ieta()) ) <= ieta_delta );
1432  bool inPhiWindow = ( abs( deltaIPhi(seedPosition[1],EBdetIdi.iphi()) ) <= iphi_delta );
1433  bool passEThresh = ( rh->energy() > energyRHThresh );
1434  bool alreadyCounted = false;
1435 
1436  // figure out if the rechit considered now is already inside the SC
1437  bool is_SCrh_inside_recHits = false;
1438  for(unsigned int i=0; i<myHitsPair.size(); i++){
1439  EcalRecHitCollection::const_iterator SCrh = recHits.find(myHitsPair[i].first);
1440  if(SCrh != recHits.end()){
1441  the_fraction = myHitsPair[i].second;
1442  is_SCrh_inside_recHits = true;
1443  if( rh->detid() == SCrh->detid() ) alreadyCounted = true;
1444  }
1445  }//for loop over SC's recHits
1446 
1447  if( is_SCrh_inside_recHits && !alreadyCounted && passEThresh && inEtaWindow && inPhiWindow){
1448  RH_ptrs_fracs.push_back( std::make_pair(&(*rh),the_fraction) );
1449  }
1450 
1451  }//for loop over rh
1452  return EcalClusterToolsT<noZS>::roundnessSelectedBarrelRecHits(RH_ptrs_fracs,weightedPositionMethod);
1453 }
1454 
1455 // this function computes the roundness and angle variables for vector of pointers to recHits you pass it
1456 // you can select linear weighting = energy_recHit/total_energy (weightedPositionMethod=0)
1457 // or log weighting = max( 0.0, 4.2 + log(energy_recHit/total_energy) ) (weightedPositionMethod=1)
1458 template<bool noZS>
1459 std::vector<float> EcalClusterToolsT<noZS>::roundnessSelectedBarrelRecHits( const std::vector<std::pair<const EcalRecHit*,float> >& RH_ptrs_fracs, int weightedPositionMethod){//int weightedPositionMethod = 0){
1460  //positionWeightingMethod = 0 linear weighting, 1 log energy weighting
1461 
1462  std::vector<float> shapes; // this is the returning vector
1463 
1464  //make sure photon has more than one crystal; else roundness and angle suck
1465  if(RH_ptrs_fracs.size()<2){
1466  shapes.push_back( -3 );
1467  shapes.push_back( -3 );
1468  return shapes;
1469  }
1470 
1471  //Find highest E RH (Seed) and save info, compute sum total energy used
1472  std::vector<int> seedPosition = EcalClusterToolsT<noZS>::getSeedPosition( RH_ptrs_fracs );// *recHits);
1473  int tempInt = seedPosition[0];
1474  if(tempInt <0) tempInt++;
1475  float energyTotal = EcalClusterToolsT<noZS>::getSumEnergy( RH_ptrs_fracs );
1476 
1477  //1st loop over rechits: compute new weighted center position in coordinates centered on seed
1478  float centerIEta = 0.;
1479  float centerIPhi = 0.;
1480  float denominator = 0.;
1481 
1482  for(std::vector<std::pair<const EcalRecHit*,float> >::const_iterator rhf_ptr = RH_ptrs_fracs.begin(); rhf_ptr != RH_ptrs_fracs.end(); rhf_ptr++){
1483  const EcalRecHit* rh_ptr = rhf_ptr->first;
1484  //get iEta, iPhi
1485  EBDetId EBdetIdi( rh_ptr->detid() );
1486  if(fabs(energyTotal) < 0.0001){
1487  // don't /0, bad!
1488  shapes.push_back( -2 );
1489  shapes.push_back( -2 );
1490  return shapes;
1491  }
1492  float rh_energy = rh_ptr->energy() * (noZS ? 1.0 : rhf_ptr->second);
1493  float weight = 0;
1494  if(std::abs(weightedPositionMethod)<0.0001){ //linear
1495  weight = rh_energy/energyTotal;
1496  }else{ //logrithmic
1497  weight = std::max(0.0, 4.2 + log(rh_energy/energyTotal));
1498  }
1499  denominator += weight;
1500  centerIEta += weight*deltaIEta(seedPosition[0],EBdetIdi.ieta());
1501  centerIPhi += weight*deltaIPhi(seedPosition[1],EBdetIdi.iphi());
1502  }
1503  if(fabs(denominator) < 0.0001){
1504  // don't /0, bad!
1505  shapes.push_back( -2 );
1506  shapes.push_back( -2 );
1507  return shapes;
1508  }
1509  centerIEta = centerIEta / denominator;
1510  centerIPhi = centerIPhi / denominator;
1511 
1512 
1513  //2nd loop over rechits: compute inertia tensor
1514  TMatrixDSym inertia(2); //initialize 2d inertia tensor
1515  double inertia00 = 0.;
1516  double inertia01 = 0.;// = inertia10 b/c matrix should be symmetric
1517  double inertia11 = 0.;
1518  int i = 0;
1519  for(std::vector<std::pair<const EcalRecHit*,float> >::const_iterator rhf_ptr = RH_ptrs_fracs.begin(); rhf_ptr != RH_ptrs_fracs.end(); rhf_ptr++){
1520  const EcalRecHit* rh_ptr = rhf_ptr->first;
1521  //get iEta, iPhi
1522  EBDetId EBdetIdi( rh_ptr->detid() );
1523 
1524  if(fabs(energyTotal) < 0.0001){
1525  // don't /0, bad!
1526  shapes.push_back( -2 );
1527  shapes.push_back( -2 );
1528  return shapes;
1529  }
1530  float rh_energy = rh_ptr->energy() * (noZS ? 1.0 : rhf_ptr->second);
1531  float weight = 0;
1532  if(std::abs(weightedPositionMethod) < 0.0001){ //linear
1533  weight = rh_energy/energyTotal;
1534  }else{ //logrithmic
1535  weight = std::max(0.0, 4.2 + log(rh_energy/energyTotal));
1536  }
1537 
1538  float ieta_rh_to_center = deltaIEta(seedPosition[0],EBdetIdi.ieta()) - centerIEta;
1539  float iphi_rh_to_center = deltaIPhi(seedPosition[1],EBdetIdi.iphi()) - centerIPhi;
1540 
1541  inertia00 += weight*iphi_rh_to_center*iphi_rh_to_center;
1542  inertia01 -= weight*iphi_rh_to_center*ieta_rh_to_center;
1543  inertia11 += weight*ieta_rh_to_center*ieta_rh_to_center;
1544  i++;
1545  }
1546 
1547  inertia[0][0] = inertia00;
1548  inertia[0][1] = inertia01; // use same number here
1549  inertia[1][0] = inertia01; // and here to insure symmetry
1550  inertia[1][1] = inertia11;
1551 
1552 
1553  //step 1 find principal axes of inertia
1554  TMatrixD eVectors(2,2);
1555  TVectorD eValues(2);
1556  //std::cout<<"EcalClusterToolsT<noZS>::showerRoundness- about to compute eVectors"<<std::endl;
1557  eVectors=inertia.EigenVectors(eValues); //ordered highest eV to lowest eV (I checked!)
1558  //and eVectors are in columns of matrix! I checked!
1559  //and they are normalized to 1
1560 
1561 
1562 
1563  //step 2 select eta component of smaller eVal's eVector
1564  TVectorD smallerAxis(2);//easiest to spin SC on this axis (smallest eVal)
1565  smallerAxis[0]=eVectors[0][1];//row,col //eta component
1566  smallerAxis[1]=eVectors[1][1]; //phi component
1567 
1568  //step 3 compute interesting quatities
1569  Double_t temp = fabs(smallerAxis[0]);// closer to 1 ->beamhalo, closer to 0 something else
1570  if(fabs(eValues[0]) < 0.0001){
1571  // don't /0, bad!
1572  shapes.push_back( -2 );
1573  shapes.push_back( -2 );
1574  return shapes;
1575  }
1576 
1577  float Roundness = eValues[1]/eValues[0];
1578  float Angle=acos(temp);
1579 
1580  if( -0.00001 < Roundness && Roundness < 0) Roundness = 0.;
1581  if( -0.00001 < Angle && Angle < 0 ) Angle = 0.;
1582 
1583  shapes.push_back( Roundness );
1584  shapes.push_back( Angle );
1585  return shapes;
1586 
1587 }
1588 
1589 
1590 template<bool noZS>
1592 {
1593  int nrSat=0;
1594  CaloRectangle rectangle{-2, 2, -2, 2};
1595  for (auto const& detId : rectangle(id, *topology)) {
1596  auto recHitIt = recHits->find(detId);
1597  if(recHitIt!=recHits->end() && recHitIt->checkFlag(EcalRecHit::kSaturated)) {
1598  nrSat++;
1599  }
1600  }
1601  return nrSat;
1602 }
1603 
1604 
1605 //private functions useful for roundnessBarrelSuperClusters etc.
1606 //compute delta iphi between a seed and a particular recHit
1607 //iphi [1,360]
1608 //safe gaurds are put in to ensure the difference is between [-180,180]
1609 template<bool noZS>
1610 int EcalClusterToolsT<noZS>::deltaIPhi(int seed_iphi, int rh_iphi){
1611  int rel_iphi = rh_iphi - seed_iphi;
1612  // take care of cyclic variable iphi [1,360]
1613  if(rel_iphi > 180) rel_iphi = rel_iphi - 360;
1614  if(rel_iphi < -180) rel_iphi = rel_iphi + 360;
1615  return rel_iphi;
1616 }
1617 
1618 //compute delta ieta between a seed and a particular recHit
1619 //ieta [-85,-1] and [1,85]
1620 //safe gaurds are put in to shift the negative ieta +1 to make an ieta=0 so differences are computed correctly
1621 template<bool noZS>
1622 int EcalClusterToolsT<noZS>::deltaIEta(int seed_ieta, int rh_ieta){
1623  // get rid of the fact that there is no ieta=0
1624  if(seed_ieta < 0) seed_ieta++;
1625  if(rh_ieta < 0) rh_ieta++;
1626  int rel_ieta = rh_ieta - seed_ieta;
1627  return rel_ieta;
1628 }
1629 
1630 //return (ieta,iphi) of highest energy recHit of the recHits passed to this function
1631 template<bool noZS>
1632 std::vector<int> EcalClusterToolsT<noZS>::getSeedPosition(const std::vector<std::pair<const EcalRecHit*, float> >& RH_ptrs_fracs){
1633  std::vector<int> seedPosition;
1634  float eSeedRH = 0;
1635  int iEtaSeedRH = 0;
1636  int iPhiSeedRH = 0;
1637 
1638  for(auto const& rhf : RH_ptrs_fracs) {
1639  const EcalRecHit* rh_ptr = rhf.first;
1640  //get iEta, iPhi
1641  EBDetId EBdetIdi( rh_ptr->detid() );
1642  float rh_energy = rh_ptr->energy() * (noZS ? 1.0 : rhf.second);
1643 
1644  if(eSeedRH < rh_energy){
1645  eSeedRH = rh_energy;
1646  iEtaSeedRH = EBdetIdi.ieta();
1647  iPhiSeedRH = EBdetIdi.iphi();
1648  }
1649 
1650  }// for loop
1651 
1652  seedPosition.push_back(iEtaSeedRH);
1653  seedPosition.push_back(iPhiSeedRH);
1654  return seedPosition;
1655 }
1656 
1657 // return the total energy of the recHits passed to this function
1658 template<bool noZS>
1659 float EcalClusterToolsT<noZS>::getSumEnergy(const std::vector<std::pair<const EcalRecHit*, float> >& RH_ptrs_fracs){
1660  float sumE = 0.;
1661  for( const auto& hAndF : RH_ptrs_fracs ) {
1662  sumE += hAndF.first->energy() * (noZS ? 1.0 : hAndF.second);
1663  }
1664  return sumE;
1665 }
1666 
1667 
1669 
1671 
1672 #endif
#define LogDebug(id)
size
Write out results.
static double zernike20(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0=6.6, bool logW=true, float w0=4.7)
static int nrSaturatedCrysIn5x5(const DetId &id, const EcalRecHitCollection *recHits, const CaloTopology *topology)
const CaloSubdetectorGeometry * getSubdetectorGeometry(const DetId &id) const
access the subdetector geometry for the given subdetector directly
Definition: CaloGeometry.cc:49
int ix() const
Definition: EEDetId.h:77
static float e2x5Bottom(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static float matrixEnergy(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, DetId id, CaloRectangle rectangle)
static math::XYZVector meanClusterPosition(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, const CaloGeometry *geometry)
static std::vector< float > covariances(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, const CaloGeometry *geometry, float w0=4.7)
const double w
Definition: UKUtility.cc:23
EcalClusterToolsT< false > EcalClusterTools
CaloTopology const * topology(0)
static float eMax(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
static std::vector< float > roundnessBarrelSuperClustersUserExtended(const reco::SuperCluster &superCluster, const EcalRecHitCollection &recHits, int ieta_delta=0, int iphi_delta=0, float energyRHThresh=0.00000, int weightedPositionMethod=0)
static int n5x5(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
bool isBarrel(GeomDetEnumerators::SubDetector m)
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
static double f33(double r)
Geom::Phi< T > phi() const
Definition: PV3DBase.h:69
const DetId & detid() const
Definition: EcalRecHit.h:72
std::vector< EcalRecHit >::const_iterator const_iterator
T y() const
Definition: PV3DBase.h:63
static double f11(double r)
Definition: weight.py:1
const std::vector< std::pair< DetId, float > > & hitsAndFractions() const
Definition: CaloCluster.h:197
static const int kTowersInPhi
Definition: EBDetId.h:139
static int deltaIEta(int seed_ieta, int rh_ieta)
static std::vector< int > getSeedPosition(const std::vector< std::pair< const EcalRecHit *, float > > &RH_ptrs)
static std::vector< DetId > matrixDetId(const CaloTopology *topology, DetId id, int size)
static double calc_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0)
static int deltaIPhi(int seed_iphi, int rh_iphi)
Definition: DQMStore.h:29
static std::vector< EcalClusterEnergyDeposition > getEnergyDepTopology(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW, float w0)
Definition: Electron.h:6
static std::vector< float > roundnessBarrelSuperClusters(const reco::SuperCluster &superCluster, const EcalRecHitCollection &recHits, int weightedPositionMethod=0, float energyThreshold=0.0)
static float e2x5Top(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
int iphi() const
get the crystal iphi
Definition: EBDetId.h:51
static double fast_AbsZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0)
U second(std::pair< T, U > const &p)
int im() const
get the number of module inside the SM (1-4)
Definition: EBDetId.h:64
static const int kCrystalsInPhi
Definition: EBDetId.h:142
static float e3x1(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static float getDPhiEndcap(const DetId &crysId, float meanX, float meanY)
static float getIEta(const DetId &id)
static double f55(double r)
static float e2x2(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static std::vector< DetId > matrixDetId(const CaloTopology *topology, DetId id, CaloRectangle rectangle)
static float getIPhi(const DetId &id)
T sqrt(T t)
Definition: SSEVec.h:18
T z() const
Definition: PV3DBase.h:64
static std::pair< DetId, float > getMaximum(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
static float e2nd(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
constexpr int subdetId() const
get the contents of the subdetector field (not cast into any detector&#39;s numbering enum) ...
Definition: DetId.h:41
static const int kModulesPerSM
Definition: EBDetId.h:140
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
static double f40(double r)
static float e2x5Max(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
float energy() const
Definition: EcalRecHit.h:68
double f[11][100]
static float eBottom(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static int matrixSize(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, DetId id, CaloRectangle rectangle)
static float getNrCrysDiffInEta(const DetId &crysId, const DetId &orginId)
static float e2x5Right(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
int iy() const
Definition: EEDetId.h:83
static std::vector< float > scLocalCovariances(const reco::SuperCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, float w0=4.7)
static float getFraction(const std::vector< std::pair< DetId, float > > &v_id, DetId id)
int ieta() const
get the crystal ieta
Definition: EBDetId.h:49
static float e3x2(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static double f31(double r)
static float getNormedIY(const DetId &id)
static double factorial(int n)
static double f44(double r)
static double absZernikeMoment(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, int n, int m, double R0, bool logW, float w0)
static float getSumEnergy(const std::vector< std::pair< const EcalRecHit *, float > > &RH_ptrs_fracs)
static float getNrCrysDiffInPhi(const DetId &crysId, const DetId &orginId)
#define M_PI
const_iterator end() const
static std::pair< float, float > mean5x5PositionInXY(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static Cluster2ndMoments cluster2ndMoments(const reco::BasicCluster &basicCluster, const EcalRecHitCollection &recHits, double phiCorrectionFactor=0.8, double w0=4.7, bool useLogWeights=true)
static double f00(double r)
static std::vector< float > roundnessSelectedBarrelRecHits(const std::vector< std::pair< const EcalRecHit *, float > > &rhVector, int weightedPositionMethod=0)
static float eTop(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
Definition: DetId.h:18
static float e4x4(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static float e5x1(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static double f53(double r)
static std::vector< float > energyBasketFractionEta(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
bool positiveZ() const
Definition: EBDetId.h:76
static const int MAX_IPHI
Definition: EBDetId.h:137
virtual std::shared_ptr< const CaloCellGeometry > getGeometry(const DetId &id) const
Get the cell geometry of a given detector id. Should return false if not found.
XYZVectorD XYZVector
spatial vector with cartesian internal representation
Definition: Vector3D.h:30
static std::vector< float > lat(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, bool logW=true, float w0=4.7)
static float recHitEnergy(DetId id, const EcalRecHitCollection *recHits)
static float e2x5Left(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static std::vector< float > energyBasketFractionPhi(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits)
static double f42(double r)
static double f51(double r)
T eta() const
Definition: PV3DBase.h:76
static double f20(double r)
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
Definition: Angle.h:17
static double f22(double r)
iterator find(key_type k)
static std::pair< float, float > mean5x5PositionInLocalCrysCoord(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static int position[264][3]
Definition: ReadPGInfo.cc:509
int factorial(int n)
factorial function
static float eRight(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static float e3x3(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
const CaloClusterPtr & seed() const
seed BasicCluster
Definition: SuperCluster.h:66
static double zernike42(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloGeometry *geometry, double R0=6.6, bool logW=true, float w0=4.7)
static float e1x3(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
double energySum(const DataFrame &df, int fs, int ls)
constexpr double pi()
Definition: Pi.h:31
static float getNormedIX(const DetId &id)
constexpr double twoPi()
Definition: Pi.h:32
T x() const
Definition: PV3DBase.h:62
static float eLeft(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
static std::vector< float > localCovariances(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology, float w0=4.7)
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
static float e1x5(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)
const_iterator begin() const
static float e5x5(const reco::BasicCluster &cluster, const EcalRecHitCollection *recHits, const CaloTopology *topology)