00001 #include "TrackingTools/TrajectoryState/interface/PerigeeConversions.h"
00002 #include "TrackingTools/TrajectoryState/interface/TrajectoryStateClosestToPoint.h"
00003 #include "MagneticField/Engine/interface/MagneticField.h"
00004 #include <cmath>
00005 #include <vdt/vdtMath.h>
00006
00007 PerigeeTrajectoryParameters PerigeeConversions::ftsToPerigeeParameters
00008 (const FTS& originalFTS, const GlobalPoint& referencePoint, double & pt)
00009
00010 {
00011 GlobalVector impactDistance = originalFTS.position() - referencePoint;
00012
00013 pt = originalFTS.momentum().perp();
00014 if (pt==0.) throw cms::Exception("PerigeeConversions", "Track with pt=0");
00015
00016 double theta = originalFTS.momentum().theta();
00017 double phi = originalFTS.momentum().phi();
00018 double field = originalFTS.parameters().magneticField().inInverseGeV(originalFTS.position()).z();
00019
00020
00021 double positiveMomentumPhi = ( (phi>0) ? phi : (2*M_PI+phi) );
00022 double positionPhi = impactDistance.phi();
00023 double positivePositionPhi =
00024 ( (positionPhi>0) ? positionPhi : (2*M_PI+positionPhi) );
00025 double phiDiff = positiveMomentumPhi - positivePositionPhi;
00026 if (phiDiff<0.0) phiDiff+= (2*M_PI);
00027 double signEpsilon = ( (phiDiff > M_PI) ? -1.0 : 1.0);
00028
00029 double epsilon = signEpsilon *
00030 sqrt ( impactDistance.x()*impactDistance.x() +
00031 impactDistance.y()*impactDistance.y() );
00032
00033
00034 AlgebraicVector5 theTrackParameters;
00035
00036 double signTC = - originalFTS.charge();
00037 bool isCharged = (signTC!=0) && (std::abs(field)>1.e-10);
00038 if (isCharged) {
00039 theTrackParameters[0] = field / pt*signTC;
00040 } else {
00041 theTrackParameters[0] = 1 / pt;
00042 }
00043 theTrackParameters[1] = theta;
00044 theTrackParameters[2] = phi;
00045 theTrackParameters[3] = epsilon;
00046 theTrackParameters[4] = impactDistance.z();
00047 return PerigeeTrajectoryParameters(theTrackParameters, isCharged);
00048 }
00049
00050
00051 PerigeeTrajectoryError PerigeeConversions::ftsToPerigeeError
00052 (const FTS& originalFTS)
00053 {
00054 AlgebraicSymMatrix55 errorMatrix = originalFTS.curvilinearError().matrix();
00055 AlgebraicMatrix55 curv2perigee = jacobianCurvilinear2Perigee(originalFTS);
00056 return PerigeeTrajectoryError(ROOT::Math::Similarity(curv2perigee,errorMatrix));
00057 }
00058
00059
00060 CurvilinearTrajectoryError PerigeeConversions::curvilinearError
00061 (const PerigeeTrajectoryError& perigeeError, const GlobalTrajectoryParameters& gtp)
00062 {
00063 AlgebraicMatrix55 perigee2curv = jacobianPerigee2Curvilinear(gtp);
00064 return CurvilinearTrajectoryError(ROOT::Math::Similarity(perigee2curv, perigeeError.covarianceMatrix()));
00065 }
00066
00067 GlobalPoint PerigeeConversions::positionFromPerigee
00068 (const PerigeeTrajectoryParameters& parameters, const GlobalPoint& referencePoint)
00069 {
00070 AlgebraicVector5 theVector = parameters.vector();
00071 return GlobalPoint(theVector[3]*vdt::fast_sin(theVector[2])+referencePoint.x(),
00072 -theVector[3]*vdt::fast_cos(theVector[2])+referencePoint.y(),
00073 theVector[4]+referencePoint.z());
00074 }
00075
00076
00077 GlobalVector PerigeeConversions::momentumFromPerigee
00078 (const PerigeeTrajectoryParameters& parameters, double pt, const GlobalPoint& referencePoint)
00079 {
00080 return GlobalVector(vdt::fast_cos(parameters.phi()) * pt,
00081 vdt::fast_sin(parameters.phi()) * pt,
00082 pt /vdt::fast_tan(parameters.theta()));
00083 }
00084
00085
00086 GlobalVector PerigeeConversions::momentumFromPerigee
00087 (const AlgebraicVector3& momentum, const TrackCharge& charge,
00088 const GlobalPoint& referencePoint, const MagneticField* field)
00089 {
00090 double pt;
00091
00092 double bz = fabs(field->inInverseGeV(referencePoint).z());
00093 if ( charge!=0 && std::abs(bz)>1.e-10 ) {
00094 pt = std::abs(bz/momentum[0]);
00095
00096 } else {
00097 pt = 1 / momentum[0];
00098 }
00099
00100 return GlobalVector(vdt::fast_cos(momentum[2]) * pt,
00101 vdt::fast_sin(momentum[2]) * pt,
00102 pt/vdt::fast_tan(momentum[1]));
00103 }
00104
00105
00106 TrajectoryStateClosestToPoint PerigeeConversions::trajectoryStateClosestToPoint
00107 (const AlgebraicVector3& momentum, const GlobalPoint& referencePoint,
00108 const TrackCharge& charge, const AlgebraicSymMatrix66& theCovarianceMatrix,
00109 const MagneticField* field)
00110 {
00111 AlgebraicMatrix66 param2cart = jacobianParameters2Cartesian
00112 (momentum, referencePoint, charge, field);
00113 CartesianTrajectoryError cartesianTrajErr(ROOT::Math::Similarity(param2cart, theCovarianceMatrix));
00114
00115 FTS theFTS(GlobalTrajectoryParameters(referencePoint,
00116 momentumFromPerigee(momentum, charge, referencePoint, field), charge,
00117 field), cartesianTrajErr);
00118
00119 return TrajectoryStateClosestToPoint(theFTS, referencePoint);
00120 }
00121
00122
00123 AlgebraicMatrix66
00124 PerigeeConversions::jacobianParameters2Cartesian(
00125 const AlgebraicVector3& momentum, const GlobalPoint& position,
00126 const TrackCharge& charge, const MagneticField* field)
00127 {
00128 float factor = -1.;
00129 float bField = field->inInverseGeV(position).z();
00130 if (charge!=0 && std::abs(bField)>1.e-10f)
00131 factor = bField*charge;
00132
00133
00134 float s1,c1; vdt::fast_sincosf(momentum[1],s1,c1);
00135 float s2,c2; vdt::fast_sincosf(momentum[2],s2,c2);
00136 float f1 = factor/(momentum[0]*momentum[0]);
00137 float f2 = factor/momentum[0];
00138
00139 AlgebraicMatrix66 frameTransJ;
00140 frameTransJ(0,0) = 1;
00141 frameTransJ(1,1) = 1;
00142 frameTransJ(2,2) = 1;
00143 frameTransJ(3,3) = (f1 * c2);
00144 frameTransJ(4,3) = (f1 * s2);
00145 frameTransJ(5,3) = (f1*c1/s1);
00146
00147 frameTransJ(3,5) = (f2 * s2);
00148 frameTransJ(4,5) = -(f2 * c2);
00149 frameTransJ(5,4) = (f2/(s1*s1));
00150
00151 return frameTransJ;
00152 }
00153
00154
00155 AlgebraicMatrix55
00156 PerigeeConversions::jacobianCurvilinear2Perigee(const FreeTrajectoryState& fts){
00157
00158 GlobalVector p = fts.momentum();
00159
00160 GlobalVector Z = GlobalVector(0.,0.,1.);
00161 GlobalVector T = p.unit();
00162 GlobalVector U = Z.cross(T).unit();;
00163 GlobalVector V = T.cross(U);
00164
00165 GlobalVector I = GlobalVector(-p.x(), -p.y(), 0.);
00166 I = I.unit();
00167 GlobalVector J(-I.y(), I.x(),0.);
00168 GlobalVector K(Z);
00169 GlobalPoint x = fts.position();
00170 GlobalVector B = fts.parameters().magneticField().inInverseGeV(x);
00171 GlobalVector H = B.unit();
00172 GlobalVector HxT = H.cross(T);
00173 GlobalVector N = HxT.unit();
00174 double alpha = HxT.mag();
00175 double qbp = fts.signedInverseMomentum();
00176 double Q = -B.mag() * qbp;
00177 double alphaQ = alpha * Q;
00178
00179 double lambda = 0.5 * M_PI - p.theta();
00180 double sinlambda, coslambda; vdt::fast_sincos(lambda, sinlambda, coslambda);
00181 double seclambda = 1./coslambda;
00182
00183 double ITI = 1./T.dot(I);
00184 double NU = N.dot(U);
00185 double NV = N.dot(V);
00186 double UI = U.dot(I);
00187 double VI = V.dot(I);
00188 double UJ = U.dot(J);
00189 double VJ = V.dot(J);
00190 double UK = U.dot(K);
00191 double VK = V.dot(K);
00192
00193 AlgebraicMatrix55 jac;
00194
00195 if( fabs(fts.transverseCurvature())<1.e-10 ) {
00196 jac(0,0) = seclambda;
00197 jac(0,1) = sinlambda*seclambda*seclambda*std::abs(qbp);
00198 }else{
00199 double Bz = B.z();
00200 jac(0,0) = -Bz * seclambda;
00201 jac(0,1) = -Bz * sinlambda*seclambda*seclambda*qbp;
00202 jac(1,3) = alphaQ * NV * UI*ITI;
00203 jac(1,4) = alphaQ * NV * VI*ITI;
00204 jac(0,3) = -jac(0,1) * jac(1,3);
00205 jac(0,4) = -jac(0,1) * jac(1,4);
00206 jac(2,3) = -alphaQ*seclambda * NU * UI*ITI;
00207 jac(2,4) = -alphaQ*seclambda * NU * VI*ITI;
00208 }
00209 jac(1,1) = -1.;
00210 jac(2,2) = 1.;
00211 jac(3,3) = VK*ITI;
00212 jac(3,4) = -UK*ITI;
00213 jac(4,3) = -VJ*ITI;
00214 jac(4,4) = UJ*ITI;
00215
00216 return jac;
00217
00218 }
00219
00220
00221
00222 AlgebraicMatrix55
00223 PerigeeConversions::jacobianPerigee2Curvilinear(const GlobalTrajectoryParameters& gtp) {
00224
00225 GlobalVector p = gtp.momentum();
00226
00227 GlobalVector Z = GlobalVector(0.f,0.f,1.f);
00228 GlobalVector T = p.unit();
00229 GlobalVector U = Z.cross(T).unit();;
00230 GlobalVector V = T.cross(U);
00231
00232 GlobalVector I = GlobalVector(-p.x(), -p.y(), 0.f);
00233 I = I.unit();
00234 GlobalVector J(-I.y(), I.x(),0.f);
00235 GlobalVector K(Z);
00236 GlobalPoint x = gtp.position();
00237 GlobalVector B = gtp.magneticField().inInverseGeV(x);
00238 GlobalVector H = B.unit();
00239 GlobalVector HxT = H.cross(T);
00240 GlobalVector N = HxT.unit();
00241 double alpha = HxT.mag();
00242 double qbp = gtp.signedInverseMomentum();
00243 double Q = -B.mag() * qbp;
00244 double alphaQ = alpha * Q;
00245
00246
00247 double lambda = 0.5 * M_PI - p.theta();
00248 double sinlambda, coslambda; vdt::fast_sincos(lambda, sinlambda, coslambda);
00249 double seclambda = 1./coslambda;
00250
00251 double mqbpt = -1./coslambda * qbp;
00252
00253 double TJ = T.dot(J);
00254 double TK = T.dot(K);
00255 double NU = N.dot(U);
00256 double NV = N.dot(V);
00257 double UJ = U.dot(J);
00258 double VJ = V.dot(J);
00259 double UK = U.dot(K);
00260 double VK = V.dot(K);
00261
00262 AlgebraicMatrix55 jac;
00263
00264 if( fabs(gtp.transverseCurvature())<1.e-10f ) {
00265 jac(0,0) = coslambda;
00266 jac(0,1) = sinlambda/coslambda/gtp.momentum().mag();
00267 }else{
00268 jac(0,0) = -coslambda/B.z();
00269 jac(0,1) = -sinlambda * mqbpt;
00270 jac(1,3) = -alphaQ * NV * TJ;
00271 jac(1,4) = -alphaQ * NV * TK;
00272 jac(2,3) = -alphaQ*seclambda * NU * TJ;
00273 jac(2,4) = -alphaQ*seclambda * NU * TK;
00274 }
00275 jac(1,1) = -1.;
00276 jac(2,2) = 1.;
00277 jac(3,3) = UJ;
00278 jac(3,4) = UK;
00279 jac(4,3) = VJ;
00280 jac(4,4) = VK;
00281
00282 return jac;
00283 }
00284