File indexing completed on 2026-06-22 07:51:51
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 #if Acts_VERSION_MAJOR >= 40
0094 acts_surface->assignGeometryId(
0095 Acts::GeometryIdentifier().withExtra(system_id).withLayer(++system_id_layers[system_id]));
0096 #else
0097 acts_surface->assignGeometryId(
0098 Acts::GeometryIdentifier().setExtra(system_id).setLayer(++system_id_layers[system_id]));
0099 #endif
0100 return acts_surface;
0101 }
0102 if (std::holds_alternative<DiscSurfaceConfig>(surface_variant)) {
0103 DiscSurfaceConfig surface = std::get<DiscSurfaceConfig>(surface_variant);
0104 const double zmin =
0105 std::visit(_toDouble, surface.zmin) / dd4hep::mm * Acts::UnitConstants::mm;
0106 const double rmin =
0107 std::visit(_toDouble, surface.rmin) / dd4hep::mm * Acts::UnitConstants::mm;
0108 const double rmax =
0109 std::visit(_toDouble, surface.rmax) / dd4hep::mm * Acts::UnitConstants::mm;
0110 const uint32_t system_id = detector->constant<uint32_t>(surface.id);
0111 auto bounds = std::make_shared<Acts::RadialBounds>(rmin, rmax);
0112 auto t = Acts::Translation3(Acts::Vector3(0, 0, zmin));
0113 auto tf = Acts::Transform3(t);
0114 auto acts_surface = Acts::Surface::makeShared<Acts::DiscSurface>(tf, bounds);
0115 #if Acts_VERSION_MAJOR >= 40
0116 acts_surface->assignGeometryId(
0117 Acts::GeometryIdentifier().withExtra(system_id).withLayer(++system_id_layers[system_id]));
0118 #else
0119 acts_surface->assignGeometryId(
0120 Acts::GeometryIdentifier().setExtra(system_id).setLayer(++system_id_layers[system_id]));
0121 #endif
0122 return acts_surface;
0123 }
0124 throw std::domain_error("Unknown surface type");
0125 };
0126 m_target_surfaces.resize(m_cfg.target_surfaces.size());
0127 std::ranges::transform(m_cfg.target_surfaces, m_target_surfaces.begin(), _toActsSurface);
0128 m_filter_surfaces.resize(m_cfg.filter_surfaces.size());
0129 std::ranges::transform(m_cfg.filter_surfaces, m_filter_surfaces.begin(), _toActsSurface);
0130
0131 trace("Initialized");
0132 }
0133
0134 void TrackPropagation::propagateToSurfaceList(const Input& input, const Output& output) const {
0135 const auto [tracks, track_states, tracks_acts] = input;
0136 auto [track_segments] = output;
0137
0138
0139 trace("Propagate tracks: --------------------");
0140 trace("number of tracks: {}", tracks->size());
0141
0142
0143 auto trackStateContainer = std::make_shared<Acts::ConstVectorMultiTrajectory>(*track_states);
0144 auto trackContainer = std::make_shared<Acts::ConstVectorTrackContainer>(*tracks_acts);
0145 ActsExamples::ConstTrackContainer constTracks(trackContainer, trackStateContainer);
0146
0147
0148 std::size_t i = 0;
0149 for (const auto& track : constTracks) {
0150
0151
0152 bool track_reaches_filter_surface{false};
0153 for (const auto& filter_surface : m_filter_surfaces) {
0154 auto point = propagate(edm4eic::Track{}, track, constTracks, filter_surface);
0155 if (point) {
0156 track_reaches_filter_surface = true;
0157 break;
0158 }
0159 }
0160 if (!track_reaches_filter_surface) {
0161 ++i;
0162 continue;
0163 }
0164
0165
0166 auto track_segment = track_segments->create();
0167
0168
0169 if (tracks->size() == constTracks.size()) {
0170 trace("track segment connected to track {}", i);
0171 track_segment.setTrack((*tracks)[i]);
0172 ++i;
0173 }
0174
0175
0176 decltype(edm4eic::TrackSegmentData::length) length = 0;
0177 decltype(edm4eic::TrackSegmentData::lengthError) length_error = 0;
0178
0179
0180 for (const auto& target_surface : m_target_surfaces) {
0181
0182
0183 auto point = propagate(edm4eic::Track{}, track, constTracks, target_surface);
0184 if (!point) {
0185 trace("<> Failed to propagate track to this plane");
0186 continue;
0187 }
0188
0189
0190 trace("<> track: x=( {:>10.2f} {:>10.2f} {:>10.2f} )", point->position.x, point->position.y,
0191 point->position.z);
0192 trace(" p=( {:>10.2f} {:>10.2f} {:>10.2f} )", point->momentum.x,
0193 point->momentum.y, point->momentum.z);
0194
0195
0196 if (!m_cfg.track_point_cut(*point)) {
0197 trace(" => REJECTED by trackPointCut");
0198 if (m_cfg.skip_track_on_track_point_cut_failure) {
0199 break;
0200 }
0201 continue;
0202 }
0203
0204
0205
0206 if (track_segment.points_size() > 0) {
0207 auto pos0 = point->position;
0208 auto pos1 = std::prev(track_segment.points_end())->position;
0209 auto dist = edm4hep::utils::magnitude(pos0 - pos1);
0210 length += dist;
0211 trace(" dist to previous point: {}", dist);
0212 }
0213
0214
0215 track_segment.addToPoints(*point);
0216
0217 }
0218
0219
0220 track_segment.setLength(length);
0221 track_segment.setLengthError(length_error);
0222
0223 }
0224 }
0225
0226 std::unique_ptr<edm4eic::TrackPoint>
0227 TrackPropagation::propagate(const edm4eic::Track& ,
0228 const ActsExamples::ConstTrackProxy& acts_track,
0229 const ActsExamples::ConstTrackContainer& trackContainer,
0230 const std::shared_ptr<const Acts::Surface>& targetSurf) const {
0231
0232 auto tipIndex = acts_track.tipIndex();
0233
0234 trace(" Propagating track with tip index {}", tipIndex);
0235
0236
0237 auto trajState =
0238 Acts::MultiTrajectoryHelpers::trajectoryState(trackContainer.trackStateContainer(), tipIndex);
0239 int m_nMeasurements = trajState.nMeasurements;
0240 int m_nStates = trajState.nStates;
0241
0242 trace(" Num measurement in trajectory: {}", m_nMeasurements);
0243 trace(" Num states in trajectory : {}", m_nStates);
0244
0245
0246
0247 auto trackState = trackContainer.trackStateContainer().getTrackState(tipIndex);
0248 auto initSurface = trackState.referenceSurface().getSharedPtr();
0249 const auto& initParams = trackState.filtered();
0250 const auto& initCov = trackState.filteredCovariance();
0251
0252 Acts::BoundTrackParameters initBoundParams(initSurface, initParams, initCov,
0253 acts_track.particleHypothesis());
0254
0255
0256 const auto initPathLength = trackState.pathLength();
0257
0258 trace(" TrackPropagation. Propagating to surface # {}", typeid(targetSurf->type()).name());
0259
0260 std::shared_ptr<const Acts::TrackingGeometry> trackingGeometry = m_geoSvc->trackingGeometry();
0261 std::shared_ptr<const Acts::MagneticFieldProvider> magneticField = m_geoSvc->getFieldProvider();
0262
0263
0264 const auto spdlog_level = static_cast<spdlog::level::level_enum>(this->level());
0265 const auto acts_level = eicrecon::SpdlogToActsLevel(spdlog_level);
0266 ACTS_LOCAL_LOGGER(Acts::getDefaultLogger("PROP", acts_level));
0267
0268 using Propagator = Acts::Propagator<Acts::EigenStepper<>, Acts::Navigator>;
0269 using PropagatorOptions = Propagator::template Options<Acts::ActorList<Acts::MaterialInteractor>>;
0270 Propagator propagator(Acts::EigenStepper<>(magneticField),
0271 Acts::Navigator({.trackingGeometry = m_geoSvc->trackingGeometry()},
0272 logger().cloneWithSuffix("Navigator")),
0273 logger().cloneWithSuffix("Propagator"));
0274
0275
0276 const auto& gctx = m_geoSvc->getActsGeometryContext();
0277 const auto& mctx = m_geoSvc->getActsMagneticFieldContext();
0278
0279 PropagatorOptions propagationOptions(gctx, mctx);
0280
0281
0282
0283
0284 auto initPosition = initBoundParams.position(gctx);
0285 auto initDirection = initBoundParams.direction();
0286 auto intersections = targetSurf->intersect(gctx, initPosition, initDirection);
0287
0288
0289 auto intersection = intersections.closestForward();
0290 auto difference = intersection.position() - initPosition;
0291 auto dot = difference.dot(initBoundParams.direction());
0292
0293
0294 propagationOptions.direction = Acts::Direction::Forward();
0295
0296
0297 if (intersection.isValid() && dot < 0) {
0298
0299
0300 auto initSurfaceExtra = initSurface->geometryId().extra();
0301 auto targetSurfaceExtra = targetSurf->geometryId().extra();
0302 debug(" inverting direction for propagator from surface {} to {}", initSurfaceExtra,
0303 targetSurfaceExtra);
0304 auto p1 = initBoundParams.position(gctx);
0305 debug(" initial position {} {} {}", p1.x(), p1.y(), p1.z());
0306 auto p2 = intersection.position();
0307 debug(" straight line intersection at {} {} {}", p2.x(), p2.y(), p2.z());
0308
0309
0310 propagationOptions.direction = Acts::Direction::Backward();
0311 }
0312
0313 auto result = propagator.propagate(initBoundParams, *targetSurf, propagationOptions);
0314
0315
0316 if (!result.ok()) {
0317 trace(" propagation failed (!result.ok())");
0318 return nullptr;
0319 }
0320 trace(" propagation result is OK");
0321
0322
0323 auto trackStateParams = *((*result).endParameters);
0324 const auto& parameter = trackStateParams.parameters();
0325 const auto& covariance = *trackStateParams.covariance();
0326
0327
0328 const float pathLength = initPathLength + (*result).pathLength;
0329 const float pathLengthError = 0;
0330 trace(" path len = {}", pathLength);
0331
0332
0333 auto projectionPos = trackStateParams.position(gctx);
0334 const decltype(edm4eic::TrackPoint::position) position{static_cast<float>(projectionPos(0)),
0335 static_cast<float>(projectionPos(1)),
0336 static_cast<float>(projectionPos(2))};
0337 const decltype(edm4eic::TrackPoint::positionError) positionError{0, 0, 0};
0338 trace(" pos x = {}", position.x);
0339 trace(" pos y = {}", position.y);
0340 trace(" pos z = {}", position.z);
0341
0342
0343 const decltype(edm4eic::TrackPoint::momentum) momentum = edm4hep::utils::sphericalToVector(
0344 static_cast<float>(1.0 / std::abs(parameter[Acts::eBoundQOverP])),
0345 static_cast<float>(parameter[Acts::eBoundTheta]),
0346 static_cast<float>(parameter[Acts::eBoundPhi]));
0347 const decltype(edm4eic::TrackPoint::momentumError) momentumError{
0348 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
0349 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
0350 static_cast<float>(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)),
0351 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi)),
0352 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundQOverP)),
0353 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundQOverP))};
0354
0355
0356 const float time{static_cast<float>(parameter(Acts::eBoundTime))};
0357 const float timeError{static_cast<float>(sqrt(covariance(Acts::eBoundTime, Acts::eBoundTime)))};
0358
0359
0360 const float theta(parameter[Acts::eBoundTheta]);
0361 const float phi(parameter[Acts::eBoundPhi]);
0362 const decltype(edm4eic::TrackPoint::directionError) directionError{
0363 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundTheta)),
0364 static_cast<float>(covariance(Acts::eBoundPhi, Acts::eBoundPhi)),
0365 static_cast<float>(covariance(Acts::eBoundTheta, Acts::eBoundPhi))};
0366
0367
0368 trace(" loc 0 = {:.4f}", parameter[Acts::eBoundLoc0]);
0369 trace(" loc 1 = {:.4f}", parameter[Acts::eBoundLoc1]);
0370 trace(" phi = {:.4f}", parameter[Acts::eBoundPhi]);
0371 trace(" theta = {:.4f}", parameter[Acts::eBoundTheta]);
0372 trace(" q/p = {:.4f}", parameter[Acts::eBoundQOverP]);
0373 trace(" p = {:.4f}", 1.0 / parameter[Acts::eBoundQOverP]);
0374 trace(" err phi = {:.4f}", sqrt(covariance(Acts::eBoundPhi, Acts::eBoundPhi)));
0375 trace(" err th = {:.4f}", sqrt(covariance(Acts::eBoundTheta, Acts::eBoundTheta)));
0376 trace(" err q/p = {:.4f}", sqrt(covariance(Acts::eBoundQOverP, Acts::eBoundQOverP)));
0377 trace(" chi2 = {:.4f}", trajState.chi2Sum);
0378 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc0)));
0379 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc1, Acts::eBoundLoc1)));
0380 trace(" loc err = {:.4f}", static_cast<float>(covariance(Acts::eBoundLoc0, Acts::eBoundLoc1)));
0381
0382 uint64_t surface = targetSurf->geometryId().value();
0383 uint32_t system = 0;
0384
0385 return std::make_unique<edm4eic::TrackPoint>(
0386 edm4eic::TrackPoint{.surface = surface,
0387 .system = system,
0388 .position = position,
0389 .positionError = positionError,
0390 .momentum = momentum,
0391 .momentumError = momentumError,
0392 .time = time,
0393 .timeError = timeError,
0394 .theta = theta,
0395 .phi = phi,
0396 .directionError = directionError,
0397 .pathlength = pathLength,
0398 .pathlengthError = pathLengthError});
0399 }
0400
0401 }