diff --git a/PWGDQ/Tasks/muonGlobalAlignment.cxx b/PWGDQ/Tasks/muonGlobalAlignment.cxx index 7ffbc5f2c6c..c2af75b9639 100644 --- a/PWGDQ/Tasks/muonGlobalAlignment.cxx +++ b/PWGDQ/Tasks/muonGlobalAlignment.cxx @@ -32,6 +32,8 @@ #include #include +#include "rapidjson/document.h" + #include #include #include @@ -114,6 +116,7 @@ struct muonGlobalAlignment { Configurable fChamberResolutionX{"cfgChamberResolutionX", 0.4, "Chamber resolution along X configuration for refit"}; // 0.4cm pp, 0.2cm PbPb Configurable fChamberResolutionY{"cfgChamberResolutionY", 0.4, "Chamber resolution along Y configuration for refit"}; // 0.4cm pp, 0.2cm PbPb Configurable fSigmaCutImprove{"cfgSigmaCutImprove", 6., "Sigma cut for track improvement"}; + Configurable fMCHRealignCorrections{"cfgMCHRealignCorrections", "", "MCH DE positions/angles corrections in JSON format"}; } configRealign; //// Variables for ccdb @@ -167,6 +170,13 @@ struct muonGlobalAlignment { TrackFitter trackFitter; // Track fitter from MCH tracking library double mImproveCutChi2; // Chi2 cut for track improvement. + struct AlignmentCorrections { + double x{0}; + double y{0}; + double z{0}; + }; + std::map mMchAlignmentCorrections; + Preslice perMuon = aod::fwdtrkcl::fwdtrackId; o2::aod::rctsel::RCTFlagsChecker rctChecker{"CBT_muon_glo", false, false, true}; @@ -361,6 +371,26 @@ struct muonGlobalAlignment { trackFitter.useChamberResolution(); mImproveCutChi2 = 2. * configRealign.fSigmaCutImprove * configRealign.fSigmaCutImprove; + // Fill table of MCH alignment corrections + rapidjson::Document document; + // Check that the json is parsed correctly + rapidjson::ParseResult jsonOk = document.Parse(configRealign.fMCHRealignCorrections.value.c_str()); + if (jsonOk) { + for (rapidjson::Value::ConstMemberIterator it = document.MemberBegin(); it != document.MemberEnd(); it++) { + LOG(info) << "DE" << it->name.GetString() << " alignment corrections:"; + LOG(info) << " x: " << it->value["x"].GetDouble(); + LOG(info) << " y: " << it->value["y"].GetDouble(); + LOG(info) << " z: " << it->value["z"].GetDouble(); + + mMchAlignmentCorrections[std::stoi(it->name.GetString())] = { + it->value["x"].GetDouble(), + it->value["y"].GetDouble(), + it->value["z"].GetDouble()}; + } + } else { + LOG(error) << "JSON parse error: " << rapidjson::GetParseErrorFunc(jsonOk.Code()) << " (" << jsonOk.Offset() << ")"; + } + float mftLadderWidth = 1.7; AxisSpec dcaxMFTAxis = {400, -0.5, 0.5, "DCA_{x} (cm)"}; AxisSpec dcayMFTAxis = {400, -0.5, 0.5, "DCA_{y} (cm)"}; @@ -375,6 +405,8 @@ struct muonGlobalAlignment { AxisSpec vyAxis = {400, -0.5, 0.5, "vtx_{y} (cm)"}; AxisSpec vzAxis = {1000, -10.0, 10.0, "vtx_{z} (cm)"}; AxisSpec phiAxis = {36, -180.0, 180.0, "#phi (degrees)"}; + AxisSpec sxAxis = {50, -0.25, 0.25, "x slope"}; + AxisSpec syAxis = {50, -0.25, 0.25, "y slope"}; AxisSpec momAxis = {500, 0, 100.0, "p (GeV/c)"}; AxisSpec nMftClustersAxis = {6, 5, 11, "# of clusters"}; AxisSpec mftTrackTypeAxis = {2, 0, 2, "track type"}; @@ -395,6 +427,11 @@ struct muonGlobalAlignment { if (fEnableVertexShiftAnalysis) { registry.add("DCA/MFT/DCA_x_vs_phi_vs_zshift", std::format("DCA(x) vs. #phi vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, phiAxis, dcaxMFTAxis}}); registry.add("DCA/MFT/DCA_y_vs_phi_vs_zshift", std::format("DCA(y) vs. #phi vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, phiAxis, dcayMFTAxis}}); + + registry.add("DCA/MFT/DCA_x_vs_slopex_vs_zshift", std::format("DCA(x) vs. x slope vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, sxAxis, dcaxMFTAxis}}); + registry.add("DCA/MFT/DCA_x_vs_slopey_vs_zshift", std::format("DCA(x) vs. y slope vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, syAxis, dcaxMFTAxis}}); + registry.add("DCA/MFT/DCA_y_vs_slopex_vs_zshift", std::format("DCA(y) vs. x slope vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, sxAxis, dcayMFTAxis}}); + registry.add("DCA/MFT/DCA_y_vs_slopey_vs_zshift", std::format("DCA(y) vs. y slope vs. z shift").c_str(), {HistType::kTH3F, {zshiftAxis, syAxis, dcayMFTAxis}}); } if (fEnableMftDcaAnalysis) { @@ -438,6 +475,9 @@ struct muonGlobalAlignment { registry.add("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_mom", std::format("DCA(x) vs. p, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {{20, 0, 100.0, "p (GeV/c)"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcaxMCHAxis}}); registry.add("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_mom", std::format("DCA(y) vs. p, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {{20, 0, 100.0, "p (GeV/c)"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcayMCHAxis}}); + registry.add("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_mom_corr", std::format("DCA(x) vs. p, quadrant, chargeSign (with corrections)").c_str(), {HistType::kTHnSparseF, {{20, 0, 100.0, "p (GeV/c)"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcaxMCHAxis}}); + registry.add("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_mom_corr", std::format("DCA(y) vs. p, quadrant, chargeSign (with corrections)").c_str(), {HistType::kTHnSparseF, {{20, 0, 100.0, "p (GeV/c)"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcayMCHAxis}}); + registry.add("residuals/dx_vs_chamber", "Cluster x residual vs. chamber, quadrant, chargeSign", {HistType::kTHnSparseF, {{10, 1, 11, "chamber"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dxAxis}}); registry.add("residuals/dy_vs_chamber", "Cluster y residual vs. chamber, quadrant, chargeSign", @@ -448,6 +488,16 @@ struct muonGlobalAlignment { registry.add("residuals/dy_vs_de", "Cluster y residual vs. DE, quadrant, chargeSign, momentum", {HistType::kTHnSparseF, {dyAxis, {getNumDE(), 0, static_cast(getNumDE()), "DE"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, {20, 0, 100.0, "p (GeV/c)"}}}); + registry.add("residuals/dx_vs_chamber_corr", "Cluster x residual vs. chamber, quadrant, chargeSign (with corrections)", + {HistType::kTHnSparseF, {{10, 1, 11, "chamber"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dxAxis}}); + registry.add("residuals/dy_vs_chamber_corr", "Cluster y residual vs. chamber, quadrant, chargeSign (with corrections)", + {HistType::kTHnSparseF, {{10, 1, 11, "chamber"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dyAxis}}); + + registry.add("residuals/dx_vs_de_corr", "Cluster x residual vs. DE, quadrant, chargeSign, momentum (with corrections)", + {HistType::kTHnSparseF, {dxAxis, {getNumDE(), 0, static_cast(getNumDE()), "DE"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, {20, 0, 100.0, "p (GeV/c)"}}}); + registry.add("residuals/dy_vs_de_corr", "Cluster y residual vs. DE, quadrant, chargeSign, momentum (with corrections)", + {HistType::kTHnSparseF, {dyAxis, {getNumDE(), 0, static_cast(getNumDE()), "DE"}, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, {20, 0, 100.0, "p (GeV/c)"}}}); + if (fEnableMftMchResidualsExtraPlots) { registry.add("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_vz", std::format("DCA(x) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcazAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcaxMCHAxis}}); registry.add("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_vz", std::format("DCA(y) vs. vz, quadrant, chargeSign").c_str(), {HistType::kTHnSparseF, {dcazAxis, {4, 0, 4, "quadrant"}, {2, 0, 2, "sign"}, dcayMCHAxis}}); @@ -917,7 +967,7 @@ struct muonGlobalAlignment { return fwdtrack; } - void TransformMFT(o2::mch::TrackParam& track) + void TransformMFTPar(o2::mch::TrackParam& track) { // double zCH10 = -1437.6; double z = track.getZ(); @@ -950,7 +1000,7 @@ struct muonGlobalAlignment { { auto mchTrack = FwdtoMCH(track); - TransformMFT(mchTrack); + TransformMFTPar(mchTrack); auto transformedTrack = sExtrap.MCHtoFwd(mchTrack); track.setParameters(transformedTrack.getParameters()); @@ -967,7 +1017,7 @@ struct muonGlobalAlignment { auto mchTrack = FwdtoMCH(track); - TransformMFT(mchTrack); + TransformMFTPar(mchTrack); auto transformedTrack = sExtrap.MCHtoFwd(mchTrack); fwdtrack.setParameters(transformedTrack.getParameters()); @@ -1217,11 +1267,11 @@ struct muonGlobalAlignment { return propmuon; } - template - o2::dataformats::GlobalFwdTrack PropagateMFTtoMCH(const TMFT& mftTrack, const TMCH& mchTrack, const double z) + template + o2::dataformats::GlobalFwdTrack PropagateMFTtoMCH(const TMFT& mftTrack, const o2::mch::TrackParam& mchTrackPar, const double z) { // extrapolation with MCH tools - auto mchTrackAtMFT = FwdtoMCH(FwdToTrackPar(mchTrack)); + auto mchTrackAtMFT = mchTrackPar; o2::mch::TrackExtrap::extrapToVertexWithoutBranson(mchTrackAtMFT, mftTrack.z()); auto mftTrackPar = FwdToTrackPar(mftTrack); @@ -1232,24 +1282,13 @@ struct muonGlobalAlignment { UpdateTrackMomentum(mftTrackProp, mchTrackAtMFT); if (z < -505.f) { o2::mch::TrackExtrap::extrapToZ(mftTrackProp, -466.f); - UpdateTrackMomentum(mftTrackProp, sExtrap.FwdtoMCH(FwdToTrackPar(mchTrack))); + UpdateTrackMomentum(mftTrackProp, mchTrackPar); } o2::mch::TrackExtrap::extrapToZ(mftTrackProp, z); return MCHtoFwd(mftTrackProp); } - template - o2::dataformats::GlobalFwdTrack PropagateMFTtoMCH_(const TMFT& mftTrack, const TMCH& mchTrack, const double z) - { - // extrapolation with MCH tools - auto mftTrackProp = sExtrap.FwdtoMCH(FwdToTrackPar(mftTrack)); - UpdateTrackMomentum(mftTrackProp, sExtrap.FwdtoMCH(FwdToTrackPar(mchTrack))); - o2::mch::TrackExtrap::extrapToZ(mftTrackProp, z); - - return sExtrap.MCHtoFwd(mftTrackProp); - } - void FillDCAPlots(MyEvents const& collisions, MyBCs const& bcs, MyMuonsWithCov const& muonTracks, @@ -1346,7 +1385,7 @@ struct muonGlobalAlignment { } if (fEnableVertexShiftAnalysis) { - if (mftTrack.chi2() <= fTrackChi2MftUp && std::fabs(collision.posZ()) < 1.f) { + if (mftTrack.chi2() <= fTrackChi2MftUp && std::fabs(collision.posZ()) < 1.f && mftNclusters >= 6) { float zshift[21] = {// in millimeters -5.0, -4.5, -4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0}; @@ -1356,6 +1395,14 @@ struct muonGlobalAlignment { double dcayShifted = mftTrackAtDCAshifted.getY() - collision.posY(); registry.get(HIST("DCA/MFT/DCA_x_vs_phi_vs_zshift"))->Fill(zshift[zi], phi, dcaxShifted); registry.get(HIST("DCA/MFT/DCA_y_vs_phi_vs_zshift"))->Fill(zshift[zi], phi, dcayShifted); + + auto mftTrackAtDCAshiftedPar = FwdtoMCH(mftTrackAtDCAshifted); + auto slopex = mftTrackAtDCAshiftedPar.getNonBendingSlope(); + auto slopey = mftTrackAtDCAshiftedPar.getBendingSlope(); + registry.get(HIST("DCA/MFT/DCA_x_vs_slopex_vs_zshift"))->Fill(zshift[zi], slopex, dcaxShifted); + registry.get(HIST("DCA/MFT/DCA_x_vs_slopey_vs_zshift"))->Fill(zshift[zi], slopey, dcaxShifted); + registry.get(HIST("DCA/MFT/DCA_y_vs_slopex_vs_zshift"))->Fill(zshift[zi], slopex, dcayShifted); + registry.get(HIST("DCA/MFT/DCA_y_vs_slopey_vs_zshift"))->Fill(zshift[zi], slopey, dcayShifted); } } } @@ -1386,7 +1433,7 @@ struct muonGlobalAlignment { continue; } - bool isGoodMFT = IsGoodMFT(mftTrack, 999.f, 5); + bool isGoodMFT = IsGoodMFT(mftTrack, fTrackChi2MftUp, 5); if (!isGoodMFT) { continue; } @@ -1409,6 +1456,68 @@ struct muonGlobalAlignment { } } + template + bool MchRealignTrack(const TMUON& mchTrack, const TCLUS& clusters, TrackRealigned& convertedTrack, bool applyCorrections) + { + // loop over attached clusters + int clIndex = -1; + auto clustersSliced = clusters.sliceBy(perMuon, mchTrack.globalIndex()); // Slice clusters by muon id + for (auto const& cluster : clustersSliced) { + clIndex += 1; + + int deId = cluster.deId(); + int chamber = deId / 100 - 1; + if (chamber < 0 || chamber > 9) { + continue; + } + + math_utils::Point3D local; + math_utils::Point3D master; + + master.SetXYZ(cluster.x(), cluster.y(), cluster.z()); + + if (configRealign.fEnableMCHRealign) { + // Transformation from reference geometry frame to new geometry frame + transformRef[cluster.deId()].MasterToLocal(master, local); + transformNew[cluster.deId()].LocalToMaster(local, master); + } + + if (applyCorrections) { + auto correctionsIt = mMchAlignmentCorrections.find(cluster.deId()); + if (correctionsIt != mMchAlignmentCorrections.end()) { + const auto& corrections = correctionsIt->second; + master.SetX(master.x() + corrections.x); + master.SetY(master.y() + corrections.y); + master.SetZ(master.z() + corrections.z); + } + } + + // realigned MCH cluster + mch::Cluster* clusterMCH = new mch::Cluster(); + clusterMCH->x = master.x(); + clusterMCH->y = master.y(); + clusterMCH->z = master.z(); + + uint32_t ClUId = mch::Cluster::buildUniqueId(static_cast(cluster.deId() / 100) - 1, cluster.deId(), clIndex); + clusterMCH->uid = ClUId; + clusterMCH->ex = cluster.isGoodX() ? 0.2 : 10.0; + clusterMCH->ey = cluster.isGoodY() ? 0.2 : 10.0; + + // Add transformed cluster into temporary variable + convertedTrack.createParamAtCluster(*clusterMCH); + } + + bool removable{false}; + // Refit the re-aligned track + if (convertedTrack.getNClusters() != 0) { + removable = RemoveTrack(convertedTrack); + } else { + LOGF(fatal, "Muon track %d has no associated clusters.", mchTrack.globalIndex()); + } + + return !removable; + } + void FillResidualsPlots(MyEvents const& collisions, MyBCs const& bcs, MyMuonsWithCov const& muonTracks, @@ -1445,13 +1554,23 @@ struct muonGlobalAlignment { if (!isGoodMFT) continue; + // refit MCH track if enabled TrackRealigned convertedTrack; + bool convertedTrackOk = false; + if (configRealign.fEnableMCHRealign) { + convertedTrackOk = MchRealignTrack(mchTrack, clusters, convertedTrack, false); + } + + // apply alignment corrections if available + TrackRealigned convertedTrackWithCorr; + bool convertedTrackWithCorrOk = false; + if (!mMchAlignmentCorrections.empty()) { + convertedTrackWithCorrOk = MchRealignTrack(mchTrack, clusters, convertedTrackWithCorr, true); + } + // loop over attached clusters - int clIndex = -1; auto clustersSliced = clusters.sliceBy(perMuon, mchTrack.globalIndex()); // Slice clusters by muon id for (auto const& cluster : clustersSliced) { - clIndex += 1; - int deId = cluster.deId(); int chamber = deId / 100 - 1; if (chamber < 0 || chamber > 9) @@ -1460,51 +1579,65 @@ struct muonGlobalAlignment { math_utils::Point3D local; math_utils::Point3D master; + math_utils::Point3D masterWithCorr; master.SetXYZ(cluster.x(), cluster.y(), cluster.z()); + masterWithCorr.SetXYZ(cluster.x(), cluster.y(), cluster.z()); + // apply realignment to MCH cluster if (configRealign.fEnableMCHRealign) { // Transformation from reference geometry frame to new geometry frame transformRef[cluster.deId()].MasterToLocal(master, local); transformNew[cluster.deId()].LocalToMaster(local, master); + transformNew[cluster.deId()].LocalToMaster(local, masterWithCorr); + } - mch::Cluster* clusterMCH = new mch::Cluster(); - clusterMCH->x = master.x(); - clusterMCH->y = master.y(); - clusterMCH->z = master.z(); + // apply alignment corrections to MCH cluster (if available) + if (!mMchAlignmentCorrections.empty()) { + auto correctionsIt = mMchAlignmentCorrections.find(cluster.deId()); + if (correctionsIt != mMchAlignmentCorrections.end()) { + const auto& corrections = correctionsIt->second; + masterWithCorr.SetX(masterWithCorr.x() + corrections.x); + masterWithCorr.SetY(masterWithCorr.y() + corrections.y); + masterWithCorr.SetZ(masterWithCorr.z() + corrections.z); + } + } - uint32_t ClUId = mch::Cluster::buildUniqueId(static_cast(cluster.deId() / 100) - 1, cluster.deId(), clIndex); - clusterMCH->uid = ClUId; - clusterMCH->ex = cluster.isGoodX() ? 0.2 : 10.0; - clusterMCH->ey = cluster.isGoodY() ? 0.2 : 10.0; + // MFT-MCH residuals (MCH cluster is realigned if enabled) + // if the realignment is enabled and successful, the MFT track is extrpolated + // by taking the momentum from the MCH track refitted with the new alignment + if (!configRealign.fEnableMCHRealign || convertedTrackOk) { + auto mftTrackAtCluster = configRealign.fEnableMCHRealign ? PropagateMFTtoMCH(mftTrack, mch::TrackParam(convertedTrack.first()), master.z()) : PropagateMFTtoMCH(mftTrack, FwdtoMCH(FwdToTrackPar(mchTrack)), master.z()); - // Add transformed cluster into temporary variable - convertedTrack.createParamAtCluster(*clusterMCH); - } + std::array xPos{master.x(), mftTrackAtCluster.getX()}; + std::array yPos{master.y(), mftTrackAtCluster.getY()}; - auto mftTrackAtCluster = PropagateMFTtoMCH(mftTrack, mchTrack, master.z()); + registry.get(HIST("residuals/dx_vs_chamber"))->Fill(chamber + 1, quadrantMch, posNeg, xPos[0] - xPos[1]); + registry.get(HIST("residuals/dy_vs_chamber"))->Fill(chamber + 1, quadrantMch, posNeg, yPos[0] - yPos[1]); - std::array xPos{master.x(), mftTrackAtCluster.getX()}; - std::array yPos{master.y(), mftTrackAtCluster.getY()}; + registry.get(HIST("residuals/dx_vs_de"))->Fill(xPos[0] - xPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); + registry.get(HIST("residuals/dy_vs_de"))->Fill(yPos[0] - yPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); + } - registry.get(HIST("residuals/dx_vs_chamber"))->Fill(chamber + 1, quadrantMch, posNeg, xPos[0] - xPos[1]); - registry.get(HIST("residuals/dy_vs_chamber"))->Fill(chamber + 1, quadrantMch, posNeg, yPos[0] - yPos[1]); + // MFT-MCH residuals with realigned and/or corrected MCH clusters + // if the alignment corrections are available and the refitting is successful, the MFT track is extrpolated + // by taking the momentum from the MCH track refitted with the alignment corrections and the new + // alignment (if realignment is enabled) + if (convertedTrackWithCorrOk) { + auto mftTrackAtClusterWithCorr = PropagateMFTtoMCH(mftTrack, mch::TrackParam(convertedTrackWithCorr.first()), masterWithCorr.z()); - registry.get(HIST("residuals/dx_vs_de"))->Fill(xPos[0] - xPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); - registry.get(HIST("residuals/dy_vs_de"))->Fill(yPos[0] - yPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); - } + std::array xPos{masterWithCorr.x(), mftTrackAtClusterWithCorr.getX()}; + std::array yPos{masterWithCorr.y(), mftTrackAtClusterWithCorr.getY()}; - bool removable{false}; - if (configRealign.fEnableMCHRealign) { - // Refit the re-aligned track - if (convertedTrack.getNClusters() != 0) { - removable = RemoveTrack(convertedTrack); - } else { - LOGF(fatal, "Muon track %d has no associated clusters.", mchTrack.globalIndex()); + registry.get(HIST("residuals/dx_vs_chamber_corr"))->Fill(chamber + 1, quadrantMch, posNeg, xPos[0] - xPos[1]); + registry.get(HIST("residuals/dy_vs_chamber_corr"))->Fill(chamber + 1, quadrantMch, posNeg, yPos[0] - yPos[1]); + + registry.get(HIST("residuals/dx_vs_de_corr"))->Fill(xPos[0] - xPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); + registry.get(HIST("residuals/dy_vs_de_corr"))->Fill(yPos[0] - yPos[1], deIndex, quadrantMch, posNeg, mchTrack.p()); } } - if (!removable) { + if (!configRealign.fEnableMCHRealign || convertedTrackOk) { auto mchTrackAtDCA = configRealign.fEnableMCHRealign ? PropagateMCHRealigned(convertedTrack, collision.posZ()) : PropagateMCH(mchTrack, collision.posZ()); auto dcax = mchTrackAtDCA.getX() - collision.posX(); auto dcay = mchTrackAtDCA.getY() - collision.posY(); @@ -1521,6 +1654,15 @@ struct muonGlobalAlignment { registry.get(HIST("residuals/dphi_at_mft"))->Fill(deltaPhi, mftTrack.x(), mftTrack.y(), posNeg, mchTrackAtMFT.getP()); } } + + if (convertedTrackWithCorrOk) { + auto mchTrackAtDCA = PropagateMCHRealigned(convertedTrackWithCorr, collision.posZ()); + auto dcax = mchTrackAtDCA.getX() - collision.posX(); + auto dcay = mchTrackAtDCA.getY() - collision.posY(); + + registry.get(HIST("DCA/MCH/DCA_x_vs_sign_vs_quadrant_vs_mom_corr"))->Fill(mchTrack.p(), quadrantMch, posNeg, dcax); + registry.get(HIST("DCA/MCH/DCA_y_vs_sign_vs_quadrant_vs_mom_corr"))->Fill(mchTrack.p(), quadrantMch, posNeg, dcay); + } } } }