diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h index 0be54aaf59818..8f2195dc9eecc 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CATrackerSpec.h @@ -41,6 +41,7 @@ enum struct Operation { OutputCAClusters, // publish the clusters produced by CA clusterer OutputCompClusters, // publish CompClusters container OutputCompClustersFlat, // publish CompClusters container + OutputQA, // Ship QA histograms to QC ProcessMC, // process MC labels SendClustersPerSector, // Send clusters and clusters mc labels per sector Noop, // skip argument on the constructor @@ -88,6 +89,9 @@ struct Config { case Operation::OutputCAClusters: outputCAClusters = true; break; + case Operation::OutputQA: + outputQA = true; + break; case Operation::ProcessMC: processMC = true; break; @@ -116,6 +120,7 @@ struct Config { bool outputCompClusters = false; bool outputCompClustersFlat = false; bool outputCAClusters = false; + bool outputQA = false; bool processMC = false; bool sendClustersPerSector = false; }; diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h index 100a35e82c0bc..d4140736b0985 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h @@ -60,6 +60,7 @@ enum struct OutputType { Digits, DisableWriter, SendClustersPerSector, ZSRaw, + QA, }; using CompletionPolicyData = std::vector; diff --git a/Detectors/TPC/workflow/src/CATrackerSpec.cxx b/Detectors/TPC/workflow/src/CATrackerSpec.cxx index bd7597b7a1a1b..bd5be552fabff 100644 --- a/Detectors/TPC/workflow/src/CATrackerSpec.cxx +++ b/Detectors/TPC/workflow/src/CATrackerSpec.cxx @@ -42,6 +42,7 @@ #include "DetectorsRaw/HBFUtils.h" #include "TPCBase/RDHUtils.h" #include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceQA.h" #include "TPCCFCalibration.h" #include "GPUDisplayBackend.h" #ifdef GPUCA_BUILD_EVENT_DISPLAY @@ -65,6 +66,10 @@ #include "GPUReconstructionConvert.h" #include "DetectorsRaw/RDHUtils.h" #include +#include +#include +#include +#include using namespace o2::framework; using namespace o2::header; @@ -96,6 +101,8 @@ DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config std::unique_ptr fastTransform; std::unique_ptr dEdxSplines; std::unique_ptr tpcCalibration; + std::unique_ptr qaConfig; + std::unique_ptr qa; std::vector clusterOutputIds; unsigned long outputBufferSize = 0; unsigned long tpcSectorMask = 0; @@ -154,6 +161,12 @@ DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config LOG(INFO) << "GPU device number selected from pipeline id: " << myId << " / " << idMax; } config.configProcessing.runMC = specconfig.processMC; + if (specconfig.outputQA) { + if (!config.configProcessing.runQA) { + config.configQA.forQC = true; + } + config.configProcessing.runQA = true; + } config.configReconstruction.NWaysOuter = true; config.configInterface.outputToExternalBuffers = true; @@ -232,6 +245,10 @@ DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config if (tracker->initialize(config) != 0) { throw std::invalid_argument("GPUCATracking initialization failed"); } + if (specconfig.outputQA) { + processAttributes->qaConfig.reset(new GPUSettingsQA(config.configQA)); + processAttributes->qa = std::make_unique(processAttributes->qaConfig.get()); + } timer.Stop(); timer.Reset(); } @@ -689,6 +706,14 @@ DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config } } } + if (specconfig.outputQA) { + TObjArray out; + std::vector copy1 = *outputRegions.qa.hist1; // Internally, this will also be used as output, so we need a non-const copy + std::vector copy2 = *outputRegions.qa.hist2; + std::vector copy3 = *outputRegions.qa.hist3; + processAttributes->qa->postprocess(copy1, copy2, copy3, out); + pc.outputs().snapshot({gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe}, out); + } timer.Stop(); LOG(INFO) << "TPC CATracker time for this TF " << timer.CpuTime() - cput << " s"; }; @@ -789,6 +814,9 @@ DataProcessorSpec getCATrackerSpec(CompletionPolicyData* policyData, ca::Config } } } + if (specconfig.outputQA) { + outputSpecs.emplace_back(gDataOriginTPC, "TRACKINGQA", 0, Lifetime::Timeframe); + } return std::move(outputSpecs); }; diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index 8c850f3b8c03e..43116540ffed7 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -85,7 +85,7 @@ const std::unordered_map OutputMap{ {"disable-writer", OutputType::DisableWriter}, {"send-clusters-per-sector", OutputType::SendClustersPerSector}, {"zsraw", OutputType::ZSRaw}, -}; + {"qa", OutputType::QA}}; framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector const& tpcSectors, std::vector const& laneConfiguration, bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, @@ -442,6 +442,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto produceCompClusters ? ca::Operation::OutputCompClusters : ca::Operation::Noop, runClusterEncoder ? ca::Operation::OutputCompClustersFlat : ca::Operation::Noop, isEnabled(OutputType::SendClustersPerSector) ? ca::Operation::SendClustersPerSector : ca::Operation::Noop, + isEnabled(OutputType::QA) ? ca::Operation::OutputQA : ca::Operation::Noop, isEnabled(OutputType::Clusters) && (caClusterer || decompressTPC) ? ca::Operation::OutputCAClusters : ca::Operation::Noop, }, tpcSectors)); diff --git a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx index 4f084afa6f527..b10b2c08f5293 100644 --- a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx @@ -46,7 +46,7 @@ void customize(std::vector& workflowOptions) std::vector options{ {"input-type", VariantType::String, "digits", {"digitizer, digits, zsraw, clustershw, clustersnative, compressed-clusters, compressed-clusters-ctf"}}, - {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clustersnative, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector"}}, + {"output-type", VariantType::String, "tracks", {"digits, zsraw, clustershw, clustersnative, tracks, compressed-clusters, encoded-clusters, disable-writer, send-clusters-per-sector, qa"}}, {"no-ca-clusterer", VariantType::Bool, false, {"Use HardwareClusterer instead of clusterer of GPUCATracking"}}, {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}, //{"tpc-sectors", VariantType::String, "0-35", {"TPC sector range, e.g. 5-7,8,9"}}, diff --git a/GPU/GPUTracking/Base/GPUSettingsList.h b/GPU/GPUTracking/Base/GPUSettingsList.h index 572cfc27636b8..c116d67c5ceb1 100644 --- a/GPU/GPUTracking/Base/GPUSettingsList.h +++ b/GPU/GPUTracking/Base/GPUSettingsList.h @@ -117,7 +117,6 @@ AddOption(prefetchTPCpageScan, int, 0, "", 0, "Prefetch Data for TPC page scan i AddOption(debugLevel, int, -1, "debug", 'd', "Set debug level (-1 = silend)") AddOption(allocDebugLevel, int, 0, "allocDebug", 0, "Some debug output for memory allocations (without messing with normal debug level)") AddOption(runQA, bool, false, "qa", 'q', "Enable tracking QA", message("Running QA: %s")) -AddOption(QAnoMC, bool, false, "", 0, "Force running QA without MC labels even if present") AddOption(runCompressionStatistics, bool, false, "compressionStat", 0, "Run statistics and verification for cluster compression") AddOption(forceMemoryPoolSize, unsigned long, 1, "memSize", 0, "Force size of allocated GPU / page locked host memory", min(0ul)) AddOption(forceHostMemoryPoolSize, unsigned long, 0, "hostMemSize", 0, "Force size of allocated host page locked host memory (overriding memSize)", min(0ul)) @@ -160,6 +159,8 @@ AddOption(writeMCLabels, bool, false, "", 0, "Store mc labels to file for later AddOptionVec(matchMCLabels, const char*, "", 0, "Read labels from files and match them, only process tracks where labels differ") AddOption(matchDisplayMinPt, float, 0, "", 0, "Minimum Pt of a matched track to be displayed") AddOption(writeRootFiles, bool, false, "", 0, "Create ROOT canvas files") +AddOption(noMC, bool, false, "", 0, "Force running QA without MC labels even if present") +AddOption(forQC, bool, false, "", 0, "Do not write output files but ship histograms for QC") AddShortcut("compare", 0, "--QAinput", "Compare QA histograms", "--qa", "--QAinputHistogramsOnly") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 7daaa1eceef1b..dec5d3d5686b0 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -135,8 +135,8 @@ set(HDRS_INSTALL # Sources only for O2 if(ALIGPU_BUILD_TYPE STREQUAL "O2") - set(SRCS ${SRCS} Interface/GPUO2Interface.cxx Interface/GPUO2InterfaceRefit.cxx Interface/GPUO2InterfaceConfigurableParam.cxx) - set(HDRS_CINT_O2 ${HDRS_CINT_O2} Interface/GPUO2Interface.h Interface/GPUO2InterfaceRefit.h Interface/GPUO2InterfaceConfigurableParam.h dEdx/TPCdEdxCalibrationSplines.h) + set(SRCS ${SRCS} Interface/GPUO2Interface.cxx Interface/GPUO2InterfaceRefit.cxx Interface/GPUO2InterfaceQA.cxx Interface/GPUO2InterfaceConfigurableParam.cxx) + set(HDRS_CINT_O2 ${HDRS_CINT_O2} Interface/GPUO2Interface.h Interface/GPUO2InterfaceRefit.h Interface/GPUO2InterfaceQA.h Interface/GPUO2InterfaceConfigurableParam.h dEdx/TPCdEdxCalibrationSplines.h) set(HDRS_CINT_O2_ADDITIONAL Base/GPUSettings.h Base/GPUSettingsList.h) # Manual depencies for ROOT dictionary generation endif() diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h index 93c1c854de59e..fe035e5a71a45 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h @@ -19,6 +19,7 @@ #pragma link C++ class o2::gpu::GPUTPCO2Interface + ; #pragma link C++ class o2::gpu::GPUTPCO2InterfaceRefit + ; +#pragma link C++ class o2::gpu::GPUO2InterfaceQA + ; #pragma link C++ class o2::gpu::TPCdEdxCalibrationSplines + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsO2 + ; #pragma link C++ class o2::gpu::GPUConfigurableParamGPUSettingsRec + ; diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 4c65f08a9aaa7..b356e5ba0f32c 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -18,6 +18,7 @@ #include "GPUOutputControl.h" #include "GPUO2InterfaceConfiguration.h" #include "GPUParam.inc" +#include "GPUQA.h" #include #include #ifdef WITH_OPENMP @@ -159,6 +160,11 @@ int GPUTPCO2Interface::RunTracking(GPUTrackingInOutPointers* data, GPUInterfaceO outputs->clustersNative.size = mOutputClustersNative->EndOfSpace ? 0 : (mChain->mIOPtrs.clustersNative->nClustersTotal * sizeof(*mChain->mIOPtrs.clustersNative->clustersLinear)); outputs->tpcTracks.size = mOutputCompressedClusters->EndOfSpace ? 0 : (size_t)((char*)mOutputCompressedClusters->OutputPtr - (char*)mOutputCompressedClusters->OutputBase); } + if (mConfig->configQA.forQC) { + outputs->qa.hist1 = &mChain->GetQA()->getHistograms1D(); + outputs->qa.hist2 = &mChain->GetQA()->getHistograms2D(); + outputs->qa.hist3 = &mChain->GetQA()->getHistograms1Dd(); + } *data = mChain->mIOPtrs; nEvent++; diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h index eac5c9d7363ec..b3ca1cabe5ab0 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h @@ -34,6 +34,10 @@ #include "GPUHostDataTypes.h" #include "DataFormatsTPC/Constants.h" +class TH1F; +class TH1D; +class TH2F; + namespace o2 { namespace tpc @@ -57,11 +61,18 @@ struct GPUInterfaceOutputRegion { std::function allocator = nullptr; }; +struct GPUInterfaceQAOutputs { + const std::vector* hist1; + const std::vector* hist2; + const std::vector* hist3; +}; + struct GPUInterfaceOutputs { GPUInterfaceOutputRegion compressedClusters; GPUInterfaceOutputRegion clustersNative; GPUInterfaceOutputRegion tpcTracks; GPUInterfaceOutputRegion clusterLabels; + GPUInterfaceQAOutputs qa; }; // Full configuration structure with all available settings of GPU... diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx new file mode 100644 index 0000000000000..a30db8bef77a8 --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.cxx @@ -0,0 +1,32 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceQA.cxx +/// \author David Rohr + +#include "GPUQA.h" +#include "GPUO2InterfaceQA.h" + +using namespace o2::gpu; +using namespace o2::tpc; + +GPUO2InterfaceQA::GPUO2InterfaceQA(const GPUSettingsQA* config) : mQA(new GPUQA(nullptr, config)) +{ +} + +GPUO2InterfaceQA::~GPUO2InterfaceQA() = default; + +int GPUO2InterfaceQA::postprocess(std::vector& in1, std::vector& in2, std::vector& in3, TObjArray& out) +{ + if (mQA->loadHistograms(in1, in2, in3)) { + return 1; + } + return mQA->DrawQAHistograms(&out); +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h new file mode 100644 index 0000000000000..83f0d00e3f018 --- /dev/null +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceQA.h @@ -0,0 +1,54 @@ +// Copyright CERN and copyright holders of ALICE O2. This software is +// distributed under the terms of the GNU General Public License v3 (GPL +// Version 3), copied verbatim in the file "COPYING". +// +// See http://alice-o2.web.cern.ch/license for full licensing information. +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUO2InterfaceQA.h +/// \author David Rohr + +#ifndef GPUO2INTERFACEQA_H +#define GPUO2INTERFACEQA_H + +// Some defines denoting that we are compiling for O2 +#ifndef HAVE_O2HEADERS +#define HAVE_O2HEADERS +#endif +#ifndef GPUCA_TPC_GEOMETRY_O2 +#define GPUCA_TPC_GEOMETRY_O2 +#endif +#ifndef GPUCA_O2_INTERFACE +#define GPUCA_O2_INTERFACE +#endif + +#include +#include + +class TH1F; +class TH1D; +class TH2F; +class TObjArray; + +namespace o2::gpu +{ +class GPUQA; +class GPUSettingsQA; +class GPUO2InterfaceQA +{ + public: + GPUO2InterfaceQA(const GPUSettingsQA* config = nullptr); + ~GPUO2InterfaceQA(); + + // Input might be modified, so we assume non-const. If it is const, a copy should be created before. + int postprocess(std::vector& in1, std::vector& in2, std::vector& in3, TObjArray& out); + + private: + std::unique_ptr mQA; +}; +} // namespace o2::gpu + +#endif diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx index 1a5c77b0a5ecb..7aa72568bac25 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx +++ b/GPU/GPUTracking/Standalone/display/GPUDisplay.cxx @@ -84,12 +84,12 @@ namespace GPUCA_NAMESPACE::gpu extern GPUSettingsStandalone configStandalone; } #endif -static const GPUSettingsDisplay& GPUDisplay_GetConfig(GPUChainTracking* rec) +static const GPUSettingsDisplay& GPUDisplay_GetConfig(GPUChainTracking* chain) { #if !defined(GPUCA_STANDALONE) static GPUSettingsDisplay defaultConfig; - if (rec->mConfigDisplay) { - return *((const GPUSettingsDisplay*)rec->mConfigDisplay); + if (chain->mConfigDisplay) { + return *((const GPUSettingsDisplay*)chain->mConfigDisplay); } else { return defaultConfig; } @@ -99,7 +99,7 @@ static const GPUSettingsDisplay& GPUDisplay_GetConfig(GPUChainTracking* rec) #endif } -GPUDisplay::GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* rec, GPUQA* qa) : mBackend(backend), mChain(rec), mConfig(GPUDisplay_GetConfig(rec)), mQA(qa), mMerger(rec->GetTPCMerger()) { backend->mDisplay = this; } +GPUDisplay::GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa) : mBackend(backend), mChain(chain), mConfig(GPUDisplay_GetConfig(chain)), mQA(qa), mMerger(chain->GetTPCMerger()) { backend->mDisplay = this; } const GPUParam& GPUDisplay::param() { return mChain->GetParam(); } const GPUTPCTracker& GPUDisplay::sliceTracker(int iSlice) { return mChain->GetTPCSliceTrackers()[iSlice]; } diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplay.h b/GPU/GPUTracking/Standalone/display/GPUDisplay.h index 8f0efea771780..565b3af52c2e8 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplay.h +++ b/GPU/GPUTracking/Standalone/display/GPUDisplay.h @@ -53,7 +53,7 @@ namespace gpu class GPUDisplay { public: - GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* rec, GPUQA* qa) {} + GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa) {} ~GPUDisplay() = default; GPUDisplay(const GPUDisplay&) = delete; @@ -94,7 +94,7 @@ struct GPUParam; class GPUDisplay { public: - GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* rec, GPUQA* qa); + GPUDisplay(GPUDisplayBackend* backend, GPUChainTracking* chain, GPUQA* qa); ~GPUDisplay() = default; GPUDisplay(const GPUDisplay&) = delete; diff --git a/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx b/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx index e7c85ef06826e..6d453b0af8e69 100644 --- a/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx +++ b/GPU/GPUTracking/Standalone/display/GPUDisplayKeys.cxx @@ -35,7 +35,6 @@ const char* HelpText[] = { "[L] / [K] Draw single collisions (next / previous)", "[C] Colorcode clusters of different collisions", "[v] Hide rejected clusters from tracks", - "[b] Hide all clusters not belonging or related to matched tracks in QA", "[j] Show global tracks as additional segments of final tracks", "[u] Cycle through track filter", "[E] / [G] Extrapolate tracks / loopers", @@ -59,7 +58,8 @@ const char* HelpText[] = { "[ALT] / [CTRL] / [m] Focus camera on origin / orient y-axis upwards (combine with [SHIFT] to lock) / Cycle through modes", "[1] ... [8] / [N] Enable display of clusters, preseeds, seeds, starthits, tracklets, tracks, global tracks, merged tracks / Show assigned clusters in colors" "[F1] / [F2] Enable / disable drawing of TPC / TRD" - // FREE: u + // FREE: b + // Test setting: # --> mHideUnmatchedClusters }; void GPUDisplay::PrintHelp() @@ -218,10 +218,6 @@ void GPUDisplay::HandleKeyRelease(unsigned char key) mHideRejectedClusters ^= 1; SetInfo("Rejected clusters are %s", mHideRejectedClusters ? "hidden" : "shown"); mUpdateDLList = true; - } else if (key == 'b') { - mHideUnmatchedClusters ^= 1; - SetInfo("Unmatched clusters are %s", mHideUnmatchedClusters ? "hidden" : "shown"); - mUpdateDLList = true; } else if (key == 'i') { mProjectXY ^= 1; SetInfo("Projection onto xy plane %s", mProjectXY ? "enabled" : "disabled"); @@ -429,12 +425,15 @@ void GPUDisplay::HandleKeyRelease(unsigned char key) PrintHelp(); SetInfo("Showing help text", 1); } - /*else if (key == '#') - { - mTestSetting++; - SetInfo("Debug test variable set to %d", mTestSetting); - mUpdateDLList = true; - }*/ + /* + else if (key == '#') + { + mTestSetting++; + SetInfo("Debug test variable set to %d", mTestSetting); + // mHideUnmatchedClusters ^= 1; + mUpdateDLList = true; + } + */ } void GPUDisplay::HandleSendKey(int key) diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx index 0aa569f33cb3c..50d3db0f8569c 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx +++ b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx @@ -26,6 +26,7 @@ #include "TTree.h" #include "TStyle.h" #include "TLatex.h" +#include "TObjArray.h" #include #include "GPUQA.h" @@ -119,12 +120,12 @@ namespace GPUCA_NAMESPACE::gpu extern GPUSettingsStandalone configStandalone; } #endif -static const GPUSettingsQA& GPUQA_GetConfig(GPUChainTracking* rec) +static const GPUSettingsQA& GPUQA_GetConfig(GPUChainTracking* chain) { #if !defined(GPUCA_STANDALONE) static GPUSettingsQA defaultConfig; - if (rec->mConfigQA) { - return *((const GPUSettingsQA*)rec->mConfigQA); + if (chain && chain->mConfigQA) { + return *((const GPUSettingsQA*)chain->mConfigQA); } else { return defaultConfig; } @@ -134,6 +135,63 @@ static const GPUSettingsQA& GPUQA_GetConfig(GPUChainTracking* rec) #endif } +static const constexpr bool PLOT_ROOT = 0; +static const constexpr bool FIX_SCALES = 0; +static const constexpr bool PERF_FIGURE = 0; +static const constexpr float FIXED_SCALES_MIN[5] = {-0.05, -0.05, -0.2, -0.2, -0.5}; +static const constexpr float FIXED_SCALES_MAX[5] = {0.4, 0.7, 5, 3, 6.5}; +static const constexpr float LOG_PT_MIN = -1.; + +static constexpr float Y_MAX = 40; +static constexpr float Z_MAX = 100; +static constexpr float PT_MIN = GPUCA_MIN_TRACK_PT_DEFAULT; +static constexpr float PT_MIN2 = 0.1; +static constexpr float PT_MIN_PRIM = 0.1; +static constexpr float PT_MIN_CLUST = GPUCA_MIN_TRACK_PT_DEFAULT; +static constexpr float PT_MAX = 20; +static constexpr float ETA_MAX = 1.5; +static constexpr float ETA_MAX2 = 0.9; + +static constexpr float MIN_WEIGHT_CLS = 40; +static constexpr float FINDABLE_WEIGHT_CLS = 70; + +static constexpr bool CLUST_HIST_INT_SUM = false; + +static constexpr const int COLORCOUNT = 12; + +static const constexpr char* EFF_TYPES[4] = {"Rec", "Clone", "Fake", "All"}; +static const constexpr char* FINDABLE_NAMES[2] = {"", "Findable"}; +static const constexpr char* PRIM_NAMES[2] = {"Prim", "Sec"}; +static const constexpr char* PARAMETER_NAMES[5] = {"Y", "Z", "#Phi", "#lambda", "Relative #it{p}_{T}"}; +static const constexpr char* PARAMETER_NAMES_NATIVE[5] = {"Y", "Z", "sin(#Phi)", "tan(#lambda)", "q/#it{p}_{T} (curvature)"}; +static const constexpr char* VSPARAMETER_NAMES[6] = {"Y", "Z", "Phi", "Eta", "Pt", "Pt_log"}; +static const constexpr char* EFF_NAMES[3] = {"Efficiency", "Clone Rate", "Fake Rate"}; +static const constexpr char* EFFICIENCY_TITLES[4] = {"Efficiency (Primary Tracks, Findable)", "Efficiency (Secondary Tracks, Findable)", "Efficiency (Primary Tracks)", "Efficiency (Secondary Tracks)"}; +static const constexpr double SCALE[5] = {10., 10., 1000., 1000., 100.}; +static const constexpr double SCALE_NATIVE[5] = {10., 10., 1000., 1000., 1.}; +static 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})"}; +static 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)"}; +static 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)"}; +static 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)", + "q*(q/#it{p}_{T} - q/#it{p}_{Tmc})/#sigma_{q/#it{p}_{T}} (Pull)"}; +static 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"}; +static 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)"}; +static const constexpr char* CLUSTER_NAMES_SHORT[GPUQA::N_CLS_HIST] = {"Attached", "Fake", "AttachAdjacent", "FakeAdjacent", "FoundTracks", "Physics", "Protected", "All"}; +static const constexpr char* CLUSTER_TYPES[GPUQA::N_CLS_TYPE] = {"", "Ratio", "Integral"}; +static const constexpr int COLORS_HEX[COLORCOUNT] = {0xB03030, 0x00A000, 0x0000C0, 0x9400D3, 0x19BBBF, 0xF25900, 0x7F7F7F, 0xFFD700, 0x07F707, 0x07F7F7, 0xF08080, 0x000000}; + +static const constexpr int CONFIG_DASHED_MARKERS = 0; + +static const constexpr float AXES_MIN[5] = {-Y_MAX, -Z_MAX, 0.f, -ETA_MAX, PT_MIN}; +static const constexpr float AXES_MAX[5] = {Y_MAX, Z_MAX, 2.f * M_PI, ETA_MAX, PT_MAX}; +static const constexpr int AXIS_BINS[5] = {51, 51, 144, 31, 50}; +static const constexpr int RES_AXIS_BINS[] = {1017, 113}; // Consecutive bin sizes, histograms are binned down until the maximum entry is 50, each bin size should evenly divide its predecessor. +static const constexpr float RES_AXES[5] = {1., 1., 0.03, 0.03, 1.0}; +static const constexpr float RES_AXES_NATIVE[5] = {1., 1., 0.1, 0.1, 5.0}; +static const constexpr float PULL_AXIS = 10.f; + +static TCanvas cfit; + #ifdef GPUCA_TPC_GEOMETRY_O2 #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" @@ -157,7 +215,7 @@ inline int GPUQA::GetMCLabelCol(unsigned int i, unsigned int j) { return mTracki inline float GPUQA::GetMCLabelWeight(unsigned int i, unsigned int j) { return 1; } inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { return 1; } inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return 1; } -inline bool GPUQA::mcPresent() { return !mTracking->GetProcessingSettings().QAnoMC && mTracking->mIOPtrs.clustersNative->clustersMCTruth && mNColTracks.size(); } +inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && mTracking->mIOPtrs.clustersNative->clustersMCTruth && mNColTracks.size(); } #define TRACK_EXPECTED_REFERENCE_X 78 #else inline GPUQA::mcLabelI_t::mcLabelI_t(const GPUQA::mcLabel_t& l) : track(l.fMCID) @@ -183,7 +241,7 @@ inline float GPUQA::GetMCLabelWeight(const mcLabels_t& label, unsigned int j) { inline float GPUQA::GetMCLabelWeight(const mcLabel_t& label) { return label.fWeight; } inline int GPUQA::FakeLabelID(int id) { return id < 0 ? id : (-2 - id); } inline int GPUQA::AbsLabelID(int id) { return id >= 0 ? id : (-id - 2); } -inline bool GPUQA::mcPresent() { return !mTracking->GetProcessingSettings().QAnoMC && GetNMCLabels() && GetNMCTracks(0); } +inline bool GPUQA::mcPresent() { return !mConfig.noMC && mTracking && GetNMCLabels() && GetNMCTracks(0); } #define TRACK_EXPECTED_REFERENCE_X 81 #endif template @@ -192,9 +250,52 @@ inline auto& GPUQA::GetMCTrackObj(T& obj, const GPUQA::mcLabelI_t& l) return obj[l.getEventID()][l.getTrackID()]; } -GPUQA::GPUQA(GPUChainTracking* rec) : mTracking(rec), mConfig(GPUQA_GetConfig(rec)) {} +template <> +auto GPUQA::getHistArray() +{ + return std::make_pair(mHist1D, &mHist1D_pos); +} +template <> +auto GPUQA::getHistArray() +{ + return std::make_pair(mHist2D, &mHist2D_pos); +} +template <> +auto GPUQA::getHistArray() +{ + return std::make_pair(mHist1Dd, &mHist1Dd_pos); +} +template +void GPUQA::createHist(T*& h, const char* name, Args... args) +{ + const auto& p = getHistArray(); + if (mHaveExternalHists) { + if (p.first->size() <= p.second->size()) { + throw std::runtime_error("Incoming histogram array incomplete"); + } + if (strcmp((*p.first)[p.second->size()].GetName(), name)) { + throw std::runtime_error("Incoming histogram has incorrect name"); + } + } else { + p.first->emplace_back(name, args...); + } + p.second->emplace_back(&h); + h = &p.first->back(); +} -GPUQA::~GPUQA() = default; +GPUQA::GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config) : mTracking(chain), mConfig(config ? *config : GPUQA_GetConfig(chain)) +{ + mRunForQC = chain == nullptr || mConfig.forQC; +} + +GPUQA::~GPUQA() +{ + if (mQAInitialized && !mHaveExternalHists) { + delete mHist1D; + delete mHist2D; + delete mHist1Dd; + } +} inline bool GPUQA::MCComp(const mcLabel_t& a, const mcLabel_t& b) { return (GPUQA::GetMCLabelID(a) > GPUQA::GetMCLabelID(b)); } @@ -281,22 +382,9 @@ void GPUQA::SetMCTrackRange(int min, int max) int GPUQA::GetMCTrackLabel(unsigned int trackId) const { return (trackId >= mTrackMCLabels.size() ? MC_LABEL_INVALID : mTrackMCLabels[trackId].getTrackID()); } -int GPUQA::InitQA() +int GPUQA::InitQACreateHistograms() { - if (mQAInitialized) { - return 1; - } char name[2048], fname[1024]; - - mColorNums = new Color_t[COLORCOUNT]; - for (int i = 0; i < COLORCOUNT; i++) { - float f1 = (float)((COLORS_HEX[i] >> 16) & 0xFF) / (float)0xFF; - float f2 = (float)((COLORS_HEX[i] >> 8) & 0xFF) / (float)0xFF; - float f3 = (float)((COLORS_HEX[i] >> 0) & 0xFF) / (float)0xFF; - TColor* c = new TColor(10000 + i, f1, f2, f3); - mColorNums[i] = c->GetNumber(); - } - // Create Efficiency Histograms for (int i = 0; i < 4; i++) { for (int j = 0; j < 2; j++) { @@ -305,13 +393,14 @@ int GPUQA::InitQA() for (int m = 0; m < 2; m++) { sprintf(name, "%s%s%s%sVs%s", m ? "eff" : "tracks", EFF_TYPES[i], FINDABLE_NAMES[j], PRIM_NAMES[k], VSPARAMETER_NAMES[l]); if (l == 4) { - double* binsPt = CreateLogAxis(AXIS_BINS[4], k == 0 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4]); - mEff[i][j][k][l][m] = new TH1F(name, name, AXIS_BINS[l], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], k == 0 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], binsPt.get()); } else { - mEff[i][j][k][l][m] = new TH1F(name, name, AXIS_BINS[l], AXES_MIN[l], AXES_MAX[l]); + createHist(mEff[i][j][k][l][m], name, name, AXIS_BINS[l], AXES_MIN[l], AXES_MAX[l]); + } + if (!mHaveExternalHists) { + mEff[i][j][k][l][m]->Sumw2(); } - mEff[i][j][k][l][m]->Sumw2(); } } } @@ -324,23 +413,21 @@ int GPUQA::InitQA() sprintf(name, "rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); sprintf(fname, "mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); if (j == 4) { - double* binsPt = CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4]); - mRes[i][j][0] = new TH1F(name, name, AXIS_BINS[j], binsPt); - mRes[i][j][1] = new TH1F(fname, fname, AXIS_BINS[j], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mRes[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); + createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); } else { - mRes[i][j][0] = new TH1F(name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - mRes[i][j][1] = new TH1F(fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mRes[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mRes[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); } sprintf(name, "res_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); const float* axis = mConfig.nativeFitResolutions ? RES_AXES_NATIVE : RES_AXES; const int nbins = i == 4 && mConfig.nativeFitResolutions ? (10 * RES_AXIS_BINS[0]) : RES_AXIS_BINS[0]; if (j == 4) { - double* binsPt = CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4]); - mRes2[i][j] = new TH2F(name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], mConfig.resPrimaries == 1 ? PT_MIN_PRIM : AXES_MIN[4], AXES_MAX[4])}; + createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], binsPt.get()); } else { - mRes2[i][j] = new TH2F(name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mRes2[i][j], name, name, nbins, -axis[i], axis[i], AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); } } } @@ -351,21 +438,19 @@ int GPUQA::InitQA() sprintf(name, "pull_rms_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); sprintf(fname, "pull_mean_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); if (j == 4) { - double* binsPt = CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4]); - mPull[i][j][0] = new TH1F(name, name, AXIS_BINS[j], binsPt); - mPull[i][j][1] = new TH1F(fname, fname, AXIS_BINS[j], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; + createHist(mPull[i][j][0], name, name, AXIS_BINS[j], binsPt.get()); + createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], binsPt.get()); } else { - mPull[i][j][0] = new TH1F(name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); - mPull[i][j][1] = new TH1F(fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mPull[i][j][0], name, name, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mPull[i][j][1], fname, fname, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); } sprintf(name, "pull_%s_vs_%s", VSPARAMETER_NAMES[i], VSPARAMETER_NAMES[j]); if (j == 4) { - double* binsPt = CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4]); - mPull2[i][j] = new TH2F(name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], AXES_MIN[4], AXES_MAX[4])}; + createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], binsPt.get()); } else { - mPull2[i][j] = new TH2F(name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); + createHist(mPull2[i][j], name, name, RES_AXIS_BINS[0], -PULL_AXIS, PULL_AXIS, AXIS_BINS[j], AXES_MIN[j], AXES_MAX[j]); } } } @@ -375,27 +460,84 @@ int GPUQA::InitQA() int ioffset = i >= (2 * N_CLS_HIST - 1) ? (2 * N_CLS_HIST - 1) : i >= N_CLS_HIST ? N_CLS_HIST : 0; int itype = i >= (2 * N_CLS_HIST - 1) ? 2 : i >= N_CLS_HIST ? 1 : 0; sprintf(name, "clusters%s%s", CLUSTER_NAMES_SHORT[i - ioffset], CLUSTER_TYPES[itype]); - double* binsPt = CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX); - mClusters[i] = new TH1D(name, name, AXIS_BINS[4], binsPt); - delete[] binsPt; + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; + createHist(mClusters[i], name, name, AXIS_BINS[4], binsPt.get()); } { sprintf(name, "nclusters"); - mNCl = new TH1F(name, name, 160, 0, 159); + createHist(mNCl, name, name, 160, 0, 159); } // Create Tracks Histograms { sprintf(name, "tracks"); - double* binsPt = CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX); - mTracks = new TH1F(name, name, AXIS_BINS[4], binsPt); + std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; + createHist(mTracks, name, name, AXIS_BINS[4], binsPt.get()); } - mkdir("plots", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + for (unsigned int i = 0; i < mHist1D->size(); i++) { + *mHist1D_pos[i] = &(*mHist1D)[i]; + } + for (unsigned int i = 0; i < mHist2D->size(); i++) { + *mHist2D_pos[i] = &(*mHist2D)[i]; + } + for (unsigned int i = 0; i < mHist1Dd->size(); i++) { + *mHist1Dd_pos[i] = &(*mHist1Dd)[i]; + } + + return 0; +} + +int GPUQA::loadHistograms(std::vector& i1, std::vector& i2, std::vector& i3) +{ + if (mQAInitialized) { + return 1; + } + mHist1D = &i1; + mHist2D = &i2; + mHist1Dd = &i3; + mHist1D_pos.clear(); + mHist2D_pos.clear(); + mHist1Dd_pos.clear(); + mHaveExternalHists = true; + if (InitQACreateHistograms()) { + return 1; + } + mQAInitialized = true; + return 0; +} + +int GPUQA::InitQA() +{ + if (mQAInitialized) { + return 1; + } + + mHist1D = new std::vector; + mHist2D = new std::vector; + mHist1Dd = new std::vector; + + mColorNums.resize(COLORCOUNT); + mColors.reserve(COLORCOUNT); + for (int i = 0; i < COLORCOUNT; i++) { + float f1 = (float)((COLORS_HEX[i] >> 16) & 0xFF) / (float)0xFF; + float f2 = (float)((COLORS_HEX[i] >> 8) & 0xFF) / (float)0xFF; + float f3 = (float)((COLORS_HEX[i] >> 0) & 0xFF) / (float)0xFF; + mColors.emplace_back(10000 + i, f1, f2, f3); + mColorNums[i] = mColors.back().GetNumber(); + } + + if (InitQACreateHistograms()) { + return 1; + } + + if (!mRunForQC) { + mkdir("plots", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + } #ifdef GPUCA_O2_LIB - TFile* fileSim = new TFile(o2::base::NameConf::getMCKinematicsFileName("o2sim").c_str()); - TTree* treeSim = (TTree*)fileSim->Get("o2sim"); + TFile fileSim(o2::base::NameConf::getMCKinematicsFileName("o2sim").c_str()); + TTree* treeSim = (TTree*)fileSim.Get("o2sim"); std::vector* tracksX; std::vector* trackRefsX; if (treeSim == nullptr) { @@ -470,8 +612,7 @@ int GPUQA::InitQA() } } - fileSim->Close(); - delete fileSim; + fileSim.Close(); #endif if (mConfig.matchMCLabels.size()) { @@ -654,6 +795,11 @@ void GPUQA::RunQA(bool matchOnly) if (ompError) { return; } + if (QA_TIMING) { + GPUInfo("QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + + // fill cluster attachment status for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; if (!track.OK()) { @@ -701,6 +847,7 @@ void GPUQA::RunQA(bool matchOnly) } } } + // fill cluster adjacent status for (unsigned int i = 0; i < GetNMCLabels(); i++) { if (mClusterParam[i].attached == 0 && mClusterParam[i].fakeAttached == 0) { int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; @@ -763,16 +910,14 @@ void GPUQA::RunQA(bool matchOnly) } } } + if (QA_TIMING) { + GPUInfo("QA Time: Cluster attach status:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } if (matchOnly) { return; } - if (QA_TIMING) { - GPUInfo("QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); - } - timer.ResetStart(); - // Recompute fNWeightCls (might have changed after merging events into timeframes) for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { @@ -793,10 +938,10 @@ void GPUQA::RunQA(bool matchOnly) } } if (QA_TIMING) { - GPUInfo("QA Time: Compute cluster label weights:\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); + GPUInfo("QA Time: Compute cluster label weights:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - timer.ResetStart(); + // Compute MC Track Parameters for MC Tracks GPUCA_OPENMP(parallel for) for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { @@ -817,7 +962,10 @@ void GPUQA::RunQA(bool matchOnly) } } } - // Compute MC Track Parameters for MC Tracks + if (QA_TIMING) { + GPUInfo("QA Time: Compute track mc parameters:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); + } + // Fill Efficiency Histograms for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { for (unsigned int i = 0; i < GetNMCTracks(iCol); i++) { @@ -895,9 +1043,8 @@ void GPUQA::RunQA(bool matchOnly) } } if (QA_TIMING) { - GPUInfo("QA Time: Fill efficiency histograms:\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); + GPUInfo("QA Time: Fill efficiency histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - timer.ResetStart(); // Fill Resolution Histograms GPUTPCGMPropagator prop; @@ -1030,9 +1177,8 @@ void GPUQA::RunQA(bool matchOnly) } } if (QA_TIMING) { - GPUInfo("QA Time: Fill resolution histograms:\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); + GPUInfo("QA Time: Fill resolution histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - timer.ResetStart(); // Fill cluster histograms for (unsigned int iTrk = 0; iTrk < mTracking->mIOPtrs.nMergedTracks; iTrk++) { @@ -1256,9 +1402,8 @@ void GPUQA::RunQA(bool matchOnly) } if (QA_TIMING) { - GPUInfo("QA Time: Fill cluster histograms:\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); + GPUInfo("QA Time: Fill cluster histograms:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - timer.ResetStart(); } else if (!mConfig.inputHistogramsOnly) { GPUWarning("No MC information available, only running partial TPC QA!"); } @@ -1335,7 +1480,7 @@ void GPUQA::RunQA(bool matchOnly) } if (QA_TIMING) { - GPUInfo("QA Time: Others:\t%6.0f us", timer.GetCurrentElapsedTime() * 1e6); + GPUInfo("QA Time: Others:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } // Create CSV DumpTrackHits @@ -1484,7 +1629,7 @@ T* GPUQA::GetHist(T*& ee, std::vector& tin, int k, int nNewInput) return (e); } -int GPUQA::DrawQAHistograms() +int GPUQA::DrawQAHistograms(TObjArray* qcout) { if (!mQAInitialized) { return 1; @@ -1504,156 +1649,162 @@ int GPUQA::DrawQAHistograms() tout = new TFile(mConfig.output.c_str(), "RECREATE"); } - float legendSpacingString = 0.025; - for (int i = 0; i < ConfigNumInputs; i++) { - GetName(fname, i); - if (strlen(fname) * 0.006 > legendSpacingString) { - legendSpacingString = strlen(fname) * 0.006; + if (!mRunForQC) { + float legendSpacingString = 0.025; + for (int i = 0; i < ConfigNumInputs; i++) { + GetName(fname, i); + if (strlen(fname) * 0.006 > legendSpacingString) { + legendSpacingString = strlen(fname) * 0.006; + } } - } - // Create Canvas / Pads for Efficiency Histograms - for (int ii = 0; ii < 6; ii++) { - int i = ii == 5 ? 4 : ii; - sprintf(fname, "ceff_%d", ii); - sprintf(name, "Efficiency versus %s", VSPARAMETER_NAMES[i]); - mCEff[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCEff[ii]->cd(); - float dy = 1. / 2.; - mPEff[ii][0] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPEff[ii][0]->Draw(); - mPEff[ii][0]->SetRightMargin(0.04); - mPEff[ii][1] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPEff[ii][1]->Draw(); - mPEff[ii][1]->SetRightMargin(0.04); - mPEff[ii][2] = new TPad("p2", "", 0.0, dy * 1, 0.5, dy * 2 - .001); - mPEff[ii][2]->Draw(); - mPEff[ii][2]->SetRightMargin(0.04); - mPEff[ii][3] = new TPad("p3", "", 0.5, dy * 1, 1.0, dy * 2 - .001); - mPEff[ii][3]->Draw(); - mPEff[ii][3]->SetRightMargin(0.04); - mLEff[ii] = new TLegend(0.92 - legendSpacingString * 1.45, 0.83 - (0.93 - 0.82) / 2. * (float)ConfigNumInputs, 0.98, 0.849); - SetLegend(mLEff[ii]); - } - - // Create Canvas / Pads for Resolution Histograms - for (int ii = 0; ii < 7; ii++) { - int i = ii == 5 ? 4 : ii; - sprintf(fname, "cres_%d", ii); - if (ii == 6) { - sprintf(name, "Integral Resolution"); - } else { - sprintf(name, "Resolution versus %s", VSPARAMETER_NAMES[i]); - } - mCRes[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCRes[ii]->cd(); - gStyle->SetOptFit(1); - - float dy = 1. / 2.; - mPRes[ii][3] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPRes[ii][3]->Draw(); - mPRes[ii][3]->SetRightMargin(0.04); - mPRes[ii][4] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPRes[ii][4]->Draw(); - mPRes[ii][4]->SetRightMargin(0.04); - mPRes[ii][0] = new TPad("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); - mPRes[ii][0]->Draw(); - mPRes[ii][0]->SetRightMargin(0.04); - mPRes[ii][0]->SetLeftMargin(0.15); - mPRes[ii][1] = new TPad("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); - mPRes[ii][1]->Draw(); - mPRes[ii][1]->SetRightMargin(0.04); - mPRes[ii][1]->SetLeftMargin(0.135); - mPRes[ii][2] = new TPad("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); - mPRes[ii][2]->Draw(); - mPRes[ii][2]->SetRightMargin(0.06); - mPRes[ii][2]->SetLeftMargin(0.135); - if (ii < 6) { - mLRes[ii] = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLRes[ii]); + // Create Canvas / Pads for Efficiency Histograms + for (int ii = 0; ii < 6; ii++) { + int i = ii == 5 ? 4 : ii; + sprintf(fname, "ceff_%d", ii); + sprintf(name, "Efficiency versus %s", VSPARAMETER_NAMES[i]); + mCEff[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCEff[ii]->cd(); + float dy = 1. / 2.; + mPEff[ii][0] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPEff[ii][0]->Draw(); + mPEff[ii][0]->SetRightMargin(0.04); + mPEff[ii][1] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPEff[ii][1]->Draw(); + mPEff[ii][1]->SetRightMargin(0.04); + mPEff[ii][2] = new TPad("p2", "", 0.0, dy * 1, 0.5, dy * 2 - .001); + mPEff[ii][2]->Draw(); + mPEff[ii][2]->SetRightMargin(0.04); + mPEff[ii][3] = new TPad("p3", "", 0.5, dy * 1, 1.0, dy * 2 - .001); + mPEff[ii][3]->Draw(); + mPEff[ii][3]->SetRightMargin(0.04); + mLEff[ii] = new TLegend(0.92 - legendSpacingString * 1.45, 0.83 - (0.93 - 0.82) / 2. * (float)ConfigNumInputs, 0.98, 0.849); + SetLegend(mLEff[ii]); } - } - // Create Canvas / Pads for Pull Histograms - for (int ii = 0; ii < 7; ii++) { - int i = ii == 5 ? 4 : ii; - sprintf(fname, "cpull_%d", ii); - if (ii == 6) { - sprintf(name, "Integral Pull"); - } else { - sprintf(name, "Pull versus %s", VSPARAMETER_NAMES[i]); + // Create Canvas / Pads for Resolution Histograms + for (int ii = 0; ii < 7; ii++) { + int i = ii == 5 ? 4 : ii; + sprintf(fname, "cres_%d", ii); + if (ii == 6) { + sprintf(name, "Integral Resolution"); + } else { + sprintf(name, "Resolution versus %s", VSPARAMETER_NAMES[i]); + } + mCRes[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCRes[ii]->cd(); + gStyle->SetOptFit(1); + + float dy = 1. / 2.; + mPRes[ii][3] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPRes[ii][3]->Draw(); + mPRes[ii][3]->SetRightMargin(0.04); + mPRes[ii][4] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPRes[ii][4]->Draw(); + mPRes[ii][4]->SetRightMargin(0.04); + mPRes[ii][0] = new TPad("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); + mPRes[ii][0]->Draw(); + mPRes[ii][0]->SetRightMargin(0.04); + mPRes[ii][0]->SetLeftMargin(0.15); + mPRes[ii][1] = new TPad("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); + mPRes[ii][1]->Draw(); + mPRes[ii][1]->SetRightMargin(0.04); + mPRes[ii][1]->SetLeftMargin(0.135); + mPRes[ii][2] = new TPad("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); + mPRes[ii][2]->Draw(); + mPRes[ii][2]->SetRightMargin(0.06); + mPRes[ii][2]->SetLeftMargin(0.135); + if (ii < 6) { + mLRes[ii] = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLRes[ii]); + } } - mCPull[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); - mCPull[ii]->cd(); - gStyle->SetOptFit(1); - - float dy = 1. / 2.; - mPPull[ii][3] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); - mPPull[ii][3]->Draw(); - mPPull[ii][3]->SetRightMargin(0.04); - mPPull[ii][4] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); - mPPull[ii][4]->Draw(); - mPPull[ii][4]->SetRightMargin(0.04); - mPPull[ii][0] = new TPad("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); - mPPull[ii][0]->Draw(); - mPPull[ii][0]->SetRightMargin(0.04); - mPPull[ii][0]->SetLeftMargin(0.15); - mPPull[ii][1] = new TPad("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); - mPPull[ii][1]->Draw(); - mPPull[ii][1]->SetRightMargin(0.04); - mPPull[ii][1]->SetLeftMargin(0.135); - mPPull[ii][2] = new TPad("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); - mPPull[ii][2]->Draw(); - mPPull[ii][2]->SetRightMargin(0.06); - mPPull[ii][2]->SetLeftMargin(0.135); - if (ii < 6) { - mLPull[ii] = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLPull[ii]); + + // Create Canvas / Pads for Pull Histograms + for (int ii = 0; ii < 7; ii++) { + int i = ii == 5 ? 4 : ii; + sprintf(fname, "cpull_%d", ii); + if (ii == 6) { + sprintf(name, "Integral Pull"); + } else { + sprintf(name, "Pull versus %s", VSPARAMETER_NAMES[i]); + } + mCPull[ii] = new TCanvas(fname, name, 0, 0, 700, 700. * 2. / 3.); + mCPull[ii]->cd(); + gStyle->SetOptFit(1); + + float dy = 1. / 2.; + mPPull[ii][3] = new TPad("p0", "", 0.0, dy * 0, 0.5, dy * 1); + mPPull[ii][3]->Draw(); + mPPull[ii][3]->SetRightMargin(0.04); + mPPull[ii][4] = new TPad("p1", "", 0.5, dy * 0, 1.0, dy * 1); + mPPull[ii][4]->Draw(); + mPPull[ii][4]->SetRightMargin(0.04); + mPPull[ii][0] = new TPad("p2", "", 0.0, dy * 1, 1. / 3., dy * 2 - .001); + mPPull[ii][0]->Draw(); + mPPull[ii][0]->SetRightMargin(0.04); + mPPull[ii][0]->SetLeftMargin(0.15); + mPPull[ii][1] = new TPad("p3", "", 1. / 3., dy * 1, 2. / 3., dy * 2 - .001); + mPPull[ii][1]->Draw(); + mPPull[ii][1]->SetRightMargin(0.04); + mPPull[ii][1]->SetLeftMargin(0.135); + mPPull[ii][2] = new TPad("p4", "", 2. / 3., dy * 1, 1.0, dy * 2 - .001); + mPPull[ii][2]->Draw(); + mPPull[ii][2]->SetRightMargin(0.06); + mPPull[ii][2]->SetLeftMargin(0.135); + if (ii < 6) { + mLPull[ii] = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLPull[ii]); + } } - } - // Create Canvas for Cluster Histos - for (int i = 0; i < 3; i++) { - sprintf(fname, "cclust_%d", i); - mCClust[i] = new TCanvas(fname, CLUSTER_TITLES[i], 0, 0, 700, 700. * 2. / 3.); - mCClust[i]->cd(); - mPClust[i] = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); - mPClust[i]->Draw(); - float y1 = i != 1 ? 0.77 : 0.27, y2 = i != 1 ? 0.9 : 0.42; - mLClust[i] = new 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); - SetLegend(mLClust[i]); - } + // Create Canvas for Cluster Histos + for (int i = 0; i < 3; i++) { + sprintf(fname, "cclust_%d", i); + mCClust[i] = new TCanvas(fname, CLUSTER_TITLES[i], 0, 0, 700, 700. * 2. / 3.); + mCClust[i]->cd(); + mPClust[i] = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); + mPClust[i]->Draw(); + float y1 = i != 1 ? 0.77 : 0.27, y2 = i != 1 ? 0.9 : 0.42; + mLClust[i] = new 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); + SetLegend(mLClust[i]); + } - // Create Canvas for other histos - { - mCTracks = new TCanvas("ctracks", "Track Pt", 0, 0, 700, 700. * 2. / 3.); - mCTracks->cd(); - mPTracks = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); - mPTracks->Draw(); - mLTracks = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLTracks); + // Create Canvas for other histos + { + mCTracks = new TCanvas("ctracks", "Track Pt", 0, 0, 700, 700. * 2. / 3.); + mCTracks->cd(); + mPTracks = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); + mPTracks->Draw(); + mLTracks = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLTracks); + + mCNCl = new TCanvas("cncl", "Number of clusters per track", 0, 0, 700, 700. * 2. / 3.); + mCNCl->cd(); + mPNCl = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); + mPNCl->Draw(); + mLNCl = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLNCl); + } - mCNCl = new TCanvas("cncl", "Number of clusters per track", 0, 0, 700, 700. * 2. / 3.); - mCNCl->cd(); - mPNCl = new TPad("p0", "", 0.0, 0.0, 1.0, 1.0); - mPNCl->Draw(); - mLNCl = new TLegend(0.9 - legendSpacingString * 1.45, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLNCl); + if (!mConfig.inputHistogramsOnly) { + 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)", (int)mEff[3][1][0][0][0]->GetEntries(), (int)mEff[3][1][0][3][0]->GetEntries(), (int)mEff[3][1][0][4][0]->GetEntries(), + mEff[0][0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0][0]->GetSumOfWeights()), (int)mEff[3][1][1][0][0]->GetEntries(), (int)mEff[3][1][1][3][0]->GetEntries(), + (int)mEff[3][1][1][4][0]->GetEntries(), mEff[0][0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0][0]->GetSumOfWeights()), mEff[0][1][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0][0]->GetSumOfWeights()), (int)mRes2[0][0]->GetEntries(), + (int)mRes2[0][3]->GetEntries(), (int)mRes2[0][4]->GetEntries()); + } } - if (!mConfig.inputHistogramsOnly) { - 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)", (int)mEff[3][1][0][0][0]->GetEntries(), (int)mEff[3][1][0][3][0]->GetEntries(), (int)mEff[3][1][0][4][0]->GetEntries(), - mEff[0][0][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][0][0][0]->GetSumOfWeights()), mEff[0][1][0][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][0][0][0]->GetSumOfWeights()), (int)mEff[3][1][1][0][0]->GetEntries(), (int)mEff[3][1][1][3][0]->GetEntries(), - (int)mEff[3][1][1][4][0]->GetEntries(), mEff[0][0][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][0][1][0][0]->GetSumOfWeights()), mEff[0][1][1][0][0]->GetSumOfWeights() / std::max(1., mEff[3][1][1][0][0]->GetSumOfWeights()), (int)mRes2[0][0]->GetEntries(), - (int)mRes2[0][3]->GetEntries(), (int)mRes2[0][4]->GetEntries()); - } + int flagShowVsPtLog = mRunForQC ? 0 : 1; // Process / Draw Efficiency Histograms - for (int ii = 0; ii < 6; ii++) { + for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { int i = ii == 5 ? 4 : ii; for (int k = 0; k < ConfigNumInputs; k++) { for (int j = 0; j < 4; j++) { - mPEff[ii][j]->cd(); + if (!mRunForQC) { + mPEff[ii][j]->cd(); + } for (int l = 0; l < 3; l++) { if (k == 0 && mConfig.inputHistogramsOnly == 0 && ii != 5) { if (l == 0) { @@ -1689,11 +1840,17 @@ int GPUQA::DrawQAHistograms() e->GetYaxis()->SetTitle("(Efficiency)"); e->GetXaxis()->SetTitle(XAXIS_TITLES[i]); - e->SetMarkerColor(kBlack); e->SetLineWidth(1); - e->SetLineColor(mColorNums[(l == 2 ? (ConfigNumInputs * 2 + k) : (k * 2 + l)) % COLORCOUNT]); e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); SetAxisSize(e); + if (qcout) { + qcout->Add(e); + } + if (mRunForQC) { + continue; + } + e->SetMarkerColor(kBlack); + e->SetLineColor(mColorNums[(l == 2 ? (ConfigNumInputs * 2 + k) : (k * 2 + l)) % COLORCOUNT]); e->Draw(k || l ? "same" : ""); if (j == 0) { GetName(fname, k); @@ -1704,10 +1861,17 @@ int GPUQA::DrawQAHistograms() mPEff[ii][j]->SetLogx(); } } + if (mRunForQC) { + continue; + } mCEff[ii]->cd(); ChangePadTitleSize(mPEff[ii][j], 0.056); } } + if (mRunForQC) { + continue; + } + mLEff[ii]->Draw(); doPerfFigure(0.2, 0.295, 0.025); @@ -1722,7 +1886,7 @@ int GPUQA::DrawQAHistograms() TH1D *resIntegral[5] = {}, *pullIntegral[5] = {}; TF1* customGaus = new TF1("G", "[0]*exp(-(x-[1])*(x-[1])/(2.*[2]*[2]))"); for (int p = 0; p < 2; p++) { - for (int ii = 0; ii < 6; ii++) { + for (int ii = 0; ii < 5 + flagShowVsPtLog; ii++) { TCanvas* can = p ? mCPull[ii] : mCRes[ii]; TLegend* leg = p ? mLPull[ii] : mLRes[ii]; int i = ii == 5 ? 4 : ii; @@ -1733,8 +1897,9 @@ int GPUQA::DrawQAHistograms() TPad* pad = p ? mPPull[ii][j] : mPRes[ii][j]; if (!mConfig.inputHistogramsOnly && ii != 5) { - TCanvas cfit; - cfit.cd(); + if (!mRunForQC) { + cfit.cd(); + } TAxis* axis = src->GetYaxis(); int nBins = axis->GetNbins(); @@ -1819,8 +1984,9 @@ int GPUQA::DrawQAHistograms() dstIntegral->SetName(fname); dstIntegral->SetTitle(name); } - pad->cd(); - + if (!mRunForQC) { + pad->cd(); + } int numColor = 0; float tmpMax = -1000.; float tmpMin = 1000.; @@ -1882,9 +2048,7 @@ int GPUQA::DrawQAHistograms() } e->SetMaximum(tmpMax); e->SetMinimum(tmpMin); - e->SetMarkerColor(kBlack); e->SetLineWidth(1); - e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->SetLineStyle(CONFIG_DASHED_MARKERS ? k + 1 : 1); SetAxisSize(e); e->GetYaxis()->SetTitle(p ? AXIS_TITLES_PULL[j] : mConfig.nativeFitResolutions ? AXIS_TITLES_NATIVE[j] : AXIS_TITLES[j]); @@ -1898,6 +2062,15 @@ int GPUQA::DrawQAHistograms() } else if (j < 3) { e->GetYaxis()->SetTitleOffset(1.4); } + if (qcout) { + qcout->Add(e); + } + if (mRunForQC) { + continue; + } + + e->SetMarkerColor(kBlack); + e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->Draw(k || l ? "same" : ""); if (j == 0) { GetName(fname, k); @@ -1910,6 +2083,10 @@ int GPUQA::DrawQAHistograms() } } } + if (mRunForQC) { + continue; + } + if (ii == 5) { pad->SetLogx(); } @@ -1918,6 +2095,10 @@ int GPUQA::DrawQAHistograms() ChangePadTitleSize(pad, 0.056); } } + if (mRunForQC) { + continue; + } + leg->Draw(); doPerfFigure(0.2, 0.295, 0.025); @@ -1937,7 +2118,9 @@ int GPUQA::DrawQAHistograms() TPad* pad = p ? mPPull[6][i] : mPRes[6][i]; TH1D* hist = p ? pullIntegral[i] : resIntegral[i]; int numColor = 0; - pad->cd(); + if (!mRunForQC) { + pad->cd(); + } if (!mConfig.inputHistogramsOnly && mcAvail) { TH1D* e = hist; e->GetEntries(); @@ -1963,14 +2146,28 @@ int GPUQA::DrawQAHistograms() } e->SetMaximum(tmpMax * 1.02); e->SetMinimum(tmpMax * -0.02); - e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); if (tout && !mConfig.inputHistogramsOnly && k == 0) { e->Write(); } + if (qcout) { + qcout->Add(e); + } + if (mRunForQC) { + continue; + } + + e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->Draw(k == 0 ? "" : "same"); } + if (mRunForQC) { + continue; + } can->cd(); } + if (mRunForQC) { + continue; + } + can->Print(p ? "plots/pull_integral.pdf" : "plots/res_integral.pdf"); if (mConfig.writeRootFiles) { can->Print(p ? "plots/pull_integral.root" : "plots/res_integral.root"); @@ -2010,7 +2207,7 @@ int GPUQA::DrawQAHistograms() if (!mcAvail) { counts[N_CLS_HIST - 1] = mClusterCounts.nTotal; } - if (counts[N_CLS_HIST - 1]) { + if (counts[N_CLS_HIST - 1] && !mRunForQC) { if (mcAvail) { for (int i = 0; i < N_CLS_HIST; i++) { printf("\t%35s: %'12llu (%6.2f%%)\n", CLUSTER_NAMES[i], counts[i], 100.f * counts[i] / counts[N_CLS_HIST - 1]); @@ -2091,8 +2288,10 @@ int GPUQA::DrawQAHistograms() } for (int i = 0; i < N_CLS_TYPE; i++) { - mPClust[i]->cd(); - mPClust[i]->SetLogx(); + if (!mRunForQC) { + mPClust[i]->cd(); + mPClust[i]->SetLogx(); + } int begin = i == 2 ? (2 * N_CLS_HIST - 1) : i == 1 ? N_CLS_HIST : 0; int end = i == 2 ? (3 * N_CLS_HIST - 1) : i == 1 ? (2 * N_CLS_HIST - 1) : N_CLS_HIST; int numColor = 0; @@ -2112,13 +2311,20 @@ int GPUQA::DrawQAHistograms() e->Write(); } e->SetStats(kFALSE); - e->SetMarkerColor(kBlack); e->SetLineWidth(1); - e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->SetLineStyle(CONFIG_DASHED_MARKERS ? j + 1 : 1); if (i == 0) { e->GetXaxis()->SetRange(2, AXIS_BINS[4]); } + if (qcout) { + qcout->Add(e); + } + if (mRunForQC) { + continue; + } + + e->SetMarkerColor(kBlack); + e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->Draw(j == end - 1 && k == 0 ? "" : "same"); GetName(fname, k); sprintf(name, "%s%s", fname, CLUSTER_NAMES[j - begin]); @@ -2128,10 +2334,21 @@ int GPUQA::DrawQAHistograms() if (ConfigNumInputs == 1) { TH1* e = reinterpret_cast(mClusters[begin + CL_att_adj]->Clone()); e->Add(mClusters[begin + CL_prot], -1); + if (qcout) { + qcout->Add(e); + } + if (mRunForQC) { + continue; + } + e->SetLineColor(mColorNums[numColor++ % COLORCOUNT]); e->Draw("same"); mLClust[i]->AddEntry(e, "Removed", "l"); } + if (mRunForQC) { + continue; + } + mLClust[i]->Draw(); doPerfFigure(i != 2 ? 0.37 : 0.6, 0.295, 0.030); @@ -2145,7 +2362,7 @@ int GPUQA::DrawQAHistograms() } // Process track histograms - { + if (!mRunForQC) { float tmpMax = 0.; for (int k = 0; k < ConfigNumInputs; k++) { TH1F* e = mTracks; @@ -2170,11 +2387,14 @@ int GPUQA::DrawQAHistograms() e->SetMaximum(tmpMax * 1.02); e->SetMinimum(tmpMax * -0.02); e->SetStats(kFALSE); - e->SetMarkerColor(kBlack); e->SetLineWidth(1); - e->SetLineColor(mColorNums[k % COLORCOUNT]); e->GetYaxis()->SetTitle("a.u."); e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); + if (qcout) { + qcout->Add(e); + } + e->SetMarkerColor(kBlack); + e->SetLineColor(mColorNums[k % COLORCOUNT]); e->Draw(k == 0 ? "" : "same"); GetName(fname, k); sprintf(name, "%sTrack Pt", fname); @@ -2209,11 +2429,14 @@ int GPUQA::DrawQAHistograms() e->SetMaximum(tmpMax * 1.02); e->SetMinimum(tmpMax * -0.02); e->SetStats(kFALSE); - e->SetMarkerColor(kBlack); e->SetLineWidth(1); - e->SetLineColor(mColorNums[k % COLORCOUNT]); e->GetYaxis()->SetTitle("a.u."); e->GetXaxis()->SetTitle("NClusters"); + if (qcout) { + qcout->Add(e); + } + e->SetMarkerColor(kBlack); + e->SetLineColor(mColorNums[k % COLORCOUNT]); e->Draw(k == 0 ? "" : "same"); GetName(fname, k); sprintf(name, "%sNClusters", fname); diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.h b/GPU/GPUTracking/Standalone/qa/GPUQA.h index df2e8b0e4a6eb..89dd94c6c9f1e 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.h +++ b/GPU/GPUTracking/Standalone/qa/GPUQA.h @@ -25,6 +25,8 @@ class TPad; class TH1; class TFile; class TH1D; +class TObjArray; +class TColor; typedef short int Color_t; #if !defined(GPUCA_BUILD_QA) || defined(GPUCA_GPUCODE) @@ -38,7 +40,7 @@ class GPUChainTracking; class GPUQA { public: - GPUQA(GPUChainTracking* rec) {} + GPUQA(GPUChainTracking* chain) {} ~GPUQA() = default; int InitQA() { return 1; } @@ -60,7 +62,8 @@ class GPUQA #include "GPUTPCDef.h" #include - +#include +#include #ifdef GPUCA_TPC_GEOMETRY_O2 #include #endif @@ -80,12 +83,13 @@ class GPUTPCMCInfo; class GPUQA { public: - GPUQA(GPUChainTracking* rec); + GPUQA(); + GPUQA(GPUChainTracking* chain, const GPUSettingsQA* config = nullptr); ~GPUQA(); int InitQA(); void RunQA(bool matchOnly = false); - int DrawQAHistograms(); + int DrawQAHistograms(TObjArray* qcout = nullptr); void SetMCTrackRange(int min, int max); bool SuppressTrack(int iTrack) const; bool SuppressHit(int iHit) const; @@ -95,6 +99,16 @@ class GPUQA static bool QAAvailable() { return true; } bool IsInitialized() { return mQAInitialized; } + const std::vector& getHistograms1D() const { return *mHist1D; } + const std::vector& getHistograms2D() const { return *mHist2D; } + const std::vector& getHistograms1Dd() const { return *mHist1Dd; } + int loadHistograms(std::vector& i1, std::vector& i2, std::vector& i3); + + static constexpr int N_CLS_HIST = 8; + static constexpr int N_CLS_TYPE = 3; + + static constexpr int MC_LABEL_INVALID = -1e9; + private: struct additionalMCParameters { float pt, phi, theta, eta, nWeightCls; @@ -105,6 +119,8 @@ class GPUQA float pt; }; + int InitQACreateHistograms(); + void SetAxisSize(TH1F* e); void SetLegend(TLegend* l); double* CreateLogAxis(int nbins, float xmin, float xmax); @@ -169,14 +185,7 @@ class GPUQA GPUChainTracking* mTracking; const GPUSettingsQA& mConfig; - - //-------------------------: Some compile time settings.... - static const constexpr bool PLOT_ROOT = 0; - static const constexpr bool FIX_SCALES = 0; - static const constexpr bool PERF_FIGURE = 0; - static const constexpr float FIXED_SCALES_MIN[5] = {-0.05, -0.05, -0.2, -0.2, -0.5}; - static const constexpr float FIXED_SCALES_MAX[5] = {0.4, 0.7, 5, 3, 6.5}; - static const constexpr float LOG_PT_MIN = -1.; + bool mRunForQC; const char* str_perf_figure_1 = "ALICE Performance 2018/03/20"; // const char* str_perf_figure_2 = "2015, MC pp, #sqrt{s} = 5.02 TeV"; @@ -217,8 +226,6 @@ class GPUQA TPad* mPPull[7][5]; TLegend* mLPull[6]; - static constexpr int N_CLS_HIST = 8; - static constexpr int N_CLS_TYPE = 3; enum CL_types { CL_attached = 0, CL_fake = 1, CL_att_adj = 2, @@ -247,6 +254,18 @@ class GPUQA TPad* mPNCl; TLegend* mLNCl; + std::vector* mHist1D = nullptr; + std::vector* mHist2D = nullptr; + std::vector* mHist1Dd = nullptr; + bool mHaveExternalHists = false; + std::vector mHist1D_pos{}; + std::vector mHist2D_pos{}; + std::vector mHist1Dd_pos{}; + template + auto getHistArray(); + template + void createHist(T*& h, const char* name, Args... args); + int mNEvents = 0; bool mQAInitialized = false; std::vector> mcEffBuffer; @@ -254,56 +273,8 @@ class GPUQA std::vector> mGoodTracks; std::vector> mGoodHits; - static constexpr float Y_MAX = 40; - static constexpr float Z_MAX = 100; - static constexpr float PT_MIN = GPUCA_MIN_TRACK_PT_DEFAULT; - static constexpr float PT_MIN2 = 0.1; - static constexpr float PT_MIN_PRIM = 0.1; - static constexpr float PT_MIN_CLUST = GPUCA_MIN_TRACK_PT_DEFAULT; - static constexpr float PT_MAX = 20; - static constexpr float ETA_MAX = 1.5; - static constexpr float ETA_MAX2 = 0.9; - - static constexpr float MIN_WEIGHT_CLS = 40; - static constexpr float FINDABLE_WEIGHT_CLS = 70; - - static constexpr int MC_LABEL_INVALID = -1e9; - - static constexpr bool CLUST_HIST_INT_SUM = false; - - static constexpr const int COLORCOUNT = 12; - Color_t* mColorNums; - - static const constexpr char* EFF_TYPES[4] = {"Rec", "Clone", "Fake", "All"}; - static const constexpr char* FINDABLE_NAMES[2] = {"", "Findable"}; - static const constexpr char* PRIM_NAMES[2] = {"Prim", "Sec"}; - static const constexpr char* PARAMETER_NAMES[5] = {"Y", "Z", "#Phi", "#lambda", "Relative #it{p}_{T}"}; - static const constexpr char* PARAMETER_NAMES_NATIVE[5] = {"Y", "Z", "sin(#Phi)", "tan(#lambda)", "q/#it{p}_{T} (curvature)"}; - static const constexpr char* VSPARAMETER_NAMES[6] = {"Y", "Z", "Phi", "Eta", "Pt", "Pt_log"}; - static const constexpr char* EFF_NAMES[3] = {"Efficiency", "Clone Rate", "Fake Rate"}; - static const constexpr char* EFFICIENCY_TITLES[4] = {"Efficiency (Primary Tracks, Findable)", "Efficiency (Secondary Tracks, Findable)", "Efficiency (Primary Tracks)", "Efficiency (Secondary Tracks)"}; - static const constexpr double SCALE[5] = {10., 10., 1000., 1000., 100.}; - static const constexpr double SCALE_NATIVE[5] = {10., 10., 1000., 1000., 1.}; - static 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})"}; - static 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)"}; - static 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)"}; - static 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)", - "q*(q/#it{p}_{T} - q/#it{p}_{Tmc})/#sigma_{q/#it{p}_{T}} (Pull)"}; - static const constexpr char* CLUSTER_NAMES[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"}; - static const constexpr char* CLUSTER_TITLES[N_CLS_TYPE] = {"Clusters Pt Distribution / Attachment", "Clusters Pt Distribution / Attachment (relative to all clusters)", "Clusters Pt Distribution / Attachment (integrated)"}; - static const constexpr char* CLUSTER_NAMES_SHORT[N_CLS_HIST] = {"Attached", "Fake", "AttachAdjacent", "FakeAdjacent", "FoundTracks", "Physics", "Protected", "All"}; - static const constexpr char* CLUSTER_TYPES[N_CLS_TYPE] = {"", "Ratio", "Integral"}; - static const constexpr int COLORS_HEX[COLORCOUNT] = {0xB03030, 0x00A000, 0x0000C0, 0x9400D3, 0x19BBBF, 0xF25900, 0x7F7F7F, 0xFFD700, 0x07F707, 0x07F7F7, 0xF08080, 0x000000}; - - static const constexpr int CONFIG_DASHED_MARKERS = 0; - - static const constexpr float AXES_MIN[5] = {-Y_MAX, -Z_MAX, 0.f, -ETA_MAX, PT_MIN}; - static const constexpr float AXES_MAX[5] = {Y_MAX, Z_MAX, 2.f * M_PI, ETA_MAX, PT_MAX}; - static const constexpr int AXIS_BINS[5] = {51, 51, 144, 31, 50}; - static const constexpr int RES_AXIS_BINS[] = {1017, 113}; // Consecutive bin sizes, histograms are binned down until the maximum entry is 50, each bin size should evenly divide its predecessor. - static const constexpr float RES_AXES[5] = {1., 1., 0.03, 0.03, 1.0}; - static const constexpr float RES_AXES_NATIVE[5] = {1., 1., 0.1, 0.1, 5.0}; - static const constexpr float PULL_AXIS = 10.f; + std::vector mColorNums; + std::vector mColors; int mMCTrackMin = -1, mMCTrackMax = -1; };