CMS 3D CMS Logo

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