CMS 3D CMS Logo

LinkByRecHit.cc
Go to the documentation of this file.
4 #include "TMath.h"
5 
8 namespace {
9  const Vector2D one2D = BVector2D(1.0, 1.0).v;
10  const Vector2D fivepercent2D = BVector2D(0.05, 0.05).v;
11  // rechit with fraction below this value will be ignored in LinkByRecHit
12  const float minPFRecHitFrac = 1E-4;
13 } // namespace
14 
15 // to enable debugs
16 //#define PFLOW_DEBUG
17 
19  const reco::PFCluster& cluster,
20  bool isBrem,
21  bool debug) {
22 #ifdef PFLOW_DEBUG
23  if (debug)
24  std::cout << "entering test link by rechit function" << std::endl;
25 #endif
26 
27  //cluster position
28  auto clustereta = cluster.positionREP().Eta();
29  auto clusterphi = cluster.positionREP().Phi();
30  auto clusterZ = cluster.position().Z();
31 
32  bool barrel = false;
33  bool hcal = false;
34  // double distance = 999999.9;
35  double horesolscale = 1.0;
36 
37  //track extrapolation
38  const reco::PFTrajectoryPoint& atVertex = track.extrapolatedPoint(reco::PFTrajectoryPoint::ClosestApproach);
39  const reco::PFTrajectoryPoint& atECAL = track.extrapolatedPoint(reco::PFTrajectoryPoint::ECALShowerMax);
40 
41  //track at calo's
42  double tracketa = 999999.9;
43  double trackphi = 999999.9;
44  double track_X = 999999.9;
45  double track_Y = 999999.9;
46  double track_Z = 999999.9;
47  double dHEta = 0.;
48  double dHPhi = 0.;
49 
50  // Quantities at vertex
51  double trackPt = isBrem ? 999. : sqrt(atVertex.momentum().Vect().Perp2());
52  // double trackEta = isBrem ? 999. : atVertex.momentum().Vect().Eta();
53 
54  switch (cluster.layer()) {
56  barrel = true;
57  [[fallthrough]];
59 #ifdef PFLOW_DEBUG
60  if (debug)
61  std::cout << "Fetching Ecal Resolution Maps" << std::endl;
62 #endif
63  // did not reach ecal, cannot be associated with a cluster.
64  if (!atECAL.isValid())
65  return -1.;
66 
67  tracketa = atECAL.positionREP().Eta();
68  trackphi = atECAL.positionREP().Phi();
69  track_X = atECAL.position().X();
70  track_Y = atECAL.position().Y();
71  track_Z = atECAL.position().Z();
72 
73  /* distance
74  = std::sqrt( (track_X-clusterX)*(track_X-clusterX)
75  +(track_Y-clusterY)*(track_Y-clusterY)
76  +(track_Z-clusterZ)*(track_Z-clusterZ)
77  );
78 */
79  break;
80 
82  barrel = true;
83  [[fallthrough]];
85 #ifdef PFLOW_DEBUG
86  if (debug)
87  std::cout << "Fetching Hcal Resolution Maps" << std::endl;
88 #endif
89  if (isBrem) {
90  return -1.;
91  } else {
92  hcal = true;
93  const reco::PFTrajectoryPoint& atHCAL = track.extrapolatedPoint(reco::PFTrajectoryPoint::HCALEntrance);
94  const reco::PFTrajectoryPoint& atHCALExit = track.extrapolatedPoint(reco::PFTrajectoryPoint::HCALExit);
95  // did not reach hcal, cannot be associated with a cluster.
96  if (!atHCAL.isValid())
97  return -1.;
98 
99  // The link is computed between 0 and ~1 interaction length in HCAL
100  dHEta = atHCALExit.positionREP().Eta() - atHCAL.positionREP().Eta();
101  dHPhi = atHCALExit.positionREP().Phi() - atHCAL.positionREP().Phi();
102  if (dHPhi > M_PI)
103  dHPhi = dHPhi - 2. * M_PI;
104  else if (dHPhi < -M_PI)
105  dHPhi = dHPhi + 2. * M_PI;
106  tracketa = atHCAL.positionREP().Eta() + 0.1 * dHEta;
107  trackphi = atHCAL.positionREP().Phi() + 0.1 * dHPhi;
108  track_X = atHCAL.position().X();
109  track_Y = atHCAL.position().Y();
110  track_Z = atHCAL.position().Z();
111  /* distance
112  = -std::sqrt( (track_X-clusterX)*(track_X-clusterX)
113  +(track_Y-clusterY)*(track_Y-clusterY)
114  +(track_Z-clusterZ)*(track_Z-clusterZ)
115  );
116 */
117  }
118  break;
119 
121  barrel = true;
122 #ifdef PFLOW_DEBUG
123  if (debug)
124  std::cout << "Fetching HO Resolution Maps" << std::endl;
125 #endif
126  if (isBrem) {
127  return -1.;
128  } else {
129  hcal = true;
130  horesolscale = 1.15;
131  const reco::PFTrajectoryPoint& atHO = track.extrapolatedPoint(reco::PFTrajectoryPoint::HOLayer);
132  // did not reach ho, cannot be associated with a cluster.
133  if (!atHO.isValid())
134  return -1.;
135 
136  //
137  tracketa = atHO.positionREP().Eta();
138  trackphi = atHO.positionREP().Phi();
139  track_X = atHO.position().X();
140  track_Y = atHO.position().Y();
141  track_Z = atHO.position().Z();
142 
143  // Is this check really useful ?
144  if (fabs(track_Z) > 700.25)
145  return -1.;
146 
147 /* distance
148  = std::sqrt( (track_X-clusterX)*(track_X-clusterX)
149  +(track_Y-clusterY)*(track_Y-clusterY)
150  +(track_Z-clusterZ)*(track_Z-clusterZ)
151  );
152 */
153 #ifdef PFLOW_DEBUG
154 /* if( debug ) {
155  std::cout <<"dist "<<distance<<" "<<cluster.energy()<<" "<<cluster.layer()<<" "
156  <<track_X<<" "<<clusterX<<" "
157  <<track_Y<<" "<<clusterY<<" "
158  <<track_Z<<" "<<clusterZ<<std::endl;
159  }
160 */
161 #endif
162  }
163  break;
164 
165  case PFLayer::PS1:
166  [[fallthrough]];
167  case PFLayer::PS2:
168  //Note Alex: Nothing implemented for the
169  //PreShower (No resolution maps yet)
170 #ifdef PFLOW_DEBUG
171  if (debug)
172  std::cout << "No link by rechit possible for pre-shower yet!" << std::endl;
173 #endif
174  return -1.;
175  default:
176  return -1.;
177  }
178 
179  // Check that, if the cluster is in the endcap,
180  // 0) the track indeed points to the endcap at vertex (DISABLED)
181  // 1) the track extrapolation is in the endcap too !
182  // 2) the track is in the same end-cap !
183  // PJ - 10-May-09
184  if (!barrel) {
185  // if ( fabs(trackEta) < 1.0 ) return -1;
186  if (!hcal && fabs(track_Z) < 300.)
187  return -1.;
188  if (track_Z * clusterZ < 0.)
189  return -1.;
190  }
191  // Check that, if the cluster is in the barrel,
192  // 1) the track is in the barrel too !
193  if (barrel) {
194  if (!hcal && fabs(track_Z) > 300.)
195  return -1.;
196  }
197 
198  double dist = LinkByRecHit::computeDist(clustereta, clusterphi, tracketa, trackphi);
199 
200 #ifdef PFLOW_DEBUG
201  if (debug)
202  std::cout << "test link by rechit " << dist << " " << std::endl;
203  if (debug) {
204  std::cout << " clustereta " << clustereta << " clusterphi " << clusterphi << " tracketa " << tracketa
205  << " trackphi " << trackphi << std::endl;
206  }
207 #endif
208 
209  //Testing if Track can be linked by rechit to a cluster.
210  //A cluster can be linked to a track if the extrapolated position
211  //of the track to the ECAL ShowerMax/HCAL entrance falls within
212  //the boundaries of any cell that belongs to this cluster.
213 
214  const std::vector<reco::PFRecHitFraction>& fracs = cluster.recHitFractions();
215 
216  bool linkedbyrechit = false;
217  //loop rechits
218  for (unsigned int rhit = 0; rhit < fracs.size(); ++rhit) {
219  const reco::PFRecHitRef& rh = fracs[rhit].recHitRef();
220  double fraction = fracs[rhit].fraction();
221  if (fraction < minPFRecHitFrac)
222  continue;
223  if (rh.isNull())
224  continue;
225 
226  //getting rechit center position
227  const auto& rechit_cluster = *rh;
228  const auto& posxyz = rechit_cluster.position();
229  const auto& posrep = rechit_cluster.positionREP();
230 
231  //getting rechit corners
232  const auto& cornersxyz = rechit_cluster.getCornersXYZ();
233  const auto& corners = rechit_cluster.getCornersREP();
234 
235  if (barrel || hcal) { // barrel case matching in eta/phi
236  // (and HCAL endcap too!)
237 
238  //rechit size determination
239  // blown up by 50% (HCAL) to 100% (ECAL) to include cracks & gaps
240  // also blown up to account for multiple scattering at low pt.
241  double rhsizeEta = std::abs(corners[3].eta() - corners[1].eta());
242  double rhsizePhi = std::abs(corners[3].phi() - corners[1].phi());
243  if (rhsizePhi > M_PI)
244  rhsizePhi = 2. * M_PI - rhsizePhi;
245  if (hcal) {
246  const double mult = horesolscale * (1.50 + 0.5 / fracs.size());
247  rhsizeEta = rhsizeEta * mult + 0.2 * std::abs(dHEta);
248  rhsizePhi = rhsizePhi * mult + 0.2 * fabs(dHPhi);
249 
250  } else {
251  const double mult = 2.00 + 1.0 / (fracs.size() * std::min(1., 0.5 * trackPt));
252  rhsizeEta *= mult;
253  rhsizePhi *= mult;
254  }
255 
256 #ifdef PFLOW_DEBUG
257  if (debug) {
258  std::cout << rhit << " Hcal RecHit=" << posrep.Eta() << " " << posrep.Phi() << " " << rechit_cluster.energy()
259  << std::endl;
260  for (unsigned jc = 0; jc < 4; ++jc)
261  std::cout << "corners " << jc << " " << corners[jc].eta() << " " << corners[jc].phi() << std::endl;
262 
263  std::cout << "RecHit SizeEta=" << rhsizeEta << " SizePhi=" << rhsizePhi << std::endl;
264  }
265 #endif
266 
267  //distance track-rechit center
268  // const math::XYZPoint& posxyz
269  // = rechit_cluster.position();
270  double deta = fabs(posrep.eta() - tracketa);
271  double dphi = fabs(posrep.phi() - trackphi);
272  if (dphi > M_PI)
273  dphi = 2. * M_PI - dphi;
274 
275 #ifdef PFLOW_DEBUG
276  if (debug) {
277  std::cout << "distance=" << deta << " " << dphi << " ";
278  if (deta < (0.5 * rhsizeEta) && dphi < (0.5 * rhsizePhi))
279  std::cout << " link here !" << std::endl;
280  else
281  std::cout << std::endl;
282  }
283 #endif
284 
285  if (deta < (0.5 * rhsizeEta) && dphi < (0.5 * rhsizePhi)) {
286  linkedbyrechit = true;
287  break;
288  }
289  } else { //ECAL & PS endcap case, matching in X,Y
290 
291 #ifdef PFLOW_DEBUG
292  if (debug) {
293  const auto& posxyz = rechit_cluster.position();
294 
295  std::cout << "RH " << posxyz.x() << " " << posxyz.y() << std::endl;
296 
297  std::cout << "TRACK " << track_X << " " << track_Y << std::endl;
298  }
299 #endif
300 
301  double x[5];
302  double y[5];
303 
304  for (unsigned jc = 0; jc < 4; ++jc) {
305  const auto& cornerposxyz = cornersxyz[jc];
306  const double mult = (1.00 + 0.50 / (fracs.size() * std::min(1., 0.5 * trackPt)));
307  x[3 - jc] = cornerposxyz.x() + (cornerposxyz.x() - posxyz.x()) * mult;
308  y[3 - jc] = cornerposxyz.y() + (cornerposxyz.y() - posxyz.y()) * mult;
309 
310 #ifdef PFLOW_DEBUG
311  if (debug) {
312  std::cout << "corners " << jc << " " << cornerposxyz.x() << " " << cornerposxyz.y() << std::endl;
313  }
314 #endif
315  } //loop corners
316 
317  //need to close the polygon in order to
318  //use the TMath::IsInside fonction from root lib
319  x[4] = x[0];
320  y[4] = y[0];
321 
322  //Check if the extrapolation point of the track falls
323  //within the rechit boundaries
324  bool isinside = TMath::IsInside(track_X, track_Y, 5, x, y);
325 
326  if (isinside) {
327  linkedbyrechit = true;
328  break;
329  }
330  } //
331 
332  } //loop rechits
333 
334  if (linkedbyrechit) {
335 #ifdef PFLOW_DEBUG
336  if (debug)
337  std::cout << "Track and Cluster LINKED BY RECHIT" << std::endl;
338 #endif
339  /*
340  //if ( distance > 40. || distance < -100. )
341  double clusterr = std::sqrt(clusterX*clusterX+clusterY*clusterY);
342  double trackr = std::sqrt(track_X*track_X+track_Y*track_Y);
343  if ( distance > 40. )
344  std::cout << "Distance = " << distance
345  << ", Barrel/Hcal/Brem ? " << barrel << " " << hcal << " " << isBrem << std::endl
346  << " Cluster " << clusterr << " " << clusterZ << " " << clusterphi << " " << clustereta << std::endl
347  << " Track " << trackr << " " << track_Z << " " << trackphi << " " << tracketa << std::endl;
348  if ( !barrel && fabs(trackEta) < 1.0 ) {
349  double clusterr = std::sqrt(clusterX*clusterX+clusterY*clusterY);
350  double trackr = std::sqrt(track_X*track_X+track_Y*track_Y);
351  std::cout << "TrackEta/Pt = " << trackEta << " " << trackPt << ", distance = " << distance << std::endl
352  << ", Barrel/Hcal/Brem ? " << barrel << " " << hcal << " " << isBrem << std::endl
353  << " Cluster " << clusterr << " " << clusterZ << " " << clusterphi << " " << clustereta << std::endl
354  << " Track " << trackr << " " << track_Z << " " << trackphi << " " << tracketa << " " << trackEta << " " << trackPt << std::endl;
355  }
356  */
357  return dist;
358  } else {
359  return -1.;
360  }
361 }
362 
364  const reco::PFCluster& clusterPS,
365  bool debug) {
366  // 0.19 <-> strip_pitch
367  // 6.1 <-> strip_length
368  static const double resPSpitch = 0.19 / sqrt(12.);
369  static const double resPSlength = 6.1 / sqrt(12.);
370 
371  // Check that clusterECAL is in ECAL endcap and that clusterPS is a preshower cluster
372  if (clusterECAL.layer() != PFLayer::ECAL_ENDCAP ||
373  (clusterPS.layer() != PFLayer::PS1 && clusterPS.layer() != PFLayer::PS2))
374  return -1.;
375 
376 #ifdef PFLOW_DEBUG
377  if (debug)
378  std::cout << "entering test link by rechit function for ECAL and PS" << std::endl;
379 #endif
380 
381  //ECAL cluster position
382  double zECAL = clusterECAL.position().Z();
383  double xECAL = clusterECAL.position().X();
384  double yECAL = clusterECAL.position().Y();
385 
386  // PS cluster position, extrapolated to ECAL
387  double zPS = clusterPS.position().Z();
388  double xPS = clusterPS.position().X(); //* zECAL/zPS;
389  double yPS = clusterPS.position().Y(); //* zECAL/zPS;
390  // MDN jan09 : check that zEcal and zPs have the same sign
391  if (zECAL * zPS < 0.)
392  return -1.;
393  double deltaX = 0.;
394  double deltaY = 0.;
395  double sqr12 = std::sqrt(12.);
396  switch (clusterPS.layer()) {
397  case PFLayer::PS1:
398  // vertical strips, measure x with pitch precision
399  deltaX = resPSpitch * sqr12;
400  deltaY = resPSlength * sqr12;
401  break;
402  case PFLayer::PS2:
403  // horizontal strips, measure y with pitch precision
404  deltaY = resPSpitch * sqr12;
405  deltaX = resPSlength * sqr12;
406  break;
407  default:
408  break;
409  }
410 
411  auto deltaXY = BVector2D(deltaX, deltaY).v * 0.5;
412  // Get the rechits
413  auto zCorr = zPS / zECAL;
414  const std::vector<reco::PFRecHitFraction>& fracs = clusterECAL.recHitFractions();
415  bool linkedbyrechit = false;
416  //loop rechits
417  for (unsigned int rhit = 0; rhit < fracs.size(); ++rhit) {
418  const auto& rh = fracs[rhit].recHitRef();
419  double fraction = fracs[rhit].fraction();
420  if (fraction < minPFRecHitFrac)
421  continue;
422  if (rh.isNull())
423  continue;
424 
425  //getting rechit center position
426  const reco::PFRecHit& rechit_cluster = *rh;
427 
428  //getting rechit corners
429  auto const& corners = rechit_cluster.getCornersXYZ();
430 
431  auto posxy = BVector2D(rechit_cluster.position().xy()).v * zCorr;
432 #ifdef PFLOW_DEBUG
433  if (debug) {
434  std::cout << "Ecal rechit " << posxy.x() << " " << posxy.y() << std::endl;
435  std::cout << "PS cluster " << xPS << " " << yPS << std::endl;
436  }
437 #endif
438 
439  double x[5];
440  double y[5];
441  for (unsigned jc = 0; jc < 4; ++jc) {
442  // corner position projected onto the preshower
443  Vector2D cornerpos = BVector2D(corners[jc].basicVector().xy()).v * zCorr;
444  auto dist = (cornerpos - posxy);
445  auto adist =
446  BVector2D(std::abs(dist[0]), std::abs(dist[1])).v; // all this beacuse icc does not support vector extension
447  // Inflate the size by the size of the PS strips, and by 5% to include ECAL cracks.
448  auto xy = cornerpos + (dist * (fivepercent2D + one2D / adist) * deltaXY);
449  /*
450  Vector2D xy(
451  cornerpos.x() + (cornerpos.x()-posxy.x()) * (0.05 +1.0/std::abs((cornerpos.x()-posxy.x()))*deltaXY.x()),
452  cornerpos.y() + (cornerpos.y()-posxy.y()) * (0.05 +1.0/std::abs((cornerpos.y()-posxy.y()))*deltaXY.y())
453  );
454  */
455  x[3 - jc] = xy[0];
456  y[3 - jc] = xy[1];
457 
458 #ifdef PFLOW_DEBUG
459  if (debug) {
460  std::cout << "corners " << jc << " " << cornerpos.x() << " " << x[3 - jc] << " " << cornerpos.y() << " "
461  << y[3 - jc] << std::endl;
462  }
463 #endif
464  } //loop corners
465 
466  //need to close the polygon in order to
467  //use the TMath::IsInside fonction from root lib
468  x[4] = x[0];
469  y[4] = y[0];
470 
471  //Check if the extrapolation point of the track falls
472  //within the rechit boundaries
473  bool isinside = TMath::IsInside(xPS, yPS, 5, x, y);
474 
475  if (isinside) {
476  linkedbyrechit = true;
477  break;
478  }
479 
480  } //loop rechits
481 
482  if (linkedbyrechit) {
483 #ifdef PFLOW_DEBUG
484  if (debug)
485  std::cout << "Cluster PS and Cluster ECAL LINKED BY RECHIT" << std::endl;
486 #endif
487  constexpr double scale = 1. / 1000.;
488  double dist = computeDist(xECAL * scale, yECAL * scale, xPS * scale, yPS * scale, false);
489  return dist;
490  } else {
491  return -1.;
492  }
493 }
494 
496  const reco::PFCluster& clusterHFHAD,
497  bool debug) {
498  const auto& posxyzEM = clusterHFEM.position();
499  const auto& posxyzHAD = clusterHFHAD.position();
500 
501  double sameZ = posxyzEM.Z() * posxyzHAD.Z();
502  if (sameZ < 0)
503  return -1.;
504 
505  double dX = posxyzEM.X() - posxyzHAD.X();
506  double dY = posxyzEM.Y() - posxyzHAD.Y();
507 
508  double dist2 = dX * dX + dY * dY;
509 
510  if (dist2 < 0.1) {
511  // less than one mm
512  double dist = sqrt(dist2);
513  return dist;
514  ;
515  } else
516  return -1.;
517 }
518 
519 double LinkByRecHit::computeDist(double eta1, double phi1, double eta2, double phi2, bool etaPhi) {
520  auto phicor = etaPhi ? normalizedPhi(phi1 - phi2) : phi1 - phi2;
521  auto etadiff = eta1 - eta2;
522 
523  // double chi2 =
524  // (eta1 - eta2)*(eta1 - eta2) / ( reta1*reta1+ reta2*reta2 ) +
525  // phicor*phicor / ( rphi1*rphi1+ rphi2*rphi2 );
526 
527  return std::sqrt(etadiff * etadiff + phicor * phicor);
528 }
const math::XYZPoint & position() const
cluster centroid position
Definition: CaloCluster.h:154
reconstructed track used as an input to particle flow
Definition: PFRecTrack.h:20
const REPPoint & positionREP() const
trajectory position in (rho, eta, phi) base
static double computeDist(double eta1, double phi1, double eta2, double phi2, bool etaPhi=true)
computes a chisquare
Particle flow cluster, see clustering algorithm in PFClusterAlgo.
Definition: PFCluster.h:42
static double testECALAndPSByRecHit(const reco::PFCluster &clusterECAL, const reco::PFCluster &clusterPS, bool debug=false)
const math::XYZTLorentzVector & momentum() const
4-momenta quadrivector
constexpr T normalizedPhi(T phi)
Definition: normalizedPhi.h:8
const std::vector< reco::PFRecHitFraction > & recHitFractions() const
vector of rechit fractions
Definition: PFCluster.h:65
PFLayer::Layer layer() const
cluster layer, see PFLayer.h in this directory
Definition: PFCluster.cc:56
PositionType const & position() const
rechit cell centre x, y, z
Definition: PFRecHit.h:117
const REPPoint & positionREP() const
cluster position: rho, eta, phi
Definition: PFCluster.h:92
CornersVec const & getCornersXYZ() const
rechit corners
Definition: PFRecHit.h:122
bool isValid() const
is this point valid ?
Particle flow rechit (rechit + geometry and topology information). See clustering algorithm in PFClus...
Definition: PFRecHit.h:31
Basic2DVector< double >::MathVector Vector2D
Definition: LinkByRecHit.cc:7
Point of closest approach from beam axis (initial point in the case of PFSimParticle) ...
T sqrt(T t)
Definition: SSEVec.h:19
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Basic2DVector< T > xy() const
bool isNull() const
Checks for null.
Definition: Ref.h:235
#define M_PI
#define debug
Definition: HDRShower.cc:19
const math::XYZPoint & position() const
cartesian position (x, y, z)
static double testHFEMAndHFHADByRecHit(const reco::PFCluster &clusterHFEM, const reco::PFCluster &clusterHFHAD, bool debug=false)
test association between HFEM and HFHAD, by rechit
Basic2DVector< double > BVector2D
Definition: LinkByRecHit.cc:6
A PFTrack holds several trajectory points, which basically contain the position and momentum of a tra...
static double testTrackAndClusterByRecHit(const reco::PFRecTrack &track, const reco::PFCluster &cluster, bool isBrem=false, bool debug=false)
Definition: LinkByRecHit.cc:18