CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_1/src/TrackingTools/GeomPropagators/src/HelixArbitraryPlaneCrossing.cc

Go to the documentation of this file.
00001 #include "TrackingTools/GeomPropagators/interface/HelixArbitraryPlaneCrossing.h"
00002 #include "DataFormats/GeometrySurface/interface/Plane.h"
00003 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00004 
00005 #include <cmath>
00006 #include <iostream>
00007 #include "FWCore/Utilities/interface/Likely.h"
00008 
00009 HelixArbitraryPlaneCrossing::HelixArbitraryPlaneCrossing(const PositionType& point,
00010                                                          const DirectionType& direction,
00011                                                          const float curvature,
00012                                                          const PropagationDirection propDir) :
00013   theQuadraticCrossingFromStart(point,direction,curvature,propDir),
00014   theX0(point.x()),
00015   theY0(point.y()),
00016   theZ0(point.z()),
00017   theRho(curvature),
00018   thePropDir(propDir),
00019   theCachedS(0),
00020   theCachedDPhi(0.),
00021   theCachedSDPhi(0.),
00022   theCachedCDPhi(1.)
00023 {
00024   //
00025   // Components of direction vector (with correct normalisation)
00026   //
00027   double px = direction.x();
00028   double py = direction.y();
00029   double pz = direction.z();
00030   double pt2 = px*px+py*py;
00031   double p2 = pt2+pz*pz;
00032   double pI = 1./sqrt(p2);
00033   double ptI = 1./sqrt(pt2);
00034   theCosPhi0 = px*ptI;
00035   theSinPhi0 = py*ptI;
00036   theCosTheta = pz*pI;
00037   theSinTheta = pt2*ptI*pI;
00038 }
00039 //
00040 // Propagation status and path length to intersection
00041 //
00042 std::pair<bool,double>
00043 HelixArbitraryPlaneCrossing::pathLength(const Plane& plane) {
00044   //
00045   // Constants used for control of convergence
00046   //
00047   const int maxIterations(100);
00048   //
00049   // maximum distance to plane (taking into account numerical precision)
00050   //
00051   float maxNumDz = theNumericalPrecision*plane.position().mag();
00052   float safeMaxDist = (theMaxDistToPlane>maxNumDz?theMaxDistToPlane:maxNumDz);
00053   //
00054   // Prepare internal value of the propagation direction and position / direction vectors for iteration 
00055   //
00056   PropagationDirection propDir = thePropDir;
00057   PositionTypeDouble xnew(theX0,theY0,theZ0);
00058   DirectionTypeDouble pnew(theCosPhi0,theSinPhi0,theCosTheta/theSinTheta);
00059   //
00060   // Prepare iterations: count and total pathlength
00061   //
00062   unsigned int iteration(maxIterations+1);
00063   double dSTotal(0.);
00064   //
00065   bool first = true;
00066   while ( notAtSurface(plane,xnew,safeMaxDist) ) {
00067     //
00068     // return empty solution vector if no convergence after maxIterations iterations
00069     //
00070     if unlikely( --iteration == 0 ) {
00071       edm::LogInfo("HelixArbitraryPlaneCrossing") << "pathLength : no convergence";
00072       return std::pair<bool,double>(false,0);
00073     }
00074 
00075     //
00076     // Use existing 2nd order object at first pass, create temporary object
00077     // for subsequent passes.
00078     //
00079     std::pair<bool,double> deltaS2;
00080     if unlikely( first ) {
00081       first = false;
00082       deltaS2 = theQuadraticCrossingFromStart.pathLength(plane);
00083     }
00084     else {
00085       HelixArbitraryPlaneCrossing2Order quadraticCrossing(xnew.x(),xnew.y(),xnew.z(),
00086                                                           pnew.x(),pnew.y(),
00087                                                           theCosTheta,theSinTheta,
00088                                                           theRho,
00089                                                           anyDirection);
00090       
00091       deltaS2 = quadraticCrossing.pathLength(plane);
00092     }
00093      
00094     if unlikely( !deltaS2.first )  return deltaS2;
00095     //
00096     // Calculate and sort total pathlength (max. 2 solutions)
00097     //
00098     dSTotal += deltaS2.second;
00099     PropagationDirection newDir = dSTotal>=0 ? alongMomentum : oppositeToMomentum;
00100     if ( propDir == anyDirection ) {
00101       propDir = newDir;
00102     }
00103     else {
00104       if unlikely( newDir!=propDir )  return std::pair<bool,double>(false,0);
00105     }
00106     //
00107     // Step forward by dSTotal.
00108     //
00109     xnew = positionInDouble(dSTotal);
00110     pnew = directionInDouble(dSTotal);
00111   }
00112   //
00113   // Return result
00114   //
00115   return std::pair<bool,double>(true,dSTotal);
00116 }
00117 //
00118 // Position on helix after a step of path length s.
00119 //
00120 HelixPlaneCrossing::PositionType
00121 HelixArbitraryPlaneCrossing::position (double s) const {
00122   // use result in double precision
00123   PositionTypeDouble pos = positionInDouble(s);
00124   return PositionType(pos.x(),pos.y(),pos.z());
00125 }
00126 //
00127 // Position on helix after a step of path length s in double precision.
00128 //
00129 HelixArbitraryPlaneCrossing::PositionTypeDouble
00130 HelixArbitraryPlaneCrossing::positionInDouble (double s) const {
00131   //
00132   // Calculate delta phi (if not already available)
00133   //
00134   if unlikely( s!=theCachedS ) {
00135     theCachedS = s;
00136     theCachedDPhi = theCachedS*theRho*theSinTheta;
00137     theCachedSDPhi = sin(theCachedDPhi);
00138     theCachedCDPhi = cos(theCachedDPhi);
00139   }
00140   //
00141   // Calculate with appropriate formulation of full helix formula or with 
00142   //   2nd order approximation.
00143   //
00144 //    if ( fabs(theCachedDPhi)>1.e-1 ) {
00145   if ( std::abs(theCachedDPhi)>1.e-4 ) {
00146     // "standard" helix formula
00147     double o = 1./theRho;
00148     return PositionTypeDouble(theX0+(-theSinPhi0*(1.-theCachedCDPhi)+theCosPhi0*theCachedSDPhi)*o,
00149                               theY0+( theCosPhi0*(1.-theCachedCDPhi)+theSinPhi0*theCachedSDPhi)*o,
00150                               theZ0+theCachedS*theCosTheta);
00151     }
00152 //    else if ( fabs(theCachedDPhi)>theNumericalPrecision ) {
00153 //      // full helix formula, but avoiding (1-cos(deltaPhi)) for small angles
00154 //      return PositionTypeDouble(theX0+(-theSinPhi0*theCachedSDPhi*theCachedSDPhi/(1.+theCachedCDPhi)+
00155 //                                   theCosPhi0*theCachedSDPhi)/theRho,
00156 //                            theY0+(theCosPhi0*theCachedSDPhi*theCachedSDPhi/(1.+theCachedCDPhi)+
00157 //                                   theSinPhi0*theCachedSDPhi)/theRho,
00158 //                            theZ0+theCachedS*theCosTheta);
00159 //    }
00160   else {
00161     // Use 2nd order.
00162     return theQuadraticCrossingFromStart.positionInDouble(theCachedS);
00163   }
00164 }
00165 //
00166 // Direction vector on helix after a step of path length s.
00167 //
00168 HelixPlaneCrossing::DirectionType
00169 HelixArbitraryPlaneCrossing::direction (double s) const {
00170   // use result in double precision
00171   DirectionTypeDouble dir = directionInDouble(s);
00172   return DirectionType(dir.x(),dir.y(),dir.z());
00173 }
00174 //
00175 // Direction vector on helix after a step of path length s in double precision.
00176 //
00177 HelixArbitraryPlaneCrossing::DirectionTypeDouble
00178 HelixArbitraryPlaneCrossing::directionInDouble (double s) const {
00179   //
00180   // Calculate delta phi (if not already available)
00181   //
00182   if unlikely( s!=theCachedS ) {
00183     theCachedS = s;
00184     theCachedDPhi = theCachedS*theRho*theSinTheta;
00185     theCachedSDPhi = sin(theCachedDPhi);
00186     theCachedCDPhi = cos(theCachedDPhi);
00187   }
00188 
00189   if ( std::abs(theCachedDPhi)>1.e-4 ) {
00190     // full helix formula
00191     return DirectionTypeDouble(theCosPhi0*theCachedCDPhi-theSinPhi0*theCachedSDPhi,
00192                                theSinPhi0*theCachedCDPhi+theCosPhi0*theCachedSDPhi,
00193                                theCosTheta/theSinTheta);
00194   }
00195   else {
00196     // 2nd order
00197     return theQuadraticCrossingFromStart.directionInDouble(theCachedS);
00198   }
00199 }
00200 //   Iteration control: continue if distance to plane > theMaxDistToPlane. Includes 
00201 //   protection for numerical precision (Surfaces work with single precision).
00202 bool HelixArbitraryPlaneCrossing::notAtSurface (const Plane& plane,                                    
00203                                                 const PositionTypeDouble& point,
00204                                                 const float maxDist) const {
00205   float dz = plane.localZ(Surface::GlobalPoint(point.x(),point.y(),point.z()));
00206   return std::abs(dz)>maxDist;
00207 }
00208 
00209 const float HelixArbitraryPlaneCrossing::theNumericalPrecision = 5.e-7f;
00210 const float HelixArbitraryPlaneCrossing::theMaxDistToPlane = 1.e-4f;