CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/RecoLocalMuon/CSCSegment/src/CSCSegAlgoDF.cc

Go to the documentation of this file.
00001 
00007 #include "CSCSegAlgoDF.h"
00008 
00009 #include "Geometry/CSCGeometry/interface/CSCLayer.h"
00010 // For clhep Matrix::solve
00011 #include "DataFormats/CLHEP/interface/AlgebraicObjects.h"
00012 
00013 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
00014 
00015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00017 
00018 #include "CommonTools/Statistics/interface/ChiSquaredProbability.h"
00019 
00020 #include "CSCSegAlgoPreClustering.h"
00021 #include "CSCSegAlgoShowering.h"
00022 
00023 #include <algorithm>
00024 #include <cmath>
00025 #include <iostream>
00026 #include <string>
00027 
00028 
00029 /* Constructor
00030  *
00031  */
00032 CSCSegAlgoDF::CSCSegAlgoDF(const edm::ParameterSet& ps) : CSCSegmentAlgorithm(ps), myName("CSCSegAlgoDF") {
00033         
00034   debug                  = ps.getUntrackedParameter<bool>("CSCSegmentDebug");
00035   minLayersApart         = ps.getParameter<int>("minLayersApart");
00036   minHitsPerSegment      = ps.getParameter<int>("minHitsPerSegment");
00037   dRPhiFineMax           = ps.getParameter<double>("dRPhiFineMax");
00038   dPhiFineMax            = ps.getParameter<double>("dPhiFineMax");
00039   tanThetaMax            = ps.getParameter<double>("tanThetaMax");
00040   tanPhiMax              = ps.getParameter<double>("tanPhiMax");        
00041   chi2Max                = ps.getParameter<double>("chi2Max");  
00042   preClustering          = ps.getUntrackedParameter<bool>("preClustering");
00043   minHitsForPreClustering= ps.getParameter<int>("minHitsForPreClustering");
00044   nHitsPerClusterIsShower= ps.getParameter<int>("nHitsPerClusterIsShower");
00045   Pruning                = ps.getUntrackedParameter<bool>("Pruning");
00046   maxRatioResidual       = ps.getParameter<double>("maxRatioResidualPrune");
00047 
00048   preCluster_            = new CSCSegAlgoPreClustering( ps );
00049   showering_             = new CSCSegAlgoShowering( ps );
00050 }
00051 
00052 
00053 /* Destructor
00054  *
00055  */
00056 CSCSegAlgoDF::~CSCSegAlgoDF() {
00057   delete preCluster_;
00058   delete showering_;
00059 }
00060 
00061 
00062 /* run
00063  *
00064  */
00065 std::vector<CSCSegment> CSCSegAlgoDF::run(const CSCChamber* aChamber, const ChamberHitContainer& rechits) {
00066 
00067   // Store chamber info in temp memory
00068   theChamber = aChamber; 
00069 
00070   int nHits = rechits.size();
00071 
00072   // Segments prior to pruning
00073   std::vector<CSCSegment> segments_temp;  
00074 
00075   if ( preClustering && nHits > minHitsForPreClustering ) {
00076     // This is where the segment origin is in the chamber on avg.
00077     std::vector<CSCSegment> testSegments;
00078     std::vector<ChamberHitContainer> clusteredHits = preCluster_->clusterHits(theChamber, rechits);
00079     // loop over the found clusters:
00080     for (std::vector<ChamberHitContainer>::iterator subrechits = clusteredHits.begin(); subrechits != clusteredHits.end(); ++subrechits ) {
00081       // build the subset of segments:
00082       std::vector<CSCSegment> segs = buildSegments( (*subrechits) );
00083       // add the found subset of segments to the collection of all segments in this chamber:
00084       segments_temp.insert( segments_temp.end(), segs.begin(), segs.end() );
00085     }
00086   } else {
00087     std::vector<CSCSegment> segs = buildSegments( rechits );
00088     // add the found subset of segments to the collection of all segments in this chamber:
00089     segments_temp.insert( segments_temp.end(), segs.begin(), segs.end() ); 
00090   }
00091 
00092   return segments_temp; 
00093 }
00094 
00095 
00096 /* This builds segments by first creating proto-segments from at least 3 hits.
00097  * We intend to try all possible pairs of hits to start segment building. 'All possible' 
00098  * means each hit lies on different layers in the chamber.  Once a hit has been assigned 
00099  * to a segment, we don't consider it again, THAT IS, FOR THE FIRST PASS ONLY !
00100  * In fact, this is one of the possible flaw with the SK algorithms as it sometimes manages
00101  * to build segments with the wrong starting points.  In the DF algorithm, the endpoints
00102  * are tested as the best starting points in a 2nd loop.
00103  *
00104  * Also, only a certain muonsPerChamberMax maximum number of segments can be produced in the chamber
00105  */
00106 std::vector<CSCSegment> CSCSegAlgoDF::buildSegments(const ChamberHitContainer& _rechits) {
00107 
00108   ChamberHitContainer rechits = _rechits;
00109   // Clear buffer for segment vector
00110   std::vector<CSCSegment> segmentInChamber;
00111   segmentInChamber.clear();
00112 
00113   unsigned nHitInChamber = rechits.size();
00114   if ( nHitInChamber < 3 ) return segmentInChamber;
00115 
00116   LayerIndex layerIndex( nHitInChamber );
00117 
00118   unsigned nLayers = 0;
00119   int old_layer = -1;   
00120   for ( unsigned int i = 0; i < nHitInChamber; i++ ) {    
00121     int this_layer = rechits[i]->cscDetId().layer();
00122     layerIndex[i] = this_layer;
00123     if ( this_layer != old_layer ) {
00124       old_layer = this_layer;
00125       nLayers++;   
00126     }
00127   }
00128   
00129   if ( nLayers < 3 ) return segmentInChamber;
00130 
00131   double z1 = theChamber->layer(1)->position().z();
00132   double z6 = theChamber->layer(6)->position().z();
00133   
00134   if ( z1 > 0. ) {
00135     if ( z1 > z6 ) { 
00136       reverse( layerIndex.begin(), layerIndex.end() );
00137       reverse( rechits.begin(),    rechits.end() );
00138     }    
00139   }
00140   else if ( z1 < 0. ) {
00141     if ( z1 < z6 ) {
00142       reverse( layerIndex.begin(), layerIndex.end() );
00143       reverse( rechits.begin(),    rechits.end() );
00144     }    
00145   }
00146 
00147   // Showering muon
00148   if ( preClustering && int(nHitInChamber) > nHitsPerClusterIsShower && nLayers > 2 ) {
00149     CSCSegment segShower = showering_->showerSeg(theChamber, rechits);
00150 
00151     // Make sure have at least 3 hits...
00152     if ( segShower.nRecHits() < 3 ) return segmentInChamber;
00153 
00154     segmentInChamber.push_back(segShower);
00155 
00156     return segmentInChamber;
00157   }
00158 
00159 
00160   // Initialize flags that a given hit has been allocated to a segment
00161   BoolContainer used_ini(rechits.size(), false);
00162   usedHits = used_ini;
00163   
00164   ChamberHitContainerCIt ib = rechits.begin();
00165   ChamberHitContainerCIt ie = rechits.end();
00166     
00167   // Now Loop over hits within the chamber to find 1st seed for segment building
00168   for ( ChamberHitContainerCIt i1 = ib; i1 < ie; ++i1 ) {
00169     if ( usedHits[i1-ib] ) continue;
00170 
00171     const CSCRecHit2D* h1 = *i1;
00172     int layer1 = layerIndex[i1-ib];
00173     const CSCLayer* l1 = theChamber->layer(layer1);
00174     GlobalPoint gp1 = l1->toGlobal(h1->localPosition());
00175     LocalPoint lp1 = theChamber->toLocal(gp1);  
00176            
00177     // Loop over hits backward to find 2nd seed for segment building
00178     for ( ChamberHitContainerCIt i2 = ie-1; i2 > ib; --i2 ) {   
00179 
00180       if ( usedHits[i2-ib] ) continue;   // Hit has been used already
00181 
00182       int layer2 = layerIndex[i2-ib];
00183       if ( (layer2 - layer1) < minLayersApart ) continue;
00184 
00185       const CSCRecHit2D* h2 = *i2;
00186       const CSCLayer* l2 = theChamber->layer(layer2);
00187       GlobalPoint gp2 = l2->toGlobal(h2->localPosition());
00188       LocalPoint lp2 = theChamber->toLocal(gp2);  
00189 
00190       // Clear proto segment so it can be (re)-filled 
00191       protoSegment.clear();
00192 
00193       // localPosition is position of hit wrt layer (so local z = 0)
00194       protoIntercept = h1->localPosition();
00195 
00196       // We want hit wrt chamber (and local z will be != 0)
00197       float dz = gp2.z()-gp1.z();
00198       protoSlope_u = (lp2.x() - lp1.x())/dz ;
00199       protoSlope_v = (lp2.y() - lp1.y())/dz ;    
00200 
00201       // Test if entrance angle is roughly pointing towards IP
00202       if (fabs(protoSlope_v) > tanThetaMax) continue;
00203       if (fabs(protoSlope_u) > tanPhiMax ) continue;
00204      
00205       protoSegment.push_back(h1);
00206       protoSegment.push_back(h2);
00207         
00208       // Try adding hits to proto segment
00209       tryAddingHitsToSegment(rechits, i1, i2, layerIndex); 
00210         
00211       // Check no. of hits on segment to see if segment is large enough
00212       bool segok = true;
00213       unsigned iadd = 0;
00214 
00215       if (protoSegment.size() < minHitsPerSegment+iadd) segok = false;
00216   
00217       if ( Pruning && segok ) pruneFromResidual();
00218 
00219       // Check if segment satisfies chi2 requirement
00220       if (protoChi2 > chi2Max) segok = false;
00221 
00222       if ( segok ) {
00223 
00224         // Fill segment properties
00225        
00226         // Local direction
00227         double dz   = 1./sqrt(1. + protoSlope_u*protoSlope_u + protoSlope_v*protoSlope_v);
00228         double dx   = dz * protoSlope_u;
00229         double dy   = dz * protoSlope_v;
00230         LocalVector localDir(dx,dy,dz);
00231       
00232         // localDir may need sign flip to ensure it points outward from IP  
00233         double globalZpos    = ( theChamber->toGlobal( protoIntercept ) ).z();
00234         double globalZdir    = ( theChamber->toGlobal( localDir ) ).z();
00235         double directionSign = globalZpos * globalZdir;
00236         protoDirection       = (directionSign * localDir).unit();
00237 
00238         // Error matrix
00239         AlgebraicSymMatrix protoErrors = calculateError();     
00240         // but reorder components to match what's required by TrackingRecHit interface
00241         // i.e. slopes first, then positions
00242         flipErrors( protoErrors );
00243 
00244         CSCSegment temp(protoSegment, protoIntercept, protoDirection, protoErrors, protoChi2); 
00245 
00246         segmentInChamber.push_back(temp); 
00247 
00248         if (nHitInChamber-protoSegment.size() < 3) return segmentInChamber; 
00249         if (segmentInChamber.size() > 4) return segmentInChamber;
00250 
00251         // Flag used hits
00252         flagHitsAsUsed(rechits);
00253       } 
00254     } 
00255   }
00256   return segmentInChamber;
00257 }
00258 
00259 
00260 /* Method tryAddingHitsToSegment
00261  *
00262  * Look at left over hits and try to add them to proto segment by looking how far they
00263  * are from the segment in terms of the hit error matrix (so how many sigmas away).
00264  *
00265  */
00266 void CSCSegAlgoDF::tryAddingHitsToSegment( const ChamberHitContainer& rechits, 
00267                                            const ChamberHitContainerCIt i1, 
00268                                            const ChamberHitContainerCIt i2,
00269                                            const LayerIndex& layerIndex ) {
00270   
00271 /* Iterate over the layers with hits in the chamber
00272  * Skip the layers containing the segment endpoints on first pass, but then
00273  * try hits on layer containing the segment starting points on 2nd pass
00274  * if segment has >2 hits.  Once a hit is added to a layer, don't replace it 
00275  * until 2nd iteration
00276  */  
00277   
00278   ChamberHitContainerCIt ib = rechits.begin();
00279   ChamberHitContainerCIt ie = rechits.end();
00280   closeHits.clear();
00281 
00282   for ( ChamberHitContainerCIt i = ib; i != ie; ++i ) {
00283 
00284     if (i == i1 || i == i2 ) continue;
00285     if ( usedHits[i-ib] ) continue;   // Don't use hits already part of a segment.
00286 
00287     const CSCRecHit2D* h = *i;
00288     int layer = layerIndex[i-ib];
00289     int layer1 = layerIndex[i1-ib];
00290     int layer2 = layerIndex[i2-ib];
00291 
00292     // Low multiplicity case
00293     if (rechits.size() < 9) {
00294       if ( isHitNearSegment( h ) ) {
00295         if ( !hasHitOnLayer(layer) ) {
00296           addHit(h, layer);
00297         } else {
00298           closeHits.push_back(h);
00299         }
00300       }
00301 
00302     // High multiplicity case
00303     } else { 
00304       if ( isHitNearSegment( h ) ) {
00305         if ( !hasHitOnLayer(layer) ) {
00306           addHit(h, layer);
00307           updateParameters();
00308         // Don't change the starting points at this stage !!!
00309         } else {
00310           closeHits.push_back(h);
00311           if (layer != layer1 && layer != layer2 ) compareProtoSegment(h, layer);
00312         }
00313       }
00314     }
00315   }
00316  
00317   if ( int(protoSegment.size()) < 3) return;
00318 
00319   updateParameters();
00320 
00321   // 2nd pass to remove biases 
00322   // This time, also consider changing the endpoints
00323   for ( ChamberHitContainerCIt i = closeHits.begin() ; i != closeHits.end(); ++i ) {      
00324     const CSCRecHit2D* h = *i;      
00325     int layer = (*i)->cscDetId().layer();     
00326     compareProtoSegment(h, layer); 
00327   } 
00328 
00329 }
00330 
00331 
00332 /* isHitNearSegment
00333  *
00334  * Compare rechit with expected position from proto_segment
00335  */
00336 bool CSCSegAlgoDF::isHitNearSegment( const CSCRecHit2D* hit) const {
00337 
00338   const CSCLayer* layer = theChamber->layer(hit->cscDetId().layer());
00339 
00340   // hit phi position in global coordinates
00341   GlobalPoint Hgp = layer->toGlobal(hit->localPosition());
00342   double Hphi = Hgp.phi();                                
00343   if (Hphi < 0.) Hphi += 2.*M_PI;
00344   LocalPoint Hlp = theChamber->toLocal(Hgp);
00345   double z = Hlp.z();  
00346 
00347   double LocalX = protoIntercept.x() + protoSlope_u * z;
00348   double LocalY = protoIntercept.y() + protoSlope_v * z;
00349   LocalPoint Slp(LocalX, LocalY, z);
00350   GlobalPoint Sgp = theChamber->toGlobal(Slp); 
00351   double Sphi = Sgp.phi();
00352   if (Sphi < 0.) Sphi += 2.*M_PI;
00353   double R = sqrt(Sgp.x()*Sgp.x() + Sgp.y()*Sgp.y());
00354   
00355   double deltaPhi = Sphi - Hphi;
00356   if (deltaPhi >  2.*M_PI) deltaPhi -= 2.*M_PI;
00357   if (deltaPhi < -2.*M_PI) deltaPhi += 2.*M_PI;
00358   if (deltaPhi < 0.) deltaPhi = -deltaPhi; 
00359 
00360   double RdeltaPhi = R * deltaPhi;
00361 
00362   if (RdeltaPhi < dRPhiFineMax && deltaPhi < dPhiFineMax ) return true;
00363 
00364   return false;
00365 }
00366 
00367 
00368 /* Method addHit
00369  *
00370  * Test if can add hit to proto segment. If so, try to add it.
00371  *
00372  */
00373 bool CSCSegAlgoDF::addHit(const CSCRecHit2D* aHit, int layer) {
00374   
00375   // Return true if hit was added successfully and then parameters are updated.
00376   // Return false if there is already a hit on the same layer, or insert failed.
00377   
00378   bool ok = true;
00379   
00380   // Test that we are not trying to add the same hit again
00381   for ( ChamberHitContainer::const_iterator it = protoSegment.begin(); it != protoSegment.end(); it++ ) 
00382     if ( aHit == (*it)  ) return false;
00383   
00384   protoSegment.push_back(aHit);
00385 
00386   return ok;
00387 }    
00388 
00389 
00390 /* Method updateParameters
00391  *      
00392  * Perform a simple Least Square Fit on proto segment to determine slope and intercept
00393  *
00394  */   
00395 void CSCSegAlgoDF::updateParameters() {
00396 
00397   // Compute slope from Least Square Fit    
00398   CLHEP::HepMatrix M(4,4,0);
00399   CLHEP::HepVector B(4,0);
00400 
00401   ChamberHitContainer::const_iterator ih;
00402   
00403   for (ih = protoSegment.begin(); ih != protoSegment.end(); ++ih) {
00404     
00405     const CSCRecHit2D& hit = (**ih);
00406     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
00407     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
00408     LocalPoint  lp         = theChamber->toLocal(gp); 
00409     
00410     double u = lp.x();
00411     double v = lp.y();
00412     double z = lp.z();
00413     
00414     // ptc: Covariance matrix of local errors 
00415     CLHEP::HepMatrix IC(2,2);
00416     IC(1,1) = hit.localPositionError().xx();
00417     IC(1,2) = hit.localPositionError().xy();
00418     IC(2,2) = hit.localPositionError().yy();
00419     IC(2,1) = IC(1,2); // since Cov is symmetric
00420     
00421     // ptc: Invert covariance matrix (and trap if it fails!)
00422     int ierr = 0;
00423     IC.invert(ierr); // inverts in place
00424     if (ierr != 0) {
00425       LogDebug("CSC") << "CSCSegment::fitSlopes: failed to invert covariance matrix=\n" << IC << "\n";      
00426     }
00427     
00428     M(1,1) += IC(1,1);
00429     M(1,2) += IC(1,2);
00430     M(1,3) += IC(1,1) * z;
00431     M(1,4) += IC(1,2) * z;
00432     B(1)   += u * IC(1,1) + v * IC(1,2);
00433     
00434     M(2,1) += IC(2,1);
00435     M(2,2) += IC(2,2);
00436     M(2,3) += IC(2,1) * z;
00437     M(2,4) += IC(2,2) * z;
00438     B(2)   += u * IC(2,1) + v * IC(2,2);
00439     
00440     M(3,1) += IC(1,1) * z;
00441     M(3,2) += IC(1,2) * z;
00442     M(3,3) += IC(1,1) * z * z;
00443     M(3,4) += IC(1,2) * z * z;
00444     B(3)   += ( u * IC(1,1) + v * IC(1,2) ) * z;
00445     
00446     M(4,1) += IC(2,1) * z;
00447     M(4,2) += IC(2,2) * z;
00448     M(4,3) += IC(2,1) * z * z;
00449     M(4,4) += IC(2,2) * z * z;
00450     B(4)   += ( u * IC(2,1) + v * IC(2,2) ) * z;
00451   }
00452   
00453   CLHEP::HepVector p = solve(M, B);
00454   
00455   // Update member variables 
00456   // Note that origin has local z = 0
00457 
00458   protoIntercept = LocalPoint(p(1), p(2), 0.);
00459   protoSlope_u = p(3);
00460   protoSlope_v = p(4);
00461 
00462 
00463   // Determine Chi^2 for the proto wire segment
00464   
00465   double chsq = 0.;
00466   
00467   for (ih = protoSegment.begin(); ih != protoSegment.end(); ++ih) {
00468     
00469     const CSCRecHit2D& hit = (**ih);
00470     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
00471     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
00472     LocalPoint lp          = theChamber->toLocal(gp);
00473     
00474     double u = lp.x();
00475     double v = lp.y();
00476     double z = lp.z();
00477     
00478     double du = protoIntercept.x() + protoSlope_u * z - u;
00479     double dv = protoIntercept.y() + protoSlope_v * z - v;
00480     
00481     CLHEP::HepMatrix IC(2,2);
00482     IC(1,1) = hit.localPositionError().xx();
00483     IC(1,2) = hit.localPositionError().xy();
00484     IC(2,2) = hit.localPositionError().yy();
00485     IC(2,1) = IC(1,2);
00486     
00487     // Invert covariance matrix
00488     int ierr = 0;
00489     IC.invert(ierr);
00490     if (ierr != 0) {
00491       LogDebug("CSC") << "CSCSegment::fillChiSquared: failed to invert covariance matrix=\n" << IC << "\n";      
00492     }
00493     chsq += du*du*IC(1,1) + 2.*du*dv*IC(1,2) + dv*dv*IC(2,2);
00494   }
00495   protoChi2 = chsq;
00496 }
00497 
00498 
00499 /* hasHitOnLayer
00500  *
00501  * Just make sure hit to be added to layer comes from different layer than those in proto segment   
00502  */
00503 bool CSCSegAlgoDF::hasHitOnLayer(int layer) const {
00504   
00505   // Is there already a hit on this layer?
00506   for ( ChamberHitContainerCIt it = protoSegment.begin(); it != protoSegment.end(); it++ )
00507     if ( (*it)->cscDetId().layer() == layer ) return true;
00508   
00509   return false;
00510 }
00511 
00512 
00513 /* Method compareProtoSegment
00514  *      
00515  * For hit coming from the same layer of an existing hit within the proto segment
00516  * test if achieve better chi^2 by using this hit than the other
00517  *
00518  */ 
00519 void CSCSegAlgoDF::compareProtoSegment(const CSCRecHit2D* h, int layer) {
00520   
00521   // Store old segment first
00522   double old_protoChi2                  = protoChi2;
00523   LocalPoint old_protoIntercept         = protoIntercept;
00524   float old_protoSlope_u                = protoSlope_u;
00525   float old_protoSlope_v                = protoSlope_v;
00526   LocalVector old_protoDirection        = protoDirection;
00527   ChamberHitContainer old_protoSegment  = protoSegment;
00528  
00529 
00530   // Try adding the hit to existing segment, and remove old one existing in same layer
00531   ChamberHitContainer::iterator it;
00532   for ( it = protoSegment.begin(); it != protoSegment.end(); ) {
00533     if ( (*it)->cscDetId().layer() == layer ) {
00534       it = protoSegment.erase(it);
00535     } else {
00536       ++it;
00537     }
00538   }
00539   bool ok = addHit(h, layer);
00540 
00541   if (ok) updateParameters();
00542   
00543   if ( (protoChi2 > old_protoChi2) || ( !ok ) ) {
00544     protoChi2       = old_protoChi2;
00545     protoIntercept  = old_protoIntercept;
00546     protoSlope_u    = old_protoSlope_u;
00547     protoSlope_v    = old_protoSlope_v;
00548     protoDirection  = old_protoDirection;
00549     protoSegment    = old_protoSegment;
00550   }
00551 }
00552 
00553 
00554 /* Method flagHitsAsUsed
00555  *
00556  * Flag hits which have entered segment building so we don't reuse them.
00557  * Also flag does which were very close to segment to reduce combinatorics
00558  */
00559 void CSCSegAlgoDF::flagHitsAsUsed(const ChamberHitContainer& rechitsInChamber) {
00560   
00561   // Flag hits on segment as used
00562   ChamberHitContainerCIt ib = rechitsInChamber.begin();
00563   ChamberHitContainerCIt hi, iu;
00564   
00565   for ( hi = protoSegment.begin(); hi != protoSegment.end(); ++hi ) {
00566     for ( iu = ib; iu != rechitsInChamber.end(); ++iu ) {
00567       if (*hi == *iu) usedHits[iu-ib] = true;
00568     }
00569   }
00570   // Don't reject hits marked as "nearby" for now.
00571   // So this is bypassed at all times for now !!!
00572   // Perhaps add back to speed up algorithm some more
00573   if (closeHits.size() > 0) return;  
00574   for ( hi = closeHits.begin(); hi != closeHits.end(); ++hi ) {
00575     for ( iu = ib; iu != rechitsInChamber.end(); ++iu ) {
00576       if (*hi == *iu) usedHits[iu-ib] = true;
00577     }
00578   }
00579 
00580 }
00581 
00582 
00583 AlgebraicSymMatrix CSCSegAlgoDF::weightMatrix() const {
00584 
00585   std::vector<const CSCRecHit2D*>::const_iterator it;
00586   int nhits = protoSegment.size();
00587   AlgebraicSymMatrix matrix(2*nhits, 0);
00588   int row = 0;
00589 
00590   for (it = protoSegment.begin(); it != protoSegment.end(); ++it) {
00591 
00592     const CSCRecHit2D& hit = (**it);
00593     ++row;
00594     matrix(row, row)   = hit.localPositionError().xx();
00595     matrix(row, row+1) = hit.localPositionError().xy();
00596     ++row;
00597     matrix(row, row-1) = hit.localPositionError().xy();
00598     matrix(row, row)   = hit.localPositionError().yy();
00599   }
00600   int ierr;
00601   matrix.invert(ierr);
00602   return matrix;
00603 }
00604 
00605 
00606 CLHEP::HepMatrix CSCSegAlgoDF::derivativeMatrix() const {
00607 
00608   ChamberHitContainer::const_iterator it;
00609   int nhits = protoSegment.size();
00610   CLHEP::HepMatrix matrix(2*nhits, 4);
00611   int row = 0;
00612 
00613   for(it = protoSegment.begin(); it != protoSegment.end(); ++it) {
00614 
00615     const CSCRecHit2D& hit = (**it);
00616     const CSCLayer* layer = theChamber->layer(hit.cscDetId().layer());
00617     GlobalPoint gp = layer->toGlobal(hit.localPosition());
00618     LocalPoint lp = theChamber->toLocal(gp);
00619     float z = lp.z();
00620     ++row;
00621     matrix(row, 1) = 1.;
00622     matrix(row, 3) = z;
00623     ++row;
00624     matrix(row, 2) = 1.;
00625     matrix(row, 4) = z;
00626   }
00627   return matrix;
00628 }
00629 
00630 /* calculateError
00631  *
00632  */
00633 AlgebraicSymMatrix CSCSegAlgoDF::calculateError() const {
00634 
00635   AlgebraicSymMatrix weights = weightMatrix();
00636   AlgebraicMatrix A = derivativeMatrix();
00637 
00638   // (AT W A)^-1
00639   // from http://www.phys.ufl.edu/~avery/fitting.html, part I
00640   int ierr;
00641   AlgebraicSymMatrix result = weights.similarityT(A);
00642   result.invert(ierr);
00643 
00644   // blithely assuming the inverting never fails...
00645   return result;
00646 }
00647 
00648 void CSCSegAlgoDF::flipErrors( AlgebraicSymMatrix& a ) const {
00649 
00650   // The CSCSegment needs the error matrix re-arranged
00651 
00652   AlgebraicSymMatrix hold( a );
00653 
00654   // errors on slopes into upper left
00655   a(1,1) = hold(3,3);
00656   a(1,2) = hold(3,4);
00657   a(2,1) = hold(4,3);
00658   a(2,2) = hold(4,4);
00659 
00660   // errors on positions into lower right
00661   a(3,3) = hold(1,1);
00662   a(3,4) = hold(1,2);
00663   a(4,3) = hold(2,1);
00664   a(4,4) = hold(2,2);
00665 
00666   // off-diagonal elements remain unchanged
00667 
00668 }
00669 
00670 
00671 // Try to clean up segments by quickly looking at residuals
00672 void CSCSegAlgoDF::pruneFromResidual(){
00673 
00674   // Only prune if have at least 5 hits 
00675   if ( protoSegment.size() < 5 ) return ;
00676 
00677 
00678   // Now Study residuals
00679       
00680   float maxResidual = 0.;
00681   float sumResidual = 0.;
00682   int nHits = 0;
00683   int badIndex = -1;
00684   int j = 0;
00685 
00686 
00687   ChamberHitContainer::const_iterator ih;
00688 
00689   for ( ih = protoSegment.begin(); ih != protoSegment.end(); ++ih ) {
00690     const CSCRecHit2D& hit = (**ih);
00691     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
00692     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
00693     LocalPoint lp          = theChamber->toLocal(gp);
00694 
00695     double u = lp.x();
00696     double v = lp.y();
00697     double z = lp.z();
00698 
00699     double du = protoIntercept.x() + protoSlope_u * z - u;
00700     double dv = protoIntercept.y() + protoSlope_v * z - v;
00701 
00702     float residual = sqrt(du*du + dv*dv);
00703 
00704     sumResidual += residual;
00705     nHits++;
00706     if ( residual > maxResidual ) {
00707       maxResidual = residual;
00708       badIndex = j;
00709     }
00710     j++;
00711   }
00712 
00713   float corrAvgResidual = (sumResidual - maxResidual)/(nHits -1);
00714 
00715   // Keep all hits 
00716   if ( maxResidual/corrAvgResidual < maxRatioResidual ) return;
00717 
00718 
00719   // Drop worse hit and recompute segment properties + fill
00720 
00721   ChamberHitContainer newProtoSegment;
00722 
00723   j = 0;
00724   for ( ih = protoSegment.begin(); ih != protoSegment.end(); ++ih ) {
00725     if ( j != badIndex ) newProtoSegment.push_back(*ih);
00726     j++;
00727   }
00728   
00729   protoSegment.clear();
00730 
00731   for ( ih = newProtoSegment.begin(); ih != newProtoSegment.end(); ++ih ) {
00732     protoSegment.push_back(*ih);
00733   }
00734 
00735   // Update segment parameters
00736   updateParameters();
00737 
00738 }
00739 
00740 
00741 /*
00742  * Order the hits such that 2nd one is closest in x,y to first seed hit in global coordinates
00743  */
00744 void CSCSegAlgoDF::orderSecondSeed( GlobalPoint gp1,
00745                                            const ChamberHitContainerCIt i1, 
00746                                            const ChamberHitContainerCIt i2, 
00747                                            const ChamberHitContainer& rechits, 
00748                                            const LayerIndex& layerIndex ) {
00749 
00750   secondSeedHits.clear();
00751 
00752   //ChamberHitContainerCIt ib = rechits.begin();
00753   ChamberHitContainerCIt ie = rechits.end();
00754 
00755   //  int layer1 = layerIndex[i1-ib];
00756   //  int layer2 = layerIndex[i2-ib];
00757 
00758 
00759   // Now fill vector of rechits closest to center of mass:
00760   // secondSeedHitsIdx.clear() = 0;
00761 
00762   // Loop over all hits and find hit closest to 1st seed.
00763   for ( ChamberHitContainerCIt i2 = ie-1; i2 > i1; --i2 ) {     
00764 
00765 
00766   }
00767 
00768         
00769 }