ATLAS Offline Software
Loading...
Searching...
No Matches
CaloCellLinkContainerCnv_p2.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5/* @file CaloCellLinkContainerCnv_p2.cxx
6 * @author Ilija Vukotic <ivukotic@cern.ch>, scott snyder <snyder@bnl.gov>
7 * @date May, 2007
8 * @brief T/P conversions for CaloCellLinkContainerCnv_p2.
9 */
10
11
12#include "AthLinks/ElementLink.h"
19
20#include "CxxUtils/fpcompare.h"
21
22#include <vector>
23#include <algorithm>
24#include <cmath>
25
26using namespace std;
27
28
29namespace {
30
31
35struct cell_t
36{
37 cell_t (int the_cell = 0,
38 float the_weight = 0)
39 : cell (the_cell), weight (the_weight) {}
40 bool operator< (const cell_t& other) const { return cell < other.cell; }
41 bool operator== (const cell_t& other) const { return cell == other.cell; }
42
44 int cell;
45
47 float weight;
48};
49
50
52const float NWEIGHT_SCALE = 1000;
53
55const int INDEX_BITS = 18;
56
58const unsigned int INDEX_MASK = (1<<INDEX_BITS) - 1;
59
61const int ISEQ_BITS = 32 - INDEX_BITS;
62
64const unsigned int ISEQ_MAX = (1 << ISEQ_BITS) - 1;
65
66
67} // anonymous namespace
68
69
76void
79 const std::string& /*key*/,
80 MsgStream& /*log*/) const
81{
82 trans->clear();
83 trans->resize(pers->m_nClusters);
84
85 if (pers->m_nClusters > pers->m_vISizes.size() ||
86 pers->m_nClusters > pers->m_vWSizes.size())
87 {
88 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
89 "CaloCellLinkContainerCnv_p2")
90 << "Inconsistent sequence array lengths: "
91 << pers->m_nClusters
92 << " " << pers->m_vISizes.size()
93 << " " << pers->m_vWSizes.size() << "\n";
94 return;
95 }
96
97 std::vector<unsigned>::const_iterator cIterI = pers->m_linkI.begin();
98 std::vector<unsigned>::const_iterator cIterIe = pers->m_linkI.end();
99 std::vector<float>::const_iterator cIterW = pers->m_linkW.begin();
100 std::vector<float>::const_iterator cIterWe = pers->m_linkW.end();
101
102 for (unsigned int iCluster=0; iCluster<pers->m_nClusters; iCluster++) {
103
104 std::vector<float>::const_iterator cIterWb = cIterW;
105
106 bool bad = false;
107 CaloCellLink* lnk=new CaloCellLink();
108 trans->at(iCluster)=lnk; // puts an empty link == cluster
109
110 float weight = 0;
111 unsigned int nw = 0;
112
113 // Get number of cells and pre-allocate vector.
114 unsigned int ncells = 0;
115 for(unsigned iCell=0; iCell<pers->m_vISizes[iCluster]; iCell++) {
116 if (cIterI >= cIterIe) {
117 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
118 "CaloCellLinkContainerCnv_p2")
119 << "Cell index array overrun";
120 bad = true;
121 goto endcells;
122 }
123 ncells += (*(cIterI+iCell)) >> INDEX_BITS;
124 }
125 if (ncells > 1000) ncells = 1000; // Don't go crazy.
126
127 // Unpacking indices and making links
128 for(unsigned iCell=0; iCell<pers->m_vISizes[iCluster]; iCell++) {
129 unsigned int compositeI = *cIterI++;
130 unsigned int realI = compositeI & INDEX_MASK;
131 unsigned int lSEQ = compositeI>>INDEX_BITS;
132 for(unsigned seq=0;seq<lSEQ;seq++) {
133 if (nw == 0) {
134 if (cIterW >= cIterWe) {
135 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
136 "CaloCellLinkContainerCnv_p2")
137 << "Cell weight array overrun";
138 bad = true;
139 goto endcells;
140 }
141 float compositeW = *cIterW++;
142 nw = static_cast<unsigned int> (compositeW*(1./NWEIGHT_SCALE));
143 weight = compositeW - (nw*NWEIGHT_SCALE);
144 }
145
146 ElementLink<CaloCellContainer> el_link(pers->m_contName, realI+seq);
147 lnk->insertElement (el_link, weight, ncells);
148 --nw;
149 }
150 }//End loop over cells in cluster
151
152 if (nw != 0) {
153 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
154 "CaloCellLinkContainerCnv_p2")
155 << "Weight/index arrays out of sync";
156 bad = true;
157 }
158
159 if (cIterW - cIterWb != static_cast<int> (pers->m_vWSizes[iCluster])) {
160 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
161 "CaloCellLinkContainerCnv_p2")
162 << "Wrong number of weight sequences";
163 bad = true;
164 }
165 endcells:
166
167 if (lnk->size() > 0 && pers->m_contName.empty()) {
168 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
169 "CaloCellLinkContainerCnv_p2")
170 << "Missing cell container name";
171 bad = true;
172 }
173
174 if (bad) {
175 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
176 "CaloCellLinkContainerCnv_p2")
177 << "Discarding cluster cells";
178 lnk->removeAll();
179 }
180
181 } // End loop over clusters
182}
183
184
191void
194 const std::string& /*key*/,
195 MsgStream& /*log*/) const
196{
197 unsigned int nclus = trans->size();
198 pers->m_nClusters = nclus; // number of clusters in container
199
200 // Gives it size of trans container ->
201 // will store number of indices per cluster.
202 pers->m_vISizes.resize(nclus);
203 pers->m_vWSizes.resize(nclus);
204
205 // Guess.
206 pers->m_linkI.reserve (5*nclus);
207 pers->m_linkW.reserve (5*nclus);
208
209 pers->m_contName.clear();
210 SG::sgkey_t first_key = 0;
211
212
213 const SG::ThinningCache* thinningCache = SG::getThinningCache();
214
215 // Declare this outside the loop to save on memory allocations.
216 std::vector<cell_t> cells;
217 for (unsigned int iCluster = 0; iCluster < nclus; ++iCluster) {
218
219 // This is actually a Navigable - contains links to the cells.
220 const CaloCellLink& lnk = *(*trans)[iCluster];
221
222 cells.clear();
223 cells.reserve (lnk.size()+1);
224 CaloCellLink::cell_iterator it_cell = lnk.begin();
225 CaloCellLink::cell_iterator it_cell_e = lnk.end();
226
227 for (;it_cell!=it_cell_e;it_cell++) { // Loop over cells in cluster.
229 it_cell.getInternalIterator();
230
231 // Put stuff into array for later sorting.
232 float weight = citer->second;
233 // Trying to store weights > NWEIGHT_SCALE will lead to corrupted data.
234 if (fabs (weight) > NWEIGHT_SCALE) {
235 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
236 "CaloCellLinkContainerCnv_p2")
237 << "Crazy cluster cell weight " << weight
238 << " reset to 1";
239 weight = 1;
240 }
241
242 size_t index = citer->first.index();
243
244 // Handle thinning.
245 if (thinningCache){
246 const SG::ThinningDecisionBase* dec =
247 thinningCache->thinning (citer->first.key());
248 if (dec) {
249 size_t persIdx = dec->index (index);
250
251 if( SG::ThinningDecisionBase::RemovedIdx == persIdx ) {
252 // Cell index has been thinned away; skip all cells.
253 cells.clear();
254 break;
255
256 }else
257 {
258 index = persIdx;
259 }
260 }
261 }
262
263 SG::sgkey_t key = citer->first.key();
264 citer->first.source()->tryELRemap (key, index, key, index);
265
266 if (pers->m_contName.empty()) {
267 pers->m_contName = *citer->first.source()->keyToString (key);
268 first_key = key;
269 }
270 else if (first_key != key) {
271 REPORT_MESSAGE_WITH_CONTEXT (MSG::ERROR,
272 "CaloCellLinkContainerCnv_p2")
273 << "Multiple container names seen; "
274 << "cannot be persistified correctly: "
275 << pers->m_contName
276 << " != " << *citer->first.source()->keyToString (key)
277 << "; cell skipped";
278 continue;
279 }
280
281 if ((index & ~INDEX_MASK) != 0) {
282 REPORT_MESSAGE_WITH_CONTEXT (MSG::WARNING,
283 "CaloCellLinkContainerCnv_p2")
284 << "Bad cell index " << index
285 << " had high bits masked off.";
286 index &= INDEX_MASK;
287 }
288 cells.push_back (cell_t (index, weight));
289 } // End loop over cells
290
291 // Sort links according to cell indices.
292 std::sort (cells.begin(), cells.end());
293
294 unsigned int& nlseq = pers->m_vISizes[iCluster];
295 unsigned int& nwseq = pers->m_vWSizes[iCluster];
296 nlseq = 0;
297 nwseq = 0;
298 int last_cell = -9999;
299 float last_weight = -9999;
300 unsigned int nl_in_seq = 0;
301 unsigned int nw_in_seq = 0;
302
303 // Sentinel.
304 cells.push_back (cell_t (-99999, -99999));
305
306 size_t ncells = cells.size();
307 for (size_t i = 0; i < ncells; ++i) {
308 const cell_t& cell = cells[i];
309
310 if (last_cell >= 0 && static_cast<int>(last_cell + nl_in_seq) == cell.cell &&
311 nl_in_seq < ISEQ_MAX)
312 {
313 ++nl_in_seq;
314 }
315 else {
316 if (nl_in_seq) {
317 pers->m_linkI.push_back (last_cell | (nl_in_seq << INDEX_BITS));
318 ++nlseq;
319 }
320 last_cell = cell.cell;
321 nl_in_seq = 1;
322 }
323
324 // Don't let the weight sequence length get too large,
325 // or we'll lose precision on the weight. A limit of 255
326 // allows the weight to be represented within ~0.02.
327 //
328 // We also need to be careful comparing weights.
329 // Because we lose precision due to adding the sequence length,
330 // it's possible to have a case where last_weight != cell.weight,
331 // but they're equal after packing. That means that if we
332 // then copy the data, the persistent data won't be exactly
333 // the same. Try to take this into account in the comparison.
334 float w1 = (nw_in_seq+1)*NWEIGHT_SCALE + last_weight;
335 float w2 = (nw_in_seq+1)*NWEIGHT_SCALE + cell.weight;
337 if (equal (nextafterf (w1, w2), w2) && nw_in_seq < 255)
338 {
339 ++nw_in_seq;
340 }
341 else {
342 if (nw_in_seq) {
343 pers->m_linkW.push_back (nw_in_seq*NWEIGHT_SCALE + last_weight);
344 ++nwseq;
345 }
346 last_weight = cell.weight;
347 nw_in_seq = 1;
348 }
349 }
350 } // End loop over clusters
351}
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME)
Report a message, with an explicitly specified context name.
bool operator<(const DataVector< T > &a, const DataVector< T > &b)
Vector ordering relation.
bool operator==(const DataVector< T > &a, const DataVector< T > &b)
Vector equality comparison.
Hold thinning decisions for one container.
virtual void transToPersWithKey(const CaloCellLinkContainer *trans, CaloCellLinkContainer_p2 *pers, const std::string &key, MsgStream &log) const override
Convert from transient to persistent object.
virtual void persToTransWithKey(const CaloCellLinkContainer_p2 *pers, CaloCellLinkContainer *trans, const std::string &key, MsgStream &log) const override
Convert from persistent to transient object.
COLL::const_iterator getInternalIterator() const
virtual unsigned int size() const
virtual object_iter begin() const
bool removeAll()
Definition Navigable.h:237
void insertElement(const CONT *objectContainer, const constituent_type *constituentObject, const RPAR &objectParameter=RPAR(), size_t sizeHint=0)
virtual object_iter end() const
constituent_coll::const_iterator constituent_const_iter
Definition Navigable.h:103
Cache thinning decisions for converters.
const ThinningDecisionBase * thinning(const std::string &key) const
Return thinning for key.
Hold thinning decisions for one container.
static const std::size_t RemovedIdx
Flag used to show that an index has been thinned away.
size_t index(size_t ndxOrig) const
Return the index corresponding to ndxOrig after thinning.
TH1F * trans(TH1F *h, bool t=false)
Workaround x86 precision issues for FP inequality comparisons.
Helpers to retrieve the current thinning cache from the event context.
bool equal(double a, double b)
Compare two FP numbers, working around x87 precision issues.
Definition fpcompare.h:114
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition sgkey_t.h:32
const SG::ThinningCache * getThinningCache()
Retrieve the current thinning cache from the current event context.
Definition index.py:1
STL namespace.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.