CMS 3D CMS Logo

MuonSelectors.cc
Go to the documentation of this file.
7 
8 namespace muon {
11  bool found = false;
12  for (int i = 0; selectionTypeStringToEnumMap[i].label && (!found); ++i)
13  if (!strcmp(label.c_str(), selectionTypeStringToEnumMap[i].label)) {
14  found = true;
16  }
17 
18  // in case of unrecognized selection type
19  if (!found)
20  throw cms::Exception("MuonSelectorError") << label << " is not a recognized SelectionType";
21  return value;
22  }
23 
26  bool found = false;
27  for (int i = 0; selectorStringToEnumMap[i].label && (!found); ++i)
28  if (!strcmp(label.c_str(), selectorStringToEnumMap[i].label)) {
29  found = true;
31  }
32 
33  // in case of unrecognized selection type
34  if (!found)
35  throw cms::Exception("MuonSelectorError") << label << " is not a recognized reco::Muon::Selector";
36  return value;
37  }
38 } // namespace muon
39 
41  double maxChamberDist,
42  double maxChamberDistPull,
44  unsigned int theMask = 0;
45 
46  for (int stationIdx = 1; stationIdx < 5; ++stationIdx) {
47  for (int detectorIdx = 1; detectorIdx < 3; ++detectorIdx) {
48  float dist = muon.trackDist(stationIdx, detectorIdx, arbitrationType);
49  if (dist < maxChamberDist &&
50  dist < maxChamberDistPull * muon.trackDistErr(stationIdx, detectorIdx, arbitrationType))
51  theMask += 1 << ((stationIdx - 1) + 4 * (detectorIdx - 1));
52  }
53  }
54  return theMask;
55 }
56 
57 // ------------ method to calculate the calo compatibility for a track with matched muon info ------------
58 float muon::caloCompatibility(const reco::Muon& muon) { return muon.caloCompatibility(); }
59 
60 // ------------ method to calculate the segment compatibility for a track with matched muon info ------------
62  bool use_weight_regain_at_chamber_boundary = true;
63  bool use_match_dist_penalty = true;
64 
65  int nr_of_stations_crossed = 0;
66  int nr_of_stations_with_segment = 0;
67  std::vector<int> stations_w_track(8);
68  std::vector<int> station_has_segmentmatch(8);
69  std::vector<int> station_was_crossed(8);
70  std::vector<float> stations_w_track_at_boundary(8);
71  std::vector<float> station_weight(8);
72  int position_in_stations = 0;
73  float full_weight = 0.;
74 
75  for (int i = 1; i <= 8; ++i) {
76  // ********************************************************;
77  // *** fill local info for this muon (do some counting) ***;
78  // ************** begin ***********************************;
79  if (i <= 4) { // this is the section for the DTs
80  float thisTrackDist = muon.trackDist(i, 1, arbitrationType);
81  if (thisTrackDist < 999999) { //current "raw" info that a track is close to a chamber
82  ++nr_of_stations_crossed;
83  station_was_crossed[i - 1] = 1;
84  if (thisTrackDist > -10.)
85  stations_w_track_at_boundary[i - 1] = thisTrackDist;
86  else
87  stations_w_track_at_boundary[i - 1] = 0.;
88  }
89  //current "raw" info that a segment is matched to the current track
90  if (muon.segmentX(i, 1, arbitrationType) < 999999) {
91  ++nr_of_stations_with_segment;
92  station_has_segmentmatch[i - 1] = 1;
93  }
94  } else { // this is the section for the CSCs
95  float thisTrackDist = muon.trackDist(i - 4, 2, arbitrationType);
96  if (thisTrackDist < 999999) { //current "raw" info that a track is close to a chamber
97  ++nr_of_stations_crossed;
98  station_was_crossed[i - 1] = 1;
99  if (thisTrackDist > -10.)
100  stations_w_track_at_boundary[i - 1] = thisTrackDist;
101  else
102  stations_w_track_at_boundary[i - 1] = 0.;
103  }
104  //current "raw" info that a segment is matched to the current track
105  if (muon.segmentX(i - 4, 2, arbitrationType) < 999999) {
106  ++nr_of_stations_with_segment;
107  station_has_segmentmatch[i - 1] = 1;
108  }
109  }
110  // rough estimation of chamber border efficiency (should be parametrized better, this is just a quick guess):
111  // TF1 * merf = new TF1("merf","-0.5*(TMath::Erf(x/6.)-1)",-100,100);
112  // use above value to "unpunish" missing segment if close to border, i.e. rather than not adding any weight, add
113  // the one from the function. Only for dist ~> -10 cm, else full punish!.
114 
115  // ********************************************************;
116  // *** fill local info for this muon (do some counting) ***;
117  // ************** end *************************************;
118  }
119 
120  // ********************************************************;
121  // *** calculate weights for each station *****************;
122  // ************** begin ***********************************;
123  // const float slope = 0.5;
124  // const float attenuate_weight_regain = 1.;
125  // if attenuate_weight_regain < 1., additional punishment if track is close to boundary and no segment
126  const float attenuate_weight_regain = 0.5;
127 
128  for (int i = 1; i <= 8; ++i) { // loop over all possible stations
129 
130  // first set all weights if a station has been crossed
131  // later penalize if a station did not have a matching segment
132 
133  //old logic if(station_has_segmentmatch[i-1] > 0 ) { // the track has an associated segment at the current station
134  if (station_was_crossed[i - 1] > 0) { // the track crossed this chamber (or was nearby)
135  // - Apply a weight depending on the "depth" of the muon passage.
136  // - The station_weight is later reduced for stations with badly matched segments.
137  // - Even if there is no segment but the track passes close to a chamber boundary, the
138  // weight is set non zero and can go up to 0.5 of the full weight if the track is quite
139  // far from any station.
140  ++position_in_stations;
141 
142  switch (nr_of_stations_crossed) { // define different weights depending on how many stations were crossed
143  case 1:
144  station_weight[i - 1] = 1.f;
145  break;
146  case 2:
147  if (position_in_stations == 1)
148  station_weight[i - 1] = 0.33f;
149  else
150  station_weight[i - 1] = 0.67f;
151  break;
152  case 3:
153  if (position_in_stations == 1)
154  station_weight[i - 1] = 0.23f;
155  else if (position_in_stations == 2)
156  station_weight[i - 1] = 0.33f;
157  else
158  station_weight[i - 1] = 0.44f;
159  break;
160  case 4:
161  if (position_in_stations == 1)
162  station_weight[i - 1] = 0.10f;
163  else if (position_in_stations == 2)
164  station_weight[i - 1] = 0.20f;
165  else if (position_in_stations == 3)
166  station_weight[i - 1] = 0.30f;
167  else
168  station_weight[i - 1] = 0.40f;
169  break;
170 
171  default:
172  // LogTrace("MuonIdentification")<<" // Message: A muon candidate track has more than 4 stations with matching segments.";
173  // LogTrace("MuonIdentification")<<" // Did not expect this - please let me know: ibloch@fnal.gov";
174  // for all other cases
175  station_weight[i - 1] = 1.f / nr_of_stations_crossed;
176  }
177 
178  if (use_weight_regain_at_chamber_boundary) { // reconstitute some weight if there is no match but the segment is close to a boundary:
179  if (station_has_segmentmatch[i - 1] <= 0 && stations_w_track_at_boundary[i - 1] != 0.) {
180  // if segment is not present but track in inefficient region, do not count as "missing match" but add some reduced weight.
181  // original "match weight" is currently reduced by at least attenuate_weight_regain, variing with an error function down to 0 if the track is
182  // inside the chamber.
183  // remark: the additional scale of 0.5 normalizes Err to run from 0 to 1 in y
184  station_weight[i - 1] = station_weight[i - 1] * attenuate_weight_regain * 0.5f *
185  (std::erf(stations_w_track_at_boundary[i - 1] / 6.f) + 1.f);
186  } else if (station_has_segmentmatch[i - 1] <= 0 &&
187  stations_w_track_at_boundary[i - 1] == 0.f) { // no segment match and track well inside chamber
188  // full penalization
189  station_weight[i - 1] = 0.f;
190  }
191  } else { // always fully penalize tracks with no matching segment, whether the segment is close to the boundary or not.
192  if (station_has_segmentmatch[i - 1] <= 0)
193  station_weight[i - 1] = 0.f;
194  }
195 
196  // if track has matching segment, but the matching is not high quality, penalize
197  if (station_has_segmentmatch[i - 1] > 0) {
198  if (i <= 4) { // we are in the DTs
199  if (muon.dY(i, 1, arbitrationType) < 999999.f &&
200  muon.dX(i, 1, arbitrationType) < 999999.f) { // have both X and Y match
201  const float pullTot2 =
202  std::pow(muon.pullX(i, 1, arbitrationType), 2.) + std::pow(muon.pullY(i, 1, arbitrationType), 2.);
203  if (pullTot2 > 1.f) {
204  const float dxy2 =
205  std::pow(muon.dX(i, 1, arbitrationType), 2.) + std::pow(muon.dY(i, 1, arbitrationType), 2.);
206  // reduce weight
207  if (use_match_dist_penalty) {
208  // only use pull if 3 sigma is not smaller than 3 cm
209  if (dxy2 < 9.f && pullTot2 > 9.f) {
210  if (dxy2 > 1.f)
211  station_weight[i - 1] *= 1.f / std::pow(dxy2, .125);
212  } else {
213  station_weight[i - 1] *= 1.f / std::pow(pullTot2, .125);
214  }
215  }
216  }
217  } else if (muon.dY(i, 1, arbitrationType) >= 999999.f) { // has no match in Y
218  // has a match in X. Pull larger that 1 to avoid increasing the weight (just penalize, don't anti-penalize)
219  if (muon.pullX(i, 1, arbitrationType) > 1.f) {
220  // reduce weight
221  if (use_match_dist_penalty) {
222  // only use pull if 3 sigma is not smaller than 3 cm
223  if (muon.dX(i, 1, arbitrationType) < 3.f && muon.pullX(i, 1, arbitrationType) > 3.f) {
224  if (muon.dX(i, 1, arbitrationType) > 1.f)
225  station_weight[i - 1] *= 1.f / std::pow(muon.dX(i, 1, arbitrationType), .25);
226  } else {
227  station_weight[i - 1] *= 1.f / std::pow(muon.pullX(i, 1, arbitrationType), .25);
228  }
229  }
230  }
231  } else { // has no match in X
232  // has a match in Y. Pull larger that 1 to avoid increasing the weight (just penalize, don't anti-penalize)
233  if (muon.pullY(i, 1, arbitrationType) > 1.f) {
234  // reduce weight
235  if (use_match_dist_penalty) {
236  // only use pull if 3 sigma is not smaller than 3 cm
237  if (muon.dY(i, 1, arbitrationType) < 3. && muon.pullY(i, 1, arbitrationType) > 3.) {
238  if (muon.dY(i, 1, arbitrationType) > 1.f)
239  station_weight[i - 1] *= 1.f / std::pow(muon.dY(i, 1, arbitrationType), .25);
240  } else {
241  station_weight[i - 1] *= 1.f / std::pow(muon.pullY(i, 1, arbitrationType), .25);
242  }
243  }
244  }
245  }
246  } else { // We are in the CSCs
247  const float pullTot2 =
248  std::pow(muon.pullX(i - 4, 2, arbitrationType), 2.) + std::pow(muon.pullY(i - 4, 2, arbitrationType), 2.);
249  if (pullTot2 > 1.f) {
250  // reduce weight
251  if (use_match_dist_penalty) {
252  const float dxy2 =
253  std::pow(muon.dX(i - 4, 2, arbitrationType), 2.) + std::pow(muon.dY(i - 4, 2, arbitrationType), 2.);
254  // only use pull if 3 sigma is not smaller than 3 cm
255  if (dxy2 < 9.f && pullTot2 > 9.f) {
256  if (dxy2 > 1.f)
257  station_weight[i - 1] *= 1.f / std::pow(dxy2, .125);
258  } else {
259  station_weight[i - 1] *= 1.f / std::pow(pullTot2, .125);
260  }
261  }
262  }
263  }
264  }
265 
266  // Thoughts:
267  // - should penalize if the segment has only x OR y info
268  // - should also use the segment direction, as it now works!
269 
270  } else { // track did not pass a chamber in this station - just reset weight
271  station_weight[i - 1] = 0.f;
272  }
273 
274  //increment final weight for muon:
275  full_weight += station_weight[i - 1];
276  }
277 
278  // if we don't expect any matches, we set the compatibility to
279  // 0.5 as the track is as compatible with a muon as it is with
280  // background - we should maybe rather set it to -0.5!
281  if (nr_of_stations_crossed == 0) {
282  // full_weight = attenuate_weight_regain*0.5;
283  full_weight = 0.5f;
284  }
285 
286  // ********************************************************;
287  // *** calculate weights for each station *****************;
288  // ************** end *************************************;
289 
290  return full_weight;
291 }
292 
295  double minCompatibility,
297  if (!muon.isMatchesValid())
298  return false;
299  bool goodMuon = false;
300 
301  switch (type) {
302  case TM2DCompatibility:
303  // Simplistic first cut in the 2D segment- vs calo-compatibility plane. Will have to be refined!
304  if (((0.8 * caloCompatibility(muon)) + (1.2 * segmentCompatibility(muon, arbitrationType))) > minCompatibility)
305  goodMuon = true;
306  else
307  goodMuon = false;
308  return goodMuon;
309  break;
310  default:
311  // LogTrace("MuonIdentification")<<" // Invalid Algorithm Type called!";
312  goodMuon = false;
313  return goodMuon;
314  break;
315  }
316 }
317 
320  int minNumberOfMatches,
321  double maxAbsDx,
322  double maxAbsPullX,
323  double maxAbsDy,
324  double maxAbsPullY,
325  double maxChamberDist,
326  double maxChamberDistPull,
328  bool syncMinNMatchesNRequiredStationsInBarrelOnly,
329  bool applyAlsoAngularCuts) {
330  if (!muon.isMatchesValid())
331  return false;
332  bool goodMuon = false;
333 
334  if (type == TMLastStation) {
335  // To satisfy my own paranoia, if the user specifies that the
336  // minimum number of matches is zero, then return true.
337  if (minNumberOfMatches == 0)
338  return true;
339 
340  unsigned int theStationMask = muon.stationMask(arbitrationType);
341  unsigned int theRequiredStationMask =
342  RequiredStationMask(muon, maxChamberDist, maxChamberDistPull, arbitrationType);
343 
344  // Require that there be at least a minimum number of segments
345  int numSegs = 0;
346  int numRequiredStations = 0;
347  for (int it = 0; it < 8; ++it) {
348  if (theStationMask & 1 << it)
349  ++numSegs;
350  if (theRequiredStationMask & 1 << it)
351  ++numRequiredStations;
352  }
353 
354  // Make sure the minimum number of matches is not greater than
355  // the number of required stations but still greater than zero
356  if (syncMinNMatchesNRequiredStationsInBarrelOnly) {
357  // Note that we only do this in the barrel region!
358  if (std::abs(muon.eta()) < 1.2) {
359  if (minNumberOfMatches > numRequiredStations)
360  minNumberOfMatches = numRequiredStations;
361  if (minNumberOfMatches < 1) //SK: this only happens for negative values
362  minNumberOfMatches = 1;
363  }
364  } else {
365  if (minNumberOfMatches > numRequiredStations)
366  minNumberOfMatches = numRequiredStations;
367  if (minNumberOfMatches < 1) //SK: this only happens for negative values
368  minNumberOfMatches = 1;
369  }
370 
371  if (numSegs >= minNumberOfMatches)
372  goodMuon = true;
373 
374  // Require that last required station have segment
375  // If there are zero required stations keep track
376  // of the last station with a segment so that we may
377  // apply the quality cuts below to it instead
378  int lastSegBit = 0;
379  if (theRequiredStationMask) {
380  for (int stationIdx = 7; stationIdx >= 0; --stationIdx)
381  if (theRequiredStationMask & 1 << stationIdx) {
382  if (theStationMask & 1 << stationIdx) {
383  lastSegBit = stationIdx;
384  goodMuon &= 1;
385  break;
386  } else {
387  goodMuon = false;
388  break;
389  }
390  }
391  } else {
392  for (int stationIdx = 7; stationIdx >= 0; --stationIdx)
393  if (theStationMask & 1 << stationIdx) {
394  lastSegBit = stationIdx;
395  break;
396  }
397  }
398 
399  if (!goodMuon)
400  return false;
401 
402  // Impose pull cuts on last segment
403  int station = 0, detector = 0;
404  station = lastSegBit < 4 ? lastSegBit + 1 : lastSegBit - 3;
405  detector = lastSegBit < 4 ? 1 : 2;
406 
407  // Check x information
408  if (std::abs(muon.pullX(station, detector, arbitrationType, true)) > maxAbsPullX &&
410  return false;
411 
412  if (applyAlsoAngularCuts && std::abs(muon.pullDxDz(station, detector, arbitrationType, true)) > maxAbsPullX)
413  return false;
414 
415  // Is this a tight algorithm, i.e. do we bother to check y information?
416  if (maxAbsDy < 999999) { // really if maxAbsDy < 1E9 as currently defined
417 
418  // Check y information
419  if (detector == 2) { // CSC
420  if (std::abs(muon.pullY(station, 2, arbitrationType, true)) > maxAbsPullY &&
422  return false;
423 
424  if (applyAlsoAngularCuts && std::abs(muon.pullDyDz(station, 2, arbitrationType, true)) > maxAbsPullY)
425  return false;
426  } else {
427  //
428  // In DT, if this is a "Tight" algorithm and the last segment is
429  // missing y information (always the case in station 4!!!), impose
430  // respective cuts on the next station in the stationMask that has
431  // a segment with y information. If there are no segments with y
432  // information then there is nothing to penalize. Should we
433  // penalize in Tight for having zero segments with y information?
434  // That is the fundamental question. Of course I am being uber
435  // paranoid; if this is a good muon then there will probably be at
436  // least one segment with y information but not always. Suppose
437  // somehow a muon only creates segments in station 4, then we
438  // definitely do not want to require that there be at least one
439  // segment with y information because we will lose it completely.
440  //
441 
442  for (int stationIdx = station; stationIdx > 0; --stationIdx) {
443  if (!(theStationMask & 1 << (stationIdx - 1))) // don't bother if the station is not in the stationMask
444  continue;
445 
446  if (muon.dY(stationIdx, 1, arbitrationType) > 999998) // no y-information
447  continue;
448 
449  if (std::abs(muon.pullY(stationIdx, 1, arbitrationType, true)) > maxAbsPullY &&
450  std::abs(muon.dY(stationIdx, 1, arbitrationType)) > maxAbsDy) {
451  return false;
452  }
453 
454  if (applyAlsoAngularCuts && std::abs(muon.pullDyDz(stationIdx, 1, arbitrationType, true)) > maxAbsPullY)
455  return false;
456 
457  // If we get this far then great this is a good muon
458  return true;
459  }
460  }
461  }
462 
463  return goodMuon;
464  } // TMLastStation
465 
466  // TMOneStation requires only that there be one "good" segment, regardless
467  // of the required stations. We do not penalize if there are absolutely zero
468  // segments with y information in the Tight algorithm. Maybe I'm being
469  // paranoid but so be it. If it's really a good muon then we will probably
470  // find at least one segment with both x and y information but you never
471  // know, and I don't want to deal with a potential inefficiency in the DT
472  // like we did with the original TMLastStation. Incidentally, not penalizing
473  // for total lack of y information in the Tight algorithm is what is done in
474  // the new TMLastStation
475  //
476  if (type == TMOneStation) {
477  unsigned int theStationMask = muon.stationMask(arbitrationType);
478 
479  // Of course there must be at least one segment
480  if (!theStationMask)
481  return false;
482 
483  int station = 0, detector = 0;
484  // Keep track of whether or not there is a DT segment with y information.
485  // In the end, if it turns out there are absolutely zero DT segments with
486  // y information, require only that there was a segment with good x info.
487  // This of course only applies to the Tight algorithms.
488  bool existsGoodDTSegX = false;
489  bool existsDTSegY = false;
490 
491  // Impose cuts on the segments in the station mask until we find a good one
492  // Might as well start with the lowest bit to speed things up.
493  for (int stationIdx = 0; stationIdx <= 7; ++stationIdx)
494  if (theStationMask & 1 << stationIdx) {
495  station = stationIdx < 4 ? stationIdx + 1 : stationIdx - 3;
496  detector = stationIdx < 4 ? 1 : 2;
497 
498  if ((std::abs(muon.pullX(station, detector, arbitrationType, true)) > maxAbsPullX &&
500  (applyAlsoAngularCuts && std::abs(muon.pullDxDz(station, detector, arbitrationType, true)) > maxAbsPullX))
501  continue;
502  else if (detector == 1)
503  existsGoodDTSegX = true;
504 
505  // Is this a tight algorithm? If yes, use y information
506  if (maxAbsDy < 999999) {
507  if (detector == 2) { // CSC
508  if ((std::abs(muon.pullY(station, 2, arbitrationType, true)) > maxAbsPullY &&
510  (applyAlsoAngularCuts && std::abs(muon.pullDyDz(station, 2, arbitrationType, true)) > maxAbsPullY))
511  continue;
512  } else {
513  if (muon.dY(station, 1, arbitrationType) > 999998) // no y-information
514  continue;
515  else
516  existsDTSegY = true;
517 
518  if ((std::abs(muon.pullY(station, 1, arbitrationType, true)) > maxAbsPullY &&
520  (applyAlsoAngularCuts && std::abs(muon.pullDyDz(station, 1, arbitrationType, true)) > maxAbsPullY)) {
521  continue;
522  }
523  }
524  }
525 
526  // If we get this far then great this is a good muon
527  return true;
528  }
529 
530  // If we get this far then for sure there are no "good" CSC segments. For
531  // DT, check if there were any segments with y information. If there
532  // were none, but there was a segment with good x, then we're happy. If
533  // there WERE segments with y information, then they must have been shit
534  // since we are here so fail it. Of course, if this is a Loose algorithm
535  // then fail immediately since if we had good x we would already have
536  // returned true
537  if (maxAbsDy < 999999) {
538  if (existsDTSegY)
539  return false;
540  else if (existsGoodDTSegX)
541  return true;
542  } else
543  return false;
544  } // TMOneStation
545 
546  if (type == RPCMu) {
547  if (minNumberOfMatches == 0)
548  return true;
549 
550  int nMatch = 0;
551  for (const auto& chamberMatch : muon.matches()) {
552  if (chamberMatch.detector() != MuonSubdetId::RPC)
553  continue;
554 
555  const float trkX = chamberMatch.x;
556  const float errX = chamberMatch.xErr;
557 
558  for (const auto& rpcMatch : chamberMatch.rpcMatches) {
559  const float rpcX = rpcMatch.x;
560  const float dX = std::abs(rpcX - trkX);
561  if (dX < maxAbsDx or dX < maxAbsPullX * errX) {
562  ++nMatch;
563  break;
564  }
565  }
566  }
567 
568  if (nMatch >= minNumberOfMatches)
569  return true;
570  else
571  return false;
572  } // RPCMu
573 
574  if (type == ME0Mu) {
575  if (minNumberOfMatches == 0)
576  return true;
577 
578  int nMatch = 0;
579  for (const auto& chamberMatch : muon.matches()) {
580  if (chamberMatch.detector() != MuonSubdetId::ME0)
581  continue;
582 
583  const float trkX = chamberMatch.x;
584  const float errX2 = chamberMatch.xErr * chamberMatch.xErr;
585  const float trkY = chamberMatch.y;
586  const float errY2 = chamberMatch.yErr * chamberMatch.yErr;
587 
588  for (const auto& segment : chamberMatch.me0Matches) {
589  const float me0X = segment.x;
590  const float me0ErrX2 = segment.xErr * segment.xErr;
591  const float me0Y = segment.y;
592  const float me0ErrY2 = segment.yErr * segment.yErr;
593 
594  const float dX = std::abs(me0X - trkX);
595  const float dY = std::abs(me0Y - trkY);
596  const float invPullX2 = errX2 + me0ErrX2;
597  const float invPullY2 = errY2 + me0ErrY2;
598 
599  if ((dX < maxAbsDx or dX < maxAbsPullX * std::sqrt(invPullX2)) and
600  (dY < maxAbsDy or dY < maxAbsPullY * std::sqrt(invPullY2))) {
601  ++nMatch;
602  break;
603  }
604  }
605  }
606 
607  return (nMatch >= minNumberOfMatches);
608  } // ME0Mu
609 
610  if (type == GEMMu) {
611  if (minNumberOfMatches == 0)
612  return true;
613 
614  int nMatch = 0;
615  for (const auto& chamberMatch : muon.matches()) {
616  if (chamberMatch.detector() != MuonSubdetId::GEM)
617  continue;
618 
619  const float trkX = chamberMatch.x;
620  const float errX2 = chamberMatch.xErr * chamberMatch.xErr;
621  const float trkY = chamberMatch.y;
622  const float errY2 = chamberMatch.yErr * chamberMatch.yErr;
623 
624  for (const auto& segment : chamberMatch.gemMatches) {
625  const float gemX = segment.x;
626  const float gemErrX2 = segment.xErr * segment.xErr;
627  const float gemY = segment.y;
628  const float gemErrY2 = segment.yErr * segment.yErr;
629 
630  const float dX = std::abs(gemX - trkX);
631  const float dY = std::abs(gemY - trkY);
632  const float invPullX2 = errX2 + gemErrX2;
633  const float invPullY2 = errY2 + gemErrY2;
634 
635  if ((dX < maxAbsDx or dX < maxAbsPullX * std::sqrt(invPullX2)) and
636  (dY < maxAbsDy or dY < maxAbsPullY * std::sqrt(invPullY2))) {
637  ++nMatch;
638  break;
639  }
640  }
641  }
642 
643  return (nMatch >= minNumberOfMatches);
644  } // GEMMu
645 
646  return goodMuon;
647 }
648 
650  switch (type) {
651  case muon::All:
652  return true;
653  break;
655  return muon.isGlobalMuon();
656  break;
658  return muon.isTrackerMuon();
659  break;
661  return muon.isStandAloneMuon();
662  break;
664  return muon.isTrackerMuon() && muon.numberOfMatches(arbitrationType) > 0;
665  break;
666  case muon::AllArbitrated:
667  return !muon.isTrackerMuon() || muon.numberOfMatches(arbitrationType) > 0;
668  break;
670  return muon.isGlobalMuon() && muon.globalTrack()->normalizedChi2() < 10. &&
671  muon.globalTrack()->hitPattern().numberOfValidMuonHits() > 0;
672  break;
673  // For "Loose" algorithms we choose maximum y quantity cuts of 1E9 instead of
674  // 9999 as before. We do this because the muon methods return 999999 (note
675  // there are six 9's) when the requested information is not available. For
676  // example, if a muon fails to traverse the z measuring superlayer in a station
677  // in the DT, then all methods involving segmentY in this station return
678  // 999999 to demonstrate that the information is missing. In order to not
679  // penalize muons for missing y information in Loose algorithms where we do
680  // not care at all about y information, we raise these limits. In the
681  // TMLastStation and TMOneStation algorithms we actually use this huge number
682  // to determine whether to consider y information at all.
684  return muon.isTrackerMuon() &&
685  isGoodMuon(muon, TMLastStation, 2, 3, 3, 1E9, 1E9, -3, -3, arbitrationType, true, false);
686  break;
688  return muon.isTrackerMuon() &&
689  isGoodMuon(muon, TMLastStation, 2, 3, 3, 3, 3, -3, -3, arbitrationType, true, false);
690  break;
692  return muon.isTrackerMuon() &&
693  isGoodMuon(muon, TMOneStation, 1, 3, 3, 1E9, 1E9, 1E9, 1E9, arbitrationType, false, false);
694  break;
696  return muon.isTrackerMuon() &&
697  isGoodMuon(muon, TMOneStation, 1, 3, 3, 3, 3, 1E9, 1E9, arbitrationType, false, false);
698  break;
700  if (muon.pt() < 8. && std::abs(muon.eta()) < 1.2)
701  return muon.isTrackerMuon() &&
702  isGoodMuon(muon, TMOneStation, 1, 3, 3, 1E9, 1E9, 1E9, 1E9, arbitrationType, false, false);
703  else
704  return muon.isTrackerMuon() &&
705  isGoodMuon(muon, TMLastStation, 2, 3, 3, 1E9, 1E9, -3, -3, arbitrationType, false, false);
706  break;
708  if (muon.pt() < 8. && std::abs(muon.eta()) < 1.2)
709  return muon.isTrackerMuon() &&
710  isGoodMuon(muon, TMOneStation, 1, 3, 3, 3, 3, 1E9, 1E9, arbitrationType, false, false);
711  else
712  return muon.isTrackerMuon() &&
713  isGoodMuon(muon, TMLastStation, 2, 3, 3, 3, 3, -3, -3, arbitrationType, false, false);
714  break;
715  //compatibility loose
717  return muon.isTrackerMuon() && isGoodMuon(muon, TM2DCompatibility, 0.7, arbitrationType);
718  break;
719  //compatibility tight
721  return muon.isTrackerMuon() && isGoodMuon(muon, TM2DCompatibility, 1.0, arbitrationType);
722  break;
724  return muon.isGlobalMuon() && muon.isQualityValid() &&
725  std::abs(muon.combinedQuality().trkRelChi2 - muon.innerTrack()->normalizedChi2()) < 2.0;
726  break;
728  return muon.isGlobalMuon() && muon.isQualityValid() &&
729  std::abs(muon.combinedQuality().staRelChi2 - muon.outerTrack()->normalizedChi2()) < 2.0;
730  break;
731  case muon::GMTkKinkTight:
732  return muon.isGlobalMuon() && muon.isQualityValid() && muon.combinedQuality().trkKink < 100.0;
733  break;
735  return muon.isTrackerMuon() &&
736  isGoodMuon(muon, TMLastStation, 2, 3, 3, 1E9, 1E9, -3, -3, arbitrationType, false, true);
737  break;
739  return muon.isTrackerMuon() &&
740  isGoodMuon(muon, TMLastStation, 2, 3, 3, 3, 3, -3, -3, arbitrationType, false, true);
741  break;
743  return muon.isTrackerMuon() &&
744  isGoodMuon(muon, TMOneStation, 1, 3, 3, 1E9, 1E9, 1E9, 1E9, arbitrationType, false, true);
745  break;
747  return muon.isTrackerMuon() &&
748  isGoodMuon(muon, TMOneStation, 1, 3, 3, 3, 3, 1E9, 1E9, arbitrationType, false, true);
749  break;
751  if (muon.pt() < 8. && std::abs(muon.eta()) < 1.2)
752  return muon.isTrackerMuon() &&
753  isGoodMuon(muon, TMOneStation, 1, 3, 3, 1E9, 1E9, 1E9, 1E9, arbitrationType, false, false);
754  else
755  return muon.isTrackerMuon() &&
756  isGoodMuon(muon, TMLastStation, 2, 3, 3, 1E9, 1E9, -3, -3, arbitrationType, true, false);
757  break;
759  if (muon.pt() < 8. && std::abs(muon.eta()) < 1.2)
760  return muon.isTrackerMuon() &&
761  isGoodMuon(muon, TMOneStation, 1, 3, 3, 3, 3, 1E9, 1E9, arbitrationType, false, false);
762  else
763  return muon.isTrackerMuon() &&
764  isGoodMuon(muon, TMLastStation, 2, 3, 3, 3, 3, -3, -3, arbitrationType, true, false);
765  break;
766  case muon::RPCMuLoose:
767  return muon.isRPCMuon() && isGoodMuon(muon, RPCMu, 2, 20, 4, 1e9, 1e9, 1e9, 1e9, arbitrationType, false, false);
768  break;
769  case muon::AllME0Muons:
770  return muon.isME0Muon();
771  break;
773  return muon.isME0Muon() &&
774  isGoodMuon(muon, ME0Mu, 1, 1e9, 1e9, 1e9, 1e9, 1e9, 1e9, arbitrationType, false, false);
775  break;
776  case muon::AllGEMMuons:
777  return muon.isGEMMuon();
778  break;
780  return muon.isGEMMuon() &&
781  isGoodMuon(muon, GEMMu, 1, 1e9, 1e9, 1e9, 1e9, 1e9, 1e9, arbitrationType, false, false);
782  break;
784  return isLooseTriggerMuon(muon);
785  break;
786  default:
787  return false;
788  }
789 }
790 
792  const reco::Muon& muon1, const reco::Muon& muon2, double pullX, double pullY, bool checkAdjacentChambers) {
793  unsigned int nMatches1 = muon1.numberOfMatches(reco::Muon::SegmentAndTrackArbitration);
794  unsigned int nMatches2 = muon2.numberOfMatches(reco::Muon::SegmentAndTrackArbitration);
795  unsigned int betterMuon = (muon1.pt() > muon2.pt() ? 1 : 2);
796  for (std::vector<reco::MuonChamberMatch>::const_iterator chamber1 = muon1.matches().begin();
797  chamber1 != muon1.matches().end();
798  ++chamber1)
799  for (std::vector<reco::MuonChamberMatch>::const_iterator chamber2 = muon2.matches().begin();
800  chamber2 != muon2.matches().end();
801  ++chamber2) {
802  // if ( (chamber1->segmentMatches.empty() || chamber2->segmentMatches.empty()) ) continue;
803 
804  // handle case where both muons have information about the same chamber
805  // here we know how close they are
806  if (chamber1->id == chamber2->id) {
807  // found the same chamber
808  if (std::abs(chamber1->x - chamber2->x) <
809  pullX * sqrt(chamber1->xErr * chamber1->xErr + chamber2->xErr * chamber2->xErr)) {
810  if (betterMuon == 1)
811  nMatches2--;
812  else
813  nMatches1--;
814  if (nMatches1 == 0 || nMatches2 == 0)
815  return true;
816  continue;
817  }
818  if (std::abs(chamber1->y - chamber2->y) <
819  pullY * sqrt(chamber1->yErr * chamber1->yErr + chamber2->yErr * chamber2->yErr)) {
820  if (betterMuon == 1)
821  nMatches2--;
822  else
823  nMatches1--;
824  if (nMatches1 == 0 || nMatches2 == 0)
825  return true;
826  }
827  } else {
828  if (!checkAdjacentChambers)
829  continue;
830  // check if tracks are pointing into overlaping region of the CSC detector
831  if (chamber1->id.subdetId() != MuonSubdetId::CSC || chamber2->id.subdetId() != MuonSubdetId::CSC)
832  continue;
833  CSCDetId id1(chamber1->id);
834  CSCDetId id2(chamber2->id);
835  if (id1.endcap() != id2.endcap())
836  continue;
837  if (id1.station() != id2.station())
838  continue;
839  if (id1.ring() != id2.ring())
840  continue;
841  if (std::abs(id1.chamber() - id2.chamber()) > 1)
842  continue;
843  // FIXME: we don't handle 18->1; 36->1 transitions since
844  // I don't know how to check for sure how many chambers
845  // are there. Probably need to hard code some checks.
846 
847  // Now we have to make sure that both tracks are close to an edge
848  // FIXME: ignored Y coordinate for now
849  if (std::abs(chamber1->edgeX) > chamber1->xErr * pullX)
850  continue;
851  if (std::abs(chamber2->edgeX) > chamber2->xErr * pullX)
852  continue;
853  if (chamber1->x * chamber2->x < 0) { // check if the same edge
854  if (betterMuon == 1)
855  nMatches2--;
856  else
857  nMatches1--;
858  if (nMatches1 == 0 || nMatches2 == 0)
859  return true;
860  }
861  }
862  }
863  return false;
864 }
865 
867  // Requirements:
868  // - no depencence on information not availabe in the muon object
869  // - use only robust inputs
870  bool tk_id = muon::isGoodMuon(muon, TMOneStationTight);
871  if (not tk_id)
872  return false;
873  bool layer_requirements = muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() > 5 &&
874  muon.innerTrack()->hitPattern().pixelLayersWithMeasurement() > 0;
875  bool match_requirements =
876  (muon.expectedNnumberOfMatchedStations() < 2) or (muon.numberOfMatchedStations() > 1) or (muon.pt() < 8);
877  return layer_requirements and match_requirements;
878 }
879 
881  if (!muon.isPFMuon() || !muon.isGlobalMuon())
882  return false;
883 
884  bool muID = isGoodMuon(muon, GlobalMuonPromptTight) && (muon.numberOfMatchedStations() > 1);
885 
886  bool hits = muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() > 5 &&
887  muon.innerTrack()->hitPattern().numberOfValidPixelHits() > 0;
888 
889  bool ip = std::abs(muon.muonBestTrack()->dxy(vtx.position())) < 0.2 &&
890  std::abs(muon.muonBestTrack()->dz(vtx.position())) < 0.5;
891 
892  return muID && hits && ip;
893 }
894 
896  return muon.isPFMuon() && (muon.isGlobalMuon() || muon.isTrackerMuon());
897 }
898 
899 bool muon::isMediumMuon(const reco::Muon& muon, bool run2016_hip_mitigation) {
900  if (not isLooseMuon(muon))
901  return false;
902  if (run2016_hip_mitigation) {
903  if (muon.innerTrack()->validFraction() < 0.49)
904  return false;
905  } else {
906  if (muon.innerTrack()->validFraction() < 0.8)
907  return false;
908  }
909 
910  bool goodGlb = muon.isGlobalMuon() && muon.globalTrack()->normalizedChi2() < 3. &&
911  muon.combinedQuality().chi2LocalPosition < 12. && muon.combinedQuality().trkKink < 20.;
912 
913  return (segmentCompatibility(muon) > (goodGlb ? 0.303 : 0.451));
914 }
915 
916 bool muon::isSoftMuon(const reco::Muon& muon, const reco::Vertex& vtx, bool run2016_hip_mitigation) {
918 
919  if (!muID)
920  return false;
921 
922  bool layers = muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() > 5 &&
923  muon.innerTrack()->hitPattern().pixelLayersWithMeasurement() > 0;
924 
925  bool ishighq = muon.innerTrack()->quality(reco::Track::highPurity);
926 
927  bool ip =
928  std::abs(muon.innerTrack()->dxy(vtx.position())) < 0.3 && std::abs(muon.innerTrack()->dz(vtx.position())) < 20.;
929 
930  return layers && ip && (ishighq | run2016_hip_mitigation);
931 }
932 
934  if (!muon.isGlobalMuon())
935  return false;
936 
937  bool muValHits = (muon.globalTrack()->hitPattern().numberOfValidMuonHits() > 0 ||
938  muon.tunePMuonBestTrack()->hitPattern().numberOfValidMuonHits() > 0);
939 
940  bool muMatchedSt = muon.numberOfMatchedStations() > 1;
941  if (!muMatchedSt) {
942  if (muon.isTrackerMuon() && muon.numberOfMatchedStations() == 1) {
943  if (muon.expectedNnumberOfMatchedStations() < 2 || !(muon.stationMask() == 1 || muon.stationMask() == 16) ||
944  muon.numberOfMatchedRPCLayers() > 2)
945  muMatchedSt = true;
946  }
947  }
948 
949  bool muID = muValHits && muMatchedSt;
950 
951  bool hits = muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() > 5 &&
952  muon.innerTrack()->hitPattern().numberOfValidPixelHits() > 0;
953 
954  bool momQuality = muon.tunePMuonBestTrack()->ptError() / muon.tunePMuonBestTrack()->pt() < 0.3;
955 
956  bool ip =
957  std::abs(muon.innerTrack()->dxy(vtx.position())) < 0.2 && std::abs(muon.innerTrack()->dz(vtx.position())) < 0.5;
958 
959  return muID && hits && momQuality && ip;
960 }
961 
963  bool muID = muon.isTrackerMuon() && muon.track().isNonnull() && (muon.numberOfMatchedStations() > 1);
964  if (!muID)
965  return false;
966 
967  bool hits = muon.innerTrack()->hitPattern().trackerLayersWithMeasurement() > 5 &&
968  muon.innerTrack()->hitPattern().numberOfValidPixelHits() > 0;
969 
970  bool momQuality = muon.tunePMuonBestTrack()->ptError() < 0.3 * muon.tunePMuonBestTrack()->pt();
971 
972  bool ip =
973  std::abs(muon.innerTrack()->dxy(vtx.position())) < 0.2 && std::abs(muon.innerTrack()->dz(vtx.position())) < 0.5;
974 
975  return muID && hits && momQuality && ip;
976 }
977 
978 int muon::sharedSegments(const reco::Muon& mu, const reco::Muon& mu2, unsigned int segmentArbitrationMask) {
979  int ret = 0;
980 
981  // Will do with a stupid double loop, since creating and filling a map is probably _more_ inefficient for a single lookup.
982  for (std::vector<reco::MuonChamberMatch>::const_iterator chamberMatch = mu.matches().begin();
983  chamberMatch != mu.matches().end();
984  ++chamberMatch) {
985  if (chamberMatch->segmentMatches.empty())
986  continue;
987  for (std::vector<reco::MuonChamberMatch>::const_iterator chamberMatch2 = mu2.matches().begin();
988  chamberMatch2 != mu2.matches().end();
989  ++chamberMatch2) {
990  if (chamberMatch2->segmentMatches.empty())
991  continue;
992  if (chamberMatch2->id() != chamberMatch->id())
993  continue;
994  for (std::vector<reco::MuonSegmentMatch>::const_iterator segmentMatch = chamberMatch->segmentMatches.begin();
995  segmentMatch != chamberMatch->segmentMatches.end();
996  ++segmentMatch) {
997  if (!segmentMatch->isMask(segmentArbitrationMask))
998  continue;
999  for (std::vector<reco::MuonSegmentMatch>::const_iterator segmentMatch2 = chamberMatch2->segmentMatches.begin();
1000  segmentMatch2 != chamberMatch2->segmentMatches.end();
1001  ++segmentMatch2) {
1002  if (!segmentMatch2->isMask(segmentArbitrationMask))
1003  continue;
1004  if ((segmentMatch->cscSegmentRef.isNonnull() &&
1005  segmentMatch->cscSegmentRef == segmentMatch2->cscSegmentRef) ||
1006  (segmentMatch->dtSegmentRef.isNonnull() && segmentMatch->dtSegmentRef == segmentMatch2->dtSegmentRef)) {
1007  ++ret;
1008  } // is the same
1009  } // segment of mu2 in chamber
1010  } // segment of mu1 in chamber
1011  } // chamber of mu2
1012  } // chamber of mu1
1013 
1014  return ret;
1015 }
1016 
1018  const auto& combinedTime = muon.time();
1019  const auto& rpcTime = muon.rpcTime();
1020  bool combinedTimeIsOk = (combinedTime.nDof > 7);
1021  bool rpcTimeIsOk = (rpcTime.nDof > 1 && std::abs(rpcTime.timeAtIpInOutErr) < 0.001);
1022  bool outOfTime = false;
1023  if (rpcTimeIsOk) {
1024  if ((std::abs(rpcTime.timeAtIpInOut) > 10) && !(combinedTimeIsOk && std::abs(combinedTime.timeAtIpInOut) < 10))
1025  outOfTime = true;
1026  } else {
1027  if (combinedTimeIsOk && (combinedTime.timeAtIpInOut > 20 || combinedTime.timeAtIpInOut < -45))
1028  outOfTime = true;
1029  }
1030  return outOfTime;
1031 }
1032 
1034  reco::Vertex const* vertex,
1035  bool run2016_hip_mitigation) {
1036  // https://twiki.cern.ch/twiki/bin/viewauth/CMS/SWGuideMuonIdRun2
1037  unsigned int selectors = muon.selectors();
1038  // Compute Id and Isolation variables
1039  double chIso = muon.pfIsolationR04().sumChargedHadronPt;
1040  double nIso = muon.pfIsolationR04().sumNeutralHadronEt;
1041  double phoIso = muon.pfIsolationR04().sumPhotonEt;
1042  double puIso = muon.pfIsolationR04().sumPUPt;
1043  double dbCorrectedIsolation = chIso + std::max(nIso + phoIso - .5 * puIso, 0.);
1044  double dbCorrectedRelIso = dbCorrectedIsolation / muon.pt();
1045  double tkRelIso = muon.isolationR03().sumPt / muon.pt();
1046 
1047  // Base selectors
1048  if (muon::isLooseMuon(muon))
1050  if (vertex) {
1051  if (muon::isTightMuon(muon, *vertex))
1053  if (muon::isSoftMuon(muon, *vertex, run2016_hip_mitigation))
1059  }
1060  if (muon::isMediumMuon(muon, run2016_hip_mitigation)) {
1062  if (vertex and std::abs(muon.muonBestTrack()->dz(vertex->position())) < 0.1 and
1063  std::abs(muon.muonBestTrack()->dxy(vertex->position())) < 0.02)
1065  }
1066 
1067  // PF isolation
1068  if (dbCorrectedRelIso < 0.40)
1070  if (dbCorrectedRelIso < 0.25)
1071  selectors |= (1UL <<reco::Muon::PFIsoLoose);
1072  if (dbCorrectedRelIso < 0.20)
1074  if (dbCorrectedRelIso < 0.15)
1075  selectors |= (1UL <<reco::Muon::PFIsoTight);
1076  if (dbCorrectedRelIso < 0.10)
1078  if (dbCorrectedRelIso < 0.05)
1080 
1081  // Tracker isolation
1082  if (tkRelIso < 0.10)
1083  selectors |= (1UL <<reco::Muon::TkIsoLoose);
1084  if (tkRelIso < 0.05)
1085  selectors |= (1UL <<reco::Muon::TkIsoTight);
1086 
1087  // Trigger selectors
1088  if (isLooseTriggerMuon(muon))
1090 
1091  // Timing
1092  if (!outOfTimeMuon(muon))
1093  selectors |= (1UL <<reco::Muon::InTimeMuon);
1094 
1095  return static_cast<reco::Muon::Selector>(selectors);
1096 }
static constexpr int GEM
Definition: MuonSubdetId.h:14
double pt() const final
transverse momentum
reco::Muon::Selector value
bool isMediumMuon(const reco::Muon &, bool run2016_hip_mitigation=false)
ret
prodAgent to be discontinued
reco::Muon::Selector makeSelectorBitset(reco::Muon const &muon, reco::Vertex const *vertex=nullptr, bool run2016_hip_mitigation=false)
float caloCompatibility(const reco::Muon &muon)
bool isLooseMuon(const reco::Muon &)
SelectionType
Selector type.
Definition: MuonSelectors.h:18
bool overlap(const reco::Muon &muon1, const reco::Muon &muon2, double pullX=1.0, double pullY=1.0, bool checkAdjacentChambers=false)
char const * label
ArbitrationType
define arbitration schemes
Definition: Muon.h:187
T sqrt(T t)
Definition: SSEVec.h:19
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::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
float segmentCompatibility(const reco::Muon &muon, reco::Muon::ArbitrationType arbitrationType=reco::Muon::SegmentAndTrackArbitration)
double f[11][100]
static constexpr int ME0
Definition: MuonSubdetId.h:15
Definition: value.py:1
bool isSoftMuon(const reco::Muon &, const reco::Vertex &, bool run2016_hip_mitigation=false)
bool isGoodMuon(const reco::Muon &muon, SelectionType type, reco::Muon::ArbitrationType arbitrationType=reco::Muon::SegmentAndTrackArbitration)
main GoodMuon wrapper call
int numberOfMatches(ArbitrationType type=SegmentAndTrackArbitration) const
get number of chambers with matched segments
int sharedSegments(const reco::Muon &muon1, const reco::Muon &muon2, unsigned int segmentArbitrationMask=reco::MuonSegmentMatch::BestInChamberByDR)
bool isHighPtMuon(const reco::Muon &, const reco::Vertex &)
SelectionType selectionTypeFromString(const std::string &label)
Definition: MuonSelectors.cc:9
const reco::Muon::ArbitrationType arbitrationType
static constexpr int RPC
Definition: MuonSubdetId.h:13
unsigned int RequiredStationMask(const reco::Muon &muon, double maxChamberDist, double maxChamberDistPull, reco::Muon::ArbitrationType arbitrationType)
std::vector< MuonChamberMatch > & matches()
get muon matching information
Definition: Muon.h:145
static const SelectorStringToEnum selectorStringToEnumMap[]
reco::Muon::Selector selectorFromString(const std::string &label)
bool outOfTimeMuon(const reco::Muon &muon)
bool isTrackerHighPtMuon(const reco::Muon &, const reco::Vertex &)
bool isTightMuon(const reco::Muon &, const reco::Vertex &)
static constexpr int CSC
Definition: MuonSubdetId.h:12
bool isLooseTriggerMuon(const reco::Muon &)
Selector
Definition: Muon.h:201
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
static const SelectionTypeStringToEnum selectionTypeStringToEnumMap[]
Definition: MuonSelectors.h:66