ATLAS Offline Software
AFPSiDLinRegTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
10 
11 
13 
14 
16  const std::string& name,
17  const IInterface* parent ) :
18  base_class( type, name, parent )
19 {
20 }
21 
22 
24 {
25  if(m_trackSelection=="loose" || m_trackSelection=="Loose")
26  {
27  m_selectionFunction = [](const std::vector<const xAOD::AFPSiHitsCluster*>&) { return true; };
28  }
29  else if(m_trackSelection=="medium" || m_trackSelection=="Medium")
30  {
31  m_selectionFunction = [this](const std::vector<const xAOD::AFPSiHitsCluster*>& t) {
32  std::vector<int> plane{0, 0, 0, 0};
33 
34  for (auto&& cluster : t) {
35  const int p = cluster->pixelLayerID();
36  plane[p]++;
37  }
38 
39  auto HasAnyClusters = [](int n) { return n > 0; };
40 
41  return std::count_if(plane.begin(), plane.end(), HasAnyClusters) >= m_minimalNumberOfPlanesInTrack;
42  };
43  }
44  else if(m_trackSelection=="tight" || m_trackSelection=="Tight")
45  {
46  m_selectionFunction = [this](const std::vector<const xAOD::AFPSiHitsCluster*>& t) {
47  std::vector<int> plane{0, 0, 0, 0};
48 
49  for (auto&& cluster : t) {
50  const int p = cluster->pixelLayerID();
51  plane[p]++;
52  }
53 
54  auto HasMultipleClusters = [](int n) { return n > 1; };
55 
56  if (std::any_of(plane.begin(), plane.end(), HasMultipleClusters)) { return false; }
57 
58  // Check number of planes (cluster/plane == 1)
59  if (t.size() < m_minimalNumberOfPlanesInTrack) { return false; }
60 
61  return true;
62  };
63  }
64  else
65  {
66  ATH_MSG_ERROR("unknown trackSelection "<<m_trackSelection<<", allowed values are \"Loose\", \"Medium\", or \"Tight\" ");
67  return StatusCode::FAILURE;
68  }
69 
70  CHECK( m_hitsClusterContainerKey.initialize() );
71 
72  return StatusCode::SUCCESS;
73 }
74 
75 
77 {
78  // All clusters should be in same station, so no need for checking
79 
80  const double xa = a->xLocal();
81  const double ya = a->yLocal();
82 
83  const double xb = b->xLocal();
84  const double yb = b->yLocal();
85 
86  const double dx = xa - xb;
87  const double dy = ya - yb;
89  return dx * dx + dy * dy <= maxDistanceSq;
90 }
91 
92 
93 std::vector<const xAOD::AFPSiHitsCluster*> AFPSiDLinRegTool::findClusterAroundElement(std::list<const xAOD::AFPSiHitsCluster*>& toJoin, const xAOD::AFPSiHitsCluster* init) const
94 {
95  // Push initial cluster
96  std::vector<const xAOD::AFPSiHitsCluster*> track;
97  track.push_back(init);
98 
99  std::vector<const xAOD::AFPSiHitsCluster*> newNeighbours;
100 
101  // Repeat while new neighbours are found
102  do {
103  newNeighbours.clear();
104  for (auto&& b : toJoin) {
105  bool isNew = false;
106  for (auto&& a : track) {
107  if (areNeighbours(a, b)) { isNew = true; }
108  }
109 
110  if (isNew) {
111  newNeighbours.push_back(b);
112  track.push_back(b);
113  }
114  }
115 
116  // Clustered clusters are taken out from "clusters" container
117  for (auto& t : newNeighbours) {
118  toJoin.remove(t);
119  }
120 
121  } while (!newNeighbours.empty());
122 
123  return track;
124 }
125 
126 
127 std::pair<double, double> AFPSiDLinRegTool::linearRegression(const std::vector<std::pair<double, double>>& YX) const
128 {
129  // here, "x" is Z axis and "y" is X or Y axis
130 
131  double meanx = 0, meany = 0;
132  for (const auto& [y, x] : YX) {
133  meany += y;
134  meanx += x;
135  }
136  meanx /= YX.size();
137  meany /= YX.size();
138 
139  double numerator = 0, denominator = 0;
140  for (const auto& [y, x] : YX) {
141  const double dy = y - meany;
142  const double dx = x - meanx;
143 
144  numerator += dx * dy;
145  denominator += dx * dx;
146  }
147 
148  const double slope = numerator / denominator;
149  const double position = meany - slope * meanx;
150 
151  return {position, slope};
152 }
153 
154 
155 StatusCode AFPSiDLinRegTool::reconstructTracks(std::unique_ptr<xAOD::AFPTrackContainer>& outputContainer, const EventContext& ctx) const
156 {
158  if(!clusters.isValid())
159  {
160  // this is allowed, there might be no AFP data in the input
161  return StatusCode::SUCCESS;
162  }
163 
164  // Select clusters in given station
165  std::list<const xAOD::AFPSiHitsCluster*> clustersInStation;
166  std::copy_if(clusters->begin(), clusters->end(), std::back_inserter(clustersInStation),
167  [this](auto cluster) { return cluster->stationID() == m_stationID; });
168 
169  ATH_MSG_DEBUG("clusters in " << m_stationID << " size: " << clustersInStation.size());
170 
171 
172  // Loop until all clusters are used
173  while (!clustersInStation.empty())
174  {
175  // Take first element from the list...
176  const auto *const initialCluster = clustersInStation.front();
177  clustersInStation.pop_front();
178 
179  // ...and find other clusters around it
180  const auto clusterOfClusters = findClusterAroundElement(clustersInStation, initialCluster);
181 
182  // If track candidate does not pass chosen selection, skip it
183  if (!m_selectionFunction(clusterOfClusters)) {
184  ATH_MSG_DEBUG("track candidate of size " << clusterOfClusters.size() << " did not pass selection.");
185  continue;
186  }
187 
188  auto *track = outputContainer->push_back(std::make_unique<xAOD::AFPTrack>());
189 
190  // Set stationID
191  track->setStationID(m_stationID);
192 
193  // Add links to clusters
194  for (const auto *const cluster : clusterOfClusters) {
196  clusterLink.toContainedElement(*clusters, cluster);
197  track->addCluster(clusterLink);
198  }
199 
200  const int nClusters = track->clusters().size();
201 
202  if(nClusters>0)
203  {
204  track->setNClusters(nClusters);
205  }
206  else
207  {
208  ATH_MSG_DEBUG("track candidate has 0 clusters, erasing ");
209  outputContainer->pop_back();
210  continue;
211  }
212 
213  // Fit the clusters with a line in X and Y direction along Z
214  double x = 0.;
215  double y = 0.;
216  double xSlope = 0.;
217  double ySlope = 0.;
218  double chi2 = 0.;
219 
220  if (nClusters == 1) {
221  x = (*(track->clusters().at(0)))->xLocal();
222  y = (*(track->clusters().at(0)))->yLocal();
223  }
224  else
225  {
226  std::vector<std::pair<double, double>> XZ;
227  std::vector<std::pair<double, double>> YZ;
228 
229  for (int i = 0; i < nClusters; i++) {
230  const xAOD::AFPSiHitsCluster* cluster = *(track->clusters().at(i));
231 
232  XZ.emplace_back(cluster->xLocal(), cluster->zLocal());
233  YZ.emplace_back(cluster->yLocal(), cluster->zLocal());
234  }
235 
236  auto linregx = linearRegression(XZ);
237  auto linregy = linearRegression(YZ);
238 
239  std::tie(x, xSlope) = linregx;
240  std::tie(y, ySlope) = linregy;
241 
242  for (int i = 0; i < nClusters; i++) {
243  const xAOD::AFPSiHitsCluster* cluster = *(track->clusters().at(i));
244 
245  const double z = cluster->zLocal();
246  const double ex = cluster->xLocalErr();
247  const double ey = cluster->yLocalErr();
248 
249  const double dx = cluster->xLocal() - (x + xSlope * z);
250  const double dy = cluster->yLocal() - (y + ySlope * z);
251 
252  chi2 += dx * dx / (ex * ex);
253  chi2 += dy * dy / (ey * ey);
254  }
255  }
256 
257  // Set track properties
258  track->setChi2(chi2);
259  track->setXLocal(x);
260  track->setXSlope(xSlope);
261  track->setYLocal(y);
262  track->setYSlope(ySlope);
263  track->setZLocal(0.); // because positions of x/y are calculated at z=0
264 
266 
267  std::vector<int> clustersPlane{0, 0, 0, 0};
268  for (const auto& cl : track->clusters()) {
269  ++clustersPlane[(*cl)->pixelLayerID()];
270  }
271  auto HasNoClusters = [](int n) { return n == 0; };
272  track->setNHoles(std::count_if(clustersPlane.begin(), clustersPlane.end(), HasNoClusters));
273 
274 
275  ATH_MSG_DEBUG("new track with " << track->clusters().size() << " clusters, x: " << track->xLocal()
276  << ", y: " << track->yLocal() << ", sx: " << track->xSlope()
277  << ", sy: " << track->ySlope() << ", chi2: " << track->chi2());
278  for (auto&& cluster : track->clusters())
279  {
280  ATH_MSG_DEBUG('\t' << (*cluster)->xLocal() << " " << (*cluster)->yLocal() << " " << (*cluster)->zLocal());
281  }
282  }
283 
284  return StatusCode::SUCCESS;
285 }
AFPSiDLinRegTool::m_minimalNumberOfPlanesInTrack
Gaudi::Property< unsigned int > m_minimalNumberOfPlanesInTrack
Minimal numer of planes required for track candidate.
Definition: AFPSiDLinRegTool.h:79
AFPSiDLinRegTool::m_allowedDistanceBetweenClustersInTrack
Gaudi::Property< double > m_allowedDistanceBetweenClustersInTrack
Maximum allowed distance between clusters to be considered coming from the same proton.
Definition: AFPSiDLinRegTool.h:70
AFPSiDLinRegTool::m_selectionFunction
std::function< bool(const std::vector< const xAOD::AFPSiHitsCluster * > &)> m_selectionFunction
Definition: AFPSiDLinRegTool.h:82
AFPSiDLinRegTool::linearRegression
std::pair< double, double > linearRegression(const std::vector< std::pair< double, double >> &YX) const
Simple linear regression Used to calculate track postions and slopes.
Definition: AFPSiDLinRegTool.cxx:127
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
DataModelTestDataCommonDict::xa
std::vector< DMTest::B > xa
Definition: DataModelTestDataCommonDict.h:54
AFPSiDLinRegTool::initialize
virtual StatusCode initialize() override
Read parameters from job options and print tool configuration.
Definition: AFPSiDLinRegTool.cxx:23
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
AFPSiDLinRegTool::m_hitsClusterContainerKey
SG::ReadHandleKey< xAOD::AFPSiHitsClusterContainer > m_hitsClusterContainerKey
Name of the xAOD container with clusters to be used in track reconstruction.
Definition: AFPSiDLinRegTool.h:85
x
#define x
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
lumiFormat.i
int i
Definition: lumiFormat.py:85
z
#define z
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
AFPSiDLinRegTool::findClusterAroundElement
std::vector< const xAOD::AFPSiHitsCluster * > findClusterAroundElement(std::list< const xAOD::AFPSiHitsCluster * > &toJoin, const xAOD::AFPSiHitsCluster *init) const
Looks for cluster around init cluster.
Definition: AFPSiDLinRegTool.cxx:93
chi2
double chi2(TH1 *h0, TH1 *h1)
Definition: comparitor.cxx:522
test_pyathena.parent
parent
Definition: test_pyathena.py:15
AnalysisUtils::copy_if
Out copy_if(In first, const In &last, Out res, const Pred &p)
Definition: IFilterUtils.h:30
xAOD::AFPSiHitsCluster_v1::xLocal
float xLocal() const
Cluster position along X axis in station local coordinate system.
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
AFPSiDLinRegTool::reconstructTracks
StatusCode reconstructTracks(std::unique_ptr< xAOD::AFPTrackContainer > &outputContainer, const EventContext &ctx) const override
Reconstructs tracks properties from track candidates.
Definition: AFPSiDLinRegTool.cxx:155
ReadTripsProbsFromCool.denominator
denominator
Definition: ReadTripsProbsFromCool.py:96
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
python.PyKernel.init
def init(v_theApp, v_rootStream=None)
Definition: PyKernel.py:45
DataModelTestDataCommonDict::xb
DMTest::CView::Pers_t xb
Definition: DataModelTestDataCommonDict.h:55
AFPSiDLinRegTool.h
Header file for AFPSiDLinRegTool used in tracks reconstruction. Adapted from AfpAnalysisToolbox.
makeTRTBarrelCans.dy
tuple dy
Definition: makeTRTBarrelCans.py:21
a
TList * a
Definition: liststreamerinfos.cxx:10
y
#define y
AFPSiDLinRegTool::areNeighbours
bool areNeighbours(const xAOD::AFPSiHitsCluster *a, const xAOD::AFPSiHitsCluster *b) const
Checks if clusters are neighbours Compares distance between them to m_allowedDistanceBetweenClustersI...
Definition: AFPSiDLinRegTool.cxx:76
DataVector::pop_back
void pop_back()
Remove the last element from the collection.
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
makeTRTBarrelCans.dx
tuple dx
Definition: makeTRTBarrelCans.py:20
RunTileMonitoring.clusters
clusters
Definition: RunTileMonitoring.py:133
AFPSiDLinRegTool::AFPSiDLinRegTool
AFPSiDLinRegTool(const std::string &type, const std::string &name, const IInterface *parent)
Definition: AFPSiDLinRegTool.cxx:15
xAOD::AFPSiHitsCluster_v1::xLocalErr
float xLocalErr() const
Uncertainty of cluster position along X axis in station local coordinate system.
xAOD::track
@ track
Definition: TrackingPrimitives.h:512
xAOD::AFPSiHitsCluster_v1
Class representing a cluster of AFP pixel hits.
Definition: AFPSiHitsCluster_v1.h:32
AFPSiDLinRegTool::m_trackSelection
Gaudi::Property< std::string > m_trackSelection
Track selection type:
Definition: AFPSiDLinRegTool.h:76
xAOD::AFPSiHitsCluster_v1::yLocal
float yLocal() const
Cluster position along Y axis in station local coordinate system.
AFPSiDLinRegTool::m_stationID
Gaudi::Property< int > m_stationID
AFP station ID for which tracks will be reconstructed.
Definition: AFPSiDLinRegTool.h:67
dq_make_web_display.cl
cl
print [x.__class__ for x in toList(dqregion.getSubRegions()) ]
Definition: dq_make_web_display.py:26
xAOD::AFPSiHitsCluster_v1::zLocal
float zLocal() const
Cluster position along Z axis in station local coordinate system.
xAOD::AFPTrackRecoAlgID::linReg
static constexpr int linReg
linear regression algorithm id=1
Definition: AFPTrackRecoAlgID.h:48
xAOD::AFPSiHitsCluster_v1::yLocalErr
float yLocalErr() const
Uncertainty of cluster position along Y axis in station local coordinate system.