@@ -1114,13 +1114,346 @@ struct filterDielectronEvent {
11141114 PROCESS_SWITCH (filterDielectronEvent, processMC_TTCA, " process reconstructed info only" , false ); // with TTCA
11151115};
11161116struct prefilterPrimaryElectron {
1117+ using MyCollisions = soa::Join<aod::Collisions, aod::EvSels, aod::EMEvSels>;
1118+ using MyCollisionsWithSWT = soa::Join<MyCollisions, aod::EMSWTriggerInfosTMP>;
1119+
11171120 Produces<aod::EMPrimaryElectronsPrefilterBit> ele_pfb;
1118- void process (aod::EMPrimaryElectrons const & primaryelectrons)
1121+
1122+ SliceCache cache;
1123+ Preslice<aod::Tracks> perCol_track = o2::aod::track::collisionId;
1124+ PresliceUnsorted<aod::EMPrimaryElectrons> perCol_ele = o2::aod::emprimaryelectron::collisionId;
1125+
1126+ // CCDB options
1127+ Configurable<std::string> ccdburl{" ccdb-url" , " http://alice-ccdb.cern.ch" , " url of the ccdb repository" };
1128+ Configurable<std::string> grpPath{" grpPath" , " GLO/GRP/GRP" , " Path of the grp file" };
1129+ Configurable<std::string> grpmagPath{" grpmagPath" , " GLO/Config/GRPMagField" , " CCDB path of the GRPMagField object" };
1130+ Configurable<bool > skipGRPOquery{" skipGRPOquery" , true , " skip grpo query" };
1131+
1132+ // Operation and minimisation criteria
1133+ Configurable<double > d_bz_input{" d_bz" , -999 , " bz field, -999 is automatic" };
1134+
1135+ Configurable<float > max_dcaxy{" max_dcaxy" , 0.3 , " DCAxy To PV for loose track sample" };
1136+ Configurable<float > max_dcaz{" max_dcaz" , 0.3 , " DCAz To PV for loose track sample" };
1137+ Configurable<float > minpt{" minpt" , 0.1 , " min pt for track for loose track sample" };
1138+ Configurable<float > maxeta{" maxeta" , 0.9 , " eta acceptance for loose track sample" };
1139+ Configurable<int > min_ncluster_tpc{" min_ncluster_tpc" , 0 , " min ncluster tpc" };
1140+ Configurable<int > mincrossedrows{" mincrossedrows" , 70 , " min crossed rows" };
1141+ Configurable<float > max_frac_shared_clusters_tpc{" max_frac_shared_clusters_tpc" , 999 .f , " max fraction of shared clusters in TPC" };
1142+ Configurable<float > min_tpc_cr_findable_ratio{" min_tpc_cr_findable_ratio" , 0.8 , " min. TPC Ncr/Nf ratio" };
1143+ Configurable<float > maxchi2tpc{" maxchi2tpc" , 5.0 , " max chi2/NclsTPC" };
1144+ Configurable<float > maxchi2its{" maxchi2its" , 6.0 , " max chi2/NclsITS" };
1145+ Configurable<int > min_ncluster_its{" min_ncluster_its" , 4 , " min ncluster its" };
1146+ Configurable<int > min_ncluster_itsib{" min_ncluster_itsib" , 1 , " min ncluster itsib" };
1147+ Configurable<float > minTPCNsigmaEl{" minTPCNsigmaEl" , -3.0 , " min. TPC n sigma for electron inclusion" };
1148+ Configurable<float > maxTPCNsigmaEl{" maxTPCNsigmaEl" , 3.0 , " max. TPC n sigma for electron inclusion" };
1149+ Configurable<float > slope{" slope" , 0.0185 , " slope for m vs. phiv" };
1150+ Configurable<float > intercept{" intercept" , -0.0280 , " intercept for m vs. phiv" };
1151+
1152+ Configurable<std::vector<float >> max_mee_vec{" max_mee_vec" , std::vector<float >{0.08 , 0.10 , 0.12 }, " vector fo max mee for prefilter in ULS. Please sort this by increasing order." }; // currently, 3 thoresholds are allowed.
1153+
1154+ HistogramRegistry fRegistry {" output" , {}, OutputObjHandlingPolicy::AnalysisObject, false , false };
1155+
1156+ int mRunNumber ;
1157+ float d_bz;
1158+ Service<o2::ccdb::BasicCCDBManager> ccdb;
1159+ o2::base::Propagator::MatCorrType matCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE;
1160+
1161+ void init (InitContext&)
1162+ {
1163+ mRunNumber = 0 ;
1164+ d_bz = 0 ;
1165+
1166+ ccdb->setURL (ccdburl);
1167+ ccdb->setCaching (true );
1168+ ccdb->setLocalObjectValidityChecking ();
1169+ ccdb->setFatalWhenNull (false );
1170+
1171+ if (!doprocessDummy) {
1172+ addHistograms ();
1173+ }
1174+ }
1175+
1176+ void addHistograms ()
1177+ {
1178+ fRegistry .add (" Track/hPt" , " pT;p_{T} (GeV/c)" , kTH1F , {{1000 , 0 .0f , 10 }}, false );
1179+ fRegistry .add (" Track/hEtaPhi" , " #eta vs. #varphi;#varphi (rad.);#eta" , kTH2F , {{180 , 0 , 2 * M_PI}, {40 , -1 .0f , 1 .0f }}, false );
1180+ fRegistry .add (" Track/hTPCNsigmaEl" , " loose track TPC PID" , kTH2F , {{1000 , 0 .f , 10 }, {100 , -5 , +5 }});
1181+ fRegistry .add (" Pair/before/uls/hMvsPt" , " mass vs. pT;m_{ee} (GeV/c^{2});p_{T,ee} (GeV/c)" , kTH2F , {{400 , 0 , 4 }, {100 , 0 , 10 }});
1182+ fRegistry .add (" Pair/before/uls/hMvsPhiV" , " mass vs. phiv;#varphi_{V} (rad.);m_{ee} (GeV/c^{2})" , kTH2F , {{90 , 0 .f , M_PI}, {100 , 0 , 1 .f }});
1183+ fRegistry .addClone (" Pair/before/uls/" , " Pair/before/lspp/" );
1184+ fRegistry .addClone (" Pair/before/uls/" , " Pair/before/lsmm/" );
1185+ fRegistry .addClone (" Pair/before/" , " Pair/after/" );
1186+ }
1187+
1188+ void initCCDB (aod::BCsWithTimestamps::iterator const & bc)
1189+ {
1190+ if (mRunNumber == bc.runNumber ()) {
1191+ return ;
1192+ }
1193+
1194+ // In case override, don't proceed, please - no CCDB access required
1195+ if (d_bz_input > -990 ) {
1196+ d_bz = d_bz_input;
1197+ o2::parameters::GRPMagField grpmag;
1198+ if (fabs (d_bz) > 1e-5 ) {
1199+ grpmag.setL3Current (30000 .f / (d_bz / 5 .0f ));
1200+ }
1201+ o2::base::Propagator::initFieldFromGRP (&grpmag);
1202+ mRunNumber = bc.runNumber ();
1203+ return ;
1204+ }
1205+
1206+ auto run3grp_timestamp = bc.timestamp ();
1207+ o2::parameters::GRPObject* grpo = 0x0 ;
1208+ o2::parameters::GRPMagField* grpmag = 0x0 ;
1209+ if (!skipGRPOquery)
1210+ grpo = ccdb->getForTimeStamp <o2::parameters::GRPObject>(grpPath, run3grp_timestamp);
1211+ if (grpo) {
1212+ o2::base::Propagator::initFieldFromGRP (grpo);
1213+ // Fetch magnetic field from ccdb for current collision
1214+ d_bz = grpo->getNominalL3Field ();
1215+ LOG (info) << " Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG" ;
1216+ } else {
1217+ grpmag = ccdb->getForTimeStamp <o2::parameters::GRPMagField>(grpmagPath, run3grp_timestamp);
1218+ if (!grpmag) {
1219+ LOG (fatal) << " Got nullptr from CCDB for path " << grpmagPath << " of object GRPMagField and " << grpPath << " of object GRPObject for timestamp " << run3grp_timestamp;
1220+ }
1221+ o2::base::Propagator::initFieldFromGRP (grpmag);
1222+ // Fetch magnetic field from ccdb for current collision
1223+ d_bz = std::lround (5 .f * grpmag->getL3Current () / 30000 .f );
1224+ LOG (info) << " Retrieved GRP for timestamp " << run3grp_timestamp << " with magnetic field of " << d_bz << " kZG" ;
1225+ }
1226+ mRunNumber = bc.runNumber ();
1227+ }
1228+
1229+ o2::base::Propagator::MatCorrType noMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE;
1230+
1231+ template <typename TCollision, typename TTrack>
1232+ bool checkTrack (TCollision const & collision, TTrack const & track)
1233+ {
1234+ if (!track.hasITS ()) {
1235+ return false ;
1236+ }
1237+ if (track.itsChi2NCl () > maxchi2its) {
1238+ return false ;
1239+ }
1240+ if (track.itsNCls () < min_ncluster_its) {
1241+ return false ;
1242+ }
1243+ if (track.itsNClsInnerBarrel () < min_ncluster_itsib) {
1244+ return false ;
1245+ }
1246+
1247+ if (!track.hasTPC ()) {
1248+ return false ;
1249+ }
1250+ if (track.tpcNSigmaEl () < minTPCNsigmaEl || maxTPCNsigmaEl < track.tpcNSigmaEl ()) {
1251+ return false ;
1252+ }
1253+ if (track.tpcNClsFound () < min_ncluster_tpc) {
1254+ return false ;
1255+ }
1256+ if (track.tpcNClsCrossedRows () < mincrossedrows) {
1257+ return false ;
1258+ }
1259+ if (track.tpcCrossedRowsOverFindableCls () < min_tpc_cr_findable_ratio) {
1260+ return false ;
1261+ }
1262+ if (track.tpcFractionSharedCls () > max_frac_shared_clusters_tpc) {
1263+ return false ;
1264+ }
1265+ if (track.tpcChi2NCl () > maxchi2its) {
1266+ return false ;
1267+ }
1268+
1269+ gpu::gpustd::array<float , 2 > dcaInfo;
1270+ auto track_par_cov_recalc = getTrackParCov (track);
1271+ std::array<float , 3 > pVec_recalc = {0 , 0 , 0 }; // px, py, pz
1272+ o2::base::Propagator::Instance ()->propagateToDCABxByBz ({collision.posX (), collision.posY (), collision.posZ ()}, track_par_cov_recalc, 2 .f , matCorr, &dcaInfo);
1273+ getPxPyPz (track_par_cov_recalc, pVec_recalc);
1274+
1275+ if (fabs (dcaInfo[0 ]) > max_dcaxy || fabs (dcaInfo[1 ]) > max_dcaz) {
1276+ return false ;
1277+ }
1278+
1279+ if (track_par_cov_recalc.getPt () < minpt || fabs (track_par_cov_recalc.getEta ()) > maxeta) {
1280+ return false ;
1281+ }
1282+
1283+ return true ;
1284+ }
1285+
1286+ Preslice<aod::TrackAssoc> trackIndicesPerCollision = aod::track_association::collisionId;
1287+
1288+ Filter trackFilter = o2::aod::track::pt > minpt&& nabs(o2::aod::track::eta) < maxeta&& ncheckbit(aod::track::v001::detectorMap, (uint8_t )o2::aod::track::ITS) == true && ncheckbit(aod::track::v001::detectorMap, (uint8_t )o2::aod::track::TPC) == true ;
1289+ using MyFilteredTracks = soa::Filtered<MyTracks>;
1290+ Partition<MyFilteredTracks> posTracks = o2::aod::track::signed1Pt > 0 .f;
1291+ Partition<MyFilteredTracks> negTracks = o2::aod::track::signed1Pt < 0 .f;
1292+
1293+ Partition<aod::EMPrimaryElectrons> positrons = o2::aod::emprimaryelectron::sign > int8_t (0 );
1294+ Partition<aod::EMPrimaryElectrons> electrons = o2::aod::emprimaryelectron::sign < int8_t (0 );
1295+ void processSA (MyCollisions const & collisions, aod::BCsWithTimestamps const &, MyFilteredTracks const &, aod::EMPrimaryElectrons const & primaryelectrons)
1296+ {
1297+ std::unordered_map<int , uint8_t > pfb_map; // map track.globalIndex -> prefilter bit
1298+
1299+ for (auto & collision : collisions) {
1300+ auto bc = collision.template foundBC_as <aod::BCsWithTimestamps>();
1301+ initCCDB (bc);
1302+ if (!collision.isSelected ()) {
1303+ continue ;
1304+ }
1305+
1306+ auto posTracks_per_coll = posTracks->sliceByCached (o2::aod::track::collisionId, collision.globalIndex (), cache); // loose track sample
1307+ auto negTracks_per_coll = negTracks->sliceByCached (o2::aod::track::collisionId, collision.globalIndex (), cache); // loose track sample
1308+
1309+ auto positrons_per_coll = positrons->sliceByCachedUnsorted (o2::aod::emprimaryelectron::collisionId, collision.globalIndex (), cache); // signal sample
1310+ auto electrons_per_coll = electrons->sliceByCachedUnsorted (o2::aod::emprimaryelectron::collisionId, collision.globalIndex (), cache); // signal sample
1311+
1312+ for (auto & pos : posTracks_per_coll) {
1313+ if (!checkTrack (collision, pos)) { // track cut is applied to loose sample
1314+ continue ;
1315+ }
1316+ fRegistry .fill (HIST (" Track/hPt" ), pos.pt ());
1317+ fRegistry .fill (HIST (" Track/hEtaPhi" ), pos.phi (), pos.eta ());
1318+ }
1319+ for (auto & neg : negTracks_per_coll) {
1320+ if (!checkTrack (collision, neg)) { // track cut is applied to loose sample
1321+ continue ;
1322+ }
1323+ fRegistry .fill (HIST (" Track/hPt" ), neg.pt ());
1324+ fRegistry .fill (HIST (" Track/hEtaPhi" ), neg.phi (), neg.eta ());
1325+ }
1326+
1327+ for (auto & [ele, empos] : combinations (CombinationsFullIndexPolicy (negTracks_per_coll, positrons_per_coll))) {
1328+ // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered.
1329+ if (!checkTrack (collision, ele)) { // track cut is applied to loose sample
1330+ continue ;
1331+ }
1332+ if (empos.trackId () == ele.globalIndex ()) {
1333+ continue ;
1334+ }
1335+
1336+ ROOT::Math::PtEtaPhiMVector v1 (ele.pt (), ele.eta (), ele.phi (), o2::constants::physics::MassElectron); // loose track
1337+ ROOT::Math::PtEtaPhiMVector v2 (empos.pt (), empos.eta (), empos.phi (), o2::constants::physics::MassElectron); // signal track
1338+ ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
1339+ float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair (empos.px (), empos.py (), empos.pz (), ele.px (), ele.py (), ele.pz (), empos.sign (), ele.sign (), d_bz);
1340+ fRegistry .fill (HIST (" Pair/before/uls/hMvsPhiV" ), phiv, v12.M ());
1341+ fRegistry .fill (HIST (" Pair/before/uls/hMvsPt" ), v12.M (), v12.Pt ());
1342+ if (v12.M () < max_mee_vec->at (static_cast <int >(max_mee_vec->size ()) - 1 )) {
1343+ fRegistry .fill (HIST (" Track/hTPCNsigmaEl" ), ele.tpcInnerParam (), ele.tpcNSigmaEl ());
1344+ }
1345+ for (int i = 0 ; i < static_cast <int >(max_mee_vec->size ()); i++) {
1346+ if (v12.M () < max_mee_vec->at (i)) {
1347+ pfb_map[empos.globalIndex ()] |= (uint8_t (1 ) << (static_cast <int >(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1 ) + i));
1348+ }
1349+ }
1350+
1351+ if (v12.M () < slope * phiv + intercept) {
1352+ pfb_map[empos.globalIndex ()] |= (uint8_t (1 ) << static_cast <int >(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC ));
1353+ }
1354+
1355+ } // end of ULS pairing
1356+
1357+ for (auto & [pos, emele] : combinations (CombinationsFullIndexPolicy (posTracks_per_coll, electrons_per_coll))) {
1358+ // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered.
1359+ if (!checkTrack (collision, pos)) { // track cut is applied to loose sample
1360+ continue ;
1361+ }
1362+ if (emele.trackId () == pos.globalIndex ()) {
1363+ continue ;
1364+ }
1365+
1366+ ROOT::Math::PtEtaPhiMVector v1 (emele.pt (), emele.eta (), emele.phi (), o2::constants::physics::MassElectron); // signal track
1367+ ROOT::Math::PtEtaPhiMVector v2 (pos.pt (), pos.eta (), pos.phi (), o2::constants::physics::MassElectron); // loose track
1368+ ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
1369+ float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair (pos.px (), pos.py (), pos.pz (), emele.px (), emele.py (), emele.pz (), pos.sign (), emele.sign (), d_bz);
1370+ fRegistry .fill (HIST (" Pair/before/uls/hMvsPhiV" ), phiv, v12.M ());
1371+ fRegistry .fill (HIST (" Pair/before/uls/hMvsPt" ), v12.M (), v12.Pt ());
1372+ if (v12.M () < max_mee_vec->at (static_cast <int >(max_mee_vec->size ()) - 1 )) {
1373+ fRegistry .fill (HIST (" Track/hTPCNsigmaEl" ), pos.tpcInnerParam (), pos.tpcNSigmaEl ());
1374+ }
1375+ for (int i = 0 ; i < static_cast <int >(max_mee_vec->size ()); i++) {
1376+ if (v12.M () < max_mee_vec->at (i)) {
1377+ pfb_map[emele.globalIndex ()] |= (uint8_t (1 ) << (static_cast <int >(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPi0_1 ) + i));
1378+ }
1379+ }
1380+
1381+ if (v12.M () < slope * phiv + intercept) {
1382+ pfb_map[emele.globalIndex ()] |= (uint8_t (1 ) << static_cast <int >(o2::aod::pwgem::dilepton::utils::pairutil::DileptonPrefilterBit::kElFromPC ));
1383+ }
1384+
1385+ } // end of ULS pairing
1386+
1387+ for (auto & [pos, empos] : combinations (CombinationsFullIndexPolicy (posTracks_per_coll, positrons_per_coll))) {
1388+ // auto pos = tracks.rawIteratorAt(empos.trackId()); // use rawIterator, if the table is filtered.
1389+ if (!checkTrack (collision, pos)) { // track cut is applied to loose sample
1390+ continue ;
1391+ }
1392+ if (empos.trackId () == pos.globalIndex ()) {
1393+ continue ;
1394+ }
1395+
1396+ ROOT::Math::PtEtaPhiMVector v1 (pos.pt (), pos.eta (), pos.phi (), o2::constants::physics::MassElectron); // loose track
1397+ ROOT::Math::PtEtaPhiMVector v2 (empos.pt (), empos.eta (), empos.phi (), o2::constants::physics::MassElectron); // signal track
1398+ ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
1399+ float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair (empos.px (), empos.py (), empos.pz (), pos.px (), pos.py (), pos.pz (), empos.sign (), pos.sign (), d_bz);
1400+ fRegistry .fill (HIST (" Pair/before/lspp/hMvsPhiV" ), phiv, v12.M ());
1401+ fRegistry .fill (HIST (" Pair/before/lspp/hMvsPt" ), v12.M (), v12.Pt ());
1402+ } // end of LS++ pairing
1403+
1404+ for (auto & [ele, emele] : combinations (CombinationsFullIndexPolicy (negTracks_per_coll, electrons_per_coll))) {
1405+ // auto ele = tracks.rawIteratorAt(emele.trackId()); // use rawIterator, if the table is filtered.
1406+ if (!checkTrack (collision, ele)) { // track cut is applied to loose sample
1407+ continue ;
1408+ }
1409+ if (emele.trackId () == ele.globalIndex ()) {
1410+ continue ;
1411+ }
1412+
1413+ ROOT::Math::PtEtaPhiMVector v1 (ele.pt (), ele.eta (), ele.phi (), o2::constants::physics::MassElectron); // loose track
1414+ ROOT::Math::PtEtaPhiMVector v2 (emele.pt (), emele.eta (), emele.phi (), o2::constants::physics::MassElectron); // signal track
1415+ ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
1416+ float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair (emele.px (), emele.py (), emele.pz (), ele.px (), ele.py (), ele.pz (), emele.sign (), ele.sign (), d_bz);
1417+ fRegistry .fill (HIST (" Pair/before/lsmm/hMvsPhiV" ), phiv, v12.M ());
1418+ fRegistry .fill (HIST (" Pair/before/lsmm/hMvsPt" ), v12.M (), v12.Pt ());
1419+ } // end of LS-- pairing
1420+
1421+ } // end of collision loop
1422+
1423+ for (auto & ele : primaryelectrons) {
1424+ ele_pfb (pfb_map[ele.globalIndex ()]);
1425+ }
1426+
1427+ // check prefilter
1428+ for (auto & collision : collisions) {
1429+ auto positrons_per_coll = positrons->sliceByCachedUnsorted (o2::aod::emprimaryelectron::collisionId, collision.globalIndex (), cache); // signal sample
1430+ auto electrons_per_coll = electrons->sliceByCachedUnsorted (o2::aod::emprimaryelectron::collisionId, collision.globalIndex (), cache); // signal sample
1431+
1432+ for (auto & [ele, pos] : combinations (CombinationsFullIndexPolicy (electrons_per_coll, positrons_per_coll))) {
1433+ if (pfb_map[ele.globalIndex ()] != 0 || pfb_map[pos.globalIndex ()] != 0 ) {
1434+ continue ;
1435+ }
1436+
1437+ ROOT::Math::PtEtaPhiMVector v1 (ele.pt (), ele.eta (), ele.phi (), o2::constants::physics::MassElectron);
1438+ ROOT::Math::PtEtaPhiMVector v2 (pos.pt (), pos.eta (), pos.phi (), o2::constants::physics::MassElectron);
1439+ ROOT::Math::PtEtaPhiMVector v12 = v1 + v2;
1440+ float phiv = o2::aod::pwgem::dilepton::utils::pairutil::getPhivPair (pos.px (), pos.py (), pos.pz (), ele.px (), ele.py (), ele.pz (), pos.sign (), ele.sign (), d_bz);
1441+ fRegistry .fill (HIST (" Pair/after/uls/hMvsPhiV" ), phiv, v12.M ());
1442+ fRegistry .fill (HIST (" Pair/after/uls/hMvsPt" ), v12.M (), v12.Pt ());
1443+ } // end of ULS pairing
1444+ } // end of collision loop
1445+
1446+ pfb_map.clear ();
1447+ }
1448+ PROCESS_SWITCH (prefilterPrimaryElectron, processSA, " process SA" , false );
1449+
1450+ void processDummy (aod::EMPrimaryElectrons const & primaryelectrons)
11191451 {
11201452 for (int i = 0 ; i < primaryelectrons.size (); i++) {
11211453 ele_pfb (0 );
11221454 }
11231455 }
1456+ PROCESS_SWITCH (prefilterPrimaryElectron, processDummy, " processDummy" , true );
11241457};
11251458struct associateAmbiguousElectron {
11261459 Produces<aod::EMAmbiguousElectronSelfIds> em_amb_ele_ids;
0 commit comments