Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
eFEXFPGATowerIdProvider.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 #include <iostream>
7 #include <fstream>
8 #include <algorithm>
9 #include <string>
11 
12 LVL1::eFEXFPGATowerIdProvider::eFEXFPGATowerIdProvider(const std::string &type, const std::string &name, const IInterface *parent):
14 {
15  declareInterface<IeFEXFPGATowerIdProvider>(this);
16 }
17 
19 {
20  std::string csvpath = PathResolver::find_file("tower_fpga_efex_map.csv", "DATAPATH");
21  if (setAddress(csvpath) == StatusCode::FAILURE) {
22  ATH_MSG_WARNING("tower_fpga_efex_map.csv missing or invalid. Swiching to hard-coded mapping.");
23  };
24  return StatusCode::SUCCESS;
25 }
26 
28 {
29  m_alltowers.clear();
30  m_towerrankingcache.clear();
31 }
32 
33 StatusCode LVL1::eFEXFPGATowerIdProvider::setAddress(const std::string& inputaddress)
34 {
35  if (inputaddress.empty()) {
36  m_hascsvfile = false;
37  return StatusCode::FAILURE;
38  }
39  m_hascsvfile = true;
40  m_csvaddress = inputaddress;
41  if (loadcsv() == StatusCode::FAILURE) {
42  m_hascsvfile = false;
43  return StatusCode::FAILURE;
44  }
45  m_towerrankingcache.clear();
46  m_towerrankingcache.resize(96);
47  // sort the towers in each FPGA
48  for (int efex{ 0 }; efex < 24; efex++) {
49  for (int fpga{ 0 }; fpga < 4; fpga++) {
50  if (rankTowerinFPGA(getFPGAIndex(efex, fpga)) == StatusCode::FAILURE) {
51  m_hascsvfile = false;
52  return StatusCode::FAILURE;
53  }
54  }
55  }
56  return StatusCode::SUCCESS;
57 }
58 
59 StatusCode LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDinFPGA(int eFEXID, int FPGAID, int(&towerlist)[10][6]) const {
60  int FPGAindex{ getFPGAIndex(eFEXID, FPGAID) };
61  if (m_towerrankingcache[FPGAindex]) {
62  // obtain the tower order from cache
63  int vectorindex{ 0 };
64  for (int i{ 0 }; i < 10; i++) {
65  for (int j{ 0 }; j < 6; j++) {
66  towerlist[i][j] = (*m_towerrankingcache[FPGAindex]).at(vectorindex++);
67  }
68  }
69  }
70  // set tower ids to 0 if the information about the FPGA stored in the .csv file is damaged
71  else {
72  for (int i{ 0 }; i < 10; i++) {
73  for (int j{ 0 }; j < 6; j++) {
74  towerlist[i][j] = 0;
75  }
76  }
77  ATH_MSG_ERROR("FPGA mapping info missing.");
78  return StatusCode::FAILURE;
79  }
80  return StatusCode::SUCCESS;
81 }
82 
83 StatusCode LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDineFEX(int eFEXID, int(&towerlist)[10][18]) const {
84  int FPGA0index{ getFPGAIndex(eFEXID, 0) };
85  int FPGA1index{ getFPGAIndex(eFEXID, 1) };
86  int FPGA2index{ getFPGAIndex(eFEXID, 2) };
87  int FPGA3index{ getFPGAIndex(eFEXID, 3) };
88 
89  if (!m_towerrankingcache[FPGA0index] || !m_towerrankingcache[FPGA1index] ||
90  !m_towerrankingcache[FPGA2index] || !m_towerrankingcache[FPGA3index]) {
91  for (int i{ 0 }; i < 10; i++) {
92  for (int j{ 0 }; j < 18; j++) {
93  towerlist[i][j] = 0;
94  }
95  }
96  ATH_MSG_ERROR("FPGA mapping info missing.");
97  return StatusCode::FAILURE;
98  }
99 
100  // FPGA0
101  int vectorindex{ 0 };
102  for (int i{ 0 }; i < 10; i++) {
103  for (int j{ 0 }; j < 6; j++) {
104  towerlist[i][j] = (*m_towerrankingcache[FPGA0index]).at(vectorindex++);
105  }
106  }
107 
108  // fPGA1 skipping overlap with FPGA0 and FPGA2
109  vectorindex = 0;
110  for (int i{ 0 }; i < 10; i++) {
111  vectorindex += 2;
112  for (int j{ 2 }; j < 4; j++) {
113  towerlist[i][j + 4] = (*m_towerrankingcache[FPGA1index]).at(vectorindex++);
114  }
115  vectorindex += 2;
116  }
117 
118  // FPGA2
119  vectorindex = 0;
120  for (int i{ 0 }; i < 10; i++) {
121  for (int j{ 0 }; j < 6; j++) {
122  towerlist[i][j + 8] = (*m_towerrankingcache[FPGA2index]).at(vectorindex++);
123  }
124  }
125 
126  // FPGA4 skipping overlap with FPGA2
127  vectorindex = 0;
128  for (int i{ 0 }; i < 10; i++) {
129  vectorindex += 2;
130  for (int j{ 2 }; j < 6; j++) {
131  towerlist[i][j + 12] = (*m_towerrankingcache[FPGA3index]).at(vectorindex++);
132  }
133  }
134  return StatusCode::SUCCESS;
135 }
136 
138  return m_hascsvfile;
139 }
140 
142 {
143  // This function determines the order of towers in an FPGA.
144  // Towers are sorted using eta and phi, and
145  // then store the result in m_towerrankingcache object for future use.
146 
147  // If the tower order of an FPGA has not been determined yet, start sorting.
148  if (!m_towerrankingcache[FPGAindex]) {
149  std::vector<std::pair<int, int>> rankingmap;
150  // the row order is determined by eta while the column order is determined by phi
151  for (auto each : *m_alltowers[FPGAindex]) {
152  if (each.eTowerPhi < 3 && each.eTowerPhi > -1 && FPGAindex >= getFPGAIndex(21, 0)) {
153  rankingmap.push_back(std::pair<int, int>(-each.eTowerEta - (90 + each.eTowerPhi) * 100, each.eTowerID));
154  } else {
155  rankingmap.push_back(std::pair<int, int>(-each.eTowerEta - each.eTowerPhi * 100, each.eTowerID));
156  }
157  }
158  // There is supposed to be 60 towers in each FPGA
159  if (rankingmap.size() != 60) {
160  return StatusCode::FAILURE;
161  }
162  std::sort(rankingmap.begin(), rankingmap.end(),
163  [](std::pair<int, int> a, std::pair<int, int> b) {
164  // tower around eta == 0 has the same eta.
165  if (a.first == b.first) {
166  return (a.second < b.second);
167  }
168  return (a.first > b.first);
169  });
170  auto output = std::make_unique<std::vector<int>>();
171  output->reserve(60);
172  int vectorindex = 0;
173  for (int i{ 0 }; i < 10; i++) {
174  for (int j{ 0 }; j < 6; j++) {
175  output->push_back(rankingmap[vectorindex++].second);
176  }
177  }
178  m_towerrankingcache[FPGAindex] = std::move(output);
179  }
180  return StatusCode::SUCCESS;
181 }
182 
183 bool LVL1::eFEXFPGATowerIdProvider::hasFPGA(int FPGAindex) const
184 {
185  // check if the info of a speific FPGA has been loaded or not
186  return m_alltowers.contains(FPGAindex);
187 }
188 
190 {
191  // read the .csv file line by line
192  std::string eachline;
193  std::ifstream myfile(m_csvaddress);
194  if (myfile.is_open()) {
195  while (std::getline(myfile, eachline)) {
196  // ignore text after #
197  std::string::size_type ipos = eachline.find("#");
198  if (ipos!=std::string::npos) eachline.resize(ipos);
199 
200  // prevent reading lines with only white spaces
201  if (std::all_of(eachline.begin(), eachline.end(), ::isspace)) {
202  continue;
203  }
204 
205  // ignore lines with non-digit characters
206  auto validchar = [](char ch) { return (::isspace(ch) || ::isdigit(ch) || ch==','); };
207  if (!std::all_of(eachline.begin(), eachline.end(), validchar)) {
208  ATH_MSG_INFO("invalid line '" << eachline << "'");
209  break;
210  }
211 
212  // split lines in the .csv file by comma
213  std::stringstream eachline_stream(eachline);
214  std::vector<int> numbers_in_eachline;
215  while (eachline_stream.good()) {
216  std::string tem_string;
217  std::getline(eachline_stream, tem_string, ',');
218  try {
219  numbers_in_eachline.push_back(std::stoi(tem_string));
220  }
221  catch (...) {
222  ATH_MSG_WARNING( "Invalid input in tower_fpga_efex_map.csv." );
223  return StatusCode::FAILURE;
224  }
225  }
226 
227  // There is supposed to be 5 numbers in each line:
228  // eFEX ID, FPGA ID, eTower ID, eta, phi
229  if (numbers_in_eachline.size() != 5) {
230  ATH_MSG_WARNING( "Invalid input in tower_fpga_efex_map.csv." );
231  return StatusCode::FAILURE;
232  }
233  // eta and phi are supposed to be positive
234  if (numbers_in_eachline[3] < 0 || numbers_in_eachline[4] < 0) {
235  ATH_MSG_WARNING("Invalid input in tower_fpga_efex_map.csv.");
236  // return scodefail
237  return StatusCode::FAILURE;
238  }
239  int FPGAindex = getFPGAIndex(numbers_in_eachline[0], numbers_in_eachline[1]);
240  // check the range of eFEX ID and FPGA ID
241  if (FPGAindex == -1) {
242  ATH_MSG_WARNING("Invalid input in tower_fpga_efex_map.csv.");
243  return StatusCode::FAILURE;
244  }
245  towerinfo tem_towerinfo;
246  tem_towerinfo.eTowerID = numbers_in_eachline[2];
247  // determine the sign of eta using the tower id
248  // positive: 200000-299999, 400000-499999, 600000-699999
249  // negative: 100000-199999, 300000-399999, 500000-599999
250  int etasign;
251  if (int(numbers_in_eachline[2] / 100000) % 2 != 0) {
252  etasign = -1;
253  } else {
254  etasign = 1;
255  }
256  tem_towerinfo.eTowerEta = etasign * (numbers_in_eachline[3]);
257  tem_towerinfo.eTowerPhi = numbers_in_eachline[4];
258 
259  // Create a key for the FPGA if the the FPGA key is not
260  // avaliable in the m_alltowers hash table object yet.
261  // Otherwise append the tower to the existing bucket.
262  if (hasFPGA(FPGAindex)) {
263  m_alltowers[FPGAindex]->push_back(tem_towerinfo);
264  } else {
265  m_alltowers[FPGAindex] = std::make_unique<std::vector<towerinfo>>(std::vector{tem_towerinfo});
266  }
267  }
268  myfile.close();
269  } else {
270  ATH_MSG_WARNING("Unable to open share/tower_fpga_efex_map.csv.");
271  return StatusCode::FAILURE;
272  }
273  return StatusCode::SUCCESS;
274 }
275 
276 int LVL1::eFEXFPGATowerIdProvider::getFPGAIndex(int eFEXid, int FPGAid) const
277 {
278  // check the range of eFEX ID and FPGA ID
279  // There is supposed to be 24 eFex and each eFex
280  // contains 4 FPGAs.
281  if (FPGAid < 0 or FPGAid > 3) {
282  return -1;
283  }
284  if (eFEXid < 0 or FPGAid > 23) {
285  return -1;
286  }
287  return eFEXid * 4 + FPGAid;
288 }
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDinFPGA
StatusCode getRankedTowerIDinFPGA(int eFEXID, int FPGAID, int(&towerlist)[10][6]) const override
obtain ordered tower IDs in an FPGA
Definition: eFEXFPGATowerIdProvider.cxx:59
sendEI_SPB.ch
ch
Definition: sendEI_SPB.py:35
LVL1::eFEXFPGATowerIdProvider::~eFEXFPGATowerIdProvider
~eFEXFPGATowerIdProvider()
Destructor.
Definition: eFEXFPGATowerIdProvider.cxx:27
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
PathResolver::find_file
static std::string find_file(const std::string &logical_file_name, const std::string &search_path, SearchType search_type=LocalSearch)
Definition: PathResolver.cxx:251
LVL1::eFEXFPGATowerIdProvider::initialize
StatusCode initialize() override
initialize the tool
Definition: eFEXFPGATowerIdProvider.cxx:18
LVL1::eFEXFPGATowerIdProvider::towerinfo
Sturcture defines the id, eta and phi position of a tower.
Definition: eFEXFPGATowerIdProvider.h:38
LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDineFEX
StatusCode getRankedTowerIDineFEX(int eFEXID, int(&towerlist)[10][18]) const override
obtain ordered tower IDs in an eFEX
Definition: eFEXFPGATowerIdProvider.cxx:83
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
LVL1::eFEXFPGATowerIdProvider::towerinfo::eTowerPhi
int eTowerPhi
tower Phi index
Definition: eFEXFPGATowerIdProvider.h:41
lumiFormat.i
int i
Definition: lumiFormat.py:85
LVL1::eFEXFPGATowerIdProvider::towerinfo::eTowerEta
int eTowerEta
tower Eta index
Definition: eFEXFPGATowerIdProvider.h:40
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
test_pyathena.parent
parent
Definition: test_pyathena.py:15
LVL1::eFEXFPGATowerIdProvider::ifhaveinputfile
bool ifhaveinputfile() const override
Definition: eFEXFPGATowerIdProvider.cxx:137
LVL1::eFEXFPGATowerIdProvider::setAddress
StatusCode setAddress(const std::string &inputaddress) override
set path to the csv file and load
Definition: eFEXFPGATowerIdProvider.cxx:33
eFEXFPGATowerIdProvider.h
Provide tower-FPGA mapping.
TrigConf::name
Definition: HLTChainList.h:35
PathResolver.h
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
LVL1::eFEXFPGATowerIdProvider::towerinfo::eTowerID
int eTowerID
tower ID
Definition: eFEXFPGATowerIdProvider.h:39
LVL1::eFEXFPGATowerIdProvider::getFPGAIndex
int getFPGAIndex(int eFEXid, int FPGAid) const override
determine the index of an FPGA
Definition: eFEXFPGATowerIdProvider.cxx:276
LVL1::eFEXFPGATowerIdProvider::rankTowerinFPGA
StatusCode rankTowerinFPGA(int FPGAindex) override
rank the tower ids in an FPGA This function determines the order of towers in an FPGA.
Definition: eFEXFPGATowerIdProvider.cxx:141
a
TList * a
Definition: liststreamerinfos.cxx:10
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
LVL1::eFEXFPGATowerIdProvider::loadcsv
StatusCode loadcsv() override
load the mapping info in the csv file
Definition: eFEXFPGATowerIdProvider.cxx:189
LVL1::eFEXFPGATowerIdProvider::hasFPGA
bool hasFPGA(int) const override
check if an FPGA exists in the csv file
Definition: eFEXFPGATowerIdProvider.cxx:183
LVL1::eFEXFPGATowerIdProvider::eFEXFPGATowerIdProvider
eFEXFPGATowerIdProvider(const std::string &type, const std::string &name, const IInterface *parent)
Constructor.
Definition: eFEXFPGATowerIdProvider.cxx:12
AthAlgTool
Definition: AthAlgTool.h:26