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