Skip to content

Commit 26437ff

Browse files
rolavickalibuild
andauthored
[PWGUD] new propagation to vertex for global muons (#15475)
Co-authored-by: ALICE Action Bot <alibuild@cern.ch>
1 parent 09779f0 commit 26437ff

File tree

1 file changed

+120
-12
lines changed

1 file changed

+120
-12
lines changed

PWGUD/TableProducer/upcCandProducerGlobalMuon.cxx

Lines changed: 120 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
#include "PWGUD/Core/UPCCutparHolder.h"
1818
#include "PWGUD/Core/UPCHelpers.h"
1919

20+
#include "Common/Core/fwdtrackUtilities.h"
21+
2022
#include "CCDB/BasicCCDBManager.h"
23+
#include "CommonConstants/GeomConstants.h"
2124
#include "CommonConstants/LHCConstants.h"
2225
#include "DataFormatsParameters/GRPMagField.h"
2326
#include "DetectorsBase/Propagator.h"
@@ -71,6 +74,13 @@ struct UpcCandProducerGlobalMuon {
7174
Configurable<float> fMaxEtaMFT{"fMaxEtaMFT", -2.5, "Maximum eta for MFT acceptance"};
7275
Configurable<bool> fSaveMFTClusters{"fSaveMFTClusters", true, "Save MFT cluster information"};
7376

77+
// Ambiguous track propagation configurables
78+
Configurable<bool> fApplyZShiftFromCCDB{"fApplyZShiftFromCCDB", false, "Apply z-shift from CCDB for global muon propagation"};
79+
Configurable<std::string> fZShiftPath{"fZShiftPath", "Users/m/mcoquet/ZShift", "CCDB path for z-shift"};
80+
Configurable<float> fManualZShift{"fManualZShift", 0.0f, "Manual z-shift for global muon propagation to PV"};
81+
Configurable<float> fMaxDCAxy{"fMaxDCAxy", 999.f, "Maximum DCAxy for global muon track selection (cm)"};
82+
Configurable<int> fBcWindowCollision{"fBcWindowCollision", 4, "BC window for collision search for DCA-based vertex assignment"};
83+
7484
using ForwardTracks = o2::soa::Join<o2::aod::FwdTracks, o2::aod::FwdTracksCov>;
7585

7686
HistogramRegistry histRegistry{"HistRegistry", {}, OutputObjHandlingPolicy::AnalysisObject};
@@ -80,10 +90,15 @@ struct UpcCandProducerGlobalMuon {
8090
o2::ccdb::CcdbApi fCCDBApi;
8191
o2::globaltracking::MatchGlobalFwd fMatching;
8292

93+
// Ambiguous track propagation members
94+
float fBz{0}; // Magnetic field at MFT center
95+
static constexpr double fCcenterMFT[3] = {0, 0, -61.4}; // Field evaluation point at center of MFT
96+
float fZShift{0}; // z-vertex shift for forward track propagation
97+
8398
void init(InitContext&)
8499
{
85100
fUpcCuts = (UPCCutparHolder)fUpcCutsConf;
86-
if (fUpcCuts.getUseFwdCuts()) {
101+
if (fUpcCuts.getUseFwdCuts() || fEnableMFT) {
87102
fCCDB->setURL("http://alice-ccdb.cern.ch");
88103
fCCDB->setCaching(true);
89104
fCCDB->setLocalObjectValidityChecking();
@@ -110,6 +125,12 @@ struct UpcCandProducerGlobalMuon {
110125
const AxisSpec axisEta{100, -4.0, -2.0, "#eta"};
111126
histRegistry.add("hEtaMFT", "MFT track eta", kTH1F, {axisEta});
112127
histRegistry.add("hEtaGlobal", "Global track eta", kTH1F, {axisEta});
128+
129+
const AxisSpec axisDCAxy{200, 0., 10., "DCA_{xy} (cm)"};
130+
const AxisSpec axisDCAz{200, -10., 10., "DCA_{z} (cm)"};
131+
histRegistry.add("hDCAxyGlobal", "DCAxy of global tracks to best collision", kTH1F, {axisDCAxy});
132+
histRegistry.add("hDCAzGlobal", "DCAz of global tracks to best collision", kTH1F, {axisDCAz});
133+
histRegistry.add("hNCompatColls", "Number of compatible collisions per global track", kTH1F, {{21, -0.5, 20.5}});
113134
}
114135
}
115136

@@ -436,6 +457,19 @@ struct UpcCandProducerGlobalMuon {
436457
return (eta > fMinEtaMFT && eta < fMaxEtaMFT);
437458
}
438459

460+
// Propagate global muon track to collision vertex using helix propagation
461+
// and compute DCA (adapted from ambiguousTrackPropagation)
462+
// Returns {DCAxy, DCAz, DCAx, DCAy}
463+
std::array<double, 4> propagateGlobalToDCA(ForwardTracks::iterator const& track,
464+
double colX, double colY, double colZ)
465+
{
466+
o2::track::TrackParCovFwd trackPar = o2::aod::fwdtrackutils::getTrackParCovFwdShift(track, fZShift);
467+
std::array<double, 3> dcaOrig;
468+
trackPar.propagateToDCAhelix(fBz, {colX, colY, colZ}, dcaOrig);
469+
double dcaXY = std::sqrt(dcaOrig[0] * dcaOrig[0] + dcaOrig[1] * dcaOrig[1]);
470+
return {dcaXY, dcaOrig[2], dcaOrig[0], dcaOrig[1]};
471+
}
472+
439473
void createCandidates(ForwardTracks const& fwdTracks,
440474
o2::aod::FwdTrkCls const& fwdTrkCls,
441475
o2::aod::AmbiguousFwdTracks const& ambFwdTracks,
@@ -451,7 +485,7 @@ struct UpcCandProducerGlobalMuon {
451485
using o2::aod::fwdtrack::ForwardTrackTypeEnum::MuonStandaloneTrack;
452486

453487
int32_t runNumber = bcs.iteratorAt(0).runNumber();
454-
if (fUpcCuts.getUseFwdCuts()) {
488+
if (fUpcCuts.getUseFwdCuts() || fEnableMFT) {
455489
if (runNumber != fRun) {
456490
fRun = runNumber;
457491
std::map<std::string, std::string> metadata;
@@ -461,7 +495,28 @@ struct UpcCandProducerGlobalMuon {
461495
o2::base::Propagator::initFieldFromGRP(grpmag);
462496
if (!o2::base::GeometryManager::isGeometryLoaded())
463497
fCCDB->get<TGeoManager>("GLO/Config/GeometryAligned");
464-
o2::mch::TrackExtrap::setField();
498+
if (fUpcCuts.getUseFwdCuts()) {
499+
o2::mch::TrackExtrap::setField();
500+
}
501+
// Initialize MFT magnetic field and z-shift for ambiguous track propagation
502+
if (fEnableMFT) {
503+
o2::field::MagneticField* field = static_cast<o2::field::MagneticField*>(TGeoGlobalMagField::Instance()->GetField());
504+
fBz = field->getBz(fCcenterMFT);
505+
LOG(info) << "Magnetic field at MFT center: bZ = " << fBz;
506+
if (fApplyZShiftFromCCDB) {
507+
auto* zShift = fCCDB->getForTimeStamp<std::vector<float>>(fZShiftPath, ts);
508+
if (zShift != nullptr && !zShift->empty()) {
509+
fZShift = (*zShift)[0];
510+
LOGF(info, "z-shift from CCDB: %f cm", fZShift);
511+
} else {
512+
fZShift = 0;
513+
LOGF(info, "z-shift not found in CCDB path %s, set to 0 cm", fZShiftPath.value);
514+
}
515+
} else {
516+
fZShift = fManualZShift;
517+
LOGF(info, "z-shift manually set to %f cm", fZShift);
518+
}
519+
}
465520
}
466521
}
467522

@@ -533,6 +588,15 @@ struct UpcCandProducerGlobalMuon {
533588
}
534589
}
535590

591+
// Map global BC to collisions for DCA-based vertex assignment
592+
std::map<uint64_t, std::vector<int64_t>> mapGlobalBCtoCollisions;
593+
if (fEnableMFT) {
594+
for (const auto& col : collisions) {
595+
uint64_t gbc = vGlobalBCs[col.bcId()];
596+
mapGlobalBCtoCollisions[gbc].push_back(col.globalIndex());
597+
}
598+
}
599+
536600
std::vector<int64_t> selTrackIds{}; // NEW: For cluster saving
537601

538602
int32_t candId = 0;
@@ -552,34 +616,77 @@ struct UpcCandProducerGlobalMuon {
552616
continue;
553617
}
554618

555-
uint16_t numContrib = 0;
556619
auto& vGlobalIds = gbc_globalids.second;
557620

558-
// Check if we have global tracks (with MFT)
621+
// Step 1: Find best collision vertex using DCA-based propagation
622+
// (adapted from ambiguousTrackPropagation processMFTReassoc3D)
623+
float bestVtxX = 0., bestVtxY = 0., bestVtxZ = 0.;
624+
double bestAvgDCA = 999.;
625+
bool hasVertex = false;
626+
int nCompatColls = 0;
627+
628+
for (int dbc = -static_cast<int>(fBcWindowCollision); dbc <= static_cast<int>(fBcWindowCollision); dbc++) {
629+
uint64_t searchBC = globalBcGlobal + dbc;
630+
auto itCol = mapGlobalBCtoCollisions.find(searchBC);
631+
if (itCol == mapGlobalBCtoCollisions.end())
632+
continue;
633+
for (auto colIdx : itCol->second) {
634+
nCompatColls++;
635+
const auto& col = collisions.iteratorAt(colIdx);
636+
double sumDCAxy = 0.;
637+
int nTracks = 0;
638+
for (const auto& iglobal : vGlobalIds) {
639+
const auto& trk = fwdTracks.iteratorAt(iglobal);
640+
auto dca = propagateGlobalToDCA(trk, col.posX(), col.posY(), col.posZ());
641+
sumDCAxy += dca[0];
642+
nTracks++;
643+
}
644+
double avgDCA = nTracks > 0 ? sumDCAxy / nTracks : 999.;
645+
if (!hasVertex || avgDCA < bestAvgDCA) {
646+
bestAvgDCA = avgDCA;
647+
bestVtxX = col.posX();
648+
bestVtxY = col.posY();
649+
bestVtxZ = col.posZ();
650+
hasVertex = true;
651+
}
652+
}
653+
}
654+
655+
histRegistry.fill(HIST("hNCompatColls"), nCompatColls);
656+
657+
// Step 2: Select tracks with DCA quality cut
559658
std::vector<int64_t> tracksToSave;
560659
for (const auto& iglobal : vGlobalIds) {
561660
const auto& trk = fwdTracks.iteratorAt(iglobal);
562661

662+
// Apply DCA cut using best collision vertex
663+
if (hasVertex) {
664+
auto dca = propagateGlobalToDCA(trk, bestVtxX, bestVtxY, bestVtxZ);
665+
histRegistry.fill(HIST("hDCAxyGlobal"), dca[0]);
666+
histRegistry.fill(HIST("hDCAzGlobal"), dca[1]);
667+
if (dca[0] > static_cast<double>(fMaxDCAxy))
668+
continue;
669+
}
670+
563671
// Check MFT acceptance and decide which track to use
564672
if (isInMFTAcceptance(trk.eta())) {
565673
// Inside MFT acceptance - use global track
566674
tracksToSave.push_back(iglobal);
567675
histRegistry.fill(HIST("hEtaMFT"), trk.eta());
568676
} else {
569677
// Outside MFT acceptance - look for MCH-MID counterpart
570-
// Find the corresponding MCH-MID track at the same BC
571678
auto itMid = mapGlobalBcsWithMCHMIDTrackIds.find(globalBcGlobal);
572679
if (itMid != mapGlobalBcsWithMCHMIDTrackIds.end()) {
573-
// Use MCH-MID track instead
574680
if (!itMid->second.empty()) {
575681
tracksToSave.push_back(itMid->second[0]);
576-
itMid->second.erase(itMid->second.begin()); // Remove used track
682+
itMid->second.erase(itMid->second.begin());
577683
}
578684
}
579685
}
580686
}
581687

582-
// Write selected tracks
688+
// Step 3: Write tracks and event candidate with actual vertex position
689+
uint16_t numContrib = 0;
583690
for (const auto& trkId : tracksToSave) {
584691
if (!addToFwdTable(candId, trkId, globalBcGlobal, 0., fwdTracks, mcFwdTrackLabels))
585692
continue;
@@ -590,7 +697,7 @@ struct UpcCandProducerGlobalMuon {
590697
if (numContrib < 1)
591698
continue;
592699

593-
eventCandidates(globalBcGlobal, runNumber, 0., 0., 0., 0, numContrib, 0, 0);
700+
eventCandidates(globalBcGlobal, runNumber, bestVtxX, bestVtxY, bestVtxZ, 0, numContrib, 0, 0);
594701
std::vector<float> amplitudesV0A{};
595702
std::vector<int8_t> relBCsV0A{};
596703
std::vector<float> amplitudesT0A{};
@@ -683,8 +790,9 @@ struct UpcCandProducerGlobalMuon {
683790
vAmbFwdTrackIndexBCs.clear();
684791
mapGlobalBcsWithMCHMIDTrackIds.clear();
685792
mapGlobalBcsWithMCHTrackIds.clear();
686-
mapGlobalBcsWithGlobalTrackIds.clear(); // NEW
687-
selTrackIds.clear(); // NEW
793+
mapGlobalBcsWithGlobalTrackIds.clear();
794+
mapGlobalBCtoCollisions.clear();
795+
selTrackIds.clear();
688796
}
689797

690798
void processFwd(ForwardTracks const& fwdTracks,

0 commit comments

Comments
 (0)