CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/RecoMuon/MuonSeedGenerator/src/SETFilter.cc

Go to the documentation of this file.
00001 
00004 #include "RecoMuon/MuonSeedGenerator/src/SETFilter.h"
00005 
00006 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00007 
00008 // FIXME: remove this
00009 #include "FWCore/Framework/interface/Event.h"
00010 
00011 #include "TrackingTools/KalmanUpdators/interface/Chi2MeasurementEstimator.h"
00012 
00013 #include "TrackingTools/TrajectoryState/interface/FreeTrajectoryState.h"
00014 #include "TrackingTools/PatternTools/interface/TrajectoryMeasurement.h"
00015 #include "TrackingTools/DetLayers/interface/DetLayer.h"
00016 
00017 #include "TrackingTools/Records/interface/TrackingComponentsRecord.h"
00018 #include "TrackingTools/TrackFitters/interface/TrajectoryFitter.h"
00019 
00020 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00021 #include "FWCore/Utilities/interface/Exception.h"
00022 
00023 #include <vector>
00024 
00025 #include <iostream>
00026 #include <fstream>
00027 
00028 // there is an existing sorter somewhere in the CMSSW code (I think) - delete that
00029 struct sorter {
00030   //bigger first!
00031   bool operator() (TransientTrackingRecHit::ConstRecHitPointer hit_1,
00032                    TransientTrackingRecHit::ConstRecHitPointer hit_2){
00033     if(hit_1->det()->subDetector() != GeomDetEnumerators::CSC ||
00034        hit_2->det()->subDetector() != GeomDetEnumerators::CSC){
00035       // this is a piculiar "fix" for CSCs
00036       return (hit_1->globalPosition().mag2()>hit_2->globalPosition().mag2());
00037     }
00038     else{
00039       return (fabs(hit_1->globalPosition().z())>fabs(hit_2->globalPosition().z()));
00040     }
00041   }
00042 } sortRadius;// bigger first
00043 
00044 
00045 
00046 using namespace edm;
00047 using namespace std;
00048 
00049 SETFilter::SETFilter(const ParameterSet& par,
00050                                                const MuonServiceProxy* service)
00051   :theService(service)//,
00052  //theOverlappingChambersFlag(true)
00053 {
00054   thePropagatorName = par.getParameter<string>("Propagator");
00055   useSegmentsInTrajectory = par.getUntrackedParameter<bool>("UseSegmentsInTrajectory");
00056 }
00057 
00058 SETFilter::~SETFilter(){
00059 
00060   LogTrace("Muon|RecoMuon|SETFilter")
00061     <<"SETFilter destructor called"<<endl;
00062   
00063 }
00064 
00065 void SETFilter::setEvent(const Event& event){
00066 }
00067 
00068 void SETFilter::reset(){
00069   totalChambers = dtChambers = cscChambers = rpcChambers = 0;
00070   
00071   theLastUpdatedTSOS =  theLastButOneUpdatedTSOS = TrajectoryStateOnSurface();
00072 
00073   theDetLayers.clear();
00074 }
00075 
00076 
00077 const Propagator* SETFilter::propagator() const {
00078   return &*theService->propagator(thePropagatorName);
00079 }
00080 
00081 
00082 void SETFilter::incrementChamberCounters(const DetLayer *layer){
00083 
00084   if(layer->subDetector()==GeomDetEnumerators::DT) dtChambers++; 
00085   else if(layer->subDetector()==GeomDetEnumerators::CSC) cscChambers++; 
00086   else if(layer->subDetector()==GeomDetEnumerators::RPCBarrel || layer->subDetector()==GeomDetEnumerators::RPCEndcap) rpcChambers++; 
00087   else 
00088     LogError("Muon|RecoMuon|SETFilter")
00089       << "Unrecognized module type in incrementChamberCounters";
00090   // FIXME:
00091   //   << layer->module() << " " <<layer->Part() << endl;
00092   
00093   totalChambers++;
00094 }
00095 
00096 //---- the SET FW-fitter within a cluster 
00097 bool SETFilter::fwfit_SET(std::vector < SeedCandidate> & validSegmentsSet_in,
00098                                    std::vector < SeedCandidate> & validSegmentsSet_out){
00099   // this is the SET algorithm fit
00100   validSegmentsSet_out.clear();
00101 
00102   //---- It is supposed to be called within a loop over "segment clusters"; 
00103   //---- so std::vector < SeedCandidate> consists of "valid" combinations (sets) within a "cluster"
00104   //---- "seed" above has nothing to do with the "Seed" in the STA code
00105  
00106   // a trajectory is not really build but a TSOS is build and is checked (below)
00107   bool validStep = true;
00108   std::vector <double> chi2AllCombinations(validSegmentsSet_in.size());
00109   std::vector < TrajectoryStateOnSurface > lastUpdatedTSOS_Vect(validSegmentsSet_in.size());
00110   // loop over all valid sets
00111   for(unsigned int iSet = 0; iSet<validSegmentsSet_in.size(); ++iSet){
00112     //std::cout<<"   iSET = "<<iSet<<std::endl;
00113     //---- start fit from the origin
00114     CLHEP::Hep3Vector origin (0.,0.,0.);
00115     Trajectory::DataContainer trajectoryMeasurementsInTheSet_tmp;
00116     //---- Find minimum chi2 (corresponding to a specific 3D-momentum)    
00117     chi2AllCombinations[iSet]  = findMinChi2(iSet, origin, validSegmentsSet_in[iSet], lastUpdatedTSOS_Vect,
00118                                              trajectoryMeasurementsInTheSet_tmp);
00119   }
00120   //---- Find the best muon candidate (min chi2) in the cluster; find more candidates?
00121   std::vector < double >::iterator itMin = min_element(chi2AllCombinations.begin(),chi2AllCombinations.end());
00122 
00123   int positionMin = itMin - chi2AllCombinations.begin();
00124 
00125   // "the best" set; have to find reasonable conditions to include more than one set   
00126   validSegmentsSet_out.push_back(validSegmentsSet_in[positionMin]);
00127 
00128   return validStep;
00129 }
00130 
00131 //---- the SET FW-fitter
00132 bool SETFilter::buildTrajectoryMeasurements(SeedCandidate * finalMuon, Trajectory::DataContainer & finalCandidate){
00133   // this is the SET algorithm fit
00134   bool validTrajectory = true;
00135   // reset the fitter 
00136   reset(); // the layer counters
00137   finalCandidate.clear();
00138 
00139   //---- Check if (only last?) TSOS is valid and build a trajectory (for the backward filter) 
00140 
00141   if(finalMuon->trajectoryMeasurementsInTheSet.size() &&
00142      finalMuon->trajectoryMeasurementsInTheSet.back().forwardPredictedState().isValid()){
00143     // loop over all measurements in the set
00144     for(unsigned int iMeas =0; iMeas<finalMuon->trajectoryMeasurementsInTheSet.size();++iMeas){
00145       // strore the measurements 
00146       finalCandidate.push_back(finalMuon->trajectoryMeasurementsInTheSet[iMeas]);
00147       const DetLayer *layer = finalMuon->trajectoryMeasurementsInTheSet[iMeas].layer();
00148 
00149       incrementChamberCounters(layer);
00150 
00151       theDetLayers.push_back(layer);
00152 
00153     }
00154     theLastUpdatedTSOS = finalMuon->trajectoryMeasurementsInTheSet.at(finalMuon->trajectoryMeasurementsInTheSet.size()-1).forwardPredictedState();
00155     //std::cout<<"  THE OUTPUT FROM FW FILTER: |P| = "<<finalMuon->momentum.mag()<<
00156     //" theta = "<<finalMuon->momentum.theta()<<" phi = "<<finalMuon->momentum.phi()<<std::endl;
00157   }
00158   else{
00159     validTrajectory = false;
00160     //std::cout<<" TSOS not valid; no trajectory build"<<std::endl;
00161   }
00162   return validTrajectory;
00163 }
00164 
00165 //
00166 bool SETFilter::transform(Trajectory::DataContainer &measurements_segments, 
00167                           TransientTrackingRecHit::ConstRecHitContainer & hitContainer, 
00168                           TrajectoryStateOnSurface & firstTSOS){
00169   // transforms "segment trajectory" to "rechit container"
00170   //sort(measurements_segments.begin(),measurements_segments.end(),sortRadius);
00171   bool success = true;
00172   // loop over all segments in the trajectory
00173   for(int iMeas = measurements_segments.size() - 1; iMeas>-1;--iMeas){
00174     TransientTrackingRecHit ::ConstRecHitContainer sortedHits;
00175     // loop over the rechits contained in the segments
00176     for(unsigned int jMeas = 0; jMeas<measurements_segments[iMeas].recHit()->transientHits().size();++jMeas){
00177       if(measurements_segments[iMeas].recHit()->transientHits().at(jMeas)->transientHits().size()>1){
00178         // loop over the rechits contained in the rechits contained in the segments (OK, OK - this is for DT only;
00179         // the convention there is a bit different from the CSCs)
00180         for(unsigned int kMeas = 0;kMeas<measurements_segments[iMeas].recHit()->transientHits().at(jMeas)->transientHits().size();
00181             ++kMeas){
00182           sortedHits.push_back( 
00183                                measurements_segments[iMeas].recHit()->transientHits().at(jMeas)->transientHits().at(kMeas));
00184         }
00185       }
00186       else{
00187         sortedHits = measurements_segments[iMeas].recHit()->transientHits();
00188       }
00189     }
00190     // sort the rechits by radius (or z) and put them in a container
00191     sort(sortedHits.begin(),sortedHits.end(),sortRadius);
00192     hitContainer.insert(hitContainer.end(),sortedHits.begin(),sortedHits.end());    
00193   }
00194 
00195   CLHEP::Hep3Vector p3_propagated,r3_propagated;
00196   AlgebraicSymMatrix66 cov_propagated, covT;//---- how to disable error propagation?
00197   covT *= 1e-20;
00198   cov_propagated *= 1e-20;
00199   // this is the last segment state
00200   FreeTrajectoryState ftsStart = *(measurements_segments.at(measurements_segments.size()-1).forwardPredictedState().freeState());
00201 
00202   // this is the last (from the IP) rechit
00203   TransientTrackingRecHit::ConstRecHitPointer muonRecHit =  hitContainer[0];
00204   DetId detId_last = hitContainer[0]->hit()->geographicalId();
00205   const GeomDet* layer_last = theService->trackingGeometry()->idToDet(detId_last);
00206   TrajectoryStateOnSurface tSOSDest;
00207   // get the last rechit TSOS
00208   tSOSDest = propagator()->propagate(ftsStart, layer_last->surface());
00209   firstTSOS = tSOSDest;
00210   // ftsStart should be at the last rechit surface
00211   if (!tSOSDest.isValid()){
00212     success = false;
00213     //     ftsStart = *tSOSDest.freeState();
00214   }
00215   return success; 
00216 }
00217 
00218 bool SETFilter::transformLight(Trajectory::DataContainer &measurements_segments,
00219                                TransientTrackingRecHit::ConstRecHitContainer & hitContainer,
00220                                TrajectoryStateOnSurface & firstTSOS){
00221   // transforms "segment trajectory" to "segment container"
00222 
00223   bool success = true;
00224   // loop over all segments in the trajectory
00225   if(useSegmentsInTrajectory){// if segments the "backword fit" (rechits)
00226                               // performed later is actually a forward one (?!) 
00227     for(unsigned int iMeas = 0; iMeas<measurements_segments.size();++iMeas){
00228       hitContainer.push_back(measurements_segments[iMeas].recHit());
00229     }
00230   }
00231   else{
00232     for(int iMeas = measurements_segments.size() - 1; iMeas>-1;--iMeas){
00233       hitContainer.push_back(measurements_segments[iMeas].recHit());
00234     }
00235 
00236   }
00237   // this is the last segment state
00238   firstTSOS = measurements_segments.at(0).forwardPredictedState();
00239   return success;
00240 }
00241 
00242 
00243 
00244 void SETFilter::getFromFTS(const FreeTrajectoryState& fts,
00245                                       CLHEP::Hep3Vector& p3, CLHEP::Hep3Vector& r3,
00246                                       int& charge, AlgebraicSymMatrix66& cov){
00247 
00248   GlobalVector p3GV = fts.momentum();
00249   GlobalPoint r3GP = fts.position();
00250 
00251   p3.set(p3GV.x(), p3GV.y(), p3GV.z());
00252   r3.set(r3GP.x(), r3GP.y(), r3GP.z());
00253 
00254   charge = fts.charge();
00255   cov = fts.hasError() ? fts.cartesianError().matrix() : AlgebraicSymMatrix66();
00256 
00257 }
00258 
00259 FreeTrajectoryState SETFilter::getFromCLHEP(const CLHEP::Hep3Vector& p3, const CLHEP::Hep3Vector& r3,
00260                                                        int charge, const AlgebraicSymMatrix66& cov,
00261                                                        const MagneticField* field){
00262 
00263   GlobalVector p3GV(p3.x(), p3.y(), p3.z());
00264   GlobalPoint r3GP(r3.x(), r3.y(), r3.z());
00265   GlobalTrajectoryParameters tPars(r3GP, p3GV, charge, field);
00266 
00267   CartesianTrajectoryError tCov(cov);
00268 
00269   return cov.kRows == 6 ? FreeTrajectoryState(tPars, tCov) : FreeTrajectoryState(tPars) ;
00270 }
00271 
00272 double SETFilter::findChi2(double pX, double pY, double pZ,
00273                                       const CLHEP::Hep3Vector& r3T,
00274                                       SeedCandidate & muonCandidate,
00275                                       TrajectoryStateOnSurface  &lastUpdatedTSOS,
00276                            Trajectory::DataContainer & trajectoryMeasurementsInTheSet,
00277                                       bool detailedOutput){
00278   //---- actual chi2 calculations; only the measurement error is taken into accout!
00279   //---- chi2 is to compare an extrapolated point to various measurements so
00280   //---- the extrapolation error is not an issue (is it?)
00281 
00282   if(detailedOutput){
00283     trajectoryMeasurementsInTheSet.clear();
00284   }
00285 
00286   int charge =  muonCandidate.charge;
00287   CLHEP::Hep3Vector p3T(pX,pY,pZ);
00288   CLHEP::Hep3Vector p3_propagated,r3_propagated;
00289   AlgebraicSymMatrix66 cov_propagated, covT;//---- how to disable error propagation?
00290   covT *= 1e-20;
00291   cov_propagated *= 1e-20;
00292     
00293   FreeTrajectoryState ftsStart = getFromCLHEP(p3T, r3T, charge, covT, &*(theService->magneticField()));
00294   TrajectoryStateOnSurface tSOSDest;
00295     
00296   double chi2_loc = 0.;
00297   for(unsigned int iMeas = 0; iMeas <muonCandidate.theSet.size(); ++iMeas){
00298     MuonTransientTrackingRecHit::MuonRecHitPointer muonRecHit =  muonCandidate.theSet[iMeas];
00299     DetId detId = muonRecHit->hit()->geographicalId();
00300     const GeomDet* layer = theService->trackingGeometry()->idToDet(detId);
00301 
00302     //---- propagate the muon starting from position r3T and momentum p3T 
00303 
00304     //    bool radX0CorrectionMode_ = false; // not needed here?
00305     //if (radX0CorrectionMode_ ){
00306     //} else {
00307 
00308     tSOSDest = propagator()->propagate(ftsStart, layer->surface());
00309     lastUpdatedTSOS = tSOSDest;
00310     if (tSOSDest.isValid()){
00311       //---- start next step ("adding" measurement) from the last TSOS
00312       ftsStart = *tSOSDest.freeState();
00313       //getFromFTS(ftsStart, p3_propagated, r3_propagated, charge, cov_propagated);
00314     } else{
00315       //std::cout<<"... not valid TSOS"<<std::endl;
00316       chi2_loc = 9999999999.;
00317       break;
00318     }
00319     //}
00320 
00321     getFromFTS(ftsStart, p3_propagated, r3_propagated, charge, cov_propagated);
00322 
00323     GlobalPoint globPos = muonRecHit->globalPosition();
00324     LocalPoint locHitPos = muonRecHit->localPosition();
00325     LocalError locHitErr = muonRecHit->localPositionError();
00326     const GlobalPoint globPropPos(r3_propagated.x(), r3_propagated.y(), r3_propagated.z());
00327     LocalPoint locPropPos = layer->toLocal(globPropPos);
00328 
00329     //
00330     //---- chi2 calculated in local system; correlation taken into accont
00331     CLHEP::HepMatrix dist(1,2);//, distT(2,1);
00332     double  chi2_intermed = -9;
00333     int ierr = 0;
00334     dist(1,1) = locPropPos.x() - locHitPos.x();
00335     dist(1,2) = locPropPos.y() - locHitPos.y();
00336     CLHEP::HepMatrix IC(2,2);
00337     IC(1,1) = locHitErr.xx();
00338     IC(2,1) = locHitErr.xy();
00339     IC(2,2) = locHitErr.yy();
00340     IC(1,2) = IC(2,1);
00341 
00342     //---- Special care is needed for "1-dim measurements" (RPCs, outer DT(?))
00343     if(4!=muonRecHit->hit()->dimension()){
00344       for(int iE = 1;iE<3;++iE){
00345         // this is bellow is a DT fix; hopefully it will not be needed
00346         if ( fabs(IC(iE,iE)) < 0.00000001){ 
00347           IC(iE,iE) = 62500./12.;// error squared - ( 250 cm /sqrt(12) )^2; large 
00348         }
00349       }
00350     }
00351     //---- Invert covariance matrix
00352     IC.invert(ierr);
00353     //if (ierr != 0) {
00354     //std::cout << "failed to invert covariance matrix (2x2) =\n" << IC << std::endl;;
00355     //}
00356     chi2_intermed = pow(dist(1,1),2)*IC(1,1) + 2.*dist(1,1)*dist(1,2)*IC(1,2) + pow(dist(1,2),2)*IC(2,2);
00357     if(chi2_intermed<0){// should we check?
00358        chi2_intermed = 9999999999.;
00359     }
00360     chi2_loc += chi2_intermed;
00361 
00362     // that's for the last call; we don't need to construct a TrajectoryMeasurement at every chi2 step
00363     if(detailedOutput){
00364       DetId detId = muonRecHit->hit()->geographicalId();
00365       const DetLayer *layer = theService->detLayerGeometry()->idToLayer( detId);
00366       //std::cout<<"    seg pos in traj : "<<lastUpdatedTSOS.globalPosition()<<std::endl;
00367       // put the measurement into the set
00368       trajectoryMeasurementsInTheSet.push_back( TrajectoryMeasurement
00369                                                 ( lastUpdatedTSOS,
00370                                                   muonRecHit.get(),
00371                                                   chi2_intermed,
00372                                                   layer ) );
00373     }
00374   }
00375   return chi2_loc;
00376 }
00377 
00378 double SETFilter::findMinChi2(unsigned int iSet, const CLHEP::Hep3Vector& r3T,
00379                                          SeedCandidate & muonCandidate,
00380                                          std::vector < TrajectoryStateOnSurface > &lastUpdatedTSOS_Vect,// delete 
00381                                          Trajectory::DataContainer & trajectoryMeasurementsInTheSet){
00382   // a chi2 minimization procedure 
00383 
00384   //---- Which three variables to use? 
00385   //---- (1/|P|, theta, phi) ? in that case many sin() and cos() operations :-/
00386   //---- maybe vary directly sin() and cos()?
00387   bool detailedOutput = false;
00388 
00389   double cosTheta = muonCandidate.momentum.cosTheta();
00390   double theta = acos(cosTheta);
00391   double phi = muonCandidate.momentum.phi();
00392   double pMag = muonCandidate.momentum.mag();
00393 
00394   double minChi2 = -999.;
00395   TrajectoryStateOnSurface  lastUpdatedTSOS;
00396 
00397   //---- Fit Parameters
00398 
00399   if(pMag<5.){// hardcoded - remove it! same in SETSeedFinder
00400     pMag = 5.;// GeV
00401   }
00402   //---- This offset helps the minimization to go faster (in the specific case)
00403   pMag *=1.2;
00404   double invP = 1./pMag;
00405   //std::cout<<"    INIT pMag = "<<pMag<<" invP = "<<invP<<" theta = "<<theta<<" phi = "<<phi<<std::endl;
00406 
00407   //---- apply downhill SIMPLEX minimization (also "amoeba" method; thus the "feet" below are  amoeba's feet)
00408 
00409   //std::cout<<"    SIMPLEX minimization"<<std::endl;
00410   //---- parameters ; the should be hardcoded   
00411   const double reflect = 1;
00412   const double expand = -0.5;
00413   const double contract = 0.25;
00414 
00415   const int nDim = 3; // invP, theta, phi
00416   //---- Now choose nDim + 1 points
00417   std::vector <CLHEP::Hep3Vector> feet(nDim+1);
00418   std::vector <double> chi2Feet(nDim+1);
00419   std::vector <TrajectoryStateOnSurface*> lastUpdatedTSOS_pointer(nDim+1);// probably not needed; to be deleted
00420    
00421   //---- The minimization procedure strats from these nDim+1 points (feet)
00422 
00423   CLHEP::Hep3Vector foot1(invP, theta, phi);// well obviuosly it is not a real Hep3Vector; better change it to a simple vector
00424   feet[0] = foot1;
00425   chi2Feet[0] = chi2AtSpecificStep(feet[0], r3T, muonCandidate, lastUpdatedTSOS,
00426                                        trajectoryMeasurementsInTheSet, detailedOutput);
00427   lastUpdatedTSOS_pointer[0] = &lastUpdatedTSOS;
00428 
00429   std::vector <CLHEP::Hep3Vector> morePoints =
00430     find3MoreStartingPoints(feet[0], r3T, muonCandidate);
00431   feet[1] = morePoints[0];
00432   feet[2] = morePoints[1];
00433   feet[3] = morePoints[2];
00434 
00435   //--- SIMPLEX initial step(s)
00436   for(unsigned int iFoot = 1; iFoot<feet.size();++iFoot){
00437 
00438     chi2Feet[iFoot] = chi2AtSpecificStep(feet[iFoot], r3T, muonCandidate, lastUpdatedTSOS,
00439                                          trajectoryMeasurementsInTheSet, detailedOutput);
00440     lastUpdatedTSOS_pointer[iFoot] = &lastUpdatedTSOS;
00441   }
00442 
00443   unsigned int high, second_high, low;  
00444   //const unsigned int iterations = 1;//---- to be replaced by something better
00445   int iCalls = 0;
00446   //for(unsigned int iIt = 0;iIt<iterations;++iIt){
00447   while(iCalls<3.){
00448     //---- SIMPLEX step 1
00449     pickElements(chi2Feet, high, second_high, low);
00450     ++iCalls;
00451     feet[high] = reflectFoot(feet, high, reflect );
00452     chi2Feet[high] = chi2AtSpecificStep(feet[high], r3T, muonCandidate, lastUpdatedTSOS,
00453                                         trajectoryMeasurementsInTheSet, detailedOutput);
00454     lastUpdatedTSOS_pointer[high] = &lastUpdatedTSOS;
00455     //---- SIMPLEX step 2.1
00456     if(chi2Feet[high] <chi2Feet[low]){
00457       ++iCalls; 
00458       feet[high] = reflectFoot(feet, high, expand);
00459       chi2Feet[high] = chi2AtSpecificStep(feet[high], r3T, muonCandidate, lastUpdatedTSOS,
00460                                           trajectoryMeasurementsInTheSet, detailedOutput);
00461       lastUpdatedTSOS_pointer[high] = &lastUpdatedTSOS;
00462     }
00463     //---- SIMPLEX step 2.2
00464     else if( chi2Feet[high] > chi2Feet[second_high]){
00465       double worstChi2 = chi2Feet[high];
00466       ++iCalls;
00467       feet[high] =  reflectFoot(feet, high, contract);
00468       chi2Feet[high] = chi2AtSpecificStep(feet[high], r3T, muonCandidate, lastUpdatedTSOS,
00469                                           trajectoryMeasurementsInTheSet, detailedOutput);
00470       lastUpdatedTSOS_pointer[high] = &lastUpdatedTSOS;
00471       //---- SIMPLEX step 2.2.1
00472       if(chi2Feet[high] <worstChi2){
00473         nDimContract(feet, low);
00474         for(unsigned int iFoot = 0; iFoot<feet.size();++iFoot){
00475           ++iCalls; 
00476           chi2Feet[iFoot] = chi2AtSpecificStep(feet[iFoot], r3T, muonCandidate, lastUpdatedTSOS,
00477                                                trajectoryMeasurementsInTheSet, detailedOutput);
00478           lastUpdatedTSOS_pointer[iFoot] = &lastUpdatedTSOS;
00479         }
00480         --iCalls;// one of the above is not changed
00481       }
00482     }
00483   }
00484   //---- Here the SIMPLEX minimization ends
00485 
00486   // this is the minimum found
00487   int bestFitElement = min_element(chi2Feet.begin(),chi2Feet.end()) - chi2Feet.begin();
00488 
00489   //---- repeat to get the trajectoryMeasurementsInTheSet (optimize?)
00490   detailedOutput = true;
00491   chi2Feet[bestFitElement] = chi2AtSpecificStep(feet[bestFitElement], r3T, muonCandidate, lastUpdatedTSOS,
00492                                                 trajectoryMeasurementsInTheSet, detailedOutput);
00493   minChi2 = chi2Feet[bestFitElement];
00494 
00495   double pMag_updated = 1./feet[bestFitElement].x();
00496   double sin_theta = sin(feet[bestFitElement].y());
00497   double cos_theta = cos(feet[bestFitElement].y());
00498   double sin_phi = sin(feet[bestFitElement].z());
00499   double cos_phi = cos(feet[bestFitElement].z());
00500 
00501   double best_pX = pMag_updated*sin_theta*cos_phi;
00502   double best_pY = pMag_updated*sin_theta*sin_phi;
00503   double best_pZ = pMag_updated*cos_theta;
00504   CLHEP::Hep3Vector bestP(best_pX, best_pY, best_pZ);
00505   //---- update the best momentum estimate  
00506   //if(minChi2<999999. && pMag_updated>0.){//fit failed?! check
00507   muonCandidate.momentum = bestP;
00508   //}
00509   //---- update the trajectory
00510   muonCandidate.trajectoryMeasurementsInTheSet = trajectoryMeasurementsInTheSet;
00511   // do we need that?
00512   lastUpdatedTSOS_Vect[iSet]= *(lastUpdatedTSOS_pointer[bestFitElement]);
00513 
00514   //std::cout<<"   FINAL:  P = "<<muonCandidate.momentum.mag()<<" theta = "<<muonCandidate.momentum.theta()<<
00515   //" phi = "<<muonCandidate.momentum.phi()<<"   chi = "<<chi2Feet[bestFitElement]<<std::endl;
00516   return minChi2;
00517 }
00518 
00519 double SETFilter::
00520 chi2AtSpecificStep(CLHEP::Hep3Vector &foot,
00521                    const CLHEP::Hep3Vector& r3T,
00522                    SeedCandidate & muonCandidate,
00523                    TrajectoryStateOnSurface  &lastUpdatedTSOS,
00524                    Trajectory::DataContainer & trajectoryMeasurementsInTheSet,
00525                    bool detailedOutput){
00526   // specific input parameters - find chi2
00527   double chi2 = 999999999999.;
00528   if(foot.x()>0){ // this is |P|; maybe return a flag too?
00529     double pMag_updated = 1./foot.x();
00530     double sin_theta = sin(foot.y());
00531     double cos_theta = cos(foot.y());
00532     double sin_phi = sin(foot.z());
00533     double cos_phi = cos(foot.z());
00534       
00535     double pX = pMag_updated*sin_theta*cos_phi;
00536     double pY = pMag_updated*sin_theta*sin_phi;
00537     double pZ = pMag_updated*cos_theta;
00538     chi2 = findChi2(pX, pY, pZ, r3T, 
00539                     muonCandidate, lastUpdatedTSOS,
00540                     trajectoryMeasurementsInTheSet, detailedOutput);
00541   }
00542   return chi2;
00543 }   
00544 
00545 std::vector <CLHEP::Hep3Vector> SETFilter::
00546 find3MoreStartingPoints(CLHEP::Hep3Vector &key_foot,
00547                    const CLHEP::Hep3Vector& r3T,
00548                    SeedCandidate & muonCandidate){
00549   // SIMPLEX uses nDim + 1 starting points; 
00550   // so here we need 3 more (one we already have)
00551   std::vector <CLHEP::Hep3Vector> morePoints;// again - CLHEP::Hep3Vector is not a good choice here
00552   double invP = key_foot.x();
00553   double theta = key_foot.y();
00554   double phi = key_foot.z();
00555 
00556 
00557   double deltaPhi_init = 0.005;
00558   double deltaTheta_init = 0.005;
00559   //double deltaInvP_init = 1.1 * invP;
00560   double deltaInvP_init = 0.1 * invP;
00561   //deltaInvP_init = 0.5 * invP;
00562 
00563   // try to chose better point to start with
00564   bool optimized = true;
00565   if(optimized){
00566     //---- Find a minimum chi2 for every variable (others are fixed) by supposing chi2 is a parabola
00567     //---- Then these points ("minima") are probably better starting points for the real minimization
00568 
00569     TrajectoryStateOnSurface  lastUpdatedTSOS;// fake here
00570     Trajectory::DataContainer trajectoryMeasurementsInTheSet;// fake here
00571     bool detailedOutput = false;// fake here
00572 
00573 
00574     std::vector < double > pInv_init(3);
00575     std::vector < double > theta_init(3);
00576     std::vector < double > phi_init(3);
00577     std::vector < double > chi2_init(3);
00578 
00579     pInv_init[0] = invP - deltaInvP_init;
00580     pInv_init[1] = invP;
00581     pInv_init[2] = invP + deltaInvP_init;
00582     //pInv_init[2] = invP +  0.1 * invP;
00583 
00584     theta_init[0] = theta-deltaTheta_init;
00585     theta_init[1] = theta;
00586     theta_init[2] = theta+deltaTheta_init;
00587 
00588     phi_init[0] = phi-deltaPhi_init;
00589     phi_init[1] = phi;
00590     phi_init[2] = phi+deltaPhi_init;
00591 
00592     double sin_theta_nom = sin(theta_init[1]);
00593     double cos_theta_nom = cos(theta_init[1]);
00594     double sin_phi_nom = sin(phi_init[1]);
00595     double cos_phi_nom = cos(phi_init[1]);
00596     double pMag_updated_nom =  1./pInv_init[1];
00597 
00598     //--- invP
00599     for(int i=0;i<3;++i){
00600       double pMag_updated = 1./pInv_init[i];
00601       double pX = pMag_updated*sin_theta_nom*cos_phi_nom;
00602       double pY = pMag_updated*sin_theta_nom*sin_phi_nom;
00603       double pZ = pMag_updated*cos_theta_nom;
00604       chi2_init[i] = findChi2(pX, pY, pZ, r3T,
00605                          muonCandidate, lastUpdatedTSOS,
00606                          trajectoryMeasurementsInTheSet, detailedOutput);
00607     }
00608     std::pair <double,double> result_pInv =
00609       findParabolaMinimum(pInv_init, chi2_init);
00610 
00611     //---- theta
00612     for(int i=0;i<3;++i){
00613       double sin_theta = sin(theta_init[i]);
00614       double cos_theta = cos(theta_init[i]);
00615       double pX = pMag_updated_nom*sin_theta*cos_phi_nom;
00616       double pY = pMag_updated_nom*sin_theta*sin_phi_nom;
00617       double pZ = pMag_updated_nom*cos_theta;
00618         chi2_init[i] =  findChi2(pX, pY, pZ, r3T,
00619                          muonCandidate, lastUpdatedTSOS,
00620                          trajectoryMeasurementsInTheSet, detailedOutput);
00621     }
00622     std::pair <double,double> result_theta =
00623       findParabolaMinimum(theta_init, chi2_init);
00624 
00625     //---- phi
00626     for(int i=0;i<3;++i){
00627       double sin_phi = sin(phi_init[i]);
00628       double cos_phi = cos(phi_init[i]);
00629       double pX = pMag_updated_nom*sin_theta_nom*cos_phi;
00630       double pY = pMag_updated_nom*sin_theta_nom*sin_phi;
00631       double pZ = pMag_updated_nom*cos_theta_nom;
00632       chi2_init[i] =  findChi2(pX, pY, pZ, r3T,
00633                          muonCandidate, lastUpdatedTSOS,
00634                          trajectoryMeasurementsInTheSet, detailedOutput);
00635     }
00636     std::pair <double,double> result_phi =
00637       findParabolaMinimum(phi_init, chi2_init);
00638     // should we use that?
00639     double newPhi = result_phi.first;
00640     if(fabs(newPhi - phi)<0.02){// too close?
00641       newPhi = phi + 0.02;
00642     }
00643     CLHEP::Hep3Vector foot2(invP, theta, result_phi.first);
00644     CLHEP::Hep3Vector foot3(invP, result_theta.first , phi);
00645     double newInvP = result_pInv.first;
00646     if(fabs(newInvP - invP)<0.001){//too close
00647       newInvP = invP + 0.001;
00648     }
00649     CLHEP::Hep3Vector foot4(result_pInv.first, theta, phi);
00650     morePoints.push_back(foot2);
00651     morePoints.push_back(foot3);
00652     morePoints.push_back(foot4);
00653   }
00654   else{
00655     // the points
00656     CLHEP::Hep3Vector foot2(invP, theta, phi-deltaPhi_init);
00657     CLHEP::Hep3Vector foot3(invP, theta-deltaTheta_init, phi);
00658     CLHEP::Hep3Vector foot4(invP-deltaInvP_init, theta, phi);
00659     morePoints.push_back(foot2);
00660     morePoints.push_back(foot3);
00661     morePoints.push_back(foot4);
00662   }
00663   return morePoints;
00664 }
00665 
00666 std::pair <double,double> SETFilter::findParabolaMinimum(std::vector <double> &quadratic_var,
00667                                                                     std::vector <double> &quadratic_chi2){
00668 
00669   // quadratic equation minimization
00670 
00671   double paramAtMin = -99.;
00672   std::vector <double> quadratic_param(3);
00673 
00674   CLHEP::HepMatrix denominator(3,3);
00675   CLHEP::HepMatrix enumerator_1(3,3);
00676   CLHEP::HepMatrix enumerator_2(3,3);
00677   CLHEP::HepMatrix enumerator_3(3,3);
00678 
00679   for(int iCol=1;iCol<4;++iCol){
00680     denominator(1,iCol) = 1;
00681     denominator(2,iCol) = quadratic_var.at(iCol-1);
00682     denominator(3,iCol) = pow(quadratic_var.at(iCol-1),2);
00683 
00684     enumerator_1(1,iCol) = quadratic_chi2.at(iCol-1);
00685     enumerator_1(2,iCol) = denominator(2,iCol);
00686     enumerator_1(3,iCol) = denominator(3,iCol);
00687 
00688     enumerator_2(1,iCol) = denominator(1,iCol);
00689     enumerator_2(2,iCol) = quadratic_chi2.at(iCol-1);
00690     enumerator_2(3,iCol) = denominator(3,iCol);
00691 
00692     enumerator_3(1,iCol) = denominator(1,iCol);
00693     enumerator_3(2,iCol) = denominator(2,iCol);
00694     enumerator_3(3,iCol) = quadratic_chi2.at(iCol-1);
00695   }
00696   const double mult = 5.;// "save" accuracy"; result is independent on "mult"
00697   denominator *=mult;
00698   enumerator_1*=mult;
00699   enumerator_2*=mult;
00700   enumerator_3*=mult;
00701 
00702   std::vector <CLHEP::HepMatrix> enumerator;
00703   enumerator.push_back(enumerator_1);
00704   enumerator.push_back(enumerator_2);
00705   enumerator.push_back(enumerator_3);
00706 
00707   double determinant = denominator.determinant();
00708   if(fabs(determinant)>0.00000000001){
00709     for(int iPar=0;iPar<3;++iPar){
00710       quadratic_param.at(iPar) = enumerator.at(iPar).determinant()/determinant;
00711     }
00712   }
00713   else{
00714     //std::cout<<" determinant 0? Check the code..."<<std::endl;
00715   }
00716   if(quadratic_param.at(2)>0){
00717     paramAtMin = - quadratic_param.at(1)/quadratic_param.at(2)/2;
00718   }
00719   else {
00720     //std::cout<<" parabola has a maximum or division by zero... Using initial value. "<<std::endl;
00721     paramAtMin = quadratic_var.at(1);
00722   }
00723   double chi2_min = quadratic_param.at(0) + quadratic_param.at(1)*paramAtMin + quadratic_param.at(2)*pow(paramAtMin,2);
00724   std::pair <double, double> result;
00725   result =  std::make_pair ( paramAtMin, chi2_min);
00726   return result;
00727 }
00728 
00729 void SETFilter::pickElements(std::vector <double> &chi2Feet,
00730                                        unsigned int & high, unsigned int & second_high, unsigned int & low){
00731   // a SIMPLEX function
00732   std::vector <double> chi2Feet_tmp = chi2Feet;
00733   std::vector <double>::iterator minEl = min_element(chi2Feet.begin(), chi2Feet.end());
00734   std::vector <double>::iterator maxEl = max_element(chi2Feet.begin(), chi2Feet.end());
00735   high = maxEl - chi2Feet.begin();
00736   low = minEl - chi2Feet.begin();
00737   chi2Feet_tmp[high] = chi2Feet_tmp[low]; 
00738   std::vector <double>::iterator second_maxEl = max_element(chi2Feet_tmp.begin(), chi2Feet_tmp.end());
00739   second_high = second_maxEl - chi2Feet_tmp.begin();
00740 
00741   return;
00742 }
00743 
00744 CLHEP::Hep3Vector SETFilter::reflectFoot(std::vector <CLHEP::Hep3Vector> & feet,
00745                                                  unsigned int key_foot, double scale ){
00746   // a SIMPLEX function
00747   CLHEP::Hep3Vector newPosition(0.,0.,0.);
00748   if(scale==0.5){
00749     //std::cout<<" STA muon: scale parameter for simplex method incorrect : "<<scale<<std::endl;
00750     return newPosition;
00751   }
00752   CLHEP::Hep3Vector centroid(0,0,0);
00753   for(unsigned int iFoot = 0; iFoot<feet.size();++iFoot){
00754     if(iFoot==key_foot){
00755       continue;
00756     }
00757     centroid += feet[iFoot];
00758   }
00759   centroid/=(feet.size()-1);
00760   CLHEP::Hep3Vector displacement = 2.*(centroid - feet[key_foot]);
00761   newPosition = feet[key_foot] + scale * displacement;
00762   return newPosition;
00763 }
00764 
00765 void SETFilter::nDimContract(std::vector <CLHEP::Hep3Vector> & feet, unsigned int low){
00766   for(unsigned int iFoot = 0; iFoot<feet.size();++iFoot){
00767     // a SIMPLEX function
00768     if(iFoot==low){
00769       continue;
00770     }
00771     feet[iFoot] +=  feet[low];
00772     feet[iFoot] /=2.;
00773   }
00774   return;
00775 }