Belle II Software development
KinkFitter.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#include <tracking/kinkFinding/fitter/KinkFitter.h>
9
10#include <framework/logging/Logger.h>
11#include <framework/geometry/VectorUtil.h>
12#include <framework/geometry/BFieldManager.h>
13#include <framework/utilities/IOIntercept.h>
14#include <framework/geometry/B2Vector3.h>
15
16#include <tracking/trackFitting/trackBuilder/factories/TrackBuilder.h>
17
18#include <mdst/dataobjects/HitPatternVXD.h>
19#include <mdst/dataobjects/HitPatternCDC.h>
20#include <mdst/dataobjects/Track.h>
21#include <cdc/dataobjects/CDCRecoHit.h>
22#include <pxd/reconstruction/PXDRecoHit.h>
23#include <svd/reconstruction/SVDRecoHit.h>
24#include <svd/reconstruction/SVDRecoHit2D.h>
25
26#include <genfit/TrackPoint.h>
27#include <genfit/MeasuredStateOnPlane.h>
28#include <genfit/FieldManager.h>
29#include <genfit/MaterialEffects.h>
30#include <genfit/FitStatus.h>
31#include <genfit/KalmanFitStatus.h>
32#include <genfit/KalmanFitterInfo.h>
33#include <genfit/KalmanFitterRefTrack.h>
34
35#include <analysis/VertexFitting/KFit/VertexFitKFit.h>
36#include <analysis/utility/ROOTToCLHEP.h>
37#include <CLHEP/Matrix/Matrix.h>
38#include <CLHEP/Matrix/SymMatrix.h>
39#include <CLHEP/Vector/LorentzVector.h>
40#include <CLHEP/Geometry/Point3D.h>
41
42using namespace Belle2;
43
44KinkFitter::KinkFitter(const std::string& trackFitResultsName, const std::string& kinksName,
45 const std::string& recoTracksName, const std::string& copiedRecoTracksName)
46 : m_recoTracksName(recoTracksName), m_kinkFitterMode(1)
47{
48 m_trackFitResults.isRequired(trackFitResultsName);
50
53
55 m_copiedRecoTracks.registerInDataStore(copiedRecoTracksName,
58
61
62 B2ASSERT("Material effects not set up. Please use SetupGenfitExtrapolationModule.",
63 genfit::MaterialEffects::getInstance()->isInitialized());
64 B2ASSERT("Magnetic field not set up. Please use SetupGenfitExtrapolationModule.",
65 genfit::FieldManager::getInstance()->isInitialized());
66}
67
68void KinkFitter::setFitterMode(const unsigned char fitterMode)
69{
70 if (not(fitterMode <= 15)) {
71 B2FATAL("Invalid fitter mode!");
72 } else {
73 m_kinkFitterMode = fitterMode;
74 // filling bits of the fitter mode
75 m_kinkFitterModeHitsReassignment = fitterMode & 0b0001;
76 m_kinkFitterModeFlipAndRefit = fitterMode & 0b0010;
77 m_kinkFitterModeCombineAndFit = fitterMode & 0b0100;
78 m_kinkFitterModeSplitTrack = fitterMode & 0b1000;
79 }
80}
81
82void KinkFitter::initializeCuts(const double vertexDistanceCut,
83 const double vertexChi2Cut,
84 const double precutDistance)
85{
86 m_vertexDistanceCut = vertexDistanceCut;
87 m_vertexChi2Cut = vertexChi2Cut;
88 m_precutDistance = precutDistance;
89}
90
92bool KinkFitter::extrapolateToVertex(genfit::MeasuredStateOnPlane& stMother, genfit::MeasuredStateOnPlane& stDaughter,
93 const ROOT::Math::XYZVector& vertexPos, unsigned int& reassignHitStatus)
94{
95 reassignHitStatus = 0;
96 try {
97 // extrapolate the state to the vertexPos
98 // the value will be positive (negative) if the direction of the extrapolation is (counter)momentum-wise
99 double extralengthMother = stMother.extrapolateToPoint(XYZToTVector(vertexPos));
100 double extralengthDaughter = stDaughter.extrapolateToPoint(XYZToTVector(vertexPos));
101 if (extralengthMother > 0
102 && extralengthDaughter > 0) reassignHitStatus |= 0x1; // both positive means daughter hits to be reassigned to mother
103 if (extralengthMother < 0
104 && extralengthDaughter < 0) reassignHitStatus |= 0x2; // both negative means mother hits to be reassigned to daughter
105 B2DEBUG(29, "extralengthMother=" << extralengthMother << ", extralengthDaughter=" << extralengthDaughter);
106 } catch (...) {
107 // Ideally, this shouldn't happen
108 B2DEBUG(29, "Could not extrapolate track to vertex.");
109 return false;
110 }
111 return true;
112}
113
116 const genfit::MeasuredStateOnPlane& msop,
117 const double Bz,
118 const Const::ParticleType trackHypothesis)
119{
120 const uint64_t hitPatternCDCInitializer = TrackBuilder::getHitPatternCDCInitializer(*recoTrack);
121 const uint32_t hitPatternVXDInitializer = TrackBuilder::getHitPatternVXDInitializer(*recoTrack);
122 const genfit::FitStatus* trackFitStatus = recoTrack->getTrackFitStatus();
123
124 TrackFitResult* kinkTrackFitResult
125 = m_trackFitResults.appendNew(ROOT::Math::XYZVector(msop.getPos()), ROOT::Math::XYZVector(msop.getMom()),
126 msop.get6DCov(), msop.getCharge(),
127 trackHypothesis,
128 trackFitStatus->getPVal(),
129 Bz, hitPatternCDCInitializer, hitPatternVXDInitializer,
130 trackFitStatus->getNdf());
131 return kinkTrackFitResult;
132}
133
136 ROOT::Math::XYZVector& vertexPos,
137 int direction)
138{
139
140 if (direction != 1 && direction != -1) {
141 B2WARNING("KinkFitter::findHitPositionForReassignment: the direction is not +-1, although should be. "
142 "Set to +1 (-1) for direction > 0 (< 0).");
143 if (direction > 0)
144 direction = 1;
145 else
146 direction = -1;
147 }
148
149 // Helper variables to store the minimum
150 double minimalDistance2 = std::numeric_limits<double>::max();
151 int minimalIndex = 0;
152 int riHit;
153
154 // CDC Hits list to loop over
155 auto cdcHits = recoTrack->getSortedCDCHitList();
156
157
158 for (int cdcHitIndex = 0; cdcHitIndex < static_cast<int>(cdcHits.size()); ++cdcHitIndex) {
159 if (direction > 0)
160 riHit = cdcHitIndex;
161 else
162 riHit = static_cast<int>(cdcHits.size()) - 1 - cdcHitIndex;
163
164 auto recoHitInfo = recoTrack->getRecoHitInformation(cdcHits[riHit]);
165 if (!recoHitInfo->useInFit()) continue;
166 try {
167 const genfit::MeasuredStateOnPlane& measuredStateOnPlane = recoTrack->getMeasuredStateOnPlaneFromRecoHit(
168 recoHitInfo);
169 const double currentDistance2 = (ROOT::Math::XYZVector(measuredStateOnPlane.getPos()) - vertexPos).Mag2();
170
171 if (currentDistance2 < minimalDistance2) {
172 minimalDistance2 = currentDistance2;
173 minimalIndex = cdcHitIndex;
174 }
175 // if it cannot find minimum in 3 iterations, stop searching
176 if (cdcHitIndex - minimalIndex > 3) break;
177 } catch (const NoTrackFitResult& exception) {
178 B2DEBUG(29, "Can not get mSoP because of: " << exception.what());
179 continue;
180 } catch (const genfit::Exception& exception) {
181 B2DEBUG(29, "Can not get mSoP because of: " << exception.what());
182 continue;
183 }
184 }
185 if (minimalIndex == 0)
186 return -1 * direction;
187 else
188 return -(minimalIndex * direction);
189
190}
191
194 const bool motherFlag, const int delta)
195{
196
197 // lists of CDC hits of mother and daughter tracks
198 const auto motherCDCHit = motherRecoTrack->getSortedCDCHitList();
199 const auto daughterCDCHit = daughterRecoTrack->getSortedCDCHitList();
200
201 // initialization of helper variables
202 const int deltaMother = delta > 0 ? -delta : 0;
203 const int deltaDaughter = delta < 0 ? -delta : 0;
204 int sortingParameterOffset = 0;
205
206 // pointer to a track to be copied
207 RecoTrack* recoTrackToCopy = nullptr;
208 if (motherFlag) {
209 recoTrackToCopy = motherRecoTrack;
210 } else {
211 recoTrackToCopy = daughterRecoTrack;
212 }
213
214 // copy recoTracks to a separate StoreArray using seed information
215 RecoTrack* recoTrack = m_copiedRecoTracks.appendNew(ROOT::Math::XYZVector(recoTrackToCopy->getPositionSeed()),
216 ROOT::Math::XYZVector(recoTrackToCopy->getMomentumSeed()),
217 static_cast<short>(recoTrackToCopy->getChargeSeed()),
218 recoTrackToCopy->getStoreArrayNameOfPXDHits(),
219 recoTrackToCopy->getStoreArrayNameOfSVDHits(),
220 recoTrackToCopy->getStoreArrayNameOfCDCHits(),
221 recoTrackToCopy->getStoreArrayNameOfBKLMHits(),
222 recoTrackToCopy->getStoreArrayNameOfEKLMHits(),
223 recoTrackToCopy->getStoreArrayNameOfRecoHitInformation());
224 recoTrack->setTimeSeed(recoTrackToCopy->getTimeSeed());
225 recoTrack->setSeedCovariance(recoTrackToCopy->getSeedCovariance());
226
227 if (motherFlag) {
228
229 // copy PXD hits (we have checked in KinkFinderModule that there are no PXD hits on the other side of the track)
230 for (const auto* pxdHit : recoTrackToCopy->getPXDHitList()) {
231 auto recoHitInfo = recoTrackToCopy->getRecoHitInformation(pxdHit);
232 recoTrack->addPXDHit(pxdHit, recoHitInfo->getSortingParameter(),
233 recoHitInfo->getFoundByTrackFinder());
234 }
235
236 // copy SVD hits (we have checked in KinkFinderModule that there are no SVD hits on the other side of the track)
237 for (const auto* svdHit : recoTrackToCopy->getSVDHitList()) {
238 auto recoHitInfo = recoTrackToCopy->getRecoHitInformation(svdHit);
239 recoTrack->addSVDHit(svdHit, recoHitInfo->getSortingParameter(),
240 recoHitInfo->getFoundByTrackFinder());
241 }
242
243 // copy CDC hits with respect to reassignment
244 for (size_t motherCDCHitIndex = 0; motherCDCHitIndex < motherCDCHit.size() + deltaMother; ++motherCDCHitIndex) {
245 auto recoHitInfo = motherRecoTrack->getRecoHitInformation(motherCDCHit[motherCDCHitIndex]);
246 recoTrack->addCDCHit(motherCDCHit[motherCDCHitIndex],
247 recoHitInfo->getSortingParameter(),
248 recoHitInfo->getRightLeftInformation(),
249 recoHitInfo->getFoundByTrackFinder());
250
251 }
252 sortingParameterOffset = recoTrack->getNumberOfTotalHits();
253 for (size_t daughterCDCHitIndex = 0; daughterCDCHitIndex < static_cast<unsigned int>(deltaDaughter); ++daughterCDCHitIndex) {
254 auto recoHitInfo = daughterRecoTrack->getRecoHitInformation(daughterCDCHit[daughterCDCHitIndex]);
255 recoTrack->addCDCHit(daughterCDCHit[daughterCDCHitIndex],
256 recoHitInfo->getSortingParameter() + sortingParameterOffset,
257 recoHitInfo->getRightLeftInformation(),
258 recoHitInfo->getFoundByTrackFinder());
259
260 }
261
262 // we do not want to have KLM hits in mother track even if they exist
263
264 } else {
265
266 // In case of hit reassignment, we do not want to have VXD hits in the beginning of daughter track
267 // even if they exist (absence of VXD hits at the end of the track was checked in KinkFinderModule)
268
269 if (deltaMother)
270 sortingParameterOffset = motherRecoTrack->getRecoHitInformation(motherCDCHit[motherCDCHit.size() +
271 deltaMother])->getSortingParameter();
272 // copy CDC hits with respect to reassignment
273 for (size_t motherCDCHitIndex = motherCDCHit.size() + deltaMother; motherCDCHitIndex < motherCDCHit.size(); ++motherCDCHitIndex) {
274 auto recoHitInfo = motherRecoTrack->getRecoHitInformation(motherCDCHit[motherCDCHitIndex]);
275 recoTrack->addCDCHit(motherCDCHit[motherCDCHitIndex],
276 recoHitInfo->getSortingParameter() - sortingParameterOffset,
277 recoHitInfo->getRightLeftInformation(),
278 recoHitInfo->getFoundByTrackFinder());
279
280 }
281 sortingParameterOffset = -deltaMother - deltaDaughter;
282 for (size_t daughterCDCHitIndex = deltaDaughter; daughterCDCHitIndex < daughterCDCHit.size(); ++daughterCDCHitIndex) {
283 auto recoHitInfo = daughterRecoTrack->getRecoHitInformation(daughterCDCHit[daughterCDCHitIndex]);
284 recoTrack->addCDCHit(daughterCDCHit[daughterCDCHitIndex],
285 recoHitInfo->getSortingParameter() + sortingParameterOffset,
286 recoHitInfo->getRightLeftInformation(),
287 recoHitInfo->getFoundByTrackFinder());
288
289 }
290
291 // copy BKLM hits
292 for (const auto* bklmHit : recoTrackToCopy->getBKLMHitList()) {
293 auto recoHitInfo = recoTrackToCopy->getRecoHitInformation(bklmHit);
294 recoTrack->addBKLMHit(bklmHit, recoHitInfo->getSortingParameter() + sortingParameterOffset,
295 recoHitInfo->getFoundByTrackFinder());
296 }
297
298 // copy EKLM hits
299 for (const auto* eklmHit : recoTrackToCopy->getEKLMHitList()) {
300 auto recoHitInfo = recoTrackToCopy->getRecoHitInformation(eklmHit);
301 recoTrack->addEKLMHit(eklmHit, recoHitInfo->getSortingParameter() + sortingParameterOffset,
302 recoHitInfo->getFoundByTrackFinder());
303 }
304 }
305
306 return recoTrack;
307
308}
309
311bool KinkFitter::refitRecoTrackAfterReassign(RecoTrack* recoTrackMotherRefit, RecoTrack* recoTrackDaughterRefit,
312 const RecoTrack* recoTrackMother, const RecoTrack* recoTrackDaughter)
313{
314
315 // initialize fitter
316 TrackFitter trackFitterDAF;
317 // fit the new tracks
318 trackFitterDAF.fit(*recoTrackMotherRefit);
319 trackFitterDAF.fit(*recoTrackDaughterRefit);
320
321 if (!recoTrackMotherRefit->wasFitSuccessful() || !recoTrackDaughterRefit->wasFitSuccessful()) {
322 B2DEBUG(29, "Refit of the tracks with reassigned hits failed ");
323 return false;
324 }
325
326 const genfit::FitStatus* motherTrackFitStatus = recoTrackMother->getTrackFitStatus();
327 const genfit::FitStatus* daughterTrackFitStatus = recoTrackDaughter->getTrackFitStatus();
328 const double chi2MotherInit = motherTrackFitStatus->getChi2();
329 const double chi2DaughterInit = daughterTrackFitStatus->getChi2();
330 const double ndfMotherInit = motherTrackFitStatus->getNdf();
331 const double ndfDaughterInit = daughterTrackFitStatus->getNdf();
332 B2DEBUG(29, "Initial mother fit result, p-value: " << motherTrackFitStatus->getPVal() << ", chi2: " <<
333 chi2MotherInit << ", ndf: " << ndfMotherInit);
334 B2DEBUG(29, "Initial daughter fit result, p-value: " << daughterTrackFitStatus->getPVal() << ", chi2: " <<
335 chi2DaughterInit << ", ndf: " << ndfDaughterInit);
336
337 const genfit::FitStatus* motherNewTrackFitStatus = recoTrackMotherRefit->getTrackFitStatus();
338 const genfit::FitStatus* daughterNewTrackFitStatus = recoTrackDaughterRefit->getTrackFitStatus();
339 const double chi2Mother = motherNewTrackFitStatus->getChi2();
340 const double chi2Daughter = daughterNewTrackFitStatus->getChi2();
341 const double ndfMother = motherNewTrackFitStatus->getNdf();
342 const double ndfDaughter = daughterNewTrackFitStatus->getNdf();
343 B2DEBUG(29, "New mother fit result, p-value: " << motherNewTrackFitStatus->getPVal() << ", chi2: " <<
344 chi2Mother << ", ndf: " << ndfMother);
345 B2DEBUG(29, "New daughter fit result, p-value: " << daughterNewTrackFitStatus->getPVal() << ", chi2: " <<
346 chi2Daughter << ", ndf: " << ndfDaughter);
347
348 // Fit is assumed to be successful if it improves sum of the chi2 divided by sum of ndf of two tracks
349 if ((chi2Mother + chi2Daughter) / (ndfMother + ndfDaughter) < (chi2MotherInit + chi2DaughterInit) /
350 (ndfMotherInit + ndfDaughterInit))
351 return true;
352 else
353 return false;
354
355}
356
359 const ROOT::Math::XYZVector& momentumSeed,
360 const ROOT::Math::XYZVector& positionSeed,
361 const double& timeSeed)
362{
363 // copy recoTracks to a separate StoreArray using seed information
364 RecoTrack* newRecoTrack = m_copiedRecoTracks.appendNew(positionSeed, -momentumSeed,
365 static_cast<short>(-recoTrack->getChargeSeed()),
366 recoTrack->getStoreArrayNameOfPXDHits(),
367 recoTrack->getStoreArrayNameOfSVDHits(),
368 recoTrack->getStoreArrayNameOfCDCHits(),
369 recoTrack->getStoreArrayNameOfBKLMHits(),
370 recoTrack->getStoreArrayNameOfEKLMHits(),
372 newRecoTrack->setTimeSeed(timeSeed);
373 newRecoTrack->setSeedCovariance(recoTrack->getSeedCovariance());
374 newRecoTrack->addHitsFromRecoTrack(recoTrack, 0, true);
375
376 // initialize fitter
377 TrackFitter trackFitterKF;
378 // DAF fitter usually works badly with flipped tracks, so kalmanFitter is used instead
379 std::shared_ptr<genfit::KalmanFitterRefTrack> kalmanFitter = std::make_shared<genfit::KalmanFitterRefTrack>();
380 kalmanFitter->setMinIterations(static_cast<unsigned int>(3));
381 kalmanFitter->setMaxIterations(static_cast<unsigned int>(10));
382 kalmanFitter->setMaxFailedHits(static_cast<unsigned int>(5));
383 trackFitterKF.resetFitter(kalmanFitter);
384 // fit the new track
385 trackFitterKF.fit(*newRecoTrack);
386
387 return newRecoTrack;
388}
389
392 const ROOT::Math::XYZVector& momentumSeed,
393 const ROOT::Math::XYZVector& positionSeed,
394 const double& timeSeed,
395 const bool blockInnerStereoHits, const bool useAnotherFitter)
396{
397
398 // copy recoTracks to a separate StoreArray using seed information
399 RecoTrack* newRecoTrack = m_copiedRecoTracks.appendNew(positionSeed, momentumSeed,
400 static_cast<short>(recoTrack->getChargeSeed()),
401 recoTrack->getStoreArrayNameOfPXDHits(),
402 recoTrack->getStoreArrayNameOfSVDHits(),
403 recoTrack->getStoreArrayNameOfCDCHits(),
404 recoTrack->getStoreArrayNameOfBKLMHits(),
405 recoTrack->getStoreArrayNameOfEKLMHits(),
407 newRecoTrack->setTimeSeed(timeSeed);
408 newRecoTrack->setSeedCovariance(recoTrack->getSeedCovariance());
409 newRecoTrack->addHitsFromRecoTrack(recoTrack);
410
411 // block the hits in the first stereo layer and all before (leave at least 6 hits for fit)
412 // (usually, wrong assignment of first stereo layer is responsible for wrong z coordinate)
413 if (blockInnerStereoHits) {
414 bool passedStereo = false;
415 auto newCDCHitRefit = newRecoTrack->getSortedCDCHitList();
416 for (int daughterCDCHitIndex = 0; daughterCDCHitIndex < static_cast<int>(newCDCHitRefit.size()) - 6; ++daughterCDCHitIndex) {
417 if (!passedStereo && (newCDCHitRefit[daughterCDCHitIndex]->getISuperLayer() % 2 != 0))
418 passedStereo = true;
419 if (passedStereo && (newCDCHitRefit[daughterCDCHitIndex]->getISuperLayer() % 2 == 0))
420 break;
421 auto recoHitInfo = newRecoTrack->getRecoHitInformation(newCDCHitRefit[daughterCDCHitIndex]);
422 recoHitInfo->setUseInFit(false);
423 }
424 }
425
426 // fit the new track
427 // initialize fitter
428 TrackFitter trackFitter;
429 // if useAnotherFitter true, set ordinary KalmanFilter (for filterFlag 6 it performs better than DAF)
430 if (useAnotherFitter) {
431 std::shared_ptr<genfit::KalmanFitterRefTrack> kalmanFitter = std::make_shared<genfit::KalmanFitterRefTrack>();
432 kalmanFitter->setMinIterations(static_cast<unsigned int>(3));
433 kalmanFitter->setMaxIterations(static_cast<unsigned int>(10));
434 kalmanFitter->setMaxFailedHits(static_cast<unsigned int>(5));
435 trackFitter.resetFitter(kalmanFitter);
436
437 trackFitter.fit(*newRecoTrack);
438 } else {
439 trackFitter.fit(*newRecoTrack);
440 }
441
442 return newRecoTrack;
443}
444
447bool KinkFitter::isRefitImproveFilter6(const RecoTrack* recoTrackDaughterRefit, const ROOT::Math::XYZVector& motherPosLast)
448{
449 // get the values near the mother last point
450 ROOT::Math::XYZVector daughterPosClosestToMotherPosLast = ROOT::Math::XYZVector(
451 recoTrackDaughterRefit->getMeasuredStateOnPlaneFromFirstHit().getPos());
452 ROOT::Math::XYZVector daughterMomClosestToMotherPosLast = ROOT::Math::XYZVector(
453 recoTrackDaughterRefit->getMeasuredStateOnPlaneFromFirstHit().getMom());
454 const double Bz = BFieldManager::getFieldInTesla(daughterPosClosestToMotherPosLast).Z();
455 // daughter Helix with move to mother last point
456 Helix daughterHelixClosestToMotherPosLast(daughterPosClosestToMotherPosLast,
457 daughterMomClosestToMotherPosLast,
458 static_cast<short>(recoTrackDaughterRefit->getTrackFitStatus()->getCharge()),
459 Bz);
460 daughterHelixClosestToMotherPosLast.passiveMoveBy(motherPosLast);
461
462 // check if the 3D distance passes loose criteria (in default track fit used in KinkFinderModule this test is failed)
463 return ((daughterHelixClosestToMotherPosLast.getD0() * daughterHelixClosestToMotherPosLast.getD0() +
464 daughterHelixClosestToMotherPosLast.getZ0() * daughterHelixClosestToMotherPosLast.getZ0()) <
466}
467
469unsigned int KinkFitter::combineTracksAndFit(const Track* trackMother, const Track* trackDaughter)
470{
471 RecoTrack* recoTrackMother = trackMother->getRelated<RecoTrack>(m_recoTracksName);
472 RecoTrack* recoTrackDaughter = trackDaughter->getRelated<RecoTrack>(m_recoTracksName);
473
474 // create a combined track by reassigning all daughter track hits to mother track
475 RecoTrack* recoTrackCombinedRefit = copyRecoTrackAndReassignCDCHits(recoTrackMother,
476 recoTrackDaughter, true, -recoTrackDaughter->getNumberOfCDCHits());
477
478 // initialize fitter
479 TrackFitter trackFitterDAF;
480 // fit the new track
481 trackFitterDAF.fit(*recoTrackCombinedRefit);
482
483 // return 19 if the track fit failed
484 if (!recoTrackCombinedRefit->wasFitSuccessful()) {
485 B2DEBUG(29, "Refit of the combined track failed ");
486 return 19;
487 }
488
489 // fit results of daughter, mother, and new combined tracks
490 const genfit::FitStatus* motherTrackFitStatus = recoTrackMother->getTrackFitStatus();
491 const genfit::FitStatus* daughterTrackFitStatus = recoTrackDaughter->getTrackFitStatus();
492 const genfit::FitStatus* combinedTrackFitStatus = recoTrackCombinedRefit->getTrackFitStatus();
493
494 B2DEBUG(29, "Initial mother fit result, p-value: " << motherTrackFitStatus->getPVal() << ", ndf: " <<
495 motherTrackFitStatus->getNdf());
496 B2DEBUG(29, "Initial daughter fit result, p-value: " << daughterTrackFitStatus->getPVal() << ", ndf: " <<
497 daughterTrackFitStatus->getNdf());
498 B2DEBUG(29, "Combined track fit result, p-value: " << combinedTrackFitStatus->getPVal() << ", ndf: " <<
499 combinedTrackFitStatus->getNdf());
500
501 // return 18 if the combined track has NDF less than mother track
502 if (combinedTrackFitStatus->getNdf() < motherTrackFitStatus->getNdf())
503 return 18;
504
505 // filling bits according to the fit result of the combined track
506 const int motherFlag = (combinedTrackFitStatus->getPVal() > motherTrackFitStatus->getPVal());
507 const int daughterFlag = 2 * (combinedTrackFitStatus->getPVal() > daughterTrackFitStatus->getPVal());
508 const int daughterNdfFlag = 4 * (combinedTrackFitStatus->getNdf() > daughterTrackFitStatus->getNdf());
509 const int pValueFlag = 8 * (combinedTrackFitStatus->getPVal() > 0.0000001); // almost 5 sigma
510
511 return motherFlag + daughterFlag + daughterNdfFlag + pValueFlag;
512}
513
516 const bool motherFlag, const unsigned int delta)
517{
518
519 // sorted list of CDC hits of track to be split
520 const auto splitCDCHit = splitRecoTrack->getSortedCDCHitList();
521
522 // seeds used for a copy RecoTrack
523 ROOT::Math::XYZVector positionSeed(0, 0, 0);
524 ROOT::Math::XYZVector momentumSeed(0, 0, 0);
525 const short chargeSeed = splitRecoTrack->getTrackFitStatus()->getCharge();
526 double timeSeed = 0;
527 if (motherFlag) {
528 positionSeed = ROOT::Math::XYZVector(splitRecoTrack->getMeasuredStateOnPlaneFromFirstHit().getPos());
529 momentumSeed = ROOT::Math::XYZVector(splitRecoTrack->getMeasuredStateOnPlaneFromFirstHit().getMom());
530 timeSeed = splitRecoTrack->getCardinalRepresentation()->getTime(
531 splitRecoTrack->getMeasuredStateOnPlaneFromFirstHit());
532 } else {
533 positionSeed = ROOT::Math::XYZVector(splitRecoTrack->getMeasuredStateOnPlaneFromLastHit().getPos());
534 momentumSeed = ROOT::Math::XYZVector(splitRecoTrack->getMeasuredStateOnPlaneFromLastHit().getMom());
535 timeSeed = splitRecoTrack->getCardinalRepresentation()->getTime(
536 splitRecoTrack->getMeasuredStateOnPlaneFromLastHit());
537 }
538
539 // copy recoTrack to a separate StoreArray using seed information
540 RecoTrack* recoTrack = m_copiedRecoTracks.appendNew(positionSeed, momentumSeed, chargeSeed,
541 splitRecoTrack->getStoreArrayNameOfPXDHits(),
542 splitRecoTrack->getStoreArrayNameOfSVDHits(),
543 splitRecoTrack->getStoreArrayNameOfCDCHits(),
544 splitRecoTrack->getStoreArrayNameOfBKLMHits(),
545 splitRecoTrack->getStoreArrayNameOfEKLMHits(),
546 splitRecoTrack->getStoreArrayNameOfRecoHitInformation());
547 recoTrack->setTimeSeed(timeSeed);
548 recoTrack->setSeedCovariance(splitRecoTrack->getSeedCovariance());
549
550 if (motherFlag) {
551 // copy PXD hits (we have checked in KinkFinderModule that there no PXD hits on the other side of the track)
552 for (const auto* pxdHit : splitRecoTrack->getPXDHitList()) {
553 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(pxdHit);
554 recoTrack->addPXDHit(pxdHit, recoHitInfo->getSortingParameter(),
555 recoHitInfo->getFoundByTrackFinder());
556 }
557
558 // copy SVD hits (we have checked in KinkFinderModule that there no SVD hits on the other side of the track)
559 for (const auto* svdHit : splitRecoTrack->getSVDHitList()) {
560 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(svdHit);
561 recoTrack->addSVDHit(svdHit, recoHitInfo->getSortingParameter(),
562 recoHitInfo->getFoundByTrackFinder());
563 }
564
565
566 // copy CDC hits with respect to reassignment
567 for (size_t splitCDCHitIndex = 0; splitCDCHitIndex < splitCDCHit.size() - delta; ++splitCDCHitIndex) {
568 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(splitCDCHit[splitCDCHitIndex]);
569 recoTrack->addCDCHit(splitCDCHit[splitCDCHitIndex],
570 recoHitInfo->getSortingParameter(),
571 recoHitInfo->getRightLeftInformation(),
572 recoHitInfo->getFoundByTrackFinder());
573
574 }
575
576 // KLM hits are never assigned to mother track during splitting
577
578 } else {
579
580 // copy CDC hits with respect to reassignment
581 int sortingParameterOffset = splitRecoTrack->getRecoHitInformation(splitCDCHit[splitCDCHit.size()
582 - delta])->getSortingParameter();
583 for (size_t splitCDCHitIndex = splitCDCHit.size() - delta; splitCDCHitIndex < splitCDCHit.size(); ++splitCDCHitIndex) {
584 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(splitCDCHit[splitCDCHitIndex]);
585 recoTrack->addCDCHit(splitCDCHit[splitCDCHitIndex],
586 splitCDCHitIndex - sortingParameterOffset,
587 recoHitInfo->getRightLeftInformation(),
588 recoHitInfo->getFoundByTrackFinder());
589
590 }
591
592 // copy BKLM hits
593 for (const auto* bklmHit : splitRecoTrack->getBKLMHitList()) {
594 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(bklmHit);
595 recoTrack->addBKLMHit(bklmHit, recoHitInfo->getSortingParameter() - sortingParameterOffset,
596 recoHitInfo->getFoundByTrackFinder());
597 }
598
599 // copy EKLM hits
600 for (const auto* eklmHit : splitRecoTrack->getEKLMHitList()) {
601 auto recoHitInfo = splitRecoTrack->getRecoHitInformation(eklmHit);
602 recoTrack->addEKLMHit(eklmHit, recoHitInfo->getSortingParameter() - sortingParameterOffset,
603 recoHitInfo->getFoundByTrackFinder());
604 }
605 }
606
607 return recoTrack;
608
609}
610
612bool KinkFitter::splitRecoTrack(const RecoTrack* recoTrackSplit, short& recoTrackIndexMother, short& recoTrackIndexDaughter)
613{
614 // initialize fitter
615 TrackFitter trackFitterDAF;
616
617 // initial default value for the |chi2/ndf - 1|
618 constexpr double defaultChi2NdfRatio = std::numeric_limits<double>::max();
619
620 // enum for the splitting points used in the best splitting point search
621 enum {
622 c_outerEdge, c_middlePoint, c_innerEdge
623 };
624
625 B2DEBUG(29, "Start splitting");
626
627 // fit result of the initial track to be split
628 const genfit::FitStatus* splitTrackFitStatus = recoTrackSplit->getTrackFitStatus();
629 const double ndfSplit = splitTrackFitStatus->getNdf();
630 const double chi2Split = splitTrackFitStatus->getChi2();
631 const double chi2NdfRatioSplit = fabs(chi2Split / ndfSplit - 1);
632 B2DEBUG(29, "Initial fit result, p-value: " << splitTrackFitStatus->getPVal() << ", chi2: " <<
633 chi2Split << ", ndf: " << ndfSplit);
634
635 // number of SVD+CDC hits of the initial track to be split
636 const unsigned int numberSVDCDCHitsSplit = recoTrackSplit->getNumberOfCDCHits() + recoTrackSplit->getNumberOfSVDHits();
637
638 // Three initial points for the binary search. Since the main target are tracks with mixed fractions of hits from two
639 // wrongly combined tracks between 30-70%, the points are chosen between 20-80%.
640 // The first point is for 80% (20%) of hits assigned to mother (daughter), the second one is for middle 50% (50%),
641 // and the last one is for 20% (80%), respectively.
642 // Due to the logic of the copyRecoTrackAndSplit function, the hits position in splitHitNumber
643 // is counted from the end of the track to split (the index 0 is for c_outerEdge, index 1 is for c_middlePoint,
644 // and index 2 is for c_innerEdge).
645 std::array<unsigned int, 3> splitHitNumber = {
646 static_cast<unsigned int>(numberSVDCDCHitsSplit * 0.2),
647 static_cast<unsigned int>(numberSVDCDCHitsSplit * 0.5),
648 static_cast<unsigned int>(numberSVDCDCHitsSplit * 0.8)
649 };
650
651 // initialization of arrays of the created mother and daughter RecoTracks and |chi2/ndf - 1| for them
652 // chi2/ndf ratios for resulting tracks are calculated as (chi2_mother + chi2_daughter)/(ndf_mother + ndf_daughter)
653 std::array<RecoTrack*, 3> recoTrackMother = {nullptr, nullptr, nullptr};
654 std::array<RecoTrack*, 3> recoTrackDaughter = {nullptr, nullptr, nullptr};
655 std::array<double, 3> chi2NdfRatio = {defaultChi2NdfRatio, defaultChi2NdfRatio, defaultChi2NdfRatio};
656
657 // initial splitting and fitting of the resulting tracks
658 for (size_t splitHitNumberIndex = 0; splitHitNumberIndex < splitHitNumber.size(); ++splitHitNumberIndex) {
659 // if there is not enough hits for fit of at least one resulting track, continue
660 if (splitHitNumber[splitHitNumberIndex] < 5 ||
661 (numberSVDCDCHitsSplit - splitHitNumber[splitHitNumberIndex]) < 5) continue;
662
663 // Splitting is based only on the CDC hits, so all VXD hits are assigned to mother. If the splitting number exceeds
664 // number of CDC hits, use the latter one.
665 if (splitHitNumber[splitHitNumberIndex] > recoTrackSplit->getNumberOfCDCHits())
666 splitHitNumber[splitHitNumberIndex] = recoTrackSplit->getNumberOfCDCHits();
667
668 B2DEBUG(29, "Initial splitting hit number for point " << splitHitNumberIndex << ": " <<
669 splitHitNumber[splitHitNumberIndex]);
670
671 // creation of split RecoTracks
672 recoTrackMother[splitHitNumberIndex] = copyRecoTrackAndSplit(recoTrackSplit, true, splitHitNumber[splitHitNumberIndex]);
673 recoTrackDaughter[splitHitNumberIndex] = copyRecoTrackAndSplit(recoTrackSplit, false, splitHitNumber[splitHitNumberIndex]);
674
675 // fit of the RecoTracks
676 trackFitterDAF.fit(*(recoTrackMother[splitHitNumberIndex]));
677 trackFitterDAF.fit(*(recoTrackDaughter[splitHitNumberIndex]));
678
679 // if the fit failed, skip this track pair
680 if (!recoTrackMother[splitHitNumberIndex]->wasFitSuccessful() ||
681 !recoTrackDaughter[splitHitNumberIndex]->wasFitSuccessful()) continue;
682
683 // fit result of the split track pair
684 const genfit::FitStatus* motherNewTrackFitStatus = recoTrackMother[splitHitNumberIndex]->getTrackFitStatus();
685 const genfit::FitStatus* daughterNewTrackFitStatus = recoTrackDaughter[splitHitNumberIndex]->getTrackFitStatus();
686 const double ndfMotherTmp = motherNewTrackFitStatus->getNdf();
687 const double ndfDaughterTmp = daughterNewTrackFitStatus->getNdf();
688 const double chi2MotherTmp = motherNewTrackFitStatus->getChi2();
689 const double chi2DaughterTmp = daughterNewTrackFitStatus->getChi2();
690 const double chi2NdfRatioTmp = fabs((chi2MotherTmp + chi2DaughterTmp) / (ndfMotherTmp + ndfDaughterTmp) - 1);
691 B2DEBUG(29, "Mother fit result for initial point " << splitHitNumberIndex << ", p-value: " <<
692 motherNewTrackFitStatus->getPVal() << ", chi2: " << chi2MotherTmp << ", ndf: " << ndfMotherTmp);
693 B2DEBUG(29, "Daughter fit result for initial point " << splitHitNumberIndex << ", p-value: " <<
694 daughterNewTrackFitStatus->getPVal() << ", chi2: " << chi2DaughterTmp << ", ndf: " << ndfDaughterTmp);
695 B2DEBUG(29, "|Chi2/NDF - 1| for initial point " << splitHitNumberIndex << ": " <<
696 chi2NdfRatioTmp << ", and for initial track: " << chi2NdfRatioSplit);
697
698 // if the resulting |chi2/ndf - 1| is bigger than one for initial track, skip this track pair
699 if (chi2NdfRatioTmp > chi2NdfRatioSplit) continue;
700
701 chi2NdfRatio[splitHitNumberIndex] = chi2NdfRatioTmp;
702 }
703
704 // Find the point with minimal difference of chi2/ndf ratio with unity using binary search.
705 // Compare the |chi2/ndf - 1| result for edge points and choose the interval between middle and the better edge.
706 // Find a middle point in the chosen interval, split the track, and fit the result.
707 // Return to the comparison.
708 // In a special case when both edges fit failed (the values of |chi2/ndf - 1| are equal),
709 // check if the middle point is fitted. If it is, use it as a result. If it is not, return false.
710 // Try five iterations (usually, enough to converge). If the middle point equals one of the edge, the result has
711 // converged earlier. Break the loop and proceed the execution of the function.
712 for (unsigned int searchIteration = 0; searchIteration < 5; ++searchIteration) {
713 B2DEBUG(29, "Splitting iteration " << searchIteration << "; hit numbers: " << splitHitNumber[c_outerEdge] << ", " <<
714 splitHitNumber[c_middlePoint] << ", " << splitHitNumber[c_innerEdge]);
715
716 if (chi2NdfRatio[c_outerEdge] < chi2NdfRatio[c_innerEdge]) { // choose outer interval
717
718 // replace the inner edge with the middle point
719 splitHitNumber[c_innerEdge] = splitHitNumber[c_middlePoint];
720 chi2NdfRatio[c_innerEdge] = chi2NdfRatio[c_middlePoint];
721 recoTrackMother[c_innerEdge] = recoTrackMother[c_middlePoint];
722 recoTrackDaughter[c_innerEdge] = recoTrackDaughter[c_middlePoint];
723 // find a new middle point in the outer interval, and fill the other arrays with the default values
724 splitHitNumber[c_middlePoint] = (splitHitNumber[c_innerEdge] + splitHitNumber[c_outerEdge]) / 2;
725 chi2NdfRatio[c_middlePoint] = defaultChi2NdfRatio;
726 recoTrackMother[c_middlePoint] = nullptr;
727 recoTrackDaughter[c_middlePoint] = nullptr;
728
729 B2DEBUG(29, "Outer interval is chosen; hit numbers: " << splitHitNumber[c_outerEdge] << ", " <<
730 splitHitNumber[c_middlePoint] << ", " << splitHitNumber[c_innerEdge]);
731
732 } else if (chi2NdfRatio[c_outerEdge] > chi2NdfRatio[c_innerEdge]) { // choose inner interval
733
734 // replace the outer edge with the middle point
735 splitHitNumber[c_outerEdge] = splitHitNumber[c_middlePoint];
736 chi2NdfRatio[c_outerEdge] = chi2NdfRatio[c_middlePoint];
737 recoTrackMother[c_outerEdge] = recoTrackMother[c_middlePoint];
738 recoTrackDaughter[c_outerEdge] = recoTrackDaughter[c_middlePoint];
739 // find a new middle point in the inner interval, and fill the other arrays with the default values
740 splitHitNumber[c_middlePoint] = (splitHitNumber[c_innerEdge] + splitHitNumber[c_outerEdge]) / 2;
741 chi2NdfRatio[c_middlePoint] = defaultChi2NdfRatio;
742 recoTrackMother[c_middlePoint] = nullptr;
743 recoTrackDaughter[c_middlePoint] = nullptr;
744
745 B2DEBUG(29, "Inner interval is chosen; hit numbers: " << splitHitNumber[c_outerEdge] << ", " <<
746 splitHitNumber[c_middlePoint] << ", " << splitHitNumber[c_innerEdge]);
747
748 } else if (chi2NdfRatio[c_middlePoint] == defaultChi2NdfRatio) { // if none of the point was fitted successfully, return false
749
750 B2DEBUG(29, "Track splitting failed");
751 return false;
752
753 } else { // if both edges fits have the same results (their fit failed), return the middle one
754
755 B2DEBUG(29, "Middle point is chosen; hit numbers: " << splitHitNumber[c_outerEdge] << ", " <<
756 splitHitNumber[c_middlePoint] << ", " << splitHitNumber[c_innerEdge]);
757 // return through references indexes of the mother and daughter tracks
758 recoTrackIndexMother = recoTrackMother[c_middlePoint]->getArrayIndex();
759 recoTrackIndexDaughter = recoTrackDaughter[c_middlePoint]->getArrayIndex();
760 return true;
761
762 }
763
764 // stop the iterations if the all possibilities were tried
765 if (splitHitNumber[c_middlePoint] == splitHitNumber[c_outerEdge] ||
766 splitHitNumber[c_middlePoint] == splitHitNumber[c_innerEdge]) break;
767
768 // if there is not enough hits for fit of at least one resulting track, continue
769 if (splitHitNumber[c_middlePoint] < 5 ||
770 (numberSVDCDCHitsSplit - splitHitNumber[c_middlePoint]) < 5) continue;
771
772 // creation of split RecoTracks in the new middle point
773 recoTrackMother[c_middlePoint] = copyRecoTrackAndSplit(recoTrackSplit, true, splitHitNumber[c_middlePoint]);
774 recoTrackDaughter[c_middlePoint] = copyRecoTrackAndSplit(recoTrackSplit, false, splitHitNumber[c_middlePoint]);
775
776 // fit of the mother and daughter RecoTracks in the new middle point
777 trackFitterDAF.fit(*(recoTrackMother[c_middlePoint]));
778 trackFitterDAF.fit(*(recoTrackDaughter[c_middlePoint]));
779
780 // if the fit failed, skip this track pair
781 if (!recoTrackMother[c_middlePoint]->wasFitSuccessful() ||
782 !recoTrackDaughter[c_middlePoint]->wasFitSuccessful()) continue;
783
784 // fit result of the split track pair
785 const genfit::FitStatus* motherNewTrackFitStatus = recoTrackMother[c_middlePoint]->getTrackFitStatus();
786 const genfit::FitStatus* daughterNewTrackFitStatus = recoTrackDaughter[c_middlePoint]->getTrackFitStatus();
787 const double ndfMotherTmp = motherNewTrackFitStatus->getNdf();
788 const double ndfDaughterTmp = daughterNewTrackFitStatus->getNdf();
789 const double chi2MotherTmp = motherNewTrackFitStatus->getChi2();
790 const double chi2DaughterTmp = daughterNewTrackFitStatus->getChi2();
791 const double chi2NdfRatioTmp = fabs((chi2MotherTmp + chi2DaughterTmp) / (ndfMotherTmp + ndfDaughterTmp) - 1);
792
793 B2DEBUG(29, "Mother fit result for approach " << searchIteration << ", p-value: " <<
794 motherNewTrackFitStatus->getPVal() << ", chi2: " << chi2MotherTmp << ", ndf: " << ndfMotherTmp);
795 B2DEBUG(29, "Daughter fit result for approach " << searchIteration << ", p-value: " <<
796 daughterNewTrackFitStatus->getPVal() << ", chi2: " << chi2DaughterTmp << ", ndf: " << ndfDaughterTmp);
797 B2DEBUG(29, "Chi2/NDF for approach " << searchIteration << ": " <<
798 chi2NdfRatioTmp << ", and for initial track: " << chi2NdfRatioSplit);
799
800 // if the resulting chi2/ndf ratio is bigger than one for initial track, skip this track pair
801 if (chi2NdfRatioTmp > chi2NdfRatioSplit) continue;
802
803 chi2NdfRatio[c_middlePoint] = chi2NdfRatioTmp;
804 }
805
806 // find the minimal difference of chi2/ndf ratio with unity among left points
807 std::array<double, 3>::iterator minChi2NdfRatioResult = std::min_element(chi2NdfRatio.begin(), chi2NdfRatio.end());
808 const size_t minIndex = std::distance(chi2NdfRatio.begin(), minChi2NdfRatioResult);
809
810
811 B2DEBUG(29, "End of splitting with |chi2/ndf - 1| for point 1:" << chi2NdfRatio[c_outerEdge] <<
812 "; 2:" << chi2NdfRatio[c_middlePoint] << "; 3:" << chi2NdfRatio[c_innerEdge]);
813 B2DEBUG(29, "Hit numbers for point 1:" << splitHitNumber[c_outerEdge] <<
814 "; 2:" << splitHitNumber[c_middlePoint] << "; 3:" << splitHitNumber[c_innerEdge]);
815 B2DEBUG(29, "Min index: " << minIndex);
816
817 // return through references indexes of the mother and daughter tracks for the best splitting point
818 recoTrackIndexMother = recoTrackMother[minIndex]->getArrayIndex();
819 recoTrackIndexDaughter = recoTrackDaughter[minIndex]->getArrayIndex();
820
821 return true;
822
823}
824
828bool KinkFitter::fitAndStore(const Track* trackMother, const Track* trackDaughter, short filterFlag)
829{
830
831 // Existence of corresponding RecoTrack already checked at the module level;
832 RecoTrack* recoTrackMother = trackMother->getRelated<RecoTrack>(m_recoTracksName);
833 RecoTrack* recoTrackDaughter = trackDaughter->getRelated<RecoTrack>(m_recoTracksName);
834
835 // Track splitting (filterFlag 7, 8, and 9)
836 if (filterFlag >= 7 && filterFlag <= 9) {
837 short recoTrackIndexMother = -1;
838 short recoTrackIndexDaughter = -1;
839 if (!splitRecoTrack(recoTrackMother, recoTrackIndexMother, recoTrackIndexDaughter))
840 return false;
841 recoTrackMother = m_copiedRecoTracks[recoTrackIndexMother];
842 recoTrackDaughter = m_copiedRecoTracks[recoTrackIndexDaughter];
843 }
844
845 // Tracks selected with filterFlag from 4 to 6 are selected by 2D distance cut assuming bad z coordinate.
846 // Initial refit is required for such tracks in the majority of the cases.
847 // If the refit successful, use new RecoTrack for the vertex fit.
848
849 // Initial refit daughter track for filterFlag 4 (mother end point and daughter start point close in 2D) and
850 // filterFlag 6 (mother end point and daughter Helix extrapolation close in 2D), which do not require flipping.
851 bool refitBadFlag = false;
852 if (filterFlag == 4 || filterFlag == 6) {
853 B2DEBUG(29, "Try to do initial refit of daughter track for filterFlag " << filterFlag);
854
855 // initialize seeds for the refit
856 // position of the last mother state
857 ROOT::Math::XYZVector motherPosLast = ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos());
858 // use mother last state time as a seed for the daughter track
859 double timeSeedDaughterRefit = recoTrackMother->getCardinalRepresentation()->getTime(
860 recoTrackMother->getMeasuredStateOnPlaneFromLastHit());
861 // use fitted state at the first hit for a momentum seed
862 ROOT::Math::XYZVector momSeedDaughterRefit(recoTrackDaughter->getMeasuredStateOnPlaneFromFirstHit().getMom());
863
864 // initialize refit conditions
865 // remove hits until the first stereo layer is passed
866 bool blockInnerStereoHits = false;
867 if (filterFlag == 4) blockInnerStereoHits = true;
868 // use ordinary KalmanFilter
869 bool anotherFitter = false;
870 if (filterFlag == 6) anotherFitter = true;
871
872 // create a copy of the daughter track and refit it
873 RecoTrack* recoTrackDaughterRefit = copyRecoTrackForRefit(recoTrackDaughter, momSeedDaughterRefit,
874 motherPosLast, timeSeedDaughterRefit,
875 blockInnerStereoHits, anotherFitter);
876
877 // if the new track fit is successful, and in addition, the distance for the filterFlag 6
878 // (mother end point and daughter Helix extrapolation close in 2D) is improved,
879 // use it for the vertex fit
880 if (recoTrackDaughterRefit->wasFitSuccessful()) {
881 if (filterFlag == 4 ||
882 (filterFlag == 6 && isRefitImproveFilter6(recoTrackDaughterRefit, motherPosLast)))
883 recoTrackDaughter = recoTrackDaughterRefit;
884 B2DEBUG(29, "Initial refit successful");
885 refitBadFlag = true;
886 }
887 }
888
889 // Flip and refit filterFlag 5 (mother end point and daughter end point close in 2D).
890 if (m_kinkFitterModeFlipAndRefit && (filterFlag == 5)) {
891 B2DEBUG(29, "Try to do initial flip and refit of daughter track for filterFlag " << filterFlag);
892
893 // initialize seeds for the refit
894 // use position of the last mother state as a seed for the daughter track
895 ROOT::Math::XYZVector motherPosLast = ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos());
896 // use mother last state time as a seed for the daughter track
897 double timeSeedDaughterFlipAndRefit = recoTrackMother->getCardinalRepresentation()->getTime(
898 recoTrackMother->getMeasuredStateOnPlaneFromLastHit());
899 // use fitted state at the last hit for a momentum seed
900 ROOT::Math::XYZVector momSeedDaughterFlipAndRefit(recoTrackDaughter->getMeasuredStateOnPlaneFromLastHit().getMom());
901
902 // create a copy of the daughter track, flipped and refitted
903 RecoTrack* recoTrackDaughterFlipAndRefit = copyRecoTrackForFlipAndRefit(recoTrackDaughter,
904 motherPosLast, momSeedDaughterFlipAndRefit,
905 timeSeedDaughterFlipAndRefit);
906
907 // if the new track fit is successful, use it for the vertex fit
908 if (recoTrackDaughterFlipAndRefit->wasFitSuccessful()) {
909 recoTrackDaughter = recoTrackDaughterFlipAndRefit;
910 B2DEBUG(29, "Initial flip and refit successful");
911 }
912 }
913
914 // fitted vertex position
915 ROOT::Math::XYZVector vertexPos = ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos());
916
917 // flag to reassign hits, final hit to reassign, and distance at the fitted vertex
918 unsigned int reassignHitStatus = 0;
919 int finalHitPositionForReassignment = 0;
920 double distanceAtVertex = std::numeric_limits<double>::max();
921
922 // Try kink vertex fit. If the fit fails, return false immediately for all except
923 // filterFlag 1 (mother end point and daughter start point close in 3D) and
924 // filterFlag 3 (mother end point and daughter Helix extrapolation close in 3D).
925 bool failedFitFlag = !vertexFitWithRecoTracks(recoTrackMother, recoTrackDaughter, reassignHitStatus, vertexPos, distanceAtVertex,
926 ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos()));
927 if (failedFitFlag && (filterFlag != 1 && filterFlag != 3))
928 return false;
929
930 // If the fit fails for filterFlag 1 (mother end point and daughter start point close in 3D),
931 // try to refit daughter track blocking the first stereo superlayer.
932 if (failedFitFlag && filterFlag == 1) {
933 B2DEBUG(29, "Try to do postVertexFit refit of daughter track for filterFlag " << filterFlag);
934
935 // initialize seeds for the refit
936 // position of the last mother state
937 const ROOT::Math::XYZVector motherPosLast = ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos());
938 // use mother last state time as a seed for the daughter track
939 const double timeSeedDaughterRefit = recoTrackMother->getCardinalRepresentation()->getTime(
940 recoTrackMother->getMeasuredStateOnPlaneFromLastHit());
941 // use fitted state at the first hit for a momentum seed
942 const ROOT::Math::XYZVector momSeedDaughterRefit(recoTrackDaughter->getMeasuredStateOnPlaneFromFirstHit().getMom());
943
944 // initialize refit conditions
945 // remove hits until the first stereo layer is passed
946 const bool blockInnerStereoHits = true;
947 // do not use ordinary KalmanFilter
948 const bool anotherFitter = false;
949
950 // create a copy of the daughter track and refit it
951 RecoTrack* recoTrackDaughterRefit = copyRecoTrackForRefit(recoTrackDaughter, momSeedDaughterRefit,
952 motherPosLast, timeSeedDaughterRefit,
953 blockInnerStereoHits, anotherFitter);
954
955 // if the new track fit is successful, and in addition, the vertex fit is successful,
956 // use a new fit and proceed. Otherwise, return false.
957 if (recoTrackDaughterRefit->wasFitSuccessful() &&
958 vertexFitWithRecoTracks(recoTrackMother, recoTrackDaughterRefit, reassignHitStatus, vertexPos, distanceAtVertex,
959 motherPosLast)) {
960 recoTrackDaughter = recoTrackDaughterRefit;
961 B2DEBUG(29, "postVertexFit refit successful");
962 refitBadFlag = true;
963 } else return false;
964 }
965
966 // If the daughter track for filterFlag 4 (mother end point and daughter start point close in 2D) or
967 // filterFlag 1 (mother end point and daughter start point close in 3D) (if required) was refitted successfully,
968 // reassignHitStatus may not be assigned due to blocked hits.
969 // In this case, reassignment from daughter to mother is required, so we set it manually.
970 if ((filterFlag == 4 || (failedFitFlag && filterFlag == 1)) && (refitBadFlag) && (reassignHitStatus == 0))
971 reassignHitStatus |= 0x1;
972
973 // Cache the objects used in vertex fit
974 // Mother and daughter States extrapolated to the fitted vertex
975 genfit::MeasuredStateOnPlane stMother = m_stMotherBuffer;
976 genfit::MeasuredStateOnPlane stDaughter = m_stDaughterBuffer;
977 // recoTracks used to fit the vertex
978 m_motherKinkRecoTrackCache = recoTrackMother;
979 m_daughterKinkRecoTrackCache = recoTrackDaughter;
980
981 // if the corresponding fitterMode is used, try to reassign hits between mother and daughter tracks
982 // This is done only for filterFlags, which require mother end point and daughter start point to be close to each other.
983 // So filterFlags are 1, 4, and from 7 to 9 (track split).
985 (filterFlag == 1 || filterFlag == 4 ||
986 (filterFlag >= 7 && filterFlag <= 9 && distanceAtVertex > m_vertexDistanceCut)) &&
987 (reassignHitStatus != 0)) {
988 B2DEBUG(29, "Start of the hits reassignment for filterFlag " << filterFlag);
989
990 // initialize counter for reassigning tries
991 unsigned short countReassignTries = 0;
992
993 // variables to store temporary values
994 int finalHitPositionForReassignmentTmp = 0;
995 double distanceAtVertexTmp = std::numeric_limits<double>::max();
996 ROOT::Math::XYZVector vertexPosTmp(vertexPos);
997 RecoTrack* recoTrackMotherRefit = nullptr;
998 RecoTrack* recoTrackDaughterRefit = nullptr;
999 RecoTrack* recoTrackMotherBuffer = recoTrackMother;
1000 RecoTrack* recoTrackDaughterBuffer = recoTrackDaughter;
1001
1002 // The number of tries is limited to 3
1003 while (reassignHitStatus != 0 && countReassignTries < 3) {
1004 ++countReassignTries;
1005 B2DEBUG(29, "Try number " << countReassignTries);
1006
1007 // counter for failed retries
1008 unsigned short countBadReassignTries = 0;
1009
1010 // find threshold hit position in the track
1011 // hit below the threshold are to be reassigned
1012 // positive for daughter hits reassignment to mother, negative vice-versa
1013 int hitPositionForReassignment = 0;
1014 if (reassignHitStatus & 0x1) {
1015
1016 // daughter hits to be reassigned (negative value); direction should be 1
1017 hitPositionForReassignment = findHitPositionForReassignment(recoTrackDaughterBuffer, vertexPosTmp, 1);
1018
1019 // test if the number of hits to be reassigned larger than the number of CDC hits in daughter tracks
1020 // minus number degree of freedom required for the fit
1021 if (static_cast<unsigned int>(-hitPositionForReassignment + 5) >
1022 recoTrackDaughterBuffer->getNumberOfCDCHits())
1023 break;
1024
1025 } else if (reassignHitStatus & 0x2) {
1026
1027 // mother hits to be reassigned (positive value); direction should be -1
1028 hitPositionForReassignment = findHitPositionForReassignment(recoTrackMotherBuffer, vertexPosTmp, -1);
1029
1030 // test if the number of hits to be reassigned larger than the number of CDC hits in mother tracks
1031 // minus number degree of freedom required for the fit
1032 if (static_cast<unsigned int>(hitPositionForReassignment + 5) > recoTrackMotherBuffer->getNumberOfCDCHits()) {
1033
1034 // if number of SVD hits is enough for the fit, reassign all the CDC hits
1035 if (recoTrackMotherBuffer->getNumberOfSVDHits() > 5)
1036 hitPositionForReassignment = recoTrackMotherBuffer->getNumberOfCDCHits();
1037 else
1038 break;
1039
1040 }
1041 }
1042 B2DEBUG(29, "Found hit index, starting from which hits are reassigned: " << hitPositionForReassignment);
1043
1044 // refit of the new tracks can fail when the position is too far
1045 // try positions closer to the end until reach it
1046 while (hitPositionForReassignment != 0) {
1047
1048 // create new RecoTracks with reassigned hits in the separate StoreArray
1049 recoTrackMotherRefit = copyRecoTrackAndReassignCDCHits(recoTrackMotherBuffer,
1050 recoTrackDaughterBuffer,
1051 true, hitPositionForReassignment);
1052 recoTrackDaughterRefit = copyRecoTrackAndReassignCDCHits(recoTrackMotherBuffer,
1053 recoTrackDaughterBuffer,
1054 false, hitPositionForReassignment);
1055
1056 // try to fit new RecoTracks assuming improvement of the result
1057 // if fit fails, try position closer to the end (no more than 5 tries)
1058 // if fit is successful, break the loop
1059 if (!refitRecoTrackAfterReassign(recoTrackMotherRefit, recoTrackDaughterRefit,
1060 recoTrackMother, recoTrackDaughter)) {
1061 if (hitPositionForReassignment > 0) {
1062 --hitPositionForReassignment;
1063 } else {
1064 ++hitPositionForReassignment;
1065 }
1066 ++countBadReassignTries;
1067
1068 if (countBadReassignTries > 5) hitPositionForReassignment = 0;
1069 } else
1070 break;
1071 B2DEBUG(29, "Refit of the tracks failed, try with smaller hit index: " << hitPositionForReassignment);
1072 }
1073
1074 // if hit position reaches end, the trial failed. Continue with default tracks.
1075 if (hitPositionForReassignment == 0) {
1076 B2DEBUG(29, "Reassigning of hits and refitting failed");
1077 break;
1078 }
1079
1080 // Try to fit vertex, using previous result as a seed. If the fit fails, continue with current tracks.
1081 if (!vertexFitWithRecoTracks(recoTrackMotherRefit, recoTrackDaughterRefit, reassignHitStatus,
1082 vertexPosTmp, distanceAtVertexTmp, vertexPosTmp))
1083 break;
1084 recoTrackMotherBuffer = recoTrackMotherRefit;
1085 recoTrackDaughterBuffer = recoTrackDaughterRefit;
1086 finalHitPositionForReassignmentTmp += hitPositionForReassignment;
1087
1088 // Remember the result leading to the smallest distance between tracks.
1089 if (distanceAtVertexTmp < m_vertexDistanceCut) {
1090 distanceAtVertex = distanceAtVertexTmp;
1091 vertexPos = vertexPosTmp;
1092 stMother = m_stMotherBuffer;
1093 stDaughter = m_stDaughterBuffer;
1094
1095 m_motherKinkRecoTrackCache = recoTrackMotherRefit;
1096 m_daughterKinkRecoTrackCache = recoTrackDaughterRefit;
1097 finalHitPositionForReassignment = finalHitPositionForReassignmentTmp;
1098 }
1099 }
1100 }
1101
1102 // If the corresponding fitterMode is used, try to flip and refit daughter track for
1103 // filterFlag 2 (mother end point and daughter end point close in 3D).
1104 if (m_kinkFitterModeFlipAndRefit && (filterFlag == 2)) {
1105 B2DEBUG(29, "Try to do postVertexFit flip and refit of daughter track for filterFlag " << filterFlag);
1106
1107 // variables to store temporary values
1108 double distanceAtVertexTmp = std::numeric_limits<double>::max();
1109 ROOT::Math::XYZVector vertexPosTmp(vertexPos);
1110
1111 // use mother last state time as a seed for the daughter track
1112 const double timeSeedDaughterFlipAndRefit = recoTrackMother->getCardinalRepresentation()->getTime(
1113 recoTrackMother->getMeasuredStateOnPlaneFromLastHit());
1114
1115 // use state at the fitted vertex for a momentum seed
1116 const ROOT::Math::XYZVector momSeedDaughterFlipAndRefit(stDaughter.getMom());
1117
1118 // create a copy of the daughter track, flipped and refitted
1119 RecoTrack* recoTrackDaughterFlipAndRefit = copyRecoTrackForFlipAndRefit(recoTrackDaughter,
1120 vertexPos, momSeedDaughterFlipAndRefit,
1121 timeSeedDaughterFlipAndRefit);
1122
1123 // if the vertex fit is successful and the result is improved, store it
1124 if (recoTrackDaughterFlipAndRefit->wasFitSuccessful() &&
1125 vertexFitWithRecoTracks(recoTrackMother, recoTrackDaughterFlipAndRefit, reassignHitStatus,
1126 vertexPosTmp, distanceAtVertexTmp, vertexPosTmp))
1127 if (distanceAtVertexTmp < distanceAtVertex) {
1128 distanceAtVertex = distanceAtVertexTmp;
1129 vertexPos = vertexPosTmp;
1130 stMother = m_stMotherBuffer;
1131 stDaughter = m_stDaughterBuffer;
1132 m_daughterKinkRecoTrackCache = recoTrackDaughterFlipAndRefit;
1133
1134 B2DEBUG(29, "postVertexFit flip and refit successful");
1135 }
1136 }
1137
1138 // Try to refit daughter track for filterFlag 3 (mother end point and daughter Helix extrapolation close in 3D).
1139 // If it improves the vertex fit, which might even fail before, use a new result.
1140 if (filterFlag == 3) {
1141 B2DEBUG(29, "Try to do postVertexFit refit of daughter track for filterFlag " << filterFlag);
1142
1143 // initialize seeds for the refit
1144 // position of the last mother state and the first daughter state
1145 const ROOT::Math::XYZVector motherPosLast = ROOT::Math::XYZVector(recoTrackMother->getMeasuredStateOnPlaneFromLastHit().getPos());
1146 // use mother last state time as a seed for the daughter track
1147 const double timeSeedDaughterRefit = recoTrackMother->getCardinalRepresentation()->getTime(
1148 recoTrackMother->getMeasuredStateOnPlaneFromLastHit());
1149 // use fitted state at the first hit for a momentum seed
1150 const ROOT::Math::XYZVector momSeedDaughterRefit(recoTrackDaughter->getMeasuredStateOnPlaneFromFirstHit().getMom());
1151
1152 // variables to store temporary values
1153 double distanceAtVertexTmp = std::numeric_limits<double>::max();
1154 ROOT::Math::XYZVector vertexPosTmp(vertexPos);
1155
1156 // initialize refit conditions
1157 // do not remove hits until the first stereo layer is passed
1158 const bool blockInnerStereoHits = false;
1159 // use ordinary KalmanFilter
1160 const bool anotherFitter = true;
1161
1162 // create a copy of the daughter track and refit it
1163 RecoTrack* recoTrackDaughterRefit = copyRecoTrackForRefit(recoTrackDaughter, momSeedDaughterRefit,
1164 motherPosLast, timeSeedDaughterRefit,
1165 blockInnerStereoHits, anotherFitter);
1166
1167 // if the vertex fit is successful and the result is improved, store it
1168 if (recoTrackDaughterRefit->wasFitSuccessful() &&
1169 vertexFitWithRecoTracks(recoTrackMother, recoTrackDaughterRefit, reassignHitStatus,
1170 vertexPosTmp, distanceAtVertexTmp, vertexPosTmp)) {
1171 if ((distanceAtVertexTmp < distanceAtVertex) || failedFitFlag) {
1172 distanceAtVertex = distanceAtVertexTmp;
1173 vertexPos = vertexPosTmp;
1174 stMother = m_stMotherBuffer;
1175 stDaughter = m_stDaughterBuffer;
1176 m_daughterKinkRecoTrackCache = recoTrackDaughterRefit;
1177
1178 B2DEBUG(29, "postVertexFit refit successful");
1179 }
1180 } else if (failedFitFlag) return false;
1181 }
1182
1183 B2DEBUG(29, "Distance between tracks at fitted kink vertex " << distanceAtVertex);
1184 B2DEBUG(29, "Radius of the kink vertex " << vertexPos.Rho());
1185 B2DEBUG(29, "Number of reassigned hits " << finalHitPositionForReassignment);
1186
1187 // for analysis purposes, there is no need to distinguish kinks selected with some filters,
1188 // so we rearrange them to simplify the output
1189 // value 1 is assigned to track pairs which have close endpoints
1190 // value 2 is assigned to track pairs which have missing layers between their endpoints,
1191 // so the Helix extrapolation was used
1192 // value 3-5 are assigned to the cases of track splitting. They define whether track to split was selected among
1193 // mother candidates (3), daughter candidates (4), or tracks not passing any of these two criteria (5)
1194 short filterFlagToStore = 0;
1195 switch (filterFlag) {
1196 case 1:
1197 case 2:
1198 case 4:
1199 case 5:
1200 filterFlagToStore = 1;
1201 break;
1202 case 3:
1203 case 6:
1204 filterFlagToStore = 2;
1205 break;
1206 case 7:
1207 filterFlagToStore = 3;
1208 break;
1209 case 8:
1210 filterFlagToStore = 4;
1211 break;
1212 case 9:
1213 filterFlagToStore = 5;
1214 }
1215
1216 // test the distance cut and remove pairs that do not pass the criteria
1217 // for split tracks, we do not remove the candidates, but fill the second digit of the flag to store
1218 if (distanceAtVertex > m_vertexDistanceCut) {
1219 if (filterFlag < 7)
1220 return false;
1221 else
1222 filterFlagToStore += 10;
1223 }
1224
1225 // check if the fitted vertex is inside CDC or just after SVD
1226 if (vertexPos.Rho() < 14)
1227 return false;
1228
1229 // extrapolate the mother state to IP (B2Vector3D(0., 0., 0.) beam spot, and B2Vector3D(0., 0., 1.) beam axis)
1230 genfit::MeasuredStateOnPlane stMotherIP = recoTrackMother->getMeasuredStateOnPlaneFromFirstHit();
1231 try {
1232 stMotherIP.extrapolateToLine(B2Vector3D(0., 0., 0.), B2Vector3D(0., 0., 1.));
1233 } catch (...) {
1234 B2DEBUG(29, "Could not extrapolate mother track to IP.");
1235 }
1236
1237 // magnetic field at the fitted vertex and IP
1238 const double BzVtx = BFieldManager::getFieldInTesla(vertexPos).Z();
1239 const double BzIP = BFieldManager::getFieldInTesla({0, 0, 0}).Z();
1240
1241 // prepare TrackFitResults for mother at IP and fitted vertex and for daughter at fitted vertex
1244 TrackFitResult* tfrDaughterVtx = buildTrackFitResult(m_daughterKinkRecoTrackCache, stDaughter, BzVtx, Const::pion);
1245
1246 // Try to combine tracks and fit them to find clones (excluding split tracks).
1247 // The result is written in the second and third digits of filter flag.
1248 if (m_kinkFitterModeCombineAndFit && (filterFlag < 7)) {
1249 unsigned int combinedFitFlag = combineTracksAndFit(trackMother, trackDaughter);
1250 filterFlagToStore += combinedFitFlag * 10;
1251 }
1252
1253 // write to the filter flag number of reassigned hits (minus for daughter to mother, plus vice-versa)
1254 // since the type of flag to store is short, we are limited by +-32768.
1255 // The number of reassigned hits is rarely exceeds 32, so for that cases we feel the corresponding digits
1256 // with maximum available value of 32
1257 if (abs(finalHitPositionForReassignment) < 32) {
1258 if (finalHitPositionForReassignment >= 0)
1259 filterFlagToStore += finalHitPositionForReassignment * 1000;
1260 else {
1261 filterFlagToStore *= -1;
1262 filterFlagToStore += finalHitPositionForReassignment * 1000;
1263 }
1264 } else {
1265 filterFlagToStore += 32 * 1000;
1266 }
1267
1268 // save the kink to the StoreArray
1269 m_kinks.appendNew(std::make_pair(trackMother, std::make_pair(tfrMotherIP, tfrMotherVtx)),
1270 std::make_pair(trackDaughter, tfrDaughterVtx),
1271 vertexPos.X(), vertexPos.Y(), vertexPos.Z(), filterFlagToStore);
1272
1273
1274 return true;
1275}
1276
1280bool KinkFitter::vertexFitWithRecoTracks(RecoTrack* recoTrackMother, RecoTrack* recoTrackDaughter,
1281 unsigned int& reassignHitStatus,
1282 ROOT::Math::XYZVector& vertexPos, double& distance,
1283 ROOT::Math::XYZVector vertexPosSeed)
1284{
1285
1286 // make a clone, not use the reference so that the genfit::Track and its TrackReps will not be altered.
1287 genfit::AbsTrackRep* motherRepresentation = recoTrackMother->getCardinalRepresentation();
1288 if ((motherRepresentation == nullptr) || !(recoTrackMother->wasFitSuccessful(motherRepresentation))) {
1289 B2ERROR("Cardinal representation is not available for track. Should never happen, but I can continue safely anyway.");
1290 return false;
1291 }
1292
1293 const double motherMass = TDatabasePDG::Instance()->GetParticle(motherRepresentation->getPDG())->Mass();
1294 const double motherCharge = recoTrackMother->getTrackFitStatus()->getCharge();
1295
1296 // make a clone, not use the reference so that the genfit::Track and its TrackReps will not be altered.
1297 genfit::AbsTrackRep* daughterRepresentation = recoTrackDaughter->getCardinalRepresentation();
1298 if ((daughterRepresentation == nullptr) || !(recoTrackDaughter->wasFitSuccessful(daughterRepresentation))) {
1299 B2ERROR("Cardinal representation is not available for track. Should never happen, but I can continue safely anyway.");
1300 return false;
1301 }
1302
1303 const double daughterMass = TDatabasePDG::Instance()->GetParticle(daughterRepresentation->getPDG())->Mass();
1304 const double daughterCharge = recoTrackDaughter->getTrackFitStatus()->getCharge();
1305
1306 // make a clone, not use the reference so that the genfit::MeasuredStateOnPlane and its TrackReps will not be altered.
1307 genfit::MeasuredStateOnPlane stMother = recoTrackMother->getMeasuredStateOnPlaneFromLastHit(motherRepresentation);
1308 genfit::MeasuredStateOnPlane stDaughter = recoTrackDaughter->getMeasuredStateOnPlaneClosestTo(vertexPosSeed,
1309 daughterRepresentation);
1310 m_stMotherBuffer = stMother;
1311 m_stDaughterBuffer = stDaughter;
1312
1313 // initialize KVertexFitter
1315
1316 // set magnetic field at the seed position
1317 const double Bz = BFieldManager::getFieldInTesla(vertexPosSeed).Z();
1318 kvf.setMagneticField(Bz);
1319
1320 // set seed position
1321 HepPoint3D vertexPosSeedHepPoint(vertexPosSeed.X(), vertexPosSeed.Y(), vertexPosSeed.Z());
1322 kvf.setInitialVertex(vertexPosSeedHepPoint);
1323
1324 // add mother state for the fit
1325 TVector3 motherPosition, motherMomentum;
1326 TMatrixDSym motherCovMatrix6(6, 6);
1327 stMother.getPosMomCov(motherPosition, motherMomentum, motherCovMatrix6);
1328
1329 const double motherEnergy = sqrt(motherMomentum.Mag2() + motherMass * motherMass);
1330 ROOT::Math::PxPyPzEVector motherFourMomentum(motherMomentum.X(), motherMomentum.Y(),
1331 motherMomentum.Z(), motherEnergy);
1332
1333 TMatrixDSym motherErrMatrixForKFit(7);
1334 errMatrixForKFit(motherFourMomentum, motherCovMatrix6, motherErrMatrixForKFit);
1335
1336 kvf.addTrack(ROOTToCLHEP::getHepLorentzVector(motherFourMomentum),
1337 ROOTToCLHEP::getPoint3D(ROOT::Math::XYZVector(motherPosition)),
1338 ROOTToCLHEP::getHepSymMatrix(motherErrMatrixForKFit),
1339 motherCharge);
1340
1341 // add daughter state for the fit
1342 TVector3 daughterPosition, daughterMomentum;
1343 TMatrixDSym daughterCovMatrix6(6, 6);
1344 stDaughter.getPosMomCov(daughterPosition, daughterMomentum, daughterCovMatrix6);
1345
1346 const double daughterEnergy = sqrt(daughterMomentum.Mag2() + daughterMass * daughterMass);
1347 ROOT::Math::PxPyPzEVector daughterFourMomentum(daughterMomentum.X(), daughterMomentum.Y(),
1348 daughterMomentum.Z(), daughterEnergy);
1349
1350 TMatrixDSym daughterErrMatrixForKFit(7);
1351 errMatrixForKFit(daughterFourMomentum, daughterCovMatrix6, daughterErrMatrixForKFit);
1352
1353 kvf.addTrack(ROOTToCLHEP::getHepLorentzVector(daughterFourMomentum),
1354 ROOTToCLHEP::getPoint3D(ROOT::Math::XYZVector(daughterPosition)),
1355 ROOTToCLHEP::getHepSymMatrix(daughterErrMatrixForKFit),
1356 daughterCharge);
1357
1358 // do the fit
1359 int err = kvf.doFit();
1360 if (err != 0) {
1361 B2DEBUG(29, "Vertex fit finished with error");
1362 return false;
1363 }
1364
1365 // test the chi2 cut
1366 if (kvf.getCHIsq() > m_vertexChi2Cut) {
1367 B2DEBUG(29, "Chi^2 of vertex fit is too large: " << kvf.getCHIsq());
1368 return false;
1369 }
1370
1371 // get the fitted vertex
1372 HepPoint3D vertexPosHepPoint = kvf.getVertex();
1373 vertexPos = ROOT::Math::XYZVector(vertexPosHepPoint.x(), vertexPosHepPoint.y(), vertexPosHepPoint.z());
1374
1375 // extrapolate the mother and the daughter states to the fitted vertex and get the status of the hit reassignment
1376 if (!extrapolateToVertex(stMother, stDaughter, vertexPos, reassignHitStatus)) {
1377 B2DEBUG(29, "Failed to extrapolate one of the tracks to the fitted kink vertex");
1378 return false;
1379 }
1380
1381 // prepare mother Helix at the fitted vertex to calculate the distance between tracks
1382 const ROOT::Math::XYZVector motherPos = ROOT::Math::XYZVector(stMother.getPos());
1383 const ROOT::Math::XYZVector motherMom = ROOT::Math::XYZVector(stMother.getMom());
1384 Helix motherHelix(motherPos,
1385 motherMom,
1386 static_cast<short>(recoTrackMother->getTrackFitStatus()->getCharge()),
1387 Bz);
1388 motherHelix.passiveMoveBy(vertexPos);
1389
1390 // prepare daughter Helix at the fitted vertex to calculate the distance between tracks
1391 const ROOT::Math::XYZVector daughterPos = ROOT::Math::XYZVector(stDaughter.getPos());
1392 const ROOT::Math::XYZVector daughterMom = ROOT::Math::XYZVector(stDaughter.getMom());
1393 Helix daughterHelix(daughterPos,
1394 daughterMom,
1395 static_cast<short>(recoTrackDaughter->getTrackFitStatus()->getCharge()),
1396 Bz);
1397 daughterHelix.passiveMoveBy(vertexPos);
1398
1399 // calculate the distance between tracks as squared sum of their impact parameters at the fitted vertex
1400 distance = sqrt(daughterHelix.getD0() * daughterHelix.getD0() + daughterHelix.getZ0() * daughterHelix.getZ0() +
1401 motherHelix.getD0() * motherHelix.getD0() + motherHelix.getZ0() * motherHelix.getZ0());
1402
1403 // save mother and daughter states to the buffer
1404 m_stMotherBuffer = stMother;
1405 m_stDaughterBuffer = stDaughter;
1406
1407 B2DEBUG(29, "Vertex fit with chi2 " << kvf.getCHIsq() << " and distance between tracks " << distance);
1408 return true;
1409}
1410
1412void KinkFitter::errMatrixForKFit(ROOT::Math::PxPyPzEVector& fourMomentum, TMatrixDSym& covMatrix6,
1413 TMatrixDSym& errMatrix7)
1414{
1415
1416 enum {
1417 c_Px, c_Py, c_Pz, c_E, c_X, c_Y, c_Z
1418 };
1419 constexpr unsigned order[] = {c_X, c_Y, c_Z, c_Px, c_Py, c_Pz};
1420
1421 for (int i = 0; i < 6; i++) {
1422 for (int j = i; j < 6; j++) {
1423 errMatrix7(order[j], order[i]) = errMatrix7(order[i], order[j]) = covMatrix6(i, j);
1424 }
1425 }
1426
1427 const double dEdp[] = {fourMomentum.X() / fourMomentum.E(),
1428 fourMomentum.Y() / fourMomentum.E(),
1429 fourMomentum.Z() / fourMomentum.E()
1430 };
1431 constexpr unsigned componentMom[] = {c_Px, c_Py, c_Pz};
1432 constexpr unsigned componentPos[] = {c_X, c_Y, c_Z};
1433
1434
1435 // covariances (p,E)
1436 for (unsigned int comp : componentMom) {
1437 double covariance = 0;
1438 for (int k = 0; k < 3; k++) {
1439 covariance += errMatrix7(comp, componentMom[k]) * dEdp[k];
1440 }
1441 errMatrix7(comp, c_E) = covariance;
1442 }
1443
1444 // covariances (x,E)
1445 for (unsigned int comp : componentPos) {
1446 double covariance = 0;
1447 for (int k = 0; k < 3; k++) {
1448 covariance += errMatrix7(comp, componentMom[k]) * dEdp[k];
1449 }
1450 errMatrix7(c_E, comp) = covariance;
1451 }
1452
1453 // variance (E,E)
1454 double covariance = 0;
1455 for (int i = 0; i < 3; i++) {
1456 covariance += errMatrix7(componentMom[i], componentMom[i]) * dEdp[i] * dEdp[i];
1457 }
1458 for (int i = 0; i < 3; i++) {
1459 int k = (i + 1) % 3;
1460 covariance += 2 * errMatrix7(componentMom[i], componentMom[k]) * dEdp[i] * dEdp[k];
1461 }
1462 errMatrix7(c_E, c_E) = covariance;
1463
1464}
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
Definition: BFieldManager.h:61
Helix parameter class.
Definition: Helix.h:48
The ParticleType class for identifying different particle types.
Definition: Const.h:408
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
@ c_WriteOut
Object/array should be saved by output modules.
Definition: DataStore.h:70
@ c_ErrorIfAlreadyRegistered
If the object/array was already registered, produce an error (aborting initialisation).
Definition: DataStore.h:72
bool splitRecoTrack(const RecoTrack *recoTrackSplit, short &recoTrackIndexMother, short &recoTrackIndexDaughter)
Split track into two based on |chi2/ndf - 1|.
Definition: KinkFitter.cc:612
bool refitRecoTrackAfterReassign(RecoTrack *recoTrackMotherRefit, RecoTrack *recoTrackDaughterRefit, const RecoTrack *recoTrackMother, const RecoTrack *recoTrackDaughter)
Try to fit new RecoTracks after hit reassignment.
Definition: KinkFitter.cc:311
StoreArray< RecoTrack > m_copiedRecoTracks
RecoTrack used to refit tracks.
Definition: KinkFitter.h:282
genfit::MeasuredStateOnPlane m_stMotherBuffer
buffer for the MeasuredStateOnPlane of mother obtained in the vertex fit
Definition: KinkFitter.h:283
bool vertexFitWithRecoTracks(RecoTrack *recoTrackMother, RecoTrack *recoTrackDaughter, unsigned int &reassignHitStatus, ROOT::Math::XYZVector &vertexPos, double &distance, ROOT::Math::XYZVector vertexPosSeed=ROOT::Math::XYZVector(0, 0, 0))
Fit kink vertex using RecoTrack's as inputs.
Definition: KinkFitter.cc:1280
StoreArray< Kink > m_kinks
Kink (output).
Definition: KinkFitter.h:262
bool m_kinkFitterModeCombineAndFit
fitter mode 3rd bit
Definition: KinkFitter.h:278
RecoTrack * m_motherKinkRecoTrackCache
cache for the RecoTrack of mother used to find the best vertex
Definition: KinkFitter.h:285
double m_vertexDistanceCut
cut on the distance at the found vertex.
Definition: KinkFitter.h:265
RecoTrack * copyRecoTrackForRefit(const RecoTrack *recoTrack, const ROOT::Math::XYZVector &momentumSeed, const ROOT::Math::XYZVector &positionSeed, const double &timeSeed, const bool blockInnerStereoHits=false, const bool useAnotherFitter=false)
Refit the daughter track blocking hits if required.
Definition: KinkFitter.cc:391
double m_vertexChi2Cut
Chi2 cut.
Definition: KinkFitter.h:266
bool fitAndStore(const Track *trackMother, const Track *trackDaughter, short filterFlag)
Fit kink with cardinal hypothesis and store it if the fit was successful.
Definition: KinkFitter.cc:828
StoreArray< TrackFitResult > m_trackFitResults
TrackFitResult (output).
Definition: KinkFitter.h:261
int findHitPositionForReassignment(const RecoTrack *recoTrack, ROOT::Math::XYZVector &vertexPos, int direction)
Find hit position closest to the vertex.
Definition: KinkFitter.cc:135
RecoTrack * m_daughterKinkRecoTrackCache
cache for the RecoTrack of daughter used to find the best vertex
Definition: KinkFitter.h:286
bool extrapolateToVertex(genfit::MeasuredStateOnPlane &stMother, genfit::MeasuredStateOnPlane &stDaughter, const ROOT::Math::XYZVector &vertexPosition, unsigned int &reassignHitStatus)
Extrapolate the fit results to the perigee to the kink vertex.
Definition: KinkFitter.cc:92
double m_precutDistance
Preselection cut on distance between ending points of two tracks used in prefilter.
Definition: KinkFitter.h:267
KinkFitter(const std::string &trackFitResultsName="", const std::string &kinksName="", const std::string &recoTracksName="", const std::string &copiedRecoTracksName="RecoTracksKinkTmp")
Constructor for the KinkFitter.
Definition: KinkFitter.cc:44
std::string m_recoTracksName
RecoTrackColName (input).
Definition: KinkFitter.h:257
TrackFitResult * buildTrackFitResult(RecoTrack *recoTrack, const genfit::MeasuredStateOnPlane &msop, const double Bz, const Const::ParticleType trackHypothesis)
Build TrackFitResult of the Kink Track.
Definition: KinkFitter.cc:115
bool m_kinkFitterModeSplitTrack
fitter mode 4th bit
Definition: KinkFitter.h:279
bool m_kinkFitterModeHitsReassignment
fitter mode 1st bit
Definition: KinkFitter.h:276
RecoTrack * copyRecoTrackAndSplit(const RecoTrack *splitRecoTrack, const bool motherFlag, const unsigned int delta)
Create a RecoTrack in a separate StoreArray based on one to be split.
Definition: KinkFitter.cc:515
StoreArray< RecoTrack > m_recoTracks
RecoTrack (input)
Definition: KinkFitter.h:258
bool isRefitImproveFilter6(const RecoTrack *recoTrackDaughterRefit, const ROOT::Math::XYZVector &motherPosLast)
check if the refit of filter 6 daughter tracks improves the distance between mother and daughter
Definition: KinkFitter.cc:447
RecoTrack * copyRecoTrackForFlipAndRefit(const RecoTrack *recoTrack, const ROOT::Math::XYZVector &momentumSeed, const ROOT::Math::XYZVector &positionSeed, const double &timeSeed)
Flip and refit the daughter track.
Definition: KinkFitter.cc:358
RecoTrack * copyRecoTrackAndReassignCDCHits(RecoTrack *motherRecoTrack, RecoTrack *daughterRecoTrack, const bool motherFlag, const int delta)
Copy RecoTrack to a separate StoreArray and reassign CDC hits according to delta.
Definition: KinkFitter.cc:193
bool m_kinkFitterModeFlipAndRefit
fitter mode 2nd bit
Definition: KinkFitter.h:277
unsigned char m_kinkFitterMode
fitter mode from 0 to 15 written in bits:
Definition: KinkFitter.h:271
void initializeCuts(const double vertexDistanceCut, const double vertexChi2Cut, const double precutDistance)
Initialize the cuts which will be applied during the fit and store process.
Definition: KinkFitter.cc:82
void errMatrixForKFit(ROOT::Math::PxPyPzEVector &fourMomentum, TMatrixDSym &covMatrix6, TMatrixDSym &errMatrix7)
Prepare the error matrix for the kFit.
Definition: KinkFitter.cc:1412
genfit::MeasuredStateOnPlane m_stDaughterBuffer
buffer for the MeasuredStateOnPlane of daughter obtained in the vertex fit
Definition: KinkFitter.h:284
void setFitterMode(const unsigned char fitterMode)
set kink fitter mode.
Definition: KinkFitter.cc:68
unsigned int combineTracksAndFit(const Track *trackMother, const Track *trackDaughter)
Combine daughter and mother tracks in one and fit.
Definition: KinkFitter.cc:469
void setUseInFit(const bool useInFit=true)
Set the hit to be used (default) or not in the next fit.
This is the Reconstruction Event-Data Model Track.
Definition: RecoTrack.h:79
size_t addHitsFromRecoTrack(const RecoTrack *recoTrack, unsigned int sortingParameterOffset=0, bool reversed=false, std::optional< double > optionalMinimalWeight=std::nullopt)
Add all hits from another RecoTrack to this RecoTrack.
Definition: RecoTrack.cc:240
const TMatrixDSym & getSeedCovariance() const
Return the covariance matrix of the seed. ATTENTION: This is not the fitted covariance.
Definition: RecoTrack.h:611
bool addBKLMHit(const UsedBKLMHit *bklmHit, const unsigned int sortingParameter, OriginTrackFinder foundByTrackFinder=OriginTrackFinder::c_undefinedTrackFinder)
Adds a bklm hit with the given information to the reco track.
Definition: RecoTrack.h:286
bool addCDCHit(const UsedCDCHit *cdcHit, const unsigned int sortingParameter, RightLeftInformation rightLeftInformation=RightLeftInformation::c_undefinedRightLeftInformation, OriginTrackFinder foundByTrackFinder=OriginTrackFinder::c_undefinedTrackFinder)
Adds a cdc hit with the given information to the reco track.
Definition: RecoTrack.h:243
std::vector< Belle2::RecoTrack::UsedPXDHit * > getPXDHitList() const
Return an unsorted list of pxd hits.
Definition: RecoTrack.h:449
const std::string & getStoreArrayNameOfEKLMHits() const
Name of the store array of the eklm hits.
Definition: RecoTrack.h:744
bool wasFitSuccessful(const genfit::AbsTrackRep *representation=nullptr) const
Returns true if the last fit with the given representation was successful.
Definition: RecoTrack.cc:336
std::vector< Belle2::RecoTrack::UsedSVDHit * > getSVDHitList() const
Return an unsorted list of svd hits.
Definition: RecoTrack.h:452
bool addEKLMHit(const UsedEKLMHit *eklmHit, const unsigned int sortingParameter, OriginTrackFinder foundByTrackFinder=OriginTrackFinder::c_undefinedTrackFinder)
Adds an eklm hit with the given information to the reco track.
Definition: RecoTrack.h:300
bool addPXDHit(const UsedPXDHit *pxdHit, const unsigned int sortingParameter, OriginTrackFinder foundByTrackFinder=OriginTrackFinder::c_undefinedTrackFinder)
Adds a pxd hit with the given information to the reco track.
Definition: RecoTrack.h:258
std::vector< Belle2::RecoTrack::UsedCDCHit * > getSortedCDCHitList() const
Return a sorted list of cdc hits. Sorted by the sortingParameter.
Definition: RecoTrack.h:470
std::vector< Belle2::RecoTrack::UsedBKLMHit * > getBKLMHitList() const
Return an unsorted list of bklm hits.
Definition: RecoTrack.h:458
const std::string & getStoreArrayNameOfSVDHits() const
Name of the store array of the svd hits.
Definition: RecoTrack.h:735
ROOT::Math::XYZVector getPositionSeed() const
Return the position seed stored in the reco track. ATTENTION: This is not the fitted position.
Definition: RecoTrack.h:480
genfit::AbsTrackRep * getCardinalRepresentation() const
Get a pointer to the cardinal track representation. You are not allowed to modify or delete it!
Definition: RecoTrack.h:631
const std::string & getStoreArrayNameOfPXDHits() const
Name of the store array of the pxd hits.
Definition: RecoTrack.h:732
const genfit::MeasuredStateOnPlane & getMeasuredStateOnPlaneClosestTo(const ROOT::Math::XYZVector &closestPoint, const genfit::AbsTrackRep *representation=nullptr)
Return genfit's MasuredStateOnPlane, that is closest to the given point useful for extrapolation of m...
Definition: RecoTrack.cc:426
unsigned int getNumberOfSVDHits() const
Return the number of svd hits.
Definition: RecoTrack.h:424
unsigned int getNumberOfCDCHits() const
Return the number of cdc hits.
Definition: RecoTrack.h:427
std::vector< Belle2::RecoTrack::UsedEKLMHit * > getEKLMHitList() const
Return an unsorted list of eklm hits.
Definition: RecoTrack.h:461
const std::string & getStoreArrayNameOfBKLMHits() const
Name of the store array of the bklm hits.
Definition: RecoTrack.h:741
void setTimeSeed(const double timeSeed)
Set the time seed. ATTENTION: This is not the fitted time.
Definition: RecoTrack.h:604
const genfit::MeasuredStateOnPlane & getMeasuredStateOnPlaneFromLastHit(const genfit::AbsTrackRep *representation=nullptr) const
Return genfit's MeasuredStateOnPlane for the last hit in a fit useful for extrapolation of measuremen...
Definition: RecoTrack.cc:619
void setSeedCovariance(const TMatrixDSym &seedCovariance)
Set the covariance of the seed. ATTENTION: This is not the fitted covariance.
Definition: RecoTrack.h:614
const std::string & getStoreArrayNameOfRecoHitInformation() const
Name of the store array of the reco hit information.
Definition: RecoTrack.h:747
RecoHitInformation * getRecoHitInformation(HitType *hit) const
Return the reco hit information for a generic hit from the storeArray.
Definition: RecoTrack.h:312
static void registerRequiredRelations(StoreArray< RecoTrack > &recoTracks, std::string const &pxdHitsStoreArrayName="", std::string const &svdHitsStoreArrayName="", std::string const &cdcHitsStoreArrayName="", std::string const &bklmHitsStoreArrayName="", std::string const &eklmHitsStoreArrayName="", std::string const &recoHitInformationStoreArrayName="")
Convenience method which registers all relations required to fully use a RecoTrack.
Definition: RecoTrack.cc:53
const std::string & getStoreArrayNameOfCDCHits() const
Name of the store array of the cdc hits.
Definition: RecoTrack.h:738
short int getChargeSeed() const
Return the charge seed stored in the reco track. ATTENTION: This is not the fitted charge.
Definition: RecoTrack.h:508
const genfit::MeasuredStateOnPlane & getMeasuredStateOnPlaneFromFirstHit(const genfit::AbsTrackRep *representation=nullptr) const
Return genfit's MeasuredStateOnPlane for the first hit in a fit useful for extrapolation of measureme...
Definition: RecoTrack.cc:605
ROOT::Math::XYZVector getMomentumSeed() const
Return the momentum seed stored in the reco track. ATTENTION: This is not the fitted momentum.
Definition: RecoTrack.h:487
const genfit::MeasuredStateOnPlane & getMeasuredStateOnPlaneFromRecoHit(const RecoHitInformation *recoHitInfo, const genfit::AbsTrackRep *representation=nullptr) const
Return genfit's MeasuredStateOnPlane on plane for associated with one RecoHitInformation.
Definition: RecoTrack.cc:579
bool addSVDHit(const UsedSVDHit *svdHit, const unsigned int sortingParameter, OriginTrackFinder foundByTrackFinder=OriginTrackFinder::c_undefinedTrackFinder)
Adds a svd hit with the given information to the reco track.
Definition: RecoTrack.h:272
const genfit::FitStatus * getTrackFitStatus(const genfit::AbsTrackRep *representation=nullptr) const
Return the track fit status for the given representation or for the cardinal one. You are not allowed...
Definition: RecoTrack.h:621
double getTimeSeed() const
Return the time seed stored in the reco track. ATTENTION: This is not the fitted time.
Definition: RecoTrack.h:511
unsigned int getNumberOfTotalHits() const
Return the number of cdc + svd + pxd + bklm + eklm hits.
Definition: RecoTrack.h:436
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
static uint32_t getHitPatternVXDInitializer(const RecoTrack &recoTrack, const genfit::AbsTrackRep *representation=nullptr)
Get the HitPattern in the VXD.
static uint64_t getHitPatternCDCInitializer(const RecoTrack &recoTrack, const genfit::AbsTrackRep *representation=nullptr)
Get the HitPattern in the CDC.
Values of the result of a track fit with a given particle hypothesis.
Algorithm class to handle the fitting of RecoTrack objects.
Definition: TrackFitter.h:121
bool fit(RecoTrack &recoTrack, genfit::AbsTrackRep *trackRepresentation, bool resortHits=false) const
Fit a reco track with a given non-default track representation.
Definition: TrackFitter.cc:108
void resetFitter(const std::shared_ptr< genfit::AbsFitter > &fitter)
Set the internal storage of the fitter to a provided one, if you want to use non-default settings.
Definition: TrackFitter.cc:180
Class that bundles various TrackFitResults.
Definition: Track.h:25
enum KFitError::ECode addTrack(const KFitTrack &kp)
Add a track to the fitter object.
Definition: KFitBase.cc:38
enum KFitError::ECode setMagneticField(const double mf)
Change a magnetic field from the default value KFitConst::kDefaultMagneticField.
Definition: KFitBase.cc:93
VertexFitKFit is a derived class from KFitBase to perform vertex-constraint kinematical fit.
Definition: VertexFitKFit.h:34
enum KFitError::ECode setInitialVertex(const HepPoint3D &v)
Set an initial vertex point for the vertex-vertex constraint fit.
double getCHIsq(void) const override
Get a chi-square of the fit.
enum KFitError::ECode doFit(void)
Perform a vertex-constraint fit.
const HepPoint3D getVertex(const int flag=KFitConst::kAfterFit) const
Get a vertex position.
static constexpr auto XYZToTVector
Helper function to convert XYZVector to TVector3.
Definition: VectorUtil.h:24
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:516
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.