File indexing completed on 2026-07-22 08:30:06
0001
0002
0003
0004 #include <Acts/Definitions/Algebra.hpp>
0005 #include <Acts/Definitions/Direction.hpp>
0006 #include <Acts/Definitions/TrackParametrization.hpp>
0007 #include <Acts/Definitions/Units.hpp>
0008 #if Acts_VERSION_MAJOR >= 46
0009 #include <Acts/EventData/BoundTrackParameters.hpp>
0010 #else
0011 #include <Acts/EventData/GenericBoundTrackParameters.hpp>
0012 #endif
0013 #include <Acts/EventData/MultiTrajectoryHelpers.hpp>
0014 #include <Acts/EventData/VectorMultiTrajectory.hpp>
0015 #include <Acts/Geometry/GeometryIdentifier.hpp>
0016 #include <Acts/Geometry/TrackingGeometry.hpp>
0017 #include <Acts/MagneticField/MagneticFieldProvider.hpp>
0018 #include <Acts/Material/MaterialInteraction.hpp>
0019 #include <Acts/Propagator/ActorList.hpp>
0020 #include <Acts/Propagator/EigenStepper.hpp>
0021 #include <Acts/Propagator/MaterialInteractor.hpp>
0022 #include <Acts/Propagator/Navigator.hpp>
0023 #include <Acts/Propagator/Propagator.hpp>
0024 #include <Acts/Propagator/PropagatorResult.hpp>
0025 #include <Acts/Surfaces/CylinderBounds.hpp>
0026 #include <Acts/Surfaces/CylinderSurface.hpp>
0027 #include <Acts/Surfaces/DiscSurface.hpp>
0028 #include <Acts/Surfaces/RadialBounds.hpp>
0029 #include <Acts/Utilities/Logger.hpp>
0030 #include <DD4hep/Handle.h>
0031 #include <Evaluator/DD4hepUnits.h>
0032 #include <edm4eic/Cov2f.h>
0033 #include <edm4eic/Cov3f.h>
0034 #include <edm4hep/Vector3f.h>
0035 #include <edm4hep/utils/vector_utils.h>
0036 #include <spdlog/common.h>
0037 #include <Eigen/Core>
0038 #include <Eigen/Geometry>
0039 #include <algorithm>
0040 #include <any>
0041 #include <cmath>
0042 #include <cstdint>
0043 #include <functional>
0044 #include <iterator>
0045 #include <map>
0046 #include <optional>
0047 #include <stdexcept>
0048 #include <string>
0049 #include <tuple>
0050 #include <typeinfo>
0051 #include <utility>
0052 #include <variant>
0053
0054 #include "algorithms/tracking/ActsGeometryProvider.h"
0055 #include "algorithms/tracking/TrackPropagation.h"
0056 #include "algorithms/tracking/TrackPropagationConfig.h"
0057 #include "extensions/spdlog/SpdlogToActs.h"
0058
0059 namespace eicrecon {
0060
0061 template <typename... L> struct multilambda : L... {
0062 using L::operator()...;
0063 constexpr multilambda(L... lambda) : L(std::move(lambda))... {}
0064 };
0065
0066 void TrackPropagation::init() {
0067 const auto* detector = m_detector;
0068
0069 std::map<uint32_t, std::size_t> system_id_layers;
0070
0071 multilambda _toDouble = {
0072 [](const std::string& v) { return dd4hep::_toDouble(v); },
0073 [](const double& v) { return v; },
0074 };
0075
0076 auto _toActsSurface =
0077 [&_toDouble, &detector, &system_id_layers](
0078 const std::variant<CylinderSurfaceConfig, DiscSurfaceConfig> surface_variant)
0079 -> std::shared_ptr<Acts::Surface> {
0080 if (std::holds_alternative<CylinderSurfaceConfig>(surface_variant)) {
0081 CylinderSurfaceConfig surface = std::get<CylinderSurfaceConfig>(surface_variant);
0082 const double rmin =
0083 std::visit(_toDouble, surface.rmin) / dd4hep::mm * Acts::UnitConstants::mm;
0084 const double zmin =
0085 std::visit(_toDouble, surface.zmin) / dd4hep::mm * Acts::UnitConstants::mm;
0086 const double zmax =
0087 std::visit(_toDouble, surface.zmax) / dd4hep::mm * Acts::UnitConstants::mm;
0088 const uint32_t system_id = detector->constant<uint32_t>(surface.id);
0089 auto bounds = std::make_shared<Acts::CylinderBounds>(rmin, (zmax - zmin) / 2);
0090 auto t = Acts::Translation3(Acts::Vector3(0, 0, (zmax + zmin) / 2));
0091 auto tf = Acts::Transform3(t);
0092 auto acts_surface = Acts::Surface::makeShared<Acts::CylinderSurface>(tf, bounds);
0093 acts_surface->assignGeometryId(
0094 Acts::GeometryIdentifier().withExtra(system_id).withLayer(++system_id_layers[system_id]));
0095 return acts_surface;
0096 }
0097 if (std::holds_alternative<DiscSurfaceConfig>(surface_variant)) {
0098 DiscSurfaceConfig surface = std::get<DiscSurfaceConfig>(surface_variant);
0099 const double zmin =
0100 std::visit(_toDouble, surface.zmin) / dd4hep::mm * Acts::UnitConstants::mm;
0101 const double rmin =
0102 std::visit(_toDouble, surface.rmin) / dd4hep::mm * Acts::UnitConstants::mm;
0103 const double rmax =
0104 std::visit(_toDouble, surface.rmax) / dd4hep::mm * Acts::UnitConstants::mm;
0105 const uint32_t system_id = detector->constant<uint32_t>(surface.id);
0106 auto bounds = std::make_shared<Acts::RadialBounds>(rmin, rmax);
0107 auto t = Acts::Translation3(Acts::Vector3(0, 0, zmin));
0108 auto tf = Acts::Transform3(t);
0109 auto acts_surface = Acts::Surface::makeShared<Acts::DiscSurface>(tf, bounds);
0110 acts_surface->assignGeometryId(
0111 Acts::GeometryIdentifier().withExtra(system_id).withLayer(++system_id_layers[system_id]));
0112 return acts_surface;
0113 }
0114 throw std::domain_error("Unknown surface type");
0115 };
0116 m_target_surfaces.resize(m_cfg.target_surfaces.size());
0117 std::ranges::transform(m_cfg.target_surfaces, m_target_surfaces.begin(), _toActsSurface);
0118 m_filter_surfaces.resize(m_cfg.filter_surfaces.size());
0119 std::ranges::transform(m_cfg.filter_surfaces, m_filter_surfaces.begin(), _toActsSurface);
0120
0121 trace("Initialized");
0122 }
0123
0124 void TrackPropagation::propagateToSurfaceList(const Input& input, const Output& output) const {
0125 const auto [tracks, track_states, tracks_acts] = input;
0126 auto [track_segments] = output;
0127
0128
0129 trace("Propagate tracks: --------------------");
0130 trace("number of tracks: {}", tracks->size());
0131
0132
0133 auto trackStateContainer = std::make_shared<Acts::ConstVectorMultiTrajectory>(*track_states);
0134 auto trackContainer = std::make_shared<Acts::ConstVectorTrackContainer>(*tracks_acts);
0135 ActsExamples::ConstTrackContainer constTracks(trackContainer, trackStateContainer);
0136
0137
0138 std::size_t i = 0;
0139 for (const auto& track : constTracks) {
0140
0141
0142 bool track_reaches_filter_surface{false};
0143 for (const auto& filter_surface : m_filter_surfaces) {
0144 auto point = propagate(edm4eic::Track{}, track, constTracks, filter_surface);
0145 if (point) {
0146 track_reaches_filter_surface = true;
0147 break;
0148 }
0149 }
0150 if (!track_reaches_filter_surface) {
0151 ++i;
0152 continue;
0153 }
0154
0155
0156 auto track_segment = track_segments->create();
0157
0158
0159 if (tracks->size() == constTracks.size()) {
0160 trace("track segment connected to track {}", i);
0161 track_segment.setTrack((*tracks)[i]);
0162 ++i;
0163 }
0164
0165
0166 decltype(edm4eic::TrackSegmentData::length) length = 0;
0167 decltype(edm4eic::TrackSegmentData::lengthError) length_error = 0;
0168
0169
0170 for (const auto& target_surface : m_target_surfaces) {
0171
0172
0173 auto point = propagate(edm4eic::Track{}, track, constTracks, target_surface);
0174 if (!point) {
0175 trace("<> Failed to propagate track to this plane");
0176 continue;
0177 }
0178
0179
0180 trace("<> track: x=( {:>10.2f} {:>10.2f} {:>10.2f} )", point->position.x, point->position.y,
0181 point->position.z);
0182 trace(" p=( {:>10.2f} {:>10.2f} {:>10.2f} )", point->momentum.x,
0183 point->momentum.y, point->momentum.z);
0184
0185
0186 if (!m_cfg.track_point_cut(*point)) {
0187 trace(" => REJECTED by trackPointCut");
0188 if (m_cfg.skip_track_on_track_point_cut_failure) {
0189 break;
0190 }
0191 continue;
0192 }
0193
0194
0195
0196 if (track_segment.points_size() > 0) {
0197 auto pos0 = point->position;
0198 auto pos1 = std::prev(track_segment.points_end())->position;
0199 auto dist = edm4hep::utils::magnitude(pos0 - pos1);
0200 length += dist;
0201 trace(" dist to previous point: {}", dist);
0202 }
0203
0204
0205 track_segment.addToPoints(*point);
0206
0207 }
0208
0209
0210 track_segment.setLength(length);
0211 track_segment.setLengthError(length_error);
0212
0213 }
0214 }
0215
0216 std::unique_ptr<edm4eic::TrackPoint>
0217 TrackPropagation::propagate(const edm4eic::Track& ,
0218 const ActsExamples::ConstTrackProxy& acts_track,
0219 const ActsExamples::ConstTrackContainer& trackContainer,
0220 const std::shared_ptr<const Acts::Surface>& targetSurf) const {
0221
0222 auto tipIndex = acts_track.tipIndex();
0223
0224 trace(" Propagating track with tip index {}", tipIndex);
0225
0226
0227 auto trajState =
0228 Acts::MultiTrajectoryHelpers::trajectoryState(trackContainer.trackStateContainer(), tipIndex);
0229 int m_nMeasurements = trajState.nMeasurements;
0230 int m_nStates = trajState.nStates;
0231
0232 trace(" Num measurement in trajectory: {}", m_nMeasurements);
0233 trace(" Num states in trajectory : {}", m_nStates);
0234
0235
0236
0237 auto trackState = trackContainer.trackStateContainer().getTrackState(tipIndex);
0238 auto initSurface = trackState.referenceSurface().getSharedPtr();
0239 const auto& initParams = trackState.filtered();
0240 const auto& initCov = trackState.filteredCovariance();
0241
0242 Acts::BoundTrackParameters initBoundParams(initSurface, initParams, initCov,
0243 acts_track.particleHypothesis());
0244
0245
0246 const auto initPathLength = trackState.pathLength();
0247
0248 trace(" TrackPropagation. Propagating to surface # {}", typeid(targetSurf->type()).name());
0249
0250 std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = m_geoSvc->trackingGeometry();
0251 std::shared_ptr<const Acts::MagneticFieldProvider> magneticField = m_geoSvc->getFieldProvider();
0252
0253
0254 const auto spdlog_level = static_cast<spdlog::level::level_enum>(this->level());
0255 const auto acts_level = eicrecon::SpdlogToActsLevel(spdlog_level);
0256 ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("PROP", acts_level));
0257
0258 using Propagator = Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>;
0259 using PropagatorOptions = Propagator::template Options<Acts::ActorList<Acts::MaterialInteractor>>;
0260 Propagator propagator(Acts::EigenStepper<>(magneticField),
0261 Acts::Navigator({.trackingGeometry = m_geoSvc->trackingGeometry()},
0262 logger().cloneWithSuffix("Navigator")),
0263 logger().cloneWithSuffix("Propagator"));
0264
0265
0266 const auto& gctx = m_geoSvc->getActsGeometryContext();
0267 const auto& mctx = m_geoSvc->getActsMagneticFieldContext();
0268
0269 PropagatorOptions propagationOptions(gctx, mctx);
0270
0271
0272
0273
0274 auto initPosition = initBoundParams.position(gctx);
0275 auto initDirection = initBoundParams.direction();
0276 auto intersections = targetSurf->intersect(gctx, initPosition, initDirection);
0277
0278
0279 auto intersection = intersections.closestForward();
0280 auto difference = intersection.position() - initPosition;
0281 auto dot = difference.dot(initBoundParams.direction());
0282
0283
0284 propagationOptions.direction = Acts::Direction::Forward();
0285
0286
0287 if (intersection.isValid() && dot < 0) {
0288
0289
0290 auto initSurfaceExtra = initSurface->geometryId().extra();
0291 auto targetSurfaceExtra = targetSurf->geometryId().extra();
0292 debug(" inverting direction for propagator from surface {} to {}", initSurfaceExtra,
0293 targetSurfaceExtra);
0294 auto p1 = initBoundParams.position(gctx);
0295 debug(" initial position {} {} {}", p1.x(), p1.y(), p1.z());
0296 auto p2 = intersection.position();
0297 debug(" straight line intersection at {} {} {}", p2.x(), p2.y(), p2.z());
0298
0299
0300 propagationOptions.direction = Acts::Direction::Backward();
0301 }
0302
0303 auto result = propagator.propagate(initBoundParams, *targetSurf, propagationOptions);
0304
0305
0306 if (!result.ok()) {
0307 trace(" propagation failed (!result.ok())");
0308 return nullptr;
0309 }
0310 trace(" propagation result is OK");
0311
0312
0313 auto trackStateParams = *((*result).endParameters);
0314 const auto& parameter = trackStateParams.parameters();
0315 const auto& covariance = *trackStateParams.covariance();
0316
0317
0318 const float pathLength = initPathLength + (*result).pathLength;
0319 const float pathLengthError = 0;
0320 trace(" path len = {}", pathLength);
0321
0322
0323 auto projectionPos = trackStateParams.position(gctx);
0324 const decltype(edm4eic::TrackPoint::position) position{static_cast<float>(projectionPos(0)),
0325 static_cast<float>(projectionPos(1)),
0326 static_cast<float>(projectionPos(2))};
0327 const decltype(edm4eic::TrackPoint::positionError) positionError{0, 0, 0};
0328 trace(" pos x = {}", position.x);
0329 trace(" pos y = {}", position.y);
0330 trace(" pos z = {}", position.z);
0331
0332
0333 const decltype(edm4eic::TrackPoint::momentum) momentum = edm4hep::utils::sphericalToVector(
0334 static_cast<float>(1.0 / std::abs(parameter[Acts::eBoundQOverP])),
0335 static_cast<float>(parameter[Acts::eBoundTheta]),
0336 static_cast<float>(parameter[Acts::eBoundPhi]));
0337 const decltype(edm4eic::TrackPoint::momentumError) momentumError{
0338 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
0339 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
0340 static_cast<float>(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)),
0341 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi)),
0342 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundQOverP)),
0343 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundQOverP))};
0344
0345
0346 const float time{static_cast<float>(parameter(Acts::eBoundTime))};
0347 const float timeError{static_cast<float>(sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime)))};
0348
0349
0350 const float theta(parameter[Acts::eBoundTheta]);
0351 const float phi(parameter[Acts::eBoundPhi]);
0352 const decltype(edm4eic::TrackPoint::directionError) directionError{
0353 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
0354 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
0355 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi))};
0356
0357
0358 trace(" loc 0 = {:.4f}", parameter[Acts::eBoundLoc0]);
0359 trace(" loc 1 = {:.4f}", parameter[Acts::eBoundLoc1]);
0360 trace(" phi = {:.4f}", parameter[Acts::eBoundPhi]);
0361 trace(" theta = {:.4f}", parameter[Acts::eBoundTheta]);
0362 trace(" q/p = {:.4f}", parameter[Acts::eBoundQOverP]);
0363 trace(" p = {:.4f}", 1.0 / parameter[Acts::eBoundQOverP]);
0364 trace(" err phi = {:.4f}", sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)));
0365 trace(" err th = {:.4f}", sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)));
0366 trace(" err q/p = {:.4f}", sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)));
0367 trace(" chi2 = {:.4f}", trajState.chi2Sum);
0368 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0369 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0370 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc1)));
0371
0372 uint64_t surface = targetSurf->geometryId().value();
0373 uint32_t system = 0;
0374
0375 return std::make_unique<edm4eic::TrackPoint>(
0376 edm4eic::TrackPoint{.surface = surface,
0377 .system = system,
0378 .position = position,
0379 .positionError = positionError,
0380 .momentum = momentum,
0381 .momentumError = momentumError,
0382 .time = time,
0383 .timeError = timeError,
0384 .theta = theta,
0385 .phi = phi,
0386 .directionError = directionError,
0387 .pathlength = pathLength,
0388 .pathlengthError = pathLengthError});
0389 }
0390
0391 }