diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h index 9eff88ef0eee884a37cf6e49d15e5e5c31b343d8..01b8d07d6950eaf2837302eeaa643ec9ff54cc75 100755 --- a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/TrkExRungeKuttaPropagator/RungeKuttaPropagator.h @@ -315,6 +315,7 @@ namespace Trk { bool m_solenoid = true; bool m_needgradient = false; bool m_newfield = true; + bool m_usegradient = false; }; private: @@ -322,38 +323,12 @@ namespace Trk { ///////////////////////////////////////////////////////////////////////////////// // Private methods: ///////////////////////////////////////////////////////////////////////////////// - /** Test quality Jacobian calculation */ - void JacobianTest(const TrackParameters&, - const Surface&, - const MagneticFieldProperties&) const; - - /** Internal RungeKutta propagation method for charge track parameters*/ - - std::unique_ptr<TrackParameters> propagateRungeKutta( - Cache& cache, - bool, - const TrackParameters&, - const Surface&, - const PropDirection, - const BoundaryCheck&, - const MagneticFieldProperties&, - double*, - bool returnCurv) const; - - /** Internal RungeKutta propagation method */ - - bool propagateRungeKutta(Cache& cache, - bool, - PatternTrackParameters&, - const Surface&, - PatternTrackParameters&, - PropDirection, - const MagneticFieldProperties&, - double&) const; - void getFieldCacheObject(Cache& cache, const EventContext& ctx) const; + ///////////////////////////////////////////////////////////////////////////////// // Private data members: + ///////////////////////////////////////////////////////////////////////////////// + // Read handle for conditions object to get the field cache SG::ReadCondHandleKey<AtlasFieldCacheCondObj> m_fieldCondObjInputKey{ this, @@ -365,7 +340,7 @@ namespace Trk { 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 into the error + bool m_usegradient; // use magnetig field gradient into the error // propagation }; diff --git a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx index 5e97916b5ed9eb499486a72fc546e27c64428d0a..d70a2369026aa9a5199ae3855cb5579bf3b46e09 100755 --- a/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx +++ b/Tracking/TrkExtrapolation/TrkExRungeKuttaPropagator/src/RungeKuttaPropagator.cxx @@ -1166,6 +1166,343 @@ globalTwoSidePositions(Cache& cache, } } } +///////////////////////////////////////////////////////////////////////////////// +// Main function for charged track parameters propagation with or without +// jacobian +///////////////////////////////////////////////////////////////////////////////// +std::unique_ptr<Trk::TrackParameters> +propagateRungeKutta(Cache& cache, + bool useJac, + const Trk::TrackParameters& Tp, + const Trk::Surface& Su, + Trk::PropDirection D, + const Trk::BoundaryCheck& B, + const Trk::MagneticFieldProperties& M, + double* Jac, + bool returnCurv) +{ + const Trk::Surface* su = &Su; + + cache.m_direction = D; + + M.magneticFieldMode() == Trk::FastField ? cache.m_solenoid = true + : cache.m_solenoid = false; + (useJac && cache.m_usegradient) ? cache.m_needgradient = true + : cache.m_needgradient = false; + M.magneticFieldMode() != Trk::NoField ? cache.m_mcondition = true + : cache.m_mcondition = false; + + if (su == &Tp.associatedSurface()) + return buildTrackParametersWithoutPropagation(Tp, Jac); + + double P[64]; + double Step = 0.; + if (!Trk::RungeKuttaUtils::transformLocalToGlobal(useJac, Tp, P)) + return nullptr; + + const Amg::Transform3D& T = Su.transform(); + Trk::SurfaceType ty = Su.type(); + + if (ty == Trk::SurfaceType::Plane) { + + double s[4]; + const double 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(cache, useJac, 1, s, P, Step)) + return nullptr; + + } else if (ty == Trk::SurfaceType::Line) { + + double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; + if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) + return nullptr; + } else if (ty == Trk::SurfaceType::Disc) { + + double s[4]; + const double 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(cache, useJac, 1, s, P, Step)) + return nullptr; + } else if (ty == Trk::SurfaceType::Cylinder) { + + const Trk::CylinderSurface* cyl = + static_cast<const Trk::CylinderSurface*>(su); + + const 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(), cache.m_direction, 0. }; + if (!propagateWithJacobian(cache, useJac, 2, s, P, Step)) + return nullptr; + + // For cylinder we do test for next cross point + // + if (cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl, r0, P)) { + s[8] = 0.; + if (!propagateWithJacobian(cache, useJac, 2, s, P, Step)) + return nullptr; + } + } else if (ty == Trk::SurfaceType::Perigee) { + double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; + if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) + return nullptr; + } else if (ty == Trk::SurfaceType::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, cache.m_direction, 0. }; + if (!propagateWithJacobian(cache, useJac, 3, s, P, Step)) + return nullptr; + } else + return nullptr; + + if (cache.m_direction && (cache.m_direction * Step) < 0.) { + return nullptr; + } + cache.m_step = Step; + + // 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; + } + + if (cache.m_maxPathLimit) + returnCurv = true; + + bool uJ = useJac; + if (returnCurv) + uJ = false; + double p[5]; + Trk::RungeKuttaUtils::transformGlobalToLocal(su, uJ, P, p, Jac); + + if (B) { + Amg::Vector2D L(p[0], p[1]); + if (!Su.insideBounds(L, 0.)) + return nullptr; + } + + // Transformation to curvilinear presentation + // + if (returnCurv) + Trk::RungeKuttaUtils::transformGlobalToCurvilinear(useJac, P, p, Jac); + + if (!useJac || !Tp.covariance()) { + + if (!returnCurv) { + return Su.createUniqueTrackParameters( + p[0], p[1], p[2], p[3], p[4], std::nullopt); + } else { + Amg::Vector3D gp(P[0], P[1], P[2]); + return std::make_unique<Trk::CurvilinearParameters>(gp, p[2], p[3], p[4]); + } + } + + AmgSymMatrix(5) e = + Trk::RungeKuttaUtils::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.) { + return nullptr; + } + + if (!returnCurv) { + return Su.createUniqueTrackParameters( + p[0], p[1], p[2], p[3], p[4], std::move(e)); + } else { + Amg::Vector3D gp(P[0], P[1], P[2]); + return std::make_unique<Trk::CurvilinearParameters>( + gp, p[2], p[3], p[4], std::move(e)); + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for simple track propagation with or without jacobian +// Ta->Su = Tb for pattern track parameters +///////////////////////////////////////////////////////////////////////////////// +bool +propagateRungeKutta(Cache& cache, + bool useJac, + Trk::PatternTrackParameters& Ta, + const Trk::Surface& Su, + Trk::PatternTrackParameters& Tb, + Trk::PropDirection D, + const Trk::MagneticFieldProperties& M, + double& Step) +{ + const Trk::Surface* su = &Su; + if (!su) + return false; + if (su == &Ta.associatedSurface()) { + Tb = Ta; + return true; + } + + cache.m_direction = D; + + if (useJac && !Ta.iscovariance()) + useJac = false; + + M.magneticFieldMode() == Trk::FastField ? cache.m_solenoid = true + : cache.m_solenoid = false; + (useJac && cache.m_usegradient) ? cache.m_needgradient = true + : cache.m_needgradient = false; + M.magneticFieldMode() != Trk::NoField ? cache.m_mcondition = true + : cache.m_mcondition = false; + + double P[45]; + if (!Trk::RungeKuttaUtils::transformLocalToGlobal(useJac, Ta, P)) + return false; + Step = 0.; + + const Amg::Transform3D& T = Su.transform(); + Trk::SurfaceType ty = Su.type(); + + if (ty == Trk::SurfaceType::Plane) { + double s[4]; + const double 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(cache, useJac, 1, s, P, Step)) + return false; + } else if (ty == Trk::SurfaceType::Line) { + + double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; + if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) + return false; + } else if (ty == Trk::SurfaceType::Disc) { + + double s[4]; + const double 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(cache, useJac, 1, s, P, Step)) { + return false; + } + } else if (ty == Trk::SurfaceType::Cylinder) { + + const Trk::CylinderSurface* cyl = + static_cast<const Trk::CylinderSurface*>(su); + + const 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(), cache.m_direction, 0. }; + + if (!propagateWithJacobian(cache, 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(cache, useJac, 2, s, P, Step)) { + return false; + } + } + } else if (ty == Trk::SurfaceType::Perigee) { + + double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; + if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) { + return false; + } + } else if (ty == Trk::SurfaceType::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, cache.m_direction, 0. }; + if (!propagateWithJacobian(cache, useJac, 3, s, P, Step)) { + return false; + } + } else { + return false; + } + + if (cache.m_maxPathLimit || + (cache.m_direction && (cache.m_direction * Step) < 0.)) + return false; + + // Common transformation for all surfaces (angles and momentum) + // + if (useJac) { + const 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]; + double Jac[21]; + Trk::RungeKuttaUtils::transformGlobalToLocal(su, useJac, P, p, Jac); + + // New simple track parameters production + // + if (useJac) { + AmgSymMatrix(5) newCov = + Trk::PatternTrackParameters::newCovarianceMatrix(*Ta.covariance(), Jac); + Tb.setParametersWithCovariance(&Su, p, newCov); + const AmgSymMatrix(5)& cv = *Tb.covariance(); + if (cv(0, 0) <= 0. || cv(1, 1) <= 0. || cv(2, 2) <= 0. || cv(3, 3) <= 0. || + cv(4, 4) <= 0.) + return false; + } else { + Tb.setParameters(&Su, p); + } + return true; +} /* * end of anonymous namespace @@ -1215,6 +1552,7 @@ Trk::RungeKuttaPropagator::propagate(const Trk::NeutralParameters& Tp, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; return propagateStraightLine(cache, true, Tp, Su, D, B, J, returnCurv); } @@ -1238,6 +1576,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1267,6 +1606,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1307,6 +1647,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1374,7 +1715,6 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, double Sl = Smax; double St = Smax; bool InS = false; - // TrackParameters* To = nullptr ; for (int i = 0; i != 45; ++i) Pn[i] = Po[i]; @@ -1386,16 +1726,18 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, //---------------------------------- cache.m_newfield = true; - /// If the extrapolation surpassed the last boundary it can super duper rarely happen that the propgator is trapped. - /// The propagator then goes the same step back and forth. The flip number limit is kind of a hack to release - /// the propagator from the limbo. The conditions are that the last_st & the current step have to be of the same size - /// but different sign. If tis happens a few times the loop is aborted. The chosen number here is at the same level - /// of arbitrariness as the rarity that this branch of the code will be chosen - constexpr unsigned int max_back_forth_flips {100}; + /// If the extrapolation surpassed the last boundary it can super duper rarely + /// happen that the propagator is trapped. The propagator then goes the same + /// step back and forth. The flip number limit is kind of a hack to release + /// the propagator from the limbo. The conditions are that the last_st & the + /// current step have to be of the same size but different sign. If this + /// happens a few times the loop is aborted. The chosen number here is at the + /// same level of arbitrariness as the rarity that this branch of the code + /// will be chosen + constexpr unsigned int max_back_forth_flips{ 100 }; unsigned int flips{0}; int last_surface{-1}; - while (std::abs(W) < Wmax) { std::pair<double, int> SN; @@ -1405,7 +1747,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, //----------------------------------Niels van Eldik patch if (reverted_P && std::abs(St - last_St) <= DBL_EPSILON && - InS == last_InS /*&& condition_fulfiled*/) { + InS == last_InS) { // inputs are not changed will get same result. break; } @@ -1420,7 +1762,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, } else { //----------------------------------Niels van Eldik patch - if (reverted_P && std::abs(St - last_St) <= DBL_EPSILON /*&& !condition_fulfiled*/) { + if (reverted_P && std::abs(St - last_St) <= DBL_EPSILON) { // inputs are not changed will get same result. break; } @@ -1445,276 +1787,109 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, for (int i = 0; i != 45; ++i) Pn[i] = Po[i]; reverted_P = true; - cache.m_newfield = true; - } - - if (std::abs(S) + 1. < std::abs(St)) - Sl = S; - InS ? St = 2. * S : St = S; - - if (SN.second >= 0) { - - double Sa = std::abs(SN.first); - - /// Update the number of flips. Reset the counter if the last surface is not the same as the current one - /// and then check that the step size & the last step size are the same but of different sign - flips += last_surface == SN.second? std::abs(last_St + SN.first) < 1.e-6 : -flips; - last_surface = SN.second; - - - if (Sa > cache.m_straightStep) { - if (std::abs(St) > Sa) - St = SN.first; - } else { - Path = W + SN.first; - if (auto To{ crossPoint(Tp, DS, Sol, Pn, SN) }; To) - return To; - Nveto = SN.second; - St = Sl; - } - } else if (std::abs(S) < DBL_EPSILON) - return nullptr; - - if (flips > max_back_forth_flips) return nullptr; - } - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////// -// Main function for track parameters propagation without covariance matrix -// without transport Jacobian production -///////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<Trk::TrackParameters> -Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, - const Trk::TrackParameters& Tp, - const Trk::Surface& Su, - Trk::PropDirection D, - const Trk::BoundaryCheck& B, - const MagneticFieldProperties& M, - ParticleHypothesis, - bool returnCurv, - const TrackingVolume*) const -{ - double J[25]; - Cache cache{}; - cache.m_dlt = m_dlt; - cache.m_helixStep = m_helixStep; - cache.m_straightStep = m_straightStep; - - // Get field cache object - getFieldCacheObject(cache, ctx); - - cache.m_maxPath = 10000.; - return propagateRungeKutta(cache, false, Tp, Su, D, B, M, J, returnCurv); -} - -///////////////////////////////////////////////////////////////////////////////// -// Main function for track parameters propagation without covariance matrix -// with transport Jacobian production -///////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<Trk::TrackParameters> -Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, - const Trk::TrackParameters& Tp, - const Trk::Surface& Su, - Trk::PropDirection D, - const Trk::BoundaryCheck& B, - const MagneticFieldProperties& M, - TransportJacobian*& Jac, - ParticleHypothesis, - bool returnCurv, - const TrackingVolume*) const -{ - double J[25]; - Cache cache{}; - cache.m_dlt = m_dlt; - cache.m_helixStep = m_helixStep; - cache.m_straightStep = m_straightStep; - // Get field cache object - getFieldCacheObject(cache, ctx); - cache.m_maxPath = 10000.; - auto Tpn{ propagateRungeKutta(cache, 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 = nullptr; - return Tpn; -} - -///////////////////////////////////////////////////////////////////////////////// -// Main function for charged track parameters propagation with or without jacobian -///////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<Trk::TrackParameters> -Trk::RungeKuttaPropagator::propagateRungeKutta(Cache& cache, - bool useJac, - const Trk::TrackParameters& Tp, - const Trk::Surface& Su, - Trk::PropDirection D, - const Trk::BoundaryCheck& B, - const MagneticFieldProperties& M, - double* Jac, - bool returnCurv) const -{ - const Trk::Surface* su = &Su; - - cache.m_direction = D; - - M.magneticFieldMode() == Trk::FastField ? cache.m_solenoid = true : cache.m_solenoid = false; - (useJac && m_usegradient) ? cache.m_needgradient = true : cache.m_needgradient = false; - M.magneticFieldMode() != Trk::NoField ? cache.m_mcondition = true : cache.m_mcondition = false; - - if (su == &Tp.associatedSurface()) - return buildTrackParametersWithoutPropagation(Tp, Jac); - - double P[64]; - double Step = 0.; - if (!Trk::RungeKuttaUtils::transformLocalToGlobal(useJac, Tp, P)) - return nullptr; - - const Amg::Transform3D& T = Su.transform(); - Trk::SurfaceType ty = Su.type(); - - if (ty == Trk::SurfaceType::Plane) { - - double s[4]; - const double 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(cache, useJac, 1, s, P, Step)) - return nullptr; - - } else if (ty == Trk::SurfaceType::Line) { - - double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; - if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) - return nullptr; - } else if (ty == Trk::SurfaceType::Disc) { - - double s[4]; - const double 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(cache, useJac, 1, s, P, Step)) - return nullptr; - } else if (ty == Trk::SurfaceType::Cylinder) { - - const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); - - const 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(), cache.m_direction, 0. }; - if (!propagateWithJacobian(cache, useJac, 2, s, P, Step)) - return nullptr; - - // For cylinder we do test for next cross point - // - if (cyl->bounds().halfPhiSector() < 3.1 && newCrossPoint(*cyl, r0, P)) { - s[8] = 0.; - if (!propagateWithJacobian(cache, useJac, 2, s, P, Step)) - return nullptr; - } - } else if (ty == Trk::SurfaceType::Perigee) { - - double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; - if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) - return nullptr; - } else if (ty == Trk::SurfaceType::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, cache.m_direction, 0. }; - if (!propagateWithJacobian(cache, useJac, 3, s, P, Step)) - return nullptr; - } else - return nullptr; - - if (cache.m_direction && (cache.m_direction * Step) < 0.) { - return nullptr; - } - cache.m_step = Step; - - // 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; - } + cache.m_newfield = true; + } - if (cache.m_maxPathLimit) - returnCurv = true; + if (std::abs(S) + 1. < std::abs(St)) + Sl = S; + InS ? St = 2. * S : St = S; - bool uJ = useJac; - if (returnCurv) - uJ = false; - double p[5]; - Trk::RungeKuttaUtils::transformGlobalToLocal(su, uJ, P, p, Jac); + if (SN.second >= 0) { - if (B) { - Amg::Vector2D L(p[0], p[1]); - if (!Su.insideBounds(L, 0.)) - return nullptr; - } + double Sa = std::abs(SN.first); - // Transformation to curvilinear presentation - // - if (returnCurv) - Trk::RungeKuttaUtils::transformGlobalToCurvilinear(useJac, P, p, Jac); + /// Update the number of flips. Reset the counter if the last surface is + /// not the same as the current one and then check that the step size & + /// the last step size are the same but of different sign + flips += last_surface == SN.second ? std::abs(last_St + SN.first) < 1.e-6 + : -flips; + last_surface = SN.second; - if (!useJac || !Tp.covariance()) { - if (!returnCurv) { - return Su.createUniqueTrackParameters(p[0], p[1], p[2], p[3], p[4], std::nullopt); - } else { - Amg::Vector3D gp(P[0], P[1], P[2]); - return std::make_unique<Trk::CurvilinearParameters>(gp, p[2], p[3], p[4]); - } + if (Sa > cache.m_straightStep) { + if (std::abs(St) > Sa) + St = SN.first; + } else { + Path = W + SN.first; + if (auto To{ crossPoint(Tp, DS, Sol, Pn, SN) }; To) + return To; + Nveto = SN.second; + St = Sl; + } + } else if (std::abs(S) < DBL_EPSILON) + return nullptr; + + if (flips > max_back_forth_flips) return nullptr; } + return nullptr; +} - AmgSymMatrix(5) e = Trk::RungeKuttaUtils::newCovarianceMatrix(Jac, *Tp.covariance()); - AmgSymMatrix(5)& cv = e; +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters propagation without covariance matrix +// without transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// +std::unique_ptr<Trk::TrackParameters> +Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, + const Trk::TrackParameters& Tp, + const Trk::Surface& Su, + Trk::PropDirection D, + const Trk::BoundaryCheck& B, + const MagneticFieldProperties& M, + ParticleHypothesis, + bool returnCurv, + const TrackingVolume*) const +{ + double J[25]; + Cache cache{}; + cache.m_dlt = m_dlt; + cache.m_helixStep = m_helixStep; + cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; - if (cv(0, 0) <= 0. || cv(1, 1) <= 0. || cv(2, 2) <= 0. || cv(3, 3) <= 0. || cv(4, 4) <= 0.) { - return nullptr; - } + // Get field cache object + getFieldCacheObject(cache, ctx); - if (!returnCurv) { - return Su.createUniqueTrackParameters(p[0], p[1], p[2], p[3], p[4], std::move(e)); - } else { - Amg::Vector3D gp(P[0], P[1], P[2]); - return std::make_unique<Trk::CurvilinearParameters>(gp, p[2], p[3], p[4], std::move(e)); - } + cache.m_maxPath = 10000.; + return propagateRungeKutta(cache, false, Tp, Su, D, B, M, J, returnCurv); +} + +///////////////////////////////////////////////////////////////////////////////// +// Main function for track parameters propagation without covariance matrix +// with transport Jacobian production +///////////////////////////////////////////////////////////////////////////////// +std::unique_ptr<Trk::TrackParameters> +Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, + const Trk::TrackParameters& Tp, + const Trk::Surface& Su, + Trk::PropDirection D, + const Trk::BoundaryCheck& B, + const MagneticFieldProperties& M, + TransportJacobian*& Jac, + ParticleHypothesis, + bool returnCurv, + const TrackingVolume*) const +{ + double J[25]; + Cache cache{}; + cache.m_dlt = m_dlt; + cache.m_helixStep = m_helixStep; + cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; + // Get field cache object + getFieldCacheObject(cache, ctx); + cache.m_maxPath = 10000.; + auto Tpn{ propagateRungeKutta(cache, 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 = nullptr; + return Tpn; } ///////////////////////////////////////////////////////////////////////////////// @@ -1739,6 +1914,7 @@ Trk::RungeKuttaPropagator::globalPositions(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1767,6 +1943,7 @@ Trk::RungeKuttaPropagator::intersect(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object @@ -1891,6 +2068,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1917,6 +2095,7 @@ Trk::RungeKuttaPropagator::propagate(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object getFieldCacheObject(cache, ctx); @@ -1943,6 +2122,7 @@ Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object @@ -1970,6 +2150,7 @@ Trk::RungeKuttaPropagator::propagateParameters(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object @@ -2001,6 +2182,7 @@ Trk::RungeKuttaPropagator::globalPositions(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; // Get field cache object @@ -2030,6 +2212,7 @@ Trk::RungeKuttaPropagator::globalPositions(const ::EventContext& ctx, cache.m_dlt = m_dlt; cache.m_helixStep = m_helixStep; cache.m_straightStep = m_straightStep; + cache.m_usegradient = m_usegradient; cache.m_direction = 0.; cache.m_mcondition = false; cache.m_maxPath = 10000.; @@ -2144,158 +2327,6 @@ Trk::RungeKuttaPropagator::globalPositions(const ::EventContext& ctx, } } -///////////////////////////////////////////////////////////////////////////////// -// Main function for simple track propagation with or without jacobian -// Ta->Su = Tb for pattern track parameters -///////////////////////////////////////////////////////////////////////////////// -bool -Trk::RungeKuttaPropagator::propagateRungeKutta(Cache& cache, - 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) - return false; - if (su == &Ta.associatedSurface()) { - Tb = Ta; - return true; - } - - cache.m_direction = D; - - if (useJac && !Ta.iscovariance()) - useJac = false; - - M.magneticFieldMode() == Trk::FastField ? cache.m_solenoid = true : cache.m_solenoid = false; - (useJac && m_usegradient) ? cache.m_needgradient = true : cache.m_needgradient = false; - M.magneticFieldMode() != Trk::NoField ? cache.m_mcondition = true : cache.m_mcondition = false; - - double P[45]; - if (!Trk::RungeKuttaUtils::transformLocalToGlobal(useJac, Ta, P)) - return false; - Step = 0.; - - const Amg::Transform3D& T = Su.transform(); - Trk::SurfaceType ty = Su.type(); - - if (ty == Trk::SurfaceType::Plane) { - double s[4]; - const double 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(cache, useJac, 1, s, P, Step)) - return false; - } else if (ty == Trk::SurfaceType::Line) { - - double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; - if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)) - return false; - } else if (ty == Trk::SurfaceType::Disc) { - - double s[4]; - const double 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(cache, useJac, 1, s, P, Step)){ - return false; - } - } else if (ty == Trk::SurfaceType::Cylinder) { - - const Trk::CylinderSurface* cyl = static_cast<const Trk::CylinderSurface*>(su); - - const 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(), cache.m_direction, 0. }; - - if (!propagateWithJacobian(cache, 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(cache, useJac, 2, s, P, Step)){ - return false; - } - } - } else if (ty == Trk::SurfaceType::Perigee) { - - double s[6] = { T(0, 3), T(1, 3), T(2, 3), T(0, 2), T(1, 2), T(2, 2) }; - if (!propagateWithJacobian(cache, useJac, 0, s, P, Step)){ - return false; - } - } else if (ty == Trk::SurfaceType::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, cache.m_direction, 0. }; - if (!propagateWithJacobian(cache, useJac, 3, s, P, Step)) { - return false; - } - } else{ - return false; - } - - if (cache.m_maxPathLimit || (cache.m_direction && (cache.m_direction * Step) < 0.)) - return false; - - // Common transformation for all surfaces (angles and momentum) - // - if (useJac) { - const 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]; - double Jac[21]; - Trk::RungeKuttaUtils::transformGlobalToLocal(su, useJac, P, p, Jac); - - // New simple track parameters production - // - if (useJac) { - AmgSymMatrix(5) newCov = Trk::PatternTrackParameters::newCovarianceMatrix(*Ta.covariance(), Jac); - Tb.setParametersWithCovariance(&Su, p, newCov); - const AmgSymMatrix(5)& cv = *Tb.covariance(); - if (cv(0, 0) <= 0. || cv(1, 1) <= 0. || cv(2, 2) <= 0. || cv(3, 3) <= 0. || cv(4, 4) <= 0.) - return false; - } else { - Tb.setParameters(&Su, p); - } - return true; -} - void Trk::RungeKuttaPropagator::getFieldCacheObject(Cache& cache, const EventContext& ctx) const {