CMS 3D CMS Logo

KFbase.cc
Go to the documentation of this file.
1 
4 
14 #include "TMatrixD.h"
15 
16 #include <algorithm>
17 #include <functional>
18 #include <fstream>
19 #include <iomanip>
20 #include <atomic>
21 #include <sstream>
22 
23 using namespace std;
24 
25 namespace tmtt {
26 
27  /* Initialize cfg parameters */
28 
29  KFbase::KFbase(const Settings *settings, const uint nHelixPar, const string &fitterName, const uint nMeas)
30  : TrackFitGeneric(settings, fitterName) {
31  nHelixPar_ = nHelixPar;
32  nMeas_ = nMeas;
33  numEtaRegions_ = settings->numEtaRegions();
34  }
35 
36  /* Do track fit */
37 
38  L1fittedTrack KFbase::fit(const L1track3D &l1track3D) {
39  iPhiSec_ = l1track3D.iPhiSec();
40  iEtaReg_ = l1track3D.iEtaReg();
41  resetStates();
42  numUpdateCalls_ = 0;
43 
44  vector<Stub *> stubs = l1track3D.stubs();
45 
46  auto orderByLayer = [](const Stub *a, const Stub *b) { return bool(a->layerId() < b->layerId()); };
47  sort(stubs.begin(), stubs.end(), orderByLayer); // Makes debug printout pretty.
48 
49  //TP
50  const TP *tpa(nullptr);
51  if (l1track3D.matchedTP()) {
52  tpa = l1track3D.matchedTP();
53  }
54  tpa_ = tpa;
55 
56  //track information dump
57  if (settings_->kalmanDebugLevel() >= 1) {
58  PrintL1trk() << "===============================================================================";
59  std::stringstream text;
60  text << std::fixed << std::setprecision(4);
61  text << "Input track cand: [phiSec,etaReg]=[" << l1track3D.iPhiSec() << "," << l1track3D.iEtaReg() << "]";
62  text << " HT(m,c)=(" << l1track3D.cellLocationHT().first << "," << l1track3D.cellLocationHT().second
63  << ") q/pt=" << l1track3D.qOverPt() << " tanL=" << l1track3D.tanLambda() << " z0=" << l1track3D.z0()
64  << " phi0=" << l1track3D.phi0() << " nStubs=" << l1track3D.numStubs() << " d0=" << l1track3D.d0();
65  PrintL1trk() << text.str();
66  if (not settings_->hybrid())
67  printTP(tpa);
68  if (settings_->kalmanDebugLevel() >= 2) {
69  printStubLayers(stubs, l1track3D.iEtaReg());
70  printStubs(stubs);
71  }
72  }
73 
74  //Kalman Filter
75  const KalmanState *cand = doKF(l1track3D, stubs, tpa);
76 
77  //return L1fittedTrk for the selected state (if KF produced one it was happy with).
78  if (cand != nullptr) {
79  // Get track helix params.
80  TVectorD trackPars = trackParams(cand);
81  double d0 = (nHelixPar_ == 5) ? trackPars[D0] : 0.;
82 
83  L1fittedTrack fitTrk(settings_,
84  &l1track3D,
85  cand->stubs(),
86  cand->hitPattern(),
87  trackPars[QOVERPT],
88  d0,
89  trackPars[PHI0],
90  trackPars[Z0],
91  trackPars[T],
92  cand->chi2rphi(),
93  cand->chi2rz(),
94  nHelixPar_);
95 
96  // Store supplementary info, specific to KF fitter.
97  fitTrk.setInfoKF(cand->nSkippedLayers(), numUpdateCalls_);
98 
99  // If doing 5 parameter fit, optionally also calculate helix params & chi2 with beam-spot constraint applied,
100  // and store inside L1fittedTrack object.
102  if (nHelixPar_ == 5) {
103  double chi2rphi_bcon = 0.;
104  TVectorD trackPars_bcon = trackParams_BeamConstr(cand, chi2rphi_bcon);
105 
106  // Check scaled chi2 cut
107  vector<double> kfLayerVsChiSqCut = settings_->kfLayerVsChiSq5();
108  double chi2scaled = chi2rphi_bcon / settings_->kalmanChi2RphiScale() + fitTrk.chi2rz();
109  bool accepted = true;
110  if (chi2scaled > kfLayerVsChiSqCut[cand->nStubLayers()])
111  accepted = false;
112 
113  fitTrk.setBeamConstr(trackPars_bcon[QOVERPT], trackPars_bcon[PHI0], chi2rphi_bcon, accepted);
114  }
115  }
116 
117  // Fitted track params must lie in same sector as HT originally found track in.
118  if (!settings_->hybrid()) { // consistentSector() function not yet working for Hybrid.
119 
120  // Bodge to take into account digitisation in sector consistency check.
121  if (settings_->enableDigitize())
122  fitTrk.digitizeTrack("KF4ParamsComb");
123 
124  if (!fitTrk.consistentSector()) {
125  if (settings_->kalmanDebugLevel() >= 1)
126  PrintL1trk() << "Track rejected by sector consistency test";
127  L1fittedTrack rejectedTrk;
128  return rejectedTrk;
129  }
130  }
131 
132  return fitTrk;
133 
134  } else { // Track rejected by fitter
135 
136  if (settings_->kalmanDebugLevel() >= 1) {
137  bool goodTrack = (tpa && tpa->useForAlgEff()); // Matches truth particle.
138  if (goodTrack) {
139  int tpin = tpa->index();
140  PrintL1trk() << "TRACK LOST: eta=" << l1track3D.iEtaReg() << " pt=" << l1track3D.pt() << " tp=" << tpin;
141 
142  for (auto stub : stubs) {
143  int kalmanLay =
144  this->kalmanLayer(l1track3D.iEtaReg(), stub->layerIdReduced(), stub->barrel(), stub->r(), stub->z());
145  std::stringstream text;
146  text << std::fixed << std::setprecision(4);
147  text << " Stub: lay_red=" << stub->layerIdReduced() << " KFlay=" << kalmanLay << " r=" << stub->r()
148  << " z=" << stub->z() << " assoc TPs =";
149  for (const TP *tp_i : stub->assocTPs())
150  text << " " << tp_i->index();
151  PrintL1trk() << text.str();
152  if (stub->assocTPs().empty())
153  PrintL1trk() << " none";
154  }
155  PrintL1trk() << "=====================";
156  }
157  }
158 
159  //dump on the missed TP for efficiency calculation.
160  if (settings_->kalmanDebugLevel() >= 3) {
161  if (tpa && tpa->useForAlgEff()) {
162  PrintL1trk() << "TP for eff. missed addr. index : " << tpa << " " << tpa->index();
163  printStubs(stubs);
164  }
165  }
166 
167  L1fittedTrack rejectedTrk;
168  return rejectedTrk;
169  }
170  }
171 
172  /* Do track fit (internal function) */
173 
174  const KalmanState *KFbase::doKF(const L1track3D &l1track3D, const vector<Stub *> &stubs, const TP *tpa) {
175  const KalmanState *finished_state = nullptr;
176 
177  map<unsigned int, const KalmanState *, std::greater<unsigned int>>
178  best_state_by_nstubs; // Best state (if any) for each viable no. of stubs on track value.
179 
180  // seed helix params & their covariance.
181  TVectorD x0 = seedX(l1track3D);
182  TMatrixD pxx0 = seedC(l1track3D);
183  TMatrixD K(nHelixPar_, 2);
184  TMatrixD dcov(2, 2);
185 
186  const KalmanState *state0 = mkState(l1track3D, 0, -1, nullptr, x0, pxx0, K, dcov, nullptr, 0, 0);
187 
188  // internal containers - i.e. the state FIFO. Contains estimate of helix params in last/next layer, with multiple entries if there were multiple stubs, yielding multiple states.
189  vector<const KalmanState *> new_states;
190  vector<const KalmanState *> prev_states;
191  prev_states.push_back(state0);
192 
193  // Get dead layers, if any.
194  bool remove2PSCut = settings_->kalmanRemove2PScut();
195  set<unsigned> kfDeadLayers = kalmanDeadLayers(remove2PSCut);
196 
197  // arrange stubs into Kalman layers according to eta region
198  int etaReg = l1track3D.iEtaReg();
199  map<int, vector<Stub *>> layerStubs;
200 
201  for (auto stub : stubs) {
202  // Get Kalman encoded layer ID for this stub.
203  int kalmanLay = this->kalmanLayer(etaReg, stub->layerIdReduced(), stub->barrel(), stub->r(), stub->z());
204 
205  if (kalmanLay != invalidKFlayer_) {
206  if (layerStubs[kalmanLay].size() < settings_->kalmanMaxStubsPerLayer()) {
207  layerStubs[kalmanLay].push_back(stub);
208  } else {
209  // If too many stubs, FW keeps the last stub.
210  layerStubs[kalmanLay].back() = stub;
211  }
212  }
213  }
214 
215  // iterate using state->nextLayer() to determine next Kalman layer(s) to add stubs from
216  constexpr unsigned int nTypicalLayers = 6; // Number of tracker layers a typical track can pass through.
217  // If user asked to add up to 7 layers to track, increase number of iterations by 1.
218  const unsigned int maxIterations = std::max(nTypicalLayers, settings_->kalmanMaxNumStubs());
219  for (unsigned iteration = 0; iteration < maxIterations; iteration++) {
220  bool easy = (l1track3D.numStubs() < settings_->kalmanMaxStubsEasy());
221  unsigned int kalmanMaxSkipLayers =
223 
224  // update each state from previous iteration (or seed) using stubs in next Kalman layer
225  vector<const KalmanState *>::const_iterator i_state = prev_states.begin();
226  for (; i_state != prev_states.end(); i_state++) {
227  const KalmanState *the_state = *i_state;
228 
229  unsigned int layer = the_state->nextLayer(); // Get KF layer where stubs to be searched for next
230  unsigned nSkipped = the_state->nSkippedLayers();
231 
232  // If this layer is known to be dead, skip to the next layer (layer+1)
233  // The next_states_skipped will then look at layer+2
234  // However, if there are stubs in this layer, then don't skip (e.g. our phi/eta boundaries might not line up exactly with a dead region)
235  // Continue to skip until you reach a functioning layer (or a layer with stubs)
236  unsigned nSkippedDeadLayers = 0;
237  unsigned nSkippedAmbiguousLayers = 0;
238  while (kfDeadLayers.find(layer) != kfDeadLayers.end() && layerStubs[layer].empty()) {
239  layer += 1;
240  ++nSkippedDeadLayers;
241  }
242  while (this->kalmanAmbiguousLayer(etaReg, layer) && layerStubs[layer].empty()) {
243  layer += 1;
244  ++nSkippedAmbiguousLayers;
245  }
246 
247  // containers for updated state+stub combinations
248  vector<const KalmanState *> next_states;
249  vector<const KalmanState *> next_states_skipped;
250 
251  // find stubs for this layer
252  // (If layer > 6, this will return empty vector, so safe).
253  vector<Stub *> thislay_stubs = layerStubs[layer];
254 
255  // find stubs for next layer if we skip a layer, except when we are on the penultimate layer,
256  // or we have exceeded the max skipped layers
257  vector<Stub *> nextlay_stubs;
258 
259  // If the next layer (layer+1) is a dead layer, then proceed to the layer after next (layer+2), if possible
260  // Also note if we need to increase "skipped" by one more for these states
261  unsigned nSkippedDeadLayers_nextStubs = 0;
262  unsigned nSkippedAmbiguousLayers_nextStubs = 0;
263  if (nSkipped < kalmanMaxSkipLayers) {
264  if (kfDeadLayers.find(layer + 1) != kfDeadLayers.end() && layerStubs[layer + 1].empty()) {
265  nextlay_stubs = layerStubs[layer + 2];
266  nSkippedDeadLayers_nextStubs++;
267  } else if (this->kalmanAmbiguousLayer(etaReg, layer + 1) && layerStubs[layer + 1].empty()) {
268  nextlay_stubs = layerStubs[layer + 2];
269  nSkippedAmbiguousLayers_nextStubs++;
270  } else {
271  nextlay_stubs = layerStubs[layer + 1];
272  }
273  }
274 
275  // If track was not rejected by isGoodState() is previous iteration, failure here usually means the tracker ran out of layers to explore.
276  // (Due to "kalmanLay" not having unique ID for each layer within a given eta sector).
277  if (settings_->kalmanDebugLevel() >= 2 && best_state_by_nstubs.empty() && thislay_stubs.empty() &&
278  nextlay_stubs.empty())
279  PrintL1trk() << "State is lost by start of iteration " << iteration
280  << " : #thislay_stubs=" << thislay_stubs.size() << " #nextlay_stubs=" << nextlay_stubs.size()
281  << " layer=" << layer << " eta=" << l1track3D.iEtaReg();
282 
283  // If we skipped over a dead layer, only increment "nSkipped" after the stubs in next+1 layer have been obtained
284  nSkipped += nSkippedDeadLayers;
285  nSkipped += nSkippedAmbiguousLayers;
286 
287  // check to guarantee no fewer than 2PS hits per state at iteration 1
288  // (iteration 0 will always include a PS hit, but iteration 1 could use 2S hits
289  // unless we include this)
290  if (iteration == 1 && !remove2PSCut) {
291  vector<Stub *> temp_thislaystubs;
292  vector<Stub *> temp_nextlaystubs;
293  for (auto stub : thislay_stubs) {
294  if (stub->psModule())
295  temp_thislaystubs.push_back(stub);
296  }
297  for (auto stub : nextlay_stubs) {
298  if (stub->psModule())
299  temp_nextlaystubs.push_back(stub);
300  }
301  thislay_stubs = temp_thislaystubs;
302  nextlay_stubs = temp_nextlaystubs;
303  }
304 
305  // loop over each stub in this layer and check for compatibility with this state
306  for (unsigned i = 0; i < thislay_stubs.size(); i++) {
307  Stub *stub = thislay_stubs[i];
308 
309  // Update helix params by adding this stub.
310  const KalmanState *new_state = kalmanUpdate(nSkipped, layer, stub, the_state, tpa);
311 
312  // Cut on track chi2, pt etc.
313  if (isGoodState(*new_state))
314  next_states.push_back(new_state);
315  }
316 
317  // loop over each stub in next layer if we skip, and check for compatibility with this state
318  for (unsigned i = 0; i < nextlay_stubs.size(); i++) {
319  Stub *stub = nextlay_stubs[i];
320 
321  const KalmanState *new_state =
322  kalmanUpdate(nSkipped + 1 + nSkippedDeadLayers_nextStubs + nSkippedAmbiguousLayers_nextStubs,
323  layer + 1 + nSkippedDeadLayers_nextStubs + nSkippedAmbiguousLayers_nextStubs,
324  stub,
325  the_state,
326  tpa);
327 
328  if (isGoodState(*new_state))
329  next_states_skipped.push_back(new_state);
330  }
331 
332  // post Kalman filter local sorting per state
333  auto orderByChi2 = [](const KalmanState *a, const KalmanState *b) {
334  return bool(a->chi2scaled() < b->chi2scaled());
335  };
336  sort(next_states.begin(), next_states.end(), orderByChi2);
337  sort(next_states_skipped.begin(), next_states_skipped.end(), orderByChi2);
338 
339  new_states.insert(new_states.end(), next_states.begin(), next_states.end());
340  new_states.insert(new_states.end(), next_states_skipped.begin(), next_states_skipped.end());
341  } //end of state loop
342 
343  // copy new_states into prev_states for next iteration or end if we are on
344  // last iteration by clearing all states and making final state selection
345 
346  auto orderByMinSkipChi2 = [](const KalmanState *a, const KalmanState *b) {
347  return bool((a->chi2scaled()) * (a->nSkippedLayers() + 1) < (b->chi2scaled()) * (b->nSkippedLayers() + 1));
348  };
349  sort(new_states.begin(), new_states.end(), orderByMinSkipChi2); // Sort by chi2*(skippedLayers+1)
350 
351  unsigned int nStubs = iteration + 1;
352  // Success. We have at least one state that passes all cuts. Save best state found with this number of stubs.
353  if (nStubs >= settings_->kalmanMinNumStubs() && not new_states.empty())
354  best_state_by_nstubs[nStubs] = new_states[0];
355 
356  if (nStubs == settings_->kalmanMaxNumStubs()) {
357  // We're done.
358  prev_states.clear();
359  new_states.clear();
360  break;
361  } else {
362  // Continue iterating.
363  prev_states = new_states;
364  new_states.clear();
365  }
366  }
367 
368  if (not best_state_by_nstubs.empty()) {
369  // Select state with largest number of stubs.
370  finished_state = best_state_by_nstubs.begin()->second; // First element has largest number of stubs.
371  if (settings_->kalmanDebugLevel() >= 1) {
372  std::stringstream text;
373  text << std::fixed << std::setprecision(4);
374  text << "Track found! final state selection: nLay=" << finished_state->nStubLayers()
375  << " hitPattern=" << std::hex << finished_state->hitPattern() << std::dec
376  << " phiSec=" << l1track3D.iPhiSec() << " etaReg=" << l1track3D.iEtaReg() << " HT(m,c)=("
377  << l1track3D.cellLocationHT().first << "," << l1track3D.cellLocationHT().second << ")";
378  TVectorD y = trackParams(finished_state);
379  text << " q/pt=" << y[QOVERPT] << " tanL=" << y[T] << " z0=" << y[Z0] << " phi0=" << y[PHI0];
380  if (nHelixPar_ == 5)
381  text << " d0=" << y[D0];
382  text << " chosen from states:";
383  for (const auto &p : best_state_by_nstubs)
384  text << " " << p.second->chi2() << "/" << p.second->nStubLayers();
385  PrintL1trk() << text.str();
386  }
387  } else {
388  if (settings_->kalmanDebugLevel() >= 1) {
389  PrintL1trk() << "Track lost";
390  }
391  }
392 
393  return finished_state;
394  }
395 
396  /*--- Update a helix state by adding a stub. */
397 
399  unsigned nSkipped, unsigned int layer, Stub *stub, const KalmanState *state, const TP *tpa) {
400  if (settings_->kalmanDebugLevel() >= 4) {
401  PrintL1trk() << "---------------";
402  PrintL1trk() << "kalmanUpdate";
403  PrintL1trk() << "---------------";
404  printStub(stub);
405  }
406 
407  numUpdateCalls_++; // For monitoring, count calls to updator per track.
408 
409  // Helix params & their covariance.
410  TVectorD vecX = state->vectorX();
411  TMatrixD matC = state->matrixC();
412  if (state->barrel() && !stub->barrel()) {
413  if (settings_->kalmanDebugLevel() >= 4) {
414  PrintL1trk() << "STATE BARREL TO ENDCAP BEFORE ";
415  PrintL1trk() << "state : " << vecX[0] << " " << vecX[1] << " " << vecX[2] << " " << vecX[3];
416  PrintL1trk() << "cov(x): ";
417  matC.Print();
418  }
419  if (settings_->kalmanDebugLevel() >= 4) {
420  PrintL1trk() << "STATE BARREL TO ENDCAP AFTER ";
421  PrintL1trk() << "state : " << vecX[0] << " " << vecX[1] << " " << vecX[2] << " " << vecX[3];
422  PrintL1trk() << "cov(x): ";
423  matC.Print();
424  }
425  }
426  // Matrix to propagate helix reference point from one layer to next.
427  TMatrixD matF = matrixF(stub, state);
428  TMatrixD matFtrans(TMatrixD::kTransposed, matF);
429  if (settings_->kalmanDebugLevel() >= 4) {
430  PrintL1trk() << "matF";
431  matF.Print();
432  }
433 
434  // Multiply matrices to get helix params relative to reference point at next layer.
435  TVectorD vecXref = matF * vecX;
436  if (settings_->kalmanDebugLevel() >= 4) {
437  PrintL1trk() << "vecFref = [";
438  for (unsigned i = 0; i < nHelixPar_; i++)
439  PrintL1trk() << vecXref[i] << ", ";
440  PrintL1trk() << "]";
441  }
442 
443  // Get stub residuals.
444  TVectorD delta = residual(stub, vecXref, state->candidate().qOverPt());
445  if (settings_->kalmanDebugLevel() >= 4) {
446  PrintL1trk() << "delta = " << delta[0] << ", " << delta[1];
447  }
448 
449  // Derivative of predicted (phi,z) intercept with layer w.r.t. helix params.
450  TMatrixD matH = matrixH(stub);
451  if (settings_->kalmanDebugLevel() >= 4) {
452  PrintL1trk() << "matH";
453  matH.Print();
454  }
455 
456  if (settings_->kalmanDebugLevel() >= 4) {
457  PrintL1trk() << "previous state covariance";
458  matC.Print();
459  }
460  // Get scattering contribution to helix parameter covariance (currently zero).
461  TMatrixD matScat(nHelixPar_, nHelixPar_);
462 
463  // Get covariance on helix parameters at new reference point including scattering..
464  TMatrixD matCref = matF * matC * matFtrans + matScat;
465  if (settings_->kalmanDebugLevel() >= 4) {
466  PrintL1trk() << "matCref";
467  matCref.Print();
468  }
469  // Get hit position covariance matrix.
470  TMatrixD matV = matrixV(stub, state);
471  if (settings_->kalmanDebugLevel() >= 4) {
472  PrintL1trk() << "matV";
473  matV.Print();
474  }
475 
476  TMatrixD matRinv = matrixRinv(matH, matCref, matV);
477  if (settings_->kalmanDebugLevel() >= 4) {
478  PrintL1trk() << "matRinv";
479  matRinv.Print();
480  }
481 
482  // Calculate Kalman Gain matrix.
483  TMatrixD matK = getKalmanGainMatrix(matH, matCref, matRinv);
484  if (settings_->kalmanDebugLevel() >= 4) {
485  PrintL1trk() << "matK";
486  matK.Print();
487  }
488 
489  // Update helix state & its covariance matrix with new stub.
490  TVectorD new_vecX(nHelixPar_);
491  TMatrixD new_matC(nHelixPar_, nHelixPar_);
492  adjustState(matK, matCref, vecXref, matH, delta, new_vecX, new_matC);
493 
494  // Update track fit chi2 with new stub.
495  double new_chi2rphi = 0, new_chi2rz = 0;
496  this->adjustChi2(state, matRinv, delta, new_chi2rphi, new_chi2rz);
497 
498  if (settings_->kalmanDebugLevel() >= 4) {
499  if (nHelixPar_ == 4)
500  PrintL1trk() << "adjusted x = " << new_vecX[0] << ", " << new_vecX[1] << ", " << new_vecX[2] << ", "
501  << new_vecX[3];
502  else if (nHelixPar_ == 5)
503  PrintL1trk() << "adjusted x = " << new_vecX[0] << ", " << new_vecX[1] << ", " << new_vecX[2] << ", "
504  << new_vecX[3] << ", " << new_vecX[4];
505  PrintL1trk() << "adjusted C ";
506  new_matC.Print();
507  PrintL1trk() << "adjust chi2rphi=" << new_chi2rphi << " chi2rz=" << new_chi2rz;
508  }
509 
510  const KalmanState *new_state = mkState(
511  state->candidate(), nSkipped, layer, state, new_vecX, new_matC, matK, matV, stub, new_chi2rphi, new_chi2rz);
512 
513  return new_state;
514  }
515 
516  /* Create a KalmanState, containing a helix state & next stub it is to be updated with. */
517 
518  const KalmanState *KFbase::mkState(const L1track3D &candidate,
519  unsigned nSkipped,
520  unsigned layer,
521  const KalmanState *last_state,
522  const TVectorD &vecX,
523  const TMatrixD &matC,
524  const TMatrixD &matK,
525  const TMatrixD &matV,
526  Stub *stub,
527  double chi2rphi,
528  double chi2rz) {
529  auto new_state = std::make_unique<const KalmanState>(
530  settings_, candidate, nSkipped, layer, last_state, vecX, matC, matK, matV, stub, chi2rphi, chi2rz);
531 
532  const KalmanState *p_new_state = new_state.get();
533  listAllStates_.push_back(std::move(new_state)); // Vector keeps ownership of all states.
534  return p_new_state;
535  }
536 
537  /* Product of H*C*H(transpose) (where C = helix covariance matrix) */
538 
539  TMatrixD KFbase::matrixHCHt(const TMatrixD &matH, const TMatrixD &matC) const {
540  TMatrixD matHtrans(TMatrixD::kTransposed, matH);
541  return matH * matC * matHtrans;
542  }
543 
544  /* Get inverted Kalman R matrix: inverse(V + HCHt) */
545 
546  TMatrixD KFbase::matrixRinv(const TMatrixD &matH, const TMatrixD &matCref, const TMatrixD &matV) const {
547  TMatrixD matHCHt = matrixHCHt(matH, matCref);
548  TMatrixD matR = matV + matHCHt;
549  TMatrixD matRinv(2, 2);
550  if (matR.Determinant() > 0) {
551  matRinv = TMatrixD(TMatrixD::kInverted, matR);
552  } else {
553  // Protection against rare maths instability.
554  const TMatrixD unitMatrix(TMatrixD::kUnit, TMatrixD(2, 2));
555  const double big = 9.9e9;
556  matRinv = big * unitMatrix;
557  }
558  if (settings_->kalmanDebugLevel() >= 4) {
559  PrintL1trk() << "matHCHt";
560  matHCHt.Print();
561  PrintL1trk() << "matR";
562  matR.Print();
563  }
564  return matRinv;
565  }
566 
567  /* Determine Kalman gain matrix K */
568 
569  TMatrixD KFbase::getKalmanGainMatrix(const TMatrixD &matH, const TMatrixD &matCref, const TMatrixD &matRinv) const {
570  TMatrixD matHtrans(TMatrixD::kTransposed, matH);
571  TMatrixD matCrefht = matCref * matHtrans;
572  TMatrixD matK = matCrefht * matRinv;
573  return matK;
574  }
575 
576  /* Calculate stub residual w.r.t. helix */
577 
578  TVectorD KFbase::residual(const Stub *stub, const TVectorD &vecX, double candQoverPt) const {
579  TVectorD vd = vectorM(stub); // Get (phi relative to sector, z) of hit.
580  TMatrixD h = matrixH(stub);
581  TVectorD hx = h * vecX; // Get intercept of helix with layer (linear approx).
582  TVectorD delta = vd - hx;
583 
584  // Calculate higher order corrections to residuals.
585  // TO DO: Check if these could be determined using Tracklet/HT input track helix params,
586  // so only need applying at input to KF, instead of very iteration?
587 
588  if (not settings_->kalmanHOfw()) {
589  TVectorD correction(2);
590 
591  float inv2R = (settings_->invPtToInvR()) * 0.5 * candQoverPt;
592  float tanL = vecX[T];
593  float z0 = vecX[Z0];
594 
595  float deltaS = 0.;
596  if (settings_->kalmanHOhelixExp()) {
597  // Higher order correction correction to circle expansion for improved accuracy at low Pt.
598  double corr = stub->r() * inv2R;
599 
600  // N.B. In endcap 2S, this correction to correction[0] is exactly cancelled by the deltaS-dependent correction to it below.
601  correction[0] += (1. / 6.) * pow(corr, 3);
602 
603  deltaS = (1. / 6.) * (stub->r()) * pow(corr, 2);
604  correction[1] -= deltaS * tanL;
605 
606  if (nHelixPar_ == 5) {
607  float d0 = vecX[D0];
608  correction[0] += (1. / 6.) * pow(d0 / stub->r(), 3); // Division by r hard in FPGA?
609  }
610  }
611 
612  if ((not stub->barrel()) && not(stub->psModule())) {
613  // These corrections rely on inside --> outside tracking, so r-z track params in 2S modules known.
614  float rShift = (stub->z() - z0) / tanL - stub->r();
615 
617  rShift -= deltaS;
618 
619  if (settings_->kalmanHOprojZcorr() == 1) {
620  // Add correlation term related to conversion of stub residuals from (r,phi) to (z,phi).
621  correction[0] += inv2R * rShift;
622  }
623 
624  if (settings_->kalmanHOalpha() == 1) {
625  // Add alpha correction for non-radial 2S endcap strips..
626  correction[0] += stub->alpha() * rShift;
627  }
628  }
629 
630  // Apply correction to residuals.
631  delta += correction;
632  }
633 
634  delta[0] = reco::deltaPhi(delta[0], 0.);
635 
636  return delta;
637  }
638 
639  /* Update helix state & its covariance matrix with new stub */
640 
641  void KFbase::adjustState(const TMatrixD &matK,
642  const TMatrixD &matCref,
643  const TVectorD &vecXref,
644  const TMatrixD &matH,
645  const TVectorD &delta,
646  TVectorD &new_vecX,
647  TMatrixD &new_matC) const {
648  new_vecX = vecXref + matK * delta;
649  const TMatrixD unitMatrix(TMatrixD::kUnit, TMatrixD(nHelixPar_, nHelixPar_));
650  TMatrixD tmp = unitMatrix - matK * matH;
651  new_matC = tmp * matCref;
652  }
653 
654  /* Update track fit chi2 with new stub */
655 
657  const TMatrixD &matRinv,
658  const TVectorD &delta,
659  double &chi2rphi,
660  double &chi2rz) const {
661  // Change in chi2 (with r-phi/r-z correlation term included in r-phi component)
662  double delChi2rphi = delta[PHI] * delta[PHI] * matRinv[PHI][PHI] + 2 * delta[PHI] * delta[Z] * matRinv[PHI][Z];
663  double delChi2rz = delta[Z] * delta[Z] * matRinv[Z][Z];
664 
665  if (settings_->kalmanDebugLevel() >= 4) {
666  PrintL1trk() << "delta(chi2rphi)=" << delChi2rphi << " delta(chi2rz)= " << delChi2rz;
667  }
668  chi2rphi = state->chi2rphi() + delChi2rphi;
669  chi2rz = state->chi2rz() + delChi2rz;
670  return;
671  }
672 
673  /* Reset internal data ready for next track. */
674 
676 
677  /* Get Kalman layer mapping (i.e. layer order in which stubs should be processed) */
678 
679  unsigned int KFbase::kalmanLayer(
680  unsigned int iEtaReg, unsigned int layerIDreduced, bool barrel, float r, float z) const {
681  if (nEta_ != numEtaRegions_)
682  throw cms::Exception("LogicError")
683  << "ERROR KFbase::getKalmanLayer hardwired value of nEta_ differs from NumEtaRegions cfg param";
684 
685  unsigned int kfEtaReg; // KF VHDL eta sector def: small in barrel & large in endcap.
686  if (iEtaReg < numEtaRegions_ / 2) {
687  kfEtaReg = numEtaRegions_ / 2 - 1 - iEtaReg;
688  } else {
689  kfEtaReg = iEtaReg - numEtaRegions_ / 2;
690  }
691 
692  unsigned int kalmanLay =
693  barrel ? layerMap_[kfEtaReg][layerIDreduced].first : layerMap_[kfEtaReg][layerIDreduced].second;
694 
695  // Switch back to the layermap that is consistent with current FW when "maybe layer" is not used
696  if (not settings_->kfUseMaybeLayers()) {
697  switch (kfEtaReg) {
698  case 6: //case 6: B1 B2+D1 D2 D3 D4 D5
699  if (layerIDreduced > 2) {
700  kalmanLay--;
701  }
702  break;
703  default:
704  break;
705  }
706  }
707 
708  /*
709  // Fix cases where a barrel layer only partially crosses the eta sector.
710  // (Logically should work, but actually reduces efficiency -- INVESTIGATE).
711 
712  const float barrelHalfLength = 120.;
713  const float barrel4Radius = 68.8;
714  const float barrel5Radius = 86.1;
715 
716  if ( not barrel) {
717  switch ( kfEtaReg ) {
718  case 4:
719  if (layerIDreduced==3) { // D1
720  float disk1_rCut = barrel5Radius*(std::abs(z)/barrelHalfLength);
721  if (r > disk1_rCut) kalmanLay++;
722  }
723  break;
724  case 5:
725  if (layerIDreduced==3) { // D1
726  float disk1_rCut = barrel4Radius*(std::abs(z)/barrelHalfLength);
727  if (r > disk1_rCut) kalmanLay++;
728  }
729  if (layerIDreduced==4) { // D2
730  float disk2_rCut = barrel4Radius*(std::abs(z)/barrelHalfLength);
731  if (r > disk2_rCut) kalmanLay++;
732  }
733  break;
734  default:
735  break;
736  }
737  }
738  */
739 
740  return kalmanLay;
741  }
742 
743  /*=== Check if particles in given eta sector are uncertain to go through the given KF layer. */
744  /*=== (If so, count layer for numbers of hit layers, but not for number of skipped layers). */
745 
746  bool KFbase::kalmanAmbiguousLayer(unsigned int iEtaReg, unsigned int kfLayer) {
747  // Only helps in extreme forward sector, and there not significantly.
748  // UNDERSTAND IF CAN BE USED ELSEWHERE.
749 
750  constexpr bool ambiguityMap[nEta_ / 2][nKFlayer_] = {
751  {false, false, false, false, false, false, false},
752  {false, false, false, false, false, false, false},
753  {false, false, false, false, false, false, false},
754  {false, false, false, false, false, false, false},
755  {false, false, false, false, false, false, false},
756  {false, false, true, false, false, false, false},
757  {true, true, false, false, false, false, false},
758  {true, false, false, false, false, false, false},
759  };
760 
761  unsigned int kfEtaReg; // KF VHDL eta sector def: small in barrel & large in endcap.
762  if (iEtaReg < numEtaRegions_ / 2) {
763  kfEtaReg = numEtaRegions_ / 2 - 1 - iEtaReg;
764  } else {
765  kfEtaReg = iEtaReg - numEtaRegions_ / 2;
766  }
767 
768  bool ambiguous = false;
769  if (settings_->kfUseMaybeLayers() && kfLayer < nKFlayer_)
770  ambiguous = ambiguityMap[kfEtaReg][kfLayer];
771 
772  return ambiguous;
773  }
774 
775  /* Adjust KF algorithm to allow for any dead tracker layers */
776 
777  set<unsigned> KFbase::kalmanDeadLayers(bool &remove2PSCut) const {
778  // Kill scenarios described StubKiller.cc
779 
780  // By which Stress Test scenario (if any) are dead modules being emulated?
781  const StubKiller::KillOptions killScenario = static_cast<StubKiller::KillOptions>(settings_->killScenario());
782  // Should TMTT tracking be modified to reduce efficiency loss due to dead modules?
783  const bool killRecover = settings_->killRecover();
784 
785  set<pair<unsigned, bool>> deadGPlayers; // GP layer ID & boolean indicating if in barrel.
786 
787  // Range of sectors chosen to cover dead regions from StubKiller.
788  if (killRecover) {
789  if (killScenario == StubKiller::KillOptions::layer5) { // barrel layer 5
790  if (iEtaReg_ >= 3 && iEtaReg_ <= 7 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
791  deadGPlayers.insert(pair<unsigned, bool>(4, true));
792  }
793  } else if (killScenario == StubKiller::KillOptions::layer1) { // barrel layer 1
794  if (iEtaReg_ <= 7 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
795  deadGPlayers.insert(pair<unsigned, bool>(1, true));
796  }
797  remove2PSCut = true;
798  } else if (killScenario == StubKiller::KillOptions::layer1layer2) { // barrel layers 1 & 2
799  if (iEtaReg_ <= 7 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
800  deadGPlayers.insert(pair<unsigned, bool>(1, true));
801  }
802  if (iEtaReg_ >= 1 && iEtaReg_ <= 7 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
803  deadGPlayers.insert(pair<unsigned, bool>(2, true));
804  }
805  remove2PSCut = true;
806  } else if (killScenario == StubKiller::KillOptions::layer1disk1) { // barrel layer 1 & disk 1
807  if (iEtaReg_ <= 7 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
808  deadGPlayers.insert(pair<unsigned, bool>(1, true));
809  }
810  if (iEtaReg_ <= 3 && iPhiSec_ >= 1 && iPhiSec_ <= 5) {
811  deadGPlayers.insert(pair<unsigned, bool>(3, false));
812  }
813  remove2PSCut = true;
814  }
815  }
816 
817  set<unsigned> kfDeadLayers;
818  for (const auto &p : deadGPlayers) {
819  unsigned int layer = p.first;
820  bool barrel = p.second;
821  float r = 0.; // This fails for r-dependent parts of kalmanLayer(). FIX
822  float z = 999.;
823  unsigned int kalmanLay = this->kalmanLayer(iEtaReg_, layer, barrel, r, z);
824  kfDeadLayers.insert(kalmanLay);
825  }
826 
827  return kfDeadLayers;
828  }
829 
830  //=== Function to calculate approximation for tilted barrel modules (aka B) copied from Stub class.
831 
832  float KFbase::approxB(float z, float r) const {
834  }
835 
836  /* Print truth particle */
837 
838  void KFbase::printTP(const TP *tp) const {
839  TVectorD tpParams(5);
840  bool useForAlgEff(false);
841  if (tp) {
842  useForAlgEff = tp->useForAlgEff();
843  tpParams[QOVERPT] = tp->qOverPt();
844  tpParams[PHI0] = tp->phi0();
845  tpParams[Z0] = tp->z0();
846  tpParams[T] = tp->tanLambda();
847  tpParams[D0] = tp->d0();
848  }
849  std::stringstream text;
850  text << std::fixed << std::setprecision(4);
851  if (tp) {
852  text << " TP index = " << tp->index() << " useForAlgEff = " << useForAlgEff << " ";
853  const string helixNames[5] = {"qOverPt", "phi0", "z0", "tanL", "d0"};
854  for (int i = 0; i < tpParams.GetNrows(); i++) {
855  text << helixNames[i] << ":" << tpParams[i] << ", ";
856  }
857  text << " inv2R = " << tp->qOverPt() * settings_->invPtToInvR() * 0.5;
858  } else {
859  text << " Fake";
860  }
861  PrintL1trk() << text.str();
862  }
863 
864  /* Print tracker layers with stubs */
865 
866  void KFbase::printStubLayers(const vector<Stub *> &stubs, unsigned int iEtaReg) const {
867  std::stringstream text;
868  text << std::fixed << std::setprecision(4);
869  if (stubs.empty())
870  text << "stub layers = []\n";
871  else {
872  text << "stub layers = [ ";
873  for (unsigned i = 0; i < stubs.size(); i++) {
874  text << stubs[i]->layerId();
875  if (i != stubs.size() - 1)
876  text << ", ";
877  }
878  text << " ] ";
879  text << "KF stub layers = [ ";
880  for (unsigned j = 0; j < stubs.size(); j++) {
881  unsigned int kalmanLay =
882  this->kalmanLayer(iEtaReg, stubs[j]->layerIdReduced(), stubs[j]->barrel(), stubs[j]->r(), stubs[j]->z());
883  text << kalmanLay;
884  if (j != stubs.size() - 1)
885  text << ", ";
886  }
887  text << " ]\n";
888  }
889  PrintL1trk() << text.str();
890  }
891 
892  /* Print a stub */
893 
894  void KFbase::printStub(const Stub *stub) const {
895  std::stringstream text;
896  text << std::fixed << std::setprecision(4);
897  text << "stub ";
898  text << "index=" << stub->index() << " ";
899  text << "layerId=" << stub->layerId() << " ";
900  text << "r=" << stub->r() << " ";
901  text << "phi=" << stub->phi() << " ";
902  text << "z=" << stub->z() << " ";
903  text << "sigmaX=" << stub->sigmaPerp() << " ";
904  text << "sigmaZ=" << stub->sigmaPar() << " ";
905  text << "TPids=";
906  std::set<const TP *> tps = stub->assocTPs();
907  for (auto tp : tps)
908  text << tp->index() << ",";
909  PrintL1trk() << text.str();
910  }
911 
912  /* Print all stubs */
913 
914  void KFbase::printStubs(const vector<Stub *> &stubs) const {
915  for (auto &stub : stubs) {
916  printStub(stub);
917  }
918  }
919 
920 } // namespace tmtt
unsigned int kalmanMaxStubsPerLayer() const
Definition: Settings.h:322
unsigned int iEtaReg() const override
Definition: L1track3D.h:175
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
bool kalmanHOhelixExp() const
Definition: Settings.h:331
static constexpr std::pair< unsigned, unsigned > layerMap_[nEta_/2][nGPlayer_+1]
Definition: KFbase.h:61
unsigned int layerId() const
Definition: Stub.h:198
float phi0() const override
Definition: L1track3D.h:158
unsigned nextLayer() const
Definition: KalmanState.h:39
bool enableDigitize() const
Definition: Settings.h:80
float r() const
Definition: Stub.h:108
unsigned nSkippedLayers() const
Definition: KalmanState.h:43
unsigned int kalmanHOalpha() const
Definition: Settings.h:333
const Settings * settings() const
Definition: KalmanState.h:37
float qOverPt() const override
Definition: L1track3D.h:149
unsigned numEtaRegions_
Definition: KFbase.h:176
double bApprox_intercept() const
Definition: Settings.h:105
void printStubLayers(const std::vector< Stub *> &stubs, unsigned int iEtaReg) const
Definition: KFbase.cc:866
void adjustState(const TMatrixD &K, const TMatrixD &pxcov, const TVectorD &x, const TMatrixD &h, const TVectorD &delta, TVectorD &new_x, TMatrixD &new_xcov) const
Definition: KFbase.cc:641
void printTP(const TP *tp) const
Definition: KFbase.cc:838
virtual unsigned int kalmanLayer(unsigned int iEtaReg, unsigned int layerIDreduced, bool barrel, float r, float z) const
Definition: KFbase.cc:679
const TP * matchedTP() const override
Definition: L1track3D.h:186
float z0() const
Definition: L1track3D.h:159
void printStubs(const std::vector< Stub *> &stubs) const
Definition: KFbase.cc:914
unsigned int killScenario() const
Definition: Settings.h:343
L1fittedTrack fit(const L1track3D &l1track3D) override
Definition: KFbase.cc:38
float alpha() const
Definition: Stub.h:119
bool kalmanRemove2PScut() const
Definition: Settings.h:305
std::set< unsigned > kalmanDeadLayers(bool &remove2PSCut) const
Definition: KFbase.cc:777
float approxB(float z, float r) const
Definition: KFbase.cc:832
static const unsigned int nEta_
Definition: KFbase.h:52
const std::vector< Stub * > & stubs() const override
Definition: L1track3D.h:95
float pt() const
Definition: L1track3D.h:153
unsigned int kalmanMaxStubsEasy() const
Definition: Settings.h:310
std::pair< unsigned int, unsigned int > cellLocationHT() const override
Definition: L1track3D.h:101
float z() const
Definition: Stub.h:109
unsigned int numEtaRegions() const
Definition: Settings.h:125
unsigned int iEtaReg_
Definition: KFbase.h:179
float tanLambda() const
Definition: L1track3D.h:160
virtual TVectorD trackParams(const KalmanState *state) const =0
bool killRecover() const
Definition: Settings.h:345
unsigned int index() const
Definition: Stub.h:101
unsigned nStubLayers() const
Definition: KalmanState.h:65
unsigned kalmanDebugLevel() const
Definition: Settings.h:297
unsigned int iPhiSec() const override
Definition: L1track3D.h:174
const KalmanState * mkState(const L1track3D &candidate, unsigned nSkipped, unsigned layer, const KalmanState *last_state, const TVectorD &x, const TMatrixD &pxx, const TMatrixD &K, const TMatrixD &dcov, Stub *stub, double chi2rphi, double chi2rz)
Definition: KFbase.cc:518
Definition: TP.h:23
dictionary corr
virtual const KalmanState * kalmanUpdate(unsigned nSkipped, unsigned layer, Stub *stub, const KalmanState *state, const TP *tp)
Definition: KFbase.cc:398
bool goodTrack(const reco::Track *pTrack, math::XYZPoint leadPV, trackSelectionParameters parameters, bool debug=false)
bool kalmanAddBeamConstr() const
Definition: Settings.h:303
static const unsigned int nKFlayer_
Definition: KFbase.h:51
virtual bool kalmanAmbiguousLayer(unsigned int iEtaReg, unsigned int kfLayer)
Definition: KFbase.cc:746
virtual TMatrixD matrixV(const Stub *stub, const KalmanState *state) const =0
const TP * tpa_
Definition: KFbase.h:186
static constexpr unsigned int invalidKFlayer_
Definition: KFbase.h:54
float sigmaPerp() const
Definition: Stub.h:189
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
virtual TVectorD seedX(const L1track3D &l1track3D) const =0
const KalmanState * doKF(const L1track3D &l1track3D, const std::vector< Stub *> &stubs, const TP *tpa)
Definition: KFbase.cc:174
const Settings * settings_
void resetStates()
Definition: KFbase.cc:675
void printStub(const Stub *stub) const
Definition: KFbase.cc:894
double bApprox_gradient() const
Definition: Settings.h:104
bool barrel() const
Definition: Stub.h:201
unsigned int kalmanMinNumStubs() const
Definition: Settings.h:299
virtual TMatrixD seedC(const L1track3D &l1track3D) const =0
std::vector< DeviationSensor2D * > vd
unsigned int kalmanMaxSkipLayersEasy() const
Definition: Settings.h:308
virtual TMatrixD matrixH(const Stub *stub) const =0
TMatrixD matrixHCHt(const TMatrixD &h, const TMatrixD &c) const
Definition: KFbase.cc:539
float phi() const
Definition: Stub.h:107
virtual TVectorD trackParams_BeamConstr(const KalmanState *state, double &chi2rphi_bcon) const =0
virtual TVectorD residual(const Stub *stub, const TVectorD &x, double candQoverPt) const
Definition: KFbase.cc:578
unsigned int kalmanMaxNumStubs() const
Definition: Settings.h:301
static constexpr float d0
void setInfoKF(unsigned int nSkippedLayers, unsigned int numUpdateCalls)
TMatrixD matrixRinv(const TMatrixD &matH, const TMatrixD &matCref, const TMatrixD &matV) const
Definition: KFbase.cc:546
bool kalmanHOfw() const
Definition: Settings.h:337
TMatrixD getKalmanGainMatrix(const TMatrixD &h, const TMatrixD &pxcov, const TMatrixD &covRinv) const
Definition: KFbase.cc:569
=== This is the base class for the linearised chi-squared track fit algorithms.
Definition: Array2D.h:16
unsigned int kalmanMaxSkipLayersHard() const
Definition: Settings.h:307
const std::set< const TP * > & assocTPs() const
Definition: Stub.h:164
virtual bool isGoodState(const KalmanState &state) const =0
double b
Definition: hdecay.h:120
unsigned int numUpdateCalls_
Definition: KFbase.h:181
unsigned nHelixPar_
Definition: KFbase.h:174
double a
Definition: hdecay.h:121
Definition: big.h:8
bool hybrid() const
Definition: Settings.h:409
unsigned int numStubs() const override
Definition: L1track3D.h:97
unsigned int iPhiSec_
Definition: KFbase.h:178
unsigned int kalmanHOprojZcorr() const
Definition: Settings.h:335
unsigned int kalmanChi2RphiScale() const
Definition: Settings.h:326
float d0() const
Definition: L1track3D.h:157
virtual TVectorD vectorM(const Stub *stub) const =0
const std::vector< double > & kfLayerVsChiSq5() const
Definition: Settings.h:319
std::vector< std::unique_ptr< const KalmanState > > listAllStates_
Definition: KFbase.h:184
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
tmp
align.sh
Definition: createJobs.py:716
unsigned int hitPattern() const
Definition: KalmanState.h:66
float sigmaPar() const
Definition: Stub.h:191
bool psModule() const
Definition: Stub.h:196
virtual TMatrixD matrixF(const Stub *stub=nullptr, const KalmanState *state=nullptr) const =0
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
def move(src, dest)
Definition: eostools.py:511
bool kfUseMaybeLayers() const
Definition: Settings.h:312
virtual void adjustChi2(const KalmanState *state, const TMatrixD &covRinv, const TVectorD &delta, double &chi2rphi, double &chi2rz) const
Definition: KFbase.cc:656
double invPtToInvR() const
Definition: Settings.h:395