Belle II Software  light-2303-iriomote
TrackVariables.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 // Own header.
10 #include <analysis/variables/TrackVariables.h>
11 
12 // include VariableManager
13 #include <analysis/VariableManager/Manager.h>
14 
15 #include <analysis/dataobjects/Particle.h>
16 #include <analysis/utility/DetectorSurface.h>
17 
18 // framework - DataStore
19 #include <framework/datastore/StoreObjPtr.h>
20 #include <framework/dataobjects/Helix.h>
21 
22 // dataobjects from the MDST
23 #include <mdst/dataobjects/Track.h>
24 #include <mdst/dataobjects/MCParticle.h>
25 #include <mdst/dataobjects/TrackFitResult.h>
26 #include <mdst/dataobjects/EventLevelTrackingInfo.h>
27 #include <mdst/dataobjects/HitPatternVXD.h>
28 #include <mdst/dataobjects/ECLCluster.h>
29 
30 // framework aux
31 #include <framework/logging/Logger.h>
32 
33 #include <cmath>
34 
35 namespace Belle2 {
40  namespace Variable {
41 
42  static const double realNaN = std::numeric_limits<double>::quiet_NaN();
43  static const B2Vector3D vecNaN(realNaN, realNaN, realNaN);
44 
45  double trackNHits(const Particle* part, const Const::EDetector& det)
46  {
47  auto trackFit = part->getTrackFitResult();
48  if (!trackFit) return realNaN;
49 
50  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
51  // Then, we have to take the detour via the related track to access the number of track hits.
52  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
53  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
54  }
55  if (det == Const::EDetector::CDC) {
56  return trackFit->getHitPatternCDC().getNHits();
57  } else if (det == Const::EDetector::SVD) {
58  return trackFit->getHitPatternVXD().getNSVDHits();
59  } else if (det == Const::EDetector::PXD) {
60  return trackFit->getHitPatternVXD().getNPXDHits();
61  } else {
62  return realNaN;
63  }
64  }
65 
66  double trackNCDCHits(const Particle* part)
67  {
68  return trackNHits(part, Const::EDetector::CDC);
69  }
70 
71  double trackNSVDHits(const Particle* part)
72  {
73  return trackNHits(part, Const::EDetector::SVD);
74  }
75 
76  double trackNPXDHits(const Particle* part)
77  {
78  return trackNHits(part, Const::EDetector::PXD);
79  }
80 
81  double trackNVXDHits(const Particle* part)
82  {
83  return trackNPXDHits(part) + trackNSVDHits(part);
84  }
85 
86  double trackNDF(const Particle* part)
87  {
88  auto trackFit = part->getTrackFitResult();
89  if (!trackFit) return realNaN;
90  return trackFit->getNDF();
91  }
92 
93  double trackChi2(const Particle* part)
94  {
95  auto trackFit = part->getTrackFitResult();
96  if (!trackFit) return realNaN;
97  return trackFit->getChi2();
98  }
99 
100  double trackFirstSVDLayer(const Particle* part)
101  {
102  auto trackFit = part->getTrackFitResult();
103  if (!trackFit) return realNaN;
104  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
105  // Then, we have to take the detour via the related track to access the real pattern and get the first SVD layer if available.
106  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
107  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
108  }
109  return trackFit->getHitPatternVXD().getFirstSVDLayer();
110  }
111 
112  double trackFirstPXDLayer(const Particle* part)
113  {
114  auto trackFit = part->getTrackFitResult();
115  if (!trackFit) return realNaN;
116  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
117  // Then, we have to take the detour via the related track to access the real pattern and get the first PXD layer if available.
118  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
119  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
120  }
121  return trackFit->getHitPatternVXD().getFirstPXDLayer(HitPatternVXD::PXDMode::normal);
122  }
123 
124  double trackFirstCDCLayer(const Particle* part)
125  {
126  auto trackFit = part->getTrackFitResult();
127  if (!trackFit) return realNaN;
128  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
129  // Then, we have to take the detour via the related track to access the real pattern and get the first CDC layer if available.
130  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
131  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
132  }
133  return trackFit->getHitPatternCDC().getFirstLayer();
134  }
135 
136  double trackLastCDCLayer(const Particle* part)
137  {
138  auto trackFit = part->getTrackFitResult();
139  if (!trackFit) return realNaN;
140  // Before release-05 (MC13 + proc 11 and older) the hit patterns of TrackFitResults for V0s from the V0Finder were set to 0.
141  // Then, we have to take the detour via the related track to access the real pattern and get the last CDC layer if available.
142  if (trackFit->getHitPatternCDC().getNHits() + trackFit->getHitPatternVXD().getNdf() < 1) {
143  trackFit = part->getTrack()->getTrackFitResultWithClosestMass(Const::ChargedStable(std::abs(part->getPDGCode())));
144  }
145  return trackFit->getHitPatternCDC().getLastLayer();
146  }
147 
148  double trackD0(const Particle* part)
149  {
150  auto trackFit = part->getTrackFitResult();
151  if (!trackFit) return realNaN;
152  return trackFit->getD0();
153  }
154 
155  double trackPhi0(const Particle* part)
156  {
157  auto trackFit = part->getTrackFitResult();
158  if (!trackFit) return realNaN;
159  return trackFit->getPhi0();
160  }
161 
162  double trackOmega(const Particle* part)
163  {
164  auto trackFit = part->getTrackFitResult();
165  if (!trackFit) return realNaN;
166  return trackFit->getOmega();
167  }
168 
169  double trackZ0(const Particle* part)
170  {
171  auto trackFit = part->getTrackFitResult();
172  if (!trackFit) return realNaN;
173  return trackFit->getZ0();
174  }
175 
176  double trackTanLambda(const Particle* part)
177  {
178  auto trackFit = part->getTrackFitResult();
179  if (!trackFit) return realNaN;
180  return trackFit->getTanLambda();
181  }
182 
183  double trackD0Error(const Particle* part)
184  {
185  auto trackFit = part->getTrackFitResult();
186  if (!trackFit) return realNaN;
187 
188  double errorSquared = trackFit->getCovariance5()[0][0];
189  if (errorSquared <= 0) return realNaN;
190  return sqrt(errorSquared);
191  }
192 
193  double trackPhi0Error(const Particle* part)
194  {
195  auto trackFit = part->getTrackFitResult();
196  if (!trackFit) return realNaN;
197 
198  double errorSquared = trackFit->getCovariance5()[1][1];
199  if (errorSquared <= 0) return realNaN;
200  return sqrt(errorSquared);
201  }
202 
203  double trackOmegaError(const Particle* part)
204  {
205  auto trackFit = part->getTrackFitResult();
206  if (!trackFit) return realNaN;
207 
208  double errorSquared = trackFit->getCovariance5()[2][2];
209  if (errorSquared <= 0) return realNaN;
210  return sqrt(errorSquared);
211  }
212 
213  double trackZ0Error(const Particle* part)
214  {
215  auto trackFit = part->getTrackFitResult();
216  if (!trackFit) return realNaN;
217 
218  double errorSquared = trackFit->getCovariance5()[3][3];
219  if (errorSquared <= 0) return realNaN;
220  return sqrt(errorSquared);
221  }
222 
223  double trackTanLambdaError(const Particle* part)
224  {
225  auto trackFit = part->getTrackFitResult();
226  if (!trackFit) return realNaN;
227 
228  double errorSquared = trackFit->getCovariance5()[4][4];
229  if (errorSquared <= 0) return realNaN;
230  return sqrt(errorSquared);
231  }
232 
233  double trackFitCovariance(const Particle* particle, const std::vector<double>& indices)
234  {
235  if (indices.size() != 2) {
236  B2FATAL("Exactly two indices must be provided to the variable trackFitCovariance!");
237  }
238  if (*(std::min_element(indices.begin(), indices.end())) < 0 or *(std::max_element(indices.begin(), indices.end())) > 4) {
239  B2FATAL("The indices provided to the variable trackFitCovariance must be in the range 0 - 4!");
240  }
241  auto trackFit = particle->getTrackFitResult();
242  if (!trackFit) return realNaN;
243  return trackFit->getCovariance5()[indices[0]][indices[1]];
244  }
245 
246  double trackPValue(const Particle* part)
247  {
248  auto trackFit = part->getTrackFitResult();
249  if (!trackFit) return realNaN;
250  return trackFit->getPValue();
251  }
252 
253  double trackFitHypothesisPDG(const Particle* part)
254  {
255  auto trackFit = part->getTrackFitResult();
256  if (!trackFit) return realNaN;
257  return trackFit->getParticleType().getPDGCode();
258  }
259 
260  double trackNECLClusters(const Particle* part)
261  {
262  const Track* track = part->getTrack();
263  if (!track) return realNaN;
264 
265  // count the number of nPhotons hypothesis ecl clusters
266  int count = 0;
267  for (const ECLCluster& cluster : track->getRelationsTo<ECLCluster>())
268  if (cluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
269  ++count;
270  return count;
271  }
272 
273  // used in trackHelixExtTheta and trackHelixExtPhi
274  B2Vector3D getPositionOnHelix(const TrackFitResult* trackFit, const std::vector<double>& pars)
275  {
276  const double r = pars[0];
277  const double zfwd = pars[1];
278  const double zbwd = pars[2];
279 
280  // get helix and parameters
281  const double z0 = trackFit->getZ0();
282  const double tanlambda = trackFit->getTanLambda();
283  const Helix h = trackFit->getHelix();
284 
285  // extrapolate to radius
286  const double arcLength = h.getArcLength2DAtCylindricalR(r);
287  const double lHelixRadius = arcLength > 0 ? arcLength : std::numeric_limits<double>::max();
288 
289  // extrapolate to FWD z
290  const double lFWD = (zfwd - z0) / tanlambda > 0 ? (zfwd - z0) / tanlambda : std::numeric_limits<double>::max();
291 
292  // extrapolate to BWD z
293  const double lBWD = (zbwd - z0) / tanlambda > 0 ? (zbwd - z0) / tanlambda : std::numeric_limits<double>::max();
294 
295  // pick smallest arclength
296  const double l = std::min({lHelixRadius, lFWD, lBWD});
297 
298  return h.getPositionAtArcLength2D(l);
299  }
300 
301  B2Vector3D getPositionOnHelix(const Particle* part, const std::vector<double>& pars)
302  {
303  if (pars.size() == 4 and pars[3]) {
304  const Track* track = part->getTrack();
305  if (!track)
306  return vecNaN;
307 
308  auto highestProbMass = part->getMostLikelyTrackFitResult().first;
309  const TrackFitResult* trackFit = track->getTrackFitResultWithClosestMass(highestProbMass);
310  return getPositionOnHelix(trackFit, pars);
311  } else {
312  const TrackFitResult* trackFit = part->getTrackFitResult();
313  return getPositionOnHelix(trackFit, pars);
314  }
315  }
316 
317  // returns extrapolated theta position based on helix parameters
318  double trackHelixExtTheta(const Particle* part, const std::vector<double>& pars)
319  {
320  const auto nParams = pars.size();
321  if (nParams != 3 && nParams != 4) {
322  B2FATAL("Exactly three (+1 optional) parameters (r, zfwd, zbwd, [useHighestProbMass]) required for helixExtTheta.");
323  }
324 
325  B2Vector3D position = getPositionOnHelix(part, pars);
326  if (position == vecNaN) return realNaN;
327  return position.Theta();
328  }
329 
330  // returns extrapolated phi position based on helix parameters
331  double trackHelixExtPhi(const Particle* part, const std::vector<double>& pars)
332  {
333  const auto nParams = pars.size();
334  if (nParams != 3 && nParams != 4) {
335  B2FATAL("Exactly three (+1 optional) parameters (r, zfwd, zbwd, [useHighestProbMass]) required for helixExtPhi.");
336  }
337 
338  B2Vector3D position = getPositionOnHelix(part, pars);
339  if (position == vecNaN) return realNaN;
340  return position.Phi();
341  }
342 
343  Manager::FunctionPtr trackHelixExtThetaOnDet(const std::vector<std::string>& arguments)
344  {
345  if (arguments.size() != 1 && arguments.size() != 2)
346  B2FATAL("Exactly one (+1 optional) parameter (detector_surface_name, [useHighestProbMass]) is required for helixExtThetaOnDet.");
347 
348  std::vector<double> parameters(3);
349  const std::string det = arguments[0];
351  parameters[0] = DetectorSurface::detToSurfBoundaries.at(det).m_rho;
352  parameters[1] = DetectorSurface::detToSurfBoundaries.at(det).m_zfwd;
353  parameters[2] = DetectorSurface::detToSurfBoundaries.at(det).m_zbwd;
355  parameters[0] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_rho;
356  parameters[1] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zfwd;
357  parameters[2] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zbwd;
358  } else
359  B2FATAL("Given detector surface name is not supported.");
360 
361  if (arguments.size() == 2)
362  parameters.push_back(std::stod(arguments[1]));
363 
364  auto func = [parameters](const Particle * part) -> double {
365 
366  B2Vector3D position = getPositionOnHelix(part, parameters);
367  if (position == vecNaN) return realNaN;
368  return position.Theta();
369  };
370  return func;
371  }
372 
373  Manager::FunctionPtr trackHelixExtPhiOnDet(const std::vector<std::string>& arguments)
374  {
375  if (arguments.size() != 1 && arguments.size() != 2)
376  B2FATAL("Exactly one (+1 optional) parameter (detector_surface_name, [useHighestProbMass]) is required for helixExtPhiOnDet.");
377 
378  std::vector<double> parameters(3);
379  const std::string det = arguments[0];
381  parameters[0] = DetectorSurface::detToSurfBoundaries.at(det).m_rho;
382  parameters[1] = DetectorSurface::detToSurfBoundaries.at(det).m_zfwd;
383  parameters[2] = DetectorSurface::detToSurfBoundaries.at(det).m_zbwd;
385  parameters[0] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_rho;
386  parameters[1] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zfwd;
387  parameters[2] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zbwd;
388  } else
389  B2FATAL("Given detector surface name is not supported.");
390 
391  if (arguments.size() == 2)
392  parameters.push_back(std::stod(arguments[1]));
393 
394  auto func = [parameters](const Particle * part) -> double {
395 
396  B2Vector3D position = getPositionOnHelix(part, parameters);
397  if (position == vecNaN) return realNaN;
398  return position.Phi();
399  };
400  return func;
401  }
402 
403 
404  /***************************************************
405  * Event level tracking quantities
406  */
407 
408  // The number of CDC hits in the event not assigned to any track
409  double nExtraCDCHits(const Particle*)
410  {
411  StoreObjPtr<EventLevelTrackingInfo> elti;
412  if (!elti) return realNaN;
413  return elti->getNCDCHitsNotAssigned();
414  }
415 
416  // The number of CDC hits in the event not assigned to any track nor very
417  // likely beam background (i.e. hits that survive a cleanup selection)
418  double nExtraCDCHitsPostCleaning(const Particle*)
419  {
420  StoreObjPtr<EventLevelTrackingInfo> elti;
421  if (!elti) return realNaN;
422  return elti->getNCDCHitsNotAssignedPostCleaning();
423  }
424 
425  // Check for the presence of a non-assigned hit in the specified CDC layer
426  double hasExtraCDCHitsInLayer(const Particle*, const std::vector<double>& layer)
427  {
428  StoreObjPtr<EventLevelTrackingInfo> elti;
429  if (!elti) return realNaN;
430  int ilayer = std::lround(layer[0]);
431  return elti->hasCDCLayer(ilayer);
432  }
433 
434  // Check for the presence of a non-assigned hit in the specified CDC SuperLayer
435  double hasExtraCDCHitsInSuperLayer(const Particle*, const std::vector<double>& layer)
436  {
437  StoreObjPtr<EventLevelTrackingInfo> elti;
438  if (!elti) return realNaN;
439  int ilayer = std::lround(layer[0]);
440  return elti->hasCDCSLayer(ilayer);
441  }
442 
443  // The number of segments that couldn't be assigned to any track
444  double nExtraCDCSegments(const Particle*)
445  {
446  StoreObjPtr<EventLevelTrackingInfo> elti;
447  if (!elti) return realNaN;
448  return elti->getNCDCSegments();
449  }
450 
451  // The number of VXD hits not assigned to any track in the specified layer
452  double nExtraVXDHitsInLayer(const Particle*, const std::vector<double>& layer)
453  {
454  StoreObjPtr<EventLevelTrackingInfo> elti;
455  if (!elti) return realNaN;
456  int ilayer = std::lround(layer[0]);
457  return elti->getNVXDClustersInLayer(ilayer);
458  }
459 
460  // The number of VXD hits not assigned to any track
461  double nExtraVXDHits(const Particle*)
462  {
463  StoreObjPtr<EventLevelTrackingInfo> elti;
464  if (!elti) return realNaN;
465  double out = 0.0;
466  for (uint16_t ilayer = 1; ilayer < 7; ++ilayer)
467  out += elti->getNVXDClustersInLayer(ilayer);
468  return out;
469  }
470 
471  // time of first SVD sample relative to event T0
472  double svdFirstSampleTime(const Particle*)
473  {
474  StoreObjPtr<EventLevelTrackingInfo> elti;
475  if (!elti) return realNaN;
476  return elti->getSVDFirstSampleTime();
477  }
478 
479  // A flag set by the tracking if there is reason to assume there was a track
480  // in the event missed by the tracking or the track finding was (partly) aborted
481  // for this event. Further information about this can be obtained from the flagBlock
482  // of the EventLevelTrackingInfo object.
483  double trackFindingFailureFlag(const Particle*)
484  {
485  StoreObjPtr<EventLevelTrackingInfo> elti;
486  if (!elti) return realNaN;
487  return elti->hasAnErrorFlag();
488  }
489 
490  double getHelixParameterPullAtIndex(const Particle* particle, const int index)
491  {
492  if (!particle) return realNaN;
493 
494  const MCParticle* mcparticle = particle->getMCParticle();
495  if (!mcparticle) return realNaN;
496 
497  const Belle2::TrackFitResult* trackfit = particle->getTrackFitResult();
498  if (!trackfit) return realNaN;
499 
500  const Belle2::UncertainHelix measHelix = trackfit->getUncertainHelix();
501  const TMatrixDSym measCovariance = measHelix.getCovariance();
502  const ROOT::Math::XYZVector mcProdVertex = mcparticle->getVertex();
503  const ROOT::Math::XYZVector mcMomentum = mcparticle->getMomentum();
504 
505  const double BzAtProdVertex = Belle2::BFieldManager::getFieldInTesla(mcProdVertex).Z();
506  const double mcParticleCharge = mcparticle->getCharge();
507  const Belle2::Helix mcHelix = Belle2::Helix(mcProdVertex, mcMomentum, mcParticleCharge, BzAtProdVertex);
508 
509  const std::vector<double> mcHelixPars = {mcHelix.getD0(), mcHelix.getPhi0(), mcHelix.getOmega(), mcHelix.getZ0(), mcHelix.getTanLambda()};
510  const std::vector<double> measHelixPars = {measHelix.getD0(), measHelix.getPhi0(), measHelix.getOmega(), measHelix.getZ0(), measHelix.getTanLambda()};
511  const std::vector<double> measErrSquare = {measCovariance[0][0], measCovariance[1][1], measCovariance[2][2], measCovariance[3][3], measCovariance[4][4]};
512 
513  return (mcHelixPars.at(index) - measHelixPars.at(index)) / std::sqrt(measErrSquare.at(index));
514  }
515 
516  double getHelixD0Pull(const Particle* part)
517  {
518  return getHelixParameterPullAtIndex(part, 0);
519  }
520 
521  double getHelixPhi0Pull(const Particle* part)
522  {
523  return getHelixParameterPullAtIndex(part, 1);
524  }
525 
526  double getHelixOmegaPull(const Particle* part)
527  {
528  return getHelixParameterPullAtIndex(part, 2);
529  }
530 
531  double getHelixZ0Pull(const Particle* part)
532  {
533  return getHelixParameterPullAtIndex(part, 3);
534  }
535  double getHelixTanLambdaPull(const Particle* part)
536  {
537  return getHelixParameterPullAtIndex(part, 4);
538  }
539  double getTrackTime(const Particle* part)
540  {
541  const Track* track = part->getTrack();
542  if (!track) return realNaN;
543  return track->getTrackTime();
544  }
545 
546  double isTrackFlippedAndRefitted(const Particle* part)
547  {
548  auto track = part->getTrack();
549  if (!track) return realNaN;
550  return track->isFlippedAndRefitted() ? 1 : 0;
551  }
552 
553  VARIABLE_GROUP("Tracking");
554  REGISTER_VARIABLE("d0Pull", getHelixD0Pull, R"DOC(
555 The pull of the tracking parameter :math:`d_0` for the reconstructed
556 pattern-recognition track, with respect to the MC track. That is:
557 
558 .. math::
559 
560  \frac{d_0^\textrm{MC} - d_0^\textrm{PR}}{\sigma_{d_0; \textrm{PR}}}
561 
562 .. seealso:: :b2:var:`d0`, :b2:var:`d0Err`
563 
564 Returns NaN if no MC particle is related or if called on something other than a
565 track-based particle.
566  )DOC");
567  REGISTER_VARIABLE("phi0Pull", getHelixPhi0Pull, R"DOC(
568 The pull of the tracking parameter :math:`\phi_0` for the reconstructed
569 pattern-recognition track, with respect to the MC track. That is:
570 
571 .. math::
572 
573  \frac{\phi_0^\textrm{MC} - \phi_0^\textrm{PR}}{\sigma_{\phi_0; \textrm{PR}}}
574 
575 .. seealso:: :b2:var:`phi0`, :b2:var:`phi0Err`
576 
577 Returns NaN if no MC particle is related or if called on something other than a
578 track-based particle.
579  )DOC");
580  REGISTER_VARIABLE("omegaPull", getHelixOmegaPull, R"DOC(
581 The pull of the tracking parameter :math:`\omega` for the reconstructed
582 pattern-recognition track, with respect to the MC track. That is:
583 
584 .. math::
585 
586  \frac{\omega^\textrm{MC} - \omega^\textrm{PR}}{\sigma_{\omega; \textrm{PR}}}
587 
588 .. seealso:: :b2:var:`omega`, :b2:var:`omegaErr`
589 
590 Returns NaN if no MC particle is related or if called on something other than a
591 track-based particle.
592  )DOC");
593  REGISTER_VARIABLE("z0Pull", getHelixZ0Pull, R"DOC(
594 The pull of the tracking parameter :math:`z_0` for the reconstructed
595 pattern-recognition track, with respect to the MC track. That is:
596 
597 .. math::
598 
599  \frac{z_0^\textrm{MC} - z_0^\textrm{PR}}{\sigma_{z_0; \textrm{PR}}}
600 
601 .. seealso:: :b2:var:`z0`, :b2:var:`z0Err`
602 
603 Returns NaN if no MC particle is related or if called on something other than a
604 track-based particle.
605  )DOC");
606  REGISTER_VARIABLE("tanLambdaPull", getHelixTanLambdaPull, R"DOC(
607 The pull of the tracking parameter :math:`\tan\lambda` for the reconstructed
608 pattern-recognition track, with respect to the MC track. That is:
609 
610 .. math::
611 
612  \frac{(\tan\lambda)^\textrm{MC} - (\tan\lambda)^\textrm{PR}}{\sigma_{\tan\lambda; \textrm{PR}}}
613 
614 .. seealso:: :b2:var:`tanLambda`, :b2:var:`tanLambdaErr`
615 
616 Returns NaN if no MC particle is related or if called on something other than a
617 track-based particle.
618  )DOC");
619  REGISTER_VARIABLE("nCDCHits", trackNCDCHits,
620  "The number of CDC hits associated to the track. Returns NaN if called for something other than a track-based particle.");
621  REGISTER_VARIABLE("nSVDHits", trackNSVDHits,
622  "The number of SVD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
623  REGISTER_VARIABLE("nPXDHits", trackNPXDHits,
624  "The number of PXD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
625  REGISTER_VARIABLE("nVXDHits", trackNVXDHits,
626  "The number of PXD and SVD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
627  REGISTER_VARIABLE("ndf", trackNDF, R"DOC(
628 Returns the number of degrees of freedom of the track fit.
629 
630 .. note::
631 
632  Note that this is not simply the number of hits -5 due to outlier hit
633  rejection.
634 
635 Returns NaN if called for something other than a track-based particle, or for
636 mdst files processed with basf2 versions older than ``release-05-01``.
637  )DOC");
638  REGISTER_VARIABLE("chi2", trackChi2, R"DOC(
639 Returns the :math:`\chi^2` of the track fit. This is actually computed based on
640 :b2:var:`pValue` and :b2:var:`ndf`.
641 
642 .. note:: Note that for :b2:var:`pValue` exactly equal to 0 it returns infinity.
643 
644 Returns NaN if called for something other than a track-based particle, or for
645 mdst files processed with basf2 versions older than ``release-05-01``.
646  )DOC");
647  REGISTER_VARIABLE("firstSVDLayer", trackFirstSVDLayer,
648  "The first activated SVD layer associated to the track. Returns NaN if called for something other than a track-based particle.");
649  REGISTER_VARIABLE("firstPXDLayer", trackFirstPXDLayer,
650  "The first activated PXD layer associated to the track. Returns NaN if called for something other than a track-based particle.");
651  REGISTER_VARIABLE("firstCDCLayer", trackFirstCDCLayer,
652  "The first activated CDC layer associated to the track. Returns NaN if called for something other than a track-based particle.");
653  REGISTER_VARIABLE("lastCDCLayer", trackLastCDCLayer,
654  "The last CDC layer associated to the track. Returns NaN if called for something other than a track-based particle.");
655  REGISTER_VARIABLE("d0", trackD0, R"DOC(
656 Returns the tracking parameter :math:`d_0`, the signed distance to the
657 point-of-closest-approach (POCA) in the :math:`r-\phi` plane.
658 
659 .. note::
660 
661  Tracking parameters are with respect to the origin (0,0,0). For the
662  POCA with respect to the measured beam interaction point, see
663  :b2:var:`dr` (you probably want this unless you're doing a tracking
664  study or some debugging).
665 
666 Returns NaN if called for something other than a track-based particle.
667 
668 )DOC", "cm");
669  REGISTER_VARIABLE("phi0", trackPhi0, R"DOC(
670 Returns the tracking parameter :math:`\phi_0`, the angle of the transverse
671 momentum in the :math:`r-\phi` plane.
672 
673 Returns NaN if called for something other than a track-based particle.
674 
675 )DOC", "rad");
676  REGISTER_VARIABLE("omega", trackOmega, R"DOC(
677 Returns the tracking parameter :math:`\omega`, the curvature of the track.
678 
679 Returns NaN if called for something other than a track-based particle.
680 
681 )DOC", ":math:`\\text{cm}^{-1}`");
682  REGISTER_VARIABLE("z0", trackZ0, R"DOC(
683 Returns the tracking parameter :math:`z_0`, the z-coordinate of the
684 point-of-closest-approach (POCA).
685 
686 .. note::
687 
688  Tracking parameters are with respect to the origin (0,0,0). For the
689  POCA with respect to the measured beam interaction point, see
690  :b2:var:`dz` (you probably want this unless you're doing a tracking
691  study or some debugging).
692 
693 Returns NaN if called for something other than a track-based particle.
694 
695 )DOC", "cm");
696  REGISTER_VARIABLE("tanLambda", trackTanLambda, R"DOC(
697 Returns :math:`\tan\lambda`, the slope of the track in the :math:`r-z` plane.
698 
699 Returns NaN if called for something other than a track-based particle.
700  )DOC");
701  REGISTER_VARIABLE("d0Err", trackD0Error, R"DOC(
702 Returns the uncertainty on :math:`d_0`, the signed distance to the
703 point-of-closest-approach (POCA) in the :math:`r-\phi` plane.
704 
705 .. seealso:: :b2:var:`d0`, :b2:var:`d0Pull`
706 
707 Returns NaN if called for something other than a track-based particle.
708 
709 )DOC", "cm");
710  REGISTER_VARIABLE("phi0Err", trackPhi0Error, R"DOC(
711 Returns the uncertainty on :math:`\phi_0`, the angle of the transverse momentum
712 in the :math:`r-\phi` plane.
713 
714 .. seealso:: :b2:var:`phi0`, :b2:var:`phi0Pull`
715 
716 Returns NaN if called for something other than a track-based particle.
717 
718 )DOC", "rad");
719  REGISTER_VARIABLE("omegaErr", trackOmegaError, R"DOC(
720 Returns the uncertainty on :math:`\omega`, the curvature of the track.
721 
722 .. seealso:: :b2:var:`omega`, :b2:var:`omegaPull`
723 
724 Returns NaN if called for something other than a track-based particle.
725 
726 )DOC", ":math:`\\text{cm}^{-1}`");
727  REGISTER_VARIABLE("z0Err", trackZ0Error, R"DOC(
728 Returns the uncertainty on :math:`z_0`, the z-coordinate of the
729 point-of-closest-approach (POCA).
730 
731 .. seealso:: :b2:var:`z0`, :b2:var:`z0Pull`
732 
733 Returns NaN if called for something other than a track-based particle."
734 
735 )DOC", "cm");
736  REGISTER_VARIABLE("tanLambdaErr", trackTanLambdaError, R"DOC(
737 Returns the uncertainty on :math:`\tan\lambda`, the slope of the track in the
738 :math:`r-z` plane.
739 
740 .. seealso:: :b2:var:`tanLambda`, :b2:var:`tanLambdaPull`
741 
742 Returns NaN if called for something other than a track-based particle.
743  )DOC");
744  REGISTER_VARIABLE("trackFitCovariance(i, j)", trackFitCovariance, R"DOC(
745  The track fit covariance matrix element corresponding to the two indices is returned.
746  This is the association between integers and parameters:
747 
748  * 0: :math:`d_0`
749  * 1: :math:`\phi_0`
750  * 2: :math:`\omega`
751  * 3: :math:`z_0`
752  * 4: :math:`\tan\lambda`
753 
754  .. note::
755 
756  The covariance is returned. This means that the return value can be negative.
757  Furthermore, it's the squared value of the track fit error variables :b2:var:`d0Err`, etc.
758  when selecting the diagonal entries.
759 
760  )DOC");
761  REGISTER_VARIABLE("pValue", trackPValue, R"DOC(
762 The :math:`\chi^2` probability of the **track** fit.
763 
764 .. note::
765 
766  This is the p-value of the track-fit. It does not get updated after
767  vertex fitting or kinematic fitting, and is meaningless for composite
768  particles.
769 
770  See :b2:var:`chiProb` (you probably want this for high-level analysis).
771 
772 Returns NaN if called for something other than a track-based particle.
773  )DOC");
774  REGISTER_VARIABLE("trackFitHypothesisPDG", trackFitHypothesisPDG, R"DOC(
775 Returns the PDG code of the track hypothesis actually used for the fit.
776 Returns NaN if called for something other than a track-based particle.
777  )DOC");
778  REGISTER_VARIABLE("trackNECLClusters", trackNECLClusters, R"DOC(
779 Returns a count of the number of ECLClusters matched to the track. This is
780 always 0 or 1 with newer versions of ECL reconstruction.
781 
782 .. note::
783 
784  For high-level analysis it is recommended to require the presence of a
785  matched ECL cluster along with a minimum energy requirement. A
786  track-based particle will have a clusterE if it is matched (NaN if
787  there is no cluster match for the track.
788 
789  .. code-block:: python
790 
791  import modularAnalysis as ma
792  # minimum energy of 200 MeV
793  ma.fillParticleList("e+:clusters", "clusterE > 0.2", path)
794 
795  # these two are equivalent
796  ma.fillParticleList("e+:unmatched", "isNAN(clusterE) == 1", path)
797  ma.fillParticleList("e+:unmatched2", "trackNECLClusters == 0", path)
798 
799 Returns NaN if called for something other than a track-based particle.
800  )DOC");
801  REGISTER_VARIABLE("helixExtTheta(radius [cm], z fwd [cm], z bwd [cm], useHighestProbMass=0)", trackHelixExtTheta,
802  R"DOC(Returns theta of extrapolated helix parameters. If ``useHighestProbMass=1`` is set, the extrapolation will
803  use the track fit result for the mass hypothesis with the highest pValue.
804 
805  )DOC", "rad");
806  REGISTER_VARIABLE("helixExtPhi(radius, z fwd, z bwd, useHighestProbMass=0)", trackHelixExtPhi,
807  "Returns phi of extrapolated helix parameters. If ``useHighestProbMass=1`` is set, the extrapolation will use the track fit result for the mass hypothesis with the highest pValue.\n\n",
808  "rad");
809 
810  REGISTER_METAVARIABLE("helixExtThetaOnDet(detector_surface_name, useHighestProbMass=0)", trackHelixExtThetaOnDet,
811  R"DOC(Returns theta of extrapolated helix parameters on the given detector surface. The unit of angle is ``rad``.
812  If ``useHighestProbMass=1`` is set, the extrapolation will use the track fit result for the mass hypothesis with the highest pValue.
813  The supported detector surface names are ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
814  Also, the detector name with number of meaningful-layer is supported, e.g. ``'CDC8'``: last superlayer of CDC, ``'ECL1'``: mid-point of ECL.
815 
816  ..note:: You can find more information in `modularAnalysis.calculateTrackIsolation`.
817  )DOC", Manager::VariableDataType::c_double);
818  REGISTER_METAVARIABLE("helixExtPhiOnDet(detector_surface_name, useHighestProbMass=0)", trackHelixExtPhiOnDet,
819  R"DOC(Returns phi of extrapolated helix parameters on the given detector surface. The unit of angle is ``rad``.
820  If ``useHighestProbMass=1`` is set, the extrapolation will use the track fit result for the mass hypothesis with the highest pValue.
821  The supported detector surface names are ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
822  Also, the detector name with number of meaningful-layer is supported, e.g. ``'CDC8'``: last superlayer of CDC, ``'ECL1'``: mid-point of ECL.
823 
824  ..note:: You can find more information in `modularAnalysis.calculateTrackIsolation`.
825  )DOC", Manager::VariableDataType::c_double);
826 
827 
828  REGISTER_VARIABLE("nExtraCDCHits", nExtraCDCHits, R"DOC(
829 [Eventbased] The number of CDC hits in the event not assigned to any track.
830 
831 Returns NaN if there is no event-level tracking information available.
832  )DOC");
833  REGISTER_VARIABLE("nExtraCDCHitsPostCleaning", nExtraCDCHitsPostCleaning, R"DOC(
834 [Eventbased] Returns a count of the number of CDC hits in the event not assigned
835 to any track nor very likely beam background (i.e. hits that survive a cleanup
836 selection).
837 
838 Returns NaN if there is no event-level tracking information available.
839  )DOC");
840  REGISTER_VARIABLE("hasExtraCDCHitsInLayer(i)", hasExtraCDCHitsInLayer, R"DOC(
841 [Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC layer,
842 0 otherwise.
843 
844 Returns NaN if there is no event-level tracking information available.
845  )DOC");
846  REGISTER_VARIABLE("hasExtraCDCHitsInSuperLayer(i)", hasExtraCDCHitsInSuperLayer, R"DOC(
847 [Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC
848 SuperLayer, 0 otherwise.
849 
850 Returns NaN if there is no event-level tracking information available.
851  )DOC");
852  REGISTER_VARIABLE("nExtraCDCSegments", nExtraCDCSegments, R"DOC(
853 [Eventbased] Returns the number of CDC segments not assigned to any track.
854 
855 Returns NaN if there is no event-level tracking information available.
856  )DOC");
857  // TODO: once the Tracking group fill the dataobject these can be
858  // uncommented - at the moment they are not filled, so leave out
859  //REGISTER_VARIABLE("nExtraVXDHitsInLayer(i)", nExtraVXDHitsInLayer,
860  //"[Eventbased] The number VXD hits not assigned in the specified VXD layer");
861  //REGISTER_VARIABLE("nExtraVXDHits", nExtraVXDHits, "[Eventbased] The number of VXD hits not assigned to any track");
862  //REGISTER_VARIABLE("svdFirstSampleTime", svdFirstSampleTime, "[Eventbased] The time of first SVD sample relatvie to event T0");
863  REGISTER_VARIABLE("trackFindingFailureFlag", trackFindingFailureFlag, R"DOC(
864 [Eventbased] Returns a flag set by the tracking if there is reason to assume
865 there was a track in the event missed by the tracking, or the track finding was
866 (partly) aborted for this event.
867 
868 Returns NaN if there is no event-level tracking information available.
869  )DOC");
870 
871  REGISTER_VARIABLE("isTrackFlippedAndRefitted", isTrackFlippedAndRefitted, R"DOC(
872 Returns 1 if the charged final state particle comes from a track that has been flipped and refitted
873 at the end of the reconstruction chain, in particular after the outer detector reconstruction.
874  )DOC");
875 
876  REGISTER_VARIABLE("trackTime", getTrackTime, R"DOC(
877 Returns the time at which the track is produced relative to the time of the collision (given by SVD EventT0).
878 Both the time of the collision and the track time are computed using only SVD hits.
879 Returns NaN if SVD EventT0 is NaN, or if no SVD Hits are attached to the track.
880 For more details, see :ref:`Time Extraction <tracking_eventTimeExtraction>` page.
881 
882 )DOC", "ns");
883  }
885 }
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
Definition: BFieldManager.h:61
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
@ c_nPhotons
CR is split into n photons (N1)
This class represents an ideal helix in perigee parameterization.
Definition: Helix.h:59
double getOmega() const
Getter for omega, which is a signed curvature measure of the track.
Definition: Helix.h:387
double getD0() const
Getter for d0, which is the signed distance to the perigee in the r-phi plane.
Definition: Helix.h:372
double getTanLambda() const
Getter for tan lambda, which is the z over two dimensional arc length slope of the track.
Definition: Helix.h:393
double getZ0() const
Getter for z0, which is the z coordinate of the perigee.
Definition: Helix.h:390
double getPhi0() const
Getter for phi0, which is the azimuth angle of the transverse momentum at the perigee.
Definition: Helix.h:378
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:946
Values of the result of a track fit with a given particle hypothesis.
UncertainHelix getUncertainHelix() const
Conversion to framework Uncertain Helix (i.e., with covariance).
This class represents an ideal helix in perigee parameterization including the covariance matrix of t...
const TMatrixDSym & getCovariance() const
Getter for covariance matrix of perigee parameters in matrix form.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition: Manager.h:113
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:516
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23
static const std::unordered_map< std::string, DetSurfCylBoundaries > detToSurfBoundaries
Map that associates to each detector its valid cylindrical surface's boundaries.
static const std::unordered_map< std::string, DetSurfCylBoundaries > detLayerToSurfBoundaries
Map that associates to each detector layer its valid cylindrical surface's boundaries.