CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_2_9/src/RecoPixelVertexing/PixelTriplets/src/ThirdHitPredictionFromCircle.cc

Go to the documentation of this file.
00001 #include <cmath>
00002 #include "DataFormats/GeometryVector/interface/GlobalVector.h"
00003 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
00004 
00005 #include "RecoTracker/TkMSParametrization/interface/PixelRecoUtilities.h"
00006 #include "RecoTracker/TkMSParametrization/interface/PixelRecoRange.h"
00007 
00008 #include "RecoPixelVertexing/PixelTriplets/interface/ThirdHitPredictionFromCircle.h"
00009 
00010 // there are tons of safety checks.
00011 // Try to move all of the out the regular control flow using gcc magic
00012 
00013 #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
00014 #       define likely(expr) (__builtin_expect(!!(expr), 1))
00015 #       define unlikely(expr) (__builtin_expect(!!(expr), 0))
00016 #else
00017 #       define likely(expr) (expr)
00018 #       define unlikely(expr) (expr)
00019 #endif
00020 
00021 typedef Basic3DVector<double> Point3D;
00022 typedef Basic2DVector<double> Point2D;
00023 
00024 namespace {
00025   template<class T> static inline T sqr(T t) { return t * t; }
00026   template<class T> static inline T sgn(T t) { return std::signbit(t) ? -1. : 1.; }
00027   template<class T> static inline T clamped_acos(T t)
00028   { return unlikely(t <= -1) ? M_PI : unlikely(t >= 1) ? T(0) : std::acos(t); }
00029   template<class T> static inline T clamped_sqrt(T t)
00030   { return likely(t > 0) ? std::sqrt(t) : T(0); }
00031 }
00032 
00033 ThirdHitPredictionFromCircle::ThirdHitPredictionFromCircle( 
00034         const GlobalPoint& P1, const GlobalPoint& P2, float tolerance)
00035   : p1(P1.x(), P1.y()), theTolerance(tolerance)
00036 {
00037   Point2D p2(P2.x(), P2.y());
00038   Point2D diff = 0.5 * (p2 - p1);
00039   delta2 = diff.mag2();
00040   delta = std::sqrt(delta2);
00041   axis = Point2D(-diff.y(), diff.x()) / delta;
00042   center = p1 + diff;
00043 }
00044 
00045 double ThirdHitPredictionFromCircle::phi(double curvature, double radius) const
00046 {
00047   double phi;
00048   if (unlikely(std::abs(curvature) < 1.0e-5)) {
00049     double cos = (center * axis) / radius;
00050     phi = axis.phi() - clamped_acos(cos);
00051   } else {
00052     double sign = sgn(curvature);
00053     double radius2 = sqr(1.0 / curvature);
00054     double orthog = clamped_sqrt(radius2 - delta2);
00055     Basic2DVector<double> lcenter = center - sign * orthog * axis;
00056     double rc2 = lcenter.mag2();
00057     double cos = (rc2 + sqr(radius) - radius2) /
00058       (2. *std:: sqrt(rc2) * radius);
00059     phi = lcenter.phi() + sign * clamped_acos(cos);
00060  }
00061 
00062   while(unlikely(phi >= M_PI)) phi -= 2. * M_PI;
00063   while(unlikely(phi < -M_PI)) phi += 2. * M_PI;
00064 
00065   return phi;
00066 }
00067 
00068 double ThirdHitPredictionFromCircle::angle(double curvature, double radius) const
00069 {
00070   if (unlikely(std::abs(curvature) < 1.0e-5)) {
00071     double sin = (center * axis) / radius;
00072     return sin / clamped_sqrt(1 - sqr(sin));
00073   } else {
00074     double radius2 = sqr(1.0 / curvature);
00075     double orthog = clamped_sqrt(radius2 - delta2);
00076     Basic2DVector<double> lcenter = center - sgn(curvature) * orthog * axis;
00077  
00078     double cos = (radius2 + sqr(radius) - lcenter.mag2()) *
00079                  curvature / (2. * radius);
00080     return - cos / clamped_sqrt(1 - sqr(cos));
00081  }
00082 }
00083 
00084 ThirdHitPredictionFromCircle::Range
00085 ThirdHitPredictionFromCircle::operator()(Range curvature, double radius) const
00086 {
00087   double phi1 = phi(curvature.second, radius);
00088   double phi2 = phi(curvature.first, radius);
00089 
00090   while(unlikely(phi2 <  phi1)) phi2 += 2. * M_PI; 
00091 
00092   return Range(phi1 * radius - theTolerance, phi2 * radius + theTolerance);
00093 }
00094 
00095 ThirdHitPredictionFromCircle::Range
00096 ThirdHitPredictionFromCircle::curvature(double transverseIP) const
00097 {
00098   // this is a mess.  Use a CAS and lots of drawings to verify...
00099 
00100   transverseIP = std::abs(transverseIP);
00101   double transverseIP2 = sqr(transverseIP);
00102   double tip = axis * center;
00103   double tip2 = sqr(tip);
00104   double lip = axis.x() * center.y() - axis.y() * center.x();
00105   double lip2 = sqr(lip);
00106 
00107   double origin = std::sqrt(tip2 + lip2);
00108   double tmp1 = lip2 + tip2 - transverseIP2;
00109   double tmp2 = 2. * (tip - transverseIP) * (tip + transverseIP);
00110   double tmp3 = 2. * delta * origin;
00111   double tmp4 = tmp1 + delta2;
00112   double tmp5 = 2. * delta * lip;
00113 
00114   // I am probably being overly careful here with border cases
00115   // but you never know what crap you might get fed
00116 
00117   double u1, u2;
00118   if (unlikely(tmp4 - tmp5 < 1.0e-5)) {
00119     u1 = -0.;   // yes, I am making use of signed zero
00120     u2 = +0.;   // -> no -ffast-math please
00121   } else {
00122     if (unlikely(std::abs(tmp2) < 1.0e-5)) {
00123       // the denominator is zero
00124       // this means that one of the tracks will be straight
00125       // and the other can be computed from the limit of the equation
00126       double tmp = lip2 - delta2;
00127       u1 = INFINITY;    // and require 1 / sqrt(inf^2 + x) = 0 (with x > 0)
00128       u2 = (sqr(0.5 * tmp) - delta2 * tip2) / (tmp * tip);
00129       if (tip < 0)
00130         std::swap(u1, u2);
00131     } else {
00132       double tmp6 = (tmp4 - tmp5) * (tmp4 + tmp5);
00133       if (unlikely(tmp6 < 1.0e-5)) {
00134         u1 = -0.;
00135         u2 = +0.;
00136       } else {
00137         double tmp7 = tmp6 > 0 ? (transverseIP * std::sqrt(tmp6) / tmp2) : 0.;
00138         double tmp8 = tip * (tmp1 - delta2) / tmp2;
00139         // the two quadratic solutions
00140         u1 = tmp8 + tmp7;
00141         u2 = tmp8 - tmp7;
00142       }
00143     }
00144 
00145     if (tmp4 <= std::abs(tmp3)) {
00146       if ((tmp3 < 0) == (tip < 0))
00147         u2 = +0.;
00148       else
00149         u1 = -0.;
00150     }
00151   }
00152 
00153   return Range(sgn(u1) / std::sqrt(sqr(u1) + delta2),
00154                sgn(u2) / std::sqrt(sqr(u2) + delta2));
00155 }
00156 
00157 double ThirdHitPredictionFromCircle::invCenterOnAxis(const Point2D &p2) const
00158 {
00159   Point2D delta = p2 - p1;
00160   Point2D axis2 = Point2D(-delta.y(), delta.x()) / delta.mag();
00161   Point2D diff = p1 + 0.5 * delta - center;
00162   double a = diff.y() * axis2.x() - diff.x() * axis2.y();
00163   double b = axis.y() * axis2.x() - axis.x() * axis2.y();
00164   return b / a;
00165 }
00166 
00167 double ThirdHitPredictionFromCircle::curvature(const Point2D &p2) const
00168 {
00169   double invDist = invCenterOnAxis(p2);
00170   double invDist2 = sqr(invDist);
00171   double curv = std::sqrt(invDist2 / (1. + invDist2 * delta2));
00172   return sgn(invDist) * curv;
00173 }
00174 
00175 double ThirdHitPredictionFromCircle::transverseIP(const Point2D &p2) const
00176 {
00177   double invDist = invCenterOnAxis(p2);
00178   if (unlikely(std::abs(invDist) < 1.0e-5))
00179     return std::abs(p2 * axis);
00180   else {
00181     double dist = 1.0 / invDist;
00182     double radius = std::sqrt(sqr(dist) + delta2);
00183     return std::abs((center + axis * dist).mag() - radius);
00184   }
00185 }
00186 
00187 ThirdHitPredictionFromCircle::HelixRZ::HelixRZ(
00188   const ThirdHitPredictionFromCircle *circle, double z1, double z2, double curv) :
00189   circle(circle), curvature(curv), z1(z1)
00190 {
00191   double absCurv = std::abs(curv);
00192   seg = circle->delta;
00193 
00194   if (likely(absCurv > 1.0e-5)) {
00195     seg *= absCurv;
00196     seg = seg < -1.0 ? -M_PI_2 : seg > 1.0 ? M_PI_2 : std::asin(seg);
00197     seg /= absCurv;
00198   }
00199 
00200   seg *= 2.;
00201   dzdu = likely(std::abs(seg) > 1.0e-5) ? ((z2 - z1) / seg) : 99999.0;
00202 }
00203 
00204 double ThirdHitPredictionFromCircle::HelixRZ::maxCurvature(
00205   const ThirdHitPredictionFromCircle *circle, double z1, double z2, double z3)
00206 {
00207   static const double maxAngle = M_PI;
00208   double halfAngle = (0.5 * maxAngle) * (z2 - z1) / (z3 - z1);
00209   if (unlikely(halfAngle <= 0.0))
00210     return 0.0;
00211 
00212   return std::sin(halfAngle) / circle->delta;
00213 }
00214 
00215 double ThirdHitPredictionFromCircle::HelixRZ::zAtR(double r) const
00216 {
00217   if (unlikely(std::abs(curvature) < 1.0e-5)) {
00218      double tip = circle->axis * circle->p1;
00219      double lip = circle->axis.y() * circle->p1.x() -
00220                   circle->axis.x() * circle->p1.y();
00221      return z1 + (std::sqrt(sqr(r) - sqr(tip)) - lip) * dzdu;
00222   }
00223 
00224   double radius = 1.0 / curvature;
00225   double radius2 = sqr(radius);
00226   double orthog = sgn(curvature) * clamped_sqrt(radius2 - circle->delta2);
00227   Point2D center = circle->center + orthog * circle->axis;
00228 
00229   double b2 = center.mag2();
00230   double b = std::sqrt(b2);
00231 
00232   double cos1 = 0.5 * (radius2 + b2 - sqr(r)) * curvature / b;
00233   double cos2 = 0.5 * (radius2 + b2 - circle->p1.mag2()) * curvature / b;
00234 
00235   double phi1 = clamped_acos(cos1);
00236   double phi2 = clamped_acos(cos2);
00237 
00238   // more plausbility checks needed...
00239   // the two circles can have two possible intersections
00240   double u1 = std::abs((phi1 - phi2) * radius);
00241   double u2 = std::abs((phi1 + phi2) * radius);
00242 
00243   return z1 + ((u1 >= seg && u1 < u2)? u1 : u2) * dzdu;
00244 }
00245 
00246 double ThirdHitPredictionFromCircle::HelixRZ::rAtZ(double z) const
00247 {
00248   if (unlikely(std::abs(dzdu) < 1.0e-5))
00249     return 99999.0;
00250 
00251   if (unlikely(std::abs(curvature) < 1.0e-5)) {
00252     double tip = circle->axis * circle->p1;
00253     double lip = circle->axis.y() * circle->p1.x() -
00254                  circle->axis.x() * circle->p1.y();
00255     return std::sqrt(sqr(tip) + sqr(lip + (z - z1) / dzdu));
00256   }
00257 
00258   // we won't go below that (see comment below)
00259   double minR = (2. * circle->center - circle->p1).mag();
00260 
00261   double phi = curvature * (z - z1) / dzdu;
00262 
00263   if (unlikely(std::abs(phi) > 2. * M_PI)) {
00264     // with a helix we can get problems here - this is used to get the limits
00265     // however, if phi gets large, we get into the regions where we loop back
00266     // to smaller r's.  The question is - do we care about these tracks?
00267     // The answer is probably no:  Too much pain, and the rest of the
00268     // tracking won't handle looping tracks anyway.
00269     // So, what we do here is to return nothing smaller than the radius
00270     // than any of the two hits, i.e. the second hit, which is presumably
00271     // outside of the 1st hit.
00272 
00273     return minR;
00274   }
00275 
00276   double radius = 1. / curvature;
00277   double orthog = sgn(curvature) * clamped_sqrt(sqr(radius) - circle->delta2);
00278   Point2D center = circle->center + orthog * circle->axis;
00279   Point2D rel = circle->p1 - center;
00280 
00281   double c = cos(phi);
00282   double s = sin(phi);
00283 
00284   Point2D p(center.x() + c * rel.x() - s * rel.y(),
00285             center.y() + s * rel.x() + c * rel.y());
00286 
00287   return std::max(minR, p.mag());
00288 }