From 2840188565fd8b8166d5ce78ca5c1d7b82a36497 Mon Sep 17 00:00:00 2001 From: Andy Salnikov <salnikov@slac.stanford.edu> Date: Sun, 22 Nov 2020 03:57:39 +0100 Subject: [PATCH] Improve vertex finding / clustering in beamspot calibration. Clusterer now has an option to do clustering at beampot position instead of (0,0) position. This improves clustering and makes resulting vertex fit less biased, and matches offline beam position. --- .../TrigT2BeamSpot/CMakeLists.txt | 5 +- .../TrigT2BeamSpot/T2VertexBeamSpotTool.h | 8 +-- .../python/T2VertexBeamSpotConfig.py | 1 + .../python/T2VertexBeamSpotMonitoring.py | 2 + .../TrigT2BeamSpot/src/T2TrackClusterer.cxx | 63 ++++++++++++++++--- .../TrigT2BeamSpot/src/T2TrackClusterer.h | 26 +++++++- .../src/T2VertexBeamSpotTool.cxx | 34 ++++++---- 7 files changed, 112 insertions(+), 27 deletions(-) diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/CMakeLists.txt b/Trigger/TrigAlgorithms/TrigT2BeamSpot/CMakeLists.txt index ce22c00a73fe..dcaab83db172 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/CMakeLists.txt +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/CMakeLists.txt @@ -11,7 +11,10 @@ atlas_add_component( TrigT2BeamSpot src/*.cxx src/components/TrigT2*.cxx INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers AthenaBaseComps AthenaMonitoringKernelLib BeamSpotConditionsData EventPrimitives GaudiKernel StoreGateLib TrigInDetEvent TrigInDetToolInterfacesLib TrigInterfacesLib TrigNavigationLib TrigSteeringEvent TrigTimeAlgsLib TrkParameters TrkTrack TrkTrackSummary xAODEventInfo ) + LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers AthenaBaseComps AthenaMonitoringKernelLib + BeamSpotConditionsData EventPrimitives GaudiKernel StoreGateLib TrigInDetEvent + TrigInDetToolInterfacesLib TrigInterfacesLib TrigNavigationLib TrigSteeringEvent + TrigTimeAlgsLib TrkParameters TrkTrack TrkTrackSummary xAODEventInfo ) # Install files from the package: atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/TrigT2BeamSpot/T2VertexBeamSpotTool.h b/Trigger/TrigAlgorithms/TrigT2BeamSpot/TrigT2BeamSpot/T2VertexBeamSpotTool.h index ba80ec2c7b4a..bbff59fcf926 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/TrigT2BeamSpot/T2VertexBeamSpotTool.h +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/TrigT2BeamSpot/T2VertexBeamSpotTool.h @@ -29,6 +29,7 @@ #include "../src/T2Track.h" #include "../src/T2BeamSpot.h" #include "../src/T2SplitVertex.h" +#include "../src/T2TrackClusterer.h" //Athena tools #include "AthenaBaseComps/AthAlgTool.h" #include "GaudiKernel/ToolHandle.h" @@ -54,7 +55,6 @@ namespace HLT { } namespace PESA { class T2SplitVertex; - class T2TrackClusterer; /** * This class uses primary vertex reconstruction to measure * and monitor the LHC beam as seen by the ATLAS detector. @@ -116,6 +116,8 @@ namespace PESA { bool m_splitWholeCluster; bool m_reclusterSplit; double m_trackSeedPt; + std::string m_clusterPerigee = "original"; // one of "original", "beamspot", "beamline" + T2TrackClusterer::TrackPerigee m_clusterTrackPerigee = T2TrackClusterer::perigee_original; /* Track selection criteria */ unsigned m_totalNTrkMin; @@ -177,10 +179,8 @@ namespace PESA { std::string m_vertexCollName; private: - ToolHandle<GenericMonitoringTool> m_monTool{this,"MonTool","","Monitoring tool"}; - - + ToolHandle<GenericMonitoringTool> m_monTool{this,"MonTool","","Monitoring tool"}; }; diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotConfig.py b/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotConfig.py index 9a82a28453f4..7b7a431bcbcf 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotConfig.py +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotConfig.py @@ -21,6 +21,7 @@ InDetTrigMTBeamSpotTool = PESA__T2VertexBeamSpotTool( MonTool = bsToolMonitoring, WeightClusterZ = True, # Use the track Z0 weighted cluster Z position as seed ReclusterSplit = False, # Recluster split track collections before vertex fitting + ClusterPerigee = "beamspot", nSplitVertices = 2, # Turn on (>1) or off vertex splitting TotalNTrackMin = 4, # Minimum number of tracks required in an event TrackMinPt = 0.5, # Minimum track pT to be considered for vertexing diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotMonitoring.py b/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotMonitoring.py index 94b7896b2184..87c857417a5a 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotMonitoring.py +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/python/T2VertexBeamSpotMonitoring.py @@ -237,6 +237,8 @@ class T2VertexBeamSpotToolMonitoring(BaseMonitoringTool): title="ClusterDeltaZ0; Delta of track Z0 and cluster Z position [mm]; Number of tracks") self.makeHisto1D('ClusterZ0Pull', 'TH1I', 100, -10.0, 10.0, title="ClusterZ0Pull; Pull of track Z0 with respect to cluster Z position; Number of tracks") + self.makeHisto1D('ClusterClusterDeltaZ0', 'TH1I', 200, -100.0, 100.0, + title="ClusterClusterDeltaZ0; Delta of cluster-cluster Z position [mm]; Number of clusters") def defineVertexHistos(self, detail): diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.cxx b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.cxx index 4454071b7e0c..fdce5e5daa8c 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.cxx +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.cxx @@ -10,14 +10,34 @@ #include "TrkParameters/TrackParameters.h" #include "EventPrimitives/EventPrimitivesHelpers.h" +#include "BeamSpotConditionsData/BeamSpotData.h" #include <cmath> +#include <stdexcept> + using std::abs; using std::sqrt; +using std::sin; +using std::cos; +using std::tan; using namespace PESA; +T2TrackClusterer::TrackPerigee +T2TrackClusterer::trackPerigeeFromString(const std::string& perigeeStr) +{ + if (perigeeStr == "original") { + return perigee_original; + } else if (perigeeStr == "beamspot") { + return perigee_beamspot; + } else if (perigeeStr == "beamline") { + return perigee_beamline; + } else { + throw std::runtime_error("Invalid value of ClusterPerigee parameter: " + perigeeStr); + } +} + double T2TrackClusterer::trackWeight( const Trk::Track& track ) const { @@ -27,7 +47,7 @@ T2TrackClusterer::trackWeight( const Trk::Track& track ) const } const TrackCollection& -T2TrackClusterer::cluster( const TrackCollection& tracks ) +T2TrackClusterer::cluster( const TrackCollection& tracks, const InDet::BeamSpotData* beamspot ) { m_seedZ0 = 0.; m_totalZ0Err = 0.; @@ -41,9 +61,9 @@ T2TrackClusterer::cluster( const TrackCollection& tracks ) } const Trk::Track* seedTrack = *tracks.begin(); - - const Trk::TrackParameters* seedTrackPars = seedTrack->perigeeParameters(); - const double seedPT = std::abs(sin(seedTrackPars->parameters()[Trk::theta])/seedTrackPars->parameters()[Trk::qOverP]); + + auto& params = seedTrack->perigeeParameters()->parameters(); + const double seedPT = std::abs(sin(params[Trk::theta])/params[Trk::qOverP]); if ( seedPT < m_minPT ) { @@ -51,16 +71,16 @@ T2TrackClusterer::cluster( const TrackCollection& tracks ) return *m_cluster.asDataVector(); } + double sumWeight = trackWeight( *seedTrack ); - m_seedZ0 = seedTrackPars->parameters()[Trk::z0]; // becomes the weighted-average z0 of the cluster + m_seedZ0 = trackPerigeeZ0(*seedTrack, beamspot); m_cluster.push_back( seedTrack ); for ( TrackCollection::const_iterator track = tracks.begin() + 1; track != tracks.end(); ++track ) { - const Trk::TrackParameters* trackPars = (*track)->perigeeParameters(); - const double trackZ0 = trackPars->parameters()[Trk::z0]; + const double trackZ0 = trackPerigeeZ0(**track, beamspot); const double deltaZ = trackZ0 - m_seedZ0; const double weight = trackWeight( **track ); @@ -81,3 +101,32 @@ T2TrackClusterer::cluster( const TrackCollection& tracks ) return *m_cluster.asDataVector(); } + +double +T2TrackClusterer::trackPerigeeZ0(const Trk::Track& track, const InDet::BeamSpotData* beamspot) const +{ + auto& params0 = track.perigeeParameters()->parameters(); + if (m_trackPerigee == perigee_original or beamspot == nullptr) { + return params0[Trk::z0]; + } else if (m_trackPerigee == perigee_beamspot or m_trackPerigee == perigee_beamline) { + // TODO: beamline is doing the same as beamspot for now, I think it should be OK + // with our track resolution, somethig to check in the future (when I retire) + + // This assumes that track perigee is defined at 0,0, transform is: + // z = z_0 + (B_x*cos(phi) + B_y*sin(phi)) / tan(theta) + + double z_0 = params0[Trk::z0]; + double phi = params0[Trk::phi]; + double theta = params0[Trk::theta]; + auto& beamPos = beamspot->beamPos(); + double B_x = beamPos[0]; + double B_y = beamPos[1]; + + double z = z_0 + (B_x*cos(phi) + B_y*sin(phi)) / tan(theta); + return z; + + } else { + // fallback to "original" + return params0[Trk::z0]; + } +} \ No newline at end of file diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.h b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.h index 130345b740f8..d58500686d0e 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.h +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2TrackClusterer.h @@ -33,6 +33,8 @@ #include <vector> #include <cmath> +namespace InDet { class BeamSpotData; } + namespace PESA { @@ -40,14 +42,28 @@ namespace PESA { public: + // option for calculating track perigee parameters + enum TrackPerigee { + perigee_original, // Use original track perigee parameters, usually means + // perigee w.r.t. coordinate system origin x,y=0,0 + perigee_beamspot, // Perigee to a beamspot position, ignoring tilt + perigee_beamline, // Perigee to a beam line, including tilt + }; + + // convert string to above enum value + static TrackPerigee trackPerigeeFromString(const std::string& perigeeStr); + // Constructor - T2TrackClusterer( double deltaZ = 10.*Gaudi::Units::mm, double minPT = 1.*Gaudi::Units::GeV, bool weightedZ = true, unsigned maxSize = 10000. ) + // clusterPerigee is one of '0'=origin, 's'=beamspot, 'l'=beamline + T2TrackClusterer( double deltaZ = 10.*Gaudi::Units::mm, double minPT = 1.*Gaudi::Units::GeV, bool weightedZ = true, unsigned maxSize = 10000., + TrackPerigee trackPerigee = perigee_original) : m_deltaZ ( deltaZ ) , m_minPT ( minPT ) , m_weightedZ ( weightedZ ) , m_maxSize ( maxSize ) , m_seedZ0 ( 0. ) , m_totalZ0Err( 0. ) + , m_trackPerigee( trackPerigee ) {} // Accessors @@ -60,9 +76,13 @@ namespace PESA // Methods double trackWeight( const Trk::Track& track ) const; - const TrackCollection& cluster( const TrackCollection& tracks ); + const TrackCollection& cluster( const TrackCollection& tracks, const InDet::BeamSpotData* beamspot = nullptr ); private: + + // return perigee z0 for a track + double trackPerigeeZ0(const Trk::Track& track, const InDet::BeamSpotData* beamspot) const; + // Data members const double m_deltaZ; const double m_minPT; @@ -72,6 +92,8 @@ namespace PESA double m_seedZ0; double m_totalZ0Err; + const TrackPerigee m_trackPerigee = perigee_original; + ConstDataVector<TrackCollection> m_cluster; ConstDataVector<TrackCollection> m_unusedTracks; }; diff --git a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2VertexBeamSpotTool.cxx b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2VertexBeamSpotTool.cxx index e9b9fa304a8c..c6a813924cc6 100644 --- a/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2VertexBeamSpotTool.cxx +++ b/Trigger/TrigAlgorithms/TrigT2BeamSpot/src/T2VertexBeamSpotTool.cxx @@ -14,7 +14,6 @@ //============================================================ // This algorithm #include "TrigT2BeamSpot/T2VertexBeamSpotTool.h" -#include "T2TrackClusterer.h" #include "T2TrackManager.h" #include "T2Timer.h" // Specific to this algorithm @@ -85,6 +84,7 @@ PESA::T2VertexBeamSpotTool::T2VertexBeamSpotTool( const std::string& type, const declareProperty("WeightClusterZ", m_weightSeed = true ); declareProperty("ReclusterSplit", m_reclusterSplit = true ); declareProperty("SplitWholeCluster", m_splitWholeCluster = false ); + declareProperty("ClusterPerigee", m_clusterPerigee = "beamspot" ); // Track Selection criteria declareProperty("TrackMinPt", m_minTrackPt = 0.7*GeV ); @@ -125,9 +125,6 @@ PESA::T2VertexBeamSpotTool::T2VertexBeamSpotTool( const std::string& type, const // Single interaction trigger declareProperty("minNpvTrigger", m_minNpvTrigger = 0); declareProperty("maxNpvTrigger", m_maxNpvTrigger = 2); - - - } @@ -145,6 +142,8 @@ StatusCode T2VertexBeamSpotTool::initialize(){ //Retrieve primary vertex fitter tool ATH_CHECK( m_primaryVertexFitterTool.retrieve() ); + m_clusterTrackPerigee = T2TrackClusterer::trackPerigeeFromString(m_clusterPerigee); + return StatusCode::SUCCESS; } @@ -253,9 +252,18 @@ unsigned int T2VertexBeamSpotTool::reconstructVertices( ConstDataVector<TrackCol auto mon = Monitored::Group(m_monTool, timeToSortTracks ); } + // Extract beam spot parameters + SG::ReadCondHandle<InDet::BeamSpotData> beamSpotHandle { m_beamSpotKey, ctx }; + const InDet::BeamSpotData* indetBeamSpot(*beamSpotHandle); + const T2BeamSpot beamSpot(indetBeamSpot); + ATH_MSG_DEBUG( "Beamspot from BeamCondSvc: " << beamSpot); + // Prepare a track clustering algorithm with the given parameters // Should we leave this as a standalone class or merge with the tool? - T2TrackClusterer trackClusterer( m_trackClusDZ, m_trackSeedPt, m_weightSeed, m_vtxNTrkMax ); + T2TrackClusterer trackClusterer( m_trackClusDZ, m_trackSeedPt, m_weightSeed, m_vtxNTrkMax, + m_clusterTrackPerigee ); + + std::vector<double> clusterZ0; // Z0 for each cluster, for monitoring only // Create clusters from the track collection until all its tracks are used while ( ! mySelectedTrackCollection.empty() ) { @@ -270,7 +278,7 @@ unsigned int T2VertexBeamSpotTool::reconstructVertices( ConstDataVector<TrackCol // as the seed. { auto timeToZCluster = Monitored::Timer("TIME_toZCluster"); - trackClusterer.cluster( *mySelectedTrackCollection.asDataVector() ); + trackClusterer.cluster( *mySelectedTrackCollection.asDataVector(), indetBeamSpot ); auto mon = Monitored::Group(m_monTool, timeToZCluster ); } @@ -330,13 +338,6 @@ unsigned int T2VertexBeamSpotTool::reconstructVertices( ConstDataVector<TrackCol // Update vertex counter nVtx++; - // Extract beam spot parameters - SG::ReadCondHandle<InDet::BeamSpotData> beamSpotHandle { m_beamSpotKey, ctx }; - - T2BeamSpot beamSpot(*beamSpotHandle); - - ATH_MSG_DEBUG( "Beamspot from BeamCondSvc: " << beamSpot); - const T2Vertex myVertex( *primaryVertex, vertexTracks, beamSpot, trackClusterer.seedZ0() ); // Monitor all vertices parameters @@ -364,6 +365,13 @@ unsigned int T2VertexBeamSpotTool::reconstructVertices( ConstDataVector<TrackCol auto deltaVtxZ = Monitored::Scalar<double> ( "ClusterDeltaVertexZ", trackClusterer.seedZ0() - myVertex.Z() ); auto mon = Monitored::Group(m_monTool, deltaVtxZ ); + // monitor cluster-cluster delta Z0 + for (double prevClusterZ0: clusterZ0) { + auto clusterClusterDeltaZ = Monitored::Scalar<double>("ClusterClusterDeltaZ0", trackClusterer.seedZ0() - prevClusterZ0); + auto mon = Monitored::Group(m_monTool, clusterClusterDeltaZ); + } + clusterZ0.push_back(trackClusterer.seedZ0()); + // If the vertex is good, splits are requested, and we have enough tracks to split, split them! if ( passVertex && m_nSplitVertices > 1 ) { -- GitLab