CMS 3D CMS Logo

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