CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_3/src/RecoMET/METAlgorithms/src/CSCHaloAlgo.cc

Go to the documentation of this file.
00001 #include "RecoMET/METAlgorithms/interface/CSCHaloAlgo.h"
00002 #include "FWCore/Common/interface/TriggerNames.h"
00003 /*
00004   [class]:  CSCHaloAlgo
00005   [authors]: R. Remington, The University of Florida
00006   [description]: See CSCHaloAlgo.h
00007   [date]: October 15, 2009
00008 */
00009 using namespace reco;
00010 using namespace std;
00011 using namespace edm;
00012 #include "TMath.h"
00013 
00014 CSCHaloAlgo::CSCHaloAlgo()
00015 {
00016   deta_threshold = 0.;
00017   min_inner_radius = 0.;
00018   max_inner_radius = 9999.;
00019   min_outer_radius = 0.;
00020   max_outer_radius = 9999.;
00021   dphi_threshold = 999.;
00022   norm_chi2_threshold = 999.;
00023   recHit_t0=0.;
00024   recHit_twindow=25.;
00025   expected_BX=3;
00026   max_dt_muon_segment=-10.0;
00027   max_free_inverse_beta=0.0;
00028   
00029   min_outer_theta = 0.;
00030   max_outer_theta = TMath::Pi();
00031   
00032   matching_dphi_threshold = 0.18; //radians
00033   matching_deta_threshold = 0.4;
00034   matching_dwire_threshold = 5.;
00035 }
00036 
00037 reco::CSCHaloData CSCHaloAlgo::Calculate(const CSCGeometry& TheCSCGeometry,
00038                                          edm::Handle<reco::MuonCollection>& TheCosmicMuons,  
00039                                          const edm::Handle<reco::MuonTimeExtraMap> TheCSCTimeMap,
00040                                          edm::Handle<reco::MuonCollection>& TheMuons,
00041                                          edm::Handle<CSCSegmentCollection>& TheCSCSegments, 
00042                                          edm::Handle<CSCRecHit2DCollection>& TheCSCRecHits,
00043                                          edm::Handle < L1MuGMTReadoutCollection >& TheL1GMTReadout,
00044                                          edm::Handle<edm::TriggerResults>& TheHLTResults,
00045                                          const edm::TriggerNames * triggerNames, 
00046                                          const edm::Handle<CSCALCTDigiCollection>& TheALCTs,
00047                                          MuonSegmentMatcher *TheMatcher,  
00048                                          const edm::Event& TheEvent)
00049 {
00050   reco::CSCHaloData TheCSCHaloData;
00051   int imucount=0;
00052   if( TheCosmicMuons.isValid() )
00053     {
00054       short int n_tracks_small_beta=0;
00055       short int n_tracks_small_dT=0;
00056       short int n_tracks_small_dT_and_beta=0;
00057       for( reco::MuonCollection::const_iterator iMuon = TheCosmicMuons->begin() ; iMuon != TheCosmicMuons->end() ; iMuon++, imucount++ )
00058         {
00059           reco::TrackRef Track = iMuon->outerTrack();
00060           if(!Track) continue;
00061 
00062           bool StoreTrack = false;
00063           // Calculate global phi coordinate for central most rechit in the track
00064           float innermost_global_z = 1500.;
00065           float outermost_global_z = 0.;
00066           GlobalPoint InnerMostGlobalPosition(0.,0.,0.);  // smallest abs(z)
00067           GlobalPoint OuterMostGlobalPosition(0.,0.,0.);  // largest abs(z)
00068           int nCSCHits = 0;
00069           for(unsigned int j = 0 ; j < Track->extra()->recHits().size(); j++ )
00070             {
00071               edm::Ref<TrackingRecHitCollection> hit( Track->extra()->recHits(), j );
00072               if( !hit->isValid() ) continue;
00073               DetId TheDetUnitId(hit->geographicalId());
00074               if( TheDetUnitId.det() != DetId::Muon ) continue;
00075               if( TheDetUnitId.subdetId() != MuonSubdetId::CSC ) continue;
00076 
00077               const GeomDetUnit *TheUnit = TheCSCGeometry.idToDetUnit(TheDetUnitId);
00078               LocalPoint TheLocalPosition = hit->localPosition();  
00079               const BoundPlane& TheSurface = TheUnit->surface();
00080               const GlobalPoint TheGlobalPosition = TheSurface.toGlobal(TheLocalPosition);
00081 
00082               float z = TheGlobalPosition.z();
00083               if( TMath::Abs(z) < innermost_global_z )
00084                 {
00085                   innermost_global_z = TMath::Abs(z);
00086                   InnerMostGlobalPosition = GlobalPoint( TheGlobalPosition);
00087                 }
00088               if( TMath::Abs(z) > outermost_global_z )
00089                 {
00090                   outermost_global_z = TMath::Abs(z);
00091                   OuterMostGlobalPosition = GlobalPoint( TheGlobalPosition );
00092                 }
00093               nCSCHits ++;
00094             }
00095 
00096           std::vector<const CSCSegment*> MatchedSegments = TheMatcher->matchCSC(*Track,TheEvent);
00097           // Find the inner and outer segments separately in case they don't agree completely with recHits
00098           // Plan for the possibility segments in both endcaps
00099           float InnerSegmentTime[2] = {0,0};
00100           float OuterSegmentTime[2] = {0,0};
00101           float innermost_seg_z[2] = {1500,1500};
00102           float outermost_seg_z[2] = {0,0};
00103           for (std::vector<const CSCSegment*>::const_iterator segment =MatchedSegments.begin();
00104                segment != MatchedSegments.end(); ++segment)
00105             {
00106               CSCDetId TheCSCDetId((*segment)->cscDetId());
00107               const CSCChamber* TheCSCChamber = TheCSCGeometry.chamber(TheCSCDetId);
00108               LocalPoint TheLocalPosition = (*segment)->localPosition();
00109               const GlobalPoint TheGlobalPosition = TheCSCChamber->toGlobal(TheLocalPosition);
00110               float z = TheGlobalPosition.z();
00111               int TheEndcap = TheCSCDetId.endcap();
00112               if( TMath::Abs(z) < innermost_seg_z[TheEndcap-1] )
00113                 {
00114                   innermost_seg_z[TheEndcap-1] = TMath::Abs(z);
00115                   InnerSegmentTime[TheEndcap-1] = (*segment)->time();
00116                 }
00117               if( TMath::Abs(z) > outermost_seg_z[TheEndcap-1] )
00118                 {
00119                   outermost_seg_z[TheEndcap-1] = TMath::Abs(z);
00120                   OuterSegmentTime[TheEndcap-1] = (*segment)->time();
00121                 }
00122             }
00123 
00124           if( nCSCHits < 3 ) continue; // This needs to be optimized, but is the minimum 
00125 
00126           float dT_Segment = 0; // default safe value, looks like collision muon
00127          
00128           if( innermost_seg_z[0] < outermost_seg_z[0]) // two segments in ME+
00129             dT_Segment =  OuterSegmentTime[0]-InnerSegmentTime[0];
00130           if( innermost_seg_z[1] < outermost_seg_z[1]) // two segments in ME-
00131             {
00132               // replace the measurement if there weren't segments in ME+ or
00133               // if the track in ME- has timing more consistent with an incoming particle
00134               if (dT_Segment == 0.0 ||  OuterSegmentTime[1]-InnerSegmentTime[1] < dT_Segment)
00135                 dT_Segment = OuterSegmentTime[1]-InnerSegmentTime[1] ;
00136             }
00137 
00138           if( OuterMostGlobalPosition.x() == 0. || OuterMostGlobalPosition.y() == 0. || OuterMostGlobalPosition.z() == 0. ) 
00139             continue;
00140           if( InnerMostGlobalPosition.x() == 0. || InnerMostGlobalPosition.y() == 0. || InnerMostGlobalPosition.z() == 0. )
00141             continue;
00142           
00143           //Its a CSC Track,store it if it passes halo selection 
00144           StoreTrack = true;      
00145 
00146           float deta = TMath::Abs( OuterMostGlobalPosition.eta() - InnerMostGlobalPosition.eta() );
00147           float dphi = TMath::ACos( TMath::Cos( OuterMostGlobalPosition.phi() - InnerMostGlobalPosition.phi() ) ) ;
00148           float theta = Track->outerMomentum().theta();
00149           float innermost_x = InnerMostGlobalPosition.x() ;
00150           float innermost_y = InnerMostGlobalPosition.y();
00151           float outermost_x = OuterMostGlobalPosition.x();
00152           float outermost_y = OuterMostGlobalPosition.y();
00153           float innermost_r = TMath::Sqrt(innermost_x *innermost_x + innermost_y * innermost_y );
00154           float outermost_r = TMath::Sqrt(outermost_x *outermost_x + outermost_y * outermost_y );
00155           
00156           if( deta < deta_threshold )
00157             StoreTrack = false;
00158           if( theta > min_outer_theta && theta < max_outer_theta )
00159             StoreTrack = false;
00160           if( dphi > dphi_threshold )
00161             StoreTrack = false;
00162           if( innermost_r < min_inner_radius )
00163             StoreTrack = false;
00164           if( innermost_r > max_inner_radius )
00165             StoreTrack = false;
00166           if( outermost_r < min_outer_radius )
00167             StoreTrack = false;
00168           if( outermost_r > max_outer_radius )
00169             StoreTrack  = false;
00170           if( Track->normalizedChi2() > norm_chi2_threshold )
00171             StoreTrack = false;
00172 
00173           if( StoreTrack )
00174             {
00175               TheCSCHaloData.GetCSCTrackImpactPositions().push_back( InnerMostGlobalPosition );
00176               TheCSCHaloData.GetTracks().push_back( Track );
00177             }
00178 
00179           // Analyze the MuonTimeExtra information
00180           if( TheCSCTimeMap.isValid() ) 
00181             {
00182               reco::MuonRef muonR(TheCosmicMuons,imucount);
00183               const reco::MuonTimeExtraMap & timeMapCSC = *TheCSCTimeMap;
00184               reco::MuonTimeExtra timecsc = timeMapCSC[muonR];
00185               float freeInverseBeta = timecsc.freeInverseBeta();
00186               
00187               if (dT_Segment < max_dt_muon_segment )
00188                 n_tracks_small_dT++;
00189               if (freeInverseBeta < max_free_inverse_beta)
00190                 n_tracks_small_beta++;
00191               if ((dT_Segment < max_dt_muon_segment) &&  (freeInverseBeta < max_free_inverse_beta))
00192                 n_tracks_small_dT_and_beta++;
00193             }
00194           else 
00195             {
00196               static bool MuonTimeFail = false;
00197               if( !MuonTimeFail ) 
00198                 {
00199                   edm::LogWarning  ("InvalidInputTag") <<  "The MuonTimeExtraMap does not appear to be in the event. Some beam halo "
00200                                                        << " identification variables will be empty" ;
00201                   MuonTimeFail = true;
00202                 }
00203             }
00204         }
00205       TheCSCHaloData.SetNIncomingTracks(n_tracks_small_dT,n_tracks_small_beta,n_tracks_small_dT_and_beta);
00206     }
00207   else // collection is invalid
00208     {
00209       static bool CosmicFail = false;
00210       if( !CosmicFail ) 
00211         {
00212           edm::LogWarning  ("InvalidInputTag") << " The Cosmic Muon collection does not appear to be in the event. These beam halo "
00213                                                << " identification variables will be empty" ;
00214           CosmicFail = true;
00215         }
00216     }
00217 
00218   if( TheHLTResults.isValid() )
00219     {
00220       bool EventPasses = false;
00221        for( unsigned int index = 0 ; index < vIT_HLTBit.size(); index++)
00222          {
00223            if( vIT_HLTBit[index].label().size() )
00224              {
00225                //Get the HLT bit and check to make sure it is valid 
00226                unsigned int bit = triggerNames->triggerIndex( vIT_HLTBit[index].label().c_str());
00227                if( bit < TheHLTResults->size() )
00228                  {
00229                    //If any of the HLT names given by the user accept, then the event passes
00230                    if( TheHLTResults->accept( bit ) && !TheHLTResults->error( bit ) )
00231                      {
00232                        EventPasses = true;
00233                      }
00234                  }
00235              }
00236          }
00237        if( EventPasses )
00238          TheCSCHaloData.SetHLTBit(true);
00239        else
00240          TheCSCHaloData.SetHLTBit(false);
00241      }
00242   else //  HLT results are not valid
00243     {
00244       static bool HLTFail = false;
00245       if( !HLTFail ) 
00246         {
00247           edm::LogWarning  ("InvalidInputTag") << "The HLT results do not appear to be in the event. The beam halo HLT trigger "
00248                                                << "decision will not be used in the halo identification"; 
00249           HLTFail = true;
00250         }
00251     }
00252 
00253    if( TheL1GMTReadout.isValid() )
00254      {
00255        L1MuGMTReadoutCollection const *gmtrc = TheL1GMTReadout.product ();
00256        std::vector < L1MuGMTReadoutRecord > gmt_records = gmtrc->getRecords ();
00257        std::vector < L1MuGMTReadoutRecord >::const_iterator igmtrr;
00258        
00259        int icsc = 0;
00260        int PlusZ = 0 ;
00261        int MinusZ = 0 ;
00262        // Check to see if CSC BeamHalo trigger is tripped
00263        for (igmtrr = gmt_records.begin (); igmtrr != gmt_records.end (); igmtrr++)
00264          {
00265            std::vector < L1MuRegionalCand >::const_iterator iter1;
00266            std::vector < L1MuRegionalCand > rmc;
00267            rmc = igmtrr->getCSCCands ();
00268            for (iter1 = rmc.begin (); iter1 != rmc.end (); iter1++)
00269              {
00270               if (!(*iter1).empty ())
00271                 {
00272                   if ((*iter1).isFineHalo ())
00273                     {
00274                       float halophi = iter1->phiValue();
00275                       halophi = halophi > TMath::Pi() ? halophi - 2.*TMath::Pi() : halophi;
00276                       float haloeta = iter1->etaValue();
00277                       bool HaloIsGood = true;
00278                       // Check if halo trigger is faked by any collision muons
00279                       if( TheMuons.isValid() )
00280                         {
00281                           float dphi = 9999.;
00282                           float deta = 9999.;
00283                           for( reco::MuonCollection::const_iterator mu = TheMuons->begin(); mu != TheMuons->end() && HaloIsGood ; mu++ )
00284                             {
00285                               // Don't match with SA-only muons
00286                               if( mu->isStandAloneMuon() && !mu->isTrackerMuon() && !mu->isGlobalMuon() )  continue;
00287                               
00288                               /*
00289                               if(!mu->isTrackerMuon())
00290                                 {
00291                                   if( mu->isStandAloneMuon() )
00292                                     {
00293                                       //make sure that this SA muon is not actually a halo-like muon
00294                                       float theta =  mu->outerTrack()->outerMomentum().theta();
00295                                       float deta = TMath::Abs(mu->outerTrack()->outerPosition().eta() - mu->outerTrack()->innerPosition().eta());
00296                                       if( theta < min_outer_theta || theta > max_outer_theta )  //halo-like
00297                                         continue;
00298                                       else if ( deta > deta_threshold ) //halo-like
00299                                         continue;
00300                                     }
00301                                 }
00302                               */
00303                             
00304                               const std::vector<MuonChamberMatch> chambers = mu->matches();
00305                               for(std::vector<MuonChamberMatch>::const_iterator iChamber = chambers.begin();
00306                                   iChamber != chambers.end() ; iChamber ++ )
00307                                 {
00308                                   if( iChamber->detector() != MuonSubdetId::CSC ) continue;
00309                                   for( std::vector<reco::MuonSegmentMatch>::const_iterator iSegment = iChamber->segmentMatches.begin() ; 
00310                                        iSegment != iChamber->segmentMatches.end(); ++iSegment )
00311                                     {
00312                                       edm::Ref<CSCSegmentCollection> cscSegment = iSegment->cscSegmentRef;
00313                                       std::vector<CSCRecHit2D> hits = cscSegment -> specificRecHits();
00314                                       for( std::vector<CSCRecHit2D>::iterator iHit = hits.begin();
00315                                            iHit != hits.end() ; iHit++ )
00316                                         {
00317                                           DetId TheDetUnitId(iHit->cscDetId());
00318                                           const GeomDetUnit *TheUnit = TheCSCGeometry.idToDetUnit(TheDetUnitId);
00319                                           LocalPoint TheLocalPosition = iHit->localPosition();
00320                                           const BoundPlane& TheSurface = TheUnit->surface();
00321                                           GlobalPoint TheGlobalPosition = TheSurface.toGlobal(TheLocalPosition);
00322                                           
00323                                           float phi_ = TheGlobalPosition.phi();
00324                                           float eta_ = TheGlobalPosition.eta();
00325                                           
00326                                           deta = deta < TMath::Abs( eta_ - haloeta ) ? deta : TMath::Abs( eta_ - haloeta );
00327                                           dphi = dphi < TMath::ACos(TMath::Cos(phi_ - halophi)) ? dphi : TMath::ACos(TMath::Cos(phi_ - halophi));
00328                                         }
00329                                     }
00330                                 }
00331                               if ( dphi < matching_dphi_threshold && deta < matching_deta_threshold) 
00332                                 HaloIsGood = false; // i.e., collision muon likely faked halo trigger
00333                             }
00334                         }
00335                       if( !HaloIsGood ) 
00336                         continue;
00337                       if( (*iter1).etaValue() > 0 )
00338                         PlusZ++;
00339                       else
00340                         MinusZ++;
00341                     }
00342                   else
00343                     icsc++;
00344                 }
00345              }
00346          }
00347        TheCSCHaloData.SetNumberOfHaloTriggers(PlusZ, MinusZ);
00348      }
00349    else
00350      {
00351        static bool L1Fail = false;
00352        if( !L1Fail ) 
00353          {
00354            edm::LogWarning  ("InvalidInputTag") << "The L1MuGMTReadoutCollection does not appear to be in the event. The L1 beam halo trigger "
00355                                                 << "decision will not be used in the halo identification"; 
00356            L1Fail = true;
00357          }
00358      }
00359 
00360    // Loop over CSCALCTDigi collection to look for out-of-time chamber triggers 
00361    // A collision muon in real data should only have ALCTDigi::getBX() = 3 ( in MC, it will be 6 )
00362    // Note that there could be two ALCTs per chamber 
00363    short int n_alctsP=0;
00364    short int n_alctsM=0;
00365    if(TheALCTs.isValid())
00366      {
00367        for (CSCALCTDigiCollection::DigiRangeIterator j=TheALCTs->begin(); j!=TheALCTs->end(); j++) 
00368          {
00369            const CSCALCTDigiCollection::Range& range =(*j).second;
00370            CSCDetId detId((*j).first.rawId());
00371            for (CSCALCTDigiCollection::const_iterator digiIt = range.first; digiIt!=range.second; ++digiIt)
00372              {
00373                if( (*digiIt).isValid() && ( (*digiIt).getBX() < expected_BX ) )
00374                  {
00375                    int digi_endcap  = detId.endcap();
00376                    int digi_station = detId.station();
00377                    int digi_ring    = detId.ring();
00378                    int digi_chamber = detId.chamber();
00379                    int digi_wire    = digiIt->getKeyWG();
00380                    if( digi_station == 1 && digi_ring == 4 )   //hack
00381                      digi_ring = 1;
00382                    
00383                    bool DigiIsGood = true;
00384                    int dwire = 999.;
00385                    if( TheMuons.isValid() ) 
00386                      {
00387                        //Check if there are any collision muons with hits in the vicinity of the digi
00388                        for(reco::MuonCollection::const_iterator mu = TheMuons->begin(); mu!= TheMuons->end() && DigiIsGood ; mu++ )
00389                          {
00390                            if( !mu->isTrackerMuon() && !mu->isGlobalMuon() && mu->isStandAloneMuon() ) continue;
00391 
00392                            const std::vector<MuonChamberMatch> chambers = mu->matches();
00393                            for(std::vector<MuonChamberMatch>::const_iterator iChamber = chambers.begin();
00394                                iChamber != chambers.end(); iChamber ++ )
00395                              {
00396                                if( iChamber->detector() != MuonSubdetId::CSC ) continue;
00397                                for( std::vector<reco::MuonSegmentMatch>::const_iterator iSegment = iChamber->segmentMatches.begin();
00398                                     iSegment != iChamber->segmentMatches.end(); iSegment++ )
00399                                  {
00400                                    edm::Ref<CSCSegmentCollection> cscSegRef = iSegment->cscSegmentRef;
00401                                    std::vector<CSCRecHit2D> hits = cscSegRef->specificRecHits();
00402                                    for( std::vector<CSCRecHit2D>::iterator iHit = hits.begin();
00403                                         iHit != hits.end(); iHit++ )
00404                                      {
00405                                        if( iHit->cscDetId().endcap() != digi_endcap ) continue;
00406                                        if( iHit->cscDetId().station() != digi_station ) continue;
00407                                        if( iHit->cscDetId().ring() != digi_ring ) continue;
00408                                        if( iHit->cscDetId().chamber() != digi_chamber ) continue;
00409                                        int hit_wire = iHit->hitWire();
00410                                        dwire = dwire < TMath::Abs(hit_wire - digi_wire)? dwire : TMath::Abs(hit_wire - digi_wire );
00411                                      }
00412                                  }
00413                              }
00414                            if( dwire <= matching_dwire_threshold ) 
00415                              DigiIsGood = false;  // collision-like muon is close to this digi
00416                          }
00417                      }
00418                    // only count out of time digis if they are not matched to collision muons
00419                    if( DigiIsGood ) 
00420                      {
00421                        if( detId.endcap() == 1 ) 
00422                          n_alctsP++;
00423                        else if ( detId.endcap() ==  2) 
00424                          n_alctsM++;
00425                      }
00426                  }
00427              }
00428          }
00429      }
00430    else
00431      {
00432        static bool DigiFail=false;
00433        if (!DigiFail){
00434          edm::LogWarning  ("InvalidInputTag") << "The CSCALCTDigiCollection does not appear to be in the event. The ALCT Digis will "
00435                                               << " not be used in the halo identification"; 
00436          DigiFail=true;
00437        }
00438      }
00439    TheCSCHaloData.SetNOutOfTimeTriggers(n_alctsP,n_alctsM);
00440 
00441    // Loop over the CSCRecHit2D collection to look for out-of-time recHits
00442    // Out-of-time is defined as tpeak outside [t_0 + TOF - t_window, t_0 + TOF + t_window]
00443    // where t_0 and t_window are configurable parameters
00444    short int n_recHitsP = 0;
00445    short int n_recHitsM = 0;
00446    if( TheCSCRecHits.isValid() )
00447      {
00448        CSCRecHit2DCollection::const_iterator dRHIter;
00449        for (dRHIter = TheCSCRecHits->begin(); dRHIter != TheCSCRecHits->end(); dRHIter++) 
00450          {
00451            if ( !((*dRHIter).isValid()) ) continue;  // only interested in valid hits
00452            CSCDetId idrec = (CSCDetId)(*dRHIter).cscDetId();
00453            float RHTime = (*dRHIter).tpeak();
00454            LocalPoint rhitlocal = (*dRHIter).localPosition();
00455            const CSCChamber* chamber = TheCSCGeometry.chamber(idrec);
00456            GlobalPoint globalPosition = chamber->toGlobal(rhitlocal);
00457            float globZ = globalPosition.z();
00458            if ( RHTime < (recHit_t0 - recHit_twindow) )
00459              {
00460                if( globZ > 0 )
00461                  n_recHitsP++;
00462                else
00463                  n_recHitsM++;
00464              }
00465            
00466            /*
00467 
00468            float globX = globalPosition.x();
00469            float globY = globalPosition.y();
00470            float globZ = globalPosition.z();
00471            float TOF = (sqrt(globX*globX+ globY*globY + globZ*globZ))/29.9792458 ; //cm -> ns
00472            if ( (RHTime < (recHit_t0 + TOF - recHit_twindow)) || (RHTime > (recHit_t0 + TOF + recHit_twindow)) )
00473              {
00474                if( globZ > 0 ) 
00475                  n_recHitsP++;
00476                else
00477                  n_recHitsM++;
00478              }
00479            */
00480          }
00481      }
00482    else
00483      {
00484        static bool RecHitFail = false;
00485        if( !RecHitFail ) 
00486          {
00487            edm::LogWarning  ("InvalidInputTag") << "The requested CSCRecHit2DCollection does not appear to be in the event. The CSC RecHit "
00488                                                 << " variables used for halo identification will not be calculated or stored";
00489            RecHitFail = true;
00490          }       
00491      }
00492    TheCSCHaloData.SetNOutOfTimeHits(n_recHitsP+n_recHitsM);
00493    // MLR
00494    // Loop through CSCSegments and count the number of "flat" segments with the same (r,phi),
00495    // saving the value in TheCSCHaloData.
00496    short int maxNSegments = 0;
00497    bool plus_endcap = false;
00498    bool minus_endcap = false;
00499    bool both_endcaps = false;
00500    //float r = 0., phi = 0.;
00501    if (TheCSCSegments.isValid()) {
00502      for(CSCSegmentCollection::const_iterator iSegment = TheCSCSegments->begin();
00503          iSegment != TheCSCSegments->end();
00504          iSegment++) {
00505 
00506        CSCDetId iCscDetID = iSegment->cscDetId();
00507        bool SegmentIsGood=true;
00508        //avoid segments from collision muons
00509        if( TheMuons.isValid() )
00510          {
00511            for(reco::MuonCollection::const_iterator mu = TheMuons->begin(); mu!= TheMuons->end() && SegmentIsGood ; mu++ )
00512              {
00513                if( !mu->isTrackerMuon() && !mu->isGlobalMuon() && mu->isStandAloneMuon() ) continue;
00514                const std::vector<MuonChamberMatch> chambers = mu->matches();
00515                for(std::vector<MuonChamberMatch>::const_iterator kChamber = chambers.begin();
00516                    kChamber != chambers.end(); kChamber ++ )
00517                  {
00518                    if( kChamber->detector() != MuonSubdetId::CSC ) continue;
00519                    for( std::vector<reco::MuonSegmentMatch>::const_iterator kSegment = kChamber->segmentMatches.begin();
00520                         kSegment != kChamber->segmentMatches.end(); kSegment++ )
00521                      {
00522                        edm::Ref<CSCSegmentCollection> cscSegRef = kSegment->cscSegmentRef;
00523                        CSCDetId kCscDetID = cscSegRef->cscDetId();
00524                        
00525                        if( kCscDetID == iCscDetID ) 
00526                          {
00527                            SegmentIsGood = false;
00528                          }
00529                      }
00530                  }
00531              }
00532          }
00533        if(!SegmentIsGood) continue;
00534 
00535        // Get local direction vector; if direction runs parallel to beamline,
00536        // count this segment as beam halo candidate.
00537        LocalPoint iLocalPosition = iSegment->localPosition();
00538        LocalVector iLocalDirection = iSegment->localDirection();
00539 
00540        GlobalPoint iGlobalPosition = TheCSCGeometry.chamber(iCscDetID)->toGlobal(iLocalPosition);
00541        GlobalVector iGlobalDirection = TheCSCGeometry.chamber(iCscDetID)->toGlobal(iLocalDirection);
00542 
00543        float iTheta = iGlobalDirection.theta();
00544        if (iTheta > max_segment_theta && iTheta < TMath::Pi() - max_segment_theta) continue;
00545        
00546        float iPhi = iGlobalPosition.phi();
00547        float iR =  TMath::Sqrt(iGlobalPosition.x()*iGlobalPosition.x() + iGlobalPosition.y()*iGlobalPosition.y());
00548        short int nSegs = 0;
00549 
00550        // Changed to loop over all Segments (so N^2) to catch as many segments as possible.
00551        for (CSCSegmentCollection::const_iterator jSegment = TheCSCSegments->begin();
00552          jSegment != TheCSCSegments->end();
00553          jSegment++) {
00554          if (jSegment == iSegment) continue;
00555 
00556          LocalPoint jLocalPosition = jSegment->localPosition();
00557          LocalVector jLocalDirection = jSegment->localDirection();
00558          CSCDetId jCscDetID = jSegment->cscDetId();
00559          GlobalPoint jGlobalPosition = TheCSCGeometry.chamber(jCscDetID)->toGlobal(jLocalPosition);
00560          GlobalVector jGlobalDirection = TheCSCGeometry.chamber(jCscDetID)->toGlobal(jLocalDirection);
00561          float jTheta = jGlobalDirection.theta();
00562          float jPhi = jGlobalPosition.phi();
00563          float jR =  TMath::Sqrt(jGlobalPosition.x()*jGlobalPosition.x() + jGlobalPosition.y()*jGlobalPosition.y());
00564 
00565          if (TMath::ACos(TMath::Cos(jPhi - iPhi)) <= max_segment_phi_diff 
00566              && TMath::Abs(jR - iR) <= max_segment_r_diff 
00567              && (jTheta < max_segment_theta || jTheta > TMath::Pi() - max_segment_theta)) {
00569            if( TheMuons.isValid() ) {
00570              for(reco::MuonCollection::const_iterator mu = TheMuons->begin(); mu!= TheMuons->end() && SegmentIsGood ; mu++ ) {
00571                if( !mu->isTrackerMuon() && !mu->isGlobalMuon() && mu->isStandAloneMuon() ) continue;
00572                const std::vector<MuonChamberMatch> chambers = mu->matches();
00573                for(std::vector<MuonChamberMatch>::const_iterator kChamber = chambers.begin();
00574                    kChamber != chambers.end(); kChamber ++ ) {
00575                  if( kChamber->detector() != MuonSubdetId::CSC ) continue;
00576                  for( std::vector<reco::MuonSegmentMatch>::const_iterator kSegment = kChamber->segmentMatches.begin();
00577                       kSegment != kChamber->segmentMatches.end(); kSegment++ ) {
00578                    edm::Ref<CSCSegmentCollection> cscSegRef = kSegment->cscSegmentRef;
00579                    CSCDetId kCscDetID = cscSegRef->cscDetId();
00580                    
00581                    if( kCscDetID == jCscDetID ) {
00582                      SegmentIsGood = false;
00583                    }
00584                  }
00585                }
00586              }
00587            }   
00588            if(SegmentIsGood) {
00589              nSegs++;
00590              minus_endcap = iGlobalPosition.z() < 0 || jGlobalPosition.z() < 0;
00591              plus_endcap = iGlobalPosition.z() > 0 || jGlobalPosition.z() > 0;
00592            }
00593          }
00594        }
00595        // Correct the fact that the way nSegs counts will always be short by 1
00596        if (nSegs > 0) nSegs++;
00597        if (nSegs > maxNSegments) {
00598          // Use value of r, phi to collect halo CSCSegments for examining timing (not coded yet...)
00599          //r = iR;
00600          //phi = iPhi;
00601          maxNSegments = nSegs;
00602          both_endcaps = both_endcaps ? both_endcaps : minus_endcap && plus_endcap;
00603        }
00604      }
00605    }
00606    TheCSCHaloData.SetNFlatHaloSegments(maxNSegments);
00607    TheCSCHaloData.SetSegmentsBothEndcaps(both_endcaps);
00608    // End MLR
00609 
00610    return TheCSCHaloData;
00611 }
00612