File indexing completed on 2026-05-07 08:04:12
0001
0002
0003
0004 #include "CKFTracking.h"
0005
0006 #include <Acts/Definitions/Algebra.hpp>
0007 #include <Acts/Definitions/Common.hpp>
0008 #include <Acts/Definitions/Direction.hpp>
0009 #include <Acts/Definitions/TrackParametrization.hpp>
0010 #include <Acts/Definitions/Units.hpp>
0011 #include <Acts/EventData/GenericBoundTrackParameters.hpp>
0012 #include <Acts/EventData/MeasurementHelpers.hpp>
0013 #include <Acts/EventData/TrackStatePropMask.hpp>
0014 #include <Acts/Geometry/GeometryContext.hpp>
0015 #include <Acts/Geometry/GeometryHierarchyMap.hpp>
0016 #include <Acts/TrackFinding/CombinatorialKalmanFilterExtensions.hpp>
0017 #include <Acts/Utilities/CalibrationContext.hpp>
0018 #include <spdlog/common.h>
0019 #include <algorithm>
0020 #include <any>
0021 #include <array>
0022 #include <cstddef>
0023 #include <cstdint>
0024 #include <functional>
0025 #include <string>
0026 #include <system_error>
0027 #include <tuple>
0028 #include <utility>
0029 #if Acts_VERSION_MAJOR < 43
0030 #include <Acts/Utilities/Iterator.hpp>
0031 #endif
0032 #include <Acts/EventData/ParticleHypothesis.hpp>
0033 #include <Acts/EventData/ProxyAccessor.hpp>
0034 #include <Acts/EventData/SourceLink.hpp>
0035 #include <Acts/EventData/TrackContainer.hpp>
0036 #include <Acts/EventData/TrackProxy.hpp>
0037 #include <Acts/EventData/VectorMultiTrajectory.hpp>
0038 #include <Acts/EventData/VectorTrackContainer.hpp>
0039 #include <Acts/Geometry/GeometryIdentifier.hpp>
0040 #include <Acts/Propagator/ActorList.hpp>
0041 #include <Acts/Propagator/EigenStepper.hpp>
0042 #include <Acts/Propagator/MaterialInteractor.hpp>
0043 #include <Acts/Propagator/Navigator.hpp>
0044 #include <Acts/Propagator/Propagator.hpp>
0045 #include <Acts/Propagator/PropagatorOptions.hpp>
0046 #include <Acts/Propagator/StandardAborters.hpp>
0047 #include <Acts/Surfaces/PerigeeSurface.hpp>
0048 #include <Acts/Surfaces/Surface.hpp>
0049 #include <Acts/TrackFinding/TrackStateCreator.hpp>
0050 #include <Acts/TrackFitting/GainMatrixUpdater.hpp>
0051 #include <Acts/Utilities/Logger.hpp>
0052 #include <Acts/Utilities/TrackHelpers.hpp>
0053 #include <ActsExamples/EventData/GeometryContainers.hpp>
0054 #include <ActsExamples/EventData/IndexSourceLink.hpp>
0055 #include <ActsExamples/EventData/Track.hpp>
0056 #include <boost/container/vector.hpp>
0057 #include <edm4eic/Cov3f.h>
0058 #include <edm4eic/Cov6f.h>
0059 #include <edm4eic/Measurement2DCollection.h>
0060 #include <edm4eic/TrackParametersCollection.h>
0061 #include <edm4eic/TrackSeedCollection.h>
0062 #include <edm4eic/unit_system.h>
0063 #include <edm4hep/Vector2f.h>
0064 #include <Eigen/Core>
0065 #include <Eigen/Geometry>
0066 #include <Eigen/LU> // IWYU pragma: keep
0067
0068
0069
0070 #include "ActsGeometryProvider.h"
0071 #include "extensions/edm4eic/EDM4eicToActs.h"
0072 #include "extensions/spdlog/SpdlogFormatters.h" // IWYU pragma: keep
0073 #include "extensions/spdlog/SpdlogToActs.h"
0074
0075 namespace {
0076
0077
0078
0079 class EDM4eicMeasurementSourceLinkCalibrator {
0080 public:
0081 explicit EDM4eicMeasurementSourceLinkCalibrator(const edm4eic::Measurement2DCollection* meas2Ds)
0082 : m_meas2Ds(meas2Ds) {
0083 for (std::size_t index = 0; index < meas2Ds->size(); ++index) {
0084 m_orderedSourceLinks.emplace(Acts::GeometryIdentifier{(*meas2Ds)[index].getSurface()}, index);
0085 }
0086 }
0087
0088 const ActsExamples::GeometryIdMultiset<ActsExamples::IndexSourceLink>&
0089 orderedSourceLinks() const {
0090 return m_orderedSourceLinks;
0091 }
0092
0093 void calibrate(const Acts::GeometryContext& , const Acts::CalibrationContext& ,
0094 const Acts::SourceLink& sourceLink,
0095 Acts::VectorMultiTrajectory::TrackStateProxy trackState) const {
0096 trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink});
0097 const auto& idxSourceLink = sourceLink.get<ActsExamples::IndexSourceLink>();
0098 const auto& meas2D = (*m_meas2Ds)[idxSourceLink.index()];
0099
0100 #if Acts_VERSION_MAJOR > 45 || (Acts_VERSION_MAJOR == 45 && Acts_VERSION_MINOR >= 2)
0101 Acts::Vector<2> loc = Acts::Vector2::Zero();
0102 Acts::SquareMatrix<2> cov = Acts::SquareMatrix<2>::Zero();
0103 #else
0104 Acts::ActsVector<2> loc = Acts::Vector2::Zero();
0105 Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero();
0106 #endif
0107 constexpr auto mm = Acts::UnitConstants::mm / edm4eic::unit::mm;
0108 constexpr auto mm2 = mm * mm;
0109 loc[Acts::eBoundLoc0] = meas2D.getLoc().a * mm;
0110 loc[Acts::eBoundLoc1] = meas2D.getLoc().b * mm;
0111 cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = meas2D.getCovariance().xx * mm2;
0112 cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = meas2D.getCovariance().yy * mm2;
0113 cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = meas2D.getCovariance().xy * mm2;
0114 cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = meas2D.getCovariance().xy * mm2;
0115
0116 trackState.allocateCalibrated(loc, cov);
0117 std::array<uint8_t, 2> indices{static_cast<uint8_t>(Acts::eBoundLoc0),
0118 static_cast<uint8_t>(Acts::eBoundLoc1)};
0119 trackState.setProjectorSubspaceIndices(indices);
0120 }
0121
0122 private:
0123 const edm4eic::Measurement2DCollection* m_meas2Ds;
0124 ActsExamples::GeometryIdMultiset<ActsExamples::IndexSourceLink> m_orderedSourceLinks;
0125 };
0126
0127 }
0128
0129 namespace eicrecon {
0130
0131 using namespace Acts::UnitLiterals;
0132
0133 void CKFTracking::init() {
0134 m_acts_logger = Acts::getDefaultLogger(
0135 "CKF", eicrecon::SpdlogToActsLevel(static_cast<spdlog::level::level_enum>(this->level())));
0136
0137
0138 m_sourcelinkSelectorCfg = {
0139 {Acts::GeometryIdentifier(),
0140 {.etaBins = m_cfg.etaBins,
0141 .chi2CutOff = m_cfg.chi2CutOff,
0142 .numMeasurementsCutOff = {m_cfg.numMeasurementsCutOff.begin(),
0143 m_cfg.numMeasurementsCutOff.end()}}},
0144 };
0145 m_trackFinderFunc = CKFTracking::makeCKFTrackingFunction(
0146 m_geoSvc->trackingGeometry(), m_geoSvc->getFieldProvider(), acts_logger());
0147 }
0148
0149 void CKFTracking::process(const Input& input, const Output& output) const {
0150 const auto [init_trk_seeds, meas2Ds] = input;
0151 auto [output_track_states, output_tracks] = output;
0152
0153
0154 if (meas2Ds->empty() || init_trk_seeds->empty()) {
0155 debug("No seeds or measurements, creating empty output containers");
0156 *output_track_states = new Acts::ConstVectorMultiTrajectory();
0157 *output_tracks = new Acts::ConstVectorTrackContainer();
0158 return;
0159 }
0160
0161 ActsExamples::TrackParametersContainer acts_init_trk_params;
0162 for (const auto& track_seed : *init_trk_seeds) {
0163
0164 const auto& track_parameter = track_seed.getParams();
0165
0166 Acts::BoundVector params;
0167 params(Acts::eBoundLoc0) =
0168 track_parameter.getLoc().a * Acts::UnitConstants::mm;
0169 params(Acts::eBoundLoc1) =
0170 track_parameter.getLoc().b * Acts::UnitConstants::mm;
0171 params(Acts::eBoundPhi) = track_parameter.getPhi();
0172 params(Acts::eBoundTheta) = track_parameter.getTheta();
0173 params(Acts::eBoundQOverP) = track_parameter.getQOverP() / Acts::UnitConstants::GeV;
0174 params(Acts::eBoundTime) = track_parameter.getTime() * Acts::UnitConstants::ns;
0175
0176 #if Acts_VERSION_MAJOR > 45 || (Acts_VERSION_MAJOR == 45 && Acts_VERSION_MINOR >= 1)
0177 Acts::BoundMatrix cov = Acts::BoundMatrix::Zero();
0178 #else
0179 Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero();
0180 #endif
0181 for (std::size_t i = 0; const auto& [a, x] : edm4eic_indexed_units) {
0182 for (std::size_t j = 0; const auto& [b, y] : edm4eic_indexed_units) {
0183 cov(a, b) = track_parameter.getCovariance()(i, j) * x * y;
0184 ++j;
0185 }
0186 ++i;
0187 }
0188
0189
0190 auto pSurface = Acts::Surface::makeShared<const Acts::PerigeeSurface>(Acts::Vector3(0, 0, 0));
0191
0192
0193 acts_init_trk_params.emplace_back(pSurface, params, cov, Acts::ParticleHypothesis::pion());
0194 }
0195
0196
0197 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.});
0198
0199
0200 const auto spdlog_level = static_cast<spdlog::level::level_enum>(this->level());
0201 const auto acts_level = eicrecon::SpdlogToActsLevel(spdlog_level);
0202 ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("CKF", acts_level));
0203
0204
0205 const auto& gctx = m_geoSvc->getActsGeometryContext();
0206 const auto& mctx = m_geoSvc->getActsMagneticFieldContext();
0207 const auto& cctx = m_geoSvc->getActsCalibrationContext();
0208
0209 Acts::PropagatorPlainOptions pOptions(gctx, mctx);
0210 pOptions.maxSteps = 10000;
0211
0212 EDM4eicMeasurementSourceLinkCalibrator calibratorImpl{meas2Ds};
0213 Acts::GainMatrixUpdater kfUpdater;
0214 Acts::MeasurementSelector measSel{m_sourcelinkSelectorCfg};
0215
0216 Acts::CombinatorialKalmanFilterExtensions<ActsExamples::TrackContainer> extensions;
0217 extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<
0218 typename ActsExamples::TrackContainer::TrackStateContainerBackend>>(&kfUpdater);
0219
0220 ActsExamples::IndexSourceLinkAccessor slAccessor;
0221 slAccessor.container = &calibratorImpl.orderedSourceLinks();
0222 using TrackStateCreatorType =
0223 Acts::TrackStateCreator<ActsExamples::IndexSourceLinkAccessor::Iterator,
0224 ActsExamples::TrackContainer>;
0225 TrackStateCreatorType trackStateCreator;
0226 trackStateCreator.sourceLinkAccessor
0227 .template connect<&ActsExamples::IndexSourceLinkAccessor::range>(&slAccessor);
0228 trackStateCreator.calibrator.template connect<&EDM4eicMeasurementSourceLinkCalibrator::calibrate>(
0229 &calibratorImpl);
0230 trackStateCreator.measurementSelector
0231 .template connect<&Acts::MeasurementSelector::select<Acts::VectorMultiTrajectory>>(&measSel);
0232
0233 extensions.createTrackStates.template connect<&TrackStateCreatorType::createTrackStates>(
0234 &trackStateCreator);
0235
0236
0237 CKFTracking::TrackFinderOptions options(gctx, mctx, cctx, extensions, pOptions);
0238
0239 using Extrapolator = Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>;
0240 using ExtrapolatorOptions = Extrapolator::template Options<
0241 Acts::ActorList<Acts::MaterialInteractor, Acts::EndOfWorldReached>>;
0242 Extrapolator extrapolator(Acts::EigenStepper<>(m_BField),
0243 Acts::Navigator({.trackingGeometry = m_geoSvc->trackingGeometry()},
0244 acts_logger().cloneWithSuffix("Navigator")),
0245 acts_logger().cloneWithSuffix("Propagator"));
0246 ExtrapolatorOptions extrapolationOptions(gctx, mctx);
0247
0248
0249 auto trackContainer = std::make_shared<Acts::VectorTrackContainer>();
0250 auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>();
0251 ActsExamples::TrackContainer acts_tracks(trackContainer, trackStateContainer);
0252
0253
0254 auto trackContainerTemp = std::make_shared<Acts::VectorTrackContainer>();
0255 auto trackStateContainerTemp = std::make_shared<Acts::VectorMultiTrajectory>();
0256 ActsExamples::TrackContainer acts_tracks_temp(trackContainerTemp, trackStateContainerTemp);
0257
0258
0259 acts_tracks.addColumn<unsigned int>("seed");
0260 acts_tracks_temp.addColumn<unsigned int>("seed");
0261 Acts::ProxyAccessor<unsigned int> seedNumber("seed");
0262
0263
0264 for (std::size_t iseed = 0; iseed < acts_init_trk_params.size(); ++iseed) {
0265
0266
0267 acts_tracks_temp.clear();
0268
0269
0270 auto result = (*m_trackFinderFunc)(acts_init_trk_params.at(iseed), options, acts_tracks_temp);
0271
0272 if (!result.ok()) {
0273 debug("Track finding failed for seed {} with error {}", iseed, result.error().message());
0274 continue;
0275 }
0276
0277
0278 auto& tracksForSeed = result.value();
0279 for (auto& track : tracksForSeed) {
0280
0281
0282 auto lastMeasurement = Acts::findLastMeasurementState(track);
0283 if (!lastMeasurement.ok()) {
0284 debug("Track {} for seed {} has no valid measurements, skipping", track.index(), iseed);
0285 continue;
0286 }
0287
0288 if (track.nMeasurements() < m_cfg.numMeasurementsMin) {
0289 trace("Track {} for seed {} has fewer measurements than minimum of {}, skipping",
0290 track.index(), iseed, m_cfg.numMeasurementsMin);
0291 continue;
0292 }
0293
0294 auto smoothingResult = Acts::smoothTrack(gctx, track, acts_logger());
0295 if (!smoothingResult.ok()) {
0296 debug("Smoothing for seed {} and track {} failed with error {}", iseed, track.index(),
0297 smoothingResult.error().message());
0298 continue;
0299 }
0300
0301 auto extrapolationResult = Acts::extrapolateTrackToReferenceSurface(
0302 track, *pSurface, extrapolator, extrapolationOptions,
0303 Acts::TrackExtrapolationStrategy::firstOrLast, acts_logger());
0304
0305 if (!extrapolationResult.ok()) {
0306 debug("Extrapolation for seed {} and track {} failed with error {}", iseed, track.index(),
0307 extrapolationResult.error().message());
0308 continue;
0309 }
0310
0311 seedNumber(track) = iseed;
0312
0313
0314 auto acts_tracks_proxy = acts_tracks.makeTrack();
0315 acts_tracks_proxy.copyFrom(track);
0316 }
0317 }
0318
0319
0320 *output_track_states = new Acts::ConstVectorMultiTrajectory(std::move(*trackStateContainer));
0321 *output_tracks = new Acts::ConstVectorTrackContainer(std::move(*trackContainer));
0322 }
0323
0324 }