@@ -106,6 +106,13 @@ struct evselConfigurables : o2::framework::ConfigurableGroup {
106106 o2::framework::Configurable<float > confEpsilonVzDiffVetoInROF{" EpsilonVzDiffVetoInROF" , 0.3 , " Minumum distance to nearby collisions along z inside this ITS ROF, cm" }; // o2-linter: disable=name/configurable (temporary fix)
107107 o2::framework::Configurable<bool > confUseWeightsForOccupancyVariable{" UseWeightsForOccupancyEstimator" , 1 , " Use or not the delta-time weights for the occupancy estimator" }; // o2-linter: disable=name/configurable (temporary fix)
108108 o2::framework::Configurable<int > confNumberOfOrbitsPerTF{" NumberOfOrbitsPerTF" , -1 , " Number of orbits per Time Frame. Take from CCDB if -1" }; // o2-linter: disable=name/configurable (temporary fix)
109+
110+ // configurables for light-ion event selection (testing mode)
111+ o2::framework::Configurable<int > confLightIonsAlternativeBcMatching{" TestAlternativeBcMatching" , 0 , " 0 - use standard matching, 1 - try alternative for light ions" }; // o2-linter: disable=name/configurable (temporary fix)
112+ o2::framework::Configurable<int > confLightIonsModifyTimeVetoOnNearbyColl{" TestModifyTimeVetoOnNearbyColl" , 0 , " 0 - use standard time veto, 1 - modify time range" }; // o2-linter: disable=name/configurable (temporary fix)
113+ o2::framework::Configurable<int > confLightIonsVetoOnTRDinPast{" TestVetoOnTRDinPast" , 0 , " 0 - use standard time veto, 1 - use veto on TRD in the past events" }; // o2-linter: disable=name/configurable (temporary fix)
114+ o2::framework::Configurable<float > confLightIonsNsigmaOnVzDiff{" TestVzDiffNsigma" , 3.0 , " +/- nSigma on vZ difference by FT0 and by tracks" }; // o2-linter: disable=name/configurable (temporary fix)
115+ o2::framework::Configurable<float > confLightIonsMarginVzDiff{" TestVzDiffMargin" , 0.2 , " margin for +/- nSigma on vZ difference by FT0 and by tracks" }; // o2-linter: disable=name/configurable (temporary fix)
109116};
110117
111118// luminosity configurables
@@ -602,13 +609,20 @@ class EventSelectionModule
602609 int run3min = 500000 ;
603610 int lastRun = -1 ; // last run number (needed to access ccdb only if run!=lastRun)
604611 std::bitset<nBCsPerOrbit> bcPatternB; // bc pattern of colliding bunches
612+ std::vector<int > bcsPattern; // pattern of colliding BCs
605613
606614 int64_t bcSOR = -1 ; // global bc of the start of the first orbit
607615 int64_t nBCsPerTF = -1 ; // duration of TF in bcs, should be 128*3564 or 32*3564
608616 int rofOffset = -1 ; // ITS ROF offset, in bc
609617 int rofLength = -1 ; // ITS ROF length, in bc
610618 std::string strLPMProductionTag = " " ; // MC production tag to be retrieved from AO2D metadata
611619
620+ // temporary (?) parameterizations for light ion runs
621+ int runLightIons = -1 ;
622+ int runListLightIons[11 ] = {564356 , 564359 , 564373 , 564374 , 564387 , 564400 , 564414 , 564430 , 564445 , 564468 , 564472 };
623+ std::vector<float > diffVzParMean; // parameterization for mean of diff vZ by FT0 vs by tracks
624+ std::vector<float > diffVzParSigma; // parameterization for stddev of diff vZ by FT0 vs by tracks
625+
612626 int32_t findClosest (int64_t globalBC, std::map<int64_t , int32_t >& bcs)
613627 {
614628 auto it = bcs.lower_bound (globalBC);
@@ -718,12 +732,38 @@ class EventSelectionModule
718732 // avoids crash related to specific run number
719733 auto grplhcif = ccdb->template getSpecific <o2::parameters::GRPLHCIFData>(" GLO/Config/GRPLHCIF" , ts);
720734 bcPatternB = grplhcif->getBunchFilling ().getBCPattern ();
735+ bcsPattern = grplhcif->getBunchFilling ().getFilledBCs ();
721736
722737 // extract ITS ROF parameters
723738 auto alppar = ccdb->template getForTimeStamp <o2::itsmft::DPLAlpideParam<0 >>(" ITS/Config/AlpideParam" , ts);
724739 rofOffset = alppar->roFrameBiasInBC ;
725740 rofLength = alppar->roFrameLengthInBC ;
726741 LOGP (debug, " ITS ROF Offset={} ITS ROF Length={}" , rofOffset, rofLength);
742+ if (evselOpts.confLightIonsAlternativeBcMatching ) {
743+ for (unsigned long i = 0 ; i < bcsPattern.size (); i++)
744+ LOGP (info, " bcsPattern: i={} bc={}" , i, bcsPattern.at (i));
745+ }
746+
747+ // special treatment of light ion runs
748+ if (lastRun >= 564356 && lastRun <= 564472 ) {
749+ for (unsigned long i = 0 ; i < sizeof (runListLightIons) / sizeof (*runListLightIons); i++) {
750+ if (runListLightIons[i] == lastRun) {
751+ runLightIons = lastRun;
752+ // extract parameterization for diff of vZ by FT0 vs by tracks
753+ auto parMeans = ccdb->template getForTimeStamp <std::vector<float >>(" Users/a/altsybee/diffVzCollVsFTOmeanPar" , ts);
754+ auto parSigmas = ccdb->template getForTimeStamp <std::vector<float >>(" Users/a/altsybee/diffVzCollVsFTOsigmaPar" , ts);
755+ diffVzParMean = *parMeans;
756+ diffVzParSigma = *parSigmas;
757+ LOGP (info, " >>> special treatment for diffVz for light ion run {}" , runLightIons);
758+ for (int i = 0 ; i < 5 ; i++)
759+ LOGP (info, " mean par {} = {}" , i, diffVzParMean[i]);
760+ for (int i = 0 ; i < 5 ; i++)
761+ LOGP (info, " sigma par {} = {}" , i, diffVzParSigma[i]);
762+ break ;
763+ }
764+ }
765+ }
766+
727767 } // if run != lastRun
728768 return true ;
729769 }
@@ -824,13 +864,19 @@ class EventSelectionModule
824864 // create maps from globalBC to bc index for TVX-fired bcs
825865 // to be used for closest TVX searches
826866 std::map<int64_t , int32_t > mapGlobalBcWithTVX;
867+ std::map<int64_t , int32_t > mapGlobalBcWithOrInFT0;
827868 std::map<int64_t , float > mapGlobalBcVtxZ;
828869 for (const auto & bc : bcs) {
829870 int64_t globalBC = bc.globalBC ();
830871 // skip non-colliding bcs for data and anchored runs
831872 if (run >= run3min && bcPatternB[globalBC % nBCsPerOrbit] == 0 ) {
832873 continue ;
833874 }
875+
876+ if (bc.has_ft0 ()) {
877+ mapGlobalBcWithOrInFT0[globalBC] = bc.globalIndex ();
878+ }
879+
834880 auto selection = bcselbuffer[bc.globalIndex ()].selection ;
835881 if (bitcheck64 (selection, aod::evsel::kIsTriggerTVX )) {
836882 mapGlobalBcWithTVX[globalBC] = bc.globalIndex ();
@@ -863,9 +909,11 @@ class EventSelectionModule
863909 std::vector<bool > vIsVertexTOFmatched (cols.size (), 0 ); // at least one of vertex contributors is matched to TOF
864910 std::vector<bool > vIsVertexTRDmatched (cols.size (), 0 ); // at least one of vertex contributors is matched to TRD
865911
866- std::vector<int > vCollisionsPerBc (bcs.size (), 0 ); // counter of collisions per found bc for pileup checks
867- std::vector<int > vFoundBCindex (cols.size (), -1 ); // indices of found bcs
868- std::vector<int64_t > vFoundGlobalBC (cols.size (), 0 ); // global BCs for collisions
912+ std::vector<int > vCollisionsPerBc (bcs.size (), 0 ); // counter of collisions per found bc for pileup checks
913+ std::vector<int > vCollisionsPileupPerColl (cols.size (), 0 ); // counter of pileup in the same bc as a given collision
914+ std::vector<int64_t > vBCinPatternPerColl (cols.size (), 0 ); // found nominal BCs for collisions
915+ std::vector<int > vFoundBCindex (cols.size (), -1 ); // indices of found bcs
916+ std::vector<int64_t > vFoundGlobalBC (cols.size (), 0 ); // global BCs for collisions
869917
870918 std::vector<bool > vIsVertexTOF (cols.size (), 0 );
871919 std::vector<bool > vIsVertexTRD (cols.size (), 0 );
@@ -937,7 +985,67 @@ class EventSelectionModule
937985 int64_t foundGlobalBC = 0 ;
938986 int32_t foundBCindex = -1 ;
939987
940- if (nPvTracksTOF > 0 ) {
988+ // alternative collision-BC matching (currently: test mode, the aim is to improve pileup rejection)
989+ if (evselOpts.confLightIonsAlternativeBcMatching ) {
990+ foundGlobalBC = globalBC;
991+ // find closest nominal bc in pattern
992+ for (unsigned long i = 0 ; i < bcsPattern.size (); i++) {
993+ int32_t localBC = globalBC % nBCsPerOrbit;
994+ int32_t bcFromPattern = bcsPattern.at (i);
995+ int64_t bcDiff = bcFromPattern - localBC;
996+ if (std::abs (bcDiff) <= 20 ) {
997+ foundGlobalBC = (globalBC / nBCsPerOrbit) * nBCsPerOrbit + bcFromPattern;
998+ break ; // the bc in pattern is found
999+ }
1000+ }
1001+
1002+ // matched with TOF --> precise time, match to TVX, but keep the nominal foundGlobalBC from pattern
1003+ if (vIsVertexTOFmatched[colIndex]) {
1004+ std::map<int64_t , int32_t >::iterator it = mapGlobalBcWithTVX.find (foundGlobalBC);
1005+ if (it != mapGlobalBcWithTVX.end ()) {
1006+ foundBCindex = it->second ; // TVX at foundGlobalBC is found
1007+ } else { // check if TVX is in nearby bcs
1008+ it = mapGlobalBcWithTVX.find (foundGlobalBC + 1 ); // next bc
1009+ if (it != mapGlobalBcWithTVX.end ()) {
1010+ // foundGlobalBC += 1;
1011+ foundBCindex = it->second ;
1012+ } else {
1013+ it = mapGlobalBcWithTVX.find (foundGlobalBC - 1 ); // previous bc
1014+ if (it != mapGlobalBcWithTVX.end ()) {
1015+ // foundGlobalBC -= 1;
1016+ foundBCindex = it->second ;
1017+ } else {
1018+ foundBCindex = bc.globalIndex (); // keep original BC index
1019+ }
1020+ }
1021+ }
1022+ } // end of if TOF-matched vertex
1023+ else { // for non-TOF and low-mult vertices, consider nearby nominal bcs
1024+ int64_t meanBC = globalBC + TMath::Nint (sumHighPtTime / sumHighPtW / bcNS);
1025+ int64_t bestGlobalBC = findBestGlobalBC (meanBC, evselOpts.confSigmaBCforHighPtTracks , vNcontributors[colIndex], col.posZ (), mapGlobalBcVtxZ);
1026+ if (bestGlobalBC > 0 ) {
1027+ foundGlobalBC = bestGlobalBC;
1028+ // find closest nominal bc in pattern
1029+ for (unsigned long j = 0 ; j < bcsPattern.size (); j++) {
1030+ int32_t bcFromPatternBest = bcsPattern.at (j);
1031+ int64_t bcDiff = bcFromPatternBest - (bestGlobalBC % nBCsPerOrbit);
1032+ if (std::abs (bcDiff) <= 20 ) {
1033+ foundGlobalBC = (bestGlobalBC / nBCsPerOrbit) * nBCsPerOrbit + bcFromPatternBest;
1034+ break ; // the bc in pattern is found
1035+ }
1036+ }
1037+ foundBCindex = mapGlobalBcWithTVX[bestGlobalBC];
1038+ } else { // failed to find a proper TVX with small vZ difference
1039+ foundBCindex = bc.globalIndex (); // keep original BC index
1040+ }
1041+ } // end of non-TOF matched vertices
1042+ // sanitity check: if BC was not found
1043+ if (foundBCindex == -1 ) {
1044+ foundBCindex = bc.globalIndex ();
1045+ }
1046+ vBCinPatternPerColl[colIndex] = foundGlobalBC;
1047+ // end of alternative coll-BC matching (test)
1048+ } else if (nPvTracksTOF > 0 ) { // "standard matching":
9411049 // for collisions with TOF tracks:
9421050 // take bc corresponding to TOF track with median time
9431051 int64_t tofGlobalBC = globalBC + TMath::Nint (getMedian (vTrackTimesTOF) / bcNS);
@@ -975,23 +1083,34 @@ class EventSelectionModule
9751083 if (foundBCindex >= 0 )
9761084 mapGlobalBcVtxZ.erase (foundGlobalBC);
9771085 }
978-
979- // second loop to match remaining low-pt TPCnoTOFnoTRD collisions
980- for (const auto & col : cols) {
981- int32_t colIndex = col.globalIndex ();
982- if (vIsVertexTPC[colIndex] > 0 && vIsVertexTOF[colIndex] == 0 && vIsVertexHighPtTPC[colIndex] == 0 ) {
983- float weightedTime = vWeightedTimesTPCnoTOFnoTRD[colIndex];
984- float weightedSigma = vWeightedSigmaTPCnoTOFnoTRD[colIndex];
985- auto bc = col.template bc_as <soa::Join<aod::BCs, aod::Run3MatchedToBCSparse>>();
986- int64_t globalBC = bc.globalBC ();
987- int64_t meanBC = globalBC + TMath::Nint (weightedTime / bcNS);
988- int64_t sigmaBC = TMath::CeilNint (weightedSigma / bcNS);
989- int64_t bestGlobalBC = findBestGlobalBC (meanBC, sigmaBC, vNcontributors[colIndex], col.posZ (), mapGlobalBcVtxZ);
990- vFoundGlobalBC[colIndex] = bestGlobalBC > 0 ? bestGlobalBC : globalBC;
991- vFoundBCindex[colIndex] = bestGlobalBC > 0 ? mapGlobalBcWithTVX[bestGlobalBC] : bc.globalIndex ();
1086+ // alternative matching: looking for collisions with the same nominal BC
1087+ if (evselOpts.confLightIonsAlternativeBcMatching ) {
1088+ for (unsigned long iCol = 0 ; iCol < vBCinPatternPerColl.size (); iCol++) {
1089+ int64_t foundNominalBC = vBCinPatternPerColl[iCol];
1090+ for (unsigned long jCol = 0 ; jCol < vBCinPatternPerColl.size (); jCol++) {
1091+ int64_t foundNominalBC2 = vBCinPatternPerColl[jCol];
1092+ if (foundNominalBC2 == foundNominalBC) {
1093+ vCollisionsPileupPerColl[iCol]++;
1094+ }
1095+ }
1096+ }
1097+ } else { // continue standard matching: second loop to match remaining low-pt TPCnoTOFnoTRD collisions
1098+ for (const auto & col : cols) {
1099+ int32_t colIndex = col.globalIndex ();
1100+ if (vIsVertexTPC[colIndex] > 0 && vIsVertexTOF[colIndex] == 0 && vIsVertexHighPtTPC[colIndex] == 0 ) {
1101+ float weightedTime = vWeightedTimesTPCnoTOFnoTRD[colIndex];
1102+ float weightedSigma = vWeightedSigmaTPCnoTOFnoTRD[colIndex];
1103+ auto bc = col.template bc_as <soa::Join<aod::BCs, aod::Run3MatchedToBCSparse>>();
1104+ int64_t globalBC = bc.globalBC ();
1105+ int64_t meanBC = globalBC + TMath::Nint (weightedTime / bcNS);
1106+ int64_t sigmaBC = TMath::CeilNint (weightedSigma / bcNS);
1107+ int64_t bestGlobalBC = findBestGlobalBC (meanBC, sigmaBC, vNcontributors[colIndex], col.posZ (), mapGlobalBcVtxZ);
1108+ vFoundGlobalBC[colIndex] = bestGlobalBC > 0 ? bestGlobalBC : globalBC;
1109+ vFoundBCindex[colIndex] = bestGlobalBC > 0 ? mapGlobalBcWithTVX[bestGlobalBC] : bc.globalIndex ();
1110+ }
1111+ // fill pileup counter
1112+ vCollisionsPerBc[vFoundBCindex[colIndex]]++;
9921113 }
993- // fill pileup counter
994- vCollisionsPerBc[vFoundBCindex[colIndex]]++;
9951114 }
9961115
9971116 // save indices of collisions for occupancy calculation (both in ROF and in time range)
@@ -1188,10 +1307,24 @@ class EventSelectionModule
11881307 sumAmpFT0CInFullTimeWindow += wOccup * vAmpFT0CperColl[thisColIndex];
11891308
11901309 // counting tracks from other collisions in fixed time windows
1191- if (std::fabs (dt) < evselOpts.confTimeRangeVetoOnCollNarrow )
1192- nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex];
1193- if (std::fabs (dt) < evselOpts.confTimeRangeVetoOnCollStandard )
1194- nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex];
1310+ if (!evselOpts.confLightIonsModifyTimeVetoOnNearbyColl ) {
1311+ if (std::fabs (dt) < evselOpts.confTimeRangeVetoOnCollNarrow )
1312+ nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex];
1313+ if (std::fabs (dt) < evselOpts.confTimeRangeVetoOnCollStandard )
1314+ nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex];
1315+ } else { // special veto ranges (tests for light ion runs)
1316+ if (dt > -4.5 && dt < 2.5 ) // avoid TOF- and TRD-related structures, with 0.5 us margin
1317+ nITS567tracksForVetoNarrow += vTracksITS567perColl[thisColIndex];
1318+
1319+ if (!evselOpts.confLightIonsVetoOnTRDinPast ) {
1320+ if (dt > -25.5 && dt < 2.5 ) // test effect from TRD triggers in the past
1321+ nITS567tracksForVetoStrict += vTracksITS567perColl[thisColIndex];
1322+ } else {
1323+ // counting TRD-matched vertices in a long time interval in the past
1324+ if (dt > -25.5 && dt < 2.5 )
1325+ nITS567tracksForVetoStrict += vIsVertexTRDmatched[thisColIndex];
1326+ }
1327+ }
11951328
11961329 // standard cut on other collisions vs delta-times
11971330 const float driftV = 2.5 ; // drift velocity in cm/us, TPC drift_length / drift_time = 250 cm / 100 us
@@ -1210,7 +1343,11 @@ class EventSelectionModule
12101343 vSumAmpFT0CinFullTimeWin[colIndex] = sumAmpFT0CInFullTimeWindow; // occupancy by a sum of FT0C amplitudes (without a current collision)
12111344 // occupancy flags based on nearby collisions
12121345 vNoCollInTimeRangeNarrow[colIndex] = (nITS567tracksForVetoNarrow == 0 );
1213- vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0 );
1346+ if (!evselOpts.confLightIonsVetoOnTRDinPast )
1347+ vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0 );
1348+ else
1349+ vNoCollInTimeRangeStrict[colIndex] = (nITS567tracksForVetoStrict == 0 && nITS567tracksForVetoNarrow == 0 );
1350+
12141351 vNoHighMultCollInTimeRange[colIndex] = (nCollsWithFT0CAboveVetoStandard == 0 );
12151352 }
12161353
@@ -1228,15 +1365,34 @@ class EventSelectionModule
12281365 bool isGoodZvtxFT0vsPV = 0 ;
12291366 if (bcselEntry.foundFT0Id > -1 ) {
12301367 auto foundFT0 = ft0s.rawIteratorAt (bcselEntry.foundFT0Id );
1231- isGoodZvtxFT0vsPV = std::fabs (foundFT0.posZ () - col.posZ ()) < evselOpts.maxDiffZvtxFT0vsPV ;
1368+ float diffVz = foundFT0.posZ () - col.posZ ();
1369+ if (runLightIons == -1 )
1370+ isGoodZvtxFT0vsPV = std::fabs (diffVz) < evselOpts.maxDiffZvtxFT0vsPV ;
1371+ else { // special treatment of light ion runs
1372+ float multT0A = bc.ft0 ().sumAmpA ();
1373+ float multT0C = bc.ft0 ().sumAmpC ();
1374+ float T0M = multT0A + multT0C;
1375+ // calc mean at this T0 ampl.
1376+ float x = (T0M < 50 ? 50 : T0M);
1377+ double diffMean = diffVzParMean[0 ] + diffVzParMean[1 ] * pow (x, diffVzParMean[2 ]) + diffVzParMean[3 ] * pow (x, diffVzParMean[4 ]);
1378+ // calc sigma at this T0 ampl.
1379+ x = (T0M < 20 ? 20 : (T0M > 1.2e4 ? 1.2e4 : T0M));
1380+ double diffSigma = diffVzParSigma[0 ] + diffVzParSigma[1 ] * pow (x, diffVzParSigma[2 ]) + diffVzParSigma[3 ] * pow (x, diffVzParSigma[4 ]);
1381+ float nSigma = evselOpts.confLightIonsNsigmaOnVzDiff ;
1382+ float margin = evselOpts.confLightIonsMarginVzDiff ;
1383+ isGoodZvtxFT0vsPV = (diffVz > diffMean - nSigma * diffSigma - margin && diffVz < diffMean + nSigma * diffSigma + margin);
1384+ }
12321385 }
12331386
12341387 // copy alias decisions from bcsel table
12351388 uint32_t alias = bcselEntry.alias ;
12361389
12371390 // copy selection decisions from bcsel table
12381391 uint64_t selection = bcselbuffer[bc.globalIndex ()].selection ;
1239- selection |= vCollisionsPerBc[foundBC] <= 1 ? BIT (aod::evsel::kNoSameBunchPileup ) : 0 ;
1392+ if (evselOpts.confLightIonsAlternativeBcMatching )
1393+ selection |= vCollisionsPileupPerColl[colIndex] <= 1 ? BIT (aod::evsel::kNoSameBunchPileup ) : 0 ;
1394+ else
1395+ selection |= vCollisionsPerBc[foundBC] <= 1 ? BIT (aod::evsel::kNoSameBunchPileup ) : 0 ;
12401396 selection |= vIsVertexITSTPC[colIndex] ? BIT (aod::evsel::kIsVertexITSTPC ) : 0 ;
12411397 selection |= vIsVertexTOFmatched[colIndex] ? BIT (aod::evsel::kIsVertexTOFmatched ) : 0 ;
12421398 selection |= vIsVertexTRDmatched[colIndex] ? BIT (aod::evsel::kIsVertexTRDmatched ) : 0 ;
0 commit comments