ATLAS Offline Software
Loading...
Searching...
No Matches
gFexTowerSummer.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5//***************************************************************************
6// gFexTowerSummer - description
7// -------------------
8// Builds gFexDataTowers50 and gFexDataTowers200 from gFexDataTowers
9//
10// begin : 25 06 2025
11// email : jared.little@cern.ch
12//***************************************************************************/
13
14#include "gFexTowerSummer.h"
16
17
18#include <vector>
19#include <memory>
20#include <cmath> //M_PI
21
22namespace LVL1 {
23
24gFexTowerSummer::gFexTowerSummer(const std::string& name, ISvcLocator* svc)
26
28
30 "Initializing L1CaloFEXAlgos/gFexEmulatedTowers algorithm with name: "
31 << name());
32 ATH_MSG_INFO("Writing into SG key: " << m_gTowersWriteKey);
33
34 // initialise keys
36 ATH_CHECK( m_gTowersWriteKey.initialize() );
37 ATH_CHECK( m_gTowers50WriteKey.initialize() );
38
41
42 return StatusCode::SUCCESS;
43}
44
45StatusCode gFexTowerSummer::execute(const EventContext& ctx) const {
46
47 // WriteHandle for gFEX Input Towers
49 ATH_CHECK( gTowersContainer.record(std::make_unique<xAOD::gFexTowerContainer>(), std::make_unique<xAOD::gFexTowerAuxContainer>()));
50 ATH_MSG_DEBUG("Recorded gFexEmulatedTower 200 MeV container with key "<< gTowersContainer.key());
51
53 ATH_CHECK( gTowers50Container.record(std::make_unique<xAOD::gFexTowerContainer>(), std::make_unique<xAOD::gFexTowerAuxContainer>()));
54 ATH_MSG_DEBUG("Recorded gFexEmulatedTower 50 MeV container with key "<< gTowers50Container.key());
55
56 xAOD::gFexTowerContainer* gTowersEMContainerPtr = nullptr;
57 xAOD::gFexTowerContainer* gTowersHADContainerPtr = nullptr;
60
61 if (!m_gTowersEMWriteKey.empty()) {
62 ATH_CHECK( gTowersEMContainer.record(std::make_unique<xAOD::gFexTowerContainer>(), std::make_unique<xAOD::gFexTowerAuxContainer>()));
63 ATH_MSG_DEBUG("Recorded gFexEmulatedTower 200 MeV EM container with key "<< m_gTowersEMWriteKey.key());
64 gTowersEMContainerPtr = &*gTowersEMContainer;
65 }
66 if (!m_gTowersHADWriteKey.empty()) {
67 ATH_CHECK( gTowersHADContainer.record(std::make_unique<xAOD::gFexTowerContainer>(), std::make_unique<xAOD::gFexTowerAuxContainer>()));
68 ATH_MSG_DEBUG("Recorded gFexEmulatedTower 200 MeV HAD container with key "<< m_gTowersHADWriteKey.key());
69 gTowersHADContainerPtr = &*gTowersHADContainer;
70 }
71
72 // Atwr, Btwr, Ctwr will contain gTowers towers for each FPGA
73 gtFPGA Atwr{};
74 gtFPGA Btwr{};
75 gtFPGA Ctwr{};
76
77 gtFPGA AtwrF{};
78 gtFPGA BtwrF{};
79 gtFPGA CtwrF{};
80
81 gtFPGA Asatur{};
82 gtFPGA Bsatur{};
83 gtFPGA Csatur{};
84
85
86 // reconstruct the gTowers/saturation
87 ATH_CHECK( gtReconstructABC(ctx, 0, AtwrF, Atwr, Asatur));
88 ATH_CHECK( gtReconstructABC(ctx, 1, BtwrF, Btwr, Bsatur));
89 ATH_CHECK( gtReconstructABC(ctx, 2, CtwrF, Ctwr, Csatur));
90
91
92 // Write the towers
93 int iEta = 0;
94 int iPhi = 0;
95 float Eta = 0;
96 float Phi = 0;
97 int Et = 0;
98 int EtF = 0;
99 int Fpga = 0;
100 char IsSaturated = 0;
101 int towerID = 0;
102
103 // Assign ID based on FPGA (FPGA-A 0->0; FPGA-B 1->10000, FPGA-C 2->20000) and gTower number assigned as per firmware convention
104
105 int twr_rows = Atwr.size(); // 32
106 int twr_cols = Atwr[0].size(); // 12
107
108 Fpga = 0;
109
110 // Save towers from FPGA A in gTower EDM
111 for (int irow = 0; irow < twr_rows; irow++){
112 for (int icol = 0; icol < twr_cols; icol++){
113 iEta = icol + 8;
114 iPhi = irow;
115 Et = Atwr[irow][icol];
116 EtF = AtwrF[irow][icol];
117 IsSaturated = Asatur[irow][icol];
118 getEtaPhi(Eta, Phi, iEta, iPhi, towerID);
119 gTowersContainer->push_back( std::make_unique<xAOD::gFexTower>() );
120 gTowersContainer->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
121 gTowers50Container->push_back( std::make_unique<xAOD::gFexTower>() );
122 gTowers50Container->back()->initialize(iEta, iPhi, Eta, Phi, EtF, Fpga, IsSaturated, towerID);
123 if (gTowersEMContainerPtr) {
124 gTowersEMContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
125 gTowersEMContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
126 }
127 if (gTowersHADContainerPtr) {
128 gTowersHADContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
129 gTowersHADContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
130 }
131 towerID += 1;
132
133 }
134 }
135
136 // Save towers from FPGA B in gTower EDM
137 Fpga = 1;
138 towerID = 10000;
139 // Save towers from FPGA B in gTower EDM
140 for (int irow = 0; irow < twr_rows; irow++){
141 for (int icol = 0; icol < twr_cols; icol++){
142 iEta = icol + 20;
143 iPhi = irow;
144 Et = Btwr[irow][icol];
145 EtF = BtwrF[irow][icol];
146 IsSaturated = Bsatur[irow][icol];
147 getEtaPhi(Eta, Phi, iEta, iPhi, towerID);
148 gTowersContainer->push_back( std::make_unique<xAOD::gFexTower>() );
149 gTowersContainer->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
150 gTowers50Container->push_back( std::make_unique<xAOD::gFexTower>() );
151 gTowers50Container->back()->initialize(iEta, iPhi, Eta, Phi, EtF, Fpga, IsSaturated, towerID);
152 if (gTowersEMContainerPtr) {
153 gTowersEMContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
154 gTowersEMContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
155 }
156 if (gTowersHADContainerPtr) {
157 gTowersHADContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
158 gTowersHADContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
159 }
160 towerID += 1;
161 }
162 }
163
164 // Save towers from FPGA C in gTower EDM
165 Fpga = 2;
166 towerID = 20000;
167 for (int irow = 0; irow < twr_rows; irow++){
168 for (int icol = 0; icol < twr_cols/2; icol++){
169 iEta = icol + 2;
170 iPhi = irow;
171 Et = Ctwr[irow][icol];
172 EtF = CtwrF[irow][icol];
173 IsSaturated = Csatur[irow][icol];
174 getEtaPhi(Eta, Phi, iEta, iPhi, towerID);
175 gTowersContainer->push_back( std::make_unique<xAOD::gFexTower>() );
176 gTowersContainer->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
177 gTowers50Container->push_back( std::make_unique<xAOD::gFexTower>() );
178 gTowers50Container->back()->initialize(iEta, iPhi, Eta, Phi, EtF, Fpga, IsSaturated, towerID);
179 if (gTowersEMContainerPtr) {
180 gTowersEMContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
181 gTowersEMContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
182 }
183 if (gTowersHADContainerPtr) {
184 gTowersHADContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
185 gTowersHADContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
186 }
187 towerID += 1;
188 }
189 for (int icol = twr_cols/2; icol < twr_cols; icol++){
190 iEta = icol + 26;
191 iPhi = irow;
192 Et = Ctwr[irow][icol];
193 EtF = CtwrF[irow][icol];
194 IsSaturated = Csatur[irow][icol];
195 getEtaPhi(Eta, Phi, iEta, iPhi, towerID);
196 gTowersContainer->push_back( std::make_unique<xAOD::gFexTower>() );
197 gTowersContainer->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
198 gTowers50Container->push_back( std::make_unique<xAOD::gFexTower>() );
199 gTowers50Container->back()->initialize(iEta, iPhi, Eta, Phi, EtF, Fpga, IsSaturated, towerID);
200 if (gTowersEMContainerPtr) {
201 gTowersEMContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
202 gTowersEMContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
203 }
204 if (gTowersHADContainerPtr) {
205 gTowersHADContainerPtr->push_back( std::make_unique<xAOD::gFexTower>() );
206 gTowersHADContainerPtr->back()->initialize(iEta, iPhi, Eta, Phi, Et, Fpga, IsSaturated, towerID);
207 }
208 towerID += 1;
209 }
210 }
211
212 return StatusCode::SUCCESS;
213}
214
215
216StatusCode gFexTowerSummer::gtReconstructABC(const EventContext& ctx,
217 unsigned int XFPGA,
218 gtFPGA &XgtF, gtFPGA &Xgt,
219 gtFPGA &Xsaturation) const{
220
221 // Loop over the Fiber Towers and fill gTower arrays as per original byte stream decoder
222
223 // Reading the Fiber Tower container
225 if (!gFexFiberTowerContainer.isValid()) {
226 ATH_MSG_ERROR("Could not retrieve Fiber tower collection "
227 << gFexFiberTowerContainer.key());
228 return StatusCode::FAILURE;
229 }
230
231 if (gFexFiberTowerContainer->empty()) {
232 ATH_MSG_WARNING("Cannot fill gTowers here, fiber container is empty. "
233 << gFexFiberTowerContainer->size());
234 return StatusCode::SUCCESS;
235 }
236
237 // Zero the input gTower sums/saturation
238 for(int irow=0; irow<LVL1::gFEXPos::ABC_ROWS; irow++){
239 for(int icolumn=0; icolumn<LVL1::gFEXPos::AB_COLUMNS; icolumn++){
240 Xgt[irow][icolumn] = 0;
241 XgtF[irow][icolumn] = 0;
242 Xsaturation[irow][icolumn] = 0;
243 }
244 }
245
246 // Energy arrays for the EM and hadronic in standard and extra eta regions
247 // 200 MeV towers
248 std::array<int, LVL1::gFEXPos::AB_TOWERS> etowerData{}; // 384
249 std::array<int, LVL1::gFEXPos::AB_TOWERS> htowerData{};
250 std::array<int, LVL1::gFEXPos::ABC_ROWS> xetowerData{}; // 32
251 std::array<int, LVL1::gFEXPos::ABC_ROWS> xhtowerData{};
252 std::array<int, LVL1::gFEXPos::ABC_ROWS> ohtowerData{};
253
254 // 50 MeV towers
255 std::array<int, LVL1::gFEXPos::AB_TOWERS> etowerDataF{};
256 std::array<int, LVL1::gFEXPos::AB_TOWERS> htowerDataF{};
257 std::array<int, LVL1::gFEXPos::ABC_ROWS> xetowerDataF{};
258 std::array<int, LVL1::gFEXPos::ABC_ROWS> xhtowerDataF{};
259 std::array<int, LVL1::gFEXPos::ABC_ROWS> ohtowerDataF{};
260
261 // saturation
262 std::array<bool, LVL1::gFEXPos::AB_TOWERS> saturationData{}; // 384
263
264 // loop over the Fiber towers, and fill the tower energy arrays
265 for(const xAOD::gFexTower* gfexFiberTower : *gFexFiberTowerContainer){
266 // first match the FPGA
267 unsigned int fiberTowerFpga = gfexFiberTower->fpga();
268 if (fiberTowerFpga != XFPGA) continue;
269
270 // working with "local" fiber number, iFiber
271 unsigned int fiberTowerId = gfexFiberTower->gFEXtowerID();
272 unsigned int offset = (XFPGA == 2) ? 20000 : (XFPGA == 1) ? 10000 : 0;
273 unsigned int iFiber = (fiberTowerId - offset)/16;
274
275 // Do not exceed maximum number of fibers for FPGA
276 unsigned int maxFiberN = (XFPGA == 2) ? LVL1::gFEXPos::C_FIBERS : LVL1::gFEXPos::AB_FIBERS;
277 if (iFiber >= maxFiberN) continue;
278
279 ATH_MSG_DEBUG(" accessing " << fiberTowerId << " " << XFPGA << " " << offset << " " << iFiber);
280
281 unsigned int iDatum = fiberTowerId%16;
282
283 int fiber_type = (XFPGA == 0) ? LVL1::gFEXPos::AMPD_NFI[iFiber] :
284 (XFPGA == 1) ? LVL1::gFEXPos::BMPD_NFI[iFiber] : LVL1::gFEXPos::CMPD_NFI[iFiber];
285
286 // tells where the data is coming from
287 // - 0 - EMB, EMB/EMEC -> EM contribution
288 // - 1 - TREX,HEC - Had contribution
289 // - 2 - extended region ( EMEC)
290 // - 3 - extended region ( HEC)
291 // - 6 - 200MeV region only ( HEC)
292 // - 11 - HEC - Had contribution
293
294 int dataType = (XFPGA == 0) ? LVL1::gFEXPos::AMPD_DTYP_ARR[fiber_type][iDatum] :
295 (XFPGA == 1) ? LVL1::gFEXPos::BMPD_DTYP_ARR[fiber_type][iDatum] :
296 LVL1::gFEXPos::CMPD_DTYP_ARR[fiber_type][iDatum];
297
298 // tower number 0 - 383
299 int ntower = (XFPGA == 0) ? LVL1::gFEXPos::AMPD_GTRN_ARR[iFiber][iDatum] :
300 (XFPGA == 1) ? LVL1::gFEXPos::BMPD_GTRN_ARR[iFiber][iDatum] :
301 LVL1::gFEXPos::CMPD_GTRN_ARR[iFiber][iDatum];
302
303 // calo type
304 // FPGA 0/1 0,1,2
305 // FPGA 2 3
306 int caloType = (XFPGA == 0) ? LVL1::gFEXPos::ACALO_TYPE[iFiber] :
307 (XFPGA == 1) ? LVL1::gFEXPos::BCALO_TYPE[iFiber] : LVL1::gFEXPos::CCALO_TYPE[iFiber];
308
309 // saturation
310 // TODO: Route saturation to the correct column based on detector type,
311 // matching the firmware behaviour in tbuilder_sat.vhd.
312 // For regular EM/HAD (types 0, 1), ntower is a tower index (0-383) and
313 // saturation goes to the tower's natural column.
314 // For extended (types 2, 3) and overlap HEC (type 6), ntower is a row
315 // index (0-31) and saturation must go to the special column:
316 // FPGA A: extended -> col 0, overlap HEC -> col 4
317 // FPGA B: extended -> col 11, overlap HEC -> col 7
318 // Also skip HEC regular (type 11) saturation for FPGA B to match
319 // the firmware bug in tbuilder_mapper.vhd pFPGA_B SAT_LOW_HEC.
320 bool fiberSaturation = (bool)(gfexFiberTower->isSaturated());
321 if (fiberSaturation) {
322 if (XFPGA < 2) {
323 // FPGA A and B: route by detector type
324 switch (dataType) {
325 case 0: // EM
326 case 1: // TREX / HAD
327 saturationData[ntower] = true;
328 break;
329 case 11: // HEC regular
330 // FPGA-B FW bug: SAT_LOW_HEC checks wrong type, never fires
331 if (XFPGA != 1) {
332 saturationData[ntower] = true;
333 }
334 break;
335 case 2: // extended EMEC
336 case 3: // extended HEC
337 {
338 int extCol = (XFPGA == 0) ? 0 : 11;
339 int extTower = ntower * 12 + extCol;
340 if (extTower >= 0 && extTower < 384) {
341 saturationData[extTower] = true;
342 }
343 }
344 break;
345 case 6: // overlap HEC
346 {
347 int olapCol = (XFPGA == 0) ? 4 : 7;
348 int olapTower = ntower * 12 + olapCol;
349 if (olapTower >= 0 && olapTower < 384) {
350 saturationData[olapTower] = true;
351 }
352 }
353 break;
354 default:
355 break;
356 }
357 } else {
358 // FPGA C: simple saturation routing
359 saturationData[ntower] = true;
360 }
361 }
362
363 // Get the MLE from the EDM (stored as float)
364 unsigned int Toweret_mle = (unsigned int)(gfexFiberTower->towerEt());
365
366 // FPGA 0/1
367 if(caloType < 3) {
368 switch(dataType){
369 case 0:
370 etowerData[ntower] = Toweret_mle;
371 undoMLE( etowerData[ntower] );
372 etowerDataF[ntower] = etowerData[ntower];
373 break;
374 case 1:
375 htowerData[ntower] = Toweret_mle;
376
377 // mulitply by 20 to make 50 MeV LSB
378 // include this here before mulitplication by 20
379 htowerData[ntower] = 20*htowerData[ntower];
380 htowerDataF[ntower] = htowerData[ntower];
381 break;
382
383 case 2:
384 xetowerData[ntower] = Toweret_mle;
385 undoMLE( xetowerData[ntower] );
386 xetowerDataF[ntower] = xetowerData[ntower];
387 break;
388
389 case 3:
390 xhtowerData[ntower] = Toweret_mle;
391 undoMLE( xhtowerData[ntower] );
392 xhtowerDataF[ntower] = xhtowerData[ntower];
393 break;
394
395 case 6:
396 ohtowerData[ntower] = Toweret_mle;
397 undoMLE( ohtowerData[ntower] );
398 ohtowerDataF[ntower] = ohtowerData[ntower];
399 break;
400
401 case 11:
402 htowerData[ntower] = Toweret_mle;
403 undoMLE( htowerData[ntower] );
404 htowerDataF[ntower] = htowerData[ntower];
405 break;
406 }
407 } else {
408
409 // this is FPGA C
410 // only types 2 and 3 exist in FPGA C
411 switch(dataType){
412 case 2:
413 //
414 etowerData[ntower] = Toweret_mle;
415 undoMLE( etowerData[ntower] );
416 etowerDataF[ntower] = etowerData[ntower];
417
418 break;
419
420 case 3:
421 htowerData[ntower] = Toweret_mle;
422 undoMLE( htowerData[ntower] );
423 htowerDataF[ntower] = htowerData[ntower];
424 break;
425
426 case 15:
427 break;
428
429 case 99:
430 break;
431
432 default:
433 ATH_MSG_ERROR("Tower with unknown datatype "
434 << dataType);
435 return StatusCode::FAILURE;
436
437 }
438 } // end of case statement for FPGAC
439
440 ATH_MSG_DEBUG(" end of loop: " << XFPGA << " tower: " << ntower << " e " << etowerDataF[ntower] << " h " << htowerData[ntower] << " fibertower " << fiberTowerId);
441
442 } // end of loop over fiber towers
443
444 // Sum the energy arrays into the output gTowers
445 if( XFPGA == 0 ) {
446 for(int itower=0;itower<384;itower++){
447 int icolumn = itower%12;
448 int irow = itower/12;
449
450 // saturation
451 Xsaturation[irow][icolumn] = saturationData[itower];
452
453
454 // 50 MeV towers
455 int xF = etowerDataF[itower] + htowerDataF[itower];
456 // 200 MeV towers
457 int x = ( (etowerData[itower]>>2) + (htowerData[itower]>>2) );
458
459 ATH_MSG_DEBUG("sss1 " << icolumn << " " << irow << " " << xF << " " << x << " " << etowerDataF[itower] <<" " << htowerDataF[itower]);
460
461 signExtend(&xF,18);
462 signExtend(&x,18);
463
464 ATH_MSG_DEBUG("sss2 " << icolumn << " " << irow << " " << xF << " " << x);
465
466 Xgt[irow][icolumn] = x;
467 XgtF[irow][icolumn] = xF;
468
469 ATH_MSG_DEBUG("sss3 " << icolumn << " " << irow << " " << XgtF[irow][icolumn] << " " << Xgt[irow][icolumn]);
470
471 // eta region in FPGA A (eta ~ -2.5)
472 if ( icolumn == 0) {
473 int xx = ( (xetowerData[irow]>>2) + (xhtowerData[irow]>>2) );
474 signExtend(&xx,18);
475 Xgt[irow][icolumn] = Xgt[irow][icolumn] + xx;
476 ATH_MSG_DEBUG("sss4 " << icolumn << " " << irow << " " << XgtF[irow][icolumn] << " " << Xgt[irow][icolumn]);
477 }
478
479 if ( icolumn == 4) {
480 // 200 MeV towers
481 int ox = (ohtowerData[irow] >> 2 ) ;
482 signExtend(&ox,18);
483 Xgt[irow][icolumn] = Xgt[irow][icolumn] + ox ;
484 ATH_MSG_DEBUG("sss5 " << icolumn << " " << irow << " " << XgtF[irow][icolumn] << " " << Xgt[irow][icolumn]);
485 }
486
487 ATH_MSG_DEBUG("sss filling standard " << Xgt[irow][icolumn] << " fiber " << XgtF[irow][icolumn]);
488 }
489 }
490 else if ( XFPGA == 1 ) {
491 for(int itower=0;itower<384;itower++){
492 int icolumn = itower%12;
493 int irow = itower/12;
494
495 // saturation
496 Xsaturation[irow][icolumn] = saturationData[itower];
497
498 // 50 MeV towers
499 int xF = etowerDataF[itower] + htowerDataF[itower] ;
500 // 200 MeV towers
501 int x = ( (etowerData[itower]>>2) + (htowerData[itower] >> 2) );
502
503 signExtend(&xF,18);
504 signExtend(&x,18);
505
506 Xgt[irow][icolumn] = x;
507 XgtF[irow][icolumn] = xF;
508
509 // extra region FPGA B (eta ~ 2.5)
510 if ( icolumn == 11) {
511 // 200 MeV towers
512 int xx = ( (xetowerData[irow]>>2) + (xhtowerData[irow]>>2) );
513 signExtend(&xx,18);
514 Xgt[irow][icolumn] = Xgt[irow][icolumn] + xx;
515 }
516 if ( icolumn == 7 ) {
517 // 200 MeV towers
518 int xo = ohtowerData[irow]>>2;
519 signExtend(&xo,18);
520 Xgt[irow][icolumn] = Xgt[irow][icolumn] + xo;
521 }
522 }
523 }
524 else if ( XFPGA == 2 ) {
525 for(int itower=0;itower<384;itower++){
526 int icolumn = itower%12;
527 int irow = itower/12;
528
529 // saturation
530 Xsaturation[irow][icolumn] = saturationData[itower];
531
532 // 50 MeV towers
533 int xF = etowerDataF[itower] + htowerDataF[itower] ;
534 // 200 MeV towers
535 int x = ( (etowerData[itower]>>2 ) + (htowerData[itower]>>2));
536 signExtend(&xF,18);
537 signExtend(&x,18);
538
539 Xgt[irow][icolumn] = x;
540 XgtF[irow][icolumn] = xF;
541 }
542 }
543
544 return StatusCode::SUCCESS;
545}
546
547void gFexTowerSummer::undoMLE(int &datumPtr ) const{
548
549 // limit input to 12 bits to avoid accidental sign extension
550 int din = (0x00000FFF & datumPtr );
551 // map all special cases to zero for now
552 // limit negative values
553 if( (din > 0) && ( din < 962 ) ) din = 962;
554 //zeroZero
555 if( din == 0) din = 0x4EE;
556
557 int dout = 0;
558
559 int FPGA_CONVLIN_TH1 = 5;
560 int FPGA_CONVLIN_TH2 = 749;
561 int FPGA_CONVLIN_TH3 = 1773;
562 int FPGA_CONVLIN_TH4 = 2541;
563 int FPGA_CONVLIN_TH5 = 4029;
564 int FPGA_CONVLIN_TH6 = 4062;
565
566 // These two variables are unused
567 //int FPGA_CONVLIN_OF0 = -5072;
568 //int FPGA_CONVLIN_OF1 = -2012;
569 int FPGA_CONVLIN_OF2 = -1262;
570 int FPGA_CONVLIN_OF3 = -3036;
571 int FPGA_CONVLIN_OF4 = -8120;
572 int FPGA_CONVLIN_OF5 = -4118720;
573
574 int oth0 = 0;
575 int oth1 = 0;
576 int oth2 = 0;
577 int oth3 = 0;
578 int oth4 = 0;
579 int oth5 = 0;
580 int oth6 = 0;
581
582 // These two variables are unused
583 //int r1shv = 0;
584 //int r2shv = 0;
585 int r3shv = 0;
586 int r4shv = 0;
587 int r5shv = 0;
588 int r6shv = 0;
589 // int trxv = 0;
590
591
592 int r3conv = 0;
593 int r4conv = 0;
594 int r5conv = 0;
595 int r6conv = 0;
596 // int r3offs = 0;
597
598 //r1shv = ((din & 0x0000007F) << 9 ) & 0x0000FE00 ;
599 //r2shv = ((din & 0x00000FFF) << 1 ) & 0x00001FFE ;
600 r3shv = (din & 0x00000FFF) ;
601 r4shv = ((din & 0x00000FFF) << 1 ) & 0x00001FFE ;
602 r5shv = ((din & 0x00000FFF) << 2 ) & 0x00003FFC ;
603 r6shv = ((din & 0x00000FFF) << 10 ) & 0x003FFC00 ;
604
605 // These two variables are unused
606 //r1conv = r1shv + FPGA_CONVLIN_OF0;
607 //r2conv = r2shv + FPGA_CONVLIN_OF1;
608 r3conv = r3shv + FPGA_CONVLIN_OF2;
609 r4conv = r4shv + FPGA_CONVLIN_OF3;
610 r5conv = r5shv + FPGA_CONVLIN_OF4;
611 r6conv = r6shv + FPGA_CONVLIN_OF5;
612
613 if( din > 0 ) {
614 oth0 = 1;
615 }
616 else{
617 oth0 = 0;
618 }
619 if ( din > FPGA_CONVLIN_TH1 ){
620 oth1 = 1;
621 }
622 else{
623 oth1 = 0;
624 }
625 if ( din > FPGA_CONVLIN_TH2 ){
626 oth2 = 1;
627 }else{
628 oth2 = 0;
629 }
630 if ( din > FPGA_CONVLIN_TH3 ){
631 oth3 = 1;
632 }else{
633 oth3 = 0;
634 }
635 if ( din > FPGA_CONVLIN_TH4 ){
636 oth4 = 1;
637 }else{
638 oth4 = 0;
639 }
640 if ( din > FPGA_CONVLIN_TH5 ){
641 oth5 = 1;
642 }
643 else{
644 oth5 = 0;
645 }
646 if ( din > FPGA_CONVLIN_TH6 ){
647 oth6 = 1;
648 }
649 else{
650 oth6 = 0;
651 }
652
653
654 // divide by 2 to 50 MeV LSB
655
656 if( (! oth0) & (! oth1 ) & (! oth2 ) & (! oth3 ) & (! oth4 ) & (! oth5 ) & (! oth6 ) ) {
657 dout = 0;
658 }
668 else if( ( oth0) & ( oth1 ) & ( oth2 ) & (! oth3 ) & (! oth4 ) & (! oth5 ) & (! oth6 ) ) {
669 // cppcheck-suppress shiftNegativeLHS; well-defined in c++20
670 dout = r3conv >>1;
671 }
672 else if( ( oth0) & ( oth1 ) & ( oth2 ) & ( oth3 ) & (! oth4 ) & (! oth5 ) & (! oth6 ) ) {
673 // cppcheck-suppress shiftNegativeLHS; well-defined in c++20
674 dout = r4conv >>1;
675 }
676 else if( ( oth0) & ( oth1 ) & ( oth2 ) & ( oth3 ) & ( oth4 ) & (! oth5 ) & (! oth6 ) ) {
677 // cppcheck-suppress shiftNegativeLHS; well-defined in c++20
678 dout = r5conv >>1;
679 }
680 else if( ( oth0) & ( oth1 ) & ( oth2 ) & ( oth3 ) & ( oth4 ) & ( oth5 ) & (! oth6 ) ) {
681 // cppcheck-suppress shiftNegativeLHS; well-defined in c++20
682 dout = r6conv >>1;
683 }
684 else if( ( oth0) & ( oth1 ) & ( oth2 ) & ( oth3 ) & ( oth4 ) & ( oth5 ) & ( oth6 ) ) {
685 dout = 0;
686 }
687 /* This code cannot be reached, given the preceding conditions.
688 else {
689 dout = 0;
690 }
691 */
692
693 signExtend(&dout,15);
694
695 datumPtr = dout;
696}
697
698
699void gFexTowerSummer::signExtend(int *xptr, int upto) const{
700
701 // sign extend x to 32 bits assuming a hardware word length upto+1 bits (e.g. for 16 bit word upto should be 15 as in firmware)
702 // xptr pointer to input datum
703 // word length in hardware
704 int x = *xptr;
705 //printf("before %x \n", x);
706 //printf("masks %x %x \n", (0x00000001<<upto) , (0xFFFFFFFF<<(upto+1)) );
707 if( x & (0x00000001<<upto) ) {
708 x = ( x | (0xFFFFFFFF<<(upto+1)) );
709 } else {
710 // for now assume 17 bits -- but could be up to 18 bits
711 x = ( x & 0x000FFFF);
712 }
713 *xptr = x;
714
715}
716
717void gFexTowerSummer::getEtaPhi(float& Eta, float& Phi, int iEta, int iPhi,
718 int gFEXtowerID) const {
719
720 float s_centralPhiWidth =
721 (2 * M_PI) / 32; // In central region, gFex has 32 bins in phi
722 float s_forwardPhiWidth =
723 (2 * M_PI) / 16; // In forward region, gFex has 16 bins in phi (before
724 // rearranging bins)
725
726 const std::vector<float> s_EtaCenter = {
727 -4.5, -3.8, -3.38, -3.18, -3.15, -3, -2.8, -2.6, -2.35, -2.1,
728 -1.9, -1.7, -1.5, -1.3, -1.1, -0.9, -0.7, -0.5, -0.3, -0.1,
729 0.1, 0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9,
730 2.1, 2.35, 2.6, 2.8, 3.0, 3.15, 3.18, 3.38, 3.8, 4.5};
731
732 // Transform Eta and Phi indices for the most forward towers into the
733 // "original" indices, as before rearranging the towers such that the forward
734 // region is 12(ieta)x32(iphi). The FPGA-C has now the same format (12*32) as
735 // FPGA-A and FPGA-B. This is the result of a transformation in the firmware.
736 // Note that for the most forward towers, the Phi index and Eta index have
737 // been considered accordingly, so in order to get the correct float values of
738 // Phi and Eta we need to retrieve the "original" indices.
739 int towerID_base = 20000;
740 int iEtaOld = 0, iPhiOld = 0;
741
742 if (iEta == 2) {
743 if (iPhi == ((gFEXtowerID - towerID_base) / 24) * 2) {
744 iEtaOld = 0;
745 iPhiOld = iPhi / 2;
746 }
747 if (iPhi == (((gFEXtowerID - towerID_base - 12) / 24) * 2) + 1) {
748 iEtaOld = 1;
749 iPhiOld = (iPhi - 1) / 2;
750 }
751 }
752
753 else if (iEta == 3) {
754 if (iPhi == ((gFEXtowerID - towerID_base - 1) / 24) * 2) {
755 iEtaOld = 2;
756 iPhiOld = iPhi / 2;
757 }
758 if (iPhi == (((gFEXtowerID - towerID_base - 13) / 24) * 2) + 1) {
759 iEtaOld = 3;
760 iPhiOld = (iPhi - 1) / 2;
761 }
762 }
763
764 else if (iEta == 36) {
765 if (iPhi == (((gFEXtowerID - towerID_base - 22) / 24) * 2) + 1) {
766 iEtaOld = 36;
767 iPhiOld = (iPhi - 1) / 2;
768 }
769 if (iPhi == ((gFEXtowerID - towerID_base - 10) / 24) * 2) {
770 iEtaOld = 37;
771 iPhiOld = iPhi / 2;
772 }
773 }
774
775 else if (iEta == 37) {
776 if (iPhi == (((gFEXtowerID - towerID_base - 23) / 24) * 2) + 1) {
777 iEtaOld = 38;
778 iPhiOld = (iPhi - 1) / 2;
779 }
780 if (iPhi == ((gFEXtowerID - towerID_base - 11) / 24) * 2) {
781 iEtaOld = 39;
782 iPhiOld = iPhi / 2;
783 }
784 }
785
786 else {
787 iEtaOld = iEta;
788 iPhiOld = iPhi;
789 }
790
791 Eta = s_EtaCenter[iEtaOld];
792
793 float Phi_gFex = -99;
794
795 if ((iEtaOld <= 3) || ((iEtaOld >= 36))) {
796 Phi_gFex = ((iPhiOld * s_forwardPhiWidth) + s_forwardPhiWidth / 2);
797 } else {
798 Phi_gFex = ((iPhiOld * s_centralPhiWidth) + s_centralPhiWidth / 2);
799 }
800
801 if (Phi_gFex < M_PI) {
802 Phi = Phi_gFex;
803 } else {
804 Phi = (Phi_gFex - 2 * M_PI);
805 }
806}
807
808} // namespace LVL1
#define M_PI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define x
An algorithm that can be simultaneously executed in multiple threads.
const T * back() const
Access the last element in the collection as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
virtual StatusCode initialize() override
Function initialising the algorithm.
gFexTowerSummer(const std::string &name, ISvcLocator *svc)
SG::WriteHandleKey< xAOD::gFexTowerContainer > m_gTowersWriteKey
void signExtend(int *xptr, int upto) const
SG::WriteHandleKey< xAOD::gFexTowerContainer > m_gTowersHADWriteKey
std::array< std::array< int, LVL1::gFEXPos::AB_COLUMNS >, LVL1::gFEXPos::ABC_ROWS > gtFPGA
virtual StatusCode execute(const EventContext &) const override
Function executing the algorithm.
SG::ReadHandleKey< xAOD::gFexTowerContainer > m_gFexFiberTowersReadKey
SG::WriteHandleKey< xAOD::gFexTowerContainer > m_gTowersEMWriteKey
StatusCode gtReconstructABC(const EventContext &ctx, unsigned int XFPGA, gtFPGA &XgtF, gtFPGA &Xgt, gtFPGA &Xsaturation) const
SG::WriteHandleKey< xAOD::gFexTowerContainer > m_gTowers50WriteKey
void getEtaPhi(float &Eta, float &Phi, int iEta, int iPhi, int gFEXtowerID) const
void undoMLE(int &datumPtr) const
virtual bool isValid() override final
Can the handle be successfully dereferenced?
virtual const std::string & key() const override final
Return the StoreGate ID for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
void initialize(const uint8_t IEta, const uint8_t IPhi)
setter for the above
constexpr std::array< std::array< int, 16 >, 100 > AMPD_GTRN_ARR
Definition gFexPos.h:125
constexpr std::array< std::array< char, 20 >, 4 > CMPD_DTYP_ARR
Definition gFexPos.h:495
constexpr std::array< int, 100 > CMPD_NFI
Definition gFexPos.h:376
constexpr int C_FIBERS
Definition gFexPos.h:61
constexpr std::array< std::array< int, 16 >, 100 > CMPD_GTRN_ARR
Definition gFexPos.h:398
constexpr int AB_COLUMNS
Definition gFexPos.h:65
constexpr std::array< int, 100 > ACALO_TYPE
Definition gFexPos.h:115
constexpr int ABC_ROWS
Definition gFexPos.h:64
constexpr std::array< std::array< char, 20 >, 4 > AMPD_DTYP_ARR
Definition gFexPos.h:217
constexpr std::array< std::array< char, 20 >, 4 > BMPD_DTYP_ARR
Definition gFexPos.h:352
constexpr std::array< int, 100 > BCALO_TYPE
Definition gFexPos.h:250
constexpr std::array< int, 100 > CCALO_TYPE
Definition gFexPos.h:390
constexpr std::array< int, 100 > AMPD_NFI
Definition gFexPos.h:106
constexpr std::array< int, 100 > BMPD_NFI
Definition gFexPos.h:242
constexpr std::array< std::array< int, 16 >, 100 > BMPD_GTRN_ARR
Definition gFexPos.h:258
constexpr int AB_FIBERS
Definition gFexPos.h:60
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
gFexTower_v1 gFexTower
Define the latest version of the TriggerTower class.
Definition gFexTower.h:15
gFexTowerContainer_v1 gFexTowerContainer
Define the latest version of the TriggerTower container.