diff --git a/Common/CCDB/EventSelectionParams.cxx b/Common/CCDB/EventSelectionParams.cxx index 6e7e75d8d3b..55ff1d04af1 100644 --- a/Common/CCDB/EventSelectionParams.cxx +++ b/Common/CCDB/EventSelectionParams.cxx @@ -44,7 +44,7 @@ const char* selectionLabels[kNsel] = { "kNoV0C012vsTklBG", "kNoInconsistentVtx", "kNoPileupInMultBins", - "kNoPilupMV", + "kNoPileupMV", "kNoPileupTPC", "kIsTriggerTVX", "kIsINT1", @@ -54,7 +54,14 @@ const char* selectionLabels[kNsel] = { "kIsGoodZvtxFT0vsPV", "kIsVertexITSTPC", "kIsVertexTOFmatched", - "kIsVertexTRDmatched"}; + "kIsVertexTRDmatched", + "kNoHighOccupancyAgressive", + "kNoHighOccupancyStrict", + "kNoHighOccupancyMedium", + "kNoHighOccupancyRelaxed", + "kNoHighOccupancyGentle", + "kNoCollInTimeRangeStandard", + "kNoCollInTimeRangeNarrow"}; } // namespace o2::aod::evsel using namespace o2::aod::evsel; diff --git a/Common/CCDB/EventSelectionParams.h b/Common/CCDB/EventSelectionParams.h index af71bebb577..dfedfd1e12f 100644 --- a/Common/CCDB/EventSelectionParams.h +++ b/Common/CCDB/EventSelectionParams.h @@ -19,48 +19,55 @@ namespace o2::aod::evsel { // Event selection criteria enum EventSelectionFlags { - kIsBBV0A = 0, // cell-averaged time in V0A in beam-beam window - kIsBBV0C, // cell-averaged time in V0C in beam-beam window (for Run 2 only) - kIsBBFDA, // cell-averaged time in FDA (or AD in Run2) in beam-beam window - kIsBBFDC, // cell-averaged time in FDC (or AD in Run2) in beam-beam window - kIsBBT0A, // cell-averaged time in T0A in beam-beam window - kIsBBT0C, // cell-averaged time in T0C in beam-beam window - kNoBGV0A, // cell-averaged time in V0A in beam-gas window - kNoBGV0C, // cell-averaged time in V0C in beam-gas window (for Run 2 only) - kNoBGFDA, // cell-averaged time in FDA (AD in Run2) in beam-gas window - kNoBGFDC, // cell-averaged time in FDC (AD in Run2) in beam-gas window - kNoBGT0A, // cell-averaged time in T0A in beam-gas window - kNoBGT0C, // cell-averaged time in T0C in beam-gas window - kIsBBZNA, // time in common ZNA channel in beam-beam window - kIsBBZNC, // time in common ZNC channel in beam-beam window - kIsBBZAC, // time in ZNA and ZNC in beam-beam window - circular cut in ZNA-ZNC plane - kNoBGZNA, // time in common ZNA channel is outside of beam-gas window - kNoBGZNC, // time in common ZNC channel is outside of beam-gas window - kNoV0MOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline VOM correlation - kNoSPDOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline SPD correlation - kNoV0Casymmetry, // no beam-gas according to correlation of V0C multiplicities in V0C3 and V0C012 - kIsGoodTimeRange, // good time range - kNoIncompleteDAQ, // complete event according to DAQ flags - kNoTPCLaserWarmUp, // no TPC laser warm-up event (used in Run 1) - kNoTPCHVdip, // no TPC HV dip - kNoPileupFromSPD, // no pileup according to SPD vertexer - kNoV0PFPileup, // no out-of-bunch pileup according to V0 past-future info - kNoSPDClsVsTklBG, // no beam-gas according to cluster-vs-tracklet correlation - kNoV0C012vsTklBG, // no beam-gas according to V0C012-vs-tracklet correlation - kNoInconsistentVtx, // no inconsistency in SPD and Track vertices - kNoPileupInMultBins, // no pileup according to multiplicity-differential pileup checks - kNoPileupMV, // no pileup according to multi-vertexer - kNoPileupTPC, // no pileup in TPC - kIsTriggerTVX, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level - kIsINT1, // SPDGFO >= 1 || V0A || V0C - kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border - kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders - kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC - kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 - kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) - kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF - kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD - kNsel // counter + kIsBBV0A = 0, // cell-averaged time in V0A in beam-beam window + kIsBBV0C, // cell-averaged time in V0C in beam-beam window (for Run 2 only) + kIsBBFDA, // cell-averaged time in FDA (or AD in Run2) in beam-beam window + kIsBBFDC, // cell-averaged time in FDC (or AD in Run2) in beam-beam window + kIsBBT0A, // cell-averaged time in T0A in beam-beam window + kIsBBT0C, // cell-averaged time in T0C in beam-beam window + kNoBGV0A, // cell-averaged time in V0A in beam-gas window + kNoBGV0C, // cell-averaged time in V0C in beam-gas window (for Run 2 only) + kNoBGFDA, // cell-averaged time in FDA (AD in Run2) in beam-gas window + kNoBGFDC, // cell-averaged time in FDC (AD in Run2) in beam-gas window + kNoBGT0A, // cell-averaged time in T0A in beam-gas window + kNoBGT0C, // cell-averaged time in T0C in beam-gas window + kIsBBZNA, // time in common ZNA channel in beam-beam window + kIsBBZNC, // time in common ZNC channel in beam-beam window + kIsBBZAC, // time in ZNA and ZNC in beam-beam window - circular cut in ZNA-ZNC plane + kNoBGZNA, // time in common ZNA channel is outside of beam-gas window + kNoBGZNC, // time in common ZNC channel is outside of beam-gas window + kNoV0MOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline VOM correlation + kNoSPDOnVsOfPileup, // no out-of-bunch pileup according to online-vs-offline SPD correlation + kNoV0Casymmetry, // no beam-gas according to correlation of V0C multiplicities in V0C3 and V0C012 + kIsGoodTimeRange, // good time range + kNoIncompleteDAQ, // complete event according to DAQ flags + kNoTPCLaserWarmUp, // no TPC laser warm-up event (used in Run 1) + kNoTPCHVdip, // no TPC HV dip + kNoPileupFromSPD, // no pileup according to SPD vertexer + kNoV0PFPileup, // no out-of-bunch pileup according to V0 past-future info + kNoSPDClsVsTklBG, // no beam-gas according to cluster-vs-tracklet correlation + kNoV0C012vsTklBG, // no beam-gas according to V0C012-vs-tracklet correlation + kNoInconsistentVtx, // no inconsistency in SPD and Track vertices + kNoPileupInMultBins, // no pileup according to multiplicity-differential pileup checks + kNoPileupMV, // no pileup according to multi-vertexer + kNoPileupTPC, // no pileup in TPC + kIsTriggerTVX, // FT0 vertex (acceptable FT0C-FT0A time difference) at trigger level + kIsINT1, // SPDGFO >= 1 || V0A || V0C + kNoITSROFrameBorder, // bunch crossing is far from ITS RO Frame border + kNoTimeFrameBorder, // bunch crossing is far from Time Frame borders + kNoSameBunchPileup, // reject collisions in case of pileup with another collision in the same foundBC + kIsGoodZvtxFT0vsPV, // small difference between z-vertex from PV and from FT0 + kIsVertexITSTPC, // at least one ITS-TPC track (reject vertices built from ITS-only tracks) + kIsVertexTOFmatched, // at least one of vertex contributors is matched to TOF + kIsVertexTRDmatched, // at least one of vertex contributors is matched to TRD + kNoHighOccupancyAgressive, // no occupancy according to the agressive cuts + kNoHighOccupancyStrict, // no occupancy according to the strict cuts + kNoHighOccupancyMedium, // no occupancy according to the medium cuts + kNoHighOccupancyRelaxed, // no occupancy according to the relaxed cuts + kNoHighOccupancyGentle, // no occupancy according to the gentle cuts + kNoCollInTimeRangeStandard, // no collisions in specified time range + kNoCollInTimeRangeNarrow, // no collisions in specified time range (narrower than Standard) + kNsel // counter }; extern const char* selectionLabels[kNsel]; @@ -147,7 +154,7 @@ class EventSelectionParams int fITSROFrameStartBorderMargin = 10; // number of bcs to cut in the beginning of ITS readout frame int fITSROFrameEndBorderMargin = 20; // number of bcs to cut in the end of ITS readout frame - ClassDefNV(EventSelectionParams, 5) + ClassDefNV(EventSelectionParams, 6) }; #endif // COMMON_CCDB_EVENTSELECTIONPARAMS_H_ diff --git a/Common/TableProducer/eventSelection.cxx b/Common/TableProducer/eventSelection.cxx index abbb338bdf2..466c60cd7b6 100644 --- a/Common/TableProducer/eventSelection.cxx +++ b/Common/TableProducer/eventSelection.cxx @@ -424,7 +424,15 @@ struct EventSelectionTask { Configurable muonSelection{"muonSelection", 0, "0 - barrel, 1 - muon selection with pileup cuts, 2 - muon selection without pileup cuts"}; Configurable maxDiffZvtxFT0vsPV{"maxDiffZvtxFT0vsPV", 1., "maximum difference (in cm) between z-vertex from FT0 and PV"}; Configurable isMC{"isMC", 0, "0 - data, 1 - MC"}; - Configurable confTimeIntervalForOccupancyCalculation{"TimeIntervalForOccupancyCalculation", 100, "Time interval for TPC occupancy calculation, us"}; + // configurables for occupancy-based event selection + Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; + Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; + Configurable> confTimeBinsForOccupancyCalculation{"TimeBinsForOccupancyCalculation", {-40, -20, 0, 25, 50, 75, 100}, "Time bins for occupancy calculation and corresponding cuts (us)"}; + Configurable> confReferenceOccupanciesInTimeBins{"ReferenceOccupanciesInTimeBins", {3000, 1400, 750, 1000, 1750, 4000}, "Occupancy cuts in time bins (n tracks)"}; + Configurable confTimeRangeVetoOnCollStandard{"TimeRangeVetoOnCollStandard", 10, "Exclusion of a collision if there are other collisions nearby, +/- us"}; + Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 4, "Exclusion of a collision if there are other collisions nearby, +/- us"}; + Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; + Partition tracklets = (aod::track::trackType == static_cast(o2::aod::track::TrackTypeEnum::Run2Tracklet)); Service ccdb; @@ -460,6 +468,7 @@ struct EventSelectionTask { histos.add("hColCounterAll", "", kTH1D, {{1, 0., 1.}}); histos.add("hColCounterTVX", "", kTH1D, {{1, 0., 1.}}); histos.add("hColCounterAcc", "", kTH1D, {{1, 0., 1.}}); + // histos.add("hOccupancy", "", kTH1D, {{200, 0., 10000}}); } void process(aod::Collisions const& collisions) @@ -599,7 +608,7 @@ struct EventSelectionTask { int32_t foundFV0 = bc.foundFV0Id(); int32_t foundFDD = bc.foundFDDId(); int32_t foundZDC = bc.foundZDCId(); - evsel(bc.alias_raw(), bc.selection_raw(), kFALSE, kFALSE, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, 0); + evsel(bc.alias_raw(), bc.selection_raw(), kFALSE, kFALSE, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, -1); } return; } @@ -611,10 +620,11 @@ struct EventSelectionTask { std::vector vCollisionsPerBc(bcs.size(), 0); // counter of collisions per found bc for pileup checks // for the occupancy study - std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions - std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per found bc for occupancy studies - std::vector vIsFullInfoForOccupancy(cols.size(), 0); // info for occupancy in +/- windows is available (i.e. a given coll is not too close to the TF borders) - const double timeWinOccupancyCalcNS = confTimeIntervalForOccupancyCalculation * 1e3; // ns, corresponds to the typical TPC drift time + std::vector vFoundGlobalBC(cols.size(), 0); // global BCs for collisions + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vIsFullInfoForOccupancy(cols.size(), 0); // info for occupancy in +/- windows is available (i.e. a given coll is not too close to the TF borders) + const float timeWinOccupancyCalcMinNS = confTimeIntervalForOccupancyCalculationMin * 1e3; // ns + const float timeWinOccupancyCalcMaxNS = confTimeIntervalForOccupancyCalculationMax * 1e3; // ns // const double timeWinOccupancyExclusionRangeNS = confExclusionIntervalForOccupancyCalculation * 1e3; // ns const double bcNS = o2::constants::lhc::LHCBunchSpacingNS; @@ -690,20 +700,24 @@ struct EventSelectionTask { // check that this collision has full information inside the time window (taking into account TF borders) int64_t bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; - vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > timeWinOccupancyCalcNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcNS) ? true : false; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; } // save indices of collisions in time range for occupancy calculation std::vector> vCollsInTimeWin; + std::vector> vTimeDeltaForColls; // delta time wrt a given collision for (auto& col : cols) { int32_t colIndex = col.globalIndex(); std::vector vAssocToThisCol; + std::vector vCollsTimeDeltaWrtGivenColl; // protection against the TF borders if (!vIsFullInfoForOccupancy[colIndex]) { vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); continue; } + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; int64_t TFid = (foundGlobalBC - bcSOR) / nBCsPerTF; @@ -715,11 +729,13 @@ struct EventSelectionTask { int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; if (thisTFid != TFid) break; + float dt = (thisBC - foundGlobalBC) * bcNS; // ns // check if we are within the chosen time range - if ((foundGlobalBC - thisBC) * bcNS > timeWinOccupancyCalcNS) + if (dt < timeWinOccupancyCalcMinNS) break; vAssocToThisCol.push_back(minColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); minColIndex--; } // find all collisions in time window after the current one @@ -729,30 +745,90 @@ struct EventSelectionTask { int64_t thisTFid = (thisBC - bcSOR) / nBCsPerTF; if (thisTFid != TFid) break; - if ((thisBC - foundGlobalBC) * bcNS > timeWinOccupancyCalcNS) + float dt = (thisBC - foundGlobalBC) * bcNS; // ns + if (dt > timeWinOccupancyCalcMaxNS) break; vAssocToThisCol.push_back(maxColIndex); + vCollsTimeDeltaWrtGivenColl.push_back(dt); maxColIndex++; } vCollsInTimeWin.push_back(vAssocToThisCol); + vTimeDeltaForColls.push_back(vCollsTimeDeltaWrtGivenColl); } // perform the occupancy calculation in the pre-defined time window - std::vector vNumTracksITS567inTimeWin(cols.size(), 0); // counter of tracks per found bc for occupancy studies + std::vector vNumTracksITS567inFullTimeWin(cols.size(), 0); // counter of tracks in full time window for occupancy studies + std::vector vNoOccupAggressiveCuts(cols.size(), 0); // no occupancy according to the agressive cuts + std::vector vNoOccupStrictCuts(cols.size(), 0); // no occupancy according to the strict cuts + std::vector vNoOccupMediumCuts(cols.size(), 0); // no occupancy according to the medium cuts + std::vector vNoOccupRelaxedCuts(cols.size(), 0); // no occupancy according to the relaxed cuts + std::vector vNoOccupGentleCuts(cols.size(), 0); // no occupancy according to the gentle cuts + std::vector vNoCollInTimeRangeStandard(cols.size(), 0); // no collisions in a specified time range + std::vector vNoCollInTimeRangeNarrow(cols.size(), 0); // no collisions in a specified time range + + // time ranges for occupancy calculation + const int nTimeIntervals = 6; + const float coeffOccupInTimeBins[] = {0.2, 0.4, 0.6, 1.}; + for (auto& col : cols) { int32_t colIndex = col.globalIndex(); // protection against TF borders if (!vIsFullInfoForOccupancy[colIndex]) { - vNumTracksITS567inTimeWin[colIndex] = -1; // occupancy in undefined (too close to TF borders) + vNumTracksITS567inFullTimeWin[colIndex] = -1; // occupancy in undefined (too close to TF borders) continue; } std::vector vAssocToThisCol = vCollsInTimeWin[colIndex]; - int nITS567tracksInTimeWindow = 0; + std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; + int nITS567tracksInFullTimeWindow = 0; + int nITS567tracksInTimeBins[nTimeIntervals] = {}; + int nITS567tracksForVetoStandard = 0; // to veto events with nearby collisions + int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) for (int iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { int thisColIndex = vAssocToThisCol[iCol]; - nITS567tracksInTimeWindow += vTracksITS567perColl[thisColIndex]; + if (thisColIndex == colIndex) // skip the same collision + continue; + float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us + + if (!confUseWeightsForOccupancyVariable) { + nITS567tracksInFullTimeWindow += vTracksITS567perColl[thisColIndex]; + } else { + // weighted occupancy + float wOccup = 0; + if (dt >= -40 && dt < -5) // collisions in the past + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); + else if (dt >= -5 && dt < 15) // collisions near a given one + wOccup = 1; + else if (dt >= 15 && dt < 100) // collisions from the future + wOccup = -1. / 85 * dt + 20. / 17; + if (wOccup > 0) + nITS567tracksInFullTimeWindow += wOccup * vTracksITS567perColl[thisColIndex]; + } + + for (int iTime = 0; iTime < nTimeIntervals; iTime++) { + if (confTimeBinsForOccupancyCalculation->at(iTime) < dt && dt <= confTimeBinsForOccupancyCalculation->at(iTime + 1)) + nITS567tracksInTimeBins[iTime] += vTracksITS567perColl[thisColIndex]; + if (fabs(dt) < confTimeRangeVetoOnCollStandard) + nITS567tracksForVetoStandard += vTracksITS567perColl[thisColIndex]; + if (fabs(dt) < confTimeRangeVetoOnCollNarrow) + nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; + } } - vNumTracksITS567inTimeWin[colIndex] = nITS567tracksInTimeWindow - vTracksITS567perColl[colIndex]; // current collision is subtracted + vNumTracksITS567inFullTimeWin[colIndex] = nITS567tracksInFullTimeWindow; // occupancy (without a current collision) + + // decisions based on occupancies in time bins + bool decisions[4]; + for (int iCut = 0; iCut < 4; iCut++) { + decisions[iCut] = true; + for (int iTime = 0; iTime < nTimeIntervals; iTime++) + decisions[iCut] *= (nITS567tracksInTimeBins[iTime] < coeffOccupInTimeBins[iCut] * confReferenceOccupanciesInTimeBins->at(iTime)); + } + vNoOccupStrictCuts[colIndex] = decisions[0]; + vNoOccupMediumCuts[colIndex] = decisions[1]; + vNoOccupRelaxedCuts[colIndex] = decisions[2]; + vNoOccupGentleCuts[colIndex] = decisions[3]; + vNoOccupAggressiveCuts[colIndex] = ((nITS567tracksInTimeBins[0] < 300) && (nITS567tracksInTimeBins[1] == 0) && (nITS567tracksInTimeBins[2] == 0) && (nITS567tracksInTimeBins[3] == 0) && (nITS567tracksInTimeBins[4] < 200) && (nITS567tracksInTimeBins[5] < 400)); + vNoCollInTimeRangeStandard[colIndex] = (nITS567tracksForVetoStandard == 0); + vNoCollInTimeRangeNarrow[colIndex] = (nITS567tracksForVetoNarrow == 0); } for (auto& col : cols) { @@ -778,6 +854,15 @@ struct EventSelectionTask { selection |= vIsVertexTRDmatched[colIndex] ? BIT(kIsVertexTRDmatched) : 0; selection |= isGoodZvtxFT0vsPV ? BIT(kIsGoodZvtxFT0vsPV) : 0; + // selection bits based on occupancy pattern + selection |= vNoOccupAggressiveCuts[colIndex] ? BIT(kNoHighOccupancyAgressive) : 0; + selection |= vNoOccupStrictCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyStrict) : 0; + selection |= vNoOccupMediumCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyMedium) : 0; + selection |= vNoOccupRelaxedCuts[colIndex] && vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoHighOccupancyRelaxed) : 0; + selection |= vNoOccupGentleCuts[colIndex] && vNoCollInTimeRangeNarrow[colIndex] ? BIT(kNoHighOccupancyGentle) : 0; + selection |= vNoCollInTimeRangeStandard[colIndex] ? BIT(kNoCollInTimeRangeStandard) : 0; + selection |= vNoCollInTimeRangeNarrow[colIndex] ? BIT(kNoCollInTimeRangeNarrow) : 0; + // apply int7-like selections bool sel7 = 0; @@ -795,9 +880,10 @@ struct EventSelectionTask { histos.get(HIST("hColCounterAcc"))->Fill(Form("%d", bc.runNumber()), 1); } - int nTracksITS567inTimeWin = vNumTracksITS567inTimeWin[colIndex]; + int nTracksITS567inFullTimeWin = vNumTracksITS567inFullTimeWin[colIndex]; + // histos.get(HIST("hOccupancy"))->Fill(nTracksITS567inFullTimeWin); - evsel(alias, selection, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, nTracksITS567inTimeWin); + evsel(alias, selection, sel7, sel8, foundBC, foundFT0, foundFV0, foundFDD, foundZDC, nTracksITS567inFullTimeWin); } }