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