23#include "TGraphAsymmErrors.h"
41#include "GPUChainTrackingGetters.inc"
49#include "GPUParam.inc"
58#ifndef GPUCA_STANDALONE
69#include "TParticlePDG.h"
70#include "TDatabasePDG.h"
80#include <oneapi/tbb.h>
98template <
bool COUNT,
class T>
102 r.unattached = attach == 0;
105 r.qpt = fabsf(mTracking->mIOPtrs.mergedTracks[
r.id].GetParam().GetQPt());
106 r.lowPt =
r.qpt * mTracking->GetParam().qptB5Scaler > mTracking->GetParam().rec.tpc.rejectQPtB5;
107 r.mev200 =
r.qpt > 5;
108 r.mergedLooperUnconnected = mTracking->mIOPtrs.mergedTracks[
r.id].MergedLooperUnconnected();
109 r.mergedLooperConnected = mTracking->mIOPtrs.mergedTracks[
r.id].MergedLooperConnected();
112 if constexpr (COUNT) {
117 if constexpr (COUNT) {
120 }
else if (
r.mergedLooperUnconnected) {
121 if constexpr (COUNT) {
122 counts->nMergedLooperUnconnected++;
124 }
else if (
r.mergedLooperConnected) {
125 if constexpr (COUNT) {
126 counts->nMergedLooperConnected++;
129 r.protect = !GPUTPCClusterRejection::GetRejectionStatus<COUNT>(attach,
r.physics, counts, &
r.mev200) && ((attach &
gputpcgmmergertypes::attachProtect) || !GPUTPCClusterRejection::IsTrackRejected(mTracking->mIOPtrs.mergedTracks[
r.id], mTracking->GetParam()));
136 static GPUSettingsQA defaultConfig;
138 return *
chain->mConfigQA;
140 return defaultConfig;
144static const constexpr float LOG_PT_MIN = -1.;
146static constexpr float Y_MAX = 40;
147static constexpr float Z_MAX = 100;
148static constexpr float PT_MIN = 0.01;
149static constexpr float PT_MIN_PRIM = 0.1;
150static constexpr float PT_MIN_CLUST = 0.01;
151static constexpr float PT_MAX = 20;
152static constexpr float ETA_MAX = 1.5;
153static constexpr float ETA_MAX2 = 0.9;
154static constexpr int32_t PADROW_CHECK_MINCLS = 50;
156static constexpr bool CLUST_HIST_INT_SUM =
false;
158static constexpr const int32_t COLORCOUNT = 12;
160static const constexpr char* EFF_TYPES[6] = {
"Rec",
"Clone",
"Fake",
"All",
"RecAndClone",
"MC"};
161static const constexpr char* FINDABLE_NAMES[2] = {
"All",
"Findable"};
162static const constexpr char* PRIM_NAMES[2] = {
"Prim",
"Sec"};
163static const constexpr char* PARAMETER_NAMES[5] = {
"Y",
"Z",
"#Phi",
"#lambda",
"Relative #it{p}_{T}"};
164static const constexpr char* PARAMETER_NAMES_NATIVE[5] = {
"Y",
"Z",
"sin(#Phi)",
"tan(#lambda)",
"q/#it{p}_{T} (curvature)"};
165static const constexpr char* VSPARAMETER_NAMES[6] = {
"Y",
"Z",
"Phi",
"Eta",
"Pt",
"Pt_log"};
166static const constexpr char* EFF_NAMES[3] = {
"Efficiency",
"Clone Rate",
"Fake Rate"};
167static const constexpr char* EFFICIENCY_TITLES[4] = {
"Efficiency (Primary Tracks, Findable)",
"Efficiency (Secondary Tracks, Findable)",
"Efficiency (Primary Tracks)",
"Efficiency (Secondary Tracks)"};
168static const constexpr double SCALE[5] = {10., 10., 1000., 1000., 100.};
169static const constexpr double SCALE_NATIVE[5] = {10., 10., 1000., 1000., 1.};
170static const constexpr char* XAXIS_TITLES[5] = {
"#it{y}_{mc} (cm)",
"#it{z}_{mc} (cm)",
"#Phi_{mc} (rad)",
"#eta_{mc}",
"#it{p}_{Tmc} (GeV/#it{c})"};
171static const constexpr char* AXIS_TITLES[5] = {
"#it{y}-#it{y}_{mc} (mm) (Resolution)",
"#it{z}-#it{z}_{mc} (mm) (Resolution)",
"#phi-#phi_{mc} (mrad) (Resolution)",
"#lambda-#lambda_{mc} (mrad) (Resolution)",
"(#it{p}_{T} - #it{p}_{Tmc}) / #it{p}_{Tmc} (%) (Resolution)"};
172static const constexpr char* AXIS_TITLES_NATIVE[5] = {
"#it{y}-#it{y}_{mc} (mm) (Resolution)",
"#it{z}-#it{z}_{mc} (mm) (Resolution)",
"sin(#phi)-sin(#phi_{mc}) (Resolution)",
"tan(#lambda)-tan(#lambda_{mc}) (Resolution)",
"q*(q/#it{p}_{T} - q/#it{p}_{Tmc}) (Resolution)"};
173static const constexpr char* AXIS_TITLES_PULL[5] = {
"#it{y}-#it{y}_{mc}/#sigma_{y} (Pull)",
"#it{z}-#it{z}_{mc}/#sigma_{z} (Pull)",
"sin(#phi)-sin(#phi_{mc})/#sigma_{sin(#phi)} (Pull)",
"tan(#lambda)-tan(#lambda_{mc})/#sigma_{tan(#lambda)} (Pull)",
174 "q*(q/#it{p}_{T} - q/#it{p}_{Tmc})/#sigma_{q/#it{p}_{T}} (Pull)"};
175static const constexpr char* CLUSTER_NAMES[GPUQA::N_CLS_HIST] = {
"Correctly attached clusters",
"Fake attached clusters",
"Attached + adjacent clusters",
"Fake adjacent clusters",
"Clusters of reconstructed tracks",
"Used in Physics",
"Protected",
"All clusters"};
176static const constexpr char* CLUSTER_TITLES[GPUQA::N_CLS_TYPE] = {
"Clusters Pt Distribution / Attachment",
"Clusters Pt Distribution / Attachment (relative to all clusters)",
"Clusters Pt Distribution / Attachment (integrated)"};
177static const constexpr char* CLUSTER_NAMES_SHORT[GPUQA::N_CLS_HIST] = {
"Attached",
"Fake",
"AttachAdjacent",
"FakeAdjacent",
"FoundTracks",
"Physics",
"Protected",
"All"};
178static const constexpr char* CLUSTER_TYPES[GPUQA::N_CLS_TYPE] = {
"",
"Ratio",
"Integral"};
179static const constexpr char* REJECTED_NAMES[3] = {
"All",
"Rejected",
"Fraction"};
180static const constexpr int32_t COLORS_HEX[COLORCOUNT] = {0xB03030, 0x00A000, 0x0000C0, 0x9400D3, 0x19BBBF, 0xF25900, 0x7F7F7F, 0xFFD700, 0x07F707, 0x07F7F7, 0xF08080, 0x000000};
182static const constexpr int32_t CONFIG_DASHED_MARKERS = 0;
184static const constexpr float AXES_MIN[5] = {-Y_MAX, -Z_MAX, 0.f, -ETA_MAX, PT_MIN};
185static const constexpr float AXES_MAX[5] = {Y_MAX, Z_MAX, 2.f * M_PI, ETA_MAX, PT_MAX};
186static const constexpr int32_t AXIS_BINS[5] = {51, 51, 144, 31, 50};
187static const constexpr int32_t RES_AXIS_BINS[] = {1017, 113};
188static const constexpr float RES_AXES[5] = {1., 1., 0.03, 0.03, 1.0};
189static const constexpr float RES_AXES_NATIVE[5] = {1., 1., 0.1, 0.1, 5.0};
190static const constexpr float PULL_AXIS = 10.f;
192std::vector<TColor*> GPUQA::mColors;
195 mColors.reserve(COLORCOUNT);
196 for (int32_t
i = 0;
i < COLORCOUNT;
i++) {
197 float f1 = (
float)((COLORS_HEX[
i] >> 16) & 0xFF) / (
float)0xFF;
198 float f2 = (
float)((COLORS_HEX[
i] >> 8) & 0xFF) / (
float)0xFF;
199 float f3 = (
float)((COLORS_HEX[
i] >> 0) & 0xFF) / (
float)0xFF;
200 mColors.emplace_back(
new TColor(10000 +
i, f1, f2, f3));
204static constexpr Color_t defaultColorNums[COLORCOUNT] = {kRed, kBlue, kGreen, kMagenta, kOrange, kAzure, kBlack, kYellow, kGray, kTeal, kSpring, kPink};
206#define TRACK_EXPECTED_REFERENCE_X_DEFAULT 81
208static inline int32_t GPUQA_O2_ConvertFakeLabel(int32_t
label) {
return label >= 0x7FFFFFFE ? -1 :
label; }
209inline uint32_t GPUQA::GetNMCCollissions()
const {
return mMCInfosCol.size(); }
210inline uint32_t GPUQA::GetNMCTracks(int32_t iCol)
const {
return mMCInfosCol[iCol].num; }
211inline uint32_t GPUQA::GetNMCTracks(
const mcLabelI_t&
label)
const {
return mMCInfosCol[mMCEventOffset[
label.getSourceID()] +
label.getEventID()].num; }
212inline uint32_t GPUQA::GetNMCLabels()
const {
return mClNative->clustersMCTruth ? mClNative->clustersMCTruth->getIndexedSize() : 0; }
213inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(
uint32_t iTrk,
uint32_t iCol) {
return mMCInfos[mMCInfosCol[iCol].first + iTrk]; }
214inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(
const mcLabel_t&
label) {
return mMCInfos[mMCInfosCol[mMCEventOffset[
label.getSourceID()] +
label.getEventID()].first +
label.getTrackID()]; }
215inline GPUQA::mcLabels_t GPUQA::GetMCLabel(
uint32_t i) {
return mClNative->clustersMCTruth->getLabels(
i); }
216inline int32_t GPUQA::GetMCLabelNID(
const mcLabels_t&
label) {
return label.size(); }
217inline int32_t GPUQA::GetMCLabelNID(
uint32_t i) {
return mClNative->clustersMCTruth->getLabels(
i).size(); }
218inline GPUQA::mcLabel_t GPUQA::GetMCLabel(
uint32_t i,
uint32_t j) {
return mClNative->clustersMCTruth->getLabels(
i)[
j]; }
219inline int32_t GPUQA::GetMCLabelID(
uint32_t i,
uint32_t j) {
return GPUQA_O2_ConvertFakeLabel(mClNative->clustersMCTruth->getLabels(
i)[
j].getTrackID()); }
220inline int32_t GPUQA::GetMCLabelID(
const mcLabels_t&
label,
uint32_t j) {
return GPUQA_O2_ConvertFakeLabel(
label[
j].getTrackID()); }
221inline int32_t GPUQA::GetMCLabelID(
const mcLabel_t&
label) {
return GPUQA_O2_ConvertFakeLabel(
label.getTrackID()); }
222inline uint32_t GPUQA::GetMCLabelCol(
uint32_t i,
uint32_t j) {
return mMCEventOffset[mClNative->clustersMCTruth->getLabels(
i)[
j].getSourceID()] + mClNative->clustersMCTruth->getLabels(
i)[
j].getEventID(); }
223inline const auto& GPUQA::GetClusterLabels() {
return mClNative->clustersMCTruth; }
225inline float GPUQA::GetMCLabelWeight(
const mcLabels_t&
label,
uint32_t j) {
return 1; }
226inline float GPUQA::GetMCLabelWeight(
const mcLabel_t&
label) {
return 1; }
227inline bool GPUQA::mcPresent() {
return !mConfig.noMC && mTracking && mClNative && mClNative->clustersMCTruth && mMCInfos.size(); }
228uint32_t GPUQA::GetMCLabelCol(
const mcLabel_t&
label)
const {
return !
label.isValid() ? 0 : (mMCEventOffset[
label.getSourceID()] +
label.getEventID()); }
230bool GPUQA::CompareIgnoreFake(
const mcLabelI_t& l1,
const mcLabelI_t& l2) {
return l1.compare(l2) >= 0; }
231#define TRACK_EXPECTED_REFERENCE_X 78
233inline GPUQA::mcLabelI_t::mcLabelI_t(
const GPUQA::mcLabel_t& l) : track(l.fMCID) {}
234inline bool GPUQA::mcLabelI_t::operator==(
const GPUQA::mcLabel_t& l) {
return AbsLabelID(track) == l.fMCID; }
235inline uint32_t GPUQA::GetNMCCollissions()
const {
return 1; }
236inline uint32_t GPUQA::GetNMCTracks(int32_t iCol)
const {
return mTracking->mIOPtrs.nMCInfosTPC; }
237inline uint32_t GPUQA::GetNMCTracks(
const mcLabelI_t&
label)
const {
return mTracking->mIOPtrs.nMCInfosTPC; }
238inline uint32_t GPUQA::GetNMCLabels()
const {
return mTracking->mIOPtrs.nMCLabelsTPC; }
239inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(
uint32_t iTrk,
uint32_t iCol) {
return mTracking->mIOPtrs.mcInfosTPC[AbsLabelID(iTrk)]; }
240inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(
const mcLabel_t&
label) {
return GetMCTrack(
label.fMCID, 0); }
241inline const GPUQA::mcInfo_t& GPUQA::GetMCTrack(
const mcLabelI_t&
label) {
return GetMCTrack(
label.track, 0); }
242inline const GPUQA::mcLabels_t& GPUQA::GetMCLabel(
uint32_t i) {
return mTracking->mIOPtrs.mcLabelsTPC[
i]; }
243inline const GPUQA::mcLabel_t& GPUQA::GetMCLabel(
uint32_t i,
uint32_t j) {
return mTracking->mIOPtrs.mcLabelsTPC[
i].fClusterID[
j]; }
244inline int32_t GPUQA::GetMCLabelNID(
const mcLabels_t&
label) {
return 3; }
248inline int32_t GPUQA::GetMCLabelID(
const mcLabel_t&
label) {
return label.fMCID; }
250inline const auto& GPUQA::GetClusterLabels() {
return mTracking->mIOPtrs.mcLabelsTPC; }
251inline float GPUQA::GetMCLabelWeight(
uint32_t i,
uint32_t j) {
return mTracking->mIOPtrs.mcLabelsTPC[
i].fClusterID[
j].fWeight; }
252inline float GPUQA::GetMCLabelWeight(
const mcLabels_t&
label,
uint32_t j) {
return label.fClusterID[
j].fWeight; }
253inline float GPUQA::GetMCLabelWeight(
const mcLabel_t&
label) {
return label.fWeight; }
254inline int32_t GPUQA::FakeLabelID(int32_t
id) {
return id < 0 ?
id : (-2 -
id); }
255inline int32_t GPUQA::AbsLabelID(int32_t
id) {
return id >= 0 ?
id : (-
id - 2); }
256inline bool GPUQA::mcPresent() {
return !mConfig.noMC && mTracking && GetNMCLabels() && GetNMCTracks(0); }
257uint32_t GPUQA::GetMCLabelCol(
const mcLabel_t&
label)
const {
return 0; }
259bool GPUQA::CompareIgnoreFake(
const mcLabelI_t& l1,
const mcLabelI_t& l2) {
return AbsLabelID(l1.track) == AbsLabelID(l2.track); }
260#define TRACK_EXPECTED_REFERENCE_X TRACK_EXPECTED_REFERENCE_X_DEFAULT
265 return obj[mMCEventOffset[l.getSourceID()] + l.getEventID()][l.getTrackID()];
269auto GPUQA::getHistArray<TH1F>()
271 return std::make_pair(mHist1D, &mHist1D_pos);
274auto GPUQA::getHistArray<TH2F>()
276 return std::make_pair(mHist2D, &mHist2D_pos);
279auto GPUQA::getHistArray<TH1D>()
281 return std::make_pair(mHist1Dd, &mHist1Dd_pos);
284auto GPUQA::getHistArray<TGraphAsymmErrors>()
286 return std::make_pair(mHistGraph, &mHistGraph_pos);
288template <
class T,
typename... Args>
289void GPUQA::createHist(T*&
h,
const char*
name, Args... args)
291 const auto&
p = getHistArray<T>();
292 if (mHaveExternalHists) {
293 if (
p.first->size() <=
p.second->size()) {
294 GPUError(
"Array sizes mismatch: Histograms %lu <= Positions %lu",
p.first->size(),
p.second->size());
295 throw std::runtime_error(
"Incoming histogram array incomplete");
297 if (strcmp((*
p.first)[
p.second->size()].GetName(),
name)) {
298 GPUError(
"Histogram name mismatch: in array %s, trying to create %s", (*
p.first)[
p.second->size()].GetName(),
name);
299 throw std::runtime_error(
"Incoming histogram has incorrect name");
302 if constexpr (std::is_same_v<T, TGraphAsymmErrors>) {
303 p.first->emplace_back();
304 p.first->back().SetName(
name);
306 p.first->emplace_back(
name, args...);
309 h = &((*
p.first)[
p.second->size()]);
310 p.second->emplace_back(&
h);
316 std::tuple<std::vector<std::unique_ptr<TCanvas>>, std::vector<std::unique_ptr<TLegend>>, std::vector<std::unique_ptr<TPad>>, std::vector<std::unique_ptr<TLatex>>, std::vector<std::unique_ptr<TH1D>>>
v;
320template <
class T,
typename... Args>
321T* GPUQA::createGarbageCollected(Args... args)
323 auto&
v = std::get<std::vector<std::unique_ptr<T>>>(mGarbageCollector->v);
324 v.emplace_back(std::make_unique<T>(args...));
325 return v.back().get();
327void GPUQA::clearGarbagageCollector()
329 std::get<std::vector<std::unique_ptr<TPad>>>(mGarbageCollector->v).
clear();
330 std::apply([](
auto&&... args) { ((args.clear()), ...); }, mGarbageCollector->v);
335 mMCEventOffset.resize(1, 0);
340 if (mQAInitialized && !mHaveExternalHists) {
346 clearGarbagageCollector();
351 const auto&
r = checkClusterState<false>(attach);
353 return r.protect ||
r.physics;
355 return (!
r.unattached && !
r.physics && !
r.protect);
359void GPUQA::SetAxisSize(T*
e)
361 e->GetYaxis()->SetTitleOffset(1.0);
362 e->GetYaxis()->SetTitleSize(0.045);
363 e->GetYaxis()->SetLabelSize(0.045);
364 e->GetXaxis()->SetTitleOffset(1.03);
365 e->GetXaxis()->SetTitleSize(0.045);
366 e->GetXaxis()->SetLabelOffset(-0.005);
367 e->GetXaxis()->SetLabelSize(0.045);
370void GPUQA::SetLegend(TLegend* l,
bool bigText)
373 l->SetTextSize(bigText ? 0.03 : 0.016);
377double* GPUQA::CreateLogAxis(int32_t nbins,
float xmin,
float xmax)
379 float logxmin = std::log10(xmin);
380 float logxmax = std::log10(xmax);
381 float binwidth = (logxmax - logxmin) / nbins;
383 double* xbins =
new double[nbins + 1];
386 for (int32_t
i = 1;
i <= nbins;
i++) {
387 xbins[
i] = std::pow(10, logxmin +
i * binwidth);
392void GPUQA::ChangePadTitleSize(TPad* p,
float size)
395 TPaveText* pt = (TPaveText*)(
p->GetPrimitive(
"title"));
397 GPUError(
"Error changing title");
399 pt->SetTextSize(
size);
404void GPUQA::DrawHisto(TH1* histo,
char*
filename,
char* options)
408 histo->Draw(options);
412void GPUQA::doPerfFigure(
float x,
float y,
float size)
414 if (mConfig.perfFigure ==
"") {
417 static constexpr const char* str_perf_figure_1 =
"ALICE Performance";
418 static constexpr const char* str_perf_figure_2_mc =
"MC, Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV";
419 static constexpr const char* str_perf_figure_2_data =
"Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV";
420 const char* str_perf_figure_2 = (mConfig.perfFigure ==
"mc" || mConfig.perfFigure ==
"MC") ? str_perf_figure_2_mc : (mConfig.perfFigure ==
"data" ? str_perf_figure_2_data : mConfig.perfFigure.c_str());
422 TLatex*
t = createGarbageCollected<TLatex>();
425 t->SetTextSize(
size);
426 t->DrawLatex(
x,
y, str_perf_figure_1);
427 t->SetTextSize(
size * 0.8);
428 t->DrawLatex(
x,
y - 0.01 -
size, str_perf_figure_2);
437int32_t GPUQA::InitQACreateHistograms()
439 char name[2048], fname[1024];
440 if (mQATasks & taskTrackingEff) {
442 for (int32_t
i = 0;
i < 6;
i++) {
443 for (int32_t
j = 0;
j < 2;
j++) {
444 for (int32_t k = 0; k < 2; k++) {
445 for (int32_t l = 0; l < 5; l++) {
446 snprintf(
name, 2048,
"%s%s%s%sVs%s",
"tracks", EFF_TYPES[
i], FINDABLE_NAMES[
j], PRIM_NAMES[k], VSPARAMETER_NAMES[l]);
448 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], k == 0 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])};
449 createHist(mEff[
i][
j][k][l],
name,
name, AXIS_BINS[l], binsPt.get());
451 createHist(mEff[
i][
j][k][l],
name,
name, AXIS_BINS[l], AXES_MIN[l], AXES_MAX[l]);
453 if (!mHaveExternalHists) {
454 mEff[
i][
j][k][l]->Sumw2();
456 strcat(
name,
"_eff");
458 createHist(mEffResult[
i][
j][k][l],
name);
467 if (mQATasks & taskTrackingRes) {
468 for (int32_t
i = 0;
i < 5;
i++) {
469 for (int32_t
j = 0;
j < 5;
j++) {
470 snprintf(
name, 2048,
"rms_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
471 snprintf(fname, 1024,
"mean_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
473 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])};
474 createHist(mRes[
i][
j][0],
name,
name, AXIS_BINS[
j], binsPt.get());
475 createHist(mRes[
i][
j][1], fname, fname, AXIS_BINS[
j], binsPt.get());
477 createHist(mRes[
i][
j][0],
name,
name, AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
478 createHist(mRes[
i][
j][1], fname, fname, AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
480 snprintf(
name, 2048,
"res_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
481 const float* axis = mConfig.nativeFitResolutions ? RES_AXES_NATIVE : RES_AXES;
482 const int32_t nbins =
i == 4 && mConfig.nativeFitResolutions ? (10 * RES_AXIS_BINS[0]) : RES_AXIS_BINS[0];
484 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])};
485 createHist(mRes2[
i][
j],
name,
name, nbins, -axis[
i], axis[
i], AXIS_BINS[
j], binsPt.get());
487 createHist(mRes2[
i][
j],
name,
name, nbins, -axis[
i], axis[
i], AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
494 if (mQATasks & taskTrackingResPull) {
495 for (int32_t
i = 0;
i < 5;
i++) {
496 for (int32_t
j = 0;
j < 5;
j++) {
497 snprintf(
name, 2048,
"pull_rms_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
498 snprintf(fname, 1024,
"pull_mean_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
500 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])};
501 createHist(mPull[
i][
j][0],
name,
name, AXIS_BINS[
j], binsPt.get());
502 createHist(mPull[
i][
j][1], fname, fname, AXIS_BINS[
j], binsPt.get());
504 createHist(mPull[
i][
j][0],
name,
name, AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
505 createHist(mPull[
i][
j][1], fname, fname, AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
507 snprintf(
name, 2048,
"pull_%s_vs_%s", VSPARAMETER_NAMES[
i], VSPARAMETER_NAMES[
j]);
509 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])};
510 createHist(mPull2[
i][
j],
name,
name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[
j], binsPt.get());
512 createHist(mPull2[
i][
j],
name,
name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[
j], AXES_MIN[
j], AXES_MAX[
j]);
519 if (mQATasks & taskClusterAttach) {
520 for (int32_t
i = 0;
i < N_CLS_TYPE * N_CLS_HIST - 1;
i++) {
521 int32_t ioffset =
i >= (2 * N_CLS_HIST - 1) ? (2 * N_CLS_HIST - 1) : (
i >= N_CLS_HIST ? N_CLS_HIST : 0);
522 int32_t itype =
i >= (2 * N_CLS_HIST - 1) ? 2 : (
i >= N_CLS_HIST ? 1 : 0);
523 snprintf(
name, 2048,
"clusters%s%s", CLUSTER_NAMES_SHORT[
i - ioffset], CLUSTER_TYPES[itype]);
524 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)};
525 createHist(mClusters[
i],
name,
name, AXIS_BINS[4], binsPt.get());
528 const int32_t maxPads = GPUTPCGeometry::NPads(GPUTPCGeometry::NROWS - 1);
529 createHist(mLowestRowDifferenceVsPad,
"lowest_row_difference_vs_pad",
"Lowest cluster row difference;Pad of lowest reconstructed cluster;Lowest reconstructed row - lowest MC row", maxPads, -0.5, maxPads - 0.5, 2 * GPUTPCGeometry::NROWS - 1, -GPUTPCGeometry::NROWS + 0.5, GPUTPCGeometry::NROWS - 0.5);
530 createHist(mLowestRowTrackMultiplicity,
"lowest_row_track_multiplicity",
"Track multiplicity for missing inner clusters;Reconstructed tracks with the same MC label;Selected reconstructed tracks", 100, -0.5, 99.5);
532 createHist(mPadRow[0],
"padrow0",
"padrow0", GPUTPCGeometry::NROWS - PADROW_CHECK_MINCLS, 0, GPUTPCGeometry::NROWS - 1 - PADROW_CHECK_MINCLS, GPUTPCGeometry::NROWS - PADROW_CHECK_MINCLS, 0, GPUTPCGeometry::NROWS - 1 - PADROW_CHECK_MINCLS);
533 createHist(mPadRow[1],
"padrow1",
"padrow1", 100.f, -0.2f, 0.2f, GPUTPCGeometry::NROWS - PADROW_CHECK_MINCLS, 0, GPUTPCGeometry::NROWS - 1 - PADROW_CHECK_MINCLS);
534 createHist(mPadRow[2],
"padrow2",
"padrow2", 100.f, -0.2f, 0.2f, GPUTPCGeometry::NROWS - PADROW_CHECK_MINCLS, 0, GPUTPCGeometry::NROWS - 1 - PADROW_CHECK_MINCLS);
535 createHist(mPadRow[3],
"padrow3",
"padrow3", 100.f, 0, 300000, GPUTPCGeometry::NROWS - PADROW_CHECK_MINCLS, 0, GPUTPCGeometry::NROWS - 1 - PADROW_CHECK_MINCLS);
538 if (mQATasks & taskTrackStatistics) {
540 for (int32_t
i = 0;
i < 2;
i++) {
541 snprintf(
name, 2048,
i ?
"nrows_with_cluster" :
"nclusters");
542 createHist(mNCl[
i],
name,
name, GPUTPCGeometry::NROWS + 1, 0, GPUTPCGeometry::NROWS);
544 std::unique_ptr<double[]> binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)};
545 createHist(mTrackPt,
"tracks_pt",
"tracks_pt", AXIS_BINS[4], binsPt.get());
546 for (int32_t
i = 0;
i < 2;
i++) {
547 snprintf(
name, 2048,
i ?
"tracks_dedx_max" :
"tracks_dedx_tot");
548 createHist(mTrackdEdx[
i],
name,
name, 200, -3, 1, 1000, 0,
i ? 1500 : 5000);
550 const uint32_t maxTime = (mTracking && mTracking->GetParam().continuousMaxTimeBin > 0) ? mTracking->GetParam().continuousMaxTimeBin : constants::TPC_MAX_TIME_BIN_TRIGGERED;
551 createHist(mT0[0],
"tracks_t0",
"tracks_t0", (maxTime + 1) / 10, 0, maxTime);
552 createHist(mT0[1],
"tracks_t0_res",
"tracks_t0_res", 1000, -100, 100);
553 createHist(mClXY,
"clXY",
"clXY", 1000, -250, 250, 1000, -250, 250);
555 if (mQATasks & taskClusterRejection) {
556 const int padCount = GPUTPCGeometry::NPads(GPUTPCGeometry::NROWS - 1);
557 for (int32_t
i = 0;
i < 3;
i++) {
558 snprintf(
name, 2048,
"clrej_%d",
i);
559 createHist(mClRej[
i],
name,
name, 2 * padCount, -padCount / 2 + 0.5f, padCount / 2 - 0.5f, GPUTPCGeometry::NROWS, 0, GPUTPCGeometry::NROWS - 1);
561 createHist(mClRejP,
"clrejp",
"clrejp", GPUTPCGeometry::NROWS, 0, GPUTPCGeometry::NROWS - 1);
564 if ((mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) {
566 mHistClusterCount.resize(
num);
567 DoClusterCounts(
nullptr, 1);
571 *mHist1D_pos[
i] = &(*mHist1D)[
i];
574 *mHist2D_pos[
i] = &(*mHist2D)[
i];
577 *mHist1Dd_pos[
i] = &(*mHist1Dd)[
i];
579 for (
uint32_t i = 0;
i < mHistGraph->size();
i++) {
580 *mHistGraph_pos[
i] = &(*mHistGraph)[
i];
586int32_t GPUQA::loadHistograms(std::vector<TH1F>& i1, std::vector<TH2F>& i2, std::vector<TH1D>& i3, std::vector<TGraphAsymmErrors>& i4, int32_t tasks)
588 if (tasks == tasksAutomatic) {
591 if (mQAInitialized && (!mHaveExternalHists || tasks != mQATasks)) {
592 throw std::runtime_error(
"QA not initialized or initialized with different task array");
600 mHist1Dd_pos.clear();
601 mHistGraph_pos.clear();
602 mHaveExternalHists =
true;
607 if (InitQACreateHistograms()) {
610 mQAInitialized =
true;
621 fwrite(&
n,
sizeof(
n), 1, fp);
622 fwrite(mMCInfos.data(),
sizeof(mMCInfos[0]),
n, fp);
623 n = mMCInfosCol.size();
624 fwrite(&
n,
sizeof(
n), 1, fp);
625 fwrite(mMCInfosCol.data(),
sizeof(mMCInfosCol[0]),
n, fp);
626 n = mMCEventOffset.size();
627 fwrite(&
n,
sizeof(
n), 1, fp);
628 fwrite(mMCEventOffset.data(),
sizeof(mMCEventOffset[0]),
n, fp);
640 if ((
x = fread(&
n,
sizeof(
n), 1, fp)) != 1) {
645 if (fread(mMCInfos.data(),
sizeof(mMCInfos[0]),
n, fp) !=
n) {
649 if ((
x = fread(&
n,
sizeof(
n), 1, fp)) != 1) {
653 mMCInfosCol.resize(
n);
654 if (fread(mMCInfosCol.data(),
sizeof(mMCInfosCol[0]),
n, fp) !=
n) {
658 if ((
x = fread(&
n,
sizeof(
n), 1, fp)) != 1) {
662 mMCEventOffset.resize(
n);
663 if (fread(mMCEventOffset.data(),
sizeof(mMCEventOffset[0]),
n, fp) !=
n) {
667 if (mTracking && mTracking->GetProcessingSettings().debugLevel >= 2) {
668 printf(
"Read %ld bytes MC Infos\n", ftell(fp));
672 CopyO2MCtoIOPtr(&mTracking->mIOPtrs);
679 ptr->mcInfosTPC = mMCInfos.data();
680 ptr->nMCInfosTPC = mMCInfos.size();
681 ptr->mcInfosTPCCol = mMCInfosCol.data();
682 ptr->nMCInfosTPCCol = mMCInfosCol.size();
687#ifndef GPUCA_STANDALONE
688 if (!mO2MCDataLoaded) {
689 HighResTimer timer(mTracking && mTracking->GetProcessingSettings().debugLevel);
690 if (mTracking && mTracking->GetProcessingSettings().debugLevel) {
691 GPUInfo(
"Start reading O2 Track MC information");
693 static constexpr float PRIM_MAX_T = 0.01f;
696 std::vector<int32_t> refId;
699 const auto& evrec = dc->getEventRecords();
700 const auto& evparts = dc->getEventParts();
701 std::vector<std::vector<float>> evTimeBins(mcReader.getNSources());
703 evTimeBins[
i].resize(mcReader.getNEvents(
i), -100.f);
706 const auto&
ir = evrec[
i];
708 const int iSim = evparts[
i][
j].sourceID;
709 const int iEv = evparts[
i][
j].entryID;
713 if (evTimeBins[iSim][iEv] >= 0) {
714 throw std::runtime_error(
"Multiple time bins for same MC collision found");
716 evTimeBins[iSim][iEv] = timebin;
721 uint32_t nSimSources = mcReader.getNSources();
722 mMCEventOffset.resize(nSimSources);
726 mMCEventOffset[
i] = nSimTotalEvents;
727 nSimTotalEvents += mcReader.getNEvents(
i);
730 mMCInfosCol.resize(nSimTotalEvents);
731 for (int32_t iSim = 0; iSim < mcReader.getNSources(); iSim++) {
732 for (int32_t
i = 0;
i < mcReader.getNEvents(iSim);
i++) {
733 const float timebin = evTimeBins[iSim][
i];
735 const std::vector<o2::MCTrack>&
tracks = mcReader.getTracks(iSim,
i);
736 const std::vector<o2::TrackReference>& trackRefs = mcReader.getTrackRefsByEvent(iSim,
i);
738 refId.resize(
tracks.size());
739 std::fill(refId.begin(), refId.end(), -1);
741 if (trackRefs[
j].getDetectorId() == o2::detectors::DetID::TPC) {
742 int32_t trkId = trackRefs[
j].getTrackID();
743 if (refId[trkId] == -1) {
748 mMCInfosCol[mMCEventOffset[iSim] +
i].first = mMCInfos.size();
749 mMCInfosCol[mMCEventOffset[iSim] +
i].num =
tracks.size();
750 mMCInfos.resize(mMCInfos.size() +
tracks.size());
752 auto&
info = mMCInfos[mMCInfosCol[mMCEventOffset[iSim] +
i].first +
j];
754 TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(trk.GetPdgCode());
756 if (abs(trk.GetPdgCode()) == kElectron) {
759 if (abs(trk.GetPdgCode()) == kMuonMinus) {
762 if (abs(trk.GetPdgCode()) == kPiPlus) {
765 if (abs(trk.GetPdgCode()) == kKPlus) {
768 if (abs(trk.GetPdgCode()) == kProton) {
772 info.charge = particle ? particle->Charge() : 0;
773 info.prim = trk.T() < PRIM_MAX_T;
774 info.primDaughters = 0;
775 if (trk.getFirstDaughterTrackId() != -1) {
776 for (int32_t k = trk.getFirstDaughterTrackId(); k <= trk.getLastDaughterTrackId(); k++) {
777 if (
tracks[k].
T() < PRIM_MAX_T) {
778 info.primDaughters = 1;
786 const auto& trkRef = trackRefs[refId[
j]];
790 info.pX = trkRef.Px();
791 info.pY = trkRef.Py();
792 info.pZ = trkRef.Pz();
793 info.genRadius = std::sqrt(trk.GetStartVertexCoordinatesX() * trk.GetStartVertexCoordinatesX() + trk.GetStartVertexCoordinatesY() * trk.GetStartVertexCoordinatesY() + trk.GetStartVertexCoordinatesZ() * trk.GetStartVertexCoordinatesZ());
801 if (timer.IsRunning()) {
802 GPUInfo(
"Finished reading O2 Track MC information (%f seconds)", timer.GetCurrentElapsedTime());
804 mO2MCDataLoaded =
true;
807 CopyO2MCtoIOPtr(updateIOPtr);
814 if (mQAInitialized) {
815 throw std::runtime_error(
"QA already initialized");
817 if (tasks == tasksAutomatic) {
821 mHist1D =
new std::vector<TH1F>;
822 mHist2D =
new std::vector<TH2F>;
823 mHist1Dd =
new std::vector<TH1D>;
824 mHistGraph =
new std::vector<TGraphAsymmErrors>;
830 if (mTracking->GetProcessingSettings().qcRunFraction != 100.f && mQATasks != taskClusterCounts) {
831 throw std::runtime_error(
"QA with qcRunFraction only supported for taskClusterCounts");
835 mClNative = mTracking->mIOPtrs.clustersNative;
838 if (InitQACreateHistograms()) {
842 if (mConfig.enableLocalOutput) {
843 mkdir(mConfig.plotsDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
846#ifndef GPUCA_STANDALONE
848 InitO2MCData(mTracking ? &mTracking->mIOPtrs : nullptr);
852 if (mConfig.matchMCLabels.size()) {
853 uint32_t nFiles = mConfig.matchMCLabels.size();
854 std::vector<std::unique_ptr<TFile>> files;
855 std::vector<std::vector<std::vector<int32_t>>*> labelsBuffer(nFiles);
856 std::vector<std::vector<std::vector<int32_t>>*> effBuffer(nFiles);
858 files.emplace_back(std::make_unique<TFile>(mConfig.matchMCLabels[
i].c_str()));
859 labelsBuffer[
i] = (std::vector<std::vector<int32_t>>*)files[
i]->Get(
"mcLabelBuffer");
860 effBuffer[
i] = (std::vector<std::vector<int32_t>>*)files[
i]->Get(
"mcEffBuffer");
861 if (labelsBuffer[
i] ==
nullptr || effBuffer[
i] ==
nullptr) {
862 GPUError(
"Error opening / reading from labels file %u/%s: %p %p",
i, mConfig.matchMCLabels[
i].c_str(), (
void*)labelsBuffer[
i], (
void*)effBuffer[
i]);
867 mGoodTracks.resize(labelsBuffer[0]->
size());
868 mGoodHits.resize(labelsBuffer[0]->
size());
869 for (
uint32_t iEvent = 0; iEvent < labelsBuffer[0]->size(); iEvent++) {
870 std::vector<bool> labelsOK((*effBuffer[0])[iEvent].
size());
871 for (
uint32_t k = 0; k < (*effBuffer[0])[iEvent].
size(); k++) {
873 for (
uint32_t l = 0; l < nFiles; l++) {
874 if ((*effBuffer[0])[iEvent][k] != (*effBuffer[l])[iEvent][k]) {
880 mGoodTracks[iEvent].resize((*labelsBuffer[0])[iEvent].size());
881 for (
uint32_t k = 0; k < (*labelsBuffer[0])[iEvent].
size(); k++) {
882 if ((*labelsBuffer[0])[iEvent][k] == MC_LABEL_INVALID) {
885 mGoodTracks[iEvent][k] = labelsOK[abs((*labelsBuffer[0])[iEvent][k])];
889 mQAInitialized =
true;
895 if (!mQAInitialized) {
896 throw std::runtime_error(
"QA not initialized");
898 if (mTracking && mTracking->GetProcessingSettings().debugLevel >= 2) {
899 GPUInfo(
"Running QA - Mask %d, Efficiency %d, Resolution %d, Pulls %d, Cluster Attachment %d, Track Statistics %d, Cluster Counts %d", mQATasks, (int32_t)(mQATasks & taskTrackingEff), (int32_t)(mQATasks & taskTrackingRes), (int32_t)(mQATasks & taskTrackingResPull), (int32_t)(mQATasks & taskClusterAttach), (int32_t)(mQATasks & taskTrackStatistics), (int32_t)(mQATasks & taskClusterCounts));
901 if (!clNative && mTracking) {
902 clNative = mTracking->mIOPtrs.clustersNative;
904 mClNative = clNative;
907 uint32_t nSimEvents = GetNMCCollissions();
908 if (mTrackMCLabelsReverse.size() < nSimEvents) {
909 mTrackMCLabelsReverse.resize(nSimEvents);
911 if (mRecTracks.size() < nSimEvents) {
912 mRecTracks.resize(nSimEvents);
914 if (mFakeTracks.size() < nSimEvents) {
915 mFakeTracks.resize(nSimEvents);
917 if (mMCParam.size() < nSimEvents) {
918 mMCParam.resize(nSimEvents);
924 if (tracksExternal) {
925#ifndef GPUCA_STANDALONE
926 nReconstructedTracks = tracksExternal->size();
929 nReconstructedTracks = mTracking->mIOPtrs.nMergedTracks;
931 mTrackMCLabels.resize(nReconstructedTracks);
932 for (
uint32_t iCol = 0; iCol < GetNMCCollissions(); iCol++) {
933 mTrackMCLabelsReverse[iCol].resize(GetNMCTracks(iCol));
934 mRecTracks[iCol].resize(GetNMCTracks(iCol));
935 mFakeTracks[iCol].resize(GetNMCTracks(iCol));
936 mMCParam[iCol].resize(GetNMCTracks(iCol));
937 memset(mRecTracks[iCol].
data(), 0, mRecTracks[iCol].
size() *
sizeof(mRecTracks[iCol][0]));
938 memset(mFakeTracks[iCol].
data(), 0, mFakeTracks[iCol].
size() *
sizeof(mFakeTracks[iCol][0]));
939 for (
size_t i = 0;
i < mTrackMCLabelsReverse[iCol].size();
i++) {
940 mTrackMCLabelsReverse[iCol][
i] = -1;
943 if (mQATasks & taskClusterAttach && GetNMCLabels()) {
944 mClusterParam.resize(GetNMCLabels());
945 memset(mClusterParam.data(), 0, mClusterParam.size() *
sizeof(mClusterParam[0]));
950 if (mConfig.writeMCLabels) {
951 mcEffBuffer.resize(mNEvents);
952 mcLabelBuffer.resize(mNEvents);
953 mcEffBuffer[mNEvents - 1].resize(GetNMCTracks(0));
954 mcLabelBuffer[mNEvents - 1].resize(nReconstructedTracks);
957 bool mcAvail = mcPresent() || tracksExtMC;
960 if (tracksExternal) {
961#ifndef GPUCA_STANDALONE
962 for (
uint32_t i = 0;
i < tracksExternal->size();
i++) {
963 mTrackMCLabels[
i] = (*tracksExtMC)[
i];
967 tbb::parallel_for(tbb::blocked_range<uint32_t>(0, nReconstructedTracks, (
QA_DEBUG == 0) ? 32 : nReconstructedTracks), [&](const tbb::blocked_range<
uint32_t>&
range) {
968 auto acc = GPUTPCTrkLbl<true, mcLabelI_t>(GetClusterLabels(), 1.f - mConfig.recThreshold);
973 std::vector<mcLabel_t>
labels;
979 uint32_t hitId = mTracking->mIOPtrs.mergedTrackHits[
track.FirstClusterRef() + k].num;
980 if (hitId >= GetNMCLabels()) {
981 GPUError(
"Invalid hit id %u > %d (nClusters %d)", hitId, GetNMCLabels(), clNative ? clNative->
nClustersTotal : 0);
982 throw std::runtime_error(
"qa error");
985 for (int32_t
j = 0;
j < GetMCLabelNID(hitId);
j++) {
986 if (GetMCLabelID(hitId,
j) >= (
int32_t)GetNMCTracks(GetMCLabelCol(hitId,
j))) {
987 GPUError(
"Invalid label %d > %d (hit %d, label %d, col %d)", GetMCLabelID(hitId,
j), GetNMCTracks(GetMCLabelCol(hitId,
j)), hitId,
j, (int32_t)GetMCLabelCol(hitId,
j));
988 throw std::runtime_error(
"qa error");
990 if (GetMCLabelID(hitId,
j) >= 0) {
992 GPUInfo(
"Track %d Cluster %u Label %d: %d (%f)",
i, k,
j, GetMCLabelID(hitId,
j), GetMCLabelWeight(hitId,
j));
998 float maxweight, sumweight;
1000 auto maxLabel = acc.computeLabel(&maxweight, &sumweight, &maxcount);
1001 mTrackMCLabels[
i] = maxLabel;
1003 const mcInfo_t& mc = GetMCTrack(maxLabel);
1004 GPUInfo(
"Track %d label %d (fake %d) weight %f clusters %d (fitted %d) (%f%% %f%%) Pt %f",
i, maxLabel.getTrackID(), (int32_t)(maxLabel.isFake()), maxweight,
nClusters,
track.NClustersFitted(), 100.f * maxweight / sumweight, 100.f * (
float)maxcount / (
float)
nClusters,
1005 std::sqrt(mc.pX * mc.pX + mc.pY * mc.pY));
1010 if (timer.IsRunning()) {
1011 GPUInfo(
"QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1014 for (
uint32_t i = 0;
i < nReconstructedTracks;
i++) {
1016 mcLabelI_t
label = mTrackMCLabels[
i];
1017 if (mQATasks & taskClusterAttach) {
1022 if (!mTrackMCLabels[
i].
isValid()) {
1027 mClusterParam[mTracking->mIOPtrs.mergedTrackHits[
track->FirstClusterRef() + k].num].fakeAttached++;
1031 if (mMCTrackMin == -1 || (
label.getTrackID() >= mMCTrackMin &&
label.getTrackID() < mMCTrackMax)) {
1036 int32_t hitId = mTracking->mIOPtrs.mergedTrackHits[
track->FirstClusterRef() + k].num;
1037 bool correct =
false;
1038 for (int32_t
j = 0;
j < GetMCLabelNID(hitId);
j++) {
1039 if (
label == GetMCLabel(hitId,
j)) {
1045 mClusterParam[hitId].attached++;
1047 mClusterParam[hitId].fakeAttached++;
1053 if (mTrackMCLabels[
i].isFake()) {
1054 (GetMCTrackObj(mFakeTracks,
label))++;
1055 }
else if (tracksExternal || !
track->MergedLooper()) {
1056 GetMCTrackObj(mRecTracks,
label)++;
1057 if (mMCTrackMin == -1 || (
label.getTrackID() >= mMCTrackMin &&
label.getTrackID() < mMCTrackMax)) {
1058 int32_t& revLabel = GetMCTrackObj(mTrackMCLabelsReverse,
label);
1059 if (tracksExternal) {
1060#ifndef GPUCA_STANDALONE
1061 if (revLabel == -1 || fabsf((*tracksExternal)[
i].getZ()) < fabsf((*tracksExternal)[revLabel].getZ())) {
1066 const auto* trks = mTracking->mIOPtrs.mergedTracks;
1068 if (revLabel == -1) {
1071 float shift1 = mTracking->GetTPCTransform()->convDeltaTimeToDeltaZinTimeFrame(trks[
i].CSide() *
GPUChainTracking::NSECTORS / 2, trks[
i].GetParam().GetTOffset());
1072 float shift2 = mTracking->GetTPCTransform()->convDeltaTimeToDeltaZinTimeFrame(trks[revLabel].CSide() *
GPUChainTracking::NSECTORS / 2, trks[revLabel].GetParam().GetTOffset());
1073 comp = fabsf(trks[
i].GetParam().GetZ() + shift1) < fabsf(trks[revLabel].GetParam().GetZ() + shift2);
1075 if (revLabel == -1 || !trks[revLabel].
OK() || (trks[
i].
OK() && comp)) {
1082 if ((mQATasks & taskClusterAttach) && !tracksExternal) {
1083 std::vector<uint8_t> lowestPadRow(mTracking->mIOPtrs.nMergedTracks);
1085 if (mTracking->mIOPtrs.mergedTrackHitAttachment) {
1087 if (mClusterParam[
i].attached == 0 && mClusterParam[
i].fakeAttached == 0) {
1088 int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[
i];
1091 mcLabelI_t trackL = mTrackMCLabels[
track];
1093 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1095 if (trackL == GetMCLabel(
i,
j)) {
1101 mClusterParam[
i].fakeAdjacent++;
1103 mClusterParam[
i].adjacent++;
1109 if (mTracking->mIOPtrs.nMergedTracks && clNative) {
1110 std::fill(lowestPadRow.begin(), lowestPadRow.end(), 255);
1112 for (
uint32_t iRow = 0; iRow < GPUTPCGeometry::NROWS; iRow++) {
1115 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1116 const mcLabelI_t
label = GetMCLabel(
i,
j);
1120 uint32_t trackId = GetMCTrackObj(mTrackMCLabelsReverse,
label);
1121 if (trackId < lowestPadRow.size() && lowestPadRow[trackId] > iRow) {
1122 lowestPadRow[trackId] = iRow;
1128 for (
uint32_t i = 0;
i < mTracking->mIOPtrs.nMergedTracks;
i++) {
1129 const auto& trk = mTracking->mIOPtrs.mergedTracks[
i];
1130 const auto&
label = mTrackMCLabels[
i];
1131 if (trk.OK() && trk.NClustersFitted() > 50 && CAMath::Abs(trk.GetParam().GetQPt()) < 1.f &&
label.isValid() && !
label.isNoise() &&
1132 (mMCTrackMin == -1 ||
label.getTrackID() >= mMCTrackMin) && (mMCTrackMax == -1 ||
label.getTrackID() < mMCTrackMax)) {
1133 const uint32_t trackId = GetMCTrackObj(mTrackMCLabelsReverse,
label);
1134 if (trackId < lowestPadRow.size() && lowestPadRow[trackId] < 10) {
1137 const auto& cl = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() +
j];
1145 mLowestRowDifferenceVsPad->Fill(pad, difference);
1146 if (CAMath::Abs(difference) > 5 && pad > 5.f && pad < GPUTPCGeometry::NPads(lowestCl->
row) - 5.f) {
1147 mLowestRowTrackMultiplicity->Fill(GetMCTrackObj(mRecTracks,
label));
1152 if (trk.OK() && lowestPadRow[
i] != 255 && trk.NClustersFitted() >= PADROW_CHECK_MINCLS && CAMath::Abs(trk.GetParam().GetQPt()) < 1.0) {
1153 const auto& lowestCl = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef()].
row < mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + trk.NClusters() - 1].row ? mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef()] : mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + trk.NClusters() - 1];
1155 mPadRow[0]->Fill(lowestPadRow[
i], lowestRow, 1.f);
1156 mPadRow[1]->Fill(CAMath::ATan2(trk.GetParam().GetY(), trk.GetParam().GetX()), lowestRow, 1.f);
1157 if (lowestPadRow[
i] < 10 && lowestRow > lowestPadRow[
i] + 3) {
1160 mTracking->GetTPCTransform()->Transform(lowestCl.
sector, lowestCl.
row, cl.getPad(), cl.getTime(),
x,
y,
z, trk.GetParam().GetTOffset());
1161 float phi = CAMath::ATan2(
y,
x);
1162 mPadRow[2]->Fill(phi, lowestRow, 1.f);
1163 if (CAMath::Abs(phi) < 0.15) {
1164 const float time = cl.getTime();
1165 mPadRow[3]->Fill(mTracking->GetParam().GetUnscaledMult(
time), lowestRow, 1.f);
1173 if (mConfig.matchMCLabels.size()) {
1174 mGoodHits[mNEvents - 1].resize(GetNMCLabels());
1175 std::vector<bool> allowMCLabels(GetNMCTracks(0));
1176 for (
uint32_t k = 0; k < GetNMCTracks(0); k++) {
1177 allowMCLabels[k] =
false;
1179 for (
uint32_t i = 0;
i < nReconstructedTracks;
i++) {
1180 if (!mGoodTracks[mNEvents - 1][
i]) {
1183 if (mConfig.matchDisplayMinPt > 0) {
1184 if (!mTrackMCLabels[
i].
isValid()) {
1187 const mcInfo_t&
info = GetMCTrack(mTrackMCLabels[
i]);
1188 if (
info.pX *
info.pX +
info.pY *
info.pY < mConfig.matchDisplayMinPt * mConfig.matchDisplayMinPt) {
1195 int32_t hitId = mTracking->mIOPtrs.mergedTrackHits[
track.FirstClusterRef() +
j].num;
1196 if (GetMCLabelNID(hitId)) {
1197 int32_t mcID = GetMCLabelID(hitId, 0);
1199 allowMCLabels[mcID] =
true;
1205 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1207 if (mcID >= 0 && allowMCLabels[mcID]) {
1208 mGoodHits[mNEvents - 1][
i] =
true;
1213 if (timer.IsRunning()) {
1214 GPUInfo(
"QA Time: Cluster attach status:\t\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1222 for (
uint32_t iCol = 0; iCol < GetNMCCollissions(); iCol++) {
1223 for (
uint32_t i = 0;
i < GetNMCTracks(iCol);
i++) {
1224 mMCParam[iCol][
i].nWeightCls = 0.;
1228 float weightTotal = 0.f;
1229 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1230 if (GetMCLabelID(
i,
j) >= 0) {
1231 weightTotal += GetMCLabelWeight(
i,
j);
1234 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1235 if (GetMCLabelID(
i,
j) >= 0) {
1236 GetMCTrackObj(mMCParam, GetMCLabel(
i,
j)).nWeightCls += GetMCLabelWeight(
i,
j) / weightTotal;
1240 if (timer.IsRunning()) {
1241 GPUInfo(
"QA Time: Compute cluster label weights:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1245 tbb::parallel_for<uint32_t>(0, GetNMCCollissions(), [&](
auto iCol) {
1246 for (
uint32_t i = 0;
i < GetNMCTracks(iCol);
i++) {
1247 const mcInfo_t&
info = GetMCTrack(
i, iCol);
1248 additionalMCParameters& mc2 = mMCParam[iCol][
i];
1250 mc2.phi = M_PI + std::atan2(-
info.pY, -
info.pX);
1253 mc2.theta = mc2.eta = 0.f;
1255 mc2.theta =
info.pZ == 0 ? (M_PI / 2) : (
std::acos(
info.pZ /
std::sqrt(
p)));
1256 mc2.eta = -std::log(std::tan(0.5 * mc2.theta));
1258 if (mConfig.writeMCLabels) {
1259 std::vector<int32_t>& effBuffer = mcEffBuffer[mNEvents - 1];
1260 effBuffer[
i] = mRecTracks[iCol][
i] * 1000 + mFakeTracks[iCol][
i];
1263 }, tbb::simple_partitioner());
1264 if (timer.IsRunning()) {
1265 GPUInfo(
"QA Time: Compute track mc parameters:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1269 if (mQATasks & taskTrackingEff) {
1270 for (
uint32_t iCol = 0; iCol < GetNMCCollissions(); iCol++) {
1271 for (
uint32_t i = 0;
i < GetNMCTracks(iCol);
i++) {
1272 if ((mMCTrackMin != -1 && (int32_t)
i < mMCTrackMin) || (mMCTrackMax != -1 && (
int32_t)
i >= mMCTrackMax)) {
1275 const mcInfo_t&
info = GetMCTrack(
i, iCol);
1276 const additionalMCParameters& mc2 = mMCParam[iCol][
i];
1277 if (mc2.nWeightCls == 0.f) {
1280 const float& mcpt = mc2.pt;
1281 const float& mcphi = mc2.phi;
1282 const float& mceta = mc2.eta;
1284 if (
info.primDaughters) {
1287 if (mc2.nWeightCls < mConfig.minNClEff) {
1290 int32_t findable = mc2.nWeightCls >= mConfig.minNClFindable;
1294 if (
info.charge == 0.f) {
1297 if (mConfig.filterCharge &&
info.charge * mConfig.filterCharge < 0) {
1300 if (mConfig.filterPID >= 0 &&
info.pid != mConfig.filterPID) {
1304 if (fabsf(mceta) > ETA_MAX || mcpt < PT_MIN || mcpt > PT_MAX) {
1309 alpha /= M_PI / 9.f;
1311 alpha *= M_PI / 9.f;
1312 alpha += M_PI / 18.f;
1314 float c = std::cos(
alpha);
1315 float s = std::sin(
alpha);
1318 if (mConfig.dumpToROOTLevel >= 1) {
1321 effdump.Fill(
alpha, localX, localY,
info.z, mcphi, mceta, mcpt, mRecTracks[iCol][
i], mFakeTracks[iCol][
i], findable,
info.prim, mc2.nWeightCls);
1324 for (int32_t
j = 0;
j < 6;
j++) {
1325 if (
j == 3 ||
j == 4) {
1328 for (int32_t k = 0; k < 2; k++) {
1329 if (k == 0 && findable == 0) {
1333 int32_t val = (
j == 0) ? (mRecTracks[iCol][
i] ? 1 : 0) : ((
j == 1) ? (mRecTracks[iCol][
i] ? mRecTracks[iCol][
i] - 1 : 0) : ((
j == 2) ? mFakeTracks[iCol][
i] : 1));
1338 for (int32_t l = 0; l < 5; l++) {
1339 if (
info.prim && mcpt < PT_MIN_PRIM) {
1342 if (l != 3 && fabsf(mceta) > ETA_MAX2) {
1345 if (l < 4 && mcpt < 1.f / mConfig.qpt) {
1349 float pos = l == 0 ? localY : (l == 1 ?
info.z : (l == 2 ? mcphi : (l == 3 ? mceta : mcpt)));
1357 if (timer.IsRunning()) {
1358 GPUInfo(
"QA Time: Fill efficiency histograms:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1363 if (mQATasks & (taskTrackingRes | taskTrackingResPull)) {
1365 prop.SetMaxSinPhi(.999);
1366 prop.SetMaterialTPC();
1367 prop.SetPolynomialField(&mParam->polynomialField);
1369 for (
uint32_t i = 0;
i < mTrackMCLabels.size();
i++) {
1370 if (mConfig.writeMCLabels) {
1371 std::vector<int32_t>& labelBuffer = mcLabelBuffer[mNEvents - 1];
1372 labelBuffer[
i] = mTrackMCLabels[
i].getTrackID();
1374 if (mTrackMCLabels[
i].isFake()) {
1377 const mcInfo_t& mc1 = GetMCTrack(mTrackMCLabels[
i]);
1378 const additionalMCParameters& mc2 = GetMCTrackObj(mMCParam, mTrackMCLabels[
i]);
1380 if (mc1.primDaughters) {
1383 if (!tracksExternal) {
1384 if (!mTracking->mIOPtrs.mergedTracks[
i].OK()) {
1387 if (mTracking->mIOPtrs.mergedTracks[
i].MergedLooper()) {
1391 if ((mMCTrackMin != -1 && mTrackMCLabels[
i].getTrackID() < mMCTrackMin) || (mMCTrackMax != -1 && mTrackMCLabels[
i].getTrackID() >= mMCTrackMax)) {
1394 if (fabsf(mc2.eta) > ETA_MAX || mc2.pt < PT_MIN || mc2.pt > PT_MAX) {
1397 if (mc1.charge == 0.f) {
1404 if (mc1.t0 == -100.f) {
1408 if (mConfig.filterCharge && mc1.charge * mConfig.filterCharge < 0) {
1411 if (mConfig.filterPID >= 0 && mc1.pid != mConfig.filterPID) {
1414 if (mc2.nWeightCls < mConfig.minNClRes) {
1417 if (mConfig.resPrimaries == 1 && !mc1.prim) {
1419 }
else if (mConfig.resPrimaries == 2 && mc1.prim) {
1422 if (GetMCTrackObj(mTrackMCLabelsReverse, mTrackMCLabels[
i]) != (int32_t)
i) {
1429 if (tracksExternal) {
1430#ifndef GPUCA_STANDALONE
1431 for (int32_t k = 0; k < 5; k++) {
1432 param.Par()[k] = (*tracksExternal)[
i].getParams()[k];
1434 for (int32_t k = 0; k < 15; k++) {
1435 param.Cov()[k] = (*tracksExternal)[
i].getCov()[k];
1437 param.X() = (*tracksExternal)[
i].getX();
1438 param.TOffset() = (*tracksExternal)[
i].getTime0();
1439 alpha = (*tracksExternal)[
i].getAlpha();
1440 side = (*tracksExternal)[
i].hasBothSidesClusters() ? 2 : ((*tracksExternal)[
i].hasCSideClusters() ? 1 : 0);
1443 param = mTracking->mIOPtrs.mergedTracks[
i].GetParam();
1444 alpha = mTracking->mIOPtrs.mergedTracks[
i].GetAlpha();
1445 side = mTracking->mIOPtrs.mergedTracks[
i].CCE() ? 2 : (mTracking->mIOPtrs.mergedTracks[
i].CSide() ? 1 : 0);
1449 float c = std::cos(
alpha);
1450 float s = std::sin(
alpha);
1453 mclocal[0] =
x *
c +
y *
s;
1454 mclocal[1] = -
x *
s +
y *
c;
1457 mclocal[2] = px *
c + py *
s;
1458 mclocal[3] = -px *
s + py *
c;
1463 if (mclocal[0] >
param.GetX() + 20) {
1466 if (
param.GetX() > mConfig.maxResX) {
1470 auto getdz = [
this, &
param, &mc1, &
side, tracksExternal]() {
1471 if (tracksExternal) {
1472 return param.GetZ();
1474 if (!mParam->continuousMaxTimeBin) {
1475 return param.GetZ() - mc1.z;
1483 return param.GetZ() + shift - mc1.z;
1487 bool inFlyDirection = 0;
1488 if (mConfig.strict) {
1490 const float dy =
param.Y() - mclocal[1];
1491 const float dz = getdz();
1492 if (dx * dx + dy * dy + dz * dz > 5.f * 5.f) {
1497 if (prop.PropagateToXAlpha(mclocal[0],
alpha, inFlyDirection)) {
1500 if (fabsf(
param.Y() - mclocal[1]) > (mConfig.strict ? 1.f : 4.f) || fabsf(getdz()) > (mConfig.strict ? 1.f : 4.f)) {
1503 float charge = mc1.charge > 0 ? 1.f : -1.f;
1505 float deltaY =
param.GetY() - mclocal[1];
1506 float deltaZ = getdz();
1507 float deltaPhiNative =
param.GetSinPhi() - mclocal[3] / mc2.pt;
1508 float deltaPhi = std::asin(
param.GetSinPhi()) - std::atan2(mclocal[3], mclocal[2]);
1509 float deltaLambdaNative =
param.GetDzDs() - mc1.pZ / mc2.pt;
1510 float deltaLambda = std::atan(
param.GetDzDs()) - std::atan2(mc1.pZ, mc2.pt);
1512 float deltaPt = (fabsf(1.f /
param.GetQPt()) - mc2.pt) / mc2.pt;
1514 float paramval[5] = {mclocal[1], mc1.z, mc2.phi, mc2.eta, mc2.pt};
1515 float resval[5] = {deltaY, deltaZ, mConfig.nativeFitResolutions ? deltaPhiNative : deltaPhi, mConfig.nativeFitResolutions ? deltaLambdaNative : deltaLambda, mConfig.nativeFitResolutions ? deltaPtNative : deltaPt};
1516 float pullval[5] = {deltaY / std::sqrt(
param.GetErr2Y()), deltaZ / std::sqrt(
param.GetErr2Z()), deltaPhiNative / std::sqrt(
param.GetErr2SinPhi()), deltaLambdaNative / std::sqrt(
param.GetErr2DzDs()), deltaPtNative / std::sqrt(
param.GetErr2QPt())};
1518 for (int32_t
j = 0;
j < 5;
j++) {
1519 for (int32_t k = 0; k < 5; k++) {
1520 if (k != 3 && fabsf(mc2.eta) > ETA_MAX2) {
1523 if (k < 4 && mc2.pt < 1.f / mConfig.qpt) {
1526 if (mQATasks & taskTrackingRes) {
1527 mRes2[
j][k]->Fill(resval[
j], paramval[k]);
1529 if (mQATasks & taskTrackingResPull) {
1530 mPull2[
j][k]->Fill(pullval[
j], paramval[k]);
1535 if (timer.IsRunning()) {
1536 GPUInfo(
"QA Time: Fill resolution histograms:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1540 if ((mQATasks & taskClusterAttach) && !tracksExternal) {
1542 for (
uint32_t iTrk = 0; iTrk < nReconstructedTracks; iTrk++) {
1547 if (!mTrackMCLabels[iTrk].
isValid()) {
1552 int32_t hitId = mTracking->mIOPtrs.mergedTrackHits[
track.FirstClusterRef() + k].num;
1553 float totalWeight = 0.;
1554 for (int32_t
j = 0;
j < GetMCLabelNID(hitId);
j++) {
1555 if (GetMCLabelID(hitId,
j) >= 0 && GetMCTrackObj(mMCParam, GetMCLabel(hitId,
j)).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1556 totalWeight += GetMCLabelWeight(hitId,
j);
1559 int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId];
1560 const auto&
r = checkClusterState<false>(attach);
1561 if (totalWeight > 0) {
1562 float weight = 1.f / (totalWeight * (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached));
1563 for (int32_t
j = 0;
j < GetMCLabelNID(hitId);
j++) {
1564 mcLabelI_t
label = GetMCLabel(hitId,
j);
1565 if (!
label.isFake() && GetMCTrackObj(mMCParam,
label).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1566 float pt = GetMCTrackObj(mMCParam,
label).pt;
1567 if (pt < PT_MIN_CLUST) {
1570 mClusters[CL_fake]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1571 mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1572 if (GetMCTrackObj(mRecTracks,
label)) {
1573 mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1575 mClusters[CL_all]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1576 if (
r.protect ||
r.physics) {
1577 mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1580 mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(hitId,
j) *
weight);
1585 float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached);
1586 mClusters[CL_fake]->Fill(0.f,
weight);
1587 mClusters[CL_att_adj]->Fill(0.f,
weight);
1588 mClusters[CL_all]->Fill(0.f,
weight);
1589 mClusterCounts.nUnaccessible +=
weight;
1590 if (
r.protect ||
r.physics) {
1591 mClusters[CL_prot]->Fill(0.f,
weight);
1594 mClusters[CL_physics]->Fill(0.f,
weight);
1600 mcLabelI_t
label = mTrackMCLabels[iTrk];
1601 if (mMCTrackMin != -1 && (
label.getTrackID() < mMCTrackMin ||
label.getTrackID() >= mMCTrackMax)) {
1608 int32_t hitId = mTracking->mIOPtrs.mergedTrackHits[
track.FirstClusterRef() + k].num;
1609 float pt = GetMCTrackObj(mMCParam,
label).pt;
1610 if (pt < PT_MIN_CLUST) {
1613 float weight = 1.f / (mClusterParam[hitId].attached + mClusterParam[hitId].fakeAttached);
1614 bool correct =
false;
1615 for (int32_t
j = 0;
j < GetMCLabelNID(hitId);
j++) {
1616 if (
label == GetMCLabel(hitId,
j)) {
1622 mClusters[CL_attached]->Fill(pt,
weight);
1623 mClusters[CL_tracks]->Fill(pt,
weight);
1625 mClusters[CL_fake]->Fill(pt,
weight);
1627 mClusters[CL_att_adj]->Fill(pt,
weight);
1628 mClusters[CL_all]->Fill(pt,
weight);
1629 int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[hitId];
1630 const auto&
r = checkClusterState<false>(attach);
1631 if (
r.protect ||
r.physics) {
1632 mClusters[CL_prot]->Fill(pt,
weight);
1635 mClusters[CL_physics]->Fill(pt,
weight);
1640 if ((mMCTrackMin != -1 && GetMCLabelID(
i, 0) < mMCTrackMin) || (mMCTrackMax != -1 && GetMCLabelID(
i, 0) >= mMCTrackMax)) {
1643 if (mClusterParam[
i].attached || mClusterParam[
i].fakeAttached) {
1646 int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[
i];
1647 const auto&
r = checkClusterState<false>(attach);
1648 if (mClusterParam[
i].adjacent) {
1651 float totalWeight = 0.;
1652 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1653 mcLabelI_t labelT = GetMCLabel(
i,
j);
1654 if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1655 totalWeight += GetMCLabelWeight(
i,
j);
1658 float weight = 1.f / totalWeight;
1659 if (totalWeight > 0) {
1660 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1661 mcLabelI_t labelT = GetMCLabel(
i,
j);
1662 if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1663 float pt = GetMCTrackObj(mMCParam, labelT).pt;
1664 if (pt < PT_MIN_CLUST) {
1667 if (GetMCTrackObj(mRecTracks, labelT)) {
1668 mClusters[CL_tracks]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1670 mClusters[CL_att_adj]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1671 mClusters[CL_fakeAdj]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1672 mClusters[CL_all]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1673 if (
r.protect ||
r.physics) {
1674 mClusters[CL_prot]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1677 mClusters[CL_physics]->Fill(pt, GetMCLabelWeight(
i,
j) *
weight);
1682 mClusters[CL_att_adj]->Fill(0.f, 1.f);
1683 mClusters[CL_fakeAdj]->Fill(0.f, 1.f);
1684 mClusters[CL_all]->Fill(0.f, 1.f);
1685 mClusterCounts.nUnaccessible++;
1686 if (
r.protect ||
r.physics) {
1687 mClusters[CL_prot]->Fill(0.f, 1.f);
1690 mClusters[CL_physics]->Fill(0.f, 1.f);
1694 float pt = GetMCTrackObj(mMCParam, mTrackMCLabels[
label]).pt;
1695 if (pt < PT_MIN_CLUST) {
1698 mClusters[CL_att_adj]->Fill(pt, 1.f);
1699 mClusters[CL_tracks]->Fill(pt, 1.f);
1700 mClusters[CL_all]->Fill(pt, 1.f);
1701 if (
r.protect ||
r.physics) {
1702 mClusters[CL_prot]->Fill(pt, 1.f);
1705 mClusters[CL_physics]->Fill(pt, 1.f);
1709 float totalWeight = 0.;
1710 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1711 mcLabelI_t labelT = GetMCLabel(
i,
j);
1712 if (!labelT.isFake() && GetMCTrackObj(mMCParam, labelT).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1713 totalWeight += GetMCLabelWeight(
i,
j);
1716 if (totalWeight > 0) {
1717 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1718 mcLabelI_t
label = GetMCLabel(
i,
j);
1719 if (!
label.isFake() && GetMCTrackObj(mMCParam,
label).pt > 1.f / mTracking->GetParam().rec.maxTrackQPtB5) {
1720 float pt = GetMCTrackObj(mMCParam,
label).pt;
1721 if (pt < PT_MIN_CLUST) {
1724 float weight = GetMCLabelWeight(
i,
j) / totalWeight;
1725 if (mClusterParam[
i].fakeAdjacent) {
1726 mClusters[CL_fakeAdj]->Fill(pt,
weight);
1728 if (mClusterParam[
i].fakeAdjacent) {
1729 mClusters[CL_att_adj]->Fill(pt,
weight);
1731 if (GetMCTrackObj(mRecTracks,
label)) {
1732 mClusters[CL_tracks]->Fill(pt,
weight);
1734 mClusters[CL_all]->Fill(pt,
weight);
1735 if (
r.protect ||
r.physics) {
1736 mClusters[CL_prot]->Fill(pt,
weight);
1739 mClusters[CL_physics]->Fill(pt,
weight);
1744 if (mClusterParam[
i].fakeAdjacent) {
1745 mClusters[CL_fakeAdj]->Fill(0.f, 1.f);
1747 if (mClusterParam[
i].fakeAdjacent) {
1748 mClusters[CL_att_adj]->Fill(0.f, 1.f);
1750 mClusters[CL_all]->Fill(0.f, 1.f);
1751 mClusterCounts.nUnaccessible++;
1752 if (
r.protect ||
r.physics) {
1753 mClusters[CL_prot]->Fill(0.f, 1.f);
1756 mClusters[CL_physics]->Fill(0.f, 1.f);
1762 if (timer.IsRunning()) {
1763 GPUInfo(
"QA Time: Fill cluster histograms:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1766 }
else if (!mConfig.inputHistogramsOnly && !mConfig.noMC && (mQATasks & (taskTrackingEff | taskTrackingRes | taskTrackingResPull | taskClusterAttach))) {
1767 GPUWarning(
"No MC information available, only running partial TPC QA!");
1770 if ((mQATasks & taskTrackStatistics) && !tracksExternal) {
1772 std::vector<std::array<float, 3>> clusterAttachCounts;
1774 clusterAttachCounts.resize(GetNMCLabels(), {0.f, 0.f});
1776 for (
uint32_t i = 0;
i < nReconstructedTracks;
i++) {
1781 mTrackPt->Fill(1.f / fabsf(
track.GetParam().GetQPt()));
1782 if (mParam->par.dodEdx && mParam->dodEdxEnabled &&
track.NClusters() >= 60) {
1783 const GPUdEdxInfo& trackdEdx = mTracking->GetProcessors()->tpcMerger.MergedTracksdEdx()[
i];
1784 const float logp = logf(1.f / fabsf(
track.GetParam().GetQPt()) * sqrtf(1.f +
track.GetParam().GetDzDs() *
track.GetParam().GetDzDs()));
1785 mTrackdEdx[0]->Fill(logp, trackdEdx.
dEdxTotTPC);
1786 mTrackdEdx[1]->Fill(logp, trackdEdx.
dEdxMaxTPC);
1788 mNCl[0]->Fill(
track.NClustersFitted());
1790 const auto& trackClusters = mTracking->mIOPtrs.mergedTrackHits;
1794 for (jNext =
j + 1;
j <
track.NClusters(); jNext++) {
1795 if (trackClusters[
track.FirstClusterRef() +
j].sector != trackClusters[
track.FirstClusterRef() + jNext].sector || trackClusters[
track.FirstClusterRef() +
j].row != trackClusters[
track.FirstClusterRef() + jNext].row) {
1800 if (!
track.MergedLooper() && rowClCount) {
1803 if (mcAvail && rowClCount) {
1805 const auto& cl = trackClusters[
track.FirstClusterRef() + k];
1809 bool labelOk =
false, labelOkNonFake =
false;
1810 const mcLabelI_t& trkLabel = mTrackMCLabels[
i];
1811 if (trkLabel.isValid() && !trkLabel.isNoise()) {
1812 for (int32_t l = 0; l < GetMCLabelNID(cl.num); l++) {
1813 const mcLabelI_t& clLabel = GetMCLabel(cl.num, l);
1814 if (clLabel.isValid() && !clLabel.isNoise() && CompareIgnoreFake(trkLabel, clLabel)) {
1816 if (!trkLabel.isFake()) {
1817 labelOkNonFake =
true;
1823 clusterAttachCounts[cl.num][0] += 1.0f;
1824 clusterAttachCounts[cl.num][1] += (
float)labelOk / rowClCount;
1825 clusterAttachCounts[cl.num][2] += (
float)labelOkNonFake / rowClCount;
1830 mNCl[1]->Fill(nClCorrected);
1832 mT0[0]->Fill(
track.GetParam().GetTOffset());
1834 if (mTrackMCLabels.size() && !mTrackMCLabels[
i].isFake() && !
track.MergedLooper() && !
track.CCE()) {
1835 const auto&
info = GetMCTrack(mTrackMCLabels[
i]);
1836 if (
info.t0 != -100.f) {
1837 mT0[1]->Fill(
track.GetParam().GetTOffset() -
info.t0);
1842 if (mClNative && mTracking && mTracking->GetTPCTransform()) {
1844 for (
uint32_t j = 0;
j < GPUTPCGeometry::NROWS;
j++) {
1845 for (
uint32_t k = 0; k < mClNative->nClusters[
i][
j]; k++) {
1846 const auto& cl = mClNative->clusters[
i][
j][k];
1848 GPUTPCConvertImpl::convert(*mTracking->GetTPCTransform(), mTracking->GetParam(),
i,
j, cl.getPad(), cl.getTime(),
x,
y,
z);
1849 mTracking->GetParam().Sector2Global(
i,
x,
y,
z, &
x, &
y, &
z);
1856 double clusterAttachNormalizedCount = 0, clusterAttachNormalizedCountNonFake = 0;
1857 for (
uint32_t i = 0;
i < clusterAttachCounts.size();
i++) {
1858 if (clusterAttachCounts[
i][0]) {
1859 clusterAttachNormalizedCount += clusterAttachCounts[
i][1] / clusterAttachCounts[
i][0];
1860 clusterAttachNormalizedCountNonFake += clusterAttachCounts[
i][2] / clusterAttachCounts[
i][0];
1863 mClusterCounts.nCorrectlyAttachedNormalized = clusterAttachNormalizedCount;
1864 mClusterCounts.nCorrectlyAttachedNormalizedNonFake = clusterAttachNormalizedCountNonFake;
1865 clusterAttachCounts.clear();
1868 if (timer.IsRunning()) {
1869 GPUInfo(
"QA Time: Fill track statistics:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1874 mClusterCounts.nTotal +=
nCl;
1875 if (mQATasks & (taskClusterCounts | taskClusterRejection)) {
1877 for (
uint32_t iRow = 0; iRow < GPUTPCGeometry::NROWS; iRow++) {
1880 int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[
i];
1881 const auto&
r = checkClusterState<true>(attach, &mClusterCounts);
1883 if (mQATasks & taskClusterRejection) {
1885 float totalWeight = 0, weight400 = 0, weight40 = 0;
1886 for (int32_t
j = 0;
j < GetMCLabelNID(
i);
j++) {
1887 const auto&
label = GetMCLabel(
i,
j);
1888 if (GetMCLabelID(
label) >= 0) {
1889 totalWeight += GetMCLabelWeight(
label);
1890 if (GetMCTrackObj(mMCParam,
label).pt >= 0.4) {
1891 weight400 += GetMCLabelWeight(
label);
1893 if (GetMCTrackObj(mMCParam,
label).pt <= 0.04) {
1894 weight40 += GetMCLabelWeight(
label);
1898 if (totalWeight > 0 && 10.f * weight400 >= totalWeight) {
1899 if (!
r.unattached && !
r.protect && !
r.physics) {
1900 mClusterCounts.nFakeRemove400++;
1901 int32_t totalFake = weight400 < 0.9f * totalWeight;
1903 mClusterCounts.nFullFakeRemove400++;
1918 mClusterCounts.nAbove400++;
1920 if (totalWeight > 0 && weight40 >= 0.9 * totalWeight) {
1921 mClusterCounts.nBelow40++;
1922 if (
r.protect ||
r.physics) {
1923 mClusterCounts.nFakeProtect40++;
1929 mClusterCounts.nPhysics++;
1932 mClusterCounts.nProt++;
1935 mClusterCounts.nUnattached++;
1938 if (mQATasks & taskClusterRejection) {
1939 if (mTracking && clNative) {
1941 mClRej[0]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f);
1942 if (!
r.unattached && !
r.protect) {
1943 mClRej[1]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f);
1953 if ((mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) {
1954 DoClusterCounts(
nullptr);
1955 mClusterCounts = counts_t();
1958 if (timer.IsRunning()) {
1959 GPUInfo(
"QA Time: Cluster Counts:\t%6.0f us", timer.GetCurrentElapsedTime(
true) * 1e6);
1962 if (mConfig.dumpToROOTLevel >= 1 && !tracksExternal) {
1963 if (!clNative || !mTracking || !mTracking->mIOPtrs.mergedTrackHitAttachment || !mTracking->mIOPtrs.mergedTracks) {
1964 throw std::runtime_error(
"Cannot dump non o2::tpc::clusterNative clusters, need also hit attachmend and GPU tracks");
1968 for (
uint32_t j = 0;
j < GPUTPCGeometry::NROWS;
j++) {
1969 for (
uint32_t k = 0; k < mClNative->nClusters[
i][
j]; k++) {
1970 const auto& cl = mClNative->clusters[
i][
j][k];
1971 uint32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[clid];
1972 float x = 0,
y = 0,
z = 0;
1975 const auto& trk = mTracking->mIOPtrs.mergedTracks[
track];
1976 mTracking->GetTPCTransform()->Transform(
i,
j, cl.getPad(), cl.getTime(),
x,
y,
z, trk.GetParam().GetTOffset());
1977 mTracking->GetParam().Sector2Global(
i,
x,
y,
z, &
x, &
y, &
z);
1979 uint32_t extState = mTracking->mIOPtrs.mergedTrackHitStates ? mTracking->mIOPtrs.mergedTrackHitStates[clid] : 0;
1981 if (mConfig.dumpToROOTLevel >= 2) {
1984 memset((
void*)&trk, 0,
sizeof(trk));
1985 memset((
void*)&trkHit, 0,
sizeof(trkHit));
1988 trk = mTracking->mIOPtrs.mergedTracks[
track];
1989 for (
uint32_t l = 0; l < trk.NClusters(); l++) {
1990 const auto& tmp = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + l];
1991 if (tmp.num == clid) {
1997 static auto cldump =
GPUROOTDump<o2::tpc::ClusterNative, GPUTPCGMMergedTrack, GPUTPCGMMergedTrackHit, uint32_t, uint32_t, float, float, float, uint32_t, uint32_t, uint32_t>::getNew(
"cluster",
"track",
"trackHit",
"attach",
"extState",
"x",
"y",
"z",
"sector",
"row",
"nEv",
"clusterTree");
1998 cldump.Fill(cl, trk, trkHit, attach, extState,
x,
y,
z,
i,
j, mNEvents - 1);
2000 static auto cldump =
GPUROOTDump<o2::tpc::ClusterNative, uint32_t, uint32_t, float, float, float, uint32_t, uint32_t, uint32_t>::getNew(
"cluster",
"attach",
"extState",
"x",
"y",
"z",
"sector",
"row",
"nEv",
"clusterTree");
2001 cldump.Fill(cl, attach, extState,
x,
y,
z,
i,
j, mNEvents - 1);
2009 for (
uint32_t i = 0;
i < mTracking->mIOPtrs.nMergedTracks;
i++) {
2010 if (mTracking->mIOPtrs.mergedTracks[
i].OK()) {
2011 trkdump.Fill(mNEvents - 1, mTracking->mIOPtrs.mergedTracks[
i]);
2015 if (mTracking && mTracking->GetProcessingSettings().createO2Output) {
2017 for (
uint32_t i = 0;
i < mTracking->mIOPtrs.nOutputTracksTPCO2;
i++) {
2018 o2trkdump.Fill(mNEvents - 1, mTracking->mIOPtrs.outputTracksTPCO2[
i]);
2023 if (mConfig.compareTrackStatus) {
2024#ifdef GPUCA_DETERMINISTIC_MODE
2025 if (!mTracking || !mTracking->GetProcessingSettings().deterministicGPUReconstruction)
2028 throw std::runtime_error(
"Need deterministic processing to compare track status");
2030 std::vector<uint8_t> status(mTracking->mIOPtrs.nMergedTracks);
2031 for (
uint32_t i = 0;
i < mTracking->mIOPtrs.nMergedTracks;
i++) {
2032 const auto& trk = mTracking->mIOPtrs.mergedTracks[
i];
2033 status[
i] = trk.OK() && trk.NClusters() && trk.GetParam().GetNDF() > 0 && (mConfig.noMC || (mTrackMCLabels[
i].isValid() && !mTrackMCLabels[
i].isFake()));
2035 if (mConfig.compareTrackStatus == 1) {
2036 std::ofstream(
"track.status", std::ios::binary).write((
char*)status.data(), status.size() *
sizeof(status[0]));
2037 }
else if (mConfig.compareTrackStatus == 2) {
2038 std::ifstream
f(
"track.status", std::ios::binary | std::ios::ate);
2039 std::vector<uint8_t> comp(
f.tellg());
2041 f.read((
char*)comp.data(), comp.size());
2043 if (comp.size() != status.size()) {
2044 throw std::runtime_error(
"Number of tracks candidates in track fit in track.status and in current reconstruction differ");
2046 std::vector<uint32_t> missing, missingComp;
2048 if (status[
i] && !comp[
i]) {
2049 missingComp.emplace_back(
i);
2051 if (comp[
i] && !status[
i]) {
2052 missing.emplace_back(
i);
2055 auto printer = [](std::vector<uint32_t>
m,
const char*
name) {
2057 printf(
"Missing in %s reconstruction: (%zu)\n",
name,
m.size());
2067 printer(missing,
"current");
2068 printer(missingComp,
"comparison");
2072 mTrackingScratchBuffer.clear();
2073 mTrackingScratchBuffer.shrink_to_fit();
2076void GPUQA::GetName(
char* fname, int32_t k,
bool noDash)
2078 const int32_t nNewInput = mConfig.inputHistogramsOnly ? 0 : 1;
2079 if (k || mConfig.inputHistogramsOnly || mConfig.name.size()) {
2080 if (!(mConfig.inputHistogramsOnly || k)) {
2081 snprintf(fname, 1024,
"%s%s", mConfig.name.c_str(), noDash ?
"" :
" - ");
2082 }
else if (mConfig.compareInputNames.size() > (
unsigned)(k - nNewInput)) {
2083 snprintf(fname, 1024,
"%s%s", mConfig.compareInputNames[k - nNewInput].c_str(), noDash ?
"" :
" - ");
2085 strcpy(fname, mConfig.compareInputs[k - nNewInput].c_str());
2086 if (strlen(fname) > 5 && strcmp(fname + strlen(fname) - 5,
".root") == 0) {
2087 fname[strlen(fname) - 5] = 0;
2090 strcat(fname,
" - ");
2099T* GPUQA::GetHist(T*& ee, std::vector<std::unique_ptr<TFile>>& tin, int32_t k, int32_t nNewInput)
2102 if ((mConfig.inputHistogramsOnly || k) && (
e =
dynamic_cast<T*
>(tin[k - nNewInput]->Get(
e->GetName()))) ==
nullptr) {
2103 GPUWarning(
"Missing histogram in input %s: %s", mConfig.compareInputs[k - nNewInput].c_str(), ee->GetName());
2110void GPUQA::DrawQAHistogramsCleanup()
2112 clearGarbagageCollector();
2115void GPUQA::resetHists()
2117 if (!mQAInitialized) {
2118 throw std::runtime_error(
"QA not initialized");
2120 if (mHaveExternalHists) {
2121 throw std::runtime_error(
"Cannot reset external hists");
2123 for (
auto&
h : *mHist1D) {
2126 for (
auto&
h : *mHist2D) {
2129 for (
auto&
h : *mHist1Dd) {
2132 for (
auto&
h : *mHistGraph) {
2133 h = TGraphAsymmErrors();
2135 mClusterCounts = counts_t();
2140 const auto oldRootIgnoreLevel = gErrorIgnoreLevel;
2141 gErrorIgnoreLevel = kWarning;
2142 if (!mQAInitialized) {
2143 throw std::runtime_error(
"QA not initialized");
2146 if (mTracking && mTracking->GetProcessingSettings().debugLevel >= 2) {
2147 printf(
"Creating QA Histograms\n");
2150 std::vector<Color_t> colorNums(COLORCOUNT);
2151 if (!(qcout || mConfig.writeFileExt ==
"root" || mConfig.writeFileExt ==
"C")) {
2152 [[maybe_unused]]
static int32_t initColorsInitialized = initColors();
2154 for (int32_t
i = 0;
i < COLORCOUNT;
i++) {
2155 colorNums[
i] = (qcout || mConfig.writeFileExt ==
"root" || mConfig.writeFileExt ==
"C") ? defaultColorNums[
i] : mColors[
i]->GetNumber();
2158 bool mcAvail = mcPresent();
2159 char name[2048], fname[1024];
2161 const int32_t nNewInput = mConfig.inputHistogramsOnly ? 0 : 1;
2162 const int32_t ConfigNumInputs = nNewInput + mConfig.compareInputs.size();
2164 std::vector<std::unique_ptr<TFile>> tin;
2165 for (
uint32_t i = 0;
i < mConfig.compareInputs.size();
i++) {
2166 tin.emplace_back(std::make_unique<TFile>(mConfig.compareInputs[
i].c_str()));
2168 std::unique_ptr<TFile> tout =
nullptr;
2169 if (mConfig.output.size()) {
2170 tout = std::make_unique<TFile>(mConfig.output.c_str(),
"RECREATE");
2173 if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) {
2174 float legendSpacingString = 0.025;
2175 for (int32_t
i = 0;
i < ConfigNumInputs;
i++) {
2177 if (strlen(fname) * 0.006 > legendSpacingString) {
2178 legendSpacingString = strlen(fname) * 0.006;
2183 if (mQATasks & taskTrackingEff) {
2184 for (int32_t ii = 0; ii < 6; ii++) {
2185 snprintf(
name, 1024,
"eff_vs_%s_layout", VSPARAMETER_NAMES[ii]);
2186 mCEff[ii] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2189 mPEff[ii][0] = createGarbageCollected<TPad>(
"p0",
"", 0.0, dy * 0, 0.5, dy * 1);
2190 mPEff[ii][0]->Draw();
2191 mPEff[ii][0]->SetRightMargin(0.04);
2192 mPEff[ii][1] = createGarbageCollected<TPad>(
"p1",
"", 0.5, dy * 0, 1.0, dy * 1);
2193 mPEff[ii][1]->Draw();
2194 mPEff[ii][1]->SetRightMargin(0.04);
2195 mPEff[ii][2] = createGarbageCollected<TPad>(
"p2",
"", 0.0, dy * 1, 0.5, dy * 2 - .001);
2196 mPEff[ii][2]->Draw();
2197 mPEff[ii][2]->SetRightMargin(0.04);
2198 mPEff[ii][3] = createGarbageCollected<TPad>(
"p3",
"", 0.5, dy * 1, 1.0, dy * 2 - .001);
2199 mPEff[ii][3]->Draw();
2200 mPEff[ii][3]->SetRightMargin(0.04);
2201 mLEff[ii] = createGarbageCollected<TLegend>(0.92 - legendSpacingString * 1.45, 0.83 - (0.93 - 0.82) / 2. * (
float)ConfigNumInputs, 0.98, 0.849);
2202 SetLegend(mLEff[ii]);
2207 if (mQATasks & taskTrackingRes) {
2208 for (int32_t ii = 0; ii < 7; ii++) {
2210 snprintf(
name, 1024,
"res_integral_layout");
2212 snprintf(
name, 1024,
"res_vs_%s_layout", VSPARAMETER_NAMES[ii]);
2214 mCRes[ii] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2216 gStyle->SetOptFit(1);
2219 mPRes[ii][3] = createGarbageCollected<TPad>(
"p0",
"", 0.0, dy * 0, 0.5, dy * 1);
2220 mPRes[ii][3]->Draw();
2221 mPRes[ii][3]->SetRightMargin(0.04);
2222 mPRes[ii][4] = createGarbageCollected<TPad>(
"p1",
"", 0.5, dy * 0, 1.0, dy * 1);
2223 mPRes[ii][4]->Draw();
2224 mPRes[ii][4]->SetRightMargin(0.04);
2225 mPRes[ii][0] = createGarbageCollected<TPad>(
"p2",
"", 0.0, dy * 1, 1. / 3., dy * 2 - .001);
2226 mPRes[ii][0]->Draw();
2227 mPRes[ii][0]->SetRightMargin(0.04);
2228 mPRes[ii][0]->SetLeftMargin(0.15);
2229 mPRes[ii][1] = createGarbageCollected<TPad>(
"p3",
"", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001);
2230 mPRes[ii][1]->Draw();
2231 mPRes[ii][1]->SetRightMargin(0.04);
2232 mPRes[ii][1]->SetLeftMargin(0.135);
2233 mPRes[ii][2] = createGarbageCollected<TPad>(
"p4",
"", 2. / 3., dy * 1, 1.0, dy * 2 - .001);
2234 mPRes[ii][2]->Draw();
2235 mPRes[ii][2]->SetRightMargin(0.06);
2236 mPRes[ii][2]->SetLeftMargin(0.135);
2238 mLRes[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (
float)ConfigNumInputs, 0.98, 0.949);
2239 SetLegend(mLRes[ii]);
2245 if (mQATasks & taskTrackingResPull) {
2246 for (int32_t ii = 0; ii < 7; ii++) {
2248 snprintf(
name, 1024,
"pull_integral_layout");
2250 snprintf(
name, 1024,
"pull_vs_%s_layout", VSPARAMETER_NAMES[ii]);
2252 mCPull[ii] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2254 gStyle->SetOptFit(1);
2257 mPPull[ii][3] = createGarbageCollected<TPad>(
"p0",
"", 0.0, dy * 0, 0.5, dy * 1);
2258 mPPull[ii][3]->Draw();
2259 mPPull[ii][3]->SetRightMargin(0.04);
2260 mPPull[ii][4] = createGarbageCollected<TPad>(
"p1",
"", 0.5, dy * 0, 1.0, dy * 1);
2261 mPPull[ii][4]->Draw();
2262 mPPull[ii][4]->SetRightMargin(0.04);
2263 mPPull[ii][0] = createGarbageCollected<TPad>(
"p2",
"", 0.0, dy * 1, 1. / 3., dy * 2 - .001);
2264 mPPull[ii][0]->Draw();
2265 mPPull[ii][0]->SetRightMargin(0.04);
2266 mPPull[ii][0]->SetLeftMargin(0.15);
2267 mPPull[ii][1] = createGarbageCollected<TPad>(
"p3",
"", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001);
2268 mPPull[ii][1]->Draw();
2269 mPPull[ii][1]->SetRightMargin(0.04);
2270 mPPull[ii][1]->SetLeftMargin(0.135);
2271 mPPull[ii][2] = createGarbageCollected<TPad>(
"p4",
"", 2. / 3., dy * 1, 1.0, dy * 2 - .001);
2272 mPPull[ii][2]->Draw();
2273 mPPull[ii][2]->SetRightMargin(0.06);
2274 mPPull[ii][2]->SetLeftMargin(0.135);
2276 mLPull[ii] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (
float)ConfigNumInputs, 0.98, 0.949);
2277 SetLegend(mLPull[ii]);
2283 if (mQATasks & taskClusterAttach) {
2284 for (int32_t
i = 0;
i < 3;
i++) {
2285 snprintf(
name, 1024,
"clusters_%s_layout", CLUSTER_TYPES[
i]);
2286 mCClust[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2288 mPClust[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2290 float y1 =
i != 1 ? 0.77 : 0.27,
y2 =
i != 1 ? 0.9 : 0.42;
2291 mLClust[
i] = createGarbageCollected<TLegend>(
i == 2 ? 0.1 : (0.65 - legendSpacingString * 1.45),
y2 - (
y2 -
y1) * (ConfigNumInputs + (
i != 1) / 2.) + 0.005,
i == 2 ? (0.3 + legendSpacingString * 1.45) : 0.9,
y2);
2292 SetLegend(mLClust[
i]);
2297 if (mQATasks & taskTrackStatistics) {
2298 for (int32_t
i = 0;
i < 3;
i++) {
2299 snprintf(
name, 2048,
"ctracks%s",
i ? (
i == 2 ?
"dedxmax" :
"dedxtot") :
"pt");
2300 mCTracks[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2302 mPTracks[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2303 mPTracks[
i]->Draw();
2304 mLTracks[
i] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.5, 0.93 - (0.93 - 0.86) / 2. * (
float)ConfigNumInputs, 0.98, 0.949);
2305 SetLegend(mLTracks[
i],
true);
2308 for (int32_t
i = 0;
i < 2;
i++) {
2309 snprintf(
name, 2048,
"ctrackst0%d",
i);
2310 mCT0[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2312 mPT0[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2314 mLT0[
i] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (
float)ConfigNumInputs, 0.98, 0.949);
2317 snprintf(
name, 2048,
"cncl%d",
i);
2318 mCNCl[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2320 mPNCl[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2322 mLNCl[
i] = createGarbageCollected<TLegend>(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (
float)ConfigNumInputs, 0.98, 0.949);
2323 SetLegend(mLNCl[
i],
true);
2326 mCClXY = createGarbageCollected<TCanvas>(
"clxy",
"clxy", 0, 0, 700, 700. * 2. / 3.);
2328 mPClXY = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2332 if (mQATasks & taskClusterRejection) {
2333 for (int32_t
i = 0;
i < 3;
i++) {
2334 snprintf(
name, 2048,
"cnclrej%d",
i);
2335 mCClRej[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2337 mPClRej[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2340 mCClRejP = createGarbageCollected<TCanvas>(
"cnclrejp",
"cnclrejp", 0, 0, 700, 700. * 2. / 3.);
2342 mPClRejP = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2346 if (mQATasks & taskClusterAttach) {
2347 for (int32_t
i = 0;
i < 4;
i++) {
2348 snprintf(
name, 2048,
"cpadrow%d",
i);
2349 mCPadRow[
i] = createGarbageCollected<TCanvas>(
name,
name, 0, 0, 700, 700. * 2. / 3.);
2351 mPPadRow[
i] = createGarbageCollected<TPad>(
"p0",
"", 0.0, 0.0, 1.0, 1.0);
2352 mPPadRow[
i]->Draw();
2357 if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && (mQATasks & taskTrackingEff) && mcPresent()) {
2358 GPUInfo(
"QA Stats: Eff: Tracks Prim %d (Eta %d, Pt %d) %f%% (%f%%) Sec %d (Eta %d, Pt %d) %f%% (%f%%) - Res: Tracks %d (Eta %d, Pt %d)", (int32_t)mEff[3][1][0][0]->GetEntries(), (int32_t)mEff[3][1][0][3]->GetEntries(), (int32_t)mEff[3][1][0][4]->GetEntries(),
2359 mEff[0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0]->GetSumOfWeights()), (int32_t)mEff[3][1][1][0]->GetEntries(), (int32_t)mEff[3][1][1][3]->GetEntries(),
2360 (int32_t)mEff[3][1][1][4]->GetEntries(), mEff[0][0][1][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0]->GetSumOfWeights()), mEff[0][1][1][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0]->GetSumOfWeights()), (int32_t)mRes2[0][0]->GetEntries(),
2361 (int32_t)mRes2[0][3]->GetEntries(), (int32_t)mRes2[0][4]->GetEntries());
2364 int32_t flagShowVsPtLog = (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) ? 1 : 0;
2366 if (mQATasks & taskTrackingEff) {
2368 for (int32_t ii = 0; ii < 5 + flagShowVsPtLog; ii++) {
2370 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2371 for (int32_t
j = 0;
j < 4;
j++) {
2372 if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) {
2375 mPEff[ii][
j]->SetLogx();
2378 for (int32_t l = 0; l < 3; l++) {
2379 if (k == 0 && mConfig.inputHistogramsOnly == 0 && ii != 5) {
2382 auto oldLevel = gErrorIgnoreLevel;
2383 gErrorIgnoreLevel = kError;
2384 mEffResult[0][
j / 2][
j % 2][
i]->Divide(mEff[l][
j / 2][
j % 2][
i], mEff[5][
j / 2][
j % 2][
i],
"cl=0.683 b(1,1) mode");
2385 gErrorIgnoreLevel = oldLevel;
2386 mEff[3][
j / 2][
j % 2][
i]->Reset();
2387 mEff[3][
j / 2][
j % 2][
i]->Add(mEff[0][
j / 2][
j % 2][
i]);
2388 mEff[3][
j / 2][
j % 2][
i]->Add(mEff[1][
j / 2][
j % 2][
i]);
2389 mEff[3][
j / 2][
j % 2][
i]->Add(mEff[2][
j / 2][
j % 2][
i]);
2390 mEff[4][
j / 2][
j % 2][
i]->Reset();
2391 mEff[4][
j / 2][
j % 2][
i]->Add(mEff[0][
j / 2][
j % 2][
i]);
2392 mEff[4][
j / 2][
j % 2][
i]->Add(mEff[1][
j / 2][
j % 2][
i]);
2395 auto oldLevel = gErrorIgnoreLevel;
2396 gErrorIgnoreLevel = kError;
2397 mEffResult[l][
j / 2][
j % 2][
i]->Divide(mEff[l][
j / 2][
j % 2][
i], mEff[l == 1 ? 4 : 3][
j / 2][
j % 2][
i],
"cl=0.683 b(1,1) mode");
2398 gErrorIgnoreLevel = oldLevel;
2402 TGraphAsymmErrors*
e = mEffResult[l][
j / 2][
j % 2][
i];
2404 if (!mConfig.inputHistogramsOnly && k == 0) {
2406 mEff[l][
j / 2][
j % 2][
i]->Write();
2409 mEff[3][
j / 2][
j % 2][
i]->Write();
2410 mEff[4][
j / 2][
j % 2][
i]->Write();
2413 }
else if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2416 e->SetTitle(EFFICIENCY_TITLES[
j]);
2417 e->GetYaxis()->SetTitle(
"(Efficiency)");
2418 e->GetXaxis()->SetTitle(XAXIS_TITLES[
i]);
2421 e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1);
2423 if (qcout && !mConfig.shipToQCAsCanvas) {
2426 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2429 e->SetMarkerColor(kBlack);
2430 e->SetLineColor(colorNums[(k < 3 ? (l * 3 + k) : (k * 3 + l)) % COLORCOUNT]);
2431 e->GetHistogram()->GetYaxis()->SetRangeUser(-0.02, 1.02);
2432 e->Draw(k || l ?
"same P" :
"AP");
2435 mLEff[ii]->AddEntry(
e, Form(
"%s%s", fname, EFF_NAMES[l]),
"l");
2438 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2442 ChangePadTitleSize(mPEff[ii][
j], 0.056);
2445 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2452 qcout->Add(mCEff[ii]);
2454 if (!mConfig.enableLocalOutput) {
2457 doPerfFigure(0.2, 0.295, 0.025);
2458 mCEff[ii]->Print(Form(
"%s/eff_vs_%s.pdf", mConfig.plotsDir.c_str(), VSPARAMETER_NAMES[ii]));
2459 if (mConfig.writeFileExt !=
"") {
2460 mCEff[ii]->Print(Form(
"%s/eff_vs_%s.%s", mConfig.plotsDir.c_str(), VSPARAMETER_NAMES[ii], mConfig.writeFileExt.c_str()));
2465 if (mQATasks & (taskTrackingRes | taskTrackingResPull)) {
2467 TH1D *resIntegral[5] = {}, *pullIntegral[5] = {};
2468 TCanvas* cfit =
nullptr;
2469 std::unique_ptr<TF1> customGaus = std::make_unique<TF1>(
"G",
"[0]*exp(-(x-[1])*(x-[1])/(2.*[2]*[2]))");
2470 for (int32_t p = 0;
p < 2;
p++) {
2471 if ((p == 0 && (mQATasks & taskTrackingRes) == 0) || (p == 1 && (mQATasks & taskTrackingResPull) == 0)) {
2474 for (int32_t ii = 0; ii < 5 + flagShowVsPtLog; ii++) {
2475 TCanvas* can =
p ? mCPull[ii] : mCRes[ii];
2476 TLegend* leg =
p ? mLPull[ii] : mLRes[ii];
2478 for (int32_t
j = 0;
j < 5;
j++) {
2479 TH2F*
src =
p ? mPull2[
j][
i] : mRes2[
j][
i];
2480 TH1F**
dst =
p ? mPull[
j][
i] : mRes[
j][
i];
2481 TH1D*& dstIntegral =
p ? pullIntegral[
j] : resIntegral[
j];
2482 TPad* pad =
p ? mPPull[ii][
j] : mPRes[ii][
j];
2484 if (!mConfig.inputHistogramsOnly && ii != 5) {
2485 if (cfit ==
nullptr) {
2486 cfit = createGarbageCollected<TCanvas>();
2490 TAxis* axis =
src->GetYaxis();
2491 int32_t nBins = axis->GetNbins();
2493 for (int32_t bin = 1; bin <= nBins; bin++) {
2494 int32_t bin0 = std::max(bin - integ, 0);
2495 int32_t bin1 = std::min(bin + integ, nBins);
2496 std::unique_ptr<TH1D> proj{
src->ProjectionX(
"proj", bin0, bin1)};
2497 proj->ClearUnderflowAndOverflow();
2498 if (proj->GetEntries()) {
2500 while (proj->GetMaximum() < 50 && rebin <
sizeof(RES_AXIS_BINS) /
sizeof(RES_AXIS_BINS[0])) {
2501 proj->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]);
2505 if (proj->GetEntries() < 20 || proj->GetRMS() < 0.00001) {
2506 dst[0]->SetBinContent(bin, proj->GetRMS());
2507 dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS()));
2508 dst[1]->SetBinContent(bin, proj->GetMean());
2509 dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS()));
2511 proj->GetXaxis()->SetRange(0, 0);
2512 proj->GetXaxis()->SetRangeUser(std::max(proj->GetXaxis()->GetXmin(), proj->GetMean() - 3. * proj->GetRMS()), std::min(proj->GetXaxis()->GetXmax(), proj->GetMean() + 3. * proj->GetRMS()));
2513 bool forceLogLike = proj->GetMaximum() < 20;
2514 for (int32_t k = forceLogLike ? 2 : 0; k < 3; k++) {
2515 proj->Fit(
"gaus", forceLogLike || k == 2 ?
"sQl" : (k ?
"sQww" :
"sQ"));
2516 TF1* fitFunc = proj->GetFunction(
"gaus");
2518 if (k && !forceLogLike) {
2519 customGaus->SetParameters(fitFunc->GetParameter(0), fitFunc->GetParameter(1), fitFunc->GetParameter(2));
2520 proj->Fit(customGaus.get(),
"sQ");
2521 fitFunc = customGaus.get();
2524 const float sigma = fabs(fitFunc->GetParameter(2));
2525 dst[0]->SetBinContent(bin, sigma);
2526 dst[1]->SetBinContent(bin, fitFunc->GetParameter(1));
2527 dst[0]->SetBinError(bin, fitFunc->GetParError(2));
2528 dst[1]->SetBinError(bin, fitFunc->GetParError(1));
2530 const bool fail1 = sigma <= 0.f;
2531 const bool fail2 = fabs(proj->GetMean() -
dst[1]->GetBinContent(bin)) > std::min<float>(p ? PULL_AXIS : (mConfig.nativeFitResolutions ? RES_AXES_NATIVE[
j] : RES_AXES[
j]), 3.f * proj->GetRMS());
2532 const bool fail3 =
dst[0]->GetBinContent(bin) > 3.f * proj->GetRMS() ||
dst[0]->GetBinError(bin) > 1 ||
dst[1]->GetBinError(bin) > 1;
2533 const bool fail4 = fitFunc->GetParameter(0) < proj->GetMaximum() / 5.;
2534 const bool fail = fail1 || fail2 || fail3 || fail4;
2539 }
else if (k >= 2) {
2540 dst[0]->SetBinContent(bin, proj->GetRMS());
2541 dst[0]->SetBinError(bin, std::sqrt(proj->GetRMS()));
2542 dst[1]->SetBinContent(bin, proj->GetMean());
2543 dst[1]->SetBinError(bin, std::sqrt(proj->GetRMS()));
2548 dst[0]->SetBinContent(bin, 0.f);
2549 dst[0]->SetBinError(bin, 0.f);
2550 dst[1]->SetBinContent(bin, 0.f);
2551 dst[1]->SetBinError(bin, 0.f);
2555 dstIntegral =
src->ProjectionX(mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[
j] : PARAMETER_NAMES[
j], 0, nBins + 1);
2557 while (dstIntegral->GetMaximum() < 50 && rebin <
sizeof(RES_AXIS_BINS) /
sizeof(RES_AXIS_BINS[0])) {
2558 dstIntegral->Rebin(RES_AXIS_BINS[rebin - 1] / RES_AXIS_BINS[rebin]);
2564 if (mConfig.inputHistogramsOnly) {
2565 dstIntegral = createGarbageCollected<TH1D>();
2567 dstIntegral->SetName(Form(p ?
"IntPull%s" :
"IntRes%s", VSPARAMETER_NAMES[
j]));
2568 dstIntegral->SetTitle(Form(p ?
"%s Pull" :
"%s Resolution",
p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[
j] : PARAMETER_NAMES[
j]));
2570 if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) {
2574 float tmpMax = -1000.;
2575 float tmpMin = 1000.;
2577 for (int32_t l = 0; l < 2; l++) {
2578 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2580 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2583 if (nNewInput && k == 0 && ii != 5) {
2585 e->Scale(mConfig.nativeFitResolutions ? SCALE_NATIVE[
j] : SCALE[
j]);
2589 e->GetXaxis()->SetRangeUser(0.2, PT_MAX);
2590 }
else if (LOG_PT_MIN > 0 && ii == 5) {
2591 e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX);
2592 }
else if (ii == 5) {
2593 e->GetXaxis()->SetRange(1, 0);
2595 e->SetMinimum(-1111);
2596 e->SetMaximum(-1111);
2598 if (
e->GetMaximum() > tmpMax) {
2599 tmpMax =
e->GetMaximum();
2601 if (
e->GetMinimum() < tmpMin) {
2602 tmpMin =
e->GetMinimum();
2608 tmpSpan = tmpMax - tmpMin;
2609 tmpMax += tmpSpan * .02;
2610 tmpMin -= tmpSpan * .02;
2611 if (
j == 2 &&
i < 3) {
2612 tmpMax += tmpSpan * 0.13 * ConfigNumInputs;
2615 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2616 for (int32_t l = 0; l < 2; l++) {
2618 if (!mConfig.inputHistogramsOnly && k == 0) {
2619 e->SetTitle(Form(p ?
"%s Pull" :
"%s Resolution",
p || mConfig.nativeFitResolutions ? PARAMETER_NAMES_NATIVE[
j] : PARAMETER_NAMES[
j]));
2620 e->SetStats(kFALSE);
2623 mRes2[
j][
i]->SetOption(
"colz");
2624 mRes2[
j][
i]->Write();
2628 }
else if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2631 e->SetMaximum(tmpMax);
2632 e->SetMinimum(tmpMin);
2634 e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1);
2636 e->GetYaxis()->SetTitle(p ? AXIS_TITLES_PULL[
j] : (mConfig.nativeFitResolutions ? AXIS_TITLES_NATIVE[
j] : AXIS_TITLES[
j]));
2637 e->GetXaxis()->SetTitle(XAXIS_TITLES[
i]);
2638 if (LOG_PT_MIN > 0 && ii == 5) {
2639 e->GetXaxis()->SetRangeUser(LOG_PT_MIN, PT_MAX);
2643 e->GetYaxis()->SetTitleOffset(1.5);
2645 e->GetYaxis()->SetTitleOffset(1.4);
2647 if (qcout && !mConfig.shipToQCAsCanvas) {
2650 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2654 e->SetMarkerColor(kBlack);
2655 e->SetLineColor(colorNums[numColor++ % COLORCOUNT]);
2656 e->Draw(k || l ?
"same" :
"");
2659 leg->AddEntry(
e, Form(
"%s%s", fname, l ?
"Mean" : (
p ?
"Pull" :
"Resolution")),
"l");
2663 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2672 ChangePadTitleSize(pad, 0.056);
2675 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2684 if (!mConfig.enableLocalOutput) {
2687 doPerfFigure(0.2, 0.295, 0.025);
2688 can->Print(Form(p ?
"%s/pull_vs_%s.pdf" :
"%s/res_vs_%s.pdf", mConfig.plotsDir.c_str(), VSPARAMETER_NAMES[ii]));
2689 if (mConfig.writeFileExt !=
"") {
2690 can->Print(Form(p ?
"%s/pull_vs_%s.%s" :
"%s/res_vs_%s.%s", mConfig.plotsDir.c_str(), VSPARAMETER_NAMES[ii], mConfig.writeFileExt.c_str()));
2696 for (int32_t p = 0;
p < 2;
p++) {
2697 if ((p == 0 && (mQATasks & taskTrackingRes) == 0) || (p == 1 && (mQATasks & taskTrackingResPull) == 0)) {
2700 TCanvas* can =
p ? mCPull[6] : mCRes[6];
2701 for (int32_t
i = 0;
i < 5;
i++) {
2702 TPad* pad =
p ? mPPull[6][
i] : mPRes[6][
i];
2703 TH1D* hist =
p ? pullIntegral[
i] : resIntegral[
i];
2705 if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) {
2708 if (!mConfig.inputHistogramsOnly && mcAvail) {
2710 if (
e &&
e->GetEntries()) {
2711 e->Fit(
"gaus",
"sQ");
2716 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2718 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2721 e->SetMaximum(-1111);
2722 if (
e->GetMaximum() > tmpMax) {
2723 tmpMax =
e->GetMaximum();
2727 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2729 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2732 e->SetMaximum(tmpMax * 1.02);
2733 e->SetMinimum(tmpMax * -0.02);
2734 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
2737 if (qcout && !mConfig.shipToQCAsCanvas) {
2740 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2744 e->SetLineColor(colorNums[numColor++ % COLORCOUNT]);
2745 e->Draw(k == 0 ?
"" :
"same");
2747 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2755 if (!mConfig.enableLocalOutput) {
2759 can->Print(Form(p ?
"%s/pull_integral.pdf" :
"%s/res_integral.pdf", mConfig.plotsDir.c_str()));
2760 if (mConfig.writeFileExt !=
"") {
2761 can->Print(Form(p ?
"%s/pull_integral.%s" :
"%s/res_integral.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str()));
2766 uint64_t attachClusterCounts[N_CLS_HIST];
2767 if (mQATasks & taskClusterAttach) {
2769 if (mConfig.inputHistogramsOnly == 0) {
2770 for (int32_t
i = N_CLS_HIST;
i < N_CLS_TYPE * N_CLS_HIST - 1;
i++) {
2771 mClusters[
i]->Sumw2(
true);
2773 double totalVal = 0;
2774 if (!CLUST_HIST_INT_SUM) {
2775 for (int32_t
j = 0;
j < mClusters[N_CLS_HIST - 1]->GetXaxis()->GetNbins() + 2;
j++) {
2776 totalVal += mClusters[N_CLS_HIST - 1]->GetBinContent(
j);
2779 if (totalVal == 0.) {
2782 for (int32_t
i = 0;
i < N_CLS_HIST;
i++) {
2784 for (int32_t
j = 0;
j < mClusters[
i]->GetXaxis()->GetNbins() + 2;
j++) {
2785 val += mClusters[
i]->GetBinContent(
j);
2786 mClusters[2 * N_CLS_HIST - 1 +
i]->SetBinContent(
j,
val / totalVal);
2788 attachClusterCounts[
i] =
val;
2791 if (!CLUST_HIST_INT_SUM) {
2792 for (int32_t
i = 0;
i < N_CLS_HIST;
i++) {
2793 mClusters[2 * N_CLS_HIST - 1 +
i]->SetMaximum(1.02);
2794 mClusters[2 * N_CLS_HIST - 1 +
i]->SetMinimum(-0.02);
2798 for (int32_t
i = 0;
i < N_CLS_HIST - 1;
i++) {
2799 auto oldLevel = gErrorIgnoreLevel;
2800 gErrorIgnoreLevel = kError;
2801 mClusters[N_CLS_HIST +
i]->Divide(mClusters[
i], mClusters[N_CLS_HIST - 1], 1, 1,
"B");
2802 gErrorIgnoreLevel = oldLevel;
2803 mClusters[N_CLS_HIST +
i]->SetMinimum(-0.02);
2804 mClusters[N_CLS_HIST +
i]->SetMaximum(1.02);
2808 float tmpMax[2] = {0, 0}, tmpMin[2] = {0, 0};
2809 for (int32_t l = 0; l <= CLUST_HIST_INT_SUM; l++) {
2810 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2811 TH1*
e = mClusters[l ? (N_CLS_TYPE * N_CLS_HIST - 2) : (N_CLS_HIST - 1)];
2812 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2815 e->SetMinimum(-1111);
2816 e->SetMaximum(-1111);
2818 e->GetXaxis()->SetRange(2, AXIS_BINS[4]);
2820 if (
e->GetMaximum() > tmpMax[l]) {
2821 tmpMax[l] =
e->GetMaximum();
2823 if (
e->GetMinimum() < tmpMin[l]) {
2824 tmpMin[l] =
e->GetMinimum();
2827 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2828 for (int32_t
i = 0;
i < N_CLS_HIST;
i++) {
2829 TH1*
e = mClusters[l ? (2 * N_CLS_HIST - 1 +
i) :
i];
2830 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2833 e->SetMaximum(tmpMax[l] * 1.02);
2834 e->SetMinimum(tmpMax[l] * -0.02);
2839 for (int32_t
i = 0;
i < N_CLS_TYPE;
i++) {
2840 if (mConfig.enableLocalOutput || mConfig.shipToQCAsCanvas) {
2842 mPClust[
i]->SetLogx();
2844 int32_t begin =
i == 2 ? (2 * N_CLS_HIST - 1) : (
i == 1 ? N_CLS_HIST : 0);
2845 int32_t end =
i == 2 ? (3 * N_CLS_HIST - 1) : (
i == 1 ? (2 * N_CLS_HIST - 1) : N_CLS_HIST);
2847 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2849 TH1*
e = mClusters[
j];
2850 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2854 e->SetTitle(mConfig.plotsNoTitle ?
"" : CLUSTER_TITLES[
i]);
2855 e->GetYaxis()->SetTitle(
i == 0 ?
"Number of TPC clusters" : (
i == 1 ?
"Fraction of TPC clusters" : (CLUST_HIST_INT_SUM ?
"Total TPC clusters (integrated)" :
"Fraction of TPC clusters (integrated)")));
2856 e->GetXaxis()->SetTitle(
"#it{p}_{Tmc} (GeV/#it{c})");
2857 e->GetXaxis()->SetTitleOffset(1.1);
2858 e->GetXaxis()->SetLabelOffset(-0.005);
2859 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
2862 e->SetStats(kFALSE);
2864 e->SetLineStyle(CONFIG_DASHED_MARKERS ?
j + 1 : 1);
2866 e->GetXaxis()->SetRange(2, AXIS_BINS[4]);
2868 if (qcout && !mConfig.shipToQCAsCanvas) {
2871 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2875 e->SetMarkerColor(kBlack);
2876 e->SetLineColor(colorNums[numColor++ % COLORCOUNT]);
2877 e->Draw(
j ==
end - 1 && k == 0 ?
"" :
"same");
2879 mLClust[
i]->AddEntry(
e, Form(
"%s%s", fname, CLUSTER_NAMES[
j - begin]),
"l");
2882 if (ConfigNumInputs == 1) {
2883 TH1*
e =
reinterpret_cast<TH1F*
>(mClusters[
begin + CL_att_adj]->Clone());
2884 e->Add(mClusters[begin + CL_prot], -1);
2885 if (qcout && !mConfig.shipToQCAsCanvas) {
2888 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2892 e->SetLineColor(colorNums[numColor++ % COLORCOUNT]);
2894 mLClust[
i]->AddEntry(
e,
"Removed (Strategy A)",
"l");
2896 if (!mConfig.enableLocalOutput && !mConfig.shipToQCAsCanvas) {
2903 qcout->Add(mCClust[
i]);
2905 if (!mConfig.enableLocalOutput) {
2908 doPerfFigure(
i == 0 ? 0.37 : (
i == 1 ? 0.34 : 0.6), 0.295, 0.030);
2910 mCClust[
i]->Print(Form(
i == 2 ?
"%s/clusters_integral.pdf" : (
i == 1 ?
"%s/clusters_relative.pdf" :
"%s/clusters.pdf"), mConfig.plotsDir.c_str()));
2911 if (mConfig.writeFileExt !=
"") {
2912 mCClust[
i]->Print(Form(
i == 2 ?
"%s/clusters_integral.%s" : (
i == 1 ?
"%s/clusters_relative.%s" :
"%s/clusters.%s"), mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str()));
2916 for (int32_t
i = 0;
i < 4;
i++) {
2917 auto*
e = mPadRow[
i];
2918 if (tout && !mConfig.inputHistogramsOnly) {
2922 e->SetOption(
"colz");
2923 std::string title =
"First Track Pad Row (p_{T} > 1GeV, N_{Cl} #geq " +
std::to_string(PADROW_CHECK_MINCLS);
2925 title +=
", row_{trk} > row_{MC} + 3, row_{MC} < 10";
2928 title +=
", #Phi_{Cl} < 0.15";
2932 e->SetTitle(mConfig.plotsNoTitle ?
"" : title.c_str());
2933 e->GetXaxis()->SetTitle(
i == 3 ?
"Local Occupancy" : (
i ?
"#Phi_{Cl} (sector)" :
"First MC Pad Row"));
2934 e->GetYaxis()->SetTitle(
"First Pad Row");
2937 static const constexpr char* PADROW_NAMES[4] = {
"MC",
"Phi",
"Phi1",
"Occ"};
2938 mCPadRow[
i]->Print(Form(
"%s/padRow%s.pdf", mConfig.plotsDir.c_str(), PADROW_NAMES[
i]));
2939 if (mConfig.writeFileExt !=
"") {
2940 mCPadRow[
i]->Print(Form(
"%s/padRow%s.%s", mConfig.plotsDir.c_str(), PADROW_NAMES[
i], mConfig.writeFileExt.c_str()));
2945 if (mQATasks & taskClusterAttach) {
2946 for (TH1*
h : {
static_cast<TH1*
>(mLowestRowDifferenceVsPad),
static_cast<TH1*
>(mLowestRowTrackMultiplicity)}) {
2947 if (tout && !mConfig.inputHistogramsOnly) {
2957 if ((mQATasks & taskClusterCounts) && !mHaveExternalHists && !mConfig.clusterRejectionHistograms && !mConfig.inputHistogramsOnly) {
2958 DoClusterCounts(attachClusterCounts);
2960 if ((qcout || tout) && (mQATasks & taskClusterCounts) && mConfig.clusterRejectionHistograms) {
2961 for (
uint32_t i = 0;
i < mHistClusterCount.size();
i++) {
2963 mHistClusterCount[
i]->Write();
2966 qcout->Add(mHistClusterCount[
i]);
2971 if (mQATasks & taskTrackStatistics) {
2975 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2977 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2980 e->SetMaximum(-1111);
2981 if (
e->GetMaximum() > tmpMax) {
2982 tmpMax =
e->GetMaximum();
2986 mPTracks[0]->SetLogx();
2987 for (int32_t k = 0; k < ConfigNumInputs; k++) {
2989 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
2992 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
2995 e->SetMaximum(tmpMax * 1.02);
2996 e->SetMinimum(tmpMax * -0.02);
2997 e->SetStats(kFALSE);
2999 e->SetTitle(mConfig.plotsNoTitle ?
"" :
"Number of Tracks vs #it{p}_{T}");
3000 e->GetYaxis()->SetTitle(
"Number of Tracks");
3001 e->GetXaxis()->SetTitle(
"#it{p}_{T} (GeV/#it{c})");
3002 e->GetXaxis()->SetTitleOffset(1.2);
3006 e->SetMarkerColor(kBlack);
3007 e->SetLineColor(colorNums[k % COLORCOUNT]);
3008 e->Draw(k == 0 ?
"" :
"same");
3009 GetName(fname, k, mConfig.inputHistogramsOnly);
3010 mLTracks[0]->AddEntry(
e, Form(mConfig.inputHistogramsOnly ?
"%s" :
"%sTrack #it{p}_{T}", fname),
"l");
3012 mLTracks[0]->Draw();
3013 doPerfFigure(0.63, 0.7, 0.030);
3015 mCTracks[0]->Print(Form(
"%s/tracks%s.pdf", mConfig.plotsDir.c_str(),
"pt"));
3016 if (mConfig.writeFileExt !=
"") {
3017 mCTracks[0]->Print(Form(
"%s/tracks%s.%s", mConfig.plotsDir.c_str(),
"pt", mConfig.writeFileExt.c_str()));
3020 for (int32_t
i = 0;
i < 2;
i++) {
3021 mPTracks[1 +
i]->cd();
3023 TH2F*
e = mTrackdEdx[
i];
3024 if (tout && !mConfig.inputHistogramsOnly) {
3028 e->SetTitle(mConfig.plotsNoTitle ?
"" : (
i ?
"Track dE/dx (Max)" :
"Track dE/dx (Tot)"));
3029 e->GetYaxis()->SetTitle(
i ?
"dE/dx (max)" :
"dE/dx (tot)");
3030 e->GetXaxis()->SetTitle(
"log(#it{p})");
3031 e->GetXaxis()->SetTitleOffset(1.2);
3035 e->SetOption(
"colz");
3038 mCTracks[1 +
i]->cd();
3039 mCTracks[1 +
i]->Print(Form(
"%s/tracks%s.pdf", mConfig.plotsDir.c_str(),
i ?
"dedx_max" :
"dedx_tot"));
3040 if (mConfig.writeFileExt !=
"") {
3041 mCTracks[1 +
i]->Print(Form(
"%s/tracks%s.%s", mConfig.plotsDir.c_str(),
i ?
"dedx_max" :
"dedx_tot", mConfig.writeFileExt.c_str()));
3045 for (int32_t k = 0; k < ConfigNumInputs; k++) {
3047 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
3050 e->SetMaximum(-1111);
3051 if (
e->GetMaximum() > tmpMax) {
3052 tmpMax =
e->GetMaximum();
3056 for (int32_t k = 0; k < ConfigNumInputs; k++) {
3058 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
3061 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
3064 e->SetMaximum(tmpMax * 1.02);
3065 e->SetMinimum(tmpMax * -0.02);
3066 e->SetStats(kFALSE);
3068 e->SetTitle(mConfig.plotsNoTitle ?
"" : (
i ?
"Track t_{0} resolution" :
"Track t_{0} distribution"));
3069 e->GetYaxis()->SetTitle(
"a.u.");
3070 e->GetXaxis()->SetTitle(
i ?
"t_{0} - t_{0, mc}" :
"t_{0}");
3074 e->SetMarkerColor(kBlack);
3075 e->SetLineColor(colorNums[k % COLORCOUNT]);
3076 e->Draw(k == 0 ?
"" :
"same");
3077 GetName(fname, k, mConfig.inputHistogramsOnly);
3078 mLT0[
i]->AddEntry(
e, Form(mConfig.inputHistogramsOnly ?
"%s (%s)" :
"%sTrack t_{0} %s", fname,
i ?
"" :
"resolution"),
"l");
3081 doPerfFigure(0.63, 0.7, 0.030);
3083 mCT0[
i]->Print(Form(
"%s/t0%s.pdf", mConfig.plotsDir.c_str(),
i ?
"_res" :
""));
3084 if (mConfig.writeFileExt !=
"") {
3085 mCT0[
i]->Print(Form(
"%s/t0%s.%s", mConfig.plotsDir.c_str(),
i ?
"_res" :
"", mConfig.writeFileExt.c_str()));
3089 for (int32_t k = 0; k < ConfigNumInputs; k++) {
3091 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
3094 e->SetMaximum(-1111);
3095 if (
e->GetMaximum() > tmpMax) {
3096 tmpMax =
e->GetMaximum();
3100 for (int32_t k = 0; k < ConfigNumInputs; k++) {
3102 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
3105 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
3108 e->SetMaximum(tmpMax * 1.02);
3109 e->SetMinimum(tmpMax * -0.02);
3110 e->SetStats(kFALSE);
3112 e->SetTitle(mConfig.plotsNoTitle ?
"" : (
i ?
"Number of Rows with attached Cluster" :
"Number of Clusters"));
3113 e->GetYaxis()->SetTitle(
"a.u.");
3114 e->GetXaxis()->SetTitle(
i ?
"N_{Rows with Clusters}" :
"N_{Clusters}");
3118 e->SetMarkerColor(kBlack);
3119 e->SetLineColor(colorNums[k % COLORCOUNT]);
3120 e->Draw(k == 0 ?
"" :
"same");
3121 GetName(fname, k, mConfig.inputHistogramsOnly);
3122 mLNCl[
i]->AddEntry(
e, Form(mConfig.inputHistogramsOnly ?
"%s" : (
i ?
"%sN_{Clusters}" :
"%sN_{Rows with Clusters}"), fname),
"l");
3125 doPerfFigure(0.6, 0.7, 0.030);
3127 mCNCl[
i]->Print(Form(
"%s/nClusters%s.pdf", mConfig.plotsDir.c_str(),
i ?
"_corrected" :
""));
3128 if (mConfig.writeFileExt !=
"") {
3129 mCNCl[
i]->Print(Form(
"%s/nClusters%s.%s", mConfig.plotsDir.c_str(),
i ?
"_corrected" :
"", mConfig.writeFileExt.c_str()));
3134 mClXY->SetOption(
"colz");
3137 mCClXY->Print(Form(
"%s/clustersXY.pdf", mConfig.plotsDir.c_str()));
3138 if (mConfig.writeFileExt !=
"") {
3139 mCClXY->Print(Form(
"%s/clustersXY.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str()));
3143 if (mQATasks & taskClusterRejection) {
3144 mClRej[2]->Divide(mClRej[1], mClRej[0]);
3146 for (int32_t
i = 0;
i < 3;
i++) {
3147 if (tout && !mConfig.inputHistogramsOnly) {
3151 mClRej[
i]->SetTitle(mConfig.plotsNoTitle ?
"" : REJECTED_NAMES[
i]);
3152 mClRej[
i]->SetOption(
"colz");
3155 mCClRej[
i]->Print(Form(
"%s/clustersRej%d%s.pdf", mConfig.plotsDir.c_str(),
i, REJECTED_NAMES[
i]));
3156 if (mConfig.writeFileExt !=
"") {
3157 mCClRej[
i]->Print(Form(
"%s/clustersRej%d%s.%s", mConfig.plotsDir.c_str(),
i, REJECTED_NAMES[
i], mConfig.writeFileExt.c_str()));
3162 for (int32_t k = 0; k < ConfigNumInputs; k++) {
3163 auto* tmp = mClRej[0];
3164 if (GetHist(tmp, tin, k, nNewInput) ==
nullptr) {
3167 TH1D* proj1 = tmp->ProjectionY(Form(
"clrejptmp1%d", k));
3168 proj1->SetDirectory(
nullptr);
3170 if (GetHist(tmp, tin, k, nNewInput) ==
nullptr) {
3173 TH1D* proj2 = tmp->ProjectionY(Form(
"clrejptmp2%d", k));
3174 proj2->SetDirectory(
nullptr);
3177 if (GetHist(
e, tin, k, nNewInput) ==
nullptr) {
3180 e->Divide(proj2, proj1);
3181 if (tout && !mConfig.inputHistogramsOnly && k == 0) {
3186 e->SetMinimum(-0.02);
3187 e->SetMaximum(0.22);
3188 e->SetTitle(mConfig.plotsNoTitle ?
"" :
"Rejected Clusters");
3189 e->GetXaxis()->SetTitle(
"Pad Row");
3190 e->GetYaxis()->SetTitle(
"Rejected Clusters (fraction)");
3191 e->Draw(k == 0 ?
"" :
"same");
3193 mPClRejP->Print(Form(
"%s/clustersRejProjected.pdf", mConfig.plotsDir.c_str()));
3194 if (mConfig.writeFileExt !=
"") {
3195 mPClRejP->Print(Form(
"%s/clustersRejProjected.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str()));
3199 if (tout && !mConfig.inputHistogramsOnly && mConfig.writeMCLabels) {
3200 gInterpreter->GenerateDictionary(
"vector<vector<int32_t>>",
"");
3201 tout->WriteObject(&mcEffBuffer,
"mcEffBuffer");
3202 tout->WriteObject(&mcLabelBuffer,
"mcLabelBuffer");
3203 remove(
"AutoDict_vector_vector_int__.cxx");
3204 remove(
"AutoDict_vector_vector_int___cxx_ACLiC_dict_rdict.pcm");
3205 remove(
"AutoDict_vector_vector_int___cxx.d");
3206 remove(
"AutoDict_vector_vector_int___cxx.so");
3212 for (
uint32_t i = 0;
i < mConfig.compareInputs.size();
i++) {
3216 clearGarbagageCollector();
3218 GPUInfo(
"GPU TPC QA histograms have been written to pdf%s%s files", mConfig.writeFileExt ==
"" ?
"" :
" and ", mConfig.writeFileExt.c_str());
3219 gErrorIgnoreLevel = oldRootIgnoreLevel;
3223void GPUQA::PrintClusterCount(int32_t
mode, int32_t&
num,
const char*
name, uint64_t
n, uint64_t normalization)
3227 }
else if (
mode == 1) {
3229 snprintf(name2, 128,
"clusterCount%d_",
num);
3230 char*
ptr = name2 + strlen(name2);
3237 createHist(mHistClusterCount[
num], name2,
name, 1000, 0, mConfig.histMaxNClusters, 1000, 0, 100);
3238 }
else if (
mode == 0) {
3239 if (normalization && mConfig.enableLocalOutput) {
3240 for (
uint32_t i = 0;
i < 1 + (mTextDump !=
nullptr);
i++) {
3241 fprintf(
i ? mTextDump : stdout,
"\t%40s: %'12" PRIu64
" (%6.2f%%)\n",
name,
n, 100.f *
n / normalization);
3244 if (mConfig.clusterRejectionHistograms) {
3245 float ratio = 100.f *
n / std::max<uint64_t>(normalization, 1);
3246 mHistClusterCount[
num]->Fill(normalization, ratio, 1);
3252int32_t GPUQA::DoClusterCounts(uint64_t* attachClusterCounts, int32_t
mode)
3254 if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && mConfig.plotsDir !=
"") {
3255 mTextDump = fopen((mConfig.plotsDir +
"/clusterCounts.txt").c_str(),
"w+");
3258 if (mcPresent() && (mQATasks & taskClusterAttach) && attachClusterCounts) {
3259 for (int32_t
i = 0;
i < N_CLS_HIST;
i++) {
3260 PrintClusterCount(
mode,
num, CLUSTER_NAMES[
i], attachClusterCounts[
i], mClusterCounts.nTotal);
3262 PrintClusterCount(
mode,
num,
"Unattached", attachClusterCounts[N_CLS_HIST - 1] - attachClusterCounts[CL_att_adj], mClusterCounts.nTotal);
3263 PrintClusterCount(
mode,
num,
"Removed (Strategy A)", attachClusterCounts[CL_att_adj] - attachClusterCounts[CL_prot], mClusterCounts.nTotal);
3264 PrintClusterCount(
mode,
num,
"Unaccessible", mClusterCounts.nUnaccessible, mClusterCounts.nTotal);
3266 PrintClusterCount(
mode,
num,
"All Clusters", mClusterCounts.nTotal, mClusterCounts.nTotal);
3267 PrintClusterCount(
mode,
num,
"Used in Physics", mClusterCounts.nPhysics, mClusterCounts.nTotal);
3268 PrintClusterCount(
mode,
num,
"Protected", mClusterCounts.nProt, mClusterCounts.nTotal);
3269 PrintClusterCount(
mode,
num,
"Unattached", mClusterCounts.nUnattached, mClusterCounts.nTotal);
3270 PrintClusterCount(
mode,
num,
"Removed (Strategy A)", mClusterCounts.nTotal - mClusterCounts.nUnattached - mClusterCounts.nProt, mClusterCounts.nTotal);
3271 PrintClusterCount(
mode,
num,
"Removed (Strategy B)", mClusterCounts.nTotal - mClusterCounts.nProt, mClusterCounts.nTotal);
3274 PrintClusterCount(
mode,
num,
"Merged Loopers (Track Merging)", mClusterCounts.nMergedLooperConnected, mClusterCounts.nTotal);
3275 PrintClusterCount(
mode,
num,
"Merged Loopers (Afterburner)", mClusterCounts.nMergedLooperUnconnected, mClusterCounts.nTotal);
3276 PrintClusterCount(
mode,
num,
"Looping Legs (other)", mClusterCounts.nLoopers, mClusterCounts.nTotal);
3277 PrintClusterCount(
mode,
num,
"High Inclination Angle", mClusterCounts.nHighIncl, mClusterCounts.nTotal);
3278 PrintClusterCount(
mode,
num,
"Rejected", mClusterCounts.nRejected, mClusterCounts.nTotal);
3279 PrintClusterCount(
mode,
num,
"Tube (> 200 MeV)", mClusterCounts.nTube, mClusterCounts.nTotal);
3280 PrintClusterCount(
mode,
num,
"Tube (< 200 MeV)", mClusterCounts.nTube200, mClusterCounts.nTotal);
3281 PrintClusterCount(
mode,
num,
"Low Pt < 50 MeV", mClusterCounts.nLowPt, mClusterCounts.nTotal);
3282 PrintClusterCount(
mode,
num,
"Low Pt < 200 MeV", mClusterCounts.n200MeV, mClusterCounts.nTotal);
3284 if (mcPresent() && (mQATasks & taskClusterAttach)) {
3285 PrintClusterCount(
mode,
num,
"Tracks > 400 MeV", mClusterCounts.nAbove400, mClusterCounts.nTotal);
3286 PrintClusterCount(
mode,
num,
"Fake Removed (> 400 MeV)", mClusterCounts.nFakeRemove400, mClusterCounts.nAbove400);
3287 PrintClusterCount(
mode,
num,
"Full Fake Removed (> 400 MeV)", mClusterCounts.nFullFakeRemove400, mClusterCounts.nAbove400);
3288 PrintClusterCount(
mode,
num,
"Tracks < 40 MeV", mClusterCounts.nBelow40, mClusterCounts.nTotal);
3289 PrintClusterCount(
mode,
num,
"Fake Protect (< 40 MeV)", mClusterCounts.nFakeProtect40, mClusterCounts.nBelow40);
3291 if (mcPresent() && (mQATasks & taskTrackStatistics)) {
3292 PrintClusterCount(
mode,
num,
"Correctly Attached all-trk normalized", mClusterCounts.nCorrectlyAttachedNormalized, mClusterCounts.nTotal);
3293 PrintClusterCount(
mode,
num,
"Correctly Attached non-fake normalized", mClusterCounts.nCorrectlyAttachedNormalizedNonFake, mClusterCounts.nTotal);
3297 mTextDump =
nullptr;
3304 mTrackingScratchBuffer.resize((nBytes +
sizeof(mTrackingScratchBuffer[0]) - 1) /
sizeof(mTrackingScratchBuffer[0]));
3305 return mTrackingScratchBuffer.data();
A const (ready only) version of MCTruthContainer.
#define TRACK_EXPECTED_REFERENCE_X_DEFAULT
#define TRACK_EXPECTED_REFERENCE_X
configStandalone Light OpenGL display display_light Apply smoothing to points Enable Z buffer Highlight links Highlight seeds Highlight sector tracks Highlight final tracks Show individual Show related Highlight grid Show only individual collision Color clusters belonging to track objects Set line Enable drawing TPC data Enable drawing TOF data Enable drawing magnetic field Set field line step count Invert colors configStandalone Heavy OpenGL display display_heavy Show tracks with ITS contribution Show tracks with TOF contribution Enable propagation of loopers Show clusters at nominal x of pad row for early transformed data Split CE tracks when they cross the central Mark clusters Mark adjacent clusters Hide rejected tracks Apply filter on tracks to be displayed Separate increase X h configStandalone Camera window renderer OpenGL display display_camera Orient the camera such that the y axis is always upwards Full Screen MultiSample Anti Downsampling Anti Enable Vertical Sync Target frame or if the backend cannot limit to the refresh Use OpenGL indirect draws to reduce number of draw calls Display h configStandalone Vulkan display display_vulkan Have uniform buffers in host accessible device memory h internal
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char Directory with events to Events directory is and not inside events Show standalone event Run event generator maximum time bin of continuous for triggered for automatic continuous for automatic continuous triggered uint64_t
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error First event to Number of events to Number of iterations to Number of iterations to Number of initial iterations excluded from const char e
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
configStandalone Reconstruction rec_tpc float
std::vector< o2::MCCompLabel > labels
std::vector< o2::its::TrackITS > tracks
Definition of the MCTrack class.
Definition of the Names Generator class.
Class for time synchronization of RawReader instances.
static const HBFUtils & Instance()
static constexpr int32_t NSECTORS
int32_t ReadO2MCData(const char *filename)
bool clusterRemovable(int32_t attach, bool prot) const
void * AllocateScratchBuffer(size_t nBytes)
void SetMCTrackRange(int32_t min, int32_t max)
mcLabelI_t GetMCTrackLabel(uint32_t trackId) const
int32_t DrawQAHistograms()
int32_t InitQA(int32_t tasks=0)
void DumpO2MCData(const char *filename) const
void RunQA(bool matchOnly=false)
static DigitizationContext * loadFromFile(std::string_view filename="")
GLfloat GLfloat GLfloat alpha
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint const GLchar * name
GLuint GLuint GLfloat weight
GLuint GLsizei const GLchar * label
GLdouble GLdouble GLdouble z
@ tasksDefaultPostprocess
o2::track::TrackParCov int int int float int nCl
const bool const int TrackITSInternal< NLayers > & track
Enum< T >::Iterator begin(Enum< T >)
std::string to_string(gsl::span< T, Size > span)
bool isValid(std::string alias)
int64_t differenceInBC(const InteractionRecord &other) const
bool mergedLooperConnected
bool mergedLooperUnconnected
std::tuple< std::vector< std::unique_ptr< TCanvas > >, std::vector< std::unique_ptr< TLegend > >, std::vector< std::unique_ptr< TPad > >, std::vector< std::unique_ptr< TLatex > >, std::vector< std::unique_ptr< TH1D > > > v
IR getFirstIRofTF(const IR &rec) const
get 1st IR of TF corresponding to the 1st sampled orbit (in MC)
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClustersTotal
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
o2::InteractionRecord ir(0, 0)
o2::InteractionRecord ir0(3, 5)