File indexing completed on 2025-12-14 09:39:38
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Seeding/CompositeSpacePointLineFitter.hpp"
0012
0013 #include "Acts/Utilities/AlgebraHelpers.hpp"
0014 #include "Acts/Utilities/StringHelpers.hpp"
0015
0016 #include <format>
0017
0018 namespace Acts::Experimental {
0019
0020 template <CompositeSpacePointContainer Cont_t>
0021 CompositeSpacePointLineFitter::DoFcounts
0022 CompositeSpacePointLineFitter::countDoF(const Cont_t& measurements) const {
0023 return countDoF(measurements, Selector_t<SpacePoint_t<Cont_t>>{});
0024 }
0025
0026 template <CompositeSpacePointContainer Cont_t>
0027 CompositeSpacePointLineFitter::DoFcounts
0028 CompositeSpacePointLineFitter::countDoF(
0029 const Cont_t& measurements,
0030 const Selector_t<SpacePoint_t<Cont_t>>& selector) const {
0031 DoFcounts counts{};
0032 std::size_t nValid{0};
0033 for (const auto& sp : measurements) {
0034 if (selector.connected() && !selector(*sp)) {
0035 ACTS_VERBOSE(__func__ << "() " << __LINE__
0036 << " - Skip invalid measurement @"
0037 << toString(sp->localPosition()));
0038 continue;
0039 }
0040 ++nValid;
0041 if (sp->measuresLoc0()) {
0042 ++counts.nonBending;
0043 }
0044 if (sp->measuresLoc1()) {
0045 ++counts.bending;
0046 }
0047 if (sp->isStraw()) {
0048 ++counts.straw;
0049 } else if (sp->hasTime()) {
0050 ++counts.time;
0051 }
0052 }
0053 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - " << nValid << "/"
0054 << measurements.size()
0055 << " valid measurements passed. Found "
0056 << counts.nonBending << "/" << counts.bending << "/"
0057 << counts.time << " measuring loc0/loc1/time with "
0058 << counts.straw << " straw measurements.");
0059 return counts;
0060 }
0061
0062 template <CompositeSpacePointContainer Cont_t>
0063 CompositeSpacePointLineFitter::FastFitResult
0064 CompositeSpacePointLineFitter::fastPrecFit(
0065 const Cont_t& measurements, const Line_t& initialGuess,
0066 const std::size_t nStraws,
0067 const std::vector<FitParIndex>& parsToUse) const {
0068 if (std::ranges::none_of(parsToUse, [](const FitParIndex idx) {
0069 using enum FitParIndex;
0070 return idx == theta || idx == y0;
0071 })) {
0072 return std::nullopt;
0073 }
0074 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fetched " << nStraws
0075 << " measurements for fast fit without time.");
0076
0077 if (nStraws > 2) {
0078 std::vector<int> signs = detail::CompSpacePointAuxiliaries::strawSigns(
0079 initialGuess, measurements);
0080 FastFitResult precResult{m_fastFitter.fit(measurements, signs)};
0081
0082
0083 if (precResult && precResult->chi2 / static_cast<double>(precResult->nDoF) >
0084 m_cfg.badFastChi2SignSwap) {
0085
0086 ACTS_DEBUG(__func__ << "() " << __LINE__
0087 << " - The fit result is of poor quality "
0088 << (*precResult) << " attempt with L<->R swapping");
0089 for (auto& s : signs) {
0090 s = -s;
0091 }
0092
0093 FastFitResult swappedPrecResult = {m_fastFitter.fit(measurements, signs)};
0094 if (swappedPrecResult && swappedPrecResult->chi2 < precResult->chi2) {
0095 ACTS_DEBUG(__func__ << "() " << __LINE__
0096 << " - Swapped fit is of better quality "
0097 << (*swappedPrecResult));
0098 swappedPrecResult->nIter += precResult->nIter;
0099 return swappedPrecResult;
0100 } else {
0101 precResult->nIter += swappedPrecResult->nIter;
0102 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fit did not improve "
0103 << (*swappedPrecResult));
0104 }
0105 }
0106 return precResult;
0107 }
0108
0109
0110 using ResidualIdx = detail::CompSpacePointAuxiliaries::ResidualIdx;
0111 return m_fastFitter.fit(measurements, ResidualIdx::bending);
0112 }
0113
0114 template <CompositeSpacePointContainer Cont_t,
0115 CompositeSpacePointFastCalibrator<
0116 CompositeSpacePointLineFitter::SpacePoint_t<Cont_t>>
0117 Calibrator_t>
0118 CompositeSpacePointLineFitter::FastFitResultT0
0119 CompositeSpacePointLineFitter::fastPrecFit(
0120 const Acts::CalibrationContext& ctx, const Calibrator_t& calibrator,
0121 const Cont_t& measurements, const Line_t& initialGuess,
0122 const double initialT0, const std::vector<FitParIndex>& parsToUse) const {
0123 if (std::ranges::none_of(parsToUse, [](const FitParIndex idx) {
0124 using enum FitParIndex;
0125 return idx == theta || idx == y0;
0126 })) {
0127 return std::nullopt;
0128 }
0129 ACTS_DEBUG(__func__ << "() " << __LINE__
0130 << " Starting precision fast fit with time.");
0131
0132 std::vector<int> signs =
0133 detail::CompSpacePointAuxiliaries::strawSigns(initialGuess, measurements);
0134 FastFitResultT0 precResult{
0135 m_fastFitter.fit(ctx, calibrator, measurements, signs, initialT0)};
0136
0137
0138 if (precResult && precResult->chi2 / static_cast<double>(precResult->nDoF) >
0139 m_cfg.badFastChi2SignSwap) {
0140
0141 ACTS_DEBUG(__func__ << "() " << __LINE__
0142 << " - The fit result is of poor quality "
0143 << (*precResult) << " attempt with L<->R swapping");
0144 for (auto& s : signs) {
0145 s = -s;
0146 }
0147
0148 FastFitResultT0 swappedPrecResult{
0149 m_fastFitter.fit(ctx, calibrator, measurements, signs, initialT0)};
0150 if (swappedPrecResult && swappedPrecResult->chi2 < precResult->chi2) {
0151 ACTS_DEBUG(__func__ << "() " << __LINE__
0152 << " - Swapped fit is of better quality "
0153 << (*swappedPrecResult));
0154 swappedPrecResult->nIter += precResult->nIter;
0155 return swappedPrecResult;
0156 } else {
0157 precResult->nIter += swappedPrecResult->nIter;
0158 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fit did not improve "
0159 << (*swappedPrecResult));
0160 }
0161 }
0162 return precResult;
0163 }
0164
0165 template <CompositeSpacePointContainer Cont_t>
0166 CompositeSpacePointLineFitter::FitParameters
0167 CompositeSpacePointLineFitter::fastFit(
0168 const Cont_t& measurements, const Line_t& initialGuess,
0169 const std::size_t nStraws,
0170 const std::vector<FitParIndex>& parsToUse) const {
0171 using enum FitParIndex;
0172
0173 FitParameters result{};
0174 const FastFitResult precResult{
0175 fastPrecFit(measurements, initialGuess, nStraws, parsToUse)};
0176 if (!precResult) {
0177 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fast fit failed.");
0178 return result;
0179 }
0180
0181
0182
0183 mergePrecAndNonPrec(result, precResult, measurements, parsToUse);
0184
0185 return result;
0186 }
0187
0188 template <CompositeSpacePointContainer Cont_t,
0189 CompositeSpacePointFastCalibrator<
0190 CompositeSpacePointLineFitter::SpacePoint_t<Cont_t>>
0191 Calibrator_t>
0192 CompositeSpacePointLineFitter::FitParameters
0193 CompositeSpacePointLineFitter::fastFit(
0194 const Acts::CalibrationContext& ctx, const Calibrator_t& calibrator,
0195 const Cont_t& measurements, const Line_t& initialGuess,
0196 const double startT0, const std::vector<FitParIndex>& parsToUse) const {
0197 using enum FitParIndex;
0198
0199 FitParameters result{};
0200 const FastFitResultT0 precResult{fastPrecFit(
0201 ctx, calibrator, measurements, initialGuess, startT0, parsToUse)};
0202 if (!precResult) {
0203 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fast fit failed.");
0204 return result;
0205 }
0206
0207 result.parameters[toUnderlying(t0)] = precResult->t0;
0208 result.covariance(toUnderlying(t0), toUnderlying(t0)) =
0209 Acts::square(precResult->dT0);
0210
0211
0212
0213 const bool fitT0{true};
0214 mergePrecAndNonPrec(result, precResult, measurements, parsToUse, fitT0);
0215
0216 return result;
0217 }
0218
0219 template <CompositeSpacePointContainer Cont_t>
0220 void CompositeSpacePointLineFitter::mergePrecAndNonPrec(
0221 FitParameters& result, const FastFitResult& precResult,
0222 const Cont_t& measurements, const std::vector<FitParIndex>& parsToUse,
0223 const bool fitT0) const {
0224 using enum FitParIndex;
0225 using namespace Acts::UnitLiterals;
0226
0227
0228 result.parameters[toUnderlying(y0)] = precResult->y0;
0229 result.parameters[toUnderlying(theta)] = precResult->theta;
0230 result.covariance(toUnderlying(y0), toUnderlying(y0)) =
0231 Acts::square(precResult->dY0);
0232 result.covariance(toUnderlying(theta), toUnderlying(theta)) =
0233 Acts::square(precResult->dTheta);
0234 result.nDoF = static_cast<unsigned>(precResult->nDoF);
0235 result.nIter = static_cast<unsigned>(precResult->nIter);
0236 result.chi2 = precResult->chi2;
0237 result.converged = true;
0238
0239
0240 if (std::ranges::none_of(parsToUse, [](const FitParIndex idx) {
0241 return idx == phi || idx == x0;
0242 })) {
0243 result.parameters[toUnderlying(phi)] = 90._degree;
0244 ACTS_DEBUG(
0245 __func__ << "() " << __LINE__
0246 << " - No measurements in non precision direction parsed.");
0247 return;
0248 }
0249
0250 ACTS_DEBUG(__func__ << "() " << __LINE__
0251 << " - Start fast non-precision fit.");
0252 using ResidualIdx = detail::CompSpacePointAuxiliaries::ResidualIdx;
0253 const FastFitResult nonPrecResult =
0254 m_fastFitter.fit(measurements, ResidualIdx::nonBending);
0255 if (!nonPrecResult) {
0256 result.parameters[toUnderlying(phi)] = 90._degree;
0257 ACTS_DEBUG(__func__ << "() " << __LINE__
0258 << " - Fast non-precision fit failed.");
0259 return;
0260 }
0261 result.parameters[toUnderlying(x0)] = nonPrecResult->y0;
0262 result.covariance(toUnderlying(x0), toUnderlying(x0)) =
0263 Acts::square(nonPrecResult->dY0);
0264 result.nDoF += nonPrecResult->nDoF;
0265 result.nIter += nonPrecResult->nIter;
0266
0267
0268 double tanTheta = std::tan(result.parameters[toUnderlying(theta)]);
0269 double tanPhi = std::tan(nonPrecResult->theta);
0270 auto dir = makeDirectionFromAxisTangents(tanPhi, tanTheta);
0271 result.parameters[toUnderlying(phi)] = VectorHelpers::phi(dir);
0272 result.parameters[toUnderlying(theta)] = VectorHelpers::theta(dir);
0273
0274
0275 Line_t recoLine{result.parameters};
0276 result.chi2 = 0.;
0277 std::ranges::for_each(
0278 measurements, [&recoLine, &result, &fitT0](const auto& m) {
0279 result.chi2 +=
0280 fitT0 ? detail::CompSpacePointAuxiliaries::chi2Term(
0281 recoLine, result.parameters[toUnderlying(t0)], *m)
0282 : detail::CompSpacePointAuxiliaries::chi2Term(recoLine, *m);
0283 });
0284 ACTS_DEBUG(__func__ << "() " << __LINE__ << ": Fast fit done. Obtained result"
0285 << result);
0286 }
0287
0288 template <CompositeSpacePointContainer Cont_t,
0289 CompositeSpacePointCalibrator<Cont_t, Cont_t> Calibrator_t>
0290 CompositeSpacePointLineFitter::FitResult<Cont_t>
0291 CompositeSpacePointLineFitter::fit(
0292 FitOptions<Cont_t, Calibrator_t>&& fitOpts) const {
0293 using namespace Acts::UnitLiterals;
0294
0295 if (!fitOpts.calibrator) {
0296 throw std::invalid_argument(
0297 "CompositeSpacePointLineFitter::fit() - Please provide a valid pointer "
0298 "to a calibrator.");
0299 }
0300
0301 FitResult<Cont_t> result{};
0302 result.measurements = std::move(fitOpts.measurements);
0303 result.parameters = std::move(fitOpts.startParameters);
0304
0305
0306 detail::CompSpacePointAuxiliaries::Config resCfg{};
0307 resCfg.localToGlobal = std::move(fitOpts.localToGlobal);
0308 resCfg.useHessian = m_cfg.useHessian;
0309 resCfg.calcAlongStraw = m_cfg.calcAlongStraw;
0310 resCfg.calcAlongStrip = m_cfg.calcAlongStrip;
0311 resCfg.includeToF = m_cfg.includeToF;
0312
0313 DoFcounts hitCounts{countDoF(result.measurements, fitOpts.selector)};
0314 const std::size_t nStraws{hitCounts.straw};
0315 resCfg.parsToUse = extractFitablePars(hitCounts);
0316 if (resCfg.parsToUse.empty()) {
0317 ACTS_WARNING(__func__ << "() " << __LINE__
0318 << ": No valid degrees of freedom parsed. Please "
0319 << "check your measurements");
0320 return result;
0321 }
0322
0323 Line_t line{};
0324
0325
0326 if (m_cfg.useFastFitter) {
0327 line.updateParameters(result.parameters);
0328 ACTS_DEBUG(__func__ << "() " << __LINE__
0329 << " - Attempt a fast fit, first.");
0330 const bool fitTime{resCfg.parsToUse.back() == FitParIndex::t0};
0331 FitParameters fastResult{};
0332 if (fitTime && nStraws > 2) {
0333 if constexpr (CompositeSpacePointFastCalibrator<Calibrator_t,
0334 SpacePoint_t<Cont_t>>) {
0335 fastResult = fastFit(fitOpts.calibContext, *fitOpts.calibrator,
0336 result.measurements, line,
0337 result.parameters[toUnderlying(FitParIndex::t0)],
0338 resCfg.parsToUse);
0339 if (fastResult.converged) {
0340 fastResult.parameters[toUnderlying(FitParIndex::t0)] -=
0341 (fitOpts.localToGlobal * line.position()).norm() /
0342 PhysicalConstants::c;
0343 }
0344 } else {
0345 ACTS_WARNING(__func__
0346 << "() " << __LINE__
0347 << ": Skipping fast fit - calibrator does not satisfy "
0348 << "CompositeSpacePointFastCalibrator concept");
0349 }
0350 } else {
0351 fastResult =
0352 fastFit(result.measurements, line, nStraws, resCfg.parsToUse);
0353 }
0354 if (fastResult.converged) {
0355 static_cast<FitParameters&>(result) = std::move(fastResult);
0356 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fit converged.");
0357
0358 if (!m_cfg.fastPreFitter) {
0359 line.updateParameters(result.parameters);
0360
0361 result.measurements = fitOpts.calibrator->calibrate(
0362 fitOpts.calibContext, line.position(), line.direction(),
0363 fitTime ? result.parameters[toUnderlying(FitParIndex::t0)] : 0.,
0364 result.measurements);
0365 return result;
0366 }
0367
0368 result.converged = false;
0369 } else {
0370 ACTS_DEBUG(__func__ << "() " << __LINE__ << " - Fit failed.");
0371 return result;
0372 }
0373 }
0374
0375 if (!m_cfg.recalibrate) {
0376 line.updateParameters(result.parameters);
0377 fitOpts.calibrator->updateSigns(line.position(), line.direction(),
0378 result.measurements);
0379 }
0380
0381 ChiSqCache cache{};
0382 detail::CompSpacePointAuxiliaries pullCalculator{resCfg, logger().clone()};
0383 for (; !result.converged && result.nIter < m_cfg.maxIter; ++result.nIter) {
0384 cache.reset();
0385
0386 line.updateParameters(result.parameters);
0387 const double t0 = result.parameters[toUnderlying(FitParIndex::t0)];
0388
0389 ACTS_VERBOSE(__func__ << "() " << __LINE__ << ": Start next iteration "
0390 << result << " --> " << toString(line.position())
0391 << " + " << toString(line.direction()) << ".");
0392
0393 if (m_cfg.recalibrate) {
0394 result.measurements = fitOpts.calibrator->calibrate(
0395 fitOpts.calibContext, line.position(), line.direction(), t0,
0396 result.measurements);
0397
0398 auto parsBkp = std::move(resCfg.parsToUse);
0399 resCfg.parsToUse =
0400 extractFitablePars(countDoF(result.measurements, fitOpts.selector));
0401
0402
0403 if (resCfg.parsToUse.empty()) {
0404 ACTS_WARNING(__func__ << "() " << __LINE__ << ": Line parameters "
0405 << toString(line.position()) << " + "
0406 << toString(line.direction()) << ", t0: "
0407 << t0 / 1._ns << " invalidated all measurements");
0408 return result;
0409 }
0410
0411 if (parsBkp != resCfg.parsToUse) {
0412
0413 pullCalculator =
0414 detail::CompSpacePointAuxiliaries{resCfg, logger().clone()};
0415 }
0416
0417 fitOpts.calibrator->updateSigns(line.position(), line.direction(),
0418 result.measurements);
0419 }
0420
0421 for (const auto& spacePoint : result.measurements) {
0422
0423 if (fitOpts.selector.connected() && !fitOpts.selector(*spacePoint)) {
0424 continue;
0425 }
0426
0427 if (pullCalculator.config().parsToUse.back() == FitParIndex::t0) {
0428 double driftV{fitOpts.calibrator->driftVelocity(fitOpts.calibContext,
0429 *spacePoint)};
0430 double driftA{fitOpts.calibrator->driftAcceleration(
0431 fitOpts.calibContext, *spacePoint)};
0432 pullCalculator.updateFullResidual(line, t0, *spacePoint, driftV,
0433 driftA);
0434 } else {
0435 pullCalculator.updateSpatialResidual(line, *spacePoint);
0436 }
0437
0438 pullCalculator.updateChiSq(cache, spacePoint->covariance());
0439 }
0440 pullCalculator.symmetrizeHessian(cache);
0441 result.chi2 = cache.chi2;
0442
0443 UpdateStep update{UpdateStep::goodStep};
0444 switch (pullCalculator.config().parsToUse.size()) {
0445
0446 case 2: {
0447 update = updateParameters<2>(pullCalculator.config().parsToUse.front(),
0448 cache, result.parameters);
0449 break;
0450 }
0451
0452 case 3: {
0453 update = updateParameters<3>(pullCalculator.config().parsToUse.front(),
0454 cache, result.parameters);
0455 break;
0456 }
0457
0458 case 4: {
0459 update = updateParameters<4>(pullCalculator.config().parsToUse.front(),
0460 cache, result.parameters);
0461 break;
0462 }
0463
0464 case 5: {
0465 update = updateParameters<5>(pullCalculator.config().parsToUse.front(),
0466 cache, result.parameters);
0467 break;
0468 }
0469 default:
0470 ACTS_WARNING(__func__ << "() " << __LINE__
0471 << ": Invalid parameter size "
0472 << pullCalculator.config().parsToUse.size());
0473 return result;
0474 }
0475
0476 for (const FitParIndex par : pullCalculator.config().parsToUse) {
0477 const auto p = toUnderlying(par);
0478 if (m_cfg.ranges[p][0] < m_cfg.ranges[p][1] &&
0479 (result.parameters[p] < m_cfg.ranges[p][0] ||
0480 result.parameters[p] > m_cfg.ranges[p][1])) {
0481 ACTS_VERBOSE(__func__ << "() " << __LINE__ << ": The parameter "
0482 << pullCalculator.parName(par) << " "
0483 << result.parameters[p] << " is out range ["
0484 << m_cfg.ranges[p][0] << ";" << m_cfg.ranges[p][1]
0485 << "]");
0486 update = UpdateStep::outOfBounds;
0487 }
0488 }
0489 switch (update) {
0490 using enum UpdateStep;
0491 case converged: {
0492 result.converged = true;
0493 break;
0494 }
0495 case goodStep: {
0496 break;
0497 }
0498 case outOfBounds: {
0499 return result;
0500 }
0501 }
0502 }
0503
0504 if (result.converged) {
0505 const DoFcounts doF = countDoF(result.measurements, fitOpts.selector);
0506 result.nDoF = doF.nonBending + doF.bending + doF.time -
0507 pullCalculator.config().parsToUse.size();
0508 line.updateParameters(result.parameters);
0509 const double t0 = result.parameters[toUnderlying(FitParIndex::t0)];
0510
0511 result.measurements = fitOpts.calibrator->calibrate(
0512 fitOpts.calibContext, line.position(), line.direction(), t0,
0513 result.measurements);
0514
0515
0516 switch (pullCalculator.config().parsToUse.size()) {
0517
0518 case 2: {
0519 fillCovariance<2>(pullCalculator.config().parsToUse.front(),
0520 cache.hessian, result.covariance);
0521 break;
0522 }
0523
0524 case 3: {
0525 fillCovariance<3>(pullCalculator.config().parsToUse.front(),
0526 cache.hessian, result.covariance);
0527 break;
0528 }
0529
0530 case 4: {
0531 fillCovariance<4>(pullCalculator.config().parsToUse.front(),
0532 cache.hessian, result.covariance);
0533 break;
0534 }
0535
0536 case 5: {
0537 fillCovariance<5>(pullCalculator.config().parsToUse.front(),
0538 cache.hessian, result.covariance);
0539 break;
0540 }
0541
0542 default:
0543 break;
0544 }
0545 }
0546 return result;
0547 }
0548
0549 template <unsigned N>
0550 CompositeSpacePointLineFitter::UpdateStep
0551 CompositeSpacePointLineFitter::updateParameters(const FitParIndex firstPar,
0552 ChiSqCache& cache,
0553 ParamVec_t& currentPars) const
0554 requires(N >= 2 && N <= s_nPars)
0555 {
0556 auto firstIdx = toUnderlying(firstPar);
0557 assert(firstIdx + N <= s_nPars);
0558
0559 if constexpr (N == 3) {
0560 auto t0Idx = toUnderlying(FitParIndex::t0);
0561 assert(firstIdx + N - 1 == 2);
0562 std::swap(currentPars[2], currentPars[t0Idx]);
0563 std::swap(cache.gradient[2], cache.gradient[t0Idx]);
0564 cache.hessian.row(2).swap(cache.hessian.row(t0Idx));
0565 cache.hessian.col(2).swap(cache.hessian.col(t0Idx));
0566 }
0567 Eigen::Map<ActsVector<N>> miniPars{currentPars.data() + firstIdx};
0568 ACTS_VERBOSE(__func__ << "<" << N << ">() - " << __LINE__
0569 << ": Current parameters " << toString(miniPars)
0570 << " with chi2: " << cache.chi2 << ", gradient: "
0571 << toString(cache.gradient) << ", hessian: \n"
0572 << cache.hessian);
0573
0574
0575 Eigen::Map<const ActsVector<N>> miniGradient{cache.gradient.data() +
0576 firstIdx};
0577
0578 if (miniGradient.norm() < m_cfg.precCutOff) {
0579 ACTS_DEBUG(__func__ << "<" << N << ">() - " << __LINE__
0580 << ": Gradient is small enough");
0581 return UpdateStep::converged;
0582 }
0583
0584 Acts::ActsSquareMatrix<N> miniHessian{
0585 cache.hessian.block<N, N>(firstIdx, firstIdx)};
0586 ACTS_VERBOSE(__func__ << "<" << N << ">() - " << __LINE__
0587 << ": Projected parameters: " << toString(miniPars)
0588 << " gradient: " << toString(miniGradient)
0589 << ", hessian: \n"
0590 << miniHessian
0591 << ", determinant: " << miniHessian.determinant());
0592
0593 auto inverseH = safeInverse(miniHessian);
0594
0595 if (inverseH) {
0596 const ActsVector<N> update{(*inverseH) * miniGradient};
0597
0598 if (update.norm() < m_cfg.precCutOff) {
0599 ACTS_DEBUG(__func__ << "<" << N << ">() - " << __LINE__ << ": Update "
0600 << toString(update) << " is negligible small.");
0601 return UpdateStep::converged;
0602 }
0603 ACTS_VERBOSE(__func__ << "<" << N << ">() - " << __LINE__
0604 << ": Inverted Hessian \n"
0605 << (*inverseH) << "\n-> Update parameters by "
0606 << toString(update));
0607 miniPars -= update;
0608
0609 } else {
0610
0611 const ActsVector<N> update{
0612 std::min(m_cfg.gradientStep, miniGradient.norm()) *
0613 miniGradient.normalized()};
0614
0615 ACTS_VERBOSE(__func__ << "<" << N << ">() - " << __LINE__
0616 << ": Update parameters by " << toString(update));
0617 miniPars -= update;
0618 }
0619
0620 if constexpr (N == 3) {
0621 std::swap(currentPars[2], currentPars[toUnderlying(FitParIndex::t0)]);
0622 }
0623
0624
0625 return UpdateStep::goodStep;
0626 }
0627
0628 template <unsigned N>
0629 void CompositeSpacePointLineFitter::fillCovariance(const FitParIndex firstPar,
0630 const CovMat_t& hessian,
0631 CovMat_t& covariance) const
0632 requires(N >= 2 && N <= s_nPars)
0633 {
0634 auto firstIdx = toUnderlying(firstPar);
0635 assert(firstIdx + N <= s_nPars);
0636
0637 Acts::ActsSquareMatrix<N> miniHessian =
0638 hessian.block<N, N>(firstIdx, firstIdx).eval();
0639
0640 auto inverseH = safeInverse(miniHessian);
0641
0642 if (inverseH) {
0643 auto covBlock = covariance.block<N, N>(firstIdx, firstIdx);
0644 covBlock = *inverseH;
0645
0646
0647 if constexpr (N == 3) {
0648 auto t0Idx = toUnderlying(FitParIndex::t0);
0649 covariance(t0Idx, t0Idx) = 1.;
0650 covariance.row(2).swap(covariance.row(t0Idx));
0651 covariance.col(2).swap(covariance.col(t0Idx));
0652 }
0653 }
0654
0655 ACTS_DEBUG(__func__ << "<" << N << ">() - " << __LINE__
0656 << ": Evaluated covariance: \n"
0657 << covariance);
0658 }
0659
0660 }