Skip to content

Commit 8fb03c6

Browse files
committed
Compact label container for TPC pad-digits
This introduces a new class to assocate an index to an arbitratry number of labels objects. The new class also suppers non-contiguous storage of labels belonging to the same index. The new class is used in the TPC digitization (in the temporary digit structure), where we now store labels in compact label container instead of internal std::vector<> members. Reduces memory and allocations/deallocations.
1 parent fdc379c commit 8fb03c6

File tree

5 files changed

+249
-81
lines changed

5 files changed

+249
-81
lines changed

DataFormats/simulation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Set(HEADERS
2020
include/${MODULE_NAME}/TrackReference.h
2121
include/${MODULE_NAME}/PrimaryChunk.h
2222
include/${MODULE_NAME}/RunContext.h
23+
include/${MODULE_NAME}/LabelContainer.h
2324
)
2425

2526
Set(LINKDEF src/SimulationDataLinkDef.h)

DataFormats/simulation/include/SimulationDataFormat/LabelContainer.h

Lines changed: 90 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// granted to it by virtue of its status as an Intergovernmental Organization
99
// or submit itself to any jurisdiction.
1010

11-
/// \file MCTruthContainer.h
12-
/// \brief Definition of a container to keep Monte Carlo truth external to simulation objects
13-
/// \author Sandro Wenzel - June 2017
11+
/// \brief Definition of a container to keep/associate and arbitrary
12+
/// number of labels associated to an index with contiguous or non-contiguous label storage
13+
// \author Sandro Wenzel - June 2017
1414

1515
#ifndef ALICEO2_DATAFORMATS_LABELCONTAINER_H_
1616
#define ALICEO2_DATAFORMATS_LABELCONTAINER_H_
@@ -21,106 +21,125 @@
2121
#include <type_traits>
2222
#include <iterator>
2323
#include <gsl/gsl> // for guideline support library; array_view
24-
#include <iostream>
2524

2625
namespace o2
2726
{
2827
namespace dataformats
2928
{
30-
29+
30+
// a label container with both contiguous and non-contiguous modes
31+
// for label storage
32+
// NOTE: the current specialization for contiguous storage is not
33+
// yet on par with MCTruthContainer ... but eventually we might unify
34+
// everything and keep only the more generic and configurable version
3135
template <typename LabelType, bool isContiguousStorage = true>
32-
class LabelContainer : public TNamed
36+
class LabelContainer
3337
{
3438
public:
3539
struct HeaderElementContinuous {
3640
HeaderElementContinuous() = default; // for ROOT IO
3741
HeaderElementContinuous(ushort s, uint i) : size(s), index(i) {}
38-
uint index = 0; // index of first label in the actual label storage
42+
uint index = 0; // index of first label in the actual label storage
3943
ushort size = 0; // total number of labels
4044
ClassDefNV(HeaderElementContinuous, 1);
4145
};
4246

4347
struct HeaderElementLinked {
4448
HeaderElementLinked() = default; // for ROOT IO
4549
HeaderElementLinked(uint i, int l, ushort s) : index(i), lastindex(l), size(s) {}
46-
uint index = 0; // index of first label in the actual label storage
50+
uint index = 0; // index of first label in the actual label storage
4751
uint lastindex = 0; // index of last label in the actual label storage
48-
ushort size = 0; // total number of labels
52+
ushort size = 0; // total number of labels
4953
ClassDefNV(HeaderElementLinked, 1);
5054
};
5155

5256
using HeaderElement = typename std::conditional<isContiguousStorage, HeaderElementContinuous, HeaderElementLinked>::type;
5357
using StoredLabelType = typename std::conditional<isContiguousStorage, LabelType, std::pair<LabelType, int>>::type;
5458

5559
// internal functions allowing the iterator implementation to be completely generic
56-
static uint getNextIndex(uint index, std::vector<LabelType> const &/*labels*/) {
57-
return index+1;
60+
static uint getNextIndex(uint index, std::vector<LabelType> const& /*labels*/)
61+
{
62+
return index + 1;
5863
}
59-
static uint getNextIndex(uint index, std::vector<std::pair<LabelType, int>> const &labels) {
64+
static uint getNextIndex(uint index, std::vector<std::pair<LabelType, int>> const& labels)
65+
{
6066
return labels[index].second;
6167
}
62-
static LabelType& dereference(std::vector<LabelType> &v, int index) {
68+
static LabelType& dereference(std::vector<LabelType>& v, int index)
69+
{
6370
return v[index];
6471
}
65-
static LabelType& dereference(std::vector<std::pair<LabelType,int>> &v, int index) {
72+
static LabelType& dereference(std::vector<std::pair<LabelType, int>>& v, int index)
73+
{
6674
return v[index].first;
6775
}
68-
static int lastIndex(HeaderElementContinuous const &h) {
76+
static int lastIndex(HeaderElementContinuous const& h)
77+
{
6978
return h.index + h.size;
7079
}
71-
static int lastIndex(HeaderElementLinked const &h) {
80+
static int lastIndex(HeaderElementLinked const& h)
81+
{
7282
// -1 since this is indication of end of linked list
7383
return -1;
7484
}
75-
76-
// an iterator class to iterate over truthelements
85+
86+
// an iterator class to iterate over truthelements
7787
class Iterator : public std::iterator<std::input_iterator_tag, LabelType>
7888
{
79-
private:
80-
std::vector<StoredLabelType> &mLabelsRef; // reference to labels vector
81-
int index; // startindex
82-
public:
83-
Iterator(std::vector<StoredLabelType> &v, int i) : mLabelsRef(v), index(i) {}
84-
Iterator(const Iterator& it) : mLabelsRef(it.mLabelsRef), index(it.index) {}
85-
Iterator& operator=(const Iterator& it) {
86-
mLabelsRef = it.mLabelsRef;
87-
index = it.index;
88-
return *this;
89-
}
90-
91-
// go to the next element as indicated by second entry of StoredLabelType
92-
Iterator& operator++() {index=getNextIndex(index, mLabelsRef);return *this;}
89+
private:
90+
std::vector<StoredLabelType>& mLabelsRef; // reference to labels vector
91+
int index; // startindex
92+
public:
93+
Iterator(std::vector<StoredLabelType>& v, int i) : mLabelsRef(v), index(i) {}
94+
Iterator(const Iterator& it) : mLabelsRef(it.mLabelsRef), index(it.index) {}
95+
Iterator& operator=(const Iterator& it)
96+
{
97+
mLabelsRef = it.mLabelsRef;
98+
index = it.index;
99+
return *this;
100+
}
101+
102+
// go to the next element as indicated by second entry of StoredLabelType
103+
Iterator& operator++()
104+
{
105+
index = getNextIndex(index, mLabelsRef);
106+
return *this;
107+
}
93108

94-
bool operator==(const Iterator& rhs) const {return index==rhs.index;}
95-
bool operator!=(const Iterator& rhs) const {return index!=rhs.index;}
96-
LabelType& operator*() {return dereference(mLabelsRef, index);}
109+
bool operator==(const Iterator& rhs) const { return index == rhs.index; }
110+
bool operator!=(const Iterator& rhs) const { return index != rhs.index; }
111+
LabelType& operator*() { return dereference(mLabelsRef, index); }
97112
};
98113

99114
// a proxy class offering a (non-owning) container view on labels of a given data index
100115
// container offers basic forward iterator functionality
101-
class LabelView {
116+
class LabelView
117+
{
102118
private:
103119
int dataindex;
104120
std::vector<HeaderElement>& mHeaderArrayRef;
105121
std::vector<StoredLabelType>& mLabelArrayRef;
106-
122+
107123
public:
108-
constexpr LabelView(int i, std::vector<HeaderElement> &v1, std::vector<StoredLabelType> &v2) : dataindex(i), mHeaderArrayRef(v1), mLabelArrayRef(v2) {}
109-
124+
constexpr LabelView(int i, std::vector<HeaderElement>& v1, std::vector<StoredLabelType>& v2) : dataindex(i), mHeaderArrayRef(v1), mLabelArrayRef(v2) {}
125+
110126
// begin + end iterators to loop over the labels
111-
Iterator begin() {return dataindex < mHeaderArrayRef.size() ?
112-
Iterator(mLabelArrayRef, mHeaderArrayRef[dataindex].index) : Iterator(mLabelArrayRef, 0);
127+
Iterator begin()
128+
{
129+
return dataindex < mHeaderArrayRef.size() ? Iterator(mLabelArrayRef, mHeaderArrayRef[dataindex].index) : Iterator(mLabelArrayRef, 0);
113130
}
114131

115-
Iterator end() {return dataindex < mHeaderArrayRef.size() ?
116-
Iterator(mLabelArrayRef, lastIndex(mHeaderArrayRef[dataindex])) : Iterator(mLabelArrayRef, 0);
132+
Iterator end()
133+
{
134+
return dataindex < mHeaderArrayRef.size() ? Iterator(mLabelArrayRef, lastIndex(mHeaderArrayRef[dataindex])) : Iterator(mLabelArrayRef, 0);
117135
}
118136

119137
// get number of labels
120-
size_t size() const {return dataindex < mHeaderArrayRef.size() ? mHeaderArrayRef[dataindex].size : 0;}
138+
size_t size() const { return dataindex < mHeaderArrayRef.size() ? mHeaderArrayRef[dataindex].size : 0; }
121139
};
122140

123-
static void addLabelImpl(int dataindex, std::vector<HeaderElementContinuous> &headerv, std::vector<LabelType> &labelv, LabelType const &label) {
141+
static void addLabelImpl(int dataindex, std::vector<HeaderElementContinuous>& headerv, std::vector<LabelType>& labelv, LabelType const& label)
142+
{
124143
if (dataindex < headerv.size()) {
125144
// look if we have something for this dataindex already
126145
// must currently be the last one
@@ -137,24 +156,24 @@ class LabelContainer : public TNamed
137156
labelv.emplace_back(label);
138157
}
139158

140-
static void addLabelImpl(int dataindex, std::vector<HeaderElementLinked> &headerv, std::vector<std::pair<LabelType,int>> &labelv, LabelType const &label) {
141-
labelv.emplace_back(std::make_pair(label,-1));
159+
static void addLabelImpl(int dataindex, std::vector<HeaderElementLinked>& headerv, std::vector<std::pair<LabelType, int>>& labelv, LabelType const& label)
160+
{
161+
labelv.emplace_back(std::make_pair(label, -1));
142162
// something exists for this dataindex already
143163
if (dataindex < headerv.size()) {
144164
auto& header = headerv[dataindex];
145165
// increase size
146166
header.size++;
147-
const auto lastindex = labelv.size();
167+
const auto lastindex = labelv.size() - 1;
148168
// fix link at previous last index
149169
labelv[header.lastindex].second = lastindex;
150170
// new last index
151171
header.lastindex = lastindex;
152-
}
153-
else {
172+
} else {
154173
// we support only appending in order?
155174
assert(dataindex == headerv.size());
156175
// add a new header element; pointing to last slot in mTruthArray
157-
const auto lastpos = labelv.size()-1;
176+
const auto lastpos = labelv.size() - 1;
158177
headerv.emplace_back(lastpos, lastpos, 1);
159178
}
160179
}
@@ -166,7 +185,15 @@ class LabelContainer : public TNamed
166185
public:
167186
// constructor
168187
LabelContainer() = default;
169-
~LabelContainer() final = default;
188+
~LabelContainer() = default;
189+
190+
// reserve some initial space in the actual storage
191+
// (to hold at least n labels)
192+
void reserve(int n)
193+
{
194+
mHeaderArray.reserve(n);
195+
mLabelArray.reserve(n);
196+
}
170197

171198
void clear()
172199
{
@@ -175,29 +202,29 @@ class LabelContainer : public TNamed
175202
}
176203

177204
/// add a label for a dataindex
178-
void addLabel(uint dataindex, LabelType const& label) {
179-
// refer to concrete specialized implementation
180-
addLabelImpl(dataindex, mHeaderArray, mLabelArray, label);
181-
}
205+
void addLabel(uint dataindex, LabelType const& label)
206+
{
207+
// refer to concrete specialized implementation
208+
addLabelImpl(dataindex, mHeaderArray, mLabelArray, label);
209+
}
182210

183211
/// get a container view on labels allowing use standard forward iteration in user code
184-
LabelView getLabels(int dataindex) {return LabelView(dataindex, mHeaderArray, mLabelArray);}
212+
LabelView getLabels(int dataindex) { return LabelView(dataindex, mHeaderArray, mLabelArray); }
185213

186214
/// fill an external vector container with labels
187215
/// might be useful to perform additional operations such as sorting on the labels;
188216
/// the external vector can be reused to avoid allocations/deallocs)
189-
void fillVectorOfLabels(int dataindex, std::vector<LabelType> &v) {
217+
void fillVectorOfLabels(int dataindex, std::vector<LabelType>& v)
218+
{
190219
/// fixme: provide a template specialized fast version for contiguous storage
191220
v.clear();
192-
for(auto &e : getLabels(dataindex)) {
221+
for (auto& e : getLabels(dataindex)) {
193222
v.push_back(e);
194223
}
195224
}
196-
197-
// ClassDefOverride(LabelContainer, 1);
198225
}; // end class
199226

200-
}
201-
}
227+
} // namespace dataformats
228+
} // namespace o2
202229

203230
#endif

DataFormats/simulation/test/testMCTruthContainer.cxx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define BOOST_TEST_DYN_LINK
1414
#include <boost/test/unit_test.hpp>
1515
#include "SimulationDataFormat/MCTruthContainer.h"
16+
#include "SimulationDataFormat/LabelContainer.h"
1617
#include <algorithm>
1718

1819
namespace o2
@@ -138,4 +139,107 @@ BOOST_AUTO_TEST_CASE(MCTruth_RandomAccess)
138139
BOOST_CHECK(view[1] == 21);
139140
}
140141
}
142+
143+
BOOST_AUTO_TEST_CASE(LabelContainer_noncont)
144+
{
145+
using TruthElement = long;
146+
// creates a container where labels might not be contiguous
147+
dataformats::LabelContainer<TruthElement, false> container;
148+
container.addLabel(0, TruthElement(1));
149+
container.addLabel(1, TruthElement(1));
150+
container.addLabel(0, TruthElement(10));
151+
container.addLabel(2, TruthElement(20));
152+
153+
auto view = container.getLabels(0);
154+
BOOST_CHECK(view.size() == 2);
155+
for (auto& e : view) {
156+
std::cerr << e << "\n";
157+
}
158+
159+
{
160+
auto view2 = container.getLabels(10);
161+
BOOST_CHECK(view2.size() == 0);
162+
for (auto& e : view2) {
163+
// should not come here
164+
BOOST_CHECK(false);
165+
}
166+
}
167+
168+
{
169+
auto view2 = container.getLabels(2);
170+
BOOST_CHECK(view2.size() == 1);
171+
std::cout << "ELEMENTS OF LABEL 2\n";
172+
for (auto& e : view2) {
173+
// should not come here
174+
std::cout << e << "\n";
175+
}
176+
std::cout << "------\n";
177+
}
178+
179+
std::vector<TruthElement> v;
180+
container.fillVectorOfLabels(0, v);
181+
BOOST_CHECK(v.size() == 2);
182+
std::sort(v.begin(), v.end(), [](TruthElement a, TruthElement b) { return a > b; });
183+
for (auto& e : v) {
184+
std::cerr << e << "\n";
185+
}
186+
187+
const int R = 3;
188+
const int L = 5;
189+
// test with more elements
190+
dataformats::LabelContainer<TruthElement, false> container2;
191+
for (int run = 0; run < R; ++run) {
192+
for (int i = 0; i < L; ++i) {
193+
container2.addLabel(i, TruthElement(run));
194+
}
195+
}
196+
// testing stage
197+
for (int i = 0; i < L; ++i) {
198+
auto labelview = container2.getLabels(i);
199+
BOOST_CHECK(labelview.size() == R);
200+
// count elements when iterating over view
201+
int counter = 0;
202+
std::cout << "CHECK CONTENT FOR INDEX " << i << "\n";
203+
std::cout << "----- \n";
204+
for (auto& l : labelview) {
205+
counter++;
206+
std::cout << l << "\n";
207+
}
208+
std::cout << "#### " << i << "\n";
209+
std::cout << counter << "\n";
210+
BOOST_CHECK(labelview.size() == counter);
211+
}
212+
213+
// in this case we have to add the elements contiguously per dataindex:
214+
dataformats::LabelContainer<TruthElement, true> cont2;
215+
cont2.addLabel(0, TruthElement(1));
216+
cont2.addLabel(0, TruthElement(10));
217+
cont2.addLabel(1, TruthElement(1));
218+
cont2.addLabel(2, TruthElement(20));
219+
{
220+
auto view2 = cont2.getLabels(0);
221+
BOOST_CHECK(view2.size() == 2);
222+
for (auto& e : view2) {
223+
std::cerr << e << "\n";
224+
}
225+
}
226+
{
227+
auto view2 = cont2.getLabels(1);
228+
BOOST_CHECK(view2.size() == 1);
229+
for (auto& e : view2) {
230+
std::cerr << e << "\n";
231+
}
232+
}
233+
{
234+
auto view2 = cont2.getLabels(2);
235+
BOOST_CHECK(view2.size() == 1);
236+
for (auto& e : view2) {
237+
std::cerr << e << "\n";
238+
}
239+
}
240+
241+
// get labels for nonexisting dataelement
242+
BOOST_CHECK(cont2.getLabels(100).size() == 0);
243+
}
244+
141245
} // end namespace

0 commit comments

Comments
 (0)