CMS 3D CMS Logo

ME0SegmentAlgorithm.cc
Go to the documentation of this file.
1 
8 #include "ME0SegmentAlgorithm.h"
9 #include "MuonSegFit.h"
10 
16 
17 #include <algorithm>
18 #include <cmath>
19 #include <iostream>
20 #include <string>
21 
22 /* Constructor
23  *
24  */
26  : ME0SegmentAlgorithmBase(ps), myName("ME0SegmentAlgorithm") {
27  debug = ps.getUntrackedParameter<bool>("ME0Debug");
28  minHitsPerSegment = ps.getParameter<unsigned int>("minHitsPerSegment");
29  preClustering = ps.getParameter<bool>("preClustering");
30  dXclusBoxMax = ps.getParameter<double>("dXclusBoxMax");
31  dYclusBoxMax = ps.getParameter<double>("dYclusBoxMax");
32  preClustering_useChaining = ps.getParameter<bool>("preClusteringUseChaining");
33  dPhiChainBoxMax = ps.getParameter<double>("dPhiChainBoxMax");
34  dEtaChainBoxMax = ps.getParameter<double>("dEtaChainBoxMax");
35  dTimeChainBoxMax = ps.getParameter<double>("dTimeChainBoxMax");
36  maxRecHitsInCluster = ps.getParameter<int>("maxRecHitsInCluster");
37 
38  edm::LogVerbatim("ME0SegmentAlgorithm")
39  << "[ME0SegmentAlgorithm::ctor] Parameters to build segments :: "
40  << "preClustering = " << preClustering << " preClustering_useChaining = " << preClustering_useChaining
41  << " dPhiChainBoxMax = " << dPhiChainBoxMax << " dEtaChainBoxMax = " << dEtaChainBoxMax
42  << " dTimeChainBoxMax = " << dTimeChainBoxMax << " minHitsPerSegment = " << minHitsPerSegment
43  << " maxRecHitsInCluster = " << maxRecHitsInCluster;
44 }
45 
46 /* Destructor
47  *
48  */
50 
51 std::vector<ME0Segment> ME0SegmentAlgorithm::run(const ME0Chamber* chamber, const HitAndPositionContainer& rechits) {
52 #ifdef EDM_ML_DEBUG // have lines below only compiled when in debug mode
53  ME0DetId chId(chamber->id());
54  edm::LogVerbatim("ME0SegAlgoMM") << "[ME0SegmentAlgorithm::run] build segments in chamber " << chId
55  << " which contains " << rechits.size() << " rechits";
56  for (auto rh = rechits.begin(); rh != rechits.end(); ++rh) {
57  auto me0id = rh->rh->me0Id();
58  auto rhLP = rh->lp;
59  edm::LogVerbatim("ME0SegmentAlgorithm")
60  << "[RecHit :: Loc x = " << std::showpos << std::setw(9) << rhLP.x() << " Loc y = " << std::showpos
61  << std::setw(9) << rhLP.y() << " Time = " << std::showpos << rh->rh->tof() << " -- " << me0id.rawId() << " = "
62  << me0id << " ]";
63  }
64 #endif
65 
66  // pre-cluster rechits and loop over all sub clusters separately
67  std::vector<ME0Segment> segments_temp;
68  std::vector<ME0Segment> segments;
69  ProtoSegments rechits_clusters; // this is a collection of groups of rechits
70 
71  if (preClustering) {
72  // run a pre-clusterer on the given rechits to split obviously separated segment seeds:
74  // it uses X,Y,Z information; there are no configurable parameters used;
75  // the X, Y, Z "cuts" are just (much) wider than reasonable high pt segments
76  rechits_clusters = this->chainHits(chamber, rechits);
77  } else {
78  // it uses X,Y information + configurable parameters
79  rechits_clusters = this->clusterHits(rechits);
80  }
81  // loop over the found clusters:
82  for (auto sub_rechits = rechits_clusters.begin(); sub_rechits != rechits_clusters.end(); ++sub_rechits) {
83  // clear the buffer for the subset of segments:
84  segments_temp.clear();
85  // build the subset of segments:
86  this->buildSegments(chamber, (*sub_rechits), segments_temp);
87  // add the found subset of segments to the collection of all segments in this chamber:
88  segments.insert(segments.end(), segments_temp.begin(), segments_temp.end());
89  }
90  return segments;
91  } else {
93  ptrRH.reserve(rechits.size());
94  for (const auto& rh : rechits)
95  ptrRH.push_back(&rh);
96  this->buildSegments(chamber, ptrRH, segments);
97  return segments;
98  }
99 }
100 
101 // ********************************************************************;
103  ProtoSegments rechits_clusters; // this is a collection of groups of rechits
104 
105  float dXclus_box = 0.0;
106  float dYclus_box = 0.0;
107 
109  seeds.reserve(rechits.size());
110 
111  std::vector<float> running_meanX;
112  running_meanX.reserve(rechits.size());
113  std::vector<float> running_meanY;
114  running_meanY.reserve(rechits.size());
115 
116  std::vector<float> seed_minX;
117  seed_minX.reserve(rechits.size());
118  std::vector<float> seed_maxX;
119  seed_maxX.reserve(rechits.size());
120  std::vector<float> seed_minY;
121  seed_minY.reserve(rechits.size());
122  std::vector<float> seed_maxY;
123  seed_maxY.reserve(rechits.size());
124 
125  // split rechits into subvectors and return vector of vectors:
126  // Loop over rechits
127  // Create one seed per hit
128  for (unsigned int i = 0; i < rechits.size(); ++i) {
129  seeds.push_back(HitAndPositionPtrContainer(1, &rechits[i]));
130 
131  // First added hit in seed defines the mean to which the next hit is compared
132  // for this seed.
133 
134  running_meanX.push_back(rechits[i].lp.x());
135  running_meanY.push_back(rechits[i].lp.y());
136 
137  // set min/max X and Y for box containing the hits in the precluster:
138  seed_minX.push_back(rechits[i].lp.x());
139  seed_maxX.push_back(rechits[i].lp.x());
140  seed_minY.push_back(rechits[i].lp.y());
141  seed_maxY.push_back(rechits[i].lp.y());
142  }
143 
144  // merge clusters that are too close
145  // measure distance between final "running mean"
146  for (size_t NNN = 0; NNN < seeds.size(); ++NNN) {
147  for (size_t MMM = NNN + 1; MMM < seeds.size(); ++MMM) {
148  if (running_meanX[MMM] == running_max || running_meanX[NNN] == running_max) {
149  LogDebug("ME0SegmentAlgorithm") << "[ME0SegmentAlgorithm::clusterHits]: ALARM! Skipping used seeds, this "
150  "should not happen - inform developers!";
151  continue; //skip seeds that have been used
152  }
153 
154  // calculate cut criteria for simple running mean distance cut:
155  //dXclus = fabs(running_meanX[NNN] - running_meanX[MMM]);
156  //dYclus = fabs(running_meanY[NNN] - running_meanY[MMM]);
157  // calculate minmal distance between precluster boxes containing the hits:
158  if (running_meanX[NNN] > running_meanX[MMM])
159  dXclus_box = seed_minX[NNN] - seed_maxX[MMM];
160  else
161  dXclus_box = seed_minX[MMM] - seed_maxX[NNN];
162  if (running_meanY[NNN] > running_meanY[MMM])
163  dYclus_box = seed_minY[NNN] - seed_maxY[MMM];
164  else
165  dYclus_box = seed_minY[MMM] - seed_maxY[NNN];
166 
167  if (dXclus_box < dXclusBoxMax && dYclus_box < dYclusBoxMax) {
168  // merge clusters!
169  // merge by adding seed NNN to seed MMM and erasing seed NNN
170 
171  // calculate running mean for the merged seed:
172  if (seeds[NNN].size() + seeds[MMM].size() != 0) {
173  running_meanX[MMM] = (running_meanX[NNN] * seeds[NNN].size() + running_meanX[MMM] * seeds[MMM].size()) /
174  (seeds[NNN].size() + seeds[MMM].size());
175  running_meanY[MMM] = (running_meanY[NNN] * seeds[NNN].size() + running_meanY[MMM] * seeds[MMM].size()) /
176  (seeds[NNN].size() + seeds[MMM].size());
177  }
178 
179  // update min/max X and Y for box containing the hits in the merged cluster:
180  if (seed_minX[NNN] < seed_minX[MMM])
181  seed_minX[MMM] = seed_minX[NNN];
182  if (seed_maxX[NNN] > seed_maxX[MMM])
183  seed_maxX[MMM] = seed_maxX[NNN];
184  if (seed_minY[NNN] < seed_minY[MMM])
185  seed_minY[MMM] = seed_minY[NNN];
186  if (seed_maxY[NNN] > seed_maxY[MMM])
187  seed_maxY[MMM] = seed_maxY[NNN];
188 
189  // add seed NNN to MMM (lower to larger number)
190  seeds[MMM].insert(seeds[MMM].end(), seeds[NNN].begin(), seeds[NNN].end());
191 
192  // mark seed NNN as used (at the moment just set running mean to 999999.)
193  running_meanX[NNN] = running_max;
194  running_meanY[NNN] = running_max;
195  // we have merged a seed (NNN) to the highter seed (MMM) - need to contimue to
196  // next seed (NNN+1)
197  break;
198  }
199  }
200  }
201 
202  // hand over the final seeds to the output
203  // would be more elegant if we could do the above step with
204  // erasing the merged ones, rather than the
205  for (size_t NNN = 0; NNN < seeds.size(); ++NNN) {
206  if (running_meanX[NNN] == running_max)
207  continue; //skip seeds that have been marked as used up in merging
208  rechits_clusters.push_back(seeds[NNN]);
209  }
210 
211  return rechits_clusters;
212 }
213 
215  const HitAndPositionContainer& rechits) {
216  ProtoSegments rechits_chains;
218  seeds.reserve(rechits.size());
219  std::vector<bool> usedCluster(rechits.size(), false);
220 
221  // split rechits into subvectors and return vector of vectors:
222  // Loop over rechits
223  // Create one seed per hit
224  for (unsigned int i = 0; i < rechits.size(); ++i) {
225  if (std::abs(rechits[i].rh->tof()) > dTimeChainBoxMax)
226  continue;
227  seeds.push_back(HitAndPositionPtrContainer(1, &rechits[i]));
228  }
229 
230  // merge chains that are too close ("touch" each other)
231  for (size_t NNN = 0; NNN < seeds.size(); ++NNN) {
232  for (size_t MMM = NNN + 1; MMM < seeds.size(); ++MMM) {
233  if (usedCluster[MMM] || usedCluster[NNN]) {
234  continue;
235  }
236  // all is in the way we define "good";
237  // try not to "cluster" the hits but to "chain" them;
238  // it does the clustering but also does a better job
239  // for inclined tracks (not clustering them together;
240  // crossed tracks would be still clustered together)
241  // 22.12.09: In fact it is not much more different
242  // than the "clustering", we just introduce another
243  // variable in the game - Z. And it makes sense
244  // to re-introduce Y (or actually wire group mumber)
245  // in a similar way as for the strip number - see
246  // the code below.
247  bool goodToMerge = isGoodToMerge(chamber, seeds[NNN], seeds[MMM]);
248  if (goodToMerge) {
249  // merge chains!
250  // merge by adding seed NNN to seed MMM and erasing seed NNN
251 
252  // add seed NNN to MMM (lower to larger number)
253  seeds[MMM].insert(seeds[MMM].end(), seeds[NNN].begin(), seeds[NNN].end());
254 
255  // mark seed NNN as used
256  usedCluster[NNN] = true;
257  // we have merged a seed (NNN) to the highter seed (MMM) - need to contimue to
258  // next seed (NNN+1)
259  break;
260  }
261  }
262  }
263 
264  // hand over the final seeds to the output
265  // would be more elegant if we could do the above step with
266  // erasing the merged ones, rather than the
267 
268  for (size_t NNN = 0; NNN < seeds.size(); ++NNN) {
269  if (usedCluster[NNN])
270  continue; //skip seeds that have been marked as used up in merging
271  rechits_chains.push_back(seeds[NNN]);
272  }
273 
274  //***************************************************************
275 
276  return rechits_chains;
277 }
278 
280  const HitAndPositionPtrContainer& newChain,
281  const HitAndPositionPtrContainer& oldChain) {
282  for (size_t iRH_new = 0; iRH_new < newChain.size(); ++iRH_new) {
283  GlobalPoint pos_new = newChain[iRH_new]->gp;
284 
285  for (size_t iRH_old = 0; iRH_old < oldChain.size(); ++iRH_old) {
286  GlobalPoint pos_old = oldChain[iRH_old]->gp;
287  // to be chained, two hits need to be in neighbouring layers...
288  // or better allow few missing layers (upto 3 to avoid inefficiencies);
289  // however we'll not make an angle correction because it
290  // worsen the situation in some of the "regular" cases
291  // (not making the correction means that the conditions for
292  // forming a cluster are different if we have missing layers -
293  // this could affect events at the boundaries )
294 
295  // to be chained, two hits need also to be "close" in phi and eta
296  if (std::abs(reco::deltaPhi(float(pos_new.phi()), float(pos_old.phi()))) >= dPhiChainBoxMax)
297  continue;
298  if (std::abs(pos_new.eta() - pos_old.eta()) >= dEtaChainBoxMax)
299  continue;
300  // and the difference in layer index should be < (nlayers-1)
301  if (std::abs(int(newChain[iRH_new]->layer) - int(oldChain[iRH_old]->layer)) >= (chamber->id().nlayers() - 1))
302  continue;
303  // and they should have a time difference compatible with the hypothesis
304  // that the rechits originate from the same particle, but were detected in different layers
305  if (std::abs(newChain[iRH_new]->rh->tof() - oldChain[iRH_old]->rh->tof()) >= dTimeChainBoxMax)
306  continue;
307 
308  return true;
309  }
310  }
311  return false;
312 }
313 
315  const HitAndPositionPtrContainer& rechits,
316  std::vector<ME0Segment>& me0segs) {
317  if (rechits.size() < minHitsPerSegment)
318  return;
319 
320 #ifdef EDM_ML_DEBUG // have lines below only compiled when in debug mode
321  edm::LogVerbatim("ME0SegmentAlgorithm")
322  << "[ME0SegmentAlgorithm::buildSegments] will now try to fit a ME0Segment from collection of " << rechits.size()
323  << " ME0 RecHits";
324  for (auto rh = rechits.begin(); rh != rechits.end(); ++rh) {
325  auto me0id = (*rh)->rh->me0Id();
326  auto rhLP = (*rh)->lp;
327  edm::LogVerbatim("ME0SegmentAlgorithm")
328  << "[RecHit :: Loc x = " << std::showpos << std::setw(9) << rhLP.x() << " Loc y = " << std::showpos
329  << std::setw(9) << rhLP.y() << " Time = " << std::showpos << (*rh)->rh->tof() << " -- " << me0id.rawId()
330  << " = " << me0id << " ]";
331  }
332 #endif
333 
335  std::vector<const ME0RecHit*> bareRHs;
336 
337  // select hits from the ensemble and sort it
338  for (auto rh = rechits.begin(); rh != rechits.end(); rh++) {
339  bareRHs.push_back((*rh)->rh);
340  // for segFit - using local point in chamber frame
341  ME0RecHit* newRH = (*rh)->rh->clone();
342  newRH->setPosition((*rh)->lp);
343 
344  MuonSegFit::MuonRecHitPtr trkRecHit(newRH);
345  muonRecHits.push_back(trkRecHit);
346  }
347 
348  // The actual fit on all hits of the vector of the selected Tracking RecHits:
349  sfit_ = std::make_unique<MuonSegFit>(muonRecHits);
350  bool goodfit = sfit_->fit();
351  edm::LogVerbatim("ME0SegmentAlgorithm") << "[ME0SegmentAlgorithm::buildSegments] ME0Segment fit done";
352 
353  // quit function if fit was not OK
354  if (!goodfit) {
355  for (auto rh : muonRecHits)
356  rh.reset();
357  return;
358  }
359 
360  // obtain all information necessary to make the segment:
361  LocalPoint protoIntercept = sfit_->intercept();
362  LocalVector protoDirection = sfit_->localdir();
363  AlgebraicSymMatrix protoErrors = sfit_->covarianceMatrix();
364  double protoChi2 = sfit_->chi2();
365  // Calculate the central value and uncertainty of the segment time
366  float averageTime = 0.;
367  for (auto rh = rechits.begin(); rh != rechits.end(); ++rh) {
368  averageTime += (*rh)->rh->tof();
369  }
370  if (!rechits.empty())
371  averageTime = averageTime / (rechits.size());
372  float timeUncrt = 0.;
373  for (auto rh = rechits.begin(); rh != rechits.end(); ++rh) {
374  timeUncrt += pow((*rh)->rh->tof() - averageTime, 2);
375  }
376 
377  if (rechits.size() > 1)
378  timeUncrt = timeUncrt / (rechits.size() - 1);
379  timeUncrt = sqrt(timeUncrt);
380 
381  const float dPhi = chamber->computeDeltaPhi(protoIntercept, protoDirection);
382 
383  // save all information inside GEMCSCSegment
384  edm::LogVerbatim("ME0SegmentAlgorithm")
385  << "[ME0SegmentAlgorithm::buildSegments] will now try to make ME0Segment from collection of " << rechits.size()
386  << " ME0 RecHits";
387  ME0Segment tmp(bareRHs, protoIntercept, protoDirection, protoErrors, protoChi2, averageTime, timeUncrt, dPhi);
388 
389  edm::LogVerbatim("ME0SegmentAlgorithm") << "[ME0SegmentAlgorithm::buildSegments] ME0Segment made";
390  edm::LogVerbatim("ME0SegmentAlgorithm") << "[ME0SegmentAlgorithm::buildSegments] " << tmp;
391 
392  for (auto rh : muonRecHits)
393  rh.reset();
394  me0segs.push_back(tmp);
395  return;
396 }
size
Write out results.
std::shared_ptr< TrackingRecHit > MuonRecHitPtr
Definition: MuonSegFit.h:38
constexpr double deltaPhi(double phi1, double phi2)
Definition: deltaPhi.h:26
Log< level::Info, true > LogVerbatim
static constexpr float running_max
T getParameter(std::string const &) const
Definition: ParameterSet.h:307
bool isGoodToMerge(const ME0Chamber *chamber, const HitAndPositionPtrContainer &newChain, const HitAndPositionPtrContainer &oldChain)
void setPosition(LocalPoint pos)
Set local position.
Definition: ME0RecHit.h:52
void buildSegments(const ME0Chamber *chamber, const HitAndPositionPtrContainer &rechits, std::vector< ME0Segment > &me0segs)
Geom::Phi< T > phi() const
Definition: PV3DBase.h:66
T eta() const
Definition: PV3DBase.h:73
unsigned int minHitsPerSegment
std::vector< ME0Segment > run(const ME0Chamber *chamber, const HitAndPositionContainer &rechits) override
std::vector< HitAndPosition > HitAndPositionContainer
ProtoSegments chainHits(const ME0Chamber *chamber, const HitAndPositionContainer &rechits)
~ME0SegmentAlgorithm() override
Destructor.
std::vector< const HitAndPosition * > HitAndPositionPtrContainer
T getUntrackedParameter(std::string const &, T const &) const
ProtoSegments clusterHits(const HitAndPositionContainer &rechits)
Utility functions.
std::unique_ptr< MuonSegFit > sfit_
T sqrt(T t)
Definition: SSEVec.h:23
std::vector< MuonRecHitPtr > MuonRecHitContainer
Definition: MuonSegFit.h:39
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::vector< HitAndPositionPtrContainer > ProtoSegments
Typedefs.
ME0RecHit * clone() const override
Definition: ME0RecHit.cc:26
CLHEP::HepSymMatrix AlgebraicSymMatrix
tmp
align.sh
Definition: createJobs.py:716
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
ME0SegmentAlgorithm(const edm::ParameterSet &ps)
Constructor.
#define LogDebug(id)