From 258e7cf3aed392ab8e67eb7e2bc87a3191803cbd Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Mon, 15 Sep 2025 16:27:41 +0200 Subject: [PATCH 1/8] Add a few new states to TrackStateProvider --- Tr/TrackExtrapolators/src/TrackStateProvider.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp index 209d391cfb5..47dcf0cc272 100644 --- a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp +++ b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp @@ -382,6 +382,16 @@ TrackCache TrackStateProvider::createCacheEntry( TkCacheKey key, const LHCb::Tra } } + // the same for T-Tracks + if ( track.type() == LHCb::Track::Types::Ttrack ) { + for ( const auto& loc : { std::pair{ LHCb::State::Location::EndMagnet, StateParameters::ZEndMag }, + std::pair{ LHCb::State::Location::MidMagnet, StateParameters::ZMidMag }, + std::pair{ LHCb::State::Location::BegMagnet, StateParameters::ZBegMag }, + std::pair{ LHCb::State::Location::EndVelo, StateParameters::ZEndVelo } } ) { + if ( !track.stateAt( loc.first ) ) { addState( tc, loc.second, geometry, loc.first ); } + } + } + // make sure all tracks (incl. Downstream) get assigned a state at // the beamline. this is useful for the trajectory approximation. if ( ( track.hasVelo() || track.hasUT() ) && track.firstState().location() != LHCb::State::Location::ClosestToBeam && -- GitLab From 4e26e6a602b1163a398426d315c552704b975f33 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Sat, 20 Sep 2025 13:04:05 +0200 Subject: [PATCH 2/8] Use POCA as a starting point in ParticleVertexFitter --- Phys/VertexFit/CMakeLists.txt | 1 + Phys/VertexFit/src/ParticleVertexFitter.cpp | 38 ++++++--------------- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/Phys/VertexFit/CMakeLists.txt b/Phys/VertexFit/CMakeLists.txt index 7acec814d00..0bd023a3be6 100644 --- a/Phys/VertexFit/CMakeLists.txt +++ b/Phys/VertexFit/CMakeLists.txt @@ -53,6 +53,7 @@ gaudi_add_module(VertexFit Rec::TrackKernel ROOT::MathCore VertexFitLib + Rec::SelToolsLib ) gaudi_add_tests(QMTest) diff --git a/Phys/VertexFit/src/ParticleVertexFitter.cpp b/Phys/VertexFit/src/ParticleVertexFitter.cpp index 9cc8ea539fd..72dd2eb05bc 100644 --- a/Phys/VertexFit/src/ParticleVertexFitter.cpp +++ b/Phys/VertexFit/src/ParticleVertexFitter.cpp @@ -20,6 +20,7 @@ #include "Kernel/ParticleProperty.h" #include "LHCbMath/MatrixTransforms.h" #include "MassConstrainer.h" +#include "SelTools/DistanceCalculator.h" #include "TrackInterfaces/ITrackStateProvider.h" #include "TrackKernel/TrackTraj.h" #include @@ -100,6 +101,8 @@ private: Gaudi::Property m_maxnumiter{ this, "MaxNumIter", 5 }; Gaudi::Property m_maxdchisq{ this, "MaxDeltaChi2", 0.01 }; Gaudi::Property m_extrapolateTtracks{ this, "extrapolateTtracks", false }; + Gaudi::Property m_ttracks_poca_min_dty{ this, "TtracksPOCAMinDty", 0.005 }; + Gaudi::Property m_ttracks_poca_initial_z{ this, "TtracksPOCAInitialZ", 5000.0 }; PublicToolHandle m_stateprovider{ this, "StateProvider", "TrackStateProvider" }; ToolHandle m_trajpoca{ "TrajPoca" }; const LHCb::IParticlePropertySvc* m_ppsvc{ nullptr }; @@ -676,8 +679,7 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau // 1. if there are 'resonance' daughters, take the vertex position of the first. // 2. if not, use the states of the first two tracks with velo or composites // 3. if not, try with downstream tracks and trajpoca - bool posinitialized{ false }; - + bool posinitialized{ false }; Gaudi::XYZPoint position; if ( counttypes[Resonance] > 0 ) { // try 1 @@ -719,36 +721,16 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau bool parallelTracks = false; if ( ntrajs == 2 && m_extrapolateTtracks ) { // this is NOT default behaviour - // For T-tracks it does not make sense to use 3-D POCA starting position - // Trajectory in YZ plane is approx straight line - // calculate the yz intersection z and extrapolate there + // Calculate the yz intersection and use it as a seed for POCA + // If tracks are essentially parallel in y-z plane, use a constant starting point const float ty0 = daughters[0]->proto()->track()->firstState().ty(); const float ty1 = daughters[1]->proto()->track()->firstState().ty(); - if ( LHCb::essentiallyEqual( ty0, ty1 ) ) { - debug() << "tracks are parallel in yz plane. Cannot calculate yz intersection. Default to 3-D POCA starting " - "position. " - << endmsg; - parallelTracks = true; - } else { - const float z0 = daughters[0]->proto()->track()->firstState().z(); - const float z1 = daughters[1]->proto()->track()->firstState().z(); - - const float y0 = daughters[0]->proto()->track()->firstState().y(); - const float y1 = daughters[1]->proto()->track()->firstState().y(); - - // calculate the y-axis intersection of each track - const float c0 = y0 - ty0 * z0; - const float c1 = y1 - ty1 * z1; - - // calculate the point in the yz-plane where the tracks intersect - const float yzIntersectionZ = ( c1 - c0 ) / ( ty0 - ty1 ); - const float yzIntersectionY = ty0 * yzIntersectionZ + c1; - - position.SetZ( yzIntersectionZ ); - position.SetY( yzIntersectionY ); - position.SetX( 0 ); + const auto poca = Sel::NonlinearDistanceCalculator::findPOCA( + *( trajs[0] ), *( trajs[1] ), *m_trajpoca, m_ttracks_poca_min_dty.value(), m_ttracks_poca_initial_z.value() ); + if ( poca.has_value() ) { + position = poca->poca; posinitialized = true; } } -- GitLab From be58eb38d8b04ee17ed48b9d52d08a1f25921c81 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Sat, 20 Sep 2025 15:52:32 +0200 Subject: [PATCH 3/8] remove unused vars --- Phys/VertexFit/src/ParticleVertexFitter.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Phys/VertexFit/src/ParticleVertexFitter.cpp b/Phys/VertexFit/src/ParticleVertexFitter.cpp index 72dd2eb05bc..2c0a33ee215 100644 --- a/Phys/VertexFit/src/ParticleVertexFitter.cpp +++ b/Phys/VertexFit/src/ParticleVertexFitter.cpp @@ -724,9 +724,6 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau // Calculate the yz intersection and use it as a seed for POCA // If tracks are essentially parallel in y-z plane, use a constant starting point - const float ty0 = daughters[0]->proto()->track()->firstState().ty(); - const float ty1 = daughters[1]->proto()->track()->firstState().ty(); - const auto poca = Sel::NonlinearDistanceCalculator::findPOCA( *( trajs[0] ), *( trajs[1] ), *m_trajpoca, m_ttracks_poca_min_dty.value(), m_ttracks_poca_initial_z.value() ); if ( poca.has_value() ) { -- GitLab From c8e7142223186e8cae2ef46abaacd54c94914c87 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Mon, 22 Sep 2025 12:47:14 +0200 Subject: [PATCH 4/8] Add back a missing state at EndUT --- Tr/TrackExtrapolators/src/TrackStateProvider.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp index 47dcf0cc272..3cae166e54b 100644 --- a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp +++ b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp @@ -387,6 +387,7 @@ TrackCache TrackStateProvider::createCacheEntry( TkCacheKey key, const LHCb::Tra for ( const auto& loc : { std::pair{ LHCb::State::Location::EndMagnet, StateParameters::ZEndMag }, std::pair{ LHCb::State::Location::MidMagnet, StateParameters::ZMidMag }, std::pair{ LHCb::State::Location::BegMagnet, StateParameters::ZBegMag }, + std::pair{ LHCb::State::Location::EndUT, StateParameters::ZEndUT }, std::pair{ LHCb::State::Location::EndVelo, StateParameters::ZEndVelo } } ) { if ( !track.stateAt( loc.first ) ) { addState( tc, loc.second, geometry, loc.first ); } } -- GitLab From 248f1f95d59df40a040852a5cc21529b1c64f029 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Mon, 22 Sep 2025 16:04:14 +0200 Subject: [PATCH 5/8] Removed m_extrapolateTtracks property --- Phys/VertexFit/src/ParticleVertexFitter.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Phys/VertexFit/src/ParticleVertexFitter.cpp b/Phys/VertexFit/src/ParticleVertexFitter.cpp index 2c0a33ee215..6d6446b5251 100644 --- a/Phys/VertexFit/src/ParticleVertexFitter.cpp +++ b/Phys/VertexFit/src/ParticleVertexFitter.cpp @@ -100,7 +100,6 @@ private: private: Gaudi::Property m_maxnumiter{ this, "MaxNumIter", 5 }; Gaudi::Property m_maxdchisq{ this, "MaxDeltaChi2", 0.01 }; - Gaudi::Property m_extrapolateTtracks{ this, "extrapolateTtracks", false }; Gaudi::Property m_ttracks_poca_min_dty{ this, "TtracksPOCAMinDty", 0.005 }; Gaudi::Property m_ttracks_poca_initial_z{ this, "TtracksPOCAInitialZ", 5000.0 }; PublicToolHandle m_stateprovider{ this, "StateProvider", "TrackStateProvider" }; @@ -679,7 +678,12 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau // 1. if there are 'resonance' daughters, take the vertex position of the first. // 2. if not, use the states of the first two tracks with velo or composites // 3. if not, try with downstream tracks and trajpoca - bool posinitialized{ false }; + bool posinitialized{ false }; + + const bool ttracks_only = std::all_of( daughters.begin(), daughters.end(), []( const LHCb::Particle* p ) { + return p && p->proto() && p->proto()->track() && !p->proto()->track()->hasVelo() && !p->proto()->track()->hasUT(); + } ); + Gaudi::XYZPoint position; if ( counttypes[Resonance] > 0 ) { // try 1 @@ -719,10 +723,10 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau } } bool parallelTracks = false; - if ( ntrajs == 2 && m_extrapolateTtracks ) { - // this is NOT default behaviour + if ( ntrajs == 2 && ttracks_only ) { // Calculate the yz intersection and use it as a seed for POCA - // If tracks are essentially parallel in y-z plane, use a constant starting point + // If tracks are essentially parallel in y-z plane (|dty| < m_ttracks_poca_min_dty), use a constant starting point + // (m_ttracks_poca_initial_z) const auto poca = Sel::NonlinearDistanceCalculator::findPOCA( *( trajs[0] ), *( trajs[1] ), *m_trajpoca, m_ttracks_poca_min_dty.value(), m_ttracks_poca_initial_z.value() ); @@ -732,7 +736,7 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau } } - if ( ( ntrajs == 2 && !m_extrapolateTtracks ) || ( ntrajs == 2 && parallelTracks ) ) { + if ( ( ntrajs == 2 && !ttracks_only ) || ( ntrajs == 2 && parallelTracks ) ) { // this is the default behaviour double mu0( 0 ), mu1( 0 ); Gaudi::XYZVector deltaX; @@ -778,7 +782,7 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau } } break; case TrackWithoutVelo: { - if ( !m_extrapolateTtracks ) { + if ( !ttracks_only ) { // this is the default behaviour const LHCb::Track* track = p->proto()->track(); const LHCb::TrackTraj* tracktraj = m_stateprovider->trajectory( *( p->proto()->track() ), geometry ); -- GitLab From 9440de02781a87fbcb19c8a665802aa376d8e665 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Mon, 22 Sep 2025 17:59:00 +0200 Subject: [PATCH 6/8] Remove unnecessary parameters --- Phys/VertexFit/src/ParticleVertexFitter.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Phys/VertexFit/src/ParticleVertexFitter.cpp b/Phys/VertexFit/src/ParticleVertexFitter.cpp index 6d6446b5251..3b13aee4961 100644 --- a/Phys/VertexFit/src/ParticleVertexFitter.cpp +++ b/Phys/VertexFit/src/ParticleVertexFitter.cpp @@ -100,8 +100,6 @@ private: private: Gaudi::Property m_maxnumiter{ this, "MaxNumIter", 5 }; Gaudi::Property m_maxdchisq{ this, "MaxDeltaChi2", 0.01 }; - Gaudi::Property m_ttracks_poca_min_dty{ this, "TtracksPOCAMinDty", 0.005 }; - Gaudi::Property m_ttracks_poca_initial_z{ this, "TtracksPOCAInitialZ", 5000.0 }; PublicToolHandle m_stateprovider{ this, "StateProvider", "TrackStateProvider" }; ToolHandle m_trajpoca{ "TrajPoca" }; const LHCb::IParticlePropertySvc* m_ppsvc{ nullptr }; @@ -728,8 +726,7 @@ StatusCode ParticleVertexFitter::fit( const LHCb::Particle::ConstVector& origdau // If tracks are essentially parallel in y-z plane (|dty| < m_ttracks_poca_min_dty), use a constant starting point // (m_ttracks_poca_initial_z) - const auto poca = Sel::NonlinearDistanceCalculator::findPOCA( - *( trajs[0] ), *( trajs[1] ), *m_trajpoca, m_ttracks_poca_min_dty.value(), m_ttracks_poca_initial_z.value() ); + const auto poca = Sel::NonlinearDistanceCalculator::findPOCA( *( trajs[0] ), *( trajs[1] ), *m_trajpoca ); if ( poca.has_value() ) { position = poca->poca; posinitialized = true; -- GitLab From 273ec166eb2ff012fd390f3284a45c3fb4a5f1b9 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Tue, 30 Sep 2025 02:45:26 +0200 Subject: [PATCH 7/8] Separate cache locations for different tools --- .../src/TrackStateProvider.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp index 3cae166e54b..d88085e0c4e 100644 --- a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp +++ b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp @@ -136,6 +136,14 @@ public: /// Standard constructor TrackStateProvider( const std::string& type, const std::string& name, const IInterface* parent ); + StatusCode initialize() override { + return GaudiTool::initialize().andThen( [&] { + // Depending on TrackStateProvider configuration, the resulting track extrapolation might differ. + // In this case we can't simply reuse the cache created by standard configuration (as it's stored in TES). + m_cachelocation = std::string( "TrackStateProviderCache_" ) + name(); + } ); + }; + /// Compute the state of the track at position z. The third /// argument is the tolerance: if an existing state is found within /// a z-distance 'tolerance', that state is returned. @@ -181,14 +189,11 @@ private: /// Get the track cache from the event store TrackCaches& trackcache() const { - // auto* obj = m_caches.getIfExists(); - // return const_cast( obj ? *obj : *( m_caches.put( TrackCaches{} ) ) ); - static constexpr auto loc = "TrackStateProviderCache"; - using CacheTES = AnyDataWrapper; - auto d = getIfExists( loc ); + using CacheTES = AnyDataWrapper; + auto d = getIfExists( m_cachelocation ); if ( !d ) { d = new CacheTES( TrackCaches{} ); - put( d, loc ); + put( d, m_cachelocation ); } return d->getData(); } @@ -203,6 +208,8 @@ private: // mutable DataObjectHandle> m_caches{this, Gaudi::DataHandle::Writer, "CacheLocation", // "TrackStateProviderCache"}; + std::string m_cachelocation; + ToolHandle m_extrapolator{ "TrackMasterExtrapolator", this }; ToolHandle m_interpolator{ "TrackInterpolator", this }; -- GitLab From 584bf4f5a5c1595a7c9aba61c9f07f6dcd747fc8 Mon Sep 17 00:00:00 2001 From: Volodymyr Svintozelskyi Date: Tue, 30 Sep 2025 19:35:51 +0200 Subject: [PATCH 8/8] Code improvement --- Tr/TrackExtrapolators/src/TrackStateProvider.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp index d88085e0c4e..06d2442ba24 100644 --- a/Tr/TrackExtrapolators/src/TrackStateProvider.cpp +++ b/Tr/TrackExtrapolators/src/TrackStateProvider.cpp @@ -136,14 +136,6 @@ public: /// Standard constructor TrackStateProvider( const std::string& type, const std::string& name, const IInterface* parent ); - StatusCode initialize() override { - return GaudiTool::initialize().andThen( [&] { - // Depending on TrackStateProvider configuration, the resulting track extrapolation might differ. - // In this case we can't simply reuse the cache created by standard configuration (as it's stored in TES). - m_cachelocation = std::string( "TrackStateProviderCache_" ) + name(); - } ); - }; - /// Compute the state of the track at position z. The third /// argument is the tolerance: if an existing state is found within /// a z-distance 'tolerance', that state is returned. @@ -208,7 +200,9 @@ private: // mutable DataObjectHandle> m_caches{this, Gaudi::DataHandle::Writer, "CacheLocation", // "TrackStateProviderCache"}; - std::string m_cachelocation; + // Depending on TrackStateProvider configuration, the resulting track extrapolation might differ. + // In this case we can't simply reuse the cache created by standard configuration (as it's stored in TES). + std::string m_cachelocation = std::string( "TrackStateProviderCache_" ) + name(); ToolHandle m_extrapolator{ "TrackMasterExtrapolator", this }; ToolHandle m_interpolator{ "TrackInterpolator", this }; -- GitLab