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