79 const std::vector<FitMeasurement*>& measurements,
FitParameters& parameters,
93 auto trackStateOnSurfaces = std::make_unique<Trk::TrackStates>();
94 unsigned size = measurements.size() + 1;
97 trackStateOnSurfaces->reserve(
size);
98 std::unique_ptr<AlignmentEffectsOnTrack> alignmentEffects{};
101 std::unique_ptr<MaterialEffectsBase> materialEffects{};
102 std::unique_ptr<MeasurementBase> measurementBase{};
103 const Surface* surface =
nullptr;
104 std::unique_ptr<TrackParameters> trackParameters{};
105 std::bitset<TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
106 const defaultPattern;
107 std::bitset<TrackStateOnSurface::NumberOfTrackStateOnSurfaceTypes>
108 typePattern = defaultPattern;
111 unsigned scatter = 0;
113 std::unique_ptr<Perigee> perigee(parameters.perigee());
116 fitQoS, std::move(measurementBase), std::move(perigee),
117 std::move(materialEffects), typePattern, std::move(alignmentEffects)));
122 for (
const auto* t : *leadingTSOS) {
124 trackStateOnSurfaces->push_back((*t).clone());
131 for (
auto* m : measurements) {
132 if (m->isMaterialDelimiter())
136 if (m->surface() != surface || alignmentEffects || m->alignmentEffects()) {
138 if (typePattern == defaultPattern) {
140 *
cache.log << MSG::DEBUG <<
" skip empty TSOS# " << tsos + 1;
141 if (m->materialEffects())
142 *
cache.log <<
" with material";
143 m->print(*
cache.log);
148 bool const withCovariance =
true;
149 trackParameters.reset(parameters.trackParameters(
150 *
cache.log, *fitMeasurement, withCovariance));
152 if (!trackParameters) {
155 <<
" fail track with incomplete return TSOS: no trackParameters"
161 fitQoS, std::move(measurementBase), std::move(trackParameters),
162 std::move(materialEffects), typePattern,
163 std::move(alignmentEffects)));
168 surface = m->surface();
169 measurementBase.reset();
170 materialEffects.reset();
171 typePattern = defaultPattern;
172 alignmentEffects.reset();
176 *
cache.log << MSG::VERBOSE <<
" tsos# " << tsos <<
" shared surface"
181 if (m->measurementBase()) {
184 if (measurementBase) {
186 bool const withCovariance =
true;
187 trackParameters.reset(parameters.trackParameters(
188 *
cache.log, *fitMeasurement, withCovariance));
189 if (!trackParameters) {
192 <<
" fail track with incomplete return TSOS: no trackParameters"
198 fitQoS, std::move(measurementBase), std::move(trackParameters),
199 std::move(materialEffects), typePattern,
200 std::move(alignmentEffects)));
203 materialEffects.reset();
204 typePattern = defaultPattern;
205 alignmentEffects.reset();
208 measurementBase = m->measurementBase()->uniqueClone();
215 if (m->materialEffects()) {
218 if (m->isEnergyDeposit()) {
219 materialEffects = m->materialEffects()->uniqueClone();
221 }
else if (m->isScatterer()) {
223 std::bitset<MaterialEffectsBase::NumberOfMaterialEffectsTypes>
235 materialEffects = std::make_unique<MaterialEffectsOnTrack>(
236 m->materialEffects()->thicknessInX0(),
237 parameters.scatteringAngles(*m, scatter), std::move(energyLoss),
238 m->materialEffects()->associatedSurface(), typeMaterial);
242 materialEffects = std::make_unique<MaterialEffectsOnTrack>(
243 m->materialEffects()->thicknessInX0(),
244 parameters.scatteringAngles(*m), std::move(energyLoss),
245 m->materialEffects()->associatedSurface(), typeMaterial);
251 materialEffects = std::make_unique<MaterialEffectsOnTrack>(
252 m->materialEffects()->thicknessInX0(),
253 parameters.scatteringAngles(*m, scatter),
254 m->materialEffects()->associatedSurface(), typeMaterial);
258 materialEffects = std::make_unique<MaterialEffectsOnTrack>(
259 m->materialEffects()->thicknessInX0(),
260 parameters.scatteringAngles(*m),
261 m->materialEffects()->associatedSurface(), typeMaterial);
267 *
cache.log << MSG::WARNING
268 <<
" deprecated TrackStateOnSurface::InertMaterial"
270 materialEffects = m->materialEffects()->uniqueClone();
276 if (m->isPerigee()) {
281 else if (m->alignmentEffects()) {
283 unsigned const align = m->alignmentParameter() - 1;
285 *
cache.log << MSG::VERBOSE <<
" Fitprocedure AEOT input deltaTranslation "
288 << parameters.alignmentOffset(align) <<
" deltaAngle "
289 << parameters.alignmentAngle(align) <<
endmsg;
290 alignmentEffects = std::make_unique<Trk::AlignmentEffectsOnTrack>(
298 else if (m->isPassive()) {
299 if (m->type() ==
hole)
305 bool const withCovariance =
true;
306 trackParameters.reset(
307 parameters.trackParameters(*
cache.log, *fitMeasurement, withCovariance));
308 if (!trackParameters) {
309 *
cache.log << MSG::WARNING
310 <<
" fail track with incomplete return TSOS: no trackParameters"
316 fitQoS, std::move(measurementBase), std::move(trackParameters),
317 std::move(materialEffects), typePattern, std::move(alignmentEffects)));
321 const double chiSquared =
cache.chiSq *
static_cast<double>(
cache.numberDoF);
323 std::make_unique<FitQuality>(chiSquared,
cache.numberDoF));
326 *
cache.log << MSG::VERBOSE <<
" track with " << tsos <<
" TSOS " <<
endmsg;
332 std::vector<FitMeasurement*>& measurements,
FitParameters*& parameters,
333 const FitQuality* perigeeQuality,
bool for_iPatTrack)
const {
336 if (
cache.log->level() > MSG::DEBUG) {
338 cache.verbose =
false;
341 if (
cache.log->level() < MSG::DEBUG)
342 cache.verbose =
true;
343 *
cache.log << MSG::DEBUG <<
"parameter start values: ";
344 parameters->print(*
cache.log);
349 const ToolHandle<IIntersector>& intersector =
353 int fitCode =
cache.fitMatrices->setDimensions(measurements, parameters);
355 cache.fitQuality = std::make_unique<FitProcedureQuality>(
356 fitCode,
cache.fitMatrices->numberDoF());
359 return *
cache.fitQuality;
364 cache.chiSqWorst = 0.;
366 cache.driftSumLast = 0.;
367 cache.fitProbability = 0.;
368 cache.iteration = -1;
369 cache.numberDoF =
cache.fitMatrices->numberDoF();
370 cache.numberParameters = parameters->numberParameters();
371 cache.worstMeasurement = 0;
373 asymmetricCaloEnergy,
cache.fitMatrices->derivativeMatrix(), intersector,
378 if (measurements.front()->isPerigee()) {
379 cache.fitMatrices->usePerigee(*measurements.front());
383 const double ptInvCut = 1. /
m_minPt;
384 cache.cutStep =
true;
385 cache.convergence =
false;
386 cache.nearConvergence =
false;
389 double bestChiSq =
cache.chiSqCut;
390 std::optional<FitParameters> bestParameters = std::nullopt;
393 while (!fitCode && !
cache.convergence) {
394 bool forceIteration =
false;
395 if (
cache.iteration >
m_maxIter && bestParameters && !for_iPatTrack) {
396 parameters->reset(*bestParameters);
397 cache.convergence =
true;
398 cache.cutStep =
false;
400 *
cache.log << MSG::VERBOSE
401 <<
" convergence problem: accept after max iter " <<
endmsg;
402 }
else if (!
cache.cutStep) {
404 if (!
cache.iteration) {
405 cache.fitMatrices->refinePointers();
409 cache.fitMatrices->printDerivativeMatrix();
412 if (!
cache.fitMatrices->solveEquations()) {
414 }
else if (parameters->fitEnergyDeposit() &&
415 !parameters->extremeMomentum() &&
418 *
cache.log << MSG::DEBUG <<
" extremeMomentum " <<
endmsg;
419 parameters->extremeMomentum(
true);
420 fitCode =
cache.fitMatrices->setDimensions(measurements, parameters);
421 bestChiSq =
cache.chiSqCut;
422 bestParameters = std::nullopt;
423 forceIteration =
true;
425 cache.chiSqWorst = 0.;
427 cache.driftSumLast = 0.;
428 cache.numberParameters = parameters->numberParameters();
431 cache.fitMatrices->printWeightMatrix();
437 *
cache.log << MSG::VERBOSE <<
" ===== start iteration "
439 if (
cache.iteration) {
441 *
cache.log <<
" ====== cutStep";
444 *
cache.log <<
" ====== for_iPatTrack ";
446 parameters->printVerbose(*
cache.log);
452 }
else if (std::abs(parameters->ptInv0()) > ptInvCut) {
454 }
else if (measurements.front()->isVertex() &&
m_indetVolume &&
457 }
else if (
cache.iteration &&
458 (std::abs(parameters->difference(3)) > 1.0 ||
460 !measurements.front()->isVertex()) {
461 if (std::abs(parameters->difference(3)) > 1.0) {
466 }
else if (!fitCode) {
471 cache.fitQuality = std::make_unique<FitProcedureQuality>(
473 cache.iteration, parameters->numberAlignments(),
474 cache.fitMatrices->numberDoF(), parameters->numberScatterers(),
475 cache.worstMeasurement);
482 return *
cache.fitQuality;
491 }
else if (
cache.iteration == 4 &&
cache.chiSq > 1000. && for_iPatTrack) {
493 }
else if (!fitCode) {
497 if (!forceIteration && !
cache.convergence &&
cache.chRatio1 > 0.9) {
499 if (
cache.iteration > 4 &&
501 cache.cutStep =
true;
502 cutStep = std::abs(
cache.driftSumLast /
509 <<
" take cutStep following chi2 increase on iteration "
510 <<
cache.iteration <<
" chi2Ratio " <<
cache.chRatio1
511 <<
" driftSum " <<
cache.driftSum <<
" prev "
513 }
else if (parameters->numberOscillations() > 2) {
514 cache.cutStep =
true;
517 *
cache.log << MSG::VERBOSE
518 <<
" take cutStep as oscillating, iteration "
519 <<
cache.iteration <<
", numberOscillations "
520 << parameters->numberOscillations() <<
endmsg;
525 cache.convergence =
false;
526 parameters->performCutStep(cutStep);
528 parameters->printVerbose(*
cache.log);
535 *
cache.log <<
" after cutStep: "
536 <<
" chi2Ratio " <<
cache.chRatio1 <<
" driftSum "
543 if (!bestParameters ||
cache.chiSq < bestChiSq) {
544 bestChiSq =
cache.chiSq;
545 bestParameters = *parameters;
546 parameters->resetOscillations();
549 if (bestParameters &&
550 ((
cache.convergence &&
cache.chiSq > bestChiSq + 0.5) ||
551 (parameters->phiInstability() &&
cache.iteration ==
m_maxIter))) {
552 parameters->reset(*bestParameters);
554 *
cache.log << MSG::VERBOSE <<
" revert to bestParameters ";
555 parameters->printVerbose(*
cache.log);
561 cache.convergence =
true;
566 cache.convergence =
false;
573 if (fitCode &&
cache.iteration && bestParameters &&
574 !parameters->phiInstability() &&
575 (**(measurements.rbegin())).position().perp() >
m_largeRadius) {
577 *
cache.log << MSG::VERBOSE <<
" phi instability " <<
endmsg;
578 parameters->reset(*bestParameters);
579 parameters->setPhiInstability();
580 cache.cutStep =
true;
581 cache.convergence =
false;
594 if (!for_iPatTrack) {
603 if (perigeeQuality) {
606 cache.chiSq *
static_cast<double>(
cache.numberDoF);
608 cache.chiSq /=
static_cast<double>(
cache.numberDoF);
612 cache.fitProbability = 1.;
613 if (
cache.numberDoF > 0 &&
cache.chiSq > 0.) {
614 if (
cache.chiSq < 100.) {
615 const double chiSquared =
616 cache.chiSq *
static_cast<double>(
cache.numberDoF);
617 cache.fitProbability -=
618 Genfun::CumulativeChiSquare(
cache.numberDoF)(chiSquared);
620 cache.fitProbability = 0.;
625 *
cache.log << MSG::VERBOSE <<
" fit converged";
626 if (
cache.chiSqWorst > 6.25)
627 *
cache.log <<
" with possible outlier #" <<
cache.worstMeasurement
628 <<
" (residual " << std::sqrt(
cache.chiSqWorst) <<
")";
636 cache.fitQuality = std::make_unique<FitProcedureQuality>(
638 cache.iteration, parameters->numberAlignments(),
cache.numberDoF,
639 parameters->numberScatterers(),
cache.worstMeasurement);
640 if (
cache.debug && (for_iPatTrack || fitCode))
643 return *
cache.fitQuality;
660 std::vector<FitMeasurement*>& measurements)
const {
662 const double dChisqConv = 0.025;
667 double driftResidual = 0.;
669 for (
auto* m : measurements) {
678 double residual = m->residual();
679 double DiffSq = residual * residual;
680 cache.chiSq += DiffSq;
681 if (m->isPositionMeasurement()) {
683 driftResidual += residual;
684 if (DiffSq > DSqMax) {
686 cache.worstMeasurement = m->hitIndex() + 1;
687 cache.chiSqWorst = std::min(999., DSqMax);
690 if (m->is2Dimensional()) {
691 residual = m->residual2();
692 DiffSq = residual * residual;
693 cache.chiSq += DiffSq;
694 if (m->isPositionMeasurement()) {
695 if (DiffSq > DSqMax) {
697 cache.worstMeasurement = m->hitIndex() + 1;
698 cache.chiSqWorst = std::min(999., DSqMax);
705 if (
cache.fitMatrices->numberDoF() > 0)
706 cache.chiSq /=
static_cast<double>(
cache.fitMatrices->numberDoF());
707 if (
cache.iteration == 0) {
715 const double DChiSq =
cache.chiSqOld -
cache.chiSq;
716 if (DChiSq > -dChisqConv) {
720 if (
cache.iteration > 0) {
724 if (
cache.fitMatrices->numberDriftCircles()) {
728 static_cast<double>(
cache.fitMatrices->numberDriftCircles());
734 *
cache.log <<
"----------------------------------" << std::endl
735 << std::setiosflags(std::ios::fixed)
736 <<
" Debugging Info in ChiSquare method" << std::endl
737 <<
" # of track-fit iterations " << std::setw(3)
738 <<
cache.iteration << std::endl
739 <<
" fit ChiSquared (per degree of freedom) " << std::setw(13)
740 << std::setprecision(3) <<
cache.chiSq
741 <<
" # of degrees of freedom "
742 <<
cache.fitMatrices->numberDoF() << std::endl
743 <<
" ChSq Ratio1/2 " << std::setw(9) << std::setprecision(3)
744 <<
cache.chRatio1 << std::setw(10) << std::setprecision(3)
745 <<
cache.chRatio2 << std::endl
746 <<
" driftResidual " << std::setw(9) << std::setprecision(3)
747 <<
cache.driftSum <<
" #driftCircles "
748 <<
cache.fitMatrices->numberDriftCircles() << std::endl
749 <<
" CutTaken " <<
cache.cutTaken << std::endl
750 <<
"----------------------------------" << std::endl
755 for (
auto* m : measurements) {
756 *
cache.log << std::setiosflags(std::ios::fixed) << std::setw(3) << ++n;
757 if (m->isPerigee()) {
758 *
cache.log <<
" perigee ";
759 *
cache.log << std::endl;
761 m->print(*
cache.log);
769 (
cache.chiSq < 0.1 ||
770 (
cache.chRatio2 < 1.1 &&
771 (std::abs(DChiSq) < dChisqConv ||
773 if ((
cache.chiSq < 2.0 ||
cache.nearConvergence ||
cache.iteration == 1) &&
775 cache.convergence =
true;
777 cache.nearConvergence =
true;
779 *
cache.log << MSG::VERBOSE <<
" near convergence " <<
endmsg;
782 cache.nearConvergence =
false;
786 cache.cutStep =
false;