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