CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/DataFormats/MuonReco/src/MuonSelectors.cc

Go to the documentation of this file.
00001 #include "DataFormats/MuonReco/interface/MuonSelectors.h"
00002 #include "DataFormats/TrackReco/interface/Track.h"
00003 #include "DataFormats/MuonDetId/interface/MuonSubdetId.h"
00004 #include "DataFormats/MuonDetId/interface/CSCDetId.h"
00005 
00006 namespace muon {
00007 SelectionType selectionTypeFromString( const std::string &label )
00008 {
00009    static SelectionTypeStringToEnum selectionTypeStringToEnumMap[] = {
00010       { "All", All },
00011       { "AllGlobalMuons", AllGlobalMuons },
00012       { "AllStandAloneMuons", AllStandAloneMuons },
00013       { "AllTrackerMuons", AllTrackerMuons },
00014       { "TrackerMuonArbitrated", TrackerMuonArbitrated },
00015       { "AllArbitrated", AllArbitrated },
00016       { "GlobalMuonPromptTight", GlobalMuonPromptTight },
00017       { "TMLastStationLoose", TMLastStationLoose },
00018       { "TMLastStationTight", TMLastStationTight },
00019       { "TM2DCompatibilityLoose", TM2DCompatibilityLoose },
00020       { "TM2DCompatibilityTight", TM2DCompatibilityTight },
00021       { "TMOneStationLoose", TMOneStationLoose },
00022       { "TMOneStationTight", TMOneStationTight },
00023       { "TMLastStationOptimizedLowPtLoose", TMLastStationOptimizedLowPtLoose },
00024       { "TMLastStationOptimizedLowPtTight", TMLastStationOptimizedLowPtTight },
00025       { "GMTkChiCompatibility", GMTkChiCompatibility },
00026       { "GMStaChiCompatibility", GMStaChiCompatibility},
00027       { "GMTkKinkTight", GMTkKinkTight},
00028       { "TMLastStationAngLoose", TMLastStationAngLoose },
00029       { "TMLastStationAngTight", TMLastStationAngTight },
00030       { "TMOneStationAngLoose", TMOneStationAngLoose },
00031       { "TMOneStationAngTight", TMOneStationAngTight },
00032       { "TMLastStationOptimizedBarrelLowPtLoose", TMLastStationOptimizedBarrelLowPtLoose },
00033       { "TMLastStationOptimizedBarrelLowPtTight", TMLastStationOptimizedBarrelLowPtTight },
00034       { 0, (SelectionType)-1 }
00035    };
00036 
00037    SelectionType value = (SelectionType)-1;
00038    bool found = false;
00039    for(int i = 0; selectionTypeStringToEnumMap[i].label && (! found); ++i)
00040       if (! strcmp(label.c_str(), selectionTypeStringToEnumMap[i].label)) {
00041          found = true;
00042          value = selectionTypeStringToEnumMap[i].value;
00043       }
00044 
00045    // in case of unrecognized selection type
00046    if (! found) throw cms::Exception("MuonSelectorError") << label << " is not a recognized SelectionType";
00047    return value;
00048 }
00049 }
00050 
00051 unsigned int muon::RequiredStationMask( const reco::Muon& muon,
00052                                           double maxChamberDist,
00053                                           double maxChamberDistPull,
00054                                           reco::Muon::ArbitrationType arbitrationType )
00055 {
00056    unsigned int theMask = 0;
00057 
00058    for(int stationIdx = 1; stationIdx < 5; ++stationIdx)
00059       for(int detectorIdx = 1; detectorIdx < 3; ++detectorIdx)
00060          if(muon.trackDist(stationIdx,detectorIdx,arbitrationType) < maxChamberDist &&
00061                muon.trackDist(stationIdx,detectorIdx,arbitrationType)/muon.trackDistErr(stationIdx,detectorIdx,arbitrationType) < maxChamberDistPull)
00062             theMask += 1<<((stationIdx-1)+4*(detectorIdx-1));
00063 
00064    return theMask;
00065 }
00066 
00067 // ------------ method to calculate the calo compatibility for a track with matched muon info  ------------
00068 float muon::caloCompatibility(const reco::Muon& muon) {
00069   return muon.caloCompatibility();
00070 }
00071 
00072 // ------------ method to calculate the segment compatibility for a track with matched muon info  ------------
00073 float muon::segmentCompatibility(const reco::Muon& muon,reco::Muon::ArbitrationType arbitrationType) {
00074   bool use_weight_regain_at_chamber_boundary = true;
00075   bool use_match_dist_penalty = true;
00076 
00077   int nr_of_stations_crossed = 0;
00078   int nr_of_stations_with_segment = 0;
00079   std::vector<int> stations_w_track(8);
00080   std::vector<int> station_has_segmentmatch(8);
00081   std::vector<int> station_was_crossed(8);
00082   std::vector<float> stations_w_track_at_boundary(8);
00083   std::vector<float> station_weight(8);
00084   int position_in_stations = 0;
00085   float full_weight = 0.;
00086 
00087   for(int i = 1; i<=8; ++i) {
00088     // ********************************************************;
00089     // *** fill local info for this muon (do some counting) ***;
00090     // ************** begin ***********************************;
00091     if(i<=4) { // this is the section for the DTs
00092       if( muon.trackDist(i,1,arbitrationType) < 999999 ) { //current "raw" info that a track is close to a chamber
00093         ++nr_of_stations_crossed;
00094         station_was_crossed[i-1] = 1;
00095         if(muon.trackDist(i,1,arbitrationType) > -10. ) stations_w_track_at_boundary[i-1] = muon.trackDist(i,1,arbitrationType); 
00096         else stations_w_track_at_boundary[i-1] = 0.;
00097       }
00098       if( muon.segmentX(i,1,arbitrationType) < 999999 ) { //current "raw" info that a segment is matched to the current track
00099         ++nr_of_stations_with_segment;
00100         station_has_segmentmatch[i-1] = 1;
00101       }
00102     }
00103     else     { // this is the section for the CSCs
00104       if( muon.trackDist(i-4,2,arbitrationType) < 999999 ) { //current "raw" info that a track is close to a chamber
00105         ++nr_of_stations_crossed;
00106         station_was_crossed[i-1] = 1;
00107         if(muon.trackDist(i-4,2,arbitrationType) > -10. ) stations_w_track_at_boundary[i-1] = muon.trackDist(i-4,2,arbitrationType);
00108         else stations_w_track_at_boundary[i-1] = 0.;
00109       }
00110       if( muon.segmentX(i-4,2,arbitrationType) < 999999 ) { //current "raw" info that a segment is matched to the current track
00111         ++nr_of_stations_with_segment;
00112         station_has_segmentmatch[i-1] = 1;
00113       }
00114     }
00115     // rough estimation of chamber border efficiency (should be parametrized better, this is just a quick guess):
00116     // TF1 * merf = new TF1("merf","-0.5*(TMath::Erf(x/6.)-1)",-100,100);
00117     // use above value to "unpunish" missing segment if close to border, i.e. rather than not adding any weight, add
00118     // the one from the function. Only for dist ~> -10 cm, else full punish!.
00119 
00120     // ********************************************************;
00121     // *** fill local info for this muon (do some counting) ***;
00122     // ************** end *************************************;
00123   }
00124 
00125   // ********************************************************;
00126   // *** calculate weights for each station *****************;
00127   // ************** begin ***********************************;
00128   //    const float slope = 0.5;
00129   //    const float attenuate_weight_regain = 1.;
00130   // if attenuate_weight_regain < 1., additional punishment if track is close to boundary and no segment
00131   const float attenuate_weight_regain = 0.5; 
00132 
00133   for(int i = 1; i<=8; ++i) { // loop over all possible stations
00134 
00135     // first set all weights if a station has been crossed
00136     // later penalize if a station did not have a matching segment
00137 
00138     //old logic      if(station_has_segmentmatch[i-1] > 0 ) { // the track has an associated segment at the current station
00139     if( station_was_crossed[i-1] > 0 ) { // the track crossed this chamber (or was nearby)
00140       // - Apply a weight depending on the "depth" of the muon passage. 
00141       // - The station_weight is later reduced for stations with badly matched segments. 
00142       // - Even if there is no segment but the track passes close to a chamber boundary, the
00143       //   weight is set non zero and can go up to 0.5 of the full weight if the track is quite
00144       //   far from any station.
00145       ++position_in_stations;
00146 
00147       switch ( nr_of_stations_crossed ) { // define different weights depending on how many stations were crossed
00148       case 1 : 
00149         station_weight[i-1] =  1.;
00150         break;
00151       case 2 :
00152         if     ( position_in_stations == 1 ) station_weight[i-1] =  0.33;
00153         else                                 station_weight[i-1] =  0.67;
00154         break;
00155       case 3 : 
00156         if     ( position_in_stations == 1 ) station_weight[i-1] =  0.23;
00157         else if( position_in_stations == 2 ) station_weight[i-1] =  0.33;
00158         else                                 station_weight[i-1] =  0.44;
00159         break;
00160       case 4 : 
00161         if     ( position_in_stations == 1 ) station_weight[i-1] =  0.10;
00162         else if( position_in_stations == 2 ) station_weight[i-1] =  0.20;
00163         else if( position_in_stations == 3 ) station_weight[i-1] =  0.30;
00164         else                                 station_weight[i-1] =  0.40;
00165         break;
00166           
00167       default : 
00168 //      LogTrace("MuonIdentification")<<"            // Message: A muon candidate track has more than 4 stations with matching segments.";
00169 //      LogTrace("MuonIdentification")<<"            // Did not expect this - please let me know: ibloch@fnal.gov";
00170         // for all other cases
00171         station_weight[i-1] = 1./nr_of_stations_crossed;
00172       }
00173 
00174       if( use_weight_regain_at_chamber_boundary ) { // reconstitute some weight if there is no match but the segment is close to a boundary:
00175         if(station_has_segmentmatch[i-1] <= 0 && stations_w_track_at_boundary[i-1] != 0. ) {
00176           // if segment is not present but track in inefficient region, do not count as "missing match" but add some reduced weight. 
00177           // original "match weight" is currently reduced by at least attenuate_weight_regain, variing with an error function down to 0 if the track is 
00178           // inside the chamber.
00179           station_weight[i-1] = station_weight[i-1]*attenuate_weight_regain*0.5*(TMath::Erf(stations_w_track_at_boundary[i-1]/6.)+1.); // remark: the additional scale of 0.5 normalizes Err to run from 0 to 1 in y
00180         }
00181         else if(station_has_segmentmatch[i-1] <= 0 && stations_w_track_at_boundary[i-1] == 0.) { // no segment match and track well inside chamber
00182           // full penalization
00183           station_weight[i-1] = 0.;
00184         }
00185       }
00186       else { // always fully penalize tracks with no matching segment, whether the segment is close to the boundary or not.
00187         if(station_has_segmentmatch[i-1] <= 0) station_weight[i-1] = 0.;
00188       }
00189 
00190       if( station_has_segmentmatch[i-1] > 0 && 42 == 42 ) { // if track has matching segment, but the matching is not high quality, penalize
00191         if(i<=4) { // we are in the DTs
00192           if( muon.dY(i,1,arbitrationType) < 999999 && muon.dX(i,1,arbitrationType) < 999999) { // have both X and Y match
00193             if(
00194                TMath::Sqrt(TMath::Power(muon.pullX(i,1,arbitrationType),2.)+TMath::Power(muon.pullY(i,1,arbitrationType),2.))> 1. ) {
00195               // reduce weight
00196               if(use_match_dist_penalty) {
00197                 // only use pull if 3 sigma is not smaller than 3 cm
00198                 if(TMath::Sqrt(TMath::Power(muon.dX(i,1,arbitrationType),2.)+TMath::Power(muon.dY(i,1,arbitrationType),2.)) < 3. && TMath::Sqrt(TMath::Power(muon.pullX(i,1,arbitrationType),2.)+TMath::Power(muon.pullY(i,1,arbitrationType),2.)) > 3. ) { 
00199                   station_weight[i-1] *= 1./TMath::Power(
00200                                                          TMath::Max((double)TMath::Sqrt(TMath::Power(muon.dX(i,1,arbitrationType),2.)+TMath::Power(muon.dY(i,1,arbitrationType),2.)),(double)1.),.25); 
00201                 }
00202                 else {
00203                   station_weight[i-1] *= 1./TMath::Power(
00204                                                          TMath::Sqrt(TMath::Power(muon.pullX(i,1,arbitrationType),2.)+TMath::Power(muon.pullY(i,1,arbitrationType),2.)),.25); 
00205                 }
00206               }
00207             }
00208           }
00209           else if (muon.dY(i,1,arbitrationType) >= 999999) { // has no match in Y
00210             if( muon.pullX(i,1,arbitrationType) > 1. ) { // has a match in X. Pull larger that 1 to avoid increasing the weight (just penalize, don't anti-penalize)
00211               // reduce weight
00212               if(use_match_dist_penalty) {
00213                 // only use pull if 3 sigma is not smaller than 3 cm
00214                 if( muon.dX(i,1,arbitrationType) < 3. && muon.pullX(i,1,arbitrationType) > 3. ) { 
00215                   station_weight[i-1] *= 1./TMath::Power(TMath::Max((double)muon.dX(i,1,arbitrationType),(double)1.),.25);
00216                 }
00217                 else {
00218                   station_weight[i-1] *= 1./TMath::Power(muon.pullX(i,1,arbitrationType),.25);
00219                 }
00220               }
00221             }
00222           }
00223           else { // has no match in X
00224             if( muon.pullY(i,1,arbitrationType) > 1. ) { // has a match in Y. Pull larger that 1 to avoid increasing the weight (just penalize, don't anti-penalize)
00225               // reduce weight
00226               if(use_match_dist_penalty) {
00227                 // only use pull if 3 sigma is not smaller than 3 cm
00228                 if( muon.dY(i,1,arbitrationType) < 3. && muon.pullY(i,1,arbitrationType) > 3. ) { 
00229                   station_weight[i-1] *= 1./TMath::Power(TMath::Max((double)muon.dY(i,1,arbitrationType),(double)1.),.25);
00230                 }
00231                 else {
00232                   station_weight[i-1] *= 1./TMath::Power(muon.pullY(i,1,arbitrationType),.25);
00233                 }
00234               }
00235             }
00236           }
00237         }
00238         else { // We are in the CSCs
00239           if(
00240              TMath::Sqrt(TMath::Power(muon.pullX(i-4,2,arbitrationType),2.)+TMath::Power(muon.pullY(i-4,2,arbitrationType),2.)) > 1. ) {
00241             // reduce weight
00242             if(use_match_dist_penalty) {
00243               // only use pull if 3 sigma is not smaller than 3 cm
00244               if(TMath::Sqrt(TMath::Power(muon.dX(i-4,2,arbitrationType),2.)+TMath::Power(muon.dY(i-4,2,arbitrationType),2.)) < 3. && TMath::Sqrt(TMath::Power(muon.pullX(i-4,2,arbitrationType),2.)+TMath::Power(muon.pullY(i-4,2,arbitrationType),2.)) > 3. ) { 
00245                 station_weight[i-1] *= 1./TMath::Power(
00246                                                        TMath::Max((double)TMath::Sqrt(TMath::Power(muon.dX(i-4,2,arbitrationType),2.)+TMath::Power(muon.dY(i-4,2,arbitrationType),2.)),(double)1.),.25);
00247               }
00248               else {
00249                 station_weight[i-1] *= 1./TMath::Power(
00250                                                        TMath::Sqrt(TMath::Power(muon.pullX(i-4,2,arbitrationType),2.)+TMath::Power(muon.pullY(i-4,2,arbitrationType),2.)),.25);
00251               }
00252             }
00253           }
00254         }
00255       }
00256         
00257       // Thoughts:
00258       // - should penalize if the segment has only x OR y info
00259       // - should also use the segment direction, as it now works!
00260         
00261     }
00262     else { // track did not pass a chamber in this station - just reset weight
00263       station_weight[i-1] = 0.;
00264     }
00265       
00266     //increment final weight for muon:
00267     full_weight += station_weight[i-1];
00268   }
00269 
00270   // if we don't expect any matches, we set the compatibility to
00271   // 0.5 as the track is as compatible with a muon as it is with
00272   // background - we should maybe rather set it to -0.5!
00273   if( nr_of_stations_crossed == 0 ) {
00274     //      full_weight = attenuate_weight_regain*0.5;
00275     full_weight = 0.5;
00276   }
00277 
00278   // ********************************************************;
00279   // *** calculate weights for each station *****************;
00280   // ************** end *************************************;
00281 
00282   return full_weight;
00283 
00284 }
00285 
00286 bool muon::isGoodMuon( const reco::Muon& muon, 
00287                          AlgorithmType type,
00288                          double minCompatibility,
00289                          reco::Muon::ArbitrationType arbitrationType ) {
00290   if (!muon.isMatchesValid()) return false;
00291   bool goodMuon = false;
00292   
00293   switch( type ) {
00294   case TM2DCompatibility:
00295     // Simplistic first cut in the 2D segment- vs calo-compatibility plane. Will have to be refined!
00296     if( ( (0.8*caloCompatibility( muon ))+(1.2*segmentCompatibility( muon, arbitrationType )) ) > minCompatibility ) goodMuon = true;
00297     else goodMuon = false;
00298     return goodMuon;
00299     break;
00300   default : 
00301     //  LogTrace("MuonIdentification")<<"            // Invalid Algorithm Type called!";
00302     goodMuon = false;
00303     return goodMuon;
00304     break;
00305   }
00306 }
00307 
00308 bool muon::isGoodMuon( const reco::Muon& muon,
00309                          AlgorithmType type,
00310                          int minNumberOfMatches,
00311                          double maxAbsDx,
00312                          double maxAbsPullX,
00313                          double maxAbsDy,
00314                          double maxAbsPullY,
00315                          double maxChamberDist,
00316                          double maxChamberDistPull,
00317                          reco::Muon::ArbitrationType arbitrationType,
00318              bool   syncMinNMatchesNRequiredStationsInBarrelOnly,
00319              bool   applyAlsoAngularCuts)
00320 {
00321    if (!muon.isMatchesValid()) return false;
00322    bool goodMuon = false;
00323 
00324    if (type == TMLastStation) {
00325       // To satisfy my own paranoia, if the user specifies that the
00326       // minimum number of matches is zero, then return true.
00327       if(minNumberOfMatches == 0) return true;
00328 
00329       unsigned int theStationMask = muon.stationMask(arbitrationType);
00330       unsigned int theRequiredStationMask = RequiredStationMask(muon, maxChamberDist, maxChamberDistPull, arbitrationType);
00331 
00332       // Require that there be at least a minimum number of segments
00333       int numSegs = 0;
00334       int numRequiredStations = 0;
00335       for(int it = 0; it < 8; ++it) {
00336          if(theStationMask & 1<<it) ++numSegs;
00337          if(theRequiredStationMask & 1<<it) ++numRequiredStations;
00338       }
00339 
00340       // Make sure the minimum number of matches is not greater than
00341       // the number of required stations but still greater than zero
00342       if (syncMinNMatchesNRequiredStationsInBarrelOnly) {
00343          // Note that we only do this in the barrel region!
00344          if (fabs(muon.eta()) < 1.2) {
00345             if(minNumberOfMatches > numRequiredStations)
00346                minNumberOfMatches = numRequiredStations;
00347             if(minNumberOfMatches < 1) //SK: this only happens for negative values
00348                minNumberOfMatches = 1;
00349          }
00350       } else {
00351          if(minNumberOfMatches > numRequiredStations)
00352             minNumberOfMatches = numRequiredStations;
00353          if(minNumberOfMatches < 1) //SK: this only happens for negative values
00354             minNumberOfMatches = 1;
00355       }
00356 
00357       if(numSegs >= minNumberOfMatches) goodMuon = 1;
00358 
00359       // Require that last required station have segment
00360       // If there are zero required stations keep track
00361       // of the last station with a segment so that we may
00362       // apply the quality cuts below to it instead
00363       int lastSegBit = 0;
00364       if(theRequiredStationMask) {
00365          for(int stationIdx = 7; stationIdx >= 0; --stationIdx)
00366            if(theRequiredStationMask & 1<<stationIdx){
00367                if(theStationMask & 1<<stationIdx) {
00368                   lastSegBit = stationIdx;
00369                   goodMuon &= 1;
00370                   break;
00371                } else {
00372                   goodMuon = false;
00373                   break;
00374                }
00375            }
00376       } else {
00377          for(int stationIdx = 7; stationIdx >= 0; --stationIdx)
00378             if(theStationMask & 1<<stationIdx) {
00379                lastSegBit = stationIdx;
00380                break;
00381             }
00382       }
00383 
00384       if(!goodMuon) return false;
00385 
00386       // Impose pull cuts on last segment
00387       int station = 0, detector = 0;
00388       station  = lastSegBit < 4 ? lastSegBit+1 : lastSegBit-3;
00389       detector = lastSegBit < 4 ? 1 : 2;
00390 
00391       // Check x information
00392       if(fabs(muon.pullX(station,detector,arbitrationType,1)) > maxAbsPullX &&
00393             fabs(muon.dX(station,detector,arbitrationType)) > maxAbsDx)
00394          return false;
00395 
00396       if(applyAlsoAngularCuts && fabs(muon.pullDxDz(station,detector,arbitrationType,1)) > maxAbsPullX)
00397          return false;
00398 
00399       // Is this a tight algorithm, i.e. do we bother to check y information?
00400       if (maxAbsDy < 999999) { // really if maxAbsDy < 1E9 as currently defined
00401 
00402          // Check y information
00403          if (detector == 2) { // CSC
00404             if(fabs(muon.pullY(station,2,arbitrationType,1)) > maxAbsPullY &&
00405                   fabs(muon.dY(station,2,arbitrationType)) > maxAbsDy)
00406                return false;
00407 
00408             if(applyAlsoAngularCuts && fabs(muon.pullDyDz(station,2,arbitrationType,1)) > maxAbsPullY)
00409                return false;
00410          } else {
00411             //
00412             // In DT, if this is a "Tight" algorithm and the last segment is
00413             // missing y information (always the case in station 4!!!), impose
00414             // respective cuts on the next station in the stationMask that has
00415             // a segment with y information.  If there are no segments with y
00416             // information then there is nothing to penalize. Should we
00417             // penalize in Tight for having zero segments with y information?
00418             // That is the fundamental question.  Of course I am being uber
00419             // paranoid; if this is a good muon then there will probably be at
00420             // least one segment with y information but not always.  Suppose
00421             // somehow a muon only creates segments in station 4, then we
00422             // definitely do not want to require that there be at least one
00423             // segment with y information because we will lose it completely.
00424             //
00425 
00426             for (int stationIdx = station; stationIdx > 0; --stationIdx) {
00427                if(! (theStationMask & 1<<(stationIdx-1)))  // don't bother if the station is not in the stationMask
00428                   continue;
00429 
00430                if(muon.dY(stationIdx,1,arbitrationType) > 999998) // no y-information
00431                   continue;
00432 
00433                if(fabs(muon.pullY(stationIdx,1,arbitrationType,1)) > maxAbsPullY &&
00434                      fabs(muon.dY(stationIdx,1,arbitrationType)) > maxAbsDy) {
00435                   return false;
00436                }
00437 
00438                if(applyAlsoAngularCuts && fabs(muon.pullDyDz(stationIdx,1,arbitrationType,1)) > maxAbsPullY)
00439                   return false;
00440 
00441                // If we get this far then great this is a good muon
00442                return true;
00443             }
00444          }
00445       }
00446 
00447       return goodMuon;
00448    } // TMLastStation
00449 
00450    // TMOneStation requires only that there be one "good" segment, regardless
00451    // of the required stations.  We do not penalize if there are absolutely zero
00452    // segments with y information in the Tight algorithm.  Maybe I'm being
00453    // paranoid but so be it.  If it's really a good muon then we will probably
00454    // find at least one segment with both x and y information but you never
00455    // know, and I don't want to deal with a potential inefficiency in the DT
00456    // like we did with the original TMLastStation.  Incidentally, not penalizing
00457    // for total lack of y information in the Tight algorithm is what is done in
00458    // the new TMLastStation
00459    //                   
00460    if (type == TMOneStation) {
00461       unsigned int theStationMask = muon.stationMask(arbitrationType);
00462 
00463       // Of course there must be at least one segment
00464       if (! theStationMask) return false;
00465 
00466       int  station = 0, detector = 0;
00467       // Keep track of whether or not there is a DT segment with y information.
00468       // In the end, if it turns out there are absolutely zero DT segments with
00469       // y information, require only that there was a segment with good x info.
00470       // This of course only applies to the Tight algorithms.
00471       bool existsGoodDTSegX = false;
00472       bool existsDTSegY = false;
00473 
00474       // Impose cuts on the segments in the station mask until we find a good one
00475       // Might as well start with the lowest bit to speed things up.
00476       for(int stationIdx = 0; stationIdx <= 7; ++stationIdx)
00477          if(theStationMask & 1<<stationIdx) {
00478             station  = stationIdx < 4 ? stationIdx+1 : stationIdx-3;
00479             detector = stationIdx < 4 ? 1 : 2;
00480 
00481             if((fabs(muon.pullX(station,detector,arbitrationType,1)) > maxAbsPullX &&
00482                   fabs(muon.dX(station,detector,arbitrationType)) > maxAbsDx) ||
00483                   (applyAlsoAngularCuts && fabs(muon.pullDxDz(station,detector,arbitrationType,1)) > maxAbsPullX))
00484                continue;
00485             else if (detector == 1)
00486                existsGoodDTSegX = true;
00487 
00488             // Is this a tight algorithm?  If yes, use y information
00489             if (maxAbsDy < 999999) {
00490                if (detector == 2) { // CSC
00491                   if((fabs(muon.pullY(station,2,arbitrationType,1)) > maxAbsPullY &&
00492                         fabs(muon.dY(station,2,arbitrationType)) > maxAbsDy) ||
00493                         (applyAlsoAngularCuts && fabs(muon.pullDyDz(station,2,arbitrationType,1)) > maxAbsPullY))
00494                      continue;
00495                } else {
00496 
00497                   if(muon.dY(station,1,arbitrationType) > 999998) // no y-information
00498                      continue;
00499                   else
00500                      existsDTSegY = true;
00501 
00502                   if((fabs(muon.pullY(station,1,arbitrationType,1)) > maxAbsPullY &&
00503                         fabs(muon.dY(station,1,arbitrationType)) > maxAbsDy) ||
00504                         (applyAlsoAngularCuts && fabs(muon.pullDyDz(station,1,arbitrationType,1)) > maxAbsPullY)) {
00505                      continue;
00506                   }
00507                }
00508             }
00509 
00510             // If we get this far then great this is a good muon
00511             return true;
00512          }
00513 
00514       // If we get this far then for sure there are no "good" CSC segments. For
00515       // DT, check if there were any segments with y information.  If there
00516       // were none, but there was a segment with good x, then we're happy. If 
00517       // there WERE segments with y information, then they must have been shit
00518       // since we are here so fail it.  Of course, if this is a Loose algorithm
00519       // then fail immediately since if we had good x we would already have
00520       // returned true
00521       if (maxAbsDy < 999999) {
00522          if (existsDTSegY)
00523             return false;
00524          else if (existsGoodDTSegX)
00525             return true;
00526       } else
00527          return false;
00528    } // TMOneStation
00529 
00530    return goodMuon;
00531 }
00532 
00533 bool muon::isGoodMuon( const reco::Muon& muon, SelectionType type,
00534                        reco::Muon::ArbitrationType arbitrationType)
00535 {
00536   switch (type)
00537     {
00538     case muon::All:
00539       return true;
00540       break;
00541     case muon::AllGlobalMuons:
00542       return muon.isGlobalMuon();
00543       break;
00544     case muon::AllTrackerMuons:
00545       return muon.isTrackerMuon();
00546       break;
00547     case muon::AllStandAloneMuons:
00548       return muon.isStandAloneMuon();
00549       break;
00550     case muon::TrackerMuonArbitrated:
00551       return muon.isTrackerMuon() && muon.numberOfMatches(arbitrationType)>0;
00552       break;
00553     case muon::AllArbitrated:
00554       return ! muon.isTrackerMuon() || muon.numberOfMatches(arbitrationType)>0;
00555       break;
00556     case muon::GlobalMuonPromptTight:
00557       return muon.isGlobalMuon() && muon.globalTrack()->normalizedChi2()<10. && muon.globalTrack()->hitPattern().numberOfValidMuonHits() >0;
00558       break;
00559       // For "Loose" algorithms we choose maximum y quantity cuts of 1E9 instead of
00560       // 9999 as before.  We do this because the muon methods return 999999 (note
00561       // there are six 9's) when the requested information is not available.  For
00562       // example, if a muon fails to traverse the z measuring superlayer in a station
00563       // in the DT, then all methods involving segmentY in this station return
00564       // 999999 to demonstrate that the information is missing.  In order to not
00565       // penalize muons for missing y information in Loose algorithms where we do
00566       // not care at all about y information, we raise these limits.  In the
00567       // TMLastStation and TMOneStation algorithms we actually use this huge number
00568       // to determine whether to consider y information at all.
00569     case muon::TMLastStationLoose:
00570       return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,1E9,1E9,-3,-3,arbitrationType,true,false);
00571       break;
00572     case muon::TMLastStationTight:
00573       return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,3,3,-3,-3,arbitrationType,true,false);
00574       break;
00575     case muon::TMOneStationLoose:
00576       return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,1E9,1E9,1E9,1E9,arbitrationType,false,false);
00577       break;
00578     case muon::TMOneStationTight:
00579       return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,3,3,1E9,1E9,arbitrationType,false,false);
00580       break;
00581     case muon::TMLastStationOptimizedLowPtLoose:
00582       if (muon.pt() < 8. && fabs(muon.eta()) < 1.2)
00583         return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,1E9,1E9,1E9,1E9,arbitrationType,false,false);
00584       else
00585         return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,1E9,1E9,-3,-3,arbitrationType,false,false);
00586       break;
00587     case muon::TMLastStationOptimizedLowPtTight:
00588       if (muon.pt() < 8. && fabs(muon.eta()) < 1.2)
00589         return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,3,3,1E9,1E9,arbitrationType,false,false);
00590       else
00591         return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,3,3,-3,-3,arbitrationType,false,false);
00592       break;
00593       //compatibility loose
00594     case muon::TM2DCompatibilityLoose:
00595       return muon.isTrackerMuon() && isGoodMuon(muon,TM2DCompatibility,0.7,arbitrationType);
00596       break;
00597       //compatibility tight
00598     case muon::TM2DCompatibilityTight:
00599       return muon.isTrackerMuon() && isGoodMuon(muon,TM2DCompatibility,1.0,arbitrationType);
00600       break;
00601     case muon::GMTkChiCompatibility:
00602       return muon.isGlobalMuon() && muon.isQualityValid() && fabs(muon.combinedQuality().trkRelChi2 - muon.innerTrack()->normalizedChi2()) < 2.0;
00603       break;
00604     case muon::GMStaChiCompatibility:
00605       return muon.isGlobalMuon() && muon.isQualityValid() && fabs(muon.combinedQuality().staRelChi2 - muon.outerTrack()->normalizedChi2()) < 2.0;
00606       break;
00607     case muon::GMTkKinkTight:
00608       return muon.isGlobalMuon() && muon.isQualityValid() && muon.combinedQuality().trkKink < 100.0;
00609       break;
00610     case muon::TMLastStationAngLoose:
00611       return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,1E9,1E9,-3,-3,arbitrationType,false,true);
00612       break;
00613     case muon::TMLastStationAngTight:
00614       return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,3,3,-3,-3,arbitrationType,false,true);
00615       break;
00616     case muon::TMOneStationAngLoose:
00617       return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,1E9,1E9,1E9,1E9,arbitrationType,false,true);
00618       break;
00619     case muon::TMOneStationAngTight:
00620       return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,3,3,1E9,1E9,arbitrationType,false,true);
00621       break;
00622     case muon::TMLastStationOptimizedBarrelLowPtLoose:
00623       if (muon.pt() < 8. && fabs(muon.eta()) < 1.2)
00624         return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,1E9,1E9,1E9,1E9,arbitrationType,false,false);
00625       else
00626         return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,1E9,1E9,-3,-3,arbitrationType,true,false);
00627       break;
00628     case muon::TMLastStationOptimizedBarrelLowPtTight:
00629       if (muon.pt() < 8. && fabs(muon.eta()) < 1.2)
00630         return muon.isTrackerMuon() && isGoodMuon(muon,TMOneStation,1,3,3,3,3,1E9,1E9,arbitrationType,false,false);
00631       else
00632         return muon.isTrackerMuon() && isGoodMuon(muon,TMLastStation,2,3,3,3,3,-3,-3,arbitrationType,true,false);
00633       break;
00634     default:
00635       return false;
00636     }
00637 }
00638 
00639 bool muon::overlap( const reco::Muon& muon1, const reco::Muon& muon2, 
00640                     double pullX, double pullY, bool checkAdjacentChambers)
00641 {
00642   unsigned int nMatches1 = muon1.numberOfMatches(reco::Muon::SegmentAndTrackArbitration);
00643   unsigned int nMatches2 = muon2.numberOfMatches(reco::Muon::SegmentAndTrackArbitration);
00644   unsigned int betterMuon = ( muon1.pt() > muon2.pt() ? 1 : 2 );
00645   for ( std::vector<reco::MuonChamberMatch>::const_iterator chamber1 = muon1.matches().begin();
00646            chamber1 != muon1.matches().end(); ++chamber1 )
00647     for ( std::vector<reco::MuonChamberMatch>::const_iterator chamber2 = muon2.matches().begin();
00648           chamber2 != muon2.matches().end(); ++chamber2 )
00649       {
00650         
00651         // if ( (chamber1->segmentMatches.empty() || chamber2->segmentMatches.empty()) ) continue;
00652         
00653         // handle case where both muons have information about the same chamber
00654         // here we know how close they are 
00655         if ( chamber1->id == chamber2->id ){
00656           // found the same chamber
00657           if ( fabs(chamber1->x-chamber2->x) < 
00658                pullX * sqrt(chamber1->xErr*chamber1->xErr+chamber2->xErr*chamber2->xErr) )
00659             {
00660               if ( betterMuon == 1 )
00661                 nMatches2--;
00662               else
00663                 nMatches1--;
00664               if ( nMatches1==0 || nMatches2==0 ) return true;
00665               continue;
00666             }
00667           if ( fabs(chamber1->y-chamber2->y) < 
00668                pullY * sqrt(chamber1->yErr*chamber1->yErr+chamber2->yErr*chamber2->yErr) )
00669             {
00670               if ( betterMuon == 1 )
00671                 nMatches2--;
00672               else
00673                 nMatches1--;
00674               if ( nMatches1==0 || nMatches2==0 ) return true;
00675             }
00676         } else {
00677           if ( ! checkAdjacentChambers ) continue;
00678           // check if tracks are pointing into overlaping region of the CSC detector
00679           if ( chamber1->id.subdetId() != MuonSubdetId::CSC || 
00680                chamber2->id.subdetId() != MuonSubdetId::CSC ) continue;
00681           CSCDetId id1(chamber1->id);
00682           CSCDetId id2(chamber2->id);
00683           if ( id1.endcap()  != id2.endcap() )  continue;
00684           if ( id1.station() != id2.station() ) continue;
00685           if ( id1.ring()    != id2.ring() )    continue;
00686           if ( abs(id1.chamber() - id2.chamber())>1 ) continue;
00687           // FIXME: we don't handle 18->1; 36->1 transitions since 
00688           // I don't know how to check for sure how many chambers
00689           // are there. Probably need to hard code some checks.
00690           
00691           // Now we have to make sure that both tracks are close to an edge
00692           // FIXME: ignored Y coordinate for now
00693           if ( fabs(chamber1->edgeX) > chamber1->xErr*pullX ) continue;
00694           if ( fabs(chamber2->edgeX) > chamber2->xErr*pullX ) continue;
00695           if ( chamber1->x * chamber2->x < 0 ) { // check if the same edge
00696             if ( betterMuon == 1 )
00697               nMatches2--;
00698             else
00699               nMatches1--;
00700             if ( nMatches1==0 || nMatches2==0 ) return true;
00701           }
00702         }
00703       }
00704   return false;
00705 }