From 909325ec7ef577cc02396cc341b056f7e069df92 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 11 Mar 2026 17:09:30 +0100 Subject: [PATCH] Methods for Barrel <-> Forward tracks conversion --- .../ReconstructionDataFormats/TrackFwd.h | 12 +++ .../TrackParametrization.h | 4 + .../TrackParametrizationWithError.h | 3 + DataFormats/Reconstruction/src/TrackFwd.cxx | 78 ++++++++++++++++++- .../src/TrackParametrization.cxx | 16 ++++ .../src/TrackParametrizationWithError.cxx | 59 ++++++++++++++ 6 files changed, 171 insertions(+), 1 deletion(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h index 50ed36d466d25..fca117583027f 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackFwd.h @@ -31,6 +31,12 @@ using SMatrix55Sym = ROOT::Math::SMatrix; using SMatrix5 = ROOT::Math::SVector; +template +class TrackParametrization; // fwd declaration for conversion method + +template +class TrackParametrizationWithError; // fwd declaration for conversion method + class TrackParFwd { // Forward track parameterization, kinematics only. public: @@ -42,6 +48,9 @@ class TrackParFwd TrackParFwd(TrackParFwd&&) = delete; TrackParFwd& operator=(TrackParFwd&&) = delete; + template + void toBarrelTrackPar(TrackParametrization& t) const; + /// return Z coordinate (cm) Double_t getZ() const { return mZ; } /// set Z coordinate (cm) @@ -145,6 +154,9 @@ class TrackParCovFwd : public TrackParFwd TrackParCovFwd& operator=(const TrackParCovFwd& tpf) = default; TrackParCovFwd(const Double_t z, const SMatrix5& parameters, const SMatrix55Sym& covariances, const Double_t chi2); + template + void toBarrelTrackParCov(TrackParametrizationWithError& t) const; + const SMatrix55Sym& getCovariances() const { return mCovariances; } void setCovariances(const SMatrix55Sym& covariances) { mCovariances = covariances; } void deleteCovariances() { mCovariances = SMatrix55Sym(); } diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h index 6389b037c3625..918633d914230 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h @@ -66,6 +66,9 @@ class DCA; namespace track { + +class TrackParFwd; // fwd declaration for conversion method + // aliases for track elements enum ParLabels : int { kY, kZ, @@ -252,6 +255,7 @@ class TrackParametrization GPUd() void printParam() const; GPUd() void printParamHexadecimal(); #ifndef GPUCA_ALIGPUCODE + void toFwdTrackPar(TrackParFwd& t) const; std::string asString() const; std::string asStringHexadecimal(); size_t hash() const { return hash(getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt()); } diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h index 0fc01e6db61a2..7f7e1e33144b1 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h @@ -25,6 +25,8 @@ namespace o2 namespace track { +class TrackParCovFwd; // fwd declaration for conversion method + template class TrackParametrizationWithError : public TrackParametrization { // track+error parameterization @@ -82,6 +84,7 @@ class TrackParametrizationWithError : public TrackParametrization GPUd() void print() const; GPUd() void printHexadecimal(); #ifndef GPUCA_ALIGPUCODE + bool toFwdTrackParCov(TrackParCovFwd& t) const; std::string asString() const; std::string asStringHexadecimal(); #endif diff --git a/DataFormats/Reconstruction/src/TrackFwd.cxx b/DataFormats/Reconstruction/src/TrackFwd.cxx index dfe72c5b2ccc4..511ba122b2822 100644 --- a/DataFormats/Reconstruction/src/TrackFwd.cxx +++ b/DataFormats/Reconstruction/src/TrackFwd.cxx @@ -10,6 +10,8 @@ // or submit itself to any jurisdiction. #include "ReconstructionDataFormats/TrackFwd.h" +#include "ReconstructionDataFormats/TrackParametrization.h" +#include "ReconstructionDataFormats/TrackParametrizationWithError.h" #include "Math/MatrixFunctions.h" #include @@ -41,7 +43,7 @@ void TrackParFwd::propagateParamToZlinear(double zEnd) auto dZ = (zEnd - getZ()); auto phi0 = getPhi(); auto [sinphi0, cosphi0] = o2::math_utils::sincosd(phi0); - auto invtanl0 = 1.0 / getTanl(); + auto invtanl0 = 1.0 / getTgl(); auto n = dZ * invtanl0; mParameters(0) += n * cosphi0; mParameters(1) += n * sinphi0; @@ -572,5 +574,79 @@ void TrackParCovFwd::propagateToDCAhelix(double zField, const std::array +void TrackParFwd::toBarrelTrackPar(TrackParametrization& t) const +{ + // we select the barrel frame with alpha = phi, then by construction the snp is 0 + auto alpha = getPhi(); + auto csa = TMath::Cos(alpha), sna = TMath::Sin(alpha); + t.setAlpha(alpha); + t.setX(csa * getX() + sna * getY()); + t.setY(-sna * getX() + csa * getY()); + t.setZ(getZ()); + t.setSnp(0); + t.setTgl(getTanl()); + t.setQ2Pt(getInvQPt()); +} + +template +void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError& t) const +{ + // We select the barrel frame with alpha = phi, then by construction the snp is 0 + auto alpha = getPhi(); + auto csa = TMath::Cos(alpha), sna = TMath::Sin(alpha); + t.setAlpha(alpha); + t.setX(csa * getX() + sna * getY()); + t.setY(-sna * getX() + csa * getY()); + t.setZ(getZ()); + t.setSnp(0); + t.setTgl(getTgl()); + t.setQ2Pt(getInvQPt()); + /* + The standard Jacobian d{barrel_param} / d{fwd_param} should be augmented by the "forward" uncertainty + in X_barrel translated to uncertainty in Z, i.e: + A fwd param variation delta_x, delta_y leads to barrel frame coordinate variaion + delta_xb = csa delta_x + sna delta_y + delta_yb = -sna delta_x + csa delta_y + with dx_b/dz = csp/tgL = 1/tgL, dy_b/dz = snp/tgL = 0 (for phi 0 in the tracking frame) the variation of delta_xb would require + a shift in delta_zb = -tgL delta_xb to stat at the same X. + So, for alpha=phi (-> snp=0) choice the full Jacobian fwd->barrel is: + / -sna csa 0 0 0 \ + | -tgL*csa -tgL*sna 0 0 0 | + | 0 0 1 0 0 | + | 0 0 0 1 0 | + \ 0 0 0 0 1 / + */ + const T a1 = -sna; + const T a2 = csa; + const T b1 = -getTgl() * csa; + const T b2 = -getTgl() * sna; + const T cphi = 1; + const auto& C = getCovariances(); + typename TrackParametrizationWithError::covMat_t covBarrel = { + T(a1 * a1 * C(0, 0) + 2 * a1 * a2 * C(0, 1) + a2 * a2 * C(1, 1)), // kSigY2 + T(a1 * b1 * C(0, 0) + (a1 * b2 + a2 * b1) * C(0, 1) + a2 * b2 * C(1, 1)), // kSigZY + T(b1 * b1 * C(0, 0) + 2 * b1 * b2 * C(0, 1) + b2 * b2 * C(1, 1)), // kSigZ2 + T(csa * (a1 * C(0, 2) + a2 * C(1, 2))), // kSigSnpY + T(csa * (b1 * C(0, 2) + b2 * C(1, 2))), // kSigSnpZ + T(csa * csa * C(2, 2)), // kSigSnp2 + T(a1 * C(0, 3) + a2 * C(1, 3)), // kSigTglY + T(b1 * C(0, 3) + b2 * C(1, 3)), // kSigTglZ + T(csa * C(2, 3)), // kSigTglSnp + T(C(3, 3)), // kSigTgl2 + T(a1 * C(0, 4) + a2 * C(1, 4)), // kSigQ2PtY + T(b1 * C(0, 4) + b2 * C(1, 4)), // kSigQ2PtZ + T(csa * C(2, 4)), // kSigQ2PtSnp + T(C(3, 4)), // kSigQ2PtTgl + T(C(4, 4)) // kSigQ2Pt2 + }; + t.setCov(covBarrel); +} + +template void TrackParFwd::toBarrelTrackPar(TrackParametrization&) const; +template void TrackParFwd::toBarrelTrackPar(TrackParametrization&) const; +template void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError&) const; +template void TrackParCovFwd::toBarrelTrackParCov(TrackParametrizationWithError&) const; + } // namespace track } // namespace o2 diff --git a/DataFormats/Reconstruction/src/TrackParametrization.cxx b/DataFormats/Reconstruction/src/TrackParametrization.cxx index 4b850fe14086b..c238b087d5086 100644 --- a/DataFormats/Reconstruction/src/TrackParametrization.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrization.cxx @@ -26,6 +26,7 @@ #ifndef GPUCA_ALIGPUCODE #include +#include "ReconstructionDataFormats/TrackFwd.h" #endif using namespace o2::gpu; @@ -985,6 +986,21 @@ GPUd() typename TrackParametrization::value_t TrackParametrization +void TrackParametrization::toFwdTrackPar(TrackParFwd& t) const +{ + auto p = getXYZGlo(); + t.setZ(p.Z()); + t.setX(p.X()); + t.setY(p.Y()); + t.setPhi(getPhi()); + t.setTanl(getTgl()); + t.setInvQPt(getQ2Pt()); +} +#endif + namespace o2::track { #if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code. diff --git a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx index 93ff7e1a2eb82..ee2e96736aa6d 100644 --- a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx @@ -21,6 +21,7 @@ #ifndef GPUCA_ALIGPUCODE #include +#include "ReconstructionDataFormats/TrackFwd.h" #endif using namespace o2::track; @@ -1768,6 +1769,64 @@ GPUd() void TrackParametrizationWithError::printHexadecimal() #endif } +#ifndef GPUCA_ALIGPUCODE +//______________________________________________________________ +template +bool TrackParametrizationWithError::toFwdTrackParCov(TrackParCovFwd& t) const +{ + auto p = this->getXYZGlo(); + t.setZ(p.Z()); + t.setX(p.X()); + t.setY(p.Y()); + t.setPhi(this->getPhi()); + t.setTanl(this->getTgl()); + t.setInvQPt(this->getQ2Pt()); + // + if (gpu::CAMath::Abs(this->getSnp()) >= o2::constants::math::Almost1 || + gpu::CAMath::Abs(this->getTgl()) <= o2::constants::math::Almost0) { + return false; + } + value_T csa, sna, csP, snP, csp = gpu::CAMath::Sqrt((1. - this->getSnp()) * (1. + this->getSnp())); + math_utils::detail::sincos(value_T(this->getAlpha()), sna, csa); + math_utils::detail::sincos(value_T(t.getPhi()), snP, csP); + /* + Jacobian is + /-sna -csP/tgL 0 0 0 \ + | csa -snP/tgL 0 0 0 | + | 0 0 1/csp 0 0 | + | 0 0 0 1 0 | + \ 0 0 0 0 1 / + */ + auto tgLI = 1 / this->getTgl(); + const value_T d1 = -sna; + const value_T d2 = -csP * tgLI; + const value_T e1 = csa; + const value_T e2 = -snP * tgLI; + const value_T f1 = 1 / csp; + SMatrix55Sym C; + C(0, 0) = d1 * d1 * getSigmaY2() + 2 * d1 * d2 * getSigmaZY() + d2 * d2 * getSigmaZ2(); + C(0, 1) = d1 * e1 * getSigmaY2() + (d1 * e2 + d2 * e1) * getSigmaZY() + d2 * e2 * getSigmaZ2(); + C(1, 1) = e1 * e1 * getSigmaY2() + 2 * e1 * e2 * getSigmaZY() + e2 * e2 * getSigmaZ2(); + + C(0, 2) = f1 * (d1 * getSigmaSnpY() + d2 * getSigmaSnpZ()); + C(1, 2) = f1 * (e1 * getSigmaSnpY() + e2 * getSigmaSnpZ()); + C(2, 2) = f1 * f1 * getSigmaSnp2(); + + C(0, 3) = d1 * getSigmaTglY() + d2 * getSigmaTglZ(); + C(1, 3) = e1 * getSigmaTglY() + e2 * getSigmaTglZ(); + C(2, 3) = f1 * getSigmaTglSnp(); + C(3, 3) = getSigmaTgl2(); + + C(0, 4) = d1 * getSigma1PtY() + d2 * getSigma1PtZ(); + C(1, 4) = e1 * getSigma1PtY() + e2 * getSigma1PtZ(); + C(2, 4) = f1 * getSigma1PtSnp(); + C(3, 4) = getSigma1PtTgl(); + C(4, 4) = getSigma1Pt2(); + t.setCovariances(C); + return true; +} +#endif + namespace o2::track { #if !defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_DEVICE) // FIXME: DR: WORKAROUND to avoid CUDA bug creating host symbols for device code.