File indexing completed on 2025-08-06 08:10:14
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/Measurement.hpp"
0016 #include "Acts/EventData/MeasurementHelpers.hpp"
0017 #include "Acts/EventData/MultiTrajectory.hpp"
0018 #include "Acts/EventData/MultiTrajectoryHelpers.hpp"
0019 #include "Acts/EventData/SourceLink.hpp"
0020 #include "Acts/EventData/TrackHelpers.hpp"
0021 #include "Acts/EventData/TrackParameters.hpp"
0022 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0023 #include "Acts/Geometry/GeometryContext.hpp"
0024 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0025 #include "Acts/Material/MaterialSlab.hpp"
0026 #include "Acts/Propagator/AbortList.hpp"
0027 #include "Acts/Propagator/ActionList.hpp"
0028 #include "Acts/Propagator/ConstrainedStep.hpp"
0029 #include "Acts/Propagator/DirectNavigator.hpp"
0030 #include "Acts/Propagator/Navigator.hpp"
0031 #include "Acts/Propagator/Propagator.hpp"
0032 #include "Acts/Propagator/StandardAborters.hpp"
0033 #include "Acts/Propagator/StraightLineStepper.hpp"
0034 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0035 #include "Acts/TrackFitting/GlobalChiSquareFitterError.hpp"
0036 #include "Acts/TrackFitting/detail/VoidFitterComponents.hpp"
0037 #include "Acts/Utilities/CalibrationContext.hpp"
0038 #include "Acts/Utilities/Delegate.hpp"
0039 #include "Acts/Utilities/Logger.hpp"
0040 #include "Acts/Utilities/Result.hpp"
0041
0042 #include <functional>
0043 #include <map>
0044 #include <memory>
0045
0046 namespace Acts::Experimental {
0047
0048 namespace Gx2fConstants {
0049 constexpr std::string_view gx2fnUpdateColumn = "Gx2fnUpdateColumn";
0050 }
0051
0052
0053 template <typename traj_t>
0054 struct Gx2FitterExtensions {
0055 using TrackStateProxy = typename MultiTrajectory<traj_t>::TrackStateProxy;
0056 using ConstTrackStateProxy =
0057 typename MultiTrajectory<traj_t>::ConstTrackStateProxy;
0058 using Parameters = typename TrackStateProxy::Parameters;
0059
0060 using Calibrator =
0061 Delegate<void(const GeometryContext&, const CalibrationContext&,
0062 const SourceLink&, TrackStateProxy)>;
0063
0064 using Updater = Delegate<Result<void>(const GeometryContext&, TrackStateProxy,
0065 Direction, const Logger&)>;
0066
0067 using OutlierFinder = Delegate<bool(ConstTrackStateProxy)>;
0068
0069
0070
0071
0072 Calibrator calibrator;
0073
0074
0075 Updater updater;
0076
0077
0078
0079 OutlierFinder outlierFinder;
0080
0081
0082 SourceLinkSurfaceAccessor surfaceAccessor;
0083
0084
0085 Gx2FitterExtensions() {
0086 calibrator.template connect<&detail::voidFitterCalibrator<traj_t>>();
0087 updater.template connect<&detail::voidFitterUpdater<traj_t>>();
0088 outlierFinder.template connect<&detail::voidOutlierFinder<traj_t>>();
0089 surfaceAccessor.connect<&detail::voidSurfaceAccessor>();
0090 }
0091 };
0092
0093
0094
0095
0096 template <typename traj_t>
0097 struct Gx2FitterOptions {
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 Gx2FitterOptions(const GeometryContext& gctx,
0113 const MagneticFieldContext& mctx,
0114 std::reference_wrapper<const CalibrationContext> cctx,
0115 Gx2FitterExtensions<traj_t> extensions_,
0116 const PropagatorPlainOptions& pOptions,
0117 const Surface* rSurface = nullptr, bool mScattering = false,
0118 bool eLoss = false,
0119 const FreeToBoundCorrection& freeToBoundCorrection_ =
0120 FreeToBoundCorrection(false),
0121 const std::size_t nUpdateMax_ = 5,
0122 const bool zeroField_ = false,
0123 double relChi2changeCutOff_ = 1e-5)
0124 : geoContext(gctx),
0125 magFieldContext(mctx),
0126 calibrationContext(cctx),
0127 extensions(extensions_),
0128 propagatorPlainOptions(pOptions),
0129 referenceSurface(rSurface),
0130 multipleScattering(mScattering),
0131 energyLoss(eLoss),
0132 freeToBoundCorrection(freeToBoundCorrection_),
0133 nUpdateMax(nUpdateMax_),
0134 zeroField(zeroField_),
0135 relChi2changeCutOff(relChi2changeCutOff_) {}
0136
0137
0138 Gx2FitterOptions() = delete;
0139
0140
0141 std::reference_wrapper<const GeometryContext> geoContext;
0142
0143 std::reference_wrapper<const MagneticFieldContext> magFieldContext;
0144
0145 std::reference_wrapper<const CalibrationContext> calibrationContext;
0146
0147 Gx2FitterExtensions<traj_t> extensions;
0148
0149
0150 PropagatorPlainOptions propagatorPlainOptions;
0151
0152
0153 const Surface* referenceSurface = nullptr;
0154
0155
0156 bool multipleScattering = false;
0157
0158
0159 bool energyLoss = false;
0160
0161
0162
0163 FreeToBoundCorrection freeToBoundCorrection;
0164
0165
0166 std::size_t nUpdateMax = 5;
0167
0168
0169 bool zeroField = false;
0170
0171
0172 double relChi2changeCutOff = 1e-7;
0173 };
0174
0175 template <typename traj_t>
0176 struct Gx2FitterResult {
0177
0178 traj_t* fittedStates{nullptr};
0179
0180
0181
0182
0183
0184 std::size_t lastMeasurementIndex = Acts::MultiTrajectoryTraits::kInvalid;
0185
0186
0187
0188
0189
0190 std::size_t lastTrackIndex = Acts::MultiTrajectoryTraits::kInvalid;
0191
0192
0193 std::optional<BoundTrackParameters> fittedParameters;
0194
0195
0196 std::size_t measurementStates = 0;
0197
0198
0199
0200
0201
0202 std::size_t measurementHoles = 0;
0203
0204
0205 std::size_t processedStates = 0;
0206
0207
0208 std::size_t processedMeasurements = 0;
0209
0210
0211 bool finished = false;
0212
0213
0214 std::vector<const Surface*> missedActiveSurfaces;
0215
0216
0217
0218 std::vector<const Surface*> passedAgainSurfaces;
0219
0220 Result<void> result{Result<void>::success()};
0221
0222
0223 std::vector<ActsScalar> collectorResiduals;
0224 std::vector<ActsScalar> collectorCovariances;
0225 std::vector<BoundVector> collectorProjectedJacobians;
0226
0227 BoundMatrix jacobianFromStart = BoundMatrix::Identity();
0228
0229
0230 std::size_t surfaceCount = 0;
0231 };
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 template <std::size_t measDim, typename traj_t>
0250 void collector(const typename traj_t::ConstTrackStateProxy& trackStateProxy,
0251 Gx2FitterResult<traj_t>& result, const Logger& logger) {
0252 auto predicted = trackStateProxy.predicted();
0253 auto measurement = trackStateProxy.template calibrated<measDim>();
0254 auto covarianceMeasurement =
0255 trackStateProxy.template calibratedCovariance<measDim>();
0256
0257 auto projJacobian = (trackStateProxy.projector()
0258 .template topLeftCorner<measDim, eBoundSize>() *
0259 result.jacobianFromStart)
0260 .eval();
0261 auto projPredicted = (trackStateProxy.projector()
0262 .template topLeftCorner<measDim, eBoundSize>() *
0263 predicted)
0264 .eval();
0265
0266 ACTS_VERBOSE("Processing and collecting measurements in Actor:"
0267 << "\n Measurement:\t" << measurement.transpose()
0268 << "\n Predicted:\t" << predicted.transpose()
0269 << "\n Projector:\t" << trackStateProxy.effectiveProjector()
0270 << "\n Projected Jacobian:\t" << projJacobian
0271 << "\n Covariance Measurements:\t" << covarianceMeasurement);
0272
0273
0274 for (std::size_t i = 0; i < measDim; i++) {
0275 if (covarianceMeasurement(i, i) < 1e-10) {
0276 ACTS_WARNING("Invalid covariance of measurement: cov(" << i << "," << i
0277 << ") ~ 0")
0278 continue;
0279 }
0280
0281 result.collectorResiduals.push_back(measurement[i] - projPredicted[i]);
0282 result.collectorCovariances.push_back(covarianceMeasurement(i, i));
0283 result.collectorProjectedJacobians.push_back(projJacobian.row(i));
0284
0285 ACTS_VERBOSE(" Splitting the measurement:"
0286 << "\n Residual:\t" << measurement[i] - projPredicted[i]
0287 << "\n Covariance:\t" << covarianceMeasurement(i, i)
0288 << "\n Projected Jacobian:\t" << projJacobian.row(i));
0289 }
0290 }
0291
0292 BoundVector calculateDeltaParams(bool zeroField, const BoundMatrix& aMatrix,
0293 const BoundVector& bVector);
0294
0295
0296
0297
0298
0299
0300 template <typename propagator_t, typename traj_t>
0301 class Gx2Fitter {
0302
0303 using Gx2fNavigator = typename propagator_t::Navigator;
0304
0305
0306 static constexpr bool isDirectNavigator =
0307 std::is_same<Gx2fNavigator, DirectNavigator>::value;
0308
0309 public:
0310 Gx2Fitter(propagator_t pPropagator,
0311 std::unique_ptr<const Logger> _logger =
0312 getDefaultLogger("Gx2Fitter", Logging::INFO))
0313 : m_propagator(std::move(pPropagator)),
0314 m_logger{std::move(_logger)},
0315 m_actorLogger{m_logger->cloneWithSuffix("Actor")} {}
0316
0317 private:
0318
0319 propagator_t m_propagator;
0320
0321
0322 std::unique_ptr<const Logger> m_logger;
0323 std::unique_ptr<const Logger> m_actorLogger;
0324
0325 const Logger& logger() const { return *m_logger; }
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335 template <typename parameters_t>
0336 class Actor {
0337 public:
0338
0339 using result_type = Gx2FitterResult<traj_t>;
0340
0341
0342 const Surface* targetSurface = nullptr;
0343
0344
0345 const std::map<GeometryIdentifier, SourceLink>* inputMeasurements = nullptr;
0346
0347
0348 bool multipleScattering = false;
0349
0350
0351 bool energyLoss = false;
0352
0353
0354
0355 FreeToBoundCorrection freeToBoundCorrection;
0356
0357
0358 std::shared_ptr<MultiTrajectory<traj_t>> outputStates;
0359
0360
0361 const Logger* actorLogger{nullptr};
0362
0363
0364 const Logger& logger() const { return *actorLogger; }
0365
0366 Gx2FitterExtensions<traj_t> extensions;
0367
0368
0369 SurfaceReached targetReached;
0370
0371
0372 const CalibrationContext* calibrationContext{nullptr};
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 template <typename propagator_state_t, typename stepper_t,
0385 typename navigator_t>
0386 void operator()(propagator_state_t& state, const stepper_t& stepper,
0387 const navigator_t& navigator, result_type& result,
0388 const Logger& ) const {
0389 assert(result.fittedStates && "No MultiTrajectory set");
0390
0391
0392 if (result.measurementStates == inputMeasurements->size()) {
0393 ACTS_INFO("Actor: finish: All measurements have been found.");
0394 result.finished = true;
0395 } else if (state.navigation.navigationBreak) {
0396 ACTS_INFO("Actor: finish: navigationBreak.");
0397 result.finished = true;
0398 }
0399
0400
0401 if (result.finished) {
0402
0403 if (result.measurementStates > 0) {
0404 result.missedActiveSurfaces.resize(result.measurementHoles);
0405 }
0406
0407 return;
0408 }
0409
0410
0411
0412 if (state.navigation.externalSurfaces.size() == 0) {
0413 for (auto measurementIt = inputMeasurements->begin();
0414 measurementIt != inputMeasurements->end(); measurementIt++) {
0415 navigator.insertExternalSurface(state.navigation,
0416 measurementIt->first);
0417 }
0418 }
0419
0420
0421
0422 auto surface = navigator.currentSurface(state.navigation);
0423 if (surface != nullptr) {
0424 ++result.surfaceCount;
0425 ACTS_VERBOSE("Surface " << surface->geometryId() << " detected.");
0426
0427
0428 if (auto sourcelink_it = inputMeasurements->find(surface->geometryId());
0429 sourcelink_it != inputMeasurements->end()) {
0430 ACTS_VERBOSE("Measurement surface " << surface->geometryId()
0431 << " detected.");
0432
0433
0434 stepper.transportCovarianceToBound(state.stepping, *surface,
0435 freeToBoundCorrection);
0436
0437 ACTS_VERBOSE(
0438 "Actor - indices before processing:"
0439 << "\n "
0440 << "result.lastMeasurementIndex: " << result.lastMeasurementIndex
0441 << "\n "
0442 << "result.lastTrackIndex: " << result.lastTrackIndex << "\n "
0443 << "result.fittedStates->size(): " << result.fittedStates->size())
0444
0445
0446 auto& fittedStates = *result.fittedStates;
0447
0448
0449 TrackStatePropMask mask = TrackStatePropMask::Predicted |
0450 TrackStatePropMask::Jacobian |
0451 TrackStatePropMask::Calibrated;
0452
0453 ACTS_VERBOSE(" processSurface: addTrackState");
0454
0455
0456
0457 typename traj_t::TrackStateProxy trackStateProxy =
0458 fittedStates.makeTrackState(mask, result.lastTrackIndex);
0459 std::size_t currentTrackIndex = trackStateProxy.index();
0460
0461
0462
0463 {
0464 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
0465
0466 auto res = stepper.boundState(state.stepping, *surface, false,
0467 freeToBoundCorrection);
0468 if (!res.ok()) {
0469 result.result = res.error();
0470 return;
0471 }
0472 const auto& [boundParams, jacobian, pathLength] = *res;
0473
0474
0475 trackStateProxy.predicted() = boundParams.parameters();
0476 trackStateProxy.predictedCovariance() = state.stepping.cov;
0477
0478 trackStateProxy.jacobian() = jacobian;
0479 trackStateProxy.pathLength() = pathLength;
0480 }
0481
0482
0483
0484 extensions.calibrator(state.geoContext, *calibrationContext,
0485 sourcelink_it->second, trackStateProxy);
0486
0487
0488 auto typeFlags = trackStateProxy.typeFlags();
0489 typeFlags.set(TrackStateFlag::ParameterFlag);
0490 if (surface->surfaceMaterial() != nullptr) {
0491 typeFlags.set(TrackStateFlag::MaterialFlag);
0492 }
0493
0494 result.jacobianFromStart =
0495 trackStateProxy.jacobian() * result.jacobianFromStart;
0496
0497
0498
0499
0500
0501 if (trackStateProxy.calibratedSize() == 1) {
0502 collector<1>(trackStateProxy, result, *actorLogger);
0503 } else if (trackStateProxy.calibratedSize() == 2) {
0504 collector<2>(trackStateProxy, result, *actorLogger);
0505 } else {
0506 ACTS_WARNING("Found measurement with "
0507 << trackStateProxy.calibratedSize()
0508 << " dimensions. Only measurements of 1 and 2 "
0509 "dimensions are implemented yet.");
0510 }
0511
0512
0513 typeFlags.set(TrackStateFlag::MeasurementFlag);
0514
0515 ++result.processedMeasurements;
0516 ACTS_VERBOSE("Actor - indices after processing, before over writing:"
0517 << "\n "
0518 << "result.lastMeasurementIndex: "
0519 << result.lastMeasurementIndex << "\n "
0520 << "trackStateProxy.index(): " << trackStateProxy.index()
0521 << "\n "
0522 << "result.lastTrackIndex: " << result.lastTrackIndex
0523 << "\n "
0524 << "currentTrackIndex: " << currentTrackIndex)
0525 result.lastMeasurementIndex = currentTrackIndex;
0526 result.lastTrackIndex = currentTrackIndex;
0527
0528
0529
0530 ++result.measurementStates;
0531
0532
0533 ++result.processedStates;
0534
0535
0536
0537 result.measurementHoles = result.missedActiveSurfaces.size();
0538 } else if (surface->associatedDetectorElement() != nullptr ||
0539 surface->surfaceMaterial() != nullptr) {
0540
0541
0542 ACTS_VERBOSE("Non-Measurement surface " << surface->geometryId()
0543 << " detected.");
0544
0545
0546
0547
0548 if (result.measurementStates > 0
0549
0550 ) {
0551 ACTS_VERBOSE("Handle hole.");
0552
0553 auto& fittedStates = *result.fittedStates;
0554
0555
0556 TrackStatePropMask mask = TrackStatePropMask::Predicted |
0557 TrackStatePropMask::Jacobian |
0558 TrackStatePropMask::Calibrated;
0559
0560 ACTS_VERBOSE(" processSurface: addTrackState");
0561
0562
0563
0564 typename traj_t::TrackStateProxy trackStateProxy =
0565 fittedStates.makeTrackState(mask, result.lastTrackIndex);
0566 std::size_t currentTrackIndex = trackStateProxy.index();
0567 {
0568
0569
0570 {
0571 trackStateProxy.setReferenceSurface(surface->getSharedPtr());
0572
0573 auto res = stepper.boundState(state.stepping, *surface, false,
0574 freeToBoundCorrection);
0575 if (!res.ok()) {
0576 result.result = res.error();
0577 return;
0578 }
0579 const auto& [boundParams, jacobian, pathLength] = *res;
0580
0581
0582 trackStateProxy.predicted() = boundParams.parameters();
0583 trackStateProxy.predictedCovariance() = state.stepping.cov;
0584
0585 trackStateProxy.jacobian() = jacobian;
0586 trackStateProxy.pathLength() = pathLength;
0587 }
0588
0589
0590 auto typeFlags = trackStateProxy.typeFlags();
0591 typeFlags.set(TrackStateFlag::ParameterFlag);
0592 if (surface->surfaceMaterial() != nullptr) {
0593 typeFlags.set(TrackStateFlag::MaterialFlag);
0594 }
0595
0596
0597 if (surface->associatedDetectorElement() != nullptr) {
0598 ACTS_VERBOSE("Detected hole on " << surface->geometryId());
0599
0600 typeFlags.set(TrackStateFlag::HoleFlag);
0601 } else {
0602 ACTS_VERBOSE("Detected in-sensitive surface "
0603 << surface->geometryId());
0604 }
0605 }
0606
0607 ACTS_VERBOSE(
0608 "Actor - indices after processing, before over writing:"
0609 << "\n "
0610 << "result.lastMeasurementIndex: "
0611 << result.lastMeasurementIndex << "\n "
0612 << "trackStateProxy.index(): " << trackStateProxy.index()
0613 << "\n "
0614 << "result.lastTrackIndex: " << result.lastTrackIndex
0615 << "\n "
0616 << "currentTrackIndex: " << currentTrackIndex)
0617 result.lastTrackIndex = currentTrackIndex;
0618
0619 if (trackStateProxy.typeFlags().test(TrackStateFlag::HoleFlag)) {
0620
0621 result.missedActiveSurfaces.push_back(surface);
0622 }
0623
0624 ++result.processedStates;
0625 } else {
0626 ACTS_VERBOSE("Ignoring hole, because no preceding measurements.");
0627 }
0628
0629 if (surface->surfaceMaterial() != nullptr) {
0630
0631
0632
0633
0634 }
0635 } else {
0636 ACTS_INFO("Actor: This case is not implemented yet")
0637 }
0638 }
0639 ACTS_DEBUG("result.processedMeasurements: "
0640 << result.processedMeasurements << "\n"
0641 << "inputMeasurements.size()" << inputMeasurements->size())
0642 if (result.processedMeasurements >= inputMeasurements->size()) {
0643 ACTS_INFO("Actor: finish: all measurements found.");
0644 result.finished = true;
0645 }
0646
0647 if (result.surfaceCount > 900) {
0648 ACTS_INFO("Actor: finish due to limit. Result might be garbage.");
0649 result.finished = true;
0650 }
0651 }
0652 };
0653
0654
0655 template <typename parameters_t>
0656 class Aborter {
0657 public:
0658
0659 using action_type = Actor<parameters_t>;
0660
0661 template <typename propagator_state_t, typename stepper_t,
0662 typename navigator_t, typename result_t>
0663 bool operator()(propagator_state_t& , const stepper_t& ,
0664 const navigator_t& , const result_t& result,
0665 const Logger& ) const {
0666 if (!result.result.ok() || result.finished) {
0667 return true;
0668 }
0669 return false;
0670 }
0671 };
0672
0673 public:
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692 template <typename source_link_iterator_t, typename start_parameters_t,
0693 typename parameters_t = BoundTrackParameters,
0694 typename track_container_t, template <typename> class holder_t,
0695 bool _isdn = isDirectNavigator>
0696 auto fit(source_link_iterator_t it, source_link_iterator_t end,
0697 const start_parameters_t& sParameters,
0698 const Gx2FitterOptions<traj_t>& gx2fOptions,
0699 TrackContainer<track_container_t, traj_t, holder_t>& trackContainer)
0700 const -> std::enable_if_t<
0701 !_isdn, Result<typename TrackContainer<track_container_t, traj_t,
0702 holder_t>::TrackProxy>> {
0703
0704
0705
0706 ACTS_VERBOSE("Preparing " << std::distance(it, end)
0707 << " input measurements");
0708 std::map<GeometryIdentifier, SourceLink> inputMeasurements;
0709
0710 for (; it != end; ++it) {
0711 SourceLink sl = *it;
0712 auto geoId = gx2fOptions.extensions.surfaceAccessor(sl)->geometryId();
0713 inputMeasurements.emplace(geoId, std::move(sl));
0714 }
0715 ACTS_VERBOSE("inputMeasurements.size() = " << inputMeasurements.size());
0716
0717
0718
0719 using GX2FAborter = Aborter<parameters_t>;
0720 using GX2FActor = Actor<parameters_t>;
0721
0722 using GX2FResult = typename GX2FActor::result_type;
0723 using Actors = Acts::ActionList<GX2FActor>;
0724 using Aborters = Acts::AbortList<GX2FAborter>;
0725
0726 using PropagatorOptions = Acts::PropagatorOptions<Actors, Aborters>;
0727
0728 start_parameters_t params = sParameters;
0729 BoundVector deltaParams = BoundVector::Zero();
0730 double chi2sum = 0;
0731 double oldChi2sum = std::numeric_limits<double>::max();
0732 BoundMatrix aMatrix = BoundMatrix::Zero();
0733 BoundVector bVector = BoundVector::Zero();
0734
0735
0736
0737
0738 std::size_t tipIndex = Acts::MultiTrajectoryTraits::kInvalid;
0739
0740 ACTS_VERBOSE("params:\n" << params);
0741
0742
0743 ACTS_DEBUG("Start to iterate");
0744
0745
0746
0747
0748 std::size_t nUpdate = 0;
0749 for (nUpdate = 0; nUpdate < gx2fOptions.nUpdateMax; nUpdate++) {
0750 ACTS_VERBOSE("nUpdate = " << nUpdate + 1 << "/"
0751 << gx2fOptions.nUpdateMax);
0752
0753
0754 params.parameters() += deltaParams;
0755 ACTS_VERBOSE("updated params:\n" << params);
0756
0757
0758 Acts::GeometryContext geoCtx = gx2fOptions.geoContext;
0759 Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext;
0760
0761 PropagatorOptions propagatorOptions(geoCtx, magCtx);
0762 auto& gx2fActor = propagatorOptions.actionList.template get<GX2FActor>();
0763 gx2fActor.inputMeasurements = &inputMeasurements;
0764 gx2fActor.extensions = gx2fOptions.extensions;
0765 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
0766 gx2fActor.actorLogger = m_actorLogger.get();
0767
0768 auto propagatorState = m_propagator.makeState(params, propagatorOptions);
0769
0770 auto& r = propagatorState.template get<Gx2FitterResult<traj_t>>();
0771 r.fittedStates = &trackContainer.trackStateContainer();
0772
0773
0774
0775 trackContainer.clear();
0776
0777 auto propagationResult = m_propagator.template propagate(propagatorState);
0778
0779 auto result = m_propagator.template makeResult(std::move(propagatorState),
0780 propagationResult,
0781 propagatorOptions, false);
0782
0783
0784
0785 auto& propRes = *result;
0786 GX2FResult gx2fResult = std::move(propRes.template get<GX2FResult>());
0787
0788 ACTS_VERBOSE("gx2fResult.collectorResiduals.size() = "
0789 << gx2fResult.collectorResiduals.size());
0790 ACTS_VERBOSE("gx2fResult.collectorCovariances.size() = "
0791 << gx2fResult.collectorCovariances.size());
0792 ACTS_VERBOSE("gx2fResult.collectorProjectedJacobians.size() = "
0793 << gx2fResult.collectorProjectedJacobians.size());
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808 constexpr std::size_t ndf = 4;
0809 if ((nUpdate > 0) && (ndf + 1 > gx2fResult.collectorResiduals.size())) {
0810 ACTS_INFO("Not enough measurements. Require "
0811 << ndf + 1 << ", but only "
0812 << gx2fResult.collectorResiduals.size() << " could be used.");
0813 return Experimental::GlobalChiSquareFitterError::NotEnoughMeasurements;
0814 }
0815
0816 chi2sum = 0;
0817 aMatrix = BoundMatrix::Zero();
0818 bVector = BoundVector::Zero();
0819
0820
0821 for (std::size_t iMeas = 0; iMeas < gx2fResult.collectorResiduals.size();
0822 iMeas++) {
0823 const auto ri = gx2fResult.collectorResiduals[iMeas];
0824 const auto covi = gx2fResult.collectorCovariances[iMeas];
0825 const auto projectedJacobian =
0826 gx2fResult.collectorProjectedJacobians[iMeas];
0827
0828 const double chi2meas = ri / covi * ri;
0829 const BoundMatrix aMatrixMeas =
0830 projectedJacobian * projectedJacobian.transpose() / covi;
0831 const BoundVector bVectorMeas = projectedJacobian / covi * ri;
0832
0833 chi2sum += chi2meas;
0834 aMatrix += aMatrixMeas;
0835 bVector += bVectorMeas;
0836 }
0837
0838
0839 deltaParams =
0840 calculateDeltaParams(gx2fOptions.zeroField, aMatrix, bVector);
0841
0842 ACTS_VERBOSE("aMatrix:\n"
0843 << aMatrix << "\n"
0844 << "bVector:\n"
0845 << bVector << "\n"
0846 << "deltaParams:\n"
0847 << deltaParams << "\n"
0848 << "oldChi2sum = " << oldChi2sum << "\n"
0849 << "chi2sum = " << chi2sum);
0850
0851 tipIndex = gx2fResult.lastMeasurementIndex;
0852
0853 if ((gx2fOptions.relChi2changeCutOff != 0) && (nUpdate > 0) &&
0854 (std::abs(chi2sum / oldChi2sum - 1) <
0855 gx2fOptions.relChi2changeCutOff)) {
0856 ACTS_VERBOSE("Abort with relChi2changeCutOff after "
0857 << nUpdate + 1 << "/" << gx2fOptions.nUpdateMax
0858 << " iterations.");
0859 break;
0860 }
0861
0862
0863 if (chi2sum > oldChi2sum + 1e-5) {
0864 ACTS_DEBUG("chi2 not converging monotonically");
0865 }
0866
0867 oldChi2sum = chi2sum;
0868 }
0869 ACTS_DEBUG("Finished to iterate");
0870 ACTS_VERBOSE("final params:\n" << params);
0871
0872
0873
0874
0875
0876
0877
0878 if (nUpdate == gx2fOptions.nUpdateMax && gx2fOptions.nUpdateMax > 5) {
0879 ACTS_INFO("Did not converge in " << gx2fOptions.nUpdateMax
0880 << " updates.");
0881 return Experimental::GlobalChiSquareFitterError::DidNotConverge;
0882 }
0883
0884
0885 BoundMatrix fullCovariancePredicted = BoundMatrix::Identity();
0886 bool aMatrixIsInvertible = false;
0887 if (gx2fOptions.zeroField) {
0888 constexpr std::size_t reducedMatrixSize = 4;
0889
0890 auto safeReducedCovariance = safeInverse(
0891 aMatrix.topLeftCorner<reducedMatrixSize, reducedMatrixSize>().eval());
0892 if (safeReducedCovariance) {
0893 aMatrixIsInvertible = true;
0894 fullCovariancePredicted
0895 .topLeftCorner<reducedMatrixSize, reducedMatrixSize>() =
0896 *safeReducedCovariance;
0897 }
0898 } else {
0899 constexpr std::size_t reducedMatrixSize = 5;
0900
0901 auto safeReducedCovariance = safeInverse(
0902 aMatrix.topLeftCorner<reducedMatrixSize, reducedMatrixSize>().eval());
0903 if (safeReducedCovariance) {
0904 aMatrixIsInvertible = true;
0905 fullCovariancePredicted
0906 .topLeftCorner<reducedMatrixSize, reducedMatrixSize>() =
0907 *safeReducedCovariance;
0908 }
0909 }
0910
0911 if (!aMatrixIsInvertible && gx2fOptions.nUpdateMax > 0) {
0912 ACTS_ERROR("aMatrix is not invertible.");
0913 return Experimental::GlobalChiSquareFitterError::AIsNotInvertible;
0914 }
0915
0916 ACTS_VERBOSE("final covariance:\n" << fullCovariancePredicted);
0917
0918
0919
0920 if (gx2fOptions.nUpdateMax > 0) {
0921 ACTS_VERBOSE("Propagate with the final covariance.");
0922
0923 ACTS_VERBOSE("finaldeltaParams:\n" << deltaParams);
0924 params.covariance() = fullCovariancePredicted;
0925
0926
0927 Acts::GeometryContext geoCtx = gx2fOptions.geoContext;
0928 Acts::MagneticFieldContext magCtx = gx2fOptions.magFieldContext;
0929
0930 PropagatorOptions propagatorOptions(geoCtx, magCtx);
0931 auto& gx2fActor = propagatorOptions.actionList.template get<GX2FActor>();
0932 gx2fActor.inputMeasurements = &inputMeasurements;
0933 gx2fActor.extensions = gx2fOptions.extensions;
0934 gx2fActor.calibrationContext = &gx2fOptions.calibrationContext.get();
0935 gx2fActor.actorLogger = m_actorLogger.get();
0936
0937 auto propagatorState = m_propagator.makeState(params, propagatorOptions);
0938
0939 auto& r = propagatorState.template get<Gx2FitterResult<traj_t>>();
0940 r.fittedStates = &trackContainer.trackStateContainer();
0941
0942
0943
0944 trackContainer.clear();
0945
0946 m_propagator.template propagate(propagatorState);
0947 }
0948
0949 if (!trackContainer.hasColumn(
0950 Acts::hashString(Gx2fConstants::gx2fnUpdateColumn))) {
0951 trackContainer.template addColumn<std::size_t>("Gx2fnUpdateColumn");
0952 }
0953
0954
0955 auto track = trackContainer.makeTrack();
0956 track.tipIndex() = tipIndex;
0957 track.parameters() = params.parameters();
0958 track.covariance() = fullCovariancePredicted;
0959 track.setReferenceSurface(params.referenceSurface().getSharedPtr());
0960
0961 if (trackContainer.hasColumn(
0962 Acts::hashString(Gx2fConstants::gx2fnUpdateColumn))) {
0963 ACTS_DEBUG("Add nUpdate to track")
0964 track.template component<std::size_t>("Gx2fnUpdateColumn") = nUpdate;
0965 }
0966
0967
0968 calculateTrackQuantities(track);
0969
0970
0971
0972 track.chi2() = chi2sum;
0973
0974
0975 return track;
0976 }
0977 };
0978
0979 }