CMS 3D CMS Logo

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