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