Skip to content

Commit ef6ad97

Browse files
authored
added TPC QC cluster workflow (#449)
1 parent 6586367 commit ef6ad97

5 files changed

Lines changed: 359 additions & 1 deletion

File tree

Modules/TPC/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ target_sources(QcTPC PRIVATE src/PID.cxx
66
src/Tracks.cxx
77
src/PIDClusterCheck.cxx
88
src/TrackClusterCheck.cxx
9-
src/ROCReductor.cxx)
9+
src/ROCReductor.cxx
10+
src/Clusters.cxx)
1011

1112
target_include_directories(
1213
QcTPC
@@ -27,6 +28,7 @@ add_root_dictionary(QcTPC
2728
include/TPC/PIDClusterCheck.h
2829
include/TPC/TrackClusterCheck.h
2930
include/TPC/ROCReductor.h
31+
include/TPC/Clusters.h
3032
LINKDEF include/TPC/LinkDef.h
3133
BASENAME QcTPC)
3234

@@ -79,4 +81,5 @@ install(FILES run/tpcQCPID_sampled.json
7981
run/tpcQCClusterChecker.json
8082
run/tpcQCSimpleTrending.json
8183
run/tpcQCTrendingClusters.json
84+
run/tpcQCClusters_direct.json
8285
DESTINATION etc)

Modules/TPC/include/TPC/Clusters.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
///
12+
/// \file Clusters.h
13+
/// \author Jens Wiechula
14+
/// \author Thomas Klemenz
15+
///
16+
17+
#ifndef QC_MODULE_TPC_CLUSTERS_H
18+
#define QC_MODULE_TPC_CLUSTERS_H
19+
20+
// O2 includes
21+
#include "TPCQC/Clusters.h"
22+
#include "TPCQC/CalPadWrapper.h"
23+
24+
// QC includes
25+
#include "QualityControl/TaskInterface.h"
26+
27+
#include "TH2F.h"
28+
29+
using namespace o2::quality_control::core;
30+
31+
namespace o2::quality_control_modules::tpc
32+
{
33+
34+
/// \brief Example Quality Control DPL Task
35+
/// It is final because there is no reason to derive from it. Just remove it if needed.
36+
/// \author Barthelemy von Haller
37+
/// \author Piotr Konopka
38+
class Clusters /*final*/ : public TaskInterface // todo add back the "final" when doxygen is fixed
39+
{
40+
public:
41+
/// \brief Constructor
42+
Clusters();
43+
/// Destructor
44+
~Clusters() override;
45+
46+
// Definition of the methods for the template method pattern
47+
void initialize(o2::framework::InitContext& ctx) override;
48+
void startOfActivity(Activity& activity) override;
49+
void startOfCycle() override;
50+
void monitorData(o2::framework::ProcessingContext& ctx) override;
51+
void endOfCycle() override;
52+
void endOfActivity(Activity& activity) override;
53+
void reset() override;
54+
55+
private:
56+
o2::tpc::qc::Clusters mQCClusters{}; ///< O2 Cluster task to perform actions on cluster objects
57+
std::vector<std::unique_ptr<TH2F>> mHistoVector{}; ///< vector holding TH2F showing average Cluster properties; published on QCG
58+
std::vector<o2::tpc::qc::CalPadWrapper> mWrapperVector{}; ///< vector holding CalPad objects wrapped as TObjects; published on QCG; will be non-wrapped CalPad objects in the future
59+
};
60+
61+
} // namespace o2::quality_control_modules::tpc
62+
63+
#endif // QC_MODULE_TPC_CLUSTERS_H

Modules/TPC/include/TPC/LinkDef.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
#pragma link C++ class o2::quality_control_modules::tpc::PIDClusterCheck+;
99
#pragma link C++ class o2::quality_control_modules::tpc::TrackClusterCheck+;
1010
#pragma link C++ class o2::quality_control_modules::tpc::ROCReductor+;
11+
#pragma link C++ class o2::quality_control_modules::tpc::Clusters+;
1112
#endif
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"qc": {
3+
"config": {
4+
"database": {
5+
"implementation": "CCDB",
6+
"host": "ccdb-test.cern.ch:8080",
7+
"username": "not_applicable",
8+
"password": "not_applicable",
9+
"name": "not_applicable"
10+
},
11+
"Activity": {
12+
"number": "42",
13+
"type": "2"
14+
},
15+
"monitoring": {
16+
"url": "infologger:///debug?qc"
17+
},
18+
"consul": {
19+
"url": "http://consul-test.cern.ch:8500"
20+
},
21+
"conditionDB": {
22+
"url": "ccdb-test.cern.ch:8080"
23+
}
24+
},
25+
"tasks": {
26+
"Clusters": {
27+
"active": "true",
28+
"className": "o2::quality_control_modules::tpc::Clusters",
29+
"moduleName": "QcTPC",
30+
"detectorName": "TPC",
31+
"cycleDurationSeconds": "10",
32+
"maxNumberCycles": "-1",
33+
"dataSource": {
34+
"type": "direct",
35+
"query" : "input0:TPC/CLUSTERNATIVE/0;input1:TPC/CLUSTERNATIVE/1;input2:TPC/CLUSTERNATIVE/2;input3:TPC/CLUSTERNATIVE/3;input4:TPC/CLUSTERNATIVE/4;input5:TPC/CLUSTERNATIVE/5;input6:TPC/CLUSTERNATIVE/6;input7:TPC/CLUSTERNATIVE/7;input8:TPC/CLUSTERNATIVE/8;input9:TPC/CLUSTERNATIVE/9;input10:TPC/CLUSTERNATIVE/10;input11:TPC/CLUSTERNATIVE/11;input12:TPC/CLUSTERNATIVE/12;input13:TPC/CLUSTERNATIVE/13;input14:TPC/CLUSTERNATIVE/14;input15:TPC/CLUSTERNATIVE/15;input16:TPC/CLUSTERNATIVE/16;input17:TPC/CLUSTERNATIVE/17;input18:TPC/CLUSTERNATIVE/18;input19:TPC/CLUSTERNATIVE/19;input20:TPC/CLUSTERNATIVE/20;input21:TPC/CLUSTERNATIVE/21;input22:TPC/CLUSTERNATIVE/22;input23:TPC/CLUSTERNATIVE/23;input24:TPC/CLUSTERNATIVE/24;input25:TPC/CLUSTERNATIVE/25;input26:TPC/CLUSTERNATIVE/26;input27:TPC/CLUSTERNATIVE/27;input28:TPC/CLUSTERNATIVE/28;input29:TPC/CLUSTERNATIVE/29;input30:TPC/CLUSTERNATIVE/30;input31:TPC/CLUSTERNATIVE/31;input32:TPC/CLUSTERNATIVE/32;input33:TPC/CLUSTERNATIVE/33;input34:TPC/CLUSTERNATIVE/34;input35:TPC/CLUSTERNATIVE/35"
36+
},
37+
"taskParameters": {
38+
"myOwnKey": "myOwnValue"
39+
},
40+
"location": "remote"
41+
}
42+
},
43+
"checks": {
44+
"QcCheck": {
45+
"active": "true",
46+
"className": "o2::quality_control_modules::skeleton::SkeletonCheck",
47+
"moduleName": "QcSkeleton",
48+
"policy": "OnAny",
49+
"detectorName": "TPC",
50+
"dataSource": [{
51+
"type": "Task",
52+
"name": "Clusters",
53+
"MOs": ["example"]
54+
}]
55+
}
56+
}
57+
},
58+
"dataSamplingPolicies": [
59+
]
60+
}

Modules/TPC/src/Clusters.cxx

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
///
12+
/// \file Clusters.cxx
13+
/// \author Thomas Klemenz
14+
///
15+
16+
#include "Framework/PartRef.h"
17+
#include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs
18+
#include "Framework/DataRefUtils.h"
19+
#include "Framework/DataSpecUtils.h"
20+
#include "Framework/ControlService.h"
21+
#include "Framework/ConfigParamRegistry.h"
22+
#include "Framework/InputRecordWalker.h"
23+
#include "DataFormatsTPC/TPCSectorHeader.h"
24+
25+
#include <bitset>
26+
27+
using namespace o2::framework;
28+
using namespace o2::header;
29+
using namespace o2::tpc;
30+
31+
// root includes
32+
#include <TCanvas.h>
33+
#include <TH1.h>
34+
#include <TH2.h>
35+
36+
// O2 includes
37+
#include "Framework/ProcessingContext.h"
38+
#include "DataFormatsTPC/Defs.h"
39+
//#include "TPCQC/Helpers.h"
40+
#include "TPCBase/Painter.h"
41+
#include "DataFormatsTPC/ClusterNative.h"
42+
#include "DataFormatsTPC/ClusterNativeHelper.h"
43+
#include "SimulationDataFormat/MCTruthContainer.h"
44+
#include "DataFormatsTPC/Constants.h"
45+
46+
// QC includes
47+
#include "QualityControl/QcInfoLogger.h"
48+
#include "TPC/Clusters.h"
49+
50+
namespace o2::quality_control_modules::tpc
51+
{
52+
53+
Clusters::Clusters() : TaskInterface()
54+
{
55+
mWrapperVector.emplace_back(&mQCClusters.getNClusters());
56+
mWrapperVector.emplace_back(&mQCClusters.getQMax());
57+
mWrapperVector.emplace_back(&mQCClusters.getQTot());
58+
mWrapperVector.emplace_back(&mQCClusters.getSigmaTime());
59+
mWrapperVector.emplace_back(&mQCClusters.getSigmaPad());
60+
mWrapperVector.emplace_back(&mQCClusters.getTimeBin());
61+
}
62+
63+
Clusters::~Clusters()
64+
{
65+
}
66+
67+
void Clusters::initialize(o2::framework::InitContext& /*ctx*/)
68+
{
69+
QcInfoLogger::GetInstance() << "initialize TPC Clusters QC task" << AliceO2::InfoLogger::InfoLogger::endm;
70+
71+
o2::tpc::Side ASide{ o2::tpc::Side::A };
72+
o2::tpc::Side CSide{ o2::tpc::Side::C };
73+
74+
auto clusAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getNClusters(), ASide));
75+
auto clusCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getNClusters(), CSide));
76+
auto qMaxAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getQMax(), ASide));
77+
auto qMaxCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getQMax(), CSide));
78+
auto qTotAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getQTot(), ASide));
79+
auto qTotCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getQTot(), CSide));
80+
auto sigmaTimeAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getSigmaTime(), ASide));
81+
auto sigmaTimeCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getSigmaTime(), CSide));
82+
auto sigmaPadAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getSigmaPad(), ASide));
83+
auto sigmaPadCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getSigmaPad(), CSide));
84+
auto timeBinAHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getTimeBin(), ASide));
85+
auto timeBinCHisto = static_cast<TH2F*>(o2::tpc::painter::getHistogram2D(mQCClusters.getTimeBin(), CSide));
86+
87+
mHistoVector.emplace_back(clusAHisto);
88+
mHistoVector.emplace_back(clusCHisto);
89+
mHistoVector.emplace_back(qMaxAHisto);
90+
mHistoVector.emplace_back(qMaxCHisto);
91+
mHistoVector.emplace_back(qTotAHisto);
92+
mHistoVector.emplace_back(qTotCHisto);
93+
mHistoVector.emplace_back(sigmaTimeAHisto);
94+
mHistoVector.emplace_back(sigmaTimeCHisto);
95+
mHistoVector.emplace_back(sigmaPadAHisto);
96+
mHistoVector.emplace_back(sigmaPadCHisto);
97+
mHistoVector.emplace_back(timeBinAHisto);
98+
mHistoVector.emplace_back(timeBinCHisto);
99+
100+
for (auto& histPtr : mHistoVector) {
101+
auto hist = histPtr.get();
102+
getObjectsManager()->startPublishing(hist);
103+
getObjectsManager()->addMetadata(hist->GetName(), "custom", "34");
104+
}
105+
106+
for (auto& wrapper : mWrapperVector) {
107+
getObjectsManager()->startPublishing(&wrapper);
108+
getObjectsManager()->addMetadata(wrapper.getObj()->getName().data(), "custom", "87");
109+
}
110+
}
111+
112+
void Clusters::startOfActivity(Activity& /*activity*/)
113+
{
114+
QcInfoLogger::GetInstance() << "startOfActivity" << AliceO2::InfoLogger::InfoLogger::endm;
115+
}
116+
117+
void Clusters::startOfCycle()
118+
{
119+
QcInfoLogger::GetInstance() << "startOfCyclesdfs" << AliceO2::InfoLogger::InfoLogger::endm;
120+
}
121+
122+
void Clusters::monitorData(o2::framework::ProcessingContext& ctx)
123+
{
124+
125+
o2::tpc::Side ASide{ o2::tpc::Side::A };
126+
o2::tpc::Side CSide{ o2::tpc::Side::C };
127+
128+
constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
129+
130+
std::vector<decltype(std::declval<InputRecord>().get<MCLabelContainer*>(DataRef{ nullptr, nullptr, nullptr }))> mcInputs;
131+
std::vector<gsl::span<const char>> inputs;
132+
struct InputRef {
133+
DataRef data;
134+
DataRef labels;
135+
};
136+
std::map<int, InputRef> inputrefs;
137+
138+
std::bitset<NSectors> validInputs = 0;
139+
140+
int operation = 0;
141+
std::vector<int> inputIds(36);
142+
std::iota(inputIds.begin(), inputIds.end(), 0);
143+
std::vector<InputSpec> filter = {
144+
{ "check", ConcreteDataTypeMatcher{ gDataOriginTPC, "CLUSTERNATIVE" }, Lifetime::Timeframe },
145+
};
146+
for (auto const& ref : InputRecordWalker(ctx.inputs(), filter)) {
147+
auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(ref);
148+
if (sectorHeader == nullptr) {
149+
// FIXME: think about error policy
150+
LOG(ERROR) << "sector header missing on header stack";
151+
return;
152+
}
153+
const int sector = sectorHeader->sector();
154+
std::bitset<o2::tpc::Constants::MAXSECTOR> sectorMask(sectorHeader->sectorBits);
155+
LOG(INFO) << "Reading TPC cluster data, sector mask is " << sectorMask;
156+
157+
if (sector < 0) {
158+
if (operation < 0 && operation != sector) {
159+
// we expect the same operation on all inputs
160+
LOG(ERROR) << "inconsistent lane operation, got " << sector << ", expecting " << operation;
161+
} else if (operation == 0) {
162+
// store the operation
163+
operation = sector;
164+
}
165+
continue;
166+
}
167+
if ((validInputs & sectorMask).any()) {
168+
// have already data for this sector, this should not happen in the current
169+
// sequential implementation, for parallel path merged at the tracker stage
170+
// multiple buffers need to be handled
171+
throw std::runtime_error("can only have one cluster data set per sector");
172+
}
173+
validInputs |= sectorMask;
174+
inputrefs[sector].data = ref;
175+
}
176+
for (auto const& refentry : inputrefs) {
177+
//auto& sector = refentry.first;
178+
auto& ref = refentry.second.data;
179+
inputs.emplace_back(gsl::span(ref.payload, DataRefUtils::getPayloadSize(ref)));
180+
}
181+
182+
ClusterNativeAccess clusterIndex;
183+
std::unique_ptr<ClusterNative[]> clusterBuffer;
184+
MCLabelContainer clustersMCBuffer;
185+
memset(&clusterIndex, 0, sizeof(clusterIndex));
186+
ClusterNativeHelper::Reader::fillIndex(clusterIndex, clusterBuffer, clustersMCBuffer,
187+
inputs, mcInputs, [&validInputs](auto& index) { return validInputs.test(index); });
188+
189+
for (int isector = 0; isector < o2::tpc::Constants::MAXSECTOR; ++isector) {
190+
for (int irow = 0; irow < o2::tpc::Constants::MAXGLOBALPADROW; ++irow) {
191+
const int nClusters = clusterIndex.nClusters[isector][irow];
192+
for (int icl = 0; icl < nClusters; ++icl) {
193+
const auto& cl = *(clusterIndex.clusters[isector][irow] + icl);
194+
mQCClusters.processCluster(cl, o2::tpc::Sector(isector), irow);
195+
}
196+
}
197+
}
198+
199+
mQCClusters.analyse();
200+
201+
int histIter = 0;
202+
for (auto& calPadWrapper : mWrapperVector) {
203+
auto& histA = *mHistoVector[histIter].get();
204+
auto& histC = *mHistoVector[histIter + 1].get();
205+
const auto& calPad = calPadWrapper.getObj();
206+
207+
o2::tpc::painter::fillHistogram2D(histA, *calPad, ASide);
208+
o2::tpc::painter::fillHistogram2D(histC, *calPad, CSide);
209+
210+
histIter += 2;
211+
}
212+
}
213+
214+
void Clusters::endOfCycle()
215+
{
216+
QcInfoLogger::GetInstance() << "endOfCycle" << AliceO2::InfoLogger::InfoLogger::endm;
217+
}
218+
219+
void Clusters::endOfActivity(Activity& /*activity*/)
220+
{
221+
QcInfoLogger::GetInstance() << "endOfActivity" << AliceO2::InfoLogger::InfoLogger::endm;
222+
}
223+
224+
void Clusters::reset()
225+
{
226+
// clean all the monitor objects here
227+
228+
QcInfoLogger::GetInstance() << "Resetting the histogram" << AliceO2::InfoLogger::InfoLogger::endm;
229+
}
230+
231+
} // namespace o2::quality_control_modules::tpc

0 commit comments

Comments
 (0)