ATLAS Offline Software
Loading...
Searching...
No Matches
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
11
12LVL1::eFEXFPGATowerIdProvider::eFEXFPGATowerIdProvider(const std::string &type, const std::string &name, const IInterface *parent):
13 AthAlgTool(type, name, parent)
14{
15 declareInterface<eFEXFPGATowerIdProvider>(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
32
33StatusCode 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
59StatusCode LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDinFPGA(int eFEXID, int FPGAID, int(&towerlist)[10][6]) const {
60 int FPGAindex{ getFPGAIndex(eFEXID, FPGAID) };
61 if (FPGAindex<0) return StatusCode::FAILURE;
62 if (m_towerrankingcache[FPGAindex]) {
63 // obtain the tower order from cache
64 int vectorindex{ 0 };
65 for (int i{ 0 }; i < 10; i++) {
66 for (int j{ 0 }; j < 6; j++) {
67 towerlist[i][j] = (*m_towerrankingcache[FPGAindex]).at(vectorindex++);
68 }
69 }
70 }
71 // set tower ids to 0 if the information about the FPGA stored in the .csv file is damaged
72 else {
73 for (int i{ 0 }; i < 10; i++) {
74 for (int j{ 0 }; j < 6; j++) {
75 towerlist[i][j] = 0;
76 }
77 }
78 ATH_MSG_ERROR("FPGA mapping info missing.");
79 return StatusCode::FAILURE;
80 }
81 return StatusCode::SUCCESS;
82}
83
84StatusCode LVL1::eFEXFPGATowerIdProvider::getRankedTowerIDineFEX(int eFEXID, int(&towerlist)[10][18]) const {
85 int FPGA0index{ getFPGAIndex(eFEXID, 0) };
86 int FPGA1index{ getFPGAIndex(eFEXID, 1) };
87 int FPGA2index{ getFPGAIndex(eFEXID, 2) };
88 int FPGA3index{ getFPGAIndex(eFEXID, 3) };
89 //
90 auto is_negative = [](int val){return val<0;};
91 if (std::ranges::any_of(std::initializer_list{FPGA0index, FPGA1index, FPGA2index, FPGA3index}, is_negative)){
92 return StatusCode::FAILURE;
93 }
94
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
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 if (FPGAindex < 0) return StatusCode::FAILURE;
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 auto output = std::make_unique<std::vector<int>>();
178 output->reserve(60);
179 int vectorindex = 0;
180 for (int i{ 0 }; i < 10; i++) {
181 for (int j{ 0 }; j < 6; j++) {
182 output->push_back(rankingmap[vectorindex++].second);
183 }
184 }
185 m_towerrankingcache[FPGAindex] = std::move(output);
186 }
187 return StatusCode::SUCCESS;
188}
189
191{
192 // check if the info of a speific FPGA has been loaded or not
193 return m_alltowers.contains(FPGAindex);
194}
195
197{
198 // read the .csv file line by line
199 std::string eachline;
200 std::ifstream myfile(m_csvaddress);
201 if (myfile.is_open()) {
202 while (std::getline(myfile, eachline)) {
203 // ignore text after #
204 std::string::size_type ipos = eachline.find("#");
205 if (ipos!=std::string::npos) eachline.resize(ipos);
206
207 // prevent reading lines with only white spaces
208 if (std::all_of(eachline.begin(), eachline.end(), ::isspace)) {
209 continue;
210 }
211
212 // ignore lines with non-digit characters
213 auto validchar = [](char ch) { return (::isspace(ch) || ::isdigit(ch) || ch==','); };
214 if (!std::all_of(eachline.begin(), eachline.end(), validchar)) {
215 ATH_MSG_INFO("invalid line '" << eachline << "'");
216 break;
217 }
218
219 // split lines in the .csv file by comma
220 std::stringstream eachline_stream(eachline);
221 std::vector<int> numbers_in_eachline;
222 while (eachline_stream.good()) {
223 std::string tem_string;
224 std::getline(eachline_stream, tem_string, ',');
225 try {
226 numbers_in_eachline.push_back(std::stoi(tem_string));
227 }
228 catch (...) {
229 ATH_MSG_WARNING( "Invalid input in tower_fpga_efex_map.csv." );
230 return StatusCode::FAILURE;
231 }
232 }
233
234 // There is supposed to be 5 numbers in each line:
235 // eFEX ID, FPGA ID, eTower ID, eta, phi
236 if (numbers_in_eachline.size() != 5) {
237 ATH_MSG_WARNING( "Invalid input in tower_fpga_efex_map.csv." );
238 return StatusCode::FAILURE;
239 }
240 // eta and phi are supposed to be positive
241 if (numbers_in_eachline[3] < 0 || numbers_in_eachline[4] < 0) {
242 ATH_MSG_WARNING("Invalid input in tower_fpga_efex_map.csv.");
243 // return scodefail
244 return StatusCode::FAILURE;
245 }
246 int FPGAindex = getFPGAIndex(numbers_in_eachline[0], numbers_in_eachline[1]);
247 // check the range of eFEX ID and FPGA ID
248 if (FPGAindex == -1) {
249 ATH_MSG_WARNING("Invalid input in tower_fpga_efex_map.csv.");
250 return StatusCode::FAILURE;
251 }
252 towerinfo tem_towerinfo;
253 tem_towerinfo.eTowerID = numbers_in_eachline[2];
254 // determine the sign of eta using the tower id
255 // positive: 200000-299999, 400000-499999, 600000-699999
256 // negative: 100000-199999, 300000-399999, 500000-599999
257 int etasign;
258 if (int(numbers_in_eachline[2] / 100000) % 2 != 0) {
259 etasign = -1;
260 } else {
261 etasign = 1;
262 }
263 tem_towerinfo.eTowerEta = etasign * (numbers_in_eachline[3]);
264 tem_towerinfo.eTowerPhi = numbers_in_eachline[4];
265
266 // Create a key for the FPGA if the the FPGA key is not
267 // avaliable in the m_alltowers hash table object yet.
268 // Otherwise append the tower to the existing bucket.
269 if (hasFPGA(FPGAindex)) {
270 m_alltowers[FPGAindex]->push_back(tem_towerinfo);
271 } else {
272 m_alltowers[FPGAindex] = std::make_unique<std::vector<towerinfo>>(std::vector{tem_towerinfo});
273 }
274 }
275 myfile.close();
276 } else {
277 ATH_MSG_WARNING("Unable to open share/tower_fpga_efex_map.csv.");
278 return StatusCode::FAILURE;
279 }
280 return StatusCode::SUCCESS;
281}
282
283int LVL1::eFEXFPGATowerIdProvider::getFPGAIndex(int eFEXid, int FPGAid) const
284{
285 // check the range of eFEX ID and FPGA ID
286 // There is supposed to be 24 eFex and each eFex
287 // contains 4 FPGAs.
288 if (FPGAid < 0 or FPGAid > 3) {
289 return -1;
290 }
291 if (eFEXid < 0 or FPGAid > 23) {
292 return -1;
293 }
294 return eFEXid * 4 + FPGAid;
295}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
static Double_t a
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
StatusCode loadcsv()
load the mapping info in the csv file
bool hasFPGA(int) const
check if an FPGA exists in the csv file
std::vector< std::unique_ptr< std::vector< int > > > m_towerrankingcache
Ordered tower Ids in each FPGAs. The index is the index of the FPGA.
StatusCode initialize()
initialize the tool
bool m_hascsvfile
if the csv file is valid
StatusCode rankTowerinFPGA(int FPGAindex)
rank the tower ids in an FPGA This function determines the order of towers in an FPGA.
int getFPGAIndex(int eFEXid, int FPGAid) const
determine the index of an FPGA
std::unordered_map< int, std::unique_ptr< std::vector< towerinfo > > > m_alltowers
Unordered tower Ids in each FPGAs. The index is the index of the FPGA.
StatusCode getRankedTowerIDinFPGA(int eFEXID, int FPGAID, int(&towerlist)[10][6]) const
obtain ordered tower IDs in an FPGA
StatusCode getRankedTowerIDineFEX(int eFEXID, int(&towerlist)[10][18]) const
obtain ordered tower IDs in an eFEX
std::string m_csvaddress
path to the input csv file
eFEXFPGATowerIdProvider(const std::string &type, const std::string &name, const IInterface *parent)
Constructor.
StatusCode setAddress(const std::string &inputaddress)
set path to the csv file and load
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
Provide tower-FPGA mapping.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
Sturcture defines the id, eta and phi position of a tower.