Skip to content

Commit 9fd35fe

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 dcc8d10 commit 9fd35fe

2 files changed

Lines changed: 207 additions & 31 deletions

File tree

PWGEM/PhotonMeson/TableProducer/photonconversionbuilder.cxx

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct PhotonConversionBuilder {
114114
// Operation and minimisation criteria
115115
Configurable<double> d_bz_input{"d_bz", -999, "bz field, -999 is automatic"};
116116
Configurable<int> useMatCorrType{"useMatCorrType", 0, "0: none, 1: TGeo, 2: LUT"};
117+
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)"};
117118

118119
// single track cuts
119120
Configurable<int> min_ncluster_tpc{"min_ncluster_tpc", 0, "min ncluster tpc"};
@@ -325,6 +326,14 @@ struct PhotonConversionBuilder {
325326
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}}});
326327
}
327328
}
329+
330+
// Compare proper propagation and fast geometrical propagation
331+
if (modeTrackPropagation == 2) {
332+
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.}}});
333+
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.}}});
334+
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}}});
335+
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}}});
336+
}
328337
}
329338

330339
void initCCDB(aod::BCsWithTimestamps::iterator const& bc)
@@ -555,8 +564,23 @@ struct PhotonConversionBuilder {
555564
return;
556565
}
557566
auto pTrackC = pTrack;
567+
o2::math_utils::Point3D<float> vtxPrim{
568+
collision.posX(),
569+
collision.posY(),
570+
collision.posZ()};
571+
if (modeTrackPropagation > 0) {
572+
dcaInfo = CalculateDCAFast(pTrackC, vtxPrim, d_bz);
573+
}
558574
pTrackC.setPID(o2::track::PID::Electron);
559-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo);
575+
576+
std::array<float, 2> dcaInfoFast = dcaInfo;
577+
if (modeTrackPropagation != 1) {
578+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackC, 2.f, matCorr, &dcaInfo);
579+
if (modeTrackPropagation == 2) {
580+
registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]);
581+
registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]);
582+
}
583+
}
560584
auto posdcaXY = dcaInfo[0];
561585
auto posdcaZ = dcaInfo[1];
562586

@@ -566,8 +590,19 @@ struct PhotonConversionBuilder {
566590
return;
567591
}
568592
auto nTrackC = nTrack;
593+
if (modeTrackPropagation > 0) {
594+
dcaInfo = CalculateDCAFast(nTrackC, vtxPrim, d_bz);
595+
}
569596
nTrackC.setPID(o2::track::PID::Electron);
570-
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo);
597+
598+
dcaInfoFast = dcaInfo;
599+
if (modeTrackPropagation != 1) {
600+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackC, 2.f, matCorr, &dcaInfo);
601+
if (modeTrackPropagation == 2) {
602+
registry.fill(HIST("V0Leg/hDCAxyPropagationCompare"), dcaInfo[0], dcaInfoFast[0]);
603+
registry.fill(HIST("V0Leg/hDCAzPropagationCompare"), dcaInfo[1], dcaInfoFast[1]);
604+
}
605+
}
571606
auto eledcaXY = dcaInfo[0];
572607
auto eledcaZ = dcaInfo[1];
573608

@@ -587,30 +622,76 @@ struct PhotonConversionBuilder {
587622

588623
float phiv = 999.f;
589624
float psipair = 999.f;
625+
float phivFast = 999.f;
626+
float psipairFast = 999.f;
590627
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;
628+
// This method uses the track Helix instead of the full propagation.
629+
// Hence, it is only an approximation but much faster
630+
if (modeTrackPropagation > 0) {
631+
632+
o2::track::TrackAuxPar helixPosEle(nTrack, d_bz);
633+
o2::track::TrackAuxPar helixPosPos(pTrack, d_bz);
634+
635+
float diffX = helixPosEle.xC - helixPosPos.xC;
636+
float diffY = helixPosEle.yC - helixPosPos.yC;
637+
float phiHelix = std::atan2(diffY, diffX);
638+
phiHelix -= o2::constants::math::PI / 2.;
639+
if (phiHelix > 2 * o2::constants::math::PI) {
640+
phiHelix -= o2::constants::math::PI * 2;
641+
}
642+
if (phiHelix < 0) {
643+
phiHelix += o2::constants::math::PI * 2;
611644
}
612-
LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset.";
645+
646+
// Electron
647+
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
648+
auto propTrackEle = getPropMomentumFromTrackHelix(arcLenghtEle, ele, d_bz / 10., helixPosEle, phiHelix - ele.phi());
649+
// Positron
650+
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
651+
auto propTrackPos = getPropMomentumFromTrackHelix(arcLenghtPos, pos, d_bz / 10., helixPosPos, phiHelix - pos.phi());
652+
653+
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);
654+
psipair = o2::aod::pwgem::dilepton::utils::pairutil::getPsiPair(propTrackPos[0], propTrackPos[1], propTrackPos[2], propTrackEle[0], propTrackEle[1], propTrackEle[2]);
655+
656+
// Store values for later comparison
657+
phivFast = phiv;
658+
psipairFast = psipair;
613659
}
660+
// This uses the full propagation including material effects
661+
if (modeTrackPropagation != 1) {
662+
float offsetsR[3] = {propV0LegsRadius, 30.f, 10.f};
663+
bool pPropagatedSuccess = false;
664+
bool nPropagatedSuccess = false;
665+
auto pTrackProp = pTrack;
666+
auto nTrackProp = nTrack;
667+
for (float offsetR : offsetsR) {
668+
pTrackProp = pTrack;
669+
pTrackProp.setPID(o2::track::PID::Electron);
670+
nTrackProp = nTrack;
671+
nTrackProp.setPID(o2::track::PID::Electron);
672+
673+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, pTrackProp, 2.f, matCorr, &dcaInfo);
674+
o2::base::Propagator::Instance()->propagateToDCABxByBz({collision.posX(), collision.posY(), collision.posZ()}, nTrackProp, 2.f, matCorr, &dcaInfo);
675+
676+
pPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(pTrackProp, baseR + offsetR);
677+
nPropagatedSuccess = o2::base::Propagator::Instance()->propagateToR(nTrackProp, baseR + offsetR);
678+
679+
if (pPropagatedSuccess && nPropagatedSuccess) {
680+
KFPTrack kfp_track_posProp = createKFPTrackFromTrackParCov(pTrackProp, pos.sign(), pos.tpcNClsFound(), pos.tpcChi2NCl());
681+
KFPTrack kfp_track_eleProp = createKFPTrackFromTrackParCov(nTrackProp, ele.sign(), ele.tpcNClsFound(), ele.tpcChi2NCl());
682+
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);
683+
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());
684+
break;
685+
} else {
686+
LOG(debug) << "Propagation to offset" << offsetR << " cm failed for " << (pPropagatedSuccess ? "negative" : "positive") << " track. Trying smaller offset.";
687+
}
688+
}
689+
if (modeTrackPropagation == 2) {
690+
registry.fill(HIST("V0/hPhivPropagationCompare"), phiv, phivFast);
691+
registry.fill(HIST("V0/hPsiPairPropagationCompare"), psipair, psipairFast);
692+
}
693+
}
694+
614695
if (phiv == 999.f || psipair == 999.f) {
615696
LOG(debug) << "Propagation failed for all radii (" << propV0LegsRadius << ", 30, 10 cm). Using default values for phiv and psipair (999.f).";
616697
}
@@ -985,14 +1066,14 @@ struct PhotonConversionBuilder {
9851066
fillV0Table<isMC, TBCs, TCollisions, TTracks>(v0, true);
9861067
} // end of fullv0Id loop
9871068

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
1069+
// for (const auto& collision : collisions) {
1070+
// if constexpr (isMC) {
1071+
// if (!collision.has_mcCollision()) {
1072+
// continue;
1073+
// }
1074+
// }
1075+
// // events_ngpcm(nv0_map[collision.globalIndex()]);
1076+
// } // end of collision loop
9961077

9971078
pca_map.clear();
9981079
cospa_map.clear();

PWGEM/PhotonMeson/Utils/PCMUtilities.h

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <CommonConstants/MathConstants.h>
2323
#include <DetectorsBase/Propagator.h>
24+
#include <Framework/ASoA.h>
2425
#include <ReconstructionDataFormats/HelixHelper.h>
2526
#include <ReconstructionDataFormats/TrackParametrizationWithError.h>
2627

@@ -104,10 +105,104 @@ inline void Vtx_recalculationParCov(o2::base::Propagator* prop, const o2::track:
104105

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

0 commit comments

Comments
 (0)