diff --git a/Muon/MuonInterfaces/include/MuonInterfaces/MuonCluster.h b/Muon/MuonInterfaces/include/MuonInterfaces/MuonCluster.h index 21df944cbab809837b4f3d7b894ac0a469f3fe4a..d25b817133117b2323d4921faf80d3484f97c838 100644 --- a/Muon/MuonInterfaces/include/MuonInterfaces/MuonCluster.h +++ b/Muon/MuonInterfaces/include/MuonInterfaces/MuonCluster.h @@ -94,21 +94,28 @@ public: /// return the MuonTileIDs of the logical pads used for this cluster std::vector<LHCb::Detector::Muon::TileID> getPadTiles() const; /// number of logical pads in this hit - int npads() const { return m_pads.size(); } - int clsizeX() const { return m_xsize; } /// cluster size in X - int clsizeY() const { return m_ysize; } /// cluster size in Y - double dX() const { return m_dx; } /// error on X position - double dY() const { return m_dy; } /// error on Y position - double dZ() const { return m_dz; } /// error on Z position - double minX() const { return m_hit_minx; } - double maxX() const { return m_hit_maxx; } - double minY() const { return m_hit_miny; } - double maxY() const { return m_hit_maxy; } - double minZ() const { return m_hit_minz; } - double maxZ() const { return m_hit_maxz; } - double X() const { return m_position.X(); } - double Y() const { return m_position.Y(); } - double Z() const { return m_position.Z(); } + int npads() const { return m_pads.size(); } + int clsizeX() const { return m_xsize; } /// cluster size in X + int clsizeY() const { return m_ysize; } /// cluster size in Y + double dx() const { return m_dx; } /// error on X position + double dX() const { return m_dx; } /// error on X position + double dy() const { return m_dy; } /// error on Y position + double dY() const { return m_dy; } /// error on Y position + double dz() const { return m_dz; } /// error on Z position + double dZ() const { return m_dz; } /// error on Z position + double minX() const { return m_hit_minx; } + double maxX() const { return m_hit_maxx; } + double minY() const { return m_hit_miny; } + double maxY() const { return m_hit_maxy; } + double minZ() const { return m_hit_minz; } + double maxZ() const { return m_hit_maxz; } + double x() const { return m_position.X(); } + double X() const { return m_position.X(); } + double y() const { return m_position.Y(); } + double Y() const { return m_position.Y(); } + double z() const { return m_position.Z(); } + double Z() const { return m_position.Z(); } + Gaudi::XYZVector pos() const { return m_position; } MuonCluster& SetXYZ( double x, double y, double z ) { m_position = { x, y, z }; diff --git a/Muon/MuonTools/CMakeLists.txt b/Muon/MuonTools/CMakeLists.txt index 4b32be5ba62246359353efe9773f3b1ea2349161..856eec278b1283da4e4747f6fc71148ccc4a821c 100644 --- a/Muon/MuonTools/CMakeLists.txt +++ b/Muon/MuonTools/CMakeLists.txt @@ -21,6 +21,7 @@ gaudi_add_module(MuonTools src/MuonPIDV2ToMuonTracks.cpp src/MergeMuonPIDs.cpp src/MergeMuonPIDsV1.cpp + src/MuonHitContainerToCommonMuonHits.cpp LINK Gaudi::GaudiAlgLib Gaudi::GaudiKernel diff --git a/Muon/MuonTools/src/MuonHitContainerToCommonMuonHits.cpp b/Muon/MuonTools/src/MuonHitContainerToCommonMuonHits.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46eb1d5197e87cd283ce1386237a925303a9e4eb --- /dev/null +++ b/Muon/MuonTools/src/MuonHitContainerToCommonMuonHits.cpp @@ -0,0 +1,52 @@ +/*****************************************************************************\ +* (c) Copyright 2000-2018 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. * +\*****************************************************************************/ + +// Gaudi +#include "LHCbAlgs/Transformer.h" + +// LHCb +#include "Event/PrHits.h" +#include "MuonDAQ/CommonMuonHit.h" +#include "MuonDAQ/MuonHitContainer.h" +#include <Detector/Muon/MuonConstants.h> + +namespace LHCb { + + /** + * Converter from MuonPIDs to MuonTracks so that alignment can work + * + * This has been developed as a work around after the replacement of MuonIDAlgLite by + * MuonIDHlt2Alg, as the former one was creating a list of MuonTracks while the later + * does not. + */ + + using CommonMuonHits = std::vector<CommonMuonHit, LHCb::Allocators::EventLocal<CommonMuonHit>>; + + class MuonHitContainerToCommonMuonHits : public Algorithm::Transformer<CommonMuonHits( const MuonHitContainer& )> { + + public: + MuonHitContainerToCommonMuonHits( const std::string& name, ISvcLocator* pSvcLocator ) + : Transformer( name, pSvcLocator, KeyValue{ "Input", "" }, KeyValue{ "Output", "" } ) {} + + CommonMuonHits operator()( const MuonHitContainer& hitContainer ) const override { + CommonMuonHits out; + out.reserve( hitContainer.hits( 0 ).size() * LHCb::Detector::Muon::nStations ); + for ( std::size_t s = 0; s < LHCb::Detector::Muon::nStations; ++s ) { + auto const& hits = hitContainer.hits( s ); + out.insert( out.end(), hits.begin(), hits.end() ); + } + return out; + } + }; + + DECLARE_COMPONENT_WITH_ID( MuonHitContainerToCommonMuonHits, "MuonHitContainerToCommonMuonHits" ) + +} // namespace LHCb diff --git a/Tr/TrackTools/src/StandaloneMuonRec.cpp b/Tr/TrackTools/src/StandaloneMuonRec.cpp index 7d40d979d5ecc5c6e18fcc1de82336342c209540..5372c690203e141c62cb2a049ab616dace84b5f6 100644 --- a/Tr/TrackTools/src/StandaloneMuonRec.cpp +++ b/Tr/TrackTools/src/StandaloneMuonRec.cpp @@ -28,7 +28,9 @@ #include "Magnet/DeMagnet.h" #include "MuonDet/DeMuonDetector.h" #include "MuonDet/MuonNamespace.h" +#include "MuonInterfaces/MuonCluster.h" #include "vdt/vdtMath.h" +#include <Detector/Muon/MuonConstants.h> #include "StandaloneMuonTrack.h" @@ -67,14 +69,14 @@ namespace { 60., 120., 240., 480. } }; // M4 // -- Set tolerances for hit search in region - constexpr std::array<float, 4> m_tolForRegion{ { 2.0, 4.0, 8.0, 10.0 } }; + constexpr std::array<float, LHCb::Detector::Muon::nRegions> m_tolForRegion{ { 2.0, 4.0, 8.0, 10.0 } }; class Cache { public: - std::array<float, 4> stationZ{}; - Gaudi::XYZVector bdl; - double zCenter{}; - int fieldPolarity{}; + std::array<float, LHCb::Detector::Muon::nStations> stationZ{}; + Gaudi::XYZVector bdl; + double zCenter{}; + int fieldPolarity{}; Cache(){}; Cache( DeMuonDetector const& det ) { for ( int s = 0; s != det.stations(); ++s ) { stationZ[s] = det.getStationZ( s ); } @@ -82,41 +84,53 @@ namespace { }; } // namespace -class StandaloneMuonRec : public LHCb::Algorithm::Transformer<LHCb::Tracks( const MuonHitContainer&, const Cache& ), - LHCb::Algorithm::Traits::usesConditions<Cache>> { +/// MuonPositionConcept makes sure we are dealing either with CommonMuonHit or with MuonCluster +template <typename MuonPosition> +concept MuonPositionConcept = + requires { requires std::is_same_v<MuonPosition, CommonMuonHit> || std::is_same_v<MuonPosition, MuonCluster>; }; + +template <MuonPositionConcept MuonPosition> +class StandaloneMuonRec + : public LHCb::Algorithm::Transformer< + LHCb::Tracks( const std::vector<MuonPosition, LHCb::Allocators::EventLocal<MuonPosition>>&, const Cache& ), + LHCb::Algorithm::Traits::usesConditions<Cache>> { public: - using base_class_t = LHCb::Algorithm::Transformer<LHCb::Tracks( const MuonHitContainer&, const Cache& ), + using MuonPositionContainer = std::vector<MuonPosition, LHCb::Allocators::EventLocal<MuonPosition>>; + using PositionsInStations = std::array<std::vector<MuonPosition>, LHCb::Detector::Muon::nStations>; + + using base_class_t = LHCb::Algorithm::Transformer<LHCb::Tracks( const MuonPositionContainer&, const Cache& ), LHCb::Algorithm::Traits::usesConditions<Cache>>; using base_class_t::addConditionDerivation; /// Standard constructor StandaloneMuonRec( const std::string& name, ISvcLocator* pSvcLocator ) - : base_class_t( name, pSvcLocator, - { KeyValue{ "MuonHitsLocation", MuonHitContainerLocation::Default }, - KeyValue{ "ConditionsCache", "StandaloneMuonAlg-" + name + "-ConditionsCache" } }, - KeyValue{ "OutputMuonTracks", "Rec/Track/Muon" } ) {} + : base_class_t( + name, pSvcLocator, + { typename base_class_t::KeyValue{ "MuonHitsLocation", MuonHitContainerLocation::Default }, + typename base_class_t::KeyValue{ "ConditionsCache", "StandaloneMuonAlg-" + name + "-ConditionsCache" } }, + typename base_class_t::KeyValue{ "OutputMuonTracks", "Rec/Track/Muon" } ) {} StatusCode initialize() override { return base_class_t::initialize().andThen( [&] { - this->addConditionDerivation( { DeMuonLocation::Default, LHCb::Det::Magnet::det_path }, - this->inputLocation<Cache>(), - [&]( const DeMuonDetector& det, const DeMagnet& magnet ) { - Cache cache{ det }; - const Gaudi::XYZPoint begin( 0., 0., 0. ); - const Gaudi::XYZPoint end( 0., 0., cache.stationZ[M2] ); - m_bIntegrator->calculateBdlAndCenter( magnet.fieldGrid(), begin, end, 0.0001, 0., - cache.zCenter, cache.bdl ); - cache.fieldPolarity = magnet.isDown() ? -1 : 1; - debug() << "Integrated B field is " << cache.bdl.x() << " Tm" - << " centered at Z=" << cache.zCenter / Gaudi::Units::m << " m" - << " with polarity " << cache.fieldPolarity << endmsg; - return cache; - } ); + this->template addConditionDerivation( + { DeMuonLocation::Default, LHCb::Det::Magnet::det_path }, this->template inputLocation<Cache>(), + [&]( const DeMuonDetector& det, const DeMagnet& magnet ) { + Cache cache{ det }; + const Gaudi::XYZPoint begin( 0., 0., 0. ); + const Gaudi::XYZPoint end( 0., 0., cache.stationZ[M2] ); + m_bIntegrator->calculateBdlAndCenter( magnet.fieldGrid(), begin, end, 0.0001, 0., cache.zCenter, + cache.bdl ); + cache.fieldPolarity = magnet.isDown() ? -1 : 1; + this->debug() << "Integrated B field is " << cache.bdl.x() << " Tm" + << " centered at Z=" << cache.zCenter / Gaudi::Units::m << " m" + << " with polarity " << cache.fieldPolarity << endmsg; + return cache; + } ); } ); } - LHCb::Tracks operator()( const MuonHitContainer& hitContainer, const Cache& cache ) const override; + LHCb::Tracks operator()( const MuonPositionContainer& hitContainer, const Cache& cache ) const override; ToolHandle<IBIntegrator> m_bIntegrator{ this, "BIntegrator", "BIntegrator" }; @@ -130,15 +144,18 @@ private: Gaudi::Property<std::vector<float>> m_ParabolicCorrection{ this, "ParabolicCorrection", { 1.04, 0.14 } }; Gaudi::Property<std::vector<float>> m_resParams{ this, "m_resParams", { 0.015, 0.29 } }; Gaudi::Property<float> m_Constant{ this, "ConstantCorrection", 0., "In MeV" }; + Gaudi::Property<float> m_yAt0Error{ this, "yAt0Error", std::numeric_limits<float>::max(), + "Error on y constraint to point to 0/0/0" }; - std::vector<StandaloneMuonTrack> muonSearch( const MuonHitContainer& hitContainer, const Cache& cache ) const; + std::vector<StandaloneMuonTrack<MuonPosition>> muonSearch( const PositionsInStations& hitContainer, + const Cache& cache ) const; bool findCoincidence( const float x, const float y, const unsigned int station, const unsigned int regionBefore, - const CommonMuonHitRange& hits, CommonMuonHit& hitcand ) const; - void findmuonTrack( const MuonHitContainer& hitContainer, const Cache& cache, - std::array<CommonMuonHit, 4>& bestCandidates, const int seed, - std::vector<StandaloneMuonTrack>& muonTracks ) const; - void recMomentum( StandaloneMuonTrack& muonTrack, const Cache& cache, LHCb::Track& track ) const; - void detectClone( std::vector<StandaloneMuonTrack>& muonTracks, const Cache& cache ) const; + const std::vector<MuonPosition>& hits, MuonPosition& hitcand ) const; + void findmuonTrack( const PositionsInStations& hitContainer, const Cache& cache, + std::array<MuonPosition, LHCb::Detector::Muon::nStations>& bestCandidates, const int seed, + std::vector<StandaloneMuonTrack<MuonPosition>>& muonTracks ) const; + void recMomentum( StandaloneMuonTrack<MuonPosition>& muonTrack, const Cache& cache, LHCb::Track& track ) const; + void detectClone( std::vector<StandaloneMuonTrack<MuonPosition>>& muonTracks, const Cache& cache ) const; // counters mutable Gaudi::Accumulators::Counter<> m_countEvents{ this, "nEvents" }; @@ -148,26 +165,33 @@ private: mutable Gaudi::Accumulators::MsgCounter<MSG::INFO> m_error_zeroBint{ this, "B integral is 0!!" }; }; -DECLARE_COMPONENT( StandaloneMuonRec ) +DECLARE_COMPONENT_WITH_ID( StandaloneMuonRec<CommonMuonHit>, "StandaloneMuonRec" ) +DECLARE_COMPONENT_WITH_ID( StandaloneMuonRec<MuonCluster>, "StandaloneMuonRecWithClusters" ) //============================================================================= // Main execution //============================================================================= -LHCb::Tracks StandaloneMuonRec::operator()( const MuonHitContainer& hitContainer, const Cache& cache ) const { +template <MuonPositionConcept MuonPosition> +LHCb::Tracks StandaloneMuonRec<MuonPosition>::operator()( const MuonPositionContainer& hitContainer, + const Cache& cache ) const { - if ( msgLevel( MSG::DEBUG ) ) debug() << "==> Execute" << endmsg; + if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << "==> Execute" << endmsg; + + PositionsInStations posInStations; + for ( auto hit : hitContainer ) { posInStations[hit.station()].push_back( hit ); } LHCb::Tracks outputTracks; - outputTracks.reserve( 1024 ); + outputTracks.reserve( 10 ); ++m_countEvents; - auto muonTracks = muonSearch( hitContainer, cache ); + auto muonTracks = muonSearch( posInStations, cache ); if ( m_cloneKiller ) { detectClone( muonTracks, cache ); } for ( auto& muTrack : muonTracks ) { if ( muTrack.isClone() ) continue; + muTrack.setYAt0Err( m_yAt0Error ); auto sc = muTrack.linearFit(); if ( !sc ) { ++m_failed_linearfit; @@ -181,14 +205,15 @@ LHCb::Tracks StandaloneMuonRec::operator()( const MuonHitContainer& hitContainer } m_countMuCandidates += outputTracks.size(); - if ( msgLevel( MSG::DEBUG ) ) debug() << " stored candidates " << outputTracks.size() << endmsg; + if ( this->msgLevel( MSG::DEBUG ) ) this->debug() << " stored candidates " << outputTracks.size() << endmsg; return outputTracks; } - -bool StandaloneMuonRec::findCoincidence( const float x, const float y, const unsigned int station, - const unsigned int regionBefore, const CommonMuonHitRange& hits, - CommonMuonHit& hitcand ) const { +template <MuonPositionConcept MuonPosition> +bool StandaloneMuonRec<MuonPosition>::findCoincidence( const float x, const float y, const unsigned int station, + const unsigned int regionBefore, + const std::vector<MuonPosition>& hits, + MuonPosition& hitcand ) const { const auto tol = m_tolForRegion[regionBefore]; float deltaYmin = 9999.; @@ -198,7 +223,8 @@ bool StandaloneMuonRec::findCoincidence( const float x, const float y, const uns float deltaX = fabs( x - hit.x() ); float deltaY = fabs( y - hit.y() ); //-- Check if the hit is within the FOI (copy from MuonCombRec); in any case a xFOI >1000 is not considered - if ( deltaX < m_Xmax[station * 4 + regionBefore] && deltaY < m_Ymax[station * 4 + regionBefore] && + if ( deltaX < m_Xmax[station * LHCb::Detector::Muon::nStations + regionBefore] && + deltaY < m_Ymax[station * LHCb::Detector::Muon::nStations + regionBefore] && ( deltaY < deltaYmin - tol || ( deltaY < deltaYmin + tol && ( deltaX < deltaXmin - tol || fabs( deltaXmin - deltaX ) < 0.1 ) ) ) ) { deltaXmin = deltaX; @@ -209,9 +235,11 @@ bool StandaloneMuonRec::findCoincidence( const float x, const float y, const uns } return findCand; } -void StandaloneMuonRec::findmuonTrack( const MuonHitContainer& hitContainer, const Cache& cache, - std::array<CommonMuonHit, 4>& bestCandidates, const int seed, - std::vector<StandaloneMuonTrack>& muonTracks ) const { +template <MuonPositionConcept MuonPosition> +void StandaloneMuonRec<MuonPosition>::findmuonTrack( + const PositionsInStations& hitContainer, const Cache& cache, + std::array<MuonPosition, LHCb::Detector::Muon::nStations>& bestCandidates, const int seed, + std::vector<StandaloneMuonTrack<MuonPosition>>& muonTracks ) const { float xseed = bestCandidates[seed].x(); float yseed = bestCandidates[seed].y(); unsigned int hit_region = bestCandidates[seed].region(); @@ -220,7 +248,7 @@ void StandaloneMuonRec::findmuonTrack( const MuonHitContainer& hitContainer, con bool findAll = false; for ( int ista = seed - 1; ista > -1; ista-- ) { - auto findCandidate = findCoincidence( x, y, ista, hit_region, hitContainer.hits( ista ), bestCandidates[ista] ); + auto findCandidate = findCoincidence( x, y, ista, hit_region, hitContainer.at( ista ), bestCandidates[ista] ); if ( !findCandidate && ( !m_secondLoop || ista < M4 ) ) break; if ( findCandidate && ista == M2 ) { findAll = true; @@ -243,34 +271,33 @@ void StandaloneMuonRec::findmuonTrack( const MuonHitContainer& hitContainer, con } if ( findAll ) { // create the muon track - StandaloneMuonTrack muon; - muon.setPoint( 0, bestCandidates[M2] ); - muon.setPoint( 1, bestCandidates[M3] ); + StandaloneMuonTrack<MuonPosition> muon; + muon.addPoint( bestCandidates[M2] ); + muon.addPoint( bestCandidates[M3] ); if ( m_secondLoop && bestCandidates[M4].station() == bestCandidates[M5].station() ) { - muon.setPoint( 2, bestCandidates[M4] ); - muon.setnHits( 3 ); + muon.addPoint( bestCandidates[M4] ); } else { - muon.setPoint( 2, bestCandidates[M4] ); - muon.setPoint( 3, bestCandidates[M5] ); - muon.setnHits( 4 ); + muon.addPoint( bestCandidates[M4] ); + muon.addPoint( bestCandidates[M5] ); } muonTracks.push_back( muon ); } } -std::vector<StandaloneMuonTrack> StandaloneMuonRec::muonSearch( const MuonHitContainer& hitContainer, - const Cache& cache ) const { - std::vector<StandaloneMuonTrack> muonTracks; - muonTracks.reserve( 48 ); - - const auto& hitsM5 = hitContainer.hits( M5 ); - std::array<CommonMuonHit, 4> bestCandidates; +template <MuonPositionConcept MuonPosition> +std::vector<StandaloneMuonTrack<MuonPosition>> +StandaloneMuonRec<MuonPosition>::muonSearch( const PositionsInStations& hitContainer, const Cache& cache ) const { + std::vector<StandaloneMuonTrack<MuonPosition>> muonTracks; + muonTracks.reserve( 12 ); + + const auto& hitsM5 = hitContainer.at( M5 ); + std::array<MuonPosition, LHCb::Detector::Muon::nStations> bestCandidates; for ( auto& hit : hitsM5 ) { bestCandidates[3] = hit; findmuonTrack( hitContainer, cache, bestCandidates, M5, muonTracks ); } ///---second loop from M4 if ( m_secondLoop ) { - const auto& hitsM4 = hitContainer.hits( M4 ); + const auto& hitsM4 = hitContainer[M4]; for ( auto& hit : hitsM4 ) { // To remove these hits of M4 used in the first round of search auto used = std::find_if( muonTracks.begin(), muonTracks.end(), @@ -285,7 +312,9 @@ std::vector<StandaloneMuonTrack> StandaloneMuonRec::muonSearch( const MuonHitCon } // estimate the momentum of muonTrack -void StandaloneMuonRec::recMomentum( StandaloneMuonTrack& track, const Cache& cache, LHCb::Track& lbtrack ) const { +template <MuonPositionConcept MuonPosition> +void StandaloneMuonRec<MuonPosition>::recMomentum( StandaloneMuonTrack<MuonPosition>& track, const Cache& cache, + LHCb::Track& lbtrack ) const { const float bdlX = cache.bdl.x(); const float fieldPolarity = cache.fieldPolarity; @@ -296,7 +325,7 @@ void StandaloneMuonRec::recMomentum( StandaloneMuonTrack& track, const Cache& ca LHCb::State state( LHCb::StateVector( trackPos, Gaudi::XYZVector( track.sx(), track.sy(), 1.0 ), 1. / 10000. ) ); const auto Zend = cache.stationZ[M5]; - Gaudi::XYZPoint endtrackPos( track.bx() + track.sx() * Zfirst, track.by() + track.sy() * Zend, Zend ); + Gaudi::XYZPoint endtrackPos( track.bx() + track.sx() * Zend, track.by() + track.sy() * Zend, Zend ); LHCb::State endstate( LHCb::StateVector( endtrackPos, Gaudi::XYZVector( track.sx(), track.sy(), 1.0 ), 1. / 10000. ) ); @@ -353,25 +382,38 @@ void StandaloneMuonRec::recMomentum( StandaloneMuonTrack& track, const Cache& ca state.setLocation( LHCb::State::Location::Muon ); endstate.setLocation( LHCb::State::Location::LastMeasurement ); - debug() << "Muon state = " << state << endmsg; + this->debug() << "Muon state = " << state << endmsg; lbtrack.clearStates(); lbtrack.addToStates( state ); lbtrack.addToStates( endstate ); lbtrack.setChi2PerDoF( track.chi2x() + track.chi2y() ); - lbtrack.setNDoF( track.nHits() - 2 ); + const int DoFForPointAtZero = m_yAt0Error < std::numeric_limits<float>::max(); + lbtrack.setNDoF( track.nHits() - 2 + DoFForPointAtZero ); // add one degree of freedom for the point at 0/0/0 for ( int i = 0; i < track.nHits(); i++ ) { - const auto Tile = track.point( i ).tile(); - lbtrack.addToLhcbIDs( ( LHCb::LHCbID )( Tile ) ); - debug() << " Muon Hit " << i << " tile " << Tile << " tiles in station " << track.point( i ).station() << endmsg; + if constexpr ( std::is_same_v<MuonPosition, CommonMuonHit> ) { + const auto tile = track.point( i ).tile(); + lbtrack.addToLhcbIDs( ( LHCb::LHCbID )( tile ) ); + this->debug() << " Muon Hit " << i << " tile " << tile << " tiles in station " << track.point( i ).station() + << endmsg; + } else { + const auto tiles = track.point( i ).getPadTiles(); + for ( const auto tile : tiles ) { + lbtrack.addToLhcbIDs( ( LHCb::LHCbID )( tile ) ); + this->debug() << " Muon Hit " << i << " tile " << tile << " tiles in station " << track.point( i ).station() + << endmsg; + } + } } lbtrack.setPatRecStatus( LHCb::Track::PatRecStatus::PatRecIDs ); lbtrack.setType( LHCb::Track::Types::Muon ); } -void StandaloneMuonRec::detectClone( std::vector<StandaloneMuonTrack>& muonTracks, const Cache& cache ) const { +template <MuonPositionConcept MuonPosition> +void StandaloneMuonRec<MuonPosition>::detectClone( std::vector<StandaloneMuonTrack<MuonPosition>>& muonTracks, + const Cache& cache ) const { for ( auto itMuonTrackFirst = muonTracks.begin(); itMuonTrackFirst < muonTracks.end(); itMuonTrackFirst++ ) { for ( auto itMuonTrackSecond = itMuonTrackFirst + 1; itMuonTrackSecond < muonTracks.end(); itMuonTrackSecond++ ) { diff --git a/Tr/TrackTools/src/StandaloneMuonTrack.h b/Tr/TrackTools/src/StandaloneMuonTrack.h index 77df068d551b160df4b2b91d424ae1084f29a521..1e6c92c531a68bfc4bf48a0fad40e652c3249d88 100644 --- a/Tr/TrackTools/src/StandaloneMuonTrack.h +++ b/Tr/TrackTools/src/StandaloneMuonTrack.h @@ -13,9 +13,11 @@ #include "Core/FloatComparison.h" #include "MuonDAQ/CommonMuonHit.h" +#include "Detector/Muon/MuonConstants.h" #include "GaudiKernel/Point3DTypes.h" #include "GaudiKernel/Vector3DTypes.h" +#include <boost/container/small_vector.hpp> #include <string> /** @class StandaloneMuonTrack StandaloneMuonTrack.h @@ -29,18 +31,33 @@ * @date 2011-03-03 */ namespace { - void LinearFitXZ( bool XZ, std::array<CommonMuonHit, 4>& m_points, int nHits, float& slope, float& trunc, - float& chi2ndof, float& err_slope, float& err_trunc, float& cov ) { + + enum class FitMode { XZ, YZ }; + + struct FitResult { + float slope = -1e6; + float trunc = -1e6; + float chi2ndof = -1e6; + float err_slope = -1e6; + float err_trunc = -1e6; + float cov = -1e6; + }; + + template <typename MuonPositionClass, FitMode fitMode> + FitResult linearFitImpl( boost::container::small_vector<MuonPositionClass, LHCb::Detector::Muon::nStations>& points, + float yAt0Err = std::numeric_limits<float>::max() ) { float sz2, sz, s0, sxz, sx, sx2; sz2 = sz = s0 = sxz = sx = sx2 = 0; - for ( int i = 0; i < nHits; i++ ) { - const auto hit = m_points[i]; - const auto z = hit.z(); - auto x = hit.x(); - auto xerr = 2. * hit.dx(); - if ( !XZ ) { - x = hit.y(); - xerr = 2 * hit.dy(); + + FitResult result; + + for ( const auto& point : points ) { + const auto z = point.z(); + auto x = point.x(); + auto xerr = 2. * point.dx(); + if ( fitMode == FitMode::YZ ) { + x = point.y(); + xerr = 2 * point.dy(); } sz2 += z * z / xerr / xerr; sz += z / xerr / xerr; @@ -49,91 +66,86 @@ namespace { sx += x / xerr / xerr; sx2 += x * x / xerr / xerr; } - float xdet = sz2 * s0 - sz * sz; - if ( !LHCb::essentiallyZero( xdet ) ) { - slope = ( sxz * s0 - sx * sz ) / xdet; - trunc = ( sx * sz2 - sxz * sz ) / xdet; - err_trunc = sqrt( sz2 / xdet ); - err_slope = sqrt( s0 / xdet ); - cov = -sz / xdet; + if ( yAt0Err < std::numeric_limits<float>::max() ) + s0 += 1.0 / ( yAt0Err * yAt0Err ); // this applies a constraint to 0/0/0 - chi2ndof = ( sx2 + slope * slope * sz2 + trunc * trunc * s0 - 2. * slope * sxz - 2. * trunc * sx + - 2 * slope * trunc * sz ) / - ( nHits - 2 ); + const float xdet = sz2 * s0 - sz * sz; + if ( !LHCb::essentiallyZero( xdet ) ) { + result.slope = ( sxz * s0 - sx * sz ) / xdet; + result.trunc = ( sx * sz2 - sxz * sz ) / xdet; + + result.err_trunc = sqrt( sz2 / xdet ); + result.err_slope = sqrt( s0 / xdet ); + result.cov = -sz / xdet; + + result.chi2ndof = + ( sx2 + result.slope * result.slope * sz2 + result.trunc * result.trunc * s0 - 2. * result.slope * sxz - + 2. * result.trunc * sx + 2 * result.slope * result.trunc * sz ) / + ( points.size() - 2 + ( yAt0Err < std::numeric_limits<float>::max() ) ); // add one degree of freedom if we + // add the "point" at 0/0/0 } + + return result; } } // namespace +template <typename MuonPositionClass> class StandaloneMuonTrack final { public: /// Standard constructor - StandaloneMuonTrack() { m_clone = 0; }; + StandaloneMuonTrack() { + m_clone = false; + m_points.reserve( 4 ); + }; virtual ~StandaloneMuonTrack(){}; ///< Destructor - void setPoint( unsigned int station, CommonMuonHit point ) { m_points[station] = point; }; + void setPoint( unsigned int station, MuonPositionClass point ) { m_points[station] = point; }; + void addPoint( MuonPositionClass point ) { m_points.push_back( point ); }; - CommonMuonHit point( unsigned int station ) const { return m_points[station]; }; + MuonPositionClass point( unsigned int station ) const { return m_points[station]; }; - void setClone() { m_clone = 1; }; - bool isClone() const { return m_clone > 0; } + void setClone() { m_clone = true; }; + bool isClone() const { return m_clone; } - double slopeX( int stationFirst, int stationSecond, double zFirst, double zSecond ) const { - return ( m_points[stationFirst].x() - m_points[stationSecond].x() ) / ( zFirst - zSecond ); - }; - double slopeY( int stationFirst, int stationSecond, double zFirst, double zSecond ) const { - return ( m_points[stationFirst].y() - m_points[stationSecond].y() ) / ( zFirst - zSecond ); - }; + // -- used to constrain the straight line fit in y to 0/0/0 + void setYAt0Err( const float yAt0Err ) { m_yAt0Err = yAt0Err; } // Fit with a min chi^2 in the 2 projections xz and yz bool linearFit() { - double dof = nHits() - 2.; + const double dof = nHits() - 2.; if ( dof < 0 ) return false; - LinearFitXZ( true, m_points, nHits(), m_sx, m_bx, m_chi2x, m_errsx, m_errbx, m_covbsx ); - LinearFitXZ( false, m_points, nHits(), m_sy, m_by, m_chi2y, m_errsy, m_errby, m_covbsy ); - if ( m_chi2x > -1.f && m_chi2y > -1.f ) - return true; - else - return false; + m_resultXZ = linearFitImpl<MuonPositionClass, FitMode::XZ>( m_points ); + m_resultYZ = linearFitImpl<MuonPositionClass, FitMode::YZ>( m_points, m_yAt0Err ); + return m_resultXZ.chi2ndof > -1.f && m_resultYZ.chi2ndof > -1.f; }; - inline double chi2x() const { return m_chi2x; } /// chi2/dof XZ - inline double chi2y() const { return m_chi2y; } /// chi2/dof YZ + inline double chi2x() const { return m_resultXZ.chi2ndof; } /// chi2/dof XZ + inline double chi2y() const { return m_resultYZ.chi2ndof; } /// chi2/dof YZ // slope XZ - inline double sx() const { return m_sx; } + inline double sx() const { return m_resultXZ.slope; } // intercept XZ - inline double bx() const { return m_bx; } + inline double bx() const { return m_resultXZ.trunc; } // slope YZ - inline double sy() const { return m_sy; } + inline double sy() const { return m_resultYZ.slope; } // intercept YZ - inline double by() const { return m_by; } + inline double by() const { return m_resultYZ.trunc; } // errors on the above parameters - inline double errsx() const { return m_errsx; } - inline double errbx() const { return m_errbx; } - inline double covbsx() const { return m_covbsx; } - inline double errsy() const { return m_errsy; } - inline double errby() const { return m_errby; } - inline double covbsy() const { return m_covbsy; } + inline double errsx() const { return m_resultXZ.err_slope; } + inline double errbx() const { return m_resultXZ.err_trunc; } + inline double covbsx() const { return m_resultXZ.cov; } + inline double errsy() const { return m_resultYZ.err_slope; } + inline double errby() const { return m_resultYZ.err_trunc; } + inline double covbsy() const { return m_resultYZ.cov; } - inline void setnHits( int n ) { m_nHits = n; } - inline int nHits() const { return m_nHits; } + inline int nHits() const { return m_points.size(); } private: - std::array<CommonMuonHit, 4> m_points; - unsigned int m_clone; - unsigned int m_nHits; - - float m_chi2x = -1.f; - float m_chi2y = -1.f; - float m_sx = -1.f; - float m_bx = -1.f; - float m_sy = -1.f; - float m_by = -1.f; - float m_errsx = -1.f; - float m_errbx = -1.f; - float m_covbsx = -1.f; - float m_errsy = -1.f; - float m_errby = -1.f; - float m_covbsy = -1.f; + boost::container::small_vector<MuonPositionClass, LHCb::Detector::Muon::nStations> m_points; + bool m_clone; + float m_yAt0Err = std::numeric_limits<float>::max(); + + FitResult m_resultXZ; + FitResult m_resultYZ; };