Belle II Software development
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 // used in trackHelixExtTheta and trackHelixExtPhi
284 ROOT::Math::XYZVector getPositionOnHelix(const TrackFitResult* trackFit, const std::vector<double>& pars)
285 {
286 const double r = pars[0];
287 const double zfwd = pars[1];
288 const double zbwd = pars[2];
289
290 // get helix and parameters
291 const double z0 = trackFit->getZ0();
292 const double tanlambda = trackFit->getTanLambda();
293 const Helix h = trackFit->getHelix();
294
295 // extrapolate to radius
296 const double arcLength = h.getArcLength2DAtCylindricalR(r);
297 const double lHelixRadius = arcLength > 0 ? arcLength : std::numeric_limits<double>::max();
298
299 // extrapolate to FWD z
300 const double lFWD = (zfwd - z0) / tanlambda > 0 ? (zfwd - z0) / tanlambda : std::numeric_limits<double>::max();
301
302 // extrapolate to BWD z
303 const double lBWD = (zbwd - z0) / tanlambda > 0 ? (zbwd - z0) / tanlambda : std::numeric_limits<double>::max();
304
305 // pick smallest arclength
306 const double l = std::min({lHelixRadius, lFWD, lBWD});
307
308 return h.getPositionAtArcLength2D(l);
309 }
310
311 ROOT::Math::XYZVector getPositionOnHelix(const Particle* part, const std::vector<double>& pars)
312 {
313 if (pars.size() == 4 and pars[3]) {
314 const Track* track = part->getTrack();
315 if (!track)
316 return vecNaN;
317
318 auto highestProbMass = part->getMostLikelyTrackFitResult().first;
319 const TrackFitResult* trackFit = track->getTrackFitResultWithClosestMass(highestProbMass);
320 if (!trackFit) return vecNaN;
321 else return getPositionOnHelix(trackFit, pars);
322 } else {
323 const TrackFitResult* trackFit = part->getTrackFitResult();
324 if (!trackFit) return vecNaN;
325 else return getPositionOnHelix(trackFit, pars);
326 }
327 }
328
329 // returns extrapolated theta position based on helix parameters
330 double trackHelixExtTheta(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 helixExtTheta.");
335 }
336
337 ROOT::Math::XYZVector position = getPositionOnHelix(part, pars);
338 if (position == vecNaN) return Const::doubleNaN;
339 return position.Theta();
340 }
341
342 // returns extrapolated phi position based on helix parameters
343 double trackHelixExtPhi(const Particle* part, const std::vector<double>& pars)
344 {
345 const auto nParams = pars.size();
346 if (nParams != 3 && nParams != 4) {
347 B2FATAL("Exactly three (+1 optional) parameters (r, zfwd, zbwd, [useHighestProbMass]) required for helixExtPhi.");
348 }
349
350 ROOT::Math::XYZVector position = getPositionOnHelix(part, pars);
351 if (position == vecNaN) return Const::doubleNaN;
352 return position.Phi();
353 }
354
355 Manager::FunctionPtr trackHelixExtThetaOnDet(const std::vector<std::string>& arguments)
356 {
357 if (arguments.size() != 1 && arguments.size() != 2)
358 B2FATAL("Exactly one (+1 optional) parameter (detector_surface_name, [useHighestProbMass]) is required for helixExtThetaOnDet.");
359
360 std::vector<double> parameters(3);
361 const std::string det = arguments[0];
363 parameters[0] = DetectorSurface::detToSurfBoundaries.at(det).m_rho;
364 parameters[1] = DetectorSurface::detToSurfBoundaries.at(det).m_zfwd;
365 parameters[2] = DetectorSurface::detToSurfBoundaries.at(det).m_zbwd;
367 parameters[0] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_rho;
368 parameters[1] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zfwd;
369 parameters[2] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zbwd;
370 } else
371 B2FATAL("Given detector surface name is not supported.");
372
373 if (arguments.size() == 2)
374 parameters.push_back(std::stod(arguments[1]));
375
376 auto func = [parameters](const Particle * part) -> double {
377
378 ROOT::Math::XYZVector position = getPositionOnHelix(part, parameters);
379 if (position == vecNaN) return Const::doubleNaN;
380 return position.Theta();
381 };
382 return func;
383 }
384
385 Manager::FunctionPtr trackHelixExtPhiOnDet(const std::vector<std::string>& arguments)
386 {
387 if (arguments.size() != 1 && arguments.size() != 2)
388 B2FATAL("Exactly one (+1 optional) parameter (detector_surface_name, [useHighestProbMass]) is required for helixExtPhiOnDet.");
389
390 std::vector<double> parameters(3);
391 const std::string det = arguments[0];
393 parameters[0] = DetectorSurface::detToSurfBoundaries.at(det).m_rho;
394 parameters[1] = DetectorSurface::detToSurfBoundaries.at(det).m_zfwd;
395 parameters[2] = DetectorSurface::detToSurfBoundaries.at(det).m_zbwd;
397 parameters[0] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_rho;
398 parameters[1] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zfwd;
399 parameters[2] = DetectorSurface::detLayerToSurfBoundaries.at(det).m_zbwd;
400 } else
401 B2FATAL("Given detector surface name is not supported.");
402
403 if (arguments.size() == 2)
404 parameters.push_back(std::stod(arguments[1]));
405
406 auto func = [parameters](const Particle * part) -> double {
407
408 ROOT::Math::XYZVector position = getPositionOnHelix(part, parameters);
409 if (position == vecNaN) return Const::doubleNaN;
410 return position.Phi();
411 };
412 return func;
413 }
414
415
416 /***************************************************
417 * Event level tracking quantities
418 */
419
420 // The number of CDC hits in the event not assigned to any track
421 double nExtraCDCHits(const Particle*)
422 {
423 StoreObjPtr<EventLevelTrackingInfo> elti;
424 if (!elti) return Const::doubleNaN;
425 return elti->getNCDCHitsNotAssigned();
426 }
427
428 // The number of CDC hits in the event not assigned to any track nor very
429 // likely beam background (i.e. hits that survive a cleanup selection)
430 double nExtraCDCHitsPostCleaning(const Particle*)
431 {
432 StoreObjPtr<EventLevelTrackingInfo> elti;
433 if (!elti) return Const::doubleNaN;
434 return elti->getNCDCHitsNotAssignedPostCleaning();
435 }
436
437 // Check for the presence of a non-assigned hit in the specified CDC layer
438 double hasExtraCDCHitsInLayer(const Particle*, const std::vector<double>& layer)
439 {
440 StoreObjPtr<EventLevelTrackingInfo> elti;
441 if (!elti) return Const::doubleNaN;
442 int ilayer = std::lround(layer[0]);
443 return elti->hasCDCLayer(ilayer);
444 }
445
446 // Check for the presence of a non-assigned hit in the specified CDC SuperLayer
447 double hasExtraCDCHitsInSuperLayer(const Particle*, const std::vector<double>& layer)
448 {
449 StoreObjPtr<EventLevelTrackingInfo> elti;
450 if (!elti) return Const::doubleNaN;
451 int ilayer = std::lround(layer[0]);
452 return elti->hasCDCSLayer(ilayer);
453 }
454
455 // The number of segments that couldn't be assigned to any track
456 double nExtraCDCSegments(const Particle*)
457 {
458 StoreObjPtr<EventLevelTrackingInfo> elti;
459 if (!elti) return Const::doubleNaN;
460 return elti->getNCDCSegments();
461 }
462
463 // The number of VXD hits not assigned to any track in the specified layer
464 double nExtraVXDHitsInLayer(const Particle*, const std::vector<double>& layer)
465 {
466 StoreObjPtr<EventLevelTrackingInfo> elti;
467 if (!elti) return Const::doubleNaN;
468 int ilayer = std::lround(layer[0]);
469 return elti->getNVXDClustersInLayer(ilayer);
470 }
471
472 // The number of VXD hits not assigned to any track
473 double nExtraVXDHits(const Particle*)
474 {
475 StoreObjPtr<EventLevelTrackingInfo> elti;
476 if (!elti) return Const::doubleNaN;
477 double out = 0.0;
478 for (uint16_t ilayer = 1; ilayer < 7; ++ilayer)
479 out += elti->getNVXDClustersInLayer(ilayer);
480 return out;
481 }
482
483 // The number of PXD hits not assigned to any track
484 double nExtraPXDHits(const Particle*)
485 {
486 StoreObjPtr<EventLevelTrackingInfo> elti;
487 if (!elti) return Const::doubleNaN;
488 double out = 0.0;
489 for (uint16_t ilayer = 1; ilayer < 3; ++ilayer)
490 out += elti->getNVXDClustersInLayer(ilayer);
491 return out;
492 }
493
494 // time of first SVD sample relative to event T0
495 double svdFirstSampleTime(const Particle*)
496 {
497 StoreObjPtr<EventLevelTrackingInfo> elti;
498 if (!elti) return Const::doubleNaN;
499 return elti->getSVDFirstSampleTime();
500 }
501
502 // A flag set by the tracking if there is reason to assume there was a track
503 // in the event missed by the tracking or the track finding was (partly) aborted
504 // for this event. Further information about this can be obtained from the flagBlock
505 // of the EventLevelTrackingInfo object.
506 double trackFindingFailureFlag(const Particle*)
507 {
508 StoreObjPtr<EventLevelTrackingInfo> elti;
509 if (!elti) return Const::doubleNaN;
510 return elti->hasAnErrorFlag();
511 }
512
513 // Build a Helix from a MCParticle's kinematics. Does NOT check for null pointer!!!
514 Helix getMCHelix(const MCParticle* mcparticle)
515 {
516 const ROOT::Math::XYZVector mcProdVertex = mcparticle->getVertex();
517 const ROOT::Math::XYZVector mcMomentum = mcparticle->getMomentum();
518 const double BzAtProdVertex = BFieldManager::getFieldInTesla(mcProdVertex).Z();
519 const double mcParticleCharge = mcparticle->getCharge();
520 return Helix(mcProdVertex, mcMomentum, mcParticleCharge, BzAtProdVertex);
521 }
522
523 double getMCHelixParameterAtIndex(const Particle* particle, const int index)
524 {
525 if (!particle) return Const::doubleNaN;
526
527 const MCParticle* mcparticle = particle->getMCParticle();
528 if (!mcparticle) return Const::doubleNaN;
529
530 const Helix mcHelix(getMCHelix(mcparticle));
531 const std::vector<double> mcHelixPars{mcHelix.getD0(), mcHelix.getPhi0(), mcHelix.getOmega(), mcHelix.getZ0(), mcHelix.getTanLambda()};
532 return mcHelixPars.at(index);
533 }
534
535 double getHelixParameterPullAtIndex(const Particle* particle, const int index)
536 {
537 if (!particle) return Const::doubleNaN;
538
539 const MCParticle* mcparticle = particle->getMCParticle();
540 if (!mcparticle) return Const::doubleNaN;
541
542 const TrackFitResult* trackfit = particle->getTrackFitResult();
543 if (!trackfit) return Const::doubleNaN;
544
545 const UncertainHelix measHelix = trackfit->getUncertainHelix();
546 const TMatrixDSym& measCovariance = measHelix.getCovariance();
547 const Helix mcHelix(getMCHelix(mcparticle));
548
549 const std::vector<double> mcHelixPars = {mcHelix.getD0(), mcHelix.getPhi0(), mcHelix.getOmega(), mcHelix.getZ0(), mcHelix.getTanLambda()};
550 const std::vector<double> measHelixPars = {measHelix.getD0(), measHelix.getPhi0(), measHelix.getOmega(), measHelix.getZ0(), measHelix.getTanLambda()};
551
552 return (mcHelixPars.at(index) - measHelixPars.at(index)) / std::sqrt(measCovariance(index, index));
553 }
554
555 double getHelixMCD0(const Particle* part) { return getMCHelixParameterAtIndex(part, 0); }
556 double getHelixMCPhi0(const Particle* part) { return getMCHelixParameterAtIndex(part, 1); }
557 double getHelixMCOmega(const Particle* part) { return getMCHelixParameterAtIndex(part, 2); }
558 double getHelixMCZ0(const Particle* part) { return getMCHelixParameterAtIndex(part, 3); }
559 double getHelixMCTanLambda(const Particle* part) { return getMCHelixParameterAtIndex(part, 4); }
560
561 double getHelixD0Pull(const Particle* part)
562 {
563 return getHelixParameterPullAtIndex(part, 0);
564 }
565
566 double getHelixPhi0Pull(const Particle* part)
567 {
568 return getHelixParameterPullAtIndex(part, 1);
569 }
570
571 double getHelixOmegaPull(const Particle* part)
572 {
573 return getHelixParameterPullAtIndex(part, 2);
574 }
575
576 double getHelixZ0Pull(const Particle* part)
577 {
578 return getHelixParameterPullAtIndex(part, 3);
579 }
580
581 double getHelixTanLambdaPull(const Particle* part)
582 {
583 return getHelixParameterPullAtIndex(part, 4);
584 }
585
586 double getTrackTime(const Particle* part)
587 {
588 const Track* track = part->getTrack();
589 if (!track) return Const::doubleNaN;
590 return track->getTrackTime();
591 }
592
593 double isTrackFlippedAndRefitted(const Particle* part)
594 {
595 auto track = part->getTrack();
596 if (!track) return Const::doubleNaN;
597 return track->isFlippedAndRefitted() ? 1 : 0;
598 }
599
600 double getTrackLength(const Particle* part)
601 {
602 auto trackFit = part->getTrackFitResult();
603 if (!trackFit) return Const::doubleNaN;
604
605 const double lastCDCLayer = trackLastCDCLayer(part);
606 if (std::isnan(lastCDCLayer) or lastCDCLayer < 0)
607 return Const::doubleNaN;
608
609 const double r = DetectorSurface::cdcWireRadiuses.at((int)lastCDCLayer);
610
611 return trackFit->getHelix().getArcLength2DAtCylindricalR(r);
612 }
613
614
615 VARIABLE_GROUP("Tracking");
616
617 REGISTER_VARIABLE("mcD0", getHelixMCD0, R"DOC(
618Returns the MC value of :math:`d_0`, the signed distance to the
619point-of-closest-approach (POCA) in the :math:`r-\phi` plane.
620
621.. seealso:: :b2:var:`d0`
622
623Returns NaN if the particle is not related to any MCParticle.
624
625)DOC", "cm");
626 REGISTER_VARIABLE("mcPhi0", getHelixMCPhi0, R"DOC(
627Returns the MC value of :math:`\phi_0`, the angle of the transverse momentum
628in the :math:`r-\phi` plane.
629
630.. seealso:: :b2:var:`phi0`
631
632Returns NaN if the particle is not related to any MCParticle.
633
634)DOC", "rad");
635 REGISTER_VARIABLE("mcOmega", getHelixMCOmega, R"DOC(
636Returns the MC value of :math:`\omega`, the curvature of the track.
637
638.. seealso:: :b2:var:`omega`
639
640Returns NaN if the particle is not related to any MCParticle.
641
642)DOC", ":math:`\\text{cm}^{-1}`");
643 REGISTER_VARIABLE("mcZ0", getHelixMCZ0, R"DOC(
644Returns the MC value of :math:`z_0`, the z-coordinate of the
645point-of-closest-approach (POCA).
646
647.. seealso:: :b2:var:`z0`
648
649Returns NaN if the particle is not related to any MCParticle.
650
651)DOC", "cm");
652 REGISTER_VARIABLE("mcTanLambda", getHelixMCTanLambda, R"DOC(
653Returns the MC value of :math:`\tan\lambda`, the slope of the track in the
654:math:`r-z` plane.
655
656.. seealso:: :b2:var:`tanLambda`
657
658Returns NaN if the particle is not related to any MCParticle.
659)DOC");
660
661 REGISTER_VARIABLE("d0Pull", getHelixD0Pull, R"DOC(
662The pull of the tracking parameter :math:`d_0` for the reconstructed
663pattern-recognition track, with respect to the MC track. That is:
664
665.. math::
666
667 \frac{d_0^\textrm{MC} - d_0^\textrm{PR}}{\sigma_{d_0; \textrm{PR}}}
668
669.. seealso:: :b2:var:`d0`, :b2:var:`d0Err`
670
671Returns NaN if no MC particle is related or if called on something other than a
672track-based particle.
673 )DOC");
674 REGISTER_VARIABLE("phi0Pull", getHelixPhi0Pull, R"DOC(
675The pull of the tracking parameter :math:`\phi_0` for the reconstructed
676pattern-recognition track, with respect to the MC track. That is:
677
678.. math::
679
680 \frac{\phi_0^\textrm{MC} - \phi_0^\textrm{PR}}{\sigma_{\phi_0; \textrm{PR}}}
681
682.. seealso:: :b2:var:`phi0`, :b2:var:`phi0Err`
683
684Returns NaN if no MC particle is related or if called on something other than a
685track-based particle.
686 )DOC");
687 REGISTER_VARIABLE("omegaPull", getHelixOmegaPull, R"DOC(
688The pull of the tracking parameter :math:`\omega` for the reconstructed
689pattern-recognition track, with respect to the MC track. That is:
690
691.. math::
692
693 \frac{\omega^\textrm{MC} - \omega^\textrm{PR}}{\sigma_{\omega; \textrm{PR}}}
694
695.. seealso:: :b2:var:`omega`, :b2:var:`omegaErr`
696
697Returns NaN if no MC particle is related or if called on something other than a
698track-based particle.
699 )DOC");
700 REGISTER_VARIABLE("z0Pull", getHelixZ0Pull, R"DOC(
701The pull of the tracking parameter :math:`z_0` for the reconstructed
702pattern-recognition track, with respect to the MC track. That is:
703
704.. math::
705
706 \frac{z_0^\textrm{MC} - z_0^\textrm{PR}}{\sigma_{z_0; \textrm{PR}}}
707
708.. seealso:: :b2:var:`z0`, :b2:var:`z0Err`
709
710Returns NaN if no MC particle is related or if called on something other than a
711track-based particle.
712 )DOC");
713 REGISTER_VARIABLE("tanLambdaPull", getHelixTanLambdaPull, R"DOC(
714The pull of the tracking parameter :math:`\tan\lambda` for the reconstructed
715pattern-recognition track, with respect to the MC track. That is:
716
717.. math::
718
719 \frac{(\tan\lambda)^\textrm{MC} - (\tan\lambda)^\textrm{PR}}{\sigma_{\tan\lambda; \textrm{PR}}}
720
721.. seealso:: :b2:var:`tanLambda`, :b2:var:`tanLambdaErr`
722
723Returns NaN if no MC particle is related or if called on something other than a
724track-based particle.
725 )DOC");
726 REGISTER_VARIABLE("nCDCHits", trackNCDCHits,
727 "The number of CDC hits associated to the track. Returns NaN if called for something other than a track-based particle.");
728 REGISTER_VARIABLE("nSVDHits", trackNSVDHits,
729 "The number of SVD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
730 REGISTER_VARIABLE("nPXDHits", trackNPXDHits,
731 "The number of PXD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
732 REGISTER_VARIABLE("nVXDHits", trackNVXDHits,
733 "The number of PXD and SVD hits associated to the track. Returns NaN if called for something other than a track-based particle.");
734 REGISTER_VARIABLE("ndf", trackNDF, R"DOC(
735Returns the number of degrees of freedom of the track fit.
736
737.. note::
738
739 Note that this is not simply the number of hits -5 due to outlier hit
740 rejection.
741
742Returns NaN if called for something other than a track-based particle, or for
743mdst files processed with basf2 versions older than ``release-05-01``.
744 )DOC");
745 REGISTER_VARIABLE("chi2", trackChi2, R"DOC(
746Returns the :math:`\chi^2` of the track fit. This is actually computed based on
747:b2:var:`pValue` and :b2:var:`ndf`.
748
749.. note:: Note that for :b2:var:`pValue` exactly equal to 0 it returns infinity.
750
751Returns NaN if called for something other than a track-based particle, or for
752mdst files processed with basf2 versions older than ``release-05-01``.
753 )DOC");
754 REGISTER_VARIABLE("firstSVDLayer", trackFirstSVDLayer,
755 "The first activated SVD layer associated to the track. Returns NaN if called for something other than a track-based particle.");
756 REGISTER_VARIABLE("firstPXDLayer", trackFirstPXDLayer,
757 "The first activated PXD layer associated to the track. Returns NaN if called for something other than a track-based particle.");
758 REGISTER_VARIABLE("firstCDCLayer", trackFirstCDCLayer,
759 "The first activated CDC layer associated to the track. Returns NaN if called for something other than a track-based particle.");
760 REGISTER_VARIABLE("lastCDCLayer", trackLastCDCLayer,
761 "The last CDC layer associated to the track. Returns NaN if called for something other than a track-based particle.");
762 REGISTER_VARIABLE("d0", trackD0, R"DOC(
763Returns the tracking parameter :math:`d_0`, the signed distance to the
764point-of-closest-approach (POCA) in the :math:`r-\phi` plane.
765
766.. note::
767
768 Tracking parameters are with respect to the origin (0,0,0). For the
769 POCA with respect to the measured beam interaction point, see
770 :b2:var:`dr` (you probably want this unless you're doing a tracking
771 study or some debugging) and :b2:var:`d0FromIP`.
772
773Returns NaN if called for something other than a track-based particle.
774
775)DOC", "cm");
776 REGISTER_VARIABLE("phi0", trackPhi0, R"DOC(
777Returns the tracking parameter :math:`\phi_0`, the angle of the transverse
778momentum in the :math:`r-\phi` plane.
779
780.. note::
781
782 Tracking parameters are with respect to the origin (0,0,0). For the
783 POCA with respect to the measured beam interaction point, see
784 :b2:var:`phi0FromIP`.
785
786Returns NaN if called for something other than a track-based particle.
787
788)DOC", "rad");
789 REGISTER_VARIABLE("omega", trackOmega, R"DOC(
790Returns the tracking parameter :math:`\omega`, the curvature of the track.
791
792Returns NaN if called for something other than a track-based particle.
793
794)DOC", ":math:`\\text{cm}^{-1}`");
795 REGISTER_VARIABLE("z0", trackZ0, R"DOC(
796Returns the tracking parameter :math:`z_0`, the z-coordinate of the
797point-of-closest-approach (POCA).
798
799.. note::
800
801 Tracking parameters are with respect to the origin (0,0,0). For the
802 POCA with respect to the measured beam interaction point, see
803 :b2:var:`dz` (you probably want this unless you're doing a tracking
804 study or some debugging) and :b2:var:`z0FromIP`.
805
806Returns NaN if called for something other than a track-based particle.
807
808)DOC", "cm");
809 REGISTER_VARIABLE("tanLambda", trackTanLambda, R"DOC(
810Returns :math:`\tan\lambda`, the slope of the track in the :math:`r-z` plane.
811
812Returns NaN if called for something other than a track-based particle.
813 )DOC");
814 REGISTER_VARIABLE("d0FromIP", trackD0FromIP, R"DOC(
815Returns the tracking parameter :math:`d_0`, the signed distance to the
816point-of-closest-approach (POCA) in the :math:`r-\phi` plane, with respect to the measured beam interaction point.
817
818Returns NaN if called for something other than a track-based particle.
819
820)DOC", "cm");
821 REGISTER_VARIABLE("z0FromIP", trackZ0FromIP, R"DOC(
822Returns the tracking parameter :math:`z_0`, the z-coordinate of the
823point-of-closest-approach (POCA), with respect to the measured beam interaction point.
824
825Returns NaN if called for something other than a track-based particle.
826
827)DOC", "cm");
828 REGISTER_VARIABLE("phi0FromIP", trackPhi0FromIP, R"DOC(
829Returns the tracking parameter :math:`\phi_0`, the angle of the transverse
830momentum in the :math:`r-\phi` plane, with respect to the measured beam interaction point.
831
832Returns NaN if called for something other than a track-based particle.
833
834)DOC", "rad");
835 REGISTER_VARIABLE("d0Err", trackD0Error, R"DOC(
836Returns the uncertainty on :math:`d_0`, the signed distance to the
837point-of-closest-approach (POCA) in the :math:`r-\phi` plane.
838
839.. seealso:: :b2:var:`d0`, :b2:var:`d0Pull`
840
841Returns NaN if called for something other than a track-based particle.
842
843)DOC", "cm");
844 REGISTER_VARIABLE("phi0Err", trackPhi0Error, R"DOC(
845Returns the uncertainty on :math:`\phi_0`, the angle of the transverse momentum
846in the :math:`r-\phi` plane.
847
848.. seealso:: :b2:var:`phi0`, :b2:var:`phi0Pull`
849
850Returns NaN if called for something other than a track-based particle.
851
852)DOC", "rad");
853 REGISTER_VARIABLE("omegaErr", trackOmegaError, R"DOC(
854Returns the uncertainty on :math:`\omega`, the curvature of the track.
855
856.. seealso:: :b2:var:`omega`, :b2:var:`omegaPull`
857
858Returns NaN if called for something other than a track-based particle.
859
860)DOC", ":math:`\\text{cm}^{-1}`");
861 REGISTER_VARIABLE("z0Err", trackZ0Error, R"DOC(
862Returns the uncertainty on :math:`z_0`, the z-coordinate of the
863point-of-closest-approach (POCA).
864
865.. seealso:: :b2:var:`z0`, :b2:var:`z0Pull`
866
867Returns NaN if called for something other than a track-based particle."
868
869)DOC", "cm");
870 REGISTER_VARIABLE("tanLambdaErr", trackTanLambdaError, R"DOC(
871Returns the uncertainty on :math:`\tan\lambda`, the slope of the track in the
872:math:`r-z` plane.
873
874.. seealso:: :b2:var:`tanLambda`, :b2:var:`tanLambdaPull`
875
876Returns NaN if called for something other than a track-based particle.
877 )DOC");
878 REGISTER_VARIABLE("trackFitCovariance(i, j)", trackFitCovariance, R"DOC(
879 The track fit covariance matrix element corresponding to the two indices is returned.
880 This is the association between integers and parameters:
881
882 * 0: :math:`d_0`
883 * 1: :math:`\phi_0`
884 * 2: :math:`\omega`
885 * 3: :math:`z_0`
886 * 4: :math:`\tan\lambda`
887
888 .. note::
889
890 The covariance is returned. This means that the return value can be negative.
891 Furthermore, it's the squared value of the track fit error variables :b2:var:`d0Err`, etc.
892 when selecting the diagonal entries.
893
894 )DOC");
895 REGISTER_VARIABLE("pValue", trackPValue, R"DOC(
896The :math:`\chi^2` probability of the **track** fit.
897
898.. note::
899
900 This is the p-value of the track-fit. It does not get updated after
901 vertex fitting or kinematic fitting, and is meaningless for composite
902 particles.
903
904 See :b2:var:`chiProb` (you probably want this for high-level analysis).
905
906Returns NaN if called for something other than a track-based particle.
907 )DOC");
908 REGISTER_VARIABLE("trackFitHypothesisPDG", trackFitHypothesisPDG, R"DOC(
909Returns the PDG code of the track hypothesis actually used for the fit.
910Returns NaN if called for something other than a track-based particle.
911 )DOC");
912 REGISTER_VARIABLE("trackNECLClusters", trackNECLClusters, R"DOC(
913Returns a count of the number of ECLClusters matched to the track. This is
914always 0 or 1 with newer versions of ECL reconstruction.
915
916.. note::
917
918 For high-level analysis it is recommended to require the presence of a
919 matched ECL cluster along with a minimum energy requirement. A
920 track-based particle will have a clusterE if it is matched (NaN if
921 there is no cluster match for the track.
922
923 .. code-block:: python
924
925 import modularAnalysis as ma
926 # minimum energy of 200 MeV
927 ma.fillParticleList("e+:clusters", "clusterE > 0.2", path)
928
929 # these two are equivalent
930 ma.fillParticleList("e+:unmatched", "isNAN(clusterE) == 1", path)
931 ma.fillParticleList("e+:unmatched2", "trackNECLClusters == 0", path)
932
933Returns NaN if called for something other than a track-based particle.
934 )DOC");
935 REGISTER_VARIABLE("helixExtTheta(radius [cm], z fwd [cm], z bwd [cm], useHighestProbMass=0)", trackHelixExtTheta, R"DOC(
936 Returns theta of extrapolated helix parameters. If ``useHighestProbMass=1`` is set, the extrapolation will
937 use the track fit result for the mass hypothesis with the highest pValue.
938
939 )DOC", "rad");
940 REGISTER_VARIABLE("helixExtPhi(radius, z fwd, z bwd, useHighestProbMass=0)", trackHelixExtPhi,
941 "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",
942 "rad");
943
944 REGISTER_METAVARIABLE("helixExtThetaOnDet(detector_surface_name, useHighestProbMass=0)", trackHelixExtThetaOnDet, R"DOC(
945 Returns theta of extrapolated helix parameters on the given detector surface. The unit of angle is ``rad``.
946 If ``useHighestProbMass=1`` is set, the extrapolation will use the track fit result for the mass hypothesis with the highest pValue.
947 The supported detector surface names are ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
948 Also, the detector name with number of meaningful-layer is supported, e.g. ``'CDC8'``: last superlayer of CDC, ``'ECL1'``: mid-point of ECL.
949
950 .. note:: You can find more information in `modularAnalysis.calculateTrackIsolation`.
951 )DOC", Manager::VariableDataType::c_double);
952 REGISTER_METAVARIABLE("helixExtPhiOnDet(detector_surface_name, useHighestProbMass=0)", trackHelixExtPhiOnDet, R"DOC(
953 Returns phi of extrapolated helix parameters on the given detector surface. The unit of angle is ``rad``.
954 If ``useHighestProbMass=1`` is set, the extrapolation will use the track fit result for the mass hypothesis with the highest pValue.
955 The supported detector surface names are ``{'CDC', 'TOP', 'ARICH', 'ECL', 'KLM'}``.
956 Also, the detector name with number of meaningful-layer is supported, e.g. ``'CDC8'``: last superlayer of CDC, ``'ECL1'``: mid-point of ECL.
957
958 .. note:: You can find more information in `modularAnalysis.calculateTrackIsolation`.
959 )DOC", Manager::VariableDataType::c_double);
960
961
962 REGISTER_VARIABLE("nExtraCDCHits", nExtraCDCHits, R"DOC(
963[Eventbased] The number of CDC hits in the event not assigned to any track.
964
965Returns NaN if there is no event-level tracking information available.
966 )DOC");
967 REGISTER_VARIABLE("nExtraCDCHitsPostCleaning", nExtraCDCHitsPostCleaning, R"DOC(
968[Eventbased] Returns a count of the number of CDC hits in the event not assigned
969to any track nor very likely beam background (i.e. hits that survive a cleanup
970selection).
971
972Returns NaN if there is no event-level tracking information available.
973 )DOC");
974 REGISTER_VARIABLE("hasExtraCDCHitsInLayer(i)", hasExtraCDCHitsInLayer, R"DOC(
975[Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC layer,
9760 otherwise.
977
978Returns NaN if there is no event-level tracking information available.
979 )DOC");
980 REGISTER_VARIABLE("hasExtraCDCHitsInSuperLayer(i)", hasExtraCDCHitsInSuperLayer, R"DOC(
981[Eventbased] Returns 1 if a non-assigned hit exists in the specified CDC
982SuperLayer, 0 otherwise.
983
984Returns NaN if there is no event-level tracking information available.
985 )DOC");
986 REGISTER_VARIABLE("nExtraCDCSegments", nExtraCDCSegments, R"DOC(
987[Eventbased] Returns the number of CDC segments not assigned to any track.
988
989Returns NaN if there is no event-level tracking information available.
990 )DOC");
991 // TODO: once the Tracking group fill the dataobject these can be
992 // uncommented - at the moment they are not filled, so leave out
993 //REGISTER_VARIABLE("nExtraVXDHitsInLayer(i)", nExtraVXDHitsInLayer,
994 //"[Eventbased] The number VXD hits not assigned in the specified VXD layer");
995 //REGISTER_VARIABLE("nExtraVXDHits", nExtraVXDHits, "[Eventbased] The number of VXD hits not assigned to any track");
996 REGISTER_VARIABLE("nExtraPXDHits", nExtraPXDHits, "[Eventbased] The number of PXD hits not assigned to any track");
997 //REGISTER_VARIABLE("svdFirstSampleTime", svdFirstSampleTime, "[Eventbased] The time of first SVD sample relatvie to event T0");
998 REGISTER_VARIABLE("trackFindingFailureFlag", trackFindingFailureFlag, R"DOC(
999[Eventbased] Returns a flag set by the tracking if there is reason to assume
1000there was a track in the event missed by the tracking, or the track finding was
1001(partly) aborted for this event.
1002
1003Returns NaN if there is no event-level tracking information available.
1004 )DOC");
1005
1006 REGISTER_VARIABLE("isTrackFlippedAndRefitted", isTrackFlippedAndRefitted, R"DOC(
1007Returns 1 if the charged final state particle comes from a track that has been flipped and refitted
1008at the end of the tracking chain, in particular before the outer detector reconstruction.
1009 )DOC");
1010
1011 REGISTER_VARIABLE("trackTime", getTrackTime, R"DOC(
1012Returns the time at which the track is produced relative to the time of the collision (given by SVD EventT0).
1013Both the time of the collision and the track time are computed using only SVD hits.
1014Returns NaN if SVD EventT0 is NaN, or if no SVD Hits are attached to the track.
1015For more details, see :ref:`Time Extraction <tracking_eventTimeExtraction>` page.
1016
1017)DOC", "ns");
1018
1019 REGISTER_VARIABLE("trackLength", getTrackLength, R"DOC(
1020Returns the arc length of the helix for the TrackFitResult associated with the particle.
1021The arc length is measured from the track origin to the radius of the CDC layer in which the Track has a hit.
1022Returns NaN if the particle has no CDC Hits.
1023
1024)DOC", "cm");
1025
1026
1027 }
1029}
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.