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