ATLAS Offline Software
CaloCellLinkContainerCnv_p2.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 // $Id: CaloCellLinkContainerCnv_p2.cxx,v 1.9 2009-02-18 22:50:08 hma Exp $
6 /* @file CaloCellLinkContainerCnv_p2.cxx
7  * @author Ilija Vukotic <ivukotic@cern.ch>, scott snyder <snyder@bnl.gov>
8  * @date May, 2007
9  * @brief T/P conversions for CaloCellLinkContainerCnv_p2.
10  */
11 
12 
13 #include "AthLinks/ElementLink.h"
19 
20 #include "CxxUtils/fpcompare.h"
21 
22 #include <vector>
23 #include <algorithm>
24 #include <cmath>
25 
26 using namespace std;
27 
28 
29 namespace {
30 
31 
35 struct 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 
52 const float NWEIGHT_SCALE = 1000;
53 
55 const int INDEX_BITS = 18;
56 
58 const unsigned int INDEX_MASK = (1<<INDEX_BITS) - 1;
59 
61 const int ISEQ_BITS = 32 - INDEX_BITS;
62 
64 const unsigned int ISEQ_MAX = (1 << ISEQ_BITS) - 1;
65 
66 
67 } // anonymous namespace
68 
69 
76 void
78  CaloCellLinkContainer* trans,
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 
191 void
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 (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 }
test_athena_ntuple_filter.seq
seq
filter configuration ## -> we use the special sequence 'AthMasterSeq' which is run before any other a...
Definition: test_athena_ntuple_filter.py:18
bad
@ bad
Definition: SUSYToolsTester.cxx:100
operator<
bool operator<(const DataVector< T > &a, const DataVector< T > &b)
Vector ordering relation.
RunTileCalibRec.cells
cells
Definition: RunTileCalibRec.py:271
operator==
bool operator==(const DataVector< T > &a, const DataVector< T > &b)
Vector equality comparison.
ReadCellNoiseFromCool.cell
cell
Definition: ReadCellNoiseFromCool.py:53
Navigable::removeAll
bool removeAll()
Definition: Navigable.h:237
index
Definition: index.py:1
SG::ThinningDecisionBase
Hold thinning decisions for one container.
Definition: ThinningDecisionBase.h:39
Navigable::insertElement
void insertElement(const CONT *objectContainer, const constituent_type *constituentObject, const RPAR &objectParameter=RPAR(), size_t sizeHint=0)
Navigable::begin
virtual object_iter begin() const
ThinningDecisionBase.h
Hold thinning decisions for one container.
Navigable::end
virtual object_iter end() const
CxxUtils::fpcompare::equal
bool equal(double a, double b)
Compare two FP numbers, working around x87 precision issues.
Definition: fpcompare.h:114
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:189
CaloCellLinkContainerCnv_p2::persToTransWithKey
virtual void persToTransWithKey(const CaloCellLinkContainer_p2 *pers, CaloCellLinkContainer *trans, const std::string &key, MsgStream &log) const override
Convert from persistent to transient object.
Definition: CaloCellLinkContainerCnv_p2.cxx:77
lumiFormat.i
int i
Definition: lumiFormat.py:85
fpcompare.h
Workaround x86 precision issues for FP inequality comparisons.
CaloCellLinkContainerCnv_p2::transToPersWithKey
virtual void transToPersWithKey(const CaloCellLinkContainer *trans, CaloCellLinkContainer_p2 *pers, const std::string &key, MsgStream &log) const override
Convert from transient to persistent object.
Definition: CaloCellLinkContainerCnv_p2.cxx:192
getThinningCache.h
Helpers to retrieve the current thinning cache from the event context.
SG::ThinningDecisionBase::RemovedIdx
static const std::size_t RemovedIdx
Flag used to show that an index has been thinned away.
Definition: ThinningDecisionBase.h:42
SG::getThinningCache
const SG::ThinningCache * getThinningCache(const EventContext &ctx)
Retrieve the current thinning cache from the event context.
Definition: getThinningCache.cxx:28
DataVector::clear
void clear()
Erase all the elements in the collection.
REPORT_MESSAGE_WITH_CONTEXT
#define REPORT_MESSAGE_WITH_CONTEXT(LVL, CONTEXT_NAME)
Report a message, with an explicitly specified context name.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:345
DataVector::resize
void resize(size_type sz)
Resizes the collection to the specified number of elements.
CaloCellLinkContainerCnv_p2.h
errorcheck.h
Helpers for checking error return status codes and reporting errors.
SG::sgkey_t
uint32_t sgkey_t
Type used for hashed StoreGate key+CLID pairs.
Definition: CxxUtils/CxxUtils/sgkey_t.h:32
Navigable
Navigable template generalization to handle navigation.
Definition: Navigable.h:93
SG::ThinningDecisionBase::index
size_t index(size_t ndxOrig) const
Return the index corresponding to ndxOrig after thinning.
SG::ThinningCache::thinning
const ThinningDecisionBase * thinning(const std::string &key) const
Return thinning for key.
Definition: ThinningCache.cxx:36
InDetDD::other
@ other
Definition: InDetDD_Defs.h:16
Navigable::size
virtual unsigned int size() const
std::sort
void sort(typename std::reverse_iterator< DataModel_detail::iterator< DVL > > beg, typename std::reverse_iterator< DataModel_detail::iterator< DVL > > end, const Compare &comp)
Specialization of sort for DataVector/List.
Definition: DVL_algorithms.h:623
if
if(febId1==febId2)
Definition: LArRodBlockPhysicsV0.cxx:567
DataVector::at
const T * at(size_type n) const
Access an element, as an rvalue.
SG::ThinningCache
Cache thinning decisions for converters.
Definition: ThinningCache.h:48
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37
ThinningCache.h