File indexing completed on 2026-05-25 07:47:09
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Definitions/Common.hpp"
0013 #include "Acts/EventData/MeasurementHelpers.hpp"
0014 #include "Acts/EventData/MultiTrajectory.hpp"
0015 #include "Acts/EventData/SourceLink.hpp"
0016 #include "Acts/EventData/TrackParameters.hpp"
0017 #include "Acts/EventData/TrackProxyConcept.hpp"
0018 #include "Acts/EventData/Types.hpp"
0019 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0020 #include "Acts/EventData/VectorTrackContainer.hpp"
0021 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0022 #include "Acts/Geometry/GeometryContext.hpp"
0023 #include "Acts/Geometry/TrackingVolume.hpp"
0024 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0025 #include "Acts/Material/Interactions.hpp"
0026 #include "Acts/Propagator/DirectNavigator.hpp"
0027 #include "Acts/Propagator/PropagatorOptions.hpp"
0028 #include "Acts/Propagator/StandardAborters.hpp"
0029 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0030 #include "Acts/TrackFitting/GlobalChiSquareFitterError.hpp"
0031 #include "Acts/TrackFitting/detail/VoidFitterComponents.hpp"
0032 #include "Acts/Utilities/CalibrationContext.hpp"
0033 #include "Acts/Utilities/Delegate.hpp"
0034 #include "Acts/Utilities/Logger.hpp"
0035 #include "Acts/Utilities/Result.hpp"
0036 #include "Acts/Utilities/TrackHelpers.hpp"
0037
0038 #include <functional>
0039 #include <limits>
0040 #include <memory>
0041 #include <type_traits>
0042 #include <unordered_map>
0043
0044 namespace Acts::Experimental {
0045
0046
0047
0048
0049 namespace Gx2fConstants {
0050 constexpr std::string_view gx2fnUpdateColumn = "Gx2fnUpdateColumn";
0051
0052
0053 constexpr TrackStatePropMask trackStateMask = TrackStatePropMask::Smoothed |
0054 TrackStatePropMask::Jacobian |
0055 TrackStatePropMask::Calibrated;
0056
0057
0058
0059 const Eigen::Matrix<double, eBoundSize, 2> phiThetaProjector = [] {
0060 Eigen::Matrix<double, eBoundSize, 2> m =
0061 Eigen::Matrix<double, eBoundSize, 2>::Zero();
0062 m(eBoundPhi, 0) = 1.0;
0063 m(eBoundTheta, 1) = 1.0;
0064 return m;
0065 }();
0066 }
0067
0068
0069 template <typename traj_t>
0070 struct Gx2FitterExtensions {
0071
0072 using TrackStateProxy = typename MultiTrajectory<traj_t>::TrackStateProxy;
0073
0074 using ConstTrackStateProxy =
0075 typename MultiTrajectory<traj_t>::ConstTrackStateProxy;
0076
0077 using Parameters = typename TrackStateProxy::Parameters;
0078
0079
0080 using Calibrator =
0081 Delegate<void(const GeometryContext&, const CalibrationContext&,
0082 const SourceLink&, TrackStateProxy)>;
0083
0084
0085
0086 using Updater = Delegate<Result<void>(const GeometryContext&, TrackStateProxy,
0087 const Logger&)>;
0088
0089
0090 using OutlierFinder = Delegate<bool(ConstTrackStateProxy)>;
0091
0092
0093
0094
0095 Calibrator calibrator;
0096
0097
0098 Updater updater;
0099
0100
0101
0102 OutlierFinder outlierFinder;
0103
0104
0105 SourceLinkSurfaceAccessor surfaceAccessor;
0106
0107
0108 Gx2FitterExtensions() {
0109 calibrator.template connect<&Acts::detail::voidFitterCalibrator<traj_t>>();
0110 updater.template connect<&Acts::detail::voidFitterUpdater<traj_t>>();
0111 outlierFinder.template connect<&Acts::detail::voidOutlierFinder<traj_t>>();
0112 surfaceAccessor.connect<&Acts::detail::voidSurfaceAccessor>();
0113 }
0114 };
0115
0116
0117
0118
0119 template <typename traj_t>
0120 struct Gx2FitterOptions {
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134 Gx2FitterOptions(const GeometryContext& gctx,
0135 const MagneticFieldContext& mctx,
0136 std::reference_wrapper<const CalibrationContext> cctx,
0137 Gx2FitterExtensions<traj_t> extensions_,
0138 const PropagatorPlainOptions& pOptions,
0139 const Surface* rSurface = nullptr, bool mScattering = false,
0140 bool eLoss = false,
0141 const FreeToBoundCorrection& freeToBoundCorrection_ =
0142 FreeToBoundCorrection(false),
0143 const std::size_t nUpdateMax_ = 5,
0144 double relChi2changeCutOff_ = 1e-5)
0145 : geoContext(gctx),
0146 magFieldContext(mctx),
0147 calibrationContext(cctx),
0148 extensions(extensions_),
0149 propagatorPlainOptions(pOptions),
0150 referenceSurface(rSurface),
0151 multipleScattering(mScattering),
0152 energyLoss(eLoss),
0153 freeToBoundCorrection(freeToBoundCorrection_),
0154 nUpdateMax(nUpdateMax_),
0155 relChi2changeCutOff(relChi2changeCutOff_) {}
0156
0157
0158 Gx2FitterOptions() = delete;
0159
0160
0161 std::reference_wrapper<const GeometryContext> geoContext;
0162
0163 std::reference_wrapper<const MagneticFieldContext> magFieldContext;
0164
0165 std::reference_wrapper<const CalibrationContext> calibrationContext;
0166
0167
0168 Gx2FitterExtensions<traj_t> extensions;
0169
0170
0171 PropagatorPlainOptions propagatorPlainOptions;
0172
0173
0174 const Surface* referenceSurface = nullptr;
0175
0176
0177 bool multipleScattering = false;
0178
0179
0180 bool energyLoss = false;
0181
0182
0183
0184 FreeToBoundCorrection freeToBoundCorrection;
0185
0186
0187 std::size_t nUpdateMax = 5;
0188
0189
0190 double relChi2changeCutOff = 1e-7;
0191 };
0192
0193
0194 template <typename traj_t>
0195 struct Gx2FitterResult {
0196
0197 traj_t* fittedStates{nullptr};
0198
0199
0200
0201
0202
0203 std::size_t lastMeasurementIndex = Acts::kTrackIndexInvalid;
0204
0205
0206
0207
0208
0209 std::size_t lastTrackIndex = Acts::kTrackIndexInvalid;
0210
0211
0212 std::optional<BoundTrackParameters> fittedParameters;
0213
0214
0215 std::size_t measurementStates = 0;
0216
0217
0218
0219
0220
0221 std::size_t measurementHoles = 0;
0222
0223
0224 std::size_t processedStates = 0;
0225
0226
0227 std::size_t processedMeasurements = 0;
0228
0229
0230 bool finished = false;
0231
0232
0233 std::vector<const Surface*> missedActiveSurfaces;
0234
0235
0236
0237 std::vector<const Surface*> passedAgainSurfaces;
0238
0239
0240 std::size_t surfaceCount = 0;
0241 };
0242
0243
0244
0245
0246
0247
0248 struct ScatteringProperties {
0249 public:
0250
0251
0252
0253
0254
0255 ScatteringProperties(const BoundVector& scatteringAngles_,
0256 const double invCovarianceMaterial_,
0257 const bool materialIsValid_)
0258 : m_scatteringAngles(scatteringAngles_),
0259 m_invCovarianceMaterial(invCovarianceMaterial_),
0260 m_materialIsValid(materialIsValid_) {}
0261
0262
0263
0264 const BoundVector& scatteringAngles() const { return m_scatteringAngles; }
0265
0266
0267
0268 BoundVector& scatteringAngles() { return m_scatteringAngles; }
0269
0270
0271
0272 double invCovarianceMaterial() const { return m_invCovarianceMaterial; }
0273
0274
0275
0276 bool materialIsValid() const { return m_materialIsValid; }
0277
0278 private:
0279
0280
0281 BoundVector m_scatteringAngles;
0282
0283
0284
0285 double m_invCovarianceMaterial;
0286
0287
0288
0289 bool m_materialIsValid;
0290 };
0291
0292
0293
0294
0295
0296 struct Gx2fSystem {
0297 public:
0298
0299
0300
0301 explicit Gx2fSystem(std::size_t nDims)
0302 : m_nDims{nDims},
0303 m_aMatrix{Eigen::MatrixXd::Zero(nDims, nDims)},
0304 m_bVector{Eigen::VectorXd::Zero(nDims)} {}
0305
0306
0307
0308 std::size_t nDims() const { return m_nDims; }
0309
0310
0311
0312 double chi2() const { return m_chi2; }
0313
0314
0315
0316 double& chi2() { return m_chi2; }
0317
0318
0319
0320 const Eigen::MatrixXd& aMatrix() const { return m_aMatrix; }
0321
0322
0323
0324 Eigen::MatrixXd& aMatrix() { return m_aMatrix; }
0325
0326
0327
0328 const Eigen::VectorXd& bVector() const { return m_bVector; }
0329
0330
0331
0332 Eigen::VectorXd& bVector() { return m_bVector; }
0333
0334
0335
0336 std::size_t ndf() const { return m_ndf; }
0337
0338
0339
0340 std::size_t& ndf() { return m_ndf; }
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 std::size_t findRequiredNdf() {
0352 std::size_t ndfSystem = 0;
0353 if (m_aMatrix(4, 4) == 0) {
0354 ndfSystem = 4;
0355 } else if (m_aMatrix(5, 5) == 0) {
0356 ndfSystem = 5;
0357 } else {
0358 ndfSystem = 6;
0359 }
0360
0361 return ndfSystem;
0362 }
0363
0364
0365
0366 bool isWellDefined() { return m_ndf > findRequiredNdf(); }
0367
0368 private:
0369
0370 std::size_t m_nDims;
0371
0372
0373 double m_chi2 = 0.;
0374
0375
0376 Eigen::MatrixXd m_aMatrix;
0377
0378
0379 Eigen::VectorXd m_bVector;
0380
0381
0382 std::size_t m_ndf = 0u;
0383 };
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 void addMeasurementToGx2fSumsBackend(
0402 Gx2fSystem& extendedSystem,
0403 const std::vector<BoundMatrix>& jacobianFromStart,
0404 const Eigen::MatrixXd& covarianceMeasurement, const BoundVector& predicted,
0405 const Eigen::VectorXd& measurement, const Eigen::MatrixXd& projector,
0406 const Logger& logger);
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 template <std::size_t kMeasDim, typename track_state_t>
0422 void addMeasurementToGx2fSums(Gx2fSystem& extendedSystem,
0423 const std::vector<BoundMatrix>& jacobianFromStart,
0424 const track_state_t& trackState,
0425 const Logger& logger) {
0426 const ActsSquareMatrix<kMeasDim> covarianceMeasurement =
0427 trackState.template calibratedCovariance<kMeasDim>();
0428
0429 const BoundVector predicted = trackState.smoothed();
0430
0431 const ActsVector<kMeasDim> measurement =
0432 trackState.template calibrated<kMeasDim>();
0433
0434 const ActsMatrix<kMeasDim, eBoundSize> projector =
0435 trackState.template projectorSubspaceHelper<kMeasDim>().projector();
0436
0437 addMeasurementToGx2fSumsBackend(extendedSystem, jacobianFromStart,
0438 covarianceMeasurement, predicted, measurement,
0439 projector, logger);
0440 }
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455 template <typename track_state_t>
0456 void addMaterialToGx2fSums(
0457 Gx2fSystem& extendedSystem, const std::size_t nMaterialsHandled,
0458 const std::unordered_map<GeometryIdentifier, ScatteringProperties>&
0459 scatteringMap,
0460 const track_state_t& trackState, const Logger& logger) {
0461
0462 const GeometryIdentifier geoId = trackState.referenceSurface().geometryId();
0463 const auto scatteringMapId = scatteringMap.find(geoId);
0464 if (scatteringMapId == scatteringMap.end()) {
0465 ACTS_ERROR("No scattering angles found for material surface " << geoId);
0466 throw std::runtime_error(
0467 "No scattering angles found for material surface.");
0468 }
0469
0470 const double sinThetaLoc = std::sin(trackState.smoothed()[eBoundTheta]);
0471
0472
0473 const std::size_t deltaPosition = eBoundSize + 2 * nMaterialsHandled;
0474
0475 const BoundVector& scatteringAngles =
0476 scatteringMapId->second.scatteringAngles();
0477
0478 const double invCov = scatteringMapId->second.invCovarianceMaterial();
0479
0480
0481 extendedSystem.aMatrix()(deltaPosition, deltaPosition) +=
0482 invCov * sinThetaLoc * sinThetaLoc;
0483 extendedSystem.bVector()(deltaPosition, 0) -=
0484 invCov * scatteringAngles[eBoundPhi] * sinThetaLoc;
0485 extendedSystem.chi2() += invCov * scatteringAngles[eBoundPhi] * sinThetaLoc *
0486 scatteringAngles[eBoundPhi] * sinThetaLoc;
0487
0488
0489 extendedSystem.aMatrix()(deltaPosition + 1, deltaPosition + 1) += invCov;
0490 extendedSystem.bVector()(deltaPosition + 1, 0) -=
0491 invCov * scatteringAngles[eBoundTheta];
0492 extendedSystem.chi2() +=
0493 invCov * scatteringAngles[eBoundTheta] * scatteringAngles[eBoundTheta];
0494
0495 ACTS_VERBOSE(
0496 "Contributions in addMaterialToGx2fSums:\n"
0497 << " invCov: " << invCov << "\n"
0498 << " sinThetaLoc: " << sinThetaLoc << "\n"
0499 << " deltaPosition: " << deltaPosition << "\n"
0500 << " Phi:\n"
0501 << " scattering angle: " << scatteringAngles[eBoundPhi] << "\n"
0502 << " aMatrix contribution: " << invCov * sinThetaLoc * sinThetaLoc
0503 << "\n"
0504 << " bVector contribution: "
0505 << invCov * scatteringAngles[eBoundPhi] * sinThetaLoc << "\n"
0506 << " chi2sum contribution: "
0507 << invCov * scatteringAngles[eBoundPhi] * sinThetaLoc *
0508 scatteringAngles[eBoundPhi] * sinThetaLoc
0509 << "\n"
0510 << " Theta:\n"
0511 << " scattering angle: " << scatteringAngles[eBoundTheta]
0512 << "\n"
0513 << " aMatrix contribution: " << invCov << "\n"
0514 << " bVector contribution: "
0515 << invCov * scatteringAngles[eBoundTheta] << "\n"
0516 << " chi2sum contribution: "
0517 << invCov * scatteringAngles[eBoundTheta] * scatteringAngles[eBoundTheta]
0518 << "\n");
0519
0520 return;
0521 }
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538 template <TrackProxyConcept track_proxy_t>
0539 void fillGx2fSystem(
0540 const track_proxy_t track, Gx2fSystem& extendedSystem,
0541 const bool multipleScattering,
0542 const std::unordered_map<GeometryIdentifier, ScatteringProperties>&
0543 scatteringMap,
0544 std::vector<GeometryIdentifier>& geoIdVector, const Logger& logger) {
0545 std::vector<BoundMatrix> jacobianFromStart;
0546 jacobianFromStart.emplace_back(BoundMatrix::Identity());
0547
0548 for (const auto& trackState : track.trackStates()) {
0549
0550 const GeometryIdentifier geoId = trackState.referenceSurface().geometryId();
0551 ACTS_DEBUG("Start to investigate trackState on surface " << geoId);
0552 const auto typeFlags = trackState.typeFlags();
0553 const bool stateHasMeasurement = typeFlags.hasMeasurement();
0554 const bool stateHasMaterial = typeFlags.hasMaterial();
0555
0556
0557
0558
0559
0560 bool doMaterial = multipleScattering && stateHasMaterial;
0561 if (doMaterial) {
0562 const auto scatteringMapId = scatteringMap.find(geoId);
0563 assert(scatteringMapId != scatteringMap.end() &&
0564 "No scattering angles found for material surface.");
0565 doMaterial = doMaterial && scatteringMapId->second.materialIsValid();
0566 }
0567
0568
0569 if (!stateHasMeasurement && !doMaterial) {
0570 ACTS_DEBUG(" Skip state.");
0571 continue;
0572 }
0573
0574
0575 for (auto& jac : jacobianFromStart) {
0576 jac = trackState.jacobian() * jac;
0577 }
0578
0579
0580 if (stateHasMeasurement) {
0581 ACTS_DEBUG(" Handle measurement.");
0582
0583 const auto measDim = trackState.calibratedSize();
0584
0585 if (measDim < 1 || 6 < measDim) {
0586 ACTS_ERROR("Can not process state with measurement with "
0587 << measDim << " dimensions.");
0588 throw std::domain_error(
0589 "Found measurement with less than 1 or more than 6 dimension(s).");
0590 }
0591
0592 extendedSystem.ndf() += measDim;
0593
0594 visit_measurement(measDim, [&](auto N) {
0595 addMeasurementToGx2fSums<N>(extendedSystem, jacobianFromStart,
0596 trackState, logger);
0597 });
0598 }
0599
0600
0601 if (doMaterial) {
0602 ACTS_DEBUG(" Handle material");
0603
0604 jacobianFromStart.emplace_back(BoundMatrix::Identity());
0605
0606
0607 addMaterialToGx2fSums(extendedSystem, geoIdVector.size(), scatteringMap,
0608 trackState, logger);
0609
0610 geoIdVector.emplace_back(geoId);
0611 }
0612 }
0613 }
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629 template <TrackProxyConcept track_proxy_t>
0630 std::size_t countMaterialStates(
0631 const track_proxy_t track,
0632 const std::unordered_map<GeometryIdentifier, ScatteringProperties>&
0633 scatteringMap,
0634 const Logger& logger) {
0635 std::size_t nMaterialSurfaces = 0;
0636 ACTS_DEBUG("Count the valid material surfaces.");
0637 for (const auto& trackState : track.trackStates()) {
0638 const auto typeFlags = trackState.typeFlags();
0639 const bool stateHasMaterial = typeFlags.hasMaterial();
0640
0641 if (!stateHasMaterial) {
0642 continue;
0643 }
0644
0645
0646 const GeometryIdentifier geoId = trackState.referenceSurface().geometryId();
0647
0648 const auto scatteringMapId = scatteringMap.find(geoId);
0649 assert(scatteringMapId != scatteringMap.end() &&
0650 "No scattering angles found for material surface.");
0651 if (!scatteringMapId->second.materialIsValid()) {
0652 continue;
0653 }
0654
0655 nMaterialSurfaces++;
0656 }
0657
0658 return nMaterialSurfaces;
0659 }
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669 Eigen::VectorXd computeGx2fDeltaParams(const Gx2fSystem& extendedSystem);
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679 void updateGx2fParams(
0680 BoundTrackParameters& params, const Eigen::VectorXd& deltaParamsExtended,
0681 const std::size_t nMaterialSurfaces,
0682 std::unordered_map<GeometryIdentifier, ScatteringProperties>& scatteringMap,
0683 const std::vector<GeometryIdentifier>& geoIdVector);
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695 void updateGx2fCovarianceParams(BoundMatrix& fullCovariancePredicted,
0696 Gx2fSystem& extendedSystem);
0697
0698
0699
0700
0701
0702
0703 template <typename propagator_t, typename traj_t>
0704 class Gx2Fitter {
0705
0706 using Gx2fNavigator = typename propagator_t::Navigator;
0707
0708
0709 static constexpr bool isDirectNavigator =
0710 std::is_same_v<Gx2fNavigator, DirectNavigator>;
0711
0712 static constexpr auto kInvalid = kTrackIndexInvalid;
0713
0714 public:
0715
0716
0717
0718
0719
0720
0721
0722
0723 explicit Gx2Fitter(propagator_t pPropagator,
0724 std::unique_ptr<const Logger> _logger =
0725 getDefaultLogger("Gx2Fitter", Logging::INFO))
0726 : m_propagator(std::move(pPropagator)),
0727 m_logger{std::move(_logger)},
0728 m_actorLogger{m_logger->cloneWithSuffix("Actor")},
0729 m_addToSumLogger{m_logger->cloneWithSuffix("AddToSum")} {}
0730
0731 private:
0732
0733 propagator_t m_propagator;
0734
0735
0736 std::unique_ptr<const Logger> m_logger;
0737 std::unique_ptr<const Logger> m_actorLogger;
0738 std::unique_ptr<const Logger> m_addToSumLogger;
0739
0740 const Logger& logger() const { return *m_logger; }
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750 class Actor {
0751 public:
0752
0753 using result_type = Gx2FitterResult<traj_t>;
0754
0755
0756 const Surface* targetSurface = nullptr;
0757
0758
0759 const std::unordered_map<const Surface*, SourceLink>* inputMeasurements{};
0760
0761
0762 bool multipleScattering = false;
0763
0764
0765 bool energyLoss = false;
0766
0767
0768
0769 FreeToBoundCorrection freeToBoundCorrection;
0770
0771
0772 std::shared_ptr<MultiTrajectory<traj_t>> outputStates;
0773
0774
0775 const Logger* actorLogger{nullptr};
0776
0777
0778 const Logger& logger() const { return *actorLogger; }
0779
0780 Gx2FitterExtensions<traj_t> extensions;
0781
0782
0783 SurfaceReached targetReached;
0784
0785
0786 const CalibrationContext* calibrationContext{nullptr};
0787
0788
0789 const BoundTrackParameters* parametersWithHypothesis = nullptr;
0790
0791
0792
0793 std::unordered_map<GeometryIdentifier, ScatteringProperties>*
0794 scatteringMap = nullptr;
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806 template <typename propagator_state_t, typename stepper_t,
0807 typename navigator_t>
0808 Result<void> act(propagator_state_t& state, const stepper_t& stepper,
0809 const navigator_t& navigator, result_type& result,
0810 const Logger& ) const {
0811 assert(result.fittedStates && "No MultiTrajectory set");
0812
0813
0814 if (result.measurementStates == inputMeasurements->size()) {
0815 ACTS_DEBUG("Actor: finish: All measurements have been found.");
0816 result.finished = true;
0817 } else if (state.navigation.navigationBreak) {
0818 ACTS_DEBUG("Actor: finish: navigationBreak.");
0819 result.finished = true;
0820 }
0821
0822
0823 if (result.finished) {
0824
0825 if (result.measurementStates > 0) {
0826 result.missedActiveSurfaces.resize(result.measurementHoles);
0827 }
0828
0829 return Result<void>::success();
0830 }
0831
0832
0833
0834 auto surface = navigator.currentSurface(state.navigation);
0835 if (surface == nullptr) {
0836 return Result<void>::success();
0837 }
0838
0839 ++result.surfaceCount;
0840 const GeometryIdentifier geoId = surface->geometryId();
0841 ACTS_DEBUG("Surface " << geoId << " detected.");
0842
0843 const bool surfaceIsSensitive = surface->isSensitive();
0844 const bool surfaceHasMaterial = (surface->surfaceMaterial() != nullptr);
0845
0846
0847
0848 bool doMaterial = multipleScattering && surfaceHasMaterial;
0849
0850
0851
0852 if (doMaterial) {
0853 ACTS_DEBUG(" The surface contains material, ...");
0854
0855 auto scatteringMapId = scatteringMap->find(geoId);
0856 if (scatteringMapId == scatteringMap->end()) {
0857 ACTS_DEBUG(" ... create entry in scattering map.");
0858
0859 const MaterialSlab slab = Acts::detail::evaluateMaterialSlab(
0860 state, stepper, *surface,
0861 Acts::detail::determineMaterialUpdateMode(
0862 state, navigator, MaterialUpdateMode::FullUpdate));
0863 const bool slabIsValid = !slab.isVacuum();
0864
0865 double invSigma2 = 0.;
0866 if (slabIsValid) {
0867 const auto& particle =
0868 parametersWithHypothesis->particleHypothesis();
0869
0870 const double sigma =
0871 static_cast<double>(Acts::computeMultipleScatteringTheta0(
0872 slab, particle.absolutePdg(), particle.mass(),
0873 static_cast<float>(
0874 parametersWithHypothesis->parameters()[eBoundQOverP]),
0875 particle.absoluteCharge()));
0876 ACTS_VERBOSE(
0877 " The Highland formula gives sigma = " << sigma);
0878 invSigma2 = 1. / std::pow(sigma, 2);
0879 } else {
0880 ACTS_VERBOSE(" Material slab is not valid.");
0881 }
0882
0883 scatteringMap->emplace(
0884 geoId, ScatteringProperties{BoundVector::Zero(), invSigma2,
0885 slabIsValid});
0886 scatteringMapId = scatteringMap->find(geoId);
0887 } else {
0888 ACTS_DEBUG(" ... found entry in scattering map.");
0889 }
0890
0891 doMaterial = doMaterial && scatteringMapId->second.materialIsValid();
0892 }
0893
0894
0895 if (auto sourceLinkIt = inputMeasurements->find(surface);
0896 sourceLinkIt != inputMeasurements->end()) {
0897 ACTS_DEBUG(" The surface contains a measurement.");
0898
0899
0900 stepper.transportCovarianceToBound(state.stepping, *surface,
0901 freeToBoundCorrection);
0902
0903
0904 auto& fittedStates = *result.fittedStates;
0905
0906
0907
0908 typename traj_t::TrackStateProxy trackStateProxy =
0909 fittedStates.makeTrackState(Gx2fConstants::trackStateMask,
0910 result.lastTrackIndex);
0911 const std::size_t currentTrackIndex = trackStateProxy.index();
0912
0913
0914
0915 {
0916 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
0917
0918 auto res = stepper.boundState(state.stepping, *surface, false,
0919 freeToBoundCorrection);
0920 if (!res.ok()) {
0921 return res.error();
0922 }
0923
0924 auto& [boundParams, jacobian, pathLength] = *res;
0925
0926
0927
0928 if (doMaterial) {
0929 ACTS_DEBUG(" Update parameters with scattering angles.");
0930 const auto scatteringMapId = scatteringMap->find(geoId);
0931 ACTS_VERBOSE(
0932 " scatteringAngles: "
0933 << scatteringMapId->second.scatteringAngles().transpose());
0934 ACTS_VERBOSE(" boundParams before the update: "
0935 << boundParams.parameters().transpose());
0936 boundParams.parameters() +=
0937 scatteringMapId->second.scatteringAngles();
0938 ACTS_VERBOSE(" boundParams after the update: "
0939 << boundParams.parameters().transpose());
0940 }
0941
0942
0943 trackStateProxy.smoothed() = boundParams.parameters();
0944 trackStateProxy.smoothedCovariance() = state.stepping.cov;
0945
0946 trackStateProxy.jacobian() = jacobian;
0947 trackStateProxy.pathLength() = pathLength;
0948
0949 if (doMaterial) {
0950 stepper.update(state.stepping,
0951 transformBoundToFreeParameters(
0952 trackStateProxy.referenceSurface(),
0953 state.geoContext, trackStateProxy.smoothed()),
0954 trackStateProxy.smoothed(),
0955 trackStateProxy.smoothedCovariance(), *surface);
0956 }
0957 }
0958
0959
0960
0961 extensions.calibrator(state.geoContext, *calibrationContext,
0962 sourceLinkIt->second, trackStateProxy);
0963
0964
0965 auto typeFlags = trackStateProxy.typeFlags();
0966 typeFlags.setHasParameters();
0967 if (surfaceHasMaterial) {
0968 typeFlags.setHasMaterial();
0969 }
0970
0971
0972 typeFlags.setIsMeasurement();
0973
0974 ++result.processedMeasurements;
0975
0976 result.lastMeasurementIndex = currentTrackIndex;
0977 result.lastTrackIndex = currentTrackIndex;
0978
0979
0980
0981 ++result.measurementStates;
0982
0983
0984 ++result.processedStates;
0985
0986
0987
0988 result.measurementHoles = result.missedActiveSurfaces.size();
0989
0990 return Result<void>::success();
0991 }
0992
0993 if (doMaterial) {
0994
0995
0996
0997 ACTS_DEBUG(
0998 " The surface contains no measurement, but material and maybe "
0999 "a hole.");
1000
1001
1002 stepper.transportCovarianceToBound(state.stepping, *surface,
1003 freeToBoundCorrection);
1004
1005
1006 auto& fittedStates = *result.fittedStates;
1007
1008
1009
1010 typename traj_t::TrackStateProxy trackStateProxy =
1011 fittedStates.makeTrackState(Gx2fConstants::trackStateMask,
1012 result.lastTrackIndex);
1013 const std::size_t currentTrackIndex = trackStateProxy.index();
1014
1015
1016
1017 {
1018 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
1019
1020 auto res = stepper.boundState(state.stepping, *surface, false,
1021 freeToBoundCorrection);
1022 if (!res.ok()) {
1023 return res.error();
1024 }
1025
1026 auto& [boundParams, jacobian, pathLength] = *res;
1027
1028
1029
1030
1031
1032 ACTS_DEBUG(" Update parameters with scattering angles.");
1033 const auto scatteringMapId = scatteringMap->find(geoId);
1034 ACTS_VERBOSE(
1035 " scatteringAngles: "
1036 << scatteringMapId->second.scatteringAngles().transpose());
1037 ACTS_VERBOSE(" boundParams before the update: "
1038 << boundParams.parameters().transpose());
1039 boundParams.parameters() +=
1040 scatteringMapId->second.scatteringAngles();
1041 ACTS_VERBOSE(" boundParams after the update: "
1042 << boundParams.parameters().transpose());
1043
1044
1045 trackStateProxy.smoothed() = boundParams.parameters();
1046 trackStateProxy.smoothedCovariance() = state.stepping.cov;
1047
1048 trackStateProxy.jacobian() = jacobian;
1049 trackStateProxy.pathLength() = pathLength;
1050
1051 stepper.update(state.stepping,
1052 transformBoundToFreeParameters(
1053 trackStateProxy.referenceSurface(),
1054 state.geoContext, trackStateProxy.smoothed()),
1055 trackStateProxy.smoothed(),
1056 trackStateProxy.smoothedCovariance(), *surface);
1057 }
1058
1059
1060 auto typeFlags = trackStateProxy.typeFlags();
1061 typeFlags.setHasParameters();
1062 typeFlags.setHasMaterial();
1063
1064
1065
1066 const bool precedingMeasurementExists = (result.measurementStates > 0);
1067 if (surfaceIsSensitive && precedingMeasurementExists) {
1068 ACTS_DEBUG(" Surface is also sensitive. Marked as hole.");
1069 typeFlags.setIsHole();
1070
1071
1072 result.missedActiveSurfaces.push_back(surface);
1073 }
1074
1075 result.lastTrackIndex = currentTrackIndex;
1076
1077 ++result.processedStates;
1078
1079 return Result<void>::success();
1080 }
1081
1082 if (surfaceIsSensitive || surfaceHasMaterial) {
1083
1084
1085
1086 if (multipleScattering) {
1087 ACTS_DEBUG(
1088 " The surface contains no measurement, but maybe a hole.");
1089 } else {
1090 ACTS_DEBUG(
1091 " The surface contains no measurement, but maybe a hole "
1092 "and/or material.");
1093 }
1094
1095
1096
1097
1098 const bool precedingMeasurementExists = (result.measurementStates > 0);
1099 if (!precedingMeasurementExists && !surfaceHasMaterial) {
1100 ACTS_DEBUG(
1101 " Ignoring hole, because there are no preceding "
1102 "measurements.");
1103 return Result<void>::success();
1104 }
1105
1106 auto& fittedStates = *result.fittedStates;
1107
1108
1109
1110 typename traj_t::TrackStateProxy trackStateProxy =
1111 fittedStates.makeTrackState(Gx2fConstants::trackStateMask,
1112 result.lastTrackIndex);
1113 const std::size_t currentTrackIndex = trackStateProxy.index();
1114
1115
1116
1117 {
1118 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
1119
1120 auto res = stepper.boundState(state.stepping, *surface, false,
1121 freeToBoundCorrection);
1122 if (!res.ok()) {
1123 return res.error();
1124 }
1125 const auto& [boundParams, jacobian, pathLength] = *res;
1126
1127
1128 trackStateProxy.smoothed() = boundParams.parameters();
1129 trackStateProxy.smoothedCovariance() = state.stepping.cov;
1130
1131 trackStateProxy.jacobian() = jacobian;
1132 trackStateProxy.pathLength() = pathLength;
1133 }
1134
1135
1136 auto typeFlags = trackStateProxy.typeFlags();
1137 typeFlags.setHasParameters();
1138 if (surfaceHasMaterial) {
1139 ACTS_DEBUG(" It is material.");
1140 typeFlags.setHasMaterial();
1141 }
1142
1143
1144 if (surfaceIsSensitive && precedingMeasurementExists) {
1145 ACTS_DEBUG(" It is a hole.");
1146 typeFlags.setIsHole();
1147
1148 result.missedActiveSurfaces.push_back(surface);
1149 }
1150
1151 result.lastTrackIndex = currentTrackIndex;
1152
1153 ++result.processedStates;
1154
1155 return Result<void>::success();
1156 }
1157
1158 ACTS_DEBUG(" The surface contains no measurement/material/hole.");
1159 return Result<void>::success();
1160 }
1161
1162 template <typename propagator_state_t, typename stepper_t,
1163 typename navigator_t, typename result_t>
1164 bool checkAbort(propagator_state_t& , const stepper_t& ,
1165 const navigator_t& , const result_t& result,
1166 const Logger& ) const {
1167 if (result.finished) {
1168 return true;
1169 }
1170 return false;
1171 }
1172 };
1173
1174 public:
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 template <typename source_link_iterator_t,
1192 TrackContainerFrontend track_container_t>
1193 Result<typename track_container_t::TrackProxy> fit(
1194 source_link_iterator_t it, source_link_iterator_t end,
1195 const BoundTrackParameters& sParameters,
1196 const Gx2FitterOptions<traj_t>& gx2fOptions,
1197 track_container_t& trackContainer) const
1198 requires(!isDirectNavigator)
1199 {
1200
1201
1202
1203 ACTS_VERBOSE("Preparing " << std::distance(it, end)
1204 << " input measurements");
1205 std::unordered_map<const Surface*, SourceLink> inputMeasurements{};
1206
1207 for (; it != end; ++it) {
1208 inputMeasurements.try_emplace(gx2fOptions.extensions.surfaceAccessor(*it),
1209 *it);
1210 }
1211
1212
1213
1214 const bool multipleScattering = gx2fOptions.multipleScattering;
1215
1216
1217 using GX2FActor = Actor;
1218
1219 using GX2FResult = typename GX2FActor::result_type;
1220 using Actors = Acts::ActorList<GX2FActor>;
1221
1222 using PropagatorOptions = typename propagator_t::template Options<Actors>;
1223
1224 BoundTrackParameters params = sParameters;
1225 double chi2sum = 0;
1226 double oldChi2sum = std::numeric_limits<double>::max();
1227
1228
1229
1230
1231
1232 typename track_container_t::TrackContainerBackend trackContainerTempBackend;
1233 traj_t trajectoryTempBackend;
1234 TrackContainer trackContainerTemp{trackContainerTempBackend,
1235 trajectoryTempBackend};
1236
1237
1238
1239
1240 std::size_t tipIndex = kInvalid;
1241
1242
1243
1244 std::unordered_map<GeometryIdentifier, ScatteringProperties> scatteringMap;
1245
1246
1247
1248 BoundMatrix fullCovariancePredicted = BoundMatrix::Identity();
1249
1250 ACTS_VERBOSE("Initial parameters: " << params.parameters().transpose());
1251
1252
1253 ACTS_DEBUG("Start to iterate");
1254
1255
1256
1257
1258 std::size_t nUpdate = 0;
1259 for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; nUpdate++) {
1260 ACTS_DEBUG("nUpdate = " << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax);
1261
1262
1263 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1264
1265
1266
1267 for (const auto& [surface, _] : inputMeasurements) {
1268 propagatorOptions.navigation.insertExternalSurface(*surface);
1269 }
1270
1271 auto& gx2fActor = propagatorOptions.actorList.template get<GX2FActor>();
1272 gx2fActor.inputMeasurements = &inputMeasurements;
1273 gx2fActor.multipleScattering = false;
1274 gx2fActor.extensions = gx2fOptions.extensions;
1275 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1276 gx2fActor.actorLogger = m_actorLogger.get();
1277 gx2fActor.scatteringMap = &scatteringMap;
1278 gx2fActor.parametersWithHypothesis = ¶ms;
1279
1280 auto propagatorState = m_propagator.makeState(propagatorOptions);
1281
1282 auto propagatorInitResult =
1283 m_propagator.initialize(propagatorState, params);
1284 if (!propagatorInitResult.ok()) {
1285 ACTS_DEBUG("Propagation initialization failed: "
1286 << propagatorInitResult.error());
1287 return propagatorInitResult.error();
1288 }
1289
1290 auto& r = propagatorState.template get<Gx2FitterResult<traj_t>>();
1291 r.fittedStates = &trajectoryTempBackend;
1292
1293
1294
1295 trackContainerTemp.clear();
1296
1297 auto propagationResult = m_propagator.propagate(propagatorState);
1298
1299
1300 auto result =
1301 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1302 propagatorOptions, false);
1303
1304 if (!result.ok()) {
1305 ACTS_DEBUG("Propagation failed: " << result.error());
1306 return result.error();
1307 }
1308
1309
1310
1311 auto& propRes = *result;
1312 GX2FResult gx2fResult = std::move(propRes.template get<GX2FResult>());
1313
1314 auto track = trackContainerTemp.makeTrack();
1315 tipIndex = gx2fResult.lastMeasurementIndex;
1316
1317
1318
1319
1320 if (tipIndex == kInvalid) {
1321 ACTS_INFO("Did not find any measurements in nUpdate "
1322 << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax);
1323 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1324 }
1325
1326 track.tipIndex() = tipIndex;
1327 track.linkForward();
1328
1329
1330
1331 const std::size_t nMaterialSurfaces = 0u;
1332
1333
1334
1335 const std::size_t dimsExtendedParams = eBoundSize + 2 * nMaterialSurfaces;
1336
1337
1338
1339 Gx2fSystem extendedSystem{dimsExtendedParams};
1340
1341
1342
1343
1344
1345 std::vector<GeometryIdentifier> geoIdVector;
1346
1347 fillGx2fSystem(track, extendedSystem, false, scatteringMap, geoIdVector,
1348 *m_addToSumLogger);
1349
1350 chi2sum = extendedSystem.chi2();
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364 if ((nUpdate > 0) && !extendedSystem.isWellDefined()) {
1365 ACTS_INFO("Not enough measurements. Require "
1366 << extendedSystem.findRequiredNdf() + 1 << ", but only "
1367 << extendedSystem.ndf() << " could be used.");
1368 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1369 }
1370
1371 Eigen::VectorXd deltaParamsExtended =
1372 computeGx2fDeltaParams(extendedSystem);
1373
1374 ACTS_VERBOSE("aMatrix:\n"
1375 << extendedSystem.aMatrix() << "\n"
1376 << "bVector:\n"
1377 << extendedSystem.bVector() << "\n"
1378 << "deltaParamsExtended:\n"
1379 << deltaParamsExtended << "\n"
1380 << "oldChi2sum = " << oldChi2sum << "\n"
1381 << "chi2sum = " << extendedSystem.chi2());
1382
1383 if ((gx2fOptions.relChi2changeCutOff != 0) && (nUpdate > 0) &&
1384 (std::abs(extendedSystem.chi2() / oldChi2sum - 1) <
1385 gx2fOptions.relChi2changeCutOff)) {
1386 ACTS_DEBUG("Abort with relChi2changeCutOff after "
1387 << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax
1388 << " iterations.");
1389 updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem);
1390 break;
1391 }
1392
1393 if (extendedSystem.chi2() > oldChi2sum + 1e-5) {
1394 ACTS_DEBUG("chi2 not converging monotonically in update " << nUpdate);
1395 }
1396
1397
1398
1399 if (nUpdate == gx2fOptions.nUpdateMax - 1) {
1400
1401
1402
1403
1404
1405 if (gx2fOptions.nUpdateMax > 5) {
1406 ACTS_INFO("Did not converge in " << gx2fOptions.nUpdateMax
1407 << " updates.");
1408 return Experimental::GlobalChiSquareFitterError::DidNotConverge;
1409 }
1410
1411 updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem);
1412 break;
1413 }
1414
1415 updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces,
1416 scatteringMap, geoIdVector);
1417 ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose());
1418
1419 oldChi2sum = extendedSystem.chi2();
1420 }
1421 ACTS_DEBUG("Finished to iterate");
1422 ACTS_VERBOSE("Final parameters: " << params.parameters().transpose());
1423
1424
1425
1426 ACTS_DEBUG("Start to evaluate material");
1427 if (multipleScattering) {
1428
1429 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1430
1431
1432
1433 for (const auto& [surface, _] : inputMeasurements) {
1434 propagatorOptions.navigation.insertExternalSurface(*surface);
1435 }
1436
1437 auto& gx2fActor = propagatorOptions.actorList.template get<GX2FActor>();
1438 gx2fActor.inputMeasurements = &inputMeasurements;
1439 gx2fActor.multipleScattering = true;
1440 gx2fActor.extensions = gx2fOptions.extensions;
1441 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1442 gx2fActor.actorLogger = m_actorLogger.get();
1443 gx2fActor.scatteringMap = &scatteringMap;
1444 gx2fActor.parametersWithHypothesis = ¶ms;
1445
1446 auto propagatorState = m_propagator.makeState(propagatorOptions);
1447
1448 auto propagatorInitResult =
1449 m_propagator.initialize(propagatorState, params);
1450 if (!propagatorInitResult.ok()) {
1451 ACTS_DEBUG("Propagation initialization failed: "
1452 << propagatorInitResult.error());
1453 return propagatorInitResult.error();
1454 }
1455
1456 auto& r = propagatorState.template get<Gx2FitterResult<traj_t>>();
1457 r.fittedStates = &trajectoryTempBackend;
1458
1459
1460
1461 trackContainerTemp.clear();
1462
1463 auto propagationResult = m_propagator.propagate(propagatorState);
1464
1465
1466 auto result =
1467 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1468 propagatorOptions, false);
1469
1470 if (!result.ok()) {
1471 ACTS_DEBUG("Propagation failed: " << result.error());
1472 return result.error();
1473 }
1474
1475
1476
1477 auto& propRes = *result;
1478 GX2FResult gx2fResult = std::move(propRes.template get<GX2FResult>());
1479
1480 auto track = trackContainerTemp.makeTrack();
1481 tipIndex = gx2fResult.lastMeasurementIndex;
1482
1483
1484
1485
1486 if (tipIndex == kInvalid) {
1487 ACTS_INFO("Did not find any measurements in material fit.");
1488 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1489 }
1490
1491 track.tipIndex() = tipIndex;
1492 track.linkForward();
1493
1494
1495
1496 const std::size_t nMaterialSurfaces =
1497 countMaterialStates(track, scatteringMap, *m_addToSumLogger);
1498
1499
1500
1501 const std::size_t dimsExtendedParams = eBoundSize + 2 * nMaterialSurfaces;
1502
1503
1504
1505 Gx2fSystem extendedSystem{dimsExtendedParams};
1506
1507
1508
1509
1510
1511 std::vector<GeometryIdentifier> geoIdVector;
1512
1513 fillGx2fSystem(track, extendedSystem, true, scatteringMap, geoIdVector,
1514 *m_addToSumLogger);
1515
1516 chi2sum = extendedSystem.chi2();
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527 if ((nUpdate > 0) && !extendedSystem.isWellDefined()) {
1528 ACTS_INFO("Not enough measurements. Require "
1529 << extendedSystem.findRequiredNdf() + 1 << ", but only "
1530 << extendedSystem.ndf() << " could be used.");
1531 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
1532 }
1533
1534 Eigen::VectorXd deltaParamsExtended =
1535 computeGx2fDeltaParams(extendedSystem);
1536
1537 ACTS_VERBOSE("aMatrix:\n"
1538 << extendedSystem.aMatrix() << "\n"
1539 << "bVector:\n"
1540 << extendedSystem.bVector() << "\n"
1541 << "deltaParamsExtended:\n"
1542 << deltaParamsExtended << "\n"
1543 << "oldChi2sum = " << oldChi2sum << "\n"
1544 << "chi2sum = " << extendedSystem.chi2());
1545
1546 chi2sum = extendedSystem.chi2();
1547
1548 updateGx2fParams(params, deltaParamsExtended, nMaterialSurfaces,
1549 scatteringMap, geoIdVector);
1550 ACTS_VERBOSE("Updated parameters: " << params.parameters().transpose());
1551
1552 updateGx2fCovarianceParams(fullCovariancePredicted, extendedSystem);
1553 }
1554 ACTS_DEBUG("Finished to evaluate material");
1555 ACTS_VERBOSE(
1556 "Final parameters after material: " << params.parameters().transpose());
1557
1558
1559 ACTS_VERBOSE("Final scattering angles:");
1560 for (const auto& [key, value] : scatteringMap) {
1561 if (!value.materialIsValid()) {
1562 continue;
1563 }
1564 const auto& angles = value.scatteringAngles();
1565 ACTS_VERBOSE(" ( " << angles[eBoundTheta] << " | " << angles[eBoundPhi]
1566 << " )");
1567 }
1568
1569 ACTS_VERBOSE("Final covariance:\n" << fullCovariancePredicted);
1570
1571
1572
1573
1574
1575
1576 if (gx2fOptions.nUpdateMax > 0) {
1577 ACTS_VERBOSE("Propagate with the final covariance.");
1578
1579 params.covariance() = fullCovariancePredicted;
1580
1581
1582 PropagatorOptions propagatorOptions{gx2fOptions.propagatorPlainOptions};
1583 auto& gx2fActor = propagatorOptions.actorList.template get<GX2FActor>();
1584 gx2fActor.inputMeasurements = &inputMeasurements;
1585 gx2fActor.multipleScattering = multipleScattering;
1586 gx2fActor.extensions = gx2fOptions.extensions;
1587 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
1588 gx2fActor.actorLogger = m_actorLogger.get();
1589 gx2fActor.scatteringMap = &scatteringMap;
1590 gx2fActor.parametersWithHypothesis = ¶ms;
1591
1592 auto propagatorState = m_propagator.makeState(propagatorOptions);
1593
1594 auto propagatorInitResult =
1595 m_propagator.initialize(propagatorState, params);
1596 if (!propagatorInitResult.ok()) {
1597 ACTS_DEBUG("Propagation initialization failed: "
1598 << propagatorInitResult.error());
1599 return propagatorInitResult.error();
1600 }
1601
1602 auto& r = propagatorState.template get<Gx2FitterResult<traj_t>>();
1603 r.fittedStates = &trackContainer.trackStateContainer();
1604
1605 auto propagationResult = m_propagator.propagate(propagatorState);
1606
1607
1608 auto result =
1609 m_propagator.makeResult(std::move(propagatorState), propagationResult,
1610 propagatorOptions, false);
1611
1612 if (!result.ok()) {
1613 ACTS_DEBUG("Propagation failed: " << result.error());
1614 return result.error();
1615 }
1616
1617 auto& propRes = *result;
1618 GX2FResult gx2fResult = std::move(propRes.template get<GX2FResult>());
1619
1620 if (tipIndex != gx2fResult.lastMeasurementIndex) {
1621 ACTS_INFO("Final fit used unreachable measurements.");
1622 tipIndex = gx2fResult.lastMeasurementIndex;
1623
1624
1625
1626 if (tipIndex == kInvalid) {
1627 ACTS_INFO("Did not find any measurements in final propagation.");
1628 return Experimental::GlobalChiSquareFitterError::
1629 NotEnoughMeasurements;
1630 }
1631 }
1632 }
1633
1634 if (!trackContainer.hasColumn(
1635 Acts::hashString(Gx2fConstants::gx2fnUpdateColumn))) {
1636 trackContainer.template addColumn<std::uint32_t>("Gx2fnUpdateColumn");
1637 }
1638
1639
1640 auto track = trackContainer.makeTrack();
1641 track.tipIndex() = tipIndex;
1642 track.parameters() = params.parameters();
1643 track.covariance() = fullCovariancePredicted;
1644 track.setReferenceSurface(params.referenceSurface().getSharedPtr());
1645
1646 if (trackContainer.hasColumn(
1647 Acts::hashString(Gx2fConstants::gx2fnUpdateColumn))) {
1648 ACTS_DEBUG("Add nUpdate to track");
1649 track.template component<std::uint32_t>("Gx2fnUpdateColumn") =
1650 static_cast<std::uint32_t>(nUpdate);
1651 }
1652
1653
1654 calculateTrackQuantities(track);
1655
1656
1657
1658 track.chi2() = chi2sum;
1659
1660
1661 return track;
1662 }
1663 };
1664
1665
1666
1667 }