Project
Loading...
Searching...
No Matches
ClustererSpec.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
16
20#include "Headers/DataHeader.h"
23#include "TPCBase/Sector.h"
27#include <fairlogger/Logger.h>
28#include <memory> // for make_shared
29#include <vector>
30#include <map>
31#include <numeric> // std::accumulate
32#include <algorithm> // std::copy
33
34using namespace o2::framework;
35using namespace o2::header;
36using namespace o2::dataformats;
37
38namespace o2
39{
40namespace tpc
41{
42
46{
47 std::string processorName = "tpc-clusterer";
48
49 constexpr static size_t NSectors = o2::tpc::Sector::MAXSECTOR;
50 struct ProcessAttributes {
51 std::vector<o2::tpc::ClusterHardwareContainer8kb> clusterArray;
52 MCLabelContainer mctruthArray;
53 std::array<std::shared_ptr<o2::tpc::HwClusterer>, NSectors> clusterers;
54 int verbosity = 1;
55 bool sendMC = false;
56 };
57
58 auto initFunction = [sendMC](InitContext& ic) {
59 // FIXME: the clusterer needs to be initialized with the sector number, so we need one
60 // per sector. Taking a closer look to the HwClusterer, the sector number is only used
61 // for calculating the CRU id. This could be achieved by passing the current sector as
62 // parameter to the clusterer processing function.
63 auto processAttributes = std::make_shared<ProcessAttributes>();
64 processAttributes->sendMC = sendMC;
65
66 auto processSectorFunction = [processAttributes](ProcessingContext& pc, DataRef const& dataref, DataRef const& mclabelref) {
67 auto& clusterArray = processAttributes->clusterArray;
68 auto& mctruthArray = processAttributes->mctruthArray;
69 auto& clusterers = processAttributes->clusterers;
70 auto& verbosity = processAttributes->verbosity;
71 auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(dataref);
72 if (sectorHeader == nullptr) {
73 LOG(error) << "sector header missing on header stack";
74 return;
75 }
76 auto const* dataHeader = DataRefUtils::getHeader<o2::header::DataHeader*>(dataref);
77 o2::header::DataHeader::SubSpecificationType fanSpec = dataHeader->subSpecification;
78
79 const auto sector = sectorHeader->sector();
80 if (sector < 0) {
81 // forward the control information
82 // FIXME define and use flags in TPCSectorHeader
83 o2::tpc::TPCSectorHeader header{sector};
84 pc.outputs().snapshot(Output{gDataOriginTPC, "CLUSTERHW", fanSpec, {header}}, fanSpec);
85 if (DataRefUtils::isValid(mclabelref)) {
86 pc.outputs().snapshot(Output{gDataOriginTPC, "CLUSTERHWMCLBL", fanSpec, {header}}, fanSpec);
87 }
88 return;
89 }
91 if (DataRefUtils::isValid(mclabelref)) {
92 inMCLabels = pc.inputs().get<gsl::span<char>>(mclabelref);
93 }
94 auto inDigits = pc.inputs().get<gsl::span<o2::tpc::Digit>>(dataref);
95 if (verbosity > 0 && inMCLabels.getBuffer().size()) {
96 LOG(info) << "received " << inDigits.size() << " digits, "
97 << inMCLabels.getIndexedSize() << " MC label objects"
98 << " input MC label size " << DataRefUtils::getPayloadSize(mclabelref);
99 }
100 if (!clusterers[sector]) {
101 // create the clusterer for this sector, take the same target arrays for all clusterers
102 // as they are not invoked in parallel
103 // the cost of creating the clusterer should be small so we do it in the processing
104 clusterers[sector] = std::make_shared<o2::tpc::HwClusterer>(&clusterArray, sector, &mctruthArray);
105 clusterers[sector]->init();
106 }
107 auto& clusterer = clusterers[sector];
108
109 if (verbosity > 0) {
110 LOG(info) << "processing " << inDigits.size() << " digit object(s) of sector " << sectorHeader->sector()
111 << " input size " << DataRefUtils::getPayloadSize(dataref);
112 }
113 // process the digits and MC labels, the bool parameter controls whether to clear all
114 // internal data or not. Have to clear it inside the process method as not only the containers
115 // are cleared but also the cluster counter. Clearing the containers externally leaves the
116 // cluster counter unchanged and leads to an inconsistency between cluster container and
117 // MC label container (the latter just grows with every call).
118 clusterer->process(inDigits, inMCLabels, true /* clear output containers and cluster counter */);
119 const std::vector<o2::tpc::Digit> emptyDigits;
120 ConstMCLabelContainerView emptyLabels;
121 clusterer->finishProcess(emptyDigits, emptyLabels, false); // keep here the false, otherwise the clusters are lost of they are not stored in the meantime
122 if (verbosity > 0) {
123 LOG(info) << "clusterer produced "
124 << std::accumulate(clusterArray.begin(), clusterArray.end(), size_t(0), [](size_t l, auto const& r) { return l + r.getContainer()->numberOfClusters; })
125 << " cluster(s)"
126 << " for sector " << sectorHeader->sector()
127 << " total size " << sizeof(ClusterHardwareContainer8kb) * clusterArray.size();
128 if (DataRefUtils::isValid(mclabelref)) {
129 LOG(info) << "clusterer produced " << mctruthArray.getIndexedSize() << " MC label object(s) for sector " << sectorHeader->sector();
130 }
131 }
132 // FIXME: that should be a case for pmr, want to send the content of the vector as a binary
133 // block by using move semantics
134 auto outputPages = pc.outputs().make<ClusterHardwareContainer8kb>(Output{gDataOriginTPC, "CLUSTERHW", fanSpec, {*sectorHeader}}, clusterArray.size());
135 std::copy(clusterArray.begin(), clusterArray.end(), outputPages.begin());
136 if (DataRefUtils::isValid(mclabelref)) {
138 mctruthArray.flatten_to(mcflat);
139 pc.outputs().snapshot(Output{gDataOriginTPC, "CLUSTERHWMCLBL", fanSpec, {*sectorHeader}}, mcflat);
140 }
141 };
142
143 auto processingFct = [processAttributes, processSectorFunction](ProcessingContext& pc) {
144 struct SectorInputDesc {
145 DataRef dataref;
146 DataRef mclabelref;
147 };
148 // loop over all inputs and their parts and associate data with corresponding mc truth data
149 // by the subspecification
150 std::map<int, SectorInputDesc> inputs;
151 std::vector<InputSpec> filter = {
152 {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}, Lifetime::Timeframe},
153 {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}, Lifetime::Timeframe},
154 };
155 for (auto const& inputRef : InputRecordWalker(pc.inputs())) {
156 auto const* sectorHeader = DataRefUtils::getHeader<o2::tpc::TPCSectorHeader*>(inputRef);
157 if (sectorHeader == nullptr) {
158 LOG(error) << "sector header missing on header stack for input on " << inputRef.spec->binding;
159 continue;
160 }
161 const int sector = sectorHeader->sector();
162 if (DataRefUtils::match(inputRef, {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITS"}})) {
163 inputs[sector].dataref = inputRef;
164 }
165 if (DataRefUtils::match(inputRef, {"check", ConcreteDataTypeMatcher{gDataOriginTPC, "DIGITSMCTR"}})) {
166 inputs[sector].mclabelref = inputRef;
167 }
168 }
169 for (auto const& input : inputs) {
170 if (processAttributes->sendMC && !DataRefUtils::isValid(input.second.mclabelref)) {
171 throw std::runtime_error("missing the required MC label data for sector " + std::to_string(input.first));
172 }
173 processSectorFunction(pc, input.second.dataref, input.second.mclabelref);
174 }
175 };
176 return processingFct;
177 };
178
179 auto createInputSpecs = [](bool makeMcInput) {
180 std::vector<InputSpec> inputSpecs{
181 InputSpec{"digits", gDataOriginTPC, "DIGITS", 0, Lifetime::Timeframe},
182 };
183 if (makeMcInput) {
184 constexpr o2::header::DataDescription datadesc("DIGITSMCTR");
185 inputSpecs.emplace_back("mclabels", gDataOriginTPC, datadesc, 0, Lifetime::Timeframe);
186 }
187 return std::move(inputSpecs);
188 };
189
190 auto createOutputSpecs = [](bool makeMcOutput) {
191 std::vector<OutputSpec> outputSpecs{
192 OutputSpec{{"clusters"}, gDataOriginTPC, "CLUSTERHW", 0, Lifetime::Timeframe},
193 };
194 if (makeMcOutput) {
195 OutputLabel label{"clusterlbl"};
196 // FIXME: define common data type specifiers
197 constexpr o2::header::DataDescription datadesc("CLUSTERHWMCLBL");
198 outputSpecs.emplace_back(label, gDataOriginTPC, datadesc, 0, Lifetime::Timeframe);
199 }
200 return std::move(outputSpecs);
201 };
202
203 return DataProcessorSpec{processorName,
204 {createInputSpecs(sendMC)},
205 {createOutputSpecs(sendMC)},
206 AlgorithmSpec(initFunction)};
207}
208
209} // namespace tpc
210} // namespace o2
#define verbosity
Definition of the TPC Digit.
Class for TPC HW cluster finding.
A helper class to iteratate over all parts of all input routes.
Definition of a container to keep Monte Carlo truth external to simulation objects.
spec definition for a TPC clusterer process
const gsl::span< const char > & getBuffer() const
void snapshot(const Output &spec, T const &object)
decltype(auto) make(const Output &spec, Args... args)
A helper class to iteratate over all parts of all input routes.
decltype(auto) get(R binding, int part=0) const
DataAllocator & outputs()
The data allocator is used to allocate memory for the output data.
InputRecord & inputs()
The inputs associated with this processing context.
static constexpr int MAXSECTOR
Definition Sector.h:44
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLboolean r
Definition glcorearb.h:1233
constexpr o2::header::DataOrigin gDataOriginTPC
Definition DataHeader.h:576
Definition of a container to keep/associate and arbitrary number of labels associated to an index wit...
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
O2 data header classes and API, v0.1.
Definition DetID.h:49
framework::DataProcessorSpec getClustererSpec(bool sendMC)
ClusterHardwareContainerFixedSize< 8192 > ClusterHardwareContainer8kb
Definition Helpers.h:58
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
static o2::header::DataHeader::PayloadSizeType getPayloadSize(const DataRef &ref)
static bool match(DataRef const &ref, const char *binding)
static bool isValid(DataRef const &ref)
uint32_t SubSpecificationType
Definition DataHeader.h:620
static int constexpr size
Definition DataHeader.h:211
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"