From 9819ff0c407b0bb5de1c1bbce8430f596fc07771 Mon Sep 17 00:00:00 2001 From: Thomas Klemenz Date: Wed, 2 Dec 2020 17:12:35 +0100 Subject: [PATCH 1/3] added a workflow that runs the TrackReader --- Detectors/TPC/workflow/CMakeLists.txt | 5 + .../include/TPCWorkflow/TrackReaderSpec.h | 6 +- .../TPC/workflow/src/TrackReaderWorkflow.cxx | 97 +++++++++++++++++++ 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 720c31d542017..d0d5657797693 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -45,6 +45,11 @@ o2_add_executable(calib-pedestal SOURCES src/tpc-calib-pedestal.cxx PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) +o2_add_executable(track-reader + COMPONENT_NAME tpc + SOURCES src/TrackReaderWorkflow.cxx + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow) + o2_add_test(workflow COMPONENT_NAME tpc LABELS tpc workflow diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h index f9899344a4213..5858ada6e2f93 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TrackReaderSpec.h @@ -53,10 +53,10 @@ class TrackReader : public Task bool mUseMC = true; // use MC truth std::string mInputFileName = "tpctracks.root"; - std::string mTrackTreeName = "events"; - std::string mTrackBranchName = "Tracks"; + std::string mTrackTreeName = "tpcrec"; + std::string mTrackBranchName = "TPCTracks"; std::string mClusRefBranchName = "ClusRefs"; - std::string mTrackMCTruthBranchName = "TracksMCTruth"; + std::string mTrackMCTruthBranchName = "TPCTracksMCTruth"; }; /// create a processor spec diff --git a/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx new file mode 100644 index 0000000000000..07cfed0f9ef65 --- /dev/null +++ b/Detectors/TPC/workflow/src/TrackReaderWorkflow.cxx @@ -0,0 +1,97 @@ +// 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 TrackReaderWorkflow.cxx + +#include "Framework/WorkflowSpec.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DispatchPolicy.h" +#include "Framework/PartRef.h" +#include "Framework/ConcreteDataMatcher.h" +#include "TPCWorkflow/RecoWorkflow.h" +#include "TPCWorkflow/TPCSectorCompletionPolicy.h" +#include "DataFormatsTPC/TPCSectorHeader.h" +#include "Algorithm/RangeTokenizer.h" +#include "CommonUtils/ConfigurableParam.h" + +#include "TPCWorkflow/TrackReaderSpec.h" + +#include +#include +#include +#include + +// we need a global variable to propagate the type the message dispatching of the +// publisher will trigger on. This is dependent on the input type +o2::framework::Output gDispatchTrigger{"", ""}; + +// Global variable used to transport data to the completion policy +o2::tpc::reco_workflow::CompletionPolicyData gPolicyData; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + using namespace o2::framework; + + std::vector options{ + {"input-type", VariantType::String, "tracks", {"tracks"}}, + {"dispatching-mode", VariantType::String, "prompt", {"determines when to dispatch: prompt, complete"}}, + {"disable-mc", VariantType::Bool, false, {"disable sending of MC information"}}}; + + std::swap(workflowOptions, options); +} + +// customize dispatch policy, dispatch immediately what is ready +void customize(std::vector& policies) +{ + using DispatchOp = o2::framework::DispatchPolicy::DispatchOp; + // we customize all devices to dispatch data immediately + auto readerMatcher = [](auto const& spec) { + return std::regex_match(spec.name.begin(), spec.name.end(), std::regex(".*-reader")); + }; + auto triggerMatcher = [](auto const& query) { + // a bit of a hack but we want this to be configurable from the command line, + // however DispatchPolicy is inserted before all other setup. Triggering depending + // on the global variable set from the command line option. If scheduled messages + // are not triggered they are sent out at the end of the computation + return gDispatchTrigger.origin == query.origin && gDispatchTrigger.description == query.description; + }; + policies.push_back({"prompt-for-reader", readerMatcher, DispatchOp::WhenReady, triggerMatcher}); +} + +#include "Framework/runDataProcessing.h" // the main driver + +using namespace o2::framework; + +/// MC info is processed by default, disabled by using command line option `--disable-mc` +/// +/// This function hooks up the the workflow specifications into the DPL driver. +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + WorkflowSpec specs; + + auto inputType = cfgc.options().get("input-type"); + auto dispmode = cfgc.options().get("dispatching-mode"); + if (dispmode == "complete") { + // nothing to do we leave the matcher empty which will suppress the dispatch + // trigger and all messages will be sent out together at end of computation + } else if (inputType == "tracks") { + gDispatchTrigger = o2::framework::Output{"TPC", "TRACKS"}; + } + + bool doMC = not cfgc.options().get("disable-mc"); + + specs.push_back(o2::tpc::getTPCTrackReaderSpec(doMC)); + + return std::move(specs); +} From d8ac9305f92b810c680ce0a1dffbf315efbc7665 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 13 Jan 2021 18:45:58 +0100 Subject: [PATCH 2/3] GPU QA: No need to fill zeroes into histograms --- GPU/GPUTracking/Standalone/qa/GPUQA.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx index a8515dba20504..a4ae866adc20c 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx +++ b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx @@ -1058,6 +1058,9 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } int val = (j == 0) ? (mRecTracks[iCol][i] ? 1 : 0) : (j == 1) ? (mRecTracks[iCol][i] ? mRecTracks[iCol][i] - 1 : 0) : (j == 2) ? mFakeTracks[iCol][i] : 1; + if (val == 0) { + continue; + } for (int l = 0; l < 5; l++) { if (info.prim && mcpt < PT_MIN_PRIM) { From 98742ca2a146db7fce8130097e40ac0c07c03b24 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 13 Jan 2021 21:52:26 +0100 Subject: [PATCH 3/3] GPU QA: Fix reverse MC label table for external track input --- GPU/GPUTracking/Standalone/qa/GPUQA.cxx | 73 +++++++++++++++---------- 1 file changed, 45 insertions(+), 28 deletions(-) diff --git a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx index a4ae866adc20c..ca2f3a92102e3 100644 --- a/GPU/GPUTracking/Standalone/qa/GPUQA.cxx +++ b/GPU/GPUTracking/Standalone/qa/GPUQA.cxx @@ -724,13 +724,15 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx mClNative = clNative; // Initialize Arrays + unsigned int nReconstructedTracks = 0; if (tracksExternal) { #ifdef GPUCA_O2_LIB - mTrackMCLabels.resize(tracksExternal->size()); + nReconstructedTracks = tracksExternal->size(); #endif } else { - mTrackMCLabels.resize(mTracking->mIOPtrs.nMergedTracks); + nReconstructedTracks = mTracking->mIOPtrs.nMergedTracks; } + mTrackMCLabels.resize(nReconstructedTracks); for (unsigned int iCol = 0; iCol < GetNMCCollissions(); iCol++) { mTrackMCLabelsReverse[iCol].resize(GetNMCTracks(iCol)); mRecTracks[iCol].resize(GetNMCTracks(iCol)); @@ -753,7 +755,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx mcEffBuffer.resize(mNEvents); mcLabelBuffer.resize(mNEvents); mcEffBuffer[mNEvents - 1].resize(GetNMCTracks(0)); - mcLabelBuffer[mNEvents - 1].resize(mTracking->mIOPtrs.nMergedTracks); + mcLabelBuffer[mNEvents - 1].resize(nReconstructedTracks); } bool mcAvail = mcPresent() || tracksExtMC; @@ -777,7 +779,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx #if QA_DEBUG == 0 GPUCA_OPENMP(parallel for firstprivate(acc)) #endif - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { + for (unsigned int i = 0; i < nReconstructedTracks; i++) { acc.reset(); int nClusters = 0; const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; @@ -821,29 +823,29 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx GPUInfo("QA Time: Assign Track Labels:\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - if (mQATasks & taskClusterAttach) { - // fill cluster attachment status - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { - const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; - if (!track.OK()) { + for (unsigned int i = 0; i < nReconstructedTracks; i++) { + const GPUTPCGMMergedTrack* track = mTracking ? &mTracking->mIOPtrs.mergedTracks[i] : nullptr; + mcLabelI_t label = mTrackMCLabels[i]; + if (mQATasks & taskClusterAttach) { + // fill cluster attachment status + if (!track->OK()) { continue; } if (!mTrackMCLabels[i].isValid()) { - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + for (unsigned int k = 0; k < track->NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { continue; } - mClusterParam[mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num].fakeAttached++; + mClusterParam[mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].num].fakeAttached++; } continue; } - mcLabelI_t label = mTrackMCLabels[i]; if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { - for (unsigned int k = 0; k < track.NClusters(); k++) { - if (mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { + for (unsigned int k = 0; k < track->NClusters(); k++) { + if (mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].state & GPUTPCGMMergedTrackHit::flagReject) { continue; } - int hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; + int hitId = mTracking->mIOPtrs.mergedTrackHits[track->FirstClusterRef() + k].num; bool correct = false; for (int j = 0; j < GetMCLabelNID(hitId); j++) { if (label == GetMCLabel(hitId, j)) { @@ -858,12 +860,21 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } } - if (mTrackMCLabels[i].isFake()) { - (GetMCTrackObj(mFakeTracks, label))++; - } else if (!track.MergedLooper()) { - GetMCTrackObj(mRecTracks, label)++; - if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { - int& revLabel = GetMCTrackObj(mTrackMCLabelsReverse, label); + } + + if (mTrackMCLabels[i].isFake()) { + (GetMCTrackObj(mFakeTracks, label))++; + } else if (tracksExternal || !track->MergedLooper()) { + GetMCTrackObj(mRecTracks, label)++; + if (mMCTrackMin == -1 || (label.getTrackID() >= mMCTrackMin && label.getTrackID() < mMCTrackMax)) { + int& revLabel = GetMCTrackObj(mTrackMCLabelsReverse, label); + if (tracksExternal) { +#ifdef GPUCA_O2_LIB + if (revLabel == -1 || fabsf((*tracksExternal)[i].getZ()) < fabsf((*tracksExternal)[revLabel].getZ())) { + revLabel = i; + } +#endif + } else { const auto* trks = mTracking->mIOPtrs.mergedTracks; bool comp; if (revLabel == -1) { @@ -881,6 +892,8 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } } + } + if (mQATasks & taskClusterAttach) { // fill cluster adjacent status for (unsigned int i = 0; i < GetNMCLabels(); i++) { if (mClusterParam[i].attached == 0 && mClusterParam[i].fakeAttached == 0) { @@ -905,13 +918,14 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } } + if (mConfig.matchMCLabels.size()) { mGoodHits[mNEvents - 1].resize(GetNMCLabels()); std::vector allowMCLabels(GetNMCTracks(0)); for (unsigned int k = 0; k < GetNMCTracks(0); k++) { allowMCLabels[k] = false; } - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { + for (unsigned int i = 0; i < nReconstructedTracks; i++) { if (!mGoodTracks[mNEvents - 1][i]) { continue; } @@ -1190,9 +1204,12 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx continue; } - auto getdz = [this, ¶m, &mc1, &side]() { + auto getdz = [this, ¶m, &mc1, &side, tracksExternal]() { + if (tracksExternal) { + return param.GetZ(); + } if (!mParam.par.continuousMaxTimeBin) { - return param.Z() - mc1.z; + return param.GetZ() - mc1.z; } #ifdef GPUCA_TPC_GEOMETRY_O2 if (!mParam.par.earlyTpcTransform) { @@ -1259,7 +1276,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (mQATasks & taskClusterAttach) { // Fill cluster histograms - for (unsigned int iTrk = 0; iTrk < mTracking->mIOPtrs.nMergedTracks; iTrk++) { + for (unsigned int iTrk = 0; iTrk < nReconstructedTracks; iTrk++) { const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[iTrk]; if (!track.OK()) { continue; @@ -1489,7 +1506,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (mQATasks & taskTrackStatistics) { // Fill track statistic histograms - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { + for (unsigned int i = 0; i < nReconstructedTracks; i++) { const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; if (!track.OK()) { continue; @@ -1581,7 +1598,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx std::vector clusterInfo(totalNCls); memset(clusterInfo.data(), 0, clusterInfo.size() * sizeof(clusterInfo[0])); - for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { + for (unsigned int i = 0; i < nReconstructedTracks; i++) { const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[i]; if (!track.OK()) { continue;