ATLAS Offline Software
Loading...
Searching...
No Matches
CaloSuperCellIDTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
10
11
12#include "CaloSuperCellIDTool.h"
17#include <format>
18
19#include <iostream>
20
21
22namespace {
23
24
25int posneg_or_section (const CaloCell_Base_ID* idhelper, Identifier id)
26{
27 if (idhelper->is_tile (id))
28 return idhelper->section (id);
29 return idhelper->pos_neg (id);
30}
31
32
33int sampling_or_side (const CaloCell_Base_ID* idhelper, Identifier id)
34{
35 if (idhelper->is_tile (id))
36 return idhelper->side (id);
37 return idhelper->sampling (id);
38}
39
40
41} // anonymous namespace
42
43
44
45
53 const std::string& name,
54 const IInterface* parent)
55 : base_class (type, name, parent),
56 m_cell_helper(nullptr),
57 m_sc_helper(nullptr)
58{
59}
60
61
66{
67 CHECK( base_class::initialize() );
68 CHECK( detStore()->retrieve (m_cell_helper, "CaloCell_ID") );
69 CHECK( detStore()->retrieve (m_sc_helper, "CaloCell_SuperCell_ID") );
70
71 initIDMap ();
72
73 return StatusCode::SUCCESS;
74}
75
76
81{
82 m_offlineIndex.clear();
83 m_superCellIndex.clear();
84 m_superCellIndexEnd.clear();
85 m_idmap.clear();
86
87 // One entry in the index tables for each region hash; -1 means no entry.
88 m_offlineIndex.resize (m_cell_helper->calo_region_hash_max(), -1);
89 m_superCellIndex.resize (m_sc_helper->calo_region_hash_max(), -1);
90 m_superCellIndexEnd.resize (m_sc_helper->calo_region_hash_max(), -1);
91
92 // Loop over all offline regions.
93 for (const Identifier& cell_reg : m_cell_helper->reg_range()) {
94 if (m_cell_helper->is_em(cell_reg) ||
95 m_cell_helper->is_hec(cell_reg) ||
96 m_cell_helper->is_fcal(cell_reg))
97 {
98 int sub_calo = m_cell_helper->sub_calo (cell_reg);
99 int pos_neg = m_cell_helper->pos_neg (cell_reg);
100 int sampling = m_cell_helper->sampling (cell_reg);
101 int cell_ietamin = m_cell_helper->eta_min (cell_reg);
102 int cell_ietamax = m_cell_helper->eta_max (cell_reg);
103 float cell_etasize = m_cell_helper->etaGranularity(cell_reg);
104 float inv_cell_etasize = 1. / cell_etasize;
105 // The condition here will never be true, but we put it in to
106 // prevent the compiler from attempting to vectorize the two divisions
107 // here. On x86_64, the two single-precision divisions take
108 // two vector lanes leaving two unused. The two unused ones
109 // can end up with zeros in the denominator leading to a spurious FPE.
110 if (inv_cell_etasize < 0) break;
111 float cell_phisize = m_cell_helper->phiGranularity(cell_reg);
112 float inv_cell_phisize = 1. / cell_phisize;
113 float cell_etamin = m_cell_helper->eta0 (cell_reg);
114 float cell_etamax = cell_etamin +
115 cell_etasize*(cell_ietamax - cell_ietamin + 1);
116
117 // Find all overlapping supercell regions in the same sampling
118 // and make table entries. HEC supercells are summed
119 // over samplings, so don't make sampling requirements there.
120 for (const Identifier& sc_reg : m_sc_helper->reg_range()) {
121 if (m_sc_helper->sub_calo (sc_reg) == sub_calo &&
122 m_sc_helper->pos_neg (sc_reg) == pos_neg &&
123 (sub_calo == CaloCell_ID::LARHEC ||
124 m_sc_helper->sampling (sc_reg) == sampling))
125 {
126 int sc_ietamin = m_sc_helper->eta_min (sc_reg);
127 int sc_ietamax = m_sc_helper->eta_max (sc_reg);
128 float sc_etasize = m_sc_helper->etaGranularity(sc_reg);
129 float sc_phisize = m_sc_helper->phiGranularity(sc_reg);
130 float sc_etamin = m_sc_helper->eta0 (sc_reg);
131 float sc_etamax= sc_etamin + sc_etasize*(sc_ietamax - sc_ietamin + 1);
132
133 // Find the overlap between the offline and supercell regions.
134 float etamin = std::max (cell_etamin, sc_etamin);
135 float etamax = std::min (cell_etamax, sc_etamax);
136
137 if (etamin < etamax - 1e-4) {
138 // There's overlap --- make a table entry.
139 IDMapElt elt;
140 elt.m_cell_reg = m_cell_helper->calo_region_hash (cell_reg);
141 elt.m_sc_reg = m_sc_helper->calo_region_hash (sc_reg);
142 elt.m_etadiv = int (sc_etasize * inv_cell_etasize + 0.1);
143 elt.m_phidiv = int (sc_phisize * inv_cell_phisize + 0.1);
144
145 if (sub_calo == CaloCell_ID::LARHEC) {
146 // FIXME: Shouldn't have to special-case this.
147 elt.m_cell_ieta_adj = 0;
148 elt.m_sc_ieta_adj = 0;
149 }
150 else {
151 elt.m_cell_ieta_adj = cell_ietamin;
152 elt.m_sc_ieta_adj = sc_ietamin;
153 }
154
155 elt.m_cell_ietamin = int ((etamin - cell_etamin) * inv_cell_etasize +
156 cell_ietamin + 0.1);
157 elt.m_cell_ietamax = int ((etamax - cell_etamin) * inv_cell_etasize +
158 cell_ietamin - 0.1);
159 const float inv_sc_etasize = 1. / sc_etasize;
160 elt.m_sc_ietamin = int ((etamin - sc_etamin) * inv_sc_etasize +
161 sc_ietamin + 0.1);
162 elt.m_sc_ietamax = int ((etamax - sc_etamin) * inv_sc_etasize +
163 sc_ietamin - 0.1);
164
165 addMapEntry (elt);
166 }
167 }
168 }
169 }
170 else if (m_cell_helper->is_tile(cell_reg)) {
171 int section = m_cell_helper->section (cell_reg);
173 continue;
174 int sub_calo = m_cell_helper->sub_calo (cell_reg);
175 int side = m_cell_helper->side (cell_reg);
176 Identifier sc_reg = m_sc_helper->region_id (sub_calo, section, side, 0);
177
178 IDMapElt elt;
179 elt.m_cell_reg = m_cell_helper->calo_region_hash (cell_reg);
180 elt.m_sc_reg = m_sc_helper->calo_region_hash (sc_reg);
181 elt.m_etadiv = 1;
182 elt.m_phidiv = 1;
183 elt.m_cell_ieta_adj = 0;
184 elt.m_sc_ieta_adj = 0;
185 elt.m_cell_ietamin = m_cell_helper->eta_min (cell_reg);
186 elt.m_cell_ietamax = m_cell_helper->eta_max (cell_reg);
187 elt.m_sc_ietamin = m_sc_helper->eta_min (sc_reg);
188 elt.m_sc_ietamax = m_sc_helper->eta_max (sc_reg);
189 addMapEntry (elt);
190 }
191 }
192
193
194 // Allow dumping the mapping table for validation.
195 if (msgLvl (MSG::DEBUG)) {
196 msg(MSG::DEBUG) << "CaloSuperCellIDTool mapping table:\n";
197 msg(MSG::DEBUG) << "LArEM ----------------------------\n";
198 for (const IDMapElt& elt : m_idmap) {
199 Identifier cell_reg = m_cell_helper->region_id (elt.m_cell_reg);
200 Identifier sc_reg = m_sc_helper->region_id (elt.m_sc_reg);
201 msg(MSG::DEBUG) <<
202 std::format(" {:3d} {}/{:2d}/{:2d}/{} {:3d} {}/{:2d}/{:2d}/{} {} {} {:3d} {:3d} {:3d} {:3d} {:3d} {:3d}\n",
203 static_cast<int>(elt.m_cell_reg),
204 m_cell_helper->sub_calo(cell_reg),
205 posneg_or_section(m_cell_helper, cell_reg),
206 sampling_or_side(m_cell_helper, cell_reg),
207 m_cell_helper->region(cell_reg),
208 static_cast<int>(elt.m_sc_reg),
209 m_sc_helper->sub_calo(sc_reg),
210 posneg_or_section(m_sc_helper, sc_reg),
211 sampling_or_side(m_sc_helper, sc_reg),
212 m_sc_helper->region(sc_reg),
213 elt.m_etadiv, elt.m_phidiv,
214 elt.m_cell_ietamin, elt.m_cell_ietamax,
215 elt.m_sc_ietamin, elt.m_sc_ietamax,
216 elt.m_cell_ieta_adj, elt.m_sc_ieta_adj);
217 }
218 msg(MSG::DEBUG) << endmsg;
219 }
220
222
223 msg(MSG::INFO ) << "Done with initIDMap" << endmsg;
224}
225
226
231{
232 assert (elt.m_cell_reg < m_offlineIndex.size());
233 if (m_offlineIndex[elt.m_cell_reg] == -1)
234 m_offlineIndex[elt.m_cell_reg] = m_idmap.size();
235
236 assert (elt.m_sc_reg < m_superCellIndex.size());
237 if (m_superCellIndex[elt.m_sc_reg] == -1)
238 m_superCellIndex[elt.m_sc_reg] = m_idmap.size();
239 assert (elt.m_sc_reg < m_superCellIndexEnd.size());
240 m_superCellIndexEnd[elt.m_sc_reg] = m_idmap.size()+1;
241
242 m_idmap.push_back (elt);
243}
244
245
250{
251 const LArFCAL_Base_ID* sfcal_helper = m_sc_helper->fcal_idHelper();
252 const LArFCAL_Base_ID* fcal_helper = m_cell_helper->fcal_idHelper();
253
254 m_fcal_fromCell.clear();
255 m_fcal_fromSuperCell.clear();
256 m_fcal_fromCell.resize(fcal_helper->channel_hash_max());
257 m_fcal_fromSuperCell.resize(sfcal_helper->channel_hash_max());
258
259 for (const Identifier& cell_id : fcal_helper->fcal_range()) {
260 const int sc_phi = fcal_helper->phi (cell_id);
261 const int sc_lay = fcal_helper->module (cell_id);
262 const int cell_ieta = fcal_helper->eta (cell_id);
263 int sc_pn = fcal_helper->pos_neg( cell_id );
264 int sc_ieta = -1;
265 if (sc_lay==3) {
266 sc_ieta = cell_ieta / 4;
267 }
268 else if (sc_lay==2) {
269 sc_ieta = cell_ieta / 4;
270 }
271 else if (sc_lay==1) {
272 if (cell_ieta < 16)
273 sc_ieta = 0;
274 else if (cell_ieta < 24)
275 sc_ieta = 1;
276 else
277 sc_ieta = 2 + (cell_ieta-24)/4;
278 }
279 Identifier sc_id = sfcal_helper->channel_id(sc_pn, sc_lay, sc_ieta, sc_phi);
280 IdentifierHash sc_hash = sfcal_helper->channel_hash( sc_id );
281 IdentifierHash cell_hash = fcal_helper->channel_hash( cell_id );
282 m_fcal_fromCell[ cell_hash ] = sc_id;
283 m_fcal_fromSuperCell[ sc_hash ].push_back( cell_id );
284 }
285
286 // Allow dumping the mapping table for validation.
287 if (msgLvl (MSG::DEBUG)) {
288 msg(MSG::DEBUG) << "\n LArFCAL ---------------------------\n";
289 for (const Identifier& sc_id : sfcal_helper->fcal_range()) {
290 IdentifierHash sc_hash = sfcal_helper->channel_hash( sc_id );
291 std::vector<Identifier> cells = m_fcal_fromSuperCell[ sc_hash ];
292 msg(MSG::DEBUG) <<
293 std::format(" {:5d} {:2d}/{:2d}/{:2d}/{:2d} ... {:2d} cells\n",
294 static_cast<int>(sc_hash),
295 static_cast<int>(sfcal_helper->pos_neg(sc_id)),
296 static_cast<int>(sfcal_helper->module(sc_id)),
297 static_cast<int>(sfcal_helper->eta(sc_id)),
298 static_cast<int>(sfcal_helper->phi(sc_id)),
299 static_cast<int>(cells.size()));
300 }
301 msg(MSG::DEBUG) << endmsg;
302 }
303}
304
305
313{
314 if (m_cell_helper->is_em(id) || m_cell_helper->is_hec(id)) {
315 // Look for the first entry in the mapping table for this offline region.
316 Identifier reg_id = m_cell_helper->region_id (id);
317 IdentifierHash rhash = m_cell_helper->calo_region_hash (reg_id);
318 assert (rhash < m_offlineIndex.size());
319 int ndx = m_offlineIndex[rhash];
320 if (ndx < 0)
321 return {};
322
323 // Now search through all entries for this offline region to find one
324 // that includes this cell.
325 int ieta = m_cell_helper->eta (id);
326
327 do {
328 const IDMapElt& elt = m_idmap[ndx];
329 if (elt.m_cell_ietamin <= ieta && elt.m_cell_ietamax >= ieta) {
330 // Found a matching entry. Calculate the corresponding supercell
331 // indices and return the new ID.
332
333 int ieta_sc = ((ieta - elt.m_cell_ietamin + elt.m_cell_ieta_adj) /
334 elt.m_etadiv) +
335 elt.m_sc_ietamin - elt.m_sc_ieta_adj;
336
337 return m_sc_helper->cell_id (m_sc_helper->region_id (elt.m_sc_reg),
338 ieta_sc,
339 m_cell_helper->phi(id) / elt.m_phidiv);
340 }
341 ++ndx;
342 } while (ndx < (int)m_idmap.size() && m_idmap[ndx].m_cell_reg == rhash);
343 }
344
345 else if (m_cell_helper->is_fcal(id)) {
346 const LArFCAL_ID* fcal_helper = m_cell_helper->fcal_idHelper();
347 IdentifierHash cell_hash = fcal_helper->channel_hash(id);
348 return m_fcal_fromCell[ cell_hash ];
349 }
350
351 else if (m_cell_helper->is_tile(id)) {
352 int section = m_cell_helper->section (id);
353 int sample_offline = m_cell_helper->sample(id);
354 int tower = m_cell_helper->tower(id);
355
356 // A couple special cases in the transition region.
357 // cf. http://hep.uchicago.edu/atlas/tilecal/level1/geometry.html
358 // The cell at the end of the barrel is grouped with barrel cells,
359 // rather than with the endcap cells at the same eta, and analogously
360 // for the D4 cell.
361 // Be careful: tower indices start with 0 here, but with 1 on the
362 // referenced diagram.
363 //
364
365 if (section == TileID::BARREL && tower == 9 &&
366 sample_offline == TileID::SAMP_A)
367 {
368 tower = 8;
369 }
370 else if (section == TileID::GAPDET && tower == 9 &&
371 sample_offline == TileID::SAMP_C)
372 {
374 }
375
376 else if (section == TileID::GAPDET && tower == 8 &&
377 sample_offline == TileID::SAMP_D)
378 {
379 tower = 9;
381 }
382
384 return {};
385
386 int sample_sc = sample_offline;
387 if (sample_sc != TileID::SAMP_D) sample_sc = TileID::SAMP_A;
388
389 return m_sc_helper->cell_id (m_cell_helper->sub_calo(id),
390 section,
391 m_cell_helper->side(id),
392 m_cell_helper->module(id),
393 tower,
394 sample_sc);
395 }
396
397 return {};
398}
399
400
405std::vector<Identifier>
407{
408 std::vector<Identifier> out;
409
410 // Look for the first entry in the mapping table for this supercell region.
411 if (m_sc_helper->is_em (id) || m_sc_helper->is_hec (id)) {
412 Identifier reg_id = m_sc_helper->region_id (id);
413 IdentifierHash rhash = m_sc_helper->calo_region_hash (reg_id);
414 assert (rhash < m_superCellIndex.size());
415 int ndx = m_superCellIndex[rhash];
416 if (ndx < 0)
417 return out;
418 int end = m_superCellIndexEnd[rhash];
419 if (end < 0)
420 return out;
421
422 // Now search through all entries for this supercell region to find one
423 // that includes this supercell.
424 int ieta = m_sc_helper->eta (id);
425
426 for (; ndx < end; ++ndx) {
427 const IDMapElt& elt = m_idmap[ndx];
428 if (elt.m_sc_reg == rhash &&
429 elt.m_sc_ietamin <= ieta &&
430 elt.m_sc_ietamax >= ieta)
431 {
432 // Found a matching entry.
433 // Find the overlapping eta range in the offline region.
434
435 int ieta0 = (ieta - elt.m_sc_ietamin + elt.m_sc_ieta_adj) * elt.m_etadiv +
437 Identifier cell_reg_id = m_cell_helper->region_id (elt.m_cell_reg);
438 int ieta = std::max (ieta0, elt.m_cell_ietamin);
439 int ietamax = std::min (ieta0 + elt.m_etadiv - 1, elt.m_cell_ietamax);
440
441 // Add all matching cells to the output list.
442 int iphi0 = m_sc_helper->phi (id) * elt.m_phidiv;
443 for (; ieta <= ietamax; ++ieta) {
444 for (int ip = 0; ip < elt.m_phidiv; ip++) {
445 out.push_back(m_cell_helper->cell_id (cell_reg_id, ieta, iphi0+ip));
446 }
447 }
448 }
449 }
450 }
451
452 else if ( m_sc_helper->is_fcal( id ) ) {
453 const LArFCAL_Base_ID* sfcal_helper = m_sc_helper->fcal_idHelper();
454 IdentifierHash sc_hash = sfcal_helper->channel_hash( id );
455 out = m_fcal_fromSuperCell[ sc_hash ];
456 }
457
458 else if (m_sc_helper->is_tile (id)) {
459 int module = m_sc_helper->module(id);
460 int tower = m_sc_helper->tower(id);
461 int sample = m_sc_helper->sample(id);
462
463 const Tile_Base_ID* tile_helper = m_cell_helper->tile_idHelper();
464
465 Identifier reg_id = tile_helper->region_id (m_sc_helper->section(id),
466 m_sc_helper->side(id));
467
468 Identifier cell_id;
469
470 // Transition region special cases.
471 if (tower == 8 && sample == TileID::SAMP_A) {
472 if (tile_helper->cell_id (reg_id, module, 9, sample, cell_id))
473 out.push_back (cell_id);
474 }
475 if (tower == 9) {
476 Identifier greg_id = tile_helper->region_id (TileID::GAPDET,
477 m_sc_helper->side(id));
478 if (tile_helper->cell_id (greg_id, module, 8, TileID::SAMP_D, cell_id))
479 out.push_back (cell_id);
480 if (sample == TileID::SAMP_A) {
481 if (tile_helper->cell_id (greg_id, module, 9, TileID::SAMP_C, cell_id))
482 out.push_back (cell_id);
483 }
484 return out;
485 }
486
487
488 if (tile_helper->cell_id (reg_id, module, tower, sample, cell_id))
489 out.push_back (cell_id);
490
491 if (sample == TileID::SAMP_A) {
492 if(tile_helper->cell_id(reg_id, module, tower, TileID::SAMP_BC, cell_id))
493 out.push_back (cell_id);
494 if(tile_helper->cell_id(reg_id, module, tower, TileID::SAMP_D, cell_id))
495 out.push_back (cell_id);
496 }
497 }
498
499 return out;
500}
501
502
510std::vector<Identifier>
512{
513 std::vector<Identifier> out;
514
515 // Look for the first entry in the mapping table for this offline region.
516 IdentifierHash rhash = m_cell_helper->calo_region_hash (reg_id);
517 assert (rhash < m_offlineIndex.size());
518 int ndx = m_offlineIndex[rhash];
519 while (ndx >= 0 &&
520 ndx < (int)m_idmap.size() &&
521 m_idmap[ndx].m_cell_reg == rhash)
522 {
523 out.push_back (m_sc_helper->region_id (m_idmap[ndx].m_sc_reg));
524 ++ndx;
525 }
526
527 return out;
528}
529
530
538std::vector<Identifier>
540{
541 std::vector<Identifier> out;
542
543 // Look for the first entry in the mapping table for this offline region.
544 IdentifierHash rhash = m_sc_helper->calo_region_hash (reg_id);
545 assert (rhash < m_superCellIndex.size());
546 int ndx = m_superCellIndex[rhash];
547 int end = m_superCellIndexEnd[rhash];
548 for (; ndx < end; ++ndx) {
549 if (m_idmap[ndx].m_sc_reg == rhash)
550 out.push_back (m_cell_helper->region_id (m_idmap[ndx].m_cell_reg));
551 }
552
553 return out;
554}
555
#define endmsg
Helper base class for offline cell identifiers.
Helper class for offline supercell identifiers.
Tool to map between calorimeter cells and supercells.
Helpers for checking error return status codes and reporting errors.
#define CHECK(...)
Evaluate an expression and check for errors.
void section(const std::string &sec)
Helper base class for offline cell identifiers.
int sampling(const Identifier id) const
LAr field values (NOT_VALID == invalid request)
int section(const Identifier id) const
Tile field values (NOT_VALID == invalid request)
int side(const Identifier id) const
Tile field values (NOT_VALID == invalid request)
bool is_tile(const Identifier id) const
test if the id belongs to the Tiles
int pos_neg(const Identifier id) const
LAr field values (NOT_VALID == invalid request)
size_type channel_hash_max() const
One more than the largest channel (cell) hash code.
std::vector< std::vector< Identifier > > m_fcal_fromSuperCell
std::vector< int > m_superCellIndex
Entry I contains the index in the mapping table of the first entry for the supercell region with hash...
void initFCALIDMap()
FCAL is a special case.
virtual StatusCode initialize()
Standard Gaudi initialize method.
virtual Identifier offlineToSuperCellID(const Identifier &id) const
Given an offline cell identifier, return the corresponding supercell identifier.
std::vector< IDMapElt > m_idmap
List of mapping table entries.
virtual std::vector< Identifier > offlineToSuperCellRegion(const Identifier &reg_id) const
Given an offline region identifier, return the corresponding supercell region identifier(s).
virtual std::vector< Identifier > superCellToOfflineID(const Identifier &id) const
Given a supercell identifier, return the list of corresponding offline cell identifiers.
std::vector< Identifier > m_fcal_fromCell
hashTable for FCAL
void addMapEntry(const IDMapElt &elt)
Add an entry to the region mapping table.
void initIDMap()
Initialize the mapping table.
std::vector< int > m_superCellIndexEnd
Entry I contains one past the index in the mapping table of the last entry for the supercell region w...
virtual std::vector< Identifier > superCellToOfflineRegion(const Identifier &reg_id) const
Given a supercell region identifier, return the corresponding offline region identifier(s).
const CaloCell_ID * m_cell_helper
Entry point for calorimeter ID helpers.
const CaloCell_SuperCell_ID * m_sc_helper
std::vector< int > m_offlineIndex
Entry I contains the index in the mapping table of the first entry for the offline region with hash I...
CaloSuperCellIDTool(const std::string &type, const std::string &name, const IInterface *parent)
Standard Gaudi tool constructor.
This is a "hash" representation of an Identifier.
id_range fcal_range() const
Range over full set of FCAL Identifiers.
int eta(const Identifier id) const
eta [0,63] module 1 ; [0,31] module 2 ; [0,15] module 3
IdentifierHash channel_hash(Identifier channelId) const
Convert a connected channel (cell) Identifier to a hash code.
int phi(const Identifier id) const
phi [0,15]
Identifier channel_id(const ExpandedIdentifier &exp_id) const
cell identifier for a channel from ExpandedIdentifier
int pos_neg(const Identifier id) const
pos_neg : +/- 2 (A/C side)
Helper class for LArFCAL offline identifiers.
Definition LArFCAL_ID.h:49
This class factors out code common between TileID and Tile_SuperCell_ID.
Identifier cell_id(const Identifier &any_id) const
Identifier region_id(int index) const
build single region, module, tower, cell, pmt, adc identifiers
IdentifierHash m_cell_reg
Offline region hash for this entry.
int m_cell_ieta_adj
Offset between the first defined cell in the region and the point were offline and supercells are ali...
int m_cell_ietamin
Offline minimum and maximum (inclusive) eta indices for this entry.
int m_sc_ietamin
Supercell minimum and maximum (inclusive) eta indices for this entry.
int m_etadiv
Number of offline cells per supercell, in eta/phi.
IdentifierHash m_sc_reg
Supercell region hash for this entry.
MsgStream & msg
Definition testRead.cxx:32