ATLAS Offline Software
Loading...
Searching...
No Matches
jFEXForwardElecAlgo.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// jFEXForwardElecAlgo - Algorithm for Forward Electron Algorithm in jFEX
6// -------------------
7// begin : 16 11 2021
8// email : Sergi.Rodriguez@cern.ch
9// email : ulla.blumenschein@cern.ch
10// email : sjolin@cern.ch
11//***************************************************************************
12
13#include "jFEXForwardElecAlgo.h"
16#include "L1CaloFEXSim/jTower.h"
19
20#include <iostream>
21#include <vector>
22#include <math.h>
23#include <fstream>
24
25namespace LVL1 {
26
27 //Default Constructor
28 LVL1::jFEXForwardElecAlgo::jFEXForwardElecAlgo(const std::string& type, const std::string& name, const IInterface* parent): AthAlgTool(type, name, parent) {
29 declareInterface<IjFEXForwardElecAlgo>(this);
30 }
31
35
47
48 //calls container for TT
51 if(! m_jTowerContainer.isValid()) {
52 ATH_MSG_ERROR("Could not retrieve jTowerContainer " << m_jTowerContainerKey.key());
53 return StatusCode::FAILURE;
54 }
55 return StatusCode::SUCCESS;
56 }
57
58
64
65 //global centre Eta and Phi coord of the TT
66 std::array<float,2> LVL1::jFEXForwardElecAlgo::getEtaPhi(uint ttID) {
67 if(ttID == 0) {
68 return {999,999};
69 }
70 const LVL1::jTower *tmpTower = m_jTowerContainer->findTower(ttID);
71 return {tmpTower->centreEta(),tmpTower->centrePhi()};
72 }
73
74 std::array<int,2> LVL1::jFEXForwardElecAlgo::getEtEmHad(uint ttID) const {
75 if(ttID == 0) {
76 return {0,0};
77 }
78 int TT_EtEM = 0;
79 if(m_map_Etvalues_EM.find(ttID) != m_map_Etvalues_EM.end()) {
80 TT_EtEM = m_map_Etvalues_EM.at(ttID)[0];
81 }
82 int TT_EtHad = 0;
83 if(m_map_Etvalues_HAD.find(ttID) != m_map_Etvalues_HAD.end()) {
84 TT_EtHad = m_map_Etvalues_HAD.at(ttID)[0];
85 }
86
87 return {TT_EtEM, TT_EtHad};
88 }
89
90 bool LVL1::jFEXForwardElecAlgo::getEMSat(unsigned int ttID ) {
91 if(ttID == 0) {
92 return false;
93 }
94
95 const LVL1::jTower * tmpTower = m_jTowerContainer->findTower(ttID);
96 return tmpTower->getEMSat();
97 }
98
100 std::unordered_map<int,std::vector<int> > etmapEM,
101 std::unordered_map<int,std::vector<int> > etmapHAD) {
102 m_map_Etvalues_EM=std::move(etmapEM);
103 m_map_Etvalues_HAD=std::move(etmapHAD);
104 }
105
106
108 auto [centreTT_EtEM,centreTT_EtHad] = getEtEmHad(seedTTID);
109 // check if seed has strictly more energy than its neighbours
110 {
111 auto it_seed_map = m_SearchGTauMap.find(seedTTID);
112 if(it_seed_map == m_SearchGTauMap.end()) {
113 ATH_MSG_ERROR("Could not find TT" << seedTTID << " in the seach (>) local maxima for tau/em file.");
114 return false;
115 }
116 for (const auto& gtt : it_seed_map->second ){
117 auto [tmp_EtEM,tmp_EtHad] = getEtEmHad(gtt);
118 if(tmp_EtEM>=centreTT_EtEM) {
119 return false;
120 }
121 }
122 }
123
124 // check if seed has equal or more energy than its neighbours
125 {
126 auto it_seed_map = m_SearchGeTauMap.find(seedTTID);
127 if(it_seed_map == m_SearchGeTauMap.end()) {
128 ATH_MSG_ERROR("Could not find TT" << seedTTID << " in the seach (>=) local maxima for tau/em file.");
129 return false;
130 }
131 for (const auto& gtt : it_seed_map->second ){
132 auto [tmp_EtEM,tmp_EtHad] = getEtEmHad(gtt);
133 if( tmp_EtEM>centreTT_EtEM) {
134 return false;
135 }
136 }
137 }
138
139 return true;
140 }
141
142
144 //determine direction for offsets (-1 : C-side, +1: A-side)
145 int direction = m_jfex < 3 ? -1 : +1;
146
147 std::vector<std::pair<int,int>> neighbours;
148 //eta/phi index offsets depend on the position of the seed the cluster is created from
149 //differentiate the (many) different cases:
150 if ( direction>0 ? neta < FEXAlgoSpaceDefs::jFEX_algoSpace_A_EMIE_eta - 1 // A-side condition
151 : neta > FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMB_start_eta) // C-side condition
152 { //Barrel
153 neighbours = { {neta , nphi+1},
154 {neta , nphi-1},
155 {neta+1, nphi },
156 {neta-1, nphi }
157 };
158 } else if ( direction>0 ? neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_EMIE_eta - 1
160 { //Barrel next to Endcap
161 neighbours = { {neta, nphi+1},
162 {neta, nphi-1},
163 {neta-direction, nphi},
164 {neta+direction, nphi/2} //boundary crossing into endcap -> reduced phi granularity
165 };
166 } else if ( direction>0 ? neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_EMIE_eta
168 { //Endcap next to Barrel
169 neighbours = { {neta, nphi+1},
170 {neta, nphi-1},
171 {neta+direction, nphi},
172 {neta-direction, 2*nphi+0}, //crossing into barrel region, higher phi granularity
173 {neta-direction, 2*nphi+1}, // -> consider both "touching" towers
174 };
176 : neta < FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMIE_end_eta - 1 && neta > FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMIE_start_eta )
177 { //Endcap
178 neighbours = { {neta , nphi+1},
179 {neta , nphi-1},
180 {neta+1, nphi },
181 {neta-1, nphi }
182 };
183 } else if ( direction>0 ? neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_FCAL_start_eta - 1
185 { //Endcap next to FCal
186 neighbours = { {neta, nphi+1},
187 {neta, nphi-1},
188 {neta-direction, nphi},
189 {neta+2*direction, nphi/2} //boundary crossing into FCal -> reduced phi granularity and skip first FCal bin
190 };
191 } else if ( direction>0 ? neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_FCAL_start_eta + 1 //first FCal bin must be skipped!
192 : neta == FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMIE_start_eta - 2 ) //first FCal bin must be skipped!
193 { //FCal next to Endcap
194 //phi spacing in FCal is very wide, no longer consider adding towers in phi direction
195 neighbours = { {neta-2*direction, 2*nphi+0}, //boundary crossing into endcap, higher phi granularity
196 {neta-2*direction, 2*nphi+1}, // -> consider both "touching" towers
197 {neta+direction, nphi}
198 };
200 : neta < FEXAlgoSpaceDefs::jFEX_algoSpace_C_FCAL_end_eta - 2 && neta > FEXAlgoSpaceDefs::jFEX_algoSpace_C_FCAL_start_eta )
201 { //FCal
202 neighbours = { {neta+1, nphi},
203 {neta-1, nphi}
204 };
205 } else if ( direction>0 ? neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_FCAL_end_eta - 1
207 { //FCal, last eta bin
208 neighbours = { {neta-direction, nphi}
209 };
210 } else {
211 ATH_MSG_ERROR("Eta index " << neta << " (side: "<< (direction>0?"A":"C") << ") does not seem to belong to any valid seed region");
212 }
213
214 //iterate over neighbours, find most energetic one
215 for (const auto& candEtaPhi: neighbours) {
216 uint candID = m_jFEXalgoTowerID[candEtaPhi.second][candEtaPhi.first];
217 const auto [candTT_EtEM, candTT_EtHad] = getEtEmHad(candID);
218 if (candTT_EtEM > elCluster.getNextTTEtEM()) {
219 elCluster.setNextTTEtEM(candTT_EtEM);
220 elCluster.setNextTTID(candID);
221 elCluster.setNextTTSatEM(getEMSat(candID));
222 }
223 }
224
225 }
226
227
228 std::unordered_map<uint, LVL1::jFEXForwardElecInfo> LVL1::jFEXForwardElecAlgo::calculateEDM(void) {
229 std::unordered_map<uint, LVL1::jFEXForwardElecInfo> clusterList;
230 std::vector<int> lower_centre_neta;
231 std::vector<int> upper_centre_neta;
232
233 //check if we are in module 0 or 5 and assign corrrect eta FEXAlgoSpace parameters
234 if(m_jfex == 0) {
235 //Module 0
236 lower_centre_neta.assign({FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMB_start_eta, // 28
239
240 upper_centre_neta.assign({FEXAlgoSpaceDefs::jFEX_algoSpace_C_EMB_end_eta, // 37
243 }
244 else {
245 //Module 5
246 lower_centre_neta.assign({FEXAlgoSpaceDefs::jFEX_algoSpace_A_EMB_eta, // 8
249
250 upper_centre_neta.assign({FEXAlgoSpaceDefs::jFEX_algoSpace_A_EMIE_eta, // 17
253 }
254
255 //define phi FEXAlgoSpace parameters
258
259 //loop over different EM/FCAL1 eta phi core fpga regions with different granularities. These are potential seed towers for electron clusters
260 for(uint region = 0; region<3; region++) {
261 for(int nphi = lower_centre_nphi[region]; nphi < upper_centre_nphi[region]; nphi++) {
262 for(int neta = lower_centre_neta[region]; neta < upper_centre_neta[region]; neta++) {
263
264 // ignore seeds for |eta| < 2.3 or from the first FCAL eta bin
265 if (m_jfex == 0 && neta >= FEXAlgoSpaceDefs::jFEX_algoSpace_C_FwdEl_start) continue;
266 if (m_jfex == 5 && neta <= FEXAlgoSpaceDefs::jFEX_algoSpace_A_FwdEl_start) continue;
267 if (m_jfex == 0 && neta == FEXAlgoSpaceDefs::jFEX_algoSpace_C_FCAL1_1st) continue;
268 if (m_jfex == 5 && neta == FEXAlgoSpaceDefs::jFEX_algoSpace_A_FCAL1_1st) continue;
269
270 // define ttID (only FCAL1 in the third region) which will be the key for class in map, ignore tower ID = 0
271 uint ttID = m_jFEXalgoTowerID[nphi][neta];
272 if(ttID == 0) continue;
273 //check if seed candidate is actual seed (passes local maximum criteria)
274 if(!isValidSeed(ttID)) continue;
275
276 //gather some first, basic information for resulting cluster/TOB
277 jFEXForwardElecInfo elCluster;
278 elCluster.setup(m_jfex, ttID, neta, nphi);
279 const auto [centreTT_eta, centreTT_phi] = getEtaPhi(ttID);
280 const auto [centreTT_EtEM, centreTT_EtHad] = getEtEmHad(ttID);
281 elCluster.setCoreTTfPhi(centreTT_phi);
282 elCluster.setCoreTTfEta(centreTT_eta);
283 elCluster.setCoreTTEtEM(centreTT_EtEM);
284 elCluster.setCoreTTSatEM(getEMSat(ttID));
285 elCluster.setNextTTEtEM(0);
286 elCluster.setNextTTID(0);
287 elCluster.setTTEtEMiso(0);
288
289 //find "NextTT", i.e., highest ET neighbour
290 findAndFillNextTT(elCluster, neta, nphi);
291
292 // sum up EM isolation using the isolation map and remove cluster ET
293 {
294 int sumEtEM = 0;
295 auto it_iso_map = m_IsoMap.find(ttID);
296 if(it_iso_map != m_IsoMap.end()) {
297 for(const auto& gtt : it_iso_map->second){
298 auto [tmp_EtEM,tmp_EtHad] = getEtEmHad(gtt);
299 sumEtEM += tmp_EtEM;
300 }
301 elCluster.setTTEtEMiso(sumEtEM-elCluster.getNextTTEtEM());
302 } else {
303 ATH_MSG_ERROR("Could not find TT" << ttID << " in jEM isolation map file.");
304 }
305 }
306
307 if(fabs(centreTT_eta) < 3.2) {
308 // for non-FCal positions only Frac1 is meaningful and has a "trivial" mapping
309 elCluster.setTTEtHad1(centreTT_EtHad);
310 elCluster.setTTEtHad2(0);
311 } else {
312 // sum up Et for hadronic fraction 1
313 {
314 int sumEtHad1 = 0;
315 auto it_frac1_map = m_Frac1Map.find(ttID);
316 if(it_frac1_map != m_Frac1Map.end()) {
317 for(const auto& gtt : it_frac1_map->second){
318 auto [tmp_EtEM,tmp_EtHad] = getEtEmHad(gtt);
319 sumEtHad1 += tmp_EtHad;
320 }
321 elCluster.setTTEtHad1(sumEtHad1);
322 } else {
323 ATH_MSG_ERROR("Could not find TT" << ttID << " in jEM frac1 map file.");
324 }
325 }
326
327 // sum up Et for hadronic fraction 2 (only FCal!)
328 {
329 int sumEtHad2 = 0;
330 auto it_frac2_map = m_Frac2Map.find(ttID);
331 if(it_frac2_map != m_Frac2Map.end()) {
332 for(const auto& gtt : it_frac2_map->second) {
333 auto [tmp_EtEM,tmp_EtHad] = getEtEmHad(gtt);
334 sumEtHad2 += tmp_EtHad;
335 }
336 elCluster.setTTEtHad2(sumEtHad2);
337 } else {
338 ATH_MSG_ERROR("Could not find TT" << ttID << " in jEM frac2 map file.");
339 }
340 }
341 }
342
343 // save this cluster in the list
344 clusterList[ttID] = std::move(elCluster);
345 }//eta
346 }//phi
347 }// 3 regions
348 return clusterList;
349 }
350
351 StatusCode LVL1::jFEXForwardElecAlgo::ReadfromFile(const std::string & fileName, std::unordered_map<unsigned int, std::vector<unsigned int> >& fillingMap) const {
352 std::string myline;
353 //opening file with ifstream
354 std::ifstream myfile(fileName);
355 if ( !myfile.is_open() ){
356 ATH_MSG_ERROR("Could not open file:" << fileName);
357 return StatusCode::FAILURE;
358 }
359
360 //loading the mapping information
361 while ( std::getline (myfile, myline) ) {
362 //removing the header of the file (it is just information!)
363 if(myline[0] == '#') continue;
364
365 //Splitting myline in different substrings
366 std::stringstream oneLine(myline);
367
368 //reading elements
369 std::vector<unsigned int> elements;
370 std::string element;
371 while(std::getline(oneLine, element, ' '))
372 {
373 elements.push_back(std::stoi(element));
374 }
375
376 // We should have at least two elements! Central TT and (at least) itself
377 if(elements.size() < 1){
378 ATH_MSG_ERROR("Unexpected number of elemennts (<1 expected) in file: "<< fileName);
379 return StatusCode::FAILURE;
380 }
381
382 //Central TiggerTower
383 unsigned int TTID = elements.at(0);
384
385 // rest of TTs that need to be checked
386 elements.erase(elements.begin());
387 fillingMap[TTID] = std::move(elements);
388 }
389 myfile.close();
390
391 return StatusCode::SUCCESS;
392 }
393}// end of namespace LVL1
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
unsigned int uint
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
static constexpr int jFEX_algoSpace_A_FCAL1_1st
static constexpr int jFEX_algoSpace_C_EMB_start_eta
static constexpr int jFEX_wide_algoSpace_width
static constexpr int jFEX_algoSpace_A_FCAL_end_eta
static constexpr int jFEX_algoSpace_C_EMB_end_eta
static constexpr int jFEX_algoSpace_EMIE_end_phi
static constexpr int jFEX_algoSpace_C_FCAL_end_eta
static constexpr int jFEX_algoSpace_A_EMB_eta
static constexpr int jFEX_algoSpace_A_FCAL_start_eta
static constexpr int jFEX_algoSpace_C_FCAL_start_eta
static constexpr int jFEX_algoSpace_A_EMIE_eta
static constexpr int jFEX_algoSpace_FCAL_end_phi
static constexpr int jFEX_algoSpace_C_FCAL1_1st
static constexpr int jFEX_algoSpace_EMB_end_phi
static constexpr int jFEX_algoSpace_A_FwdEl_start
static constexpr int jFEX_algoSpace_FCAL_start_phi
static constexpr int jFEX_algoSpace_EMIE_start_phi
static constexpr int jFEX_algoSpace_C_FwdEl_start
static constexpr int jFEX_algoSpace_EMB_start_phi
static constexpr int jFEX_algoSpace_height
static constexpr int jFEX_algoSpace_C_EMIE_start_eta
static constexpr int jFEX_algoSpace_C_EMIE_end_eta
Gaudi::Property< std::string > m_Frac2MapStr
std::unordered_map< int, std::vector< int > > m_map_Etvalues_EM
std::unordered_map< int, std::vector< int > > m_map_Etvalues_HAD
std::unordered_map< unsigned int, std::vector< unsigned int > > m_Frac1Map
std::unordered_map< unsigned int, std::vector< unsigned int > > m_Frac2Map
virtual std::array< int, 2 > getEtEmHad(uint) const override
jFEXForwardElecAlgo(const std::string &type, const std::string &name, const IInterface *parent)
Constructors.
int m_jFEXalgoTowerID[FEXAlgoSpaceDefs::jFEX_algoSpace_height][FEXAlgoSpaceDefs::jFEX_wide_algoSpace_width]
SG::ReadHandleKey< LVL1::jTowerContainer > m_jTowerContainerKey
virtual void setup(int inputTable[FEXAlgoSpaceDefs::jFEX_algoSpace_height][FEXAlgoSpaceDefs::jFEX_wide_algoSpace_width], int jfex, int fpga) override
virtual StatusCode safetyTest() override
Standard methods.
virtual std::array< float, 2 > getEtaPhi(uint) override
void findAndFillNextTT(jFEXForwardElecInfo &elCluster, int neta, int nphi)
Gaudi::Property< std::string > m_SearchGeTauStr
bool isValidSeed(uint seedTTID) const
SG::ReadHandle< jTowerContainer > m_jTowerContainer
Gaudi::Property< std::string > m_SearchGTauStr
bool getEMSat(unsigned int ttID)
StatusCode ReadfromFile(const std::string &, std::unordered_map< unsigned int, std::vector< unsigned int > > &) const
virtual void setFPGAEnergy(std::unordered_map< int, std::vector< int > > etmapEM, std::unordered_map< int, std::vector< int > > etmapHAD) override
virtual StatusCode initialize() override
standard Athena-Algorithm method
virtual ~jFEXForwardElecAlgo()
Destructor.
Gaudi::Property< std::string > m_IsoMapStr
Gaudi::Property< std::string > m_Frac1MapStr
std::unordered_map< unsigned int, std::vector< unsigned int > > m_IsoMap
std::unordered_map< unsigned int, std::vector< unsigned int > > m_SearchGTauMap
std::unordered_map< unsigned int, std::vector< unsigned int > > m_SearchGeTauMap
virtual std::unordered_map< uint, jFEXForwardElecInfo > calculateEDM() override
void setup(int jfex, uint ttid, int neta, int nphi)
The jTower class is an interface object for jFEX trigger algorithms The purposes are twofold:
Definition jTower.h:36
float centrePhi() const
Definition jTower.h:80
bool getEMSat() const
Definition jTower.h:56
float centreEta() const
Definition jTower.h:79
static std::string find_calib_file(const std::string &logical_file_name)
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...