diff --git a/Common/Tools/EventSelectionModule.h b/Common/Tools/EventSelectionModule.h index 5a7c46d3cc7..972849f579a 100644 --- a/Common/Tools/EventSelectionModule.h +++ b/Common/Tools/EventSelectionModule.h @@ -111,22 +111,19 @@ struct evselConfigurables : o2::framework::ConfigurableGroup { o2::framework::Configurable confSigmaBCforHighPtTracks{"confSigmaBCforHighPtTracks", 4, "Custom sigma (in bcs) for collisions with high-pt tracks"}; // configurables for occupancy-based event selection - o2::framework::Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confTimeRangeVetoOnCollStandard{"TimeRangeVetoOnCollStandard", 10.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 2.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confFT0CamplCutVetoOnCollInTimeRange{"FT0CamplPerCollCutVetoOnCollInTimeRange", 8000, "Max allowed FT0C amplitude for each nearby collision in +/- time range"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confFT0CamplCutVetoOnCollInROF{"FT0CamplPerCollCutVetoOnCollInROF", 5000, "Max allowed FT0C amplitude for each nearby collision inside this ITS ROF"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confEpsilonVzDiffVetoInROF{"EpsilonVzDiffVetoInROF", 0.3, "Minumum distance to nearby collisions along z inside this ITS ROF, cm"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) - - // configurables for light-ion event selection (testing mode) - o2::framework::Configurable confLightIonsAlternativeBcMatching{"TestAlternativeBcMatching", 0, "0 - use standard matching, 1 - try alternative for light ions"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confLightIonsModifyTimeVetoOnNearbyColl{"TestModifyTimeVetoOnNearbyColl", 0, "0 - use standard time veto, 1 - modify time range"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confLightIonsVetoOnTRDinPast{"TestVetoOnTRDinPast", 0, "0 - use standard time veto, 1 - use veto on TRD in the past events"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confLightIonsNsigmaOnVzDiff{"TestVzDiffNsigma", 3.0, "+/- nSigma on vZ difference by FT0 and by tracks"}; // o2-linter: disable=name/configurable (temporary fix) - o2::framework::Configurable confLightIonsMarginVzDiff{"TestVzDiffMargin", 0.2, "margin for +/- nSigma on vZ difference by FT0 and by tracks"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeIntervalForOccupancyCalculationMin{"TimeIntervalForOccupancyCalculationMin", -40, "Min time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeIntervalForOccupancyCalculationMax{"TimeIntervalForOccupancyCalculationMax", 100, "Max time diff window for TPC occupancy calculation, us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeRangeVetoOnCollStrict{"TimeRangeVetoOnCollStrict", 10.0, "Exclusion of a collision if there are other collisions nearby, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confTimeRangeVetoOnCollNarrow{"TimeRangeVetoOnCollNarrow", 0.25, "Exclusion of a collision if other collisions nearby, to suppress bc-collision mis-associations, +/- us"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confFT0CamplCutVetoOnCollInTimeRange{"FT0CamplPerCollCutVetoOnCollInTimeRange", 8000, "Max allowed FT0C amplitude for each nearby collision in +/- time range"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confFT0CamplCutVetoOnCollInROF{"FT0CamplPerCollCutVetoOnCollInROF", 5000, "Max allowed FT0C amplitude for each nearby collision inside this ITS ROF"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confEpsilonVzDiffVetoInROF{"EpsilonVzDiffVetoInROF", 0.3, "Minumum distance to nearby collisions along z inside this ITS ROF, cm"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confUseWeightsForOccupancyVariable{"UseWeightsForOccupancyEstimator", 1, "Use or not the delta-time weights for the occupancy estimator"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confNumberOfOrbitsPerTF{"NumberOfOrbitsPerTF", -1, "Number of orbits per Time Frame. Take from CCDB if -1"}; // o2-linter: disable=name/configurable (temporary fix) + + // configurables for light-ion event selection + o2::framework::Configurable confLightIonsNsigmaOnVzDiff{"VzDiffNsigma", 3.0, "+/- nSigma on vZ difference by FT0 and by tracks"}; // o2-linter: disable=name/configurable (temporary fix) + o2::framework::Configurable confLightIonsMarginVzDiff{"VzDiffMargin", 0.2, "margin for +/- nSigma cut on vZ difference by FT0 and by tracks, cm"}; // o2-linter: disable=name/configurable (temporary fix) }; // luminosity configurables @@ -232,8 +229,6 @@ class BcSelectionModule bcSOR = runInfo.orbitSOR * nBCsPerOrbit; // duration of TF in bcs nBCsPerTF = bcselOpts.confNumberOfOrbitsPerTF < 0 ? runInfo.orbitsPerTF * nBCsPerOrbit : bcselOpts.confNumberOfOrbitsPerTF * nBCsPerOrbit; - if (strLPMProductionTag == "LHC25f3") // temporary workaround for MC production LHC25f3 anchored to Pb-Pb 2023 apass5 (to be removed once the info is in ccdb) - nBCsPerTF = 8 * nBCsPerOrbit; } // timestamp of the middle of the run used to access run-wise CCDB entries @@ -692,6 +687,20 @@ class EventSelectionModule return bestGlobalBC; } + float calcWeightForOccupancy(float dt) + { + float wOccup = 0; + if (dt >= -40 && dt < -5) // collisions in the past // o2-linter: disable=magic-number + wOccup = 1. / 1225 * (dt + 40) * (dt + 40); // o2-linter: disable=magic-number + else if (dt >= -5 && dt < 15) // collisions near a given one // o2-linter: disable=magic-number + wOccup = 1; + else if (dt >= 15 && dt < 40) // collisions from the future // o2-linter: disable=magic-number + wOccup = -0.4 / 25 * dt + 1.24; // o2-linter: disable=magic-number + else if (dt >= 40 && dt < 100) // collisions from the distant future // o2-linter: disable=magic-number + wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; // o2-linter: disable=magic-number + return wOccup; + } + // declaration of structs here // (N.B.: will be invisible to the outside, create your own copies) o2::common::eventselection::evselConfigurables evselOpts; @@ -753,20 +762,20 @@ class EventSelectionModule auto grplhcif = ccdb->template getSpecific("GLO/Config/GRPLHCIF", ts); bcPatternB = grplhcif->getBunchFilling().getBCPattern(); bcsPattern = grplhcif->getBunchFilling().getFilledBCs(); + if (runLightIons >= 0) { + for (uint32_t i = 0; i < bcsPattern.size(); i++) + LOGP(debug, "bcsPattern: i={} bc={}", i, bcsPattern.at(i)); + } // extract ITS ROF parameters auto alppar = ccdb->template getForTimeStamp>("ITS/Config/AlpideParam", ts); rofOffset = alppar->roFrameBiasInBC; rofLength = alppar->roFrameLengthInBC; LOGP(debug, "ITS ROF Offset={} ITS ROF Length={}", rofOffset, rofLength); - if (evselOpts.confLightIonsAlternativeBcMatching) { - for (unsigned long i = 0; i < bcsPattern.size(); i++) - LOGP(info, "bcsPattern: i={} bc={}", i, bcsPattern.at(i)); - } // special treatment of light ion runs if (lastRun >= 564356 && lastRun <= 564472) { - for (unsigned long i = 0; i < sizeof(runListLightIons) / sizeof(*runListLightIons); i++) { + for (uint32_t i = 0; i < sizeof(runListLightIons) / sizeof(*runListLightIons); i++) { if (runListLightIons[i] == lastRun) { runLightIons = lastRun; // extract parameterization for diff of vZ by FT0 vs by tracks @@ -919,15 +928,12 @@ class EventSelectionModule } return; } - std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies - std::vector vAmpFT0CperColl(cols.size(), 0); // amplitude FT0C per collision - std::vector vCollVz(cols.size(), 0); // vector with vZ positions for each collision - 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 = evselOpts.confTimeIntervalForOccupancyCalculationMin * 1e3; // ns - const float timeWinOccupancyCalcMaxNS = evselOpts.confTimeIntervalForOccupancyCalculationMax * 1e3; // ns - std::vector vIsVertexITSTPC(cols.size(), 0); // at least one of vertex contributors is ITS-TPC track - std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF - std::vector vIsVertexTRDmatched(cols.size(), 0); // at least one of vertex contributors is matched to TRD + std::vector vTracksITS567perColl(cols.size(), 0); // counter of tracks per collision for occupancy studies + std::vector vAmpFT0CperColl(cols.size(), 0); // amplitude FT0C per collision + std::vector vCollVz(cols.size(), 0); // vector with vZ positions for each collision + std::vector vIsVertexITSTPC(cols.size(), 0); // at least one of vertex contributors is ITS-TPC track + std::vector vIsVertexTOFmatched(cols.size(), 0); // at least one of vertex contributors is matched to TOF + std::vector vIsVertexTRDmatched(cols.size(), 0); // at least one of vertex contributors is matched to TRD std::vector vCollisionsPerBc(bcs.size(), 0); // counter of collisions per found bc for pileup checks std::vector vCollisionsPileupPerColl(cols.size(), 0); // counter of pileup in the same bc as a given collision @@ -950,19 +956,13 @@ class EventSelectionModule // first loop to match collisions to TVX, also extract other per-collision information for further use for (const auto& col : cols) { int32_t colIndex = col.globalIndex(); - auto bc = col.template bc_as>(); - vCollVz[colIndex] = col.posZ(); - int64_t globalBC = bc.globalBC(); - int bcInTF = (bc.globalBC() - bcSOR) % nBCsPerTF; - vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 300) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 4000 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; - - const auto& colPvTracks = pvTracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); vTrackTimesTOF.clear(); vTrackTimesTRDnoTOF.clear(); int nPvTracksTPCnoTOFnoTRD = 0; int nPvTracksHighPtTPCnoTOFnoTRD = 0; + const auto& colPvTracks = pvTracks.sliceByCached(aod::track::collisionId, col.globalIndex(), cache); float sumTime = 0, sumW = 0, sumHighPtTime = 0, sumHighPtW = 0; for (const auto& track : colPvTracks) { float trackTime = track.trackTime(); @@ -1002,14 +1002,17 @@ class EventSelectionModule vIsVertexTPC[colIndex] = nPvTracksTPCnoTOFnoTRD > 0; vIsVertexHighPtTPC[colIndex] = nPvTracksHighPtTPCnoTOFnoTRD > 0; + // collision-bc association, other bc-related routine + auto bc = col.template bc_as>(); + int64_t globalBC = bc.globalBC(); int64_t foundGlobalBC = 0; int32_t foundBCindex = -1; // alternative collision-BC matching (currently: test mode, the aim is to improve pileup rejection) - if (evselOpts.confLightIonsAlternativeBcMatching) { + if (runLightIons >= 0) { foundGlobalBC = globalBC; // find closest nominal bc in pattern - for (unsigned long i = 0; i < bcsPattern.size(); i++) { + for (uint32_t i = 0; i < bcsPattern.size(); i++) { int32_t localBC = globalBC % nBCsPerOrbit; int32_t bcFromPattern = bcsPattern.at(i); int64_t bcDiff = bcFromPattern - localBC; @@ -1046,7 +1049,7 @@ class EventSelectionModule if (bestGlobalBC > 0) { foundGlobalBC = bestGlobalBC; // find closest nominal bc in pattern - for (unsigned long j = 0; j < bcsPattern.size(); j++) { + for (uint32_t j = 0; j < bcsPattern.size(); j++) { int32_t bcFromPatternBest = bcsPattern.at(j); int64_t bcDiff = bcFromPatternBest - (bestGlobalBC % nBCsPerOrbit); if (std::abs(bcDiff) <= 20) { @@ -1104,10 +1107,10 @@ class EventSelectionModule mapGlobalBcVtxZ.erase(foundGlobalBC); } // alternative matching: looking for collisions with the same nominal BC - if (evselOpts.confLightIonsAlternativeBcMatching) { - for (unsigned long iCol = 0; iCol < vBCinPatternPerColl.size(); iCol++) { + if (runLightIons >= 0) { + for (uint32_t iCol = 0; iCol < vBCinPatternPerColl.size(); iCol++) { int64_t foundNominalBC = vBCinPatternPerColl[iCol]; - for (unsigned long jCol = 0; jCol < vBCinPatternPerColl.size(); jCol++) { + for (uint32_t jCol = 0; jCol < vBCinPatternPerColl.size(); jCol++) { int64_t foundNominalBC2 = vBCinPatternPerColl[jCol]; if (foundNominalBC2 == foundNominalBC) { vCollisionsPileupPerColl[iCol]++; @@ -1133,6 +1136,36 @@ class EventSelectionModule } } + // pre-loop for occupancy calculation + 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) + std::vector vIsCollAtROFborder(cols.size(), 0); // collision is close to ITS ROF border + std::vector vIsCollRejectedByTFborderCut(cols.size(), 0); // helper vector with + std::vector vCanHaveAssocCollsWithinLastDriftTime(cols.size(), 0); // to see if for some collisions in the occupancy calc (that are close to TF border) we will switch to FT0C based occupancy estimation + + const float timeWinOccupancyCalcMinNS = evselOpts.confTimeIntervalForOccupancyCalculationMin * 1e3; // ns + const float timeWinOccupancyCalcMaxNS = evselOpts.confTimeIntervalForOccupancyCalculationMax * 1e3; // ns + + for (const auto& col : cols) { + int32_t colIndex = col.globalIndex(); + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int bcInTF = (foundGlobalBC - bcSOR) % nBCsPerTF; + vIsFullInfoForOccupancy[colIndex] = ((bcInTF - 10) * bcNS > -timeWinOccupancyCalcMinNS) && ((nBCsPerTF - 10 - bcInTF) * bcNS > timeWinOccupancyCalcMaxNS) ? true : false; // 10 BCs is margin + + int32_t foundBC = vFoundBCindex[colIndex]; + auto bcselEntry = bcselbuffer[foundBC]; + // check if we are close to ROF or TF borders => N tracks are not reliable, but FT0 can be used for occupancy estimation + if (!bitcheck64(bcselEntry.selection, aod::evsel::kNoITSROFrameBorder)) { + vIsCollAtROFborder[colIndex] = true; + } + + if (!bitcheck64(bcselEntry.selection, aod::evsel::kNoTimeFrameBorder)) { + vIsCollRejectedByTFborderCut[colIndex] = true; + } + if (nBCsPerTF - bcInTF < 4000 * 2) { + vCanHaveAssocCollsWithinLastDriftTime[colIndex] = true; + } + } + // save indices of collisions for occupancy calculation (both in ROF and in time range) std::vector> vCollsInSameITSROF; std::vector> vCollsInPrevITSROF; @@ -1302,73 +1335,85 @@ class EventSelectionModule std::vector vCollsTimeDeltaWrtGivenColl = vTimeDeltaForColls[colIndex]; int nITS567tracksInFullTimeWindow = 0; float sumAmpFT0CInFullTimeWindow = 0; - int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrower range) + int nITS567tracksForVetoNarrow = 0; // to veto events with nearby collisions (narrow range) with per-collision multiplicity above threshold int nITS567tracksForVetoStrict = 0; // to veto events with nearby collisions - int nCollsWithFT0CAboveVetoStandard = 0; // to veto events with per-collision multiplicity above threshold + int nCollsWithFT0CAboveVetoStandard = 0; // to veto events with nearby collisions that have per-collision multiplicity above threshold + int colIndexFirstRejectedByTFborderCut = -1; for (uint32_t iCol = 0; iCol < vAssocToThisCol.size(); iCol++) { int thisColIndex = vAssocToThisCol[iCol]; + // check if we are close to TF borders => N ITS tracks is not reliable, and FT0C ampl will be used for occupancy estimation (a loop below) + if (vIsCollRejectedByTFborderCut[thisColIndex]) { + if (colIndexFirstRejectedByTFborderCut == -1) + colIndexFirstRejectedByTFborderCut = thisColIndex; + continue; + } float dt = vCollsTimeDeltaWrtGivenColl[iCol] / 1e3; // ns -> us float wOccup = 1.; if (evselOpts.confUseWeightsForOccupancyVariable) { // weighted occupancy - wOccup = 0; - if (dt >= -40 && dt < -5) // collisions in the past // o2-linter: disable=magic-number (to be checked by Igor) - wOccup = 1. / 1225 * (dt + 40) * (dt + 40); // o2-linter: disable=magic-number (to be checked by Igor) - else if (dt >= -5 && dt < 15) // collisions near a given one // o2-linter: disable=magic-number (to be checked by Igor) - wOccup = 1; - // else if (dt >= 15 && dt < 100) // collisions from the future - // wOccup = -1. / 85 * dt + 20. / 17; - else if (dt >= 15 && dt < 40) // collisions from the future // o2-linter: disable=magic-number (to be checked by Igor) - wOccup = -0.4 / 25 * dt + 1.24; // o2-linter: disable=magic-number (to be checked by Igor) - else if (dt >= 40 && dt < 100) // collisions from the distant future // o2-linter: disable=magic-number (to be checked by Igor) - wOccup = -0.4 / 60 * dt + 0.6 + 0.8 / 3; // o2-linter: disable=magic-number (to be checked by Igor) + wOccup = calcWeightForOccupancy(dt); } - nITS567tracksInFullTimeWindow += wOccup * vTracksITS567perColl[thisColIndex]; + + // check if we are close to ITS ROF borders => N ITS tracks is not reliable, and FT0C ampl can be used for occupancy estimation + // denominator for vAmpFT0CperColl is the approximate conversion factor b/n FT0C ampl and number of PV tracks after cuts + int nItsTracksAssocColl = !vIsCollAtROFborder[thisColIndex] ? vTracksITS567perColl[thisColIndex] : vAmpFT0CperColl[thisColIndex] / 10.; + + nITS567tracksInFullTimeWindow += wOccup * nItsTracksAssocColl; sumAmpFT0CInFullTimeWindow += wOccup * vAmpFT0CperColl[thisColIndex]; // counting tracks from other collisions in fixed time windows - if (!evselOpts.confLightIonsModifyTimeVetoOnNearbyColl) { - if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollNarrow) - nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; - if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollStandard) - nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex]; - } else { // special veto ranges (tests for light ion runs) - if (dt > -4.5 && dt < 2.5) // avoid TOF- and TRD-related structures, with 0.5 us margin - nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex]; - - if (!evselOpts.confLightIonsVetoOnTRDinPast) { - if (dt > -25.5 && dt < 2.5) // test effect from TRD triggers in the past - nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex]; - } else { - // counting TRD-matched vertices in a long time interval in the past - if (dt > -25.5 && dt < 2.5) - nITS567tracksForVetoStrict += vIsVertexTRDmatched[thisColIndex]; - } + if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollNarrow) + nITS567tracksForVetoNarrow += nItsTracksAssocColl; + if (std::fabs(dt) < evselOpts.confTimeRangeVetoOnCollStrict) + nITS567tracksForVetoStrict += nItsTracksAssocColl; + + // standard cut on other collisions vs delta-times: + // veto on high-mult collisions nearby, where artificial structures in the dt-occupancy plots are observed + if (dt > -4.0 && dt < 2.0 && vAmpFT0CperColl[thisColIndex] > evselOpts.confFT0CamplCutVetoOnCollInTimeRange) { // dt in us // o2-linter: disable=magic-number + nCollsWithFT0CAboveVetoStandard++; } + } - // standard cut on other collisions vs delta-times - const float driftV = 2.5; // drift velocity in cm/us, TPC drift_length / drift_time = 250 cm / 100 us - if (std::fabs(dt) < 2.0) { // us, complete veto on other collisions // o2-linter: disable=magic-number (to be checked by Igor) - nCollsWithFT0CAboveVetoStandard++; - } else if (dt > -4.0 && dt <= -2.0) { // us, strict veto to suppress fake ITS-TPC matches more // o2-linter: disable=magic-number (to be checked by Igor) - if (vAmpFT0CperColl[thisColIndex] > evselOpts.confFT0CamplCutVetoOnCollInTimeRange / 5) - nCollsWithFT0CAboveVetoStandard++; - } else if (std::fabs(dt) < 8 + std::fabs(vZ) / driftV) { // loose veto, 8 us corresponds to maximum possible |vZ|, which is ~20 cm // o2-linter: disable=magic-number (to be checked by Igor) - // counting number of other collisions with multiplicity above threshold - if (vAmpFT0CperColl[thisColIndex] > evselOpts.confFT0CamplCutVetoOnCollInTimeRange) - nCollsWithFT0CAboveVetoStandard++; + // if some associated collisions are close to TF border - take FT0C amplitude instead of nTracks + if (vCanHaveAssocCollsWithinLastDriftTime[colIndex] && colIndexFirstRejectedByTFborderCut >= 0) { + int64_t foundGlobalBC = vFoundGlobalBC[colIndex]; + int64_t tfId = (foundGlobalBC - bcSOR) / nBCsPerTF; + std::map::iterator it = mapGlobalBcWithTVX.find(vFoundGlobalBC[colIndexFirstRejectedByTFborderCut]); + while (it != mapGlobalBcWithTVX.end()) { + int64_t thisFoundGlobalBC = it->first; + int32_t thisFoundBCindex = it->second; + auto bc = bcs.iteratorAt(thisFoundBCindex); + int64_t thisTFid = (bc.globalBC() - bcSOR) / nBCsPerTF; + if (thisTFid != tfId) + break; + + float dt = (thisFoundGlobalBC - foundGlobalBC) * bcNS; // ns + if (dt > timeWinOccupancyCalcMaxNS) + break; + + float multT0C = -1; + if (bc.has_ft0()) { + multT0C = bc.ft0().sumAmpC(); + float wOccup = 1.; + if (evselOpts.confUseWeightsForOccupancyVariable) { + wOccup = calcWeightForOccupancy(dt / 1e3); // ns -> us + } + if (multT0C > 50.) // multiplicity in TVX is non-negligible, take it into occupancy calc + { + nITS567tracksInFullTimeWindow += wOccup * multT0C / 10.; + sumAmpFT0CInFullTimeWindow += wOccup * multT0C; + } + } + it++; } } + vNumTracksITS567inFullTimeWin[colIndex] = nITS567tracksInFullTimeWindow; // occupancy by a sum of number of ITS tracks (without a current collision) vSumAmpFT0CinFullTimeWin[colIndex] = sumAmpFT0CInFullTimeWindow; // occupancy by a sum of FT0C amplitudes (without a current collision) // occupancy flags based on nearby collisions vNoCollInTimeRangeNarrow[colIndex] = (nITS567tracksForVetoNarrow == 0); - if (!evselOpts.confLightIonsVetoOnTRDinPast) - vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0); - else - vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0 && nITS567tracksForVetoNarrow == 0); - - vNoHighMultCollInTimeRange[colIndex] = (nCollsWithFT0CAboveVetoStandard == 0); + vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0); + vNoHighMultCollInTimeRange[colIndex] = (nCollsWithFT0CAboveVetoStandard == 0 && nITS567tracksForVetoNarrow == 0); } for (const auto& col : cols) { @@ -1409,7 +1454,7 @@ class EventSelectionModule // copy selection decisions from bcsel table uint64_t selection = bcselbuffer[bc.globalIndex()].selection; - if (evselOpts.confLightIonsAlternativeBcMatching) + if (runLightIons >= 0) // for light ions, apply different condition to assign pileup flags selection |= vCollisionsPileupPerColl[colIndex] <= 1 ? BIT(aod::evsel::kNoSameBunchPileup) : 0; else selection |= vCollisionsPerBc[foundBC] <= 1 ? BIT(aod::evsel::kNoSameBunchPileup) : 0;