CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_6_1_2_SLHC2/src/RecoLocalMuon/CSCSegment/src/CSCSegAlgoST.cc

Go to the documentation of this file.
00001 
00010 #include "CSCSegAlgoST.h"
00011 #include "CSCSegAlgoShowering.h"
00012 
00013 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
00014 
00015 // // For clhep Matrix::solve
00016 // #include "DataFormats/CLHEP/interface/AlgebraicObjects.h"
00017 #include "Geometry/CSCGeometry/interface/CSCLayer.h"
00018 
00019 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00020 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00021 
00022 #include "CommonTools/Statistics/interface/ChiSquaredProbability.h"
00023 
00024 #include <algorithm>
00025 #include <cmath>
00026 #include <iostream>
00027 #include <string>
00028 
00029 
00030 /* Constructor
00031  *
00032  */
00033 CSCSegAlgoST::CSCSegAlgoST(const edm::ParameterSet& ps) : CSCSegmentAlgorithm(ps), myName("CSCSegAlgoST") {
00034         
00035   debug                  = ps.getUntrackedParameter<bool>("CSCDebug");
00036   //  minLayersApart         = ps.getParameter<int>("minLayersApart");
00037   //  nSigmaFromSegment      = ps.getParameter<double>("nSigmaFromSegment");
00038   minHitsPerSegment      = ps.getParameter<int>("minHitsPerSegment");
00039   //  muonsPerChamberMax     = ps.getParameter<int>("CSCSegmentPerChamberMax");      
00040   //  chi2Max                = ps.getParameter<double>("chi2Max");
00041   dXclusBoxMax           = ps.getParameter<double>("dXclusBoxMax");
00042   dYclusBoxMax           = ps.getParameter<double>("dYclusBoxMax");
00043   preClustering          = ps.getParameter<bool>("preClustering");
00044   preClustering_useChaining    = ps.getParameter<bool>("preClusteringUseChaining");
00045   Pruning                = ps.getParameter<bool>("Pruning");
00046   BrutePruning           = ps.getParameter<bool>("BrutePruning");
00047   BPMinImprovement        = ps.getParameter<double>("BPMinImprovement");
00048   // maxRecHitsInCluster is the maximal number of hits in a precluster that is being processed
00049   // This cut is intended to remove messy events. Currently nothing is returned if there are
00050   // more that maxRecHitsInCluster hits. It could be useful to return an estimate of the 
00051   // cluster position, which is available.
00052   maxRecHitsInCluster    = ps.getParameter<int>("maxRecHitsInCluster");
00053   onlyBestSegment        = ps.getParameter<bool>("onlyBestSegment");
00054 
00055   hitDropLimit4Hits      = ps.getParameter<double>("hitDropLimit4Hits");
00056   hitDropLimit5Hits      = ps.getParameter<double>("hitDropLimit5Hits");
00057   hitDropLimit6Hits      = ps.getParameter<double>("hitDropLimit6Hits");
00058   
00059   yweightPenaltyThreshold      = ps.getParameter<double>("yweightPenaltyThreshold");
00060   yweightPenalty               = ps.getParameter<double>("yweightPenalty");
00061                                                                                          
00062   curvePenaltyThreshold        = ps.getParameter<double>("curvePenaltyThreshold");
00063   curvePenalty                 = ps.getParameter<double>("curvePenalty");
00064 
00065   useShowering = ps.getParameter<bool>("useShowering");
00066   showering_   = new CSCSegAlgoShowering( ps );
00067   // std::cout<<"Constructor called..."<<std::endl;
00069   correctCov_     = ps.getParameter<bool>("CorrectTheErrors");
00070   chi2Norm_2D_        = ps.getParameter<double>("NormChi2Cut2D");
00071   chi2Norm_3D_        = ps.getParameter<double>("NormChi2Cut3D");
00072   prePrun_        = ps.getParameter<bool>("prePrun");
00073   prePrunLimit_   = ps.getParameter<double>("prePrunLimit");
00074   //
00075   condSeed1_  = ps.getParameter<double>("SeedSmall");
00076   condSeed2_  = ps.getParameter<double>("SeedBig");
00077   covToAnyNumber_ = ps.getParameter<bool>("ForceCovariance");
00078   covToAnyNumberAll_ = ps.getParameter<bool>("ForceCovarianceAll");
00079   covAnyNumber_ = ps.getParameter<double>("Covariance");
00080   passCondNumber=false;
00081   passCondNumber_2=false;
00082   protoChiUCorrection=1.0;
00083   maxContrIndex=0;
00084   protoNDF = 1.;
00085 
00086 }
00087 
00088 /* Destructor
00089  *
00090  */
00091 CSCSegAlgoST::~CSCSegAlgoST() {
00092   delete showering_;
00093 }
00094 
00095 
00096 std::vector<CSCSegment> CSCSegAlgoST::run(const CSCChamber* aChamber, ChamberHitContainer rechits) {
00097 
00098   // Store chamber in temp memory
00099   theChamber = aChamber; 
00100 
00101   LogTrace("CSCSegAlgoST") << "[CSCSegAlgoST::run] build segments in chamber " << theChamber->id();
00102 
00103   // pre-cluster rechits and loop over all sub clusters seperately
00104   std::vector<CSCSegment>          segments_temp;
00105   std::vector<CSCSegment>          segments;
00106   std::vector<ChamberHitContainer> rechits_clusters; // this is a collection of groups of rechits
00107 
00108   // Define yweight penalty depending on chamber. We fixed the relative ratios, but
00109   // they can be scaled by parameters:
00110   
00111   for(int a = 0; a<5; ++a) {
00112     for(int b = 0; b<5; ++b) {
00113       a_yweightPenaltyThreshold[a][b] = 0.0;
00114     }
00115   }
00116   
00117   a_yweightPenaltyThreshold[1][1] = yweightPenaltyThreshold * 10.20;
00118   a_yweightPenaltyThreshold[1][2] = yweightPenaltyThreshold * 14.00;
00119   a_yweightPenaltyThreshold[1][3] = yweightPenaltyThreshold * 20.40;
00120   a_yweightPenaltyThreshold[1][4] = yweightPenaltyThreshold * 10.20;
00121   a_yweightPenaltyThreshold[2][1] = yweightPenaltyThreshold *  7.60;
00122   a_yweightPenaltyThreshold[2][2] = yweightPenaltyThreshold * 20.40;
00123   a_yweightPenaltyThreshold[3][1] = yweightPenaltyThreshold *  7.60;
00124   a_yweightPenaltyThreshold[3][2] = yweightPenaltyThreshold * 20.40;
00125   a_yweightPenaltyThreshold[4][1] = yweightPenaltyThreshold *  6.75;
00126   
00127   if(preClustering) {
00128     // run a pre-clusterer on the given rechits to split obviously separated segment seeds:
00129     if(preClustering_useChaining){
00130       // it uses X,Y,Z information; there are no configurable parameters used;
00131       // the X, Y, Z "cuts" are just (much) wider than the LCT readout ones
00132       // (which are actually not step functions); this new code could accomodate
00133       // the clusterHits one below but we leave it for security and backward 
00134       // comparison reasons 
00135       rechits_clusters = chainHits( theChamber, rechits );
00136     }
00137     else{
00138       // it uses X,Y information + configurable parameters
00139       rechits_clusters = clusterHits( theChamber, rechits );
00140     }
00141     // loop over the found clusters:
00142     for(std::vector<ChamberHitContainer>::iterator sub_rechits = rechits_clusters.begin(); sub_rechits !=  rechits_clusters.end(); ++sub_rechits ) {
00143       // clear the buffer for the subset of segments:
00144       segments_temp.clear();
00145       // build the subset of segments:
00146       segments_temp = buildSegments( (*sub_rechits) );
00147       // add the found subset of segments to the collection of all segments in this chamber:
00148       segments.insert( segments.end(), segments_temp.begin(), segments_temp.end() );
00149     }
00150     // this is the place to prune:
00151     if( Pruning ) {
00152       segments_temp.clear(); // segments_temp needed?!?!
00153       segments_temp = prune_bad_hits( theChamber, segments );
00154       segments.clear(); // segments_temp needed?!?!
00155       segments.swap(segments_temp); // segments_temp needed?!?!
00156     }
00157   
00158     //@@ Ganged strips in ME1/1A?
00159     if ( ("ME1/a" == aChamber->specs()->chamberTypeName()) && aChamber->specs()->gangedStrips() ){
00160     //  if ( aChamber->specs()->gangedStrips() ){
00161       findDuplicates(segments);
00162     }
00163     return segments;
00164   }
00165   else {
00166     segments = buildSegments(rechits);
00167     if( Pruning ) {
00168       segments_temp.clear(); // segments_temp needed?!?!
00169       segments_temp = prune_bad_hits( theChamber, segments );
00170       segments.clear(); // segments_temp needed?!?!
00171       segments.swap(segments_temp); // segments_temp needed?!?!
00172     }
00173 
00174     //@@ Ganged strips in ME1/1A?
00175     if ( ("ME1/a" == aChamber->specs()->chamberTypeName()) && aChamber->specs()->gangedStrips() ){
00176     //  if ( aChamber->specs()->gangedStrips() ){
00177       findDuplicates(segments);
00178     }
00179     return segments;
00180     //return buildSegments(rechits); 
00181   }
00182 }
00183 
00184 // ********************************************************************;
00185 // *** This method is meant to remove clear bad hits, using as      ***; 
00186 // *** much information from the chamber as possible (e.g. charge,  ***;
00187 // *** hit position, timing, etc.)                                  ***;
00188 // ********************************************************************;
00189 std::vector<CSCSegment> CSCSegAlgoST::prune_bad_hits(const CSCChamber* aChamber, std::vector<CSCSegment> & segments) {
00190   
00191   //   std::cout<<"*************************************************************"<<std::endl;
00192   //   std::cout<<"Called prune_bad_hits in Chamber "<< theChamber->specs()->chamberTypeName()<<std::endl;
00193   //   std::cout<<"*************************************************************"<<std::endl;
00194   
00195   std::vector<CSCSegment>          segments_temp;
00196   std::vector<ChamberHitContainer> rechits_clusters; // this is a collection of groups of rechits
00197   
00198   const float chi2ndfProbMin = 1.0e-4;
00199   bool   use_brute_force = BrutePruning;
00200 
00201   int hit_nr = 0;
00202   int hit_nr_worst = -1;
00203   //int hit_nr_2ndworst = -1;
00204   
00205   for(std::vector<CSCSegment>::iterator it=segments.begin(); it != segments.end(); ++it) {
00206     
00207     // do nothing for nhit <= minHitPerSegment
00208     if( (*it).nRecHits() <= minHitsPerSegment ) continue;
00209     
00210     if( !use_brute_force ) {// find worst hit
00211       
00212       float chisq    = (*it).chi2();
00213       int nhits      = (*it).nRecHits();
00214       LocalPoint localPos = (*it).localPosition();
00215       LocalVector segDir = (*it).localDirection();
00216       const CSCChamber* cscchamber = theChamber;
00217       float globZ       ;
00218           
00219       GlobalPoint globalPosition = cscchamber->toGlobal(localPos);
00220       globZ = globalPosition.z();
00221       
00222       
00223       if( ChiSquaredProbability((double)chisq,(double)(2*nhits-4)) < chi2ndfProbMin  ) {
00224 
00225         // find (rough) "residuals" (NOT excluding the hit from the fit - speed!) of hits on segment
00226         std::vector<CSCRecHit2D> theseRecHits = (*it).specificRecHits();
00227         std::vector<CSCRecHit2D>::const_iterator iRH_worst;
00228         //float xdist_local       = -99999.;
00229 
00230         float xdist_local_worst_sig = -99999.;
00231         float xdist_local_2ndworst_sig = -99999.;
00232         float xdist_local_sig       = -99999.;
00233 
00234         hit_nr = 0;
00235         hit_nr_worst = -1;
00236         //hit_nr_2ndworst = -1;
00237 
00238         for ( std::vector<CSCRecHit2D>::const_iterator iRH = theseRecHits.begin(); iRH != theseRecHits.end(); ++iRH) {
00239           //mark "worst" hit:
00240           
00241           //float z_at_target ;
00242           //float radius      ;
00243           float loc_x_at_target ;
00244           //float loc_y_at_target ;
00245           //float loc_z_at_target ;
00246 
00247           //z_at_target  = 0.;
00248           loc_x_at_target  = 0.;
00249           //loc_y_at_target  = 0.;
00250           //loc_z_at_target  = 0.;
00251           //radius       = 0.;
00252           
00253           // set the z target in CMS global coordinates:
00254           const CSCLayer* csclayerRH = theChamber->layer((*iRH).cscDetId().layer());
00255           LocalPoint localPositionRH = (*iRH).localPosition();
00256           GlobalPoint globalPositionRH = csclayerRH->toGlobal(localPositionRH); 
00257           
00258           LocalError rerrlocal = (*iRH).localPositionError();  
00259           float xxerr = rerrlocal.xx();
00260           
00261           float target_z     = globalPositionRH.z();  // target z position in cm (z pos of the hit)
00262           
00263           if(target_z > 0.) {
00264             loc_x_at_target = localPos.x() + (segDir.x()/fabs(segDir.z())*( target_z - globZ ));
00265             //loc_y_at_target = localPos.y() + (segDir.y()/fabs(segDir.z())*( target_z - globZ ));
00266             //loc_z_at_target = target_z;
00267           }
00268           else {
00269             loc_x_at_target = localPos.x() + ((-1)*segDir.x()/fabs(segDir.z())*( target_z - globZ ));
00270             //loc_y_at_target = localPos.y() + ((-1)*segDir.y()/fabs(segDir.z())*( target_z - globZ ));
00271             //loc_z_at_target = target_z;
00272           }
00273           // have to transform the segments coordinates back to the local frame... how?!!!!!!!!!!!!
00274           
00275           //xdist_local  = fabs(localPositionRH.x() - loc_x_at_target);
00276           xdist_local_sig  = fabs((localPositionRH.x() -loc_x_at_target)/(xxerr));
00277           
00278           if( xdist_local_sig > xdist_local_worst_sig ) {
00279             xdist_local_2ndworst_sig = xdist_local_worst_sig;
00280             xdist_local_worst_sig    = xdist_local_sig;
00281             iRH_worst            = iRH;
00282             //hit_nr_2ndworst = hit_nr_worst;
00283             hit_nr_worst = hit_nr;
00284           }
00285           else if(xdist_local_sig > xdist_local_2ndworst_sig) {
00286             xdist_local_2ndworst_sig = xdist_local_sig;
00287             //hit_nr_2ndworst = hit_nr;
00288           }
00289           ++hit_nr;
00290         }
00291 
00292         // reset worst hit number if certain criteria apply.
00293         // Criteria: 2nd worst hit must be at least a factor of
00294         // 1.5 better than the worst in terms of sigma:
00295         if ( xdist_local_worst_sig / xdist_local_2ndworst_sig < 1.5 ) {
00296           hit_nr_worst    = -1;
00297           //hit_nr_2ndworst = -1;
00298         }
00299       }
00300     }
00301 
00302     // if worst hit was found, refit without worst hit and select if considerably better than original fit.
00303     // Can also use brute force: refit all n-1 hit segments and choose one over the n hit if considerably "better"
00304    
00305     std::vector< CSCRecHit2D > buffer;
00306     std::vector< std::vector< CSCRecHit2D > > reduced_segments;
00307     std::vector< CSCRecHit2D > theseRecHits = (*it).specificRecHits();
00308     float best_red_seg_prob = 0.0;
00309     // usefor chi2 1 diff   float best_red_seg_prob = 99999.;
00310     buffer.clear();
00311 
00312     if( ChiSquaredProbability((double)(*it).chi2(),(double)((2*(*it).nRecHits())-4)) < chi2ndfProbMin  ) {
00313         
00314       buffer = theseRecHits;
00315 
00316       // Dirty switch: here one can select to refit all possible subsets or just the one without the 
00317       // tagged worst hit:
00318       if( use_brute_force ) { // Brute force method: loop over all possible segments:
00319         for(size_t bi = 0; bi < buffer.size(); ++bi) {
00320           reduced_segments.push_back(buffer);
00321           reduced_segments[bi].erase(reduced_segments[bi].begin()+(bi),reduced_segments[bi].begin()+(bi+1));
00322         }
00323       }
00324       else { // More elegant but still biased: erase only worst hit
00325         // Comment: There is not a very strong correlation of the worst hit with the one that one should remove... 
00326         if( hit_nr_worst >= 0 && hit_nr_worst <= int(buffer.size())  ) {
00327           // fill segment in buffer, delete worst hit
00328           buffer.erase(buffer.begin()+(hit_nr_worst),buffer.begin()+(hit_nr_worst+1));
00329           reduced_segments.push_back(buffer);
00330         }
00331         else {
00332           // only fill segment in array, do not delete anything
00333           reduced_segments.push_back(buffer);
00334         }
00335       }
00336     }
00337       
00338     // Loop over the subsegments and fit (only one segment if "use_brute_force" is false):
00339     for(size_t iSegment=0; iSegment<reduced_segments.size(); ++iSegment) {
00340       // loop over hits on given segment and push pointers to hits into protosegment
00341       protoSegment.clear();
00342       for(size_t m = 0; m<reduced_segments[iSegment].size(); ++m ) {
00343         protoSegment.push_back(&reduced_segments[iSegment][m]);
00344       }
00345       passCondNumber=false;
00346       passCondNumber_2 = false;
00347       protoChiUCorrection=1.0;
00348       doSlopesAndChi2();
00349       // Attempt to handle numerical instability of the fit;
00350       // The same as in the build method;
00351       // Preprune is not applied;
00352       if(correctCov_){
00353         if(protoChi2/protoNDF>chi2Norm_3D_){
00354           passCondNumber = true;
00355           doSlopesAndChi2();
00356         }
00357         if((protoChiUCorrection<1.00005)&&(protoChi2/protoNDF>chi2Norm_3D_)){
00358           passCondNumber_2=true;
00359           doSlopesAndChi2();
00360         }
00361       }
00362       fillLocalDirection();
00363       // calculate error matrix
00364       AlgebraicSymMatrix protoErrors = calculateError();   
00365       // but reorder components to match what's required by TrackingRecHit interface 
00366       // i.e. slopes first, then positions 
00367       flipErrors( protoErrors ); 
00368       //
00369       CSCSegment temp(protoSegment, protoIntercept, protoDirection, protoErrors, protoChi2);
00370 
00371       // replace n hit segment with n-1 hit segment, if segment probability is BPMinImprovement better:
00372       if( ( ChiSquaredProbability((double)(*it).chi2(),(double)((2*(*it).nRecHits())-4)) 
00373             < 
00374             (1./BPMinImprovement)*(ChiSquaredProbability((double)temp.chi2(),(double)(2*temp.nRecHits()-4))) ) // was (1.e-3) 081202
00375 
00376           && 
00377           ( (ChiSquaredProbability((double)temp.chi2(),(double)(2*temp.nRecHits()-4))) 
00378             > best_red_seg_prob 
00379             )
00380           &&
00381           ( (ChiSquaredProbability((double)temp.chi2(),(double)(2*temp.nRecHits()-4))) > 1e-10 )
00382           ) {
00383         best_red_seg_prob = ChiSquaredProbability((double)temp.chi2(),(double)(2*temp.nRecHits()-4));
00384         // The alternative n-1 segment is much cleaner. If this segment 
00385         // has >= minHitsPerSegment hits exchange current n hit segment (*it) 
00386         // with better n-1 hit segment:
00387         if( temp.nRecHits() >= minHitsPerSegment ) {
00388           (*it) = temp;
00389         }
00390       }
00391     }
00392   }
00393   
00394   return segments;
00395   
00396 }
00397 
00398 
00399 // ********************************************************************;
00400 std::vector< std::vector<const CSCRecHit2D*> > CSCSegAlgoST::clusterHits(const CSCChamber* aChamber, ChamberHitContainer & rechits) {
00401   theChamber = aChamber; 
00402 
00403   std::vector<ChamberHitContainer> rechits_clusters; // this is a collection of groups of rechits
00404   //   const float dXclus_box_cut       = 4.; // seems to work reasonably 070116
00405   //   const float dYclus_box_cut       = 8.; // seems to work reasonably 070116
00406 
00407   //float dXclus = 0.0;
00408   //float dYclus = 0.0;
00409   float dXclus_box = 0.0;
00410   float dYclus_box = 0.0;
00411 
00412   std::vector<const CSCRecHit2D*> temp;
00413 
00414   std::vector< ChamberHitContainer > seeds;
00415 
00416   std::vector<float> running_meanX;
00417   std::vector<float> running_meanY;
00418 
00419   std::vector<float> seed_minX;
00420   std::vector<float> seed_maxX;
00421   std::vector<float> seed_minY;
00422   std::vector<float> seed_maxY;
00423 
00424   //std::cout<<"*************************************************************"<<std::endl;
00425   //std::cout<<"Called clusterHits in Chamber "<< theChamber->specs()->chamberTypeName()<<std::endl;
00426   //std::cout<<"*************************************************************"<<std::endl;
00427 
00428   // split rechits into subvectors and return vector of vectors:
00429   // Loop over rechits 
00430   // Create one seed per hit
00431   for(unsigned int i = 0; i < rechits.size(); ++i) {
00432 
00433     temp.clear();
00434 
00435     temp.push_back(rechits[i]);
00436 
00437     seeds.push_back(temp);
00438 
00439     // First added hit in seed defines the mean to which the next hit is compared
00440     // for this seed.
00441 
00442     running_meanX.push_back( rechits[i]->localPosition().x() );
00443     running_meanY.push_back( rechits[i]->localPosition().y() );
00444         
00445     // set min/max X and Y for box containing the hits in the precluster:
00446     seed_minX.push_back( rechits[i]->localPosition().x() );
00447     seed_maxX.push_back( rechits[i]->localPosition().x() );
00448     seed_minY.push_back( rechits[i]->localPosition().y() );
00449     seed_maxY.push_back( rechits[i]->localPosition().y() );
00450   }
00451     
00452   // merge clusters that are too close
00453   // measure distance between final "running mean"
00454   for(size_t NNN = 0; NNN < seeds.size(); ++NNN) {
00455         
00456     for(size_t MMM = NNN+1; MMM < seeds.size(); ++MMM) {
00457       if(running_meanX[MMM] == 999999. || running_meanX[NNN] == 999999. ) {
00458         LogDebug("CSCSegment|CSC") << "CSCSegmentST::clusterHits: Warning: Skipping used seeds, this should happen - inform developers!";
00459         //      std::cout<<"We should never see this line now!!!"<<std::endl;
00460         continue; //skip seeds that have been used 
00461       }
00462           
00463       // calculate cut criteria for simple running mean distance cut:
00464       //dXclus = fabs(running_meanX[NNN] - running_meanX[MMM]);
00465       //dYclus = fabs(running_meanY[NNN] - running_meanY[MMM]);
00466 
00467       // calculate minmal distance between precluster boxes containing the hits:
00468       if ( running_meanX[NNN] > running_meanX[MMM] ) dXclus_box = seed_minX[NNN] - seed_maxX[MMM];
00469       else                                           dXclus_box = seed_minX[MMM] - seed_maxX[NNN];
00470       if ( running_meanY[NNN] > running_meanY[MMM] ) dYclus_box = seed_minY[NNN] - seed_maxY[MMM];
00471       else                                           dYclus_box = seed_minY[MMM] - seed_maxY[NNN];
00472           
00473           
00474       if( dXclus_box < dXclusBoxMax && dYclus_box < dYclusBoxMax ) {
00475         // merge clusters!
00476         // merge by adding seed NNN to seed MMM and erasing seed NNN
00477             
00478         // calculate running mean for the merged seed:
00479         running_meanX[MMM] = (running_meanX[NNN]*seeds[NNN].size() + running_meanX[MMM]*seeds[MMM].size()) / (seeds[NNN].size()+seeds[MMM].size());
00480         running_meanY[MMM] = (running_meanY[NNN]*seeds[NNN].size() + running_meanY[MMM]*seeds[MMM].size()) / (seeds[NNN].size()+seeds[MMM].size());
00481             
00482         // update min/max X and Y for box containing the hits in the merged cluster:
00483         if ( seed_minX[NNN] <= seed_minX[MMM] ) seed_minX[MMM] = seed_minX[NNN];
00484         if ( seed_maxX[NNN] >  seed_maxX[MMM] ) seed_maxX[MMM] = seed_maxX[NNN];
00485         if ( seed_minY[NNN] <= seed_minY[MMM] ) seed_minY[MMM] = seed_minY[NNN];
00486         if ( seed_maxY[NNN] >  seed_maxY[MMM] ) seed_maxY[MMM] = seed_maxY[NNN];
00487             
00488         // add seed NNN to MMM (lower to larger number)
00489         seeds[MMM].insert(seeds[MMM].end(),seeds[NNN].begin(),seeds[NNN].end());
00490             
00491         // mark seed NNN as used (at the moment just set running mean to 999999.)
00492         running_meanX[NNN] = 999999.;
00493         running_meanY[NNN] = 999999.;
00494         // we have merged a seed (NNN) to the highter seed (MMM) - need to contimue to 
00495         // next seed (NNN+1)
00496         break;
00497       }
00498 
00499     }
00500   }
00501 
00502   // hand over the final seeds to the output
00503   // would be more elegant if we could do the above step with 
00504   // erasing the merged ones, rather than the 
00505   for(size_t NNN = 0; NNN < seeds.size(); ++NNN) {
00506     if(running_meanX[NNN] == 999999.) continue; //skip seeds that have been marked as used up in merging
00507     rechits_clusters.push_back(seeds[NNN]);
00508   }
00509 
00510   //***************************************************************
00511 
00512       return rechits_clusters; 
00513 }
00514 
00515 
00516 std::vector< std::vector<const CSCRecHit2D*> > CSCSegAlgoST::chainHits(const CSCChamber* aChamber, ChamberHitContainer & rechits) {
00517 
00518   std::vector<ChamberHitContainer> rechits_chains; // this is a collection of groups of rechits
00519 
00520 
00521   std::vector<const CSCRecHit2D*> temp;
00522 
00523   std::vector< ChamberHitContainer > seeds;
00524 
00525   std::vector <bool> usedCluster;
00526 
00527   // split rechits into subvectors and return vector of vectors:
00528   // Loop over rechits
00529   // Create one seed per hit
00530   //std::cout<<" rechits.size() = "<<rechits.size()<<std::endl;
00531   for(unsigned int i = 0; i < rechits.size(); ++i) {
00532     temp.clear();
00533     temp.push_back(rechits[i]);
00534     seeds.push_back(temp);
00535     usedCluster.push_back(false);
00536   }
00537   //@@ Only ME1/1A can have ganged strips so no need to test name
00538   bool gangedME11a = false;
00539   if ( ("ME1/a" == aChamber->specs()->chamberTypeName()) && aChamber->specs()->gangedStrips() ){
00540   //  if ( aChamber->specs()->gangedStrips() ){
00541     gangedME11a = true;
00542   }
00543   // merge chains that are too close ("touch" each other)
00544   for(size_t NNN = 0; NNN < seeds.size(); ++NNN) {
00545     for(size_t MMM = NNN+1; MMM < seeds.size(); ++MMM) {
00546       if(usedCluster[MMM] || usedCluster[NNN]){
00547         continue;
00548       }
00549       // all is in the way we define "good";
00550       // try not to "cluster" the hits but to "chain" them;
00551       // it does the clustering but also does a better job
00552       // for inclined tracks (not clustering them together;
00553       // crossed tracks would be still clustered together) 
00554       // 22.12.09: In fact it is not much more different 
00555       // than the "clustering", we just introduce another
00556       // variable in the game - Z. And it makes sense 
00557       // to re-introduce Y (or actually wire group mumber)
00558       // in a similar way as for the strip number - see
00559       // the code below.
00560       bool goodToMerge  = isGoodToMerge(gangedME11a, seeds[NNN], seeds[MMM]);
00561       if(goodToMerge){
00562         // merge chains!
00563         // merge by adding seed NNN to seed MMM and erasing seed NNN
00564 
00565         // add seed NNN to MMM (lower to larger number)
00566         seeds[MMM].insert(seeds[MMM].end(),seeds[NNN].begin(),seeds[NNN].end());
00567 
00568         // mark seed NNN as used
00569         usedCluster[NNN] = true;
00570         // we have merged a seed (NNN) to the highter seed (MMM) - need to contimue to
00571         // next seed (NNN+1)
00572         break;
00573       }
00574 
00575     }
00576   }
00577 
00578   // hand over the final seeds to the output
00579   // would be more elegant if we could do the above step with
00580   // erasing the merged ones, rather than the
00581 
00582   for(size_t NNN = 0; NNN < seeds.size(); ++NNN) {
00583     if(usedCluster[NNN]) continue; //skip seeds that have been marked as used up in merging
00584     rechits_chains.push_back(seeds[NNN]);
00585   }
00586 
00587   //***************************************************************
00588 
00589       return rechits_chains;
00590 }
00591 
00592 bool CSCSegAlgoST::isGoodToMerge(bool gangedME11a, ChamberHitContainer & newChain, ChamberHitContainer & oldChain) {
00593   for(size_t iRH_new = 0;iRH_new<newChain.size();++iRH_new){
00594     int layer_new = newChain[iRH_new]->cscDetId().layer()-1;     
00595     int middleStrip_new = newChain[iRH_new]->nStrips()/2;
00596     int centralStrip_new = newChain[iRH_new]->channels(middleStrip_new);
00597     int centralWire_new = newChain[iRH_new]->hitWire();
00598     bool layerRequirementOK = false;
00599     bool stripRequirementOK = false;
00600     bool wireRequirementOK = false;
00601     bool goodToMerge = false;
00602     for(size_t iRH_old = 0;iRH_old<oldChain.size();++iRH_old){      
00603       int layer_old = oldChain[iRH_old]->cscDetId().layer()-1;
00604       int middleStrip_old = oldChain[iRH_old]->nStrips()/2;
00605       int centralStrip_old = oldChain[iRH_old]->channels(middleStrip_old);
00606       int centralWire_old = oldChain[iRH_old]->hitWire();
00607 
00608       // to be chained, two hits need to be in neighbouring layers...
00609       // or better allow few missing layers (upto 3 to avoid inefficiencies);
00610       // however we'll not make an angle correction because it
00611       // worsen the situation in some of the "regular" cases 
00612       // (not making the correction means that the conditions for
00613       // forming a cluster are different if we have missing layers -
00614       // this could affect events at the boundaries ) 
00615       if(layer_new==layer_old+1 || layer_new==layer_old-1 ||
00616          layer_new==layer_old+2 || layer_new==layer_old-2 ||
00617          layer_new==layer_old+3 || layer_new==layer_old-3 ||
00618          layer_new==layer_old+4 || layer_new==layer_old-4 ){
00619         layerRequirementOK = true;
00620       }
00621       int allStrips = 48;
00622       //to be chained, two hits need to be "close" in strip number (can do it in phi
00623       // but it doesn't really matter); let "close" means upto 2 strips (3?) - 
00624       // this is more compared to what CLCT readout patterns allow 
00625       if(centralStrip_new==centralStrip_old ||
00626          centralStrip_new==centralStrip_old+1 || centralStrip_new==centralStrip_old-1 ||
00627          centralStrip_new==centralStrip_old+2 || centralStrip_new==centralStrip_old-2){
00628         stripRequirementOK = true;
00629       }
00630       // same for wires (and ALCT patterns)
00631       if(centralWire_new==centralWire_old ||
00632          centralWire_new==centralWire_old+1 || centralWire_new==centralWire_old-1 ||
00633          centralWire_new==centralWire_old+2 || centralWire_new==centralWire_old-2){
00634         wireRequirementOK = true;
00635       }
00636 
00637       if(gangedME11a){
00638         if(centralStrip_new==centralStrip_old+1-allStrips || centralStrip_new==centralStrip_old-1-allStrips ||
00639            centralStrip_new==centralStrip_old+2-allStrips || centralStrip_new==centralStrip_old-2-allStrips ||
00640            centralStrip_new==centralStrip_old+1+allStrips || centralStrip_new==centralStrip_old-1+allStrips ||
00641            centralStrip_new==centralStrip_old+2+allStrips || centralStrip_new==centralStrip_old-2+allStrips){
00642           stripRequirementOK = true;
00643         }
00644       }
00645       if(layerRequirementOK && stripRequirementOK && wireRequirementOK){
00646         goodToMerge = true;
00647         return goodToMerge;
00648       }
00649     }
00650   }
00651   return false;
00652 }
00653 
00654 
00655 
00656 
00657 double CSCSegAlgoST::theWeight(double coordinate_1, double coordinate_2, double coordinate_3, float layer_1, float layer_2, float layer_3) {
00658   double sub_weight = 0;
00659   sub_weight = fabs( 
00660                     ( (coordinate_2 - coordinate_3) / (layer_2  - layer_3) ) - 
00661                     ( (coordinate_1 - coordinate_2) / (layer_1  - layer_2) ) 
00662                     );
00663   return sub_weight;
00664 }
00665 
00666 /* 
00667  * This algorithm is based on the Minimum Spanning Tree (ST) approach 
00668  * for building endcap muon track segments out of the rechit's in a CSCChamber.
00669  */
00670 std::vector<CSCSegment> CSCSegAlgoST::buildSegments(ChamberHitContainer rechits) {
00671 
00672   // Clear buffer for segment vector
00673   std::vector<CSCSegment> segmentInChamber;
00674   segmentInChamber.clear(); // list of final segments
00675 
00676   // CSC Ring;
00677   unsigned int thering    = 999;
00678   unsigned int thestation = 999;
00679   //unsigned int thecham    = 999;
00680 
00681   std::vector<int> hits_onLayerNumber(6);
00682 
00683   unsigned int UpperLimit = maxRecHitsInCluster;
00684   if (int(rechits.size()) < minHitsPerSegment) return segmentInChamber;
00685  
00686   for(int iarray = 0; iarray <6; ++iarray) { // magic number 6: number of layers in CSC chamber - not gonna change :)
00687     PAhits_onLayer[iarray].clear();
00688     hits_onLayerNumber[iarray] = 0;    
00689   }
00690 
00691   chosen_Psegments.clear();
00692   chosen_weight_A.clear();
00693 
00694   Psegments.clear();
00695   Psegments_noLx.clear();
00696   Psegments_noL1.clear();
00697   Psegments_noL2.clear();
00698   Psegments_noL3.clear();
00699   Psegments_noL4.clear();
00700   Psegments_noL5.clear();
00701   Psegments_noL6.clear();
00702 
00703   Psegments_hits.clear();
00704   
00705   weight_A.clear();
00706   weight_noLx_A.clear();
00707   weight_noL1_A.clear();
00708   weight_noL2_A.clear();
00709   weight_noL3_A.clear();
00710   weight_noL4_A.clear();
00711   weight_noL5_A.clear();
00712   weight_noL6_A.clear();
00713 
00714   weight_B.clear();
00715   weight_noL1_B.clear();
00716   weight_noL2_B.clear();
00717   weight_noL3_B.clear();
00718   weight_noL4_B.clear();
00719   weight_noL5_B.clear();
00720   weight_noL6_B.clear();
00721 
00722   curv_A.clear();
00723   curv_noL1_A.clear();
00724   curv_noL2_A.clear();
00725   curv_noL3_A.clear();
00726   curv_noL4_A.clear();
00727   curv_noL5_A.clear();
00728   curv_noL6_A.clear();
00729 
00730   // definition of middle layer for n-hit segment
00731   int midlayer_pointer[6] = {0,0,2,3,3,4};
00732   
00733   // int n_layers_missed_tot = 0;
00734   int n_layers_occupied_tot = 0;
00735   int n_layers_processed = 0;
00736 
00737   float min_weight_A = 99999.9;
00738   float min_weight_noLx_A = 99999.9;
00739 
00740   //float best_weight_B = -1.;
00741   //float best_weight_noLx_B = -1.;
00742 
00743   //float best_curv_A = -1.;
00744   //float best_curv_noLx_A = -1.;
00745 
00746   int best_pseg = -1;
00747   int best_noLx_pseg = -1;
00748   int best_Layer_noLx = -1;
00749 
00750   //************************************************************************;    
00751   //***   Start segment building   *****************************************;    
00752   //************************************************************************;    
00753   
00754   // Determine how many layers with hits we have
00755   // Fill all hits into the layer hit container:
00756   
00757   // Have 2 standard arrays: one giving the number of hits per layer. 
00758   // The other the corresponding hits. 
00759   
00760   // Loop all available hits, count hits per layer and fill the hits into array by layer
00761   for(size_t M = 0; M < rechits.size(); ++M) {
00762     // add hits to array per layer and count hits per layer:
00763     hits_onLayerNumber[ rechits[M]->cscDetId().layer()-1 ] += 1;
00764     if(hits_onLayerNumber[ rechits[M]->cscDetId().layer()-1 ] == 1 ) n_layers_occupied_tot += 1;
00765     // add hits to vector in array
00766     PAhits_onLayer[rechits[M]->cscDetId().layer()-1]    .push_back(rechits[M]);    
00767   }
00768  
00769   // We have now counted the hits per layer and filled pointers to the hits into an array
00770   
00771   int tothits = 0;
00772   int maxhits = 0;
00773   int nexthits = 0;
00774   int maxlayer = -1;
00775   int nextlayer = -1;
00776 
00777   for(size_t i = 0; i< hits_onLayerNumber.size(); ++i){
00778     //std::cout<<"We have "<<hits_onLayerNumber[i]<<" hits on layer "<<i+1<<std::endl;
00779     tothits += hits_onLayerNumber[i];
00780     if (hits_onLayerNumber[i] > maxhits) {
00781       nextlayer = maxlayer;
00782       nexthits = maxhits;
00783       maxlayer = i;
00784       maxhits = hits_onLayerNumber[i];
00785     }
00786     else if (hits_onLayerNumber[i] > nexthits) {
00787       nextlayer = i;
00788       nexthits = hits_onLayerNumber[i];
00789     }
00790   }
00791 
00792 
00793   if (tothits > (int)UpperLimit) {
00794     if (n_layers_occupied_tot > 4) {
00795       tothits = tothits - hits_onLayerNumber[maxlayer];
00796       n_layers_occupied_tot = n_layers_occupied_tot - 1;
00797       PAhits_onLayer[maxlayer].clear();
00798       hits_onLayerNumber[maxlayer] = 0;
00799     }
00800   }
00801 
00802   if (tothits > (int)UpperLimit) {
00803     if (n_layers_occupied_tot > 4) {
00804       tothits = tothits - hits_onLayerNumber[nextlayer];
00805       n_layers_occupied_tot = n_layers_occupied_tot - 1;
00806       PAhits_onLayer[nextlayer].clear();
00807       hits_onLayerNumber[nextlayer] = 0;
00808     }
00809   }
00810 
00811   if (tothits > (int)UpperLimit){ 
00812 
00813   //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00814   // Showering muon - returns nothing if chi2 == -1 (see comment in SegAlgoShowering)
00815   //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
00816   if (useShowering) {
00817     CSCSegment segShower = showering_->showerSeg(theChamber, rechits);
00818 
00819     // Make sure have at least 3 hits...
00820     if ( segShower.nRecHits() < 3 ) return segmentInChamber;
00821     if ( segShower.chi2() == -1 ) return segmentInChamber;
00822 
00823     segmentInChamber.push_back(segShower);
00824     return segmentInChamber;  
00825 
00826   } else{
00827         LogDebug("CSCSegment|CSC") <<"Number of rechits in the cluster/chamber > "<< UpperLimit<<
00828           " ... Segment finding in the cluster/chamber canceled!";
00829         //     std::cout<<"Number of rechits in the cluster/chamber > "<< UpperLimit<<
00830         //     " ... Segment finding in the cluster/chamber canceled! "<<std::endl;
00831         return segmentInChamber;  
00832         }
00833   }
00834 
00835   // Find out which station, ring and chamber we are in 
00836   // Used to choose station/ring dependant y-weight cuts
00837 
00838   if( rechits.size() > 0 ) {
00839     thering = rechits[0]->cscDetId().ring();
00840     thestation = rechits[0]->cscDetId().station();
00841     //thecham = rechits[0]->cscDetId().chamber();
00842   }
00843 
00844   // std::cout<<"We are in Station/ring/chamber: "<<thestation <<" "<< thering<<" "<< thecham<<std::endl;
00845 
00846   // Cut-off parameter - don't reconstruct segments with less than X hits
00847   if( n_layers_occupied_tot < minHitsPerSegment ) { 
00848     return segmentInChamber;
00849   }
00850   
00851   // Start building all possible hit combinations:
00852 
00853   // loop over the six chamber layers and form segment candidates from the available hits:
00854 
00855   for(int layer = 0; layer < 6; ++layer) {
00856 
00857     // *****************************************************************
00858     // *** Set missed layer counter here (not currently implemented) ***
00859     // *****************************************************************
00860     // if( PAhits_onLayer[layer].size() == 0 ) {
00861     //   n_layers_missed_tot += 1;
00862     // }
00863 
00864     if( PAhits_onLayer[layer].size() > 0 ) {
00865       n_layers_processed += 1;
00866     }
00867 
00868     // Save the size of the protosegment before hits were added on the current layer
00869     int orig_number_of_psegs = Psegments.size();
00870     int orig_number_of_noL1_psegs = Psegments_noL1.size();
00871     int orig_number_of_noL2_psegs = Psegments_noL2.size();
00872     int orig_number_of_noL3_psegs = Psegments_noL3.size();
00873     int orig_number_of_noL4_psegs = Psegments_noL4.size();
00874     int orig_number_of_noL5_psegs = Psegments_noL5.size();
00875     int orig_number_of_noL6_psegs = Psegments_noL6.size();
00876 
00877     // loop over the hits on the layer and initiate protosegments or add hits to protosegments
00878     for(int hit = 0; hit < int(PAhits_onLayer[layer].size()); ++hit) { // loop all hits on the Layer number "layer"
00879 
00880       // create protosegments from all hits on the first layer with hits
00881       if( orig_number_of_psegs == 0 ) { // would be faster to turn this around - ask for "orig_number_of_psegs != 0"
00882 
00883         Psegments_hits.push_back(PAhits_onLayer[layer][hit]);
00884 
00885         Psegments.push_back(Psegments_hits); 
00886         Psegments_noL6.push_back(Psegments_hits); 
00887         Psegments_noL5.push_back(Psegments_hits); 
00888         Psegments_noL4.push_back(Psegments_hits); 
00889         Psegments_noL3.push_back(Psegments_hits); 
00890         Psegments_noL2.push_back(Psegments_hits); 
00891 
00892         // Initialize weights corresponding to this segment for first hit (with 0)
00893 
00894         curv_A.push_back(0.0);
00895         curv_noL6_A.push_back(0.0); 
00896         curv_noL5_A.push_back(0.0); 
00897         curv_noL4_A.push_back(0.0); 
00898         curv_noL3_A.push_back(0.0); 
00899         curv_noL2_A.push_back(0.0); 
00900 
00901         weight_A.push_back(0.0);
00902         weight_noL6_A.push_back(0.0); 
00903         weight_noL5_A.push_back(0.0); 
00904         weight_noL4_A.push_back(0.0); 
00905         weight_noL3_A.push_back(0.0); 
00906         weight_noL2_A.push_back(0.0); 
00907 
00908         weight_B.push_back(0.0);
00909         weight_noL6_B.push_back(0.0); 
00910         weight_noL5_B.push_back(0.0); 
00911         weight_noL4_B.push_back(0.0); 
00912         weight_noL3_B.push_back(0.0); 
00913         weight_noL2_B.push_back(0.0); 
00914     
00915         // reset array for next hit on next layer
00916         Psegments_hits    .clear();
00917       }
00918       else {
00919         if( orig_number_of_noL1_psegs == 0 ) {
00920 
00921           Psegments_hits.push_back(PAhits_onLayer[layer][hit]);
00922 
00923           Psegments_noL1.push_back(Psegments_hits); 
00924 
00925           // Initialize weight corresponding to this segment for first hit (with 0)
00926 
00927           curv_noL1_A.push_back(0.0);
00928 
00929           weight_noL1_A.push_back(0.0);
00930 
00931           weight_noL1_B.push_back(0.0);
00932     
00933           // reset array for next hit on next layer
00934           Psegments_hits    .clear();
00935 
00936         }
00937 
00938         // loop over the protosegments and create a new protosegments for each hit-1 on this layer
00939         
00940         for( int pseg = 0; pseg < orig_number_of_psegs; ++pseg ) { 
00941 
00942           int pseg_pos = (pseg)+((hit)*orig_number_of_psegs);
00943           int pseg_noL1_pos = (pseg)+((hit)*orig_number_of_noL1_psegs);
00944           int pseg_noL2_pos = (pseg)+((hit)*orig_number_of_noL2_psegs);
00945           int pseg_noL3_pos = (pseg)+((hit)*orig_number_of_noL3_psegs);
00946           int pseg_noL4_pos = (pseg)+((hit)*orig_number_of_noL4_psegs);
00947           int pseg_noL5_pos = (pseg)+((hit)*orig_number_of_noL5_psegs);
00948           int pseg_noL6_pos = (pseg)+((hit)*orig_number_of_noL6_psegs);
00949 
00950           // - Loop all psegs. 
00951           // - If not last hit, clone  existing protosegments  (PAhits_onLayer[layer].size()-1) times
00952           // - then add the new hits
00953 
00954           if( ! (hit == int(PAhits_onLayer[layer].size()-1)) ) { // not the last hit - prepare (copy) new protosegments for the following hits
00955             // clone psegs (to add next hits or last hit on layer):
00956 
00957             Psegments.push_back(Psegments[ pseg_pos ]); 
00958             if (n_layers_processed != 2 && pseg < orig_number_of_noL1_psegs) Psegments_noL1.push_back(Psegments_noL1[ pseg_noL1_pos ]); 
00959             if (n_layers_processed != 2 && pseg < orig_number_of_noL2_psegs) Psegments_noL2.push_back(Psegments_noL2[ pseg_noL2_pos ]); 
00960             if (n_layers_processed != 3 && pseg < orig_number_of_noL3_psegs) Psegments_noL3.push_back(Psegments_noL3[ pseg_noL3_pos ]); 
00961             if (n_layers_processed != 4 && pseg < orig_number_of_noL4_psegs) Psegments_noL4.push_back(Psegments_noL4[ pseg_noL4_pos ]); 
00962             if (n_layers_processed != 5 && pseg < orig_number_of_noL5_psegs) Psegments_noL5.push_back(Psegments_noL5[ pseg_noL5_pos ]); 
00963             if (n_layers_processed != 6 && pseg < orig_number_of_noL6_psegs) Psegments_noL6.push_back(Psegments_noL6[ pseg_noL6_pos ]); 
00964             // clone weight corresponding to this segment too
00965             weight_A.push_back(weight_A[ pseg_pos ]);
00966             if (n_layers_processed != 2 && pseg < orig_number_of_noL1_psegs) weight_noL1_A.push_back(weight_noL1_A[ pseg_noL1_pos ]);
00967             if (n_layers_processed != 2 && pseg < orig_number_of_noL2_psegs) weight_noL2_A.push_back(weight_noL2_A[ pseg_noL2_pos ]);
00968             if (n_layers_processed != 3 && pseg < orig_number_of_noL3_psegs) weight_noL3_A.push_back(weight_noL3_A[ pseg_noL3_pos ]);
00969             if (n_layers_processed != 4 && pseg < orig_number_of_noL4_psegs) weight_noL4_A.push_back(weight_noL4_A[ pseg_noL4_pos ]);
00970             if (n_layers_processed != 5 && pseg < orig_number_of_noL5_psegs) weight_noL5_A.push_back(weight_noL5_A[ pseg_noL5_pos ]);
00971             if (n_layers_processed != 6 && pseg < orig_number_of_noL6_psegs) weight_noL6_A.push_back(weight_noL6_A[ pseg_noL6_pos ]);
00972             // clone curvature variable corresponding to this segment too
00973             curv_A.push_back(curv_A[ pseg_pos ]);
00974             if (n_layers_processed != 2 && pseg < orig_number_of_noL1_psegs) curv_noL1_A.push_back(curv_noL1_A[ pseg_noL1_pos ]);
00975             if (n_layers_processed != 2 && pseg < orig_number_of_noL2_psegs) curv_noL2_A.push_back(curv_noL2_A[ pseg_noL2_pos ]);
00976             if (n_layers_processed != 3 && pseg < orig_number_of_noL3_psegs) curv_noL3_A.push_back(curv_noL3_A[ pseg_noL3_pos ]);
00977             if (n_layers_processed != 4 && pseg < orig_number_of_noL4_psegs) curv_noL4_A.push_back(curv_noL4_A[ pseg_noL4_pos ]);
00978             if (n_layers_processed != 5 && pseg < orig_number_of_noL5_psegs) curv_noL5_A.push_back(curv_noL5_A[ pseg_noL5_pos ]);
00979             if (n_layers_processed != 6 && pseg < orig_number_of_noL6_psegs) curv_noL6_A.push_back(curv_noL6_A[ pseg_noL6_pos ]);
00980             // clone "y"-weight corresponding to this segment too
00981             weight_B.push_back(weight_B[ pseg_pos ]);
00982             if (n_layers_processed != 2 && pseg < orig_number_of_noL1_psegs) weight_noL1_B.push_back(weight_noL1_B[ pseg_noL1_pos ]);
00983             if (n_layers_processed != 2 && pseg < orig_number_of_noL2_psegs) weight_noL2_B.push_back(weight_noL2_B[ pseg_noL2_pos ]);
00984             if (n_layers_processed != 3 && pseg < orig_number_of_noL3_psegs) weight_noL3_B.push_back(weight_noL3_B[ pseg_noL3_pos ]);
00985             if (n_layers_processed != 4 && pseg < orig_number_of_noL4_psegs) weight_noL4_B.push_back(weight_noL4_B[ pseg_noL4_pos ]);
00986             if (n_layers_processed != 5 && pseg < orig_number_of_noL5_psegs) weight_noL5_B.push_back(weight_noL5_B[ pseg_noL5_pos ]);
00987             if (n_layers_processed != 6 && pseg < orig_number_of_noL6_psegs) weight_noL6_B.push_back(weight_noL6_B[ pseg_noL6_pos ]);
00988           }
00989           // add hits to original pseg:
00990           Psegments[ pseg_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00991           if (n_layers_processed != 2 && pseg < orig_number_of_noL1_psegs) Psegments_noL1[ pseg_noL1_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00992           if (n_layers_processed != 2 && pseg < orig_number_of_noL2_psegs) Psegments_noL2[ pseg_noL2_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00993           if (n_layers_processed != 3 && pseg < orig_number_of_noL3_psegs) Psegments_noL3[ pseg_noL3_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00994           if (n_layers_processed != 4 && pseg < orig_number_of_noL4_psegs) Psegments_noL4[ pseg_noL4_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00995           if (n_layers_processed != 5 && pseg < orig_number_of_noL5_psegs) Psegments_noL5[ pseg_noL5_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00996           if (n_layers_processed != 6 && pseg < orig_number_of_noL6_psegs) Psegments_noL6[ pseg_noL6_pos ].push_back(PAhits_onLayer[ layer ][ hit ]);
00997             
00998           // calculate/update the weight (only for >2 hits on psegment):
00999 
01000           if( Psegments[ pseg_pos ].size() > 2 ) {
01001               
01002             // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01003             // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01004 
01005             weight_A[ pseg_pos ] += theWeight(
01006                                               (*(Psegments[ pseg_pos ].end()-1 ))->localPosition().x(), 
01007                                               (*(Psegments[ pseg_pos ].end()-2 ))->localPosition().x(),
01008                                               (*(Psegments[ pseg_pos ].end()-3 ))->localPosition().x(),
01009                                               float((*(Psegments[ pseg_pos ].end()-1))->cscDetId().layer()),
01010                                               float((*(Psegments[ pseg_pos ].end()-2))->cscDetId().layer()),
01011                                               float((*(Psegments[ pseg_pos ].end()-3))->cscDetId().layer())
01012                                               );
01013 
01014             weight_B[ pseg_pos ] += theWeight(
01015                                               (*(Psegments[ pseg_pos ].end()-1 ))->localPosition().y(), 
01016                                               (*(Psegments[ pseg_pos ].end()-2 ))->localPosition().y(),
01017                                               (*(Psegments[ pseg_pos ].end()-3 ))->localPosition().y(),
01018                                               float((*(Psegments[ pseg_pos ].end()-1))->cscDetId().layer()),
01019                                               float((*(Psegments[ pseg_pos ].end()-2))->cscDetId().layer()),
01020                                               float((*(Psegments[ pseg_pos ].end()-3))->cscDetId().layer())
01021                                               );
01022 
01023             // if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01024 
01025             if(int(Psegments[ pseg_pos ].size()) == n_layers_occupied_tot) {
01026 
01027               curv_A[ pseg_pos ] += theWeight(
01028                                               (*(Psegments[ pseg_pos ].end()-1 ))->localPosition().x(), 
01029                                               (*(Psegments[ pseg_pos ].end()-midlayer_pointer[n_layers_occupied_tot-1] ))->localPosition().x(),
01030                                               (*(Psegments[ pseg_pos ].end()-n_layers_occupied_tot ))->localPosition().x(),
01031                                               float((*(Psegments[ pseg_pos ].end()-1))->cscDetId().layer()),
01032                                               float((*(Psegments[ pseg_pos ].end()-midlayer_pointer[n_layers_occupied_tot-1] ))->cscDetId().layer()),
01033                                               float((*(Psegments[ pseg_pos ].end()-n_layers_occupied_tot ))->cscDetId().layer())
01034                                               );
01035 
01036               if (curv_A[ pseg_pos ] > curvePenaltyThreshold) weight_A[ pseg_pos ] = weight_A[ pseg_pos ] * curvePenalty;
01037 
01038               if (weight_B[ pseg_pos ] > a_yweightPenaltyThreshold[thestation][thering]) weight_A[ pseg_pos ] = weight_A[ pseg_pos ] * yweightPenalty;
01039                
01040               if (weight_A[ pseg_pos ] < min_weight_A ) {
01041                 min_weight_A = weight_A[ pseg_pos ];
01042                 //best_weight_B = weight_B[ pseg_pos ];
01043                 //best_curv_A = curv_A[ pseg_pos ];
01044                 best_pseg = pseg_pos ;
01045               }
01046 
01047             }
01048 
01049             // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01050             // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01051 
01052           }
01053 
01054           if ( n_layers_occupied_tot > 3 ) {
01055             if (pseg < orig_number_of_noL1_psegs && (n_layers_processed != 2)) {
01056               if(( Psegments_noL1[ pseg_noL1_pos ].size() > 2 ) ) {
01057                 
01058                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01059                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01060                 
01061                 weight_noL1_A[ pseg_noL1_pos ] += theWeight(
01062                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-1 ))->localPosition().x(), 
01063                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-2 ))->localPosition().x(),
01064                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-3 ))->localPosition().x(),
01065                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-1))->cscDetId().layer()),
01066                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-2))->cscDetId().layer()),
01067                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-3))->cscDetId().layer())
01068                                                             );
01069 
01070                 weight_noL1_B[ pseg_noL1_pos ] += theWeight(
01071                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-1 ))->localPosition().y(), 
01072                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-2 ))->localPosition().y(),
01073                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-3 ))->localPosition().y(),
01074                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-1))->cscDetId().layer()),
01075                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-2))->cscDetId().layer()),
01076                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-3))->cscDetId().layer())
01077                                                             );
01078 
01079                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01080 
01081                 if(int(Psegments_noL1[ pseg_noL1_pos ].size()) == n_layers_occupied_tot -1 ) {
01082 
01083                   curv_noL1_A[ pseg_noL1_pos ] += theWeight(
01084                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-1 ))->localPosition().x(), 
01085                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01086                                                             (*(Psegments_noL1[ pseg_noL1_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01087                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-1 ))->cscDetId().layer()),
01088                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01089                                                             float((*(Psegments_noL1[ pseg_noL1_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01090                                                             );
01091 
01092                   if (curv_noL1_A[ pseg_noL1_pos ] > curvePenaltyThreshold) weight_noL1_A[ pseg_noL1_pos ] = weight_noL1_A[ pseg_noL1_pos ] * curvePenalty;
01093 
01094                   if (weight_noL1_B[ pseg_noL1_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01095                     weight_noL1_A[ pseg_noL1_pos ] = weight_noL1_A[ pseg_noL1_pos ] * yweightPenalty;
01096 
01097                   if (weight_noL1_A[ pseg_noL1_pos ] < min_weight_noLx_A ) {
01098                     min_weight_noLx_A = weight_noL1_A[ pseg_noL1_pos ];
01099                     //best_weight_noLx_B = weight_noL1_B[ pseg_noL1_pos ];
01100                     //best_curv_noLx_A = curv_noL1_A[ pseg_noL1_pos ];
01101                     best_noLx_pseg = pseg_noL1_pos;
01102                     best_Layer_noLx = 1;
01103                   }
01104 
01105                 }
01106 
01107                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01108                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01109                 
01110               }
01111             }
01112           }
01113 
01114           if ( n_layers_occupied_tot > 3 ) {
01115             if (pseg < orig_number_of_noL2_psegs && ( n_layers_processed != 2 )) {
01116               if(( Psegments_noL2[ pseg_noL2_pos ].size() > 2 )) {
01117               
01118                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01119                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01120 
01121                 weight_noL2_A[ pseg_noL2_pos ] += theWeight(
01122                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-1 ))->localPosition().x(), 
01123                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-2 ))->localPosition().x(),
01124                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-3 ))->localPosition().x(),
01125                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-1))->cscDetId().layer()),
01126                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-2))->cscDetId().layer()),
01127                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-3))->cscDetId().layer())
01128                                                             );
01129 
01130                 weight_noL2_B[ pseg_noL2_pos ] += theWeight(
01131                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-1 ))->localPosition().y(), 
01132                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-2 ))->localPosition().y(),
01133                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-3 ))->localPosition().y(),
01134                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-1))->cscDetId().layer()),
01135                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-2))->cscDetId().layer()),
01136                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-3))->cscDetId().layer())
01137                                                             );
01138 
01139                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01140 
01141                 if(int(Psegments_noL2[ pseg_noL2_pos ].size()) == n_layers_occupied_tot -1 ) {
01142 
01143                   curv_noL2_A[ pseg_noL2_pos ] += theWeight(
01144                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-1 ))->localPosition().x(), 
01145                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01146                                                             (*(Psegments_noL2[ pseg_noL2_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01147                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-1 ))->cscDetId().layer()),
01148                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01149                                                             float((*(Psegments_noL2[ pseg_noL2_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01150                                                             );
01151 
01152                   if (curv_noL2_A[ pseg_noL2_pos ] > curvePenaltyThreshold) weight_noL2_A[ pseg_noL2_pos ] = weight_noL2_A[ pseg_noL2_pos ] * curvePenalty;
01153 
01154                   if (weight_noL2_B[ pseg_noL2_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01155                     weight_noL2_A[ pseg_noL2_pos ] = weight_noL2_A[ pseg_noL2_pos ] * yweightPenalty;
01156 
01157                   if (weight_noL2_A[ pseg_noL2_pos ] < min_weight_noLx_A ) {
01158                     min_weight_noLx_A = weight_noL2_A[ pseg_noL2_pos ];
01159                     //best_weight_noLx_B = weight_noL2_B[ pseg_noL2_pos ];
01160                     //best_curv_noLx_A = curv_noL2_A[ pseg_noL2_pos ];
01161                     best_noLx_pseg = pseg_noL2_pos;
01162                     best_Layer_noLx = 2;
01163                   }
01164 
01165                 }
01166 
01167                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01168                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01169 
01170               }
01171             }
01172           }
01173 
01174           if ( n_layers_occupied_tot > 3 ) {
01175             if (pseg < orig_number_of_noL3_psegs && ( n_layers_processed != 3 )) {
01176               if(( Psegments_noL3[ pseg_noL3_pos ].size() > 2 )) {
01177               
01178                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01179                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01180 
01181                 weight_noL3_A[ pseg_noL3_pos ] += theWeight(
01182                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-1 ))->localPosition().x(), 
01183                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-2 ))->localPosition().x(),
01184                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-3 ))->localPosition().x(),
01185                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-1))->cscDetId().layer()),
01186                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-2))->cscDetId().layer()),
01187                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-3))->cscDetId().layer())
01188                                                             );
01189 
01190                 weight_noL3_B[ pseg_noL3_pos ] += theWeight(
01191                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-1 ))->localPosition().y(), 
01192                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-2 ))->localPosition().y(),
01193                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-3 ))->localPosition().y(),
01194                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-1))->cscDetId().layer()),
01195                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-2))->cscDetId().layer()),
01196                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-3))->cscDetId().layer())
01197                                                             );
01198 
01199                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01200 
01201                 if(int(Psegments_noL3[ pseg_noL3_pos ].size()) == n_layers_occupied_tot -1 ) {
01202 
01203                   curv_noL3_A[ pseg_noL3_pos ] += theWeight(
01204                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-1 ))->localPosition().x(), 
01205                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01206                                                             (*(Psegments_noL3[ pseg_noL3_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01207                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-1 ))->cscDetId().layer()),
01208                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01209                                                             float((*(Psegments_noL3[ pseg_noL3_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01210                                                             );
01211 
01212                   if (curv_noL3_A[ pseg_noL3_pos ] > curvePenaltyThreshold) weight_noL3_A[ pseg_noL3_pos ] = weight_noL3_A[ pseg_noL3_pos ] * curvePenalty;
01213 
01214                   if (weight_noL3_B[ pseg_noL3_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01215                     weight_noL3_A[ pseg_noL3_pos ] = weight_noL3_A[ pseg_noL3_pos ] * yweightPenalty;
01216 
01217                   if (weight_noL3_A[ pseg_noL3_pos ] < min_weight_noLx_A ) {
01218                     min_weight_noLx_A = weight_noL3_A[ pseg_noL3_pos ];
01219                     //best_weight_noLx_B = weight_noL3_B[ pseg_noL3_pos ];
01220                     //best_curv_noLx_A = curv_noL3_A[ pseg_noL3_pos ];
01221                     best_noLx_pseg = pseg_noL3_pos;
01222                     best_Layer_noLx = 3;
01223                   }
01224 
01225                 }
01226 
01227                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01228                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01229 
01230               }
01231             }
01232           }
01233 
01234           if ( n_layers_occupied_tot > 3 ) {
01235             if (pseg < orig_number_of_noL4_psegs && ( n_layers_processed != 4 )) {
01236               if(( Psegments_noL4[ pseg_noL4_pos ].size() > 2 )) {
01237               
01238                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01239                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01240               
01241                 weight_noL4_A[ pseg_noL4_pos ] += theWeight(
01242                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-1 ))->localPosition().x(), 
01243                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-2 ))->localPosition().x(),
01244                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-3 ))->localPosition().x(),
01245                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-1))->cscDetId().layer()),
01246                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-2))->cscDetId().layer()),
01247                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-3))->cscDetId().layer())
01248                                                             );
01249 
01250                 weight_noL4_B[ pseg_noL4_pos ] += theWeight(
01251                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-1 ))->localPosition().y(), 
01252                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-2 ))->localPosition().y(),
01253                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-3 ))->localPosition().y(),
01254                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-1))->cscDetId().layer()),
01255                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-2))->cscDetId().layer()),
01256                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-3))->cscDetId().layer())
01257                                                             );
01258 
01259                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01260 
01261                 if(int(Psegments_noL4[ pseg_noL4_pos ].size()) == n_layers_occupied_tot -1 ) {
01262 
01263                   curv_noL4_A[ pseg_noL4_pos ] += theWeight(
01264                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-1 ))->localPosition().x(), 
01265                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01266                                                             (*(Psegments_noL4[ pseg_noL4_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01267                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-1 ))->cscDetId().layer()),
01268                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01269                                                             float((*(Psegments_noL4[ pseg_noL4_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01270                                                             );
01271 
01272                   if (curv_noL4_A[ pseg_noL4_pos ] > curvePenaltyThreshold) weight_noL4_A[ pseg_noL4_pos ] = weight_noL4_A[ pseg_noL4_pos ] * curvePenalty;
01273 
01274                   if (weight_noL4_B[ pseg_noL4_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01275                     weight_noL4_A[ pseg_noL4_pos ] = weight_noL4_A[ pseg_noL4_pos ] * yweightPenalty;
01276 
01277                   if (weight_noL4_A[ pseg_noL4_pos ] < min_weight_noLx_A ) {
01278                     min_weight_noLx_A = weight_noL4_A[ pseg_noL4_pos ];
01279                     //best_weight_noLx_B = weight_noL4_B[ pseg_noL4_pos ];
01280                     //best_curv_noLx_A = curv_noL4_A[ pseg_noL4_pos ];
01281                     best_noLx_pseg = pseg_noL4_pos;
01282                     best_Layer_noLx = 4;
01283                   }
01284 
01285                 }
01286 
01287                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01288                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01289 
01290               }
01291             }
01292           }
01293 
01294           if ( n_layers_occupied_tot > 4 ) {
01295             if (pseg < orig_number_of_noL5_psegs && ( n_layers_processed != 5 )) {
01296               if(( Psegments_noL5[ pseg_noL5_pos ].size() > 2 )){
01297               
01298                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01299                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01300 
01301                 weight_noL5_A[ pseg_noL5_pos ] += theWeight(
01302                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-1 ))->localPosition().x(), 
01303                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-2 ))->localPosition().x(),
01304                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-3 ))->localPosition().x(),
01305                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-1))->cscDetId().layer()),
01306                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-2))->cscDetId().layer()),
01307                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-3))->cscDetId().layer())
01308                                                             );
01309 
01310                 weight_noL5_B[ pseg_noL5_pos ] += theWeight(
01311                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-1 ))->localPosition().y(), 
01312                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-2 ))->localPosition().y(),
01313                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-3 ))->localPosition().y(),
01314                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-1))->cscDetId().layer()),
01315                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-2))->cscDetId().layer()),
01316                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-3))->cscDetId().layer())
01317                                                             );
01318 
01319                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01320 
01321                 if(int(Psegments_noL5[ pseg_noL5_pos ].size()) == n_layers_occupied_tot -1 ) {
01322 
01323                   curv_noL5_A[ pseg_noL5_pos ] += theWeight(
01324                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-1 ))->localPosition().x(), 
01325                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01326                                                             (*(Psegments_noL5[ pseg_noL5_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01327                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-1 ))->cscDetId().layer()),
01328                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01329                                                             float((*(Psegments_noL5[ pseg_noL5_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01330                                                             );
01331 
01332                   if (curv_noL5_A[ pseg_noL5_pos ] > curvePenaltyThreshold) weight_noL5_A[ pseg_noL5_pos ] = weight_noL5_A[ pseg_noL5_pos ] * curvePenalty;
01333 
01334                   if (weight_noL5_B[ pseg_noL5_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01335                     weight_noL5_A[ pseg_noL5_pos ] = weight_noL5_A[ pseg_noL5_pos ] * yweightPenalty;
01336 
01337                   if (weight_noL5_A[ pseg_noL5_pos ] < min_weight_noLx_A ) {
01338                     min_weight_noLx_A = weight_noL5_A[ pseg_noL5_pos ];
01339                     //best_weight_noLx_B = weight_noL5_B[ pseg_noL5_pos ];
01340                     //best_curv_noLx_A = curv_noL5_A[ pseg_noL5_pos ];
01341                     best_noLx_pseg = pseg_noL5_pos;
01342                     best_Layer_noLx = 5;
01343                   }
01344 
01345                 }
01346 
01347                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01348                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01349 
01350               }
01351             }
01352           }
01353 
01354           if ( n_layers_occupied_tot > 5 ) {
01355             if (pseg < orig_number_of_noL6_psegs && ( n_layers_processed != 6 )) {
01356               if(( Psegments_noL6[ pseg_noL6_pos ].size() > 2 )){
01357               
01358                 // looks more exciting than it is. Here the weight is calculated. It is the difference in x of the last two and one but the last two hits, 
01359                 // divided by the distance of the corresponding hits. Please refer to twiki page XXXX or CMS Note YYY (and use layer_distance)
01360 
01361                 weight_noL6_A[ pseg_noL6_pos ] += theWeight(
01362                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-1 ))->localPosition().x(), 
01363                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-2 ))->localPosition().x(),
01364                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-3 ))->localPosition().x(),
01365                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-1))->cscDetId().layer()),
01366                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-2))->cscDetId().layer()),
01367                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-3))->cscDetId().layer())
01368                                                             );
01369 
01370                 weight_noL6_B[ pseg_noL6_pos ] += theWeight(
01371                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-1 ))->localPosition().y(), 
01372                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-2 ))->localPosition().y(),
01373                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-3 ))->localPosition().y(),
01374                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-1))->cscDetId().layer()),
01375                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-2))->cscDetId().layer()),
01376                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-3))->cscDetId().layer())
01377                                                             );
01378 
01379                 //if we have picked up the last hit go looking for pseg with the lowest (and second lowest?) weight
01380 
01381                 if(int(Psegments_noL6[ pseg_noL6_pos ].size()) == n_layers_occupied_tot -1 ) {
01382 
01383                   curv_noL6_A[ pseg_noL6_pos ] += theWeight(
01384                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-1 ))->localPosition().x(), 
01385                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->localPosition().x(),
01386                                                             (*(Psegments_noL6[ pseg_noL6_pos ].end()-(n_layers_occupied_tot-1) ))->localPosition().x(),
01387                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-1 ))->cscDetId().layer()),
01388                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-midlayer_pointer[n_layers_occupied_tot-2] ))->cscDetId().layer()),
01389                                                             float((*(Psegments_noL6[ pseg_noL6_pos ].end()-(n_layers_occupied_tot-1) ))->cscDetId().layer())
01390                                                             );
01391 
01392                   if (curv_noL6_A[ pseg_noL6_pos ] > curvePenaltyThreshold) weight_noL6_A[ pseg_noL6_pos ] = weight_noL6_A[ pseg_noL6_pos ] * curvePenalty;
01393 
01394                   if (weight_noL6_B[ pseg_noL6_pos ] > a_yweightPenaltyThreshold[thestation][thering]) 
01395                     weight_noL6_A[ pseg_noL6_pos ] = weight_noL6_A[ pseg_noL6_pos ] * yweightPenalty;
01396 
01397                   if (weight_noL6_A[ pseg_noL6_pos ] < min_weight_noLx_A ) {
01398                     min_weight_noLx_A = weight_noL6_A[ pseg_noL6_pos ];
01399                     //best_weight_noLx_B = weight_noL6_B[ pseg_noL6_pos ];
01400                     //best_curv_noLx_A = curv_noL6_A[ pseg_noL6_pos ];
01401                     best_noLx_pseg = pseg_noL6_pos;
01402                     best_Layer_noLx = 6;
01403                   }
01404 
01405                 }
01406 
01407                 // alternative: fill map with weight and pseg (which is already ordered)? Seems a very good tool to go looking for segments from. 
01408                 // As I understand, the segments would be inserted according to their weight, so the list would "automatically" be sorted.
01409 
01410               }
01411             }
01412           }
01413 
01414         }
01415       }
01416     }
01417   }
01418 
01419   //************************************************************************;    
01420   //***   End segment building   *******************************************;    
01421   //************************************************************************;    
01422 
01423   // Important part! Here segment(s) are actually chosen. All the good segments
01424   // could be chosen or some (best) ones only (in order to save time).
01425 
01426   // Check if there is a segment with n-1 hits that has a signifcantly better 
01427   // weight than the best n hit segment
01428 
01429   // IBL 070828: implicit assumption here is that there will always only be one segment per 
01430   // cluster - if there are >1 we will need to find out which segment the alternative n-1 hit 
01431   // protosegment belongs to!
01432 
01433 
01434   //float chosen_weight = min_weight_A;
01435   //float chosen_ywgt = best_weight_B;
01436   //float chosen_curv = best_curv_A;
01437   //int chosen_nlayers = n_layers_occupied_tot;
01438   int chosen_pseg = best_pseg;
01439   if (best_pseg<0) { 
01440     return segmentInChamber; 
01441   }
01442   chosen_Psegments = (Psegments);
01443   chosen_weight_A = (weight_A);
01444 
01445   float hit_drop_limit = -999999.999;
01446 
01447   // define different weight improvement requirements depending on how many layers are in the segment candidate
01448   switch ( n_layers_processed ) {
01449   case 1 : 
01450     // do nothing;
01451     break;
01452   case 2 :
01453     // do nothing;
01454     break;
01455   case 3 : 
01456     // do nothing;
01457     break;
01458   case 4 : 
01459     hit_drop_limit =  hitDropLimit6Hits * (1./2.) * hitDropLimit4Hits;
01460     if ((best_Layer_noLx < 1) || (best_Layer_noLx > 4)) {
01461       //      std::cout<<"CSCSegAlgoST: For four layers, best_Layer_noLx = "<< best_Layer_noLx << std::endl;
01462     }
01463     if ((best_Layer_noLx == 2) || (best_Layer_noLx == 3)) hit_drop_limit = hit_drop_limit * (1./2.); 
01464     break;
01465   case 5 : 
01466     hit_drop_limit =  hitDropLimit6Hits * (2./3.) * hitDropLimit5Hits;
01467     if ((best_Layer_noLx < 1) || (best_Layer_noLx > 5)) {
01468       //      std::cout<<"CSCSegAlgoST: For five layers, best_Layer_noLx = "<< best_Layer_noLx << std::endl;
01469     }
01470     if ((best_Layer_noLx == 2) || (best_Layer_noLx == 4)) hit_drop_limit = hit_drop_limit * (1./2.); 
01471     if (best_Layer_noLx == 3) hit_drop_limit = hit_drop_limit * (1./3.); 
01472     break;
01473   case 6 : 
01474     hit_drop_limit =  hitDropLimit6Hits * (3./4.);
01475     if ((best_Layer_noLx < 1) || (best_Layer_noLx > 6)) {
01476       //      std::cout<<"CSCSegAlgoST: For six layers, best_Layer_noLx = "<< best_Layer_noLx << std::endl;
01477     }
01478     if ((best_Layer_noLx == 2) || (best_Layer_noLx == 5)) hit_drop_limit = hit_drop_limit * (1./2.); 
01479     if ((best_Layer_noLx == 3) || (best_Layer_noLx == 4)) hit_drop_limit = hit_drop_limit * (1./3.); 
01480     break;
01481     
01482   default : 
01483     // Fallback - should never occur.
01484     LogDebug("CSCSegment|CSC") <<"CSCSegAlgoST: Unexpected number of layers with hits - please inform developers.";
01485     //     std::cout<<"CSCSegAlgoST: Unexpected number of layers with hits - please inform developers."<<std::endl;
01486     hit_drop_limit = 0.1;
01487   }
01488 
01489   // choose the NoLx collection (the one that contains the best N-1 candidate)
01490   switch ( best_Layer_noLx ) {
01491   case 1 : 
01492     Psegments_noLx.clear();
01493     Psegments_noLx = Psegments_noL1;
01494     weight_noLx_A.clear();
01495     weight_noLx_A = weight_noL1_A;
01496     break;
01497   case 2 :
01498     Psegments_noLx.clear();
01499     Psegments_noLx = Psegments_noL2;
01500     weight_noLx_A.clear();
01501     weight_noLx_A = weight_noL2_A;
01502     break;
01503   case 3 : 
01504     Psegments_noLx.clear();
01505     Psegments_noLx = Psegments_noL3;
01506     weight_noLx_A.clear();
01507     weight_noLx_A = weight_noL3_A;
01508     break;
01509   case 4 : 
01510     Psegments_noLx.clear();
01511     Psegments_noLx = Psegments_noL4;
01512     weight_noLx_A.clear();
01513     weight_noLx_A = weight_noL4_A;
01514     break;
01515   case 5 : 
01516     Psegments_noLx.clear();
01517     Psegments_noLx = Psegments_noL5;
01518     weight_noLx_A.clear();
01519     weight_noLx_A = weight_noL5_A;
01520     break;
01521   case 6 : 
01522     Psegments_noLx.clear();
01523     Psegments_noLx = Psegments_noL6;
01524     weight_noLx_A.clear();
01525     weight_noLx_A = weight_noL6_A;
01526     break;
01527     
01528   default : 
01529     // Fallback - should occur only for preclusters with only 3 layers with hits.
01530     Psegments_noLx.clear();
01531     weight_noLx_A.clear();
01532   }
01533   
01534   if( min_weight_A > 0. ) {
01535     if ( min_weight_noLx_A/min_weight_A < hit_drop_limit ) {
01536       //chosen_weight = min_weight_noLx_A;
01537       //chosen_ywgt = best_weight_noLx_B;
01538       //chosen_curv = best_curv_noLx_A;
01539       //chosen_nlayers = n_layers_occupied_tot-1;
01540       chosen_pseg = best_noLx_pseg;
01541       chosen_Psegments.clear();
01542       chosen_weight_A.clear();
01543       chosen_Psegments = (Psegments_noLx);
01544       chosen_weight_A = (weight_noLx_A);
01545     }
01546   }
01547 
01548   if(onlyBestSegment) {
01549     ChooseSegments2a( chosen_Psegments, chosen_pseg );
01550   }
01551   else {
01552     ChooseSegments3( chosen_Psegments, chosen_weight_A, chosen_pseg ); 
01553   }
01554 
01555   for(unsigned int iSegment=0; iSegment<GoodSegments.size();++iSegment){
01556     protoSegment = GoodSegments[iSegment];
01557     passCondNumber=false;
01558     passCondNumber_2 = false;
01559     protoChiUCorrection=1.0;
01560     doSlopesAndChi2();
01561     // Attempt to handle numerical instability of the fit;
01562     // Any segment with protoChi2/protoNDF>chi2Norm_3D_
01563     // considered as that one potentially suffering from
01564     // numerical instability in fit.
01565     if(correctCov_){
01566     // Call the fit with prefitting option;
01567     // First fit a straight line to X-Z coordinates
01568     // and calculate chi^2 (chiUZ in correctTheCovX(void)) for X-Z fit;
01569     // Scale up errors in X if chiUZ too big (default 20);
01570     // Refit XY-Z with the scaled up X errors 
01571       if(protoChi2/protoNDF>chi2Norm_3D_){
01572         passCondNumber = true;
01573         doSlopesAndChi2();
01574       }
01575       if(protoChiUCorrection<1.00005){
01576         LogDebug("CSCSegment|segmWierd") << "Wierd segment, ErrXX scaled, refit " <<std::endl;
01577         if(protoChi2/protoNDF>chi2Norm_3D_){
01578      // Call the fit with direct adjustment of condition number;
01579      // If the attempt to improve fit by scaling up X error fails
01580      // call the procedure to make the condition number of M compatible with
01581      // the precision of X and Y measurements;
01582      // Achieved by decreasing abs value of the Covariance
01583           LogDebug("CSCSegment|segmWierd") << "Wierd segment, ErrXY changed to match cond. number, refit  " << std::endl;
01584           passCondNumber_2=true;
01585           doSlopesAndChi2();
01586         }
01587       }
01588       // Call the pre-pruning procedure;
01589       // If the attempt to improve fit by scaling up X error is successfull,
01590       // while scale factor for X errors is too big.
01591       // Prune the recHit inducing the biggest contribution into X-Z chi^2
01592       // and refit;
01593       if(prePrun_ && (sqrt(protoChiUCorrection)>prePrunLimit_) &&
01594          (protoSegment.size()>3)){   
01595         LogDebug("CSCSegment|segmWierd") << "Scale factor protoChiUCorrection too big, pre-Prune, refit  " << std::endl;
01596         protoSegment.erase(protoSegment.begin()+(maxContrIndex),
01597                            protoSegment.begin()+(maxContrIndex+1));                 
01598         doSlopesAndChi2();
01599       }
01600     }
01601 
01602     fillLocalDirection();
01603     // calculate error matrix
01604     AlgebraicSymMatrix protoErrors = calculateError();   
01605     // but reorder components to match what's required by TrackingRecHit interface 
01606     // i.e. slopes first, then positions 
01607     flipErrors( protoErrors ); 
01608     //
01609     CSCSegment temp(protoSegment, protoIntercept, protoDirection, protoErrors, protoChi2);
01610 
01611     LogTrace("CSCSegAlgoST") << "[CSCSegAlgoST::buildSegments] protosegment\n " << temp;
01612 
01613     segmentInChamber.push_back(temp); 
01614   }
01615   return segmentInChamber;
01616 }
01617 
01618 void CSCSegAlgoST::ChooseSegments2a(std::vector< ChamberHitContainer > & chosen_segments, int chosen_seg) {
01619   // just return best segment
01620   GoodSegments.clear();
01621   GoodSegments.push_back( chosen_segments[chosen_seg] );
01622 }
01623 
01624 void CSCSegAlgoST::ChooseSegments3(std::vector< ChamberHitContainer > & chosen_segments, std::vector< float > & chosen_weight, int chosen_seg) {
01625 
01626   int SumCommonHits = 0;
01627   GoodSegments.clear();
01628   int nr_remaining_candidates;
01629   unsigned int nr_of_segment_candidates;
01630   
01631   nr_remaining_candidates = nr_of_segment_candidates = chosen_segments.size();
01632 
01633   // always select and return best protosegment:  
01634   GoodSegments.push_back( chosen_segments[ chosen_seg ] );
01635 
01636   float chosen_weight_temp = 999999.;
01637   int chosen_seg_temp = -1;
01638 
01639   // try to find further segment candidates:
01640   while( nr_remaining_candidates > 0 ) {
01641 
01642     for(unsigned int iCand=0; iCand < nr_of_segment_candidates; ++iCand) {
01643       //only compare current best to psegs that have not been marked bad:
01644       if( chosen_weight[iCand] < 0. ) continue;
01645       SumCommonHits = 0;
01646 
01647       for( int ihits = 0; ihits < int(chosen_segments[iCand].size()); ++ihits ) { // iCand and iiCand NEED to have same nr of hits! (always have by construction)
01648         if( chosen_segments[iCand][ihits] == chosen_segments[chosen_seg][ihits]) {
01649           ++SumCommonHits;
01650         }
01651       }
01652 
01653       //mark a pseg bad:
01654       if(SumCommonHits>1) { // needs to be a card; should be investigated first
01655         chosen_weight[iCand] = -1.;
01656         nr_remaining_candidates -= 1;
01657       }
01658       else {
01659         // save the protosegment with the smallest weight
01660         if( chosen_weight[ iCand ] < chosen_weight_temp ) {
01661           chosen_weight_temp = chosen_weight[ iCand ];
01662           chosen_seg_temp = iCand ;
01663         }
01664       }
01665     }
01666 
01667     if( chosen_seg_temp > -1 ) GoodSegments.push_back( chosen_segments[ chosen_seg_temp ] );
01668 
01669     chosen_seg = chosen_seg_temp;
01670     // re-initialze temporary best parameters
01671     chosen_weight_temp = 999999;
01672     chosen_seg_temp = -1;
01673   }
01674 }
01675 
01676 void CSCSegAlgoST::ChooseSegments2(int best_seg) {
01677   //  std::vector <int> CommonHits(6); // nice  concept :)
01678   std::vector <unsigned int> BadCandidate;
01679   int SumCommonHits =0;
01680   GoodSegments.clear();
01681   BadCandidate.clear();
01682   for(unsigned int iCand=0;iCand<Psegments.size();++iCand) {
01683     // skip here if segment was marked bad
01684     for(unsigned int iiCand=iCand+1;iiCand<Psegments.size();++iiCand){
01685       // skip here too if segment was marked bad
01686       SumCommonHits =0;
01687       if( Psegments[iCand].size() != Psegments[iiCand].size() ) {
01688         LogDebug("CSCSegment|CSC") <<"CSCSegmentST::ChooseSegments2: ALARM!! THIS should not happen!!";
01689 //      std::cout<<"CSCSegmentST::ChooseSegments2: ALARM!! THIS should not happen!!"<<std::endl;
01690       }
01691       else {
01692         for( int ihits = 0; ihits < int(Psegments[iCand].size()); ++ihits ) { // iCand and iiCand NEED to have same nr of hits! (alsways have by construction)
01693           if( Psegments[iCand][ihits] == Psegments[iiCand][ihits]) {
01694             ++SumCommonHits;
01695           }
01696         }
01697       }
01698       if(SumCommonHits>1) {
01699         if( weight_A[iCand]>weight_A[iiCand] ) { // use weight_A here
01700           BadCandidate.push_back(iCand);
01701           // rather mark segment bad by an array which is in sync with protosegments!! e.g. set weight = weight*1000 or have an addidional array or set it to weight *= -1
01702         }
01703         else{
01704           BadCandidate.push_back(iiCand);
01705           // rather mark segment bad by an array which is in sync with protosegments!! e.g. set weight = weight*1000 or have an addidional array or set it to weight *= -1
01706         }
01707       }
01708     }
01709   }
01710   bool discard;
01711   for(unsigned int isegm=0;isegm<Psegments.size();++isegm) {
01712     // For best results another iteration/comparison over Psegments 
01713     //should be applied here... It would make the program much slower.
01714     discard = false;
01715     for(unsigned int ibad=0;ibad<BadCandidate.size();++ibad) {
01716       // can save this loop if we used an array in sync with Psegments!!!!
01717       if(isegm == BadCandidate[ibad]) {
01718         discard = true;
01719       }
01720     }
01721     if(!discard) {
01722       GoodSegments.push_back( Psegments[isegm] );
01723     }
01724   }
01725 }
01726 //Method doSlopesAndChi2
01727 // fitSlopes() and  fillChiSquared() are always called one after the other 
01728 // In fact the code is duplicated in the two functions (as we need 2 loops) - 
01729 // it is much better to fix that at some point 
01730 void CSCSegAlgoST::doSlopesAndChi2(){
01731   fitSlopes();
01732   fillChiSquared();
01733 }
01734 /* Method fitSlopes
01735  *
01736  * Perform a Least Square Fit on a segment as per SK algo
01737  *
01738  */
01739 void CSCSegAlgoST::fitSlopes() {
01740   e_Cxx.clear(); 
01741   if(passCondNumber && !passCondNumber_2){
01742     correctTheCovX();
01743     if(e_Cxx.size()!=protoSegment.size()){
01744       LogDebug("CSCSegment|segmWierd") << "e_Cxx.size()!=protoSegment.size() IT IS A SERIOUS PROBLEM!!! " <<std::endl;
01745     }
01746   }
01747   CLHEP::HepMatrix M(4,4,0);
01748   CLHEP::HepVector B(4,0);
01749   ChamberHitContainer::const_iterator ih = protoSegment.begin();
01750   for (ih = protoSegment.begin(); ih != protoSegment.end(); ++ih) {
01751     const CSCRecHit2D& hit = (**ih);
01752     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
01753     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
01754     LocalPoint  lp         = theChamber->toLocal(gp); 
01755     // ptc: Local position of hit w.r.t. chamber
01756     double u = lp.x();
01757     double v = lp.y();
01758     double z = lp.z();
01759     // ptc: Covariance matrix of local errors 
01760     CLHEP::HepMatrix IC(2,2);
01761     if(passCondNumber&& !passCondNumber_2){
01762       IC(1,1) = e_Cxx.at(ih-protoSegment.begin());
01763     }
01764     else{
01765       IC(1,1) = hit.localPositionError().xx();
01766     }
01767     //    IC(1,1) = hit.localPositionError().xx();
01768     IC(1,2) = hit.localPositionError().xy();
01769     IC(2,2) = hit.localPositionError().yy();
01770     IC(2,1) = IC(1,2); // since Cov is symmetric
01772     if(passCondNumber_2){
01773       correctTheCovMatrix(IC);
01774     }
01775     // ptc: Invert covariance matrix (and trap if it fails!)
01776     int ierr = 0;
01777     IC.invert(ierr); // inverts in place
01778     if (ierr != 0) {
01779       LogDebug("CSCSegment|CSC") << "CSCSegment::fitSlopes: failed to invert covariance matrix=\n" << IC;      
01780       //       std::cout<< "CSCSegment::fitSlopes: failed to invert covariance matrix=\n" << IC << "\n"<<std::endl;
01781     }
01782     
01783     M(1,1) += IC(1,1);
01784     M(1,2) += IC(1,2);
01785     M(1,3) += IC(1,1) * z;
01786     M(1,4) += IC(1,2) * z;
01787     B(1)   += u * IC(1,1) + v * IC(1,2);
01788     
01789     M(2,1) += IC(2,1);
01790     M(2,2) += IC(2,2);
01791     M(2,3) += IC(2,1) * z;
01792     M(2,4) += IC(2,2) * z;
01793     B(2)   += u * IC(2,1) + v * IC(2,2);
01794     
01795     M(3,1) += IC(1,1) * z;
01796     M(3,2) += IC(1,2) * z;
01797     M(3,3) += IC(1,1) * z * z;
01798     M(3,4) += IC(1,2) * z * z;
01799     B(3)   += ( u * IC(1,1) + v * IC(1,2) ) * z;
01800     
01801     M(4,1) += IC(2,1) * z;
01802     M(4,2) += IC(2,2) * z;
01803     M(4,3) += IC(2,1) * z * z;
01804     M(4,4) += IC(2,2) * z * z;
01805     B(4)   += ( u * IC(2,1) + v * IC(2,2) ) * z;
01806   }
01807   CLHEP::HepVector p = solve(M, B);
01808   
01809   // Update member variables 
01810   // Note that origin has local z = 0
01811   protoIntercept = LocalPoint(p(1), p(2), 0.);
01812   protoSlope_u = p(3);
01813   protoSlope_v = p(4);
01814 }
01815 /* Method fillChiSquared
01816  *
01817  * Determine Chi^2 for the proto wire segment
01818  *
01819  */
01820 void CSCSegAlgoST::fillChiSquared() {
01821   
01822   double chsq = 0.;
01823   
01824   ChamberHitContainer::const_iterator ih;
01825   for (ih = protoSegment.begin(); ih != protoSegment.end(); ++ih) {
01826     
01827     const CSCRecHit2D& hit = (**ih);
01828     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
01829     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
01830     LocalPoint lp          = theChamber->toLocal(gp);
01831     
01832     double u = lp.x();
01833     double v = lp.y();
01834     double z = lp.z();
01835     
01836     double du = protoIntercept.x() + protoSlope_u * z - u;
01837     double dv = protoIntercept.y() + protoSlope_v * z - v;
01838     
01839     CLHEP::HepMatrix IC(2,2);
01840     if(passCondNumber&& !passCondNumber_2){
01841       IC(1,1) = e_Cxx.at(ih-protoSegment.begin());
01842     }
01843     else{
01844       IC(1,1) = hit.localPositionError().xx();
01845     }
01846     //    IC(1,1) = hit.localPositionError().xx();
01847     IC(1,2) = hit.localPositionError().xy();
01848     IC(2,2) = hit.localPositionError().yy();
01849     IC(2,1) = IC(1,2);
01851     if(passCondNumber_2){
01852       correctTheCovMatrix(IC);
01853     }
01854     
01855     // Invert covariance matrix
01856     int ierr = 0;
01857     IC.invert(ierr);
01858     if (ierr != 0) {
01859       LogDebug("CSCSegment|CSC") << "CSCSegment::fillChiSquared: failed to invert covariance matrix=\n" << IC;
01860       //       std::cout << "CSCSegment::fillChiSquared: failed to invert covariance matrix=\n" << IC << "\n";
01861       
01862     }
01863     
01864     chsq += du*du*IC(1,1) + 2.*du*dv*IC(1,2) + dv*dv*IC(2,2);
01865   }
01866 
01867   protoChi2 = chsq;
01868   protoNDF = 2.*protoSegment.size() - 4;
01869 }
01870 /* fillLocalDirection
01871  *
01872  */
01873 void CSCSegAlgoST::fillLocalDirection() {
01874   // Always enforce direction of segment to point from IP outwards
01875   // (Incorrect for particles not coming from IP, of course.)
01876   
01877   double dxdz = protoSlope_u;
01878   double dydz = protoSlope_v;
01879   double dz   = 1./sqrt(1. + dxdz*dxdz + dydz*dydz);
01880   double dx   = dz*dxdz;
01881   double dy   = dz*dydz;
01882   LocalVector localDir(dx,dy,dz);
01883   
01884   // localDir may need sign flip to ensure it points outward from IP
01885   // ptc: Examine its direction and origin in global z: to point outward
01886   // the localDir should always have same sign as global z...
01887   
01888   double globalZpos    = ( theChamber->toGlobal( protoIntercept ) ).z();
01889   double globalZdir    = ( theChamber->toGlobal( localDir ) ).z();
01890   double directionSign = globalZpos * globalZdir;
01891   protoDirection       = (directionSign * localDir).unit();
01892 }
01893 /* weightMatrix
01894  *   
01895  */
01896 AlgebraicSymMatrix CSCSegAlgoST::weightMatrix() const {
01897   
01898   std::vector<const CSCRecHit2D*>::const_iterator it;
01899   int nhits = protoSegment.size();
01900   AlgebraicSymMatrix matrix(2*nhits, 0);
01901   int row = 0;
01902   
01903   for (it = protoSegment.begin(); it != protoSegment.end(); ++it) {
01904     
01905     const CSCRecHit2D& hit = (**it);
01906     ++row;
01907     matrix(row, row)   = protoChiUCorrection*hit.localPositionError().xx();
01908     matrix(row, row+1) = hit.localPositionError().xy();
01909     ++row;
01910     matrix(row, row-1) = hit.localPositionError().xy();
01911     matrix(row, row)   = hit.localPositionError().yy();
01912   }
01913   int ierr;
01914   matrix.invert(ierr);
01915   return matrix;
01916 }
01917 
01918 
01919 /* derivativeMatrix
01920  *
01921  */
01922 CLHEP::HepMatrix CSCSegAlgoST::derivativeMatrix() const {
01923   
01924   ChamberHitContainer::const_iterator it;
01925   int nhits = protoSegment.size();
01926   CLHEP::HepMatrix matrix(2*nhits, 4);
01927   int row = 0;
01928   
01929   for(it = protoSegment.begin(); it != protoSegment.end(); ++it) {
01930     
01931     const CSCRecHit2D& hit = (**it);
01932     const CSCLayer* layer = theChamber->layer(hit.cscDetId().layer());
01933     GlobalPoint gp = layer->toGlobal(hit.localPosition());      
01934     LocalPoint lp = theChamber->toLocal(gp); 
01935     float z = lp.z();
01936     ++row;
01937     matrix(row, 1) = 1.;
01938     matrix(row, 3) = z;
01939     ++row;
01940     matrix(row, 2) = 1.;
01941     matrix(row, 4) = z;
01942   }
01943   return matrix;
01944 }
01945 
01946 
01947 /* calculateError
01948  *
01949  */
01950 AlgebraicSymMatrix CSCSegAlgoST::calculateError() const {
01951   
01952   AlgebraicSymMatrix weights = weightMatrix();
01953   AlgebraicMatrix A = derivativeMatrix();
01954   
01955   // (AT W A)^-1
01956   // from https://www.phys.ufl.edu/~avery/fitting.html, part I
01957   int ierr;
01958   AlgebraicSymMatrix result = weights.similarityT(A);
01959   result.invert(ierr);
01960   
01961   // blithely assuming the inverting never fails...
01962   return result;
01963 }
01964 
01965 
01966 void CSCSegAlgoST::flipErrors( AlgebraicSymMatrix& a ) const { 
01967     
01968   // The CSCSegment needs the error matrix re-arranged to match
01969   //  parameters in order (uz, vz, u0, v0) where uz, vz = slopes, u0, v0 = intercepts
01970     
01971   AlgebraicSymMatrix hold( a ); 
01972     
01973   // errors on slopes into upper left 
01974   a(1,1) = hold(3,3); 
01975   a(1,2) = hold(3,4); 
01976   a(2,1) = hold(4,3); 
01977   a(2,2) = hold(4,4); 
01978     
01979   // errors on positions into lower right 
01980   a(3,3) = hold(1,1); 
01981   a(3,4) = hold(1,2); 
01982   a(4,3) = hold(2,1); 
01983   a(4,4) = hold(2,2); 
01984     
01985   // must also interchange off-diagonal elements of off-diagonal 2x2 submatrices
01986   a(4,1) = hold(2,3);
01987   a(3,2) = hold(1,4);
01988   a(2,3) = hold(4,1); // = hold(1,4)
01989   a(1,4) = hold(3,2); // = hold(2,3)
01990 } 
01991 //
01992 void CSCSegAlgoST::correctTheCovX(void){
01993   std::vector<double> uu, vv, zz;  
01994   //std::vector<double> e_Cxx;
01995   e_Cxx.clear();
01996   double sum_U_err=0.0;
01997   double sum_Z_U_err=0.0; 
01998   double sum_Z2_U_err=0.0;
01999   double sum_U_U_err=0.0;
02000   double sum_UZ_U_err=0.0;
02001   std::vector<double> chiUZind;
02002   std::vector<double>::iterator chiContribution;
02003   double chiUZ=0.0;
02004   ChamberHitContainer::const_iterator ih = protoSegment.begin();
02005   for (ih = protoSegment.begin(); ih != protoSegment.end(); ++ih) {
02006     const CSCRecHit2D& hit = (**ih);
02007     e_Cxx.push_back(hit.localPositionError().xx());
02008     // 
02009     const CSCLayer* layer  = theChamber->layer(hit.cscDetId().layer());
02010     GlobalPoint gp         = layer->toGlobal(hit.localPosition());
02011     LocalPoint  lp         = theChamber->toLocal(gp); 
02012     // ptc: Local position of hit w.r.t. chamber
02013     double u = lp.x();
02014     double v = lp.y();
02015     double z = lp.z();
02016     uu.push_back(u); 
02017     vv.push_back(v); 
02018     zz.push_back(z);
02020     sum_U_err += 1./e_Cxx.back();
02021     sum_Z_U_err += z/e_Cxx.back();
02022     sum_Z2_U_err += (z*z)/e_Cxx.back();
02023     sum_U_U_err += u/e_Cxx.back();
02024     sum_UZ_U_err += (u*z)/e_Cxx.back();
02025   }
02026  
02029   
02030   double denom=sum_U_err*sum_Z2_U_err-pow(sum_Z_U_err,2);
02031   double U0=(sum_Z2_U_err*sum_U_U_err-sum_Z_U_err*sum_UZ_U_err)/denom;
02032   double UZ=(sum_U_err*sum_UZ_U_err-sum_Z_U_err*sum_U_U_err)/denom;
02033   
02036   
02037   for(unsigned i=0; i<uu.size(); ++i){
02038     double uMean = U0+UZ*zz[i];
02039     chiUZind.push_back((pow((uMean-uu[i]),2))/e_Cxx[i]);
02040     chiUZ += (pow((uMean-uu[i]),2))/e_Cxx[i];
02041   }
02042   chiUZ = chiUZ/(uu.size()-2);
02043   
02044   if(chiUZ>=chi2Norm_2D_){
02045     protoChiUCorrection = chiUZ/chi2Norm_2D_;
02046     for(unsigned i=0; i<uu.size(); ++i)
02047       e_Cxx[i]=e_Cxx[i]*protoChiUCorrection;
02048   }
02049   
02051   
02052   if(sqrt(protoChiUCorrection)>prePrunLimit_){
02053     chiContribution=max_element(chiUZind.begin(),chiUZind.end());
02054     maxContrIndex = chiContribution - chiUZind.begin();
02055     /*
02056     for(unsigned i=0; i<chiUZind.size();++i){
02057       if(*chiContribution==chiUZind[i]){
02058         maxContrIndex=i;
02059       }
02060     }
02061     */
02062   }
02063   //  
02064   //return e_Cxx;
02065 }
02066 //
02067 void CSCSegAlgoST::correctTheCovMatrix(CLHEP::HepMatrix &IC){
02068   //double condNumberCorr1=0.0;
02069   double condNumberCorr2=0.0; 
02070   double detCov=0.0;
02071   double diag1=0.0;
02072   double diag2=0.0;
02073   double IC_12_corr=0.0;
02074   double  IC_11_corr=0.0;
02075   if(!covToAnyNumberAll_){
02076     //condNumberCorr1=condSeed1_*IC(2,2);
02077     condNumberCorr2=condSeed2_*IC(2,2);
02078     diag1=IC(1,1)*IC(2,2);
02079     diag2=IC(1,2)*IC(1,2);
02080     detCov=fabs(diag1-diag2);
02081     if((diag1<condNumberCorr2)&&(diag2<condNumberCorr2)){
02082           if(covToAnyNumber_)
02083             IC(1,2)=covAnyNumber_;
02084           else{ 
02085             IC_11_corr=condSeed1_+fabs(IC(1,2))/IC(2,2);
02086             IC(1,1)=IC_11_corr;
02087           }
02088     }
02089     
02090     if(((detCov<condNumberCorr2)&&(diag1>condNumberCorr2))||
02091        ((diag2>condNumberCorr2)&&(detCov<condNumberCorr2)
02092         )){
02093       if(covToAnyNumber_)
02094         IC(1,2)=covAnyNumber_;
02095       else{     
02096         IC_12_corr=sqrt(fabs(diag1-condNumberCorr2));
02097         if(IC(1,2)<0)
02098           IC(1,2)=(-1)*IC_12_corr;
02099         else
02100           IC(1,2)=IC_12_corr;
02101       }
02102     }
02103   }
02104   else{
02105     IC(1,2)=covAnyNumber_;
02106   }
02107 }
02108 //
02109 void CSCSegAlgoST::findDuplicates(std::vector<CSCSegment>  & segments ){
02110   // this is intended for ME1/1a only - we have ghost segments because of the strips ganging 
02111   // this function finds them (first the rechits by sharesInput() )
02112   // if a segment shares all the rechits with another segment it is a duplicate (even if
02113   // it has less rechits) 
02114   
02115   for(std::vector<CSCSegment>::iterator it=segments.begin(); it != segments.end(); ++it) {
02116     std::vector<CSCSegment*> duplicateSegments;
02117     for(std::vector<CSCSegment>::iterator it2=segments.begin(); it2 != segments.end(); ++it2) {
02118       //
02119       bool allShared = true;
02120       if(it!=it2){
02121         allShared = it->sharesRecHits(*it2);
02122       }
02123       else{
02124         allShared = false;
02125       }
02126       //
02127       if(allShared){
02128         duplicateSegments.push_back(&(*it2));
02129       }
02130     }
02131     it->setDuplicateSegments(duplicateSegments);
02132   }
02133 
02134 }
02135 //
02136