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