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