diff --git a/Pr/PrAlgorithms/src/PrForwardTracking.cpp b/Pr/PrAlgorithms/src/PrForwardTracking.cpp index 99518baadf9327f29bfbcab786d4ef087cf19985..92938d03e9afc35d3e67638f83772bf0d0dea3ab 100644 --- a/Pr/PrAlgorithms/src/PrForwardTracking.cpp +++ b/Pr/PrAlgorithms/src/PrForwardTracking.cpp @@ -2493,7 +2493,7 @@ namespace LHCb::Pr::Forward { for ( auto idx{0}; idx < n_vphits.cast(); ++idx ) { out.field()[idx].template field().set( ancestTrack.vp_index( idx ) ); - out.field()[idx].template field().set( ancestTrack.lhcbID( idx ) ); + out.field()[idx].template field().set( ancestTrack.vp_lhcbID( idx ) ); } } diff --git a/Pr/PrAlgorithms/src/PrLongLivedTracking.cpp b/Pr/PrAlgorithms/src/PrLongLivedTracking.cpp index 6f2096397b9b2d73b6d567a73b90e133fb1a6062..d77d00c34322a5181d42825e086c939d9fd977da 100644 --- a/Pr/PrAlgorithms/src/PrLongLivedTracking.cpp +++ b/Pr/PrAlgorithms/src/PrLongLivedTracking.cpp @@ -597,7 +597,7 @@ private: // Copy seed hits newTrack.field().resize( seed.nHits() ); for ( i = 0; i < seed.nHits().cast(); i++ ) { - auto id = seed.lhcbID( i ); + auto id = seed.ft_lhcbID( i ); newTrack.field()[i].template field().set( id ); newTrack.field()[i].template field().set( seed.ft_index( i ) ); } diff --git a/Pr/PrAlgorithms/src/PrMatchNN.cpp b/Pr/PrAlgorithms/src/PrMatchNN.cpp index f9eba6e1403b7b07b24ae725ce6f32228964b8b8..1d1b50a7bb6f3c8f9837d8e97c246f6c5b85a656 100644 --- a/Pr/PrAlgorithms/src/PrMatchNN.cpp +++ b/Pr/PrAlgorithms/src/PrMatchNN.cpp @@ -336,11 +336,11 @@ LHCb::Pr::Long::Tracks PrMatchNN::makeTracks( const LHCb::Pr::Velo::Tracks& v for ( auto idx{0}; idx < n_vphits.hmax( loopMask ); ++idx ) { oTrack.field()[idx].template field().set( velo_track.vp_index( idx ) ); - oTrack.field()[idx].template field().set( velo_track.lhcbID( idx ) ); + oTrack.field()[idx].template field().set( velo_track.vp_lhcbID( idx ) ); } for ( auto idx{0}; idx < n_fthits.hmax( loopMask ); ++idx ) { oTrack.field()[idx].template field().set( seed_track.ft_index( idx ) ); - oTrack.field()[idx].template field().set( seed_track.lhcbID( idx ) ); + oTrack.field()[idx].template field().set( seed_track.ft_lhcbID( idx ) ); } //== get Velo and T states at the usual pattern reco positions diff --git a/Pr/PrConverters/CMakeLists.txt b/Pr/PrConverters/CMakeLists.txt index 67eec084422ab5541db1364db5604a1ace805169..66402806ce4a07301838ca64a507ee523c3d61c5 100644 --- a/Pr/PrConverters/CMakeLists.txt +++ b/Pr/PrConverters/CMakeLists.txt @@ -24,6 +24,7 @@ gaudi_add_module(PrConverters src/fromTrackv2PrSeedingTrack.cpp src/fromV1TrackV2Track.cpp src/fromV2TrackV1Track.cpp + src/fromV3TrackV1Track.cpp src/fromVectorLHCbRecVertex.cpp src/fromVectorLHCbRecVertexv2.cpp src/fromVectorLHCbTrack.cpp @@ -45,6 +46,7 @@ gaudi_add_module(PrConverters Rec::PrKernel Rec::SelKernelLib Rec::TrackKernel + Rec::TrackInterfacesLib ) gaudi_add_tests(QMTest) diff --git a/Pr/PrConverters/src/fromPrSeedTrackTrackv2.cpp b/Pr/PrConverters/src/fromPrSeedTrackTrackv2.cpp index ea27557b09a973f47d02a5193868028d7e8a2121..491e4bfbf965e97b39db15cd9d69181dc8da7a03 100644 --- a/Pr/PrConverters/src/fromPrSeedTrackTrackv2.cpp +++ b/Pr/PrConverters/src/fromPrSeedTrackTrackv2.cpp @@ -47,7 +47,7 @@ namespace LHCb::Converters::Track::v2 { auto nHits = ( inputTrack.field() ).size().cast(); auto chi2PerDoF = ( inputTrack.get() ).cast(); auto getP = outTrack.setChi2PerDoF( {chi2PerDoF, static_cast( nHits ) - 5} ); - for ( int iID = 0; iID < nHits; iID++ ) outTrack.addToLhcbIDs( inputTrack.lhcbID( iID ).LHCbID() ); + for ( int iID = 0; iID < nHits; iID++ ) outTrack.addToLhcbIDs( inputTrack.ft_lhcbID( iID ).LHCbID() ); // Copying the states for ( int iState = 0; iState < 3; iState++ ) { auto state = inputTrack.getLHCbState( iState ); diff --git a/Pr/PrConverters/src/fromV3TrackV1Track.cpp b/Pr/PrConverters/src/fromV3TrackV1Track.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf9b21883ea0d4564ca1908b07f03ce621ca523c --- /dev/null +++ b/Pr/PrConverters/src/fromV3TrackV1Track.cpp @@ -0,0 +1,245 @@ +/*****************************************************************************\ +* (c) Copyright 2000-2020 CERN for the benefit of the LHCb Collaboration * +* * +* This software is distributed under the terms of the GNU General Public * +* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * +* * +* In applying this licence, CERN does not waive the privileges and immunities * +* granted to it by virtue of its status as an Intergovernmental Organization * +* or submit itself to any jurisdiction. * +\*****************************************************************************/ +#include "Event/GhostProbability.h" +#include "Event/PartialChiSquareds.h" +#include "Event/PrKalmanFitResult.h" +#include "Event/SOATrackConversion.h" +#include "Event/StateParameters.h" +#include "Event/Track.h" +#include "Event/Track_v3.h" +#include "GaudiKernel/GaudiException.h" +#include "GaudiKernel/StdArrayAsProperty.h" +#include "LHCbAlgs/Transformer.h" +#include "SelKernel/TrackZips.h" +#include "TrackInterfaces/IGhostProbability.h" +#include + +/** + * Converter between LHCb::Event::v3::Tracks ( SoA PoD ) and vector + * + */ + +namespace { + using dType = SIMDWrapper::scalar::types; + using I = dType::int_v; + using F = dType::float_v; + + namespace conversion = LHCb::Event::conversion; + using output_t = LHCb::Event::v1::Tracks; + + using V3ExtraOutput = std::tuple; + using V3FullOutput = std::tuple>; + using V3Output_with_GhostProb = std::tuple; + using V3FullOutput_with_GhostProb = + std::tuple>; + + using v3Proxy = decltype( *( std::declval().scalar().begin() ) ); + + /// Update a single state + template + void update_state( LHCb::Event::v1::Track& new_track, TrackProxy const& inTrack ) { + + auto s = inTrack.state( L ); + auto location = conversion::to_aos_state_loc_v; + + LHCb::State state; + state.setState( s.x().cast(), s.y().cast(), s.z().cast(), s.tx().cast(), s.ty().cast(), s.qOverP().cast() ); + state.setLocation( location ); + + auto inCov = inTrack.covariance( L ); + Gaudi::TrackSymMatrix cov; + for ( int i = 0; i < inCov.n_rows; i++ ) + for ( int j = 0; j <= i; j++ ) cov( i, j ) = inCov( i, j ).cast(); + + state.setCovariance( cov ); + new_track.addToStates( state ); + } + + template + void add_partial_chi2s( LHCb::Event::v1::Track& new_track, PartialChiSquaredsProxy const& in_partial_chi2 ) { + + using out_track = LHCb::Event::v1::Track; + switch ( new_track.type() ) { + case out_track::Types::Long: + new_track.addInfo( out_track::AdditionalInfo::FitTChi2, in_partial_chi2.FitTChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitTNDoF, in_partial_chi2.FitTNDoF().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitVeloChi2, in_partial_chi2.FitVeloChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitVeloNDoF, in_partial_chi2.FitVeloNDoF().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitMatchChi2, in_partial_chi2.FitMatchChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::NUTOutliers, in_partial_chi2.NUTOutliers().cast() ); + break; + case out_track::Types::Downstream: + new_track.addInfo( out_track::AdditionalInfo::FitTChi2, in_partial_chi2.FitTChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitTNDoF, in_partial_chi2.FitTNDoF().cast() ); + new_track.addInfo( out_track::AdditionalInfo::NUTOutliers, in_partial_chi2.NUTOutliers().cast() ); + break; + case out_track::Types::Velo: + new_track.addInfo( out_track::AdditionalInfo::FitTChi2, in_partial_chi2.FitTChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitTNDoF, in_partial_chi2.FitTNDoF().cast() ); + new_track.addInfo( out_track::AdditionalInfo::NUTOutliers, in_partial_chi2.NUTOutliers().cast() ); + break; + case out_track::Types::Ttrack: + new_track.addInfo( out_track::AdditionalInfo::FitTChi2, in_partial_chi2.FitTChi2().cast() ); + new_track.addInfo( out_track::AdditionalInfo::FitTNDoF, in_partial_chi2.FitTNDoF().cast() ); + break; + default: + throw GaudiException( "PartialChiSquareds is empty for this track type", "fromV3TrackV1Track", + StatusCode::FAILURE ); + } + } + + /// Actual implementation of the "update_states" function + template + static void update_states_impl( LHCb::Event::v1::Track& new_track, TrackProxy const& inTrack, + LHCb::Event::v3::state_collection ) { + ( update_state( new_track, inTrack ), ... ); + } + + /// Update all the states of a track + template + void update_states( LHCb::Event::v1::Track& new_track, TrackProxy const& inTrack, LHCb::Event::v3::TrackType type ) { + + using trtype_t = LHCb::Event::v3::TrackType; + switch ( type ) { + case LHCb::Event::v3::TrackType::Long: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Downstream: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Velo: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Ttrack: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Upstream: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Muon: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Calo: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::UT: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + case LHCb::Event::v3::TrackType::Unknown: + return update_states_impl( new_track, inTrack, LHCb::Event::v3::available_states_t{} ); + default: + throw GaudiException( "unknown v3 track type", "fromV3TrackV1Track", StatusCode::FAILURE ); + } + __builtin_unreachable(); + } + + template + void convert_track( LHCb::Event::v1::Track& new_track, TrackProxy const& inTrack ) { + + auto v1_track_type = conversion::to_v1_track_type( inTrack.type() ); + + new_track.setType( v1_track_type ); + new_track.setHistory( inTrack.history().cast() ); + + new_track.setPatRecStatus( LHCb::Event::v1::Track::PatRecStatus::PatRecIDs ); + new_track.setFitStatus( LHCb::Event::v1::Track::FitStatus::Fitted ); // assume that v3 tracks are fitted + + new_track.setLhcbIDs( inTrack.lhcbIDs() ); + new_track.setChi2AndDoF( inTrack.chi2().cast(), inTrack.nDoF().cast() ); + + update_states( new_track, inTrack, inTrack.type() ); + } +} // namespace + +namespace LHCb::Converters::Track::v1 { + + template + class fromV3TrackV1Track : public Algorithm::Transformer { + + public: + using base_class = Algorithm::Transformer; + using KeyValue = typename base_class::KeyValue; + + fromV3TrackV1Track( const std::string& name, ISvcLocator* pSvcLocator ) + : base_class( name, pSvcLocator, {KeyValue{"InputTracks", ""}}, KeyValue{"OutputTracks", ""} ) {} + + output_t operator()( const V3InputType& inTracks ) const override { + + auto out = output_t{}; + + if constexpr ( std::is_same_v ) { + out.reserve( inTracks.size() ); + for ( auto const& in_track : inTracks.scalar() ) { + auto new_track = new LHCb::Event::v1::Track{}; + if ( inTracks.backward() ) new_track->setFlag( LHCb::Track::Flags::Backward, true ); + convert_track( *new_track, in_track ); + new_track->setGhostProbability( std::numeric_limits::max() ); + out.insert( new_track ); + ++m_no_ghostProb; + } + } else if constexpr ( std::is_same_v || + std::is_same_v ) { + + const auto& [in_tracks, extra_infos] = inTracks; + assert( in_tracks.size() == extra_infos.size() ); + out.reserve( in_tracks.size() ); + + auto tracks_with_extra_infos = + LHCb::Event::make_zip( in_tracks, extra_infos ); + for ( auto const& track_with_extra_info : tracks_with_extra_infos ) { + auto new_track = new LHCb::Event::v1::Track{}; + if ( in_tracks.backward() ) new_track->setFlag( LHCb::Track::Flags::Backward, true ); + convert_track( *new_track, track_with_extra_info ); + if constexpr ( std::is_same_v ) { + add_partial_chi2s( *new_track, track_with_extra_info ); + m_ghostTool->execute( *new_track ).ignore(); + } else { + new_track->setGhostProbability( + track_with_extra_info.template get().cast() ); + } + out.insert( new_track ); + } + } else if constexpr ( std::is_same_v || + std::is_same_v ) { + + const auto& [in_tracks, extra_infos, fit_results] = inTracks; + assert( in_tracks.size() == extra_infos.size() ); + out.reserve( in_tracks.size() ); + + auto tracks_with_extra_infos = + LHCb::Event::make_zip( in_tracks, extra_infos ); + int counter = 0; + for ( auto const& track_with_extra_info : tracks_with_extra_infos ) { + auto new_track = new LHCb::Event::v1::Track{}; + if ( in_tracks.backward() ) new_track->setFlag( LHCb::Track::Flags::Backward, true ); + convert_track( *new_track, track_with_extra_info ); + if constexpr ( std::is_same_v ) { + add_partial_chi2s( *new_track, track_with_extra_info ); + m_ghostTool->execute( *new_track ).ignore(); + } else if constexpr ( std::is_same_v ) { + new_track->setGhostProbability( + track_with_extra_info.template get().cast() ); + } + new_track->setFitResult( new LHCb::PrKalmanFitResult{std::move( fit_results[counter] )} ); + out.insert( new_track ); + ++counter; + } + } + + m_nbTracksCounter += out.size(); + return out; + } + + private: + ToolHandle m_ghostTool{this, "GhostIdTool", "UpgradeGhostId"}; + mutable Gaudi::Accumulators::SummingCounter<> m_nbTracksCounter{this, "Nb of Produced Tracks"}; + mutable Gaudi::Accumulators::MsgCounter m_no_ghostProb{this, "Track ghostProb set to default value"}; + }; // namespace + + DECLARE_COMPONENT_WITH_ID( fromV3TrackV1Track, "fromV3TrackV1Track" ) + DECLARE_COMPONENT_WITH_ID( fromV3TrackV1Track, "fromV3TrackExtraV1Track" ) + DECLARE_COMPONENT_WITH_ID( fromV3TrackV1Track, "fromV3TrackFullV1Track" ) + DECLARE_COMPONENT_WITH_ID( fromV3TrackV1Track, "fromV3TrackWithGhostProbV1Track" ) + DECLARE_COMPONENT_WITH_ID( fromV3TrackV1Track, "fromV3TrackFullWithGhostProbV1Track" ) +} // namespace LHCb::Converters::Track::v1 diff --git a/Pr/PrVeloUT/src/PrVeloUT.cpp b/Pr/PrVeloUT/src/PrVeloUT.cpp index a574d0ef32913247c7d2bbf9987960111ac1c277..18ee4cff8ca1006fd01b811cd403ff45f40c22db 100644 --- a/Pr/PrVeloUT/src/PrVeloUT.cpp +++ b/Pr/PrVeloUT/src/PrVeloUT.cpp @@ -725,7 +725,7 @@ namespace LHCb::Pr { track.field( 2 ).set( covX.z ); for ( int idx = 0; idx < velotrack.nHits().hmax( outMask ); ++idx ) { track.field()[idx].template field().set( velotrack.vp_index( idx ) ); - track.field()[idx].template field().set( velotrack.lhcbID( idx ) ); + track.field()[idx].template field().set( velotrack.vp_lhcbID( idx ) ); } } } @@ -1115,7 +1115,7 @@ namespace LHCb::Pr { oTrack.field( 2 ).set( covX.z ); for ( int idx = 0; idx < velo_ancestor.nHits().hmax( finalMask ); ++idx ) { oTrack.field()[idx].field().set( velo_ancestor.vp_index( idx ) ); - oTrack.field()[idx].field().set( velo_ancestor.lhcbID( idx ) ); + oTrack.field()[idx].field().set( velo_ancestor.vp_lhcbID( idx ) ); } if ( m_filterMode ) { diff --git a/Tr/PrKalmanFilter/include/PrKalmanFilter/KF.h b/Tr/PrKalmanFilter/include/PrKalmanFilter/KF.h index 8a3a67e9520c28c823b0ddb2dc7088acd5578020..30a4f82459e92eabd1a0a602c2a135beae9106e0 100644 --- a/Tr/PrKalmanFilter/include/PrKalmanFilter/KF.h +++ b/Tr/PrKalmanFilter/include/PrKalmanFilter/KF.h @@ -24,6 +24,9 @@ #include "Event/TrackTypes.h" #include "LHCbMath/Similarity.h" +#include "Event/PartialChiSquareds.h" +#include "Event/Track_v3.h" + // Gaudi #include "GaudiKernel/Kernel.h" // std @@ -72,6 +75,49 @@ namespace LHCb::Pr::Tracks::Fit { template inline constexpr bool isVelo = std::is_same_v; + using TracksV1 = LHCb::Event::v1::Tracks; + + template + inline constexpr bool isV1Tracks = std::is_same_v; + + using dType = SIMDWrapper::scalar::types; + using I = dType::int_v; + using F = dType::float_v; + + using V3ExtraOutput = std::tuple; + using V3FullOutput = std::tuple>; + + template + inline constexpr bool isV3Tracks = std::is_same_v; + + template + inline constexpr bool isV3TracksExtra = std::is_same_v; + + template + inline constexpr bool isV3TracksFull = std::is_same_v; + + template + constexpr inline auto v3_track_type() { + if ( isLong ) + return LHCb::Event::v3::TrackType::Long; + else if ( isDownstream ) + return LHCb::Event::v3::TrackType::Downstream; + else if ( isVelo ) + return LHCb::Event::v3::TrackType::Velo; + else if ( isSeed ) + return LHCb::Event::v3::TrackType::Ttrack; + }; + + template + inline constexpr bool hasFT = isLong || isDownstream || isSeed; + + template + inline constexpr bool hasUT = isLong || isDownstream; + + template + inline constexpr bool hasVP = isVelo || isLong; + template using proxy_type = decltype( *( std::declval().scalar().begin() ) ); @@ -799,12 +845,104 @@ namespace LHCb::Pr::Tracks::Fit { return z; } - template - StatusCode add_fitted_states( LHCb::Event::v1::Track& newtrack, LHCb::span fitnodes, - double const scatteringMomentum, IGeometryInfo const& geometry, - const ITrackExtrapolator& extrap ) { + inline auto calc_extra_info( const std::vector& fitnodes ) { + + auto velo_chi2 = LHCb::ChiSquare{0, -5}; + auto down_chi2 = LHCb::ChiSquare{0, -5}; + auto upstream_chi2 = LHCb::ChiSquare{}; + auto NUTOutliers = 0; + + for ( auto const& node : fitnodes ) { + switch ( node.type() ) { + case Node::Type::VPHit: + velo_chi2 += node.delta_chi2[Node::backward]; + break; + case Node::Type::UTHit: + upstream_chi2 += node.delta_chi2[Node::backward]; + if ( node.m_is_outlier ) ++NUTOutliers; + break; + case Node::Type::FTHit: + down_chi2 += node.delta_chi2[Node::forward]; + break; + default: + break; + } + } + upstream_chi2 += velo_chi2; + + return std::tuple{velo_chi2, upstream_chi2, down_chi2, NUTOutliers}; + } + + inline auto make_fit_result( std::vector& fitnodes, int nIter, double scatteringMomentum, + bool classic_smoothing_post ) { - assert( newtrack.states().size() == 0 && "this should be a new track without states on it" ); + auto kfr = LHCb::PrKalmanFitResult{}; + + if ( classic_smoothing_post ) { + // run a classical smoothing iteration for the alignment + // and store the gain matrices from that step + kfr.gain_matrices.resize( fitnodes.size() ); + KF::classical_smoother_iteration_for_alignment( fitnodes, kfr.gain_matrices ); + } + + // transfer our nodes into the FitResult + kfr.fitnodes = std::move( fitnodes ); + kfr.scattering_momentum = scatteringMomentum; + kfr.number_of_iter = nIter; + // need to re-reserve since I just moved out of a container that I use every loop + // that should make my "moved from" vector usable again. + fitnodes.reserve( 50 ); + return kfr; + } + + template + void update_state( TrackProxy& newtrack, const LHCb::State& state ) { + + if constexpr ( std::is_same_v ) { + auto& statevec = newtrack.states(); + statevec.emplace_back( new LHCb::State{std::move( state )} ); + } else { + using SL = LHCb::Event::v3::Tracks::StateLocation; + const auto loc = [&] { + switch ( state.location() ) { + case State::ClosestToBeam: + return SL::ClosestToBeam; + case State::FirstMeasurement: + return SL::FirstMeasurement; + case State::LastMeasurement: + return SL::LastMeasurement; + case State::BegRich1: + return SL::BegRich1; + case State::EndRich1: + return SL::EndRich1; + case State::BegRich2: + return SL::BegRich2; + case State::EndRich2: + return SL::EndRich2; + default: + throw GaudiException( "Invalid State Location", "PrKalmanFilter", StatusCode::FAILURE ); + } + }(); + + // positions, slopes, q/p + namespace tag = LHCb::Event::v3::Tag; + newtrack.template field( loc ).setPosition( state.x(), state.y(), state.z() ); + newtrack.template field( loc ).setDirection( state.tx(), state.ty() ); + newtrack.template field( loc ).setQOverP( state.qOverP() ); + + // covariance + auto const& cov = state.covariance(); + newtrack.template field( loc ).set( + cov( 0, 0 ), cov( 0, 1 ), cov( 0, 2 ), cov( 0, 3 ), cov( 0, 4 ), cov( 1, 1 ), cov( 1, 2 ), cov( 1, 3 ), + cov( 1, 4 ), cov( 2, 2 ), cov( 2, 3 ), cov( 2, 4 ), cov( 3, 3 ), cov( 3, 4 ), cov( 4, 4 ) ); + } + } + + template + StatusCode add_fitted_states( TrackProxy& newtrack, LHCb::span fitnodes, double const scatteringMomentum, + IGeometryInfo const& geometry, const ITrackExtrapolator& extrap ) { + if constexpr ( std::is_same_v ) + assert( newtrack.states().size() == 0 && "this should be a new track without states on it" ); Gaudi::TrackMatrix transMat = ROOT::Math::SMatrixIdentity(); auto const extrapolate_and_noise = [&extrap, scatteringMomentum, &transMat, &geometry]( @@ -823,8 +961,6 @@ namespace LHCb::Pr::Tracks::Fit { } ); }; - auto& statevec = newtrack.states(); - auto const& first_hit = fitnodes.back(); auto const& last_hit = fitnodes.front(); auto const fwd = Node::forward; @@ -834,30 +970,34 @@ namespace LHCb::Pr::Tracks::Fit { // for long and velo we add CTB first measurement here if constexpr ( isVelo || isLong ) { - auto state = std::make_unique( first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], - first_hit.z(), LHCb::State::ClosestToBeam ); + + auto state = LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], first_hit.z(), + LHCb::State::ClosestToBeam}; + // don't go outside the Velo volume // if CTB state is outside Velo: define CTB state to be the same as FirstMeasurement auto is_ctb_first = true; - if ( const auto ctb_z = calc_ctb_z( *state ); ctb_z < StateParameters::ZEndVelo && ctb_z > ZBegVelo ) { - ret = extrapolate_and_noise( *state, ctb_z, TrackFit::param_scatter_impl::NodeType::ClosestToBeam, + if ( const auto ctb_z = calc_ctb_z( state ); ctb_z < StateParameters::ZEndVelo && ctb_z > ZBegVelo ) { + ret = extrapolate_and_noise( state, ctb_z, TrackFit::param_scatter_impl::NodeType::ClosestToBeam, TrackFit::param_scatter_impl::NodeType::VPHit ); if ( ret.isFailure() ) { return ret; } is_ctb_first = ctb_z < first_hit.z(); - if ( newtrack.checkFlag( LHCb::Track::Flags::Backward ) ) is_ctb_first = !is_ctb_first; + if constexpr ( std::is_same_v ) { + // no effect for v3::Tracks + if ( newtrack.checkFlag( LHCb::Track::Flags::Backward ) ) is_ctb_first = !is_ctb_first; + } } - auto first_meas = - std::make_unique( first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], - first_hit.z(), LHCb::State::Location::FirstMeasurement ); - // make sure that CTB state is sorted in statevec + auto first_meas = LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], first_hit.z(), + LHCb::State::Location::FirstMeasurement}; + if ( is_ctb_first ) { - statevec.emplace_back( state.release() ); - statevec.emplace_back( first_meas.release() ); + update_state( newtrack, state ); + update_state( newtrack, first_meas ); } else { - statevec.emplace_back( first_meas.release() ); - statevec.emplace_back( state.release() ); + update_state( newtrack, first_meas ); + update_state( newtrack, state ); } } @@ -918,73 +1058,72 @@ namespace LHCb::Pr::Tracks::Fit { KF::average_node( rich1_nodes[1] ); KF::average_node( rich1_nodes[2] ); - statevec.emplace_back( new LHCb::State{rich1_nodes[2].final_state_vec, rich1_nodes[2].final_state_cov, - rich1_nodes[2].z(), LHCb::State::Location::BegRich1} ); - - statevec.emplace_back( new LHCb::State{rich1_nodes[1].final_state_vec, rich1_nodes[1].final_state_cov, - rich1_nodes[1].z(), LHCb::State::Location::EndRich1} ); + update_state( newtrack, LHCb::State{rich1_nodes[2].final_state_vec, rich1_nodes[2].final_state_cov, + rich1_nodes[2].z(), LHCb::State::Location::BegRich1} ); + update_state( newtrack, LHCb::State{rich1_nodes[1].final_state_vec, rich1_nodes[1].final_state_cov, + rich1_nodes[1].z(), LHCb::State::Location::EndRich1} ); } else if constexpr ( isSeed ) { - statevec.emplace_back( new LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], - first_hit.z(), LHCb::State::Location::FirstMeasurement} ); + update_state( newtrack, LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], + first_hit.z(), LHCb::State::Location::FirstMeasurement} ); } else if constexpr ( isSeed ) { - statevec.emplace_back( new LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], - first_hit.z(), LHCb::State::Location::FirstMeasurement} ); - + update_state( newtrack, LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], + first_hit.z(), LHCb::State::Location::FirstMeasurement} ); } else if constexpr ( isDownstream ) { // for downstream tracks, first measurement is after RICH1 // thus create state here but first add the RICH states - auto first_meas = - std::make_unique( first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], - first_hit.z(), LHCb::State::Location::FirstMeasurement ); + auto first_meas = LHCb::State{first_hit.filtered_state_vec[fwd], first_hit.filtered_state_cov[fwd], first_hit.z(), + LHCb::State::Location::FirstMeasurement}; // RICH1 states are much simpler because they are only an extrapolation - auto end_rich1 = std::make_unique( *first_meas ); - ret = extrapolate_and_noise( *end_rich1, StateParameters::ZEndRich1, + auto end_rich1 = LHCb::State{first_meas}; + ret = extrapolate_and_noise( end_rich1, StateParameters::ZEndRich1, TrackFit::param_scatter_impl::NodeType::EndRich1, TrackFit::param_scatter_impl::nodetype( first_hit ) ); if ( ret.isFailure() ) { return ret; } - end_rich1->setLocation( LHCb::State::Location::EndRich1 ); + end_rich1.setLocation( LHCb::State::Location::EndRich1 ); // to keep the right order we first insert the BegRICH1 state - auto* beg_rich1 = statevec.emplace_back( new LHCb::State{*end_rich1} ); - // then the EndRICH1 state - statevec.emplace_back( end_rich1.release() ); - - ret = extrapolate_and_noise( *beg_rich1, StateParameters::ZBegRich1, + auto beg_rich1 = LHCb::State{end_rich1}; + ret = extrapolate_and_noise( beg_rich1, StateParameters::ZBegRich1, TrackFit::param_scatter_impl::NodeType::BegRich1, TrackFit::param_scatter_impl::NodeType::EndRich1 ); if ( ret.isFailure() ) { return ret; } - beg_rich1->setLocation( LHCb::State::Location::BegRich1 ); - + beg_rich1.setLocation( LHCb::State::Location::BegRich1 ); + update_state( newtrack, beg_rich1 ); + // then the EndRICH1 state + update_state( newtrack, end_rich1 ); // now add first measurement - statevec.emplace_back( first_meas.release() ); + update_state( newtrack, first_meas ); } - statevec.emplace_back( new LHCb::State{last_hit.filtered_state_vec[bkwd], last_hit.filtered_state_cov[bkwd], - last_hit.z(), LHCb::State::Location::LastMeasurement} ); + auto last_meas = LHCb::State{last_hit.filtered_state_vec[bkwd], last_hit.filtered_state_cov[bkwd], last_hit.z(), + LHCb::State::Location::LastMeasurement}; + update_state( newtrack, last_meas ); // Rich2 only for downstream and long and seed if constexpr ( isLong || isDownstream || isSeed ) { // begRich2 is copy of last measurement // now extrapolate - auto* beg_rich2 = statevec.emplace_back( new LHCb::State{*statevec.back()} ); - ret = extrapolate_and_noise( *beg_rich2, StateParameters::ZBegRich2, + auto beg_rich2 = LHCb::State{last_meas}; + ret = extrapolate_and_noise( beg_rich2, StateParameters::ZBegRich2, TrackFit::param_scatter_impl::NodeType::BegRich2, TrackFit::param_scatter_impl::nodetype( last_hit ) ); if ( ret.isFailure() ) { return ret; } - beg_rich2->setLocation( LHCb::State::Location::BegRich2 ); - - auto* end_rich2 = statevec.emplace_back( new LHCb::State{*statevec.back()} ); + beg_rich2.setLocation( LHCb::State::Location::BegRich2 ); - ret = extrapolate_and_noise( *end_rich2, StateParameters::ZEndRich2, + auto end_rich2 = LHCb::State{beg_rich2}; + ret = extrapolate_and_noise( end_rich2, StateParameters::ZEndRich2, TrackFit::param_scatter_impl::NodeType::EndRich2, TrackFit::param_scatter_impl::NodeType::BegRich2 ); if ( ret.isFailure() ) { return ret; } - end_rich2->setLocation( LHCb::State::Location::EndRich2 ); + end_rich2.setLocation( LHCb::State::Location::EndRich2 ); + + update_state( newtrack, beg_rich2 ); + update_state( newtrack, end_rich2 ); } return ret; } @@ -1030,26 +1169,7 @@ namespace LHCb::Pr::Tracks::Fit { new_track->setNDoF( prev_chi2.nDoF() ); new_track->setChi2PerDoF( prev_chi2.chi2() / prev_chi2.nDoF() ); - auto velo_chi2 = LHCb::ChiSquare{0, -5}; - auto down_chi2 = LHCb::ChiSquare{0, -5}; - auto upstream_chi2 = LHCb::ChiSquare{}; - - for ( auto const& node : fitnodes ) { - switch ( node.type() ) { - case Node::Type::VPHit: - velo_chi2 += node.delta_chi2[Node::backward]; - break; - case Node::Type::UTHit: - upstream_chi2 += node.delta_chi2[Node::backward]; - break; - case Node::Type::FTHit: - down_chi2 += node.delta_chi2[Node::forward]; - break; - default: - break; - } - } - upstream_chi2 += velo_chi2; + const auto [velo_chi2, upstream_chi2, down_chi2, n_ut_outliers] = calc_extra_info( fitnodes ); if constexpr ( isLong ) { @@ -1058,7 +1178,7 @@ namespace LHCb::Pr::Tracks::Fit { new_track->addInfo( AdditionalInfo::FitVeloChi2, velo_chi2.chi2() ); new_track->addInfo( AdditionalInfo::FitVeloNDoF, velo_chi2.nDoF() ); new_track->addInfo( AdditionalInfo::FitMatchChi2, prev_chi2.chi2() - upstream_chi2.chi2() - down_chi2.chi2() ); - + new_track->addInfo( AdditionalInfo::NUTOutliers, n_ut_outliers ); } else if constexpr ( isVelo ) { new_track->addInfo( AdditionalInfo::FitVeloChi2, velo_chi2.chi2() ); @@ -1069,6 +1189,7 @@ namespace LHCb::Pr::Tracks::Fit { new_track->addInfo( AdditionalInfo::FitTChi2, down_chi2.chi2() ); new_track->addInfo( AdditionalInfo::FitTNDoF, down_chi2.nDoF() ); + new_track->addInfo( AdditionalInfo::NUTOutliers, n_ut_outliers ); } if ( add_fitted_states( *new_track, fitnodes, scatteringMomentum, geo, extrap ).isFailure() ) { @@ -1076,25 +1197,111 @@ namespace LHCb::Pr::Tracks::Fit { } if ( fill_fitresult ) { - auto* kfr = new LHCb::PrKalmanFitResult{}; - new_track->setFitResult( kfr ); - - if ( classic_smoothing_post ) { - // run a classical smoothing iteration for the alignment - // and store the gain matrices from that step - kfr->gain_matrices.resize( fitnodes.size() ); - KF::classical_smoother_iteration_for_alignment( fitnodes, kfr->gain_matrices ); + auto kfr = make_fit_result( fitnodes, nIter, scatteringMomentum, classic_smoothing_post ); + new_track->setFitResult( new LHCb::PrKalmanFitResult{std::move( kfr )} ); + } + + return new_track; + } + + template + StatusCode add_output_v3_track( LHCb::Event::v3::Tracks& new_tracks, const InputTrackType& tracks, + const proxy_type& track, std::vector& fitnodes, + LHCb::ChiSquare prev_chi2, double scatteringMomentum, const IGeometryInfo& geo, + const ITrackExtrapolator& extrap, LHCb::UniqueIDGenerator const& unique_id_gen ) { + // + // start creating our output track + // + + static_assert( isLong || isVelo || isDownstream || + isSeed, + "Only Velo, Downstream, Long or Seed tracks are supported currently." ); + + auto new_track = new_tracks.emplace_back(); + + namespace tag = LHCb::Event::v3::Tag; + using int_v = decltype( new_track.template field().get() ); + new_track.field().set( unique_id_gen.generate().value() ); + + const auto history = [&] { + if constexpr ( isLong ) + return tracks.history(); + else if constexpr ( isDownstream ) + return LHCb::Event::Enum::Track::History::PrDownstream; + else if constexpr ( isVelo ) + return LHCb::Event::Enum::Track::History::PrPixel; + else if constexpr ( isSeed ) + return LHCb::Event::Enum::Track::History::PrSeeding; + }(); + new_track.field().set( history ); + new_track.field().set( prev_chi2.nDoF() ); + new_track.field().set( prev_chi2.chi2() ); + + if constexpr ( hasVP ) { + if constexpr ( isVelo ) { + new_track.field().set( track.indices() ); + } else { + new_track.field().set( track.trackVP() ); } + auto n_vp_hits = track.nVPHits(); + new_track.template field().resize( n_vp_hits ); + for ( int i{0}; i < n_vp_hits; ++i ) { + auto id = track.vp_lhcbID( i ); + new_track.template field()[i].template field().set( id ); + } + } else { + new_track.field().set( I{-1} ); + } - // transfer our nodes into the FitResult - kfr->fitnodes = std::move( fitnodes ); - kfr->scattering_momentum = scatteringMomentum; - kfr->number_of_iter = nIter; - // need to re-reserve since I just moved out of a container that I use every loop - // that should make my "moved from" vector usable again. - fitnodes.reserve( 50 ); + if constexpr ( hasUT ) { + auto n_ut_hits = track.nUTHits(); + new_track.template field().resize( n_ut_hits ); + for ( int i{0}; i < n_ut_hits; ++i ) { + auto id = track.ut_lhcbID( i ); + new_track.template field()[i].template field().set( id ); + } + if constexpr ( isLong ) + new_track.field().set( track.trackUT() ); + else + new_track.field().set( I{-1} ); + } else { + new_track.field().set( I{-1} ); } - return new_track; + + if constexpr ( hasFT ) { + auto n_ft_hits = track.nFTHits(); + new_track.template field().resize( n_ft_hits ); + for ( int i{0}; i < n_ft_hits; ++i ) { + auto id = track.ft_lhcbID( i ); + new_track.template field()[i].template field().set( id ); + } + if constexpr ( isDownstream ) + new_track.field().set( track.seed_track_index() ); + else if constexpr ( isLong ) + new_track.field().set( track.trackSeed() ); + else if constexpr ( isSeed ) + new_track.field().set( track.indices() ); + } else { + new_track.field().set( I{-1} ); + } + + StatusCode ret = add_fitted_states( new_track, fitnodes, scatteringMomentum, geo, extrap ); + return ret; } + inline void add_output_v3_partial_chi2( LHCb::Event::v3::Track::PartialChiSquareds& out_partial_chi2s, + std::vector& fitnodes, LHCb::ChiSquare prev_chi2 ) { + + auto new_partial_chi2 = out_partial_chi2s.emplace_back(); + + const auto [velo_chi2, upstream_chi2, down_chi2, NUTOutliers] = calc_extra_info( fitnodes ); + + namespace tag = LHCb::Event::v3::Track::PartialChiSquaredsTag; + new_partial_chi2.field().set( velo_chi2.chi2() ); + new_partial_chi2.field().set( velo_chi2.nDoF() ); + new_partial_chi2.field().set( down_chi2.chi2() ); + new_partial_chi2.field().set( down_chi2.nDoF() ); + new_partial_chi2.field().set( prev_chi2.chi2() - upstream_chi2.chi2() - down_chi2.chi2() ); + new_partial_chi2.field().set( NUTOutliers ); + } } // namespace LHCb::Pr::Tracks::Fit diff --git a/Tr/PrKalmanFilter/src/KalmanFilter.cpp b/Tr/PrKalmanFilter/src/KalmanFilter.cpp index 8a864a903285faf8d2a3eddafe4ef81e66f7b92a..6dbef0a24925b9d27537e8396bb7e0b0d5ace0ea 100644 --- a/Tr/PrKalmanFilter/src/KalmanFilter.cpp +++ b/Tr/PrKalmanFilter/src/KalmanFilter.cpp @@ -14,23 +14,29 @@ #include "Event/ParametrisedScatters.h" #include "Event/PrFitNode.h" #include "TrackInterfaces/ITrackExtrapolator.h" - // LHCb #include "DetDesc/DetectorElement.h" #include "DetDesc/GenericConditionAccessorHolder.h" #include "Event/ChiSquare.h" +#include "Event/PartialChiSquareds.h" #include "Event/PrDownstreamTracks.h" #include "Event/PrLongTracks.h" #include "Event/PrSeedTracks.h" #include "Event/PrTracksTag.h" #include "Event/PrVeloTracks.h" +#include "Event/SIMDEventTypes.h" +#include "Event/SOACollection.h" +#include "Event/SOAUtils.h" #include "Event/StateParameters.h" #include "Event/StateVector.h" #include "Event/Track.h" #include "Event/TrackTypes.h" +#include "Event/Track_v3.h" +#include "Event/UniqueIDGenerator.h" #include "Kernel/STLExtensions.h" #include "LHCbAlgs/Transformer.h" #include "LHCbMath/LHCbMath.h" +#include "LHCbMath/SIMDWrapper.h" #include "LHCbMath/Similarity.h" // Gaudi #include "Gaudi/Accumulators.h" @@ -63,15 +69,16 @@ namespace LHCb::Pr { } // namespace - template + template class KalmanFilter - : public LHCb::Algorithm::Transformer&..., - DetectorElement const& ), + : public LHCb::Algorithm::Transformer&..., + DetectorElement const&, const LHCb::UniqueIDGenerator& ), LHCb::DetDesc::usesConditions> { public: - using base_t = LHCb::Algorithm::Transformer&..., - DetectorElement const& ), - LHCb::DetDesc::usesConditions>; + using base_t = + LHCb::Algorithm::Transformer&..., + DetectorElement const&, const LHCb::UniqueIDGenerator& ), + LHCb::DetDesc::usesConditions>; using base_t::info; using KeyValue = typename base_t::KeyValue; @@ -79,14 +86,15 @@ namespace LHCb::Pr { KalmanFilter( std::string const& name, ISvcLocator* pSvcLocator ) : base_t( name, pSvcLocator, {KeyValue( "Input", "" ), KeyValue( getKey(), "" )..., - KeyValue( "StandardGeometryTop", LHCb::standard_geometry_top )}, + KeyValue( "StandardGeometryTop", LHCb::standard_geometry_top ), + KeyValue( "InputUniqueIDGenerator", LHCb::UniqueIDGeneratorLocation::Default )}, KeyValue( "Output", "" ) ) {} using tag = LHCb::Pr::tag_type_t; using proxy_type = decltype( *( std::declval().scalar().begin() ) ); - LHCb::Event::Tracks operator()( InputTrackType const& tracks, const Hits&..., - DetectorElement const& lhcb ) const override; + OutputTrackType operator()( InputTrackType const& tracks, const Hits&..., DetectorElement const& lhcb, + LHCb::UniqueIDGenerator const& unique_id_gen ) const override; private: Gaudi::Property m_classic_smoothing_post{this, "ClassicSmoothing", true, @@ -117,9 +125,10 @@ namespace LHCb::Pr { mutable Gaudi::Accumulators::SummingCounter m_counter_transport_failed{this, "Transport failed"}; }; - template - LHCb::Event::Tracks KalmanFilter:: - operator()( InputTrackType const& tracks, const Hits&... hits, DetectorElement const& lhcb ) const { + template + OutputTrackType KalmanFilter:: + operator()( InputTrackType const& tracks, const Hits&... hits, DetectorElement const& lhcb, + LHCb::UniqueIDGenerator const& unique_id_gen ) const { m_counter_tracks_in += tracks.size(); const auto* extrap = m_extrap.get(); @@ -136,8 +145,37 @@ namespace LHCb::Pr { m_errorTy * m_errorTy, m_errorQoP * m_errorQoP, m_maxchi2perdof_pre_outlier, m_maxchi2perdof, m_max_outlier_iter, m_max_fit_iter}; - LHCb::Tracks output; - output.reserve( tracks.size() ); + bool backward = [&] { + if constexpr ( isVelo ) + return tracks.backward(); + else + return false; + }(); + + auto output = [&] { + if constexpr ( isV1Tracks ) { + auto result = OutputTrackType{}; + result.reserve( tracks.size() ); + return result; + } else if constexpr ( isV3Tracks ) { + auto result = OutputTrackType{v3_track_type(), backward, unique_id_gen}; + result.reserve( tracks.size() ); + return result; + } else if constexpr ( isV3TracksExtra || isV3TracksFull ) { + auto out_tracks = LHCb::Event::v3::Tracks{v3_track_type(), backward, unique_id_gen}; + out_tracks.reserve( tracks.size() ); + auto out_partial_chi2s = LHCb::Event::v3::Track::PartialChiSquareds{out_tracks.zipIdentifier()}; + out_partial_chi2s.reserve( tracks.size() ); + if constexpr ( isV3TracksExtra ) { + return std::make_tuple( std::move( out_tracks ), std::move( out_partial_chi2s ) ); + } else if constexpr ( isV3TracksFull ) { + std::vector fit_results; + fit_results.reserve( tracks.size() ); + return std::make_tuple( std::move( out_tracks ), std::move( out_partial_chi2s ), std::move( fit_results ) ); + } + } + }(); + std::vector fitnodes; fitnodes.reserve( 50 ); @@ -170,29 +208,105 @@ namespace LHCb::Pr { if ( !KF::remove_outliers( fitnodes, fit_config, chi2, outlier_iter_buffer, chi2_cut_buffer ) ) { continue; } - auto new_track = make_output_track( tracks, track, fitnodes, chi2, nIter, scatteringMomentum, m_fill_fitresult, - m_classic_smoothing_post, *lhcb.geometry(), *extrap ); - if ( !new_track ) { - ++states_failed_buffer; - continue; + if constexpr ( isV1Tracks ) { + auto new_track = make_output_track( tracks, track, fitnodes, chi2, nIter, scatteringMomentum, m_fill_fitresult, + m_classic_smoothing_post, *lhcb.geometry(), *extrap ); + if ( !new_track ) { + ++states_failed_buffer; + continue; + } + output.add( new_track.release() ); + } else if constexpr ( isV3Tracks ) { + auto sc = add_output_v3_track( output, tracks, track, fitnodes, chi2, scatteringMomentum, *lhcb.geometry(), + *extrap, unique_id_gen ); + if ( sc.isFailure() ) { + ++states_failed_buffer; + continue; + } + } else if constexpr ( isV3TracksExtra || isV3TracksFull ) { + auto& new_tracks = std::get<0>( output ); + auto& new_partial_chi2s = std::get<1>( output ); + auto sc = add_output_v3_track( new_tracks, tracks, track, fitnodes, chi2, scatteringMomentum, *lhcb.geometry(), + *extrap, unique_id_gen ); + if ( sc.isFailure() ) { + ++states_failed_buffer; + continue; + } + add_output_v3_partial_chi2( new_partial_chi2s, fitnodes, chi2 ); + if constexpr ( isV3TracksFull ) { + auto& new_fit_results = std::get<2>( output ); + new_fit_results.emplace_back( + make_fit_result( fitnodes, nIter, scatteringMomentum, m_classic_smoothing_post ) ); + } } - output.add( new_track.release() ); } // loop over tracks - m_counter_tracks_out += output.size(); - return output; + + if constexpr ( isV1Tracks || isV3Tracks ) { + m_counter_tracks_out += output.size(); + return output; + } else if constexpr ( isV3TracksExtra ) { + auto& [new_tracks, new_partial_chi2s] = output; + assert( new_tracks.size() == new_partial_chi2s.size() ); + m_counter_tracks_out += new_tracks.size(); + return output; + } else if constexpr ( isV3TracksFull ) { + auto& [new_tracks, new_partial_chi2s, new_fit_results] = output; + assert( new_tracks.size() == new_partial_chi2s.size() ); + assert( new_tracks.size() == new_fit_results.size() ); + m_counter_tracks_out += new_tracks.size(); + return output; + } } - using PrKalmanFilter = KalmanFilter; - using PrKalmanFilter_noUT = KalmanFilter; - using PrKalmanFilter_Downstream = KalmanFilter; - using PrKalmanFilter_Seed = KalmanFilter; - using PrKalmanFilter_Velo = KalmanFilter; - - DECLARE_COMPONENT_WITH_ID( PrKalmanFilter, "PrKalmanFilter" ) - DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_noUT, "PrKalmanFilter_noUT" ) - DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Downstream, "PrKalmanFilter_Downstream" ) - DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Seed, "PrKalmanFilter_Seed" ) - DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Velo, "PrKalmanFilter_Velo" ) + using PrKalmanFilter_V1 = KalmanFilter; + using PrKalmanFilter_noUT_V1 = KalmanFilter; + using PrKalmanFilter_Downstream_V1 = + KalmanFilter; + using PrKalmanFilter_Seed_V1 = KalmanFilter; + using PrKalmanFilter_Velo_V1 = KalmanFilter; + + using PrKalmanFilter_V3 = KalmanFilter; + using PrKalmanFilter_noUT_V3 = KalmanFilter; + using PrKalmanFilter_Downstream_V3 = + KalmanFilter; + using PrKalmanFilter_Seed_V3 = KalmanFilter; + using PrKalmanFilter_Velo_V3 = KalmanFilter; + + using PrKalmanFilter_V3Extra = KalmanFilter; + using PrKalmanFilter_noUT_V3Extra = KalmanFilter; + using PrKalmanFilter_Downstream_V3Extra = KalmanFilter; + using PrKalmanFilter_Seed_V3Extra = KalmanFilter; + using PrKalmanFilter_Velo_V3Extra = KalmanFilter; + + using PrKalmanFilter_V3Full = KalmanFilter; + using PrKalmanFilter_noUT_V3Full = KalmanFilter; + using PrKalmanFilter_Downstream_V3Full = KalmanFilter; + using PrKalmanFilter_Seed_V3Full = KalmanFilter; + using PrKalmanFilter_Velo_V3Full = KalmanFilter; + + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_V1, "PrKalmanFilter" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_noUT_V1, "PrKalmanFilter_noUT" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Downstream_V1, "PrKalmanFilter_Downstream" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Seed_V1, "PrKalmanFilter_Seed" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Velo_V1, "PrKalmanFilter_Velo" ) + + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_V3, "PrKalmanFilter_V3" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_noUT_V3, "PrKalmanFilter_noUT_V3" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Downstream_V3, "PrKalmanFilter_Downstream_V3" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Seed_V3, "PrKalmanFilter_Seed_V3" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Velo_V3, "PrKalmanFilter_Velo_V3" ) + + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_V3Extra, "PrKalmanFilter_V3Extra" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_noUT_V3Extra, "PrKalmanFilter_noUT_V3Extra" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Downstream_V3Extra, "PrKalmanFilter_Downstream_V3Extra" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Seed_V3Extra, "PrKalmanFilter_Seed_V3Extra" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Velo_V3Extra, "PrKalmanFilter_Velo_V3Extra" ) + + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_V3Full, "PrKalmanFilter_V3Full" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_noUT_V3Full, "PrKalmanFilter_noUT_V3Full" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Downstream_V3Full, "PrKalmanFilter_Downstream_V3Full" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Seed_V3Full, "PrKalmanFilter_Seed_V3Full" ) + DECLARE_COMPONENT_WITH_ID( PrKalmanFilter_Velo_V3Full, "PrKalmanFilter_Velo_V3Full" ) } // namespace LHCb::Pr diff --git a/Tr/PrKalmanFilter/src/KalmanFilterTool.cpp b/Tr/PrKalmanFilter/src/KalmanFilterTool.cpp index f3523fe35ed938b3687dedc0a4c1e8603bef6013..98726d4f9a241b11f970cfb064b306360df215d8 100644 --- a/Tr/PrKalmanFilter/src/KalmanFilterTool.cpp +++ b/Tr/PrKalmanFilter/src/KalmanFilterTool.cpp @@ -12,6 +12,7 @@ #include "DetDesc/DetectorElement.h" #include "DetDesc/GenericConditionAccessorHolder.h" #include "Event/PrFitNode.h" +#include "Event/UniqueIDGenerator.h" #include "GaudiAlg/FunctionalTool.h" #include "GaudiAlg/GaudiTool.h" #include "GaudiKernel/IBinder.h" @@ -259,36 +260,40 @@ namespace LHCb::Pr { class KalmanFilterTool : public Gaudi::Functional::ToolBinder< - Gaudi::Interface::Bind::Box( const DetectorElement&, const ITrackExtrapolator& ), + Gaudi::Interface::Bind::Box( const DetectorElement&, const ITrackExtrapolator&, + const LHCb::UniqueIDGenerator& ), LHCb::DetDesc::usesBaseAndConditions>, DetectorElement>> { private: class BoundInstance final : public Gaudi::Interface::Bind::Stub { - const KalmanFilterTool* m_parent; - const DetectorElement& m_geometry; - const ITrackExtrapolator& m_extrap; + const KalmanFilterTool* m_parent; + const DetectorElement& m_geometry; + const ITrackExtrapolator& m_extrap; + const LHCb::UniqueIDGenerator& m_unique_id_gen; public: - BoundInstance( const KalmanFilterTool* parent, const DetectorElement& lhcb, const ITrackExtrapolator& extrap ) - : m_parent{parent}, m_geometry{lhcb}, m_extrap{extrap} {} + BoundInstance( const KalmanFilterTool* parent, const DetectorElement& lhcb, const ITrackExtrapolator& extrap, + const LHCb::UniqueIDGenerator& unique_id_gen ) + : m_parent{parent}, m_geometry{lhcb}, m_extrap{extrap}, m_unique_id_gen{unique_id_gen} {} // these operators implement the interface! TracksV1 operator()( const Long::Tracks& tracks, const Hits& hits_vp, const Hits& hits_ut, const Hits& hits_ft ) const override { - return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, hits_vp, hits_ut, hits_ft ); + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_vp, hits_ut, + hits_ft ); } TracksV1 operator()( const Downstream::Tracks& tracks, const Hits& hits_ut, const Hits& hits_ft ) const override { - return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, hits_ut, hits_ft ); + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_ut, hits_ft ); } TracksV1 operator()( const Seeding::Tracks& tracks, const Hits& hits_ft ) const override { - return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, hits_ft ); + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_ft ); } TracksV1 operator()( const Velo::Tracks& tracks, const Hits& hits_vp ) const override { - return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, hits_vp ); + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_vp ); } TracksV1 operator()( const TracksV1& tracks, const Hits& hits_vp, const Hits& hits_ut, @@ -309,6 +314,26 @@ namespace LHCb::Pr { return m_parent->fit_v1_tracks( tracks, m_geometry, m_extrap, hits_ut, hits_ft ); } + V3FullOutput fitted_v3_tracks( const Long::Tracks& tracks, const Hits& hits_vp, + const Hits& hits_ut, + const Hits& hits_ft ) const override { + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_vp, hits_ut, + hits_ft ); + } + + V3FullOutput fitted_v3_tracks( const Downstream::Tracks& tracks, const Hits& hits_ut, + const Hits& hits_ft ) const override { + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_ut, hits_ft ); + } + + V3FullOutput fitted_v3_tracks( const Seeding::Tracks& tracks, const Hits& hits_ft ) const override { + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_ft ); + } + + V3FullOutput fitted_v3_tracks( const Velo::Tracks& tracks, const Hits& hits_vp ) const override { + return m_parent->fit_pr_tracks( tracks, m_geometry, m_extrap, m_unique_id_gen, hits_vp ); + } + TrackV1 operator()( const TrackV1& track, const Hits& hits_vp, const Hits& hits_ut, const Hits& hits_ft ) const override { std::vector fitnodes; @@ -342,13 +367,14 @@ namespace LHCb::Pr { std::move( name ), parent, {{"StandardGeometryTop", LHCb::standard_geometry_top}, - {"ReferenceExtrapolator", "TrackMasterExtrapolator"}}, + {"ReferenceExtrapolator", "TrackMasterExtrapolator"}, + {"UniqueIDGenerator", LHCb::UniqueIDGeneratorLocation::Default}}, construct( this )} {} // these functions are called by BoundInstance::operator() - template - TracksV1 fit_pr_tracks( const InputTrackType&, const DetectorElement&, const ITrackExtrapolator& extrap, - const Hits&... ) const; + template + OutputTrackType fit_pr_tracks( const InputTrackType&, const DetectorElement&, const ITrackExtrapolator& extrap, + const LHCb::UniqueIDGenerator& unique_id_gen, const Hits&... ) const; template TrackV1 fit_v1_track( const TrackV1&, std::vector&, const DetectorElement&, const ITrackExtrapolator& extrap, @@ -449,9 +475,13 @@ namespace LHCb::Pr { * @note the underlying code is the same as for the algorithm PrKalmanFilter and thus gives the * same results */ - template - TracksV1 KalmanFilterTool::fit_pr_tracks( const InputTrackType& tracks, const DetectorElement& lhcb, - const ITrackExtrapolator& extrap, const Hits&... hits ) const { + template + OutputTrackType KalmanFilterTool::fit_pr_tracks( const InputTrackType& tracks, const DetectorElement& lhcb, + const ITrackExtrapolator& extrap, + const UniqueIDGenerator& unique_id_gen, + const Hits&... hits ) const { + static_assert( isV1Tracks || isV3TracksFull ); + m_counter_tracks_in += tracks.size(); auto outlier_iter_buffer{m_counter_outlier_iterations.buffer()}; @@ -466,10 +496,33 @@ namespace LHCb::Pr { m_errorTy * m_errorTy, m_errorQoP * m_errorQoP, m_maxchi2perdof_pre_outlier, m_maxchi2perdof, m_max_outlier_iter, m_max_fit_iter}; - TracksV1 output; - output.reserve( tracks.size() ); + auto output = [&] { + if constexpr ( isV1Tracks ) { + auto result = OutputTrackType{}; + result.reserve( tracks.size() ); + return result; + } else if constexpr ( isV3Tracks ) { + auto result = OutputTrackType{v3_track_type(), unique_id_gen}; + result.reserve( tracks.size() ); + return result; + } else if constexpr ( isV3TracksExtra || isV3TracksFull ) { + auto out_tracks = LHCb::Event::v3::Tracks{v3_track_type(), unique_id_gen}; + out_tracks.reserve( tracks.size() ); + auto out_partial_chi2s = LHCb::Event::v3::Track::PartialChiSquareds{out_tracks.zipIdentifier()}; + out_partial_chi2s.reserve( tracks.size() ); + if constexpr ( isV3TracksExtra ) { + return std::make_tuple( std::move( out_tracks ), std::move( out_partial_chi2s ) ); + } else if constexpr ( isV3TracksFull ) { + std::vector fit_results; + fit_results.reserve( tracks.size() ); + return std::make_tuple( std::move( out_tracks ), std::move( out_partial_chi2s ), std::move( fit_results ) ); + } + } + }(); + std::vector fitnodes; fitnodes.reserve( 50 ); + auto const input_tracks = tracks.scalar(); for ( auto const track : input_tracks ) { mydebug( "intput track", track.offset() ); @@ -498,18 +551,55 @@ namespace LHCb::Pr { if ( !KF::remove_outliers( fitnodes, fit_config, chi2, outlier_iter_buffer, chi2_cut_buffer ) ) { continue; } - auto new_track = - Tracks::Fit::make_output_track( tracks, track, fitnodes, chi2, nIter, scatteringMomentum, m_fill_fitresult, - m_classic_smoothing_post, *lhcb.geometry(), extrap ); - if ( !new_track ) { - ++states_failed_buffer; - continue; + if constexpr ( isV1Tracks ) { + auto new_track = make_output_track( tracks, track, fitnodes, chi2, nIter, scatteringMomentum, m_fill_fitresult, + m_classic_smoothing_post, *lhcb.geometry(), extrap ); + if ( !new_track ) { + ++states_failed_buffer; + continue; + } + output.add( new_track.release() ); + } else if constexpr ( isV3Tracks ) { + auto sc = add_output_v3_track( output, tracks, track, fitnodes, chi2, scatteringMomentum, *lhcb.geometry(), + extrap, unique_id_gen ); + if ( sc.isFailure() ) { + ++states_failed_buffer; + continue; + } + } else if constexpr ( isV3TracksExtra || isV3TracksFull ) { + auto& new_tracks = std::get<0>( output ); + auto& new_partial_chi2s = std::get<1>( output ); + auto sc = add_output_v3_track( new_tracks, tracks, track, fitnodes, chi2, scatteringMomentum, *lhcb.geometry(), + extrap, unique_id_gen ); + if ( sc.isFailure() ) { + ++states_failed_buffer; + continue; + } + add_output_v3_partial_chi2( new_partial_chi2s, fitnodes, chi2 ); + if constexpr ( isV3TracksFull ) { + auto& new_fit_results = std::get<2>( output ); + new_fit_results.emplace_back( + make_fit_result( fitnodes, nIter, scatteringMomentum, m_classic_smoothing_post ) ); + } } - output.add( new_track.release() ); } // loop over tracks - m_counter_tracks_out += output.size(); - return output; + + if constexpr ( isV1Tracks || isV3Tracks ) { + m_counter_tracks_out += output.size(); + return output; + } else if constexpr ( isV3TracksExtra ) { + auto& [new_tracks, new_partial_chi2s] = output; + assert( new_tracks.size() == new_partial_chi2s.size() ); + m_counter_tracks_out += new_tracks.size(); + return output; + } else if constexpr ( isV3TracksFull ) { + auto& [new_tracks, new_partial_chi2s, new_fit_results] = output; + assert( new_tracks.size() == new_partial_chi2s.size() ); + assert( new_tracks.size() == new_fit_results.size() ); + m_counter_tracks_out += new_tracks.size(); + return output; + } } /** diff --git a/Tr/PrKalmanFilter/src/ToolExample.cpp b/Tr/PrKalmanFilter/src/ToolExample.cpp index 9ddb02ec7aa9863c1e13cc70ce4710858ae34057..bbc6f64b4e7c3d34608d917f0dc01e128a959fe9 100644 --- a/Tr/PrKalmanFilter/src/ToolExample.cpp +++ b/Tr/PrKalmanFilter/src/ToolExample.cpp @@ -11,13 +11,16 @@ #include "TrackInterfaces/IPrFitterTool.h" +#include "Event/PartialChiSquareds.h" #include "Event/PrDownstreamTracks.h" +#include "Event/PrKalmanFitResult.h" #include "Event/PrLongTracks.h" #include "Event/PrSciFiHits.h" #include "Event/PrSeedTracks.h" #include "Event/PrVeloHits.h" #include "Event/PrVeloTracks.h" #include "Event/Track_v1.h" +#include "Event/Track_v3.h" #include "Gaudi/Accumulators.h" #include "GaudiAlg/Transformer.h" @@ -25,17 +28,19 @@ #include "GaudiKernel/ToolHandle.h" namespace { - using TracksV1 = LHCb::Event::v1::Tracks; - using TrackV1 = LHCb::Event::v1::Track; + using TracksV1 = LHCb::Event::v1::Tracks; + using TrackV1 = LHCb::Event::v1::Track; + using V3FullOutput = std::tuple>; } // namespace -template -class KalmanFilterToolExample : public Gaudi::Functional::Transformer +class KalmanFilterToolExample : public Gaudi::Functional::Transformer&, const LHCb::Pr::Hits&, const LHCb::Pr::Hits&, const IPrFitterTool& )> { public: - using base_t = Gaudi::Functional::Transformer&, const LHCb::Pr::Hits&, const LHCb::Pr::Hits&, const IPrFitterTool& )>; @@ -47,68 +52,105 @@ public: typename base_t::KeyValue{"TrackFitter", ""}}, typename base_t::KeyValue{"Output", ""} ) {} - TracksV1 operator()( const InputTrackType&, const LHCb::Pr::Hits&, - const LHCb::Pr::Hits&, const LHCb::Pr::Hits&, - const IPrFitterTool& ) const override; + OutputTrackType operator()( const InputTrackType&, const LHCb::Pr::Hits&, + const LHCb::Pr::Hits&, + const LHCb::Pr::Hits&, const IPrFitterTool& ) const override; }; -template -TracksV1 KalmanFilterToolExample:: - operator()( const InputTrackType& tracks, const LHCb::Pr::Hits& hits_vp, +template +OutputTrackType KalmanFilterToolExample:: + operator()( const InputTrackType& tracks, const LHCb::Pr::Hits& hits_vp, const LHCb::Pr::Hits& hits_ut, const LHCb::Pr::Hits& hits_ft, const IPrFitterTool& fit ) const { - if constexpr ( std::is_same_v ) { - // by construction same as PrKalmanFilter_Velo - return fit( tracks, hits_vp ); - } else if constexpr ( std::is_same_v ) { - // by construction same as PrKalmanFilter_Downstream - return fit( tracks, hits_ut, hits_ft ); - } else if constexpr ( std::is_same_v ) { - // by construction same as PrKalmanFilter - return fit( tracks, hits_vp, hits_ut, hits_ft ); - } else if constexpr ( std::is_same_v ) { - // by construction same as PrKalmanFilter_Seed - return fit( tracks, hits_ft ); - } else { - // v1 tracks as input! - // let's first fit the whole container - if ( tracks.empty() ) return TracksV1{}; - const auto* single_track = *tracks.begin(); - auto tracks_v1 = [&] { - if ( single_track->checkType( TrackV1::Types::Velo ) ) { - return fit( tracks, hits_vp ); - } else if ( single_track->checkType( TrackV1::Types::Downstream ) ) { - return fit( tracks, hits_ut, hits_ft ); - } else if ( single_track->checkType( TrackV1::Types::Ttrack ) ) { - return fit( tracks, hits_ft ); - } else { - // long tracks ... but in principle this operator is as well suitable for velo and downstream, cool! - return fit( tracks, hits_vp, hits_ut, hits_ft ); - } - }(); + if constexpr ( std::is_same_v ) { + if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Velo + return fit( tracks, hits_vp ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Downstream + return fit( tracks, hits_ut, hits_ft ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter + return fit( tracks, hits_vp, hits_ut, hits_ft ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Seed + return fit( tracks, hits_ft ); + } else { + // v1 tracks as input! + // let's first fit the whole container + if ( tracks.empty() ) return TracksV1{}; + const auto* single_track = *tracks.begin(); + auto tracks_v1 = [&] { + if ( single_track->checkType( TrackV1::Types::Velo ) ) { + return fit( tracks, hits_vp ); + } else if ( single_track->checkType( TrackV1::Types::Downstream ) ) { + return fit( tracks, hits_ut, hits_ft ); + } else if ( single_track->checkType( TrackV1::Types::Ttrack ) ) { + return fit( tracks, hits_ft ); + } else { + // long tracks ... but in principle this operator is as well suitable for velo and downstream, cool! + return fit( tracks, hits_vp, hits_ut, hits_ft ); + } + }(); - // we can also fit single v1 tracks, nice! - auto track_v1 = [&] { - if ( single_track->checkType( TrackV1::Types::Velo ) ) { - return fit( *single_track, hits_vp ); - } else if ( single_track->checkType( TrackV1::Types::Downstream ) ) { - return fit( *single_track, hits_ut, hits_ft ); - } else if ( single_track->checkType( TrackV1::Types::Ttrack ) ) { - return fit( *single_track, hits_ft ); - } else { - // long tracks ... but in principle this operator is as well suitable for velo and downstream, cool! - return fit( *single_track, hits_vp, hits_ut, hits_ft ); - } - }(); - // let's add the track to the container, why not? one reason not to might be that track is not valid :) - if ( !track_v1.checkFlag( TrackV1::Flags::Invalid ) ) tracks_v1.add( new TrackV1( std::move( track_v1 ) ) ); - return tracks_v1; + // we can also fit single v1 tracks, nice! + auto track_v1 = [&] { + if ( single_track->checkType( TrackV1::Types::Velo ) ) { + return fit( *single_track, hits_vp ); + } else if ( single_track->checkType( TrackV1::Types::Downstream ) ) { + return fit( *single_track, hits_ut, hits_ft ); + } else if ( single_track->checkType( TrackV1::Types::Ttrack ) ) { + return fit( *single_track, hits_ft ); + } else { + // long tracks ... but in principle this operator is as well suitable for velo and downstream, cool! + return fit( *single_track, hits_vp, hits_ut, hits_ft ); + } + }(); + // let's add the track to the container, why not? one reason not to might be that track is not valid :) + if ( !track_v1.checkFlag( TrackV1::Flags::Invalid ) ) tracks_v1.add( new TrackV1( std::move( track_v1 ) ) ); + return tracks_v1; + } + } else if constexpr ( std::is_same_v ) { + + static_assert( std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v ); + + if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Velo + return fit.fitted_v3_tracks( tracks, hits_vp ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Downstream + return fit.fitted_v3_tracks( tracks, hits_ut, hits_ft ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter + return fit.fitted_v3_tracks( tracks, hits_vp, hits_ut, hits_ft ); + } else if constexpr ( std::is_same_v ) { + // by construction same as PrKalmanFilter_Seed + return fit.fitted_v3_tracks( tracks, hits_ft ); + } } } -DECLARE_COMPONENT_WITH_ID( KalmanFilterToolExample, "PrKalmanFilterToolExampleAlgo" ) -DECLARE_COMPONENT_WITH_ID( KalmanFilterToolExample, - "PrKalmanFilterToolExampleAlgo_Downstream" ) -DECLARE_COMPONENT_WITH_ID( KalmanFilterToolExample, "PrKalmanFilterToolExampleAlgo_Seed" ) -DECLARE_COMPONENT_WITH_ID( KalmanFilterToolExample, "PrKalmanFilterToolExampleAlgo_Velo" ) -DECLARE_COMPONENT_WITH_ID( KalmanFilterToolExample, "PrKalmanFilterToolExampleAlgo_V1" ) +using PrKalmanFilterToolExampleAlgo = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Downstream = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Seed = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Velo = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_V1V1 = KalmanFilterToolExample; + +using PrKalmanFilterToolExampleAlgo_V3 = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Downstream_V3 = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Seed_V3 = KalmanFilterToolExample; +using PrKalmanFilterToolExampleAlgo_Velo_V3 = KalmanFilterToolExample; + +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo, "PrKalmanFilterToolExampleAlgo" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Downstream, "PrKalmanFilterToolExampleAlgo_Downstream" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Seed, "PrKalmanFilterToolExampleAlgo_Seed" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Velo, "PrKalmanFilterToolExampleAlgo_Velo" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_V1V1, "PrKalmanFilterToolExampleAlgo_V1V1" ) + +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_V3, "PrKalmanFilterToolExampleAlgo_V3" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Downstream_V3, "PrKalmanFilterToolExampleAlgo_Downstream_V3" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Seed_V3, "PrKalmanFilterToolExampleAlgo_Seed_V3" ) +DECLARE_COMPONENT_WITH_ID( PrKalmanFilterToolExampleAlgo_Velo_V3, "PrKalmanFilterToolExampleAlgo_Velo_V3" ) \ No newline at end of file diff --git a/Tr/TrackFitter/src/TrackMasterFitter.cpp b/Tr/TrackFitter/src/TrackMasterFitter.cpp index 491d2d846d0c7dc4e98c7ba18eb879281efb0fdc..7007a1ab7d267852690433d17481cdb2ee72fb7c 100644 --- a/Tr/TrackFitter/src/TrackMasterFitter.cpp +++ b/Tr/TrackFitter/src/TrackMasterFitter.cpp @@ -61,7 +61,7 @@ namespace { track.eraseInfo( Track::AdditionalInfo::FitTChi2 ); track.eraseInfo( Track::AdditionalInfo::FitTNDoF ); track.eraseInfo( Track::AdditionalInfo::FitMatchChi2 ); - track.eraseInfo( Track::AdditionalInfo::FitFracUsedOTTimes ); + track.eraseInfo( Track::AdditionalInfo::NUTOutliers ); auto kalfit = static_cast( track.fitResult() ); @@ -75,6 +75,12 @@ namespace { track.addInfo( Track::AdditionalInfo::FitVeloNDoF, kalfit->chi2Velo().nDoF() ); if ( track.hasT() ) track.addInfo( Track::AdditionalInfo::FitMatchChi2, kalfit->chi2Match().chi2() ); } + + if ( track.hasUT() ) { + int n_ut_outliers = + kalfit->nMeasurements() - kalfit->nActiveMeasurements(); + track.addInfo( Track::AdditionalInfo::NUTOutliers, n_ut_outliers ); + } } //========================================================================= diff --git a/Tr/TrackInterfaces/include/TrackInterfaces/IPrFitterTool.h b/Tr/TrackInterfaces/include/TrackInterfaces/IPrFitterTool.h index dbdb306afaaa9e09f146e6b5f93a10b644d0c084..671528562340f194e07aa38c8f70487aa854c7f1 100644 --- a/Tr/TrackInterfaces/include/TrackInterfaces/IPrFitterTool.h +++ b/Tr/TrackInterfaces/include/TrackInterfaces/IPrFitterTool.h @@ -16,6 +16,10 @@ #include "DetDesc/DetectorElement.h" +#include "Event/PartialChiSquareds.h" +#include "Event/PrKalmanFitResult.h" +#include "Event/Track_v3.h" + namespace LHCb::Pr { namespace Long { struct Tracks; @@ -31,6 +35,9 @@ namespace LHCb::Pr { } } // namespace LHCb::Pr +using V3FullOutput = std::tuple>; + struct IPrFitterTool : extend_interfaces { DeclareInterfaceID( IPrFitterTool, 1, 1 ); @@ -59,6 +66,22 @@ struct IPrFitterTool : extend_interfaces { // fit v1 velo tracks virtual LHCb::Event::Tracks operator()( const LHCb::Event::Tracks&, const LHCb::Pr::Hits& ) const = 0; + + // Same fit methods as above but now returning v3::Tracks + virtual V3FullOutput fitted_v3_tracks( const LHCb::Pr::Long::Tracks&, const LHCb::Pr::Hits&, + const LHCb::Pr::Hits&, + const LHCb::Pr::Hits& ) const = 0; + + virtual V3FullOutput fitted_v3_tracks( const LHCb::Pr::Downstream::Tracks&, + const LHCb::Pr::Hits&, + const LHCb::Pr::Hits& ) const = 0; + + virtual V3FullOutput fitted_v3_tracks( const LHCb::Pr::Seeding::Tracks&, + const LHCb::Pr::Hits& ) const = 0; + + virtual V3FullOutput fitted_v3_tracks( const LHCb::Pr::Velo::Tracks&, + const LHCb::Pr::Hits& ) const = 0; + // fit v1 downstream tracks virtual LHCb::Event::Tracks operator()( const LHCb::Event::Tracks&, const LHCb::Pr::Hits&, const LHCb::Pr::Hits& ) const = 0;