00001 #include "RecoPixelVertexing/PixelLowPtUtilities/interface/ThirdHitPrediction.h"
00002
00003 #include "DataFormats/GeometryVector/interface/GlobalPoint.h"
00004
00005 #include "TrackingTools/DetLayers/interface/BarrelDetLayer.h"
00006 #include "TrackingTools/DetLayers/interface/ForwardDetLayer.h"
00007 #include "TrackingTools/DetLayers/interface/DetLayer.h"
00008
00009 #include "RecoTracker/TkMSParametrization/interface/MultipleScatteringParametrisation.h"
00010 #include "RecoPixelVertexing/PixelTrackFitting/src/CircleFromThreePoints.h"
00011
00012 #include "MagneticField/Engine/interface/MagneticField.h"
00013 #include "MagneticField/Records/interface/IdealMagneticFieldRecord.h"
00014
00015 #include "TrackingTools/TransientTrackingRecHit/interface/TransientTrackingRecHitBuilder.h"
00016 #include "TrackingTools/Records/interface/TransientRecHitRecord.h"
00017
00018 inline float sqr(float x) { return x*x; }
00019
00020 using namespace std;
00021
00022
00023 ThirdHitPrediction::ThirdHitPrediction
00024 (const TrackingRegion & region, GlobalPoint inner, GlobalPoint outer,
00025 const edm::EventSetup& es,
00026 double nSigMultipleScattering, double maxAngleRatio,
00027 string builderName)
00028 {
00029 using namespace edm;
00030 ESHandle<MagneticField> magfield;
00031 es.get<IdealMagneticFieldRecord>().get(magfield);
00032
00033 edm::ESHandle<TransientTrackingRecHitBuilder> ttrhbESH;
00034 es.get<TransientRecHitRecord>().get(builderName,ttrhbESH);
00035 theTTRecHitBuilder = ttrhbESH.product();
00036
00037 Bz = fabs(magfield->inInverseGeV(GlobalPoint(0,0,0)).z());
00038
00039 c0 = Global2DVector(region.origin().x(),
00040 region.origin().y());
00041
00042 r0 = region.originRBound();
00043 rm = region.ptMin() / Bz;
00044
00045 g1 = inner;
00046 g2 = outer;
00047
00048 p1 = Global2DVector(g1.x(), g1.y());
00049 p2 = Global2DVector(g2.x(), g2.y());
00050
00051 dif = p1 - p2;
00052
00053
00054 keep = true;
00055 arc_0m = findArcIntersection(findMinimalCircles (rm),
00056 findTouchingCircles(r0), keep);
00057
00058 nSigma = nSigMultipleScattering;
00059 maxRatio = maxAngleRatio;
00060 }
00061
00062
00063 ThirdHitPrediction::~ThirdHitPrediction()
00064 {
00065 }
00066
00067
00068 void ThirdHitPrediction::invertCircle(Global2DVector& c,float& r)
00069 {
00070 float s = dif.mag2() / ((c - p1).mag2() - sqr(r));
00071
00072 c = p1 + (c - p1)*s;
00073 r *= fabsf(s);
00074 }
00075
00076
00077 void ThirdHitPrediction::invertPoint(Global2DVector& p)
00078 {
00079 float s = dif.mag2() / (p - p1).mag2();
00080
00081 p = p1 + (p - p1)*s;
00082 }
00083
00084
00085 pair<float,float> ThirdHitPrediction::findMinimalCircles(float r)
00086 {
00087 pair<float,float> a(0.,0.);
00088
00089 if(dif.mag2() < 2 * sqr(r))
00090 a = pair<float,float>( dif.phi(),
00091 0.5*acos(1 - 0.5 * dif.mag2()/sqr(r)) );
00092
00093 return a;
00094 }
00095
00096
00097 pair<float,float> ThirdHitPrediction::findTouchingCircles(float r)
00098 {
00099 Global2DVector c = c0;
00100 invertCircle(c,r);
00101
00102 pair<float,float> a(0.,0.);
00103 a = pair<float,float>( (c - p2).phi(),
00104 0.5*acos(1 - 2*sqr(r)/(c - p2).mag2()) );
00105
00106 return a;
00107 }
00108
00109
00110 pair<float,float> ThirdHitPrediction::findArcIntersection
00111 (pair<float,float> a, pair<float,float> b, bool& keep)
00112 {
00113
00114 while(b.first < a.first - M_PI) b.first += 2*M_PI;
00115 while(b.first > a.first + M_PI) b.first -= 2*M_PI;
00116
00117 float min,max;
00118
00119 if(a.first - a.second > b.first - b.second)
00120 min = a.first - a.second;
00121 else
00122 { min = b.first - b.second; keep = false; }
00123
00124 if(a.first + a.second < b.first + b.second)
00125 max = a.first + a.second;
00126 else
00127 { max = b.first + b.second; keep = false; }
00128
00129 pair<float,float> c(0.,0.);
00130
00131 if(min < max)
00132 {
00133 c.first = 0.5*(max + min);
00134 c.second = 0.5*(max - min);
00135 }
00136
00137 return c;
00138 }
00139
00140
00141 void ThirdHitPrediction::fitParabola
00142 (const float x[3], const float y[3], float par[3])
00143 {
00144 float s2 = sqr(x[0]) * (y[1] - y[2]) +
00145 sqr(x[1]) * (y[2] - y[0]) +
00146 sqr(x[2]) * (y[0] - y[1]);
00147
00148 float s1 = x[0] * (y[1] - y[2]) +
00149 x[1] * (y[2] - y[0]) +
00150 x[2] * (y[0] - y[1]);
00151
00152 float s3 = (x[0] - x[1]) * (x[1] - x[2]) * (x[2] - x[0]);
00153 float s4 = x[0]*x[1]*y[2] * (x[0] - x[1]) +
00154 x[0]*y[1]*x[2] * (x[2] - x[0]) +
00155 y[0]*x[1]*x[2] * (x[1] - x[2]);
00156
00157 par[2] = s1 / s3;
00158 par[1] = -s2 / s3;
00159 par[0] = -s4 / s3;
00160 }
00161
00162
00163 void ThirdHitPrediction::findRectangle
00164 (const float x[3], const float y[3], const float par[3],
00165 float phi[2],float z[2])
00166 {
00167
00168 phi[0] = min(x[0],x[2]); z[0] = min(y[0],y[2]);
00169 phi[1] = max(x[0],x[2]); z[1] = max(y[0],y[2]);
00170
00171
00172 float xe = -par[1]/(2*par[2]);
00173 float ye = par[0] - sqr(par[1])/(4*par[2]);
00174
00175
00176 if(phi[0] < xe && xe < phi[1])
00177 {
00178 if(ye < z[0]) z[0] = ye;
00179 if(ye > z[1]) z[1] = ye;
00180 }
00181 }
00182
00183
00184 float ThirdHitPrediction::areaParallelogram
00185 (const Global2DVector& a, const Global2DVector& b)
00186 {
00187 return a.x() * b.y() - a.y() * b.x();
00188 }
00189
00190
00191 float ThirdHitPrediction::angleRatio
00192 (const Global2DVector& p3, const Global2DVector& c)
00193 {
00194 float rad2 = (p1 - c).mag2();
00195
00196 float a12 = asin(fabsf(areaParallelogram(p1 - c, p2 - c)) / rad2);
00197 float a23 = asin(fabsf(areaParallelogram(p2 - c, p3 - c)) / rad2);
00198
00199 return a23/a12;
00200 }
00201
00202
00203 void ThirdHitPrediction::spinCloser(float phi[3])
00204 {
00205 while(phi[1] < phi[0] - M_PI) phi[1] += 2*M_PI;
00206 while(phi[1] > phi[0] + M_PI) phi[1] -= 2*M_PI;
00207
00208 while(phi[2] < phi[1] - M_PI) phi[2] += 2*M_PI;
00209 while(phi[2] > phi[1] + M_PI) phi[2] -= 2*M_PI;
00210 }
00211
00212
00213 void ThirdHitPrediction::calculateRangesBarrel
00214 (float r3, float phi[2],float z[2], bool keep)
00215 {
00216 pair<float,float> arc_all =
00217 findArcIntersection(arc_0m, findTouchingCircles(r3), keep);
00218
00219 if(arc_all.second != 0.)
00220 {
00221 Global2DVector c3(0.,0.);
00222 invertCircle(c3,r3);
00223
00224 float angle[3];
00225 angle[0] = arc_all.first - arc_all.second;
00226 angle[1] = arc_all.first;
00227 angle[2] = arc_all.first + arc_all.second;
00228
00229 float phi3[3], z3[3];
00230 Global2DVector delta = c3 - p2;
00231
00232 for(int i=0; i<3; i++)
00233 {
00234 Global2DVector vec(cos(angle[i]), sin(angle[i]));
00235 float lambda = delta*vec - sqrt(sqr(delta*vec) - delta*delta + sqr(r3));
00236
00237 Global2DVector p3 = p2 + lambda * vec;
00238 invertPoint(p3);
00239 phi3[i] = p3.phi();
00240
00241 float ratio;
00242
00243 if(keep && i==1)
00244 {
00245 ratio = (p2 - p3).mag() / (p1 - p2).mag();
00246 }
00247 else
00248 {
00249 Global2DVector c = p2 - vec * (vec * (p2 - p1));
00250 invertPoint(c);
00251 c = 0.5*(p1 + c);
00252
00253 ratio = angleRatio(p3,c);
00254 }
00255
00256 z3[i] = g2.z() + (g2.z() - g1.z()) * ratio;
00257 }
00258
00259 spinCloser(phi3);
00260
00261
00262 float par[3];
00263 fitParabola (phi3,z3, par);
00264 findRectangle(phi3,z3, par, phi,z);
00265 }
00266 }
00267
00268
00269 void ThirdHitPrediction::calculateRangesForward
00270 (float z3, float phi[2],float r[2], bool keep)
00271 {
00272 float angle[3];
00273 angle[0] = arc_0m.first - arc_0m.second;
00274 angle[1] = arc_0m.first;
00275 angle[2] = arc_0m.first + arc_0m.second;
00276
00277 float ratio = (z3 - g2.z()) / (g2.z() - g1.z());
00278
00279 if(0 < ratio && ratio < maxRatio)
00280 {
00281 float phi3[3], r3[3];
00282
00283 for(int i=0; i<3; i++)
00284 {
00285 Global2DVector p3;
00286
00287 if(keep && i==1)
00288 {
00289 p3 = p2 + ratio * (p2 - p1);
00290 }
00291 else
00292 {
00293 Global2DVector vec(cos(angle[i]), sin(angle[i]));
00294
00295 Global2DVector c = p2 - vec * (vec * (p2 - p1));
00296 invertPoint(c);
00297 c = 0.5*(p1 + c);
00298
00299 float rad2 = (p1 - c).mag2();
00300
00301 float a12 = asin(areaParallelogram(p1 - c, p2 - c) / rad2);
00302 float a23 = ratio * a12;
00303
00304 p3 = c + Global2DVector((p2-c).x()*cos(a23) - (p2-c).y()*sin(a23),
00305 (p2-c).x()*sin(a23) + (p2-c).y()*cos(a23));
00306 }
00307
00308 phi3[i] = p3.phi();
00309 r3[i] = p3.mag();
00310 }
00311
00312 spinCloser(phi3);
00313
00314
00315 float par[3];
00316 fitParabola (phi3,r3, par);
00317 findRectangle(phi3,r3, par, phi,r);
00318 }
00319 }
00320
00321
00322 void ThirdHitPrediction::calculateRanges
00323 (float rz3, float phi[2],float rz[2])
00324 {
00325
00326 phi[0] = 0.; rz[0] = 0.;
00327 phi[1] = 0.; rz[1] = 0.;
00328
00329
00330 if(theBarrel) calculateRangesBarrel (rz3, phi,rz, keep);
00331 else calculateRangesForward(rz3, phi,rz, keep);
00332 }
00333
00334
00335 void ThirdHitPrediction::getRanges
00336 (const DetLayer *layer, float phi[],float rz[])
00337 {
00338 theLayer = layer;
00339
00340 if (layer) initLayer(layer);
00341
00342 float phi_inner[2],rz_inner[2];
00343 calculateRanges(theDetRange.min(), phi_inner,rz_inner);
00344
00345 float phi_outer[2],rz_outer[2];
00346 calculateRanges(theDetRange.max(), phi_outer,rz_outer);
00347
00348 if( (phi_inner[0] == 0. && phi_inner[1] == 0.) ||
00349 (phi_outer[0] == 0. && phi_outer[1] == 0.) )
00350 {
00351 phi[0] = 0.;
00352 phi[1] = 0.;
00353
00354 rz[0] = 0.;
00355 rz[1] = 0.;
00356 }
00357 else
00358 {
00359 while(phi_outer[0] > phi_inner[0] + M_PI)
00360 { phi_outer[0] -= 2*M_PI; phi_outer[1] -= 2*M_PI; }
00361
00362 while(phi_outer[0] < phi_inner[0] - M_PI)
00363 { phi_outer[0] += 2*M_PI; phi_outer[1] += 2*M_PI; }
00364
00365 phi[0] = min(phi_inner[0],phi_outer[0]);
00366 phi[1] = max(phi_inner[1],phi_outer[1]);
00367
00368 rz[0] = min( rz_inner[0], rz_outer[0]);
00369 rz[1] = max( rz_inner[1], rz_outer[1]);
00370 }
00371 }
00372
00373
00374 void ThirdHitPrediction::getRanges
00375 (float rz3, float phi[],float rz[])
00376 {
00377 calculateRanges(rz3, phi,rz);
00378 }
00379
00380
00381 bool ThirdHitPrediction::isCompatibleWithMultipleScattering
00382 (GlobalPoint g3, vector<const TrackingRecHit*> h,
00383 vector<GlobalVector>& globalDirs, const edm::EventSetup& es)
00384 {
00385 Global2DVector p1(g1.x(),g1.y());
00386 Global2DVector p2(g2.x(),g2.y());
00387 Global2DVector p3(g3.x(),g3.y());
00388
00389 CircleFromThreePoints circle(g1,g2,g3);
00390
00391 if(circle.curvature() != 0.)
00392 {
00393 Global2DVector c (circle.center().x(), circle.center().y());
00394
00395 float rad2 = (p1 - c).mag2();
00396 float a12 = asin(fabsf(areaParallelogram(p1 - c, p2 - c)) / rad2);
00397 float a23 = asin(fabsf(areaParallelogram(p2 - c, p3 - c)) / rad2);
00398
00399 float slope = (g2.z() - g1.z()) / a12;
00400
00401 float rz3 = g2.z() + slope * a23;
00402 float delta_z = g3.z() - rz3;
00403
00404
00405 vector<TransientTrackingRecHit::RecHitPointer> th;
00406 for(vector<const TrackingRecHit*>::iterator ih = h.begin(); ih!= h.end(); ih++)
00407 th.push_back(theTTRecHitBuilder->build(*ih));
00408
00409 float sigma1_le2 = max(th[0]->parametersError()[0][0],
00410 th[0]->parametersError()[1][1]);
00411 float sigma2_le2 = max(th[1]->parametersError()[0][0],
00412 th[1]->parametersError()[1][1]);
00413
00414 float sigma_z2 = (1 + a23/a12)*(1 + a23/a12) * sigma2_le2 +
00415 ( a23/a12)*( a23/a12) * sigma1_le2;
00416
00417 float cotTheta = slope * circle.curvature();
00418 float coshEta = sqrt(1 + sqr(cotTheta));
00419
00420 float pt = Bz / circle.curvature();
00421 float p = pt * coshEta;
00422
00423 float m_pi = 0.13957018;
00424 float beta = p / sqrt(sqr(p) + sqr(m_pi));
00425
00426 MultipleScatteringParametrisation msp(theLayer,es);
00427 PixelRecoPointRZ rz2(g2.perp(), g2.z());
00428
00429 float sigma_z = msp(pt, cotTheta, rz2) / beta;
00430
00431
00432 float sinTheta = 1. / coshEta;
00433 float cosTheta = cotTheta * sinTheta;
00434
00435 int dir;
00436 if(areaParallelogram(p1 - c, p2 - c) > 0) dir = 1; else dir = -1;
00437
00438 float curvature = circle.curvature();
00439
00440 {
00441 Global2DVector v = (p1 - c)*curvature*dir;
00442 globalDirs.push_back(GlobalVector(-v.y()*sinTheta,v.x()*sinTheta,cosTheta));
00443 }
00444
00445 {
00446 Global2DVector v = (p2 - c)*curvature*dir;
00447 globalDirs.push_back(GlobalVector(-v.y()*sinTheta,v.x()*sinTheta,cosTheta));
00448 }
00449
00450 {
00451 Global2DVector v = (p3 - c)*curvature*dir;
00452 globalDirs.push_back(GlobalVector(-v.y()*sinTheta,v.x()*sinTheta,cosTheta));
00453 }
00454
00455
00456 float sigma_ms = sigma_z * coshEta;
00457
00458
00459 float sigma_le2 = max(th[2]->parametersError()[0][0],
00460 th[2]->parametersError()[1][1]);
00461
00462 return (delta_z*delta_z / (sigma_ms*sigma_ms + sigma_le2 + sigma_z2)
00463 < nSigma * nSigma);
00464 }
00465
00466 return false;
00467 }
00468
00469
00470 void ThirdHitPrediction::initLayer(const DetLayer *layer)
00471 {
00472 if ( layer->location() == GeomDetEnumerators::barrel) {
00473 theBarrel = true;
00474 theForward = false;
00475 const BarrelDetLayer& bl = dynamic_cast<const BarrelDetLayer&>(*layer);
00476 float halfThickness = bl.surface().bounds().thickness()/2;
00477 float radius = bl.specificSurface().radius();
00478 theDetRange = Range(radius-halfThickness, radius+halfThickness);
00479 } else if ( layer->location() == GeomDetEnumerators::endcap) {
00480 theBarrel= false;
00481 theForward = true;
00482 const ForwardDetLayer& fl = dynamic_cast<const ForwardDetLayer&>(*layer);
00483 float halfThickness = fl.surface().bounds().thickness()/2;
00484 float zLayer = fl.position().z() ;
00485 theDetRange = Range(zLayer-halfThickness, zLayer+halfThickness);
00486 }
00487 }