From 751ca083edcd37992494d9e0215039019a8ceabd Mon Sep 17 00:00:00 2001 From: mcoquet642 Date: Tue, 21 Jan 2025 13:39:30 +0100 Subject: [PATCH] Muon only option for filterpp --- PWGDQ/Tasks/filterPPwithAssociation.cxx | 459 +++++++++++++++--------- 1 file changed, 298 insertions(+), 161 deletions(-) diff --git a/PWGDQ/Tasks/filterPPwithAssociation.cxx b/PWGDQ/Tasks/filterPPwithAssociation.cxx index d2d374b06ef..b369b1061e9 100644 --- a/PWGDQ/Tasks/filterPPwithAssociation.cxx +++ b/PWGDQ/Tasks/filterPPwithAssociation.cxx @@ -747,145 +747,149 @@ struct DQFilterPPTask { VarManager::FillEvent(collision); // event properties could be needed for cuts or histogramming std::vector objCountersBarrel(fNBarrelCuts, 0); // init all counters to zero + uint32_t pairingMask = 0; // in order to know which of the selections actually require pairing + uint32_t pairingLS = 0; // used to set in which cut setting LS pairs will be analysed + uint32_t pairFilter = 0; // count the number of barrel tracks fulfilling each cut - for (auto trackAssoc : barrelAssocs) { - for (int i = 0; i < fNBarrelCuts; ++i) { - if (trackAssoc.isDQBarrelSelected() & (static_cast(1) << i)) { - objCountersBarrel[i] += 1; + if constexpr (static_cast(TTrackFillMap)) { + for (auto trackAssoc : barrelAssocs) { + for (int i = 0; i < fNBarrelCuts; ++i) { + if (trackAssoc.isDQBarrelSelected() & (static_cast(1) << i)) { + objCountersBarrel[i] += 1; + } } } - } - // check which selections require pairing - uint32_t pairingMask = 0; // in order to know which of the selections actually require pairing - for (int i = 0; i < fNBarrelCuts; i++) { - if (fBarrelRunPairing[i]) { - if (objCountersBarrel[i] > 1) { // pairing has to be enabled and at least two tracks are needed - pairingMask |= (static_cast(1) << i); + // check which selections require pairing + for (int i = 0; i < fNBarrelCuts; i++) { + if (fBarrelRunPairing[i]) { + if (objCountersBarrel[i] > 1) { // pairing has to be enabled and at least two tracks are needed + pairingMask |= (static_cast(1) << i); + } + objCountersBarrel[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - objCountersBarrel[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - } - // check which selection should use like sign (LS) (--/++) barrel track pairs - uint32_t pairingLS = 0; // used to set in which cut setting LS pairs will be analysed - TString barrelLSstr = fConfigFilterLsBarrelTracksPairs.value; - std::unique_ptr objArrayLS(barrelLSstr.Tokenize(",")); - for (int icut = 0; icut < fNBarrelCuts; icut++) { - TString objStr = objArrayLS->At(icut)->GetName(); - if (!objStr.CompareTo("true")) { - pairingLS |= (static_cast(1) << icut); + // check which selection should use like sign (LS) (--/++) barrel track pairs + TString barrelLSstr = fConfigFilterLsBarrelTracksPairs.value; + std::unique_ptr objArrayLS(barrelLSstr.Tokenize(",")); + for (int icut = 0; icut < fNBarrelCuts; icut++) { + TString objStr = objArrayLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + pairingLS |= (static_cast(1) << icut); + } } - } - - // run pairing if there is at least one selection that requires it - uint32_t pairFilter = 0; - if (pairingMask > 0) { - // run pairing on the collision grouped associations - for (auto& [a1, a2] : combinations(barrelAssocs, barrelAssocs)) { - // get the tracks from the index stored in the association - auto t1 = a1.template track_as(); - auto t2 = a2.template track_as(); + // run pairing if there is at least one selection that requires it + if (pairingMask > 0) { + // run pairing on the collision grouped associations + for (auto& [a1, a2] : combinations(barrelAssocs, barrelAssocs)) { - // check the pairing mask and that the tracks share a cut bit - pairFilter = pairingMask & a1.isDQBarrelSelected() & a2.isDQBarrelSelected(); - if (pairFilter == 0) { - continue; - } - // construct the pair and apply pair cuts - VarManager::FillPair(t1, t2); // compute pair quantities - for (int icut = 0; icut < fNBarrelCuts; icut++) { - // select like-sign pairs if trigger has set boolean true within fConfigFilterLsBarrelTracksPairs - if (!(pairingLS & (static_cast(1) << icut))) { - if (t1.sign() * t2.sign() > 0) { - continue; - } - } + // get the tracks from the index stored in the association + auto t1 = a1.template track_as(); + auto t2 = a2.template track_as(); - if (!(pairFilter & (static_cast(1) << icut))) { - continue; - } - if (!fBarrelPairCuts[icut].IsSelected(VarManager::fgValues)) { + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQBarrelSelected() & a2.isDQBarrelSelected(); + if (pairFilter == 0) { continue; } - objCountersBarrel[icut] += 1; // count the pair - if (fConfigQA) { // fill histograms if QA is enabled - fHistMan->FillHistClass(fBarrelPairHistNames[icut].Data(), VarManager::fgValues); + // construct the pair and apply pair cuts + VarManager::FillPair(t1, t2); // compute pair quantities + for (int icut = 0; icut < fNBarrelCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsBarrelTracksPairs + if (!(pairingLS & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } + + if (!(pairFilter & (static_cast(1) << icut))) { + continue; + } + if (!fBarrelPairCuts[icut].IsSelected(VarManager::fgValues)) { + continue; + } + objCountersBarrel[icut] += 1; // count the pair + if (fConfigQA) { // fill histograms if QA is enabled + fHistMan->FillHistClass(fBarrelPairHistNames[icut].Data(), VarManager::fgValues); + } } } } } std::vector objCountersMuon(fNMuonCuts, 0); // init all counters to zero - // count the number of muon-collision associations fulfilling each selection - for (auto muon : muonAssocs) { - for (int i = 0; i < fNMuonCuts; ++i) { - if (muon.isDQMuonSelected() & (static_cast(1) << i)) { - objCountersMuon[i] += 1; + if constexpr (static_cast(TMuonFillMap)) { + // count the number of muon-collision associations fulfilling each selection + for (auto muon : muonAssocs) { + for (int i = 0; i < fNMuonCuts; ++i) { + if (muon.isDQMuonSelected() & (static_cast(1) << i)) { + objCountersMuon[i] += 1; + } } } - } - // check which muon selections require pairing - pairingMask = 0; // reset the mask for the muons - for (int i = 0; i < fNMuonCuts; i++) { - if (fMuonRunPairing[i]) { // pairing has to be enabled and at least two tracks are needed - if (objCountersMuon[i] > 1) { - pairingMask |= (static_cast(1) << i); + // check which muon selections require pairing + pairingMask = 0; // reset the mask for the muons + for (int i = 0; i < fNMuonCuts; i++) { + if (fMuonRunPairing[i]) { // pairing has to be enabled and at least two tracks are needed + if (objCountersMuon[i] > 1) { + pairingMask |= (static_cast(1) << i); + } + objCountersMuon[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - objCountersMuon[i] = 0; // reset counters for selections where pairing is needed (count pairs instead) } - } - // check which selection should use like sign (LS) (--/++) muon track pairs - pairingLS = 0; // reset the decisions for muons - TString musonLSstr = fConfigFilterLsMuonsPairs.value; - std::unique_ptr objArrayMuonLS(musonLSstr.Tokenize(",")); - for (int icut = 0; icut < fNMuonCuts; icut++) { - TString objStr = objArrayMuonLS->At(icut)->GetName(); - if (!objStr.CompareTo("true")) { - pairingLS |= (static_cast(1) << icut); + // check which selection should use like sign (LS) (--/++) muon track pairs + pairingLS = 0; // reset the decisions for muons + TString musonLSstr = fConfigFilterLsMuonsPairs.value; + std::unique_ptr objArrayMuonLS(musonLSstr.Tokenize(",")); + for (int icut = 0; icut < fNMuonCuts; icut++) { + TString objStr = objArrayMuonLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + pairingLS |= (static_cast(1) << icut); + } } - } - // run pairing if there is at least one selection that requires it - pairFilter = 0; - if (pairingMask > 0) { - // pairing is done using the collision grouped muon associations - for (auto& [a1, a2] : combinations(muonAssocs, muonAssocs)) { + // run pairing if there is at least one selection that requires it + pairFilter = 0; + if (pairingMask > 0) { + // pairing is done using the collision grouped muon associations + for (auto& [a1, a2] : combinations(muonAssocs, muonAssocs)) { - // check the pairing mask and that the tracks share a cut bit - pairFilter = pairingMask & a1.isDQMuonSelected() & a2.isDQMuonSelected(); - if (pairFilter == 0) { - continue; - } + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQMuonSelected() & a2.isDQMuonSelected(); + if (pairFilter == 0) { + continue; + } - // get the real muon tracks - auto t1 = a1.template fwdtrack_as(); - auto t2 = a2.template fwdtrack_as(); + // get the real muon tracks + auto t1 = a1.template fwdtrack_as(); + auto t2 = a2.template fwdtrack_as(); - // construct the pair and apply cuts - VarManager::FillPair(t1, t2); // compute pair quantities - if (fPropMuon) { - VarManager::FillPairPropagateMuon(t1, t2, collision); - } - for (int icut = 0; icut < fNMuonCuts; icut++) { - // select like-sign pairs if trigger has set boolean true within fConfigFilterLsMuonsPairs - if (!(pairingLS & (static_cast(1) << icut))) { - if (t1.sign() * t2.sign() > 0) { + // construct the pair and apply cuts + VarManager::FillPair(t1, t2); // compute pair quantities + if (fPropMuon) { + VarManager::FillPairPropagateMuon(t1, t2, collision); + } + for (int icut = 0; icut < fNMuonCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsMuonsPairs + if (!(pairingLS & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } + if (!(pairFilter & (static_cast(1) << icut))) { continue; } - } - if (!(pairFilter & (static_cast(1) << icut))) { - continue; - } - if (!fMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { - continue; - } - objCountersMuon[icut] += 1; - if (fConfigQA) { - fHistMan->FillHistClass(fMuonPairHistNames[icut].Data(), VarManager::fgValues); + if (!fMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { + continue; + } + objCountersMuon[icut] += 1; + if (fConfigQA) { + fHistMan->FillHistClass(fMuonPairHistNames[icut].Data(), VarManager::fgValues); + } } } } @@ -893,77 +897,85 @@ struct DQFilterPPTask { // electron-muon pair std::vector objCountersElectronMuon(fNElectronMuonCuts, 0); // init all counters to zero - pairingMask = 0; - for (auto& [trackAssoc, muon] : combinations(barrelAssocs, muonAssocs)) { - for (int i = 0; i < fNElectronMuonCuts; ++i) { - if (trackAssoc.isDQEMuBarrelSelected() & muon.isDQEMuMuonSelected() & (static_cast(1) << i)) { - if (fElectronMuonRunPairing[i]) { - pairingMask |= (static_cast(1) << i); + if constexpr (static_cast(TTrackFillMap) && static_cast(TMuonFillMap)) { + pairingMask = 0; + for (auto& [trackAssoc, muon] : combinations(barrelAssocs, muonAssocs)) { + for (int i = 0; i < fNElectronMuonCuts; ++i) { + if (trackAssoc.isDQEMuBarrelSelected() & muon.isDQEMuMuonSelected() & (static_cast(1) << i)) { + if (fElectronMuonRunPairing[i]) { + pairingMask |= (static_cast(1) << i); + } } } } - } - // check which selection should use like sign (LS) (--/++) muon track pairs - pairingLS = 0; // reset the decisions for electron-muons - TString electronMuonLSstr = fConfigFilterLsElectronMuonsPairs.value; - std::unique_ptr objArrayElectronMuonLS(electronMuonLSstr.Tokenize(",")); - for (int icut = 0; icut < fNElectronMuonCuts; icut++) { - TString objStr = objArrayElectronMuonLS->At(icut)->GetName(); - if (!objStr.CompareTo("true")) { - pairingLS |= (static_cast(1) << icut); + // check which selection should use like sign (LS) (--/++) muon track pairs + pairingLS = 0; // reset the decisions for electron-muons + TString electronMuonLSstr = fConfigFilterLsElectronMuonsPairs.value; + std::unique_ptr objArrayElectronMuonLS(electronMuonLSstr.Tokenize(",")); + for (int icut = 0; icut < fNElectronMuonCuts; icut++) { + TString objStr = objArrayElectronMuonLS->At(icut)->GetName(); + if (!objStr.CompareTo("true")) { + pairingLS |= (static_cast(1) << icut); + } } - } - // run pairing if there is at least one selection that requires it - pairFilter = 0; - if (pairingMask > 0) { - // pairing is done using the collision grouped electron and muon associations - for (auto& [a1, a2] : combinations(barrelAssocs, muonAssocs)) { - // check the pairing mask and that the tracks share a cut bit - pairFilter = pairingMask & a1.isDQEMuBarrelSelected() & a2.isDQEMuMuonSelected(); - if (pairFilter == 0) { - continue; - } - // get the real electron and muon tracks - auto t1 = a1.template track_as(); - auto t2 = a2.template fwdtrack_as(); - // construct the pair and apply cuts - VarManager::FillPair(t1, t2); // compute pair quantities - for (int icut = 0; icut < fNElectronMuonCuts; icut++) { - // select like-sign pairs if trigger has set boolean true within fConfigFilterLsElectronMuonsPairs - if (!(pairingLS & (static_cast(1) << icut))) { - if (t1.sign() * t2.sign() > 0) { - continue; - } - } - if (!(pairFilter & (static_cast(1) << icut))) { - continue; - } - if (!fElectronMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { + // run pairing if there is at least one selection that requires it + pairFilter = 0; + if (pairingMask > 0) { + // pairing is done using the collision grouped electron and muon associations + for (auto& [a1, a2] : combinations(barrelAssocs, muonAssocs)) { + // check the pairing mask and that the tracks share a cut bit + pairFilter = pairingMask & a1.isDQEMuBarrelSelected() & a2.isDQEMuMuonSelected(); + if (pairFilter == 0) { continue; } - objCountersElectronMuon[icut] += 1; - if (fConfigQA) { - fHistMan->FillHistClass(fElectronMuonPairHistNames[icut].Data(), VarManager::fgValues); + // get the real electron and muon tracks + auto t1 = a1.template track_as(); + auto t2 = a2.template fwdtrack_as(); + // construct the pair and apply cuts + VarManager::FillPair(t1, t2); // compute pair quantities + for (int icut = 0; icut < fNElectronMuonCuts; icut++) { + // select like-sign pairs if trigger has set boolean true within fConfigFilterLsElectronMuonsPairs + if (!(pairingLS & (static_cast(1) << icut))) { + if (t1.sign() * t2.sign() > 0) { + continue; + } + } + if (!(pairFilter & (static_cast(1) << icut))) { + continue; + } + if (!fElectronMuonPairCuts[icut].IsSelected(VarManager::fgValues)) { + continue; + } + objCountersElectronMuon[icut] += 1; + if (fConfigQA) { + fHistMan->FillHistClass(fElectronMuonPairHistNames[icut].Data(), VarManager::fgValues); + } } } } } // compute the decisions and publish uint64_t filter = 0; - for (int i = 0; i < fNBarrelCuts; i++) { - if (objCountersBarrel[i] >= fBarrelNreqObjs[i]) { - filter |= (static_cast(1) << i); + if constexpr (static_cast(TTrackFillMap)) { + for (int i = 0; i < fNBarrelCuts; i++) { + if (objCountersBarrel[i] >= fBarrelNreqObjs[i]) { + filter |= (static_cast(1) << i); + } } } - for (int i = 0; i < fNMuonCuts; i++) { - if (objCountersMuon[i] >= fMuonNreqObjs[i]) { - filter |= (static_cast(1) << (i + fNBarrelCuts)); + if constexpr (static_cast(TMuonFillMap)) { + for (int i = 0; i < fNMuonCuts; i++) { + if (objCountersMuon[i] >= fMuonNreqObjs[i]) { + filter |= (static_cast(1) << (i + fNBarrelCuts)); + } } } - for (int i = 0; i < fNElectronMuonCuts; i++) { - if (objCountersElectronMuon[i] >= fElectronMuonNreqObjs[i]) { - filter |= (static_cast(1) << (i + fNBarrelCuts + fNMuonCuts)); + if constexpr (static_cast(TTrackFillMap) && static_cast(TMuonFillMap)) { + for (int i = 0; i < fNElectronMuonCuts; i++) { + if (objCountersElectronMuon[i] >= fElectronMuonNreqObjs[i]) { + filter |= (static_cast(1) << (i + fNBarrelCuts + fNMuonCuts)); + } } } return filter; @@ -1146,6 +1158,130 @@ struct DQFilterPPTask { cout << "-------------------- In this TF, eventsFired / totalTriggered :: " << eventsFired << "/" << totalEventsTriggered << endl; } + void processFilterMuonPP(MyEventsSelected const& collisions, + aod::BCsWithTimestamps const& bcs, + MyMuons const& muons, + MyMuonsAssocSelected const& muonAssocs) + { + fFiltersMap.clear(); + fCEFPfilters.clear(); + + cout << "------------------- filterPP, n assocs muon :: " << muonAssocs.size() << endl; + + uint64_t muonMask = 0; + for (int i = 0; i < fNMuonCuts; i++) { + muonMask |= (static_cast(1) << i); + } + // Loop over collisions + // int event = 0; + int eventsFired = 0; + for (const auto& collision : collisions) { + // skip those that do not pass our selection + if (!collision.isDQEventSelected()) { + // event++; + continue; + } + // group the muons for this collision + auto groupedMuonIndices = muonAssocs.sliceBy(muonIndicesPerCollision, collision.globalIndex()); + + uint64_t filter = 0; + // if there is at least one track or muon, run the filtering function and compute triggers + if (groupedMuonIndices.size() > 0) { + filter = runFilterPP(collision, bcs, nullptr, muons, nullptr, groupedMuonIndices); + } + if (filter == 0) { + // event++; + continue; + } + eventsFired++; + // compute the CEPF decisions (this is done in a spacial setup with exactly kNTriggersDQ configured triggers) + std::vector decisions(kNTriggersDQ, false); // event decisions to be transmitted to CEFP + for (int i = 0; i < fNMuonCuts; i++) { + if (filter & (static_cast(1) << i)) { + if (i < kNTriggersDQ) { + decisions[i] = true; + } + } + } + // if this collision fired at least one input, add it to the map, or if it is there already, update the decisions with a logical OR + // This may happen in the case when some collisions beyond the iterator are added because they contain ambiguous tracks fired on by another collision + if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { + fFiltersMap[collision.globalIndex()] = filter; + fCEFPfilters[collision.globalIndex()] = decisions; + } else { // this collision was already fired, possible via collision - track association; add as an OR the new decisions + fFiltersMap[collision.globalIndex()] |= filter; + for (int i = 0; i < kNTriggersDQ; i++) { + if (decisions[i]) { + fCEFPfilters[collision.globalIndex()][i] = true; + } + } + } + + // Do the same for muons + if (filter & muonMask) { + for (auto& a : groupedMuonIndices) { + auto t = a.template fwdtrack_as(); + if (!t.has_collision()) { + continue; + } + auto tColl = t.collisionId(); + if (tColl == collision.globalIndex()) { // track from this collision, nothing to do + continue; + } else { + if (fFiltersMap.find(tColl) == fFiltersMap.end()) { + fFiltersMap[tColl] = filter; + fCEFPfilters[tColl] = decisions; + } else { // this collision was already fired, possible via collision - track association; add as an OR the new decisions + fFiltersMap[tColl] |= filter; + for (int i = 0; i < kNTriggersDQ; i++) { + if (decisions[i]) { + fCEFPfilters[tColl][i] = true; + } + } + } + } + } + } + // event++; + } + + // At this point, we have all the non-null decisions for all collisions. + // we loop again over collisions and create the decision tables + // NOTE: For the CEFP decisions, decisions are placed in a vector of bool in an ordered way: + // start with all configured barrel selections and then continue with those from muons + // The configured order has to be in sync with that implemented in the cefp task and can be done + // by preparing a dedicated json configuration file + int totalEventsTriggered = 0; + for (const auto& collision : collisions) { + fStats->Fill(-2.0); + if (!collision.isDQEventSelected()) { + eventFilter(0); + dqtable(false, false, false, false, false, false, false); + // dqtable(false, false, false, false, false, false, false, false); // the ElectronMuon trigger is not available now + continue; + } + fStats->Fill(-1.0); + + if (fFiltersMap.find(collision.globalIndex()) == fFiltersMap.end()) { + eventFilter(0); + dqtable(false, false, false, false, false, false, false); + // dqtable(false, false, false, false, false, false, false, false); // the ElectronMuon trigger is not available now + } else { + totalEventsTriggered++; + for (int i = 0; i < fNMuonCuts; i++) { + if (fFiltersMap[collision.globalIndex()] & (static_cast(1) << i)) + fStats->Fill(static_cast(i)); + } + eventFilter(fFiltersMap[collision.globalIndex()]); + auto dqDecisions = fCEFPfilters[collision.globalIndex()]; + dqtable(dqDecisions[0], dqDecisions[1], dqDecisions[2], dqDecisions[3], dqDecisions[4], dqDecisions[5], dqDecisions[6]); + // dqtable(dqDecisions[0], dqDecisions[1], dqDecisions[2], dqDecisions[3], dqDecisions[4], dqDecisions[5], dqDecisions[6], dqDecisions[7]); // the ElectronMuon trigger is not available now + } + } + + cout << "-------------------- In this TF, eventsFired / totalTriggered :: " << eventsFired << "/" << totalEventsTriggered << endl; + } + // TODO: dummy function for the case when no process function is enabled void processDummy(MyEvents&) { @@ -1153,6 +1289,7 @@ struct DQFilterPPTask { } PROCESS_SWITCH(DQFilterPPTask, processFilterPP, "Run filter task", false); + PROCESS_SWITCH(DQFilterPPTask, processFilterMuonPP, "Run filter task for muons only", false); PROCESS_SWITCH(DQFilterPPTask, processDummy, "Dummy function", false); };