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