/* Copyright 2008-2009, Technische Universitaet Muenchen, Authors: Christian Hoeppner & Sebastian Neubert This file is part of GENFIT. GENFIT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GENFIT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with GENFIT. If not, see . */ /* The Runge Kutta implementation stems from GEANT3 originally (R. Brun et al.) Porting to C goes back to Igor Gavrilenko @ CERN The code was taken from the Phast analysis package of the COMPASS experiment (Sergei Gerrassimov @ CERN) */ #include"RKTrackRep.h" #include #include #include #include"assert.h" #include "stdlib.h" #include"math.h" #include"TMath.h" #include"TGeoManager.h" #include"TDatabasePDG.h" #include"GFException.h" #include"GFFieldManager.h" #include"GFMaterialEffects.h" #define MINSTEP 0.001 // minimum step [cm] for Runge Kutta and iteration to POCA void RKTrackRep::setData(const TMatrixT& st, const GFDetPlane& pl, const TMatrixT* cov, const TMatrixT* aux){ if(aux != NULL) { fCacheSpu = (*aux)(0,0); } else { if(pl!=fCachePlane){ std::cerr << "RKTrackRep::setData() - a fatal error ocurred! It was called with a reference plane which is not the same as the one from the last extrapolate(plane,state,cov)-> abort in line " << __LINE__ << std::endl; throw; } } GFAbsTrackRep::setData(st,pl,cov); if (fCharge*fState[0][0] < 0) fCharge *= -1; // set charge accordingly! (fState[0][0] = q/p) fSpu=fCacheSpu; } const TMatrixT* RKTrackRep::getAuxInfo(const GFDetPlane& pl) { if(pl!=fCachePlane) { std::cerr << "RKTrackRep::getAuxInfo() - Fatal error: Trying to get auxillary information with planes mismatch (Information returned does not belong to requested plane)! -> abort in line " << __LINE__ << std::endl; throw; } fAuxInfo.ResizeTo(1,1); fAuxInfo(0,0) = fCacheSpu; return &fAuxInfo; } RKTrackRep::~RKTrackRep(){ //GFMaterialEffects is now a Singleton } RKTrackRep::RKTrackRep() : GFAbsTrackRep(5), fDirection(true), fPdg(0), fMass(0.), fCharge(-1), fCachePlane(), fCacheSpu(1), fSpu(1), fAuxInfo(1,1) { } RKTrackRep::RKTrackRep(const TVector3& pos, const TVector3& mom, const TVector3& poserr, const TVector3& momerr, const int& PDGCode) : GFAbsTrackRep(5), fDirection(true), fCachePlane(), fCacheSpu(1), fAuxInfo(1,1) { setPDG(PDGCode); // also sets charge and mass fRefPlane.setO(pos); fRefPlane.setNormal(mom); fState[0][0]=fCharge/mom.Mag(); //u' and v' fState[1][0]=0.0; fState[2][0]=0.0; //u and v fState[3][0]=0.0; fState[4][0]=0.0; //spu fSpu=1.; TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); double pu=0.; double pv=0.; double pw=mom.Mag(); fCov[3][3] = poserr.X()*poserr.X() * u.X()*u.X() + poserr.Y()*poserr.Y() * u.Y()*u.Y() + poserr.Z()*poserr.Z() * u.Z()*u.Z(); fCov[4][4] = poserr.X()*poserr.X() * v.X()*v.X() + poserr.Y()*poserr.Y() * v.Y()*v.Y() + poserr.Z()*poserr.Z() * v.Z()*v.Z(); fCov[0][0] = fCharge*fCharge/pow(mom.Mag(),6.) * (mom.X()*mom.X() * momerr.X()*momerr.X()+ mom.Y()*mom.Y() * momerr.Y()*momerr.Y()+ mom.Z()*mom.Z() * momerr.Z()*momerr.Z()); fCov[1][1] = pow((u.X()/pw - w.X()*pu/(pw*pw)),2.)*momerr.X()*momerr.X() + pow((u.Y()/pw - w.Y()*pu/(pw*pw)),2.)*momerr.Y()*momerr.Y() + pow((u.Z()/pw - w.Z()*pu/(pw*pw)),2.)*momerr.Z()*momerr.Z(); fCov[2][2] = pow((v.X()/pw - w.X()*pv/(pw*pw)),2.)*momerr.X()*momerr.X() + pow((v.Y()/pw - w.Y()*pv/(pw*pw)),2.)*momerr.Y()*momerr.Y() + pow((v.Z()/pw - w.Z()*pv/(pw*pw)),2.)*momerr.Z()*momerr.Z(); } RKTrackRep::RKTrackRep(const GFTrackCand* aGFTrackCandPtr) : GFAbsTrackRep(5), fDirection(true), fCachePlane(), fCacheSpu(1), fAuxInfo(1,1) { setPDG(aGFTrackCandPtr->getPdgCode()); // also sets charge and mass TVector3 mom = aGFTrackCandPtr->getDirSeed(); fRefPlane.setO(aGFTrackCandPtr->getPosSeed()); fRefPlane.setNormal(mom); double pw=mom.Mag(); fState[0][0]=fCharge/pw; //u' and v' fState[1][0]=0.0; fState[2][0]=0.0; //u and v fState[3][0]=0.0; fState[4][0]=0.0; //spu fSpu=1.; TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); double pu=0.; double pv=0.; TVector3 poserr = aGFTrackCandPtr->getPosError(); TVector3 momerr = aGFTrackCandPtr->getDirError(); fCov[3][3] = poserr.X()*poserr.X() * u.X()*u.X() + poserr.Y()*poserr.Y() * u.Y()*u.Y() + poserr.Z()*poserr.Z() * u.Z()*u.Z(); fCov[4][4] = poserr.X()*poserr.X() * v.X()*v.X() + poserr.Y()*poserr.Y() * v.Y()*v.Y() + poserr.Z()*poserr.Z() * v.Z()*v.Z(); fCov[0][0] = fCharge*fCharge/pow(mom.Mag(),6.) * (mom.X()*mom.X() * momerr.X()*momerr.X()+ mom.Y()*mom.Y() * momerr.Y()*momerr.Y()+ mom.Z()*mom.Z() * momerr.Z()*momerr.Z()); fCov[1][1] = pow((u.X()/pw - w.X()*pu/(pw*pw)),2.)*momerr.X()*momerr.X() + pow((u.Y()/pw - w.Y()*pu/(pw*pw)),2.)*momerr.Y()*momerr.Y() + pow((u.Z()/pw - w.Z()*pu/(pw*pw)),2.)*momerr.Z()*momerr.Z(); fCov[2][2] = pow((v.X()/pw - w.X()*pv/(pw*pw)),2.)*momerr.X()*momerr.X() + pow((v.Y()/pw - w.Y()*pv/(pw*pw)),2.)*momerr.Y()*momerr.Y() + pow((v.Z()/pw - w.Z()*pv/(pw*pw)),2.)*momerr.Z()*momerr.Z(); } RKTrackRep::RKTrackRep(const TVector3& pos, const TVector3& mom, const int& PDGCode) : GFAbsTrackRep(5),fDirection(true), fCachePlane(), fCacheSpu(1), fAuxInfo(1,1){ setPDG(PDGCode); // also sets charge and mass fRefPlane.setO(pos); fRefPlane.setNormal(mom); fState[0][0]=fCharge/mom.Mag(); //u' and v' fState[1][0]=0.0; fState[2][0]=0.0; //u and v fState[3][0]=0.0; fState[4][0]=0.0; //spu fSpu=1.; TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); double pu=0.; double pv=0.; double pw=mom.Mag(); static const TVector3 stdPosErr(1.,1.,1.); static const TVector3 stdMomErr(1.,1.,1.); fCov[3][3] = stdPosErr.X()*stdPosErr.X() * u.X()*u.X() + stdPosErr.Y()*stdPosErr.Y() * u.Y()*u.Y() + stdPosErr.Z()*stdPosErr.Z() * u.Z()*u.Z(); fCov[4][4] = stdPosErr.X()*stdPosErr.X() * v.X()*v.X() + stdPosErr.Y()*stdPosErr.Y() * v.Y()*v.Y() + stdPosErr.Z()*stdPosErr.Z() * v.Z()*v.Z(); fCov[0][0] = fCharge*fCharge/pow(mom.Mag(),6.) * (mom.X()*mom.X() * stdMomErr.X()*stdMomErr.X()+ mom.Y()*mom.Y() * stdMomErr.Y()*stdMomErr.Y()+ mom.Z()*mom.Z() * stdMomErr.Z()*stdMomErr.Z()); fCov[1][1] = pow((u.X()/pw - w.X()*pu/(pw*pw)),2.)*stdMomErr.X()*stdMomErr.X() + pow((u.Y()/pw - w.Y()*pu/(pw*pw)),2.)*stdMomErr.Y()*stdMomErr.Y() + pow((u.Z()/pw - w.Z()*pu/(pw*pw)),2.)*stdMomErr.Z()*stdMomErr.Z(); fCov[2][2] = pow((v.X()/pw - w.X()*pv/(pw*pw)),2.)*stdMomErr.X()*stdMomErr.X() + pow((v.Y()/pw - w.Y()*pv/(pw*pw)),2.)*stdMomErr.Y()*stdMomErr.Y() + pow((v.Z()/pw - w.Z()*pv/(pw*pw)),2.)*stdMomErr.Z()*stdMomErr.Z(); } RKTrackRep::RKTrackRep(const GFDetPlane& pl, const TVector3& mom, const int& PDGCode) : GFAbsTrackRep(5),fDirection(true), fCachePlane(), fCacheSpu(1), fAuxInfo(1,1){ setPDG(PDGCode); // also sets charge and mass fRefPlane = pl; TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); double pu=mom*u; double pv=mom*v; double pw=mom*w; fState[0][0]=fCharge/mom.Mag(); //u' and v' fState[1][0]=pu/pw; fState[2][0]=pv/pw; //u and v fState[3][0]=0.0; fState[4][0]=0.0; //spu fSpu=1.; static const TVector3 stdPosErr2(1.,1.,1.); static const TVector3 stdMomErr2(1.,1.,1.); fCov[3][3] = stdPosErr2.X()*stdPosErr2.X() * u.X()*u.X() + stdPosErr2.Y()*stdPosErr2.Y() * u.Y()*u.Y() + stdPosErr2.Z()*stdPosErr2.Z() * u.Z()*u.Z(); fCov[4][4] = stdPosErr2.X()*stdPosErr2.X() * v.X()*v.X() + stdPosErr2.Y()*stdPosErr2.Y() * v.Y()*v.Y() + stdPosErr2.Z()*stdPosErr2.Z() * v.Z()*v.Z(); fCov[0][0] = fCharge*fCharge/pow(mom.Mag(),6.) * (mom.X()*mom.X() * stdMomErr2.X()*stdMomErr2.X()+ mom.Y()*mom.Y() * stdMomErr2.Y()*stdMomErr2.Y()+ mom.Z()*mom.Z() * stdMomErr2.Z()*stdMomErr2.Z()); fCov[1][1] = pow((u.X()/pw - w.X()*pu/(pw*pw)),2.)*stdMomErr2.X()*stdMomErr2.X() + pow((u.Y()/pw - w.Y()*pu/(pw*pw)),2.)*stdMomErr2.Y()*stdMomErr2.Y() + pow((u.Z()/pw - w.Z()*pu/(pw*pw)),2.)*stdMomErr2.Z()*stdMomErr2.Z(); fCov[2][2] = pow((v.X()/pw - w.X()*pv/(pw*pw)),2.)*stdMomErr2.X()*stdMomErr2.X() + pow((v.Y()/pw - w.Y()*pv/(pw*pw)),2.)*stdMomErr2.Y()*stdMomErr2.Y() + pow((v.Z()/pw - w.Z()*pv/(pw*pw)),2.)*stdMomErr2.Z()*stdMomErr2.Z(); } void RKTrackRep::setPDG(int i){ fPdg = i; TParticlePDG * part = TDatabasePDG::Instance()->GetParticle(fPdg); if(part == 0){ std::cerr << "RKTrackRep::setPDG particle " << i << " not known to TDatabasePDG -> abort" << std::endl; exit(1); } fMass = part->Mass(); fCharge = part->Charge()/(3.); } TVector3 RKTrackRep::getPos(const GFDetPlane& pl){ if(pl!=fRefPlane){ TMatrixT s(5,1); extrapolate(pl,s); return pl.getO()+s[3][0]*pl.getU()+s[4][0]*pl.getV(); } return fRefPlane.getO()+fState[3][0]*fRefPlane.getU()+fState[4][0]*fRefPlane.getV(); } TVector3 RKTrackRep::getMom(const GFDetPlane& pl){ TMatrixT statePred(fState); TVector3 retmom; if(pl!=fRefPlane) { extrapolate(pl,statePred); retmom = fCacheSpu*(pl.getNormal()+statePred[1][0]*pl.getU()+statePred[2][0]*pl.getV()); } else{ retmom = fSpu*(pl.getNormal()+statePred[1][0]*pl.getU()+statePred[2][0]*pl.getV()); } retmom.SetMag(1./fabs(statePred[0][0])); return retmom; } void RKTrackRep::getPosMom(const GFDetPlane& pl,TVector3& pos, TVector3& mom){ TMatrixT statePred(fState); if(pl!=fRefPlane) { extrapolate(pl,statePred); mom = fCacheSpu*(pl.getNormal()+statePred[1][0]*pl.getU()+statePred[2][0]*pl.getV()); } else{ mom = fSpu*(pl.getNormal()+statePred[1][0]*pl.getU()+statePred[2][0]*pl.getV()); } mom.SetMag(1./fabs(statePred[0][0])); pos = pl.getO()+(statePred[3][0]*pl.getU())+(statePred[4][0]*pl.getV()); } void RKTrackRep::extrapolateToPoint(const TVector3& pos, TVector3& poca, TVector3& dirInPoca){ static const int maxIt(30); TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); TVector3 pTilde = fSpu* (w + fState[1][0] * u + fState[2][0] * v); pTilde.SetMag(1.); TVector3 point = o + fState[3][0]*u + fState[4][0]*v; TMatrixT state7(7,1); state7[0][0] = point.X(); state7[1][0] = point.Y(); state7[2][0] = point.Z(); state7[3][0] = pTilde.X(); state7[4][0] = pTilde.Y(); state7[5][0] = pTilde.Z(); state7[6][0] = fState[0][0]; double coveredDistance(0.); GFDetPlane pl; int iterations(0); while(true){ pl.setON(pos,TVector3(state7[3][0],state7[4][0],state7[5][0])); coveredDistance = this->Extrap(pl,&state7); if(fabs(coveredDistance) extrapolation to point failed, maximum number of iterations reached",__LINE__,__FILE__); throw exc; } } poca.SetXYZ(state7[0][0],state7[1][0],state7[2][0]); dirInPoca.SetXYZ(state7[3][0],state7[4][0],state7[5][0]); } TVector3 RKTrackRep::poca2Line(const TVector3& extr1,const TVector3& extr2,const TVector3& point) const { TVector3 theWire = extr2-extr1; if(theWire.Mag()<1.E-8){ GFException exc("RKTrackRep::poca2Line ==> try to find poca between line and point, but the line is really just a point",__LINE__,__FILE__); throw exc; } double t = 1./(theWire*theWire)*(point*theWire+extr1*extr1-extr1*extr2); return (extr1+t*theWire); } void RKTrackRep::extrapolateToLine(const TVector3& point1, const TVector3& point2, TVector3& poca, TVector3& dirInPoca, TVector3& poca_onwire){ static const int maxIt(30); TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); TVector3 pTilde = fSpu* (w + fState[1][0] * u + fState[2][0] * v); pTilde.SetMag(1.); TVector3 point = o + fState[3][0]*u + fState[4][0]*v; TMatrixT state7(7,1); state7[0][0] = point.X(); state7[1][0] = point.Y(); state7[2][0] = point.Z(); state7[3][0] = pTilde.X(); state7[4][0] = pTilde.Y(); state7[5][0] = pTilde.Z(); state7[6][0] = fState[0][0]; double coveredDistance(0.); GFDetPlane pl; int iterations(0); while(true){ pl.setO(point1); TVector3 currentDir(state7[3][0],state7[4][0],state7[5][0]); pl.setU(currentDir.Cross(point2-point1)); pl.setV(point2-point1); coveredDistance = this->Extrap(pl,&state7); if(fabs(coveredDistance) extrapolation to line failed, maximum number of iterations reached",__LINE__,__FILE__); throw exc; } } poca.SetXYZ(state7[0][0],state7[1][0],state7[2][0]); dirInPoca.SetXYZ(state7[3][0],state7[4][0],state7[5][0]); poca_onwire = poca2Line(point1,point2,poca); } double RKTrackRep::extrapolate(const GFDetPlane& pl, TMatrixT& statePred, TMatrixT& covPred){ TMatrixT cov7x7(7,7); TMatrixT J_pM(7,5); TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); J_pM[0][3] = u.X();J_pM[0][4]=v.X(); // dx/du J_pM[1][3] = u.Y();J_pM[1][4]=v.Y(); J_pM[2][3] = u.Z();J_pM[2][4]=v.Z(); TVector3 pTilde = fSpu * (w + fState[1][0] * u + fState[2][0] * v); double pTildeMag = pTilde.Mag(); //J_pM matrix is d(x,y,z,ax,ay,az,q/p) / d(q/p,u',v',u,v) // da_x/du' J_pM[3][1] = fSpu/pTildeMag*(u.X()-pTilde.X()/(pTildeMag*pTildeMag)*u*pTilde); J_pM[4][1] = fSpu/pTildeMag*(u.Y()-pTilde.Y()/(pTildeMag*pTildeMag)*u*pTilde); J_pM[5][1] = fSpu/pTildeMag*(u.Z()-pTilde.Z()/(pTildeMag*pTildeMag)*u*pTilde); // da_x/dv' J_pM[3][2] = fSpu/pTildeMag*(v.X()-pTilde.X()/(pTildeMag*pTildeMag)*v*pTilde); J_pM[4][2] = fSpu/pTildeMag*(v.Y()-pTilde.Y()/(pTildeMag*pTildeMag)*v*pTilde); J_pM[5][2] = fSpu/pTildeMag*(v.Z()-pTilde.Z()/(pTildeMag*pTildeMag)*v*pTilde); // dqOp/dqOp J_pM[6][0] = 1.; TMatrixT J_pM_transp(J_pM); J_pM_transp.T(); cov7x7 = J_pM*(fCov*J_pM_transp); TVector3 pos = o + fState[3][0]*u + fState[4][0]*v; TMatrixT state7(7,1); state7[0][0] = pos.X(); state7[1][0] = pos.Y(); state7[2][0] = pos.Z(); state7[3][0] = pTilde.X()/pTildeMag;; state7[4][0] = pTilde.Y()/pTildeMag;; state7[5][0] = pTilde.Z()/pTildeMag;; state7[6][0] = fState[0][0]; double coveredDistance = this->Extrap(pl,&state7,&cov7x7); TVector3 O = pl.getO(); TVector3 U = pl.getU(); TVector3 V = pl.getV(); TVector3 W = pl.getNormal(); double X = state7[0][0]; double Y = state7[1][0]; double Z = state7[2][0]; double AX = state7[3][0]; double AY = state7[4][0]; double AZ = state7[5][0]; double QOP = state7[6][0]; TVector3 A(AX,AY,AZ); TVector3 Point(X,Y,Z); TMatrixT J_Mp(5,7); // J_Mp matrix is d(q/p,u',v',u,v) / d(x,y,z,ax,ay,az,q/p) J_Mp[0][6] = 1.; //du'/da_x double AtW = A*W; J_Mp[1][3] = (U.X()*(AtW)-W.X()*(A*U))/(AtW*AtW); J_Mp[1][4] = (U.Y()*(AtW)-W.Y()*(A*U))/(AtW*AtW); J_Mp[1][5] = (U.Z()*(AtW)-W.Z()*(A*U))/(AtW*AtW); //dv'/da_x J_Mp[2][3] = (V.X()*(AtW)-W.X()*(A*V))/(AtW*AtW); J_Mp[2][4] = (V.Y()*(AtW)-W.Y()*(A*V))/(AtW*AtW); J_Mp[2][5] = (V.Z()*(AtW)-W.Z()*(A*V))/(AtW*AtW); //du/dx J_Mp[3][0] = U.X(); J_Mp[3][1] = U.Y(); J_Mp[3][2] = U.Z(); //dv/dx J_Mp[4][0] = V.X(); J_Mp[4][1] = V.Y(); J_Mp[4][2] = V.Z(); TMatrixT J_Mp_transp(J_Mp); J_Mp_transp.T(); covPred.ResizeTo(5,5); covPred = J_Mp*(cov7x7*J_Mp_transp); statePred.ResizeTo(5,1); statePred[0][0] = QOP; statePred[1][0] = (A*U)/(A*W); statePred[2][0] = (A*V)/(A*W); statePred[3][0] = (Point-O)*U; statePred[4][0] = (Point-O)*V; fCachePlane = pl; fCacheSpu = (A*W)/fabs(A*W); return coveredDistance; } double RKTrackRep::extrapolate(const GFDetPlane& pl, TMatrixT& statePred){ TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); TVector3 pTilde = fSpu* (w + fState[1][0] * u + fState[2][0] * v); double pTildeMag = pTilde.Mag(); TVector3 pos = o + fState[3][0]*u + fState[4][0]*v; TMatrixT state7(7,1); state7[0][0] = pos.X(); state7[1][0] = pos.Y(); state7[2][0] = pos.Z(); state7[3][0] = pTilde.X()/pTildeMag; state7[4][0] = pTilde.Y()/pTildeMag; state7[5][0] = pTilde.Z()/pTildeMag; state7[6][0] = fState[0][0]; TVector3 O = pl.getO(); TVector3 U = pl.getU(); TVector3 V = pl.getV(); TVector3 W = pl.getNormal(); double coveredDistance = this->Extrap(pl,&state7); double X = state7[0][0]; double Y = state7[1][0]; double Z = state7[2][0]; double AX = state7[3][0]; double AY = state7[4][0]; double AZ = state7[5][0]; double QOP = state7[6][0]; TVector3 A(AX,AY,AZ); TVector3 Point(X,Y,Z); statePred.ResizeTo(5,1); statePred[0][0] = QOP; statePred[1][0] = (A*U)/(A*W); statePred[2][0] = (A*V)/(A*W); statePred[3][0] = (Point-O)*U; statePred[4][0] = (Point-O)*V; return coveredDistance; } // // Runge-Kutta method for tracking a particles through a magnetic field. // Uses Nystroem algorithm (See Handbook Nat. Bur. of Standards, procedure 25.5.20) // // Input parameters: // SU - plane parameters // SU[0] - direction cosines normal to surface Ex // SU[1] - ------- Ey // SU[2] - ------- Ez; Ex*Ex+Ey*Ey+Ez*Ez=1 // SU[3] - distance to surface from (0,0,0) > 0 cm // // ND - number of variables for derivatives calculation // P - initial parameters (coordinates(cm), direction cosines, // charge/momentum (Gev-1) and derivatives this parameters (8x7) // // X Y Z Ax Ay Az q/P // P[ 0] P[ 1] P[ 2] P[ 3] P[ 4] P[ 5] P[ 6] // // dX/dp dY/dp dZ/dp dAx/dp dAy/dp dAz/dp d(q/P)/dp*P[6] // P[ 7] P[ 8] P[ 9] P[10] P[11] P[12] P[13] d()/dp1 // // P[14] P[15] P[16] P[17] P[18] P[19] P[20] d()/dp2 // ............................................................................ d()/dpND // // Output parameters: // // P - output parameters and derivatives after propagation in magnetic field // defined by Mfield (KGauss) // Where a Mfield(R,H) - is interface to magnetic field information // input R[ 0],R[ 1],R[ 2] - X , Y and Z of the track // output H[ 0],H[ 1],H[ 2] - Hx , Hy and Hz of the magnetic field // H[ 3],H[ 4],H[ 5] - dHx/dx, dHx/dy and dHx/dz // // H[ 6],H[ 7],H[ 8] - dHy/dx, dHy/dy and dHy/dz // (not used) // H[ 9],H[10],H[11] - dHz/dx, dHz/dy and dHz/dz // // // Authors: R.Brun, M.Hansroul, V.Perevoztchikov (Geant3) // bool RKTrackRep::RKutta (const GFDetPlane& plane, double* P, double& coveredDistance, std::vector& points, std::vector& pointPaths, const double& maxLen, // currently not used bool calcCov) const { static const double EC = .000149896229; // c/(2*10^12) resp. c/2Tera static const double DLT = .0002; // max. deviation for approximation-quality test static const double DLT32 = DLT/32.; // static const double P3 = 1./3.; // 1/3 static const double Smax = 100.; // max. step allowed > 0 static const double Wmax = 3000.; // max. way allowed static const double Pmin = 4.E-3; // minimum momentum for propagation [GeV] static const int ND = 56; // number of variables for derivatives calculation static const int ND1 = ND-7; // = 49 double* R = &P[0]; // Start coordinates in cm ( x, y, z) double* A = &P[3]; // Start directions (ax, ay, az); ax^2+ay^2+az^2=1 double SA[3] = {0.,0.,0.}; // Start directions derivatives double Pinv = P[6]*EC; // P[6] is charge/momentum in e/(Gev/c) double Way = 0.; // Total way of the trajectory double Way2 = 0.; // Total way of the trajectory with correct signs bool error = false; // Error of propogation bool stopBecauseOfMaterial = false; // does not go through main loop again when stepsize is reduced by stepper points.clear(); pointPaths.clear(); //std::cout<<"coords "< momentum too low: " << fabs(fCharge/P[6])*1000. << " MeV" << std::endl; return (false); } double SU[4]; TVector3 O = plane.getO(); TVector3 W = plane.getNormal(); if(W*O > 0){ // make SU vector point away from origin SU[0] = W.X(); SU[1] = W.Y(); SU[2] = W.Z(); } else{ SU[0] = -1.*W.X(); SU[1] = -1.*W.Y(); SU[2] = -1.*W.Z(); } SU[3] = plane.distance(0.,0.,0.); // // Step estimation until surface // double Step,An,Dist,Dis,S,Sl=0; points.push_back(TVector3(R[0],R[1],R[2])); pointPaths.push_back(0.); An=A[0]*SU[0]+A[1]*SU[1]+A[2]*SU[2]; // An = A * N; component of A normal to surface if(fabs(An) < 1.E-6) { std::cerr << "RKTrackRep::RKutta ==> cannot propagate perpendicular to plane " << std::endl; return false; // no propagation if A perpendicular to surface } if( plane.inActive(TVector3(R[0],R[1],R[2]),TVector3(A[0],A[1],A[2]))) { // if direction is not pointing to active part of surface Dist=SU[3]-R[0]*SU[0]-R[1]*SU[1]-R[2]*SU[2]; // Distance between start coordinates and surface Step=Dist/An; } else{ // make sure to extrapolate towards surface if( (O.X()-R[0])*A[0] + (O.Y()-R[1])*A[1] + (O.Z()-R[2])*A[2] >0 ){ // if direction A pointing from start coordinates R towards surface Dist = sqrt((R[0]-O.X())*(R[0]-O.X())+ // |R-O|; Distance between start coordinates and origin of surface (R[1]-O.Y())*(R[1]-O.Y())+ (R[2]-O.Z())*(R[2]-O.Z())); } else{ // if direction pointing away from surface Dist = -1.*sqrt((R[0]-O.X())*(R[0]-O.X())+ (R[1]-O.Y())*(R[1]-O.Y())+ (R[2]-O.Z())*(R[2]-O.Z())); } Step=Dist; } if(fabs(Step)>Wmax) { std::cerr<<"RKTrackRep::RKutta ==> Too long extrapolation requested : "< Trajectory is longer than length limit : "<Wmax) { Dis=0.; Dist=0.; S=0; Step=0.; break; } An=A[0]*SU[0]+A[1]*SU[1]+A[2]*SU[2]; if(fabs(An) < 1.E-6) { error=true; Step=0; break; } if( plane.inActive(TVector3(R[0],R[1],R[2]),TVector3(A[0],A[1],A[2]))) { Dis=SU[3]-R[0]*SU[0]-R[1]*SU[1]-R[2]*SU[2]; Step=Dis/An; } else{ if( (O.X()-R[0])*A[0] + (O.Y()-R[1])*A[1] + (O.Z()-R[2])*A[2] >0 ){ Dis = sqrt((R[0]-O.X())*(R[0]-O.X())+ (R[1]-O.Y())*(R[1]-O.Y())+ (R[2]-O.Z())*(R[2]-O.Z())); } else{ Dis = -1.*sqrt((R[0]-O.X())*(R[0]-O.X())+ (R[1]-O.Y())*(R[1]-O.Y())+ (R[2]-O.Z())*(R[2]-O.Z())); } Step = Dis; // signed distance to surface } if (Dis*Dist>0 && fabs(Dis)>fabs(Dist)) { // did not get closer to surface error=true; Step=0; break; } Dist=Dis; // // reset & check step size // // reset S to Step if extrapolation too long or in wrong direction if (S*Step<0. || fabs(S)>fabs(Step)) S=Step; else if (EST 1.E-12) Sl=1./Sl; // Sl = inverted last Stepsize Sl A [0]+=(SA[0]*=Sl)*Step; // Step = distance to surface A [1]+=(SA[1]*=Sl)*Step; // SA*Sl = delta A / delta way; local derivative of A with respect to the length of the way A [2]+=(SA[2]*=Sl)*Step; // A = A + Step * SA*Sl P[0] = R[0]+Step*(A[0]-.5*Step*SA[0]); // P = R + Step*(A - 1/2*Step*SA); approximation for final point on surface P[1] = R[1]+Step*(A[1]-.5*Step*SA[1]); P[2] = R[2]+Step*(A[2]-.5*Step*SA[2]); points.push_back(TVector3(P[0],P[1],P[2])); pointPaths.push_back(Step); } double CBA = 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); P[3] = A[0]*CBA; // normalize A P[4] = A[1]*CBA; P[5] = A[2]*CBA; // // Output derivatives of track parameters preparation // An = A[0]*SU[0]+A[1]*SU[1]+A[2]*SU[2]; fabs(An) < 1.E-6 ? An=1./An : An = 0; // 1/A_normal if(calcCov && !stopBecauseOfMaterial){ for(int i=7; i!=ND; i+=7) { double* dR = &P[i]; double* dA = &P[i+3]; S = (dR[0]*SU[0]+dR[1]*SU[1]+dR[2]*SU[2])*An; // dR_normal / A_normal dR[0]-=S*A [0]; dR[1]-=S*A [1]; dR[2]-=S*A [2]; dA[0]-=S*SA[0]; dA[1]-=S*SA[1]; dA[2]-=S*SA[2]; } } if(error){ std::cerr << "RKTrackRep::RKutta ==> Do not get closer. Path = " << Way << " cm" << " p/q = " << 1./P[6] << " GeV" << std::endl; return(false); } // calculate covered distance if (!stopBecauseOfMaterial) coveredDistance=Way2+Step; else coveredDistance=Way2; return(true); } double RKTrackRep::Extrap( const GFDetPlane& plane, TMatrixT* state, TMatrixT* cov) const { static const int maxNumIt(2000); int numIt(0); bool calcCov(true); if(cov==NULL) calcCov=false; double *P; if(calcCov) {P = new double[56]; memset(P,0x00,56*sizeof(double));} else {P = new double[7];} // not needed memset(P,0x00,7*sizeof(double));}; for(int i=0;i<7;++i){ P[i] = (*state)[i][0]; } TMatrixT jac(7,7); TMatrixT jacT(7,7); TMatrixT oldCov(7,7); if(calcCov) oldCov=(*cov); double coveredDistance(0.); double sumDistance(0.); while(true){ if(numIt++ > maxNumIt){ GFException exc("RKTrackRep::Extrap ==> maximum number of iterations exceeded", __LINE__,__FILE__); exc.setFatal(); delete[] P; throw exc; } if(calcCov){ memset(&P[7],0x00,49*sizeof(double)); for(int i=0; i<6; ++i){ P[(i+1)*7+i] = 1.; } P[55] = (*state)[6][0]; } double dir(1.); { TVector3 Pvect(P[0],P[1],P[2]); //position TVector3 Avect(P[3],P[4],P[5]); //direction TVector3 dist = plane.dist(Pvect); //from point to plane if(dist*Avect<0.) dir=-1.; } TVector3 directionBefore(P[3],P[4],P[5]); // direction before propagation directionBefore.SetMag(1.); // propagation std::vector points; std::vector pointPaths; if( ! this->RKutta(plane, P, coveredDistance, points, pointPaths, -1., calcCov) ) { // maxLen currently not used GFException exc("RKTrackRep::Extrap ==> Runge Kutta propagation failed",__LINE__,__FILE__); exc.setFatal(); // stops propagation; faster, but some hits will be lost delete[] P; throw exc; } TVector3 directionAfter(P[3],P[4],P[5]); // direction after propagation directionAfter.SetMag(1.); sumDistance+=coveredDistance; // filter Points std::vector pointsFilt(1, points.at(0)); std::vector pointPathsFilt(1, 0.); // only if in right direction for(unsigned int i=1;i 0.) { pointsFilt.push_back(points.at(i)); pointPathsFilt.push_back(pointPaths.at(i)); } else { pointsFilt.back() = points.at(i); pointPathsFilt.back() += pointPaths.at(i); } // clean up tiny steps int position = pointsFilt.size()-1; // position starts with 0 if (fabs(pointPathsFilt.back()) < MINSTEP && position > 1) { pointsFilt.at(position-1) = pointsFilt.at(position); pointsFilt.pop_back(); pointPathsFilt.at(position-1) += pointPathsFilt.at(position); pointPathsFilt.pop_back(); } } //consistency check double checkSum(0.); for(unsigned int i=0;i1.E-7){ GFException exc("RKTrackRep::Extrap ==> fabs(checkSum-coveredDistance)>1.E-7",__LINE__,__FILE__); exc.setFatal(); delete[] P; throw exc; } if(calcCov){ //calculate Jacobian jac for(int i=0;i<7;++i){ for(int j=0;j<7;++j){ if(i<6) jac[i][j] = P[ (i+1)*7+j ]; else jac[i][j] = P[ (i+1)*7+j ]/P[6]; } } jacT = jac; jacT.T(); } TMatrixT noise(7,7); // zero everywhere by default // call MatEffects double momLoss; // momLoss has a sign - negative loss means momentum gain momLoss = GFMaterialEffects::getInstance()->effects(pointsFilt, pointPathsFilt, fabs(fCharge/P[6]), // momentum fPdg, calcCov, &noise, &jac, &directionBefore, &directionAfter); if(fabs(P[6])>1.E-10){ // do momLoss only for defined 1/momentum .ne.0 P[6] = fCharge/(fabs(fCharge/P[6])-momLoss); } if(calcCov){ //propagate cov and add noise if(!(oldCov < 1.E200)){ GFException exc("RKTrackRep::Extrap ==> covariance matrix exceeds numerical limits",__LINE__,__FILE__); exc.setFatal(); delete[] P; throw exc; } oldCov = *cov; *cov = jacT*((oldCov)*jac)+noise; } //we arrived at the destination plane, if we point to the active area //of the plane (if it is finite), and the distance is below threshold if( plane.inActive(TVector3(P[0],P[1],P[2]),TVector3(P[3],P[4],P[5]))) { if(plane.distance(P[0],P[1],P[2])& cov){ const TVector3 U=pl.getU(); const TVector3 V=pl.getV(); const TVector3 W=U.Cross(V); TMatrixT statePred=fState; TMatrixT covPred=fCov; double spu=fSpu; if(pl!=fRefPlane) { extrapolate(pl, statePred, covPred); spu=fCacheSpu; } const double p=fCharge/statePred[0][0]; //Magnitude of the momentum. const TVector3 pTilde=spu*(W+statePred[1][0]*U+statePred[2][0]*V); const double pTildeMagnitude=pTilde.Mag(); TMatrixT jacobian(6, 5); //Jacobian matrix \frac{\partial\left(x, y, z, p_x, p_y, p_z\right)}{\partial\left(\frac{q}{p}, u^\prime, v^\prime, u, v\right)} jacobian[0][3]=U.X(); jacobian[0][4]=V.X(); jacobian[1][3]=U.Y(); jacobian[1][4]=V.Y(); jacobian[2][3]=U.Z(); jacobian[2][4]=V.Z(); jacobian[3][1]=p*spu/pTildeMagnitude*(U.X()-pTilde.X()*(U*pTilde)/(pTildeMagnitude*pTildeMagnitude)); jacobian[3][2]=p*spu/pTildeMagnitude*(V.X()-pTilde.X()*(V*pTilde)/(pTildeMagnitude*pTildeMagnitude)); jacobian[4][1]=p*spu/pTildeMagnitude*(U.Y()-pTilde.Y()*(U*pTilde)/(pTildeMagnitude*pTildeMagnitude)); jacobian[4][2]=p*spu/pTildeMagnitude*(V.Y()-pTilde.Y()*(V*pTilde)/(pTildeMagnitude*pTildeMagnitude)); jacobian[5][1]=p*spu/pTildeMagnitude*(U.Z()-pTilde.Z()*(U*pTilde)/(pTildeMagnitude*pTildeMagnitude)); jacobian[5][2]=p*spu/pTildeMagnitude*(V.Z()-pTilde.Z()*(V*pTilde)/(pTildeMagnitude*pTildeMagnitude)); TMatrixT transposedJacobian=jacobian; transposedJacobian.T(); cov.ResizeTo(6, 6); pos=pl.getO()+statePred[3][0]*U+statePred[4][0]*V; mom=p/pTildeMagnitude*pTilde; cov=jacobian*covPred*transposedJacobian; } double RKTrackRep::stepalong(double h, TVector3& pos, TVector3& dir){ TVector3 dest; static const int maxIt(30); TVector3 o=fRefPlane.getO(); TVector3 u=fRefPlane.getU(); TVector3 v=fRefPlane.getV(); TVector3 w=u.Cross(v); TVector3 pTilde = fSpu* (w + fState[1][0] * u + fState[2][0] * v); pTilde.SetMag(1.); TVector3 point = o + fState[3][0]*u + fState[4][0]*v; TMatrixT state7(7,1); state7[0][0] = point.X(); state7[1][0] = point.Y(); state7[2][0] = point.Z(); state7[3][0] = pTilde.X(); state7[4][0] = pTilde.Y(); state7[5][0] = pTilde.Z(); state7[6][0] = fState[0][0]; double coveredDistance(0.); GFDetPlane pl; int iterations(0); while(true){ pos.SetXYZ(state7[0][0], state7[1][0], state7[2][0]); dir.SetXYZ(state7[3][0], state7[4][0], state7[5][0]); dir.SetMag(1.); dest = pos + (h - coveredDistance) * dir; pl.setON(dest, dir); coveredDistance += this->Extrap(pl,&state7); if(fabs(h - coveredDistance) maximum number of iterations reached",__LINE__,__FILE__); throw exc; } } pos.SetXYZ(state7[0][0], state7[1][0], state7[2][0]); dir.SetXYZ(state7[3][0], state7[4][0], state7[5][0]); dir.SetMag(1.); return coveredDistance; } ClassImp(RKTrackRep)