CMS 3D CMS Logo

BaseParticlePropagator.cc

Go to the documentation of this file.
00001 //FAMOS headers
00002 #include "FastSimulation/BaseParticlePropagator/interface/BaseParticlePropagator.h"
00003 
00004 BaseParticlePropagator::BaseParticlePropagator() :
00005   RawParticle(), rCyl(0.), rCyl2(0.), zCyl(0.), bField(0), properDecayTime(1E99)
00006 {;}
00007 
00008 BaseParticlePropagator::BaseParticlePropagator( 
00009          const RawParticle& myPart,double R, double Z, double B, double t ) :
00010   RawParticle(myPart), rCyl(R), rCyl2(R*R), zCyl(Z), bField(B), properDecayTime(t) 
00011 {
00012   init();
00013 }
00014 
00015 BaseParticlePropagator::BaseParticlePropagator( 
00016          const RawParticle& myPart,double R, double Z, double B) :
00017   RawParticle(myPart), rCyl(R), rCyl2(R*R), zCyl(Z), bField(B), properDecayTime(1E99) 
00018 {
00019   init();
00020 }
00021 
00022 void 
00023 BaseParticlePropagator::init() {
00024   
00025   // The status of the propagation
00026   success = 0;
00027   // Propagate only for the first half-loop
00028   firstLoop = true;
00029   //
00030   fiducial = true;
00031   // The particle has not yet decayed
00032   decayed = false;
00033   // The proper time is set to zero
00034   properTime = 0.;
00035   // The propagation direction is along the momentum
00036   propDir = 1;
00037   //
00038   debug = false;
00039 
00040 }
00041 
00042 bool 
00043 BaseParticlePropagator::propagate() { 
00044 
00045   //
00046   // Check that the particle is not already on the cylinder surface
00047   //
00048   double rPos2 = R2();
00049 
00050   if ( onBarrel(rPos2) ) { 
00051     success = 1;
00052     return true;
00053   }
00054   //
00055   if ( onEndcap(rPos2) ) { 
00056     success = 2;
00057     return true;
00058   }
00059   //
00060   // Treat neutral particles (or no magnetic field) first 
00061   //
00062   if ( fabs(charge()) < 1E-12 || bField < 1E-12 ) {
00063 
00064     //
00065     // First check that the particle crosses the cylinder
00066     //
00067     double pT2 = Perp2();
00068     //    double pT2 = pT*pT;
00069     //    double b2 = rCyl * pT;
00070     double b2 = rCyl2 * pT2;
00071     double ac = fabs ( X()*Py() - Y()*Px() );
00072     double ac2 = ac*ac;
00073     //
00074     // The particle never crosses (or never crossed) the cylinder
00075     //
00076     //    if ( ac > b2 ) return false;
00077     if ( ac2 > b2 ) return false;
00078 
00079     //    double delta  = std::sqrt(b2*b2 - ac*ac);
00080     double delta  = std::sqrt(b2 - ac2);
00081     double tplus  = -( X()*Px()+Y()*Py() ) + delta;
00082     double tminus = -( X()*Px()+Y()*Py() ) - delta;
00083     //
00084     // Find the first (time-wise) intersection point with the cylinder
00085     //
00086 
00087     double solution = tminus < 0 ? tplus/pT2 : tminus/pT2;
00088     if ( solution < 0. ) return false;
00089     //
00090     // Check that the particle does (did) not exit from the endcaps first.
00091     //
00092     double zProp = Z() + Pz() * solution;
00093     if ( fabs(zProp) > zCyl ) {
00094       tplus  = ( zCyl - Z() ) / Pz();
00095       tminus = (-zCyl - Z() ) / Pz();
00096       solution = tminus < 0 ? tplus : tminus;
00097       if ( solution < 0. ) return false;
00098       zProp = Z() + Pz() * solution;
00099       success = 2;
00100     }
00101     else {
00102       success = 1;
00103     }
00104 
00105     //
00106     // Check the decay time
00107     //
00108     double delTime = propDir * (zProp-Z())*mass()/Pz();
00109     double factor = 1.;
00110     properTime += delTime;
00111     if ( properTime > properDecayTime ) {
00112       factor = 1.-(properTime-properDecayTime)/delTime;
00113       properTime = properDecayTime;
00114       decayed = true;
00115     }
00116 
00117     //
00118     // Compute the coordinates of the RawParticle after propagation
00119     //
00120     double xProp = X() + Px() * solution * factor;
00121     double yProp = Y() + Py() * solution * factor;
00122            zProp = Z() + Pz() * solution * factor;
00123     double tProp = T() + E()  * solution * factor;
00124 
00125     //
00126     // Last check : Although propagated to the endcaps, R could still be
00127     // larger than rCyl because the cylinder was too short...
00128     //
00129     if ( success == 2 && xProp*xProp+yProp*yProp > rCyl2 ) { 
00130       success = -1;
00131       return true;
00132     }
00133 
00134     //
00135     // ... and update the particle with its propagated coordinates
00136     //
00137     setVertex( XYZTLorentzVector(xProp,yProp,zProp,tProp) );
00138     
00139     return true;
00140   }
00141   //
00142   // Treat charged particles with magnetic field next.
00143   //
00144   else {
00145     //
00146     // First check that the particle can cross the cylinder
00147     //
00148     double pT = Pt();
00149     double radius = helixRadius(pT);
00150     double phi0 = helixStartPhi();
00151     double xC = helixCentreX(radius,phi0);
00152     double yC = helixCentreY(radius,phi0);
00153     double dist = helixCentreDistToAxis(xC,yC);
00154     //
00155     // The helix either is outside or includes the cylinder -> no intersection
00156     //
00157     if ( fabs ( fabs(radius) - dist ) > rCyl ) return false;
00158     //
00159     // The particle is already away from the endcaps, and will never come back
00160     // Could be back-propagated, so warn the user that it is so.
00161     // 
00162     if ( Z() * Pz() > zCyl * fabs(Pz()) ) { 
00163       success = -2;
00164       return true;
00165     }
00166 
00167     double pZ = Pz();
00168     double phiProp, zProp;
00169     //
00170     // Does the helix cross the cylinder barrel ? If not, do the first half-loop
00171     //
00172     double rProp = std::min(fabs(radius)+dist-0.000001, rCyl);
00173 
00174     // Check for rounding errors in the ArcSin.
00175     double sinPhiProp = 
00176       (rProp*rProp-radius*radius-dist*dist)/( 2.*dist*radius);
00177     //
00178     double deltaPhi = 1E99;
00179 
00180     // Taylor development up to third order for large momenta 
00181     if ( 1.-fabs(sinPhiProp) < 1E-12 ) { 
00182 
00183       double cphi0 = std::cos(phi0);
00184       double sphi0 = std::sin(phi0);
00185       double r0 = (X()*cphi0 + Y()*sphi0)/radius;
00186       double q0 = (X()*sphi0 - Y()*cphi0)/radius;
00187       double rcyl2 = (rCyl2 - X()*X() - Y()*Y())/(radius*radius);
00188       double delta = r0*r0 + rcyl2*(1.-q0);
00189 
00190       // This is a solution of a second order equation, assuming phi = phi0 + epsilon
00191       // and epsilon is small. 
00192       deltaPhi = radius > 0 ? 
00193         ( -r0 + std::sqrt(delta ) ) / (1.-q0) :   
00194         ( -r0 - std::sqrt(delta ) ) / (1.-q0); 
00195       
00196     }
00197 
00198     // Use complete calculation otherwise, or if the delta phi is large anyway.
00199     if ( fabs(deltaPhi) > 1E-3 ) { 
00200 
00201     //    phiProp =  fabs(sinPhiProp) < 0.99999999  ? 
00202     //      std::asin(sinPhiProp) : M_PI/2. * sinPhiProp;
00203       phiProp =  std::asin(sinPhiProp);
00204 
00205       //
00206       // Compute phi after propagation (two solutions, but the asin definition
00207       // (between -pi/2 and +pi/2) takes care of the wrong one.
00208       //
00209       phiProp = helixCentrePhi(xC,yC) + 
00210         ( inside(rPos2) || onSurface(rPos2) ? phiProp : M_PI-phiProp ); 
00211       
00212       //
00213       // Solve the obvious two-pi ambiguities: more than one turn!
00214       //
00215       if ( fabs(phiProp - phi0) > 2.*M_PI )
00216         phiProp += ( phiProp > phi0 ? -2.*M_PI : +2.*M_PI );
00217       
00218       //
00219       // Check that the phi difference has the right sign, according to Q*B
00220       // (Another two pi ambuiguity, slightly more subtle)
00221       //
00222       if ( (phiProp-phi0)*radius < 0.0 )
00223         radius > 0.0 ? phiProp += 2 * M_PI : phiProp -= 2 * M_PI;
00224       
00225     } else { 
00226 
00227       // Use Taylor
00228       phiProp = phi0 + deltaPhi;
00229 
00230     }
00231 
00232     //
00233     // Check that the particle does not exit from the endcaps first.
00234     //
00235     zProp = Z() + ( phiProp - phi0 ) * pZ * radius / pT ;
00236     if ( fabs(zProp) > zCyl ) {
00237 
00238       zProp = zCyl * fabs(pZ)/pZ;
00239       phiProp = phi0 + (zProp - Z()) / radius * pT / pZ;
00240       success = 2;
00241 
00242     } else {
00243 
00244       //
00245       // If the particle does not cross the barrel, either process the
00246       // first-half loop only or propagate all the way down to the endcaps
00247       //
00248       if ( rProp < rCyl ) {
00249 
00250         if ( firstLoop ) {
00251 
00252           success = 0;
00253 
00254         } else {
00255 
00256           zProp = zCyl * fabs(pZ)/pZ;
00257           phiProp = phi0 + (zProp - Z()) / radius * pT / pZ;
00258           success = 2;
00259 
00260         }
00261       //
00262       // The particle crossed the barrel 
00263       // 
00264       } else {
00265 
00266         success = 1;
00267 
00268       }
00269     }
00270     //
00271     // Compute the coordinates of the RawParticle after propagation
00272     //
00273     //
00274     // Check the decay time
00275     //
00276     double delTime = propDir * (zProp-Z())*mass() / pZ;
00277     double factor = 1.;
00278     properTime += delTime;
00279     if ( properTime > properDecayTime ) {
00280       factor = 1.-(properTime-properDecayTime)/delTime;
00281       properTime = properDecayTime;
00282       decayed = true;
00283     }
00284 
00285     zProp = Z() + (zProp-Z())*factor;
00286 
00287     phiProp = phi0 + (zProp - Z()) / radius * pT / pZ;
00288 
00289     double sProp = std::sin(phiProp);
00290     double cProp = std::cos(phiProp);
00291     double xProp = xC + radius * sProp;
00292     double yProp = yC - radius * cProp;
00293     double tProp = T() + (zProp-Z())*E()/pZ;
00294     double pxProp = pT * cProp;
00295     double pyProp = pT * sProp;
00296 
00297     //
00298     // Last check : Although propagated to the endcaps, R could still be
00299     // larger than rCyl because the cylinder was too short...
00300     //
00301     if ( success == 2 && xProp*xProp+yProp*yProp > rCyl2 ) { 
00302       success = -1;
00303       return true;
00304     }
00305     //
00306     // ... and update the particle vertex and momentum
00307     //
00308     setVertex( XYZTLorentzVector(xProp,yProp,zProp,tProp) );
00309     SetXYZT(pxProp,pyProp,pZ,E());
00310     //    SetPx(pxProp);
00311     //    SetPy(pyProp);
00312     return true;
00313  
00314   }
00315 }
00316 
00317 bool
00318 BaseParticlePropagator::backPropagate() {
00319 
00320   // Backpropagate
00321   SetXYZT(-Px(),-Py(),-Pz(),E());
00322   setCharge(-charge());
00323   propDir = -1;
00324   bool done = propagate();
00325   SetXYZT(-Px(),-Py(),-Pz(),E());
00326   setCharge(-charge());
00327   propDir = +1;
00328 
00329   return done;
00330 }
00331 
00332 BaseParticlePropagator
00333 BaseParticlePropagator::propagated() const {
00334   // Copy the input particle in a new instance
00335   BaseParticlePropagator myPropPart(*this);
00336   // Allow for many loops
00337   myPropPart.firstLoop=false;
00338   // Propagate the particle ! 
00339   myPropPart.propagate();
00340   // Back propagate if the forward propagation was not a success
00341   if (myPropPart.success < 0 )
00342     myPropPart.backPropagate();
00343   // Return the new instance
00344   return myPropPart;
00345 }
00346 
00347 void 
00348 BaseParticlePropagator::setPropagationConditions(double R, double Z, bool f) { 
00349   rCyl = R;
00350   rCyl2 = R*R;
00351   zCyl = Z;
00352   firstLoop = f;
00353 }
00354 
00355 bool
00356 BaseParticlePropagator::propagateToClosestApproach(double x0, double y0, bool first) {
00357 
00358   // Pre-computed quantities
00359   double pT = Pt();
00360   double radius = helixRadius(pT);
00361   double phi0 = helixStartPhi();
00362 
00363   // The Helix centre coordinates are computed wrt to the z axis
00364   // Actually the z axis might be centred on 0,0: it's the beam spot position (x0,y0)!
00365   double xC = helixCentreX(radius,phi0);
00366   double yC = helixCentreY(radius,phi0);
00367   double distz = helixCentreDistToAxis(xC-x0,yC-y0);
00368   double dist0 = helixCentreDistToAxis(xC,yC);
00369 
00370   //
00371   // Propagation to point of clostest approach to z axis
00372   //
00373   double rz,r0,z;
00374   if ( charge() != 0.0 && bField != 0.0 ) {
00375     rz = fabs ( fabs(radius) - distz ) + std::sqrt(x0*x0+y0*y0) + 0.0000001;
00376     r0 = fabs ( fabs(radius) - dist0 ) + 0.0000001;
00377   } else {
00378     rz = fabs( Px() * (Y()-y0) - Py() * (X()-x0) ) / Pt(); 
00379     r0 = fabs( Px() *  Y()     - Py() *  X() ) / Pt(); 
00380   }
00381 
00382   z = 999999.;
00383 
00384   // Propagate to the first interesection point 
00385   // with cylinder of radius sqrt(x0**2+y0**2)
00386   setPropagationConditions(rz , z, first);
00387   bool done = backPropagate();
00388 
00389   // Unsuccessful propagation - should not happen!
00390   if ( !done ) return done; 
00391 
00392   // The z axis is (0,0) - no need to go further
00393   if ( fabs(rz-r0) < 1E-10 ) return done;
00394   double dist1 = (X()-x0)*(X()-x0) + (Y()-y0)*(Y()-y0);
00395 
00396   // We are already at closest approach - no need to go further
00397   if ( dist1 < 1E-10 ) return done;
00398 
00399   // Keep for later if it happens to be the right solution
00400   XYZTLorentzVector vertex1 = vertex();
00401   XYZTLorentzVector momentum1 = momentum();
00402   
00403   // Propagate to the distance of closest approach to (0,0)
00404   setPropagationConditions(r0 , z, first);
00405   done = backPropagate();
00406   if ( !done ) return done; 
00407 
00408   // Propagate to the first interesection point 
00409   // with cylinder of radius sqrt(x0**2+y0**2)
00410   setPropagationConditions(rz , z, first);
00411   done = backPropagate();
00412   if ( !done ) return done; 
00413   double dist2 = (X()-x0)*(X()-x0) + (Y()-y0)*(Y()-y0);
00414 
00415   // Keep the good solution.
00416   if ( dist2 > dist1 ) { 
00417     setVertex(vertex1);
00418     SetXYZT(momentum1.X(),momentum1.Y(),momentum1.Z(),momentum1.E());
00419     dist2 = dist1;
00420   }
00421 
00422   // Done
00423   return done;
00424 
00425 }
00426 
00427 bool
00428 BaseParticlePropagator::propagateToEcal(bool first) {
00429   //
00430   // Propagation to Ecal (including preshower) after the
00431   // last Tracker layer
00432   // TODO: include proper geometry
00433   // Geometry taken from CMS ECAL TDR
00434   //
00435   // First propagate to global barrel / endcap cylinder 
00436   //  setPropagationConditions(1290. , 3045 , first);
00437   //  New position of the preshower as of CMSSW_1_7_X
00438   setPropagationConditions(129.0 , 303.353 , first);
00439   return propagate();
00440 
00441 }
00442 
00443 bool
00444 BaseParticlePropagator::propagateToPreshowerLayer1(bool first) {
00445   //
00446   // Propagation to Preshower Layer 1
00447   // TODO: include proper geometry
00448   // Geometry taken from CMS ECAL TDR
00449   //
00450   // First propagate to global barrel / endcap cylinder 
00451   //  setPropagationConditions(1290., 3045 , first);
00452   //  New position of the preshower as of CMSSW_1_7_X
00453   setPropagationConditions(129.0, 303.353 , first);
00454   bool done = propagate();
00455 
00456   // Check that were are on the Layer 1 
00457   if ( done && (R2() > 125.0*125.0 || R2() < 45.0*45.0) ) 
00458     success = 0;
00459   
00460   return done;
00461 }
00462 
00463 bool
00464 BaseParticlePropagator::propagateToPreshowerLayer2(bool first) {
00465   //
00466   // Propagation to Preshower Layer 2
00467   // TODO: include proper geometry
00468   // Geometry taken from CMS ECAL TDR
00469   //
00470   // First propagate to global barrel / endcap cylinder 
00471   //  setPropagationConditions(1290. , 3090 , first);
00472   //  New position of the preshower as of CMSSW_1_7_X
00473   setPropagationConditions(129.0 , 307.838 , first);
00474   bool done = propagate();
00475 
00476   // Check that we are on Layer 2 
00477   if ( done && (R2() > 125.0*125.0 || R2() < 45.0*45.0 ) )
00478     success = 0;
00479 
00480   return done;
00481 
00482 }
00483 
00484 bool
00485 BaseParticlePropagator::propagateToEcalEntrance(bool first) {
00486   //
00487   // Propagation to ECAL entrance
00488   // TODO: include proper geometry
00489   // Geometry taken from CMS ECAL TDR
00490   //
00491   // First propagate to global barrel / endcap cylinder 
00492   setPropagationConditions(129.0 , 320.9,first);
00493   bool done = propagate();
00494 
00495   // Go to endcap cylinder in the "barrel cut corner" 
00496   // eta = 1.479 -> cos^2(theta) = 0.81230
00497   //  if ( done && eta > 1.479 && success == 1 ) {
00498   if ( done && cos2ThetaV() > 0.81230 && success == 1 ) {
00499     setPropagationConditions(152.6 , 320.9, first);
00500     done = propagate();
00501   }
00502 
00503   // We are not in the ECAL acceptance
00504   // eta = 3.0 -> cos^2(theta) = 0.99013
00505   if ( cos2ThetaV() > 0.99014 ) success = 0;
00506 
00507   return done;
00508 }
00509 
00510 bool
00511 BaseParticlePropagator::propagateToHcalEntrance(bool first) {
00512   //
00513   // Propagation to HCAL entrance
00514   // TODO: include proper geometry
00515   // Geometry taken from DAQ TDR Chapter 13
00516   //
00517 
00518   // First propagate to global barrel / endcap cylinder 
00519   setPropagationConditions(183.0 , 388.0, first);
00520   propDir = 0;
00521   bool done = propagate();
00522   propDir = 1;
00523 
00524   // We are not in the HCAL acceptance
00525   // eta = 3.0 -> cos^2(theta) = 0.99014
00526   if ( done && cos2ThetaV() > 0.99014 ) success = 0;
00527 
00528   return done;
00529 }
00530 
00531 bool
00532 BaseParticlePropagator::propagateToVFcalEntrance(bool first) {
00533   //
00534   // Propagation to VFCAL entrance
00535   // TODO: include proper geometry
00536   // Geometry taken from DAQ TDR Chapter 13
00537 
00538   setPropagationConditions(200.0 , 1110.0, first);
00539   propDir = 0;
00540   bool done = propagate();
00541   propDir = 1;
00542 
00543   // We are not in the VFCAL acceptance
00544   // eta = 3.0 -> cos^2(theta) = 0.99014
00545   // eta = 5.0 -> cos^2(theta) = 0.9998184
00546   double c2teta = cos2ThetaV();
00547   if ( done && ( c2teta < 0.99014 || c2teta > 0.9998184 ) ) success = 0;
00548 
00549   return done;
00550 }
00551 
00552 bool
00553 BaseParticlePropagator::propagateToHcalExit(bool first) {
00554   //
00555   // Propagation to HCAL exit
00556   // TODO: include proper geometry
00557   // Geometry taken from DAQ TDR Chapter 13
00558   //
00559 
00560   // Approximate it to a single cylinder as it is not that crucial.
00561   setPropagationConditions(285.0 , 560.0, first);
00562   //  this->rawPart().setCharge(0.0); ?? Shower Propagation ??
00563   propDir = 0;
00564   bool done = propagate();
00565   propDir = 1;
00566 
00567   return done;
00568 }
00569 
00570 bool
00571 BaseParticlePropagator::propagateToNominalVertex(const XYZTLorentzVector& v) 
00572 {
00573 
00574 
00575   // Not implemented for neutrals (used for electrons only)
00576   if ( charge() == 0. || bField == 0.) return false;
00577 
00578   // Define the proper pT direction to meet the point (vx,vy) in (x,y)
00579   double dx = X()-v.X();
00580   double dy = Y()-v.Y();
00581   double phi = std::atan2(dy,dx) + std::asin ( std::sqrt(dx*dx+dy*dy)/(2.*helixRadius()) );
00582 
00583   // The absolute pT (kept to the original value)
00584   double pT = pt();
00585 
00586   // Set the new pT
00587   SetPx(pT*std::cos(phi));
00588   SetPy(pT*std::sin(phi));
00589 
00590   return propagateToClosestApproach(v.X(),v.Y());
00591   
00592 }
00593 
00594 bool
00595 BaseParticlePropagator::propagateToBeamCylinder(const XYZTLorentzVector& v, double radius) 
00596 {
00597 
00598   // For neutral (or BField = 0, simply check that the track passes through the cylinder
00599   if ( charge() == 0. || bField == 0.) 
00600     return fabs( Px() * Y() - Py() * X() ) / Pt() < radius; 
00601 
00602   // Now go to the charged particles
00603 
00604   // A few needed intermediate variables (to make the code understandable)
00605   // The inner cylinder
00606   double r = radius;
00607   double r2 = r*r;
00608   double r4 = r2*r2;
00609   // The two hits
00610   double dx = X()-v.X();
00611   double dy = Y()-v.Y();
00612   double dz = Z()-v.Z();
00613   double Sxy = X()*v.X() + Y()*v.Y();
00614   double Dxy = Y()*v.X() - X()*v.Y();
00615   double Dxy2 = Dxy*Dxy;
00616   double Sxy2 = Sxy*Sxy;
00617   double SDxy = dx*dx + dy*dy;
00618   double SSDxy = std::sqrt(SDxy);
00619   double ATxy = std::atan2(dy,dx);
00620   // The coefficients of the second order equation for the trajectory radius
00621   double a = r2 - Dxy2/SDxy;
00622   double b = r * (r2 - Sxy);
00623   double c = r4 - 2.*Sxy*r2 + Sxy2 + Dxy2;
00624 
00625   // Here are the four possible solutions for
00626   // 1) The trajectory radius
00627   std::vector<double> helixRs(4,static_cast<double>(0.));
00628   helixRs[0] = (b - std::sqrt(b*b - a*c))/(2.*a); 
00629   helixRs[1] = (b + std::sqrt(b*b - a*c))/(2.*a); 
00630   helixRs[2] = -helixRs[0]; 
00631   helixRs[3] = -helixRs[1]; 
00632   // 2) The azimuthal direction at the second point
00633   std::vector<double> helixPhis(4,static_cast<double>(0.));
00634   helixPhis[0] = std::asin ( SSDxy/(2.*helixRs[0]) );
00635   helixPhis[1] = std::asin ( SSDxy/(2.*helixRs[1]) );
00636   helixPhis[2] = -helixPhis[0];
00637   helixPhis[3] = -helixPhis[1];
00638   // Only two solutions are valid though
00639   double solution1=0.;
00640   double solution2=0.;
00641   double phi1=0.;
00642   double phi2=0.;
00643   // Loop over the four possibilities
00644   for ( unsigned int i=0; i<4; ++i ) {
00645     helixPhis[i] = ATxy + helixPhis[i];
00646     // The centre of the helix
00647     double xC = helixCentreX(helixRs[i],helixPhis[i]);
00648     double yC = helixCentreY(helixRs[i],helixPhis[i]);
00649     // The distance of that centre to the origin
00650     double dist = helixCentreDistToAxis(xC, yC);
00651     /*
00652     std::cout << "Solution "<< i << " = " << helixRs[i] << " accepted ? " 
00653               << fabs(fabs(helixRs[i]) - dist ) << " - " << radius << " = " 
00654               << fabs(fabs(helixRs[i]) - dist ) - fabs(radius) << " " 
00655               << ( fabs( fabs(fabs(helixRs[i]) - dist) -fabs(radius) ) < 1e-6)  << std::endl;
00656     */
00657     // Check that the propagation will lead to a trajectroy tangent to the inner cylinder
00658     if ( fabs( fabs(fabs(helixRs[i]) - dist) -fabs(radius) ) < 1e-6 ) { 
00659       // Fill first solution
00660       if ( solution1 == 0. ) { 
00661         solution1 = helixRs[i];
00662         phi1 = helixPhis[i];
00663       // Fill second solution (ordered)
00664       } else if ( solution2 == 0. ) {
00665         if ( helixRs[i] < solution1 ) {
00666           solution2 = solution1;
00667           solution1 = helixRs[i];
00668           phi2 = phi1;
00669           phi1 = helixPhis[i];
00670         } else {
00671           solution2 = helixRs[i];
00672           phi2 = helixPhis[i];
00673         }
00674       // Must not happen! 
00675       } else { 
00676         std::cout << "warning !!! More than two solutions for this track !!! " << std::endl;
00677       }
00678     }
00679   }
00680 
00681   // Find the largest possible pT compatible with coming from within the inne cylinder
00682   double pT = 0.;
00683   double helixPhi = 0.;
00684   double helixR = 0.;
00685   // This should not happen
00686   if ( solution1*solution2 == 0. ) { 
00687     std::cout << "warning !!! Less than two solution for this track! " 
00688               << solution1 << " " << solution2 << std::endl;
00689     return false;
00690   // If the two solutions have opposite sign, it means that pT = infinity is a possibility.
00691   } else if ( solution1*solution2 < 0. ) { 
00692     pT = 1000.;
00693     double norm = pT/std::sqrt(SDxy);
00694     setCharge(+1.);
00695     SetXYZT(dx*norm,dy*norm,dz*norm,0.);
00696     SetE(std::sqrt(Vect().Mag2()));
00697   // Otherwise take the solution that gives the largest transverse momentum 
00698   } else { 
00699     if (solution1<0.) { 
00700       helixR   = solution1;
00701       helixPhi = phi1;
00702       pT = fabs(solution1) * 1e-5 * c_light() *bField;
00703       setCharge(+1.);
00704     } else {
00705       helixR = solution2;
00706       helixPhi = phi2;
00707       pT = fabs(solution2) * 1e-5 * c_light() *bField;
00708       setCharge(-1.);
00709     }
00710     double norm = pT/std::sqrt(SDxy);
00711     SetXYZT(pT*std::cos(helixPhi),pT*std::sin(helixPhi),dz*norm,0.);
00712     SetE(std::sqrt(Vect().Mag2()));      
00713   }
00714     
00715   // Propagate to closest approach to get the Z value (a bit of an overkill)
00716   return propagateToClosestApproach();
00717   
00718 }
00719 
00720 double 
00721 BaseParticlePropagator::xyImpactParameter(double x0, double y0) const {
00722 
00723   double ip=0.;
00724   double pT = Pt();
00725 
00726   if ( charge() != 0.0 && bField != 0.0 ) {
00727     double radius = helixRadius(pT);
00728     double phi0 = helixStartPhi();
00729     
00730     // The Helix centre coordinates are computed wrt to the z axis
00731     double xC = helixCentreX(radius,phi0);
00732     double yC = helixCentreY(radius,phi0);
00733     double distz = helixCentreDistToAxis(xC-x0,yC-y0);
00734     ip = distz - fabs(radius);
00735   } else {
00736     ip = fabs( Px() * (Y()-y0) - Py() * (X()-x0) ) / pT; 
00737   }
00738 
00739   return ip;
00740 
00741 }

Generated on Tue Jun 9 17:35:00 2009 for CMSSW by  doxygen 1.5.4