File indexing completed on 2025-07-05 08:15:18
0001
0002
0003
0004 #include "CKFTracking.h"
0005
0006 #include <Acts/Definitions/Algebra.hpp>
0007 #include <Acts/Definitions/Direction.hpp>
0008 #include <Acts/Definitions/TrackParametrization.hpp>
0009 #include <Acts/Definitions/Units.hpp>
0010 #include <Acts/EventData/GenericBoundTrackParameters.hpp>
0011 #include <Acts/EventData/TrackStateProxy.hpp>
0012 #include <Acts/EventData/Types.hpp>
0013 #if Acts_VERSION_MAJOR < 36
0014 #include <Acts/EventData/Measurement.hpp>
0015 #endif
0016 #include <Acts/EventData/MultiTrajectory.hpp>
0017 #include <Acts/EventData/ParticleHypothesis.hpp>
0018 #include <Acts/EventData/ProxyAccessor.hpp>
0019 #include <Acts/EventData/SourceLink.hpp>
0020 #include <Acts/EventData/TrackContainer.hpp>
0021 #include <Acts/EventData/TrackProxy.hpp>
0022 #include <Acts/EventData/VectorMultiTrajectory.hpp>
0023 #include <Acts/EventData/VectorTrackContainer.hpp>
0024 #include <Acts/Geometry/GeometryIdentifier.hpp>
0025 #include <Acts/Geometry/Layer.hpp>
0026 #if Acts_VERSION_MAJOR >= 34
0027 #if Acts_VERSION_MAJOR >= 37
0028 #include <Acts/Propagator/ActorList.hpp>
0029 #else
0030 #include <Acts/Propagator/AbortList.hpp>
0031 #include <Acts/Propagator/ActionList.hpp>
0032 #endif
0033 #include <Acts/Propagator/EigenStepper.hpp>
0034 #include <Acts/Propagator/MaterialInteractor.hpp>
0035 #include <Acts/Propagator/Navigator.hpp>
0036 #endif
0037 #include <Acts/Propagator/Propagator.hpp>
0038 #if Acts_VERSION_MAJOR >= 36
0039 #include <Acts/Propagator/PropagatorOptions.hpp>
0040 #endif
0041 #if Acts_VERSION_MAJOR >= 34
0042 #include <Acts/Propagator/StandardAborters.hpp>
0043 #endif
0044 #include <Acts/Surfaces/PerigeeSurface.hpp>
0045 #include <Acts/Surfaces/Surface.hpp>
0046 #if Acts_VERSION_MAJOR >= 39
0047 #include <Acts/TrackFinding/TrackStateCreator.hpp>
0048 #endif
0049 #if Acts_VERSION_MAJOR < 34
0050 #include <Acts/TrackFitting/GainMatrixSmoother.hpp>
0051 #endif
0052 #include <Acts/TrackFitting/GainMatrixUpdater.hpp>
0053 #include <Acts/Utilities/Logger.hpp>
0054 #if Acts_VERSION_MAJOR >= 34
0055 #include <Acts/Utilities/TrackHelpers.hpp>
0056 #endif
0057 #include <ActsExamples/EventData/IndexSourceLink.hpp>
0058 #include <ActsExamples/EventData/Measurement.hpp>
0059 #include <ActsExamples/EventData/MeasurementCalibration.hpp>
0060 #include <ActsExamples/EventData/Track.hpp>
0061 #include <boost/container/vector.hpp>
0062 #include <edm4eic/Cov3f.h>
0063 #include <edm4eic/Cov6f.h>
0064 #include <edm4eic/Measurement2DCollection.h>
0065 #include <edm4eic/TrackParametersCollection.h>
0066 #include <edm4hep/Vector2f.h>
0067 #include <fmt/core.h>
0068 #include <Eigen/Core>
0069 #include <Eigen/Geometry>
0070 #include <algorithm>
0071 #include <array>
0072 #include <cmath>
0073 #include <cstddef>
0074 #include <functional>
0075 #include <list>
0076 #include <optional>
0077 #include <ostream>
0078 #include <set>
0079 #include <system_error>
0080 #include <utility>
0081
0082 #include "ActsGeometryProvider.h"
0083 #include "DD4hepBField.h"
0084 #include "extensions/spdlog/SpdlogFormatters.h" // IWYU pragma: keep
0085 #include "extensions/spdlog/SpdlogToActs.h"
0086
0087 namespace eicrecon {
0088
0089 using namespace Acts::UnitLiterals;
0090
0091
0092
0093
0094
0095
0096
0097 static constexpr std::array<std::pair<Acts::BoundIndices, double>, 6> edm4eic_indexed_units{
0098 {{Acts::eBoundLoc0, Acts::UnitConstants::mm},
0099 {Acts::eBoundLoc1, Acts::UnitConstants::mm},
0100 {Acts::eBoundPhi, 1.},
0101 {Acts::eBoundTheta, 1.},
0102 {Acts::eBoundQOverP, 1. / Acts::UnitConstants::GeV},
0103 {Acts::eBoundTime, Acts::UnitConstants::ns}}};
0104
0105 CKFTracking::CKFTracking() = default;
0106
0107 void CKFTracking::init(std::shared_ptr<const ActsGeometryProvider> geo_svc,
0108 std::shared_ptr<spdlog::logger> log) {
0109 m_log = log;
0110 m_acts_logger = eicrecon::getSpdlogLogger("CKF", m_log);
0111
0112 m_geoSvc = geo_svc;
0113
0114 m_BField =
0115 std::dynamic_pointer_cast<const eicrecon::BField::DD4hepBField>(m_geoSvc->getFieldProvider());
0116 m_fieldctx = eicrecon::BField::BFieldVariant(m_BField);
0117
0118
0119 m_sourcelinkSelectorCfg = {
0120 {Acts::GeometryIdentifier(),
0121 {m_cfg.etaBins,
0122 m_cfg.chi2CutOff,
0123 {m_cfg.numMeasurementsCutOff.begin(), m_cfg.numMeasurementsCutOff.end()}}},
0124 };
0125 m_trackFinderFunc =
0126 CKFTracking::makeCKFTrackingFunction(m_geoSvc->trackingGeometry(), m_BField, logger());
0127 }
0128
0129 std::tuple<std::vector<ActsExamples::Trajectories*>,
0130 std::vector<ActsExamples::ConstTrackContainer*>>
0131 CKFTracking::process(const edm4eic::TrackParametersCollection& init_trk_params,
0132 const edm4eic::Measurement2DCollection& meas2Ds) {
0133
0134
0135 auto measurements = std::make_shared<ActsExamples::MeasurementContainer>();
0136
0137
0138 std::list<ActsExamples::IndexSourceLink> sourceLinkStorage;
0139 #if Acts_VERSION_MAJOR < 37 || (Acts_VERSION_MAJOR == 37 && Acts_VERSION_MINOR < 1)
0140 ActsExamples::IndexSourceLinkContainer src_links;
0141 src_links.reserve(meas2Ds.size());
0142 #endif
0143 std::size_t hit_index = 0;
0144
0145 for (const auto& meas2D : meas2Ds) {
0146
0147 Acts::GeometryIdentifier geoId{meas2D.getSurface()};
0148
0149
0150 sourceLinkStorage.emplace_back(geoId, hit_index);
0151 ActsExamples::IndexSourceLink& sourceLink = sourceLinkStorage.back();
0152
0153
0154
0155
0156 #if Acts_VERSION_MAJOR < 37 || (Acts_VERSION_MAJOR == 37 && Acts_VERSION_MINOR < 1)
0157 src_links.insert(src_links.end(), sourceLink);
0158 #endif
0159
0160
0161
0162 Acts::ActsVector<2> loc = Acts::Vector2::Zero();
0163 loc[Acts::eBoundLoc0] = meas2D.getLoc().a;
0164 loc[Acts::eBoundLoc1] = meas2D.getLoc().b;
0165
0166 Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero();
0167 cov(0, 0) = meas2D.getCovariance().xx;
0168 cov(1, 1) = meas2D.getCovariance().yy;
0169 cov(0, 1) = meas2D.getCovariance().xy;
0170 cov(1, 0) = meas2D.getCovariance().xy;
0171
0172 #if Acts_VERSION_MAJOR > 37 || (Acts_VERSION_MAJOR == 37 && Acts_VERSION_MINOR >= 1)
0173 std::array<Acts::BoundIndices, 2> indices{Acts::eBoundLoc0, Acts::eBoundLoc1};
0174 Acts::visit_measurement(
0175 indices.size(), [&](auto dim) -> ActsExamples::VariableBoundMeasurementProxy {
0176 if constexpr (dim == indices.size()) {
0177 return ActsExamples::VariableBoundMeasurementProxy{
0178 measurements->emplaceMeasurement<dim>(geoId, indices, loc, cov)};
0179 } else {
0180 throw std::runtime_error("Dimension not supported in measurement creation");
0181 }
0182 });
0183 #elif Acts_VERSION_MAJOR == 37 && Acts_VERSION_MINOR == 0
0184 std::array<Acts::BoundIndices, 2> indices{Acts::eBoundLoc0, Acts::eBoundLoc1};
0185 Acts::visit_measurement(
0186 indices.size(), [&](auto dim) -> ActsExamples::VariableBoundMeasurementProxy {
0187 if constexpr (dim == indices.size()) {
0188 return ActsExamples::VariableBoundMeasurementProxy{
0189 measurements->emplaceMeasurement<dim>(Acts::SourceLink{sourceLink}, indices, loc,
0190 cov)};
0191 } else {
0192 throw std::runtime_error("Dimension not supported in measurement creation");
0193 }
0194 });
0195 #elif Acts_VERSION_MAJOR == 36 && Acts_VERSION_MINOR >= 1
0196 auto measurement = ActsExamples::makeVariableSizeMeasurement(
0197 Acts::SourceLink{sourceLink}, loc, cov, Acts::eBoundLoc0, Acts::eBoundLoc1);
0198 measurements->emplace_back(std::move(measurement));
0199 #elif Acts_VERSION_MAJOR == 36 && Acts_VERSION_MINOR == 0
0200 auto measurement = ActsExamples::makeFixedSizeMeasurement(
0201 Acts::SourceLink{sourceLink}, loc, cov, Acts::eBoundLoc0, Acts::eBoundLoc1);
0202 measurements->emplace_back(std::move(measurement));
0203 #else
0204 auto measurement = Acts::makeMeasurement(Acts::SourceLink{sourceLink}, loc, cov,
0205 Acts::eBoundLoc0, Acts::eBoundLoc1);
0206 measurements->emplace_back(std::move(measurement));
0207 #endif
0208
0209 hit_index++;
0210 }
0211
0212 ActsExamples::TrackParametersContainer acts_init_trk_params;
0213 for (const auto& track_parameter : init_trk_params) {
0214
0215 Acts::BoundVector params;
0216 params(Acts::eBoundLoc0) =
0217 track_parameter.getLoc().a * Acts::UnitConstants::mm;
0218 params(Acts::eBoundLoc1) =
0219 track_parameter.getLoc().b * Acts::UnitConstants::mm;
0220 params(Acts::eBoundPhi) = track_parameter.getPhi();
0221 params(Acts::eBoundTheta) = track_parameter.getTheta();
0222 params(Acts::eBoundQOverP) = track_parameter.getQOverP() / Acts::UnitConstants::GeV;
0223 params(Acts::eBoundTime) = track_parameter.getTime() * Acts::UnitConstants::ns;
0224
0225 Acts::BoundSquareMatrix cov = Acts::BoundSquareMatrix::Zero();
0226 for (std::size_t i = 0; const auto& [a, x] : edm4eic_indexed_units) {
0227 for (std::size_t j = 0; const auto& [b, y] : edm4eic_indexed_units) {
0228 cov(a, b) = track_parameter.getCovariance()(i, j) * x * y;
0229 ++j;
0230 }
0231 ++i;
0232 }
0233
0234
0235 auto pSurface = Acts::Surface::makeShared<const Acts::PerigeeSurface>(Acts::Vector3(0, 0, 0));
0236
0237
0238 acts_init_trk_params.emplace_back(pSurface, params, cov, Acts::ParticleHypothesis::pion());
0239 }
0240
0241
0242 auto pSurface = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3{0., 0., 0.});
0243
0244 ACTS_LOCAL_LOGGER(eicrecon::getSpdlogLogger("CKF", m_log, {"^No tracks found$"}));
0245
0246 #if Acts_VERSION_MAJOR >= 36
0247 Acts::PropagatorPlainOptions pOptions(m_geoctx, m_fieldctx);
0248 #else
0249 Acts::PropagatorPlainOptions pOptions;
0250 #endif
0251 pOptions.maxSteps = 10000;
0252
0253 ActsExamples::PassThroughCalibrator pcalibrator;
0254 ActsExamples::MeasurementCalibratorAdapter calibrator(pcalibrator, *measurements);
0255 Acts::GainMatrixUpdater kfUpdater;
0256 #if Acts_VERSION_MAJOR < 34
0257 Acts::GainMatrixSmoother kfSmoother;
0258 #endif
0259 Acts::MeasurementSelector measSel{m_sourcelinkSelectorCfg};
0260
0261 #if Acts_VERSION_MAJOR >= 36
0262 Acts::CombinatorialKalmanFilterExtensions<ActsExamples::TrackContainer> extensions;
0263 #else
0264 Acts::CombinatorialKalmanFilterExtensions<Acts::VectorMultiTrajectory> extensions;
0265 #endif
0266 #if Acts_VERSION_MAJOR < 39
0267 extensions.calibrator.connect<&ActsExamples::MeasurementCalibratorAdapter::calibrate>(
0268 &calibrator);
0269 #endif
0270 #if Acts_VERSION_MAJOR >= 36
0271 extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<
0272 typename ActsExamples::TrackContainer::TrackStateContainerBackend>>(&kfUpdater);
0273 #else
0274 extensions.updater.connect<&Acts::GainMatrixUpdater::operator()<Acts::VectorMultiTrajectory>>(
0275 &kfUpdater);
0276 #endif
0277 #if Acts_VERSION_MAJOR < 34
0278 extensions.smoother.connect<&Acts::GainMatrixSmoother::operator()<Acts::VectorMultiTrajectory>>(
0279 &kfSmoother);
0280 #endif
0281 #if (Acts_VERSION_MAJOR >= 36) && (Acts_VERSION_MAJOR < 39)
0282 extensions.measurementSelector.connect<&Acts::MeasurementSelector::select<
0283 typename ActsExamples::TrackContainer::TrackStateContainerBackend>>(&measSel);
0284 #elif Acts_VERSION_MAJOR < 39
0285 extensions.measurementSelector
0286 .connect<&Acts::MeasurementSelector::select<Acts::VectorMultiTrajectory>>(&measSel);
0287 #endif
0288
0289 ActsExamples::IndexSourceLinkAccessor slAccessor;
0290 #if Acts_VERSION_MAJOR > 37 || (Acts_VERSION_MAJOR == 37 && Acts_VERSION_MINOR >= 1)
0291 slAccessor.container = &measurements->orderedIndices();
0292 #else
0293 slAccessor.container = &src_links;
0294 #endif
0295 #if Acts_VERSION_MAJOR >= 39
0296 using TrackStateCreatorType =
0297 Acts::TrackStateCreator<ActsExamples::IndexSourceLinkAccessor::Iterator,
0298 ActsExamples::TrackContainer>;
0299 TrackStateCreatorType trackStateCreator;
0300 trackStateCreator.sourceLinkAccessor
0301 .template connect<&ActsExamples::IndexSourceLinkAccessor::range>(&slAccessor);
0302 trackStateCreator.calibrator
0303 .template connect<&ActsExamples::MeasurementCalibratorAdapter::calibrate>(&calibrator);
0304 trackStateCreator.measurementSelector
0305 .template connect<&Acts::MeasurementSelector::select<Acts::VectorMultiTrajectory>>(&measSel);
0306
0307 extensions.createTrackStates.template connect<&TrackStateCreatorType::createTrackStates>(
0308 &trackStateCreator);
0309 #else
0310 Acts::SourceLinkAccessorDelegate<ActsExamples::IndexSourceLinkAccessor::Iterator>
0311 slAccessorDelegate;
0312 slAccessorDelegate.connect<&ActsExamples::IndexSourceLinkAccessor::range>(&slAccessor);
0313 #endif
0314
0315
0316 #if Acts_VERSION_MAJOR >= 39
0317 CKFTracking::TrackFinderOptions options(m_geoctx, m_fieldctx, m_calibctx, extensions, pOptions);
0318 #elif Acts_VERSION_MAJOR >= 34
0319 CKFTracking::TrackFinderOptions options(m_geoctx, m_fieldctx, m_calibctx, slAccessorDelegate,
0320 extensions, pOptions);
0321 #else
0322 CKFTracking::TrackFinderOptions options(m_geoctx, m_fieldctx, m_calibctx, slAccessorDelegate,
0323 extensions, pOptions, &(*pSurface));
0324 #endif
0325
0326 #if Acts_VERSION_MAJOR >= 36
0327 using Extrapolator = Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>;
0328 #if Acts_VERSION_MAJOR >= 37
0329 using ExtrapolatorOptions = Extrapolator::template Options<
0330 Acts::ActorList<Acts::MaterialInteractor, Acts::EndOfWorldReached>>;
0331 #else
0332 using ExtrapolatorOptions =
0333 Extrapolator::template Options<Acts::ActionList<Acts::MaterialInteractor>,
0334 Acts::AbortList<Acts::EndOfWorldReached>>;
0335 #endif
0336 Extrapolator extrapolator(
0337 Acts::EigenStepper<>(m_BField),
0338 Acts::Navigator({m_geoSvc->trackingGeometry()}, logger().cloneWithSuffix("Navigator")),
0339 logger().cloneWithSuffix("Propagator"));
0340 ExtrapolatorOptions extrapolationOptions(m_geoctx, m_fieldctx);
0341 #elif Acts_VERSION_MAJOR >= 34
0342 Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator> extrapolator(
0343 Acts::EigenStepper<>(m_BField),
0344 Acts::Navigator({m_geoSvc->trackingGeometry()}, logger().cloneWithSuffix("Navigator")),
0345 logger().cloneWithSuffix("Propagator"));
0346 Acts::PropagatorOptions<Acts::ActionList<Acts::MaterialInteractor>,
0347 Acts::AbortList<Acts::EndOfWorldReached>>
0348 extrapolationOptions(m_geoctx, m_fieldctx);
0349 #endif
0350
0351
0352 auto trackContainer = std::make_shared<Acts::VectorTrackContainer>();
0353 auto trackStateContainer = std::make_shared<Acts::VectorMultiTrajectory>();
0354 ActsExamples::TrackContainer acts_tracks(trackContainer, trackStateContainer);
0355
0356
0357 acts_tracks.addColumn<unsigned int>("seed");
0358 Acts::ProxyAccessor<unsigned int> seedNumber("seed");
0359 std::set<Acts::TrackIndexType> passed_tracks;
0360
0361
0362 for (std::size_t iseed = 0; iseed < acts_init_trk_params.size(); ++iseed) {
0363 auto result = (*m_trackFinderFunc)(acts_init_trk_params.at(iseed), options, acts_tracks);
0364
0365 if (!result.ok()) {
0366 m_log->debug("Track finding failed for seed {} with error {}", iseed, result.error());
0367 continue;
0368 }
0369
0370
0371 auto& tracksForSeed = result.value();
0372 for (auto& track : tracksForSeed) {
0373 #if Acts_VERSION_MAJOR >= 34
0374 auto smoothingResult = Acts::smoothTrack(m_geoctx, track, logger());
0375 if (!smoothingResult.ok()) {
0376 ACTS_ERROR("Smoothing for seed " << iseed << " and track " << track.index()
0377 << " failed with error " << smoothingResult.error());
0378 continue;
0379 }
0380
0381 auto extrapolationResult = Acts::extrapolateTrackToReferenceSurface(
0382 track, *pSurface, extrapolator, extrapolationOptions,
0383 Acts::TrackExtrapolationStrategy::firstOrLast, logger());
0384
0385 if (!extrapolationResult.ok()) {
0386 ACTS_ERROR("Extrapolation for seed " << iseed << " and track " << track.index()
0387 << " failed with error "
0388 << extrapolationResult.error());
0389 continue;
0390 }
0391 #endif
0392
0393 passed_tracks.insert(track.index());
0394 seedNumber(track) = iseed;
0395 }
0396 }
0397
0398 for (std::size_t track_index = acts_tracks.size(); (track_index--) != 0U;) {
0399 if (!passed_tracks.contains(track_index)) {
0400
0401
0402
0403
0404 acts_tracks.removeTrack(track_index);
0405 #if Acts_VERSION_MAJOR < 36 || (Acts_VERSION_MAJOR == 36 && Acts_VERSION_MINOR < 1)
0406
0407
0408 trackContainer->m_particleHypothesis.erase(trackContainer->m_particleHypothesis.begin() +
0409 track_index);
0410 #endif
0411 }
0412 }
0413
0414
0415
0416
0417 auto constTrackStateContainer =
0418 std::make_shared<Acts::ConstVectorMultiTrajectory>(std::move(*trackStateContainer));
0419
0420 auto constTrackContainer =
0421 std::make_shared<Acts::ConstVectorTrackContainer>(std::move(*trackContainer));
0422
0423
0424
0425 std::vector<ActsExamples::ConstTrackContainer*> constTracks_v;
0426 constTracks_v.push_back(
0427 new ActsExamples::ConstTrackContainer(constTrackContainer, constTrackStateContainer));
0428 auto& constTracks = *(constTracks_v.front());
0429
0430
0431 const Acts::ConstProxyAccessor<unsigned int> constSeedNumber("seed");
0432
0433
0434 std::vector<ActsExamples::Trajectories*> acts_trajectories;
0435 acts_trajectories.reserve(init_trk_params.size());
0436
0437 ActsExamples::Trajectories::IndexedParameters parameters;
0438 std::vector<Acts::MultiTrajectoryTraits::IndexType> tips;
0439
0440 std::optional<unsigned int> lastSeed;
0441 for (const auto& track : constTracks) {
0442 if (!lastSeed) {
0443 lastSeed = constSeedNumber(track);
0444 }
0445
0446 if (constSeedNumber(track) != lastSeed.value()) {
0447
0448 acts_trajectories.push_back(
0449 new ActsExamples::Trajectories(constTracks.trackStateContainer(), tips, parameters));
0450
0451 tips.clear();
0452 parameters.clear();
0453 }
0454
0455 lastSeed = constSeedNumber(track);
0456
0457 tips.push_back(track.tipIndex());
0458 parameters.emplace(std::pair{
0459 track.tipIndex(),
0460 ActsExamples::TrackParameters{track.referenceSurface().getSharedPtr(), track.parameters(),
0461 track.covariance(), track.particleHypothesis()}});
0462 }
0463
0464 if (tips.empty()) {
0465 m_log->info("Last trajectory is empty");
0466 }
0467
0468
0469 acts_trajectories.push_back(new ActsExamples::Trajectories(
0470 constTracks.trackStateContainer(), std::move(tips), std::move(parameters)));
0471
0472 return std::make_tuple(std::move(acts_trajectories), std::move(constTracks_v));
0473 }
0474
0475 }