Skip to content

Commit e7aa961

Browse files
Bugfix: clear the output containers for the TPC HwClusterer consistently
Have to clear the output containers inside the process method as not only the containers are cleared but also the cluster counter. Clearing the containers externally leaves the cluster counter unchanged and leads to an inconsistency between cluster container and MC label container (the latter just grows with every call). This is probably a bug of the TPC HwClusterer. Also implementing: - some minor changes on the logging output. - boundary check for MC label object processing in the decoder
1 parent 8e0941a commit e7aa961

File tree

3 files changed

+32
-10
lines changed

3 files changed

+32
-10
lines changed

Detectors/TPC/workflow/src/ClusterConverterSpec.cxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,17 @@ DataProcessorSpec getClusterConverterSpec(bool sendMC, int fanNumber)
8888
// this will return a span of TPC clusters
8989
auto inClusters = pc.inputs().get<std::vector<o2::TPC::Cluster>>("clusterin");
9090
int nClusters = inClusters.size();
91-
LOG(INFO) << "got clusters from input: " << nClusters;
9291

9392
// MC labels are received as one container of labels in the sequence matching clusters
9493
// in the input
9594
std::unique_ptr<const MCLabelContainer> mcin;
9695
MCLabelContainer mcout;
96+
std::string mcMesssage;
9797
if (sendMC) {
9898
mcin = std::move(pc.inputs().get<MCLabelContainer*>("mclblin"));
99+
mcMesssage = ", " + std::to_string(mcin->getIndexedSize()) + " MC label objects";
99100
}
101+
LOG(INFO) << "got " << nClusters << " cluster(s) from input" << mcMesssage;
100102

101103
// clusters need to be sorted to write clusters of one CRU to raw pages
102104
struct ClusterMapper {

Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <cassert>
2929
#include <iomanip>
3030
#include <string>
31+
#include <numeric>
3132

3233
using namespace o2::framework;
3334
using namespace o2::header;
@@ -123,6 +124,7 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC, int fanNumber)
123124
// only for single 8kb pages. So we have to add the raw pages individually and create
124125
// MC label containers for the corresponding clusters.
125126
size_t mcinPos = 0;
127+
size_t totalNumberOfClusters = 0;
126128
for (size_t page = 0; page < nPages; page++) {
127129
inputList.emplace_back(reinterpret_cast<const ClusterHardwareContainer*>(ref.payload + page * 8192), 1);
128130
const ClusterHardwareContainer& container = *(inputList.back().first);
@@ -131,15 +133,24 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC, int fanNumber)
131133
<< "CRU " << std::setw(3) << container.CRU << " " //
132134
<< std::setw(3) << container.numberOfClusters << " cluster(s)"; //
133135
}
136+
totalNumberOfClusters += container.numberOfClusters;
134137
if (mcin) {
135-
for (size_t mccopyPos = 0; mccopyPos < container.numberOfClusters; mccopyPos++, mcinPos++) {
138+
for (size_t mccopyPos = 0;
139+
mccopyPos < container.numberOfClusters && mcinPos < mcin->getIndexedSize();
140+
mccopyPos++, mcinPos++) {
136141
for (auto const& label : mcin->getLabels(mcinPos)) {
137142
mcinCopies[page].addElement(mccopyPos, label);
138143
}
139144
}
140145
}
141146
}
142-
assert(!mcin || mcinPos == mcin->getIndexedSize());
147+
// FIXME: introduce error handling policy: throw, ignore, warn
148+
//assert(!mcin || mcinPos == mcin->getIndexedSize());
149+
if (mcin && mcinPos != totalNumberOfClusters) {
150+
LOG(ERROR) << "inconsistent number of MC label objects processed"
151+
<< ", expecting MC label objects for " << totalNumberOfClusters << " cluster(s)"
152+
<< ", got " << mcin->getIndexedSize();
153+
}
143154
// output of the decoder is sorted in (sector,globalPadRow) coordinates, individual
144155
// containers are created for clusters and MC labels per (sector,globalPadRow) address
145156
std::vector<ClusterNativeContainer> cont;
@@ -160,7 +171,7 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC, int fanNumber)
160171
auto* target = pc.outputs().newChunk(OutputRef{ "clusterout", fanSpec, std::move(rawHeaderStack) }, totalSize).data;
161172

162173
for (const auto& coll : cont) {
163-
if (verbosity > 0) {
174+
if (verbosity > 1) {
164175
LOG(INFO) << "decoder " << std::setw(2) << sectorHeader->sector //
165176
<< ": decoded " << std::setw(4) << coll.clusters.size() << " clusters on sector " //
166177
<< std::setw(2) << (int)coll.sector << "[" << (int)coll.globalPadRow << "]"; //
@@ -173,7 +184,9 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC, int fanNumber)
173184
}
174185
if (sendMC) {
175186
if (verbosity > 0) {
176-
LOG(INFO) << "sending " << mcoutList.size() << " MC label containers" << std::endl;
187+
LOG(INFO) << "sending " << mcoutList.size() << " MC label container(s) with in total "
188+
<< std::accumulate(mcoutList.begin(), mcoutList.end(), size_t(0), [](size_t l, auto const& r) { return l + r.getIndexedSize(); })
189+
<< " label object(s)" << std::endl;
177190
}
178191
// serialize the complete list of MC label containers
179192
pc.outputs().snapshot(OutputRef{ "mclblout", fanSpec, std::move(mcHeaderStack) }, mcoutList);

Detectors/TPC/workflow/src/ClustererSpec.cxx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ DataProcessorSpec getClustererSpec(bool sendMC, int fanNumber)
9090
auto inMCLabels = pc.inputs().get<const MCLabelContainer*>("mclabels");
9191
auto inDigits = pc.inputs().get<const std::vector<o2::TPC::Digit>>("digits");
9292
if (verbosity > 0) {
93-
LOG(INFO) << "received " << inDigits.size() << " digits";
93+
LOG(INFO) << "received " << inDigits.size() << " digits, "
94+
<< inMCLabels->getIndexedSize() << " MC label objects";
9495
}
9596
if (!clusterers[sector]) {
9697
// create the clusterer for this sector, take the same target arrays for all clusterers
@@ -103,13 +104,19 @@ DataProcessorSpec getClustererSpec(bool sendMC, int fanNumber)
103104
if (verbosity > 0) {
104105
LOG(INFO) << "processing " << inDigits.size() << " digit object(s) of sector " << sectorHeader->sector;
105106
}
106-
clusterArray.clear(); // this would also be done in the HwClusterer if the clearContainerFirst of process() would be set to true instead of false
107-
mctruthArray.clear(); // this would also be done in the HwClusterer if the clearContainerFirst of process() would be set to true instead of false
108-
clusterer->process(inDigits, inMCLabels.get(), false);
107+
// process the digits and MC labels, the bool parameter controls whether to clear all
108+
// internal data or not. Have to clear it inside the process method as not only the containers
109+
// are cleared but also the cluster counter. Clearing the containers externally leaves the
110+
// cluster counter unchanged and leads to an inconsistency between cluster container and
111+
// MC label container (the latter just grows with every call).
112+
clusterer->process(inDigits, inMCLabels.get(), true /* clear output containers and cluster counter */);
109113
const std::vector<o2::TPC::Digit> emptyDigits;
110114
clusterer->finishProcess(emptyDigits, nullptr, false); // keep here the false, otherwise the clusters are lost of they are not stored in the meantime
111115
if (verbosity > 0) {
112-
LOG(INFO) << "clusterer produced " << clusterArray.size() << " cluster container";
116+
LOG(INFO) << "clusterer produced " << clusterArray.size() << " cluster(s)";
117+
if (sendMC) {
118+
LOG(INFO) << "clusterer produced " << mctruthArray.getIndexedSize() << " MC label object(s)";
119+
}
113120
}
114121
pc.outputs().snapshot(OutputRef{ "clusters", fanSpec, { *sectorHeader } }, clusterArray);
115122
if (sendMC) {

0 commit comments

Comments
 (0)