ATLAS Offline Software
Loading...
Searching...
No Matches
Muon::MuonNSWSegmentFinderTool Class Reference

#include <MuonNSWSegmentFinderTool.h>

Inheritance diagram for Muon::MuonNSWSegmentFinderTool:
Collaboration diagram for Muon::MuonNSWSegmentFinderTool:

Public Types

using SeedMeasurement = NSWSeed::SeedMeasurement
using MeasVec = NSWSeed::MeasVec
using LayerMeasVec = std::vector<MeasVec>
using MuonClusterPtr = std::unique_ptr<const Muon::MuonClusterOnTrack>
using MuonClusterVec = std::vector<MuonClusterPtr>

Public Member Functions

 MuonNSWSegmentFinderTool (const std::string &type, const std::string &name, const IInterface *parent)
 default constructor
virtual ~MuonNSWSegmentFinderTool ()=default
 destructor
virtual StatusCode initialize () override
void find (const EventContext &ctx, SegmentMakingCache &cache) const override
int wedgeNumber (const Muon::MuonClusterOnTrack *cluster) const
int layerNumber (const Muon::MuonClusterOnTrack *cluster) const
int channel (const Muon::MuonClusterOnTrack *cluster) const
 Returns the channel of the measurement on the layer.
const IMuonIdHelperSvcidHelper () const
bool isPad (const Muon::MuonClusterOnTrack *clust) const
bool isStrip (const Muon::MuonClusterOnTrack *clust) const
bool isWire (const Muon::MuonClusterOnTrack *clust) const
template<size_t N>
std::string printSeed (const std::array< SeedMeasurement, N > &seed) const
std::string print (const SeedMeasurement &meas) const
std::string print (const MeasVec &clusters) const
std::string print (const LayerMeasVec &sortedVec) const
ServiceHandle< StoreGateSvc > & evtStore ()
 The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
const ServiceHandle< StoreGateSvc > & detStore () const
 The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
virtual StatusCode sysInitialize () override
 Perform system initialization for an algorithm.
virtual StatusCode sysStart () override
 Handle START transition.
virtual std::vector< Gaudi::DataHandle * > inputHandles () const override
 Return this algorithm's input handles.
virtual std::vector< Gaudi::DataHandle * > outputHandles () const override
 Return this algorithm's output handles.
Gaudi::Details::PropertyBase & declareProperty (Gaudi::Property< T, V, H > &t)
void updateVHKA (Gaudi::Details::PropertyBase &)
MsgStream & msg () const
bool msgLvl (const MSG::Level lvl) const

Static Public Member Functions

static const InterfaceID & interfaceID ()
 access to tool interface

Protected Member Functions

void renounceArray (SG::VarHandleKeyArray &handlesArray)
 remove all handles from I/O resolution
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce (T &h)
void extraDeps_update_handler (Gaudi::Details::PropertyBase &ExtraDeps)
 Add StoreName to extra input/output deps as needed.

Private Types

enum  HitType { Eta = 1 , Phi = 1 << 1 , Wire = 1 << 2 , Pad = 1 << 3 }
enum class  ChannelConstraint { InWindow , TooNarrow , TooWide }
typedef ServiceHandle< StoreGateSvcStoreGateSvc_t

Private Member Functions

std::vector< std::unique_ptr< Muon::MuonSegment > > findStereoSegments (const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &allClusts, int singleWedge=0) const
 Runs the NSW segment maker by combining 4 Micromega layers to a stereo seed.
std::vector< std::unique_ptr< Muon::MuonSegment > > findStgcPrecisionSegments (const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int singleWedge=0) const
 Combines 2 sTgc strip layers to find 2D segments constraining the muon in the eta direction.
std::vector< std::unique_ptr< Muon::MuonSegment > > find3DSegments (const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, std::vector< std::unique_ptr< Muon::MuonSegment > > &etaSegs, int singleWedge=0) const
MeasVec cleanClusters (const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int hit_sel, int singleWedge) const
LayerMeasVec classifyByLayer (const MeasVec &clusters, int hit_sel) const
std::vector< NSWSeedsegmentSeedFromStgc (const LayerMeasVec &orderedClusters, bool usePhi) const
std::vector< NSWSeedsegmentSeedFromMM (const LayerMeasVec &orderedClusters) const
std::vector< NSWSeedsegmentSeedFromMM (const LayerMeasVec &orderedClusters, std::array< unsigned int, 4 > selLayers, unsigned int &trial_counter) const
std::vector< NSWSeedsegmentSeedFromPads (const LayerMeasVec &orderedClusters, const Muon::MuonSegment &etaSeg) const
std::vector< std::pair< double, double > > getPadPhiOverlap (const std::vector< std::vector< const Muon::sTgcPrepData * > > &pads) const
int getClustersOnSegment (const LayerMeasVec &orderedclusters, NSWSeed &seed, const std::set< unsigned int > &exclude, bool useStereo=true) const
MeasVec getCalibratedClusters (NSWSeed &seed) const
bool hitsToTrack (const EventContext &ctx, const MeasVec &etaHitVec, const MeasVec &phiHitVec, const Trk::TrackParameters &startpar, TrackCollection &segTrkColl) const
std::unique_ptr< Trk::PseudoMeasurementOnTrackipConstraint (const EventContext &ctx) const
 creates the IP constraint
std::unique_ptr< Trk::PseudoMeasurementOnTrackcaloConstraint (const Trk::TrackParameters &startpar) const
std::vector< NSWSeedresolveAmbiguities (std::vector< NSWSeed > &&unresolved) const
std::vector< std::unique_ptr< Muon::MuonSegment > > resolveAmbiguities (const EventContext &ctx, const TrackCollection &segColl, const Trk::Segment::Author a) const
std::unique_ptr< Trk::Trackfit (const EventContext &ctx, const std::vector< const Trk::MeasurementBase * > &fit_meas, const Trk::TrackParameters &perigee) const
ChannelConstraint compatiblyFromIP (const SeedMeasurement &meas1, const SeedMeasurement &meas2) const
 Checks whether the two measurements are compatible within the IP constraint.
std::pair< double, double > coveredRadii (const SeedMeasurement &meas) const
 Returns the minimal & maximal radial distance of a measurement.
MeasVec vetoBursts (MeasVec &&clustInLay) const
 Removes clusters from high activity areas in the detector.
Gaudi::Details::PropertyBase & declareGaudiProperty (Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
 specialization for handling Gaudi::Property<SG::VarHandleKey>

Private Attributes

ServiceHandle< IMuonIdHelperSvcm_idHelperSvc
ServiceHandle< IMuonEDMHelperSvcm_edmHelperSvc
ToolHandle< Trk::ITrackAmbiguityProcessorToolm_ambiTool
 Tool for ambiguity solving.
ToolHandle< Trk::ITrackFitterm_slTrackFitter
ToolHandle< IMuonTrackToSegmentToolm_trackToSegmentTool
PublicToolHandle< MuonEDMPrinterToolm_printer
ToolHandle< IMuonTrackCleanerm_trackCleaner
ToolHandle< Trk::ITrackSummaryToolm_trackSummary
ToolHandle< IMuonClusterOnTrackCreatorm_muonClusterCreator {this, "MuonClusterCreator", ""}
Gaudi::Property< bool > m_ipConstraint {this, "IPConstraint", true}
Gaudi::Property< bool > m_caloConstraint {this, "CaloConstraint", false}
 Use a virtual point at the calorimeter exit with same Z as constraint...
Gaudi::Property< double > m_maxClustDist {this, "ClusterDistance", 5.}
Gaudi::Property< int > m_nOfSeedLayers {this, "NOfSeedLayers", 1}
Gaudi::Property< bool > m_useStereoSeeding {this, "SeedMMStereos", true}
Gaudi::Property< bool > m_usesTGCSeeding {this, "SeedWithsTGCS", true}
Gaudi::Property< unsigned int > m_ocupMmBinWidth
 Protection against slobbering Micromega events.
Gaudi::Property< unsigned int > m_ocupMmNumPerBin
Gaudi::Property< unsigned int > m_ocupMmNumPerPair
Gaudi::Property< uintm_maxInputPads {this, "maxInputPads", 40, "Maximum number of pads per wedge layer."}
StoreGateSvc_t m_evtStore
 Pointer to StoreGate (event store by default)
StoreGateSvc_t m_detStore
 Pointer to StoreGate (detector store by default)
std::vector< SG::VarHandleKeyArray * > m_vhka
bool m_varHandleArraysDeclared

Detailed Description

Definition at line 126 of file MuonNSWSegmentFinderTool.h.

Member Typedef Documentation

◆ LayerMeasVec

Definition at line 204 of file MuonNSWSegmentFinderTool.h.

◆ MeasVec

◆ MuonClusterPtr

Definition at line 27 of file IMuonNSWSegmentFinderTool.h.

◆ MuonClusterVec

Definition at line 28 of file IMuonNSWSegmentFinderTool.h.

◆ SeedMeasurement

◆ StoreGateSvc_t

typedef ServiceHandle<StoreGateSvc> AthCommonDataStore< AthCommonMsg< AlgTool > >::StoreGateSvc_t
privateinherited

Definition at line 388 of file AthCommonDataStore.h.

Member Enumeration Documentation

◆ ChannelConstraint

Enumerator
InWindow 
TooNarrow 
TooWide 

Definition at line 298 of file MuonNSWSegmentFinderTool.h.

298 {
299 InWindow,
300 TooNarrow,
301 TooWide
302
303 };

◆ HitType

Constructor & Destructor Documentation

◆ MuonNSWSegmentFinderTool()

Muon::MuonNSWSegmentFinderTool::MuonNSWSegmentFinderTool ( const std::string & type,
const std::string & name,
const IInterface * parent )

default constructor

Definition at line 256 of file MuonNSWSegmentFinderTool.cxx.

256 :
257 AthAlgTool(type, name, parent) {
258 declareInterface<IMuonNSWSegmentFinderTool>(this);
259 }
AthAlgTool()
Default constructor:

◆ ~MuonNSWSegmentFinderTool()

virtual Muon::MuonNSWSegmentFinderTool::~MuonNSWSegmentFinderTool ( )
virtualdefault

destructor

Member Function Documentation

◆ caloConstraint()

std::unique_ptr< Trk::PseudoMeasurementOnTrack > Muon::MuonNSWSegmentFinderTool::caloConstraint ( const Trk::TrackParameters & startpar) const
private

Definition at line 701 of file MuonNSWSegmentFinderTool.cxx.

701 {
702 if (!m_caloConstraint) return nullptr;
703 constexpr double errVtx{1.*Gaudi::Units::m};
704 Amg::MatrixX covVtx(2,2);
705 covVtx.setIdentity();
706 covVtx = errVtx * errVtx * covVtx;
707 const Amg::Vector3D parPos{startpar.position()};
708 Amg::Vector3D projection{parPos.x(), parPos.y(), 0};
709 // project
710 Trk::PerigeeSurface perVtx(projection);
711 return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX),
713 std::move(covVtx),
714 std::move(perVtx));
715
716 }
Gaudi::Property< bool > m_caloConstraint
Use a virtual point at the calorimeter exit with same Z as constraint...
const Amg::Vector3D & position() const
Access method for the position.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 3, 1 > Vector3D
@ locY
local cartesian
Definition ParamDefs.h:38
@ locX
Definition ParamDefs.h:37
std::pair< double, ParamDefs > DefinedParameter
Typedef to of a std::pair<double, ParamDefs> to identify a passed-through double as a specific type o...

◆ channel()

int Muon::MuonNSWSegmentFinderTool::channel ( const Muon::MuonClusterOnTrack * cluster) const

Returns the channel of the measurement on the layer.

Definition at line 953 of file MuonNSWSegmentFinderTool.cxx.

953 {
954 if (m_idHelperSvc->isMM(cluster->identify())) return m_idHelperSvc->mmIdHelper().channel(cluster->identify());
955 if (m_idHelperSvc->issTgc(cluster->identify())) return m_idHelperSvc->stgcIdHelper().channel(cluster->identify());
956 return -1;
957 }
ServiceHandle< IMuonIdHelperSvc > m_idHelperSvc
Identifier identify() const
return the identifier -extends MeasurementBase

◆ classifyByLayer()

MuonNSWSegmentFinderTool::LayerMeasVec Muon::MuonNSWSegmentFinderTool::classifyByLayer ( const MeasVec & clusters,
int hit_sel ) const
private

Definition at line 819 of file MuonNSWSegmentFinderTool.cxx.

820 {
821 // Classifies clusters by layer, starting from the layer closest to the IP and moving outwards.
822 // "clusters" is expected to contain only eta (MM+sTGC strip) or only phi hits (sTGC pads XOR wires).
823 // The returned vector contains only layers that have hits.
824
825 LayerMeasVec orderedClusters(16);
826 std::array<std::set<Identifier>,16> used_hits{};
827 int nBad{0};
828 for (const Muon::MuonClusterOnTrack* hit : clusters) {
829 const int iorder = layerNumber(hit);
830 if (iorder < 0) {
831 ++nBad;
832 continue;
833 }
834 const Identifier id = hit->identify();
835 if (m_idHelperSvc->issTgc(id)) {
836 const int channelType = m_idHelperSvc->stgcIdHelper().channelType(id);
837 // skip sTGC pads if using wires, or skip wires if using pads
838 if (!(hit_sel & HitType::Pad) && channelType == sTgcIdHelper::Pad) continue;
839 if (!(hit_sel & HitType::Wire) && channelType == sTgcIdHelper::Wire) continue;
840 }
841 std::set<Identifier>& lay_hits = used_hits[iorder];
842 if (lay_hits.count(id)) continue;
843 lay_hits.insert(id);
844 orderedClusters[iorder].emplace_back(hit);
845 }
846 if (nBad) ATH_MSG_WARNING("Unable to classify " << nBad << " clusters by their layer since they are neither MM nor sTGC");
847
848 // Erase layers without hits
849 orderedClusters.erase(std::remove_if(orderedClusters.begin(), orderedClusters.end(),
850 [](const MeasVec& vec) { return vec.empty(); }),
851 orderedClusters.end());
852
853
854 for( MeasVec& lays: orderedClusters){
855 std::sort(lays.begin(),lays.end(), [this](const SeedMeasurement& a, const SeedMeasurement& b){
856 return channel(a) < channel(b);
857 });
858 ATH_MSG_DEBUG("Found in layer "<<m_idHelperSvc->toStringDetEl(lays[0]->identify())<<" "<<lays.size()<<" clusters");
859
860
861 }
862 ATH_MSG_VERBOSE("Collected clusters "<<print(orderedClusters));
863
864 return orderedClusters;
865 }
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
std::vector< size_t > vec
static Double_t a
int layerNumber(const Muon::MuonClusterOnTrack *cluster) const
std::string print(const SeedMeasurement &meas) const
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.

◆ cleanClusters()

MeasVec Muon::MuonNSWSegmentFinderTool::cleanClusters ( const std::vector< const Muon::MuonClusterOnTrack * > & MuonClusters,
int hit_sel,
int singleWedge ) const
private

Definition at line 799 of file MuonNSWSegmentFinderTool.cxx.

800 {
801 // Keep only eta (MM && sTGC) or phi (sTGC) clusters
802 // In single-wedge mode keep only clusters from the requested wedge
804 clusters.reserve(muonClusters.size());
805 for (const Muon::MuonClusterOnTrack* cluster : muonClusters) {
806 if (!cluster) continue;
807 if (singleWedge && singleWedge != wedgeNumber(cluster)) continue;
808 const Identifier id = cluster->identify();
809 if (((hit_sel & HitType::Eta) && !m_idHelperSvc->measuresPhi(id)) ||
810 ((hit_sel & HitType::Phi) && m_idHelperSvc->measuresPhi(id)))
811 clusters.emplace_back(cluster);
812 }
813
814 ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() );
815 return clusters;
816 }
int wedgeNumber(const Muon::MuonClusterOnTrack *cluster) const

◆ compatiblyFromIP()

MuonNSWSegmentFinderTool::ChannelConstraint Muon::MuonNSWSegmentFinderTool::compatiblyFromIP ( const SeedMeasurement & meas1,
const SeedMeasurement & meas2 ) const
inlineprivate

Checks whether the two measurements are compatible within the IP constraint.

direction of final segment is well compatible with the IP cut

Use the Identity that 1./sinh(eta) = tan(theta) https://www.wolframalpha.com/input?i=1.%2Fsinh%28-ln%28tan%28x%2F2%29%29%29+-+tan%28x%29 Add another 0.25 as safety margin

Calculate the transverse radii at the edges of the

Definition at line 1370 of file MuonNSWSegmentFinderTool.cxx.

1370 {
1372
1373 // For a given dZ the measurements can only be separated by a certain dR such that the
1375 const double dZ = std::abs(meas2->globalPosition().z()) -
1376 std::abs(meas1->globalPosition().z());
1377
1381 static const double minTanTheta = 0.75 / std::sinh(maxEtaNSW);
1382 static const double maxTanTheta = 1.25 / std::sinh(minEtaNSW);
1383
1384 const double minDR = minTanTheta * std::abs(dZ);
1385 const double maxDR = maxTanTheta * std::abs(dZ);
1386
1387 const std::pair<double, double> rad1 = coveredRadii(meas1);
1388 const std::pair<double, double> rad2 = coveredRadii(meas2);
1390 const double dlR = rad2.first - rad1.first;
1391 const double drR = rad2.second - rad1.second;
1392 ATH_MSG_VERBOSE("compatiblyFromIP() -- Measurements "<<std::endl
1393 <<print(meas1)<<std::endl<<print(meas2)
1394 <<std::endl<<". Separation in dR (left/right) "<<dlR<<"/"<<drR<<", dZ "<<dZ
1395 <<" --> dR has to be in "<<minDR<<" "<<maxDR);
1396 if ((std::abs(dlR) < minDR && std::abs(drR) < minDR) ||
1397 (dZ > 0 && dlR <0 && drR <0) || (dZ < 0 && dlR >0 && drR > 0)) {
1399 } if (std::abs(dlR) > maxDR && std::abs(drR) > maxDR && dlR * drR > 0.){
1401 }
1403 }
std::pair< double, double > coveredRadii(const SeedMeasurement &meas) const
Returns the minimal & maximal radial distance of a measurement.

◆ coveredRadii()

std::pair< double, double > Muon::MuonNSWSegmentFinderTool::coveredRadii ( const SeedMeasurement & meas) const
inlineprivate

Returns the minimal & maximal radial distance of a measurement.

Definition at line 1404 of file MuonNSWSegmentFinderTool.cxx.

1404 {
1405 const MuonGM::MuonChannelDesign* design = getDesign(meas);
1406 const int chNum = channel(meas);
1407 Amg::Vector2D left{Amg::Vector2D::Zero()}, right{Amg::Vector2D::Zero()};
1408 design->leftEdge(chNum, left);
1409 design->rightEdge(chNum, right);
1410 const double radLeft{meas->associatedSurface().localToGlobal(left).perp()};
1411 const double radRight{meas->associatedSurface().localToGlobal(right).perp()};
1412 return std::make_pair(radLeft, radRight);
1413 }
int channel(const Muon::MuonClusterOnTrack *cluster) const
Returns the channel of the measurement on the layer.
Eigen::Matrix< double, 2, 1 > Vector2D
bool leftEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the left edge of the strip.
bool rightEdge(int channel, Amg::Vector2D &pos) const
STRIPS ONLY: Returns the right edge of the strip.

◆ declareGaudiProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< AlgTool > >::declareGaudiProperty ( Gaudi::Property< T, V, H > & hndl,
const SG::VarHandleKeyType &  )
inlineprivateinherited

specialization for handling Gaudi::Property<SG::VarHandleKey>

Definition at line 156 of file AthCommonDataStore.h.

158 {
160 hndl.value(),
161 hndl.documentation());
162
163 }
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)

◆ declareProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty ( Gaudi::Property< T, V, H > & t)
inlineinherited

Definition at line 145 of file AthCommonDataStore.h.

145 {
146 typedef typename SG::HandleClassifier<T>::type htype;
148 }
Gaudi::Details::PropertyBase & declareGaudiProperty(Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
specialization for handling Gaudi::Property<SG::VarHandleKey>

◆ detStore()

const ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< AlgTool > >::detStore ( ) const
inlineinherited

The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 95 of file AthCommonDataStore.h.

◆ evtStore()

ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< AlgTool > >::evtStore ( )
inlineinherited

The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 85 of file AthCommonDataStore.h.

◆ extraDeps_update_handler()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::extraDeps_update_handler ( Gaudi::Details::PropertyBase & ExtraDeps)
protectedinherited

Add StoreName to extra input/output deps as needed.

use the logic of the VarHandleKey to parse the DataObjID keys supplied via the ExtraInputs and ExtraOuputs Properties to add the StoreName if it's not explicitly given

◆ find()

void Muon::MuonNSWSegmentFinderTool::find ( const EventContext & ctx,
SegmentMakingCache & cache ) const
overridevirtual

Remove all stereo segment hits from further processing

All segments

Single wedge segments. Important for the alignment runs

Loop over the 4 quads to create the segment container

The micromegas need 4 hits on track

Create the perigee parameter

Create the segment

Implements Muon::IMuonNSWSegmentFinderTool.

Definition at line 283 of file MuonNSWSegmentFinderTool.cxx.

283 {
284
285 std::vector<const Muon::MuonClusterOnTrack*> muonClusters{};
286 muonClusters.reserve(cache.inputClust.size());
287 std::transform(cache.inputClust.begin(), cache.inputClust.end(), std::back_inserter(muonClusters),
288 [](const std::unique_ptr<const MuonClusterOnTrack>& cl){return cl.get();});
289 ATH_MSG_DEBUG("Entering MuonNSWSegmentFinderTool with " << muonClusters.size() << " clusters to be fit");
290
291 // Find segments using the MM strips as a seed
292 MuonSegmentVec out_segments{};
293 {
294 MuonSegmentVec stereoSegs = findStereoSegments(ctx, muonClusters, 0);
295 ATH_MSG_VERBOSE("Found " << stereoSegs.size() << " MMG stereo seeded segments");
296 out_segments.insert(out_segments.end(), std::make_move_iterator(stereoSegs.begin()),
297 std::make_move_iterator(stereoSegs.end()));
298 }
299
300 // Push back mm seded segments and cache used hits
301 auto dump_output = [&]() {
302 cache.constructedSegs.reserve(cache.constructedSegs.size() + out_segments.size());
303 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
304 for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
305 const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
306 if (clus) cache.usedHits.insert(clus->identify());
307 }
308 cache.constructedSegs.push_back(std::move(seg));
309 }
310 };
311
312 std::vector<const Muon::MuonClusterOnTrack*> clustPostStereo{};
314 std::array<std::set<Identifier>, 16> masked_segs{};
315 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
316 for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
317 const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
318 if (clus) masked_segs[layerNumber(clus)].insert(clus->identify());
319 }
320 }
321
322 // Create new vector of clusters excluding the ones used in the mm seeded segments
323 if (!out_segments.empty()) {
324 clustPostStereo.reserve(muonClusters.size());
325 for (const Muon::MuonClusterOnTrack* clus : muonClusters) {
326 if (!masked_segs[layerNumber(clus)].count(clus->identify())) clustPostStereo.push_back(clus);
327 }
328 }
329
330 // If we did not find any mm seeded segments use the full hit vector to build stgc seeded segments
331 // otherwise use the ones that did not make it onto a segment yet
332 const std::vector<const Muon::MuonClusterOnTrack*>& segmentInput = !out_segments.empty() ? clustPostStereo : muonClusters;
333
335 {
336 MuonSegmentVec etaSegs = findStgcPrecisionSegments(ctx, segmentInput);
337 ATH_MSG_VERBOSE("Found " << etaSegs.size() << " stgc seeded eta segments");
338 MuonSegmentVec precSegs = find3DSegments(ctx, segmentInput, etaSegs);
339 ATH_MSG_VERBOSE("Found " << precSegs.size() << " 3D segments");
340 out_segments.insert(out_segments.end(),
341 std::make_move_iterator(precSegs.begin()),
342 std::make_move_iterator(precSegs.end()));
343 }
344
345
346
347 if (!cache.buildQuads) {
348 dump_output();
349 return;
350 }
352 for (std::unique_ptr<Muon::MuonSegment>& seg : out_segments) {
353 std::vector<const MuonClusterOnTrack*> seg_hits{};
354 seg_hits.reserve(seg->containedMeasurements().size());
355 for (const Trk::MeasurementBase* meas : seg->containedMeasurements()) {
356 const Muon::MuonClusterOnTrack* clus = dynamic_cast<const Muon::MuonClusterOnTrack*>(meas);
357 if (clus) seg_hits.push_back(clus);
358 }
360 for (int iWedge{1}; iWedge<=4 ; ++iWedge) {
361 MeasVec quad_hits = cleanClusters(seg_hits, HitType::Eta | HitType::Phi, iWedge);
363 if ( quad_hits.size () < 2 || ((iWedge == 2 || iWedge == 3) && quad_hits.size() < 4)) continue;
364 std::vector<const Trk::MeasurementBase*> fit_meas{};
365 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
366 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
367 std::copy(quad_hits.begin(), quad_hits.end(), std::back_inserter(fit_meas));
369 const Trk::Surface& surf = quad_hits.front()->associatedSurface();
370 Trk::Intersection intersect = surf.straightLineIntersection(seg->globalPosition(), seg->globalDirection(), false, false);
371 const Amg::Vector3D& gpos_seg = intersect.position;
372 Amg::Vector3D gdir_seg{seg->globalDirection()};
373 Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
374 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
375 Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
377 std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
378 if (!segtrack) continue;
379
380 std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *segtrack)};
381 if (seg) {
382 ATH_MSG_VERBOSE(" adding new quad segment " << m_printer->print(*seg) << std::endl
383 <<"position: "<<to_string(seg->globalPosition())<< std::endl
384 <<"direction: "<<to_string(seg->globalDirection())<< std::endl
385 << m_printer->print(seg->containedMeasurements()));
386 seg->setAuthor(Trk::Segment::NswQuadAlign);
387 cache.quadSegs.emplace_back(std::move(seg));
388 }
389 }
390 }
391 dump_output();
392 }
static std::string to_string(const std::vector< T > &v)
MeasVec cleanClusters(const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int hit_sel, int singleWedge) const
std::vector< std::unique_ptr< Muon::MuonSegment > > findStereoSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &allClusts, int singleWedge=0) const
Runs the NSW segment maker by combining 4 Micromega layers to a stereo seed.
std::vector< std::unique_ptr< Muon::MuonSegment > > findStgcPrecisionSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, int singleWedge=0) const
Combines 2 sTgc strip layers to find 2D segments constraining the muon in the eta direction.
std::unique_ptr< Trk::PseudoMeasurementOnTrack > ipConstraint(const EventContext &ctx) const
creates the IP constraint
PublicToolHandle< MuonEDMPrinterTool > m_printer
ToolHandle< IMuonTrackToSegmentTool > m_trackToSegmentTool
std::unique_ptr< Trk::Track > fit(const EventContext &ctx, const std::vector< const Trk::MeasurementBase * > &fit_meas, const Trk::TrackParameters &perigee) const
std::vector< std::unique_ptr< Muon::MuonSegment > > find3DSegments(const EventContext &ctx, const std::vector< const Muon::MuonClusterOnTrack * > &MuonClusters, std::vector< std::unique_ptr< Muon::MuonSegment > > &etaSegs, int singleWedge=0) const
Intersection straightLineIntersection(const T &pars, bool forceDir=false, const Trk::BoundaryCheck &bchk=false) const
fst straight line intersection schema - templated for charged and neutral parameters
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee

◆ find3DSegments()

MuonSegmentVec Muon::MuonNSWSegmentFinderTool::find3DSegments ( const EventContext & ctx,
const std::vector< const Muon::MuonClusterOnTrack * > & MuonClusters,
std::vector< std::unique_ptr< Muon::MuonSegment > > & etaSegs,
int singleWedge = 0 ) const
private

1 - All micromega layers have ideally been consumed. Try the seeding from the phi wires.

Definition at line 581 of file MuonNSWSegmentFinderTool.cxx.

584 {
585 MuonSegmentVec segments{};
586 // cluster cleaning #1; select only phi hits (must be from all wedges, in order to phi-seed)
587
588 ATH_MSG_DEBUG("Cleaning phi clusters in stgc seeded 3D segments ");
589 MeasVec phiClusters = cleanClusters(muonClusters, HitType::Phi | HitType::Wire, singleWedge);
590 ATH_MSG_DEBUG("After hit cleaning, there are " << phiClusters.size() << " phi clusters to be fit");
591
592
593 // classify the phi clusters by layer
594 LayerMeasVec orderedWireClusters = classifyByLayer(phiClusters, HitType::Wire);
595 LayerMeasVec orderedPadClusters = classifyByLayer(phiClusters, HitType::Pad); // pads only
596 if (orderedWireClusters.size() + orderedPadClusters.size() < 2) {
597 ATH_MSG_DEBUG("Not enough phi hits present, cannot perform the 3D fit!");
598 segments.insert(segments.end(), std::make_move_iterator(etaSegs.begin()), std::make_move_iterator(etaSegs.end()));
599 return segments;
600 }
601
602 // cluster cleaning #2; select only eta hits
603 ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 3D segments ");
604 MeasVec etaClusters = cleanClusters(muonClusters, HitType::Eta, singleWedge);
605 LayerMeasVec orderedEtaClusters = classifyByLayer(etaClusters, HitType::Eta);
606
607 // loop on eta segments
608 bool triedWireSeed{false}; // wire seeds need to be retrieved only once (the first time they are needed)
609 std::vector<NSWSeed> seeds_WiresSTGC;
611 // Loop on eta segments
612 for (std::unique_ptr<Muon::MuonSegment>& etaSeg : etaSegs) {
613 bool is3Dseg{false};
614 NSWSeed seed2D{this, *etaSeg};
615 getClustersOnSegment(orderedEtaClusters, seed2D, {}); // eta clusters
616
617 std::vector<NSWSeed> seeds;
620 if (std::abs(etaSeg->globalPosition().eta()) < 2.4) {
621 if (!triedWireSeed) {
622 // wire seeds need to be retrieved only once (they don't depend on the eta segment)
623 triedWireSeed = true;
624 seeds_WiresSTGC = segmentSeedFromStgc(orderedWireClusters, true);
625 }
626
627 if (!seeds_WiresSTGC.empty()) {
628 seeds = seeds_WiresSTGC;
629 ATH_MSG_DEBUG(" Seeding from sTGC wires");
630 }
631 }
632
633 // 3 - last resort, try sTGC pads
634 if (seeds.empty() ) {
635
636 // only perform seeding with layers that have less than m_maxInputPads hits
637 LayerMeasVec orderedPadClustersForSeeding;
638 std::ranges::copy_if(orderedPadClusters,
639 std::back_inserter(orderedPadClustersForSeeding),
640 [this](const MeasVec& vec) { return vec.size() < m_maxInputPads; });
641
642 seeds = segmentSeedFromPads(orderedPadClustersForSeeding, *etaSeg);
643 ATH_MSG_DEBUG(" Seeding from sTGC pads");
644 }
645
646 // Loop on phi seeds
647 MeasVec phiHitVec;
648 const Trk::PlaneSurface& etaSegSurf = etaSeg->associatedSurface();
649 double etaSegLocX = etaSeg->localParameters()[Trk::locX];
650 double etaSegLocXZ = etaSeg->localDirection().angleXZ();
651
652 for (NSWSeed& seed : seeds) {
653 // calculate start parameters for the fit
654 // combine the local position and direction of the eta-seed (segment)
655 // and local position and direction of the phi-seed to generate 3D starting parameters
656 Trk::Intersection intersect = etaSegSurf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
657 Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
658 Trk::LocalDirection ldir_seed{};
659 etaSegSurf.globalToLocal(intersect.position, intersect.position, lpos_seed);
660 etaSegSurf.globalToLocalDirection(seed.dir(), ldir_seed);
661
662 Amg::Vector2D lpos_seg(etaSegLocX, lpos_seed[Trk::locY]);
663 Trk::LocalDirection ldir_seg(etaSegLocXZ, ldir_seed.angleYZ());
664
665 Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
666 etaSegSurf.localToGlobal(lpos_seg, gpos_seg, gpos_seg);
667 etaSegSurf.localToGlobalDirection(ldir_seg, gdir_seg);
668
669 Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
670 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
671 const Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
672
673 NSWSeed seed3D{this, perpos, gdir_seg};
674
675 // gather phi hits aligned with the segment
676 int nPhiHits = getClustersOnSegment(orderedPadClusters, seed3D,{}); // add pad hits (from the requested wedge if any)
677 nPhiHits += getClustersOnSegment(orderedWireClusters, seed3D, {}); // add wire hits (from the requested wedge if any)
678 if (nPhiHits < 2) continue; // at least two phi hits
679
680 MeasVec phiHitVec = seed3D.measurements();
681 // calibrate the eta hits
682 MeasVec etaHitsCalibrated = getCalibratedClusters(seed2D);
683
684 // fit
685 if (hitsToTrack(ctx, etaHitsCalibrated, phiHitVec, startpar, segTrkColl)) {
686 is3Dseg = true;
687 ATH_MSG_VERBOSE("Segment successfully fitted for wedge "<<singleWedge<<std::endl<<
688 m_printer->print(*segTrkColl.back()));
689 }
690 } // end loop on phi seeds
691
692 // if we failed to combine the eta segment with phi measurements,
693 // just add the eta segment to the collection.
694 if (!is3Dseg) { segments.push_back(std::move(etaSeg)); }
695 } // end loop on precision plane segments
696 MuonSegmentVec new_segs = resolveAmbiguities(ctx, segTrkColl, Trk::Segment::NswStgcSeeded);
697 segments.insert(segments.end(), std::make_move_iterator(new_segs.begin()), std::make_move_iterator(new_segs.end()));
698 return segments;
699 }
DataVector< Trk::Track > TrackCollection
This typedef represents a collection of Trk::Track objects.
const T * back() const
Access the last element in the collection as an rvalue.
bool hitsToTrack(const EventContext &ctx, const MeasVec &etaHitVec, const MeasVec &phiHitVec, const Trk::TrackParameters &startpar, TrackCollection &segTrkColl) const
MeasVec getCalibratedClusters(NSWSeed &seed) const
std::vector< NSWSeed > resolveAmbiguities(std::vector< NSWSeed > &&unresolved) const
std::vector< NSWSeed > segmentSeedFromPads(const LayerMeasVec &orderedClusters, const Muon::MuonSegment &etaSeg) const
std::vector< NSWSeed > segmentSeedFromStgc(const LayerMeasVec &orderedClusters, bool usePhi) const
LayerMeasVec classifyByLayer(const MeasVec &clusters, int hit_sel) const
int getClustersOnSegment(const LayerMeasVec &orderedclusters, NSWSeed &seed, const std::set< unsigned int > &exclude, bool useStereo=true) const
double angleYZ() const
access method for angle of local YZ projection
void localToGlobalDirection(const Trk::LocalDirection &locdir, Amg::Vector3D &globdir) const
This method transforms a local direction wrt the plane to a global direction.
virtual void localToGlobal(const Amg::Vector2D &locp, const Amg::Vector3D &mom, Amg::Vector3D &glob) const override final
Specified for PlaneSurface: LocalToGlobal method without dynamic memory allocation.
virtual Intersection straightLineIntersection(const Amg::Vector3D &pos, const Amg::Vector3D &dir, bool forceDir, Trk::BoundaryCheck bchk) const override final
fast straight line intersection schema - standard: provides closest intersection and (signed) path le...
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for PlaneSurface: GlobalToLocal method without dynamic memory allocation - boolean checks i...
void globalToLocalDirection(const Amg::Vector3D &glodir, Trk::LocalDirection &locdir) const
This method transforms the global direction to a local direction wrt the plane.
@ OWN_ELEMENTS
this data object owns its elements

◆ findStereoSegments()

MuonSegmentVec Muon::MuonNSWSegmentFinderTool::findStereoSegments ( const EventContext & ctx,
const std::vector< const Muon::MuonClusterOnTrack * > & allClusts,
int singleWedge = 0 ) const
private

Runs the NSW segment maker by combining 4 Micromega layers to a stereo seed.

Subsequentally, the hits on the hit road are added to the seeed and the segment is fitted

Parameters
ctxEventContext
allClustsCollection of all EventContext objects
singleWedge0 (use all 4 multiplets) 2/3
Returns

Order any parsed hit into the layer structure

Loop over the seeds

Require that the seed has at least one extra hit, if we're not restricting ourselves to a single wedge

Craete the perigee parameter

Create the segment

Definition at line 393 of file MuonNSWSegmentFinderTool.cxx.

395 {
396
397 if (!m_useStereoSeeding){
398 ATH_MSG_VERBOSE("MMStereoSeeding disabled!");
399 return {};
400 }
401
402 ATH_MSG_VERBOSE("Running MMStereoSeeding");
404 LayerMeasVec orderedClust =
406
407 for (MeasVec& hitsInLayer : orderedClust) hitsInLayer = vetoBursts(std::move(hitsInLayer));
408 orderedClust.erase(std::remove_if(orderedClust.begin(), orderedClust.end(),
409 [](const MeasVec& vec) { return vec.empty(); }),
410 orderedClust.end());
411 if (orderedClust.empty()) return {};
412
413
414 std::vector<NSWSeed> seeds = segmentSeedFromMM(orderedClust);
415 ATH_MSG_DEBUG("Retrieved " << seeds.size() << " seeds in the MMStereoAlg after the ambiguity resolution" );
416
417 if (seeds.empty()) return {};
420 for (NSWSeed& seed : seeds) {
423 std::vector<const Trk::MeasurementBase*> fit_meas{};
424
425 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)};
426 if (pseudoVtx) fit_meas.push_back(pseudoVtx.get());
427 MeasVec calib_clust = getCalibratedClusters(seed);
428 std::copy(calib_clust.begin(), calib_clust.end(), std::back_inserter(fit_meas));
430 const Trk::Surface& surf = calib_clust.front()->associatedSurface();
431
432 Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
433 const Amg::Vector3D& gpos_seg = intersect.position;
434 Amg::Vector3D gdir_seg{seed.dir()};
435 Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
436 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
437
438 Trk::Perigee startpar{perpos, gdir_seg, 0, perpos};
439
441 std::unique_ptr<Trk::Track> segtrack = fit(ctx, fit_meas, startpar);
442 if (segtrack) trackSegs.push_back(std::move(segtrack));
443 }
445 }
value_type push_back(value_type pElem)
Add an element to the end of the collection.
std::vector< NSWSeed > segmentSeedFromMM(const LayerMeasVec &orderedClusters) const
MeasVec vetoBursts(MeasVec &&clustInLay) const
Removes clusters from high activity areas in the detector.

◆ findStgcPrecisionSegments()

MuonSegmentVec Muon::MuonNSWSegmentFinderTool::findStgcPrecisionSegments ( const EventContext & ctx,
const std::vector< const Muon::MuonClusterOnTrack * > & MuonClusters,
int singleWedge = 0 ) const
private

Combines 2 sTgc strip layers to find 2D segments constraining the muon in the eta direction.

Resolve the ambiguities amongsty the tracks and convert the result

Definition at line 478 of file MuonNSWSegmentFinderTool.cxx.

480 {
481
482 if (!m_usesTGCSeeding){
483 ATH_MSG_VERBOSE("2D sTGC seeding disabled!");
484 return {};
485 }
486
487 ATH_MSG_VERBOSE("Running 2D sTGC seeding");
488
489
490 // clean the muon clusters; select only the eta hits.
491 // in single-wedge mode the eta seeds are retrieved from the specific wedge
492
493 ATH_MSG_DEBUG("Cleaning eta clusters in stgc seeded 2D segments ");
494 MeasVec clusters = cleanClusters(muonClusters, HitType::Eta, singleWedge); // eta hits only
495 ATH_MSG_VERBOSE(" After hit cleaning, there are " << clusters.size() << " precision 2D clusters");
496
497 // classify eta clusters by layer
498 LayerMeasVec orderedClusters = classifyByLayer(clusters, 0);
499
500 if (orderedClusters.size() < 4) return {}; // at least four layers with eta hits (MM and sTGC)
501
502 // create segment seeds
503 std::vector<NSWSeed> seeds = segmentSeedFromStgc(orderedClusters, false);
504 ATH_MSG_DEBUG(" Found " << seeds.size() << " 2D seeds");
505 // Loop on seeds: find all clusters near the seed and try to fit
506 MeasVec etaHitVec, phiHitVec;
508
509 for (NSWSeed& seed : seeds) {
510 if (seed.size() < 4){
511 ATH_MSG_VERBOSE(__func__<<" :"<<__LINE__<< " - Seed size: " << seed.size() << " is below the cut (4)");
512 continue;
513 }
514
515 etaHitVec = seed.measurements();
516 const Trk::PlaneSurface& surf = static_cast<const Trk::PlaneSurface&>(etaHitVec.front()->associatedSurface());
517 // calculate start parameters for the fit
518 // local position and direction of the eta-seed on the surface of the first cluster
519 Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
520 Amg::Vector2D lpos_seed{Amg::Vector2D::Zero()};
521 Trk::LocalDirection ldir_seed{};
522 surf.globalToLocal(intersect.position, intersect.position, lpos_seed);
523 surf.globalToLocalDirection(seed.dir(), ldir_seed);
524
525 // use the seed info to generate start parameters (dummy values for phi)
526 Amg::Vector2D lpos(lpos_seed[Trk::locX], 0.);
527 Trk::LocalDirection ldir(ldir_seed.angleXZ(), -M_PI_2);
528 Amg::Vector3D gpos_seg{Amg::Vector3D::Zero()}, gdir_seg{Amg::Vector3D::Zero()};
529 surf.localToGlobal(lpos, gpos_seg, gpos_seg);
530 surf.localToGlobalDirection(ldir, gdir_seg);
531
532 Amg::Vector3D perpos = gpos_seg - 10 * gdir_seg.unit();
533 if (perpos.dot(gdir_seg) < 0) gdir_seg *= -1;
534 const auto startpar = Trk::Perigee(perpos, gdir_seg, 0, perpos);
535 ATH_MSG_VERBOSE(" start parameter " << perpos << " pp " << startpar.position() << " gd " << gdir_seg.unit() << " pp "
536 << startpar.momentum().unit());
537
538 // fit the hits
539 hitsToTrack(ctx, etaHitVec, phiHitVec, startpar, segTrkColl);
540 }
543 }
double angleXZ() const
access method for angle of local XZ projection

◆ fit()

std::unique_ptr< Trk::Track > Muon::MuonNSWSegmentFinderTool::fit ( const EventContext & ctx,
const std::vector< const Trk::MeasurementBase * > & fit_meas,
const Trk::TrackParameters & perigee ) const
private

Definition at line 447 of file MuonNSWSegmentFinderTool.cxx.

449 {
450 ATH_MSG_DEBUG("Fit segment from (" << to_string(perigee.position())<< " pointing to " <<
451 to_string(perigee.momentum())<<". Contained measurements in candidate: " << std::endl
452 << m_printer->print(fit_meas));
453 std::unique_ptr<Trk::Track> segtrack = m_slTrackFitter->fit(ctx, fit_meas, perigee, false, Trk::nonInteracting);
454 if (!segtrack) {
455 ATH_MSG_DEBUG("Fit failed");
456 return nullptr;
457 }
458 ATH_MSG_VERBOSE("--> Fit succeeded");
459 std::unique_ptr<Trk::Track> cleanedTrack = m_trackCleaner->clean(*segtrack, ctx);
460 if (cleanedTrack && cleanedTrack->perigeeParameters() != segtrack->perigeeParameters()) { segtrack.swap(cleanedTrack); }
461 // quality criteria
462 if (!m_edmHelperSvc->goodTrack(*segtrack, 10)) {
463 if (segtrack->fitQuality()) {
464 ATH_MSG_DEBUG("Segment fit with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
465 << segtrack->fitQuality()->numberDoF());
466 }
467 return nullptr;
468 }
469 // update the track summary and add the track to the collection
470 m_trackSummary->updateTrack(ctx, *segtrack);
471 ATH_MSG_DEBUG("Segment accepted with chi^2/nDoF = " << segtrack->fitQuality()->chiSquared() << "/"
472 << segtrack->fitQuality()->numberDoF());
473 return segtrack;
474 }
ToolHandle< Trk::ITrackSummaryTool > m_trackSummary
ServiceHandle< IMuonEDMHelperSvc > m_edmHelperSvc
ToolHandle< IMuonTrackCleaner > m_trackCleaner
ToolHandle< Trk::ITrackFitter > m_slTrackFitter
const Amg::Vector3D & momentum() const
Access method for the momentum.

◆ getCalibratedClusters()

MeasVec Muon::MuonNSWSegmentFinderTool::getCalibratedClusters ( NSWSeed & seed) const
private

Definition at line 1540 of file MuonNSWSegmentFinderTool.cxx.

1540 {
1541
1542 MeasVec calibratedClusters;
1543 MeasVec clusters = seed.measurements();
1544
1545 // loop on the segment clusters and use the phi of the seed to correct them
1546 for (const SeedMeasurement& clus : clusters) {
1547 std::unique_ptr<const Muon::MuonClusterOnTrack> newClus;
1548
1549 // get the intercept of the seed direction with the cluster surface
1550 const Identifier hitID = clus->identify();
1551 const Trk::Surface& surf = clus->associatedSurface();
1552 Trk::Intersection intersect = surf.straightLineIntersection(seed.pos(), seed.dir(), false, false);
1553
1554 if (m_idHelperSvc->isMM(hitID)) {
1555 // build a new MM cluster on track with correct position
1556 std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1557 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1558 } else if (m_idHelperSvc->issTgc(hitID)) {
1559 // build a new sTGC cluster on track with correct position
1560 std::unique_ptr<const Muon::MuonClusterOnTrack> newClus {m_muonClusterCreator->correct(*clus->prepRawData(), intersect.position, seed.dir())};
1561 calibratedClusters.emplace_back(seed.newCalibClust(std::move(newClus)));
1562 }
1563 }
1564
1565 return calibratedClusters;
1566 }
ToolHandle< IMuonClusterOnTrackCreator > m_muonClusterCreator

◆ getClustersOnSegment()

int Muon::MuonNSWSegmentFinderTool::getClustersOnSegment ( const LayerMeasVec & orderedclusters,
NSWSeed & seed,
const std::set< unsigned int > & exclude,
bool useStereo = true ) const
private

Definition at line 960 of file MuonNSWSegmentFinderTool.cxx.

961 {
962 ATH_MSG_VERBOSE(" getClustersOnSegment: layers " << orderedclusters.size());
963 int nHitsAdded{0};
964
965 for (const MeasVec& surfHits : orderedclusters) {
966 if (exclude.count(layerNumber(surfHits[0]))) continue;
967 // get the best hit candidate on this layer
968
969 for (const SeedMeasurement& hit : surfHits) {
970
971 const Identifier id = hit->identify();
972 const MuonGM::MuonChannelDesign* design = getDesign(hit);
973
974 //In case of the 2D eta stgc seeding we don't want the MMG stereo hits on the segment
975 if ( !useStereo && m_idHelperSvc->isMM(id) && design->hasStereoAngle() ) continue;
976
977 nHitsAdded += seed.add(hit, m_maxClustDist);
978 }
979 }
980 ATH_MSG_VERBOSE(" getClustersOnSegment: returning " << nHitsAdded << " hits ");
981 return nHitsAdded;
982 }
Gaudi::Property< double > m_maxClustDist
std::set< std::string > exclude
list of directories to be excluded
Definition hcg.cxx:98
double hasStereoAngle() const
returns whether the stereo angle is non-zero

◆ getPadPhiOverlap()

std::vector< std::pair< double, double > > Muon::MuonNSWSegmentFinderTool::getPadPhiOverlap ( const std::vector< std::vector< const Muon::sTgcPrepData * > > & pads) const
private

Definition at line 1440 of file MuonNSWSegmentFinderTool.cxx.

1441 {
1442 // 'pads' contains segment hit candidates, classified in four layers (IP or HO).
1443 // Layers are ordered; for IP, the layer with hits that is nearest to
1444 // the IP is first, while for HO, the one furthest from the IP is first.
1445
1446 std::vector<std::vector<double>> padsPhiL, padsPhiR;
1447 std::vector<double> padsPhiC;
1448
1449 // Loop on layers
1450 for (const std::vector<const Muon::sTgcPrepData*>& surfHits : pads) {
1451 // Loop on layer hits
1452 std::vector<double> surfPadsPhiL, surfPadsPhiR;
1453 for (const Muon::sTgcPrepData* prd : surfHits) {
1454 const Identifier id = prd->identify();
1455 const MuonGM::MuonPadDesign* design = prd->detectorElement()->getPadDesign(id);
1456 if (!design) {
1457 ATH_MSG_WARNING("No design available for " << m_idHelperSvc->toString(id));
1458 continue;
1459 }
1460
1461 // Phi boundaries of this pad in local coordinates
1462 const double halfWidthX = 0.5 * design->channelWidth(prd->localPosition(), true);
1463 const double hitPadX = prd->localPosition().x(); // x is in the phi direction
1464
1465 // Reject hit candidates on pads too close (in phi) to any pad kept so far
1466 // (pad fuzziness) to constrain the number of combinations.
1467 bool samePhi = std::find_if(padsPhiC.begin(), padsPhiC.end(), [&hitPadX, &halfWidthX](const double prevPadPhi) {
1468 return std::abs(hitPadX - prevPadPhi) < 0.9 * halfWidthX;
1469 }) != padsPhiC.end();
1470
1471 if (samePhi) continue;
1472
1473 // Store the new pad candidate
1474 surfPadsPhiL.push_back(hitPadX - halfWidthX);
1475 surfPadsPhiR.push_back(hitPadX + halfWidthX);
1476 padsPhiC.push_back(hitPadX);
1477 ATH_MSG_DEBUG(" keep pad id " << m_idHelperSvc->toString(id) << " local x: " << hitPadX << " width: " << halfWidthX);
1478 }
1479
1480 padsPhiL.push_back(std::move(surfPadsPhiL));
1481 padsPhiR.push_back(std::move(surfPadsPhiR));
1482 }
1483
1484 unsigned int nSurf = padsPhiR.size();
1485
1486 // number of combinations we can make out of pads in different layers
1487 // we want to keep combinations of overlapping pads.
1488 unsigned int nCombos{1};
1489 for (const std::vector<double>& surfPadsPhiR : padsPhiR) {
1490 if (!surfPadsPhiR.empty()) nCombos *= surfPadsPhiR.size();
1491 }
1492
1493 std::vector<std::pair<double, double>> phiOverlap;
1494 phiOverlap.reserve(nCombos);
1495
1496 if (nCombos <= 100) {
1497 unsigned int N{nCombos};
1498 for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1499 if (padsPhiR[isurf].empty()) continue;
1500 unsigned int nSurfHits = padsPhiR[isurf].size();
1501 N /= nSurfHits;
1502
1503 for (unsigned int icombo{0}; icombo < nCombos; ++icombo) {
1504 // index of the pad that corresponds to this combination
1505 unsigned int padIdx = (icombo / N) % nSurfHits;
1506 if (isurf == 0) {
1507 // first surface: just add the range of each hit pad
1508 phiOverlap.emplace_back(padsPhiL[isurf][padIdx], padsPhiR[isurf][padIdx]);
1509 } else {
1510 // subsequent surfaces: use staggering to narrow the phi ranges
1511 phiOverlap[icombo].first = std::max(padsPhiL[isurf][padIdx], phiOverlap[icombo].first);
1512 phiOverlap[icombo].second = std::min(padsPhiR[isurf][padIdx], phiOverlap[icombo].second);
1513 }
1514 }
1515 }
1516
1517 // delete bad combinations with xmin > xmax (indicates non overlapping pads)
1518 phiOverlap.erase(std::remove_if(phiOverlap.begin(), phiOverlap.end(),
1519 [](std::pair<double, double>& range) { return range.first >= range.second; }),
1520 phiOverlap.end());
1521 ATH_MSG_DEBUG("Pad seeding - #combinations initial: " << nCombos
1522 << ", after cleaning for non overlapping pads: " << phiOverlap.size());
1523
1524 } else {
1525 // in case combinations are too many, store the phi ranges of individual pads
1526 for (unsigned int isurf{0}; isurf < nSurf; ++isurf) {
1527 unsigned int nSurfHits = padsPhiR[isurf].size();
1528 for (unsigned int ihit{0}; ihit < nSurfHits; ++ihit) {
1529 phiOverlap.emplace_back(padsPhiL[isurf][ihit], padsPhiR[isurf][ihit]);
1530 }
1531 }
1532 ATH_MSG_DEBUG("Pad seeding - #combinations: " << nCombos << " is too large. Seeding from" << phiOverlap.size()
1533 << " individual pads.");
1534 }
1535
1536 return phiOverlap;
1537 }
static const Attributes_t empty
double channelWidth(const Amg::Vector2D &pos, bool measPhi, bool preciseMeas=false) const
calculate local channel width

◆ hitsToTrack()

bool Muon::MuonNSWSegmentFinderTool::hitsToTrack ( const EventContext & ctx,
const MeasVec & etaHitVec,
const MeasVec & phiHitVec,
const Trk::TrackParameters & startpar,
TrackCollection & segTrkColl ) const
private

Definition at line 741 of file MuonNSWSegmentFinderTool.cxx.

745 {
746 // vector of hits for the fit
747 std::vector<const Trk::MeasurementBase*> vecFitPts;
748 unsigned int nHitsEta = etaHitVec.size();
749 unsigned int nHitsPhi = phiHitVec.size();
750 vecFitPts.reserve(nHitsEta + nHitsPhi + 2 + m_ipConstraint + m_caloConstraint);
751
752 std::unique_ptr<Trk::PseudoMeasurementOnTrack> pseudoVtx{ipConstraint(ctx)},
753 pseudoVtxCalo{caloConstraint(startpar)},
754 pseudoPhi1{nullptr}, pseudoPhi2{nullptr};
755 // is chosen, add a pseudo measurement as vtx at the center of ATLAS
756 if (pseudoVtx) { vecFitPts.push_back(pseudoVtx.get()); }
757 if (pseudoVtxCalo) { vecFitPts.push_back(pseudoVtxCalo.get()); }
758
759 if (!nHitsPhi) {
760 // generate two pseudo phi measurements for the fit,
761 // one on the first hit surface and one on the last hit surface.
762
763 Amg::MatrixX cov(1, 1);
764 constexpr double pseudoPrecision = 100 * Gaudi::Units::micrometer;
765 cov(0, 0) = pseudoPrecision;
766 static const Trk::LocalParameters loc_pseudopars{Trk::DefinedParameter(0, Trk::locY)};
767 pseudoPhi1 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
768 Amg::MatrixX(cov),
769 etaHitVec.front()->associatedSurface());
770 pseudoPhi2 = std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(loc_pseudopars),
771 Amg::MatrixX(cov),
772 etaHitVec.back()->associatedSurface());
773
774 // add the first pseudo phi hit, the hit vector, and the second pseudo phi hit
775 vecFitPts.push_back(pseudoPhi1.get());
776 std::copy(etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts));
777 vecFitPts.push_back(pseudoPhi2.get());
778 ATH_MSG_DEBUG("Fitting a 2D-segment track with " << nHitsEta << " Eta hits");
779
780 } else {
781 // sorted eta and sorted phi hits combined (sorted by their the z-coordinate)
782 std::merge(phiHitVec.begin(), phiHitVec.end(), etaHitVec.begin(), etaHitVec.end(), std::back_inserter(vecFitPts),
783 [](const Muon::MuonClusterOnTrack* c1, const Muon::MuonClusterOnTrack* c2) {
784 double z1 = std::abs(c1->detectorElement()->center(c1->identify()).z());
785 double z2 = std::abs(c2->detectorElement()->center(c2->identify()).z());
786 return z1 < z2;
787 });
788 ATH_MSG_DEBUG("Fitting a 3D-segment track with " << nHitsEta << " Eta hits and " << nHitsPhi << " Phi hits");
789 }
790
791 // fit the hits and generate the Trk::Track
792 std::unique_ptr<Trk::Track> segtrack = fit(ctx, vecFitPts, startpar);
793 if (!segtrack) return false;
794 segTrkColl.push_back(std::move(segtrack));
795 return true;
796 }
std::unique_ptr< Trk::PseudoMeasurementOnTrack > caloConstraint(const Trk::TrackParameters &startpar) const

◆ idHelper()

const IMuonIdHelperSvc * Muon::MuonNSWSegmentFinderTool::idHelper ( ) const

Definition at line 281 of file MuonNSWSegmentFinderTool.cxx.

281{ return m_idHelperSvc.get(); }

◆ initialize()

StatusCode Muon::MuonNSWSegmentFinderTool::initialize ( )
overridevirtual

Definition at line 262 of file MuonNSWSegmentFinderTool.cxx.

262 {
263 ATH_CHECK(m_slTrackFitter.retrieve());
264 ATH_CHECK(m_printer.retrieve());
265 ATH_CHECK(m_edmHelperSvc.retrieve());
266 ATH_CHECK(m_ambiTool.retrieve());
268 ATH_CHECK(m_idHelperSvc.retrieve());
269 ATH_CHECK(m_trackCleaner.retrieve());
270 ATH_CHECK(m_trackSummary.retrieve());
273 ATH_MSG_FATAL("The muon should come from the IP && horizontally from the Calo..."<<
274 "We need to place a very good basball player at the calo exit to deflect the muon horizontally.");
275 return StatusCode::FAILURE;
276 }
277 ATH_MSG_DEBUG(" Max cut " << m_maxClustDist);
278 return StatusCode::SUCCESS;
279 }
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
ToolHandle< Trk::ITrackAmbiguityProcessorTool > m_ambiTool
Tool for ambiguity solving.

◆ inputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< AlgTool > >::inputHandles ( ) const
overridevirtualinherited

Return this algorithm's input handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ interfaceID()

const InterfaceID & Muon::IMuonNSWSegmentFinderTool::interfaceID ( )
inlinestaticinherited

access to tool interface

Definition at line 22 of file IMuonNSWSegmentFinderTool.h.

22 {
23 static const InterfaceID IID_IMuonNSWSegmentFinderTool("Muon::IMuonNSWSegmentFinderTool", 1, 0);
24 return IID_IMuonNSWSegmentFinderTool;
25 }

◆ ipConstraint()

std::unique_ptr< Trk::PseudoMeasurementOnTrack > Muon::MuonNSWSegmentFinderTool::ipConstraint ( const EventContext & ctx) const
private

creates the IP constraint

Beamspot constraint?

Definition at line 718 of file MuonNSWSegmentFinderTool.cxx.

718 {
719 if (!m_ipConstraint) return nullptr;
720 constexpr double errVtx{10.*Gaudi::Units::cm};
721 Amg::MatrixX covVtx(1, 1);
722 covVtx(0, 0) = errVtx * errVtx;
724 Trk::PerigeeSurface perVtx(Amg::Vector3D::Zero());
725 return std::make_unique<Trk::PseudoMeasurementOnTrack>(Trk::LocalParameters(Trk::DefinedParameter(0, Trk::locX)), std::move(covVtx),
726 std::move(perVtx));
727 }

◆ isPad()

bool Muon::MuonNSWSegmentFinderTool::isPad ( const Muon::MuonClusterOnTrack * clust) const

Definition at line 728 of file MuonNSWSegmentFinderTool.cxx.

728 {
729 const Identifier id = clust->identify();
730 return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Pad;
731 }

◆ isStrip()

bool Muon::MuonNSWSegmentFinderTool::isStrip ( const Muon::MuonClusterOnTrack * clust) const

Definition at line 732 of file MuonNSWSegmentFinderTool.cxx.

732 {
733 const Identifier id = clust->identify();
734 return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Strip;
735 }

◆ isWire()

bool Muon::MuonNSWSegmentFinderTool::isWire ( const Muon::MuonClusterOnTrack * clust) const

Definition at line 736 of file MuonNSWSegmentFinderTool.cxx.

736 {
737 const Identifier id = clust->identify();
738 return m_idHelperSvc->issTgc(id) && m_idHelperSvc->stgcIdHelper().channelType(id) == sTgcIdHelper::Wire;
739 }

◆ layerNumber()

int Muon::MuonNSWSegmentFinderTool::layerNumber ( const Muon::MuonClusterOnTrack * cluster) const

Definition at line 943 of file MuonNSWSegmentFinderTool.cxx.

943 {
944 // Internal logic. Initialize with 16 layers:
945 // [0-3] for the four sTGC IP layers
946 // [4-11] for the eight MM IP+HO layers (empty when phi hits are requested)
947 // [12-15] for the four sTGC HO layers
948 int layer{0};
949 if (m_idHelperSvc->isMM(cluster->identify())) layer = m_idHelperSvc->mmIdHelper().gasGap(cluster->identify());
950 if (m_idHelperSvc->issTgc(cluster->identify())) layer = m_idHelperSvc->stgcIdHelper().gasGap(cluster->identify());
951 return 4 * (wedgeNumber(cluster) - 1) + layer - 1;
952 }
@ layer
Definition HitInfo.h:79

◆ msg()

MsgStream & AthCommonMsg< AlgTool >::msg ( ) const
inlineinherited

Definition at line 24 of file AthCommonMsg.h.

24 {
25 return this->msgStream();
26 }

◆ msgLvl()

bool AthCommonMsg< AlgTool >::msgLvl ( const MSG::Level lvl) const
inlineinherited

Definition at line 30 of file AthCommonMsg.h.

30 {
31 return this->msgLevel(lvl);
32 }

◆ outputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< AlgTool > >::outputHandles ( ) const
overridevirtualinherited

Return this algorithm's output handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ print() [1/3]

std::string Muon::MuonNSWSegmentFinderTool::print ( const LayerMeasVec & sortedVec) const

Definition at line 1592 of file MuonNSWSegmentFinderTool.cxx.

1592 {
1593 std::stringstream sstr{};
1594 unsigned int lay{0};
1595 for (const MeasVec& clusts: sortedVec){
1596 sstr<<"Clusters in Layer: "<<(lay+1)<<std::endl;
1597 sstr<<"#################################################"<<std::endl;
1598 sstr<<print(clusts);
1599 ++lay;
1600 }
1601 return sstr.str();
1602 }

◆ print() [2/3]

std::string Muon::MuonNSWSegmentFinderTool::print ( const MeasVec & clusters) const

Definition at line 1585 of file MuonNSWSegmentFinderTool.cxx.

1585 {
1586 std::stringstream sstr{};
1587 for (const SeedMeasurement& cl : measurements){
1588 sstr<<" *** "<<print(cl)<<std::endl;
1589 }
1590 return sstr.str();
1591 }

◆ print() [3/3]

std::string Muon::MuonNSWSegmentFinderTool::print ( const SeedMeasurement & meas) const

Definition at line 1578 of file MuonNSWSegmentFinderTool.cxx.

1578 {
1579 std::stringstream sstr{};
1580 sstr << m_idHelperSvc->toString(cl->identify()) << " at " <<to_string(cl.pos())
1581 <<" pointing to (" <<to_string(cl.dir())<<" cluster size: "<<clusterSize(cl);
1582
1583 return sstr.str();
1584 }
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]

◆ printSeed()

template<size_t N>
std::string Muon::MuonNSWSegmentFinderTool::printSeed ( const std::array< SeedMeasurement, N > & seed) const

Definition at line 1570 of file MuonNSWSegmentFinderTool.cxx.

1570 {
1571 std::stringstream sstr{};
1572 sstr << std::endl;
1573 for (const SeedMeasurement& cl : seed) sstr << " *** " << print(cl) << std::endl;
1574 return sstr.str();
1575 }

◆ renounce()

std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > AthCommonDataStore< AthCommonMsg< AlgTool > >::renounce ( T & h)
inlineprotectedinherited

Definition at line 380 of file AthCommonDataStore.h.

381 {
382 h.renounce();
384 }
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)

◆ renounceArray()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::renounceArray ( SG::VarHandleKeyArray & handlesArray)
inlineprotectedinherited

remove all handles from I/O resolution

Definition at line 364 of file AthCommonDataStore.h.

364 {
366 }

◆ resolveAmbiguities() [1/2]

MuonSegmentVec Muon::MuonNSWSegmentFinderTool::resolveAmbiguities ( const EventContext & ctx,
const TrackCollection & segColl,
const Trk::Segment::Author a ) const
private

Definition at line 544 of file MuonNSWSegmentFinderTool.cxx.

546 {
547 if (msgLvl(MSG::DEBUG)) {
548 ATH_MSG_DEBUG("Tracks before ambi solving: ");
549 for (const Trk::Track* trk : segTrkColl) {
550 ATH_MSG_DEBUG(m_printer->print(*trk));
551 const DataVector<const Trk::MeasurementBase>* meas = trk->measurementsOnTrack();
552 if (meas) ATH_MSG_DEBUG(m_printer->print(meas->stdcont()));
553 }
554 }
555
556 MuonSegmentVec segments{};
557 std::unique_ptr<const TrackCollection> resolvedTracks(m_ambiTool->process(&segTrkColl));
558 ATH_MSG_DEBUG("Resolved track candidates: old size " << segTrkColl.size() << " new size " << resolvedTracks->size());
559
560 // store the resolved segments
561 for (const Trk::Track* trk : *resolvedTracks) {
562 const auto* measurements = trk->measurementsOnTrack();
563 const bool has_eta = std::find_if(measurements->begin(), measurements->end(),
564 [this](const Trk::MeasurementBase* meas) {
565 Identifier id = m_edmHelperSvc->getIdentifier(*meas);
566 return id.is_valid() && !m_idHelperSvc->measuresPhi(id);
567 }) != trk->measurementsOnTrack()->end();
568 if (!has_eta) continue;
569 std::unique_ptr<MuonSegment> seg{m_trackToSegmentTool->convert(ctx, *trk)};
570 if (seg) {
571 ATH_MSG_DEBUG(" adding " << m_printer->print(*seg) << std::endl << m_printer->print(seg->containedMeasurements()));
572 seg->setAuthor(a);
573 segments.emplace_back(std::move(seg));
574 } else {
575 ATH_MSG_VERBOSE("Segment conversion failed, no segment created. ");
576 }
577 }
578 return segments;
579 }
bool msgLvl(const MSG::Level lvl) const
const PtrVector & stdcont() const
Return the underlying std::vector of the container.

◆ resolveAmbiguities() [2/2]

std::vector< NSWSeed > Muon::MuonNSWSegmentFinderTool::resolveAmbiguities ( std::vector< NSWSeed > && unresolved) const
private

Definition at line 1414 of file MuonNSWSegmentFinderTool.cxx.

1414 {
1415 std::vector<NSWSeed> seeds;
1416 seeds.reserve(unresolved.size());
1417 std::sort(unresolved.begin(), unresolved.end(),[](const NSWSeed& a, const NSWSeed& b){
1418 return a.chi2() < b.chi2();
1419 });
1420 for (NSWSeed& seed : unresolved) {
1421 bool add_seed{true};
1422 for (NSWSeed& good : seeds) {
1423 NSWSeed::SeedOR ov = good.overlap(seed);
1424 if (ov == NSWSeed::SeedOR::SubSet) {
1425 std::swap(seed, good);
1426 add_seed = false;
1427 break;
1428 } else if (ov == NSWSeed::SeedOR::Same || ov == NSWSeed::SeedOR::SuperSet) {
1429 add_seed = false;
1430 break;
1431 }
1432 }
1433 if (add_seed) seeds.push_back(std::move(seed));
1434 }
1435 ATH_MSG_VERBOSE(seeds.size()<<" out of "<<unresolved.size()<<" passed the overlap removal");
1436 return seeds;
1437 }
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)

◆ segmentSeedFromMM() [1/2]

std::vector< NSWSeed > Muon::MuonNSWSegmentFinderTool::segmentSeedFromMM ( const LayerMeasVec & orderedClusters) const
private

layers 12-15 contain stgcs and are not of interest...

Combinatorics debugging stream

Definition at line 1122 of file MuonNSWSegmentFinderTool.cxx.

1123 {
1124 std::vector<NSWSeed> seeds;
1125 std::array<unsigned int, 4> layers{};
1126 unsigned int trials{0}, used_layers{0};
1128 constexpr size_t lastMMLay = 11;
1129 std::vector<NSWSeed> laySeeds;
1130
1132 std::stringstream sstr{};
1133 for (int e4 = std::min(lastMMLay, orderedClusters.size() -1); e4 >= 3 ; --e4) {
1134 layers[3] = e4;
1135 for (int e3 = e4 -1 ; e3 >= 2; --e3) {
1136 layers[2] = e3;
1137 for (int e2 = 1 ; e2 < e3; ++e2) {
1138 layers[1] = e2;
1139 for (int e1= 0; e1< e2; ++e1) {
1140 layers[0] = e1;
1141 const unsigned int old_trials = trials;
1142 laySeeds = segmentSeedFromMM(orderedClusters,layers, trials);
1143 if (old_trials == trials) continue;
1144
1145 used_layers += !laySeeds.empty();
1146 seeds.insert(seeds.end(), std::make_move_iterator(laySeeds.begin()),
1147 std::make_move_iterator(laySeeds.end()));
1148
1149 if (msgLvl(MSG::VERBOSE)) {
1150 sstr<<" Attempts thus far "<<old_trials<<" attempts now "<<trials<<" --- "<<e1<<","<<e2<<","<<e3<<","<<e4<<std::endl;
1151 for (int lay : layers) {
1152 sstr<<"Layer: "<<lay<<" number of measurements "<<orderedClusters[lay].size()<<std::endl;
1153 for (const SeedMeasurement& meas : orderedClusters[lay] ){
1154 sstr<<" **** "<< print(meas)<<std::endl;
1155 }
1156 sstr<<std::endl<<std::endl<<std::endl;
1157 }
1158 }
1159 }
1160 }
1161 }
1162 }
1163 if (trials > 100000) {
1164 ATH_MSG_VERBOSE(sstr.str());
1165 }
1166 ATH_MSG_VERBOSE("Out of "<<trials<<" possible seeds, "<<seeds.size()<<" were finally built. Used in total "<<used_layers<<" layers");
1167 return resolveAmbiguities(std::move(seeds));
1168 }
layers(flags, cells_name, *args, **kw)
Here we define wrapper functions to set up all of the standard corrections.
double e2(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 2nd sampling
double e1(const xAOD::CaloCluster &cluster)
return the uncorrected cluster energy in 1st sampling

◆ segmentSeedFromMM() [2/2]

std::vector< NSWSeed > Muon::MuonNSWSegmentFinderTool::segmentSeedFromMM ( const LayerMeasVec & orderedClusters,
std::array< unsigned int, 4 > selLayers,
unsigned int & trial_counter ) const
inlineprivate

Determine whether the layer is X(1) / U(2) or V(3)

Order the strips such that the first and second pair consist each of crossing strips

The second pair is parallel

Assign the first measurement of each layer to calculate the linear transformation

Habemus valid strip quartett

Function to calculate the muon crossing

Reserve space for 200 seeds

The two channels are too narrow. Same conclusion holds for all previous hits from this layer combined with the next ones of layer 1

The opening angle of these two channels is just too wide

The first or the second one can cross with the third one

Reject combinations that consist only of 1 strip clusters

We will revise this requirement in the near future. Keep the block for the moment

Definition at line 1173 of file MuonNSWSegmentFinderTool.cxx.

1175 {
1176 std::vector<NSWSeed> seeds{};
1177
1178 std::array<unsigned int, 4> lay_ord{};
1179 for (size_t s = 0; s < selLayers.size(); ++s) {
1180 unsigned int lay = selLayers[s];
1181 const SeedMeasurement& seed = orderedClusters[lay].front();
1182 const Identifier id = seed->identify();
1183 if (!m_idHelperSvc->isMM(id)) return seeds;
1184 const MuonGM::MuonChannelDesign* design = getDesign(seed);
1186 if (!design->hasStereoAngle()) lay_ord[s] = 1;
1187 else if (design->stereoAngle() >0.) lay_ord[s] = 2;
1188 else lay_ord[s] = 3;
1189 }
1190 auto swap_strips = [&selLayers, &lay_ord] (unsigned int i, unsigned j){
1191 std::swap(lay_ord[i], lay_ord[j]);
1192 std::swap(selLayers[i],selLayers[j]);
1193 };
1195 if (lay_ord[0] == lay_ord[1]){
1196 if (lay_ord[1] != lay_ord[2]) swap_strips(1,2);
1197 else if (lay_ord[1] != lay_ord[3]) swap_strips(1,3);
1198 else {
1199 ATH_MSG_VERBOSE("Strips are all parallel.");
1200 return seeds;
1201 }
1202 }
1204 if (lay_ord[2] == lay_ord[3]) {
1205 // Check if the last hit can be exchanged by the first one.
1206 // But also ensure that the second and fourth are not the same
1207 if (lay_ord[3] != lay_ord[0] && lay_ord[3] != lay_ord[1]) swap_strips(3,0);
1208 else {
1209 ATH_MSG_VERBOSE("No way to rearrange the strips such that the latter two strips cross.");
1210 return seeds;
1211 }
1212 }
1214 std::array<SeedMeasurement, 4> base_seed{};
1215 for (size_t s = 0; s < selLayers.size(); ++s) {
1216 unsigned int lay = selLayers[s];
1217 base_seed[s] = orderedClusters[lay].front();
1218 }
1219
1220 const double A = (base_seed[1].pos().z() - base_seed[0].pos().z());
1221 const double G = (base_seed[2].pos().z() - base_seed[0].pos().z());
1222 const double K = (base_seed[3].pos().z() - base_seed[0].pos().z());
1223
1224 AmgSymMatrix(2) diamond{AmgSymMatrix(2)::Zero()};
1225 diamond.block<2, 1>(0, 1) = ((A - G) * base_seed[3].dirDot(base_seed[1]) * base_seed[1].dir() + G * base_seed[3].dirDot(base_seed[0]) * base_seed[0].dir() - A * base_seed[3].dir()).block<2, 1>(0, 0);
1226 diamond.block<2, 1>(0, 0) = ((K - A) * base_seed[2].dirDot(base_seed[1]) * base_seed[1].dir() - K * base_seed[2].dirDot(base_seed[0]) * base_seed[0].dir() + A * base_seed[2].dir()).block<2, 1>(0, 0);
1227
1228 if (std::abs(diamond.determinant()) < std::numeric_limits<float>::epsilon()) {
1229 ATH_MSG_VERBOSE(" The seed built from " << printSeed(base_seed) << " cannot constrain phi as " << std::endl
1230 << diamond << std::endl
1231 << " is singular " << diamond.determinant() << " with rank "
1232 << (Eigen::FullPivLU<AmgSymMatrix(2)>{diamond}.rank()));
1233
1234 return seeds;
1235 }
1236 ATH_MSG_VERBOSE("The combination of " << printSeed(base_seed) << " to " << std::endl
1237 << diamond << std::endl
1238 << "May give a couple of stereo seeds " << diamond.determinant());
1239
1241 const AmgSymMatrix(2) seed_builder = diamond.inverse();
1243 const double KmG = K-G;
1244 const double KmA = K-A;
1245 const double AmG = A-G;
1246
1247 const double TwoDotZero = base_seed[2].dirDot(base_seed[0]);
1248 const double ThreeDotZero = base_seed[3].dirDot(base_seed[0]);
1249 const double ThreeDotOne = base_seed[3].dirDot(base_seed[1]);
1250 const double TwoDotOne = base_seed[2].dirDot(base_seed[1]);
1251
1252 auto estimate_muon = [&] () -> std::optional<std::array<double,2>> {
1253 const Amg::Vector3D Y0 = K * base_seed[2].pos() - G * base_seed[3].pos() - KmG * base_seed[0].pos();
1254 const Amg::Vector3D Y1 = AmG * base_seed[3].pos() - KmG * base_seed[1].pos() + KmA * base_seed[2].pos();
1255 const double Y0dotE0 = base_seed[0].dirDot(Y0);
1256 const double Y1dotE1 = base_seed[1].dirDot(Y1);
1257
1258 const AmgVector(2) centers = (KmG * (base_seed[0].pos() - base_seed[1].pos()) +
1259 Y0dotE0 * base_seed[0].dir() +
1260 A * (base_seed[3].pos() - base_seed[2].pos()) -
1261 Y1dotE1 * base_seed[1].dir())
1262 .block<2, 1>(0, 0);
1263
1264 const AmgVector(2) sol_pars = seed_builder * centers;
1265 const std::array<double, 4> lengths{(Y0dotE0 + K * sol_pars[0] * TwoDotZero - G * sol_pars[1] * ThreeDotZero) / KmG,
1266 (Y1dotE1 + AmG * sol_pars[1] *ThreeDotOne + KmA * sol_pars[0] * TwoDotOne) / KmG, sol_pars[0], sol_pars[1]};
1267 bool accept{true};
1268 ATH_MSG_VERBOSE("Check intersections of "<<printSeed(base_seed));
1269 constexpr double tolerance = 10.* Gaudi::Units::mm;
1270 std::optional<Amg::Vector3D> seg_pos{std::nullopt}, seg_dir{std::nullopt};
1271 for (unsigned int i = 0; i < base_seed.size(); ++i) {
1272 const MuonGM::MuonChannelDesign* design = getDesign(base_seed[i]);
1273 const double halfLength = design->channelHalfLength(channel(base_seed[i]), true);
1274 accept &= (halfLength + tolerance > std::abs(lengths[i]));
1275 if (msgLvl(MSG::VERBOSE)) {
1276 if (!seg_pos) {
1277 seg_pos = std::make_optional<Amg::Vector3D>(base_seed[0].pos() +
1278 lengths[0] * base_seed[0].dir());
1279 ATH_MSG_VERBOSE("Position "<<to_string(*seg_pos));
1280 }
1281 if (!seg_dir){
1282 seg_dir = std::make_optional<Amg::Vector3D>((base_seed[1].pos() +
1283 lengths[1] *base_seed[1].dir() - (*seg_pos)).unit());
1284 ATH_MSG_VERBOSE("Direction "<<to_string(*seg_dir));
1285 }
1286 std::optional<double> mu_crossing = Amg::intersect<3>(*seg_pos, *seg_dir, base_seed[i].pos(),base_seed[i].dir());
1287 ATH_MSG_VERBOSE(" ----- "<<(i+1)<<" at "<<to_string(base_seed[i].pos() + lengths[i]*base_seed[i].dir())
1288 << " ("<< std::string( halfLength > std::abs(lengths[i]) ? "inside" : "outside")<<" wedge) "
1289 << halfLength <<" vs. "<<std::abs(lengths[i])<<" crossing point: "<<std::abs(*mu_crossing));
1290 } else if (!accept) return std::nullopt;
1291 }
1292 if (!accept) return std::nullopt;
1293 return std::make_optional<std::array<double,2>>({lengths[0], lengths[1]});
1294 };
1295
1297 seeds.reserve(200);
1298 MeasVec::const_iterator begin2{orderedClusters[selLayers[1]].begin()};
1299 MeasVec::const_iterator begin3{orderedClusters[selLayers[2]].begin()};
1300 MeasVec::const_iterator begin4{orderedClusters[selLayers[3]].begin()};
1301
1302 const MeasVec::const_iterator end2{orderedClusters[selLayers[1]].end()};
1303 const MeasVec::const_iterator end3{orderedClusters[selLayers[2]].end()};
1304 const MeasVec::const_iterator end4{orderedClusters[selLayers[3]].end()};
1305
1306 for (const SeedMeasurement& lay1 : orderedClusters[selLayers[0]]) {
1307 base_seed[0] = lay1;
1308 for (MeasVec::const_iterator lay2 = begin2; lay2 != end2; ++lay2) {
1309
1310 base_seed[1] = *lay2;
1311 ChannelConstraint chCheck = compatiblyFromIP(lay1, *lay2);
1314 if (chCheck == ChannelConstraint::TooNarrow) {
1315 begin2 = lay2 + 1;
1316 continue;
1317 }
1319 else if (chCheck == ChannelConstraint::TooWide) {
1320 break;
1321 }
1323 for (MeasVec::const_iterator lay3 = begin3; lay3 != end3; ++lay3) {
1324 chCheck = compatiblyFromIP(lay1, *lay3);
1325 const ChannelConstraint chCheck1 = compatiblyFromIP(*lay2, *lay3);
1326 if (chCheck == ChannelConstraint::TooNarrow && chCheck1 == ChannelConstraint::TooNarrow) {
1327 begin3 = lay3 + 1;
1328 continue;
1329 } else if (chCheck == ChannelConstraint::TooWide && chCheck1 == ChannelConstraint::TooWide) {
1330 break;
1331 }
1332 base_seed[2] = *lay3;
1334 for (MeasVec::const_iterator lay4 = begin4 ; lay4 != end4; ++lay4) {
1335 chCheck = compatiblyFromIP(*lay3, *lay4);
1336 if (chCheck == ChannelConstraint::TooNarrow) {
1337 begin4 = lay4 + 1;
1338 continue;
1339 } else if (chCheck == ChannelConstraint::TooWide) {
1340 break;
1341 }
1342
1343 base_seed[3] = (*lay4);
1344 std::optional<std::array<double, 2>> isects = estimate_muon();
1345 ++trial_counter;
1346 if (!isects) continue;
1347 NSWSeed seed{this, base_seed, *isects};
1348
1349 if (seed.size() < 4) continue;
1350 if (m_ipConstraint) {
1351 const double eta = std::abs(seed.dir().eta());
1352 if (eta < minEtaNSW || eta > maxEtaNSW) {
1353 continue;
1354 }
1355 if (seed.dir().block<2,1>(0,0).dot(seed.pos().block<2,1>(0,0)) < 0.) continue;
1357 static const Muon::MuonSectorMapping sector_mapping{};
1358 const double deltaPhi = std::abs(seed.dir().deltaPhi(seed.pos()));
1359 if (deltaPhi > sector_mapping.sectorWidth(m_idHelperSvc->sector(base_seed[0]->identify()))) continue;
1360 }
1361 getClustersOnSegment(orderedClusters, seed, {selLayers[0], selLayers[1],selLayers[2], selLayers[3]});
1362 seeds.emplace_back(std::move(seed));
1363 }
1364 }
1365 }
1366 }
1367 return seeds;
1368 }
Scalar eta() const
pseudorapidity method
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
const PlainObject unit() const
This is a plugin that makes Eigen look like CLHEP & defines some convenience methods.
#define AmgSymMatrix(dim)
#define AmgVector(rows)
#define G(x, y, z)
Definition MD5.cxx:113
#define z
std::string printSeed(const std::array< SeedMeasurement, N > &seed) const
ChannelConstraint compatiblyFromIP(const SeedMeasurement &meas1, const SeedMeasurement &meas2) const
Checks whether the two measurements are compatible within the IP constraint.
double sectorWidth(int sector) const
sector width (with overlap) in radians
StatusCode accept(const xAOD::Muon *mu)
void Zero(TH1D *hin)
Definition generate.cxx:32
constexpr double tolerance
double stereoAngle() const
returns the stereo angle
double channelHalfLength(int st, bool left) const
STRIPS ONLY: calculate channel length on the given side of the x axis (for MM stereo strips)

◆ segmentSeedFromPads()

std::vector< NSWSeed > Muon::MuonNSWSegmentFinderTool::segmentSeedFromPads ( const LayerMeasVec & orderedClusters,
const Muon::MuonSegment & etaSeg ) const
private

Do not run an empty container

Definition at line 985 of file MuonNSWSegmentFinderTool.cxx.

986 {
987 std::vector<NSWSeed> seeds;
989 if (orderedClusters.empty()) return seeds;
990
991 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcIP(4); // IP: layers nearest to the IP will be added first
992 std::vector<std::vector<const Muon::sTgcPrepData*>> sTgcHO(4); // HO: layers furthest from the IP will be added first
993
994 // Process clusters separately for each multilayer
995 for (int iml : {1, 2}) {
996 int il = (iml == 1) ? 0 : orderedClusters.size() - 1;
997 int iend = (iml == 1) ? orderedClusters.size() : -1;
998 int idir = (iml == 1) ? 1 : -1;
999 unsigned int nLayersWithHitMatch{0};
1000
1001 // Loop on layers (reverse loop for HO)
1002 for (; il != iend; il += idir) {
1003 double lastDistance{1000.};
1004 if (nLayersWithHitMatch >= sTgcIP.size()) {
1005 sTgcIP.resize(nLayersWithHitMatch + 1);
1006 sTgcHO.resize(nLayersWithHitMatch + 1);
1007 }
1008 std::vector<const Muon::sTgcPrepData*>& matchedHits =
1009 (iml == 1) ? sTgcIP.at(nLayersWithHitMatch) : sTgcHO.at(nLayersWithHitMatch);
1010
1011 // Loop on the hits on this layer. Find the one closest (in eta) to the segment intersection.
1012 for (const Muon::MuonClusterOnTrack* rio : orderedClusters[il]) {
1013 const sTgcPrepData* padHit = dynamic_cast<const sTgcPrepData*>(rio->prepRawData());
1014 if (!padHit) continue;
1015
1016 // check the multilayer the hit is on
1017 if (m_idHelperSvc->stgcIdHelper().multilayer(padHit->identify()) != iml) continue;
1018
1019 const MuonGM::MuonPadDesign* design = padHit->detectorElement()->getPadDesign(padHit->identify());
1020 if (!design) continue;
1021
1022 // local position of the segment intersection with the plane
1023 const Trk::Surface& surf = padHit->detectorElement()->surface(padHit->identify());
1024 Trk::Intersection intersect =
1025 surf.straightLineIntersection(etaSeg.globalPosition(), etaSeg.globalDirection(), false, false);
1026 Amg::Vector2D segLocPosOnSurf{Amg::Vector2D::Zero()};
1027 surf.globalToLocal(intersect.position, intersect.position, segLocPosOnSurf);
1028
1029 // eta distance between the hit and the segment intersection with the plane
1030 // check that it's no more than half of the pad eta-pitch.
1031 double chWidth = design->channelWidth(padHit->localPosition(), false);
1032 double etaDistance = std::abs(padHit->localPosition().y() - segLocPosOnSurf[1]);
1033 if (etaDistance > 0.5 * chWidth) continue;
1034 ATH_MSG_DEBUG(" etaDistance " << etaDistance << " between pad center and position on the pad.");
1035
1036 if (matchedHits.empty()) {
1037 // first hit
1038 matchedHits.push_back(padHit);
1039 ATH_MSG_DEBUG(" best etaDistance: " << etaDistance);
1040 } else if (std::abs(etaDistance - lastDistance) < 0.001) {
1041 // competing hit pad, keep both (all hit pads of the same eta row will be candidates)
1042 matchedHits.push_back(padHit);
1043 ATH_MSG_DEBUG(" added etaDistance: " << etaDistance << " size " << matchedHits.size());
1044 } else if (etaDistance < lastDistance) {
1045 // found a better hit; clear the old ones (possible only for clustered pad hits)
1046 matchedHits.clear();
1047 matchedHits.push_back(padHit);
1048 ATH_MSG_DEBUG(" replacing best etaDistance with: " << etaDistance);
1049 } else {
1050 continue;
1051 }
1052 lastDistance = etaDistance;
1053 } // end of loop on hits
1054
1055 if (!matchedHits.empty()) ++nLayersWithHitMatch;
1056
1057 } // end of loop on layers
1058
1059 // need at least one hit in each multilayer to create a seed
1060 if (!nLayersWithHitMatch) return seeds;
1061
1062 } // end of loop on multilayers
1063
1064 // get refined phi ranges on each ml, by taking into account pad staggering
1065 std::vector<std::pair<double, double>> sTgcIP_phiRanges = getPadPhiOverlap(sTgcIP);
1066 std::vector<std::pair<double, double>> sTgcHO_phiRanges = getPadPhiOverlap(sTgcHO);
1067
1068 // reference prds on the outermost hit surfaces
1069 const sTgcPrepData* prdL1 = sTgcIP.front().front();
1070 const sTgcPrepData* prdL2 = sTgcHO.front().front();
1071 const auto& surfPrdL1 = prdL1->detectorElement()->surface();
1072 const auto& surfPrdL2 = prdL2->detectorElement()->surface();
1073
1074 // create a seed for each combination of IP and HO points
1075 for (const std::pair<double, double>& range1 : sTgcIP_phiRanges) {
1076 double midPhi1 = 0.5 * (range1.first + range1.second);
1077 Amg::Vector2D lp1(midPhi1, prdL1->localPosition().y());
1078 Amg::Vector3D gpL1{Amg::Vector3D::Zero()};
1079 surfPrdL1.localToGlobal(lp1, gpL1, gpL1);
1080
1081 Amg::Vector2D lp1_lowPhi{range1.first, prdL1->localPosition().y()};
1082 Amg::Vector2D lp1_highPhi{range1.second, prdL1->localPosition().y()};
1083
1084 Amg::Vector3D gp1_lowPhi{Amg::Vector3D::Zero()};
1085 Amg::Vector3D gp1_highPhi{Amg::Vector3D::Zero()};
1086
1087 surfPrdL1.localToGlobal(lp1_lowPhi, gp1_lowPhi, gp1_lowPhi);
1088 surfPrdL1.localToGlobal(lp1_highPhi, gp1_highPhi, gp1_highPhi);
1089
1090 Trk::Intersection intersect_lowPhi = surfPrdL2.straightLineIntersection(gp1_lowPhi, gp1_lowPhi, false, false);
1091 Trk::Intersection intersect_highPhi = surfPrdL2.straightLineIntersection(gp1_highPhi, gp1_highPhi, false, false);
1092
1093 Amg::Vector2D lpIntersect_lowPhi{Amg::Vector2D::Zero()};
1094 Amg::Vector2D lpIntersect_highPhi{Amg::Vector2D::Zero()};
1095
1096 surfPrdL2.globalToLocal(intersect_lowPhi.position, intersect_lowPhi.position, lpIntersect_lowPhi);
1097 surfPrdL2.globalToLocal(intersect_highPhi.position, intersect_highPhi.position, lpIntersect_highPhi);
1098
1099 for (const std::pair<double, double>& range2 : sTgcHO_phiRanges) {
1100 double midPhi2 = 0.5 * (range2.first + range2.second);
1101 // let's check that the phi ranges in the two multilayer overlap
1102 if( lpIntersect_highPhi.x() - range2.first < 0 || range2.second - lpIntersect_lowPhi.x() < 0) {
1103 ATH_MSG_DEBUG(" segmentSeedFromPads: skipping seed with non-overlapping phi ranges");
1104 continue;
1105 }
1106
1107 Amg::Vector2D lp2(midPhi2, prdL2->localPosition().y());
1108 Amg::Vector3D gpL2{Amg::Vector3D::Zero()};
1109 surfPrdL2.localToGlobal(lp2, gpL2, gpL2);
1110 // create the seed taking the average position (w.r.t. IP)
1111 // as global direction (as for an infinite momentum track).
1112 Amg::Vector3D gDir = (gpL2 + gpL1).unit();
1113 seeds.emplace_back(this, gpL1, gDir);
1114 }
1115 }
1116
1117 ATH_MSG_DEBUG(" segmentSeedFromPads: seeds.size() " << seeds.size());
1118 return seeds;
1119 }
std::vector< std::pair< double, double > > getPadPhiOverlap(const std::vector< std::vector< const Muon::sTgcPrepData * > > &pads) const
virtual const Amg::Vector3D & globalPosition() const override final
global position
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const =0
Specified by each surface type: GlobalToLocal method without dynamic memory allocation - boolean chec...
Amg::Vector3D position

◆ segmentSeedFromStgc()

std::vector< NSWSeed > Muon::MuonNSWSegmentFinderTool::segmentSeedFromStgc ( const LayerMeasVec & orderedClusters,
bool usePhi ) const
private

Reject

Definition at line 868 of file MuonNSWSegmentFinderTool.cxx.

869 {
870 std::vector<NSWSeed> seeds;
871
872 // oderedClusters should contain either eta clusters (MM and sTGC)
873 // or sTGC phi hits. For MM phi, use the dedicated function.
874 if (orderedClusters.size() < 4) return seeds;
875
876 // Create seeds using each pair of hits on the two most distant layers (that containing hits).
877 // m_nOfSeedLayers (default = 1) dictates whether we want to also use hits from inner layers.
878
879 // Loop on layers to get the first seed point
880 int seedingLayersL{0};
881 for (unsigned int ilayerL{0}; (ilayerL < orderedClusters.size() && seedingLayersL < m_nOfSeedLayers); ++ilayerL) {
882 bool usedLayerL{false};
883 for (const SeedMeasurement& hitL : orderedClusters[ilayerL]) {
885 if (usePhi != m_idHelperSvc->measuresPhi(hitL->identify())) continue;
886 else if(m_idHelperSvc->isMM(hitL->identify())) break;
887
888
889 // For the second point, loop on layers in reverse to be as far as possible from the first.
890 int seedingLayersR{0};
891 for (unsigned int ilayerR = orderedClusters.size() - 1; (ilayerR > ilayerL && seedingLayersR < m_nOfSeedLayers);
892 --ilayerR) {
893 bool usedLayerR{false};
894 for (const SeedMeasurement& hitR : orderedClusters[ilayerR]) {
895 if (usePhi != m_idHelperSvc->measuresPhi(hitR->identify())) continue;
896 else if (m_idHelperSvc->isMM(hitR->identify())) break;
897 NSWSeed seed{this,hitL, hitR};
898 if (!usePhi && m_ipConstraint) {
899 const double eta = seed.dir().perp() > std::numeric_limits<float>::epsilon() ? std::abs(seed.dir().eta()): FLT_MAX;
900 if (eta < minEtaNSW || eta > maxEtaNSW) {
901 continue;
902 }
903 } else if (usePhi && m_ipConstraint) {
904 // first make sure that the wires are in the same or neigbouring quads
905 if(std::abs(std::abs(m_idHelperSvc->stationEta(hitL->identify())) - std::abs(m_idHelperSvc->stationEta(hitR->identify()))) > 1) {
906 continue;
907 }
908 // project the hit in the first layer assuming the track comes from the IP
909 Trk::Intersection intersect = hitR->detectorElement()->surface(hitR->identify()).straightLineIntersection(hitL->globalPosition(),hitL->globalPosition().unit(), false, false);
910 Amg::Vector2D lpos_intersect{Amg::Vector2D::Zero()};
911 hitR->detectorElement()->surface(hitR->identify()).globalToLocal(intersect.position, intersect.position, lpos_intersect);
912
913 Amg::Vector2D lPosR;
914 hitR->detectorElement()->surface(hitR->identify()).globalToLocal(hitR->globalPosition(), hitR->globalPosition(), lPosR);
915
916
917 if(std::abs(lpos_intersect.x() - lPosR.x()) > 87.5 ) continue; // reject seed if the projection is more than 2.5 wire groups away
918 }
919
920 usedLayerR = true;
921 usedLayerL = true;
922 getClustersOnSegment(orderedClusters, seed, {ilayerL, ilayerR}, false);
923 seeds.emplace_back(std::move(seed));
924
925 }
926 if (usedLayerR) ++seedingLayersR;
927 }
928 }
929 if (usedLayerL) ++seedingLayersL;
930 }
931
932 return resolveAmbiguities(std::move(seeds));
933 }

◆ sysInitialize()

virtual StatusCode AthCommonDataStore< AthCommonMsg< AlgTool > >::sysInitialize ( )
overridevirtualinherited

Perform system initialization for an algorithm.

We override this to declare all the elements of handle key arrays at the end of initialization. See comments on updateVHKA.

Reimplemented in asg::AsgMetadataTool, AthCheckedComponent< AthAlgTool >, AthCheckedComponent<::AthAlgTool >, and DerivationFramework::CfAthAlgTool.

◆ sysStart()

virtual StatusCode AthCommonDataStore< AthCommonMsg< AlgTool > >::sysStart ( )
overridevirtualinherited

Handle START transition.

We override this in order to make sure that conditions handle keys can cache a pointer to the conditions container.

◆ updateVHKA()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::updateVHKA ( Gaudi::Details::PropertyBase & )
inlineinherited

Definition at line 308 of file AthCommonDataStore.h.

308 {
309 // debug() << "updateVHKA for property " << p.name() << " " << p.toString()
310 // << " size: " << m_vhka.size() << endmsg;
311 for (auto &a : m_vhka) {
313 for (auto k : keys) {
314 k->setOwner(this);
315 }
316 }
317 }
std::vector< SG::VarHandleKeyArray * > m_vhka

◆ vetoBursts()

MeasVec Muon::MuonNSWSegmentFinderTool::vetoBursts ( MeasVec && clustInLay) const
private

Removes clusters from high activity areas in the detector.

The micromegas are slobbering quite a lot in the 2023 data taking leading to uncopable comptuing times. The burst vetoing aims to mitigate this situation. A histogram with a bin width of m_ocupMmBinWidth is defined Hits are filled into the accoring bin using their channel number Bins with large activity are then cleared. In the second step, pairs of bins where their sum is too exhaustive are removed.

Define the number of bins

Fill the measurements into the histograms

Apply the single bin cleaning

Apply the pair wise bin cleaning

Copy the rest over

Definition at line 1604 of file MuonNSWSegmentFinderTool.cxx.

1604 {
1605 if (clustInLay.size() < m_ocupMmNumPerBin || m_idHelperSvc->issTgc(clustInLay[0]->identify())) return clustInLay;
1611 MeasVec prunedMeas{};
1612 prunedMeas.reserve(clustInLay.size());
1613 const unsigned int firstCh = channel(clustInLay[0]);
1614 const unsigned int lastCh = channel(clustInLay[clustInLay.size() -1]);
1616 const unsigned int deltaCh = lastCh - firstCh;
1617 const unsigned int nBins = deltaCh / m_ocupMmBinWidth + (deltaCh % m_ocupMmBinWidth > 0);
1618 ATH_MSG_VERBOSE("Clusters in layer "<<print(clustInLay)<<" lowest channel: "<<
1619 firstCh<<", highest channel: "<<lastCh<<" bin width: "<<m_ocupMmBinWidth<<" number of bins"<<nBins);
1620
1621 LayerMeasVec occupancyHisto{};
1622 occupancyHisto.resize(nBins);
1623 for (MeasVec& bin : occupancyHisto) {
1624 bin.reserve(clustInLay.size());
1625 }
1626 ATH_MSG_VERBOSE("Clusters sorted into bins "<<print(occupancyHisto));
1628 for (SeedMeasurement& meas : clustInLay){
1629 unsigned int bin = (channel(meas) - firstCh) % nBins;
1630 occupancyHisto[bin].push_back(std::move(meas));
1631 }
1633 for (MeasVec& bin : occupancyHisto) {
1634 if(bin.size() >= m_ocupMmNumPerBin){
1635 ATH_MSG_VERBOSE("The micromegas are slobbering. Detected too many clusters "<<bin.size()<<std::endl<<print(bin));
1636 bin.clear();
1637 }
1638 }
1640 for (unsigned int i = 0; i < occupancyHisto.size() -1; ++i) {
1641 if (occupancyHisto[i].size() + occupancyHisto[i+1].size() >= m_ocupMmNumPerPair){
1642 ATH_MSG_VERBOSE("The two neighbouring bins "<<i<<"&"<<(i+1)<<" have too many clusters "<<std::endl<<
1643 print(occupancyHisto[i])<<std::endl<<print(occupancyHisto[i+1]));
1644 occupancyHisto[i].clear();
1645 occupancyHisto[i+1].clear();
1646 }
1647 }
1649 for (MeasVec& bin : occupancyHisto){
1650 std::copy(std::make_move_iterator(bin.begin()),
1651 std::make_move_iterator(bin.end()),
1652 std::back_inserter(prunedMeas));
1653 }
1654
1655 ATH_MSG_VERBOSE("Number of measurements before pruning "<<clustInLay.size()<<" number of measurments survived the pruning "<<prunedMeas.size());
1656 return prunedMeas;
1657
1658 }
Gaudi::Property< unsigned int > m_ocupMmNumPerPair
Gaudi::Property< unsigned int > m_ocupMmNumPerBin
Gaudi::Property< unsigned int > m_ocupMmBinWidth
Protection against slobbering Micromega events.

◆ wedgeNumber()

int Muon::MuonNSWSegmentFinderTool::wedgeNumber ( const Muon::MuonClusterOnTrack * cluster) const

Definition at line 936 of file MuonNSWSegmentFinderTool.cxx.

936 {
937 if (m_idHelperSvc->isMM(cluster->identify()))
938 return m_idHelperSvc->mmIdHelper().multilayer(cluster->identify()) + 1; // [IP:2, HO:3]
939 if (m_idHelperSvc->issTgc(cluster->identify()))
940 return 3 * (m_idHelperSvc->stgcIdHelper().multilayer(cluster->identify()) - 1) + 1; // [IP:1, HO:4];
941 return -1;
942 }

Member Data Documentation

◆ m_ambiTool

ToolHandle<Trk::ITrackAmbiguityProcessorTool> Muon::MuonNSWSegmentFinderTool::m_ambiTool
private
Initial value:
{
this,
"SegmentAmbiguityTool",
"Trk::SimpleAmbiguityProcessorTool/MuonAmbiProcessor",
}

Tool for ambiguity solving.

Definition at line 148 of file MuonNSWSegmentFinderTool.h.

148 {
149 this,
150 "SegmentAmbiguityTool",
151 "Trk::SimpleAmbiguityProcessorTool/MuonAmbiProcessor",
152 };

◆ m_caloConstraint

Gaudi::Property<bool> Muon::MuonNSWSegmentFinderTool::m_caloConstraint {this, "CaloConstraint", false}
private

Use a virtual point at the calorimeter exit with same Z as constraint...

Definition at line 184 of file MuonNSWSegmentFinderTool.h.

184{this, "CaloConstraint", false};

◆ m_detStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< AlgTool > >::m_detStore
privateinherited

Pointer to StoreGate (detector store by default)

Definition at line 393 of file AthCommonDataStore.h.

◆ m_edmHelperSvc

ServiceHandle<IMuonEDMHelperSvc> Muon::MuonNSWSegmentFinderTool::m_edmHelperSvc
private
Initial value:
{
this,
"edmHelper",
"Muon::MuonEDMHelperSvc/MuonEDMHelperSvc",
"Handle to the service providing the IMuonEDMHelperSvc interface",
}

Definition at line 141 of file MuonNSWSegmentFinderTool.h.

141 {
142 this,
143 "edmHelper",
144 "Muon::MuonEDMHelperSvc/MuonEDMHelperSvc",
145 "Handle to the service providing the IMuonEDMHelperSvc interface",
146 }; //<! Id helper tool

◆ m_evtStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< AlgTool > >::m_evtStore
privateinherited

Pointer to StoreGate (event store by default)

Definition at line 390 of file AthCommonDataStore.h.

◆ m_idHelperSvc

ServiceHandle<IMuonIdHelperSvc> Muon::MuonNSWSegmentFinderTool::m_idHelperSvc
private
Initial value:
{
this,
"MuonIdHelperSvc",
"Muon::MuonIdHelperSvc/MuonIdHelperSvc",
}

Definition at line 136 of file MuonNSWSegmentFinderTool.h.

136 {
137 this,
138 "MuonIdHelperSvc",
139 "Muon::MuonIdHelperSvc/MuonIdHelperSvc",
140 };

◆ m_ipConstraint

Gaudi::Property<bool> Muon::MuonNSWSegmentFinderTool::m_ipConstraint {this, "IPConstraint", true}
private

Definition at line 181 of file MuonNSWSegmentFinderTool.h.

181{this, "IPConstraint", true}; // use a ip perigee(0,0) constraint in the segment fit

◆ m_maxClustDist

Gaudi::Property<double> Muon::MuonNSWSegmentFinderTool::m_maxClustDist {this, "ClusterDistance", 5.}
private

Definition at line 185 of file MuonNSWSegmentFinderTool.h.

185{this, "ClusterDistance", 5.};

◆ m_maxInputPads

Gaudi::Property<uint> Muon::MuonNSWSegmentFinderTool::m_maxInputPads {this, "maxInputPads", 40, "Maximum number of pads per wedge layer."}
private

Definition at line 199 of file MuonNSWSegmentFinderTool.h.

199{this, "maxInputPads", 40, "Maximum number of pads per wedge layer."};

◆ m_muonClusterCreator

ToolHandle<IMuonClusterOnTrackCreator> Muon::MuonNSWSegmentFinderTool::m_muonClusterCreator {this, "MuonClusterCreator", ""}
private

Definition at line 179 of file MuonNSWSegmentFinderTool.h.

179{this, "MuonClusterCreator", ""};

◆ m_nOfSeedLayers

Gaudi::Property<int> Muon::MuonNSWSegmentFinderTool::m_nOfSeedLayers {this, "NOfSeedLayers", 1}
private

Definition at line 186 of file MuonNSWSegmentFinderTool.h.

186{this, "NOfSeedLayers", 1};

◆ m_ocupMmBinWidth

Gaudi::Property<unsigned int> Muon::MuonNSWSegmentFinderTool::m_ocupMmBinWidth
private
Initial value:
{this, "MmOccupancyBinWidth", 100,
"Size of the channel window to group the MicroMegaCluster"}

Protection against slobbering Micromega events.

Definition at line 193 of file MuonNSWSegmentFinderTool.h.

193 {this, "MmOccupancyBinWidth", 100,
194 "Size of the channel window to group the MicroMegaCluster"};

◆ m_ocupMmNumPerBin

Gaudi::Property<unsigned int> Muon::MuonNSWSegmentFinderTool::m_ocupMmNumPerBin
private
Initial value:
{this, "MmOccupancySingleCut", 5,
"Cut on the number of MicroMega clusters in a particular occupancy bin"}

Definition at line 195 of file MuonNSWSegmentFinderTool.h.

195 {this, "MmOccupancySingleCut", 5,
196 "Cut on the number of MicroMega clusters in a particular occupancy bin"};

◆ m_ocupMmNumPerPair

Gaudi::Property<unsigned int> Muon::MuonNSWSegmentFinderTool::m_ocupMmNumPerPair
private
Initial value:
{this, "MmOccupancyPairCut", 7,
"Cut on the number of MicroMega clusters in two neighbouring occupancy bins"}

Definition at line 197 of file MuonNSWSegmentFinderTool.h.

197 {this, "MmOccupancyPairCut", 7,
198 "Cut on the number of MicroMega clusters in two neighbouring occupancy bins"};

◆ m_printer

PublicToolHandle<MuonEDMPrinterTool> Muon::MuonNSWSegmentFinderTool::m_printer
private
Initial value:
{
this,
"Printer",
"Muon::MuonEDMPrinterTool/MuonEDMPrinterTool",
}

Definition at line 163 of file MuonNSWSegmentFinderTool.h.

163 {
164 this,
165 "Printer",
166 "Muon::MuonEDMPrinterTool/MuonEDMPrinterTool",
167 };

◆ m_slTrackFitter

ToolHandle<Trk::ITrackFitter> Muon::MuonNSWSegmentFinderTool::m_slTrackFitter
private
Initial value:
{
this,
"SLFitter",
"Trk::GlobalChi2Fitter/MCTBSLFitter",
}

Definition at line 153 of file MuonNSWSegmentFinderTool.h.

153 {
154 this,
155 "SLFitter",
156 "Trk::GlobalChi2Fitter/MCTBSLFitter",
157 }; //<! fitter, always use straightline

◆ m_trackCleaner

ToolHandle<IMuonTrackCleaner> Muon::MuonNSWSegmentFinderTool::m_trackCleaner
private
Initial value:
{
this,
"TrackCleaner",
"Muon::MuonTrackCleaner/MuonTrackCleaner",
}

Definition at line 168 of file MuonNSWSegmentFinderTool.h.

168 {
169 this,
170 "TrackCleaner",
171 "Muon::MuonTrackCleaner/MuonTrackCleaner",
172 };

◆ m_trackSummary

ToolHandle<Trk::ITrackSummaryTool> Muon::MuonNSWSegmentFinderTool::m_trackSummary
private
Initial value:
{
this,
"TrackSummaryTool",
"Trk::TrackSummaryTool/MuidTrackSummaryTool",
}

Definition at line 173 of file MuonNSWSegmentFinderTool.h.

173 {
174 this,
175 "TrackSummaryTool",
176 "Trk::TrackSummaryTool/MuidTrackSummaryTool",
177 };

◆ m_trackToSegmentTool

ToolHandle<IMuonTrackToSegmentTool> Muon::MuonNSWSegmentFinderTool::m_trackToSegmentTool
private
Initial value:
{
this,
"TrackToSegmentTool",
"Muon::MuonTrackToSegmentTool/MuonTrackToSegmentTool",
}

Definition at line 158 of file MuonNSWSegmentFinderTool.h.

158 {
159 this,
160 "TrackToSegmentTool",
161 "Muon::MuonTrackToSegmentTool/MuonTrackToSegmentTool",
162 }; //<! track to segment converter

◆ m_useStereoSeeding

Gaudi::Property<bool> Muon::MuonNSWSegmentFinderTool::m_useStereoSeeding {this, "SeedMMStereos", true}
private

Definition at line 189 of file MuonNSWSegmentFinderTool.h.

189{this, "SeedMMStereos", true};

◆ m_usesTGCSeeding

Gaudi::Property<bool> Muon::MuonNSWSegmentFinderTool::m_usesTGCSeeding {this, "SeedWithsTGCS", true}
private

Definition at line 190 of file MuonNSWSegmentFinderTool.h.

190{this, "SeedWithsTGCS", true};

◆ m_varHandleArraysDeclared

bool AthCommonDataStore< AthCommonMsg< AlgTool > >::m_varHandleArraysDeclared
privateinherited

Definition at line 399 of file AthCommonDataStore.h.

◆ m_vhka

std::vector<SG::VarHandleKeyArray*> AthCommonDataStore< AthCommonMsg< AlgTool > >::m_vhka
privateinherited

Definition at line 398 of file AthCommonDataStore.h.


The documentation for this class was generated from the following files: