diff --git a/Phys/FunctorCore/include/Functors/TrackLike.h b/Phys/FunctorCore/include/Functors/TrackLike.h index 4fafed823457ccb11a3e8224e8bff9989525d750..6195e53eba407de14ab76c65e4cfcdf856f749b4 100644 --- a/Phys/FunctorCore/include/Functors/TrackLike.h +++ b/Phys/FunctorCore/include/Functors/TrackLike.h @@ -13,9 +13,14 @@ #include "DetDesc/DetectorElement.h" #include "DetDesc/GenericConditionAccessorHolder.h" #include "Event/Bremsstrahlung.h" +#include "Event/ChiSquare.h" +#include "Event/ITrackFitResult.h" +#include "Event/KalmanFitResult.h" +#include "Event/PrKalmanFitResult.h" #include "Event/ProtoParticle.h" #include "Event/StateParameters.h" #include "Event/TrackEnums.h" +#include "Event/TrackFitResult.h" #include "Event/Track_v1.h" #include "Event/Track_v3.h" #include "Functors/Function.h" @@ -215,12 +220,56 @@ namespace Functors::Track { constexpr auto LHCbIDs = GenericFunctor{ "LHCbIDs", []( auto const& d ) -> decltype( d.lhcbIDs() ) { return d.lhcbIDs(); } }; + namespace detail { + template <size_t N> + constexpr auto make_nFTHits_functor( const char ( &name )[N], bool ( LHCb::Detector::FTChannelID::*fun )() const ) { + return chain( TrivialFunctor{ name, + [=]( std::span<const LHCb::LHCbID> ids ) { + return std::count_if( ids.begin(), ids.end(), [=]( auto id ) { + return id.isFT() && ( id.ftID().*fun )(); + } ); + } }, + LHCbIDs ); + } + } // namespace detail + + constexpr auto nFTHitsRight = detail::make_nFTHits_functor( "nFTHitsRight", &LHCb::Detector::FTChannelID::isRight ); + constexpr auto nFTHitsLeft = detail::make_nFTHits_functor( "nFTHitsLeft", &LHCb::Detector::FTChannelID::isLeft ); + constexpr auto nFTHitsTop = detail::make_nFTHits_functor( "nFTHitsTop", &LHCb::Detector::FTChannelID::isTop ); + constexpr auto nFTHitsBottom = + detail::make_nFTHits_functor( "nFTHitsBottom", &LHCb::Detector::FTChannelID::isBottom ); + + /** + * @brief Check if track has hits in different sensors of same VELO module (i.e. track in sensor overlap region) + * + */ + + constexpr auto hasVPSensorOverlap = chain( + TrivialPredicate{ "hasVPSensorOverlap", + []( std::span<const LHCb::LHCbID> ids ) { + auto vpids = std::ranges::filter_view( ids, []( auto i ) { return i.isVP(); } ); + return vpids.end() != std::ranges::adjacent_find( + vpids, + []( LHCb::Detector::VPChannelID i, LHCb::Detector::VPChannelID j ) { + return i.module() == j.module() && i.sensor() != j.sensor(); + }, + []( LHCb::LHCbID id ) { return id.vpID(); } ); + } }, + LHCbIDs ); + /** * @brief Access HitPattern of LHCbIDs. * */ constexpr auto HitPattern = TrivialFunctor{ "HitPattern", []( auto const& d ) { return LHCb::HitPattern( d ); } }; + /** + * @brief Access number of VP layers on HitPattern. + * + */ + constexpr auto nVPLayers = + chain( Functors::TrivialFunctor{ "HitPattern::numVelo", &LHCb::HitPattern::numVelo }, HitPattern, LHCbIDs ); + /** * @brief Access number of A-side VP hits on HitPattern. * @@ -229,20 +278,146 @@ namespace Functors::Track { chain( Functors::TrivialFunctor{ "HitPattern::numVeloA", &LHCb::HitPattern::numVeloA }, HitPattern, LHCbIDs ); /** - * @brief Access number of c-side VP hits on HitPattern. + * @brief Access number of C-side VP hits on HitPattern. * */ constexpr auto nVPHitsC = chain( Functors::TrivialFunctor{ "HitPattern::numVeloC", &LHCb::HitPattern::numVeloC }, HitPattern, LHCbIDs ); /** - * @brief Acces number of overlap VP hits on HitPattern. + * @brief Access number of overlap VP hits on HitPattern. * */ constexpr auto nVPOverlap = chain( Functors::TrivialFunctor{ "HitPattern::numVeloStationsOverlap", &LHCb::HitPattern::numVeloStationsOverlap }, HitPattern, LHCbIDs ); + /** + * @brief Access number of VP holes of track from HitPattern. + * + */ + constexpr auto nVPHoles = chain( + Functors::TrivialFunctor{ "HitPattern::numVeloHoles", &LHCb::HitPattern::numVeloHoles }, HitPattern, LHCbIDs ); + + /** + * @brief Access number of FT holes of trackk from HitPattern. + * + */ + constexpr auto nFTHoles = + chain( Functors::TrivialFunctor{ "HitPattern::numFTHoles", &LHCb::HitPattern::numFTHoles }, HitPattern, LHCbIDs ); + + /** + * @brief Access fitResult of track. + * + */ + constexpr auto FitResult = + GenericFunctor{ "FitResult", []( auto const& t ) -> decltype( t.fitResult() ) { return t.fitResult(); } }; + + /** + * @brief Access VELO ChiSquare of fit result. + * + */ + constexpr auto FitResultChi2Velo = + GenericFunctor{ "FitResultChi2Velo", []( auto const& f ) -> decltype( f.chi2Velo() ) { return f.chi2Velo(); }, + []( LHCb::ITrackFitResult const& ifr ) { + return dispatch<LHCb::TrackFitResult, LHCb::PrKalmanFitResult, LHCb::KalmanFitResult>( + ifr, []( auto const& r ) -> LHCb::ChiSquare { return r.chi2Velo(); } ); + } + + }; + + /** + * @brief Get chi2 of fitted VELO track segment + * + */ + constexpr auto VeloChi2 = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2", &LHCb::ChiSquare::chi2 }, FitResultChi2Velo, FitResult ); + + /** + * @brief Get chi2/ndof of fitted VELO track segment + * + */ + constexpr auto VeloChi2DoF = chain( Functors::TrivialFunctor{ "ChiSquare::chi2PerDoF", &LHCb::ChiSquare::chi2PerDoF }, + FitResultChi2Velo, FitResult ); + + /** + * @brief Access Upstream ChiSquare of fit result. + * + */ + constexpr auto FitResultChi2Upstream = GenericFunctor{ + "FitResultChi2Upstream", []( auto const& f ) -> decltype( f.chi2Velo() ) { return f.chi2Upstream(); }, + []( LHCb::ITrackFitResult const& ifr ) { + return dispatch<LHCb::TrackFitResult, LHCb::PrKalmanFitResult, LHCb::KalmanFitResult>( + ifr, []( auto const& r ) -> LHCb::ChiSquare { return r.chi2Upstream(); } ); + } }; + + /** + * @brief Get chi2 of fitted upstream track segment + * + */ + constexpr auto UpstreamChi2 = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2", &LHCb::ChiSquare::chi2 }, FitResultChi2Upstream, FitResult ); + + /** + * @brief Get chi2/ndof of fitted upstream track segment + * + */ + constexpr auto UpstreamChi2DoF = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2PerDoF", &LHCb::ChiSquare::chi2PerDoF }, FitResultChi2Upstream, + FitResult ); + + /** + * @brief Access Downstream ChiSquare of fit result. + * + */ + constexpr auto FitResultChi2Downstream = GenericFunctor{ + "FitResultChi2Downstream", []( auto const& f ) -> decltype( f.chi2Velo() ) { return f.chi2Downstream(); }, + []( LHCb::ITrackFitResult const& ifr ) { + return dispatch<LHCb::TrackFitResult, LHCb::PrKalmanFitResult, LHCb::KalmanFitResult>( + ifr, []( auto const& r ) -> LHCb::ChiSquare { return r.chi2Downstream(); } ); + } }; + + /** + * @brief Get chi2 of fitted downstream track segment + * + */ + constexpr auto DownstreamChi2 = chain( Functors::TrivialFunctor{ "ChiSquare::chi2", &LHCb::ChiSquare::chi2 }, + FitResultChi2Downstream, FitResult ); + + /** + * @brief Get chi2/ndof of fitted downstream track segment + * + */ + constexpr auto DownstreamChi2DoF = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2PerDoF", &LHCb::ChiSquare::chi2PerDoF }, FitResultChi2Downstream, + FitResult ); + + /** + * @brief Access Match ChiSquare of fit result. + * + */ + constexpr auto FitResultChi2Match = + GenericFunctor{ "FitResultChi2Match", []( auto const& f ) -> decltype( f.chi2Velo() ) { return f.chi2Match(); }, + []( LHCb::ITrackFitResult const& ifr ) { + return dispatch<LHCb::TrackFitResult, LHCb::PrKalmanFitResult, LHCb::KalmanFitResult>( + ifr, []( auto const& r ) -> LHCb::ChiSquare { return r.chi2Match(); } ); + } }; + + /** + * @brief Get chi2 of upstream-downstream match + * + */ + constexpr auto MatchChi2 = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2", &LHCb::ChiSquare::chi2 }, FitResultChi2Match, FitResult ); + + /** + * @brief Get chi2/ndof of upstream-downstream match + * + */ + constexpr auto MatchChi2DoF = + chain( Functors::TrivialFunctor{ "ChiSquare::chi2PerDoF", &LHCb::ChiSquare::chi2PerDoF }, FitResultChi2Match, + FitResult ); + /** * @brief referencePoint, as defined by the referencePoint() accessor. * @note referencePoint is the position at which the object has its threeMomentum diff --git a/Phys/FunctorCore/python/Functors/__init__.py b/Phys/FunctorCore/python/Functors/__init__.py index 922b102bce3e40cb49e0de5c93704e1a7c3df606..f20a5753c80cf7b1ba38f0089c5010975f1539e8 100644 --- a/Phys/FunctorCore/python/Functors/__init__.py +++ b/Phys/FunctorCore/python/Functors/__init__.py @@ -195,6 +195,16 @@ LHCBIDS = Functor("LHCBIDS", "Track::LHCbIDs", "Get LHCbIDs from track-like obje HIT_PATTERN = Functor("HIT_PATTERN", "Track::HitPattern", "Get HitPattern from LHCbIDs") +NVPLAYERS = Functor( + "NVLAYERS", + "Track::nVPLayers", + """ + Return number of VELO layers of track as defined by HitPattern + + Functor's call operator expects a track-like object. + """, +) + NVPHITSA = Functor( "NVPHITSA", "Track::nVPHitsA", @@ -219,12 +229,177 @@ NVPOVERLAP = Functor( "NVPOVERLAP", "Track::nVPOverlap", """ - Return number of overlap hits in VELO + Return number of station overlaps in VELO as defined by HitPattern of a track + + Functor's call operator expects a track-like object. + """, +) + + +NVPHOLES = Functor( + "NVPHOLES", + "Track::nVPHoles", + """ + Return number of holes in VELO of track as defined by HitPattern + + Functor's call operator expects a track-like object. + """, +) + + +HASVPSENSOROVERLAP = Functor( + "HASVPSENSOROVERLAP", + "Track::hasVPSensorOverlap", + """ + Check if track has hits in different sensors of same VELO module + + Functor's call operator expects a track-like object. + """, +) + + +NFTHOLES = Functor( + "NFTHOLES", + "Track::nFTHoles", + """ + Return number of holes in SciFi of track as defined by HitPattern + + Functor's call operator expects a track-like object. + """, +) + + +NFTHITSLEFT = Functor( + "NFTHITSLEFT", + "Track::nFTHitsLeft", + """ + Return number of hits in left SciFi half (quarters Q1 and Q3) of track + + Functor's call operator expects a track-like object. + """, +) + + +NFTHITSRIGHT = Functor( + "NFTHITSRIGHT", + "Track::nFTHitsRight", + """ + Return number of hits in right SciFi half (quarters Q0 and Q2) of track + + Functor's call operator expects a track-like object. + """, +) + + +NFTHITSTOP = Functor( + "NFTHITSTOP", + "Track::nFTHitsTop", + """ + Return number of hits in top SciFi half (quarters Q2 and Q3) of track + + Functor's call operator expects a track-like object. + """, +) + + +NFTHITSBOTTOM = Functor( + "NFTHITSBOTTOM", + "Track::nFTHitsBottom", + """ + Return number of hits in bottom SciFi half (quarters Q0 and Q1) of track Functor's call operator expects a track-like object. """, ) +VELOCHI2 = Functor( + "VELOCHI2", + "Track::VeloChi2", + """ + Return chi2 of fitted VELO segment + + Functor's call operator expects a track-like object. + """, +) + + +VELOCHI2DOF = Functor( + "VELOCHI2DOF", + "Track::VeloChi2DoF", + """ + Return chi2/ndof of fitted VELO segment + + Functor's call operator expects a track-like object. + """, +) + + +UPSTREAMCHI2 = Functor( + "UPSTREAMCHI2", + "Track::UpstreamChi2", + """ + Return chi2 of fitted upstream track segment + + Functor's call operator expects a track-like object. + """, +) + + +UPSTREAMCHI2DOF = Functor( + "UPSTREAMCHI2DOF", + "Track::UpstreamChi2DoF", + """ + Return chi2/ndof of fitted upstream track segment + + Functor's call operator expects a track-like object. + """, +) + + +DOWNSTREAMCHI2 = Functor( + "DOWNSTREAMMCHI2", + "Track::DownstreamChi2", + """ + Return chi2 of fitted downstream track segment + + Functor's call operator expects a track-like object. + """, +) + + +DOWNSTREAMCHI2DOF = Functor( + "DOWNSTREAMCHI2DOF", + "Track::DownstreamChi2DoF", + """ + Return chi2/ndof of fitted downstream track segment + + Functor's call operator expects a track-like object. + """, +) + + +MATCHCHI2 = Functor( + "MATCHMCHI2", + "Track::MatchChi2", + """ + Return chi2 of upstream-downstream match of fitted track + + Functor's call operator expects a track-like object. + """, +) + + +MATCHCHI2DOF = Functor( + "MATCHCHI2DOF", + "Track::MatchChi2DoF", + """ + Return chi2/ndof of upstream-downstream match of fitted track + + Functor's call operator expects a track-like object. + """, +) + + EXTRAPOLATE_TRACK = Functor( "EXTRAPOLATE_TRACK", "Track::Extrapolate", diff --git a/Phys/FunctorCore/tests/src/TestFunctors.cpp b/Phys/FunctorCore/tests/src/TestFunctors.cpp index 46c47d25e70ad01d00bc40d5c65d4800dfc441d6..15a38561d2b9b7512900f7c6e1b8c4131b6a4d42 100644 --- a/Phys/FunctorCore/tests/src/TestFunctors.cpp +++ b/Phys/FunctorCore/tests/src/TestFunctors.cpp @@ -114,6 +114,14 @@ struct DummyState { } }; +// dummy fit result +struct DummyFitResult { + LHCb::ChiSquare chi2Velo() const { return LHCb::ChiSquare{ 3.9, 3 }; }; + LHCb::ChiSquare chi2Upstream() const { return LHCb::ChiSquare{ 5.5, 5 }; }; + LHCb::ChiSquare chi2Downstream() const { return LHCb::ChiSquare{ 6., 4 }; }; + LHCb::ChiSquare chi2Match() const { return LHCb::ChiSquare{ 4.2, 2 }; }; +}; + // dummy track type struct DummyTrack { float m_pt{ 0.f }, m_eta{ 0.f }; @@ -151,10 +159,45 @@ struct DummyTrack { bool checkFlag( LHCb::Event::Enum::Track::Flag flag ) const { return static_cast<int>( flag ) == 0; } const std::vector<DummyState*>& states() const { return m_states; } void addToStates( DummyState* state ) { m_states.push_back( state ); }; - // VELO LHCbIDs: two C-side, one A-side + auto fitResult() const { return DummyFitResult{}; }; + + using FTChannelID = LHCb::Detector::FTChannelID; + using FTStationID = FTChannelID::StationID; + using FTLayerID = FTChannelID::LayerID; + using FTQuarterID = FTChannelID::QuarterID; + using FTModuleID = FTChannelID::ModuleID; + using FTMatID = FTChannelID::MatID; + using VPChannelID = LHCb::Detector::VPChannelID; + using VPSensorID = VPChannelID::SensorID; + using VPChipID = VPChannelID::ChipID; + using VPColumnID = VPChannelID::ColumnID; + using VPRowID = VPChannelID::RowID; + + // VELO LHCbIDs: three C-side, one A-side with sensor overlap in C-side + // FT LHCbIDs: 3 in quarter 0, 4 in quarter 3 std::vector<LHCb::LHCbID> lhcbIDs() const { - std::vector<LHCb::LHCbID> tmp_ids{ LHCb::LHCbID{ 604130029 }, LHCb::LHCbID{ 605211373 }, - LHCb::LHCbID{ 606223851 } }; + std::vector<LHCb::LHCbID> tmp_ids{ + LHCb::LHCbID{ VPChannelID{ VPSensorID{ 0 }, VPChipID{ 2 }, VPColumnID{ 74 }, VPRowID{ 237 } } }, + LHCb::LHCbID{ VPChannelID{ VPSensorID{ 4 }, VPChipID{ 2 }, VPColumnID{ 202 }, VPRowID{ 237 } } }, + LHCb::LHCbID{ VPChannelID{ VPSensorID{ 8 }, VPChipID{ 2 }, VPColumnID{ 61 }, VPRowID{ 235 } } }, + LHCb::LHCbID{ VPChannelID{ VPSensorID{ 154 }, VPChipID{ 2 }, VPColumnID{ 104 }, VPRowID{ 3 } } }, + LHCb::LHCbID{ VPChannelID{ VPSensorID{ 155 }, VPChipID{ 0 }, VPColumnID{ 154 }, VPRowID{ 254 } } }, + + LHCb::LHCbID{ FTChannelID{ FTStationID{ 1 }, FTLayerID{ 0 }, FTQuarterID{ 0 }, FTModuleID{ 0 }, FTMatID{ 3 }, 1, + 81 } }, // channel =81 sipm =1 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 1 }, FTLayerID{ 1 }, FTQuarterID{ 0 }, FTModuleID{ 0 }, FTMatID{ 0 }, 2, + 4 } }, // channel =4 sipm =2 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 1 }, FTLayerID{ 3 }, FTQuarterID{ 0 }, FTModuleID{ 0 }, FTMatID{ 0 }, 2, + 56 } }, // channel =56 sipm =2 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 2 }, FTLayerID{ 0 }, FTQuarterID{ 3 }, FTModuleID{ 1 }, FTMatID{ 1 }, 3, + 38 } }, // channel =38 sipm =3 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 2 }, FTLayerID{ 1 }, FTQuarterID{ 3 }, FTModuleID{ 1 }, FTMatID{ 1 }, 3, + 106 } }, // channel =106 sipm =3 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 2 }, FTLayerID{ 2 }, FTQuarterID{ 3 }, FTModuleID{ 1 }, FTMatID{ 1 }, 0, + 114 } }, // channel =114 sipm =0 + LHCb::LHCbID{ FTChannelID{ FTStationID{ 2 }, FTLayerID{ 3 }, FTQuarterID{ 3 }, FTModuleID{ 1 }, FTMatID{ 2 }, 2, + 50 } }, // channel =50 sipm =2 + }; return tmp_ids; } @@ -201,6 +244,7 @@ struct DummyTrack { DummyTrack( float pt, float eta, bool inacceptance, bool ismuon, float ebrem = 0.f ) : m_pt( pt ), m_eta( eta ), m_inacceptance( inacceptance ), m_ismuon( ismuon ), m_ebrem( ebrem ) {} }; + struct DummyReconstructedObject { DummyReconstructedObject( const int charge, const DummyTrack* track ) : m_charge( charge ), m_track( track ) {} const DummyTrack* track() const { return m_track; } @@ -456,33 +500,50 @@ BOOST_AUTO_TEST_CASE( test_1trackmva_functor ) { BOOST_AUTO_TEST_CASE( test_general_track_functor ) { - auto const TYPE = Functors::Track::Type; - auto const HAST = Functors::Track::HasT; - auto const HASUT = Functors::Track::HasUT; - auto const HASVELO = Functors::Track::HasVelo; - auto const HISTORY = Functors::Track::History; - auto const NFTHITS = Functors::Track::nFTHits; - auto const NUTHITS = Functors::Track::nUTHits; - auto const NVPHITS = Functors::Track::nVPHits; - auto const NHITS = Functors::Track::nHits; - auto const NDOF = Functors::Track::nDoF; - auto const CHI2 = Functors::Track::Chi2; - auto const MC_RECONSTRUCTED = Functors::Track::MC_Reconstructed; - auto const STATES = Functors::Track::States; - auto const GETTRACK = Functors::Particle::GetTrack; - auto const REFERENCEPOINT = Functors::Track::ReferencePoint; - auto const ISTTRACK = trivial_prepare( Functors::Track::IsTtrack ); - auto const ISDOWNSTREAM = trivial_prepare( Functors::Track::IsDownstream ); - auto const ISUPSTREAM = trivial_prepare( Functors::Track::IsUpstream ); - auto const ISLONG = trivial_prepare( Functors::Track::IsLong ); - auto const ISVELO = trivial_prepare( Functors::Track::IsVelo ); - auto const ISVELOBACKWARD = trivial_prepare( Functors::Track::IsVeloBackward ); - auto const ISINVALID = Functors::Track::IsInvalid; - auto const ISSELECTED = Functors::Track::IsSelected; - auto const ISCLONE = Functors::Track::IsClone; - auto const NVPHITSA = trivial_prepare( Functors::Track::nVPHitsA ); - auto const NVPHITSC = trivial_prepare( Functors::Track::nVPHitsC ); - auto const NVPOVERLAP = trivial_prepare( Functors::Track::nVPOverlap ); + auto const TYPE = Functors::Track::Type; + auto const HAST = Functors::Track::HasT; + auto const HASUT = Functors::Track::HasUT; + auto const HASVELO = Functors::Track::HasVelo; + auto const HISTORY = Functors::Track::History; + auto const NFTHITS = Functors::Track::nFTHits; + auto const NUTHITS = Functors::Track::nUTHits; + auto const NVPHITS = Functors::Track::nVPHits; + auto const NHITS = Functors::Track::nHits; + auto const NDOF = Functors::Track::nDoF; + auto const CHI2 = Functors::Track::Chi2; + auto const MC_RECONSTRUCTED = Functors::Track::MC_Reconstructed; + auto const STATES = Functors::Track::States; + auto const GETTRACK = Functors::Particle::GetTrack; + auto const REFERENCEPOINT = Functors::Track::ReferencePoint; + auto const ISTTRACK = trivial_prepare( Functors::Track::IsTtrack ); + auto const ISDOWNSTREAM = trivial_prepare( Functors::Track::IsDownstream ); + auto const ISUPSTREAM = trivial_prepare( Functors::Track::IsUpstream ); + auto const ISLONG = trivial_prepare( Functors::Track::IsLong ); + auto const ISVELO = trivial_prepare( Functors::Track::IsVelo ); + auto const ISVELOBACKWARD = trivial_prepare( Functors::Track::IsVeloBackward ); + auto const ISINVALID = Functors::Track::IsInvalid; + auto const ISSELECTED = Functors::Track::IsSelected; + auto const ISCLONE = Functors::Track::IsClone; + auto const NVPLAYERS = trivial_prepare( Functors::Track::nVPLayers ); + auto const NVPHITSA = trivial_prepare( Functors::Track::nVPHitsA ); + auto const NVPHITSC = trivial_prepare( Functors::Track::nVPHitsC ); + auto const NVPOVERLAP = trivial_prepare( Functors::Track::nVPOverlap ); + auto const HASVPSSENSOROVERLAP = trivial_prepare( Functors::Track::hasVPSensorOverlap ); + auto const NVPHOLES = trivial_prepare( Functors::Track::nVPHoles ); + + auto const VELOCHI2 = trivial_prepare( Functors::Track::VeloChi2 ); + auto const VELOCHI2DOF = trivial_prepare( Functors::Track::VeloChi2DoF ); + auto const UPSTREAMCHI2 = trivial_prepare( Functors::Track::UpstreamChi2 ); + auto const UPSTREAMCHI2DOF = trivial_prepare( Functors::Track::UpstreamChi2DoF ); + auto const DOWNSTREAMCHI2 = trivial_prepare( Functors::Track::DownstreamChi2 ); + auto const DOWNSTREAMCHI2DOF = trivial_prepare( Functors::Track::DownstreamChi2DoF ); + auto const MATCHCHI2 = trivial_prepare( Functors::Track::MatchChi2 ); + auto const MATCHCHI2DOF = trivial_prepare( Functors::Track::MatchChi2DoF ); + auto const NFTHITSRIGHT = trivial_prepare( Functors::Track::nFTHitsRight ); + auto const NFTHITSLEFT = trivial_prepare( Functors::Track::nFTHitsLeft ); + auto const NFTHITSBOTTOM = trivial_prepare( Functors::Track::nFTHitsBottom ); + auto const NFTHITSTOP = trivial_prepare( Functors::Track::nFTHitsTop ); + auto const NFTHOLES = trivial_prepare( Functors::Track::nFTHoles ); auto const CAST_TO_INT = Functors::Functional::CastTo<int>; BOOST_CHECK_EQUAL( CAST_TO_INT( true ), 1 ); @@ -509,9 +570,27 @@ BOOST_AUTO_TEST_CASE( test_general_track_functor ) { BOOST_CHECK_EQUAL( NHITS( track ), 12 ); BOOST_CHECK_EQUAL( NDOF( track ), 1 ); BOOST_CHECK_EQUAL( CHI2( track ), 1.f ); + BOOST_CHECK_EQUAL( NVPLAYERS( track ), 4 ); BOOST_CHECK_EQUAL( NVPHITSA( track ), 1 ); - BOOST_CHECK_EQUAL( NVPHITSC( track ), 2 ); + BOOST_CHECK_EQUAL( NVPHITSC( track ), 3 ); BOOST_CHECK_EQUAL( NVPOVERLAP( track ), 1 ); + BOOST_CHECK_EQUAL( NVPHOLES( track ), 17 ); + BOOST_CHECK_EQUAL( HASVPSSENSOROVERLAP( track ), true ); + + BOOST_CHECK_EQUAL( VELOCHI2( track ), 3.9 ); + BOOST_CHECK_EQUAL( VELOCHI2DOF( track ), 1.3 ); + BOOST_CHECK_EQUAL( UPSTREAMCHI2( track ), 5.5 ); + BOOST_CHECK_EQUAL( UPSTREAMCHI2DOF( track ), 1.1 ); + BOOST_CHECK_EQUAL( DOWNSTREAMCHI2( track ), 6. ); + BOOST_CHECK_EQUAL( DOWNSTREAMCHI2DOF( track ), 1.5 ); + BOOST_CHECK_EQUAL( MATCHCHI2( track ), 4.2 ); + BOOST_CHECK_EQUAL( MATCHCHI2DOF( track ), 2.1 ); + + BOOST_CHECK_EQUAL( NFTHITSBOTTOM( track ), 3 ); + BOOST_CHECK_EQUAL( NFTHITSTOP( track ), 4 ); + BOOST_CHECK_EQUAL( NFTHITSLEFT( track ), 4 ); + BOOST_CHECK_EQUAL( NFTHITSRIGHT( track ), 3 ); + BOOST_CHECK_EQUAL( NFTHOLES( track ), 1 ); DummyReconstructedObject rec{ 1, &track }; BOOST_CHECK_EQUAL( MC_RECONSTRUCTED( rec ), 1 ); diff --git a/Tr/TrackFitEvent/include/Event/Measurement.h b/Tr/TrackFitEvent/include/Event/Measurement.h index d2c08ff75a87fdfd8533dd8cd279a5edb92dabb9..217c9e82042c1338c0631eac1b1c9c1f83fb2508 100644 --- a/Tr/TrackFitEvent/include/Event/Measurement.h +++ b/Tr/TrackFitEvent/include/Event/Measurement.h @@ -71,19 +71,19 @@ namespace LHCb { return idx; } + // Scaffolding for visit overloading with another variant + template <typename T> + struct is_variant_ : std::false_type {}; + template <typename... Ts> + struct is_variant_<std::variant<Ts...>> : std::true_type {}; + template <typename T> + constexpr bool is_variant_v = is_variant_<std::decay_t<T>>::value; + } // namespace details::Measurement using Point = typename ROOT::Math::PositionVector3D<ROOT::Math::Cartesian3D<double>, ROOT::Math::DefaultCoordinateSystemTag>; - // Scaffolding for visit overloading with another variant - template <typename T> - struct is_variant_ : std::false_type {}; - template <typename... Ts> - struct is_variant_<std::variant<Ts...>> : std::true_type {}; - template <typename T> - constexpr bool is_variant_v = is_variant_<std::decay_t<T>>::value; - class Measurement final { public: struct FT { @@ -219,7 +219,7 @@ namespace LHCb { // Same as above, but allow for an additional variant as first argument of visit template <typename F, typename... Fs> decltype( auto ) visit( F&& f, Fs&&... fs ) const { - if constexpr ( is_variant_v<F> ) { + if constexpr ( details::Measurement::is_variant_v<F> ) { return std::visit( Gaudi::overload( std::forward<Fs>( fs )... ), m_sub, std::forward<F>( f ) ); } else { return std::visit( Gaudi::overload( std::forward<F>( f ), std::forward<Fs>( fs )... ), m_sub );