Skip to content

Commit 7c6d3aa

Browse files
author
jokonig
committed
[PWGEM/PhotonMeson] Add option for fast analytical propagation of tracks
- Photonconversion builder is slow due to many propagation of the tracks to the primary vertex etc. - Add a fast routine to calcuate DCA and Phiv, Psi-Pair from the track helix. - Add histograms to compare the results of both methods
1 parent e0cd446 commit 7c6d3aa

2 files changed

Lines changed: 194 additions & 31 deletions

File tree

PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ enum MatCorrType {
9494
LUT = 2
9595
};
9696

97+
enum TrackPropMode {
98+
kProper = 0,
99+
kFast = 1,
100+
kBoth = 2
101+
};
102+
97103
struct PhotonConversionBuilder {
98104
Produces<aod::V0PhotonsKF> v0photonskf;
99105
Produces<aod::V0Legs> v0legs;
@@ -114,6 +120,7 @@ struct PhotonConversionBuilder {
114120
// Operation and minimisation criteria
115121
Configurable<double> d_bz_input{"d_bz", -999, "bz field, -999 is automatic"};
116122
Configurable<int> useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"};
123+
Configurable<int> modeTrackPropagation{"modeTrackPropagation", 0, "0: use real track propagation, including material, 1: use fast approximation using only geometry, 2: Use real track propagation and make comparison to fast propagation (only for debugging and testing)"};
117124

118125
// single track cuts
119126
Configurable<int> min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"};
@@ -325,6 +332,14 @@ struct PhotonConversionBuilder {
325332
registry.add("V0/hBDTScoreAfterCutVsPt", "BDT score after cut vs pT; pT (GeV/c); BDT score", {HistType::kTH2F, {{1000, 0.0f, 20.0f}, {1000, 0.0f, 1.0f}}});
326333
}
327334
}
335+
336+
// Compare proper propagation and fast geometrical propagation
337+
if (modeTrackPropagation == TrackPropMode::kBoth) {
338+
registry.add("V0Leg/hDCAxyPropagationCompare", "Comparison of DCA_{xy} propagation;DCA_{xy} (cm) proper propagation; DCA_{xy} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}});
339+
registry.add("V0Leg/hDCAzPropagationCompare", "Comparison of DCA_{z} propagation;DCA_{z} (cm) proper propagation; DCA_{z} (cm) geom. propagation", {HistType::kTH2F, {{200, -10., 10.}, {200, -10., 10.}}});
340+
registry.add("V0/hPhivPropagationCompare", "Comparison of #phi_{v};#phi_{v} proper propagation; #phi_{v} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}});
341+
registry.add("V0/hPsiPairPropagationCompare", "Comparison of #Psi_{pair};#Psi_{pair} proper propagation; #Psi_{pair} geom. propagation", {HistType::kTH2F, {{100, 0., 1.6}, {100, 0., 1.6}}});
342+
}
328343
}
329344

330345
void initCCDB(aod::BCsWithTimestamps::iterator const& bc)
@@ -555,8 +570,23 @@ struct PhotonConversionBuilder {
555570
return;
556571
}
557572
auto pTrackC = pTrack;
573+
o2::math_utils::Point3D<float> vtxPrim{
574+
collision.posX(),
575+
collision.posY(),
576+
collision.posZ()};
577+
if (modeTrackPropagation != TrackPropMode::kProper) {
578+
dcaInfo = CalculateDCAFast(pTrackC, vtxPrim, d_bz);
579+
}
558580
pTrackC.setPID(o2::track::PID::Electron);
559-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo);
581+
582+
std::array<float, 2> dcaInfoFast = dcaInfo;
583+
if (modeTrackPropagation != TrackPropMode::kFast) {
584+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo);
585+
if (modeTrackPropagation == TrackPropMode::kBoth) {
586+
registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]);
587+
registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]);
588+
}
589+
}
560590
auto posdcaXY = dcaInfo[0];
561591
auto posdcaZ = dcaInfo[1];
562592

@@ -566,8 +596,19 @@ struct PhotonConversionBuilder {
566596
return;
567597
}
568598
auto nTrackC = nTrack;
599+
if (modeTrackPropagation != TrackPropMode::kProper) {
600+
dcaInfo = CalculateDCAFast(nTrackC, vtxPrim, d_bz);
601+
}
569602
nTrackC.setPID(o2::track::PID::Electron);
570-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo);
603+
604+
dcaInfoFast = dcaInfo;
605+
if (modeTrackPropagation != TrackPropMode::kFast) {
606+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo);
607+
if (modeTrackPropagation == TrackPropMode::kBoth) {
608+
registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]);
609+
registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]);
610+
}
611+
}
571612
auto eledcaXY = dcaInfo[0];
572613
auto eledcaZ = dcaInfo[1];
573614

@@ -587,30 +628,69 @@ struct PhotonConversionBuilder {
587628

588629
float phiv = 999.f;
589630
float psipair = 999.f;
631+
float phivFast = 999.f;
632+
float psipairFast = 999.f;
590633
float baseR = std::hypot(xyz[0], xyz[1]);
591-
std::array<float, 3> offsetsR = {propV0LegsRadius, 30.f, 10.f};
592-
bool pPropagatedSuccess = false;
593-
bool nPropagatedSuccess = false;
594-
auto pTrackProp = pTrack;
595-
auto nTrackProp = nTrack;
596-
for (const float& offsetR : offsetsR) {
597-
pTrackProp = pTrack;
598-
pTrackProp.setPID(o2::track::PID::Electron);
599-
nTrackProp = nTrack;
600-
nTrackProp.setPID(o2::track::PID::Electron);
601-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo);
602-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo);
603-
pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR);
604-
nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR);
605-
if (pPropagatedSuccess && nPropagatedSuccess) {
606-
KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl());
607-
KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl());
608-
phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz);
609-
psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz());
610-
break;
634+
// This method uses the track Helix instead of the full propagation.
635+
// Hence, it is only an approximation but much faster
636+
if (modeTrackPropagation != TrackPropMode::kProper) {
637+
638+
o2::track::TrackAuxPar helixPosEle(nTrack, d_bz);
639+
o2::track::TrackAuxPar helixPosPos(pTrack, d_bz);
640+
641+
float diffX = helixPosEle.xC - helixPosPos.xC;
642+
float diffY = helixPosEle.yC - helixPosPos.yC;
643+
auto phiHelix = RecoDecay::constrainAngle<float, float>(std::atan2(diffY, diffX) - o2::constants::math::PI / 2.);
644+
645+
// Electron
646+
float arcLenghtEle = helixPosEle.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosEle.rC) * helixPosEle.rC : o2::constants::math::PI / 2.2 * helixPosEle.rC; // This assumes that the photon momentum vector is a tangent of the circle
647+
auto propTrackEle = getPropMomentumFromTrackHelix(arcLenghtEle, ele, helixPosEle, d_bz / 10., phiHelix - ele.phi());
648+
// Positron
649+
float arcLenghtPos = helixPosPos.rC * 0.9 > propV0LegsRadius ? std::asin(propV0LegsRadius / helixPosPos.rC) * helixPosPos.rC : o2::constants::math::PI / 2.2 * helixPosPos.rC; // This assumes that the photon momentum vector is a tangent of the circle
650+
auto propTrackPos = getPropMomentumFromTrackHelix(arcLenghtPos, pos, helixPosPos, d_bz / 10., phiHelix - pos.phi());
651+
652+
phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2], pos.sign(), ele.sign(), d_bz);
653+
psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2]);
654+
655+
// Store values for later comparison
656+
phivFast = phiv;
657+
psipairFast = psipair;
658+
}
659+
// This uses the full propagation including material effects
660+
if (modeTrackPropagation != TrackPropMode::kFast) {
661+
std::array<float, 3> offsetsR = {propV0LegsRadius, 30.f, 10.f};
662+
bool pPropagatedSuccess = false;
663+
bool nPropagatedSuccess = false;
664+
auto pTrackProp = pTrack;
665+
auto nTrackProp = nTrack;
666+
for (const auto& offsetR : offsetsR) {
667+
pTrackProp = pTrack;
668+
pTrackProp.setPID(o2::track::PID::Electron);
669+
nTrackProp = nTrack;
670+
nTrackProp.setPID(o2::track::PID::Electron);
671+
672+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo);
673+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo);
674+
675+
pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR);
676+
nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR);
677+
678+
if (pPropagatedSuccess && nPropagatedSuccess) {
679+
KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl());
680+
KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl());
681+
phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz(), pos.sign(), ele.sign(), d_bz);
682+
psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(kfp_track_posProp.GetPx(), kfp_track_posProp.GetPy(), kfp_track_posProp.GetPz(), kfp_track_eleProp.GetPx(), kfp_track_eleProp.GetPy(), kfp_track_eleProp.GetPz());
683+
break;
684+
} else {
685+
LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset.";
686+
}
687+
}
688+
if (modeTrackPropagation == TrackPropMode::kBoth) {
689+
registry.fill(HIST("V0/hPhivPropagationCompare"), phiv, phivFast);
690+
registry.fill(HIST("V0/hPsiPairPropagationCompare"), psipair, psipairFast);
611691
}
612-
LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset.";
613692
}
693+
614694
if (phiv == 999.f || psipair == 999.f) {
615695
LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f).";
616696
}
@@ -985,14 +1065,14 @@ struct PhotonConversionBuilder {
9851065
fillV0Table<isMC, TBCs, TCollisions, TTracks>(v0, true);
9861066
} // end of fullv0Id loop
9871067

988-
for (const auto& collision : collisions) {
989-
if constexpr (isMC) {
990-
if (!collision.has_mcCollision()) {
991-
continue;
992-
}
993-
}
994-
// events_ngpcm(nv0_map[collision.globalIndex()]);
995-
} // end of collision loop
1068+
// for (const auto& collision : collisions) {
1069+
// if constexpr (isMC) {
1070+
// if (!collision.has_mcCollision()) {
1071+
// continue;
1072+
// }
1073+
// }
1074+
// // events_ngpcm(nv0_map[collision.globalIndex()]);
1075+
// } // end of collision loop
9961076

9971077
pca_map.clear();
9981078
cospa_map.clear();

PWGEM/PhotonMeson/Utils/PCMUtilities.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <CommonConstants/MathConstants.h>
2323
#include <DetectorsBase/Propagator.h>
2424
#include <Framework/Concepts.h>
25+
#include <Framework/ASoA.h>
2526
#include <ReconstructionDataFormats/HelixHelper.h>
2627
#include <ReconstructionDataFormats/TrackParametrizationWithError.h>
2728

@@ -101,10 +102,92 @@ inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track:
101102

102103
xyz[2] = (trackPosInformationCopy.getZ() * helixNeg.rC + trackNegInformationCopy.getZ() * helixPos.rC) / (helixPos.rC + helixNeg.rC);
103104
}
105+
106+
//_______________________________________________________________________
107+
/// \brief Calculate DCA for tracks using the track helix and the inclination angl tan(lambda)
108+
/// \param trk track parameterization to obtain helix parameters
109+
/// \param vtx primary vertex position
110+
/// \param magField magnetic field strenght of L3
111+
/// \return DCAxy, DCAz
112+
template <typename TrackPrecision = float>
113+
std::array<float, 2> CalculateDCAFast(const o2::track::TrackParametrizationWithError<TrackPrecision>& trk, const o2::math_utils::Point3D<float>& vtx, const float magField)
114+
{
115+
116+
std::array<float, 2> dca;
117+
118+
// obtain circle from track in x-y plane
119+
const o2::track::TrackAuxPar helixPos(trk, magField);
120+
121+
// obtain position in global coordinates and tan(lambda)
122+
const auto posTrack = trk.getXYZGlo();
123+
const float trX = posTrack.X();
124+
const float trY = posTrack.Y();
125+
const float trZ = posTrack.Z();
126+
const float tangentLambda = trk.getTgl();
127+
128+
// Calculate DCAxy
129+
// Use distance in x and y between circle center and vtx, afterwards subtract radius of circle
130+
const float distX = helixPos.xC - vtx.X();
131+
const float distY = helixPos.yC - vtx.Y();
132+
const float trackCircCenter = std::sqrt(distX * distX + distY * distY);
133+
dca[0] = helixPos.rC - trackCircCenter;
134+
135+
// Calculate DCAz
136+
// First step: Calculate arc lenght of circle between current position and primary vertex in x-y
137+
const float theta0 = std::atan2(trY - helixPos.yC, trX - helixPos.xC);
138+
const float thetav = std::atan2(vtx.Y() - helixPos.yC, vtx.X() - helixPos.xC);
139+
140+
// Make sure angle is between -pi and pi
141+
const auto dtheta = RecoDecay::constrainAngle<float>(thetav - theta0, -o2::constants::math::PI);
142+
143+
// arc-lenght along helix
144+
const float arcLenght = std::fabs(helixPos.rC * dtheta);
145+
146+
// get global z-position at DCA
147+
const float ZPosGlo = trZ - arcLenght * tangentLambda;
148+
149+
// DCA calculated from
150+
dca[1] = ZPosGlo - vtx.Z();
151+
152+
return dca;
153+
}
154+
155+
//_______________________________________________________________________
156+
/// \brief Calculate the track momentum at a different place of the track Helix.
157+
/// \param s arc-lenght where track should be propagated to
158+
/// \param track particle track
159+
/// \param trHelix track helix param. for circle approximation
160+
/// \param bz magnetic field strenght of L3
161+
/// \param addPhi optional additional rotation of the track in phi-direction
162+
/// \return track momentum vector at new position
163+
template <o2::soa::is_iterator TTrack>
164+
inline std::array<float, 3> getPropMomentumFromTrackHelix(const float s, const TTrack& track, const o2::track::TrackAuxPar& trHelix, const float bz, float addPhi = 0.f)
165+
{
166+
167+
// Calculate the change in phi considering the track radius and the track arc lenght s
168+
const float dphi = -track.sign() * 0.3f * bz * s / 100. / track.pt(); // s in cm
169+
const float dotProd = std::cos(track.phi() + addPhi) * track.pt() * trHelix.xC + std::sin(track.phi() + addPhi) * track.pt() * trHelix.yC;
170+
if (dotProd < 0) {
171+
addPhi -= o2::constants::math::PI;
172+
}
173+
174+
// Calculate the phi at the secondary vertex
175+
const auto phi = RecoDecay::constrainAngle<float>(track.phi() + dphi + addPhi);
176+
177+
// Calculate px,y,z at the new propagated vertex
178+
std::array<float, 3> trackP;
179+
trackP[0] = std::cos(phi) * track.pt();
180+
trackP[1] = std::sin(phi) * track.pt();
181+
trackP[2] = track.tgl() * track.pt();
182+
183+
return trackP;
184+
}
185+
104186
//_______________________________________________________________________
105187
template <typename TrackPrecision = float, o2::soa::is_iterator T1, o2::soa::is_iterator T2>
106188
inline void Vtx_recalculation(o2::base::Propagator* prop, T1 lTrackPos, T2 lTrackNeg, std::array<float, 3>& xyz, o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE)
107189
{
190+
108191
// o2::track::TrackParametrizationWithError<TrackPrecision> = TrackParCov, I use the full version to have control over the data type
109192
o2::track::TrackParametrizationWithError<TrackPrecision> trackPosInformation = getTrackParCov(lTrackPos); // first get an object that stores Track information (positive)
110193
o2::track::TrackParametrizationWithError<TrackPrecision> trackNegInformation = getTrackParCov(lTrackNeg); // first get an object that stores Track information (negative)

0 commit comments

Comments
 (0)