Project
Loading...
Searching...
No Matches
ClusterNativeHelper.h
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
17#ifndef CLUSTERNATIVEHELPER_H
18#define CLUSTERNATIVEHELPER_H
19
26#include <gsl/gsl>
27#include <TFile.h>
28#include <TTree.h>
29#include <array>
30#include <vector>
31#include <string>
32#include <tuple> //std::tuple_size
33#include <type_traits>
34
35namespace o2
36{
37namespace tpc
38{
39
50
51 size_t getFlatSize() const { return sizeof(attribute_type) + clusters.size() * sizeof(value_type); }
52
53 const value_type* data() const { return clusters.data(); }
54
55 value_type* data() { return clusters.data(); }
56
57 std::vector<ClusterNative> clusters;
58};
59
71
72 size_t getFlatSize() const { return sizeof(attribute_type) + nClusters * sizeof(value_type); }
73
74 const value_type* data() const { return clusters; }
75
76 value_type* data() { return clusters; }
77
79};
80
81// @struct ClusterCountIndex
82// Index of cluster counts per {sector,padrow} for the full TPC
83//
84// This is the header for the transport format of TPC ClusterNative data,
85// followed by a linear buffer of clusters.
89
90// @struct ClusterCountIndex
91// Index of cluster counts per {sector,padrow} coordinate
92// TODO: remove or merge with the above
93struct alignas(64) ClusterIndexBuffer {
95
97
98 size_t getNClusters() const
99 {
100 size_t count = 0;
101 for (auto sector = 0; sector < constants::MAXSECTOR; sector++) {
102 for (auto row = 0; row < constants::MAXGLOBALPADROW; row++) {
103 count += nClusters[sector][row];
104 }
105 }
106 return count;
107 }
108
109 size_t getFlatSize() const { return sizeof(this) + getNClusters() * sizeof(value_type); }
110
111 const value_type* data() const { return clusters; }
112
113 value_type* data() { return clusters; }
114
116};
117
135{
136 public:
141
144
145 constexpr static unsigned int NSectors = constants::MAXSECTOR;
146 constexpr static unsigned int NPadRows = constants::MAXGLOBALPADROW;
147
150 static void convert(const char* fromFile, const char* toFile, const char* toTreeName = "tpcnative");
151
152 // Helper function to create a ClusterNativeAccess structure from a std::vector of ClusterNative containers
153 // This is not contained in the ClusterNative class itself to reduce the dependencies of the class
154 static std::unique_ptr<ClusterNativeAccess> createClusterNativeIndex(
155 std::unique_ptr<ClusterNative[]>& buffer, std::vector<ClusterNativeContainer>& clusters,
156 MCLabelContainer* bufferMC = nullptr,
157 std::vector<MCLabelContainer>* mcTruth = nullptr);
158
159 // add clusters from a flattened buffer starting with an attribute, e.g. ClusterGroupAttribute followed
160 // by the array of ClusterNative, the number of clusters is determined from the size of the buffer
161 // FIXME: add mc labels
162 template <typename AttributeT>
163 static int addFlatBuffer(ClusterNativeAccess& clusterIndex, unsigned char* buffer, size_t size)
164 {
165 if (buffer == nullptr || size < sizeof(AttributeT) || (size - sizeof(AttributeT)) % sizeof(ClusterNative) != 0) {
166 // this is not a valid message, incompatible size
167 return -1;
168 }
169 const auto& groupAttribute = *reinterpret_cast<AttributeT*>(buffer);
170 auto nofClusters = (size - sizeof(AttributeT)) / sizeof(ClusterNative);
171 auto ptrClusters = reinterpret_cast<ClusterNative*>(buffer + sizeof(groupAttribute));
172 clusterIndex.clusters[groupAttribute.sector][groupAttribute.globalPadRow] = ptrClusters;
173 clusterIndex.nClusters[groupAttribute.sector][groupAttribute.globalPadRow] = nofClusters;
174 return nofClusters;
175 }
176
180 class Reader
181 {
182 public:
183 Reader();
184 ~Reader();
185
186 void init(const char* filename, const char* treename = nullptr);
187 size_t getTreeSize() const
188 {
189 return (mTree ? mTree->GetEntries() : 0);
190 }
191 void read(size_t entry);
192 void clear();
193
194 // Fill the ClusterNative access structure from data and corresponding mc label arrays
195 // from the internal data structures of the reader.
196 int fillIndex(ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer,
198
199 // Fill the ClusterNative access structure from data and corresponding mc label arrays.
200 // Both cluster data input and mc containers are provided as a collection with one entry per
201 // sector. The data per sector itself is again a collection.
202 //
203 // MC truth per sector is organized as one MCLabelContainer per row.
204 //
205 // The index structure does not own the data, specific buffers owned by the caller must be
206 // provided for both clusters and mc labels.
207 //
208 // FIXME: while this function was originally indendet to fill the index only and leaver any
209 // data as is, commit 65e17cb73e (PR2166) introduces a rearrangement of data which probably
210 // should be moved to a separate function for clarity. Maybe another access index named
211 // ClusterNativeMonAccess is more appropriate. Also it probably makes sense to performe the
212 // linarization already in the decoder and abandon the partitioning of data pad-row wise.
213 //
214 // @param clusterIndex the target where all the pointers are set
215 // @param clusterBuffer array of ClusterNative, clusters are copied to consecutive sections
216 // pointers in the index point to regions in this buffer
217 // @param mcBuffer
218 // @param inputs data arrays, fixed array, one per sector
219 // @param mcinputs vectors mc truth container, fixed array, one per sector
220 // @param sectorMask Bitmask with tpc sectors to process
221 template <typename DataArrayType, typename MCArrayType>
222 static int fillIndex(
223 ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer,
224 ConstMCLabelContainerViewWithBuffer& mcBuffer, DataArrayType& inputs, MCArrayType const& mcinputs,
225 unsigned long sectorMask = 0xFFFFFFFFF);
226
227 template <typename DataArrayType>
228 static int fillIndex(
229 ClusterNativeAccess& clusterIndex, std::unique_ptr<ClusterNative[]>& clusterBuffer,
230 DataArrayType& inputs, unsigned long sectorMask = 0xFFFFFFFFF)
231 {
232 // just use a dummy parameter with empty vectors
233 // TODO: maybe do in one function with conditional template parameter
234 std::vector<std::unique_ptr<MCLabelContainer>> dummy;
235 // another default, nothing will be added to the container
237 return fillIndex(clusterIndex, clusterBuffer, mcBuffer, inputs, dummy, sectorMask);
238 }
239
240 // Process data for one sector.
241 // This function does not copy any data but sets the corresponding poiters in the index.
242 // Cluster data are provided as a raw buffer of consecutive ClusterNative arrays preceded by ClusterGroupHeader
243 // MC labels are provided as a span of MCLabelContainers, one per sector.
244 static int parseSector(const char* buffer, size_t size, gsl::span<ConstMCLabelContainerView const> const& mcinput, //
245 ClusterNativeAccess& clusterIndex, //
246 const ConstMCLabelContainerView* (&clustersMCTruth)[NSectors]); //
247
248 // Process data for one sector
249 // Helper method receiving raw buffer provided as container
250 // This function does not copy any data but sets the corresponding poiters in the index.
251 template <typename ContainerT>
252 static int parseSector(ContainerT const cont, gsl::span<ConstMCLabelContainerView const> const& mcinput, //
253 ClusterNativeAccess& clusterIndex, //
254 const ConstMCLabelContainerView* (&clustersMCTruth)[NSectors]) //
255 {
256 using T = typename std::remove_pointer<ContainerT>::type;
257 static_assert(sizeof(typename T::value_type) == 1, "raw container must be byte-type");
258 T const* container = nullptr;
259 if constexpr (std::is_pointer<ContainerT>::value) {
260 if (cont == nullptr) {
261 return 0;
262 }
263 container = cont;
264 } else {
265 container = &cont;
266 }
267 return parseSector(container->data(), container->size(), mcinput, clusterIndex, clustersMCTruth);
268 }
269
270 private:
272 std::string mTreeName = "tpcrec";
274 std::string mDataBranchName = "TPCClusterNative";
276 std::string mMCBranchName = "TPCClusterNativeMCTruth";
277
279 std::unique_ptr<TFile> mFile;
281 TTree* mTree = nullptr;
283 std::array<std::vector<char>*, NSectors> mSectorRaw = {nullptr};
285 std::array<size_t, NSectors> mSectorRawSize = {0};
287 std::array<dataformats::IOMCTruthContainerView*, NSectors> mSectorMCPtr{};
288 };
289
293 {
294 public:
295 TreeWriter() = default;
296 ~TreeWriter();
297
298 void init(const char* filename, const char* treename);
299 void close();
300
302 int fillFrom(ClusterNativeAccess const& clusterIndex);
304 int fillFrom(int sector, int padrow, ClusterNative const* clusters, size_t nClusters,
305 MCLabelContainer* = nullptr);
306
307 struct BranchData {
309 {
310 time = rhs.getTime();
311 pad = rhs.getPad();
312 sigmaTime = rhs.getSigmaTime();
313 sigmaPad = rhs.getSigmaPad();
314 qMax = rhs.qMax;
315 qTot = rhs.qTot;
316 flags = rhs.getFlags();
317 return *this;
318 }
319 int sector = -1;
320 int padrow = -1;
321 float time = 0.;
322 float pad = 0.;
323 float sigmaTime = 0.;
324 float sigmaPad = 0.;
325 uint16_t qMax = 0;
326 uint16_t qTot = 0;
327 uint8_t flags = 0;
328 };
329
330 private:
332 std::unique_ptr<TFile> mFile;
334 std::unique_ptr<TTree> mTree;
336 std::vector<BranchData> mStoreClusters = {};
338 std::vector<BranchData>* mStore = &mStoreClusters;
340 int mEvent = -1;
341 };
342
348 template <typename BufferType, typename MCArrayType>
349 static void copySectorData(ClusterNativeAccess const& index, int sector, BufferType& target, MCArrayType& mcTarget);
350};
351
352template <typename DataArrayType, typename MCArrayType>
353int ClusterNativeHelper::Reader::fillIndex(ClusterNativeAccess& clusterIndex,
354 std::unique_ptr<ClusterNative[]>& clusterBuffer, ConstMCLabelContainerViewWithBuffer& mcBuffer,
355 DataArrayType& inputs, MCArrayType const& mcinputs, unsigned long sectorMask)
356{
357 if (mcinputs.size() > 0 && mcinputs.size() != inputs.size()) {
358 std::runtime_error("inconsistent size of MC label array " + std::to_string(mcinputs.size()) + ", expected " + std::to_string(inputs.size()));
359 }
360 memset(&clusterIndex, 0, sizeof(clusterIndex));
361 if (inputs.size() == 1) {
362 if (inputs[0].size() >= sizeof(ClusterCountIndex)) {
363 // there is only one data block and we can set the index directly from it
364 const ClusterCountIndex* hdr = reinterpret_cast<ClusterCountIndex const*>(inputs[0].data());
365 memcpy((void*)&clusterIndex.nClusters[0][0], hdr, sizeof(*hdr));
366 clusterIndex.clustersLinear = reinterpret_cast<const ClusterNative*>(inputs[0].data() + sizeof(*hdr));
367 clusterIndex.setOffsetPtrs();
368 if (mcinputs.size() > 0) {
369 clusterIndex.clustersMCTruth = &mcinputs[0];
370 }
371 }
372 if (sizeof(ClusterCountIndex) + clusterIndex.nClustersTotal * sizeof(ClusterNative) > inputs[0].size()) {
373 throw std::runtime_error("inconsistent input buffer, expecting size " + std::to_string(sizeof(ClusterCountIndex) + clusterIndex.nClustersTotal * sizeof(ClusterNative)) + " got " + std::to_string(inputs[0].size()));
374 }
375 if (sectorMask != 0xFFFFFFFFF) {
376 for (unsigned int sector = 0; sector < NSectors; sector++) {
377 if (!(sectorMask & (1ul << sector)) && clusterIndex.nClustersSector[sector]) {
378 throw std::runtime_error("TPC sector mask provided, but received more sectors than set. (A filter could be implemented here if needed.)");
379 }
380 }
381 }
382 return clusterIndex.nClustersTotal;
383 }
384
385 // multiple data blocks need to be merged into the single block
386 const ConstMCLabelContainerView* clustersMCTruth[NSectors] = {nullptr};
387 int result = 0;
388 for (size_t index = 0, end = inputs.size(); index < end; index++) {
390 std::size_t extent = 0;
391 if (index < mcinputs.size()) {
392 labelsptr = &mcinputs[index];
393 extent = 1;
394 }
395 int locres = parseSector(inputs[index], {labelsptr, extent}, clusterIndex, clustersMCTruth);
396 if (locres < 0) {
397 return locres;
398 }
399 result += locres;
400 }
401
402 // Now move all data to a new consecutive buffer
403 ClusterNativeAccess old = clusterIndex;
404 clusterBuffer.reset(new ClusterNative[result]);
405 MCLabelContainer tmpMCBuffer;
406 tmpMCBuffer.clear();
407 bool mcPresent = false;
408 clusterIndex.clustersLinear = clusterBuffer.get();
409 clusterIndex.setOffsetPtrs();
410 for (unsigned int i = 0; i < NSectors; i++) {
411 int sectorLabelId = 0;
412 for (unsigned int j = 0; j < NPadRows; j++) {
413 memcpy(&clusterBuffer[clusterIndex.clusterOffset[i][j]], old.clusters[i][j], sizeof(*old.clusters[i][j]) * old.nClusters[i][j]);
414 if (clustersMCTruth[i]) {
415 mcPresent = true;
416 for (unsigned int k = 0; k < old.nClusters[i][j]; k++, sectorLabelId++) {
417 for (auto const& label : clustersMCTruth[i]->getLabels(sectorLabelId)) {
418 tmpMCBuffer.addElement(clusterIndex.clusterOffset[i][j] + k, label);
419 }
420 }
421 }
422 }
423 }
424 if (mcPresent) {
425 tmpMCBuffer.flatten_to(mcBuffer.first);
426 mcBuffer.second = mcBuffer.first;
427 clusterIndex.clustersMCTruth = &mcBuffer.second;
428 }
429
430 return result;
431}
432
433template <typename BufferType, typename MCArrayType>
434void ClusterNativeHelper::copySectorData(ClusterNativeAccess const& index, int sector, BufferType& target, MCArrayType& mcTarget)
435{
436 static_assert(sizeof(typename BufferType::value_type) == 1, "Target container must be byte-type");
437 if (index.clustersLinear == nullptr) {
438 return;
439 }
440 size_t nRows = 0;
441 size_t nClusters = 0;
442 for (unsigned int row = 0; row < NPadRows; row++) {
443 // count rows with clusters
444 nRows += index.nClusters[sector][row] > 0 ? 1 : 0;
445 nClusters += index.nClusters[sector][row];
446 }
447 size_t rawSize = nRows * sizeof(ClusterNativeBuffer) + nClusters * sizeof(ClusterNative);
448 target.resize(rawSize);
449 ClusterNativeBuffer* current = reinterpret_cast<ClusterNativeBuffer*>(target.data());
450 for (unsigned int row = 0; row < NPadRows; row++) {
451 if (index.nClusters[sector][row] == 0) {
452 continue;
453 }
454 current->sector = sector;
455 current->globalPadRow = row;
456 current->nClusters = index.nClusters[sector][row];
457 memcpy(current->clusters, index.clusters[sector][row], sizeof(*(current->clusters)) * current->nClusters);
458 current = reinterpret_cast<ClusterNativeBuffer*>(current->clusters + current->nClusters);
459 if (index.clustersMCTruth) {
460 mcTarget.emplace_back();
461 for (unsigned int k = 0; k < index.nClusters[sector][row]; k++) {
462 for (auto const& label : index.clustersMCTruth->getLabels(k + index.clusterOffset[sector][row])) {
463 mcTarget.back().addElement(k, label);
464 }
465 }
466 }
467 }
468}
469
470} // namespace tpc
471} // namespace o2
472#endif // CLUSTERNATIVEHELPER_H
Meta data for a group describing it by sector number and global padrow.
Class of a TPC cluster in TPC-native coordinates (row, time)
A const (ready only) version of MCTruthContainer.
int32_t i
A special IO container - splitting a given vector to enable ROOT IO.
uint32_t j
Definition RawData.h:0
uint32_t padrow
Definition RawData.h:5
int nClusters
gsl::span< const TruthElement > getLabels(uint32_t dataindex) const
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
size_t flatten_to(ContainerType &container) const
A reader class for the raw cluster native data.
static int fillIndex(ClusterNativeAccess &clusterIndex, std::unique_ptr< ClusterNative[]> &clusterBuffer, DataArrayType &inputs, unsigned long sectorMask=0xFFFFFFFFF)
int fillIndex(ClusterNativeAccess &clusterIndex, std::unique_ptr< ClusterNative[]> &clusterBuffer, ConstMCLabelContainerViewWithBuffer &mcBuffer)
void init(const char *filename, const char *treename=nullptr)
static int parseSector(ContainerT const cont, gsl::span< ConstMCLabelContainerView const > const &mcinput, ClusterNativeAccess &clusterIndex, const ConstMCLabelContainerView *(&clustersMCTruth)[NSectors])
static int parseSector(const char *buffer, size_t size, gsl::span< ConstMCLabelContainerView const > const &mcinput, ClusterNativeAccess &clusterIndex, const ConstMCLabelContainerView *(&clustersMCTruth)[NSectors])
Utility to write native cluster format to a ROOT tree.
void init(const char *filename, const char *treename)
int fillFrom(ClusterNativeAccess const &clusterIndex)
fill tree from the full index of cluster arrays
static std::unique_ptr< ClusterNativeAccess > createClusterNativeIndex(std::unique_ptr< ClusterNative[]> &buffer, std::vector< ClusterNativeContainer > &clusters, MCLabelContainer *bufferMC=nullptr, std::vector< MCLabelContainer > *mcTruth=nullptr)
static constexpr unsigned int NSectors
static constexpr unsigned int NPadRows
static void copySectorData(ClusterNativeAccess const &index, int sector, BufferType &target, MCArrayType &mcTarget)
ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer ConstMCLabelContainerViewWithBuffer
static void convert(const char *fromFile, const char *toFile, const char *toTreeName="tpcnative")
static int addFlatBuffer(ClusterNativeAccess &clusterIndex, unsigned char *buffer, size_t size)
GLint GLsizei count
Definition glcorearb.h:399
GLuint buffer
Definition glcorearb.h:655
GLuint entry
Definition glcorearb.h:5735
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint index
Definition glcorearb.h:781
GLenum target
Definition glcorearb.h:1641
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLbitfield flags
Definition glcorearb.h:1570
o2::dataformats::ConstMCTruthContainer< o2::MCCompLabel > ConstMCLabelContainer
o2::dataformats::MCTruthContainer< o2::MCCompLabel > MCLabelContainer
o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > ConstMCLabelContainerView
constexpr int MAXSECTOR
Definition Constants.h:28
constexpr int MAXGLOBALPADROW
Definition Constants.h:34
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
std::string filename()
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const value_type * data() const
unsigned int nClusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int nClustersSector[constants::MAXSECTOR]
const o2::dataformats::ConstMCTruthContainerView< o2::MCCompLabel > * clustersMCTruth
std::pair< ConstMCLabelContainer, ConstMCLabelContainerView > ConstMCLabelContainerViewWithBuffer
const ClusterNative * clusters[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
unsigned int clusterOffset[constants::MAXSECTOR][constants::MAXGLOBALPADROW]
const ClusterNative * clustersLinear
const value_type * data() const
std::vector< ClusterNative > clusters
const value_type * data() const
BranchData & operator=(ClusterNative const &rhs)
std::vector< Cluster > clusters
std::vector< int > row