Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:23:36

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include "Acts/Definitions/Common.hpp"
0012 #include "Acts/Definitions/TrackParametrization.hpp"
0013 #include "Acts/EventData/BoundTrackParameters.hpp"
0014 #include "Acts/EventData/MultiTrajectory.hpp"
0015 #include "Acts/EventData/TrackContainerFrontendConcept.hpp"
0016 #include "Acts/EventData/VectorMultiTrajectory.hpp"
0017 #include "Acts/EventData/detail/CorrectedTransformationFreeToBound.hpp"
0018 #include "Acts/Geometry/GeometryContext.hpp"
0019 #include "Acts/MagneticField/MagneticFieldContext.hpp"
0020 #include "Acts/Propagator/ActorList.hpp"
0021 #include "Acts/Propagator/DirectNavigator.hpp"
0022 #include "Acts/Propagator/PropagatorOptions.hpp"
0023 #include "Acts/Propagator/StandardAborters.hpp"
0024 #include "Acts/Propagator/detail/LoopProtection.hpp"
0025 #include "Acts/Propagator/detail/PointwiseMaterialInteraction.hpp"
0026 #include "Acts/Utilities/CalibrationContext.hpp"
0027 #include "Acts/Utilities/Logger.hpp"
0028 #include "Acts/Utilities/Result.hpp"
0029 
0030 #include <memory>
0031 #include <vector>
0032 
0033 namespace Acts::Experimental {
0034 
0035 /// @tparam traj_t The trajectory type
0036 template <typename traj_t>
0037 struct ReferenceTrajectoryBuilderOptions {
0038   /// PropagatorOptions with context.
0039   ///
0040   /// @param gctx The geometry context
0041   /// @param mctx The magnetic context
0042   /// @param pOptions The plain propagator options
0043   /// @param tSurface The target surface for the fit
0044   /// @param mScattering Whether to include multiple scattering
0045   /// @param eLoss Whether to include energy loss
0046   /// @param freeToBoundCorrection_ Correction for non-linearity effect during transform from free to bound
0047   ReferenceTrajectoryBuilderOptions(
0048       const GeometryContext& gctx, const MagneticFieldContext& mctx,
0049       const PropagatorPlainOptions& pOptions, const Surface* tSurface = nullptr,
0050       bool mScattering = true, bool eLoss = true,
0051       const FreeToBoundCorrection& freeToBoundCorrection_ =
0052           FreeToBoundCorrection(false))
0053       : geoContext(gctx),
0054         magFieldContext(mctx),
0055         propagatorPlainOptions(pOptions),
0056         referenceSurface(tSurface),
0057         multipleScattering(mScattering),
0058         energyLoss(eLoss),
0059         freeToBoundCorrection(freeToBoundCorrection_) {}
0060 
0061   /// Context object for the geometry
0062   std::reference_wrapper<const GeometryContext> geoContext;
0063   /// Context object for the magnetic field
0064   std::reference_wrapper<const MagneticFieldContext> magFieldContext;
0065 
0066   /// The trivial propagator options
0067   PropagatorPlainOptions propagatorPlainOptions;
0068 
0069   /// The reference surface
0070   const Surface* referenceSurface = nullptr;
0071 
0072   /// Whether to consider multiple scattering
0073   bool multipleScattering = true;
0074 
0075   /// Whether to consider energy loss
0076   bool energyLoss = true;
0077 
0078   /// Whether to include non-linear correction during global to local
0079   /// transformation
0080   FreeToBoundCorrection freeToBoundCorrection;
0081 };
0082 
0083 /// The result struct for the reference trajectory builder actor
0084 template <typename traj_t>
0085 struct ReferenceTrajectoryBuilderResult {
0086   /// The trajectory being built
0087   traj_t* trajectory{nullptr};
0088 
0089   /// The index of the last track state added to the trajectory
0090   std::size_t lastTrackStateIndex = kTrackIndexInvalid;
0091 
0092   /// The track parameters at the target surface if the target surface is
0093   /// reached
0094   std::optional<BoundTrackParameters> referenceParameters;
0095 
0096   /// Whether the reference trajectory building is finished
0097   bool finished = false;
0098 
0099   /// Path limit aborter
0100   PathLimitReached pathLimitReached;
0101 };
0102 
0103 /// Reference trajectory implementation.
0104 template <typename propagator_t, typename traj_t>
0105 class ReferenceTrajectoryBuilder {
0106   /// The navigator type
0107   using NavigatorType = typename propagator_t::Navigator;
0108 
0109   /// The navigator has DirectNavigator type or not
0110   static constexpr bool isDirectNavigator =
0111       std::is_same_v<NavigatorType, DirectNavigator>;
0112 
0113   /// The result type of the actor
0114   using ResultType = ReferenceTrajectoryBuilderResult<traj_t>;
0115 
0116  public:
0117   /// The options struct for the reference trajectory builder
0118   using Options = ReferenceTrajectoryBuilderOptions<traj_t>;
0119 
0120   /// Type alias for track state proxy from trajectory
0121   using TrackStateProxy = typename traj_t::TrackStateProxy;
0122 
0123   /// Type alias for const track state proxy from trajectory
0124   using ConstTrackStateProxy = typename traj_t::ConstTrackStateProxy;
0125 
0126   /// Constructor with propagator and logger
0127   /// @param pPropagator Propagator instance for track propagation
0128   /// @param _logger Logger for diagnostic output
0129   explicit ReferenceTrajectoryBuilder(
0130       propagator_t pPropagator,
0131       std::unique_ptr<const Logger> _logger =
0132           getDefaultLogger("ReferenceTrajectoryBuilder", Logging::INFO))
0133       : m_propagator(std::move(pPropagator)),
0134         m_logger{std::move(_logger)},
0135         m_actorLogger{m_logger->cloneWithSuffix("Actor")} {}
0136 
0137  private:
0138   /// The propagator for the transport and material update
0139   propagator_t m_propagator;
0140 
0141   /// The logger instance
0142   std::unique_ptr<const Logger> m_logger;
0143   /// The logger instance for the actor
0144   std::unique_ptr<const Logger> m_actorLogger;
0145 
0146   /// Logger helper
0147   const Logger& logger() const { return *m_logger; }
0148 
0149   class Actor {
0150    public:
0151     /// Broadcast the result_type
0152     using result_type = ResultType;
0153 
0154     /// The target surface aborter
0155     SurfaceReached targetReached{std::numeric_limits<double>::lowest()};
0156 
0157     /// Whether to consider multiple scattering.
0158     bool multipleScattering = true;
0159 
0160     /// Whether to consider energy loss.
0161     bool energyLoss = true;
0162 
0163     /// Whether to include non-linear correction during global to local
0164     /// transformation
0165     FreeToBoundCorrection freeToBoundCorrection;
0166 
0167     /// End of world aborter
0168     EndOfWorldReached endOfWorldReached;
0169 
0170     /// Volume constraint aborter
0171     VolumeConstraintAborter volumeConstraintAborter;
0172 
0173     /// The logger instance
0174     const Logger* actorLogger{nullptr};
0175 
0176     /// Logger helper
0177     const Logger& logger() const { return *actorLogger; }
0178 
0179     /// Actor operation
0180     ///
0181     /// @tparam propagator_state_t is the type of Propagator state
0182     /// @tparam stepper_t Type of the stepper
0183     /// @tparam navigator_t Type of the navigator
0184     ///
0185     /// @param state is the mutable propagator state object
0186     /// @param stepper The stepper in use
0187     /// @param navigator The navigator in use
0188     /// @param result is the mutable result state object
0189     template <typename propagator_state_t, typename stepper_t,
0190               typename navigator_t>
0191     Result<void> act(propagator_state_t& state, const stepper_t& stepper,
0192                      const navigator_t& navigator, result_type& result,
0193                      const Logger& /*logger*/) const {
0194       assert(result.trajectory && "No MultiTrajectory set");
0195 
0196       if (result.finished) {
0197         return Result<void>::success();
0198       }
0199 
0200       ACTS_VERBOSE("ReferenceTrajectory step at pos: "
0201                    << stepper.position(state.stepping).transpose()
0202                    << " dir: " << stepper.direction(state.stepping).transpose()
0203                    << " momentum: "
0204                    << stepper.absoluteMomentum(state.stepping));
0205 
0206       if (result.pathLimitReached.internalLimit ==
0207           std::numeric_limits<double>::max()) {
0208         detail::setupLoopProtection(state, stepper, result.pathLimitReached,
0209                                     true, logger());
0210       }
0211 
0212       if (const Surface* surface = navigator.currentSurface(state.navigation);
0213           surface != nullptr) {
0214         ACTS_VERBOSE("Handle Surface " << surface->geometryId() << " "
0215                                        << state.options.direction);
0216         auto res = handleSurface(*surface, state, stepper, navigator, result);
0217         if (!res.ok()) {
0218           ACTS_DEBUG("Error in " << state.options.direction
0219                                  << " filter: " << res.error());
0220           return res.error();
0221         }
0222       }
0223 
0224       const bool isEndOfWorldReached =
0225           endOfWorldReached.checkAbort(state, stepper, navigator, logger());
0226       const bool isVolumeConstraintReached = volumeConstraintAborter.checkAbort(
0227           state, stepper, navigator, logger());
0228       const bool isPathLimitReached = result.pathLimitReached.checkAbort(
0229           state, stepper, navigator, logger());
0230       const bool isTargetReached =
0231           targetReached.checkAbort(state, stepper, navigator, logger());
0232       if (isEndOfWorldReached || isVolumeConstraintReached ||
0233           isPathLimitReached || isTargetReached) {
0234         ACTS_VERBOSE(
0235             "Finalizing reference trajectory: "
0236             << (isEndOfWorldReached ? "end of world reached; " : "")
0237             << (isVolumeConstraintReached ? "volume constraint reached; " : "")
0238             << (isPathLimitReached ? "path limit reached; " : "")
0239             << (isTargetReached ? "target surface reached; " : ""));
0240 
0241         if (isTargetReached) {
0242           ACTS_VERBOSE("Setting parameters at target surface");
0243 
0244           auto res = stepper.boundState(state.stepping, *targetReached.surface);
0245           if (!res.ok()) {
0246             ACTS_DEBUG("Error while acquiring bound state for target surface: "
0247                        << res.error() << " " << res.error().message());
0248             return res.error();
0249           } else {
0250             const auto& [boundParams, jacobian, pathLength] = *res;
0251             result.referenceParameters = boundParams;
0252           }
0253         }
0254 
0255         result.finished = true;
0256       }
0257 
0258       return Result<void>::success();
0259     }
0260 
0261     template <typename propagator_state_t, typename stepper_t,
0262               typename navigator_t>
0263     bool checkAbort(propagator_state_t& /*state*/, const stepper_t& /*stepper*/,
0264                     const navigator_t& /*navigator*/, const result_type& result,
0265                     const Logger& /*logger*/) const {
0266       return result.finished;
0267     }
0268 
0269     template <typename propagator_state_t, typename stepper_t,
0270               typename navigator_t>
0271     Result<void> handleSurface(const Surface& surface,
0272                                propagator_state_t& state,
0273                                const stepper_t& stepper,
0274                                const navigator_t& navigator,
0275                                result_type& result) const {
0276       stepper.transportCovarianceToBound(state.stepping, surface,
0277                                          freeToBoundCorrection);
0278 
0279       detail::performMaterialInteraction(
0280           state, stepper, surface,
0281           detail::determineMaterialUpdateMode(state, navigator,
0282                                               MaterialUpdateMode::PreUpdate),
0283           NoiseUpdateMode::addNoise, multipleScattering, energyLoss, logger());
0284 
0285       TrackStatePropMask mask =
0286           TrackStatePropMask::Predicted | TrackStatePropMask::Jacobian;
0287       TrackStateProxy trackStateProxy =
0288           result.trajectory->makeTrackState(mask, result.lastTrackStateIndex);
0289 
0290       ConstTrackStateProxy trackStateProxyConst{trackStateProxy};
0291 
0292       trackStateProxy.setReferenceSurface(surface.getSharedPtr());
0293       auto res = stepper.boundState(state.stepping, surface, false,
0294                                     freeToBoundCorrection);
0295       if (!res.ok()) {
0296         ACTS_DEBUG("Propagate to surface " << surface.geometryId()
0297                                            << " failed: " << res.error());
0298         return res.error();
0299       }
0300       const auto& [boundParams, jacobian, pathLength] = *res;
0301 
0302       trackStateProxy.predicted() = boundParams.parameters();
0303       trackStateProxy.predictedCovariance() = state.stepping.cov;
0304       trackStateProxy.jacobian() = jacobian;
0305       trackStateProxy.pathLength() = pathLength;
0306 
0307       auto typeFlags = trackStateProxy.typeFlags();
0308       typeFlags.setHasParameters();
0309       if (surface.hasMaterial()) {
0310         typeFlags.setHasMaterial();
0311       }
0312 
0313       result.lastTrackStateIndex = trackStateProxy.index();
0314 
0315       detail::performMaterialInteraction(
0316           state, stepper, surface,
0317           detail::determineMaterialUpdateMode(state, navigator,
0318                                               MaterialUpdateMode::PostUpdate),
0319           NoiseUpdateMode::addNoise, multipleScattering, energyLoss, logger());
0320 
0321       return Result<void>::success();
0322     }
0323   };
0324 
0325  public:
0326   /// Build the reference trajectory and return a track proxy to the built
0327   /// trajectory
0328   /// @tparam track_container_t The type of the track container frontend
0329   /// @param sParameters The starting track parameters for the reference trajectory building
0330   /// @param actorOptions The options for the reference trajectory builder actor
0331   /// @param trackContainer The track container to hold the built trajectory
0332   /// @return A Result containing the track proxy to the built trajectory or an error if the building failed
0333   template <TrackContainerFrontend track_container_t>
0334   Result<typename track_container_t::TrackProxy> build(
0335       const BoundTrackParameters& sParameters, const Options& actorOptions,
0336       track_container_t& trackContainer) const {
0337     auto propagatorOptions = makePropagatorOptions(
0338         actorOptions, nullptr, actorOptions.referenceSurface);
0339     return buildImpl(sParameters, propagatorOptions, trackContainer);
0340   }
0341 
0342   /// Build the reference trajectory with a given surface sequence and return a
0343   /// track proxy to the built trajectory. This is only available for
0344   /// DirectNavigator.
0345   /// @tparam track_container_t The type of the track container frontend
0346   /// @param sParameters The starting track parameters for the reference trajectory building
0347   /// @param actorOptions The options for the reference trajectory builder actor
0348   /// @param sSequence The surface sequence for the DirectNavigator
0349   /// @param trackContainer The track container to hold the built trajectory
0350   /// @return A Result containing the track proxy to the built trajectory or an error if the building failed
0351   template <TrackContainerFrontend track_container_t>
0352   Result<typename track_container_t::TrackProxy> build(
0353       const BoundTrackParameters& sParameters, const Options& actorOptions,
0354       const std::vector<const Surface*>& sSequence,
0355       track_container_t& trackContainer) const
0356     requires isDirectNavigator
0357   {
0358     auto propagatorOptions = makePropagatorOptions(
0359         actorOptions, &sSequence, actorOptions.referenceSurface);
0360     return buildImpl(sParameters, propagatorOptions, trackContainer);
0361   }
0362 
0363   /// Attach source links to the track states in the trajectory based on the
0364   /// reference surfaces and the provided source link range. Mark track states
0365   /// as holes if no matching source link is found for their reference surface.
0366   /// @tparam track_proxy_t The type of the track proxy
0367   /// @tparam source_link_range_t The type of the source link range, which should be a range of SourceLink objects
0368   /// @param trackProxy The track proxy to which the source links will be attached
0369   /// @param sourceLinkRange The range of source links to be attached to the track states
0370   /// @param surfaceAccessor A function or functor that takes a SourceLink and returns a pointer to the corresponding Surface object
0371   template <typename track_proxy_t, typename source_link_range_t>
0372   void attachSourceLinks(
0373       track_proxy_t trackProxy, const source_link_range_t& sourceLinkRange,
0374       const SourceLinkSurfaceAccessor& surfaceAccessor) const {
0375     const std::size_t nMeasurements = std::ranges::distance(sourceLinkRange);
0376 
0377     ACTS_VERBOSE("Preparing " << nMeasurements << " input measurements");
0378     std::unordered_map<const Surface*, SourceLink> inputMeasurements;
0379     for (const SourceLink& sourceLink : sourceLinkRange) {
0380       const Surface* surface = surfaceAccessor(sourceLink);
0381       inputMeasurements.try_emplace(surface, sourceLink);
0382     }
0383 
0384     for (auto trackState : trackProxy.trackStates()) {
0385       if (!trackState.hasReferenceSurface()) {
0386         continue;
0387       }
0388       const Surface& surface = trackState.referenceSurface();
0389 
0390       if (!surface.isSensitive()) {
0391         continue;
0392       }
0393 
0394       auto typeFlagsMap = trackState.typeFlags();
0395 
0396       if (const auto it = inputMeasurements.find(&surface);
0397           it == inputMeasurements.end()) {
0398         typeFlagsMap.setIsHole();
0399       } else {
0400         SourceLink sourceLink = it->second;
0401 
0402         trackState.setUncalibratedSourceLink(std::move(sourceLink));
0403         typeFlagsMap.setHasMeasurement();
0404       }
0405     }
0406   }
0407 
0408   /// Calibrator interface
0409   using Calibrator =
0410       Delegate<void(const GeometryContext&, const CalibrationContext&,
0411                     const SourceLink&, TrackStateProxy)>;
0412 
0413   /// Calibrate the measurements in the track states using the provided
0414   /// calibrator. The calibrator is called for each track state that has a
0415   /// measurement.
0416   /// @tparam track_proxy_t The type of the track proxy
0417   /// @param geoContext The geometry context to be passed to the calibrator
0418   /// @param calibrationContext The calibration context to be passed to the calibrator
0419   /// @param trackProxy The track proxy whose track states will be calibrated
0420   /// @param calibrator The calibrator to be called for each track state with a measurement
0421   template <typename track_proxy_t>
0422   void calibrateMeasurements(const GeometryContext& geoContext,
0423                              const CalibrationContext& calibrationContext,
0424                              track_proxy_t trackProxy,
0425                              const Calibrator& calibrator) const {
0426     for (auto trackState : trackProxy.trackStates()) {
0427       if (!trackState.typeFlags().hasMeasurement()) {
0428         continue;
0429       }
0430 
0431       trackState.addComponents(TrackStatePropMask::Calibrated);
0432 
0433       const SourceLink& sourceLink = trackState.getUncalibratedSourceLink();
0434       calibrator(geoContext, calibrationContext, sourceLink, trackState);
0435     }
0436   }
0437 
0438   /// Filter interface
0439   using Updater = Delegate<Result<void>(const GeometryContext&, TrackStateProxy,
0440                                         const Logger&)>;
0441 
0442   /// Update the track states in the trajectory using the provided updater. The
0443   /// updater is called for each track state that has a measurement.
0444   /// @tparam track_proxy_t The type of the track proxy
0445   /// @param geoContext The geometry context to be passed to the updater
0446   /// @param trackProxy The track proxy whose track states will be updated
0447   /// @param updater The updater to be called for each track state with a measurement
0448   /// @return A Result indicating success or failure of the update process
0449   template <typename track_proxy_t>
0450   Result<void> filter(const GeometryContext& geoContext,
0451                       track_proxy_t trackProxy, const Updater& updater) const {
0452     std::optional<TrackStateProxy> lastTrackState;
0453     BoundVector accumulatedBoundDeltas = BoundVector::Zero();
0454     BoundMatrix predictedCovariance = BoundMatrix::Zero();
0455 
0456     for (auto trackState : trackProxy.trackStates()) {
0457       if (lastTrackState.has_value()) {
0458         // Transport the last delta to the current surface using the Jacobian of
0459         // the track state
0460 
0461         accumulatedBoundDeltas = trackState.jacobian() * accumulatedBoundDeltas;
0462         trackState.predicted() += accumulatedBoundDeltas;
0463 
0464         predictedCovariance = trackState.jacobian() * predictedCovariance *
0465                               trackState.jacobian().transpose();
0466 
0467         {
0468           const FreeVector freeParams = transformBoundToFreeParameters(
0469               trackState.referenceSurface(), geoContext,
0470               trackState.predicted());
0471 
0472           const MaterialSlab materialSlab = detail::evaluateMaterialSlab(
0473               geoContext, trackState.referenceSurface(), Direction::Forward(),
0474               freeParams.segment<3>(eFreePos0),
0475               freeParams.segment<3>(eFreeDir0), MaterialUpdateMode::PreUpdate);
0476 
0477           const detail::PointwiseMaterialEffects materialEffects =
0478               detail::computeMaterialEffects(
0479                   materialSlab, trackProxy.particleHypothesis(),
0480                   freeParams.segment<3>(eFreeDir0), freeParams[eFreeQOverP],
0481                   true, true, true);
0482 
0483           predictedCovariance(eBoundPhi, eBoundPhi) +=
0484               materialEffects.variancePhi;
0485           predictedCovariance(eBoundTheta, eBoundTheta) +=
0486               materialEffects.varianceTheta;
0487           predictedCovariance(eBoundQOverP, eBoundQOverP) +=
0488               materialEffects.varianceQoverP;
0489         }
0490 
0491         trackState.predictedCovariance() = predictedCovariance;
0492       }
0493 
0494       if (!trackState.typeFlags().hasMeasurement()) {
0495         trackState.shareFrom(trackState, TrackStatePropMask::Predicted,
0496                              TrackStatePropMask::Filtered);
0497       } else {
0498         trackState.addComponents(TrackStatePropMask::Filtered);
0499 
0500         const Result<void> updateResult =
0501             updater(geoContext, trackState, logger());
0502         if (!updateResult.ok()) {
0503           ACTS_DEBUG("Error in filter: " << updateResult.error());
0504           return updateResult.error();
0505         }
0506       }
0507 
0508       lastTrackState = trackState;
0509       accumulatedBoundDeltas += trackState.filtered() - trackState.predicted();
0510       predictedCovariance = trackState.filteredCovariance();
0511 
0512       {
0513         const FreeVector freeParams = transformBoundToFreeParameters(
0514             trackState.referenceSurface(), geoContext, trackState.filtered());
0515 
0516         const MaterialSlab materialSlab = detail::evaluateMaterialSlab(
0517             geoContext, trackState.referenceSurface(), Direction::Forward(),
0518             freeParams.segment<3>(eFreePos0), freeParams.segment<3>(eFreeDir0),
0519             MaterialUpdateMode::PostUpdate);
0520 
0521         const detail::PointwiseMaterialEffects materialEffects =
0522             detail::computeMaterialEffects(
0523                 materialSlab, trackProxy.particleHypothesis(),
0524                 freeParams.segment<3>(eFreeDir0), freeParams[eFreeQOverP], true,
0525                 true, true);
0526 
0527         predictedCovariance(eBoundPhi, eBoundPhi) +=
0528             materialEffects.variancePhi;
0529         predictedCovariance(eBoundTheta, eBoundTheta) +=
0530             materialEffects.varianceTheta;
0531         predictedCovariance(eBoundQOverP, eBoundQOverP) +=
0532             materialEffects.varianceQoverP;
0533       }
0534     }
0535 
0536     return Result<void>::success();
0537   }
0538 
0539  private:
0540   auto makePropagatorOptions(const Options& actorOptions,
0541                              const std::vector<const Surface*>* sSequence,
0542                              const Surface* targetSurface) const {
0543     using Actors = ActorList<Actor>;
0544     using PropagatorOptions = typename propagator_t::template Options<Actors>;
0545 
0546     PropagatorOptions propagatorOptions(actorOptions.geoContext,
0547                                         actorOptions.magFieldContext);
0548     propagatorOptions.setPlainOptions(actorOptions.propagatorPlainOptions);
0549 
0550     if constexpr (!isDirectNavigator) {
0551       if (sSequence != nullptr) {
0552         for (const Surface* surface : *sSequence) {
0553           propagatorOptions.navigation.appendExternalSurface(*surface);
0554         }
0555       }
0556     } else {
0557       assert(sSequence != nullptr &&
0558              "DirectNavigator requires a surface sequence for "
0559              "ReferenceTrajectory");
0560       propagatorOptions.navigation.externalSurfaces = *sSequence;
0561     }
0562 
0563     auto& actor = propagatorOptions.actorList.template get<Actor>();
0564     actor.targetReached.surface = targetSurface;
0565     actor.multipleScattering = actorOptions.multipleScattering;
0566     actor.energyLoss = actorOptions.energyLoss;
0567     actor.freeToBoundCorrection = actorOptions.freeToBoundCorrection;
0568     actor.actorLogger = m_actorLogger.get();
0569 
0570     return propagatorOptions;
0571   }
0572 
0573   template <typename propagator_options_t,
0574             TrackContainerFrontend track_container_t>
0575   auto buildImpl(const BoundTrackParameters& sParameters,
0576                  const propagator_options_t& propagatorOptions,
0577                  track_container_t& trackContainer) const
0578       -> Result<typename track_container_t::TrackProxy> {
0579     auto propagatorState = m_propagator.makeState(propagatorOptions);
0580 
0581     auto propagatorInitResult =
0582         m_propagator.initialize(propagatorState, sParameters);
0583     if (!propagatorInitResult.ok()) {
0584       ACTS_DEBUG("Propagation initialization failed: "
0585                  << propagatorInitResult.error());
0586       return propagatorInitResult.error();
0587     }
0588 
0589     auto& actorResult = propagatorState.template get<ResultType>();
0590     actorResult.trajectory = &trackContainer.trackStateContainer();
0591 
0592     auto result = m_propagator.propagate(propagatorState);
0593 
0594     if (!result.ok()) {
0595       ACTS_DEBUG("Propagation failed: " << result.error());
0596       return result.error();
0597     }
0598 
0599     auto track = trackContainer.makeTrack();
0600     track.tipIndex() = actorResult.lastTrackStateIndex;
0601     if (actorResult.referenceParameters.has_value()) {
0602       const auto& params = *actorResult.referenceParameters;
0603       track.parameters() = params.parameters();
0604       track.covariance() = params.covariance().value();
0605       track.setReferenceSurface(params.referenceSurface().getSharedPtr());
0606     }
0607 
0608     track.linkForward();
0609 
0610     return track;
0611   }
0612 };
0613 
0614 }  // namespace Acts::Experimental