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