CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
PFAlgo3.cc
Go to the documentation of this file.
3 
5 
7 
9 
10 namespace {
11  template <typename T1, typename T2>
12  float floatDR(const T1 &t1, const T2 &t2) {
13  return deltaR(t1.floatEta(), t1.floatPhi(), t2.floatEta(), t2.floatPhi());
14  }
15 } // namespace
16 
17 using namespace l1tpf_impl;
18 
20  debug_ = iConfig.getUntrackedParameter<int>("debugPFAlgo3", iConfig.getUntrackedParameter<int>("debug", 0));
21  edm::ParameterSet linkcfg = iConfig.getParameter<edm::ParameterSet>("linking");
22  drMatchMu_ = linkcfg.getParameter<double>("trackMuDR");
23 
24  std::string muMatchMode = linkcfg.getParameter<std::string>("trackMuMatch");
25  if (muMatchMode == "boxBestByPtRatio")
27  else if (muMatchMode == "drBestByPtRatio")
29  else if (muMatchMode == "drBestByPtDiff")
31  else
32  throw cms::Exception("Configuration", "bad value for trackMuMatch configurable");
33 
34  std::string tkCaloLinkMetric = linkcfg.getParameter<std::string>("trackCaloLinkMetric");
35  if (tkCaloLinkMetric == "bestByDR")
37  else if (tkCaloLinkMetric == "bestByDRPt")
39  else if (tkCaloLinkMetric == "bestByDR2Pt2")
41  else
42  throw cms::Exception("Configuration", "bad value for tkCaloLinkMetric configurable");
43 
44  drMatch_ = linkcfg.getParameter<double>("trackCaloDR");
45  ptMatchLow_ = linkcfg.getParameter<double>("trackCaloNSigmaLow");
46  ptMatchHigh_ = linkcfg.getParameter<double>("trackCaloNSigmaHigh");
47  useTrackCaloSigma_ = linkcfg.getParameter<bool>("useTrackCaloSigma");
48  maxInvisiblePt_ = linkcfg.getParameter<double>("maxInvisiblePt");
49 
50  drMatchEm_ = linkcfg.getParameter<double>("trackEmDR");
51  trackEmUseAlsoTrackSigma_ = linkcfg.getParameter<bool>("trackEmUseAlsoTrackSigma");
52  trackEmMayUseCaloMomenta_ = linkcfg.getParameter<bool>("trackEmMayUseCaloMomenta");
53  emCaloUseAlsoCaloSigma_ = linkcfg.getParameter<bool>("emCaloUseAlsoCaloSigma");
54  ptMinFracMatchEm_ = linkcfg.getParameter<double>("caloEmPtMinFrac");
55  drMatchEmHad_ = linkcfg.getParameter<double>("emCaloDR");
56  emHadSubtractionPtSlope_ = linkcfg.getParameter<double>("emCaloSubtractionPtSlope");
57  caloReLinkStep_ = linkcfg.getParameter<bool>("caloReLink");
58  caloReLinkDr_ = linkcfg.getParameter<double>("caloReLinkDR");
59  caloReLinkThreshold_ = linkcfg.getParameter<double>("caloReLinkThreshold");
60  rescaleTracks_ = linkcfg.getParameter<bool>("rescaleTracks");
61  caloTrkWeightedAverage_ = linkcfg.getParameter<bool>("useCaloTrkWeightedAverage");
62  sumTkCaloErr2_ = linkcfg.getParameter<bool>("sumTkCaloErr2");
63  ecalPriority_ = linkcfg.getParameter<bool>("ecalPriority");
64  tightTrackMinStubs_ = linkcfg.getParameter<unsigned>("tightTrackMinStubs");
65  tightTrackMaxChi2_ = linkcfg.getParameter<double>("tightTrackMaxChi2");
66  tightTrackMaxInvisiblePt_ = linkcfg.getParameter<double>("tightTrackMaxInvisiblePt");
67 }
68 
69 void PFAlgo3::runPF(Region &r) const {
70  initRegion(r);
71 
73 
74  if (debug_) {
75  dbgPrintf(
76  "PFAlgo3\nPFAlgo3 region eta [ %+5.2f , %+5.2f ], phi [ %+5.2f , %+5.2f ], fiducial eta [ %+5.2f , %+5.2f ], "
77  "phi [ %+5.2f , %+5.2f ]\n",
78  r.etaMin - r.etaExtra,
79  r.etaMax + r.etaExtra,
82  r.etaMin,
83  r.etaMax,
84  r.phiCenter - r.phiHalfWidth,
85  r.phiCenter + r.phiHalfWidth);
86  dbgPrintf("PFAlgo3 \t N(track) %3lu N(em) %3lu N(calo) %3lu N(mu) %3lu\n",
87  r.track.size(),
88  r.emcalo.size(),
89  r.calo.size(),
90  r.muon.size());
91  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
92  const auto &tk = r.track[itk];
93  dbgPrintf(
94  "PFAlgo3 \t track %3d: pt %7.2f +- %5.2f vtx eta %+5.2f vtx phi %+5.2f calo eta %+5.2f calo phi %+5.2f "
95  "fid %1d calo ptErr %7.2f stubs %2d chi2 %7.1f\n",
96  itk,
97  tk.floatPt(),
98  tk.floatPtErr(),
99  tk.floatVtxEta(),
100  tk.floatVtxPhi(),
101  tk.floatEta(),
102  tk.floatPhi(),
103  int(r.fiducialLocal(tk.floatEta(), tk.floatPhi())),
104  tk.floatCaloPtErr(),
105  int(tk.hwStubs),
106  tk.hwChi2 * 0.1f);
107  }
108  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
109  const auto &em = r.emcalo[iem];
110  dbgPrintf(
111  "PFAlgo3 \t EM %3d: pt %7.2f +- %5.2f vtx eta %+5.2f vtx phi %+5.2f calo eta %+5.2f calo phi %+5.2f "
112  "fid %1d calo ptErr %7.2f\n",
113  iem,
114  em.floatPt(),
115  em.floatPtErr(),
116  em.floatEta(),
117  em.floatPhi(),
118  em.floatEta(),
119  em.floatPhi(),
120  int(r.fiducialLocal(em.floatEta(), em.floatPhi())),
121  em.floatPtErr());
122  }
123  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
124  auto &calo = r.calo[ic];
125  dbgPrintf(
126  "PFAlgo3 \t calo %3d: pt %7.2f +- %5.2f vtx eta %+5.2f vtx phi %+5.2f calo eta %+5.2f calo phi %+5.2f "
127  "fid %1d calo ptErr %7.2f em pt %7.2f \n",
128  ic,
129  calo.floatPt(),
130  calo.floatPtErr(),
131  calo.floatEta(),
132  calo.floatPhi(),
133  calo.floatEta(),
134  calo.floatPhi(),
135  int(r.fiducialLocal(calo.floatEta(), calo.floatPhi())),
136  calo.floatPtErr(),
137  calo.floatEmPt());
138  }
139  for (int im = 0, nm = r.muon.size(); im < nm; ++im) {
140  auto &mu = r.muon[im];
141  dbgPrintf(
142  "PFAlgo3 \t muon %3d: pt %7.2f vtx eta %+5.2f vtx phi %+5.2f calo eta %+5.2f calo phi %+5.2f "
143  "fid %1d \n",
144  im,
145  mu.floatPt(),
146  mu.floatEta(),
147  mu.floatPhi(),
148  mu.floatEta(),
149  mu.floatPhi(),
150  int(r.fiducialLocal(mu.floatEta(), mu.floatPhi())));
151  }
152  }
153 
154  std::vector<int> tk2mu(r.track.size(), -1), mu2tk(r.muon.size(), -1);
155  link_tk2mu(r, tk2mu, mu2tk);
156 
157  // match all tracks to the closest EM cluster
158  std::vector<int> tk2em(r.track.size(), -1);
159  link_tk2em(r, tk2em);
160 
161  // match all em to the closest had (can happen in parallel to the above)
162  std::vector<int> em2calo(r.emcalo.size(), -1);
163  link_em2calo(r, em2calo);
164 
166  // for each EM cluster, count and add up the pt of all the corresponding tracks (skipping muons)
167  std::vector<int> em2ntk(r.emcalo.size(), 0);
168  std::vector<float> em2sumtkpt(r.emcalo.size(), 0);
169  std::vector<float> em2sumtkpterr(r.emcalo.size(), 0);
170  sum_tk2em(r, tk2em, em2ntk, em2sumtkpt, em2sumtkpterr);
171 
173  // process ecal clusters after linking
174  emcalo_algo(r, em2ntk, em2sumtkpt, em2sumtkpterr);
175 
177  // promote all flagged tracks to electrons
178  emtk_algo(r, tk2em, em2ntk, em2sumtkpterr);
179  sub_em2calo(r, em2calo);
180 
182  // track to calo matching (first iteration, with a lower bound on the calo pt; there may be another one later)
183  std::vector<int> tk2calo(r.track.size(), -1);
184  link_tk2calo(r, tk2calo);
185 
187  // for each calo, compute the sum of the track pt
188  std::vector<int> calo2ntk(r.calo.size(), 0);
189  std::vector<float> calo2sumtkpt(r.calo.size(), 0);
190  std::vector<float> calo2sumtkpterr(r.calo.size(), 0);
191  sum_tk2calo(r, tk2calo, calo2ntk, calo2sumtkpt, calo2sumtkpterr);
192 
193  // in the meantime, promote unlinked low pt tracks to hadrons
194  unlinkedtk_algo(r, tk2calo);
195 
198  // off by default, as it seems to not do much in jets even if it helps remove tails in single-pion events
199  if (caloReLinkStep_)
200  calo_relink(r, calo2ntk, calo2sumtkpt, calo2sumtkpterr);
201 
203  // process matched calo clusters, compare energy to sum track pt
204  std::vector<float> calo2alpha(r.calo.size(), 1);
205  linkedcalo_algo(r, calo2ntk, calo2sumtkpt, calo2sumtkpterr, calo2alpha);
206 
209  linkedtk_algo(r, tk2calo, calo2ntk, calo2alpha);
210  // process unmatched calo clusters
212  // finally do muons
213  save_muons(r, tk2mu);
214 }
215 
216 void PFAlgo3::link_tk2mu(Region &r, std::vector<int> &tk2mu, std::vector<int> &mu2tk) const {
217  // do a rectangular match for the moment; make a box of the same are as a 0.2 cone
218  int intDrMuonMatchBox = std::ceil(drMatchMu_ * CaloCluster::ETAPHI_SCALE * std::sqrt(M_PI / 4));
219  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
220  tk2mu[itk] = false;
221  }
222  for (int imu = 0, nmu = r.muon.size(); imu < nmu; ++imu) {
223  const auto &mu = r.muon[imu];
224  if (debug_)
225  dbgPrintf(
226  "PFAlgo3 \t muon %3d (pt %7.2f, eta %+5.2f, phi %+5.2f) \n", imu, mu.floatPt(), mu.floatEta(), mu.floatPhi());
227  float minDistance = 9e9;
228  switch (muMatchMode_) {
230  minDistance = 4.;
231  break;
233  minDistance = 4.;
234  break;
236  minDistance = 0.5 * mu.floatPt();
237  break;
238  }
239  int imatch = -1;
240  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
241  const auto &tk = r.track[itk];
242  int deta = std::abs(mu.hwEta - tk.hwEta);
243  int dphi = std::abs((mu.hwPhi - tk.hwPhi) % CaloCluster::PHI_WRAP);
244  float dr = floatDR(mu, tk);
245  float dpt = std::abs(mu.floatPt() - tk.floatPt());
246  float dptr = (mu.hwPt > tk.hwPt ? mu.floatPt() / tk.floatPt() : tk.floatPt() / mu.floatPt());
247  bool ok = false;
248  float distance = 9e9;
249  switch (muMatchMode_) {
251  ok = (deta < intDrMuonMatchBox) && (dphi < intDrMuonMatchBox);
252  distance = dptr;
253  break;
255  ok = (dr < drMatchMu_);
256  distance = dptr;
257  break;
259  ok = (dr < drMatchMu_);
260  distance = dpt;
261  break;
262  }
263  if (debug_ && dr < 0.4) {
264  dbgPrintf(
265  "PFAlgo3 \t\t possible match with track %3d (pt %7.2f, caloeta %+5.2f, calophi %+5.2f, dr %.2f, eta "
266  "%+5.2f, phi %+5.2f, dr %.2f): angular %1d, distance %.3f (vs %.3f)\n",
267  itk,
268  tk.floatPt(),
269  tk.floatEta(),
270  tk.floatPhi(),
271  dr,
272  tk.floatVtxEta(),
273  tk.floatVtxPhi(),
274  deltaR(mu.floatEta(), mu.floatPhi(), tk.floatVtxEta(), tk.floatVtxPhi()),
275  (ok ? 1 : 0),
276  distance,
277  minDistance);
278  }
279  if (!ok)
280  continue;
281  // FIXME for the moment, we do the floating point matching in pt
282  if (distance < minDistance) {
283  minDistance = distance;
284  imatch = itk;
285  }
286  }
287  if (debug_ && imatch > -1)
288  dbgPrintf("PFAlgo3 \t muon %3d (pt %7.2f) linked to track %3d (pt %7.2f)\n",
289  imu,
290  mu.floatPt(),
291  imatch,
292  r.track[imatch].floatPt());
293  if (debug_ && imatch == -1)
294  dbgPrintf("PFAlgo3 \t muon %3d (pt %7.2f) not linked to any track\n", imu, mu.floatPt());
295  mu2tk[imu] = imatch;
296  if (imatch > -1) {
297  tk2mu[imatch] = imu;
298  r.track[imatch].muonLink = true;
299  }
300  }
301 }
302 
303 void PFAlgo3::link_tk2em(Region &r, std::vector<int> &tk2em) const {
304  // match all tracks to the closest EM cluster
305  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
306  const auto &tk = r.track[itk];
307  //if (tk.muonLink) continue; // not necessary I think
308  float drbest = drMatchEm_;
309  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
310  const auto &em = r.emcalo[iem];
311  float dr = floatDR(tk, em);
312  if (dr < drbest) {
313  tk2em[itk] = iem;
314  drbest = dr;
315  }
316  }
317  if (debug_ && tk2em[itk] != -1)
318  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) matches to EM %3d (pt %7.2f) with dr %.3f\n",
319  itk,
320  tk.floatPt(),
321  tk2em[itk],
322  tk2em[itk] == -1 ? 0.0 : r.emcalo[tk2em[itk]].floatPt(),
323  drbest);
324  }
325 }
326 
327 void PFAlgo3::link_em2calo(Region &r, std::vector<int> &em2calo) const {
328  // match all em to the closest had (can happen in parallel to the above)
329  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
330  const auto &em = r.emcalo[iem];
331  float drbest = drMatchEmHad_;
332  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
333  const auto &calo = r.calo[ic];
334  if (calo.floatEmPt() < ptMinFracMatchEm_ * em.floatPt())
335  continue;
336  float dr = floatDR(calo, em);
337  if (dr < drbest) {
338  em2calo[iem] = ic;
339  drbest = dr;
340  }
341  }
342  if (debug_ && em2calo[iem] != -1)
343  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) matches to calo %3d (pt %7.2f, empt %7.2f) with dr %.3f\n",
344  iem,
345  em.floatPt(),
346  em2calo[iem],
347  em2calo[iem] == -1 ? 0.0 : r.calo[em2calo[iem]].floatPt(),
348  em2calo[iem] == -1 ? 0.0 : r.calo[em2calo[iem]].floatEmPt(),
349  drbest);
350  }
351 }
352 
354  const std::vector<int> &tk2em,
355  std::vector<int> &em2ntk,
356  std::vector<float> &em2sumtkpt,
357  std::vector<float> &em2sumtkpterr) const {
358  // for each EM cluster, count and add up the pt of all the corresponding tracks (skipping muons)
359  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
360  const auto &em = r.emcalo[iem];
361  if (r.globalAbsEta(em.floatEta()) > 2.5)
362  continue;
363  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
364  if (tk2em[itk] == iem) {
365  const auto &tk = r.track[itk];
366  if (tk.muonLink)
367  continue;
368  em2ntk[iem]++;
369  em2sumtkpt[iem] += tk.floatPt();
370  em2sumtkpterr[iem] += tk.floatPtErr();
371  }
372  }
373  }
374 }
375 
377  const std::vector<int> &em2ntk,
378  const std::vector<float> &em2sumtkpt,
379  const std::vector<float> &em2sumtkpterr) const {
380  // process ecal clusters after linking
381  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
382  auto &em = r.emcalo[iem];
383  em.isEM = false;
384  em.used = false;
385  em.hwFlags = 0;
386  if (r.globalAbsEta(em.floatEta()) > 2.5)
387  continue;
388  if (debug_)
389  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) has %2d tracks (sumpt %7.2f, sumpterr %7.2f), ptdif %7.2f +- %7.2f\n",
390  iem,
391  em.floatPt(),
392  em2ntk[iem],
393  em2sumtkpt[iem],
394  em2sumtkpterr[iem],
395  em.floatPt() - em2sumtkpt[iem],
396  std::max<float>(em2sumtkpterr[iem], em.floatPtErr()));
397  if (em2ntk[iem] == 0) { // Photon
398  em.isEM = true;
399  addCaloToPF(r, em);
400  em.used = true;
401  if (debug_)
402  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) ---> promoted to photon\n", iem, em.floatPt());
403  continue;
404  }
405  float ptdiff = em.floatPt() - em2sumtkpt[iem];
406  float pterr = trackEmUseAlsoTrackSigma_ ? std::max<float>(em2sumtkpterr[iem], em.floatPtErr()) : em.floatPtErr();
407  // avoid "pt = inf +- inf" track to become an electron.
408  if (pterr > 2 * em.floatPt()) {
409  pterr = 2 * em.floatPt();
410  if (debug_)
411  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) ---> clamp pterr ---> new ptdiff %7.2f +- %7.2f\n",
412  iem,
413  em.floatPt(),
414  ptdiff,
415  pterr);
416  }
417 
418  if (ptdiff > -ptMatchLow_ * pterr) {
419  em.isEM = true;
420  em.used = true;
421  // convert leftover to a photon if significant
422  if (ptdiff > +ptMatchHigh_ * pterr) {
423  auto &p = addCaloToPF(r, em);
424  p.setFloatPt(ptdiff);
425  if (debug_)
426  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) ---> promoted to electron(s) + photon (pt %7.2f)\n",
427  iem,
428  em.floatPt(),
429  ptdiff);
430  } else {
431  em.hwFlags = 1; // may use calo momentum
432  if (debug_)
433  dbgPrintf("PFAlgo3 \t EM %3d (pt %7.2f) ---> promoted to electron(s)\n", iem, em.floatPt());
434  }
435  } else {
436  em.isEM = false;
437  em.used = false;
438  em.hwFlags = 0;
439  //discardCalo(r, em, 2);
440  }
441  }
442 }
443 
445  const std::vector<int> &tk2em,
446  const std::vector<int> &em2ntk,
447  const std::vector<float> &em2sumtkpterr) const {
448  // promote all flagged tracks to electrons
449  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
450  auto &tk = r.track[itk];
451  if (tk2em[itk] == -1 || tk.muonLink)
452  continue;
453  const auto &em = r.emcalo[tk2em[itk]];
454  if (em.isEM) {
455  auto &p = addTrackToPF(r, tk);
456  p.cluster.src = em.src;
457  // FIXME to check if this is useful
458  if (trackEmMayUseCaloMomenta_ && em2ntk[tk2em[itk]] == 1 && em.hwFlags == 1) {
459  if (em.floatPtErr() < em2sumtkpterr[tk2em[itk]]) {
460  p.setFloatPt(em.floatPt());
461  }
462  }
463  if (debug_)
464  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) matched to EM %3d (pt %7.2f) promoted to electron with pt %7.2f\n",
465  itk,
466  tk.floatPt(),
467  tk2em[itk],
468  em.floatPt(),
469  p.floatPt());
471  tk.used = true;
472  }
473  }
474 }
475 
476 void PFAlgo3::sub_em2calo(Region &r, const std::vector<int> &em2calo) const {
477  // subtract EM component from Calo clusters for all photons and electrons (within tracker coverage)
478  // kill clusters that end up below their own uncertainty, or that loose 90% of the energy,
479  // unless they still have live EM clusters pointing to them
480  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
481  auto &calo = r.calo[ic];
482  float pt0 = calo.floatPt(), ept0 = calo.floatEmPt(), pt = pt0, ept = ept0;
483  bool keepme = false;
484  for (int iem = 0, nem = r.emcalo.size(); iem < nem; ++iem) {
485  if (em2calo[iem] == ic) {
486  const auto &em = r.emcalo[iem];
487  if (em.isEM) {
488  if (debug_)
489  dbgPrintf(
490  "PFAlgo3 \t EM %3d (pt %7.2f) is subtracted from calo %3d (pt %7.2f) scaled by %.3f (deltaPt = "
491  "%7.2f)\n",
492  iem,
493  em.floatPt(),
494  ic,
495  calo.floatPt(),
497  emHadSubtractionPtSlope_ * em.floatPt());
498  pt -= emHadSubtractionPtSlope_ * em.floatPt();
499  ept -= em.floatPt();
500  } else {
501  keepme = true;
502  if (debug_)
503  dbgPrintf(
504  "PFAlgo3 \t EM %3d (pt %7.2f) not subtracted from calo %3d (pt %7.2f), and calo marked to be kept "
505  "after EM subtraction\n",
506  iem,
507  em.floatPt(),
508  ic,
509  calo.floatPt());
510  }
511  }
512  }
513  if (pt < pt0) {
514  if (debug_)
515  dbgPrintf(
516  "PFAlgo3 \t calo %3d (pt %7.2f +- %7.2f) has a subtracted pt of %7.2f, empt %7.2f -> %7.2f, isem %d\n",
517  ic,
518  calo.floatPt(),
519  calo.floatPtErr(),
520  pt,
521  ept0,
522  ept,
523  calo.isEM);
524  calo.setFloatPt(pt);
525  calo.setFloatEmPt(ept);
526  if (!keepme &&
527  ((emCaloUseAlsoCaloSigma_ ? pt < calo.floatPtErr() : false) || pt <= 0.125 * pt0 ||
528  (calo.isEM && ept <= 0.125 * ept0))) { // the <= is important since in firmware the pt0/8 can be zero
529  if (debug_)
530  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) ----> discarded\n", ic, calo.floatPt());
531  calo.used = true;
532  calo.setFloatPt(pt0); //discardCalo(r, calo, 1); // log this as discarded, for debugging
533  }
534  }
535  }
536 }
537 
538 void PFAlgo3::link_tk2calo(Region &r, std::vector<int> &tk2calo) const {
539  // track to calo matching (first iteration, with a lower bound on the calo pt; there may be another one later)
540  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
541  const auto &tk = r.track[itk];
542  if (tk.muonLink || tk.used)
543  continue; // not necessary but just a waste of CPU otherwise
544  float drbest = drMatch_, dptscale = 0;
545  switch (tkCaloLinkMetric_) {
547  drbest = drMatch_;
548  break;
550  drbest = 1.0;
551  dptscale = drMatch_ / tk.floatCaloPtErr();
552  break;
554  drbest = 1.0;
555  dptscale = drMatch_ / tk.floatCaloPtErr();
556  break;
557  }
558  float minCaloPt = tk.floatPt() - ptMatchLow_ * tk.floatCaloPtErr();
559  if (debug_)
560  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) to be matched to calo, min pT %7.2f\n", itk, tk.floatPt(), minCaloPt);
561  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
562  auto &calo = r.calo[ic];
563  if (calo.used || calo.floatPt() <= minCaloPt)
564  continue;
565  float dr = floatDR(tk, calo), dq;
566  switch (tkCaloLinkMetric_) {
568  if (dr < drbest) {
569  tk2calo[itk] = ic;
570  drbest = dr;
571  }
572  break;
574  dq = dr + std::max<float>(tk.floatPt() - calo.floatPt(), 0.) * dptscale;
575  //if (debug_ && dr < 0.2) dbgPrintf("PFAlgo3 \t\t\t track %3d (pt %7.2f) vs calo %3d (pt %7.2f): dr %.3f, dq %.3f\n", itk, tk.floatPt(), ic, calo.floatPt(), dr, dq);
576  if (dr < drMatch_ && dq < drbest) {
577  tk2calo[itk] = ic;
578  drbest = dq;
579  }
580  break;
582  dq = hypot(dr, std::max<float>(tk.floatPt() - calo.floatPt(), 0.) * dptscale);
583  //if (debug_ && dr < 0.2) dbgPrintf("PFAlgo3 \t\t\t track %3d (pt %7.2f) vs calo %3d (pt %7.2f): dr %.3f, dq %.3f\n", itk, tk.floatPt(), ic, calo.floatPt(), dr, dq);
584  if (dr < drMatch_ && dq < drbest) {
585  tk2calo[itk] = ic;
586  drbest = dq;
587  }
588  break;
589  }
590  }
591  if (debug_ && tk2calo[itk] != -1)
592  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) matches to calo %3d (pt %7.2f) with dist %.3f\n",
593  itk,
594  tk.floatPt(),
595  tk2calo[itk],
596  tk2calo[itk] == -1 ? 0.0 : r.calo[tk2calo[itk]].floatPt(),
597  drbest);
598  // now we re-do this for debugging sake, it may be done for real later
599  if (debug_ && tk2calo[itk] == -1) {
600  int ibest = -1;
601  drbest = 0.3;
602  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
603  auto &calo = r.calo[ic];
604  if (calo.used)
605  continue;
606  float dr = floatDR(tk, calo);
607  if (dr < drbest) {
608  ibest = ic;
609  drbest = dr;
610  }
611  }
612  if (ibest != -1)
613  dbgPrintf(
614  "PFAlgo3 \t track %3d (pt %7.2f) would match to calo %3d (pt %7.2f) with dr %.3f if the pt min and dr "
615  "requirement had been relaxed\n",
616  itk,
617  tk.floatPt(),
618  ibest,
619  r.calo[ibest].floatPt(),
620  drbest);
621  }
622  }
623 }
624 
626  const std::vector<int> &tk2calo,
627  std::vector<int> &calo2ntk,
628  std::vector<float> &calo2sumtkpt,
629  std::vector<float> &calo2sumtkpterr) const {
630  // for each calo, compute the sum of the track pt
631  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
632  const auto &calo = r.calo[ic];
633  if (r.globalAbsEta(calo.floatEta()) > 2.5)
634  continue;
635  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
636  if (tk2calo[itk] == ic) {
637  const auto &tk = r.track[itk];
638  if (tk.muonLink || tk.used)
639  continue;
640  calo2ntk[ic]++;
641  calo2sumtkpt[ic] += tk.floatPt();
642  calo2sumtkpterr[ic] += std::pow(tk.floatCaloPtErr(), sumTkCaloErr2_ ? 2 : 1);
643  }
644  }
645  if (sumTkCaloErr2_ && calo2sumtkpterr[ic] > 0)
646  calo2sumtkpterr[ic] = std::sqrt(calo2sumtkpterr[ic]);
647  }
648 }
649 
650 void PFAlgo3::unlinkedtk_algo(Region &r, const std::vector<int> &tk2calo) const {
651  // in the meantime, promote unlinked low pt tracks to hadrons
652  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
653  auto &tk = r.track[itk];
654  if (tk2calo[itk] != -1 || tk.muonLink || tk.used)
655  continue;
656  float maxPt = (tk.hwStubs >= tightTrackMinStubs_ && tk.hwChi2 < 10 * tightTrackMaxChi2_) ? tightTrackMaxInvisiblePt_
657  : maxInvisiblePt_;
658  if (tk.floatPt() < maxPt) {
659  if (debug_)
660  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) not matched to calo, kept as charged hadron\n", itk, tk.floatPt());
661  auto &p = addTrackToPF(r, tk);
662  p.hwStatus = GoodTK_NoCalo;
663  tk.used = true;
664  } else {
665  if (debug_)
666  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) not matched to calo, dropped\n", itk, tk.floatPt());
667  //discardTrack(r, tk, BadTK_NoCalo); // log this as discarded, for debugging
668  }
669  }
670 }
671 
673  const std::vector<int> &calo2ntk,
674  const std::vector<float> &calo2sumtkpt,
675  const std::vector<float> &calo2sumtkpterr) const {
677  // take hadrons that are not track matched, close by a hadron which has an excess of track pt vs calo pt
678  // add this pt to the calo pt of the other cluster
679  // off by default, as it seems to not do much in jets even if it helps remove tails in single-pion events
680  std::vector<float> addtopt(r.calo.size(), 0);
681  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
682  auto &calo = r.calo[ic];
683  if (calo2ntk[ic] != 0 || calo.used || r.globalAbsEta(calo.floatEta()) > 2.5)
684  continue;
685  int i2best = -1;
686  float drbest = caloReLinkDr_;
687  for (int ic2 = 0; ic2 < nc; ++ic2) {
688  const auto &calo2 = r.calo[ic2];
689  if (calo2ntk[ic2] == 0 || calo2.used || r.globalAbsEta(calo2.floatEta()) > 2.5)
690  continue;
691  float dr = floatDR(calo, calo2);
693  //if (debug_ && dr < 0.5) dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) with no tracks is at dr %.3f from calo %3d with pt %7.2f (sum tk pt %7.2f), track excess %7.2f +- %7.2f\n", ic, calo.floatPt(), dr, ic2, calo2.floatPt(), calo2sumtkpt[ic2], calo2sumtkpt[ic2] - calo2.floatPt(), useTrackCaloSigma_ ? calo2sumtkpterr[ic2] : calo2.floatPtErr());
694  if (dr < drbest) {
695  float ptdiff =
696  calo2sumtkpt[ic2] - calo2.floatPt() + (useTrackCaloSigma_ ? calo2sumtkpterr[ic2] : calo2.floatPtErr());
697  if (ptdiff >= caloReLinkThreshold_ * calo.floatPt()) {
698  i2best = ic2;
699  drbest = dr;
700  }
701  }
702  }
703  if (i2best != -1) {
704  const auto &calo2 = r.calo[i2best];
705  if (debug_)
706  dbgPrintf(
707  "PFAlgo3 \t calo %3d (pt %7.2f) with no tracks matched within dr %.3f with calo %3d with pt %7.2f (sum tk "
708  "pt %7.2f), track excess %7.2f +- %7.2f\n",
709  ic,
710  calo.floatPt(),
711  drbest,
712  i2best,
713  calo2.floatPt(),
714  calo2sumtkpt[i2best],
715  calo2sumtkpt[i2best] - calo2.floatPt(),
716  useTrackCaloSigma_ ? calo2sumtkpterr[i2best] : calo2.floatPtErr());
717  calo.used = true;
718  addtopt[i2best] += calo.floatPt();
719  }
720  }
721  // we do this at the end, so that the above loop is parallelizable
722  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
723  if (addtopt[ic]) {
724  auto &calo = r.calo[ic];
725  if (debug_)
726  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f, sum tk pt %7.2f) is increased to pt %7.2f after merging\n",
727  ic,
728  calo.floatPt(),
729  calo2sumtkpt[ic],
730  calo.floatPt() + addtopt[ic]);
731  calo.setFloatPt(calo.floatPt() + addtopt[ic]);
732  }
733  }
734 }
735 
737  const std::vector<int> &calo2ntk,
738  const std::vector<float> &calo2sumtkpt,
739  const std::vector<float> &calo2sumtkpterr,
740  std::vector<float> &calo2alpha) const {
742  // process matched calo clusters, compare energy to sum track pt
743  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
744  auto &calo = r.calo[ic];
745  if (calo2ntk[ic] == 0 || calo.used)
746  continue;
747  float ptdiff = calo.floatPt() - calo2sumtkpt[ic];
748  float pterr = useTrackCaloSigma_ ? calo2sumtkpterr[ic] : calo.floatPtErr();
749  if (debug_)
750  dbgPrintf(
751  "PFAlgo3 \t calo %3d (pt %7.2f +- %7.2f, empt %7.2f) has %2d tracks (sumpt %7.2f, sumpterr %7.2f), ptdif "
752  "%7.2f +- %7.2f\n",
753  ic,
754  calo.floatPt(),
755  calo.floatPtErr(),
756  calo.floatEmPt(),
757  calo2ntk[ic],
758  calo2sumtkpt[ic],
759  calo2sumtkpterr[ic],
760  ptdiff,
761  pterr);
762  if (ptdiff > +ptMatchHigh_ * pterr) {
763  if (ecalPriority_) {
764  if (calo.floatEmPt() > 1) {
765  float emptdiff = std::min(ptdiff, calo.floatEmPt());
766  if (debug_)
767  dbgPrintf(
768  "PFAlgo3 \t calo %3d (pt %7.2f, empt %7.2f) ---> make photon with pt %7.2f, reduce ptdiff to %7.2f "
769  "+- %7.2f\n",
770  ic,
771  calo.floatPt(),
772  calo.floatEmPt(),
773  emptdiff,
774  ptdiff - emptdiff,
775  pterr);
776  auto &p = addCaloToPF(r, calo);
777  p.setFloatPt(emptdiff);
778  p.hwId = l1t::PFCandidate::Photon;
779  ptdiff -= emptdiff;
780  }
781  if (ptdiff > 2) {
782  if (debug_)
783  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f, empt %7.2f) ---> make also neutral hadron with pt %7.2f\n",
784  ic,
785  calo.floatPt(),
786  calo.floatEmPt(),
787  ptdiff);
788  auto &p = addCaloToPF(r, calo);
789  p.setFloatPt(ptdiff);
791  }
792  } else {
793  if (debug_)
794  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) ---> promoted to neutral with pt %7.2f\n",
795  ic,
796  calo.floatPt(),
797  ptdiff);
798  auto &p = addCaloToPF(r, calo);
799  p.setFloatPt(ptdiff);
800  calo.hwFlags = 0;
801  }
802  } else if (ptdiff > -ptMatchLow_ * pterr) {
803  // nothing to do (weighted average happens when we process the tracks)
804  calo.hwFlags = 1;
805  if (debug_)
806  dbgPrintf(
807  "PFAlgo3 \t calo %3d (pt %7.2f) ---> to be deleted, will use tracks instead\n", ic, calo.floatPt());
808  //discardCalo(r, calo, 0); // log this as discarded, for debugging
809  } else {
810  // tracks overshoot, rescale to tracks to calo
811  calo2alpha[ic] = rescaleTracks_ ? calo.floatPt() / calo2sumtkpt[ic] : 1.0;
812  calo.hwFlags = 2;
813  if (debug_ && rescaleTracks_)
814  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) ---> tracks overshoot and will be scaled down by %.4f\n",
815  ic,
816  calo.floatPt(),
817  calo2alpha[ic]);
818  if (debug_ && !rescaleTracks_)
819  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) ---> tracks overshoot by %.4f\n",
820  ic,
821  calo.floatPt(),
822  calo2sumtkpt[ic] / calo.floatPt());
823  }
824  calo.used = true;
825  }
826 }
827 
829  const std::vector<int> &tk2calo,
830  const std::vector<int> &calo2ntk,
831  const std::vector<float> &calo2alpha) const {
832  // process matched tracks, if necessary rescale or average
833  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
834  auto &tk = r.track[itk];
835  if (tk2calo[itk] == -1 || tk.muonLink || tk.used)
836  continue;
837  auto &p = addTrackToPF(r, tk);
838  tk.used = true;
839  const auto &calo = r.calo[tk2calo[itk]];
840  p.cluster.src = calo.src;
841  if (calo.hwFlags == 1) {
842  // can do weighted average if there's just one track
843  if (calo2ntk[tk2calo[itk]] == 1 && caloTrkWeightedAverage_) {
844  p.hwStatus = GoodTK_Calo_TkPt;
845  float ptavg = tk.floatPt();
846  if (tk.floatPtErr() > 0) {
847  float wcalo = 1.0 / std::pow(tk.floatCaloPtErr(), 2);
848  float wtk = 1.0 / std::pow(tk.floatPtErr(), 2);
849  ptavg = (calo.floatPt() * wcalo + tk.floatPt() * wtk) / (wcalo + wtk);
850  p.hwStatus = GoodTK_Calo_TkCaloPt;
851  }
852  p.setFloatPt(ptavg);
853  if (debug_)
854  dbgPrintf(
855  "PFAlgo3 \t track %3d (pt %7.2f +- %7.2f) combined with calo %3d (pt %7.2f +- %7.2f (from tk) yielding "
856  "candidate of pt %7.2f\n",
857  itk,
858  tk.floatPt(),
859  tk.floatPtErr(),
860  tk2calo[itk],
861  calo.floatPt(),
862  tk.floatCaloPtErr(),
863  ptavg);
864  } else {
865  p.hwStatus = GoodTK_Calo_TkPt;
866  if (debug_)
867  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) linked to calo %3d promoted to charged hadron\n",
868  itk,
869  tk.floatPt(),
870  tk2calo[itk]);
871  }
872  } else if (calo.hwFlags == 2) {
873  // must rescale
874  p.setFloatPt(tk.floatPt() * calo2alpha[tk2calo[itk]]);
875  p.hwStatus = GoodTk_Calo_CaloPt;
876  if (debug_)
877  dbgPrintf(
878  "PFAlgo3 \t track %3d (pt %7.2f, stubs %2d chi2 %7.1f) linked to calo %3d promoted to charged hadron with "
879  "pt %7.2f after maybe rescaling\n",
880  itk,
881  tk.floatPt(),
882  int(tk.hwStubs),
883  tk.hwChi2 * 0.1f,
884  tk2calo[itk],
885  p.floatPt());
886  }
887  }
888 }
889 
891  // process unmatched calo clusters
892  for (int ic = 0, nc = r.calo.size(); ic < nc; ++ic) {
893  if (!r.calo[ic].used) {
894  addCaloToPF(r, r.calo[ic]);
895  if (debug_)
896  dbgPrintf("PFAlgo3 \t calo %3d (pt %7.2f) not linked, promoted to neutral\n", ic, r.calo[ic].floatPt());
897  }
898  }
899 }
900 
901 void PFAlgo3::save_muons(Region &r, const std::vector<int> &tk2mu) const {
902  // finally do muons
903  for (int itk = 0, ntk = r.track.size(); itk < ntk; ++itk) {
904  if (r.track[itk].muonLink) {
905  auto &p = addTrackToPF(r, r.track[itk]);
906  p.muonsrc = r.muon[tk2mu[itk]].src;
907  if (debug_)
908  dbgPrintf("PFAlgo3 \t track %3d (pt %7.2f) promoted to muon.\n", itk, r.track[itk].floatPt());
909  }
910  }
911 }
bool useTrackCaloSigma_
Definition: PFAlgo3.h:16
constexpr int32_t ceil(float num)
T getUntrackedParameter(std::string const &, T const &) const
float caloReLinkThreshold_
Definition: PFAlgo3.h:22
bool trackEmMayUseCaloMomenta_
Definition: PFAlgo3.h:23
PFAlgo3(const edm::ParameterSet &)
Definition: PFAlgo3.cc:19
void link_tk2calo(Region &r, std::vector< int > &tk2calo) const
track to calo matching
Definition: PFAlgo3.cc:538
void runPF(Region &r) const override
Definition: PFAlgo3.cc:69
void link_tk2em(Region &r, std::vector< int > &tk2em) const
match all tracks to the closest EM cluster
Definition: PFAlgo3.cc:303
void link_em2calo(Region &r, std::vector< int > &em2calo) const
match all em to the closest had (can happen in parallel to the above)
Definition: PFAlgo3.cc:327
float globalAbsEta(float localEta) const
Definition: Region.h:86
std::vector< CaloCluster > calo
std::vector< Muon > muon
void sub_em2calo(Region &r, const std::vector< int > &em2calo) const
subtract EM component from Calo clusters for all photons and electrons (within tracker coverage) ...
Definition: PFAlgo3.cc:476
void dbgPrintf(const char *formatString, Args &&...args)
Definition: dbgPrintf.h:5
float caloReLinkDr_
Definition: PFAlgo3.h:22
void unlinkedtk_algo(Region &r, const std::vector< int > &tk2calo) const
promote unlinked low pt tracks to hadrons
Definition: PFAlgo3.cc:650
float ptMatchHigh_
Definition: PFAlgo3.h:15
void sum_tk2calo(Region &r, const std::vector< int > &tk2calo, std::vector< int > &calo2ntk, std::vector< float > &calo2sumtkpt, std::vector< float > &calo2sumtkpterr) const
for each calo, compute the sum of the track pt
Definition: PFAlgo3.cc:625
T sqrt(T t)
Definition: SSEVec.h:19
bool emCaloUseAlsoCaloSigma_
Definition: PFAlgo3.h:23
void linkedtk_algo(Region &r, const std::vector< int > &tk2calo, const std::vector< int > &calo2ntk, const std::vector< float > &calo2alpha) const
process matched tracks, if necessary rescale or average
Definition: PFAlgo3.cc:828
PFParticle & addCaloToPF(Region &r, const CaloCluster &calo) const
Definition: PFAlgoBase.h:21
float emHadSubtractionPtSlope_
Definition: PFAlgo3.h:19
void emtk_algo(Region &r, const std::vector< int > &tk2em, const std::vector< int > &em2ntk, const std::vector< float > &em2sumtkpterr) const
promote all flagged tracks to electrons
Definition: PFAlgo3.cc:444
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
const int mu
Definition: Constants.h:22
T min(T a, T b)
Definition: MathUtil.h:58
float tightTrackMaxInvisiblePt_
Definition: PFAlgo3.h:26
void calo_relink(Region &r, const std::vector< int > &calo2ntk, const std::vector< float > &calo2sumtkpt, const std::vector< float > &calo2sumtkpterr) const
try to recover split hadron showers (v1.0):
Definition: PFAlgo3.cc:672
float tightTrackMaxChi2_
Definition: PFAlgo3.h:26
float ptMinFracMatchEm_
Definition: PFAlgo3.h:18
#define M_PI
void initRegion(Region &r) const
Definition: PFAlgoBase.cc:11
bool trackEmUseAlsoTrackSigma_
Definition: PFAlgo3.h:23
enum l1tpf_impl::PFAlgo3::MuMatchMode muMatchMode_
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
bool caloReLinkStep_
Definition: PFAlgo3.h:21
void sum_tk2em(Region &r, const std::vector< int > &tk2em, std::vector< int > &em2ntk, std::vector< float > &em2sumtkpt, std::vector< float > &em2sumtkpterr) const
for each EM cluster, count and add up the pt of all the corresponding tracks (skipping muons) ...
Definition: PFAlgo3.cc:353
std::vector< PropagatedTrack > track
unsigned int tightTrackMinStubs_
Definition: PFAlgo3.h:25
std::vector< CaloCluster > emcalo
void unlinkedcalo_algo(Region &r) const
process unmatched calo clusters
Definition: PFAlgo3.cc:890
TkCaloLinkMetric tkCaloLinkMetric_
Definition: PFAlgo3.h:20
float maxInvisiblePt_
Definition: PFAlgo3.h:15
bool caloTrkWeightedAverage_
Definition: PFAlgo3.h:16
void linkedcalo_algo(Region &r, const std::vector< int > &calo2ntk, const std::vector< float > &calo2sumtkpt, const std::vector< float > &calo2sumtkpterr, std::vector< float > &calo2alpha) const
process matched calo clusters, compare energy to sum track pt, compute track rescaling factor if need...
Definition: PFAlgo3.cc:736
void emcalo_algo(Region &r, const std::vector< int > &em2ntk, const std::vector< float > &em2sumtkpt, const std::vector< float > &em2sumtkpterr) const
process ecal clusters after linking
Definition: PFAlgo3.cc:376
bool fiducialLocal(float localEta, float localPhi) const
Definition: Region.h:76
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
void save_muons(Region &r, const std::vector< int > &tk2mu) const
save muons in output list
Definition: PFAlgo3.cc:901
PFParticle & addTrackToPF(Region &r, const PropagatedTrack &tk) const
Definition: PFAlgoBase.h:20
float drMatchEmHad_
Definition: PFAlgo3.h:18
void link_tk2mu(Region &r, std::vector< int > &tk2mu, std::vector< int > &mu2tk) const
do muon track linking (also sets track.muonLink)
Definition: PFAlgo3.cc:216