CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
CSCGEMMatcher.cc
Go to the documentation of this file.
7 
8 #include <algorithm>
9 #include <cmath>
10 
12  int endcap, unsigned station, unsigned chamber, const edm::ParameterSet& tmbParams, const edm::ParameterSet& conf)
13  : endcap_(endcap), station_(station), chamber_(chamber) {
14  isEven_ = (chamber_ % 2 == 0);
15 
16  // These LogErrors are sanity checks and should not be printed
17  if (station_ == 3 or station_ == 4) {
18  edm::LogError("CSCGEMMatcher") << "Class constructed for a chamber in ME3 or ME4!";
19  };
20 
21  maxDeltaBXALCTGEM_ = tmbParams.getParameter<unsigned>("maxDeltaBXALCTGEM");
22  maxDeltaBXCLCTGEM_ = tmbParams.getParameter<unsigned>("maxDeltaBXCLCTGEM");
23 
24  matchWithHS_ = tmbParams.getParameter<bool>("matchWithHS");
25 
26  maxDeltaHsEven_ = tmbParams.getParameter<unsigned>("maxDeltaHsEven");
27  maxDeltaHsOdd_ = tmbParams.getParameter<unsigned>("maxDeltaHsOdd");
28 
29  if (station_ == 1) {
30  maxDeltaHsEvenME1a_ = tmbParams.getParameter<unsigned>("maxDeltaHsEvenME1a");
31  maxDeltaHsOddME1a_ = tmbParams.getParameter<unsigned>("maxDeltaHsOddME1a");
32  }
33 
34  mitigateSlopeByCosi_ = tmbParams.getParameter<bool>("mitigateSlopeByCosi");
35  assign_gem_csc_bending_ = tmbParams.getParameter<bool>("assignGEMCSCBending");
36 }
37 
39 
41 
42 unsigned CSCGEMMatcher::calculateGEMCSCBending(const CSCCLCTDigi& clct, const GEMInternalCluster& cluster) const {
43  // difference in 1/8-strip number
44  const unsigned diff = std::abs(int(clct.getKeyStrip(8)) - int(cluster.getKeyStrip(8)));
45 
46  unsigned slope = 0;
47 
48  // need LUT to convert differences in 1/8-strips between GEM and CSC to slope
49  if (station_ == 2) {
50  if (isEven_) {
51  if (cluster.id().layer() == 1)
53  else
55  } else {
56  if (cluster.id().layer() == 1)
58  else
60  }
61  } else if (station_ == 1) {
62  if (clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B) { //is in ME1a
63  if (isEven_) {
64  if (cluster.id().layer() == 1)
66  else
68  } else {
69  if (cluster.id().layer() == 1)
71  else
73  }
74  } else {
75  if (isEven_) {
76  if (cluster.id().layer() == 1)
78  else
80  } else {
81  if (cluster.id().layer() == 1)
83  else
85  }
86  }
87  }
88 
89  return slope;
90 }
91 
92 // match an ALCT to GEMInternalCluster by bunch-crossing
95  GEMInternalClusters& output) const {
96  if (!alct.isValid() or clusters.empty())
97  return;
98 
99  // select clusters matched in time
100  for (const auto& cl : clusters) {
101  const unsigned diff = std::abs(int(alct.getBX()) - cl.bx());
102  if (diff <= maxDeltaBXALCTGEM_)
103  output.push_back(cl);
104  }
105 }
106 
107 // match a CLCT to GEMInternalCluster by bunch-crossing
110  GEMInternalClusters& output) const {
111  if (!clct.isValid() or clusters.empty())
112  return;
113 
114  // select clusters matched in time
115  for (const auto& cl : clusters) {
116  const unsigned diff = std::abs(int(clct.getBX()) - cl.bx());
117  if (diff <= maxDeltaBXCLCTGEM_)
118  output.push_back(cl);
119  }
120 }
121 
122 // match an ALCT and CLCT to GEMInternalCluster by bunch-crossing
124  const CSCCLCTDigi& clct,
126  GEMInternalClusters& output) const {
127  // both need to be valid
128  if (!alct.isValid() or !clct.isValid() or clusters.empty())
129  return;
130 
131  // get the single matches
132  GEMInternalClusters alctClusters, clctClusters;
133  matchingClustersBX(alct, clusters, alctClusters);
134  matchingClustersBX(clct, clusters, clctClusters);
135 
136  // get the intersection
137  for (const auto& p : alctClusters) {
138  for (const auto& q : clctClusters) {
139  if (p == q) {
140  output.push_back(p);
141  }
142  }
143  }
144 }
145 
148  GEMInternalClusters& output) const {
149  if (!alct.isValid() or clusters.empty())
150  return;
151 
152  // select clusters matched in wiregroup
153  for (const auto& cl : clusters) {
154  // for now add 10 wiregroups to make sure the matching can be done
155  // this should be quite generous
156  unsigned deltaWG(station_ == 1 ? 10 : 20);
157  if (cl.min_wg() <= alct.getKeyWG() and alct.getKeyWG() <= cl.max_wg() + deltaWG) {
158  output.push_back(cl);
159  }
160  }
161 }
162 
165  GEMInternalClusters& output) const {
166  if (!clct.isValid() or clusters.empty())
167  return;
168 
169  // select clusters matched by 1/2-strip or 1/8-strip
170  for (const auto& cl : clusters) {
171  const bool isMatched(matchWithHS_ ? matchedClusterLocHS(clct, cl) : matchedClusterLocES(clct, cl));
172  if (isMatched) {
173  output.push_back(cl);
174  }
175  }
176 }
177 
178 // match by 1/2-strip
179 bool CSCGEMMatcher::matchedClusterLocHS(const CSCCLCTDigi& clct, const GEMInternalCluster& cluster) const {
180  const bool isME1a(station_ == 1 and clct.getKeyStrip() > CSCConstants::MAX_HALF_STRIP_ME1B);
181 
182  unsigned halfStripDiff = std::abs(int(clct.getKeyStrip(2)) - int(cluster.getKeyStrip(2)));
183  if (isME1a) {
184  halfStripDiff = std::abs(int(clct.getKeyStrip(2)) - int(cluster.getKeyStripME1a(2)));
185  }
186 
187  // 98% acceptance cuts
188  unsigned halfStripCut;
189  if (isEven_) {
190  if (isME1a)
191  halfStripCut = maxDeltaHsEvenME1a_;
192  else
193  halfStripCut = maxDeltaHsEven_;
194  } else {
195  if (isME1a)
196  halfStripCut = maxDeltaHsOddME1a_;
197  else
198  halfStripCut = maxDeltaHsOdd_;
199  }
200  // 10 degree chamber is ~0.18 radian wide
201  // 98% acceptance for clusters in odd/even chambers for muons with 5 GeV
202  // {5, 0.02123785, 0.00928431}
203  // This corresponds to 0.12 and 0.052 fractions of the chamber
204  // or 16 and 7 half-strips
205 
206  // 20 degree chamber is ~0.35 radian wide
207  // 98% acceptance for clusters in odd/even chambers for muons with 5 GeV
208  // {5, 0.01095490, 0.00631625},
209  // This corresponds to 0.031 and 0.018 fractions of the chamber
210  // or 5 and 3 half-strips
211 
212  return halfStripDiff <= halfStripCut;
213 }
214 
215 // match by 1/8-strip
217  // key 1/8-strip
218  int key_es = -1;
219 
220  //modification of DeltaStrip by CLCT slope
221  int SlopeShift = 0;
222  uint16_t baseSlope = 0;
224  baseSlope = mitigatedSlopeByConsistency(clct);
225  else
226  baseSlope = clct.getSlope();
227  int clctSlope = pow(-1, clct.getBend()) * baseSlope;
228 
229  // for coincidences or single clusters in L1
230  if (cl.isCoincidence() or cl.id().layer() == 1) {
231  key_es = cl.layer1_middle_es();
233  key_es = cl.layer1_middle_es_me1a();
234 
235  //set SlopeShift for L1 or Copad case
236  SlopeShift =
237  CSCGEMSlopeCorrector(true, clctSlope); // fixed to facing detectors, must be determined at motherboard level
238  }
239 
240  // for single clusters in L2
241  else if (cl.id().layer() == 2) {
242  key_es = cl.layer2_middle_es();
244  key_es = cl.layer2_middle_es_me1a();
245 
246  //set SlopeShift for L2 case
247  SlopeShift =
248  CSCGEMSlopeCorrector(false, clctSlope); // fixed to facing detectors, must be determined at motherboard level
249 
250  }
251 
252  else
253  edm::LogWarning("CSCGEMMatcher") << "cluster.id().layer =" << cl.id().layer() << " out of acceptable range 1-2!";
254 
255  // matching by 1/8-strip
256  // determine matching window by chamber, assuming facing chambers only are processed
257  int window = chamber_ % 2 == 0 ? 20 : 40;
258 
259  return std::abs(clct.getKeyStrip(8) - key_es + SlopeShift) < window;
260 }
261 
263  const CSCCLCTDigi& clct,
265  GEMInternalClusters& output) const {
266  // both need to be valid
267  if (!alct.isValid() or !clct.isValid() or clusters.empty())
268  return;
269 
270  // get the single matches
271  GEMInternalClusters alctClusters, clctClusters;
272  matchingClustersLoc(alct, clusters, alctClusters);
273  matchingClustersLoc(clct, clusters, clctClusters);
274 
275  // get the intersection
276  for (const auto& p : alctClusters) {
277  for (const auto& q : clctClusters) {
278  if (p == q) {
279  output.push_back(p);
280  }
281  }
282  }
283 }
284 
287  GEMInternalClusters& output) const {
288  if (!alct.isValid() or clusters.empty())
289  return;
290 
291  // match by BX
292  GEMInternalClusters clustersBX;
293  matchingClustersBX(alct, clusters, clustersBX);
294 
295  // match spatially
296  matchingClustersLoc(alct, clustersBX, output);
297 }
298 
301  GEMInternalClusters& output) const {
302  if (!clct.isValid() or clusters.empty())
303  return;
304 
305  // match by BX
306  GEMInternalClusters clustersBX;
307  matchingClustersBX(clct, clusters, clustersBX);
308 
309  // match spatially
310  matchingClustersLoc(clct, clustersBX, output);
311 }
312 
314  const CSCCLCTDigi& clct,
316  GEMInternalClusters& selected) const {
317  // both need to be valid
318  if (!alct.isValid() or !clct.isValid() or clusters.empty())
319  return;
320 
321  // match by BX
322  GEMInternalClusters clustersBX;
323  matchingClustersBX(alct, clct, clusters, clustersBX);
324 
325  // match spatially
326  matchingClustersLoc(alct, clct, clustersBX, selected);
327 }
328 
331  GEMInternalCluster& best) const {
332  if (!alct.isValid() or clusters.empty())
333  return;
334 
335  GEMInternalClusters clustersBXLoc;
336  matchingClustersBXLoc(alct, clusters, clustersBXLoc);
337 
338  // simply pick the first matching one
339  if (!clustersBXLoc.empty())
340  best = clustersBXLoc[0];
341 }
342 
345  GEMInternalCluster& best) const {
346  if (!clct.isValid() or clusters.empty())
347  return;
348 
349  // match by BX
350  GEMInternalClusters clustersBXLoc;
351  matchingClustersBXLoc(clct, clusters, clustersBXLoc);
352 
353  // FIXME - for now: pick the first matching one
354  if (!clustersBXLoc.empty())
355  best = clustersBXLoc[0];
356 }
357 
359  const CSCCLCTDigi& clct,
361  GEMInternalCluster& best) const {
362  // match by BX
363  GEMInternalClusters clustersBXLoc;
364  matchingClustersBXLoc(alct, clct, clusters, clustersBXLoc);
365 
366  // FIXME - for now: pick the first matching one
367  if (!clustersBXLoc.empty())
368  best = clustersBXLoc[0];
369 }
370 
372  //extract hit values from CLCT hit matrix
373  std::vector<std::vector<uint16_t>> CLCTHitMatrix = clct.getHits();
374  int CLCTHits[6] = {-1, -1, -1, -1, -1, -1};
375 
376  for (unsigned layer = 0; layer < CLCTHitMatrix.size(); ++layer) {
377  for (unsigned position = 0; position < CLCTHitMatrix.at(layer).size(); ++position) {
378  const uint16_t value = CLCTHitMatrix.at(layer).at(position);
379  if (value != 0 && value != 65535) {
380  CLCTHits[layer] = (int)value;
381  break;
382  }
383  }
384  }
385 
386  //calculate slope consistency
387  float MinMaxPairDifferences[2] = {999., -999.};
388  for (unsigned First = 0; First < 5; ++First) {
389  //skip empty layers
390  if (CLCTHits[First] == -1)
391  continue;
392  for (unsigned Second = First + 1; Second < 6; ++Second) {
393  //skip empty layers
394  if (CLCTHits[Second] == -1)
395  continue;
396  float PairDifference = (CLCTHits[First] - CLCTHits[Second]) / (float)(Second - First);
397  if (PairDifference < MinMaxPairDifferences[0])
398  MinMaxPairDifferences[0] = PairDifference;
399  if (PairDifference > MinMaxPairDifferences[1])
400  MinMaxPairDifferences[1] = PairDifference;
401  }
402  }
403 
404  //calculate consistency of slope indicator: cosi
405  uint16_t cosi = std::ceil(std::abs(MinMaxPairDifferences[1] - MinMaxPairDifferences[0]));
406 
407  //disambiguate cosi cases
408 
409  //extremely inconsistent track, deprecate slope
410  if (cosi > 3)
411  return 0;
412  //consistent slope, do not change
413  else if (cosi < 2)
414  return clct.getSlope();
415  //need to look up in table 2->1
416  else if (cosi == 2) {
417  if (chamber_ % 2 == 0)
419  else
421  }
422  //need to look up in table 3->1
423  else if (cosi == 3) {
424  if (chamber_ % 2 == 0)
426  else
428  }
429  //just to avoid compiler errors an error code
430  else {
431  return 999;
432  }
433 }
434 
435 int CSCGEMMatcher::CSCGEMSlopeCorrector(bool isL1orCoincidence, int cscSlope) const {
436  int SlopeShift = 0;
437  int SlopeSign = cscSlope / std::abs(cscSlope);
438  //account for slope mitigation by cosi, if opted-in
439  if (mitigateSlopeByCosi_) {
440  //determine cosi-based slope correction
441  if (chamber_ % 2 == 0) {
442  if (isL1orCoincidence)
444  else
446  } else {
447  if (isL1orCoincidence)
449  else
451  }
452  } else {
453  //determine shift by slope correction
454  if (chamber_ % 2 == 0) {
455  if (isL1orCoincidence)
457  else
459  } else {
460  if (isL1orCoincidence)
462  else
464  }
465  }
466  return std::round(SlopeShift * SlopeSign * endcap_);
467 }
unsigned maxDeltaHsOdd_
constexpr int32_t ceil(float num)
void matchingClustersBXLoc(const CSCALCTDigi &alct, const GEMInternalClusters &clusters, GEMInternalClusters &selected) const
uint16_t getKeyStrip(int n=2) const
def window
Definition: svgfig.py:643
uint16_t getKeyStripME1a(int n=2) const
unsigned CSC_slope_corr_L2_ME11_odd(unsigned channel) const
unsigned maxDeltaBXALCTGEM_
bool mitigateSlopeByCosi_
unsigned CSC_slope_cosi_corr_L2_ME11_even(unsigned channel) const
unsigned station_
unsigned CSC_slope_corr_L2_ME11_even(unsigned channel) const
uint16_t getBX() const
return BX
Definition: CSCCLCTDigi.h:123
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventIDconst &, edm::Timestampconst & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
unsigned maxDeltaHsEvenME1a_
uint16_t getBend() const
Definition: CSCCLCTDigi.h:93
unsigned es_diff_slope_L2_ME1a_odd(unsigned es_diff) const
bool isValid() const
check ALCT validity (1 - valid ALCT)
Definition: CSCALCTDigi.h:40
static const double slope[3]
GEMDetId id() const
int layer1_middle_es_me1a() const
uint16_t getBX() const
return BX - five low bits of BXN counter tagged by the ALCT
Definition: CSCALCTDigi.h:73
bool assign_gem_csc_bending_
unsigned maxDeltaHsEven_
unsigned CSC_slope_corr_L1_ME11_odd(unsigned channel) const
unsigned calculateGEMCSCBending(const CSCCLCTDigi &clct, const GEMInternalCluster &cluster) const
Log< level::Error, false > LogError
int layer1_middle_es() const
bool matchedClusterLocES(const CSCCLCTDigi &clct, const GEMInternalCluster &cluster) const
void setESLookupTables(const CSCL1TPLookupTableME11ILT *conf)
void bestClusterBXLoc(const CSCALCTDigi &alct, const GEMInternalClusters &clusters, GEMInternalCluster &best) const
unsigned es_diff_slope_L1_ME1b_even(unsigned es_diff) const
tuple cl
Definition: haddnano.py:49
constexpr std::array< uint8_t, layerIndexSize > layer
unsigned es_diff_slope_L2_ME21_odd(unsigned es_diff) const
CSCGEMMatcher(int endcap, unsigned station, unsigned chamber, const edm::ParameterSet &tmbParams, const edm::ParameterSet &luts)
unsigned es_diff_slope_L1_ME21_even(unsigned es_diff) const
uint16_t getKeyStrip(const uint16_t n=2) const
Definition: CSCCLCTDigi.cc:107
unsigned maxDeltaBXCLCTGEM_
unsigned CSC_slope_corr_L1_ME11_even(unsigned channel) const
unsigned chamber_
unsigned es_diff_slope_L1_ME1a_odd(unsigned es_diff) const
unsigned es_diff_slope_L1_ME1b_odd(unsigned es_diff) const
int CSCGEMSlopeCorrector(const bool isL1orCopad, const int cscSlope) const
void matchingClustersBX(const CSCALCTDigi &alct, const GEMInternalClusters &clusters, GEMInternalClusters &selected) const
uint16_t mitigatedSlopeByConsistency(const CSCCLCTDigi &clct) const
const CSCL1TPLookupTableME11ILT * lookupTableME11ILT_
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
unsigned es_diff_slope_L2_ME1b_even(unsigned es_diff) const
unsigned CSC_slope_cosi_2to1_L1_ME11_odd(unsigned channel) const
bool isValid() const
check CLCT validity (1 - valid CLCT)
Definition: CSCCLCTDigi.h:50
unsigned es_diff_slope_L2_ME1b_odd(unsigned es_diff) const
bool isMatched(TrackingRecHit const &hit)
bool matchedClusterLocHS(const CSCCLCTDigi &clct, const GEMInternalCluster &cluster) const
unsigned CSC_slope_cosi_corr_L1_ME11_odd(unsigned channel) const
unsigned CSC_slope_cosi_2to1_L1_ME11_even(unsigned channel) const
unsigned CSC_slope_cosi_3to1_L1_ME11_odd(unsigned channel) const
int layer2_middle_es() const
unsigned es_diff_slope_L1_ME1a_even(unsigned es_diff) const
int layer2_middle_es_me1a() const
uint16_t getKeyWG() const
return key wire group
Definition: CSCALCTDigi.h:67
constexpr int layer() const
Definition: GEMDetId.h:190
T getParameter(std::string const &) const
Definition: ParameterSet.h:303
const ComparatorContainer & getHits() const
Definition: CSCCLCTDigi.h:176
unsigned endcap_
uint16_t getSlope() const
return the slope
Definition: CSCCLCTDigi.h:74
void matchingClustersLoc(const CSCALCTDigi &alct, const GEMInternalClusters &clusters, GEMInternalClusters &selected) const
unsigned CSC_slope_cosi_corr_L2_ME11_odd(unsigned channel) const
static int position[264][3]
Definition: ReadPGInfo.cc:289
std::vector< GEMInternalCluster > GEMInternalClusters
Definition: CSCGEMMatcher.h:26
unsigned es_diff_slope_L2_ME21_even(unsigned es_diff) const
const CSCL1TPLookupTableME21ILT * lookupTableME21ILT_
unsigned CSC_slope_cosi_corr_L1_ME11_even(unsigned channel) const
Log< level::Warning, false > LogWarning
bool isCoincidence() const
unsigned maxDeltaHsOddME1a_
unsigned es_diff_slope_L1_ME21_odd(unsigned es_diff) const
unsigned CSC_slope_cosi_3to1_L1_ME11_even(unsigned channel) const
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
unsigned es_diff_slope_L2_ME1a_even(unsigned es_diff) const