ATLAS Offline Software
Loading...
Searching...
No Matches
CaloTowerStore.h
Go to the documentation of this file.
1// This file's extension implies that it's C, but it's really -*- C++ -*-.
2
3/*
4 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5*/
6
7#ifndef CALOTOWERSTORE_H
8#define CALOTOWERSTORE_H
9/********************************************************************
10
11NAME: CaloTowerStore
12PACKAGE: offline/Calorimeter/CaloRec
13
14AUTHORS: S. Laplace
15CREATED: May 2005
16
17PURPOSE: Intermediate store for cell/tower maps. This is NOT to be
18 confused with CaloTowerContainer, even though
19 it is a container class for CaloTower objects. In particular,
20 this class is NOT inherited from CaloTowerContainer classes.
21
22Updated: Jul 2009, sss
23
24 Rewritten to greatly compress the mapping tables,
25 to save virtual memory.
26
27 To understand what's happening, it helps to go through
28 the optimizations step-by-step.
29
30 Originally, the table was stored like this:
31
32 vector<vector<pair<unsigned int, double> > >
33
34 The outer vector was indexed by the tower number;
35 for each tower, we had a list of (cell hash, weight) pairs.
36
37 The first thing to notice is that there are only a very
38 few distinct weights used. The weight is the ratio
39 of tower/cell size, capped at 1. The tower segmentations
40 used during reconstruction give a maximum of five
41 distinct weight values (1/n, where n is a small integer).
42 So we can start by moving the weights to a separate list,
43 and storing just the indices into that list. I.e., something
44 like
45
46 struct Entry {
47 unsigned int hash : ...;
48 unsigned int weight_index : ...;
49 };
50 vector<vector<Entry> >
51
52 The bitfield sizes can be set to pack Entry into a 32-bit word.
53
54 The next step is to flatten the nested vector: there may
55 be many towers, each with not so many cells. So, instead of
56 a nested vector, we can store two vectors, one for the
57 cell entries:
58
59 vector<Entry> m_entries;
60
61 and one for the towers:
62
63 vector<unsigned int> m_towers;
64
65 where the entries here give the indices into m_entries.
66
67 The next thing to notice is that the entries list contains
68 many runs of cells with consecutive hash codes, plus even longer
69 runs where the hash codes are regularly spaced at intervals
70 of 64. So we can compress things further: for each entry,
71 we now store:
72
73 - The starting hash code
74 - The number of cells that this entry represents.
75 - A flag for the stride (1 or 64).
76 - The weight index.
77
78 This can still be packed into 32 bits.
79
80 When we do this, we also need to add to each tower the
81 total count of cells. We need this when building towers
82 in order to reserve space for the cell list, and don't want
83 to have to run through the entries a separate time to count.
84 The cell count plus the entry index can be packed into 32 bits.
85
86 Finally, we notice that seqeunces of entries used
87 by adjacent towers tend to be quite similar, except that
88 the hashes are offset by a small integer. This offset may
89 not be constant over the entire sequence, though. For example,
90 consider these two adjacent towers:
91
92 hash windex stride ncells
93 15008 1 64 4
94 25600 0 1 1
95 31232 3 1 1
96
97 15008 1 64 4
98 25601 0 1 1
99 31233 3 1 1
100
101 The first entry has an offset of 0, the other two have
102 an offset of 1.
103
104 What we do is this. For each tower, we encode two offsets,
105 and also a count of the number of entries using the first
106 offset (call this n1). We choose n1 to be in the range 0--3;
107 this catches most of the observed patterns. If n1 is 0,
108 then the first offset is applied to all entries.
109
110 It's not possible to usefully pack both offsets and n1 along with
111 an entry index and a count of the cells into 32 bits. But
112 instead of storing the entry index, we can store the number
113 of entries used by this tower. (That suffices since we only
114 ever iterate forwards over the entire container.) We also need
115 to store a flag to tell if we're reusing the list of entries
116 from the previous tower (with offsets). So the information
117 required for each tower is:
118
119 - The number of entries this tower uses.
120 - A flag to say if the next tower will reuse the entries
121 for this tower.
122 - The number of cells for this tower.
123 - The first and second offset, and the count of entries
124 using the first offset.
125
126 With judicious choices, this fits in 32 bits.
127
128 Further optimizations are possible.
129 Many adjacent towers use have an OFFS1,OFFS2,OFFS1 pattern
130 rather and OFFS1,OFFS2. Examination of the compressed
131 entry lists shows that the hash codes are often regularly
132 spaced; adding a second outer stride could compress these
133 further.
134
135 I think we're reaching diminishing returns, though, so those
136 compressions haven't been implemented. With the current
137 version, the entry lists made by the standard reconstruction
138 have a length of about ~17000 words.
139
140 The upshot is that memory usage is reduced by ~20x.
141 Execution time is not observed to change significantly.
142
143********************************************************************/
144
145// include header files
148#include "CxxUtils/CachedValue.h"
149#include <vector>
150#include <utility>
151
152
154
155
157{
158private:
159 struct Entry
160 {
161 static const unsigned int hash_width = 18;
162 static const unsigned int hash_max = (1<<hash_width)-1;
163 static const unsigned int windex_width = 6;
164 static const unsigned int windex_max = (1<<windex_width)-1;
165 static const unsigned int ncells_width = 7;
166 static const unsigned int ncells_max = (1<<ncells_width)-1;
167 static const unsigned int stride_width = 1;
168 static const unsigned int stride_max = (1<<stride_width)-1;
169
170 // Work around link problems with some gcc versions.
171 //static const unsigned int large_stride = 64;
172 //static const unsigned int small_stride = 1;
173 enum {
176 };
177
178 unsigned int hash : hash_width;
179 unsigned int windex : windex_width;
180 unsigned int ncells : ncells_width;
181 unsigned int stride : stride_width;
182
183 Entry (unsigned int the_hash = 0,
184 unsigned int the_windex = 0,
185 unsigned int the_ncells = 1,
186 unsigned int the_stride = 0);
187 };
188
189 struct Tower
190 {
191 static const unsigned int nentries_width = 5;
192 static const unsigned int nentries_max = (1<<nentries_width)-1;
193 static const unsigned int backref_next_width = 1;
194 static const unsigned int backref_next_max = (1<<backref_next_width)-1;
195 static const unsigned int n1_width = 2;
196 static const unsigned int n1_max = (1<<n1_width)-1;
197 static const unsigned int ncells_width = 8;
198 static const unsigned int ncells_max = (1<<ncells_width)-1;
199 static const unsigned int offs1_width = 8;
200 static const unsigned int offs1_max = (1<<offs1_width)-1;
201 static const unsigned int offs2_width = 8;
202 static const unsigned int offs2_max = (1<<offs2_width)-1;
203
204 unsigned int nentries : nentries_width;
206 unsigned int n1 : n1_width;
207 unsigned int ncells : ncells_width;
208 unsigned int offs1 : offs1_width;
209 unsigned int offs2 : offs2_width;
210
211 Tower (unsigned int the_nentries, unsigned int the_ncells);
212 Tower (unsigned int the_nentries, unsigned int the_ncells,
213 unsigned int the_n1,
214 unsigned int the_offs1, unsigned int the_offs2);
215 };
216
217
218 public:
219
222
225
227 {
228 public:
229 cell_iterator (std::vector<Entry>::const_iterator it,
230 unsigned int n1,
231 unsigned int offs1,
232 unsigned int offs2,
233 std::vector<double>::const_iterator weights)
234 : m_weights (weights),
235 m_it (it),
236 m_hash (0),
237 m_nleft (0),
238 m_n1 (n1),
239 m_offs (offs1),
240 m_offs2 (offs2),
241 m_stride (0)
242 { }
243 cell_iterator (std::vector<Entry>::const_iterator it)
244 : m_it (it),
245 m_hash(0),
246 m_nleft(0),
247 m_n1(0),
248 m_offs(0),
249 m_offs2(0),
250 m_stride(0)
251 { }
252 unsigned int hash()
253 {
254 if (m_nleft == 0) {
255 m_hash = m_it->hash + m_offs;
256 m_nleft = m_it->ncells;
258 }
259 return m_hash;
260 }
261 double weight() const { return m_weights[m_it->windex]; }
263 if (m_nleft == 0) hash();
264 --m_nleft;
265 if (m_nleft > 0) {
266 m_hash += m_stride;
267 }
268 else {
269 ++m_it;
270 if (m_n1 && --m_n1 == 0) {
271 m_offs = m_offs2;
272 }
273 }
274 return *this;
275 }
276 bool operator!= (const cell_iterator& other)
277 { return this->m_it != other.m_it;}
278
279
280 private:
281 std::vector<double>::const_iterator m_weights{};
282 std::vector<Entry>::const_iterator m_it{};
283 unsigned int m_hash{};
284 unsigned int m_nleft{};
285 unsigned int m_n1{};
286 unsigned int m_offs{};
287 unsigned int m_offs2{};
288 unsigned int m_stride{};
289 };
290
292 {
293 public:
294 tower_iterator (std::vector<Tower>::const_iterator it,
295 const std::vector<Entry>::const_iterator entry,
296 const CaloTowerStore& store)
297 : m_entry (entry),
298 m_it (it),
299 m_store (store)
300 {}
302 { return cell_iterator (m_entry, m_it->n1, m_it->offs1, m_it->offs2,
303 m_store.m_weights.begin()); }
305 { return cell_iterator (m_entry + m_it->nentries); }
306 size_t size() const { return m_it->ncells; }
308 if (!m_it->backref_next)
309 m_entry += m_it->nentries;
310 ++m_it;
311 return *this;
312 }
313
315 {
316 m_it += offs;
317 m_entry = m_store.m_entries.begin() +
318 (*m_store.m_entry_index.ptr())[m_it - m_store.m_towers.begin()];
319 return *this;
320 }
321
322 protected:
323 std::vector<Entry>::const_iterator m_entry;
324 std::vector<Tower>::const_iterator m_it;
326 };
327
328
330 {
331 return tower_iterator (m_towers.begin(),
332 m_entries.begin(),
333 *this);
334 }
335
336
338
339
352
353
354 size_t size() const { return m_towers.size(); }
355
357 bool buildLookUp(const CaloDetDescrManager& theManager,
358 const CaloTowerSeg& theTowerSeg,
359 const std::vector<CaloCell_ID::SUBCALO>& theCalos);
360
361 private:
362 friend class tower_iterator;
363
364 void pushTower (unsigned int nentries, unsigned int ncells);
365
366
370 void checkEntryIndex() const;
371
373 std::vector<Entry> m_entries;
374 std::vector<Tower> m_towers;
375 std::vector<double> m_weights;
376
383};
384
385
386//************************************************************************
387
388
389
390#endif
Cached value with atomic update.
This class provides the client interface for accessing the detector description information common to...
Iterator over a rectangular window of towers.
A rectangular window within the segmentation.
Data object stores CaloTower segmentation.
bool operator!=(const cell_iterator &other)
std::vector< double >::const_iterator m_weights
cell_iterator(std::vector< Entry >::const_iterator it)
std::vector< Entry >::const_iterator m_it
cell_iterator(std::vector< Entry >::const_iterator it, unsigned int n1, unsigned int offs1, unsigned int offs2, std::vector< double >::const_iterator weights)
tower_iterator(std::vector< Tower >::const_iterator it, const std::vector< Entry >::const_iterator entry, const CaloTowerStore &store)
cell_iterator lastCell() const
std::vector< Tower >::const_iterator m_it
cell_iterator firstCell() const
const CaloTowerStore & m_store
tower_iterator & operator+=(size_t offs)
std::vector< Entry >::const_iterator m_entry
size_t size() const
~CaloTowerStore()
destructor
CaloTowerSeg m_seg
std::vector< Tower > m_towers
std::vector< double > m_weights
CxxUtils::CachedValue< std::vector< unsigned short > > m_entry_index
One of these for each entry in m_towers, giving the index of the corresponding entry in m_entries.
friend class tower_iterator
bool buildLookUp(const CaloDetDescrManager &theManager, const CaloTowerSeg &theTowerSeg, const std::vector< CaloCell_ID::SUBCALO > &theCalos)
setup trigger
void pushTower(unsigned int nentries, unsigned int ncells)
CaloTowerStore()
constructor
void checkEntryIndex() const
Check m_entry_index and fill it in if we haven't done so yet.
tower_iterator towers() const
CaloTowerSeg::SubSegIterator< tower_iterator > tower_subseg_iterator
std::vector< Entry > m_entries
Cached value with atomic update.
Definition CachedValue.h:55
static const unsigned int windex_max
static const unsigned int stride_max
static const unsigned int hash_max
static const unsigned int stride_width
static const unsigned int ncells_max
Entry(unsigned int the_hash=0, unsigned int the_windex=0, unsigned int the_ncells=1, unsigned int the_stride=0)
static const unsigned int ncells_width
static const unsigned int hash_width
static const unsigned int windex_width
static const unsigned int nentries_width
static const unsigned int offs2_width
Tower(unsigned int the_nentries, unsigned int the_ncells)
static const unsigned int backref_next_width
static const unsigned int nentries_max
static const unsigned int offs1_width
static const unsigned int ncells_max
static const unsigned int n1_max
static const unsigned int backref_next_max
static const unsigned int ncells_width
static const unsigned int offs1_max
static const unsigned int offs2_max
static const unsigned int n1_width