CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_4/src/RecoTracker/ConversionSeedGenerators/src/SeedForPhotonConversionFromQuadruplets.cc

Go to the documentation of this file.
00001 #include "RecoTracker/ConversionSeedGenerators/interface/SeedForPhotonConversionFromQuadruplets.h"
00002 
00003 #include <TVector3.h>
00004 #include "RecoTracker/ConversionSeedGenerators/interface/Conv4HitsReco.h"
00005 
00006 #include "TrackingTools/KalmanUpdators/interface/KFUpdator.h"
00007 #include "RecoTracker/TkSeedGenerator/interface/FastHelix.h"
00008 #include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
00009 #include "Geometry/Records/interface/TrackerDigiGeometryRecord.h"
00010 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00011 #include "MagneticField/Engine/interface/MagneticField.h"
00012 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00013 #include "TrackingTools/Records/interface/TrackingComponentsRecord.h" 
00014 #include "TrackingTools/Records/interface/TransientRecHitRecord.h" 
00015 #include "TrackingTools/MaterialEffects/interface/PropagatorWithMaterial.h"
00016 #include "FWCore/Framework/interface/ESHandle.h"
00017 #include "TrackingTools/GeomPropagators/interface/PropagationExceptions.h"
00018 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateTransform.h"
00019 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateOnSurface.h"
00020 #include "RecoTracker/TransientTrackingRecHit/interface/TSiStripRecHit2DLocalPos.h"
00021 
00022 //#define mydebug_sguazz
00023 //#define quadDispLine
00024 template <class T> T sqr( T t) {return t*t;}
00025 
00026 const TrajectorySeed * SeedForPhotonConversionFromQuadruplets::trajectorySeed(
00027     TrajectorySeedCollection & seedCollection,
00028     const SeedingHitSet & phits,
00029     const SeedingHitSet & mhits,
00030     const TrackingRegion & region,
00031     const edm::EventSetup& es,
00032     std::stringstream& ss,
00033     std::vector<Quad>& quadV)
00034 {
00035 
00036   //  return 0; //FIXME, remove this line to make the code working. 
00037 
00038   pss = &ss;
00039  
00040   if ( phits.size() < 2) return 0;
00041   if ( mhits.size() < 2) return 0;
00042 
00043   //PUT HERE THE QUADRUPLET ALGORITHM, AND IN CASE USE THE METHODS ALREADY DEVELOPED, ADAPTING THEM
00044 
00045   //
00046   // Rozzo ma efficace (per ora)
00047   //
00048 
00049 #ifdef mydebug_sguazz
00050   std::cout << " --------------------------------------------------------------------------" << "\n";   
00051   std::cout << "  Starting a hit quad fast reco " << "\n";   
00052   std::cout << " --------------------------------------------------------------------------" << "\n";   
00053 #endif
00054 
00055   //
00056   // Let's build the 4 hits
00057   TransientTrackingRecHit::ConstRecHitPointer ptth1 = phits[0];
00058   TransientTrackingRecHit::ConstRecHitPointer ptth2 = phits[1];
00059   TransientTrackingRecHit::ConstRecHitPointer mtth1 = mhits[0];
00060   TransientTrackingRecHit::ConstRecHitPointer mtth2 = mhits[1];
00061 
00062   GlobalPoint vHit[4];
00063   vHit[0]=ptth2->globalPosition();
00064   vHit[1]=ptth1->globalPosition();
00065   vHit[2]=mtth1->globalPosition();
00066   vHit[3]=mtth2->globalPosition();
00067   //double zErr2[4];
00068   //zErr2[0]=ptth2->globalPositionError().czz();
00069   //zErr2[1]=ptth1->globalPositionError().czz();
00070   //zErr2[2]=mtth1->globalPositionError().czz();
00071   //zErr2[3]=mtth2->globalPositionError().czz();
00072   //double perpErr2[4];
00073   //perpErr2[0]=ptth2->globalPositionError().rerr(ptth2->globalPosition());
00074   //perpErr2[1]=ptth1->globalPositionError().rerr(ptth1->globalPosition());
00075   //perpErr2[2]=mtth1->globalPositionError().rerr(mtth1->globalPosition());
00076   //perpErr2[3]=mtth2->globalPositionError().rerr(mtth2->globalPosition());
00077 
00078   //Photon source vertex primary vertex
00079   GlobalPoint vgPhotVertex=region.origin();
00080   TVector3 vPhotVertex(vgPhotVertex.x(), vgPhotVertex.y(), vgPhotVertex.z());
00081 
00082   TVector3 h1(vHit[0].x(),vHit[0].y(),vHit[0].z());
00083   TVector3 h2(vHit[1].x(),vHit[1].y(),vHit[1].z());
00084   TVector3 h3(vHit[2].x(),vHit[2].y(),vHit[2].z());
00085   TVector3 h4(vHit[3].x(),vHit[3].y(),vHit[3].z());
00086   
00087   Conv4HitsReco quad(vPhotVertex, h1, h2, h3, h4);
00088   quad.SetMaxNumberOfIterations(100);
00089 #ifdef mydebug_sguazz
00090   quad.Dump();
00091 #endif
00092   TVector3 candVtx;
00093   double candPtPlus, candPtMinus;
00094   //  double truePtPlus, truePtMinus;
00095   double rPlus, rMinus;
00096   int nite = quad.ConversionCandidate(candVtx, candPtPlus, candPtMinus); 
00097 
00098   if ( ! (nite && abs(nite) < 25 && nite != -1000 && nite != -2000) ) return 0;
00099 
00100   TVector3 plusCenter = quad.GetPlusCenter(rPlus);
00101   TVector3 minusCenter = quad.GetMinusCenter(rMinus);
00102  
00103 #ifdef mydebug_sguazz
00104     std::cout << " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << "\n";   
00105     std::cout << " >>>>>>>>>>> Conv Cand: " << " Vertex X: " << candVtx.X() << " [cm] Y: " << candVtx.Y() << " [cm] pt+: " << candPtPlus<< " [GeV] pt-: " << candPtMinus << " [GeV]; #its: " << nite << "\n";   
00106 #endif
00107 
00108 
00109 
00110     //Do a very simple fit to estimate the slope
00111     double quadPhotCotTheta = 0.;
00112     double quadZ0 = 0.;
00113     simpleGetSlope(ptth2, ptth1, mtth1, mtth2, region, quadPhotCotTheta, quadZ0);
00114 
00115 
00116     double quadPhotPhi = (candVtx-vPhotVertex).Phi();
00117 
00118     TVector3 fittedPrimaryVertex(vgPhotVertex.x(), vgPhotVertex.y(),quadZ0);
00119 
00120     candVtx.SetZ(candVtx.Perp()*quadPhotCotTheta+quadZ0);
00121     GlobalPoint convVtxGlobalPoint(candVtx.X(),candVtx.Y(),candVtx.Z());
00122 
00123     //
00124     // Comparing new quad with old quad
00125     //
00126     //Arbitration
00127     Quad thisQuad;
00128     thisQuad.x = candVtx.X();
00129     thisQuad.y = candVtx.Y();
00130     thisQuad.z = candVtx.Z();
00131     thisQuad.ptPlus = candPtPlus;
00132     thisQuad.ptMinus = candPtMinus;
00133     thisQuad.cot = quadPhotCotTheta;
00134     if ( similarQuadExist(thisQuad, quadV) ) return 0;
00135     
00136     // not able to get the mag field... doing the dirty way
00137     //
00138     // Plus
00139     FastHelix helixPlus(ptth2->globalPosition(), ptth1->globalPosition(), convVtxGlobalPoint, es, convVtxGlobalPoint);
00140     GlobalTrajectoryParameters kinePlus = helixPlus.stateAtVertex().parameters();
00141     kinePlus = GlobalTrajectoryParameters(convVtxGlobalPoint,
00142                                           GlobalVector(candPtPlus*cos(quadPhotPhi),candPtPlus*sin(quadPhotPhi),candPtPlus*quadPhotCotTheta),
00143                                           1,
00144                                           & kinePlus.magneticField()
00145                                           );
00146 
00147     //
00148     // Minus
00149     FastHelix helixMinus(mtth2->globalPosition(), mtth1->globalPosition(), convVtxGlobalPoint, es, convVtxGlobalPoint);
00150     GlobalTrajectoryParameters kineMinus = helixMinus.stateAtVertex().parameters();
00151     kineMinus = GlobalTrajectoryParameters(convVtxGlobalPoint,
00152                                           GlobalVector(candPtMinus*cos(quadPhotPhi),candPtMinus*sin(quadPhotPhi),candPtMinus*quadPhotCotTheta),
00153                                           -1,
00154                                           & kineMinus.magneticField()
00155                                           );
00156 
00157     float sinThetaPlus = sin(kinePlus.momentum().theta());
00158     float sinThetaMinus = sin(kineMinus.momentum().theta());
00159     float ptmin = region.ptMin();
00160     //vertexBounds da region
00161     GlobalVector vertexBounds(region.originRBound(),region.originRBound(),region.originZBound());
00162 
00163     CurvilinearTrajectoryError errorPlus = initialError(vertexBounds, ptmin,  sinThetaPlus);
00164     CurvilinearTrajectoryError errorMinus = initialError(vertexBounds, ptmin,  sinThetaMinus);
00165     FreeTrajectoryState ftsPlus(kinePlus, errorPlus);
00166     FreeTrajectoryState ftsMinus(kineMinus, errorMinus);
00167     
00168     //FIXME: here probably you want to go in parallel with phits and mhits
00169     //NB: the seedCollection is filled (the important thing) the return of the last TrajectorySeed is not used, but is needed
00170     //to maintain the inheritance
00171     
00172 #ifdef quadDispLine
00173     double vError = region.originZBound();
00174     if ( vError > 15. ) vError = 1.;
00175     std::cout << "QuadDispLine " 
00176               << vgPhotVertex.x() << " " << vgPhotVertex.y() << " " << vgPhotVertex.z() << " " << vError << " "
00177               << vHit[0].x() << " " << vHit[0].y() << " " << vHit[0].z() << " " << sqrt(getSqrEffectiveErrorOnZ(ptth2, region)) << " "
00178               << vHit[1].x() << " " << vHit[1].y() << " " << vHit[1].z() << " " << sqrt(getSqrEffectiveErrorOnZ(ptth1, region)) << " "
00179               << vHit[2].x() << " " << vHit[2].y() << " " << vHit[2].z() << " " << sqrt(getSqrEffectiveErrorOnZ(mtth1, region)) << " "
00180               << vHit[3].x() << " " << vHit[3].y() << " " << vHit[3].z() << " " << sqrt(getSqrEffectiveErrorOnZ(mtth2, region)) << " "
00181               << candVtx.X() << " " << candVtx.Y() << " " << candVtx.Z() << " "
00182               << fittedPrimaryVertex.X() << " " << fittedPrimaryVertex.Y() << " " << fittedPrimaryVertex.Z() << " "
00183               << candPtPlus  << " " << rPlus << " " << plusCenter.X() << " " << plusCenter.Y() << " " 
00184               << candPtMinus << " " << rMinus << " " << minusCenter.X() << " " << minusCenter.Y() << " " 
00185               << nite << " " << chi2 << "\n";   
00186 #endif
00187 #ifdef mydebug_sguazz
00188     std::cout << " >>>>> Hit quad fast reco done >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" << "\n";   
00189     uint32_t detid;
00190     std::cout << "[SeedForPhotonConversionFromQuadruplets]\n ptth1 " ;
00191     detid=ptth1->geographicalId().rawId();
00192     //    po.print(std::cout , detid );
00193     std::cout << " \t " << detid << " " << ptth1->localPosition()  << " " << ptth1->globalPosition()    ;
00194     detid=ptth2->geographicalId().rawId();
00195     std::cout << " \n\t ptth2 ";
00196     //    po.print(std::cout , detid );
00197     std::cout << " \t " << detid << " " << ptth2->localPosition()  << " " << ptth2->globalPosition()  
00198               << "\nhelix momentum " << kinePlus.momentum() << " pt " << kinePlus.momentum().perp() << " radius " << 1/kinePlus.transverseCurvature() << " q " << kinePlus.charge(); 
00199     std::cout << " \n\t mtth1 ";
00200     detid=mtth1->geographicalId().rawId();
00201     std::cout << " \t " << detid << " " << mtth1->localPosition()  << " " << mtth1->globalPosition()    ;
00202     std::cout << " \n\t mtth2 ";
00203     detid=mtth2->geographicalId().rawId();
00204     //    po.print(std::cout , detid );
00205     std::cout << " \t " << detid << " " << mtth2->localPosition()  << " " << mtth2->globalPosition()  
00206               << "\nhelix momentum " << kineMinus.momentum() << " pt " << kineMinus.momentum().perp() << " radius " << 1/kineMinus.transverseCurvature() << " q " << kineMinus.charge(); 
00207     std::cout << "\n <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" << "\n";   
00208 #endif
00209 
00210     buildSeed(seedCollection,phits,ftsPlus,es); 
00211     return buildSeed(seedCollection,mhits,ftsMinus,es); 
00212 
00213 }
00214 
00215 
00216 GlobalTrajectoryParameters SeedForPhotonConversionFromQuadruplets::initialKinematic(
00217       const SeedingHitSet & hits, 
00218       const GlobalPoint & vertexPos, 
00219       const edm::EventSetup& es,
00220       const float cotTheta) const
00221 {
00222   GlobalTrajectoryParameters kine;
00223 
00224   TransientTrackingRecHit::ConstRecHitPointer tth1 = hits[0];
00225   TransientTrackingRecHit::ConstRecHitPointer tth2 = hits[1];
00226 
00227 
00228   FastHelix helix(tth2->globalPosition(), tth1->globalPosition(), vertexPos, es, vertexPos);
00229   kine = helix.stateAtVertex().parameters();
00230 
00231   //force the pz/pt equal to the measured one
00232   if(fabs(cotTheta)<cotTheta_Max)
00233     kine = GlobalTrajectoryParameters(kine.position(),
00234                                       GlobalVector(kine.momentum().x(),kine.momentum().y(),kine.momentum().perp()*cotTheta),
00235                                       kine.charge(),
00236                                       & kine.magneticField()
00237                                       );
00238   else
00239     kine = GlobalTrajectoryParameters(kine.position(),
00240                                       GlobalVector(kine.momentum().x(),kine.momentum().y(),kine.momentum().perp()*cotTheta_Max),
00241                                       kine.charge(),
00242                                       & kine.magneticField()
00243                                       );
00244 
00245 #ifdef mydebug_seed
00246   uint32_t detid;
00247   (*pss) << "[SeedForPhotonConversionFromQuadruplets] initialKinematic tth1 " ;
00248   detid=tth1->geographicalId().rawId();
00249   po.print(*pss, detid );
00250   (*pss) << " \t " << detid << " " << tth1->localPosition()  << " " << tth1->globalPosition()    ;
00251   detid= tth2->geographicalId().rawId();
00252   (*pss) << " \n\t tth2 ";
00253   po.print(*pss, detid );
00254   (*pss) << " \t " << detid << " " << tth2->localPosition()  << " " << tth2->globalPosition()  
00255          << "\nhelix momentum " << kine.momentum() << " pt " << kine.momentum().perp() << " radius " << 1/kine.transverseCurvature(); 
00256 #endif
00257 
00258   edm::ESHandle<MagneticField> bfield;
00259   es.get<IdealMagneticFieldRecord>().get(bfield);
00260   bool isBOFF = ( std::abs(bfield->inTesla(GlobalPoint(0,0,0)).z()) < 1e-3 );
00261   if (isBOFF && (theBOFFMomentum > 0)) {
00262     kine = GlobalTrajectoryParameters(kine.position(),
00263                               kine.momentum().unit() * theBOFFMomentum,
00264                               kine.charge(),
00265                               &*bfield);
00266   }
00267   return kine;
00268 }
00269 
00270 
00271 
00272 CurvilinearTrajectoryError SeedForPhotonConversionFromQuadruplets::
00273 initialError( 
00274              const GlobalVector& vertexBounds, 
00275              float ptMin,  
00276              float sinTheta) const
00277 {
00278   // Set initial uncertainty on track parameters, using only P.V. constraint and no hit
00279   // information.
00280   GlobalError vertexErr( sqr(vertexBounds.x()), 0, 
00281                          sqr(vertexBounds.y()), 0, 0,
00282                          sqr(vertexBounds.z())
00283                          );
00284   
00285  
00286   AlgebraicSymMatrix55 C = ROOT::Math::SMatrixIdentity();
00287 
00288 // FIXME: minC00. Prevent apriori uncertainty in 1/P from being too small, 
00289 // to avoid instabilities.
00290 // N.B. This parameter needs optimising ...
00291   float sin2th = sqr(sinTheta);
00292   float minC00 = 1.0;
00293   C[0][0] = std::max(sin2th/sqr(ptMin), minC00);
00294   float zErr = vertexErr.czz();
00295   float transverseErr = vertexErr.cxx(); // assume equal cxx cyy
00296   C[3][3] = transverseErr;
00297   C[4][4] = zErr*sin2th + transverseErr*(1-sin2th);
00298 
00299   return CurvilinearTrajectoryError(C);
00300 }
00301 
00302 const TrajectorySeed * SeedForPhotonConversionFromQuadruplets::buildSeed(
00303     TrajectorySeedCollection & seedCollection,
00304     const SeedingHitSet & hits,
00305     const FreeTrajectoryState & fts,
00306     const edm::EventSetup& es) const
00307 {
00308   // get tracker
00309   edm::ESHandle<TrackerGeometry> tracker;
00310   es.get<TrackerDigiGeometryRecord>().get(tracker);
00311   
00312   // get propagator
00313   edm::ESHandle<Propagator>  propagatorHandle;
00314   es.get<TrackingComponentsRecord>().get(thePropagatorLabel, propagatorHandle);
00315   const Propagator*  propagator = &(*propagatorHandle);
00316   
00317   // get updator
00318   KFUpdator  updator;
00319   
00320   // Now update initial state track using information from seed hits.
00321   
00322   TrajectoryStateOnSurface updatedState;
00323   edm::OwnVector<TrackingRecHit> seedHits;
00324   
00325   const TrackingRecHit* hit = 0;
00326   for ( unsigned int iHit = 0; iHit < hits.size() && iHit<1; iHit++) {
00327     hit = hits[iHit]->hit();
00328     TrajectoryStateOnSurface state = (iHit==0) ? 
00329       propagator->propagate(fts,tracker->idToDet(hit->geographicalId())->surface())
00330       : propagator->propagate(updatedState, tracker->idToDet(hit->geographicalId())->surface());
00331     if (!state.isValid()) return 0;
00332     
00333     TransientTrackingRecHit::ConstRecHitPointer tth = hits[iHit]; 
00334     
00335     TransientTrackingRecHit::RecHitPointer newtth =  refitHit( tth, state);
00336 
00337     
00338     if (!checkHit(state,newtth,es)) return 0;
00339 
00340     updatedState =  updator.update(state, *newtth);
00341     if (!updatedState.isValid()) return 0;
00342     
00343     seedHits.push_back(newtth->hit()->clone());
00344 #ifdef mydebug_seed
00345     uint32_t detid = hit->geographicalId().rawId();
00346     (*pss) << "\n[SeedForPhotonConversionFromQuadruplets] hit " << iHit;
00347     po.print(*pss, detid);
00348     (*pss) << " "  << detid << "\t lp " << hit->localPosition()
00349            << " tth " << tth->localPosition() << " newtth " << newtth->localPosition() << " state " << state.globalMomentum().perp();
00350 #endif
00351   } 
00352   
00353   
00354   PTrajectoryStateOnDet const &  PTraj = 
00355       trajectoryStateTransform::persistentState(updatedState, hit->geographicalId().rawId());
00356   
00357   seedCollection.push_back( TrajectorySeed(PTraj,seedHits,alongMomentum));
00358   return &seedCollection.back();
00359 }
00360 
00361 TransientTrackingRecHit::RecHitPointer SeedForPhotonConversionFromQuadruplets::refitHit(
00362       const TransientTrackingRecHit::ConstRecHitPointer &hit, 
00363       const TrajectoryStateOnSurface &state) const
00364 {
00365   //const TransientTrackingRecHit* a= hit.get();
00366   //return const_cast<TransientTrackingRecHit*> (a);
00367   //This was modified otherwise the rechit will have just the local x component and local y=0
00368   // To understand how to modify for pixels
00369 
00370   //const TSiStripRecHit2DLocalPos* b = dynamic_cast<const TSiStripRecHit2DLocalPos*>(a);
00371   //return const_cast<TSiStripRecHit2DLocalPos*>(b);
00372   return hit->clone(state);
00373 }
00374 
00375 //
00376 // Below: stupid utils method by sguazz
00377 //
00378 //
00379 void SeedForPhotonConversionFromQuadruplets::
00380 stupidPrint(std::string s,float* d){
00381   (*pss) << "\n" << s << "\t";
00382   for(size_t i=0;i<2;++i)
00383       (*pss) << std::setw (60)  << d[i] << std::setw(1) << " | ";
00384 }    
00385 
00386 void SeedForPhotonConversionFromQuadruplets::
00387 stupidPrint(std::string s,double* d){
00388   (*pss) << "\n" << s << "\t";
00389   for(size_t i=0;i<2;++i)
00390       (*pss) << std::setw (60) << d[i] << std::setw(1) << " | ";
00391 }    
00392 
00393 void SeedForPhotonConversionFromQuadruplets::
00394 stupidPrint(const char* s,GlobalPoint* d){
00395   (*pss) << "\n" << s << "\t";
00396   for(size_t i=0;i<2;++i)
00397     (*pss) << std::setw(20) << d[i] << " r " << d[i].perp() << " phi " << d[i].phi() << " | ";
00398 }    
00399 
00400 void SeedForPhotonConversionFromQuadruplets::
00401 stupidPrint(const char* s, GlobalPoint* d, int n){
00402   (*pss) << "\n" << s << "\n";
00403   for(int i=0;i<n;++i)
00404     (*pss) << std::setw(20) << d[i] << " r " << d[i].perp() << " phi " << d[i].phi() << "\n";
00405 }    
00406 
00407 #include "DataFormats/Math/interface/deltaPhi.h"
00408 
00409 void SeedForPhotonConversionFromQuadruplets::
00410 bubbleSortVsPhi(GlobalPoint arr[], int n, GlobalPoint vtx) {
00411   bool swapped = true;
00412   int j = 0;
00413   GlobalPoint tmp;
00414   while (swapped) {
00415     swapped = false;
00416     j++;
00417     for (int i = 0; i < n - j; i++) {
00418       if ( reco::deltaPhi( (arr[i]-vtx).phi(), (arr[i + 1]-vtx).phi() ) > 0. ) {
00419         tmp = arr[i];
00420         arr[i] = arr[i + 1];
00421         arr[i + 1] = tmp;
00422         swapped = true;
00423       }
00424     }
00425   }
00426 }
00427 
00428 void SeedForPhotonConversionFromQuadruplets::
00429 bubbleReverseSortVsPhi(GlobalPoint arr[], int n, GlobalPoint vtx) {
00430   bool swapped = true;
00431   int j = 0;
00432   GlobalPoint tmp;
00433   while (swapped) {
00434     swapped = false;
00435     j++;
00436     for (int i = 0; i < n - j; i++) {
00437       if ( reco::deltaPhi( (arr[i]-vtx).phi(), (arr[i + 1]-vtx).phi() ) < 0. ) {
00438         tmp = arr[i];
00439         arr[i] = arr[i + 1];
00440         arr[i + 1] = tmp;
00441         swapped = true;
00442       }
00443     }
00444   }
00445 }
00446 
00447 
00448 double SeedForPhotonConversionFromQuadruplets::
00449 simpleGetSlope(const TransientTrackingRecHit::ConstRecHitPointer &ohit, const TransientTrackingRecHit::ConstRecHitPointer &nohit, const TransientTrackingRecHit::ConstRecHitPointer &ihit, const TransientTrackingRecHit::ConstRecHitPointer &nihit, const TrackingRegion & region, double & cotTheta, double & z0){
00450 
00451   double x[5], y[5], e2y[5];
00452 
00453   //The fit is done filling x with r values, y with z values of the four hits and the vertex
00454   //
00455   //Hits
00456   x[0] = ohit->globalPosition().perp();
00457   y[0] = ohit->globalPosition().z();
00458   e2y[0] = getSqrEffectiveErrorOnZ(ohit, region);
00459   //
00460   x[1] = nohit->globalPosition().perp();
00461   y[1] = nohit->globalPosition().z();
00462   e2y[1] = getSqrEffectiveErrorOnZ(nohit, region);
00463   //
00464   x[2] = nihit->globalPosition().perp();
00465   y[2] = nihit->globalPosition().z();
00466   e2y[2] = getSqrEffectiveErrorOnZ(nihit, region);
00467   //
00468   x[3] = ihit->globalPosition().perp();
00469   y[3] = ihit->globalPosition().z();
00470   e2y[3] = getSqrEffectiveErrorOnZ(ihit, region);
00471   //
00472   //Vertex
00473   x[4] = region.origin().perp();
00474   y[4] = region.origin().z();
00475   double vError = region.originZBound();
00476   if ( vError > 15. ) vError = 1.;
00477   e2y[4] = sqr(vError);
00478 
00479   double e2z0;
00480   double chi2 = verySimpleFit(5, x, y, e2y, z0, e2z0, cotTheta);
00481 
00482   return chi2;
00483 
00484 }
00485 
00486 double SeedForPhotonConversionFromQuadruplets::verySimpleFit(int size, double* ax, double* ay, double* e2y, double& p0, double& e2p0, double& p1){
00487 
00488   //#include "RecoTracker/ConversionSeedGenerators/interface/verySimpleFit.icc"
00489   return 0;
00490 }
00491 
00492 double SeedForPhotonConversionFromQuadruplets::getSqrEffectiveErrorOnZ(const TransientTrackingRecHit::ConstRecHitPointer &hit, const TrackingRegion & region){
00493 
00494   //
00495   //Fit-wise the effective error on Z is the sum in quadrature of the error on Z 
00496   //and the error on R correctly projected by using hit-vertex direction
00497 
00498   double sqrProjFactor = sqr((hit->globalPosition().z()-region.origin().z())/(hit->globalPosition().perp()-region.origin().perp()));
00499   return (hit->globalPositionError().czz()+sqrProjFactor*hit->globalPositionError().rerr(hit->globalPosition()));
00500 
00501 }
00502 
00503 bool SeedForPhotonConversionFromQuadruplets::similarQuadExist(Quad & thisQuad, std::vector<Quad>& quadV){
00504   
00505   BOOST_FOREACH( Quad quad, quadV )
00506     {
00507       double dx = thisQuad.x-quad.x;
00508       double dy = thisQuad.y-quad.y;
00509       double dz = abs(thisQuad.z-quad.z);
00510       if ( sqrt(dx*dx+dy*dy)<1. && 
00511            dz<3. && 
00512            abs(thisQuad.ptPlus-quad.ptPlus)<0.5*quad.ptPlus &&
00513            abs(thisQuad.ptMinus-quad.ptMinus)<0.5*quad.ptMinus &&
00514            abs(thisQuad.cot-quad.cot)<0.3*quad.cot
00515            ) return true;
00516     }
00517   
00518   quadV.push_back(thisQuad);
00519   return false;
00520 
00521 }