|
9 | 9 | using namespace o2; |
10 | 10 | using namespace o2::framework; |
11 | 11 |
|
12 | | -// output textfile for muon tracks |
13 | | -std::ofstream muonTracksOut("muontracks.txt"); |
14 | | - |
15 | 12 | struct HFMuonFwdTracks { |
16 | 13 | // Histogram registry: an object to hold your histograms |
17 | 14 | HistogramRegistry histos{"histos", {}, |
18 | 15 | OutputObjHandlingPolicy::AnalysisObject}; |
19 | 16 |
|
20 | | - // store id of selected tracks to account for ambiguous tracks |
21 | | - std::vector<int64_t> selectedTracksID; |
| 17 | + // output textfile for muon tracks |
| 18 | + std::ofstream muonTracksOut; |
22 | 19 |
|
23 | 20 | void init(InitContext const&) |
24 | 21 | { |
| 22 | + // open output file and write header |
| 23 | + muonTracksOut.open("muonTracks_HF.csv"); |
| 24 | + if (!muonTracksOut.is_open()) { |
| 25 | + LOGF(fatal, "Failed to open muonTracks.csv for writing"); |
| 26 | + } |
| 27 | + muonTracksOut << "trackID,trackType,phi,tgl,signed1Pt,nClusters,pDCA,rAtAbsorberEnd,sign,chi2,chi2MatchMCHMID,chi2MatchMCHMFT,trackTime,eta,pt,p" << std::endl; |
| 28 | + |
25 | 29 | // define axes you want to use |
26 | 30 | const AxisSpec axisCounter{1, 0, +1, ""}; |
27 | 31 | const AxisSpec axisEta{10, -4.0, -2.5, "#eta"}; |
28 | 32 | const AxisSpec axisPt{10, 0.0, +20.0, "p_{T} (GeV/c)"}; |
| 33 | + const AxisSpec axisTrackType{5, 0, 5, "Track Type"}; |
29 | 34 |
|
30 | 35 | // create histograms |
31 | 36 | histos.add("eventCounterReco", "eventCounterReco", kTH1F, {axisCounter}); |
32 | 37 | histos.add("muPtHistReco", "muPtHistReco", kTH1F, {axisPt}); |
33 | | - histos.add("muPtHistRecoD", "muPtHistRecoD", kTH1F, {axisPt}); |
| 38 | + histos.add("trackType", "trackType", kTH1D, {axisTrackType}); |
| 39 | + } |
34 | 40 |
|
35 | | - // set textfile header |
36 | | - muonTracksOut << "ID,eta,pt,p,phi,motherPDG,nClusters,pDca,chi2,chi2MatchMCHMID,chi2MatchMCHMFT,isPrompt\n"; |
| 41 | + Int_t GetFlavour(Int_t pdgCode) |
| 42 | + { |
| 43 | + // |
| 44 | + // return the flavour of a particle |
| 45 | + // input: pdg code of the particle |
| 46 | + // output: Int_t |
| 47 | + // 3 in case of strange (open and hidden) |
| 48 | + // 4 in case of charm (") |
| 49 | + // 5 in case of beauty (") |
| 50 | + // |
| 51 | + Int_t pdg = TMath::Abs(pdgCode); |
| 52 | + // Resonance |
| 53 | + if (pdg > 100000) |
| 54 | + pdg %= 100000; |
| 55 | + if (pdg > 10000) |
| 56 | + pdg %= 10000; |
| 57 | + // meson ? |
| 58 | + if (pdg > 10) |
| 59 | + pdg /= 100; |
| 60 | + // baryon ? |
| 61 | + if (pdg > 10) |
| 62 | + pdg /= 10; |
| 63 | + return pdg; |
37 | 64 | } |
38 | 65 |
|
39 | 66 | using muonTracks = soa::Join<aod::FwdTracks, aod::McFwdTrackLabels>; |
40 | 67 |
|
41 | | - void process(aod::Collision const& collision, muonTracks const& tracks, aod::McParticles const&) |
| 68 | + void process(muonTracks const& tracks, aod::McParticles const&) |
42 | 69 | { |
43 | 70 | histos.fill(HIST("eventCounterReco"), 0.5); |
44 | 71 | for (auto& track : tracks) { |
45 | 72 | if(track.has_mcParticle()){ |
46 | 73 | auto mcParticle = track.mcParticle(); |
| 74 | + int64_t recoTrackID = track.globalIndex(); // Reconstructed track ID |
47 | 75 | //auto statusCode = mcParticle.getGenStatusCode(); |
48 | 76 | if (abs(mcParticle.pdgCode())==13) { |
49 | | - auto muID = mcParticle.globalIndex(); |
50 | | - auto muEta = mcParticle.eta(); |
51 | | - if (muEta >= -4.0 && muEta <= -2.5) histos.fill(HIST("muPtHistReco"), mcParticle.pt()); // forward eta region |
52 | | - |
53 | | - // check if duplicate (ambiguous track) |
54 | | - int occuranceCount = count(selectedTracksID.begin(), selectedTracksID.end(), muID); |
55 | | - |
56 | | - // write to textfile |
57 | | - if (occuranceCount < 1) { |
58 | | - auto muRecoEta = track.eta(); |
59 | | - auto muRecoPt = track.pt(); |
60 | | - auto muRecoP = track.p(); |
61 | | - auto muRecoPhi = track.phi(); |
62 | | - auto muCluster = track.nClusters(); |
63 | | - auto muDCA = track.pDca(); |
64 | | - auto muChi2 = track.chi2(); |
65 | | - auto muChi2MCHMID = track.chi2MatchMCHMID(); |
66 | | - auto muChi2MCHMFT = track.chi2MatchMCHMFT(); |
67 | | - |
68 | | - // look for HF mother |
69 | | - auto muMother = mcParticle.mothers_first_as<aod::McParticles>(); |
70 | | - auto muMotherPDG = abs(muMother.pdgCode()); |
71 | | - auto motherStatusCode = muMother.getGenStatusCode(); |
72 | | - if (abs(muMotherPDG) >= 411 && abs(muMotherPDG) <= 435) { // D meson parent - can be prompt/no-prompt |
73 | | - histos.fill(HIST("muPtHistRecoD"), mcParticle.pt()); |
74 | | - } |
| 77 | + int64_t mcTrackID = mcParticle.globalIndex(); // Simulated track ID |
| 78 | + |
| 79 | + // check if muon is from HF decay |
| 80 | + auto muMother = mcParticle.mothers_first_as<aod::McParticles>(); |
| 81 | + auto muMotherPDG = abs(muMother.pdgCode()); |
| 82 | + auto muMotherFlavour = GetFlavour(muMotherPDG); |
75 | 83 |
|
76 | | - // check whether is prompt HF hadron |
| 84 | + bool hasHFmother = false; |
| 85 | + std::cout << "==== Mu decay chain: 13 <- " << muMotherPDG; |
| 86 | + |
| 87 | + if (muMotherFlavour != 4 && muMotherFlavour != 5) { // direct mother is not HF hadron |
| 88 | + // check if HF hadron mother in decay chain |
77 | 89 | auto mcPart(muMother); |
78 | | - auto prevMcPart(muMother); |
79 | 90 | auto mcPartPDG = abs(mcPart.pdgCode()); |
80 | | - int isPrompt = 1; |
81 | | - std::cout << "==== Forward muon decay chain: mu"; |
82 | | - while (mcPart.has_mothers() && (abs(mcPart.getGenStatusCode()) > 80 || mcPart.getGenStatusCode() == 0)) { // print out mother chain |
83 | | - std::cout << " <- " << mcPartPDG; |
84 | | - prevMcPart = *(mcPart); |
| 91 | + auto mcPartFlavour = GetFlavour(mcPartPDG); |
| 92 | + |
| 93 | + while (mcPart.has_mothers()) { |
85 | 94 | mcPart = *(mcPart.mothers_first_as<aod::McParticles>()); |
86 | 95 | mcPartPDG = abs(mcPart.pdgCode()); |
87 | | - } |
88 | | - if (div(abs(prevMcPart.pdgCode()), 100).quot != div(muMotherPDG, 100).quot) isPrompt = 0; |
89 | | - std::cout << "; isPrompt = " << isPrompt << std::endl; |
| 96 | + mcPartFlavour = GetFlavour(mcPartPDG); |
| 97 | + std::cout << " <- " << mcPartPDG; |
90 | 98 |
|
91 | | - muonTracksOut << muID << "," << muRecoEta << "," << muRecoPt << "," << muRecoP << "," << muRecoPhi << "," << muMotherPDG << "," << std::to_string(muCluster) << "," << muDCA << "," << muChi2 << "," << muChi2MCHMID << "," << muChi2MCHMFT << "," << isPrompt << std::endl; |
92 | | - selectedTracksID.emplace(selectedTracksID.end(), muID); |
| 99 | + if (mcPartFlavour == 4 || mcPartFlavour == 5) { |
| 100 | + hasHFmother = true; |
| 101 | + break; |
| 102 | + } |
| 103 | + } |
| 104 | + } else { |
| 105 | + hasHFmother = true; |
93 | 106 | } |
| 107 | + if (hasHFmother) std::cout << " (PICKED)"; |
| 108 | + std::cout << std::endl; |
| 109 | + |
| 110 | + if (hasHFmother) { |
| 111 | + auto muTrackType = static_cast<int64_t>(track.trackType()); |
| 112 | + auto muChi2 = track.chi2(); |
| 113 | + auto muChi2MatchMCHMID = track.chi2MatchMCHMID(); |
| 114 | + auto muChi2MatchMCHMFT = track.chi2MatchMCHMFT(); |
| 115 | + auto muMatchScoreMCHMFT = track.matchScoreMCHMFT(); |
| 116 | + auto muMatchMFTTrackId = track.matchMFTTrackId(); |
| 117 | + auto muDca = track.pDca(); |
| 118 | + auto muPt = track.pt(); |
| 119 | + auto muEta = track.eta(); |
| 120 | + auto ptResolution = abs(mcParticle.pt() - track.pt()); |
| 121 | + |
| 122 | + histos.fill(HIST("trackType"), muTrackType); |
| 123 | + |
| 124 | + if (muTrackType == 3) histos.fill(HIST("muPtHistReco"), muPt); // look at pT for standalone tracks |
| 125 | + |
| 126 | + // save all muon tracks to the output file |
| 127 | + muonTracksOut << recoTrackID << "," << muTrackType << "," << track.phi() << "," << track.tgl() << "," << track.signed1Pt() << "," |
| 128 | + << static_cast<int64_t>(track.nClusters()) << "," << muDca << "," << track.rAtAbsorberEnd() << "," |
| 129 | + << static_cast<int64_t>(track.sign()) << "," << muChi2 << "," << muChi2MatchMCHMID << "," << muChi2MatchMCHMFT << "," |
| 130 | + << track.trackTime() << "," << muEta << "," << muPt << "," << track.p() << std::endl; |
| 131 | + }; |
| 132 | + |
| 133 | + // check whether is prompt HF hadron |
| 134 | + // auto mcPart(muMother); |
| 135 | + // auto prevMcPart(muMother); |
| 136 | + // auto mcPartPDG = abs(mcPart.pdgCode()); |
| 137 | + // int isPrompt = 1; |
| 138 | + // std::cout << "==== Forward muon decay chain: mu"; |
| 139 | + // while (mcPart.has_mothers() && (abs(mcPart.getGenStatusCode()) > 80 || mcPart.getGenStatusCode() == 0)) { // print out mother chain |
| 140 | + // std::cout << " <- " << mcPartPDG; |
| 141 | + // prevMcPart = *(mcPart); |
| 142 | + // mcPart = *(mcPart.mothers_first_as<aod::McParticles>()); |
| 143 | + // mcPartPDG = abs(mcPart.pdgCode()); |
| 144 | + // } |
| 145 | + // if (div(abs(prevMcPart.pdgCode()), 100).quot != div(muMotherPDG, 100).quot) isPrompt = 0; |
| 146 | + // std::cout << "; isPrompt = " << isPrompt << std::endl; |
94 | 147 | } |
95 | 148 | } |
96 | 149 | } |
|
0 commit comments