From 0d8bcd80a8c920050b38aca26b2fdc4f6cd9873e Mon Sep 17 00:00:00 2001 From: aferrero2707 Date: Tue, 8 Sep 2026 10:05:06 +0200 Subject: [PATCH] [PWGDQ] added derived tables to global muon alignment task The derived tables provide the minimal information neederd to run the alignment analysis on new geometries, thus avoiding to pocess each time the original large-size AO2Ds. A pre-processor switch allows to use the same task for either producing or processing the derived tables. --- PWGDQ/Tasks/muonGlobalAlignment.cxx | 560 ++++++++++++++++++++++++---- 1 file changed, 490 insertions(+), 70 deletions(-) diff --git a/PWGDQ/Tasks/muonGlobalAlignment.cxx b/PWGDQ/Tasks/muonGlobalAlignment.cxx index 200b241cc11..685c0bfdb89 100644 --- a/PWGDQ/Tasks/muonGlobalAlignment.cxx +++ b/PWGDQ/Tasks/muonGlobalAlignment.cxx @@ -119,18 +119,126 @@ using SMatrix5 = ROOT::Math::SVector; using o2::dataformats::GlobalFwdTrack; using o2::track::TrackParCovFwd; +namespace muonaligncoll +{ +DECLARE_SOA_COLUMN(RunNumber, runNumber, int); +DECLARE_SOA_COLUMN(Timestamp, timestamp, uint64_t); //! Timestamp of a BC in ms (epoch style) +} // namespace muonaligncoll + +namespace o2::aod +{ +// Reduced collisions table +DECLARE_SOA_TABLE(MuonAlignCollisions, "AOD", "MUONALIGNCOLL", //! Time and vertex information of collision + o2::soa::Index<>, muonaligncoll::RunNumber, muonaligncoll::Timestamp, + collision::PosX, collision::PosY, collision::PosZ, + collision::CovXX, collision::CovYY, collision::CovZZ); +using MuonAlignCollision = MuonAlignCollisions::iterator; +} // namespace o2::aod + namespace o2::aod { +// Reduced MFT tracks table +DECLARE_SOA_TABLE_FULL(StoredMuonAlignMFTTracks, "MuonAlignMFTTracks", "AOD", "MAMFTTRK", //! On disk version of MFTTracks + o2::soa::Index<>, fwdtrack::CollisionId, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, fwdtrack::Signed1Pt, + fwdtrack::v001::NClusters, fwdtrack::MFTClusterSizesAndTrackFlags, fwdtrack::IsCA, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, fwdtrack::Chi2); + +DECLARE_SOA_EXTENDED_TABLE_USER(MuonAlignMFTTracks, StoredMuonAlignMFTTracks, "MAMFTTRK", //! Additional MFTTracks information (Pt, Eta, P), version 0 + aod::fwdtrack::Pt, + aod::fwdtrack::Eta, + aod::fwdtrack::P); +using MuonAlignMFTTrack = MuonAlignMFTTracks::iterator; +} // namespace o2::aod + +namespace muonalignfwdtrk +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(Collision, collision, int32_t, o2::aod::MuonAlignCollisions, "MACOLLs", ""); +// Index of matching MCH track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_SELF_INDEX_COLUMN_FULL(MuonAlignMCHTrack, matchMCHTrack, int, "MuonAlignFwdTracks_MatchMCHTrack"); // o2-linter: disable=name/o2-column (to match naming in official tables) +// ID of matching MFT track for GlobalMuonTracks and GlobalForwardTracks +DECLARE_SOA_INDEX_COLUMN(MuonAlignMFTTrack, matchMFTTrack); // o2-linter: disable=name/o2-column (to match naming in official tables) +} // namespace muonalignfwdtrk + +namespace o2::aod +{ +// Reduced forward tracks table +DECLARE_SOA_TABLE_FULL(StoredMuonAlignFwdTracks, "MuonAlignFwdTracks", "AOD", "MAFWDTRK", + o2::soa::Index<>, muonalignfwdtrk::CollisionId, fwdtrack::TrackType, + fwdtrack::X, fwdtrack::Y, fwdtrack::Z, fwdtrack::Phi, fwdtrack::Tgl, + fwdtrack::Signed1Pt, fwdtrack::NClusters, fwdtrack::PDca, fwdtrack::RAtAbsorberEnd, + fwdtrack::Px, + fwdtrack::Py, + fwdtrack::Pz, + fwdtrack::Sign, + fwdtrack::Chi2, fwdtrack::Chi2MatchMCHMFT, + muonalignfwdtrk::MuonAlignMFTTrackId, muonalignfwdtrk::MuonAlignMCHTrackId, + fwdtrack::CXX, + fwdtrack::CXY, + fwdtrack::CYY, + fwdtrack::CPhiX, + fwdtrack::CPhiY, + fwdtrack::CPhiPhi, + fwdtrack::CTglX, + fwdtrack::CTglY, + fwdtrack::CTglPhi, + fwdtrack::CTglTgl, + fwdtrack::C1PtX, + fwdtrack::C1PtY, + fwdtrack::C1PtPhi, + fwdtrack::C1PtTgl, + fwdtrack::C1Pt21Pt2); + +DECLARE_SOA_EXTENDED_TABLE_USER(MuonAlignFwdTracks, StoredMuonAlignFwdTracks, "MAFWDTRK", //! + aod::fwdtrack::Pt, + aod::fwdtrack::Eta, + aod::fwdtrack::P); +using MuonAlignFwdTrack = MuonAlignFwdTracks::iterator; +} // namespace o2::aod + +namespace muonaligncl +{ +DECLARE_SOA_INDEX_COLUMN_FULL_CUSTOM(FwdTrack, fwdTrack, int32_t, o2::aod::StoredMuonAlignFwdTracks, "MAFWDTRKs", ""); +} // namespace muonaligncl + +namespace o2::aod +{ +// Reduced MCH clusters table +DECLARE_SOA_TABLE(MuonAlignFwdTrkCls, "AOD", "MAFWDTRKCL", //! Forward Track Cluster information + o2::soa::Index<>, + fwdtrkcl::FwdTrackId, + fwdtrkcl::X, + fwdtrkcl::Y, + fwdtrkcl::Z, + fwdtrkcl::ClInfo, + fwdtrkcl::DEId, + fwdtrkcl::IsGoodX, + fwdtrkcl::IsGoodY); + +using MuonAlignFwdTrkCl = MuonAlignFwdTrkCls::iterator; +} // namespace o2::aod + +namespace o2::aod +{ +// Compact collision + MFT tracks table for DCA analysis DECLARE_SOA_TABLE(CompactMFTTracks, "AOD", "COMPACTMFT", //! standalone table for studying alignment collision::PosX, collision::PosY, collision::PosZ, fwdtrack::Signed1Pt, fwdtrack::Tgl, fwdtrack::Phi, fwdtrack::FwdDcaX, fwdtrack::FwdDcaY, o2::aod::fwdtrack::CXX, o2::aod::fwdtrack::CYY, o2::aod::fwdtrack::CXY, fwdtrack::NClusters, fwdtrack::Chi2, fwdtrack::X, fwdtrack::Y, fwdtrack::Z); -using CompactMFTTrack = CompactMFTTracks; +using CompactMFTTrack = CompactMFTTracks::iterator; } // namespace o2::aod -struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struct (exception) +// Switch to enable/disable the processing of the derived tables +// 0: process standard AO2Ds and produce the derived tables +// 1: process derived AO2Ds and disable the derived tables creation +#define PROCESS_DERIVED_TABLES 0 + +struct MuonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struct (exception) static constexpr int GlobalTrackTypeMax = 2; static constexpr int NMchChambers = 10; @@ -140,8 +248,15 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc static constexpr double AbsorberBackZ = -505.f; static constexpr double BransonPlaneZ = -466.f; - Produces mftTable; - Configurable cfgProduceMFTTable{"cfgProduceMFTTable", false, "flag to produce MFTsa table"}; +#if (PROCESS_DERIVED_TABLES == 0) + Produces collTable; + Produces fwdTable; + Produces mftTable; + Produces clusTable; + Produces compactMftTable; + Configurable cfgProduceMuonAlignmentTables{"cfgProduceMuonAlignmentTables", false, "flag to produce derived tables for muon alignment"}; + Configurable cfgProduceMFTTable{"cfgProduceMFTTable", false, "flag to produce MFTs table"}; +#endif //// Variables for selecting MCH and MFT tracks Configurable cfgTrackChi2MchUp{"cfgTrackChi2MchUp", 5.f, ""}; @@ -196,7 +311,7 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc Configurable cfgMCHRealignCorrections{"cfgMCHRealignCorrections", "", "MCH DE positions/angles corrections in JSON format"}; } configRealign; - //// Variables for re-alignment setup + //// Variables for forward two-prong fitter struct : ConfigurableGroup { Configurable cfgFitterTwoProngFwdPropagateToPCA{"cfgFitterTwoProngFwdPropagateToPCA", true, ""}; Configurable cfgFitterTwoProngFwdMaxR{"cfgFitterTwoProngFwdMaxR", 200.f, ""}; @@ -329,7 +444,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc }; std::map mMchAlignmentCorrections; +#if (PROCESS_DERIVED_TABLES == 0) Preslice perMuon = aod::fwdtrkcl::fwdtrackId; +#else + Preslice perMuon = aod::fwdtrkcl::fwdtrackId; +#endif o2::aod::rctsel::RCTFlagsChecker rctChecker{"CBT_muon_glo", false, false, true}; @@ -345,7 +464,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc using MatchingCandidates = std::map>; struct CollisionInfo { - uint64_t bc{0}; + int runNumber{0}; + uint64_t timestamp{0}; // z position of the collision double zVertex{0}; // number of MFT tracks associated to the collision @@ -1128,37 +1248,39 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::array rAbsCut, double nSigmaPdcaCut) { - auto const& mchTrack = (static_cast(muonTrack.trackType()) <= GlobalTrackTypeMax) ? muonTrack.template matchMCHTrack_as() : muonTrack; + if (static_cast(muonTrack.trackType()) <= GlobalTrackTypeMax) { + LOGF(warning, "IsGoodMuon() called with global forward track"); + } // chi2 cut - if (mchTrack.chi2() > chi2Cut) { + if (muonTrack.chi2() > chi2Cut) { return false; } // momentum cut - if (mchTrack.p() < pCut) { + if (muonTrack.p() < pCut) { return false; // skip low-momentum tracks } // transverse momentum cut - if (mchTrack.pt() < pTCut) { + if (muonTrack.pt() < pTCut) { return false; // skip low-momentum tracks } // Eta cut - double eta = mchTrack.eta(); + double eta = muonTrack.eta(); if ((eta < etaCut[0] || eta > etaCut[1])) { return false; } // RAbs cut - double rAbs = mchTrack.rAtAbsorberEnd(); + double rAbs = muonTrack.rAtAbsorberEnd(); if ((rAbs < rAbsCut[0] || rAbs > rAbsCut[1])) { return false; } // pDCA cut - if (!pDCACut(mchTrack, collision, nSigmaPdcaCut)) { + if (!pDCACut(muonTrack, collision, nSigmaPdcaCut)) { return false; } @@ -1790,12 +1912,13 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc return !removable; } - template + template void InitCollisions(COLL const& collisions, BC const& bcs, TMUON const& muonTracks, - aod::FwdTrkCls const& clusters, - std::map& collisionInfos) + TCLS const& clusters, + TMFT const& mftTracks, + std::unordered_map& collisionInfos) { mMchTrackPars.clear(); mMchTrackParsNew.clear(); @@ -1807,6 +1930,13 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + const auto& bc = bcs.rawIteratorAt(collision.bcId()); + + // remove TF/ROF borders and ambiguous collisions + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || + !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } if (cfgRequireGoodRCT && !rctChecker(collision)) { continue; @@ -1814,10 +1944,9 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc uint64_t collisionIndex = collision.globalIndex(); - auto bc = bcs.rawIteratorAt(collision.bcId()); - auto& collisionInfo = collisionInfos[collisionIndex]; - collisionInfo.bc = bc.globalBC(); + collisionInfo.runNumber = bc.runNumber(); + collisionInfo.timestamp = bc.timestamp(); collisionInfo.zVertex = collision.posZ(); if (static_cast(muonTrack.trackType()) > GlobalTrackTypeMax) { @@ -1880,16 +2009,141 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareChi2); } } + + mMftTrackPars.clear(); + mMftTrackParsNew.clear(); + + // fill collision information for MFT standalone tracks + for (const auto& mftTrack : mftTracks) { + if (!mftTrack.has_collision()) { + continue; + } + + auto collision = collisions.rawIteratorAt(mftTrack.collisionId()); + uint64_t collisionIndex = collision.globalIndex(); + + auto bc = bcs.rawIteratorAt(collision.bcId()); + + // remove TF/ROF borders and ambiguous collisions + if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || + !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + continue; + } + + if (cfgRequireGoodRCT && !rctChecker(collision)) { + continue; + } + + uint64_t mftTrackIndex = mftTrack.globalIndex(); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.runNumber = bc.runNumber(); + collisionInfo.timestamp = bc.timestamp(); + collisionInfo.zVertex = collision.posZ(); + + collisionInfo.mftTracks.push_back(mftTrackIndex); + + // initialize the original MFT track parameters + auto mftTrackFwd = TrackToParCovFwd(mftTrack); + mMftTrackPars.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + + // initialize the corrected MFT track parameters, if requested + if (configMFTAlignmentCorrections.cfgEnableMFTAlignmentCorrections) { + TransformMFT(mftTrackFwd); + mMftTrackParsNew.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + } else { + // initialize the new MFT track parameters with the original ones, without corrections + mMftTrackParsNew.try_emplace(mftTrackIndex, TrackParExt(mftTrackFwd, mftTrack.nClusters())); + } + } } - void InitCollisions(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - aod::FwdTrkCls const& clusters, - MyMFTs const& mftTracks, - std::map& collisionInfos) + template + void InitCollisionsDerivedTables(COLL const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& mftTracks, + std::unordered_map& collisionInfos) { - InitCollisions(collisions, bcs, muonTracks, clusters, collisionInfos); + // InitCollisions(collisions, bcs, muonTracks, clusters, collisionInfos); + + mMchTrackPars.clear(); + mMchTrackParsNew.clear(); + + // fill collision information for global muon tracks (MFT-MCH-MID matches) + for (const auto& muonTrack : muonTracks) { + if (!muonTrack.has_collision()) { + continue; + } + + auto collision = collisions.rawIteratorAt(muonTrack.collisionId()); + uint64_t collisionIndex = collision.globalIndex(); + + auto& collisionInfo = collisionInfos[collisionIndex]; + collisionInfo.runNumber = collision.runNumber(); + collisionInfo.timestamp = collision.timestamp(); + collisionInfo.zVertex = collision.posZ(); + + if (static_cast(muonTrack.trackType()) > GlobalTrackTypeMax) { + // standalone MCH or MCH-MID tracks + uint64_t mchTrackIndex = muonTrack.globalIndex(); + collisionInfo.mchTracks.push_back(mchTrackIndex); + + // initialize the original MCH track parameters + mMchTrackPars.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); + + // refit MCH track if requested + if (configRealign.cfgEnableMCHRefit || configRealign.cfgEnableMCHRealign) { + TrackRealigned convertedTrack; + bool convertedTrackOk = MchRefitTrack(muonTrack, clusters, convertedTrack, !mMchAlignmentCorrections.empty()); + + // Get the re-aligned track parameters: track param at the first cluster + mch::TrackParam trackParam = mch::TrackParam(convertedTrack.first()); + + auto mchTrackParIt = mMchTrackParsNew.try_emplace(mchTrackIndex, TrackParExt(MCHtoFwd(trackParam), convertedTrack.getNClusters())); + if (mchTrackParIt.second) { + // the insertion succeeded + mchTrackParIt.first->second.setTrackChi2(trackParam.getTrackChi2() / convertedTrack.getNDF()); + if (!convertedTrackOk) { + mchTrackParIt.first->second.setRemovable(); + } + } + } else { + // initialize the new MCH track parameters with the original ones, without refitting + mMchTrackParsNew.try_emplace(mchTrackIndex, TrackParExt(fwdtrackutils::getTrackParCovFwd(muonTrack, muonTrack), muonTrack.nClusters())); + } + } else { + // global muon tracks (MFT-MCH or MFT-MCH-MID) + uint64_t muonTrackIndex = muonTrack.globalIndex(); + auto const& mchTrack = muonTrack.template matchMCHTrack_as(); + uint64_t mchTrackIndex = mchTrack.globalIndex(); + + // check if a vector of global muon candidates is already available for the current MCH index + // if not, initialize a new one and add the current global muon track + // bool globalMuonTrackFound = false; + auto matchingCandidateIterator = collisionInfo.globalMuonTracks.find(mchTrackIndex); + if (matchingCandidateIterator != collisionInfo.globalMuonTracks.end()) { + matchingCandidateIterator->second.push_back(muonTrackIndex); + // globalMuonTrackFound = true; + } else { + collisionInfo.globalMuonTracks[mchTrackIndex].push_back(muonTrackIndex); + } + } + } + + // sort the vectors of matching candidates in ascending order based on the matching chi2 value + auto compareChi2 = [&muonTracks](uint64_t trackIndex1, uint64_t trackIndex2) -> bool { + auto const& track1 = muonTracks.rawIteratorAt(trackIndex1); + auto const& track2 = muonTracks.rawIteratorAt(trackIndex2); + + return (track1.chi2MatchMCHMFT() < track2.chi2MatchMCHMFT()); + }; + + for (auto& [collisionIndex, collisionInfo] : collisionInfos) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + for (auto& [mchIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { // o2-linter: disable=const-ref-in-for-loop (object is modified in loop) + std::sort(globalTracksVector.begin(), globalTracksVector.end(), compareChi2); + } + } mMftTrackPars.clear(); mMftTrackParsNew.clear(); @@ -1903,12 +2157,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc auto collision = collisions.rawIteratorAt(mftTrack.collisionId()); uint64_t collisionIndex = collision.globalIndex(); - auto bc = bcs.rawIteratorAt(collision.bcId()); - uint64_t mftTrackIndex = mftTrack.globalIndex(); auto& collisionInfo = collisionInfos[collisionIndex]; - collisionInfo.bc = bc.globalBC(); + collisionInfo.runNumber = collision.runNumber(); + collisionInfo.timestamp = collision.timestamp(); collisionInfo.zVertex = collision.posZ(); collisionInfo.mftTracks.push_back(mftTrackIndex); @@ -1928,23 +2181,126 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } - void FillMftPlots(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - MyMFTs const& mftTracks, - const std::map& collisionInfos) +#if (PROCESS_DERIVED_TABLES == 0) + template + void StoreCollisions(const std::unordered_map& collisionInfos, + COLL const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& /*mftTracks*/) { - // outer loop over collisions + int32_t collId = 0; + int32_t fwdTrkId = 0; + int32_t mftTrkId = 0; + + std::unordered_map mchTrackIdRemapping; for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { - auto const& collision = collisions.rawIteratorAt(collisionIndex); - const auto& bc = bcs.rawIteratorAt(collision.bcId()); + auto const& c = collisions.rawIteratorAt(collisionIndex); - // remove TF/ROF borders and ambiguous collisions - if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || - !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { + if (collisionInfo.globalMuonTracks.empty()) { continue; } + collTable(collisionInfo.runNumber, collisionInfo.timestamp, + c.posX(), c.posY(), c.posZ(), + c.covXX(), c.covYY(), c.covZZ()); + + // loop over MCH tracks + for (const auto& mchIndex : collisionInfo.mchTracks) { + auto const& mchTrack = muonTracks.rawIteratorAt(mchIndex); + + fwdTable(collId, + mchTrack.trackType(), + mchTrack.x(), mchTrack.y(), mchTrack.z(), + mchTrack.phi(), mchTrack.tgl(), mchTrack.signed1Pt(), + mchTrack.nClusters(), mchTrack.pDca(), mchTrack.rAtAbsorberEnd(), + mchTrack.chi2(), mchTrack.chi2MatchMCHMFT(), + mchTrack.matchMFTTrackId(), mchTrack.matchMCHTrackId(), + mchTrack.cXX(), + mchTrack.cXY(), + mchTrack.cYY(), + mchTrack.cPhiX(), + mchTrack.cPhiY(), + mchTrack.cPhiPhi(), + mchTrack.cTglX(), + mchTrack.cTglY(), + mchTrack.cTglPhi(), + mchTrack.cTglTgl(), + mchTrack.c1PtX(), + mchTrack.c1PtY(), + mchTrack.c1PtPhi(), + mchTrack.c1PtTgl(), + mchTrack.c1Pt21Pt2()); + + // loop over attached clusters + auto clustersSliced = clusters.sliceBy(perMuon, mchTrack.globalIndex()); // Slice clusters by muon id + for (auto const& cluster : clustersSliced) { + clusTable(fwdTrkId, cluster.x(), cluster.y(), cluster.z(), cluster.clInfo()); + } + + mchTrackIdRemapping[mchTrack.globalIndex()] = fwdTrkId; + fwdTrkId += 1; + } + + // loop over global muon tracks + for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { + auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + + try { + auto remappedMchId = mchTrackIdRemapping.at(mchTrack.globalIndex()); + + mftTable(collId, + mftTrack.x(), mftTrack.y(), mftTrack.z(), + mftTrack.phi(), mftTrack.tgl(), mftTrack.signed1Pt(), + mftTrack.mftClusterSizesAndTrackFlags(), mftTrack.chi2()); + + fwdTable(collId, + muonTrack.trackType(), + muonTrack.x(), muonTrack.y(), muonTrack.z(), + muonTrack.phi(), muonTrack.tgl(), muonTrack.signed1Pt(), + muonTrack.nClusters(), muonTrack.pDca(), muonTrack.rAtAbsorberEnd(), + muonTrack.chi2(), muonTrack.chi2MatchMCHMFT(), + mftTrkId, remappedMchId, + muonTrack.cXX(), + muonTrack.cXY(), + muonTrack.cYY(), + muonTrack.cPhiX(), + muonTrack.cPhiY(), + muonTrack.cPhiPhi(), + muonTrack.cTglX(), + muonTrack.cTglY(), + muonTrack.cTglPhi(), + muonTrack.cTglTgl(), + muonTrack.c1PtX(), + muonTrack.c1PtY(), + muonTrack.c1PtPhi(), + muonTrack.c1PtTgl(), + muonTrack.c1Pt21Pt2()); + + fwdTrkId += 1; + mftTrkId += 1; + } catch (const std::exception& e) { + continue; + } + } + + collId += 1; + } + } +#endif + + template + void FillMftPlots(C const& collisions, + TMUON const& muonTracks, + TMFT const& mftTracks, + const std::unordered_map& collisionInfos) + { + // outer loop over collisions + for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { + auto const& collision = collisions.rawIteratorAt(collisionIndex); + registry.get(HIST("vertex_y_vs_x"))->Fill(collision.posX(), collision.posY()); registry.get(HIST("vertex_z"))->Fill(collision.posZ()); @@ -2017,13 +2373,15 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.get(HIST("DCA/MFT/DCAyVsVz"))->Fill(dcay, collision.posZ(), mftTrack.x(), mftTrack.y(), mftNclusters); } +#if (PROCESS_DERIVED_TABLES == 0) if (cfgProduceMFTTable) { - mftTable(collision.posX(), collision.posY(), collision.posZ(), - mftTrack.signed1Pt(), mftTrack.tgl(), mftTrack.phi(), - dcax, dcay, mftTrackAtDCA.getSigma2X(), mftTrackAtDCA.getSigma2Y(), mftTrackAtDCA.getSigmaXY(), - mftNclusters, mftTrack.chi2(), - mftTrack.x(), mftTrack.y(), mftTrack.z()); + compactMftTable(collision.posX(), collision.posY(), collision.posZ(), + mftTrack.signed1Pt(), mftTrack.tgl(), mftTrack.phi(), + dcax, dcay, mftTrackAtDCA.getSigma2X(), mftTrackAtDCA.getSigma2Y(), mftTrackAtDCA.getSigmaXY(), + mftNclusters, mftTrack.chi2(), + mftTrack.x(), mftTrack.y(), mftTrack.z()); } +#endif if (cfgEnableMftDcaExtraPlots) { static constexpr int nMftClustersMin = 6; @@ -2077,8 +2435,8 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc // loop over global muon tracks for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); - const auto& mchTrack = muonTrack.template matchMCHTrack_as(); - const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); auto mchIndex = mchTrack.globalIndex(); auto mftIndex = mftTrack.globalIndex(); @@ -2139,11 +2497,12 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } - void FillMchPlots(MyEvents const& collisions, - MyBCs const& bcs, - MyMuonsWithCov const& muonTracks, - aod::FwdTrkCls const& clusters, - const std::map& collisionInfos) + template + void FillMchPlots(C const& collisions, + TMUON const& muonTracks, + TCLS const& clusters, + TMFT const& /*mftTracks*/, + const std::unordered_map& collisionInfos) { if (!cfgEnableMftMchResidualsAnalysis && !cfgEnableMftMchMatchingAnalysis) { return; @@ -2152,19 +2511,12 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc // loop over collisions for (const auto& [collisionIndex, collisionInfo] : collisionInfos) { auto const& collision = collisions.rawIteratorAt(collisionIndex); - const auto& bc = bcs.rawIteratorAt(collision.bcId()); - - // remove TF/ROF borders and ambiguous collisions - if (!bc.selection_bit(o2::aod::evsel::kNoTimeFrameBorder) || - !bc.selection_bit(o2::aod::evsel::kNoITSROFrameBorder)) { - continue; - } // loop over global muon tracks for (const auto& [muonIndex, globalTracksVector] : collisionInfo.globalMuonTracks) { auto const& muonTrack = muonTracks.rawIteratorAt(globalTracksVector[0]); - const auto& mchTrack = muonTrack.template matchMCHTrack_as(); - const auto& mftTrack = muonTrack.template matchMFTTrack_as(); + const auto& mchTrack = muonTrack.template matchMCHTrack_as(); + const auto& mftTrack = muonTrack.template matchMFTTrack_as(); // int quadrant = GetQuadrant(mchTrack); int quadrant = GetQuadrant(mftTrack); int posNeg = (mchTrack.sign() >= 0) ? 0 : 1; @@ -2437,9 +2789,10 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc registry.get(histConfigTauz)->Fill(tauz, invMass, p, pT, quadrant1, quadrant2); } - void FillDimuonPlots(MyEvents const& collisions, - MyMuonsWithCov const& muonTracks, - const std::map& collisionInfos) + template + void FillDimuonPlots(C const& collisions, + TMUON const& muonTracks, + const std::unordered_map& collisionInfos) { if (!cfgEnableDimuonAnalysis) { return; @@ -2611,11 +2964,11 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc } } +#if (PROCESS_DERIVED_TABLES == 0) void processQA(MyEvents const& collisions, MyBCs const& bcs, MyMuonsWithCov const& muonTracks, MyMFTs const& mftTracks, - // MyMFTCovariances const& mftCovariances, aod::FwdTrkCls const& clusters) { auto bc = bcs.begin(); @@ -2626,21 +2979,88 @@ struct muonGlobalAlignment { // o2-linter: disable=name/workflow-file,name/struc mRunNumber = bc.runNumber(); } - std::map collisionInfos; + std::unordered_map collisionInfos; InitCollisions(collisions, bcs, muonTracks, clusters, mftTracks, collisionInfos); - FillMftPlots(collisions, bcs, muonTracks, mftTracks, collisionInfos); + if (cfgProduceMuonAlignmentTables) { + StoreCollisions(collisionInfos, collisions, muonTracks, clusters, mftTracks); + } + + FillMftPlots(collisions, muonTracks, mftTracks, collisionInfos); - FillMchPlots(collisions, bcs, muonTracks, clusters, collisionInfos); + FillMchPlots(collisions, muonTracks, clusters, mftTracks, collisionInfos); FillDimuonPlots(collisions, muonTracks, collisionInfos); } - PROCESS_SWITCH(muonGlobalAlignment, processQA, "processQA", true); + PROCESS_SWITCH(MuonGlobalAlignment, processQA, "processQA", true); + +#else + + void processDerivedTables(o2::aod::MuonAlignCollisions const& collisions, + o2::aod::MuonAlignFwdTrkCls const& clusters, + o2::aod::MuonAlignMFTTracks const& mftTracks, + o2::aod::MuonAlignFwdTracks const& muonTracks) + { + if (collisions.size() < 1) { + return; + } + const auto& c = collisions.begin(); + if (mRunNumber != c.runNumber()) { + initCCDB(c); + LOGF(info, "Set field for muons"); + VarManager::SetupMuonMagField(); + mRunNumber = c.runNumber(); + } + + std::unordered_map collisionInfos; + InitCollisionsDerivedTables(collisions, muonTracks, clusters, mftTracks, collisionInfos); + + FillMftPlots(collisions, muonTracks, mftTracks, collisionInfos); + + FillMchPlots(collisions, muonTracks, clusters, mftTracks, collisionInfos); + + FillDimuonPlots(collisions, muonTracks, collisionInfos); + } + + PROCESS_SWITCH(MuonGlobalAlignment, processDerivedTables, "processDerivedTables", true); +#endif }; +#if (PROCESS_DERIVED_TABLES == 1) +// Extends the fwdtracksrealign table with expression columns +struct MuonGlobalAlignmentSpawner { + Spawns realignFwdTrks; + Spawns realignMftTrks; + void init(InitContext const&) {} + + auto process(o2::aod::StoredMuonAlignFwdTracks const& storedFwd, + o2::aod::StoredMuonAlignMFTTracks const& storedMft) + { + // Evaluate the dynamic kinematic expressions on the fly + auto fwdExtended = o2::soa::Extend(storedFwd); + + auto mftExtended = o2::soa::Extend(storedMft); + + return std::make_tuple(fwdExtended, mftExtended); + } +}; +#endif + WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) { +#if (PROCESS_DERIVED_TABLES == 0) + return WorkflowSpec{ + adaptAnalysisTask(cfgc)}; +#else return WorkflowSpec{ - adaptAnalysisTask(cfgc)}; + adaptAnalysisTask(cfgc), + adaptAnalysisTask(cfgc)}; +#endif };