|
30 | 30 | #include "Common/DataModel/TrackSelectionTables.h" |
31 | 31 | #include "Common/Core/TrackSelection.h" |
32 | 32 | #include "Common/Core/TrackSelectionDefaults.h" |
| 33 | +#include "DataFormatsTPC/BetheBlochAleph.h" |
| 34 | +#include "ReconstructionDataFormats/PID.h" |
| 35 | + |
| 36 | +#include "TF1.h" |
33 | 37 |
|
34 | 38 | using namespace o2; |
35 | 39 | using namespace o2::framework; |
@@ -67,6 +71,10 @@ struct qaEventTrackLite { |
67 | 71 | Configurable<float> nCrossedRowsTpcOverFindableClustersTpcMin{"nCrossedRowsTpcOverFindableClustersTpcMin", -1, "Minimum ratio between TPC crossed rows and findable clusters"}; |
68 | 72 | Configurable<float> chi2TpcMin{"chi2TpcMin", -1001.f, "Max TPC chi2"}; |
69 | 73 | Configurable<float> chi2TpcMax{"chi2TpcMax", 1000.f, "Max TPC chi2"}; |
| 74 | + Configurable<std::string> tpcSplinesPeriod{"tpcSplinesPeriod", std::string(""), "Period of used TPC dEdx splines"}; |
| 75 | + Configurable<bool> b_tpcResProton{"b_tpcResProton", false, "Do TPC dEdx residuals around proton hypothesis"}; |
| 76 | + Configurable<bool> b_tpcResKaon{"b_tpcResKaon", false, "Do TPC dEdx residuals around kaon hypothesis"}; |
| 77 | + Configurable<bool> b_tpcResPion{"b_tpcResPion", false, "Do TPC dEdx residuals around pion hypothesis"}; |
70 | 78 | // TOF selections |
71 | 79 | Configurable<float> chi2TofMin{"chi2TofMin", -1001.f, "Max TOF chi2"}; |
72 | 80 | Configurable<float> lengthMin{"lengthMin", -1001.f, "Min length"}; |
@@ -109,13 +117,80 @@ struct qaEventTrackLite { |
109 | 117 | Configurable<int> pdgCodeSel{"pdgCodeSel", 2, "pdgCode based particle selection, 1 defines pi,K,p,mu,e, 2 all final-state charged particles including light (hyper)nuclei"}; |
110 | 118 | Configurable<bool> checkPdgAtReco{"checkPdgAtReco", false, "check pdg code also at reco levo for data-like reference"}; |
111 | 119 |
|
| 120 | + // TPC dEdx splines |
| 121 | + struct BBAleph { |
| 122 | + |
| 123 | + // --- data members --- |
| 124 | + double mMip = 0; |
| 125 | + std::vector<double> mBetheBlockAleph = {0., 0., 0., 0., 0.}; |
| 126 | + double mChargeFactor = 0; |
| 127 | + bool initBBok = false; |
| 128 | + |
| 129 | + // --- functions --- |
| 130 | + double operator()(double* x, double* par) |
| 131 | + { |
| 132 | + /// === Parameters === |
| 133 | + /// [0]: mass |
| 134 | + /// [1]: charge |
| 135 | + /// |
| 136 | + /// From A. Kalteyer: |
| 137 | + /// const float bethe = mMIP |
| 138 | + /// * o2::tpc::BetheBlochAleph(track.tpcInnerParam() / o2::track::pid_constants::sMasses[id] |
| 139 | + /// , mBetheBlochParams[0], mBetheBlochParams[1], mBetheBlochParams[2], mBetheBlochParams[3], mBetheBlochParams[4]) |
| 140 | + /// * std::pow((float)o2::track::pid_constants::sCharges[id], mChargeFactor); |
| 141 | + /// |
| 142 | + return initBBok ? mMip * o2::tpc::BetheBlochAleph(x[0] / par[0], mBetheBlockAleph[0], mBetheBlockAleph[1], mBetheBlockAleph[2], mBetheBlockAleph[3], mBetheBlockAleph[4]) * std::pow(par[1], mChargeFactor) : 0.; |
| 143 | + } |
| 144 | + void setUpBetheBlockAleph(std::string str_case) |
| 145 | + { |
| 146 | + if (str_case.find("LHC22c") != std::string::npos) { |
| 147 | + // From A. Kalteyer (2022 Jul 18) |
| 148 | + mMip = 52.35295; |
| 149 | + mChargeFactor = 4.382516; |
| 150 | + mBetheBlockAleph[0] = 0.038508328324810444; |
| 151 | + mBetheBlockAleph[1] = 20.173734667349745; |
| 152 | + mBetheBlockAleph[2] = 7.811839314098901e-10; |
| 153 | + mBetheBlockAleph[3] = 2.3572347501513162; |
| 154 | + mBetheBlockAleph[4] = 3.896773574265881; |
| 155 | + initBBok = true; |
| 156 | + } else if (str_case.find("LHC22d") != std::string::npos) { |
| 157 | + // From A. Kalteyer (2022 Jul 18) |
| 158 | + mMip = 52.35295; |
| 159 | + mChargeFactor = 4.382516; |
| 160 | + mBetheBlockAleph[0] = 0.0370972540453123; |
| 161 | + mBetheBlockAleph[1] = 21.29155104648775; |
| 162 | + mBetheBlockAleph[2] = 1.2702695962030138e-10; |
| 163 | + mBetheBlockAleph[3] = 2.3297081952872936; |
| 164 | + mBetheBlockAleph[4] = 4.1832594396288725; |
| 165 | + initBBok = true; |
| 166 | + } else { |
| 167 | + LOG(info) << "===> WARNING: no Bethe Block parameters defined for " << str_case << ". Ignoring it." << std::endl; |
| 168 | + return; |
| 169 | + } |
| 170 | + LOG(info) << "=== Bethe Block Alep parametrization loaded for period " << str_case << ":" << std::endl; |
| 171 | + LOG(info) << "mMip = " << mMip << std::endl; |
| 172 | + LOG(info) << "mChargeFactor = " << mChargeFactor << std::endl; |
| 173 | + LOG(info) << "mBetheBlockAleph[0] = " << mBetheBlockAleph[0] << std::endl; |
| 174 | + LOG(info) << "mBetheBlockAleph[1] = " << mBetheBlockAleph[1] << std::endl; |
| 175 | + LOG(info) << "mBetheBlockAleph[2] = " << mBetheBlockAleph[2] << std::endl; |
| 176 | + LOG(info) << "mBetheBlockAleph[3] = " << mBetheBlockAleph[3] << std::endl; |
| 177 | + LOG(info) << "mBetheBlockAleph[4] = " << mBetheBlockAleph[4] << std::endl; |
| 178 | + LOG(info) << "initBBok = " << initBBok << std::endl; |
| 179 | + } |
| 180 | + }; |
| 181 | + BBAleph betheBlock; |
| 182 | + TF1 funcBBpion, funcBBkaon, funcBBproton; // TPC dEdx splines |
| 183 | + |
112 | 184 | void init(InitContext const&) |
113 | 185 | { |
114 | 186 | const AxisSpec axisPt{binsPt, "#it{p}_{T} (GeV/c)"}; |
115 | 187 | const AxisSpec axis1overPt{bins1overPt, "1/#it{p}_{T} (GeV/c)^{-1}"}; |
116 | 188 | const AxisSpec axisEta{binsEta, "#it{#eta}"}; |
117 | 189 | const AxisSpec axisPhi{binsPhi, "#it{#phi} (rad)"}; |
118 | 190 |
|
| 191 | + // TPC dEdx splines |
| 192 | + betheBlock.setUpBetheBlockAleph(tpcSplinesPeriod); |
| 193 | + |
119 | 194 | // kine histograms |
120 | 195 | histos.add("Tracks/VertexPositionZ", "", kTH1D, {{100, -20.f, 20.f, "Vertex Z (cm)"}}); |
121 | 196 | histos.add("Tracks/VertexPositionZvsEta", "", kTH2D, {axisEta, {100, -20.f, 20.f, "Vertex Z (cm)"}}); |
@@ -150,6 +225,35 @@ struct qaEventTrackLite { |
150 | 225 | histos.add("Tracks/TPC/TPCnClstvsEtavsPt", "profile2D;", kTProfile2D, {axisEta, axisPt}); |
151 | 226 | histos.add("Tracks/TPC/dEdxvsP", "", kTH2D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {500, 0, 1000, "d#it{E}/d#it{x} (a.u.)"}}); |
152 | 227 | histos.add("Tracks/TPC/dEdxvsPvsEta", "", kTH3D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {20, -2, 2, "#it{#eta}"}, {500, 0, 1000, "d#it{E}/d#it{x} (a.u.)"}}); |
| 228 | + if (betheBlock.initBBok) { |
| 229 | + if (b_tpcResProton) { |
| 230 | + // Bethe-Block parametrization proton |
| 231 | + funcBBproton = TF1("funcBBproton", betheBlock, 0.1, 20, 3); |
| 232 | + funcBBproton.SetParameter(0, o2::track::pid_constants::sMasses[o2::track::PID::Proton]); // mass |
| 233 | + funcBBproton.SetParameter(1, o2::track::pid_constants::sCharges[o2::track::PID::Proton]); // electric charge (units of e) |
| 234 | + // histograms of residuals |
| 235 | + histos.add("Tracks/TPC/dEdxvsPproton", "", kTH2D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{proton} (a.u.)"}}); |
| 236 | + histos.add("Tracks/TPC/dEdxvsPprotonvsEta", "", kTH3D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {20, -2, 2, "#it{#eta}"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{proton} (a.u.)"}}); |
| 237 | + } |
| 238 | + if (b_tpcResKaon) { |
| 239 | + // Bethe-Block parametrization kaon |
| 240 | + funcBBkaon = TF1("funcBBkaon", betheBlock, 0.1, 20, 3); |
| 241 | + funcBBkaon.SetParameter(0, o2::track::pid_constants::sMasses[o2::track::PID::Kaon]); // mass |
| 242 | + funcBBkaon.SetParameter(1, o2::track::pid_constants::sCharges[o2::track::PID::Kaon]); // electric charge (units of e) |
| 243 | + // histograms of residuals |
| 244 | + histos.add("Tracks/TPC/dEdxvsPkaon", "", kTH2D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{kaon} (a.u.)"}}); |
| 245 | + histos.add("Tracks/TPC/dEdxvsPkaonvsEta", "", kTH3D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {20, -2, 2, "#it{#eta}"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{kaon} (a.u.)"}}); |
| 246 | + } |
| 247 | + if (b_tpcResPion) { |
| 248 | + // Bethe-Block parametrization pion |
| 249 | + funcBBpion = TF1("funcBBpion", betheBlock, 0.1, 20, 3); |
| 250 | + funcBBpion.SetParameter(0, o2::track::pid_constants::sMasses[o2::track::PID::Pion]); // mass |
| 251 | + funcBBpion.SetParameter(1, o2::track::pid_constants::sCharges[o2::track::PID::Pion]); // electric charge (units of e) |
| 252 | + // histograms of residuals |
| 253 | + histos.add("Tracks/TPC/dEdxvsPpion", "", kTH2D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{pion} (a.u.)"}}); |
| 254 | + histos.add("Tracks/TPC/dEdxvsPpionvsEta", "", kTH3D, {{5000, 0, 10, "#it{p} (GeV/#it{c})"}, {20, -2, 2, "#it{#eta}"}, {500, -100, 100, "d#it{E}/d#it{x}-d#it{E}/d#it{x}|_{pion} (a.u.)"}}); |
| 255 | + } |
| 256 | + } |
153 | 257 | // trd histograms |
154 | 258 | histos.add("Tracks/TRD/trdChi2", "chi2 in TRD", kTH1D, {{100, 0, 10, "chi2 / cluster TRD"}}); |
155 | 259 | // tof histograms |
@@ -277,8 +381,24 @@ struct qaEventTrackLite { |
277 | 381 | histos.fill(HIST("Tracks/TPC/tpcNClsFoundvsPt"), track.pt(), track.tpcNClsFound()); |
278 | 382 | histos.fill(HIST("Tracks/TPC/tpcCrossedRowsvsPt"), track.pt(), track.tpcNClsCrossedRows()); |
279 | 383 | histos.fill(HIST("Tracks/TPC/tpcCrossedRowsOverFindableClsvsPt"), track.pt(), track.tpcCrossedRowsOverFindableCls()); |
280 | | - histos.fill(HIST("Tracks/TPC/dEdxvsP"), track.pt() / (sin(2 * atan2(1, exp(track.eta())))), track.tpcSignal()); |
281 | | - histos.fill(HIST("Tracks/TPC/dEdxvsPvsEta"), track.pt() / (sin(2 * atan2(1, exp(track.eta())))), track.eta(), track.tpcSignal()); |
| 384 | + const double p = track.pt() / (sin(2 * atan2(1, exp(track.eta())))); |
| 385 | + histos.fill(HIST("Tracks/TPC/dEdxvsP"), p, track.tpcSignal()); |
| 386 | + histos.fill(HIST("Tracks/TPC/dEdxvsPvsEta"), p, track.eta(), track.tpcSignal()); |
| 387 | + if (betheBlock.initBBok) { |
| 388 | + auto tpcdEdxRes = [&](TF1 func) { return track.tpcSignal() - func.Eval(p); }; |
| 389 | + if (b_tpcResProton) { |
| 390 | + histos.fill(HIST("Tracks/TPC/dEdxvsPproton"), p, tpcdEdxRes(funcBBproton)); |
| 391 | + histos.fill(HIST("Tracks/TPC/dEdxvsPprotonvsEta"), p, track.eta(), tpcdEdxRes(funcBBproton)); |
| 392 | + } |
| 393 | + if (b_tpcResKaon) { |
| 394 | + histos.fill(HIST("Tracks/TPC/dEdxvsPkaon"), p, tpcdEdxRes(funcBBkaon)); |
| 395 | + histos.fill(HIST("Tracks/TPC/dEdxvsPkaonvsEta"), p, track.eta(), tpcdEdxRes(funcBBkaon)); |
| 396 | + } |
| 397 | + if (b_tpcResPion) { |
| 398 | + histos.fill(HIST("Tracks/TPC/dEdxvsPpion"), p, tpcdEdxRes(funcBBpion)); |
| 399 | + histos.fill(HIST("Tracks/TPC/dEdxvsPpionvsEta"), p, track.eta(), tpcdEdxRes(funcBBpion)); |
| 400 | + } |
| 401 | + } |
282 | 402 | histos.fill(HIST("Tracks/TRD/trdChi2"), track.trdChi2()); |
283 | 403 | histos.fill(HIST("Tracks/TOF/tofChi2"), track.tofChi2()); |
284 | 404 | if (track.hasTPC()) { |
|
0 commit comments