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