CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/RecoMuon/GlobalTrackingTools/src/GlobalMuonTrackMatcher.cc

Go to the documentation of this file.
00001 
00015 #include "RecoMuon/GlobalTrackingTools/interface/GlobalMuonTrackMatcher.h"
00016 
00017 //---------------
00018 // C++ Headers --
00019 //---------------
00020 
00021 
00022 //-------------------------------
00023 // Collaborating Class Headers --
00024 //-------------------------------
00025 
00026 #include "FWCore/ServiceRegistry/interface/Service.h"
00027 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00028 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00029 
00030 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
00031 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
00032 #include "TrackingTools/GeomPropagators/interface/StateOnTrackerBound.h"
00033 #include "TrackingTools/TransientTrack/interface/TransientTrack.h"
00034 #include "TrackingTools/PatternTools/interface/Trajectory.h"
00035 
00036 #include "RecoMuon/TrackingTools/interface/MuonServiceProxy.h"
00037 
00038 #include "DataFormats/TrackReco/interface/Track.h"
00039 #include "DataFormats/TrajectoryState/interface/LocalTrajectoryParameters.h"
00040 
00041 #include "DataFormats/GeometrySurface/interface/TangentPlane.h"
00042 #include "DataFormats/Math/interface/deltaR.h"
00043 
00044 #include "Geometry/CommonDetUnit/interface/GeomDetUnit.h"
00045 
00046 using namespace std;
00047 using namespace reco;
00048 
00049 //
00050 // constructor
00051 //
00052 GlobalMuonTrackMatcher::GlobalMuonTrackMatcher(const edm::ParameterSet& par, 
00053                                                const MuonServiceProxy* service) : 
00054   theService(service) {
00055   theMinP = par.getParameter<double>("MinP");
00056   theMinPt = par.getParameter<double>("MinPt");
00057   thePt_threshold1 = par.getParameter<double>("Pt_threshold1");
00058   thePt_threshold2 = par.getParameter<double>("Pt_threshold2");
00059   theEta_threshold= par.getParameter<double>("Eta_threshold");
00060   theChi2_1= par.getParameter<double>("Chi2Cut_1");
00061   theChi2_2= par.getParameter<double>("Chi2Cut_2");
00062   theChi2_3= par.getParameter<double>("Chi2Cut_3");
00063   theLocChi2= par.getParameter<double>("LocChi2Cut");
00064   theDeltaD_1= par.getParameter<double>("DeltaDCut_1");
00065   theDeltaD_2= par.getParameter<double>("DeltaDCut_2");
00066   theDeltaD_3= par.getParameter<double>("DeltaDCut_3");
00067   theDeltaR_1= par.getParameter<double>("DeltaRCut_1");
00068   theDeltaR_2= par.getParameter<double>("DeltaRCut_2");
00069   theDeltaR_3= par.getParameter<double>("DeltaRCut_3");
00070   theQual_1= par.getParameter<double>("Quality_1");
00071   theQual_2= par.getParameter<double>("Quality_2");
00072   theQual_3= par.getParameter<double>("Quality_3");
00073   theOutPropagatorName = par.getParameter<string>("Propagator");
00074 
00075 }
00076 
00077 
00078 //
00079 // destructor
00080 //
00081 GlobalMuonTrackMatcher::~GlobalMuonTrackMatcher() {
00082 
00083 }
00084 
00085 
00086 //
00087 // check if two tracks are compatible with the *tight* criteria
00088 //
00089 bool 
00090 GlobalMuonTrackMatcher::matchTight(const TrackCand& sta,
00091                               const TrackCand& track) const {
00092 
00093   std::pair<TrajectoryStateOnSurface, TrajectoryStateOnSurface> tsosPair
00094       = convertToTSOSMuHit(sta,track);
00095 
00096   double chi2 = match_Chi2(tsosPair.first,tsosPair.second);
00097   if ( chi2 > 0. && chi2 < theChi2_2 ) return true;
00098 
00099   double distance = match_d(tsosPair.first,tsosPair.second);
00100   if ( distance > 0. && distance < theDeltaD_2 ) return true;
00101 
00102   //double deltaR = match_Rpos(tsosPair.first,tsosPair.second);
00103   //if ( deltaR > 0. && deltaR < theDeltaR_3 ) return true;
00104 
00105   return false;
00106 
00107 }
00108 
00109 
00110 //
00111 // check if two tracks are compatible
00112 //
00113 double
00114 GlobalMuonTrackMatcher::match(const TrackCand& sta,
00115                               const TrackCand& track,
00116                               int matchOption,
00117                               int surfaceOption) const {
00118 
00119   std::pair<TrajectoryStateOnSurface, TrajectoryStateOnSurface> tsosPair;
00120   if ( surfaceOption == 0 ) tsosPair = convertToTSOSMuHit(sta,track);
00121   if ( surfaceOption == 1 ) tsosPair = convertToTSOSTkHit(sta,track);
00122   if ( surfaceOption != 0 && surfaceOption != 1 ) return -1.0;
00123 
00124   if ( matchOption == 0 ) {
00125     // chi^2
00126     return  match_Chi2(tsosPair.first,tsosPair.second);
00127   }
00128   else if ( matchOption == 1 ) {
00129     // distance
00130     return match_d(tsosPair.first,tsosPair.second);
00131   }
00132   else if ( matchOption == 2 ) {
00133     // deltaR
00134     return match_Rpos(tsosPair.first,tsosPair.second);
00135   }
00136   else if ( matchOption == 3 ) {
00137     return match_dist(tsosPair.first,tsosPair.second);
00138   }
00139   else {
00140     return -1.0;
00141   }
00142 }
00143 
00144 
00145 //
00146 // choose the track from a TrackCollection which best
00147 // matches a given standalone muon track
00148 //
00149 std::vector<GlobalMuonTrackMatcher::TrackCand>::const_iterator 
00150 GlobalMuonTrackMatcher::matchOne(const TrackCand& sta,
00151                                  const std::vector<TrackCand>& tracks) const {
00152 
00153   if ( tracks.empty() ) return tracks.end();
00154 
00155   double minChi2 = 1000.0;
00156   vector<TrackCand>::const_iterator result = tracks.end();
00157   for (vector<TrackCand>::const_iterator is = tracks.begin(); is != tracks.end(); ++is) {
00158     // propagate to common surface
00159     std::pair<TrajectoryStateOnSurface, TrajectoryStateOnSurface> tsosPair
00160       = convertToTSOSMuHit(sta,*is);
00161 
00162     // calculate chi^2 of local track parameters
00163     double chi2 = match_Chi2(tsosPair.first,tsosPair.second);
00164     if ( chi2 > 0. && chi2 <= minChi2 ) {
00165       minChi2 = chi2;
00166       result = is;
00167     }
00168     
00169   }
00170   
00171   return result;
00172   
00173 }
00174 
00175 
00176 //
00177 // choose a vector of tracks from a TrackCollection that are compatible
00178 // with a given standalone track. The order of checks for compatability 
00179 // * for low momentum: use chi2 selection 
00180 // * high momentum: use direction or local position 
00181 //
00182 vector<GlobalMuonTrackMatcher::TrackCand>
00183 GlobalMuonTrackMatcher::match(const TrackCand& sta, 
00184                               const vector<TrackCand>& tracks) const {
00185   const string category = "GlobalMuonTrackMatcher";
00186   
00187   vector<TrackCand> result;
00188   
00189   if ( tracks.empty() ) return result;
00190   
00191   typedef std::pair<TrackCand, TrajectoryStateOnSurface> TrackCandWithTSOS;
00192   vector<TrackCandWithTSOS> cands;
00193   int iiTk = 1;
00194   TrajectoryStateOnSurface muonTSOS;
00195 
00196   LogTrace(category) << "   ***" << endl << "STA Muon pT "<< sta.second->pt(); 
00197   LogTrace(category) << "   Tk in Region " << tracks.size() << endl;
00198 
00199   for (vector<TrackCand>::const_iterator is = tracks.begin(); is != tracks.end(); ++is,iiTk++) {
00200     // propagate to a common surface 
00201     std::pair<TrajectoryStateOnSurface, TrajectoryStateOnSurface> tsosPair = convertToTSOSMuHit(sta,*is);
00202     LogTrace(category) << "    Tk " << iiTk << " of " << tracks.size() << "  ConvertToMuHitSurface muon isValid " << tsosPair.first.isValid() << " tk isValid " << tsosPair.second.isValid() << endl;
00203     if(tsosPair.first.isValid()) muonTSOS = tsosPair.first;
00204     cands.push_back(TrackCandWithTSOS(*is,tsosPair.second));
00205   }
00206   
00207   // initialize variables
00208   double min_chisq = 999999;
00209   double min_d = 999999;
00210   double min_de= 999999;
00211   double min_r_pos = 999999;
00212   std::vector<bool> passes(cands.size(),false);
00213   int jj=0;
00214 
00215   int iTkCand = 1;
00216   for (vector<TrackCandWithTSOS>::const_iterator ii = cands.begin(); ii != cands.end(); ++ii,jj++,iTkCand++) {
00217     
00218     // tracks that are able not able propagate to a common surface
00219     if(!muonTSOS.isValid() || !(*ii).second.isValid()) continue;
00220     
00221     // calculate matching variables
00222     double distance = match_d(muonTSOS,(*ii).second);
00223     double chi2 = match_Chi2(muonTSOS,(*ii).second);
00224     double loc_chi2 = match_dist(muonTSOS,(*ii).second);
00225     double deltaR = match_Rpos(muonTSOS,(*ii).second);
00226 
00227     LogTrace(category) << "   iTk " << iTkCand << " of " << cands.size() << " eta " << (*ii).second.globalPosition().eta() << " phi " << (*ii).second.globalPosition().phi() << endl; 
00228     LogTrace(category) << "    distance " << distance << " distance cut " << " " << endl;
00229     LogTrace(category) << "    chi2 " << chi2 << " chi2 cut " << " " << endl;
00230     LogTrace(category) << "    loc_chi2 " << loc_chi2 << " locChi2 cut " << " " << endl;
00231     LogTrace(category) << "    deltaR " << deltaR << " deltaR cut " << " " << endl;   
00232     
00233     if( (*ii).second.globalMomentum().perp()<thePt_threshold1){
00234       LogTrace(category) << "    Enters  a1" << endl;
00235 
00236       if( ( chi2>0 && fabs((*ii).second.globalMomentum().eta())<theEta_threshold && chi2<theChi2_1 ) || (distance>0 && distance/(*ii).first.second->pt()<theDeltaD_1 && loc_chi2>0 && loc_chi2<theLocChi2) ){
00237         LogTrace(category) << "    Passes a1" << endl;
00238         result.push_back((*ii).first);
00239         passes[jj]=true;
00240       }
00241     }
00242     if( (passes[jj]==false) && (*ii).second.globalMomentum().perp()<thePt_threshold2){
00243       LogTrace(category) << "    Enters a2" << endl;
00244       if( ( chi2>0 && chi2< theChi2_2 ) || (distance>0 && distance<theDeltaD_2) ){
00245         LogTrace(category) << "    Passes a2" << endl;
00246         result.push_back((*ii).first);
00247         passes[jj] = true;
00248       }
00249     }else{
00250       LogTrace(category) << "    Enters a3" << endl;
00251       if( distance>0 && distance<theDeltaD_3 && deltaR>0 && deltaR<theDeltaR_1){
00252         LogTrace(category) << "    Passes a3" << endl;
00253         result.push_back((*ii).first);
00254         passes[jj]=true;
00255       }
00256     }
00257     
00258     if(passes[jj]){
00259       if(distance<min_d) min_d = distance;
00260       if(loc_chi2<min_de) min_de = loc_chi2;
00261       if(deltaR<min_r_pos) min_r_pos = deltaR;
00262       if(chi2<min_chisq) min_chisq = chi2;
00263     }
00264 
00265   }
00266   
00267   // re-initialize mask counter
00268   jj=0;
00269   
00270   if ( result.empty() ) {
00271     LogTrace(category) << "   Stage 1 returned 0 results";
00272     for (vector<TrackCandWithTSOS>::const_iterator is = cands.begin(); is != cands.end(); ++is,jj++) {
00273       double deltaR = match_Rpos(muonTSOS,(*is).second);
00274 
00275       if (muonTSOS.isValid() && (*is).second.isValid()) {
00276         // check matching between tracker and muon tracks using dEta cut looser then dPhi cut 
00277         LogTrace(category) << "    Stage 2 deltaR " << deltaR << " deltaEta " << fabs((*is).second.globalPosition().eta()-muonTSOS.globalPosition().eta()<1.5*theDeltaR_2) << " deltaPhi " << (fabs(deltaPhi((*is).second.globalPosition().phi(),muonTSOS.globalPosition().phi()))<theDeltaR_2) << endl;
00278         
00279         if(fabs((*is).second.globalPosition().eta()-muonTSOS.globalPosition().eta())<1.5*theDeltaR_2
00280            &&fabs(deltaPhi((*is).second.globalPosition().phi(),muonTSOS.globalPosition().phi()))<theDeltaR_2){
00281           result.push_back((*is).first);
00282           passes[jj]=true;
00283         }
00284       }
00285       
00286       if(passes[jj]){
00287         double distance = match_d(muonTSOS,(*is).second);
00288         double chi2 = match_Chi2(muonTSOS,(*is).second);
00289         double loc_chi2 = match_dist(muonTSOS,(*is).second);
00290         if(distance<min_d) min_d = distance;
00291         if(loc_chi2<min_de) min_de = loc_chi2;
00292         if(deltaR<min_r_pos) min_r_pos = deltaR;
00293         if(chi2<min_chisq) min_chisq = chi2;
00294         
00295       }
00296       
00297     }
00298     
00299   }  
00300 
00301   for(vector<TrackCand>::const_iterator iTk=result.begin();
00302       iTk != result.end(); ++iTk) {
00303     LogTrace(category) << "   -----" << endl 
00304                               << "selected pt " << iTk->second->pt() 
00305                               << " eta " << iTk->second->eta() 
00306                               << " phi " << iTk->second->phi() << endl; 
00307   }
00308 
00309   if(result.size()<2)
00310     return result;
00311   else
00312     result.clear();
00313   
00314   LogTrace(category) << "   Cleaning matched candiates" << endl;
00315 
00316   // re-initialize mask counter
00317   jj=0;
00318   
00319   
00320   for (vector<TrackCandWithTSOS>::const_iterator is = cands.begin(); is != cands.end(); ++is,jj++) {
00321     
00322     if(!passes[jj]) continue;
00323     
00324     double distance = match_d(muonTSOS,(*is).second);
00325     double chi2 = match_Chi2(muonTSOS,(*is).second);
00326     //unused    double loc_chi2 = match_dist(muonTSOS,(*is).second);
00327     double deltaR = match_Rpos(muonTSOS,(*is).second);
00328     
00329     // compute quality as the relative ratio to the minimum found for each variable
00330     
00331     int qual = (int)(chi2/min_chisq + distance/min_d + deltaR/min_r_pos);
00332     int n_min = ((chi2/min_chisq==1)?1:0) + ((distance/min_d==1)?1:0) + ((deltaR/min_r_pos==1)?1:0);
00333     
00334     if(n_min == 3){
00335       result.push_back((*is).first);
00336     }
00337     
00338     if(n_min == 2 && qual < theQual_1 ){
00339       result.push_back((*is).first);
00340     }
00341     
00342     if(n_min == 1 && qual < theQual_2 ){
00343       result.push_back((*is).first);
00344     }
00345     
00346     if(n_min == 0 && qual < theQual_3 ){
00347       result.push_back((*is).first);
00348     }
00349     
00350   }
00351 
00352   for(vector<TrackCand>::const_iterator iTk=result.begin();
00353       iTk != result.end(); ++iTk) {
00354     LogTrace(category) << "   -----" << endl 
00355                               << "selected pt " << iTk->second->pt() 
00356                               << " eta " << iTk->second->eta() 
00357                               << " phi " << iTk->second->phi() << endl; 
00358   }
00359  
00360   return result;
00361 }
00362 
00363 
00364 //
00365 // propagate the two track candidates to the tracker bound surface
00366 //
00367 std::pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>
00368 GlobalMuonTrackMatcher::convertToTSOSTk(const TrackCand& staCand,
00369                                         const TrackCand& tkCand) const {
00370   
00371   const string category = "GlobalMuonTrackMatcher";
00372 
00373   TrajectoryStateOnSurface empty; 
00374   
00375   TransientTrack muTT(*staCand.second,&*theService->magneticField(),theService->trackingGeometry());
00376   TrajectoryStateOnSurface impactMuTSOS = muTT.impactPointState();
00377 
00378   TrajectoryStateOnSurface outerTkTsos;
00379   if (tkCand.second.isNonnull()) {
00380     // make sure the tracker track has enough momentum to reach the muon chambers
00381     if ( !(tkCand.second->p() < theMinP || tkCand.second->pt() < theMinPt )) {
00382       
00383       outerTkTsos = trajectoryStateTransform::outerStateOnSurface(*tkCand.second,*theService->trackingGeometry(),&*theService->magneticField());
00384     }
00385   }
00386   
00387   if ( !impactMuTSOS.isValid() || !outerTkTsos.isValid() ) return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty,empty);
00388   
00389   // define StateOnTrackerBound object
00390   StateOnTrackerBound fromInside(&*theService->propagator(theOutPropagatorName));
00391   
00392   // extrapolate to outer tracker surface
00393   TrajectoryStateOnSurface tkTsosFromMu = fromInside(impactMuTSOS);
00394   TrajectoryStateOnSurface tkTsosFromTk = fromInside(outerTkTsos);
00395 
00396   if ( !samePlane(tkTsosFromMu,tkTsosFromTk) ) {
00397     // propagate tracker track to same surface as muon
00398     bool same1, same2;
00399     TrajectoryStateOnSurface newTkTsosFromTk, newTkTsosFromMu;
00400     if ( tkTsosFromMu.isValid() ) newTkTsosFromTk = theService->propagator(theOutPropagatorName)->propagate(outerTkTsos,tkTsosFromMu.surface());
00401     same1 = samePlane(newTkTsosFromTk,tkTsosFromMu);
00402     LogTrace(category) << "Propagating to same tracker surface (Mu):" << same1;
00403     if ( !same1 ) {
00404       if ( tkTsosFromTk.isValid() ) newTkTsosFromMu = theService->propagator(theOutPropagatorName)->propagate(impactMuTSOS,tkTsosFromTk.surface());
00405       same2 = samePlane(newTkTsosFromMu,tkTsosFromTk);
00406       LogTrace(category) << "Propagating to same tracker surface (Tk):" << same2;
00407     }
00408     if (same1) tkTsosFromTk = newTkTsosFromTk;
00409     else if (same2) tkTsosFromMu = newTkTsosFromMu;
00410     else  {
00411       LogTrace(category) << "Could not propagate Muon and Tracker track to the same tracker bound!";
00412       return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty, empty);
00413     }
00414   }
00415  
00416   return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(tkTsosFromMu, tkTsosFromTk);
00417 
00418 }
00419 
00420 
00421 //
00422 // propagate the two track candidates to the surface of the innermost muon hit
00423 //
00424 std::pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>
00425 GlobalMuonTrackMatcher::convertToTSOSMuHit(const TrackCand& staCand,
00426                                            const TrackCand& tkCand) const {
00427   
00428   const string category = "GlobalMuonTrackMatcher";
00429   TrajectoryStateOnSurface empty; 
00430   TransientTrack muTT(*staCand.second,&*theService->magneticField(),theService->trackingGeometry());
00431   TrajectoryStateOnSurface innerMuTSOS = muTT.innermostMeasurementState();
00432   TrajectoryStateOnSurface outerTkTsos,innerTkTsos;
00433   if ( tkCand.second.isNonnull() ) {
00434     // make sure the tracker track has enough momentum to reach the muon chambers
00435     if ( !(tkCand.second->p() < theMinP || tkCand.second->pt() < theMinPt ) ) {
00436       TrajectoryStateOnSurface innerTkTsos;
00437       
00438       outerTkTsos = trajectoryStateTransform::outerStateOnSurface(*tkCand.second,*theService->trackingGeometry(),&*theService->magneticField());
00439       innerTkTsos = trajectoryStateTransform::innerStateOnSurface(*tkCand.second,*theService->trackingGeometry(),&*theService->magneticField());
00440       // for cosmics, outer-most referst to last traversed layer
00441       if ( (innerMuTSOS.globalPosition() -  outerTkTsos.globalPosition()).mag() > (innerMuTSOS.globalPosition() -  innerTkTsos.globalPosition()).mag() )
00442         outerTkTsos = innerTkTsos;
00443       
00444     }
00445   }
00446     
00447   if ( !innerMuTSOS.isValid() || !outerTkTsos.isValid() ) {
00448     LogTrace(category) << "A TSOS validity problem! MuTSOS " << innerMuTSOS.isValid() << " TkTSOS " << outerTkTsos.isValid();
00449     return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty,empty);
00450   }
00451   
00452   const Surface& refSurface = innerMuTSOS.surface();
00453   TrajectoryStateOnSurface tkAtMu = theService->propagator(theOutPropagatorName)->propagate(*outerTkTsos.freeState(),refSurface);
00454   
00455   if ( !tkAtMu.isValid() ) {
00456     LogTrace(category) << "Could not propagate Muon and Tracker track to the same muon hit surface!";
00457     return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty,empty);    
00458   }
00459   
00460   return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(innerMuTSOS, tkAtMu);
00461 
00462 }
00463 
00464 
00465 //
00466 // propagate the two track candidates to the surface of the outermost tracker hit
00467 //
00468 std::pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>
00469 GlobalMuonTrackMatcher::convertToTSOSTkHit(const TrackCand& staCand,
00470                                            const TrackCand& tkCand) const {
00471   
00472   const string category = "GlobalMuonTrackMatcher";
00473 
00474   TrajectoryStateOnSurface empty; 
00475 
00476   TransientTrack muTT(*staCand.second,&*theService->magneticField(),theService->trackingGeometry());
00477   TrajectoryStateOnSurface impactMuTSOS = muTT.impactPointState();
00478   TrajectoryStateOnSurface innerMuTSOS = muTT.innermostMeasurementState();
00479   
00480   TrajectoryStateOnSurface outerTkTsos,innerTkTsos;
00481   if ( tkCand.second.isNonnull() ) {
00482     // make sure the tracker track has enough momentum to reach the muon chambers
00483     if ( !(tkCand.second->p() < theMinP || tkCand.second->pt() < theMinPt )) {
00484       
00485       outerTkTsos = trajectoryStateTransform::outerStateOnSurface(*tkCand.second,*theService->trackingGeometry(),&*theService->magneticField());
00486       innerTkTsos = trajectoryStateTransform::innerStateOnSurface(*tkCand.second,*theService->trackingGeometry(),&*theService->magneticField());
00487       
00488       // for cosmics, outer-most referst to last traversed layer
00489       if ( (innerMuTSOS.globalPosition() -  outerTkTsos.globalPosition()).mag() > (innerMuTSOS.globalPosition() -  innerTkTsos.globalPosition()).mag() )
00490         outerTkTsos = innerTkTsos;
00491       
00492     }
00493   }
00494 
00495   if ( !impactMuTSOS.isValid() || !outerTkTsos.isValid() ) {
00496     LogTrace(category) << "A TSOS validity problem! MuTSOS " << impactMuTSOS.isValid() << " TkTSOS " << outerTkTsos.isValid();
00497     return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty,empty);
00498   }
00499 
00500   const Surface& refSurface = outerTkTsos.surface();
00501   TrajectoryStateOnSurface muAtTk = theService->propagator(theOutPropagatorName)->propagate(*impactMuTSOS.freeState(),refSurface);
00502   
00503   if ( !muAtTk.isValid() ) {
00504     LogTrace(category) << "Could not propagate Muon and Tracker track to the same tracker hit surface!";
00505     return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(empty,empty);    
00506   }
00507 
00508   return pair<TrajectoryStateOnSurface,TrajectoryStateOnSurface>(muAtTk, outerTkTsos);
00509 
00510 }
00511 
00512 
00513 //
00514 //
00515 //
00516 bool
00517 GlobalMuonTrackMatcher::samePlane(const TrajectoryStateOnSurface& tsos1,
00518                                   const TrajectoryStateOnSurface& tsos2) const {
00519 
00520   if ( !tsos1.isValid() || !tsos2.isValid() ) return false;
00521 
00522   if ( fabs(match_D(tsos1,tsos2) - match_d(tsos1,tsos2)) > 0.1 ) return false;
00523 
00524   const float maxtilt = 0.999;
00525   const float maxdist = 0.01; // in cm
00526 
00527   ReferenceCountingPointer<TangentPlane> p1(tsos1.surface().tangentPlane(tsos1.localPosition()));
00528   ReferenceCountingPointer<TangentPlane> p2(tsos2.surface().tangentPlane(tsos2.localPosition()));
00529 
00530   bool returnValue = ( (fabs(p1->normalVector().dot(p2->normalVector())) > maxtilt) || (fabs((p1->toLocal(p2->position())).z()) < maxdist) ) ? true : false;
00531 
00532   return returnValue; 
00533  
00534 }
00535 
00536 
00537 //
00538 // calculate Chi^2 of two trajectory states
00539 //
00540 double 
00541 GlobalMuonTrackMatcher::match_Chi2(const TrajectoryStateOnSurface& tsos1, 
00542                                    const TrajectoryStateOnSurface& tsos2) const {
00543   
00544   const string category = "GlobalMuonTrackMatcher";
00545   //LogTrace(category) << "match_Chi2 sanity check: " << tsos1.isValid() << " " << tsos2.isValid();
00546   if ( !tsos1.isValid() || !tsos2.isValid() ) return -1.;
00547   
00548   AlgebraicVector5 v(tsos1.localParameters().vector() - tsos2.localParameters().vector());
00549   AlgebraicSymMatrix55 m(tsos1.localError().matrix() + tsos2.localError().matrix());
00550   
00551   //LogTrace(category) << "match_Chi2 vector v " << v;
00552 
00553   bool ierr = !m.Invert();
00554  
00555   if ( ierr ) { 
00556     edm::LogInfo(category) << "Error inverting covariance matrix";
00557     return -1;
00558   }
00559  
00560   double est = ROOT::Math::Similarity(v,m);
00561  
00562   //LogTrace(category) << "Chi2 " << est;
00563 
00564   return est;
00565 
00566 }
00567 
00568 
00569 //
00570 // calculate Delta_R of two track candidates at the IP
00571 //
00572 double
00573 GlobalMuonTrackMatcher::match_R_IP(const TrackCand& staCand, 
00574                                    const TrackCand& tkCand) const {
00575 
00576   double dR = 99.0;
00577   if (tkCand.second.isNonnull()) {
00578     dR = (deltaR<double>(staCand.second->eta(),staCand.second->phi(),
00579                          tkCand.second->eta(),tkCand.second->phi()));
00580   }
00581 
00582   return dR;
00583 
00584 }
00585 
00586 
00587 //
00588 // calculate Delta_R of two trajectory states
00589 //
00590 double
00591 GlobalMuonTrackMatcher::match_Rmom(const TrajectoryStateOnSurface& sta, 
00592                                    const TrajectoryStateOnSurface& tk) const {
00593 
00594   if( !sta.isValid() || !tk.isValid() ) return -1;
00595   return (deltaR<double>(sta.globalMomentum().eta(),sta.globalMomentum().phi(),
00596                          tk.globalMomentum().eta(),tk.globalMomentum().phi()));
00597 
00598 }
00599 
00600 
00601 //
00602 // calculate Delta_R of two trajectory states
00603 //
00604 double
00605 GlobalMuonTrackMatcher::match_Rpos(const TrajectoryStateOnSurface& sta, 
00606                                    const TrajectoryStateOnSurface& tk) const {
00607 
00608   if ( !sta.isValid() || !tk.isValid() ) return -1;
00609   return (deltaR<double>(sta.globalPosition().eta(),sta.globalPosition().phi(),
00610                          tk.globalPosition().eta(),tk.globalPosition().phi()));
00611 
00612 }
00613 
00614 
00615 //
00616 // calculate the distance in global position of two trajectory states
00617 //
00618 double
00619 GlobalMuonTrackMatcher::match_D(const TrajectoryStateOnSurface& sta, 
00620                                 const TrajectoryStateOnSurface& tk) const {
00621 
00622   if ( !sta.isValid() || !tk.isValid() ) return -1;
00623   return (sta.globalPosition() - tk.globalPosition()).mag();
00624 
00625 }
00626 
00627 
00628 //
00629 // calculate the distance in local position of two trajectory states
00630 //
00631 double
00632 GlobalMuonTrackMatcher::match_d(const TrajectoryStateOnSurface& sta, 
00633                                 const TrajectoryStateOnSurface& tk) const {
00634 
00635   if ( !sta.isValid() || !tk.isValid() ) return -1;
00636   return (sta.localPosition() - tk.localPosition()).mag();
00637 
00638 }
00639 
00640 
00641 //
00642 // calculate the chi2 of the distance in local position of two 
00643 // trajectory states including local errors
00644 //
00645 double
00646 GlobalMuonTrackMatcher::match_dist(const TrajectoryStateOnSurface& sta, 
00647                                    const TrajectoryStateOnSurface& tk) const {
00648  
00649    const string category = "GlobalMuonTrackMatcher";
00650    
00651    if ( !sta.isValid() || !tk.isValid() ) return -1;
00652  
00653    AlgebraicMatrix22 m;
00654    m(0,0) = tk.localError().positionError().xx() + sta.localError().positionError().xx();
00655    m(1,0) = m(0,1) = tk.localError().positionError().xy() + sta.localError().positionError().xy();
00656    m(1,1) = tk.localError().positionError().yy() + sta.localError().positionError().yy();
00657  
00658    AlgebraicVector2 v;
00659    v[0] = tk.localPosition().x() - sta.localPosition().x();
00660    v[1] = tk.localPosition().y() - sta.localPosition().y();
00661  
00662    if ( !m.Invert() ) {
00663      LogTrace(category) << "Error inverting local matrix ";
00664      return -1;
00665    }
00666  
00667    return ROOT::Math::Similarity(v,m);
00668 
00669 }