diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h new file mode 100755 index 0000000000000000000000000000000000000000..67e42103f4ea1151b27ec703db128623f560f8ad --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h @@ -0,0 +1,445 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +///////////////////////////////////////////////////////////////////////////////// +// Header file for class RungeKuttaPropagator, (c) ATLAS Detector software +///////////////////////////////////////////////////////////////////////////////// + +#ifndef RungeKuttaPropagator_H +#define RungeKuttaPropagator_H + +#include <list> +#include "AthenaBaseComps/AthAlgTool.h" +#include "GaudiKernel/ServiceHandle.h" +#include "MagFieldInterfaces/IMagFieldSvc.h" +#include "TrkExInterfaces/IPropagator.h" +#include "TrkExInterfaces/IPatternParametersPropagator.h" +#include "TrkEventPrimitives/ParticleHypothesis.h" +#include "TrkEventPrimitives/PropDirection.h" +#include "TrkParameters/TrackParameters.h" +#include "TrkNeutralParameters/NeutralParameters.h" + +namespace Trk { + + class Surface ; + class MagneticFieldProperties ; + class CylinderBounds ; + class CylinderSurface ; + class PatternTrackParameters ; + + /** + @class RungeKuttaPropagator + + Trk::RungeKuttaPropagator is algorithm for track parameters propagation through + magnetic field with or without jacobian of transformation. This algorithm + contains three steps. + + 1.The first step of the algorithm is track parameters transformation from + local presentation for given start surface to global Runge Kutta coordinates. + + 2.The second step is propagation through magnetic field with or without jacobian. + + 3.Third step is transformation from global Runge Kutta presentation to local + presentation of given output surface. + + + AtaPlane AtaStraightLine AtaDisc AtaCylinder Perigee + | | | | | + | | | | | + V V V V V + ----------------------------------------------------------------- + | Local->Global transformation + V + Global position (Runge Kutta presentation) + | + | + Propagation to next surface with or without jacobian + using Nystroem algorithm + (See Handbook Net. Bur. of Standards, procedure 25.5.20) + | + V Global->Local transformation + ---------------------------------------------------------------- + | | | | | + | | | | | + V V V V V + PlaneSurface StraightLineSurface DiscSurface CylinderSurface PerigeeSurface + + For propagation using Runge Kutta method we use global coordinate, direction, + inverse momentum and Jacobian of transformation. All this parameters we save + in array P[42]. + /dL0 /dL1 /dPhi /dThe /dCM + X ->P[0] dX / P[ 7] P[14] P[21] P[28] P[35] + Y ->P[1] dY / P[ 8] P[15] P[22] P[29] P[36] + Z ->P[2] dZ / P[ 9] P[16] P[23] P[30] P[37] + Ax ->P[3] dAx/ P[10] P[17] P[24] P[31] P[38] + Ay ->P[4] dAy/ P[11] P[18] P[25] P[32] P[39] + Az ->P[5] dAz/ P[12] P[19] P[26] P[33] P[40] + CM ->P[6] dCM/ P[13] P[20] P[27] P[34] P[41] + + where + in case local presentation + + L0 - first local coordinate (surface dependent) + L1 - second local coordinate (surface dependent) + Phi - Azimuthal angle + The - Polar angle + CM - charge/momentum + + in case global presentation + + X - global x-coordinate = surface dependent + Y - global y-coordinate = surface dependent + Z - global z-coordinate = sutface dependent + Ax - direction cosine to x-axis = Sin(The)*Cos(Phi) + Ay - direction cosine to y-axis = Sin(The)*Sin(Phi) + Az - direction cosine to z-axis = Cos(The) + CM - charge/momentum = local CM + + Comment: + if pointer to const * = 0 algorithm will propagate track + parameters and jacobian of transformation according straight line model + + + @author Igor.Gavrilenko@cern.ch + */ + + class RungeKuttaPropagator : public AthAlgTool, virtual public IPropagator, + virtual public IPatternParametersPropagator + { + ///////////////////////////////////////////////////////////////////////////////// + // Public methods: + ///////////////////////////////////////////////////////////////////////////////// + + public: + + RungeKuttaPropagator(const std::string&,const std::string&,const IInterface*); + + virtual ~RungeKuttaPropagator (); + + /** AlgTool initailize method.*/ + StatusCode initialize(); + + /** AlgTool finalize method */ + StatusCode finalize(); + + /** Main propagation mehtod NeutralParameters */ + + const NeutralParameters* propagate + (const NeutralParameters &, + const Surface &, + PropDirection , + BoundaryCheck , + bool ) const; + + /** Main propagation mehtod without transport jacobian production*/ + + const TrackParameters* propagate + (const TrackParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + const MagneticFieldProperties &, + ParticleHypothesis , + bool , + const TrackingVolume* ) const; + + /** Main propagation mehtod with transport jacobian production*/ + + const TrackParameters* propagate + (const TrackParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + const MagneticFieldProperties &, + TransportJacobian *&, + ParticleHypothesis , + bool , + const TrackingVolume* ) const; + + /** The propagation method finds the closest surface */ + + const TrackParameters* propagate + (const TrackParameters &, + std::vector<DestSurf> &, + PropDirection , + const MagneticFieldProperties &, + ParticleHypothesis , + std::vector<unsigned int> &, + double &, + bool , + bool , + const TrackingVolume* ) const; + + /** Main propagation mehtod for parameters only without transport jacobian productio*/ + + const TrackParameters* propagateParameters + (const TrackParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + const MagneticFieldProperties &, + ParticleHypothesis , + bool , + const TrackingVolume* ) const; + + + /** Main propagation mehtod for parameters only with transport jacobian productio*/ + + const TrackParameters* propagateParameters + (const TrackParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + const MagneticFieldProperties &, + TransportJacobian *&, + ParticleHypothesis , + bool , + const TrackingVolume* ) const; + + /** Global position together with direction of the trajectory on the surface */ + + const IntersectionSolution* intersect + (const TrackParameters &, + const Surface &, + const MagneticFieldProperties &, + ParticleHypothesis particle=pion, + const TrackingVolume* tvol=0 ) const; + + /** GlobalPositions list interface:*/ + + void globalPositions + (std::list<Amg::Vector3D> &, + const TrackParameters &, + const MagneticFieldProperties &, + const CylinderBounds& , + double , + ParticleHypothesis particle=pion, + const TrackingVolume* tvol=0 ) const; + + /** Test quality Jacobian calculation */ + + void JacobianTest + (const TrackParameters &, + const Surface &, + const MagneticFieldProperties&) const; + + ///////////////////////////////////////////////////////////////////////////////// + // Public methods for Trk::PatternTrackParameters (from IPattern'Propagator) + ///////////////////////////////////////////////////////////////////////////////// + + /** Main propagation mehtod */ + + bool propagate + (PatternTrackParameters &, + const Surface &, + PatternTrackParameters &, + PropDirection , + const MagneticFieldProperties &, + ParticleHypothesis particle=pion) const; + + /** Main propagation mehtod with step to surface calculation*/ + + bool propagate + (PatternTrackParameters &, + const Surface &, + PatternTrackParameters &, + PropDirection , + const MagneticFieldProperties &, + double &, + ParticleHypothesis particle=pion) const; + + /** Main propagation mehtod for parameters only */ + + bool propagateParameters + (PatternTrackParameters &, + const Surface &, + PatternTrackParameters &, + PropDirection , + const MagneticFieldProperties &, + ParticleHypothesis particle=pion) const; + + /** Main propagation mehtod for parameters only with step to surface calculation*/ + + bool propagateParameters + (PatternTrackParameters &, + const Surface &, + PatternTrackParameters &, + PropDirection , + const MagneticFieldProperties &, + double &, + ParticleHypothesis particle=pion) const; + + /** GlobalPositions list interface:*/ + + void globalPositions + (std::list<Amg::Vector3D> &, + const PatternTrackParameters &, + const MagneticFieldProperties &, + const CylinderBounds &, + double , + ParticleHypothesis particle=pion) const; + + /** GlobalPostions and steps for set surfaces */ + + void globalPositions + (const PatternTrackParameters &, + std::list<const Surface*> &, + std::list< std::pair<Amg::Vector3D,double> > &, + const MagneticFieldProperties &, + ParticleHypothesis particle=pion ) const; + + private: + + ///////////////////////////////////////////////////////////////////////////////// + // Private methods: + ///////////////////////////////////////////////////////////////////////////////// + + /** Internal RungeKutta propagation method for charge track parameters*/ + + const TrackParameters* propagateRungeKutta + (bool , + const TrackParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + const MagneticFieldProperties&, + double *, + bool returnCurv) const; + + /** Internal RungeKutta propagation method for neutral track parameters*/ + + const NeutralParameters* propagateStraightLine + (bool , + const NeutralParameters &, + const Surface &, + const PropDirection , + BoundaryCheck , + double *, + bool returnCurv) const; + + /** Internal RungeKutta propagation method */ + + bool propagateRungeKutta + (bool , + PatternTrackParameters &, + const Surface &, + PatternTrackParameters &, + PropDirection , + const MagneticFieldProperties&, + double &) const; + + /** Internal RungeKutta propagation method for propation with jacobian*/ + + bool propagateWithJacobian + (bool , + int , + double *, + double *, + double &) const; + + /** Propagation methods runge kutta step*/ + + double rungeKuttaStep + (bool , + double , + double *, + bool &) const; + + /** Propagation methods runge kutta step*/ + + double rungeKuttaStepWithGradient + (double , + double *, + bool &) const; + + /** Propagation methods straight line step*/ + + double straightLineStep + (bool , + double , + double*) const; + + /** Test new propagation to cylinder boundary */ + + bool newCrossPoint + (const CylinderSurface&, + const double *, + const double *) const; + + /** Step estimator with directions correction */ + + double stepEstimatorWithCurvature(int,double*,const double*,bool&) const; + + /** Step reduction */ + double stepReduction(const double*) const; + + /** Build new track parameters without propagation */ + + const TrackParameters* buildTrackParametersWithoutPropagation + (const TrackParameters &,double*) const; + + const NeutralParameters* buildTrackParametersWithoutPropagation + (const NeutralParameters&,double*) const; + + void globalOneSidePositions + (std::list<Amg::Vector3D> &, + const double *, + const MagneticFieldProperties &, + const CylinderBounds &, + double , + ParticleHypothesis particle=pion) const; + + void globalTwoSidePositions + (std::list<Amg::Vector3D> &, + const double *, + const MagneticFieldProperties &, + const CylinderBounds &, + double , + ParticleHypothesis particle=pion) const; + + const Trk::TrackParameters* crossPoint + (const TrackParameters &, + std::vector<DestSurf> &, + std::vector<unsigned int>&, + double *, + std::pair<double,int> &) const; + + void getField (double*,double* ) const; + void getFieldGradient(double*,double*,double*) const; + + + ///////////////////////////////////////////////////////////////////////////////// + // Private data members: + ///////////////////////////////////////////////////////////////////////////////// + + double m_dlt ; // accuracy parameter + double m_helixStep ; // max step whith helix model + double m_straightStep ; // max step whith srtaight line model + bool m_usegradient ; // use magnetif field gradient + mutable double m_direction ; + mutable bool m_mcondition ; + mutable bool m_solenoid ; + mutable bool m_needgradient ; + ServiceHandle<MagField::IMagFieldSvc> m_fieldServiceHandle; + MagField::IMagFieldSvc* m_fieldService ; + }; + + ///////////////////////////////////////////////////////////////////////////////// + // Inline methods for magnetic field information + ///////////////////////////////////////////////////////////////////////////////// + + inline void RungeKuttaPropagator::getField(double* R,double* H) const + { + if(m_solenoid) return m_fieldService->getFieldZR(R,H); + return m_fieldService->getField (R,H); + } + + inline void RungeKuttaPropagator::getFieldGradient(double* R,double* H,double* dH) const + { + if(m_solenoid) return m_fieldService->getFieldZR(R,H,dH); + return m_fieldService->getField (R,H,dH); + } +} + +#endif // RungeKuttaPropagator_H diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/cmt/requirements b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/cmt/requirements new file mode 100755 index 0000000000000000000000000000000000000000..7719e0da1877d4c7dd7960c85926c3de2591873c --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/cmt/requirements @@ -0,0 +1,26 @@ +package TrkExRungeKuttaPropagator + +author Igor Gavrilenko <Igor.Gavrilenko@cern.ch> +manager Igor Gavrilenko <Igor.Gavrilenko@cern.ch> + +private + +use TrkPatternParameters TrkPatternParameters-* Tracking/TrkEvent +use TrkExUtils TrkExUtils-* Tracking/TrkExtrapolation +use TrkSurfaces TrkSurfaces-* Tracking/TrkDetDescr +use TrkGeometry TrkGeometry-* Tracking/TrkDetDescr + +public + +use GaudiInterface GaudiInterface-* External +use AtlasPolicy AtlasPolicy-* +use MagFieldInterfaces * MagneticField +use AthenaBaseComps AthenaBaseComps-* Control +use TrkExInterfaces TrkExInterfaces-* Tracking/TrkExtrapolation +use TrkEventPrimitives TrkEventPrimitives-* Tracking/TrkEvent +use TrkParameters TrkParameters-* Tracking/TrkEvent +use TrkNeutralParameters TrkNeutralParameters-* Tracking/TrkEvent + +library TrkExRungeKuttaPropagator *.cxx components/*.cxx +apply_pattern component_library + diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/doc/mainpage.h b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/doc/mainpage.h new file mode 100755 index 0000000000000000000000000000000000000000..e5bcf45bbfe79fd0763eeb1a427ff8b9a9ee7a5c --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/doc/mainpage.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** +@mainpage The TrkExRungeKutta package + +Propagation of TrackParameters and their associated covariance matrices in a Runge-Kutta integrated method + +@section TrkExRkIntroduction Introduction + +The RungeKuttaPropagator implements the IPropagator interface with a Runge-Kutta +integrated method to be used in a non-homogenous magnetic field. +In case of absence of a magnetic field the RungeKuttaPropagator would propagate the track-parameters +according to a straight line, in case of an homogenous magnetic field, a helical propagation is performed. + +Common transformations with the STEP_Propagator can be found in the TrkExUtils package. + +The tool implements two abstract interfaces: +- under Trk::IPropagator it provides propagation of EDM Trk::TrackParameters +- under Trk::IPatternParametersPropagator it provides propagation of parameters for internal use, the Trk::PatternTrackParameters + +@section TrkExRkComments Comments + +Please let me know of any errors, or if anything is unclear. +@author Igor.Gavrilenko@cern.ch + +*/ + diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx new file mode 100755 index 0000000000000000000000000000000000000000..9a01e5d43576577b10743648eab5f52e460e4b05 --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx @@ -0,0 +1,1729 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +///////////////////////////////////////////////////////////////////////////////// +// RungeKuttaPropagator.cxx, (c) ATLAS Detector software +///////////////////////////////////////////////////////////////////////////////// + +#include "TrkExUtils/RungeKuttaUtils.h" +#include "TrkExRungeKuttaPropagator/RungeKuttaPropagator.h" +#include "TrkSurfaces/ConeSurface.h" +#include "TrkSurfaces/DiscSurface.h" +#include "TrkSurfaces/PlaneSurface.h" +#include "TrkSurfaces/PerigeeSurface.h" +#include "TrkSurfaces/CylinderSurface.h" +#include "TrkSurfaces/StraightLineSurface.h" +#include "TrkGeometry/MagneticFieldProperties.h" +#include "TrkExUtils/IntersectionSolution.h" +#include "TrkExUtils/TransportJacobian.h" +#include "TrkPatternParameters/PatternTrackParameters.h" + +///////////////////////////////////////////////////////////////////////////////// +// Constructor +///////////////////////////////////////////////////////////////////////////////// + +Trk::RungeKuttaPropagator::RungeKuttaPropagator +(const std::string& p,const std::string& n,const IInterface* t) : + AthAlgTool(p,n,t), + m_fieldServiceHandle("AtlasFieldSvc",n) +{ + m_dlt = .000200; + m_helixStep = 1. ; + m_straightStep = .01 ; + m_usegradient = false ; + m_fieldService = 0 ; + m_solenoid = true ; + + declareInterface<Trk::IPropagator>(this); + declareInterface<Trk::IPatternParametersPropagator>(this); + declareProperty("AccuracyParameter" ,m_dlt ); + declareProperty("MaxHelixStep" ,m_helixStep ); + declareProperty("MaxStraightLineStep", m_straightStep); + declareProperty("IncludeBgradients" , m_usegradient ); + declareProperty("MagFieldSvc" , m_fieldServiceHandle); +} + +///////////////////////////////////////////////////////////////////////////////// +// initialize +///////////////////////////////////////////////////////////////////////////////// + +StatusCode Trk::RungeKuttaPropagator::initialize() +{ + if( !m_fieldServiceHandle.retrieve() ){ + ATH_MSG_FATAL("Failed to retrieve " << m_fieldServiceHandle ); + return StatusCode::FAILURE; + } + ATH_MSG_DEBUG("Retrieved " << m_fieldServiceHandle ); + m_fieldService = &*m_fieldServiceHandle; + + msg(MSG::INFO) << name() <<" initialize() successful" << endreq; + return StatusCode::SUCCESS; +} + +///////////////////////////////////////////////////////////////////////////////// +// finalize +///////////////////////////////////////////////////////////////////////////////// + +StatusCode Trk::RungeKuttaPropagator::finalize() +{ + msg(MSG::INFO) << name() <<" finalize() successful" << endreq; + return StatusCode::SUCCESS; +} + +///////////////////////////////////////////////////////////////////////////////// +// Destructor +///////////////////////////////////////////////////////////////////////////////// + +Trk::RungeKuttaPropagator::~RungeKuttaPropagator(){} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for NeutralParameters propagation +///////////////////////////////////////////////////////////////////////////////// + +const Trk::NeutralParameters* Trk::RungeKuttaPropagator::propagate +(const Trk::NeutralParameters & Tp, + const Trk::Surface & Su, + Trk::PropDirection D , + Trk::BoundaryCheck B , + bool returnCurv) const +{ + double J[25]; + return propagateStraightLine(true,Tp,Su,D,B,J,returnCurv); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters and covariance matrix propagation +// without transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagate +(const Trk::TrackParameters & Tp, + const Trk::Surface & Su, + Trk::PropDirection D, + Trk::BoundaryCheck B, + const MagneticFieldProperties& M, + ParticleHypothesis , + bool returnCurv, + const TrackingVolume* ) const +{ + double J[25]; + return propagateRungeKutta(true,Tp,Su,D,B,M,J,returnCurv); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters and covariance matrix propagation +// with transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagate +(const Trk::TrackParameters & Tp , + const Trk::Surface& Su , + Trk::PropDirection D , + Trk::BoundaryCheck B , + const MagneticFieldProperties& M , + TransportJacobian *& Jac, + ParticleHypothesis , + bool returnCurv, + const TrackingVolume* ) const +{ + double J[25]; + + const Trk::TrackParameters* Tpn = propagateRungeKutta(true,Tp,Su,D,B,M,J,returnCurv); + + if(Tpn) { + J[24]=J[20]; J[23]=0.; J[22]=0.; J[21]=0.; J[20]=0.; + Jac = new Trk::TransportJacobian(J); + } + else Jac = 0; + return Tpn; +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function to finds the closest surface +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagate +(const TrackParameters & Tp , + std::vector<DestSurf> & DS , + PropDirection D , + const MagneticFieldProperties& M , + ParticleHypothesis , + std::vector<unsigned int> & Sol , + double & Path, + bool usePathLim, + bool , + const TrackingVolume* ) const +{ + Sol.erase(Sol.begin(),Sol.end()); Path = 0.; if(DS.empty()) return 0; + m_direction = D; + + // Test is it measured track parameters + // + bool useJac; Tp.covariance() ? useJac = true : useJac = false; + + // Magnetic field information preparation + // + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + (useJac && m_usegradient) ? m_needgradient = true : m_needgradient = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + // Transform to global presentation + // + Trk::RungeKuttaUtils utils; + + double Po[45],Pn[45]; + if(!utils.transformLocalToGlobal(useJac,Tp,Po)) return 0; Po[42]=Po[43]=Po[44]=0.; + + // Straight line track propagation for small step + // + if(D!=0) { + double S= m_straightStep; if(D < 0) S = -S; S = straightLineStep(useJac,S,Po); + } + + double Wmax = 50000. ; // Max pass + double W = 0. ; // Current pass + double Smax = 100. ; // Max step + if(D < 0) Smax = -Smax; + if(usePathLim) Wmax = fabs(Path); + + std::multimap<double,int> DN; double Scut[3]; + int Nveto = utils.fillDistancesMap(DS,DN,Po,W,&Tp.associatedSurface(),Scut); + + // Test conditions tor start propagation and chocse direction if D == 0 + // + if(DN.empty()) return 0; + + if(D == 0 && fabs(Scut[0]) < fabs(Scut[1])) Smax = -Smax; + + if(Smax < 0. && Scut[0] > Smax) Smax = Scut[0]; + if(Smax > 0. && Scut[1] < Smax) Smax = Scut[1]; + if(Wmax > 3.*Scut[2] ) Wmax = 3.*Scut[2]; + + double Sl = Smax ; + double St = Smax ; + bool InS = false; + const TrackParameters* To = 0 ; + + for(int i=0; i!=45; ++i) Pn[i]=Po[i]; + + //----------------------------------Niels van Eldik patch + double last_St = 0. ; + bool last_InS = !InS ; + bool reverted_P = false; + //---------------------------------- + while (fabs(W) < Wmax) { + + std::pair<double,int> SN; + double S; + + if(m_mcondition) { + + //----------------------------------Niels van Eldik patch + if (reverted_P && St == last_St && InS == last_InS /*&& condition_fulfiled*/) { + // inputs are not changed will get same result. + break; + } + last_St = St; + last_InS = InS; + //---------------------------------- + + if(!m_needgradient) S = rungeKuttaStep (useJac,St,Pn,InS); + else S = rungeKuttaStepWithGradient( St,Pn,InS); + } + else { + + //----------------------------------Niels van Eldik patch + if (reverted_P && St == last_St /*&& !condition_fulfiled*/) { + // inputs are not changed will get same result. + break; + } + last_St = St; + last_InS = InS; + //---------------------------------- + + S = straightLineStep(useJac,St,Pn); + } + //----------------------------------Niels van Eldik patch + reverted_P=false; + //---------------------------------- + + bool next; SN=utils.stepEstimator(DS,DN,Po,Pn,W,m_straightStep,Nveto,next); + + if(next) {for(int i=0; i!=45; ++i) Po[i]=Pn[i]; W+=S; Nveto=-1; } + else {for(int i=0; i!=45; ++i) Pn[i]=Po[i]; reverted_P=true;} + + if (fabs(S)+1. < fabs(St)) Sl=S; + InS ? St = 2.*S : St = S; + + if(SN.second >= 0) { + + double Sa = fabs(SN.first); + + if(Sa > m_straightStep) { + if(fabs(St) > Sa) St = SN.first; + } + else { + Path = W+SN.first; + if((To = crossPoint(Tp,DS,Sol,Pn,SN))) return To; + Nveto = SN.second; St = Sl; + } + } + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters propagation without covariance matrix +// without transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagateParameters +(const Trk::TrackParameters & Tp, + const Trk::Surface & Su, + Trk::PropDirection D, + Trk::BoundaryCheck B, + const MagneticFieldProperties& M, + ParticleHypothesis , + bool returnCurv, + const TrackingVolume* ) const +{ + double J[25]; + return propagateRungeKutta(false,Tp,Su,D,B,M,J,returnCurv); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters propagation without covariance matrix +// with transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagateParameters +(const Trk::TrackParameters & Tp , + const Trk::Surface & Su , + Trk::PropDirection D , + Trk::BoundaryCheck B , + const MagneticFieldProperties& M , + TransportJacobian *& Jac, + ParticleHypothesis , + bool returnCurv, + const TrackingVolume* ) const +{ + double J[25]; + const Trk::TrackParameters* Tpn = propagateRungeKutta (true,Tp,Su,D,B,M,J,returnCurv); + + if(Tpn) { + J[24]=J[20]; J[23]=0.; J[22]=0.; J[21]=0.; J[20]=0.; + Jac = new Trk::TransportJacobian(J); + } + else Jac = 0; + return Tpn; +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for neutral track parameters propagation with or without jacobian +///////////////////////////////////////////////////////////////////////////////// + +const Trk::NeutralParameters* Trk::RungeKuttaPropagator::propagateStraightLine +(bool useJac, + const Trk::NeutralParameters & Tp , + const Trk::Surface & Su , + Trk::PropDirection D , + Trk::BoundaryCheck B , + double * Jac , + bool returnCurv) const +{ + const Trk::Surface* su = &Su; + if(su == &Tp.associatedSurface()) return buildTrackParametersWithoutPropagation(Tp,Jac); + + m_direction = D ; + m_mcondition = false; + + + Trk::RungeKuttaUtils utils; + + double P[64],Step = 0; if(!utils.transformLocalToGlobal(useJac,Tp,P)) return 0; + + const Amg::Transform3D& T = Su.transform(); + int ty = Su.type(); + + if (ty == Trk::Surface::Plane ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Line ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2)}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Disc ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cylinder ) { + + const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); + + double r0[3] = {P[0],P[1],P[2]}; + double s [9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),cyl->bounds().r(),m_direction,0.}; + + if(!propagateWithJacobian(useJac,2,s,P,Step)) return 0; + + // For cylinder we do test for next cross point + // + if(cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl,r0,P)) { + s[8] = 0.; if(!propagateWithJacobian(useJac,2,s,P,Step)) return 0; + } + } + else if (ty == Trk::Surface::Perigee ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),0.,0.,1.}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cone ) { + + double k = static_cast<const Trk::ConeSurface*>(su)->bounds().tanAlpha(); k = k*k+1.; + double s[9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),k,m_direction,0.}; + if(!propagateWithJacobian(useJac,3,s,P,Step)) return 0; + } + else return 0; + + if(m_direction!=0. && (m_direction*Step)<0.) return 0; + + // Common transformation for all surfaces (angles and momentum) + // + if(useJac) { + double p=1./P[6]; P[35]*=p; P[36]*=p; P[37]*=p; P[38]*=p; P[39]*=p; P[40]*=p; + } + + bool uJ = useJac; if(returnCurv) uJ = false; + + double p[5]; utils.transformGlobalToLocal(su,uJ,P,p,Jac); + + if(B) {Amg::Vector2D L(p[0],p[1]); if(!Su.insideBounds(L,0.)) return 0;} + + + // Transformation to curvilinear presentation + // + if(returnCurv) utils.transformGlobalToCurvilinear(useJac,P,p,Jac); + + + if(!useJac || !Tp.covariance()) { + + if(!returnCurv) { + return Su.createNeutralParameters(p[0],p[1],p[2],p[3],p[4],0); + } + else { + Amg::Vector3D gp(P[0],P[1],P[2]); + return new Trk::NeutralCurvilinearParameters(gp,p[2],p[3],p[4]); + } + } + + AmgSymMatrix(5)* e = utils.newCovarianceMatrix(Jac,*Tp.covariance()); + AmgSymMatrix(5)& cv = *e; + + if(cv(0,0)<=0. || cv(1,1)<=0. || cv(2,2)<=0. || cv(3,3)<=0. || cv(4,4)<=0.) { + delete e; return 0; + } + + if(!returnCurv) { + return Su.createNeutralParameters(p[0],p[1],p[2],p[3],p[4],e); + } + else { + Amg::Vector3D gp(P[0],P[1],P[2]); + return new Trk::NeutralCurvilinearParameters(gp,p[2],p[3],p[4],e); + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for charged track parameters propagation with or without jacobian +///////////////////////////////////////////////////////////////////////////////// +const Trk::TrackParameters* Trk::RungeKuttaPropagator::propagateRungeKutta +(bool useJac, + const Trk::TrackParameters & Tp , + const Trk::Surface & Su , + Trk::PropDirection D , + Trk::BoundaryCheck B , + const MagneticFieldProperties& M , + double * Jac , + bool returnCurv) const +{ + const Trk::Surface* su = &Su; + + if(!&Tp || !su) return 0; + + m_direction = D ; + + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + (useJac && m_usegradient)? m_needgradient = true : m_needgradient = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + if(su == &Tp.associatedSurface()) return buildTrackParametersWithoutPropagation(Tp,Jac); + + Trk::RungeKuttaUtils utils; + + double P[64],Step = 0.; if(!utils.transformLocalToGlobal(useJac,Tp,P)) return 0; + + const Amg::Transform3D& T = Su.transform(); + int ty = Su.type(); + + if (ty == Trk::Surface::Plane ) { + + double s[4], d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return 0; + + } + else if (ty == Trk::Surface::Line ) { + + double s[6] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2)}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Disc ) { + + double s[4], d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cylinder ) { + + const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); + + double r0[3] = {P[0],P[1],P[2]}; + double s [9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),cyl->bounds().r(),m_direction,0.}; + if(!propagateWithJacobian(useJac,2,s,P,Step)) return 0; + + // For cylinder we do test for next cross point + // + if(cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl,r0,P)) { + s[8] = 0.; if(!propagateWithJacobian(useJac,2,s,P,Step)) return 0; + } + } + else if (ty == Trk::Surface::Perigee ) { + + double s[6] = {T(0,3),T(1,3),T(2,3),0.,0.,1.}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cone ) { + + double k = static_cast<const Trk::ConeSurface*>(su)->bounds().tanAlpha(); k = k*k+1.; + double s[9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),k,m_direction,0.}; + if(!propagateWithJacobian(useJac,3,s,P,Step)) return 0; + } + else return 0; + + if(m_direction && (m_direction*Step)<0.) {return 0;} + + // Common transformation for all surfaces (angles and momentum) + // + if(useJac) { + double p=1./P[6]; P[35]*=p; P[36]*=p; P[37]*=p; P[38]*=p; P[39]*=p; P[40]*=p; + } + + bool uJ = useJac; if(returnCurv) uJ = false; + double p[5]; utils.transformGlobalToLocal(su,uJ,P,p,Jac); + + if(B) {Amg::Vector2D L(p[0],p[1]); if(!Su.insideBounds(L,0.)) return 0;} + + // Transformation to curvilinear presentation + // + if(returnCurv) utils.transformGlobalToCurvilinear(useJac,P,p,Jac); + + if(!useJac || !Tp.covariance()) { + + if(!returnCurv) { + return Su.createTrackParameters(p[0],p[1],p[2],p[3],p[4],0); + } + else { + Amg::Vector3D gp(P[0],P[1],P[2]); + return new Trk::CurvilinearParameters(gp,p[2],p[3],p[4]); + } + } + + AmgSymMatrix(5)* e = utils.newCovarianceMatrix(Jac,*Tp.covariance()); + AmgSymMatrix(5)& cv = *e; + + if(cv(0,0)<=0. || cv(1,1)<=0. || cv(2,2)<=0. || cv(3,3)<=0. || cv(4,4)<=0.) { + delete e; return 0; + } + + if(!returnCurv) { + return Su.createTrackParameters(p[0],p[1],p[2],p[3],p[4],e); + } + else { + Amg::Vector3D gp(P[0],P[1],P[2]); + return new Trk::CurvilinearParameters(gp,p[2],p[3],p[4],e); + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Global positions calculation inside CylinderBounds +// where mS - max step allowed if mS > 0 propagate along momentum +// mS < 0 propogate opposite momentum +///////////////////////////////////////////////////////////////////////////////// + +void Trk::RungeKuttaPropagator::globalPositions +(std::list<Amg::Vector3D> & GP, + const TrackParameters & Tp, + const MagneticFieldProperties & M , + const CylinderBounds & CB, + double mS, + ParticleHypothesis , + const TrackingVolume* ) const +{ + Trk::RungeKuttaUtils utils; + double P[45]; if(!utils.transformLocalToGlobal(false,Tp,P)) return; + + m_direction = fabs(mS); + if(mS > 0.) globalOneSidePositions(GP,P,M,CB, mS); + else globalTwoSidePositions(GP,P,M,CB,-mS); +} + +///////////////////////////////////////////////////////////////////////////////// +// Global position together with direction of the trajectory on the surface +///////////////////////////////////////////////////////////////////////////////// + +const Trk::IntersectionSolution* Trk::RungeKuttaPropagator::intersect +( const Trk::TrackParameters & Tp, + const Trk::Surface & Su, + const MagneticFieldProperties& M , + ParticleHypothesis , + const TrackingVolume* ) const +{ + bool nJ = false; + const Trk::Surface* su = &Su; + m_direction = 0. ; + + m_needgradient = false; + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + Trk::RungeKuttaUtils utils; + + double P[64]; if(!utils.transformLocalToGlobal(false,Tp,P)) return 0; + double Step = 0.; + + const Amg::Transform3D& T = Su.transform(); + int ty = Su.type(); + + if (ty == Trk::Surface::Plane ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(nJ,1,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Line ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2)}; + if(!propagateWithJacobian(nJ,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Disc ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(nJ,1,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cylinder ) { + + const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); + + double r0[3] = {P[0],P[1],P[2]}; + double s [9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),cyl->bounds().r(),m_direction,0.}; + + if(!propagateWithJacobian(nJ,2,s,P,Step)) return 0; + + // For cylinder we do test for next cross point + // + if(cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl,r0,P)) { + s[8] = 0.; if(!propagateWithJacobian(nJ,2,s,P,Step)) return 0; + } + } + else if (ty == Trk::Surface::Perigee ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),0.,0.,1.}; + if(!propagateWithJacobian(nJ,0,s,P,Step)) return 0; + } + else if (ty == Trk::Surface::Cone ) { + + double k = static_cast<const Trk::ConeSurface*>(su)->bounds().tanAlpha(); k = k*k+1.; + double s[9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),k,m_direction,0.}; + if(!propagateWithJacobian(nJ,3,s,P,Step)) return 0; + } + else return 0; + + Amg::Vector3D Glo(P[0],P[1],P[2]); + Amg::Vector3D Dir(P[3],P[4],P[5]); + Trk::IntersectionSolution* Int = new Trk::IntersectionSolution(); + Int->push_back(new Trk::TrackSurfaceIntersection(Glo,Dir,Step)); + return Int; +} + +///////////////////////////////////////////////////////////////////////////////// +// Runge Kutta main program for propagation with or without Jacobian +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::propagateWithJacobian +(bool Jac , + int kind , + double * Su, + double * P , + double & W ) const +{ + const double Smax = 1000. ; // max. step allowed + double Wmax = 100000. ; // Max way allowed + double Wwrong = 500. ; // Max way with wrong direction + double* R = &P[ 0] ; // Start coordinates + double* A = &P[ 3] ; // Start directions + double* SA = &P[42] ; SA[0]=SA[1]=SA[2]=0.; + + if(m_mcondition && fabs(P[6]) > .1) return false; + + // Step estimation until surface + // + Trk::RungeKuttaUtils utils; + bool Q; double S, Step=utils.stepEstimator(kind,Su,P,Q); if(!Q) return false; + + bool dir = true; + if(m_mcondition && m_direction && m_direction*Step < 0.) { + Step = -Step; dir = false; + } + + Step>Smax ? S=Smax : Step<-Smax ? S=-Smax : S=Step; + double So = fabs(S); int iS = 0; + + bool InS = false; + + // Rkuta extrapolation + // + int niter = 0; + while(fabs(Step) > m_straightStep) { + + if(++niter > 10000) return false; + + if(m_mcondition) { + + if(!m_needgradient) W+=(S=rungeKuttaStep (Jac,S,P,InS)); + else W+=(S=rungeKuttaStepWithGradient( S,P,InS)); + } + else { + W+=(S=straightLineStep(Jac,S,P)); + } + + Step = stepEstimatorWithCurvature(kind,Su,P,Q); if(!Q) return false; + + if(!dir) { + if(m_direction && m_direction*Step < 0.) Step = -Step; + else dir = true; + } + + if(S*Step<0.) {S = -S; ++iS;} + + double aS = fabs(S ); + double aStep = fabs(Step); + if ( aS > aStep ) S = Step; + else if(!iS && InS && aS*2. < aStep) S*=2. ; + if(!dir && fabs(W) > Wwrong ) return false; + if(iS > 10 || (iS>3 && fabs(S)>=So) || fabs(W)>Wmax ) {if(!kind) break; return false;} + So=fabs(S); + } + + // Output track parameteres + // + W+=Step; + + if(fabs(Step) < .001) return true; + + A [0]+=(SA[0]*Step); + A [1]+=(SA[1]*Step); + A [2]+=(SA[2]*Step); + double CBA = 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); + R[0]+=Step*(A[0]-.5*Step*SA[0]); A[0]*=CBA; + R[1]+=Step*(A[1]-.5*Step*SA[1]); A[1]*=CBA; + R[2]+=Step*(A[2]-.5*Step*SA[2]); A[2]*=CBA; + return true; +} + +///////////////////////////////////////////////////////////////////////////////// +// Runge Kutta trajectory model (units->mm,MeV,kGauss) +// Uses Nystroem algorithm (See Handbook Net. Bur. ofStandards, procedure 25.5.20) +///////////////////////////////////////////////////////////////////////////////// + +double Trk::RungeKuttaPropagator::rungeKuttaStep + (bool Jac, + double S , + double * P , + bool & InS) const +{ + const double C33 = 1./3. ; + double* R = &P[ 0]; // Coordinates + double* A = &P[ 3]; // Directions + double* sA = &P[42]; + double Pi = 149.89626*P[6]; // Invert mometum/2. + double dltm = m_dlt*.03 ; + + double f0[3],f[3]; getField(R,f0); + + bool Helix = false; if(fabs(S) < m_helixStep) Helix = true; + while(S != 0.) { + + double S3=C33*S, S4=.25*S, PS2=Pi*S; + + // First point + // + double H0[3] = {f0[0]*PS2, f0[1]*PS2, f0[2]*PS2}; + double A0 = A[1]*H0[2]-A[2]*H0[1] ; + double B0 = A[2]*H0[0]-A[0]*H0[2] ; + double C0 = A[0]*H0[1]-A[1]*H0[0] ; + double A2 = A[0]+A0 ; + double B2 = A[1]+B0 ; + double C2 = A[2]+C0 ; + double A1 = A2+A[0] ; + double B1 = B2+A[1] ; + double C1 = C2+A[2] ; + + // Second point + // + if(!Helix) { + double gP[3]={R[0]+A1*S4, R[1]+B1*S4, R[2]+C1*S4}; + getField(gP,f); + } + else {f[0]=f0[0]; f[1]=f0[1]; f[2]=f0[2];} + + double H1[3] = {f[0]*PS2,f[1]*PS2,f[2]*PS2}; + double A3 = B2*H1[2]-C2*H1[1]+A[0] ; + double B3 = C2*H1[0]-A2*H1[2]+A[1] ; + double C3 = A2*H1[1]-B2*H1[0]+A[2] ; + double A4 = B3*H1[2]-C3*H1[1]+A[0] ; + double B4 = C3*H1[0]-A3*H1[2]+A[1] ; + double C4 = A3*H1[1]-B3*H1[0]+A[2] ; + double A5 = A4-A[0]+A4 ; + double B5 = B4-A[1]+B4 ; + double C5 = C4-A[2]+C4 ; + + // Last point + // + if(!Helix) { + double gP[3]={R[0]+S*A4, R[1]+S*B4, R[2]+S*C4}; + getField(gP,f); + } + else {f[0]=f0[0]; f[1]=f0[1]; f[2]=f0[2];} + + double H2[3] = {f[0]*PS2,f[1]*PS2,f[2]*PS2}; + double A6 = B5*H2[2]-C5*H2[1] ; + double B6 = C5*H2[0]-A5*H2[2] ; + double C6 = A5*H2[1]-B5*H2[0] ; + + + // Test approximation quality on give step and possible step reduction + // + //double dE[4] = {(A1+A6)-(A3+A4),(B1+B6)-(B3+B4),(C1+C6)-(C3+C4),S}; + //double cS = stepReduction(dE); + //if (cSn < 1.) {S*=cS; continue;} + //cSn == 1. InS = false : InS = true; + // + + // Test approximation quality on give step and possible step reduction + // + double EST = fabs((A1+A6)-(A3+A4))+fabs((B1+B6)-(B3+B4))+fabs((C1+C6)-(C3+C4)); + if(EST>m_dlt) {S*=.5; dltm = 0.; continue;} EST<dltm ? InS = true : InS = false; + + // Parameters calculation + // + double A00 = A[0], A11=A[1], A22=A[2]; + R[0]+=(A2+A3+A4)*S3; A[0] = ((A0+2.*A3)+(A5+A6))*C33; + R[1]+=(B2+B3+B4)*S3; A[1] = ((B0+2.*B3)+(B5+B6))*C33; + R[2]+=(C2+C3+C4)*S3; A[2] = ((C0+2.*C3)+(C5+C6))*C33; + double CBA = 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); + A[0]*=CBA; A[1]*=CBA; A[2]*=CBA; + + double Sl = 2./S; + sA[0] = A6*Sl; + sA[1] = B6*Sl; + sA[2] = C6*Sl; + + if(!Jac) return S; + + // Jacobian calculation + // + for(int i=21; i<35; i+=7) { + + double* dR = &P[i] ; + double* dA = &P[i+3] ; + double dA0 = H0[ 2]*dA[1]-H0[ 1]*dA[2] ; + double dB0 = H0[ 0]*dA[2]-H0[ 2]*dA[0] ; + double dC0 = H0[ 1]*dA[0]-H0[ 0]*dA[1] ; + double dA2 = dA0+dA[0] ; + double dB2 = dB0+dA[1] ; + double dC2 = dC0+dA[2] ; + double dA3 = dA[0]+dB2*H1[2]-dC2*H1[1] ; + double dB3 = dA[1]+dC2*H1[0]-dA2*H1[2] ; + double dC3 = dA[2]+dA2*H1[1]-dB2*H1[0] ; + double dA4 = dA[0]+dB3*H1[2]-dC3*H1[1] ; + double dB4 = dA[1]+dC3*H1[0]-dA3*H1[2] ; + double dC4 = dA[2]+dA3*H1[1]-dB3*H1[0] ; + double dA5 = dA4+dA4-dA[0] ; + double dB5 = dB4+dB4-dA[1] ; + double dC5 = dC4+dC4-dA[2] ; + double dA6 = dB5*H2[2]-dC5*H2[1] ; + double dB6 = dC5*H2[0]-dA5*H2[2] ; + double dC6 = dA5*H2[1]-dB5*H2[0] ; + dR[0]+=(dA2+dA3+dA4)*S3; dA[0]=((dA0+2.*dA3)+(dA5+dA6))*C33 ; + dR[1]+=(dB2+dB3+dB4)*S3; dA[1]=((dB0+2.*dB3)+(dB5+dB6))*C33 ; + dR[2]+=(dC2+dC3+dC4)*S3; dA[2]=((dC0+2.*dC3)+(dC5+dC6))*C33 ; + } + + double* dR = &P[35] ; + double* dA = &P[38] ; + double dA0 = H0[ 2]*dA[1]-H0[ 1]*dA[2]+A0 ; + double dB0 = H0[ 0]*dA[2]-H0[ 2]*dA[0]+B0 ; + double dC0 = H0[ 1]*dA[0]-H0[ 0]*dA[1]+C0 ; + double dA2 = dA0+dA[0] ; + double dB2 = dB0+dA[1] ; + double dC2 = dC0+dA[2] ; + double dA3 = (dA[0]+dB2*H1[2]-dC2*H1[1])+(A3-A00) ; + double dB3 = (dA[1]+dC2*H1[0]-dA2*H1[2])+(B3-A11) ; + double dC3 = (dA[2]+dA2*H1[1]-dB2*H1[0])+(C3-A22) ; + double dA4 = (dA[0]+dB3*H1[2]-dC3*H1[1])+(A4-A00) ; + double dB4 = (dA[1]+dC3*H1[0]-dA3*H1[2])+(B4-A11) ; + double dC4 = (dA[2]+dA3*H1[1]-dB3*H1[0])+(C4-A22) ; + double dA5 = dA4+dA4-dA[0] ; + double dB5 = dB4+dB4-dA[1] ; + double dC5 = dC4+dC4-dA[2] ; + double dA6 = dB5*H2[2]-dC5*H2[1]+A6 ; + double dB6 = dC5*H2[0]-dA5*H2[2]+B6 ; + double dC6 = dA5*H2[1]-dB5*H2[0]+C6 ; + dR[0]+=(dA2+dA3+dA4)*S3; dA[0]=((dA0+2.*dA3)+(dA5+dA6))*C33 ; + dR[1]+=(dB2+dB3+dB4)*S3; dA[1]=((dB0+2.*dB3)+(dB5+dB6))*C33 ; + dR[2]+=(dC2+dC3+dC4)*S3; dA[2]=((dC0+2.*dC3)+(dC5+dC6))*C33 ; + return S; + } + return S; +} + +///////////////////////////////////////////////////////////////////////////////// +// Runge Kutta trajectory model (units->mm,MeV,kGauss) +// Uses Nystroem algorithm (See Handbook Net. Bur. ofStandards, procedure 25.5.20) +// Where magnetic field information iS +// f[ 0],f[ 1],f[ 2] - Hx , Hy and Hz of the magnetic field +// f[ 3],f[ 4],f[ 5] - dHx/dx, dHx/dy and dHx/dz +// f[ 6],f[ 7],f[ 8] - dHy/dx, dHy/dy and dHy/dz +// f[ 9],f[10],f[11] - dHz/dx, dHz/dy and dHz/dz +// +///////////////////////////////////////////////////////////////////////////////// + +double Trk::RungeKuttaPropagator::rungeKuttaStepWithGradient +(double S , + double * P , + bool & InS) const +{ + const double C33 = 1./3. ; + double* R = &P[ 0]; // Coordinates + double* A = &P[ 3]; // Directions + double* sA = &P[42]; + double Pi = 149.89626*P[6]; // Invert mometum/2. + double dltm = m_dlt*.03 ; + + double f0[3],f1[3],f2[3],g0[9],g1[9],g2[9],H0[12],H1[12],H2[12]; + getFieldGradient(R,f0,g0); + + while(S != 0.) { + + + double S3=C33*S, S4=.25*S, PS2=Pi*S; + + // First point + // + H0[0] = f0[0]*PS2; H0[1] = f0[1]*PS2; H0[2] = f0[2]*PS2; + double A0 = A[1]*H0[2]-A[2]*H0[1] ; + double B0 = A[2]*H0[0]-A[0]*H0[2] ; + double C0 = A[0]*H0[1]-A[1]*H0[0] ; + double A2 = A[0]+A0 ; + double B2 = A[1]+B0 ; + double C2 = A[2]+C0 ; + double A1 = A2+A[0] ; + double B1 = B2+A[1] ; + double C1 = C2+A[2] ; + + // Second point + // + double gP1[3]={R[0]+A1*S4, R[1]+B1*S4, R[2]+C1*S4}; + getFieldGradient(gP1,f1,g1); + + H1[0] = f1[0]*PS2; H1[1] = f1[1]*PS2; H1[2] = f1[2]*PS2; + double A3 = B2*H1[2]-C2*H1[1]+A[0] ; + double B3 = C2*H1[0]-A2*H1[2]+A[1] ; + double C3 = A2*H1[1]-B2*H1[0]+A[2] ; + double A4 = B3*H1[2]-C3*H1[1]+A[0] ; + double B4 = C3*H1[0]-A3*H1[2]+A[1] ; + double C4 = A3*H1[1]-B3*H1[0]+A[2] ; + double A5 = A4-A[0]+A4 ; + double B5 = B4-A[1]+B4 ; + double C5 = C4-A[2]+C4 ; + + // Last point + // + double gP2[3]={R[0]+S*A4, R[1]+S*B4, R[2]+S*C4}; + getFieldGradient(gP2,f2,g2); + + H2[0] = f2[0]*PS2; H2[1] = f2[1]*PS2; H2[2] = f2[2]*PS2; + double A6 = B5*H2[2]-C5*H2[1] ; + double B6 = C5*H2[0]-A5*H2[2] ; + double C6 = A5*H2[1]-B5*H2[0] ; + + + // Test approximation quality on give step and possible step reduction + /* + double dE[4] = {(A1+A6)-(A3+A4),(B1+B6)-(B3+B4),(C1+C6)-(C3+C4),S}; + double cS = stepReduction(dE); + if (cSn < 1.) {S*=cS; continue;} + cSn == 1. InS = false : InS = true; + */ + + // Test approximation quality on give step and possible step reduction + // + double EST = fabs((A1+A6)-(A3+A4))+fabs((B1+B6)-(B3+B4))+fabs((C1+C6)-(C3+C4)); + if(EST>m_dlt) {S*=.5; dltm = 0.; continue;} EST<dltm ? InS = true : InS = false; + + // Parameters calculation + // + double A00 = A[0], A11=A[1], A22=A[2]; + R[0]+=(A2+A3+A4)*S3; A[0] = ((A0+2.*A3)+(A5+A6))*C33; + R[1]+=(B2+B3+B4)*S3; A[1] = ((B0+2.*B3)+(B5+B6))*C33; + R[2]+=(C2+C3+C4)*S3; A[2] = ((C0+2.*C3)+(C5+C6))*C33; + double CBA = 1./sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]); + A[0]*=CBA; A[1]*=CBA; A[2]*=CBA; + + double Sl = 2./S; + sA[0] = A6*Sl; + sA[1] = B6*Sl; + sA[2] = C6*Sl; + + // Jacobian calculation + // + for(int i=3; i!=12; ++i) {H0[i]=g0[i-3]*PS2; H1[i]=g1[i-3]*PS2; H2[i]=g2[i-3]*PS2;} + + for(int i=7; i<35; i+=7) { + + double* dR = &P[i] ; + double* dA = &P[i+3] ; + double dH0 = H0[ 3]*dR[0]+H0[ 4]*dR[1]+H0[ 5]*dR[2] ; // dHx/dp + double dH1 = H0[ 6]*dR[0]+H0[ 7]*dR[1]+H0[ 8]*dR[2] ; // dHy/dp + double dH2 = H0[ 9]*dR[0]+H0[10]*dR[1]+H0[11]*dR[2] ; // dHz/dp + double dA0 =(H0[ 2]*dA[1]-H0[ 1]*dA[2])+(A[1]*dH2-A[2]*dH1) ; // dA0/dp + double dB0 =(H0[ 0]*dA[2]-H0[ 2]*dA[0])+(A[2]*dH0-A[0]*dH2) ; // dB0/dp + double dC0 =(H0[ 1]*dA[0]-H0[ 0]*dA[1])+(A[0]*dH1-A[1]*dH0) ; // dC0/dp + double dA2 = dA0+dA[0], dX = dR[0]+(dA2+dA[0])*S4 ; // dX /dp + double dB2 = dB0+dA[1], dY = dR[1]+(dB2+dA[1])*S4 ; // dY /dp + double dC2 = dC0+dA[2], dZ = dR[2]+(dC2+dA[2])*S4 ; // dZ /dp + dH0 = H1[ 3]*dX +H1[ 4]*dY +H1[ 5]*dZ ; // dHx/dp + dH1 = H1[ 6]*dX +H1[ 7]*dY +H1[ 8]*dZ ; // dHy/dp + dH2 = H1[ 9]*dX +H1[10]*dY +H1[11]*dZ ; // dHz/dp + double dA3 =(dA[0]+dB2*H1[2]-dC2*H1[1])+(B2*dH2-C2*dH1) ; // dA3/dp + double dB3 =(dA[1]+dC2*H1[0]-dA2*H1[2])+(C2*dH0-A2*dH2) ; // dB3/dp + double dC3 =(dA[2]+dA2*H1[1]-dB2*H1[0])+(A2*dH1-B2*dH0) ; // dC3/dp + double dA4 =(dA[0]+dB3*H1[2]-dC3*H1[1])+(B3*dH2-C3*dH1) ; // dA4/dp + double dB4 =(dA[1]+dC3*H1[0]-dA3*H1[2])+(C3*dH0-A3*dH2) ; // dB4/dp + double dC4 =(dA[2]+dA3*H1[1]-dB3*H1[0])+(A3*dH1-B3*dH0) ; // dC4/dp + double dA5 = dA4+dA4-dA[0]; dX = dR[0]+dA4*S ; // dX /dp + double dB5 = dB4+dB4-dA[1]; dY = dR[1]+dB4*S ; // dY /dp + double dC5 = dC4+dC4-dA[2]; dZ = dR[2]+dC4*S ; // dZ /dp + dH0 = H2[ 3]*dX +H2[ 4]*dY +H2[ 5]*dZ ; // dHx/dp + dH1 = H2[ 6]*dX +H2[ 7]*dY +H2[ 8]*dZ ; // dHy/dp + dH2 = H2[ 9]*dX +H2[10]*dY +H2[11]*dZ ; // dHz/dp + double dA6 =(dB5*H2[2]-dC5*H2[1])+(B5*dH2-C5*dH1) ; // dA6/dp + double dB6 =(dC5*H2[0]-dA5*H2[2])+(C5*dH0-A5*dH2) ; // dB6/dp + double dC6 =(dA5*H2[1]-dB5*H2[0])+(A5*dH1-B5*dH0) ; // dC6/dp + dR[0]+=(dA2+dA3+dA4)*S3; dA[0]=((dA0+2.*dA3)+(dA5+dA6))*C33 ; + dR[1]+=(dB2+dB3+dB4)*S3; dA[1]=((dB0+2.*dB3)+(dB5+dB6))*C33 ; + dR[2]+=(dC2+dC3+dC4)*S3; dA[2]=((dC0+2.*dC3)+(dC5+dC6))*C33 ; + } + + double* dR = &P[35] ; + double* dA = &P[38] ; + + double dH0 = H0[ 3]*dR[0]+H0[ 4]*dR[1]+H0[ 5]*dR[2] ; // dHx/dp + double dH1 = H0[ 6]*dR[0]+H0[ 7]*dR[1]+H0[ 8]*dR[2] ; // dHy/dp + double dH2 = H0[ 9]*dR[0]+H0[10]*dR[1]+H0[11]*dR[2] ; // dHz/dp + double dA0 =(H0[ 2]*dA[1]-H0[ 1]*dA[2])+(A[1]*dH2-A[2]*dH1+A0) ; // dA0/dp + double dB0 =(H0[ 0]*dA[2]-H0[ 2]*dA[0])+(A[2]*dH0-A[0]*dH2+B0) ; // dB0/dp + double dC0 =(H0[ 1]*dA[0]-H0[ 0]*dA[1])+(A[0]*dH1-A[1]*dH0+C0) ; // dC0/dp + double dA2 = dA0+dA[0], dX = dR[0]+(dA2+dA[0])*S4 ; // dX /dp + double dB2 = dB0+dA[1], dY = dR[1]+(dB2+dA[1])*S4 ; // dY /dp + double dC2 = dC0+dA[2], dZ = dR[2]+(dC2+dA[2])*S4 ; // dZ /dp + dH0 = H1[ 3]*dX +H1[ 4]*dY +H1[ 5]*dZ ; // dHx/dp + dH1 = H1[ 6]*dX +H1[ 7]*dY +H1[ 8]*dZ ; // dHy/dp + dH2 = H1[ 9]*dX +H1[10]*dY +H1[11]*dZ ; // dHz/dp + double dA3 =(dA[0]+dB2*H1[2]-dC2*H1[1])+((B2*dH2-C2*dH1)+(A3-A00)) ; // dA3/dp + double dB3 =(dA[1]+dC2*H1[0]-dA2*H1[2])+((C2*dH0-A2*dH2)+(B3-A11)) ; // dB3/dp + double dC3 =(dA[2]+dA2*H1[1]-dB2*H1[0])+((A2*dH1-B2*dH0)+(C3-A22)) ; // dC3/dp + double dA4 =(dA[0]+dB3*H1[2]-dC3*H1[1])+((B3*dH2-C3*dH1)+(A4-A00)) ; // dA4/dp + double dB4 =(dA[1]+dC3*H1[0]-dA3*H1[2])+((C3*dH0-A3*dH2)+(B4-A11)) ; // dB4/dp + double dC4 =(dA[2]+dA3*H1[1]-dB3*H1[0])+((A3*dH1-B3*dH0)+(C4-A22)) ; // dC4/dp + double dA5 = dA4+dA4-dA[0]; dX = dR[0]+dA4*S ; // dX /dp + double dB5 = dB4+dB4-dA[1]; dY = dR[1]+dB4*S ; // dY /dp + double dC5 = dC4+dC4-dA[2]; dZ = dR[2]+dC4*S ; // dZ /dp + dH0 = H2[ 3]*dX +H2[ 4]*dY +H2[ 5]*dZ ; // dHx/dp + dH1 = H2[ 6]*dX +H2[ 7]*dY +H2[ 8]*dZ ; // dHy/dp + dH2 = H2[ 9]*dX +H2[10]*dY +H2[11]*dZ ; // dHz/dp + double dA6 =(dB5*H2[2]-dC5*H2[1])+(B5*dH2-C5*dH1+A6) ; // dA6/dp + double dB6 =(dC5*H2[0]-dA5*H2[2])+(C5*dH0-A5*dH2+B6) ; // dB6/dp + double dC6 =(dA5*H2[1]-dB5*H2[0])+(A5*dH1-B5*dH0+C6) ; // dC6/dp + dR[0]+=(dA2+dA3+dA4)*S3; dA[0]=((dA0+2.*dA3)+(dA5+dA6))*C33 ; + dR[1]+=(dB2+dB3+dB4)*S3; dA[1]=((dB0+2.*dB3)+(dB5+dB6))*C33 ; + dR[2]+=(dC2+dC3+dC4)*S3; dA[2]=((dC0+2.*dC3)+(dC5+dC6))*C33 ; + return S; + } + return S; +} + +///////////////////////////////////////////////////////////////////////////////// +// Straight line trajectory model +///////////////////////////////////////////////////////////////////////////////// + +double Trk::RungeKuttaPropagator::straightLineStep +(bool Jac, + double S , + double* P ) const +{ + double* R = &P[ 0]; // Start coordinates + double* A = &P[ 3]; // Start directions + double* sA = &P[42]; + + // Track parameters in last point + // + R[0]+=(A[0]*S); R[1]+=(A[1]*S); R[2]+=(A[2]*S); if(!Jac) return S; + + // Derivatives of track parameters in last point + // + for(int i=7; i<42; i+=7) { + + double* dR = &P[i]; + double* dA = &P[i+3]; + dR[0]+=(dA[0]*S); dR[1]+=(dA[1]*S); dR[2]+=(dA[2]*S); + } + sA[0]=sA[1]=sA[2]=0.; return S; +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track parameters and covariance matrix propagation +// Ta->Su = Tb +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::propagate +(Trk::PatternTrackParameters & Ta, + const Trk::Surface & Su, + Trk::PatternTrackParameters & Tb, + Trk::PropDirection D , + const MagneticFieldProperties& M , + ParticleHypothesis ) const +{ + double S; + return propagateRungeKutta(true,Ta,Su,Tb,D,M,S); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track parameters and covariance matrix propagation +// Ta->Su = Tb with step to surface calculation +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::propagate +(Trk::PatternTrackParameters & Ta, + const Trk::Surface & Su, + Trk::PatternTrackParameters & Tb, + Trk::PropDirection D , + const MagneticFieldProperties& M , + double & S , + ParticleHypothesis ) const +{ + return propagateRungeKutta(true,Ta,Su,Tb,D,M,S); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track parameters propagation without covariance matrix +// Ta->Su = Tb +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::propagateParameters +(Trk::PatternTrackParameters & Ta, + const Trk::Surface & Su, + Trk::PatternTrackParameters & Tb, + Trk::PropDirection D , + const MagneticFieldProperties& M , + ParticleHypothesis ) const +{ + double S; + return propagateRungeKutta(false,Ta,Su,Tb,D,M,S); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track parameters propagation without covariance matrix +// Ta->Su = Tb with step calculation +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::propagateParameters +(Trk::PatternTrackParameters & Ta, + const Trk::Surface & Su, + Trk::PatternTrackParameters & Tb, + Trk::PropDirection D , + const MagneticFieldProperties& M , + double & S , + ParticleHypothesis ) const +{ + return propagateRungeKutta(false,Ta,Su,Tb,D,M,S); +} + +///////////////////////////////////////////////////////////////////////////////// +// Global positions calculation inside CylinderBounds +// where mS - max step allowed if mS > 0 propagate along momentum +// mS < 0 propogate opposite momentum +///////////////////////////////////////////////////////////////////////////////// + +void Trk::RungeKuttaPropagator::globalPositions +(std::list<Amg::Vector3D> & GP, + const Trk::PatternTrackParameters& Tp, + const MagneticFieldProperties & M, + const CylinderBounds & CB, + double mS, + ParticleHypothesis ) const +{ + Trk::RungeKuttaUtils utils; + double P[45]; if(!utils.transformLocalToGlobal(false,Tp,P)) return; + + m_direction = fabs(mS); + if(mS > 0.) globalOneSidePositions(GP,P,M,CB, mS); + else globalTwoSidePositions(GP,P,M,CB,-mS); +} + +///////////////////////////////////////////////////////////////////////////////// +// GlobalPostions and steps for set surfaces +///////////////////////////////////////////////////////////////////////////////// + +void Trk::RungeKuttaPropagator::globalPositions +(const PatternTrackParameters & Tp, + std::list<const Trk::Surface*> & SU, + std::list< std::pair<Amg::Vector3D,double> > & GP, + const Trk::MagneticFieldProperties & M , + ParticleHypothesis ) const +{ + m_direction = 0. ; + m_mcondition = false; + + m_needgradient = false; + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + Trk::RungeKuttaUtils utils; + + double Step = 0.,P[64]; if(!utils.transformLocalToGlobal(false,Tp,P)) return; + + + std::list<const Trk::Surface*>::iterator su = SU.begin(), sue = SU.end(); + + // Loop trough all input surfaces + // + for(; su!=sue; ++su) { + + const Amg::Transform3D& T = (*su)->transform(); + int ty = (*su)->type(); + + if( ty == Trk::Surface::Plane ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(false,1,s,P,Step)) return; + } + else if(ty == Trk::Surface::Line ) { + + double s[6]={T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2)}; + if(!propagateWithJacobian(false,0,s,P,Step)) return; + } + else if (ty == Trk::Surface::Disc ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(false,1,s,P,Step)) return; + } + else if (ty == Trk::Surface::Cylinder ) { + + const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(*su); + double r0[3] = {P[0],P[1],P[2]}; + double s [9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),cyl->bounds().r(),m_direction,0.}; + + if(!propagateWithJacobian(false,2,s,P,Step)) return; + + // For cylinder we do test for next cross point + // + if(cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl,r0,P)) { + s[8] = 0.; if(!propagateWithJacobian(false,2,s,P,Step)) return; + } + } + else if (ty == Trk::Surface::Perigee ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),0.,0.,1.}; + if(!propagateWithJacobian(false,0,s,P,Step)) return ; + } + else if (ty == Trk::Surface::Cone ) { + + double k = static_cast<const Trk::ConeSurface*>(*su)->bounds().tanAlpha(); k = k*k+1.; + double s[9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),k,m_direction,0.}; + if(!propagateWithJacobian(false,3,s,P,Step)) return; + } + else return; + + Amg::Vector3D gp(P[0],P[1],P[2]); GP.push_back(std::make_pair(gp,Step)); + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track propagation with or without jacobian +// Ta->Su = Tb for pattern track parameters +///////////////////////////////////////////////////////////////////////////////// +bool Trk::RungeKuttaPropagator::propagateRungeKutta +(bool useJac, + Trk::PatternTrackParameters & Ta , + const Trk::Surface & Su , + Trk::PatternTrackParameters & Tb , + Trk::PropDirection D , + const MagneticFieldProperties& M , + double & Step ) const +{ + const Trk::Surface* su = &Su; + if(su == Ta.associatedSurface()) {Tb = Ta; return true;} + + m_direction = D ; + + if(useJac && !Ta.iscovariance()) useJac = false; + + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + (useJac && m_usegradient) ? m_needgradient = true : m_needgradient = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + Trk::RungeKuttaUtils utils; + + double P[45]; if(!utils.transformLocalToGlobal(useJac,Ta,P)) return false; Step = 0.; + + const Amg::Transform3D& T = Su.transform(); + int ty = Su.type(); + + if (ty == Trk::Surface::Plane ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return false; + } + else if (ty == Trk::Surface::Line ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2)}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return false; + } + else if (ty == Trk::Surface::Disc ) { + + double s[4],d = T(0,3)*T(0,2)+T(1,3)*T(1,2)+T(2,3)*T(2,2); + + if(d>=0.) {s[0]= T(0,2); s[1]= T(1,2); s[2]= T(2,2); s[3]= d;} + else {s[0]=-T(0,2); s[1]=-T(1,2); s[2]=-T(2,2); s[3]=-d;} + if(!propagateWithJacobian(useJac,1,s,P,Step)) return false; + } + else if (ty == Trk::Surface::Cylinder ) { + + const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); + + double r0[3] = {P[0],P[1],P[2]}; + double s [9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),cyl->bounds().r(),m_direction,0.}; + + if(!propagateWithJacobian(useJac,2,s,P,Step)) return false; + + // For cylinder we do test for next cross point + // + if(cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl,r0,P)) { + s[8] = 0.; if(!propagateWithJacobian(useJac,2,s,P,Step)) return false; + } + } + else if (ty == Trk::Surface::Perigee ) { + + double s[6] ={T(0,3),T(1,3),T(2,3),0.,0.,1.}; + if(!propagateWithJacobian(useJac,0,s,P,Step)) return false; + } + else if (ty == Trk::Surface::Cone ) { + + double k = static_cast<const Trk::ConeSurface*>(su)->bounds().tanAlpha(); k = k*k+1.; + double s[9] = {T(0,3),T(1,3),T(2,3),T(0,2),T(1,2),T(2,2),k,m_direction,0.}; + if(!propagateWithJacobian(useJac,3,s,P,Step)) return false; + } + else return false; + + if(m_direction && (m_direction*Step)<0.) return false; + + // Common transformation for all surfaces (angles and momentum) + // + if(useJac) { + double p=1./P[6]; P[35]*=p; P[36]*=p; P[37]*=p; P[38]*=p; P[39]*=p; P[40]*=p; + } + + double p[5],Jac[21]; utils.transformGlobalToLocal(su,useJac,P,p,Jac); + + // New simple track parameters production + // + Tb.setParameters(&Su,p); + if(useJac) { + Tb.newCovarianceMatrix(Ta,Jac); + const double* cv = Tb.cov(); + if( cv[0]<=0. || cv[2]<=0. || cv[5]<=0. || cv[9]<=0. || cv[14]<=0.) return false; + } + return true; +} + +///////////////////////////////////////////////////////////////////////////////// +// Test new cross point +///////////////////////////////////////////////////////////////////////////////// + +bool Trk::RungeKuttaPropagator::newCrossPoint +(const Trk::CylinderSurface& Su, + const double * Ro, + const double * P ) const +{ + const double pi = 3.1415927, pi2=2.*pi; + const Amg::Transform3D& T = Su.transform(); + double Ax[3] = {T(0,0),T(1,0),T(2,0)}; + double Ay[3] = {T(0,1),T(1,1),T(2,1)}; + + double R = Su.bounds().r(); + double x = Ro[0]-T(0,3); + double y = Ro[1]-T(1,3); + double z = Ro[2]-T(2,3); + + double RC = x*Ax[0]+y*Ax[1]+z*Ax[2]; + double RS = x*Ay[0]+y*Ay[1]+z*Ay[2]; + + if( (RC*RC+RS*RS) <= (R*R) ) return false; + + x = P[0]-T(0,3); + y = P[1]-T(1,3); + z = P[2]-T(2,3); + RC = x*Ax[0]+y*Ax[1]+z*Ax[2]; + RS = x*Ay[0]+y*Ay[1]+z*Ay[2]; + double dF = fabs(atan2(RS,RC)-Su.bounds().averagePhi()); + if(dF > pi) dF = pi2-pi; + if(dF <= Su.bounds().halfPhiSector()) return false; + return true; +} + +///////////////////////////////////////////////////////////////////////////////// +// Build new track parameters without propagation +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::buildTrackParametersWithoutPropagation +(const Trk::TrackParameters& Tp,double* Jac) const +{ + Jac[0]=Jac[6]=Jac[12]=Jac[18]=Jac[20]=1.; + Jac[1]=Jac[2]=Jac[3]=Jac[4]=Jac[5]=Jac[7]=Jac[8]=Jac[9]=Jac[10]=Jac[11]=Jac[13]=Jac[14]=Jac[15]=Jac[16]=Jac[17]=Jac[19]=0.; + return Tp.clone(); +} + +///////////////////////////////////////////////////////////////////////////////// +// Build new neutral track parameters without propagation +///////////////////////////////////////////////////////////////////////////////// + +const Trk::NeutralParameters* Trk::RungeKuttaPropagator::buildTrackParametersWithoutPropagation +(const Trk::NeutralParameters& Tp,double* Jac) const +{ + Jac[0]=Jac[6]=Jac[12]=Jac[18]=Jac[20]=1.; + Jac[1]=Jac[2]=Jac[3]=Jac[4]=Jac[5]=Jac[7]=Jac[8]=Jac[9]=Jac[10]=Jac[11]=Jac[13]=Jac[14]=Jac[15]=Jac[16]=Jac[17]=Jac[19]=0.; + return Tp.clone(); +} + +///////////////////////////////////////////////////////////////////////////////// +// Step estimator take into accout curvature +///////////////////////////////////////////////////////////////////////////////// + +double Trk::RungeKuttaPropagator::stepEstimatorWithCurvature +(int kind,double* Su,const double* P,bool& Q) const +{ + // Straight step estimation + // + Trk::RungeKuttaUtils utils; + double Step = utils.stepEstimator(kind,Su,P,Q); if(!Q) return 0.; + double AStep = fabs(Step); + if( kind || AStep < m_straightStep || !m_mcondition ) return Step; + + const double* SA = &P[42]; // Start direction + double S = .5*Step; + + double Ax = P[3]+S*SA[0]; + double Ay = P[4]+S*SA[1]; + double Az = P[5]+S*SA[2]; + double As = 1./sqrt(Ax*Ax+Ay*Ay+Az*Az); + double PN[6] = {P[0],P[1],P[2],Ax*As,Ay*As,Az*As}; + double StepN = utils.stepEstimator(kind,Su,PN,Q); if(!Q) {Q = true; return Step;} + if(fabs(StepN) < AStep) return StepN; return Step; +} + +///////////////////////////////////////////////////////////////////////////////// +// Global positions calculation inside CylinderBounds (one side) +// where mS - max step allowed if mS > 0 propagate along momentum +// mS < 0 propogate opposite momentum +///////////////////////////////////////////////////////////////////////////////// + +void Trk::RungeKuttaPropagator::globalOneSidePositions +(std::list<Amg::Vector3D> & GP, + const double * P, + const MagneticFieldProperties & M , + const CylinderBounds & CB, + double mS, + ParticleHypothesis ) const +{ + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + double Pm[45]; for(int i=0; i!=7; ++i) Pm[i]=P[i]; + + double W = 0. ; // way + double R2max = CB.r()*CB.r() ; // max. radius**2 of region + double Zmax = CB.halflengthZ() ; // max. Z of region + double R2 = P[0]*P[0]+P[1]*P[1]; // Start radius**2 + double Dir = P[0]*P[3]+P[1]*P[4]; // Direction + double S = mS ; // max step allowed + double R2m = R2 ; + + if(m_mcondition && fabs(P[6]) > .1) return; + + // Test position of the track + // + if(fabs(P[2]) > Zmax || R2 > R2max) return; + + Amg::Vector3D g0(P[0],P[1],P[2]); GP.push_back(g0); + + bool per = false; if(fabs(Dir)<.00001) per = true; + bool InS = false; + + int niter = 0; + int sm = 1; + for(int s = 0; s!=2; ++s) { + + if(s) {if(per) break; S = -S;} + double p[45]; for(int i=0; i!=7; ++i) p[i]=P[i]; p[42]=p[43]=p[44]=0.; + + while(W<100000. && ++niter < 1000) { + + if(m_mcondition) { + W+=(S=rungeKuttaStep (0,S,p,InS)); + } + else { + W+=(S=straightLineStep(0, S,p)); + } + if(InS && fabs(2.*S)<mS) S*=2.; + + Amg::Vector3D g(p[0],p[1],p[2]); + if(!s) GP.push_back(g); else GP.push_front(g); + + // Test position of the track + // + R2 = p[0]*p[0]+p[1]*p[1]; + + if(R2 < R2m) { + Pm[0]=p[0]; Pm[1]=p[1]; Pm[2]=p[2]; + Pm[3]=p[3]; Pm[4]=p[4]; Pm[5]=p[5]; R2m = R2; sm = s; + } + if(fabs(p[2]) > Zmax || R2 > R2max) break; + if(!s && P[3]*p[3]+P[4]*p[4] < 0. ) break; + + // Test perigee + // + if((p[0]*p[3]+p[1]*p[4])*Dir < 0.) { + if(s) break; per = true; + } + } + } + + if(R2m < 400.) return; + + // Propagate to perigee + // + Pm[42]=Pm[43]=Pm[44]=0.; + per = false; + + for(int s = 0; s!=3; ++s) { + + double A = (1.-Pm[5])*(1.+Pm[5]); if(A==0.) break; + S = -(Pm[0]*Pm[3]+Pm[1]*Pm[4])/A; + if(fabs(S) < 1. || ++niter > 1000) break; + + if(m_mcondition) { + W+=(S=rungeKuttaStep (0,S,Pm,InS)); + } + else { + W+=(S=straightLineStep(0,S,Pm)); + } + per = true; + } + + if(per) { + if(sm) {Amg::Vector3D gf(Pm[0],Pm[1],Pm[2]); GP.front() = gf;} + else {Amg::Vector3D gf(Pm[0],Pm[1],Pm[2]); GP.back () = gf;} + } + else { + double x = GP.front().x() , y = GP.front().y(); + if( (x*x+y*y) > (Pm[0]*Pm[0]+Pm[1]*Pm[1]) ) { + if(sm) GP.pop_front(); + else GP.pop_back (); + } + } + return; +} + +///////////////////////////////////////////////////////////////////////////////// +// Global positions calculation inside CylinderBounds (one side) +// where mS - max step allowed if mS > 0 propagate along momentum +// mS < 0 propogate opposite momentum +///////////////////////////////////////////////////////////////////////////////// + +void Trk::RungeKuttaPropagator::globalTwoSidePositions +(std::list<Amg::Vector3D> & GP, + const double * P, + const MagneticFieldProperties & M , + const CylinderBounds & CB, + double mS, + ParticleHypothesis ) const +{ + M.magneticFieldMode()==2 ? m_solenoid = true : m_solenoid = false; + M.magneticFieldMode()!=0 ? m_mcondition = true : m_mcondition = false; + + double W = 0. ; // way + double R2max = CB.r()*CB.r() ; // max. radius**2 of region + double Zmax = CB.halflengthZ() ; // max. Z of region + double R2 = P[0]*P[0]+P[1]*P[1]; // Start radius**2 + double S = mS ; // max step allowed + + if(m_mcondition && fabs(P[6]) > .1) return; + + // Test position of the track + // + if(fabs(P[2]) > Zmax || R2 > R2max) return; + + Amg::Vector3D g0(P[0],P[1],P[2]); GP.push_back(g0); + + bool InS = false; + + int niter = 0; + for(int s = 0; s!=2; ++s) { + + if(s) {S = -S;} + double p[45]; for(int i=0; i!=7; ++i) p[i]=P[i]; p[42]=p[43]=p[44]=0.; + + while(W<100000. && ++niter < 1000) { + + if(m_mcondition) { + W+=(S=rungeKuttaStep (0,S,p,InS)); + } + else { + W+=(S=straightLineStep(0, S,p)); + } + if(InS && fabs(2.*S)<mS) S*=2.; + + Amg::Vector3D g(p[0],p[1],p[2]); + if(!s) GP.push_back(g); else GP.push_front(g); + + // Test position of the track + // + R2 = p[0]*p[0]+p[1]*p[1]; + if(fabs(p[2]) > Zmax || R2 > R2max) break; + } + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Track parameters in cross point preparation +///////////////////////////////////////////////////////////////////////////////// + +const Trk::TrackParameters* Trk::RungeKuttaPropagator::crossPoint +(const TrackParameters & Tp, + std::vector<DestSurf> & SU, + std::vector<unsigned int>& So, + double * P , + std::pair<double,int> & SN) const +{ + double* R = &P[ 0] ; // Start coordinates + double* A = &P[ 3] ; // Start directions + double* SA = &P[42] ; // d(directions)/dStep + double Step = SN.first ; + int N = SN.second; + + double As[3],Rs[3]; + + As[0] = A[0]+SA[0]*Step; + As[1] = A[1]+SA[1]*Step; + As[2] = A[2]+SA[2]*Step; + + double CBA = 1./sqrt(As[0]*As[0]+As[1]*As[1]+As[2]*As[2]); + + Rs[0] = R[0]+Step*(As[0]-.5*Step*SA[0]); As[0]*=CBA; + Rs[1] = R[1]+Step*(As[1]-.5*Step*SA[1]); As[1]*=CBA; + Rs[2] = R[2]+Step*(As[2]-.5*Step*SA[2]); As[2]*=CBA; + + Amg::Vector3D pos(Rs[0],Rs[1],Rs[2]); + Amg::Vector3D dir(As[0],As[1],As[2]); + + Trk::DistanceSolution ds = SU[N].first->straightLineDistanceEstimate(pos,dir,SU[N].second); + if(ds.currentDistance(false) > .010) return 0; + + P[0] = Rs[0]; A[0] = As[0]; + P[1] = Rs[1]; A[1] = As[1]; + P[2] = Rs[2]; A[2] = As[2]; + + So.push_back(N); + + // Transformation track parameters + // + Trk::RungeKuttaUtils utils; + bool useJac; Tp.covariance() ? useJac = true : useJac = false; + + if(useJac) { + double d=1./P[6]; P[35]*=d; P[36]*=d; P[37]*=d; P[38]*=d; P[39]*=d; P[40]*=d; + } + double p[5],Jac[25]; + utils.transformGlobalToLocal(SU[N].first,useJac,P,p,Jac); + + if(!useJac) return SU[N].first->createTrackParameters(p[0],p[1],p[2],p[3],p[4],0); + + AmgSymMatrix(5)* e = utils.newCovarianceMatrix(Jac,*Tp.covariance()); + AmgSymMatrix(5)& cv = *e; + + if(cv(0,0)<=0. || cv(1,1)<=0. || cv(2,2)<=0. || cv(3,3)<=0. || cv(4,4)<=0.) { + delete e; return 0; + } + return SU[N].first->createTrackParameters(p[0],p[1],p[2],p[3],p[4],e); +} + +///////////////////////////////////////////////////////////////////////////////// +// Step reduction from STEP propagator +// Input information ERRx,ERRy,ERRz,current step +///////////////////////////////////////////////////////////////////////////////// + +double Trk::RungeKuttaPropagator::stepReduction(const double* E) const +{ + double dlt2 = m_dlt*m_dlt; + double dR2 = (E[0]*E[0]+E[1]*E[1]+E[2]*E[2])*E[3]*E[3]*4.; if(dR2 < 1.e-40) dR2 = 1.e-40; + double cS = std::pow(dlt2/dR2,0.125); + if(cS < .25) cS = .25; + if((dR2 > 16.*dlt2 && cS < 1.) || cS >=3.) return cS; + return 1.; +} diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_entries.cxx b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_entries.cxx new file mode 100755 index 0000000000000000000000000000000000000000..3163d9b61f48ef6cbd3efe000ce29e36490c33c9 --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_entries.cxx @@ -0,0 +1,13 @@ +#include "GaudiKernel/DeclareFactoryEntries.h" +#include "TrkExRungeKuttaPropagator/RungeKuttaPropagator.h" + +using namespace Trk; + +DECLARE_TOOL_FACTORY( RungeKuttaPropagator ) + +/** factory entries need to have the name of the package */ +DECLARE_FACTORY_ENTRIES( TrkExRungeKuttaPropagator ) +{ + DECLARE_TOOL( RungeKuttaPropagator ) +} + diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_load.cxx b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_load.cxx new file mode 100755 index 0000000000000000000000000000000000000000..88ab7fe92bfd6fe9a2057ec7eca8a7a7b4a44808 --- /dev/null +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/components/TrkExRungeKuttaPropagator_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES( TrkExRungeKuttaPropagator )