diff --git a/src/algorithms/tracking/CKFTracking.cc b/src/algorithms/tracking/CKFTracking.cc index dfcd8eb654..e7600ec103 100644 --- a/src/algorithms/tracking/CKFTracking.cc +++ b/src/algorithms/tracking/CKFTracking.cc @@ -6,35 +6,23 @@ #include #include #include +#include +#include #if Acts_VERSION_MAJOR >= 46 -#include #else #include #endif #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include +#include #include #include +#include +#include #include #include #include @@ -45,8 +33,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -60,9 +50,20 @@ #include #include #include +#include #include #include #include // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: no_include // IWYU pragma: no_include @@ -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(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(); + auto pSurface = Acts::Surface::makeShared(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()); diff --git a/src/algorithms/tracking/TrackParamTruthInit.cc b/src/algorithms/tracking/TrackParamTruthInit.cc index 35ab17917b..61699dc8b0 100644 --- a/src/algorithms/tracking/TrackParamTruthInit.cc +++ b/src/algorithms/tracking/TrackParamTruthInit.cc @@ -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::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); + } - 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(perigee_center); // convert from global to local coordinates using the defined line surface auto local = perigee->globalToLocal(m_geoSvc->getActsGeometryContext(), global, direction); @@ -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(perigee_center.x()), + static_cast(perigee_center.y()), + static_cast(perigee_center.z())}); track_seed.setParams(track_parameter); // There are no hits to store to the seed diff --git a/src/algorithms/tracking/TrackParamTruthInitConfig.h b/src/algorithms/tracking/TrackParamTruthInitConfig.h index 09ae8ec69a..7f0f70a16e 100644 --- a/src/algorithms/tracking/TrackParamTruthInitConfig.h +++ b/src/algorithms/tracking/TrackParamTruthInitConfig.h @@ -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; }; diff --git a/src/factories/tracking/TrackParamTruthInit_factory.h b/src/factories/tracking/TrackParamTruthInit_factory.h index 450838cfa9..8e88c1b7b2 100644 --- a/src/factories/tracking/TrackParamTruthInit_factory.h +++ b/src/factories/tracking/TrackParamTruthInit_factory.h @@ -48,6 +48,9 @@ class TrackParamTruthInit_factory ParameterRef m_momentumSmear{ this, "MomentumSmear", config().momentumSmear, "Momentum magnitude fraction to use as width of gaussian smearing"}; + ParameterRef m_useVertexAsPerigee{ + this, "UseVertexAsPerigee", config().useVertexAsPerigee, + "Anchor the seed perigee at the MCParticle vertex (for displaced tracks)"}; Service m_ACTSGeoSvc{this}; Service m_algorithmsInit{this}; diff --git a/src/global/tracking/tracking.cc b/src/global/tracking/tracking.cc index 18db46f52b..6c9e8b08c0 100644 --- a/src/global/tracking/tracking.cc +++ b/src/global/tracking/tracking.cc @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -11,24 +10,18 @@ #include #include #include -#include -#include #include #include -#include #include -#include #include #include -#include #include #include -#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" @@ -49,19 +42,26 @@ void InitPlugin(JApplication* app) { using namespace eicrecon; + // Central tracker truth seeds: charged particles near the IP within the configured vertex cuts. + // (Includes Geant4 secondaries with simulatorStatus != 0; generator intermediates are rejected.) app->Add(new JOmniFactoryGeneratorT( - "TrackerTruthSeeds", {"EventHeader", "MCParticles"}, - {"TrackerTruthSeeds", "TrackerTruthSeedParameters"}, {}, app)); - - std::vector> thetaRanges{{0, 50 * dd4hep::mrad}, - {50 * dd4hep::mrad, 180 * dd4hep::deg}}; - app->Add(new JOmniFactoryGeneratorT>( - "CentralB0TrackerTruthSeeds", {"TrackerTruthSeeds"}, - {"B0TrackerTruthSeeds", "CentralTrackerTruthSeeds"}, - { - .function = RangeSplit< - Chain<&edm4eic::TrackSeed::getParams, &edm4eic::TrackParameters::getTheta>>( - thetaRanges), + "CentralTrackerTruthSeeds", {"EventHeader", "MCParticles"}, + {"CentralTrackerTruthSeeds", "CentralTrackerTruthSeedParameters"}, {}, app)); + + // 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( + "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)); diff --git a/src/services/io/podio/JEventProcessorPODIO.cc b/src/services/io/podio/JEventProcessorPODIO.cc index c7ec93153d..7b49a9fada 100644 --- a/src/services/io/podio/JEventProcessorPODIO.cc +++ b/src/services/io/podio/JEventProcessorPODIO.cc @@ -62,9 +62,10 @@ JEventProcessorPODIO::JEventProcessorPODIO() { "MCParticlesHeadOnFrameNoBeamFX", // Central tracking hits combined - "TrackerTruthSeeds", - "TrackerTruthSeedParameters", + "CentralTrackerTruthSeedParameters", "CentralTrackerTruthSeeds", + "B0TrackerTruthSeedParameters", + "B0TrackerTruthSeeds", "CentralTrackingRecHits", "CentralTrackingRawHitLinks", "CentralTrackingRawHitAssociations",