Skip to content

Commit 940159c

Browse files
minjungkim12claude
andcommitted
[PWGHF] Refactor UPC code: move utilities to utilsUpcHf.h
- Add new utility header PWGHF/Utils/utilsUpcHf.h with: - GapType enum for UPC gap classification - determineGapType() function with configurable thresholds - Helper functions: isSingleSidedGap(), gapTypeToInt(), getGapTypeName() - UpcQaHistoConfig struct for consistent histogram binning - Refactor taskD0.cxx and taskDplus.cxx to use shared utilities - Remove duplicate GapType enum and determineGapType() from both tasks - Add gap type axis to THnSparse histograms for UPC analysis - Improve code maintainability and reusability across HF UPC tasks 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3257fd4 commit 940159c

File tree

3 files changed

+182
-67
lines changed

3 files changed

+182
-67
lines changed

PWGHF/D2H/Tasks/taskD0.cxx

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "PWGHF/DataModel/CandidateSelectionTables.h"
2626
#include "PWGHF/DataModel/TrackIndexSkimmingTables.h"
2727
#include "PWGHF/Utils/utilsEvSelHf.h"
28+
#include "PWGHF/Utils/utilsUpcHf.h"
2829
#include "PWGUD/Core/UPCHelpers.h"
2930

3031
#include "Common/CCDB/ctpRateFetcher.h"
@@ -61,12 +62,7 @@ using namespace o2::framework::expressions;
6162
using namespace o2::hf_centrality;
6263
using namespace o2::hf_occupancy;
6364
using namespace o2::hf_evsel;
64-
65-
enum class GapType {
66-
GapA = 0,
67-
GapC = 1,
68-
DoubleGap = 2,
69-
};
65+
using namespace o2::analysis::hf_upc;
7066

7167
/// D0 analysis task
7268
namespace
@@ -157,6 +153,7 @@ struct HfTaskD0 {
157153
ConfigurableAxis thnConfigAxisMinItsNCls{"thnConfigAxisMinItsNCls", {5, 3, 8}, "axis for minimum ITS NCls of candidate prongs"};
158154
ConfigurableAxis thnConfigAxisMinTpcNCrossedRows{"thnConfigAxisMinTpcNCrossedRows", {10, 70, 180}, "axis for minimum TPC NCls crossed rows of candidate prongs"};
159155
ConfigurableAxis thnConfigAxisIR{"thnConfigAxisIR", {5000, 0, 500}, "Interaction rate (kHz)"};
156+
ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"};
160157

161158
HistogramRegistry registry{
162159
"registry",
@@ -301,6 +298,7 @@ struct HfTaskD0 {
301298
const AxisSpec thnAxisMinItsNCls{thnConfigAxisMinItsNCls, "Minimum ITS cluster found"};
302299
const AxisSpec thnAxisMinTpcNCrossedRows{thnConfigAxisMinTpcNCrossedRows, "Minimum TPC crossed rows"};
303300
const AxisSpec thnAxisIR{thnConfigAxisIR, "Interaction rate"};
301+
const AxisSpec thnAxisGapType{thnConfigAxisGapType, "Gap type"};
304302

305303
if (doprocessMcWithDCAFitterN || doprocessMcWithDCAFitterNCent || doprocessMcWithKFParticle || doprocessMcWithDCAFitterNMl || doprocessMcWithDCAFitterNMlCent || doprocessMcWithKFParticleMl) {
306304
std::vector<AxisSpec> axesAcc = {thnAxisGenPtD, thnAxisGenPtB, thnAxisY, thnAxisOrigin, thnAxisNumPvContr};
@@ -334,6 +332,9 @@ struct HfTaskD0 {
334332
axes.push_back(thnAxisMinItsNCls);
335333
axes.push_back(thnAxisMinTpcNCrossedRows);
336334
}
335+
if (doprocessDataWithDCAFitterNMlWithUpc) {
336+
axes.push_back(thnAxisGapType);
337+
}
337338
if (applyMl) {
338339
const AxisSpec thnAxisBkgScore{thnConfigAxisBkgScore, "BDT score bkg."};
339340
const AxisSpec thnAxisNonPromptScore{thnConfigAxisNonPromptScore, "BDT score non-prompt."};
@@ -544,20 +545,6 @@ struct HfTaskD0 {
544545
}
545546
}
546547

547-
GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC)
548-
{
549-
constexpr float FT0AThreshold = 100.0;
550-
constexpr float FT0CThreshold = 50.0;
551-
constexpr float ZDCThreshold = 1.0;
552-
if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) {
553-
return GapType::GapA;
554-
}
555-
if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) {
556-
return GapType::GapC;
557-
}
558-
return GapType::DoubleGap;
559-
}
560-
561548
template <bool fillMl, typename CollType, typename CandType, typename BCsType>
562549
void runAnalysisPerCollisionDataWithUpc(CollType const& collisions,
563550
CandType const& candidates,
@@ -582,10 +569,11 @@ struct HfTaskD0 {
582569
auto zdc = bc.zdc();
583570
qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C);
584571
qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC());
585-
gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC());
586-
qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast<int>(gap));
572+
gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC());
573+
qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap));
587574
}
588-
if (gap == GapType::GapA || gap == GapType::GapC) {
575+
if (hf_upc::isSingleSidedGap(gap)) {
576+
int const gapTypeInt = hf_upc::gapTypeToInt(gap);
589577
const auto thisCollId = collision.globalIndex();
590578
const auto& groupedD0Candidates = candidates.sliceBy(candD0PerCollision, thisCollId);
591579

@@ -614,21 +602,21 @@ struct HfTaskD0 {
614602

615603
if constexpr (fillMl) {
616604
if (candidate.isSelD0() >= selectionFlagD0) {
617-
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0);
618-
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0);
605+
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast<float>(gapTypeInt));
606+
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast<float>(gapTypeInt));
619607
}
620608
if (candidate.isSelD0bar() >= selectionFlagD0bar) {
621-
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar);
622-
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar);
609+
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast<float>(gapTypeInt));
610+
registry.fill(HIST("hBdtScoreVsMassVsPtVsPtBVsYVsOriginVsD0Type"), candidate.mlProbD0()[0], candidate.mlProbD0()[1], candidate.mlProbD0()[2], massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast<float>(gapTypeInt));
623611
}
624612
} else {
625613
if (candidate.isSelD0() >= selectionFlagD0) {
626-
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0);
627-
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0);
614+
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), SigD0, static_cast<float>(gapTypeInt));
615+
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0bar() ? ReflectedD0 : PureSigD0, static_cast<float>(gapTypeInt));
628616
}
629617
if (candidate.isSelD0bar() >= selectionFlagD0bar) {
630-
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar);
631-
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar);
618+
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), SigD0bar, static_cast<float>(gapTypeInt));
619+
registry.fill(HIST("hMassVsPtVsPtBVsYVsOriginVsD0Type"), massD0bar, ptCandidate, HfHelper::yD0(candidate), candidate.isSelD0() ? ReflectedD0bar : PureSigD0bar, static_cast<float>(gapTypeInt));
632620
}
633621
}
634622
}

PWGHF/D2H/Tasks/taskDplus.cxx

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "PWGHF/DataModel/TrackIndexSkimmingTables.h"
2828
#include "PWGHF/Utils/utilsAnalysis.h"
2929
#include "PWGHF/Utils/utilsEvSelHf.h"
30+
#include "PWGHF/Utils/utilsUpcHf.h"
3031
#include "PWGUD/Core/UPCHelpers.h"
3132

3233
#include "Common/Core/RecoDecay.h"
@@ -63,12 +64,7 @@ using namespace o2::framework::expressions;
6364
using namespace o2::hf_centrality;
6465
using namespace o2::hf_occupancy;
6566
using namespace o2::hf_evsel;
66-
67-
enum class GapType {
68-
GapA = 0,
69-
GapC = 1,
70-
DoubleGap = 2,
71-
};
67+
using namespace o2::analysis::hf_upc;
7268

7369
/// D± analysis task
7470
struct HfTaskDplus {
@@ -128,6 +124,7 @@ struct HfTaskDplus {
128124
ConfigurableAxis thnConfigAxisMlScore0{"thnConfigAxisMlScore0", {100, 0., 1.}, "axis for ML output score 0"};
129125
ConfigurableAxis thnConfigAxisMlScore1{"thnConfigAxisMlScore1", {100, 0., 1.}, "axis for ML output score 1"};
130126
ConfigurableAxis thnConfigAxisMlScore2{"thnConfigAxisMlScore2", {100, 0., 1.}, "axis for ML output score 2"};
127+
ConfigurableAxis thnConfigAxisGapType{"thnConfigAxisGapType", {3, -0.5, 2.5}, "axis for UPC gap type (0=GapA, 1=GapC, 2=DoubleGap)"};
131128

132129
HistogramRegistry registry{
133130
"registry",
@@ -161,6 +158,7 @@ struct HfTaskDplus {
161158
AxisSpec const thnAxisCent{thnConfigAxisCent, "Centrality"};
162159
AxisSpec const thnAxisOccupancy{thnConfigAxisOccupancy, "Occupancy"};
163160
AxisSpec const thnAxisPvContributors{thnConfigAxisPvContributors, "PV contributors"};
161+
AxisSpec const thnAxisGapType{thnConfigAxisGapType, "Gap type"};
164162

165163
registry.add("hMass", "3-prong candidates;inv. mass (#pi K #pi) (GeV/#it{c}^{2});entries", {HistType::kTH2F, {{350, 1.7, 2.05}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}});
166164
registry.add("hEta", "3-prong candidates;candidate #it{#eta};entries", {HistType::kTH2F, {{100, -2., 2.}, {vbins, "#it{p}_{T} (GeV/#it{c})"}}});
@@ -200,10 +198,10 @@ struct HfTaskDplus {
200198
registry.add("hPtVsYGenPrompt", "MC particles (matched, prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}});
201199
registry.add("hPtVsYGenNonPrompt", "MC particles (matched, non-prompt);#it{p}_{T}^{gen.}; #it{y}", {HistType::kTH2F, {{vbins, "#it{p}_{T} (GeV/#it{c})"}, {100, -5., 5.}}});
202200

203-
if (doprocessDataWithMl || doprocessData) {
201+
if (doprocessDataWithMl || doprocessData || doprocessDataWithMlWithUpc) {
204202
std::vector<AxisSpec> axes = {thnAxisMass, thnAxisPt};
205203

206-
if (doprocessDataWithMl) {
204+
if (doprocessDataWithMl || doprocessDataWithMlWithUpc) {
207205
axes.push_back(thnAxisMlScore0);
208206
axes.push_back(thnAxisMlScore1);
209207
axes.push_back(thnAxisMlScore2);
@@ -214,6 +212,9 @@ struct HfTaskDplus {
214212
if (storeOccupancy) {
215213
axes.push_back(thnAxisOccupancy);
216214
}
215+
if (doprocessDataWithMlWithUpc) {
216+
axes.push_back(thnAxisGapType);
217+
}
217218

218219
registry.add("hSparseMass", "THn for Dplus", HistType::kTHnSparseF, axes);
219220
}
@@ -313,13 +314,15 @@ struct HfTaskDplus {
313314
/// \param centrality collision centrality
314315
/// \param occupancy collision occupancy
315316
/// \param numPvContributors contributors to the PV
317+
/// \param gapType UPC gap type (-1 for non-UPC)
316318
template <bool IsMc, bool IsMatched, typename T1>
317319
void fillSparseML(const T1& candidate,
318320
float ptbhad,
319321
int flagBHad,
320322
float centrality,
321323
float occupancy,
322-
float numPvContributors)
324+
float numPvContributors,
325+
int gapType = -1)
323326
{
324327
std::vector<float> outputMl = {-999., -999., -999.};
325328
for (unsigned int iclass = 0; iclass < classMl->size(); iclass++) {
@@ -384,16 +387,30 @@ struct HfTaskDplus {
384387
}
385388
}
386389
} else { // Data
387-
if (storeCentrality && storeOccupancy) {
388-
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy);
389-
} else if (storeCentrality && !storeOccupancy) {
390-
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality);
391-
} else if (!storeCentrality && storeOccupancy) {
392-
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy);
393-
} else if (!storeCentrality && !storeOccupancy && storePvContributors) {
394-
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors);
390+
if (gapType >= 0) {
391+
// UPC mode: always include gap type
392+
if (storeCentrality && storeOccupancy) {
393+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy, static_cast<float>(gapType));
394+
} else if (storeCentrality && !storeOccupancy) {
395+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, static_cast<float>(gapType));
396+
} else if (!storeCentrality && storeOccupancy) {
397+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy, static_cast<float>(gapType));
398+
} else {
399+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], static_cast<float>(gapType));
400+
}
395401
} else {
396-
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]);
402+
// Non-UPC mode: original behavior
403+
if (storeCentrality && storeOccupancy) {
404+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality, occupancy);
405+
} else if (storeCentrality && !storeOccupancy) {
406+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], centrality);
407+
} else if (!storeCentrality && storeOccupancy) {
408+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], occupancy);
409+
} else if (!storeCentrality && !storeOccupancy && storePvContributors) {
410+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2], numPvContributors);
411+
} else {
412+
registry.fill(HIST("hSparseMass"), HfHelper::invMassDplusToPiKPi(candidate), candidate.pt(), outputMl[0], outputMl[1], outputMl[2]);
413+
}
397414
}
398415
}
399416
}
@@ -680,20 +697,6 @@ struct HfTaskDplus {
680697
}
681698
}
682699

683-
GapType determineGapType(float FT0A, float FT0C, float ZNA, float ZNC)
684-
{
685-
constexpr float FT0AThreshold = 100.0;
686-
constexpr float FT0CThreshold = 50.0;
687-
constexpr float ZDCThreshold = 1.0;
688-
if (FT0A < FT0AThreshold && FT0C > FT0CThreshold && ZNA < ZDCThreshold && ZNC > ZDCThreshold) {
689-
return GapType::GapA;
690-
}
691-
if (FT0A > FT0AThreshold && FT0C < FT0CThreshold && ZNA > ZDCThreshold && ZNC < ZDCThreshold) {
692-
return GapType::GapC;
693-
}
694-
return GapType::DoubleGap;
695-
}
696-
697700
template <bool fillMl, typename CollType, typename CandType, typename BCsType>
698701
void runAnalysisPerCollisionDataWithUpc(CollType const& collisions,
699702
CandType const& candidates,
@@ -719,10 +722,10 @@ struct HfTaskDplus {
719722
auto zdc = bc.zdc();
720723
qaRegistry.fill(HIST("Data/fitInfo/ampFT0A_vs_ampFT0C"), fitInfo.ampFT0A, fitInfo.ampFT0C);
721724
qaRegistry.fill(HIST("Data/zdc/energyZNA_vs_energyZNC"), zdc.energyCommonZNA(), zdc.energyCommonZNC());
722-
gap = determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC());
723-
qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), static_cast<int>(gap));
725+
gap = hf_upc::determineGapType(fitInfo.ampFT0A, fitInfo.ampFT0C, zdc.energyCommonZNA(), zdc.energyCommonZNC());
726+
qaRegistry.fill(HIST("Data/hUpcGapAfterSelection"), hf_upc::gapTypeToInt(gap));
724727
}
725-
if (gap == GapType::GapA || gap == GapType::GapC) {
728+
if (hf_upc::isSingleSidedGap(gap)) {
726729
// Use the candidates from this collision
727730
const auto thisCollId = collision.globalIndex();
728731
const auto& groupedDplusCandidates = candidates.sliceBy(candDplusPerCollision, thisCollId);
@@ -731,14 +734,15 @@ struct HfTaskDplus {
731734
float numPvContr{-1.f};
732735
float ptBhad{-1.f};
733736
int const flagBHad{-1};
737+
int const gapTypeInt = hf_upc::gapTypeToInt(gap);
734738

735739
for (const auto& candidate : groupedDplusCandidates) {
736740
if ((yCandRecoMax >= 0. && std::abs(HfHelper::yDplus(candidate)) > yCandRecoMax)) {
737741
continue;
738742
}
739743
fillHisto(candidate);
740744
if constexpr (fillMl) {
741-
fillSparseML<false, false>(candidate, ptBhad, flagBHad, cent, occ, numPvContr);
745+
fillSparseML<false, false>(candidate, ptBhad, flagBHad, cent, occ, numPvContr, gapTypeInt);
742746
}
743747
}
744748
}

0 commit comments

Comments
 (0)