ATLAS Offline Software
jFexEmulatedTowers.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 // jFexEmulatedTowers - description
7 // -------------------
8 // This reentrant algorithm is meant build jFEX Towers from LAr and Tile
9 // Information about SCellContainer objetcs are in:
10 // - https://gitlab.cern.ch/atlas/athena/-/blob/22.0/Calorimeter/CaloEvent/CaloEvent/CaloCell.h
11 //
12 // begin : 01 11 2022
13 // email : sergi.rodriguez@cern.ch
14 //***************************************************************************/
15 
16 
17 #include "jFexEmulatedTowers.h"
19 
20 #include <iostream>
21 #include <fstream>
22 #include <sstream>
23 #include <algorithm>
24 #include <string>
25 #include <stdio.h>
26 
27 namespace LVL1 {
28 
30 
32 
33  ATH_MSG_INFO( "Initializing L1CaloFEXAlgos/jFexEmulatedTowers algorithm with name: "<< name());
34  ATH_MSG_INFO( "Writting into SG key: "<< m_jTowersWriteKey);
35  ATH_MSG_INFO( "SCell masking: "<< m_apply_masking);
36  ATH_MSG_INFO( "Thinnig towers: "<< m_doThinning);
37 
39  ATH_CHECK( m_triggerTowerKey.initialize() );
40  ATH_CHECK( m_jTowersWriteKey.initialize() );
41 
42 
43  //Reading from CVMFS Fiber mapping
45 
46  //Reading from CVMFS Trigger Tower and their corresponding SCell ID
49 
50  return StatusCode::SUCCESS;
51 }
52 
53 StatusCode jFexEmulatedTowers::execute(const EventContext& ctx) const {
54 
55  //Reading the Scell container
56  SG::ReadHandle<CaloCellContainer> ScellContainer(m_SCellKey, ctx);
57  if(!ScellContainer.isValid()) {
58  ATH_MSG_ERROR("Could not retrieve collection " << ScellContainer.key() );
59  return StatusCode::FAILURE;
60  }
61 
62  //Reading the TriggerTower container
64  if(!triggerTowerContainer.isValid()) {
65  ATH_MSG_ERROR("Could not retrieve collection " << triggerTowerContainer.key() );
66  return StatusCode::FAILURE;
67  }
68 
69  //WriteHandle for jFEX EDMs
70  //---jTower EDM
72  ATH_CHECK(jTowersContainer.record(std::make_unique<xAOD::jFexTowerContainer>(), std::make_unique<xAOD::jFexTowerAuxContainer>()));
73  ATH_MSG_DEBUG("Recorded jFexEmulatedTower container with key " << jTowersContainer.key());
74 
75  if(ScellContainer->empty() || triggerTowerContainer->empty() ){
76  ATH_MSG_WARNING("Cannot fill jTowers here, at least one container is empty. ScellContainer.size="<<ScellContainer->size() << " or triggerTowerContainer.size=" << triggerTowerContainer->size() );
77  return StatusCode::SUCCESS;
78  }
79 
80  // building Scell ID pointers
81  std::unordered_map< uint64_t, const CaloCell*> map_ScellID2ptr;
82 
83  for(const CaloCell* scell : *ScellContainer){
84  const uint64_t ID = scell->ID().get_compact();
85  map_ScellID2ptr[ID] = scell;
86  }
87 
88  // building Tile ID pointers
89  std::unordered_map< uint32_t, const xAOD::TriggerTower*> map_TileID2ptr;
90 
91  for(const xAOD::TriggerTower* tower : *triggerTowerContainer){
92 
93  // keeping just tile information
94  if(std::abs(tower->eta())>1.5 || tower->sampling()!=1) continue;
95 
96  map_TileID2ptr[tower->coolId()]=tower;
97  }
98 
99 
100  for( const auto& [key, element] : m_Firm2Tower_map){
101 
102  unsigned int jfex = (key >> 16) & 0xf;
103  unsigned int fpga = (key >> 12) & 0xf;
104  unsigned int channel = (key >> 4 ) & 0xff;
105  unsigned int tower = (key >> 0 ) & 0xf;
106 
107  const auto [f_IDSimulation, eta, phi, f_source, f_iEta, f_iPhi] = element;
108 
109  //elements that need to be casted
110  unsigned int IDSimulation = static_cast<int>(f_IDSimulation);
111  unsigned int source = static_cast<int>(f_source);
112  unsigned int iEta = static_cast<int>(f_iEta);
113  unsigned int iPhi = static_cast<int>(f_iPhi);
114 
115 
116  uint16_t Total_Et_encoded = 0;
117  char jTower_sat = 0;
118 
119  if( source != 1 ){
120 
121  const std::unordered_map< uint32_t, std::vector<uint64_t> > * ptr_TTower2Cells;
122 
123  //HAD layer for HEC, FCAL2 and FCAL3
124  if(source == 3 or source > 4){
125  ptr_TTower2Cells = &m_map_TTower2SCellsHAD;
126  }
127  else{
128  ptr_TTower2Cells = &m_map_TTower2SCellsEM;
129  }
130 
131  //check that the jFEX Tower ID exists in the map
132  auto it_TTower2SCells = (*ptr_TTower2Cells).find(IDSimulation);
133  if(it_TTower2SCells == (*ptr_TTower2Cells).end()) {
134  ATH_MSG_ERROR("jFEX ID: "<<IDSimulation<< " not found on map m_map_TTower2SCellsEM/HAD");
135  return StatusCode::FAILURE;
136  }
137 
138  int Total_Et = 0;
139  float Total_Et_float = 0;
140  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.
141  bool masked = m_apply_masking;
142  for (auto const& SCellID : it_TTower2SCells->second ) {
143  //check that the SCell Identifier exists in the map
144  auto it_ScellID2ptr = map_ScellID2ptr.find(SCellID);
145  if(it_ScellID2ptr == map_ScellID2ptr.end()) {
146  if(m_isDATA) ATH_MSG_DEBUG("Scell ID: 0x"<<std::hex<< (SCellID >> 32) <<std::dec<< " not found in the CaloCell Container, skipping");
147  // this is equivalent to treat the scell as a masked input, since masking takes precedence over invalidity
148  continue;
149  }
150 
151  const CaloCell* myCell = it_ScellID2ptr->second;
152  int val = std::round(myCell->energy()/(12.5*std::cosh(myCell->eta()))); // 12.5 is b.c. energy is in units of 12.5MeV per count
153  bool isMasked = m_apply_masking ? ((myCell)->provenance()&0x80) : false;
154  bool isInvalid = (m_apply_masking&&m_isDATA) ? ((myCell)->provenance()&0x40) : false;
155  bool isSaturated = (m_isDATA) ? myCell->quality() : false; // saturation algorithm not implemented in MC yet
156 
157  invalid &= isInvalid;
158  masked &= isMasked;
159  if (!isMasked) {
160  jTower_sat |= isSaturated;
161  }
162 
163  if( isMasked ) {
164  //if masked then Et = 0
165  val = 0;
166  //countMasked++;
167  } else if( isInvalid ) {
168  val = 0;
169  }
170 
171  Total_Et += val;
172  if(val!=0) Total_Et_float += myCell->et();
173 
174  }
175 
176  // now must convert Total_Et int value into fex value: multi-level encoding
177  if(masked) {
178  Total_Et_encoded = 0; // no data
179  } else if(invalid) {
180  Total_Et_encoded = 4095; // invalid
181  } else {
182  Total_Et_encoded = jFEXCompression::Compress( Total_Et*12.5, false );
183  }
184 
185  // leaving this commented while outstanding questions above about treatment of supercells
186  // using floating point for MC until determine correct procedure for MC values re invalid/masking
187  if(!m_isDATA) Total_Et_encoded = jFEXCompression::Compress( Total_Et_float, masked );
188 
189  }
190  else{
191 
192  //check that the jFEX Tower ID exists in the map
193  auto it_TTower2Tile = m_map_TTower2Tile.find(IDSimulation);
194  if(it_TTower2Tile == m_map_TTower2Tile.end()) {
195  ATH_MSG_ERROR("ID: "<<IDSimulation<< " not found on map m_map_TTower2Tile");
196  return StatusCode::FAILURE;
197  }
198 
199  uint32_t TileID = std::get<0>( it_TTower2Tile->second );
200 
201  //check that the Tile Identifier exists in the map
202  auto it_TileID2ptr = map_TileID2ptr.find(TileID);
203  if(it_TileID2ptr == map_TileID2ptr.end()) {
204  if(m_isDATA) ATH_MSG_WARNING("Tile cool ID: "<<TileID<< " not found in the xAOD::TriggerTower, skipping");
205  continue;
206  }
207  else{
208  Total_Et_encoded = (it_TileID2ptr->second)->cpET();
209  }
210  }
211 
212  std::vector<uint16_t> vtower_ET;
213  vtower_ET.clear();
214  vtower_ET.push_back(Total_Et_encoded);
215 
216  std::vector<char> vtower_SAT;
217  vtower_SAT.clear();
218 
219  //Needs to be updated with Saturation flag from LAr CaloCell container, not ready yet!
220  vtower_SAT.push_back(jTower_sat);
221 
222  jTowersContainer->push_back( std::make_unique<xAOD::jFexTower>() );
223  jTowersContainer->back()->initialize(eta, phi, iEta, iPhi, IDSimulation, source, vtower_ET, jfex, fpga, channel, tower, vtower_SAT );
224 
225  if( m_doThinning && !jTowersContainer->back()->isCore() ){
226  jTowersContainer->pop_back();
227  }
228  }
229 
230  // Return gracefully
231  return StatusCode::SUCCESS;
232 }
233 
234 
236 
237 
238 
239  //openning file with ifstream
240  std::ifstream file(fileName);
241 
242  if ( !file.is_open() ){
243  ATH_MSG_ERROR("Could not open file:" << fileName);
244  return StatusCode::FAILURE;
245  }
246 
247  std::string line;
248  //loading the mapping information
249  while ( std::getline (file, line) ) {
250 
251  //removing the header of the file (it is just information!)
252  if(line[0] == '#') continue;
253 
254  //Splitting line in different substrings
255  std::stringstream oneLine(line);
256 
257  //reading elements
258  std::vector<float> elements;
259  std::string element;
260  while(std::getline(oneLine, element, ' '))
261  {
262  elements.push_back(std::stof(element));
263  }
264 
265  // It should have 10 elements
266  // ordered as: jfex fpga channel towerNr source globalEtaIndex globalPhiIndex IDSimulation eta phi
267  if(elements.size() != 10){
268  ATH_MSG_ERROR("Unexpected number of elemennts (10 expected) in file: "<< fileName);
269  return StatusCode::FAILURE;
270  }
271  // building array of <IDSimulation, eta, phi, source, iEta, iPhi>
272  std::array<float,6> aux_arr{ {elements.at(7),elements.at(8),elements.at(9),elements.at(4),elements.at(5),elements.at(6)} };
273 
274  //filling the map with the hash given by mapIndex()
275  m_Firm2Tower_map[ mapIndex(elements.at(0),elements.at(1),elements.at(2),elements.at(3)) ] = aux_arr;
276 
277  }
278  file.close();
279 
280  return StatusCode::SUCCESS;
281 }
282 
283 
284 constexpr unsigned int jFexEmulatedTowers::mapIndex(unsigned int jfex, unsigned int fpga, unsigned int channel, unsigned int tower) {
285  // values from hardware: jfex=[0,5] 4 bits, fpga=[0,3] 4 bits, channel=[0,59] 8 bits, tower=[0,15] 4 bits
286  return (jfex << 16) | (fpga << 12) | (channel << 4) | tower;
287 }
288 
290 
291 
292 
293  //openning file with ifstream
294  std::ifstream file(fileName);
295 
296  if ( !file.is_open() ){
297  ATH_MSG_ERROR("Could not open file:" << fileName);
298  return StatusCode::FAILURE;
299  }
300 
301  std::string line;
302  //loading the mapping information into an unordered_map <Fex Tower ID, vector of SCell IDs>
303  while ( std::getline (file, line) ) {
304  std::vector<uint64_t> SCellvectorEM;
305  SCellvectorEM.clear();
306  std::vector<uint64_t> SCellvectorHAD;
307  SCellvectorHAD.clear();
308 
309  //removing the header of the file (it is just information!)
310  if(line[0] == '#') continue;
311 
312  //Splitting line in different substrings
313  std::stringstream oneSCellID(line);
314 
315  //reading elements
316  std::string substr = "";
317  int TTID = 0;
318  int elem = 0;
319 
320  while(std::getline(oneSCellID, substr, ' '))
321  {
322  ++elem;
323  if(elem == 1){
324  TTID = std::stoi(substr);
325  }
326  else{
327  //Check if it looks like a SCell Identifier
328  if(isBadSCellID(substr)){
329  return StatusCode::FAILURE;
330  }
331 
332  // converts hex number to unsigned long long int
333  uint64_t scid_uint64 = std::strtoull(substr.c_str(), nullptr, 0);
334 
335  //empty slots are filled with 0xffffffffffffffff
336  if(scid_uint64 == 0xffffffffffffffff) continue;
337 
338  //from element from 2 to 13 are EM SCells, element 14 is a HAD SCell
339  if(elem<14) SCellvectorEM.push_back(scid_uint64);
340  else SCellvectorHAD.push_back(scid_uint64);
341  }
342  }
343 
344  m_map_TTower2SCellsEM[TTID] = std::move(SCellvectorEM);
345  m_map_TTower2SCellsHAD[TTID] = std::move(SCellvectorHAD);
346 
347  }
348  file.close();
349 
350  return StatusCode::SUCCESS;
351 }
352 
353 bool jFexEmulatedTowers::isBadSCellID(const std::string& ID) const{
354 
355  // does it start with "0x"?, if so then is a GOOD SCell ID!
356  if (ID.find("0x") == std::string::npos) {
357  ATH_MSG_ERROR("Invalid SuperCell ID " << ID << ". Expecting hexadecimal number on the mapping file");
358  return true;
359  }
360  return false;
361 }
362 
363 
364 
365 
367 
368  //openning file with ifstream
369  std::ifstream file(fileName);
370 
371  if ( !file.is_open() ){
372  ATH_MSG_ERROR("Could not open file:" << fileName);
373  return StatusCode::FAILURE;
374  }
375 
376  std::string line;
377  //loading the mapping information into an unordered_map <Fex Tower ID, vector of SCell IDs>
378  while ( std::getline (file, line) ) {
379 
380  //removing the header of the file (it is just information!)
381  if(line[0] == '#') continue;
382 
383  //Splitting line in different substrings
384  std::stringstream oneLine(line);
385 
386  std::vector<std::string> elements;
387  std::string element = "";
388 
389  while(std::getline(oneLine, element, ' ')){
390  elements.push_back(element);
391  }
392 
393  if(elements.size() != 4){
394  ATH_MSG_ERROR("Invalid number of element in " << line << ". Expecting 4 elements {jFexID, TileID, eta, phi}");
395  return StatusCode::FAILURE;
396  }
397 
398  uint32_t jFexID = std::stoi( elements.at(0) );
399  uint32_t TileID = std::stoi( elements.at(1) );
400  float eta = std::stof( elements.at(2) );
401  float phi = std::stof( elements.at(3) );
402 
403  m_map_TTower2Tile[jFexID] = {TileID,eta,phi};
404 
405  }
406  file.close();
407 
408  return StatusCode::SUCCESS;
409 }
410 
411 
412 
413 
414 
415 }
LVL1::jFexEmulatedTowers::execute
virtual StatusCode execute(const EventContext &) const override
Function executing the algorithm.
Definition: jFexEmulatedTowers.cxx:53
plotting.yearwise_efficiency.channel
channel
Definition: yearwise_efficiency.py:24
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
MuonGM::round
float round(const float toRound, const unsigned int decimals)
Definition: Mdt.cxx:27
LVL1::jFexEmulatedTowers::initialize
virtual StatusCode initialize() override
Function initialising the algorithm.
Definition: jFexEmulatedTowers.cxx:31
LVL1::jFexEmulatedTowers::m_jFEX2Scellmapping
Gaudi::Property< std::string > m_jFEX2Scellmapping
Definition: jFexEmulatedTowers.h:62
LVL1::jFexEmulatedTowers::ReadTilefromFile
StatusCode ReadTilefromFile(const std::string &)
Definition: jFexEmulatedTowers.cxx:366
LVL1
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
Definition: ICMMCPHitsCnvTool.h:18
dq_defect_bulk_create_defects.line
line
Definition: dq_defect_bulk_create_defects.py:27
LVL1::jFexEmulatedTowers::isBadSCellID
bool isBadSCellID(const std::string &) const
Definition: jFexEmulatedTowers.cxx:353
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
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
xAOD::uint16_t
setWord1 uint16_t
Definition: eFexEMRoI_v1.cxx:93
TileID
Helper class for TileCal offline identifiers.
Definition: TileID.h:68
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
LVL1::jFEXCompression::Compress
static unsigned int Compress(float floatEt, bool empty=false)
Compress data.
Definition: jFEXCompression.cxx:25
xAOD::TriggerTower_v2
Description of TriggerTower_v2.
Definition: TriggerTower_v2.h:49
file
TFile * file
Definition: tile_monitor.h:29
CaloCell::et
virtual double et() const override final
get et
Definition: CaloCell.h:417
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
LVL1::jFexEmulatedTowers::jFexEmulatedTowers
jFexEmulatedTowers(const std::string &name, ISvcLocator *svc)
Definition: jFexEmulatedTowers.cxx:29
LVL1::jFexEmulatedTowers::m_Firm2Tower_map
std::unordered_map< unsigned int, std::array< float, 6 > > m_Firm2Tower_map
Definition: jFexEmulatedTowers.h:78
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
LVL1::jFexEmulatedTowers::m_jTowersWriteKey
SG::WriteHandleKey< xAOD::jFexTowerContainer > m_jTowersWriteKey
Definition: jFexEmulatedTowers.h:51
TrigConf::name
Definition: HLTChainList.h:35
LVL1::jFexEmulatedTowers::m_map_TTower2SCellsHAD
std::unordered_map< uint32_t, std::vector< uint64_t > > m_map_TTower2SCellsHAD
Definition: jFexEmulatedTowers.h:73
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
DataVector::push_back
value_type push_back(value_type pElem)
Add an element to the end of the collection.
LVL1::jFexEmulatedTowers::m_map_TTower2SCellsEM
std::unordered_map< uint32_t, std::vector< uint64_t > > m_map_TTower2SCellsEM
Definition: jFexEmulatedTowers.h:72
LVL1::jFexEmulatedTowers::m_triggerTowerKey
SG::ReadHandleKey< xAOD::TriggerTowerContainer > m_triggerTowerKey
Definition: jFexEmulatedTowers.h:48
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
LVL1::jFexEmulatedTowers::m_SCellKey
SG::ReadHandleKey< CaloCellContainer > m_SCellKey
Definition: jFexEmulatedTowers.h:45
Trk::iPhi
@ iPhi
Definition: ParamDefs.h:47
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:73
LVL1::jFexEmulatedTowers::m_jFEX2Tilemapping
Gaudi::Property< std::string > m_jFEX2Tilemapping
Definition: jFexEmulatedTowers.h:63
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
DataVector::pop_back
void pop_back()
Remove the last element from the collection.
LVL1::jFexEmulatedTowers::ReadSCfromFile
StatusCode ReadSCfromFile(const std::string &)
Definition: jFexEmulatedTowers.cxx:289
jFEXCompression.h
LVL1::jFexEmulatedTowers::m_apply_masking
Gaudi::Property< bool > m_apply_masking
Definition: jFexEmulatedTowers.h:57
copySelective.source
string source
Definition: copySelective.py:31
LVL1::jFexEmulatedTowers::m_isDATA
Gaudi::Property< bool > m_isDATA
Definition: jFexEmulatedTowers.h:58
LVL1::jFexEmulatedTowers::ReadFibersfromFile
StatusCode ReadFibersfromFile(const std::string &)
Definition: jFexEmulatedTowers.cxx:235
jobOptions.fileName
fileName
Definition: jobOptions.SuperChic_ALP2.py:39
LVL1::jFexEmulatedTowers::m_map_TTower2Tile
std::unordered_map< uint32_t, std::tuple< uint32_t, float, float > > m_map_TTower2Tile
Definition: jFexEmulatedTowers.h:74
LVL1::jFexEmulatedTowers::m_FiberMapping
Gaudi::Property< std::string > m_FiberMapping
Definition: jFexEmulatedTowers.h:54
xAOD::iEta
setScale setgFexType iEta
Definition: gFexJetRoI_v1.cxx:77
LVL1::jFexEmulatedTowers::m_doThinning
Gaudi::Property< bool > m_doThinning
Definition: jFexEmulatedTowers.h:59
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
jFexEmulatedTowers.h
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
LVL1::jFexEmulatedTowers::mapIndex
constexpr static unsigned int mapIndex(unsigned int jfex, unsigned int fpga, unsigned int channel, unsigned int tower)
Definition: jFexEmulatedTowers.cxx:284
mapkey::key
key
Definition: TElectronEfficiencyCorrectionTool.cxx:37