12 #include <tracking/modules/trackFinderMCTruth/TrackFinderMCTruthRecoTracksModule.h>
14 #include <framework/datastore/StoreArray.h>
15 #include <framework/datastore/RelationArray.h>
16 #include <framework/datastore/StoreObjPtr.h>
17 #include <framework/dataobjects/EventMetaData.h>
18 #include <framework/gearbox/Const.h>
19 #include <mdst/dataobjects/MCParticle.h>
20 #include <cdc/dataobjects/CDCHit.h>
21 #include <cdc/dataobjects/CDCSimHit.h>
22 #include <cdc/geometry/CDCGeometryPar.h>
23 #include <pxd/dataobjects/PXDTrueHit.h>
24 #include <pxd/dataobjects/PXDCluster.h>
25 #include <svd/dataobjects/SVDTrueHit.h>
26 #include <svd/dataobjects/SVDCluster.h>
27 #include <top/dataobjects/TOPBarHit.h>
28 #include <tracking/dataobjects/RecoTrack.h>
29 #include <simulation/monopoles/MonopoleConstants.h>
31 #include <framework/geometry/BFieldManager.h>
32 #include <framework/dataobjects/Helix.h>
56 setDescription(
"Uses the MC information to create genfit::TrackCandidates for primary MCParticles and Relations between them. "
57 "Fills the created genfit::TrackCandidates with all information (start values, hit indices) needed for the fitting.");
58 setPropertyFlags(c_ParallelProcessingCertified);
61 addParam(
"UsePXDHits",
63 "Set true if PXDHits or PXDClusters should be used",
65 addParam(
"UseSVDHits",
67 "Set true if SVDHits or SVDClusters should be used",
69 addParam(
"UseCDCHits",
71 "Set true if CDCHits should be used",
73 addParam(
"UseOnlyAxialCDCHits",
74 m_useOnlyAxialCDCHits,
75 "Set true if only the axial CDCHits should be used",
79 "Set the number of loops whose hits will be marked as priortiy hits. All other hits "
80 "will be marked as auxiliary and therfore not considered for efficiency computations "
81 "By default, all hits will be priority hits.",
83 addParam(
"UseOnlyBeforeTOP",
85 "Mark hits as auxiliary after the track left the CDC and touched the TOP detector "
86 "(only implemented for CDCHits).",
88 addParam(
"UseReassignedHits",
90 "Include hits reassigned from discarded seconardy daughters in the tracks.",
92 addParam(
"UseSecondCDCHits",
94 "Also includes the CDC 2nd hit information in the MC tracks.",
96 addParam(
"MinPXDHits",
98 "Minimum number of PXD hits needed to allow the created of a track candidate",
100 addParam(
"MinSVDHits",
102 "Minimum number of SVD hits needed to allow the created of a track candidate",
104 addParam(
"MinCDCAxialHits",
106 "Minimum number of CDC hits form an axial wire needed to allow the created of a track candidate",
108 addParam(
"MinCDCStereoHits",
110 "Minimum number of CDC hits form a stereo wire needed to allow the created of a track candidate",
112 addParam(
"AllowFirstCDCSuperLayerOnly",
113 m_allowFirstCDCSuperLayerOnly,
114 "Allow tracks to pass the stereo hit requirement if they touched only the first (axial) CDC layer",
117 addParam(
"MinimalNDF",
119 "Minimum number of total hits needed to allow the creation of a track candidate. "
120 "It is called NDF (number of degrees of freedom) because it counts the dimensionality. "
121 "2D hits are counted as 2",
126 addParam(
"WhichParticles",
128 "List of keywords to mark what properties particles must have to get a track candidate. "
129 "If several properties are given all of them must be true: "
130 "\"primary\" particle must come from the generator, "
131 "\"PXD\", \"SVD\", \"CDC\", \"TOP\", \"ARICH\", \"ECL\" or \"KLM\" particle must have hits in the subdetector with that name. "
132 "\"is:X\" where X is a PDG code: particle must have this code. "
133 "\"from:X\" any of the particles's ancestors must have this (X) code",
134 std::vector<std::string>(1,
"primary"));
136 addParam(
"EnergyCut",
138 "Track candidates are only created for MCParticles with energy larger than this cut ",
143 "Set true if track candidates should be created also for neutral particles",
146 addParam(
"MergeDecayInFlight",
147 m_mergeDecayInFlight,
148 "Merge decay in flights that produce a single charged particle to the mother particle",
151 addParam(
"SetTimeSeed",
153 "Set true to forward the production time as time seed of the particles to the RecoTrack",
159 "Smearing of MCMomentum/MCVertex prior to storing it in genfit::TrackCandidate (in %). "
160 "A negative value will switch off smearing. This is also the default.",
163 addParam(
"SmearingCov",
165 "Covariance matrix used to smear the true pos and mom before passed to track candidate. "
166 "This matrix will also passed to Genfit as the initial covarance matrix. "
167 "If any diagonal value is negative this feature will not be used. "
168 "OFF DIAGONAL ELEMENTS DO NOT HAVE AN EFFECT AT THE MOMENT",
169 std::vector<double>(36, -1.0));
171 addParam(
"SplitAfterDeltaT",
173 "Minimal time delay between two sim hits (in ns) after which MC reco track will be "
174 "split into seperate tracks. If < 0, don't do splitting."
175 "This feature was designed to be used in MC cosmics reconstruction to get two MCRecoTracks"
176 "when track pass through empty SVD region, so that number of MCRecoTracks can be compared with"
177 "number of non merged reco tracks. ",
181 addParam(
"RecoTracksStoreArrayName",
182 m_recoTracksStoreArrayName,
183 "Name of store array holding the RecoTracks (output)",
186 addParam(
"TrueHitMustExist",
188 "If set true only cluster hits that have a relation to a TrueHit will be included in the track candidate",
191 addParam(
"discardAuxiliaryHits",
192 m_discardAuxiliaryHits,
193 "If set true hits marked as auxiliary (e.g. hits in higher loops) will not be included in the track candidate.",
194 m_discardAuxiliaryHits);
203 if (mcparticles.isOptional()) {
218 for (
int i = 0; i not_eq nProperties; ++i) {
237 std::stringstream(pdgCodeString) >> aPdgCode;
238 B2DEBUG(20,
"PDG code added to m_particlePdgCodes " << aPdgCode <<
" *******");
242 std::stringstream(pdgCodeString) >> aPdgCode;
243 B2DEBUG(20,
"PDG code added to m_fromPdgCodes " << aPdgCode <<
" *******");
246 B2FATAL(
"Invalid values were given to the MCTrackFinder parameter WhichParticles");
255 B2FATAL(
"SmearingCov does not have exactly 36 elements. So 6x6 covariance matrix can be formed from it");
259 for (
int i = 0; i != 6; ++i) {
266 B2FATAL(
"Both relative smearing (Smearing) and using a smearing cov (SmearingCov) is activated but only one of both can be used");
283 B2DEBUG(20,
"Skipping MC Track Finder as there are no MC Particles registered in the DataStore.");
288 const int eventCounter = eventMetaDataPtr->getEvent();
289 B2DEBUG(20,
"******* MCTrackFinderModule processing event number: " << eventCounter <<
" *******");
293 const int nMcParticles = mcParticles.
getEntries();
294 B2DEBUG(20,
"MCTrackFinder: total Number of MCParticles: " << nMcParticles);
298 const int nPXDHits = pxdTrueHits.
getEntries();
299 B2DEBUG(20,
"MCTrackFinder: Number of PXDTrueHits: " << nPXDHits);
302 const int nMcPartToPXDHits = mcPartToPXDTrueHits.
getEntries();
303 B2DEBUG(20,
"MCTrackFinder: Number of relations between MCParticles and PXDHits: " << nMcPartToPXDHits);
307 const int nPXDClusters = pxdClusters.
getEntries();
308 B2DEBUG(20,
"MCTrackFinder: Number of PXDClusters: " << nPXDClusters);
310 RelationArray pxdClusterToMCParticle(pxdClusters, mcParticles);
311 const int nPxdClusterToMCPart = pxdClusterToMCParticle.
getEntries();
312 B2DEBUG(20,
"MCTrackFinder: Number of relations between PXDCluster and MCParticles: " << nPxdClusterToMCPart);
316 const int nSVDHits = svdTrueHits.
getEntries();
317 B2DEBUG(20,
"MCTrackFinder: Number of SVDDHits: " << nSVDHits);
320 const int nMcPartToSVDHits = mcPartToSVDTrueHits.
getEntries();
321 B2DEBUG(20,
"MCTrackFinder: Number of relations between MCParticles and SVDHits: " << nMcPartToSVDHits);
325 const int nSVDClusters = svdClusters.
getEntries();
326 B2DEBUG(20,
"MCTrackFinder: Number of SVDClusters: " << nSVDClusters);
328 RelationArray svdClusterToMCParticle(svdClusters, mcParticles);
329 const int nSvdClusterToMCPart = svdClusterToMCParticle.
getEntries();
330 B2DEBUG(20,
"MCTrackFinder: Number of relations between SVDCluster and MCParticles: " << nSvdClusterToMCPart);
335 B2DEBUG(20,
"MCTrackFinder: Number of CDCHits: " << nCDCHits);
338 const int nMcPartToCDCHits = mcPartToCDCHits.
getEntries();
339 B2DEBUG(20,
"MCTrackFinder: Number of relations between MCParticles and CDCHits: " << nMcPartToCDCHits);
342 const int nCDCSimHits = cdcSimHits.
getEntries();
343 B2DEBUG(20,
"MCTrackFinder: Number of CDCSimHits: " << nCDCSimHits);
346 const int nCdcSimHitToHitRel = cdcSimHitToHitRel.
getEntries();
347 B2DEBUG(20,
"MCTrackFinder: Number of relations between CDCSimHit and CDCHits: " << nCdcSimHitToHitRel);
356 std::set<int> alreadyConsumedMCParticles;
357 for (
int iPart = 0; iPart < nMcParticles; ++iPart) {
358 if (alreadyConsumedMCParticles.count(iPart))
continue;
359 alreadyConsumedMCParticles.insert(iPart);
361 MCParticle* aMcParticlePtr = mcParticles[iPart];
364 B2DEBUG(20,
"Particle that did not propagate significantly cannot make track.");
369 int mcParticleProperties = 0;
371 mcParticleProperties += 1;
374 mcParticleProperties += 2;
377 mcParticleProperties += 4;
380 mcParticleProperties += 8;
383 mcParticleProperties += 16;
386 mcParticleProperties += 32;
389 mcParticleProperties += 64;
392 mcParticleProperties += 128;
396 B2DEBUG(20,
"PDG: " << aMcParticlePtr->
getPDG() <<
" | property mask of particle " << mcParticleProperties <<
402 B2DEBUG(20,
"particle energy too low. MC particle will be skipped");
409 if (nPdgCodes not_eq 0) {
410 const int currentPdgCode = aMcParticlePtr->
getPDG();
411 int nFalsePdgCodes = 0;
412 for (
int i = 0; i not_eq nPdgCodes; ++i) {
417 if (nFalsePdgCodes == nPdgCodes) {
418 B2DEBUG(20,
"particle does not have one of the user provided pdg codes and will therefore be skipped");
426 if (nFromPdgCodes not_eq 0) {
428 int nFalsePdgCodes = 0;
430 while (currentMother not_eq NULL) {
431 int currentMotherPdgCode = currentMother->
getPDG();
432 for (
int i = 0; i not_eq nFromPdgCodes; ++i) {
438 currentMother = currentMother->
getMother();
441 if (nFalsePdgCodes == (nAncestor * nFromPdgCodes)) {
442 B2DEBUG(20,
"particle does not have and ancestor with one of the user provided pdg codes and will therefore be skipped");
449 if (abs(aMcParticlePtr->
getPDG()) > 1000000000
450 && abs(aMcParticlePtr->
getPDG()) != 1000010020) {
451 B2DEBUG(20,
"Skipped Baryon.");
457 if (!
m_neutrals && (aMcParticlePtr->
getCharge() == 0 && abs(aMcParticlePtr->
getPDG()) != Monopoles::c_monopolePDGCode)) {
458 B2DEBUG(20,
"particle does not have the right charge. MC particle will be skipped");
463 B2DEBUG(20,
"Build a track for the MCParticle with index: " << iPart <<
" (PDG: " << aMcParticlePtr->
getPDG() <<
")");
465 std::vector<const MCParticle*> trackMCParticles;
466 trackMCParticles.push_back(aMcParticlePtr);
469 std::vector<MCParticle*> daughters = aMcParticlePtr->
getDaughters();
470 std::vector<MCParticle*> decayInFlightParticles;
472 if (daughter->getSecondaryPhysicsProcess() > 200 and daughter->getCharge() != 0) {
473 decayInFlightParticles.push_back(daughter);
476 if (decayInFlightParticles.size() == 1) {
477 trackMCParticles.push_back(decayInFlightParticles.front());
478 alreadyConsumedMCParticles.insert(trackMCParticles.back()->getArrayIndex());
487 typedef std::tuple<double, int, RecoHitInformation::OriginTrackFinder, Const::EDetector> TimeHitIDDetector;
488 std::vector<TimeHitIDDetector> hitsWithTimeAndDetectorInformation;
495 for (
const MCParticle* trackMCParticle : trackMCParticles) {
498 for (
size_t i = 0; i < relatedClusters.
size(); ++i) {
499 bool isReassigned = relatedClusters.
weight(i) < 0;
503 auto mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderPriorityHit;
507 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
512 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
516 if (
m_discardAuxiliaryHits and mcFinder == RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit)
continue;
528 for (
const PXDTrueHit& pxdTrueHit : relatedTrueHits) {
532 if (std::find_if(relatedMCParticles.
begin(),
533 relatedMCParticles.
end(),
534 [trackMCParticle](
const MCParticle & mcParticle) {
535 return &mcParticle == trackMCParticle;
536 }) != relatedMCParticles.
end()) {
537 time = pxdTrueHit.getGlobalTime();
541 if (not std::isnan(time)) {
542 hitsWithTimeAndDetectorInformation.emplace_back(time, pxdCluster->
getArrayIndex(), mcFinder, Const::PXD);
548 B2DEBUG(20,
" add " << hitCounter <<
" PXDClusters. " << relatedClusters.
size() - hitCounter <<
549 " PXDClusters were not added because they do not have a corresponding PXDTrueHit");
561 for (
const MCParticle* trackMCParticle : trackMCParticles) {
564 for (
size_t i = 0; i < relatedClusters.
size(); ++i) {
565 bool isReassigned = relatedClusters.
weight(i) < 0;
568 auto mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderPriorityHit;
572 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
577 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
581 if (
m_discardAuxiliaryHits and mcFinder == RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit)
continue;
593 for (
const SVDTrueHit& svdTrueHit : relatedTrueHits) {
597 if (std::find_if(relatedMCParticles.
begin(),
598 relatedMCParticles.
end(),
599 [trackMCParticle](
const MCParticle & mcParticle) {
600 return &mcParticle == trackMCParticle;
601 }) != relatedMCParticles.
end()) {
602 time = svdTrueHit.getGlobalTime();
606 if (not std::isnan(time)) {
607 hitsWithTimeAndDetectorInformation.emplace_back(time, svdCluster->
getArrayIndex(), mcFinder, Const::SVD);
613 B2DEBUG(20,
" add " << hitCounter <<
" SVDClusters. " << relatedClusters.
size() - hitCounter <<
614 " SVDClusters were not added because they do not have a corresponding SVDTrueHit");
624 auto didParticleExitCDC = [](
const CDCHit * hit) {
626 if (not simHit)
return false;
629 if (not mcParticle)
return false;
630 if (not mcParticle->hasSeenInDetector(Const::TOP))
return false;
633 if (topHits.
size() == 0)
return false;
637 return lhs.
getTime() < rhs.getTime();
639 auto itFirstTopHit = std::min_element(topHits.
begin(), topHits.
end(), lessTime);
641 return simHit->getGlobalTime() > itFirstTopHit->getTime();
648 std::array<int, 9> nHitsBySuperLayerId{};
650 for (
const MCParticle* trackMCParticle : trackMCParticles) {
653 for (
size_t i = 0; i < relatedHits.
size(); ++i) {
654 bool isReassigned = relatedHits.
weight(i) < 0;
664 auto mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderPriorityHit;
668 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
673 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
678 mcFinder = RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit;
682 if (
m_discardAuxiliaryHits and mcFinder == RecoHitInformation::OriginTrackFinder::c_MCTrackFinderAuxiliaryHit)
continue;
687 if (not aCDCSimHitPtr) {
688 B2DEBUG(20,
" Skipping CDCHit without related CDCSimHit.");
691 double time = aCDCSimHitPtr->getFlightTime();
695 if (superLayerId % 2 == 0) {
696 hitsWithTimeAndDetectorInformation.emplace_back(time, cdcHit->
getArrayIndex(), mcFinder, Const::CDC);
699 ++nHitsBySuperLayerId[superLayerId];
702 hitsWithTimeAndDetectorInformation.emplace_back(time, cdcHit->
getArrayIndex(), mcFinder, Const::CDC);
705 ++nHitsBySuperLayerId[superLayerId];
710 B2DEBUG(20,
" added " << nAxialHits <<
" axial and " << nStereoHits <<
" stereo CDCHits");
719 nHitsBySuperLayerId[0] == nAxialHits and
739 std::sort(hitsWithTimeAndDetectorInformation.begin(), hitsWithTimeAndDetectorInformation.end(),
740 [](
const TimeHitIDDetector & rhs,
const TimeHitIDDetector & lhs) {
741 return std::get<0>(rhs) < std::get<0>(lhs);
747 std::vector< std::vector<TimeHitIDDetector> > hitsWithTimeAndDetectorInformationVectors;
750 hitsWithTimeAndDetectorInformationVectors.push_back(hitsWithTimeAndDetectorInformation);
753 std::vector<TimeHitIDDetector>::size_type splitFromIdx = 0;
754 for (std::vector<TimeHitIDDetector>::size_type i = 1; i != hitsWithTimeAndDetectorInformation.size(); i++) {
756 double delta_t = (std::get<0>(hitsWithTimeAndDetectorInformation[i])
757 - std::get<0>(hitsWithTimeAndDetectorInformation[i - 1]));
761 hitsWithTimeAndDetectorInformationVectors
762 .emplace_back(hitsWithTimeAndDetectorInformation.begin() + splitFromIdx,
763 hitsWithTimeAndDetectorInformation.begin() + i);
768 hitsWithTimeAndDetectorInformationVectors
769 .emplace_back(hitsWithTimeAndDetectorInformation.begin() + splitFromIdx,
770 hitsWithTimeAndDetectorInformation.end());
775 B2DEBUG(20,
"We came pass all filter of the MCPartile and hit properties. TrackCandidate " << counter <<
776 " will be created from the MCParticle with index: " << iPart <<
" (PDG: " << aMcParticlePtr->
getPDG() <<
")");
782 TVector3 momentumTrue = aMcParticlePtr->
getMomentum();
786 TVector3 momentum = momentumTrue;
787 TVector3 position = positionTrue;
788 double time = timeTrue;
789 TVectorD stateSeed(6);
790 TMatrixDSym covSeed(6);
792 covSeed(0, 0) = 1; covSeed(1, 1) = 1; covSeed(2, 2) = 2 * 2;
793 covSeed(3, 3) = 0.1 * 0.1; covSeed(4, 4) = 0.1 * 0.1; covSeed(5, 5) = 0.2 * 0.2;
801 double smearedX = gRandom->Gaus(positionTrue.x(), smearing * positionTrue.x());
802 double smearedY = gRandom->Gaus(positionTrue.y(), smearing * positionTrue.y());
803 double smearedZ = gRandom->Gaus(positionTrue.z(), smearing * positionTrue.z());
804 position.SetXYZ(smearedX, smearedY, smearedZ);
805 double smearedPX = gRandom->Gaus(momentumTrue.x(), smearing * momentumTrue.x());
806 double smearedPY = gRandom->Gaus(momentumTrue.y(), smearing * momentumTrue.y());
807 double smearedPZ = gRandom->Gaus(momentumTrue.z(), smearing * momentumTrue.z());
808 momentum.SetXYZ(smearedPX, smearedPY, smearedPZ);
815 double smearedX = gRandom->Gaus(positionTrue.x(), sqrt(
m_initialCov(0, 0)));
816 double smearedY = gRandom->Gaus(positionTrue.y(), sqrt(
m_initialCov(1, 1)));
817 double smearedZ = gRandom->Gaus(positionTrue.z(), sqrt(
m_initialCov(2, 2)));
818 position.SetXYZ(smearedX, smearedY, smearedZ);
819 double smearedPX = gRandom->Gaus(momentumTrue.x(), sqrt(
m_initialCov(3, 3)));
820 double smearedPY = gRandom->Gaus(momentumTrue.y(), sqrt(
m_initialCov(4, 4)));
821 double smearedPZ = gRandom->Gaus(momentumTrue.z(), sqrt(
m_initialCov(5, 5)));
822 momentum.SetXYZ(smearedPX, smearedPY, smearedPZ);
828 for (
const auto& hitInformationVector : hitsWithTimeAndDetectorInformationVectors) {
831 short int charge =
static_cast<short int>(aMcParticlePtr->
getCharge());
834 if (hitInformationVector.size() != 0) {
836 time = std::get<0>(hitInformationVector.at(0));
839 TLorentzVector lorentzV;
840 lorentzV.SetVectM(momentum, aMcParticlePtr->
get4Vector().M());
841 const double beta_xy = momentum.Perp() / lorentzV.E();
847 momentum = helix.getMomentumAtArcLength2D(arclength2D, Bz);
848 position = helix.getPositionAtArcLength2D(arclength2D);
860 B2DEBUG(20,
" --- Create relation between genfit::TrackCand " << counter <<
" and MCParticle " << iPart);
863 for (
const TimeHitIDDetector& hitInformation : hitInformationVector) {
866 const int hitID = std::get<1>(hitInformation);
867 const auto hitOriginMCFinderType = std::get<2>(hitInformation);
870 if (detectorInformation == Const::CDC) {
871 const CDCHit* cdcHit = cdcHits[hitID];
877 TVector3 simHitPosOnWire = aCDCSimHitPtr->
getPosWire();
880 const unsigned short isRightHit = cdcGeometry.
getNewLeftRightRaw(simHitPosOnWire, simHitPos, simMom);
883 newRecoTrack->
addCDCHit(cdcHit, hitCounter, RecoHitInformation::RightLeftInformation::c_right, hitOriginMCFinderType);
885 newRecoTrack->
addCDCHit(cdcHit, hitCounter, RecoHitInformation::RightLeftInformation::c_left, hitOriginMCFinderType);
887 B2DEBUG(20,
"CDC hit " << hitID <<
" has reft/right sign " << isRightHit);
888 }
else if (detectorInformation == Const::PXD) {
889 const PXDCluster* pxdCluster = pxdClusters[hitID];
890 newRecoTrack->
addPXDHit(pxdCluster, hitCounter, hitOriginMCFinderType);
891 }
else if (detectorInformation == Const::SVD) {
892 const SVDCluster* svdCluster = svdClusters[hitID];
893 newRecoTrack->
addSVDHit(svdCluster, hitCounter, hitOriginMCFinderType);
898 B2DEBUG(20,
"New RecoTrack: #PXDHits: " << newRecoTrack->
getPXDHitList().size() <<
908 template<
class THit,
class TSimHit>
916 const TSimHit* aSimHit =
nullptr;
917 for (
const auto& thisSimHit : relatedSimHits) {
918 mcParticle = thisSimHit.template getRelated<MCParticle>();
919 aSimHit = &thisSimHit;
920 if (mcParticle)
break;
922 if (not mcParticle or not aSimHit) {
930 const float absMom3D = mcParticle->
getMomentum().Mag();
932 const double loopLength = 2 * M_PI * absMom3D / (Bz * 0.00299792458);
933 const double loopTOF = loopLength / speed;
934 if (tof > loopTOF * nLoops) {
947 " number of degrees of freedom (NDF). No Track Candidates were created from them so they will not be passed to the track fitter");
951 " cluster hits did not have a relation to a true hit and were therefore not included in a track candidate");
953 B2INFO(
"The MCTrackFinder created a total of " <<
m_nRecoTracks <<
" track candidates");