ATLAS Offline Software
gFexTowerBuilder.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 //***************************************************************************
6 // gFexTowerBuilder - description
7 // -------------------
8 // Builds a gFexTowerContainer from CaloCellContainer (for supercells)
9 // TriggerTowerContainer (for ppm tile towers)
10 // Information about SCellContainer objects are in:
11 // - https://gitlab.cern.ch/atlas/athena/-/blob/22.0/Calorimeter/CaloEvent/CaloEvent/CaloCell.h
12 //
13 // begin : 22 04 2025
14 // email : jared.little@cern.ch
15 //***************************************************************************/
16 
17 #include "gFexTowerBuilder.h"
18 
19 #include <stdio.h>
20 
21 #include <algorithm>
22 #include <fstream>
23 #include <iostream>
24 #include <sstream>
25 #include <string>
26 #include <format>
27 
29 
30 namespace LVL1 {
31 
32  gFexTowerBuilder::gFexTowerBuilder(const std::string& name, ISvcLocator* svc)
34 
36 
38  "Initializing L1CaloFEXAlgos/gFexEmulatedTowers algorithm with name: "
39  << name());
40  ATH_MSG_INFO("Writing into SG key: " << m_gTowersWriteKey);
41  ATH_MSG_INFO("SCell masking: " << m_apply_masking);
42 
44  ATH_CHECK(m_triggerTowerKey.initialize());
45  ATH_CHECK(m_gTowersWriteKey.initialize());
46 
47  // Reading from CVMFS Fiber mapping
49 
50  // Reading from CVMFS Trigger Tower and their corresponding SCell ID
53 
54  return StatusCode::SUCCESS;
55  }
56 
57  StatusCode gFexTowerBuilder::execute(const EventContext& ctx) const {
58 
59  // Reading the Scell container
60  SG::ReadHandle<CaloCellContainer> ScellContainer(m_SCellKey, ctx);
61  if (!ScellContainer.isValid()) {
62  ATH_MSG_ERROR("Could not retrieve collection " << ScellContainer.key());
63  return StatusCode::FAILURE;
64  }
65 
66  // Reading the TriggerTower container
67  SG::ReadHandle<xAOD::TriggerTowerContainer> triggerTowerContainer(
68  m_triggerTowerKey, ctx);
69  if (!triggerTowerContainer.isValid()) {
70  ATH_MSG_ERROR("Could not retrieve collection "
71  << triggerTowerContainer.key());
72  return StatusCode::FAILURE;
73  }
74 
75  // WriteHandle for gFEX EDMs
77  ATH_CHECK( gTowersContainer.record(std::make_unique<xAOD::gFexTowerContainer>(),
78  std::make_unique<xAOD::gFexTowerAuxContainer>()) );
79  ATH_MSG_DEBUG("Recorded gFexEmulatedTower container with key " << gTowersContainer.key());
80 
81  if (ScellContainer->empty() || triggerTowerContainer->empty()) {
83  "Cannot fill gTowers here, at least one container is empty. "
84  "ScellContainer.size="
85  << ScellContainer->size()
86  << " or triggerTowerContainer.size=" << triggerTowerContainer->size());
87  return StatusCode::SUCCESS;
88  }
89 
90  // building Scell ID pointers
91  std::unordered_map<uint64_t, const CaloCell*> map_ScellID2ptr;
92 
93  for (const CaloCell* scell : *ScellContainer) {
94  const uint64_t ID = scell->ID().get_compact();
95  map_ScellID2ptr[ID] = scell;
96  }
97 
98  // building Tile ID pointers
99  std::unordered_map<uint32_t, const xAOD::TriggerTower*> map_TileID2ptr;
100 
101  for (const xAOD::TriggerTower* tower : *triggerTowerContainer) {
102  map_TileID2ptr[tower->coolId()] = tower;
103  }
104  for (const auto& [key, element] : m_Firm2Tower_map) {
105  unsigned int towerID = key;
106  const auto [fpga, eta, phi, source] = element;
107 
108  // the summed encoded Et from LAr or Tile
109  uint16_t total_et_encoded = 0;
110  char gTower_sat = 0;
111  // Note input fpga distinguishes between LAr (0,1,2), Tile (3) and duplicated channels (4)
112  if (source == 0) {
113 
114  const std::unordered_map<uint32_t, std::vector<uint64_t> >*
115  ptr_TTower2Cells;
116  ptr_TTower2Cells = &m_map_TTower2SCells;
117 
118  // check if the towerID exists in the LAr map
119  auto it_TTower2SCells = (*ptr_TTower2Cells).find(towerID);
120  if (it_TTower2SCells == (*ptr_TTower2Cells).end()) {
121  ATH_MSG_ERROR("gFEX ID: " << towerID
122  << " not found on map m_map_TTower2SCells");
123  return StatusCode::FAILURE;
124  }
125 
126 
127  bool invalid = m_apply_masking && m_isDATA; // the isDATA is because there is no concept of invalid supercell in MC (the provenance bit is actually used for BCID in MC), so can never have an invalid jTower
128  bool masked = m_apply_masking;
129 
130  // loop over the SCell IDs and calculate encoded Et
131  int total_Et = 0;
132  bool isConnected = true;
133  for (const auto& scellID : it_TTower2SCells->second) {
134  // check if the SCell ID exists in the map
135  auto it_ScellID2ptr = map_ScellID2ptr.find(scellID);
136 
137  // unconnected Towers have a single SCell with special id, set energy to zero
138  if (scellID == 0xffffffffffffffff) {
139  isConnected = false;
140  continue;
141  }
142 
143  // check if other SCells are in the map
144  std::string str_hex = std::format("{:x}", scellID);
145 
146  if (it_ScellID2ptr == map_ScellID2ptr.end()) {
147  if (m_isDATA)
148  ATH_MSG_WARNING("SCell ID: "
149  << scellID
150  << " not found in the CaloCellContainer, skipping");
151  continue;
152  }
153 
154  const CaloCell* scell = it_ScellID2ptr->second;
155  int val = std::round(
156  scell->energy() /
157  (12.5 * std::cosh(scell->eta()))); // 12.5 is b.c. energy is in
158  // units of 12.5 MeV per count
159 
160  bool isMasked =
161  m_apply_masking ? ((scell)->provenance() & 0x80) : false;
162  bool isInvalid =
163  (m_apply_masking&&m_isDATA) ? ((scell)->provenance()&0x40) : false;
164  bool isSaturated = (m_isDATA) ? scell->quality() : false; // saturation algorithm not implemented in MC yet
165 
166  invalid &= isInvalid;
167  masked &= isMasked;
168  if (!isMasked) {
169  gTower_sat |= isSaturated;
170  }
171 
172  if (isMasked) {
173  val = 0;
174  } else if( isInvalid&&m_isDATA) {
175  val = 0;
176  }
177 
178  if (val != 0)
179  total_Et += val;
180 
181  } // end of SCell loop
182 
183  // now must convert Total_Et int value into fex value: multi-level encoding
184  if(!isConnected) {
185  total_et_encoded = 0; // no data
186  } else if(masked) {
187  total_et_encoded = 0; // no data
188  } else if(invalid) {
189  total_et_encoded = 4095; // invalid
190  } else {
191  total_et_encoded = gFEXCompression::compress(12.5 * total_Et);
192  }
193 
194 
195  } else if (source == 1) {
196 
197  // Tile
198  // check that the gFEX Tower ID exists in the Tile map
199  auto it_TTower2Tile = m_map_TTower2Tile.find(towerID);
200 
201  int Tile_Et = 0;
202  for (auto const& TileTowerID : it_TTower2Tile->second) {
203  auto it_TileID2ptr = map_TileID2ptr.find(TileTowerID);
204  if (it_TileID2ptr == map_TileID2ptr.end()) {
205  if(m_isDATA) {
206  ATH_MSG_WARNING("Tile cool ID: " << TileTowerID
207  << " not found in the xAOD::TriggerTower (map_TileID2ptr)");
208  }
209  continue; // in MC the xAODTriggerTowers have variable size due to noise cuts, continue on to the next tower
210  } else {
211  const xAOD::TriggerTower* tileTower = it_TileID2ptr->second;
212  unsigned int jepEt = tileTower->jepET();
213  Tile_Et += jepEt; // add the encoded energies
214  }
215  }
216  total_et_encoded = Tile_Et;
217 
218  } else if (source == 2) {
219  // duplicated Towers, LATOME sends 0
220  total_et_encoded = 0;
221  }
222 
223  // the EDM requires a float
224  float total_et_encoded_flt = total_et_encoded;
225 
226  unsigned int fpga_out = (towerID < 10000) ? 0 : (towerID < 20000) ? 1 : 2;
227  unsigned int iEta = 0;
228  unsigned int iPhi = 0;
229 
230  gTowersContainer->push_back(std::make_unique<xAOD::gFexTower>());
231  gTowersContainer->back()->initialize(iEta, iPhi, eta, phi,
232  total_et_encoded_flt, fpga_out,
233  gTower_sat, towerID);
234  }
235 
236  return StatusCode::SUCCESS;
237  }
238 
240  // opening file with ifstream
241  std::ifstream file(fileName);
242 
243  if (!file.is_open()) {
244  ATH_MSG_ERROR("Could not open file:" << fileName);
245  return StatusCode::FAILURE;
246  }
247  std::string line;
248  // loading the mapping information
249  while (std::getline(file, line)) {
250  // removing the header of the file (it is just information!)
251  if (line[0] == '#') continue;
252 
253  // Splitting line in different substrings
254  std::stringstream oneLine(line);
255  // reading elements
256  std::vector<float> elements;
257  std::string element;
258  while (std::getline(oneLine, element, ' ')) {
259  elements.push_back(std::stof(element));
260  }
261 
262  // It should have 5 elements
263  // ordered as: towerID fpga source eta phi
264 
265  if (elements.size() != 5) {
267  "Unexpected number of elements (5 expected) in file: " << fileName);
268  return StatusCode::FAILURE;
269  }
270 
271  // building array of <fpga, eta, phi, source>
272  std::array<float, 4> aux_arr{{elements.at(1), elements.at(3),
273  elements.at(4), elements.at(2)}};
274 
275  // filling the map with the hash given by mapIndex()
276  m_Firm2Tower_map[elements.at(0)] = aux_arr;
277  }
278 
279  file.close();
280 
281  return StatusCode::SUCCESS;
282  }
283 
285 
286  // opening file with ifstream
287  std::ifstream file(fileName);
288 
289  if (!file.is_open()) {
290  ATH_MSG_ERROR("Could not open file:" << fileName);
291  return StatusCode::FAILURE;
292  }
293 
294  std::string line;
295  // loading the mapping information into an unordered_map <Fex Tower ID, vector
296  // of SCell IDs>
297  while (std::getline(file, line)) {
298  std::vector<uint64_t> SCellvector;
299  SCellvector.clear();
300 
301  // removing the header of the file (it is just information!)
302  if (line[0] == '#')
303  continue;
304 
305  // Splitting line in different substrings
306  std::stringstream oneSCellID(line);
307 
308  // reading elements
309  std::string substr = "";
310  int TTID = 0;
311  int elem = 0;
312 
313  while (std::getline(oneSCellID, substr, ' ')) {
314  ++elem;
315  if (elem == 1) {
316  TTID = std::stoi(substr);
317  } else {
318  // Check if it looks like a SCell Identifier
319  if (isBadSCellID(substr)) {
320  return StatusCode::FAILURE;
321  }
322 
323  // converts hex number to unsigned long long int
324  // unconnnected slots are filled with 0xffffffffffffffff
325  // otherwise SCell map used shorter form, add extra zeroes back
326  std::string scell_full =
327  (substr == "0xffffffffffffffff") ? substr : substr + "00000000";
328  uint64_t scid_uint64 = std::strtoull(scell_full.c_str(), nullptr, 0);
329  SCellvector.push_back(scid_uint64);
330  }
331  }
332 
333  m_map_TTower2SCells[TTID] = std::move(SCellvector);
334  }
335  file.close();
336 
337  return StatusCode::SUCCESS;
338  }
339 
340  bool gFexTowerBuilder::isBadSCellID(const std::string& ID) const {
341 
342  // does it start with "0x"?, if so then is a GOOD SCell ID!
343  if (ID.find("0x") == std::string::npos) {
344  ATH_MSG_ERROR("Invalid SuperCell ID "
345  << ID
346  << ". Expecting hexadecimal number on the mapping file");
347  return true;
348  }
349  return false;
350  }
351 
353 
354  std::string myline;
355 
356  // openning file with ifstream
357  std::ifstream myfile(fileName);
358 
359  if (!myfile.is_open()) {
360  ATH_MSG_FATAL("Could not open file:" << fileName);
361  return StatusCode::FAILURE;
362  }
363 
364  // loading the mapping information into an unordered_map <Fex Tower ID, vector
365  // of Tile IDs>
366  while (std::getline(myfile, myline)) {
367 
368  std::vector<uint32_t> Tilevector;
369  Tilevector.clear();
370  // removing the header of the file
371  myline.erase(myline.begin(),
372  std::find_if(myline.begin(), myline.end(),
373  [](int ch) { return !std::isspace(ch); }));
374  if (myline[0] == '#')
375  continue;
376 
377  // Splitting myline in different substrings
378  std::stringstream oneTileID(myline);
379 
380  // reading elements
381  std::string substr = "";
382  int gTowerID = 0;
383  int elem = 0;
384 
385  while (std::getline(oneTileID, substr, ' ')) {
386  ++elem;
387  if (elem == 1) {
388  gTowerID = std::stoi(substr);
389  } else {
390  uint32_t tileid_uint32 = std::strtoul(substr.c_str(), nullptr, 0);
391  Tilevector.push_back(tileid_uint32);
392  }
393  }
394  m_map_TTower2Tile[gTowerID] = std::move(Tilevector);
395  }
396  myfile.close();
397 
398  return StatusCode::SUCCESS;
399  }
400 
401 
402 } // namespace LVL1
PathResolver::find_calib_file
static std::string find_calib_file(const std::string &logical_file_name)
Definition: PathResolver.cxx:235
LVL1::gFexTowerBuilder::m_gTowersWriteKey
SG::WriteHandleKey< xAOD::gFexTowerContainer > m_gTowersWriteKey
Definition: gFexTowerBuilder.h:53
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
sendEI_SPB.ch
ch
Definition: sendEI_SPB.py:35
vtune_athena.format
format
Definition: vtune_athena.py:14
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
ID
std::vector< Identifier > ID
Definition: CalibHitIDCheck.h:24
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:67
LVL1::gFEXCompression::compress
static unsigned int compress(float Energy)
Compress data.
Definition: gFEXCompression.cxx:20
LVL1::gFexTowerBuilder::ReadTilefromFile
StatusCode ReadTilefromFile(const std::string &)
Definition: gFexTowerBuilder.cxx:352
LVL1::gFexTowerBuilder::m_Firm2Tower_map
std::unordered_map< unsigned int, std::array< float, 4 > > m_Firm2Tower_map
Definition: gFexTowerBuilder.h:93
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
LVL1::gFexTowerBuilder::m_gFEX2Tilemapping
Gaudi::Property< std::string > m_gFEX2Tilemapping
Definition: gFexTowerBuilder.h:77
LVL1
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
Definition: ICMMCPHitsCnvTool.h:18
LVL1::gFexTowerBuilder::m_map_TTower2Tile
std::unordered_map< uint32_t, std::vector< uint32_t > > m_map_TTower2Tile
Definition: gFexTowerBuilder.h:91
dq_defect_bulk_create_defects.line
line
Definition: dq_defect_bulk_create_defects.py:27
gFEXCompression.h
CaloCell::energy
double energy() const
get energy (data member)
Definition: CaloCell.h:321
AthReentrantAlgorithm
An algorithm that can be simultaneously executed in multiple threads.
Definition: AthReentrantAlgorithm.h:74
LVL1::gFexTowerBuilder::m_triggerTowerKey
SG::ReadHandleKey< xAOD::TriggerTowerContainer > m_triggerTowerKey
Definition: gFexTowerBuilder.h:48
LVL1::gFexTowerBuilder::m_isDATA
Gaudi::Property< bool > m_isDATA
Definition: gFexTowerBuilder.h:67
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
xAOD::uint16_t
setWord1 uint16_t
Definition: eFexEMRoI_v1.cxx:93
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::TriggerTower_v2
Description of TriggerTower_v2.
Definition: TriggerTower_v2.h:49
file
TFile * file
Definition: tile_monitor.h:29
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
DataVector::back
const T * back() const
Access the last element in the collection as an rvalue.
SG::ReadHandle::isValid
virtual bool isValid() override final
Can the handle be successfully dereferenced?
CaloCell::quality
uint16_t quality() const
get quality (data member)
Definition: CaloCell.h:342
TrigConf::name
Definition: HLTChainList.h:35
LVL1::gFexTowerBuilder::ReadSCfromFile
StatusCode ReadSCfromFile(const std::string &)
Definition: gFexTowerBuilder.cxx:284
LVL1::gFexTowerBuilder::ReadFibersfromFile
StatusCode ReadFibersfromFile(const std::string &)
Definition: gFexTowerBuilder.cxx:239
LVL1::gFexTowerBuilder::m_FiberMapping
Gaudi::Property< std::string > m_FiberMapping
Definition: gFexTowerBuilder.h:58
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
LVL1::gFexTowerBuilder::m_map_TTower2SCells
std::unordered_map< uint32_t, std::vector< uint64_t > > m_map_TTower2SCells
Definition: gFexTowerBuilder.h:90
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
LVL1::gFexTowerBuilder::gFexTowerBuilder
gFexTowerBuilder(const std::string &name, ISvcLocator *svc)
Definition: gFexTowerBuilder.cxx:32
gFexTowerBuilder.h
SG::VarHandleBase::key
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleBase.cxx:64
Trk::iPhi
@ iPhi
Definition: ParamDefs.h:47
LVL1::gFexTowerBuilder::isBadSCellID
bool isBadSCellID(const std::string &) const
Definition: gFexTowerBuilder.cxx:340
LVL1::gFexTowerBuilder::execute
virtual StatusCode execute(const EventContext &) const override
Function executing the algorithm.
Definition: gFexTowerBuilder.cxx:57
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:73
LVL1::gFexTowerBuilder::initialize
virtual StatusCode initialize() override
Function initialising the algorithm.
Definition: gFexTowerBuilder.cxx:35
SG::WriteHandle::record
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
CaloCell
Data object for each calorimeter readout cell.
Definition: CaloCell.h:57
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
LVL1::gFexTowerBuilder::m_SCellKey
SG::ReadHandleKey< CaloCellContainer > m_SCellKey
Definition: gFexTowerBuilder.h:44
LVL1::gFexTowerBuilder::m_apply_masking
Gaudi::Property< bool > m_apply_masking
Definition: gFexTowerBuilder.h:65
LVL1::gFexTowerBuilder::m_gFEX2Scellmapping
Gaudi::Property< std::string > m_gFEX2Scellmapping
Definition: gFexTowerBuilder.h:72
copySelective.source
string source
Definition: copySelective.py:31
jobOptions.fileName
fileName
Definition: jobOptions.SuperChic_ALP2.py:39
xAOD::iEta
setScale setgFexType iEta
Definition: gFexJetRoI_v1.cxx:77
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
xAOD::TriggerTower_v2::jepET
uint8_t jepET() const
get jepET from peak of lut_jep
Definition: TriggerTower_v2.cxx:186
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.
CaloCell::eta
virtual double eta() const override final
get eta (through CaloDetDescrElement)
Definition: CaloCell.h:376
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37