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