Skip to content

Commit 7012202

Browse files
[PWGDQ] Add post-prefilter single-track selection task to dqEfficiency_withAssoc
AnalysisTrackSelection runs before AnalysisPrefilterSelection, so the effect of the conversion-prefilter veto cannot be inspected at the single-track level anywhere in the workflow (the only prefilter-aware consumers are the pairing tasks). The new AnalysisPostPrefilterTrackSelection task joins the track-collision associations with both the BarrelTrackCuts and the Prefilter decisions and fills track-level histograms, separately for tracks surviving the prefilter veto and for vetoed tracks, per track cut and per MC signal. Use cases: post-prefilter per-origin DCA templates for HF-electron template fits, MC measurement of the photonic-electron tagging efficiency (vetoed / (vetoed + survived)), and track-level prefilter QA. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 59bcc15 commit 7012202

1 file changed

Lines changed: 218 additions & 0 deletions

File tree

PWGDQ/Tasks/dqEfficiency_withAssoc.cxx

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,223 @@ struct AnalysisPrefilterSelection {
13501350
PROCESS_SWITCH(AnalysisPrefilterSelection, processDummy, "Do nothing", true);
13511351
};
13521352

1353+
// Single-track selection on the barrel tracks after the prefilter decisions (which are not visible in the
1354+
// AnalysisTrackSelection histograms): fills track-level histograms separately for surviving and vetoed tracks,
1355+
// per track cut and per MC signal.
1356+
// NOTE: Histograms are filled per association, regardless of whether the association is the correct one.
1357+
struct AnalysisPostPrefilterTrackSelection {
1358+
OutputObj<THashList> fOutputList{"output"};
1359+
1360+
Configurable<std::string> fConfigTrackCuts{"cfgTrackCuts", "", "Comma separated list of track cuts (among those of analysis-track-selection) for which to fill histograms"};
1361+
Configurable<std::string> fConfigAddTrackHistogram{"cfgAddTrackHistogram", "", "Comma separated list of histograms"};
1362+
Configurable<std::string> fConfigAddJSONHistograms{"cfgAddJSONHistograms", "", "Histograms in JSON format"};
1363+
Configurable<std::string> fConfigMCSignals{"cfgTrackMCSignals", "", "Comma separated list of MC signals"};
1364+
Configurable<std::string> fConfigMCSignalsJSON{"cfgTrackMCsignalsJSON", "", "Additional list of MC signals via JSON"};
1365+
Configurable<std::string> fConfigCcdbUrl{"ccdb-url", "http://alice-ccdb.cern.ch", "url of the ccdb repository"};
1366+
Configurable<std::string> grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "CCDB path of the GRPMagField object"};
1367+
1368+
Service<o2::ccdb::BasicCCDBManager> fCCDB{};
1369+
1370+
HistogramManager* fHistMan = nullptr;
1371+
std::vector<MCSignal*> fMCSignals;
1372+
std::vector<int> fCutBits; // bit positions of the requested cuts in the track-selection task cut list
1373+
std::vector<TString> fHistNamesSurvived; // [icut]
1374+
std::vector<TString> fHistNamesVetoed; // [icut]
1375+
std::vector<TString> fHistNamesMCSurvived; // [icut * nSignals + isig]
1376+
std::vector<TString> fHistNamesMCVetoed; // [icut * nSignals + isig]
1377+
1378+
int fCurrentRun = 0; // current run (needed to detect run changes for loading CCDB parameters)
1379+
1380+
void init(o2::framework::InitContext& context)
1381+
{
1382+
if (context.mOptions.get<bool>("processDummy")) {
1383+
return;
1384+
}
1385+
VarManager::SetDefaultVarNames();
1386+
1387+
fCurrentRun = 0;
1388+
TString trackCutsStr = fConfigTrackCuts.value;
1389+
std::unique_ptr<TObjArray> objArrayCuts(trackCutsStr.Tokenize(","));
1390+
if (objArrayCuts == nullptr || objArrayCuts->GetEntries() == 0) {
1391+
LOG(fatal) << " No track cuts specified! Check the cfgTrackCuts configurable";
1392+
}
1393+
// get the full list of cuts computed by the track-selection task and resolve the requested cuts to bit positions
1394+
std::string trackCuts;
1395+
getTaskOptionValue<std::string>(context, "analysis-track-selection", "cfgTrackCuts", trackCuts, false);
1396+
TString allTrackCutsStr = trackCuts;
1397+
// check also the cuts added via JSON and add them to the string of cuts
1398+
getTaskOptionValue<std::string>(context, "analysis-track-selection", "cfgBarrelTrackCutsJSON", trackCuts, false);
1399+
TString addTrackCutsStr = trackCuts;
1400+
if (addTrackCutsStr != "") {
1401+
std::vector<AnalysisCut*> addTrackCuts = dqcuts::GetCutsFromJSON(addTrackCutsStr.Data());
1402+
for (auto const& t : addTrackCuts) {
1403+
allTrackCutsStr += Form(",%s", t->GetName());
1404+
}
1405+
}
1406+
std::unique_ptr<TObjArray> objArrayAllCuts(allTrackCutsStr.Tokenize(","));
1407+
if (objArrayAllCuts == nullptr) {
1408+
LOG(fatal) << " Not getting any track cuts from the barrel-track-selection ";
1409+
}
1410+
std::vector<TString> cutNames;
1411+
for (int icut = 0; icut < objArrayCuts->GetEntries(); ++icut) {
1412+
TString cutName = objArrayCuts->At(icut)->GetName();
1413+
if (objArrayAllCuts->FindObject(cutName.Data()) == nullptr) {
1414+
LOG(fatal) << " Track cut " << cutName << " not among the cuts calculated by the track-selection task! ";
1415+
}
1416+
for (int jcut = 0; jcut < objArrayAllCuts->GetEntries(); ++jcut) {
1417+
if (cutName.CompareTo(objArrayAllCuts->At(jcut)->GetName()) == 0) {
1418+
fCutBits.push_back(jcut);
1419+
}
1420+
}
1421+
cutNames.push_back(cutName);
1422+
}
1423+
1424+
// Setting the MC signals
1425+
TString configSigNamesStr = fConfigMCSignals.value;
1426+
std::unique_ptr<TObjArray> sigNamesArray(configSigNamesStr.Tokenize(","));
1427+
for (int isig = 0; isig < sigNamesArray->GetEntries(); ++isig) {
1428+
MCSignal* sig = o2::aod::dqmcsignals::GetMCSignal(sigNamesArray->At(isig)->GetName());
1429+
if (sig) {
1430+
if (sig->GetNProngs() != 1) { // NOTE: only 1 prong signals
1431+
continue;
1432+
}
1433+
fMCSignals.push_back(sig);
1434+
}
1435+
}
1436+
// Add the MCSignals from the JSON config
1437+
TString addMCSignalsStr = fConfigMCSignalsJSON.value;
1438+
if (addMCSignalsStr != "") {
1439+
std::vector<MCSignal*> addMCSignals = dqmcsignals::GetMCSignalsFromJSON(addMCSignalsStr.Data());
1440+
for (auto const& mcIt : addMCSignals) {
1441+
if (mcIt->GetNProngs() != 1) { // NOTE: only 1 prong signals
1442+
continue;
1443+
}
1444+
fMCSignals.push_back(mcIt);
1445+
}
1446+
}
1447+
1448+
fHistMan = new HistogramManager("analysisHistos", "aa", VarManager::kNVars);
1449+
fHistMan->SetUseDefaultVariableNames(kTRUE);
1450+
fHistMan->SetDefaultVarNames(dqefficiency_helpers::varNames(), dqefficiency_helpers::varUnits());
1451+
1452+
// Configure histogram classes for each track cut, separately for prefilter-surviving and prefilter-vetoed tracks,
1453+
// and for each requested MC signal (reconstructed tracks with MC truth)
1454+
TString histClasses = "";
1455+
for (auto const& cutName : cutNames) {
1456+
TString nameStr = Form("TrackBarrelPostPrefilter_%s", cutName.Data());
1457+
fHistNamesSurvived.push_back(nameStr);
1458+
histClasses += Form("%s;", nameStr.Data());
1459+
nameStr = Form("TrackBarrelPrefilterVetoed_%s", cutName.Data());
1460+
fHistNamesVetoed.push_back(nameStr);
1461+
histClasses += Form("%s;", nameStr.Data());
1462+
for (auto const& sig : fMCSignals) {
1463+
TString nameStr2 = Form("TrackBarrelPostPrefilter_%s_%s", cutName.Data(), sig->GetName());
1464+
fHistNamesMCSurvived.push_back(nameStr2);
1465+
histClasses += Form("%s;", nameStr2.Data());
1466+
nameStr2 = Form("TrackBarrelPrefilterVetoed_%s_%s", cutName.Data(), sig->GetName());
1467+
fHistNamesMCVetoed.push_back(nameStr2);
1468+
histClasses += Form("%s;", nameStr2.Data());
1469+
}
1470+
}
1471+
1472+
DefineHistograms(fHistMan, histClasses.Data(), fConfigAddTrackHistogram.value.data());
1473+
dqhistograms::AddHistogramsFromJSON(fHistMan, fConfigAddJSONHistograms.value.c_str()); // ad-hoc histograms via JSON
1474+
VarManager::SetUseVars(fHistMan->GetUsedVars()); // provide the list of required variables so that VarManager knows what to fill
1475+
fOutputList.setObject(fHistMan->GetMainHistogramList());
1476+
1477+
fCCDB->setURL(fConfigCcdbUrl.value);
1478+
fCCDB->setCaching(true);
1479+
fCCDB->setLocalObjectValidityChecking();
1480+
}
1481+
1482+
template <uint32_t TEventFillMap, uint32_t TTrackFillMap, typename TEvents, typename TTracks, typename TTracksMC>
1483+
void runPostPrefilterTrackSelection(soa::Join<aod::ReducedTracksAssoc, aod::BarrelTrackCuts, aod::Prefilter> const& assocs,
1484+
TEvents const& events, TTracks const& /*tracks*/, TTracksMC const& tracksMC)
1485+
{
1486+
// load the magnetic field (needed to recompute the DCA with respect to the associated collision)
1487+
if (events.size() > 0 && fCurrentRun != events.begin().runNumber()) {
1488+
auto grpmag = fCCDB->getForTimeStamp<o2::parameters::GRPMagField>(grpmagPath, events.begin().timestamp());
1489+
if (grpmag != nullptr) {
1490+
VarManager::SetMagneticField(grpmag->getNominalL3Field());
1491+
} else {
1492+
LOGF(fatal, "GRP object is not available in CCDB at timestamp=%llu", events.begin().timestamp());
1493+
}
1494+
fCurrentRun = events.begin().runNumber();
1495+
}
1496+
1497+
// Loop over associations
1498+
for (auto const& assoc : assocs) {
1499+
auto event = assoc.template reducedevent_as<TEvents>();
1500+
if (!event.isEventSelected_bit(0)) {
1501+
continue;
1502+
}
1503+
1504+
// check which of the requested cuts are fulfilled by this association and which of those are prefilter-vetoed
1505+
uint32_t selectedMap = 0;
1506+
uint32_t vetoMap = 0;
1507+
for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) {
1508+
if (assoc.isBarrelSelected_bit(fCutBits[icut])) {
1509+
selectedMap |= (static_cast<uint32_t>(1) << icut);
1510+
if (!assoc.isBarrelSelectedPrefilter_bit(fCutBits[icut])) {
1511+
vetoMap |= (static_cast<uint32_t>(1) << icut);
1512+
}
1513+
}
1514+
}
1515+
if (selectedMap == 0) {
1516+
continue;
1517+
}
1518+
1519+
VarManager::ResetValues(0, VarManager::kNBarrelTrackVariables);
1520+
// fill event information which might be needed in histograms that combine track and event properties
1521+
VarManager::FillEvent<TEventFillMap>(event);
1522+
if (event.has_reducedMCevent()) {
1523+
VarManager::FillEvent<VarManager::ObjTypes::ReducedEventMC>(event.reducedMCevent());
1524+
}
1525+
1526+
auto track = assoc.template reducedtrack_as<TTracks>();
1527+
VarManager::FillTrack<TTrackFillMap>(track);
1528+
// compute quantities which depend on the associated collision, such as DCA
1529+
VarManager::FillTrackCollision<TTrackFillMap>(track, event);
1530+
if (track.has_reducedMCTrack()) {
1531+
VarManager::FillTrackMC(tracksMC, track.reducedMCTrack());
1532+
}
1533+
1534+
for (std::size_t icut = 0; icut < fCutBits.size(); ++icut) {
1535+
if (!(selectedMap & (static_cast<uint32_t>(1) << icut))) {
1536+
continue;
1537+
}
1538+
bool isVetoed = (vetoMap & (static_cast<uint32_t>(1) << icut)) > 0;
1539+
fHistMan->FillHistClass((isVetoed ? fHistNamesVetoed[icut] : fHistNamesSurvived[icut]).Data(), dqefficiency_helpers::varValues());
1540+
if (track.has_reducedMCTrack()) {
1541+
int isig = 0;
1542+
for (auto sig = fMCSignals.begin(); sig != fMCSignals.end(); sig++, isig++) {
1543+
if ((*sig)->CheckSignal(true, track.reducedMCTrack())) {
1544+
fHistMan->FillHistClass((isVetoed ? fHistNamesMCVetoed : fHistNamesMCSurvived)[icut * fMCSignals.size() + isig].Data(), dqefficiency_helpers::varValues());
1545+
}
1546+
}
1547+
}
1548+
} // end loop over cuts
1549+
} // end loop over associations
1550+
}
1551+
1552+
void processSkimmed(soa::Join<aod::ReducedTracksAssoc, aod::BarrelTrackCuts, aod::Prefilter> const& assocs, MyEventsSelected const& events, MyBarrelTracks const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC)
1553+
{
1554+
runPostPrefilterTrackSelection<gkEventFillMap, gkTrackFillMap>(assocs, events, tracks, tracksMC);
1555+
}
1556+
void processSkimmedWithCov(soa::Join<aod::ReducedTracksAssoc, aod::BarrelTrackCuts, aod::Prefilter> const& assocs, MyEventsVtxCovSelected const& events, MyBarrelTracksWithCov const& tracks, ReducedMCEvents const& /*eventsMC*/, ReducedMCTracks const& tracksMC)
1557+
{
1558+
runPostPrefilterTrackSelection<gkEventFillMapWithCov, gkTrackFillMapWithCov>(assocs, events, tracks, tracksMC);
1559+
}
1560+
void processDummy(MyEvents const&)
1561+
{
1562+
// do nothing
1563+
}
1564+
1565+
PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmed, "Run barrel track post-prefilter selection on DQ skimmed track associations", false);
1566+
PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processSkimmedWithCov, "Run barrel track post-prefilter selection on DQ skimmed track associations w/ cov matrix", false);
1567+
PROCESS_SWITCH(AnalysisPostPrefilterTrackSelection, processDummy, "Dummy function", true);
1568+
};
1569+
13531570
// Run the same-event pairing
13541571
// This task assumes that both legs of the resonance fulfill the same cuts (symmetric decay channel)
13551572
// Runs combinatorics for barrel-barrel, muon-muon and barrel-muon combinations
@@ -5183,6 +5400,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
51835400
adaptAnalysisTask<AnalysisTrackSelection>(cfgc),
51845401
adaptAnalysisTask<AnalysisMuonSelection>(cfgc),
51855402
adaptAnalysisTask<AnalysisPrefilterSelection>(cfgc),
5403+
adaptAnalysisTask<AnalysisPostPrefilterTrackSelection>(cfgc),
51865404
adaptAnalysisTask<AnalysisSameEventPairing>(cfgc),
51875405
adaptAnalysisTask<AnalysisAsymmetricPairing>(cfgc),
51885406
adaptAnalysisTask<AnalysisDileptonTrack>(cfgc)};

0 commit comments

Comments
 (0)