From c6c4c381c8ccc566ad0927d6350a8fdee100eb7f Mon Sep 17 00:00:00 2001 From: Joonsuk Date: Wed, 25 Feb 2026 22:22:02 +0100 Subject: [PATCH 1/2] [Common] Fix stale Q/Pt values in TrackTuner graph-based smearing When qOverPtMC and qOverPtData are configured as negative sentinels (requesting graph-based evaluation), the original code overwrites the member variables on the first track call. All subsequent tracks then skip graph evaluation and reuse stale values from the first track's pT, applying incorrect smearing. Fix: use local variables (currentQOverPtMC, currentQOverPtData) so each track evaluates the graphs at its own pT. The member variable sentinels remain negative, ensuring graph evaluation on every call. --- Common/Tools/TrackTuner.h | 65 +++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index 9a04b51be04..452e4642185 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -755,19 +755,24 @@ struct TrackTuner : o2::framework::ConfigurableGroup { dcaZResMC = evalGraph(ptMC, grDcaZResVsPtPionMC[phiBin].get()); dcaZResData = evalGraph(ptMC, grDcaZResVsPtPionData[phiBin].get()); - // For Q/Pt corrections, files on CCDB will be used if both qOverPtMC and qOverPtData are null + // Local Q/Pt resolution: either the constant configurable value, or evaluated per-track from graphs + double currentQOverPtMC = qOverPtMC; + double currentQOverPtData = qOverPtData; if (updateCurvature || updateCurvatureIU) { - if ((qOverPtMC < 0) || (qOverPtData < 0)) { - if (debugInfo) { - LOG(info) << "### q/pt smearing: qOverPtMC=" << qOverPtMC << ", qOverPtData=" << qOverPtData << ". One of them is negative. Retrieving then values from graphs from input .root file"; - } + if ((currentQOverPtMC < 0) || (currentQOverPtData < 0)) { /// check that input graphs for q/pt smearing are correctly retrieved if (!grOneOverPtPionData.get() || !grOneOverPtPionMC.get()) { LOG(fatal) << "### q/pt smearing: input graphs not correctly retrieved. Aborting."; } - qOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); - qOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); - } // qOverPtMC, qOverPtData block ends here + currentQOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); + currentQOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); + if (debugInfo) { + LOG(info) << "### q/pt graph-based smearing: pT=" << ptMC + << " sigma(1/pT)_MC=" << currentQOverPtMC + << " sigma(1/pT)_Data=" << currentQOverPtData + << " ratio(Data/MC)=" << (currentQOverPtMC > 0. ? currentQOverPtData / currentQOverPtMC : -1.); + } + } // currentQOverPtMC, currentQOverPtData block ends here } // updateCurvature, updateCurvatureIU block ends here if (updateTrackDCAs) { @@ -836,7 +841,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // double dpt1o =pt1o-pt1mc; deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (currentQOverPtMC > 0. ? (currentQOverPtData / currentQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -844,36 +849,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // updating track cov matrix elements for 1/Pt at innermost update point // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && qOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + if (dcaXYResMC > 0. && currentQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (currentQOverPtData / currentQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && qOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + if (dcaZResMC > 0. && currentQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (currentQOverPtData / currentQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (qOverPtMC > 0.) { - sigma1PtSnp *= (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1PtSnp *= (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (qOverPtMC > 0.) { - sigma1PtTgl *= (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1PtTgl *= (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (qOverPtMC > 0.) { - sigma1Pt2 *= (qOverPtData / qOverPtMC) * (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1Pt2 *= (currentQOverPtData / currentQOverPtMC) * (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // updateCurvatureIU block ends here @@ -969,7 +974,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { } deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (qOverPtMC > 0. ? (qOverPtData / qOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (currentQOverPtMC > 0. ? (currentQOverPtData / currentQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -1030,36 +1035,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { if ((updateCurvature) && (!updateCurvatureIU)) { // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && qOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (qOverPtData / qOverPtMC)); + if (dcaXYResMC > 0. && currentQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (currentQOverPtData / currentQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && qOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (qOverPtData / qOverPtMC)); + if (dcaZResMC > 0. && currentQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (currentQOverPtData / currentQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (qOverPtMC > 0.) { - sigma1PtSnp *= (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1PtSnp *= (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (qOverPtMC > 0.) { - sigma1PtTgl *= (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1PtTgl *= (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (qOverPtMC > 0.) { - sigma1Pt2 *= (qOverPtData / qOverPtMC) * (qOverPtData / qOverPtMC); + if (currentQOverPtMC > 0.) { + sigma1Pt2 *= (currentQOverPtData / currentQOverPtMC) * (currentQOverPtData / currentQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // ---> track cov matrix elements for 1/Pt ends here From 43abeddca78de4b07567ec9437a0ebec42e1f20c Mon Sep 17 00:00:00 2001 From: Joonsuk Date: Thu, 26 Feb 2026 10:56:15 +0100 Subject: [PATCH 2/2] Rename currentQOverPt -> smearQOverPt per review --- Common/Tools/TrackTuner.h | 62 +++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Common/Tools/TrackTuner.h b/Common/Tools/TrackTuner.h index 452e4642185..01ca6930d89 100644 --- a/Common/Tools/TrackTuner.h +++ b/Common/Tools/TrackTuner.h @@ -756,23 +756,23 @@ struct TrackTuner : o2::framework::ConfigurableGroup { dcaZResData = evalGraph(ptMC, grDcaZResVsPtPionData[phiBin].get()); // Local Q/Pt resolution: either the constant configurable value, or evaluated per-track from graphs - double currentQOverPtMC = qOverPtMC; - double currentQOverPtData = qOverPtData; + double smearQOverPtMC = qOverPtMC; + double smearQOverPtData = qOverPtData; if (updateCurvature || updateCurvatureIU) { - if ((currentQOverPtMC < 0) || (currentQOverPtData < 0)) { + if ((smearQOverPtMC < 0) || (smearQOverPtData < 0)) { /// check that input graphs for q/pt smearing are correctly retrieved if (!grOneOverPtPionData.get() || !grOneOverPtPionMC.get()) { LOG(fatal) << "### q/pt smearing: input graphs not correctly retrieved. Aborting."; } - currentQOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); - currentQOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); + smearQOverPtMC = std::max(0.0, evalGraph(ptMC, grOneOverPtPionMC.get())); + smearQOverPtData = std::max(0.0, evalGraph(ptMC, grOneOverPtPionData.get())); if (debugInfo) { LOG(info) << "### q/pt graph-based smearing: pT=" << ptMC - << " sigma(1/pT)_MC=" << currentQOverPtMC - << " sigma(1/pT)_Data=" << currentQOverPtData - << " ratio(Data/MC)=" << (currentQOverPtMC > 0. ? currentQOverPtData / currentQOverPtMC : -1.); + << " sigma(1/pT)_MC=" << smearQOverPtMC + << " sigma(1/pT)_Data=" << smearQOverPtData + << " ratio(Data/MC)=" << (smearQOverPtMC > 0. ? smearQOverPtData / smearQOverPtMC : -1.); } - } // currentQOverPtMC, currentQOverPtData block ends here + } // smearQOverPtMC, smearQOverPtData block ends here } // updateCurvature, updateCurvatureIU block ends here if (updateTrackDCAs) { @@ -841,7 +841,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // double dpt1o =pt1o-pt1mc; deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (currentQOverPtMC > 0. ? (currentQOverPtData / currentQOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (smearQOverPtMC > 0. ? (smearQOverPtData / smearQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -849,36 +849,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { // updating track cov matrix elements for 1/Pt at innermost update point // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && currentQOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (currentQOverPtData / currentQOverPtMC)); + if (dcaXYResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && currentQOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (currentQOverPtData / currentQOverPtMC)); + if (dcaZResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (currentQOverPtMC > 0.) { - sigma1PtSnp *= (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtSnp *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (currentQOverPtMC > 0.) { - sigma1PtTgl *= (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtTgl *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (currentQOverPtMC > 0.) { - sigma1Pt2 *= (currentQOverPtData / currentQOverPtMC) * (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1Pt2 *= (smearQOverPtData / smearQOverPtMC) * (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // updateCurvatureIU block ends here @@ -974,7 +974,7 @@ struct TrackTuner : o2::framework::ConfigurableGroup { } deltaQpt = trackParQPtMCRec - trackParQPtMC; // double dpt1n =dpt1o *(spt1o >0. ? (spt1n /spt1o ) : 1.); - deltaQptTuned = deltaQpt * (currentQOverPtMC > 0. ? (currentQOverPtData / currentQOverPtMC) : 1.); + deltaQptTuned = deltaQpt * (smearQOverPtMC > 0. ? (smearQOverPtData / smearQOverPtMC) : 1.); // double pt1n = pt1mc+dpt1n; trackParQPtTuned = trackParQPtMC + deltaQptTuned; trackParCov.setQ2Pt(trackParQPtTuned); @@ -1035,36 +1035,36 @@ struct TrackTuner : o2::framework::ConfigurableGroup { if ((updateCurvature) && (!updateCurvatureIU)) { // if(sd0rpo>0. && spt1o>0.)covar[10]*=(sd0rpn/sd0rpo)*(spt1n/spt1o);//ypt sigma1PtY = trackParCov.getSigma1PtY(); - if (dcaXYResMC > 0. && currentQOverPtMC > 0.) { - sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (currentQOverPtData / currentQOverPtMC)); + if (dcaXYResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtY *= ((dcaXYResData / dcaXYResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtY, 10); } // if(sd0zo>0. && spt1o>0.) covar[11]*=(sd0zn/sd0zo)*(spt1n/spt1o);//zpt sigma1PtZ = trackParCov.getSigma1PtZ(); - if (dcaZResMC > 0. && currentQOverPtMC > 0.) { - sigma1PtZ *= ((dcaZResData / dcaZResMC) * (currentQOverPtData / currentQOverPtMC)); + if (dcaZResMC > 0. && smearQOverPtMC > 0.) { + sigma1PtZ *= ((dcaZResData / dcaZResMC) * (smearQOverPtData / smearQOverPtMC)); trackParCov.setCov(sigma1PtZ, 11); } // if(spt1o>0.) covar[12]*=(spt1n/spt1o);//sinPhipt sigma1PtSnp = trackParCov.getSigma1PtSnp(); - if (currentQOverPtMC > 0.) { - sigma1PtSnp *= (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtSnp *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtSnp, 12); } // if(spt1o>0.) covar[13]*=(spt1n/spt1o);//tanTpt sigma1PtTgl = trackParCov.getSigma1PtTgl(); - if (currentQOverPtMC > 0.) { - sigma1PtTgl *= (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1PtTgl *= (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1PtTgl, 13); } // if(spt1o>0.) covar[14]*=(spt1n/spt1o)*(spt1n/spt1o);//ptpt sigma1Pt2 = trackParCov.getSigma1Pt2(); - if (currentQOverPtMC > 0.) { - sigma1Pt2 *= (currentQOverPtData / currentQOverPtMC) * (currentQOverPtData / currentQOverPtMC); + if (smearQOverPtMC > 0.) { + sigma1Pt2 *= (smearQOverPtData / smearQOverPtMC) * (smearQOverPtData / smearQOverPtMC); trackParCov.setCov(sigma1Pt2, 14); } } // ---> track cov matrix elements for 1/Pt ends here