Skip to content
Open
45 changes: 26 additions & 19 deletions src/algorithms/tracking/CKFTracking.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,23 @@
#include <Acts/Definitions/Algebra.hpp>
#include <Acts/Definitions/TrackParametrization.hpp>
#include <Acts/Definitions/Units.hpp>
#include <Acts/Utilities/MathHelpers.hpp>
#include <edm4hep/Vector3f.h>
#if Acts_VERSION_MAJOR >= 46
#include <Acts/EventData/BoundTrackParameters.hpp>
#else
#include <Acts/EventData/GenericBoundTrackParameters.hpp>
#endif
#include <Acts/EventData/MeasurementHelpers.hpp>
#include <Acts/EventData/TrackStatePropMask.hpp>
#include <Acts/Geometry/GeometryContext.hpp>
#include <Acts/Geometry/GeometryHierarchyMap.hpp>
#include <Acts/TrackFinding/CombinatorialKalmanFilterExtensions.hpp>
#include <Acts/Utilities/CalibrationContext.hpp>
#include <spdlog/common.h>
#include <algorithm>
#include <any>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
#include <Acts/EventData/ParticleHypothesis.hpp>
#include <Acts/EventData/ProxyAccessor.hpp>
#include <Acts/EventData/SourceLink.hpp>
#include <Acts/EventData/TrackContainer.hpp>
#include <Acts/EventData/TrackProxy.hpp>
#include <Acts/EventData/TrackStatePropMask.hpp>
#include <Acts/EventData/VectorMultiTrajectory.hpp>
#include <Acts/EventData/VectorTrackContainer.hpp>
#include <Acts/Geometry/GeometryContext.hpp>
#include <Acts/Geometry/GeometryHierarchyMap.hpp>
#include <Acts/Geometry/GeometryIdentifier.hpp>
#include <Acts/Propagator/ActorList.hpp>
#include <Acts/Propagator/EigenStepper.hpp>
Expand All @@ -45,8 +33,10 @@
#include <Acts/Propagator/StandardAborters.hpp>
#include <Acts/Surfaces/PerigeeSurface.hpp>
#include <Acts/Surfaces/Surface.hpp>
#include <Acts/TrackFinding/CombinatorialKalmanFilterExtensions.hpp>
#include <Acts/TrackFinding/TrackStateCreator.hpp>
#include <Acts/TrackFitting/GainMatrixUpdater.hpp>
#include <Acts/Utilities/CalibrationContext.hpp>
#include <Acts/Utilities/Logger.hpp>
#include <Acts/Utilities/TrackHelpers.hpp>
#include <ActsExamples/EventData/GeometryContainers.hpp>
Expand All @@ -60,9 +50,20 @@
#include <edm4eic/TrackSeedCollection.h>
#include <edm4eic/unit_system.h>
#include <edm4hep/Vector2f.h>
#include <spdlog/common.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/LU> // IWYU pragma: keep
#include <algorithm>
#include <any>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <string>
#include <system_error>
#include <tuple>
#include <utility>
// IWYU pragma: no_include <Acts/Utilities/detail/ContextType.hpp>
// IWYU pragma: no_include <Acts/Utilities/detail/ContainerIterator.hpp>

Expand Down Expand Up @@ -185,8 +186,14 @@ void CKFTracking::process(const Input& input, const Output& output) const {
++i;
}

// Construct a perigee surface as the target surface
auto pSurface = Acts::Surface::makeShared<const Acts::PerigeeSurface>(Acts::Vector3(0, 0, 0));
// Construct the perigee surface at the seed's reference point.
// For IP-originating tracks this is (0,0,0); for displaced seeds (e.g. from
// Lambda decay daughters) the seed carries the actual decay-vertex position
// so the CKF propagates from there instead of from the IP.
const auto& perigee_pos = track_seed.getPerigee();
Comment thread
veprbl marked this conversation as resolved.
auto pSurface = Acts::Surface::makeShared<const Acts::PerigeeSurface>(Acts::Vector3(
perigee_pos.x * Acts::UnitConstants::mm, perigee_pos.y * Acts::UnitConstants::mm,
perigee_pos.z * Acts::UnitConstants::mm));

// Create parameters
acts_init_trk_params.emplace_back(pSurface, params, cov, Acts::ParticleHypothesis::pion());
Expand Down
41 changes: 29 additions & 12 deletions src/algorithms/tracking/TrackParamTruthInit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,34 @@ void TrackParamTruthInit::process(const Input& input, const Output& output) cons
// modify initial momentum to avoid bleeding truth to results when fit fails
const auto pinit = pmag * (1.0 + m_cfg.momentumSmear * gaussian(generator));

// define line surface for local position values
auto perigee = Acts::Surface::makeShared<Acts::PerigeeSurface>(Acts::Vector3(0, 0, 0));

// track particle back to transverse point-of-closest approach
// with respect to the defined line surface
auto linesurface_parameter = -(v.x * p.x + v.y * p.y) / (p.x * p.x + p.y * p.y);
Acts::Vector3 direction(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));

auto xpca = v.x + linesurface_parameter * p.x;
auto ypca = v.y + linesurface_parameter * p.y;
auto zpca = v.z + linesurface_parameter * p.z;
// Choose the perigee reference point and compute local (d0, z0) coordinates.
//
// Default: back-extrapolate to the transverse PCA w.r.t. the beam axis at z=0.
// This is correct for IP-originating tracks but produces a reference point far
// behind the IP for displaced vertices (e.g. Lambda decay daughters at large z),
// which forces ACTS to propagate many metres before reaching the detector.
//
// useVertexAsPerigee: anchor the perigee at the MCParticle vertex itself so
// the CKF only needs to propagate forward from the actual production point.
Acts::Vector3 perigee_center;
Acts::Vector3 global;

if (m_cfg.useVertexAsPerigee) {
// Place perigee at the vertex; the particle starts there so d0=z0=0 exactly.
perigee_center = Acts::Vector3(v.x, v.y, v.z);
global = perigee_center; // PCA = vertex itself
} else {
// Standard: perigee at beam axis origin, back-extrapolate to transverse PCA.
perigee_center = Acts::Vector3(0, 0, 0);
auto linesurface_parameter = -(v.x * p.x + v.y * p.y) / (p.x * p.x + p.y * p.y);
global = Acts::Vector3(v.x + linesurface_parameter * p.x, v.y + linesurface_parameter * p.y,
v.z + linesurface_parameter * p.z);
Comment thread
veprbl marked this conversation as resolved.
}
Comment thread
veprbl marked this conversation as resolved.

Acts::Vector3 global(xpca, ypca, zpca);
Acts::Vector3 direction(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
// define line surface for local position values
auto perigee = Acts::Surface::makeShared<Acts::PerigeeSurface>(perigee_center);

// convert from global to local coordinates using the defined line surface
auto local = perigee->globalToLocal(m_geoSvc->getActsGeometryContext(), global, direction);
Expand Down Expand Up @@ -131,7 +146,9 @@ void TrackParamTruthInit::process(const Input& input, const Output& output) cons

// Insert into edm4eic::TrackSeeds
auto track_seed = track_seeds->create();
track_seed.setPerigee({0.F, 0.F, 0.F});
track_seed.setPerigee({static_cast<float>(perigee_center.x()),
static_cast<float>(perigee_center.y()),
static_cast<float>(perigee_center.z())});
track_seed.setParams(track_parameter);
// There are no hits to store to the seed

Expand Down
8 changes: 8 additions & 0 deletions src/algorithms/tracking/TrackParamTruthInitConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ struct TrackParamTruthInitConfig {
double maxEtaForward = 6.0;
double maxEtaBackward = 4.1;
double momentumSmear = 0.1;
/** When true the seed perigee is placed at the MCParticle vertex instead
* of being extrapolated back to the beam axis. This is essential for
* particles produced at large |z| (e.g. Lambda decay daughters) where
* the standard back-extrapolation puts the reference point far behind
* the IP, forcing ACTS to propagate many metres before reaching the
* detector, which degrades or eliminates CKF efficiency.
*/
bool useVertexAsPerigee = false;
};
3 changes: 3 additions & 0 deletions src/factories/tracking/TrackParamTruthInit_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class TrackParamTruthInit_factory
ParameterRef<double> m_momentumSmear{
this, "MomentumSmear", config().momentumSmear,
"Momentum magnitude fraction to use as width of gaussian smearing"};
ParameterRef<bool> m_useVertexAsPerigee{
this, "UseVertexAsPerigee", config().useVertexAsPerigee,
"Anchor the seed perigee at the MCParticle vertex (for displaced tracks)"};

Service<ACTSGeo_service> m_ACTSGeoSvc{this};
Service<AlgorithmsInit_service> m_algorithmsInit{this};
Expand Down
37 changes: 19 additions & 18 deletions src/global/tracking/tracking.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,25 @@

#include <Acts/Definitions/Units.hpp>
#include <Evaluator/DD4hepUnits.h>
#include <JANA/JApplication.h>
#include <JANA/JApplicationFwd.h>
#include <JANA/Utils/JTypeInfo.h>
#include <edm4eic/MCRecoTrackParticleAssociationCollection.h>
#include <edm4eic/MCRecoTrackerHitAssociationCollection.h>
#include <edm4eic/MCRecoTrackerHitLinkCollection.h>
#include <edm4eic/Measurement2D.h>
#include <edm4eic/TrackCollection.h>
#include <edm4eic/TrackParameters.h>
#include <edm4eic/TrackSeed.h>
#include <edm4eic/TrackerHitCollection.h>
#include <podio/detail/Link.h>
#include <cmath>
#include <deque>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <vector>

#include "algorithms/meta/SubDivideFunctors.h"
#include "algorithms/tracking/TrackParamTruthInitConfig.h"
#include "algorithms/tracking/TrackPropagationConfig.h"
#include "extensions/jana/JOmniFactoryGeneratorT.h"
#include "factories/meta/CollectionCollector_factory.h"
#include "factories/meta/SubDivideCollection_factory.h"
#include "factories/tracking/ActsToTracks_factory.h"
#include "factories/tracking/ActsTrackMerger_factory.h"
#include "factories/tracking/AmbiguitySolver_factory.h"
Expand All @@ -49,19 +42,27 @@ void InitPlugin(JApplication* app) {

using namespace eicrecon;

// Central tracker truth seeds: all IP-originating charged particles.
// Sub-50-mrad seeds included without filtering — the central CKF will simply
// find no hits for them and discard them, which is acceptable.
Comment thread
Copilot marked this conversation as resolved.
Outdated
app->Add(new JOmniFactoryGeneratorT<TrackParamTruthInit_factory>(
"TrackerTruthSeeds", {"EventHeader", "MCParticles"},
{"TrackerTruthSeeds", "TrackerTruthSeedParameters"}, {}, app));
{"CentralTrackerTruthSeeds", "TrackerTruthSeedParameters"}, {}, app));
Comment thread
veprbl marked this conversation as resolved.
Outdated
Comment thread
veprbl marked this conversation as resolved.
Outdated

std::vector<std::pair<double, double>> thetaRanges{{0, 50 * dd4hep::mrad},
{50 * dd4hep::mrad, 180 * dd4hep::deg}};
app->Add(new JOmniFactoryGeneratorT<SubDivideCollection_factory<edm4eic::TrackSeed>>(
"CentralB0TrackerTruthSeeds", {"TrackerTruthSeeds"},
{"B0TrackerTruthSeeds", "CentralTrackerTruthSeeds"},
{
.function = RangeSplit<
Chain<&edm4eic::TrackSeed::getParams, &edm4eic::TrackParameters::getTheta>>(
thetaRanges),
// Dedicated B0 truth seeder: relaxed vertex-z cut so that charged daughters of Lambda
// decays at large z (up to ~O(meters)) are also seeded for the B0 tracker CKF.
app->Add(new JOmniFactoryGeneratorT<TrackParamTruthInit_factory>(
"B0TrackerTruthSeeds", {"EventHeader", "MCParticles"},
{"B0TrackerTruthSeeds", "B0TrackerTruthSeedParameters"},
TrackParamTruthInitConfig{
.maxVertexX = 120 * dd4hep::mm, // maxVertexZ * tan(20mrad) ~ 120mm
.maxVertexY = 120 * dd4hep::mm,
.maxVertexZ = 6000 * dd4hep::mm, // B0 tracker starts at ~6 m from IP
.minMomentum = 100 * dd4hep::MeV,
.maxEtaForward = 6.0,
.maxEtaBackward = 0.0, // forward-going particles only
.momentumSmear = 0.1,
.useVertexAsPerigee = true, // anchor at decay vertex, not beam-axis PCA
},
app));

Expand Down
Loading