ATLAS Offline Software
Loading...
Searching...
No Matches
EFexEMClusterTool.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
9
10#include "EFexEMClusterTool.h"
12#include <cmath>
13
14
15LVL1::EFexEMClusterTool::EFexEMClusterTool(const std::string& type, const std::string& name, const IInterface* parent)
16 : AthAlgTool(type, name, parent)
17{
18 declareProperty("CleanCellContainer", m_useProvenance=true);
19 declareProperty("QualBitMask", m_qualBitMask=0x40);
20
21 // baseline selection properties
22 declareProperty("ClusterEnergyThreshold", m_clustET_thresh = 28., "Cluster energy threshold for baseline selection");
23 declareProperty("EnergyThresholdToApplyIsolation", m_clustET_NoIso_thresh = 60., "Cluster energy above which no isolation cut is applied for baseline selection");
24 declareProperty("REtaThreshold", m_REta_thresh = 0.12, "Reta cut for baseline selection");
25 declareProperty("RHadThreshold", m_RHad_thresh = 0.16, "Rhad cut for baseline selection");
26 declareProperty("L1WidthThreshold", m_L1Width_thresh = 0.02, "L1Width cut for baseline selection");
27 declareProperty("EtaThresholdToApplyL1Width", m_eta_dropL1Width = 2.3, "Eta outside of which no L1Width cut is applied for baseline selection");
28
29 // loose selection properties
30 declareProperty("UseTileCells", m_use_tileCells = false);
31 declareProperty("NominalDigitizationValue", m_nominalDigitization = 25.);
32 declareProperty("NominalNoiseThreshold", m_nominalNoise_thresh = 100.);
33 declareProperty("TileNoiseThreshold", m_tileNoise_tresh = 100.);
34 declareProperty("EtaWidthTDRCluster", m_etaWidth_TDRCluster = 3);
35 declareProperty("PhiWidthTDRCluster", m_phiWidth_TDRCluster = 2);
36 declareProperty("EtaWidthWStotIsolation", m_etaWidth_wstotIsolation = 5);
37 declareProperty("PhiWidthWStotIsolation", m_phiWidth_wstotIsolation = 3);
38 declareProperty("EtaEMWidthRHadIsolation", m_etaEMWidth_RHadIsolation = 3); // 1 for a 1-eta-tower had cluster, 5 for 2-tower, 9 for 3-tower
39 declareProperty("PhiEMWidthRHadIsolation", m_phiEMWidth_RHadIsolation = 3);
40 declareProperty("EtaWidthREtaIsolationDenominator", m_etaWidth_REtaIsolation_den = 7);
41 declareProperty("PhiWidthREtaIsolationDenominator", m_phiWidth_REtaIsolation_den = 3);
42 declareProperty("EtaWidthREtaIsolationNumerator", m_etaWidth_REtaIsolation_num = 3);
43 declareProperty("PhiWidthREtaIsolationNumerator", m_phiWidth_REtaIsolation_num = 2);
44 declareProperty("ClusterEnergyThresholdLooseEFEX", m_clustET_looseAlg_thresh = 10.);
45 declareProperty("EtaHadWidthRHadIsolation", m_etaHadWidth_RHadIsolation = 9); // 1 for a 1-eta-tower had cluster, 5 for 2-tower, 9 for 3-tower
46 declareProperty("PhiHadWidthRHadIsolation", m_phiHadWidth_RHadIsolation = 3);
47}
48
49std::vector<LVL1::EFexEMClusterTool::AlgResult>
51 const CaloConstCellContainer* scells, const xAOD::TriggerTowerContainer* TTs,
52 const CaloCell_SuperCell_ID* idHelper, const TileID* tileIDHelper,
53 const CaloConstCellContainer* tileCellCon) const
54{
55 std::vector<AlgResult> baselineClusters;
56 for (auto & cluster : looseAlg(scells, TTs, idHelper, tileIDHelper, tileCellCon) ) {
57
58 // cluster E_T
59 cluster.passClusterEnergy = cluster.clusterET >= m_clustET_thresh; // if ET cut passes
60
61 // R_eta
62 cluster.passREta = cluster.rEta <= m_REta_thresh || // if reta cut passes
63 cluster.clusterET > m_clustET_NoIso_thresh; // or ET above threshold where any isolation is applied
64
65 // R_had
66 cluster.passRHad = cluster.rHad <= m_RHad_thresh || // if rhad cut passes
67 cluster.clusterET > m_clustET_NoIso_thresh; // or ET above threshold where any isolation is applied
68
69 // Wstot
70 cluster.passWstot = cluster.l1Width < m_L1Width_thresh || // if cut passes
71 std::abs(cluster.eta) > m_eta_dropL1Width || // or eta outside range where cut is applied
72 cluster.clusterET > m_clustET_NoIso_thresh; // or ET above threshold where any isolation is applied
73
74 bool passBaseLineSelection = cluster.passClusterEnergy &&
75 cluster.passRHad &&
76 cluster.passREta &&
77 cluster.passWstot;
78
79 if (applyBaselineCuts and not passBaseLineSelection ) {
80 continue;
81 }
82
83 baselineClusters.push_back(cluster);
84 }
85 return baselineClusters;
86}
87
88std::vector<LVL1::EFexEMClusterTool::AlgResult>
90 const CaloCell_SuperCell_ID* idHelper, const TileID* tileIDHelper,
91 const CaloConstCellContainer* tileCellCon ) const
92{
93 std::vector<AlgResult> result;
94 // Loops through and find L2 SCs that are local maxes and adds to list of local maxes if cluster ET is at least 10GeV
95 std::vector<const CaloCell*> potentialCentres;
96 for (auto ithCell : *SCs) {
97 if ( !( std::abs(CaloCellET(ithCell, m_nominalDigitization, m_nominalNoise_thresh)) > 0) ) {
98 continue;
99 }
100 Identifier ithID = ithCell->ID();
101 if (idHelper->sampling(ithID) != 2) {
102 continue;
103 }
104
105 if (idHelper->sub_calo(ithID) != 0) {
106 continue;
107 }
108
109 bool inEfexCoverage = false;
110 if ( std::abs(idHelper->pos_neg(ithID)) < 3) {
111 inEfexCoverage = true;
112 }
113
114 if (!inEfexCoverage) {
115 continue;
116 }
117
118 if (localMax(SCs, ithCell, idHelper, m_nominalDigitization, m_nominalNoise_thresh)) {
119 potentialCentres.push_back(ithCell);
120 }
121 }
122
123 // Looops through the local maxes and skips the less energetic ones that belong to the same TT
124 for (auto ithCell : potentialCentres){
125 bool useSC = true;
126 for (auto jthCell : potentialCentres){
127 if (jthCell == ithCell) continue;
128 if (!SameTT(ithCell, jthCell, idHelper)) continue;
131 if (ithEt > jthEt) continue;
132 if (ithEt == jthEt && ithCell->eta() > jthCell->eta()) continue;
133 useSC = false;
134 }
137 if (clustET < m_clustET_looseAlg_thresh) useSC = false;
138
139 if (useSC) {
140 float HadET = -999;
141 float ithRHad = -1;
142 float ithEta = ithCell->eta();
143 float ithPhi = ithCell->phi();
146 if (!m_use_tileCells) {
148 } else {
149 ithRHad = RHadTile(ithCell, m_etaEMWidth_RHadIsolation, m_phiEMWidth_RHadIsolation, SCs, idHelper, m_nominalDigitization, m_nominalNoise_thresh, tileIDHelper, tileCellCon, m_tileNoise_tresh, HadET);
150 }
151
152 float ithL1Width = L1Width( ithCell, m_etaWidth_wstotIsolation, m_phiWidth_wstotIsolation, SCs,
154 float L2ClusterET33 = L2clusET( ithCell, 3, 3, SCs, idHelper, m_nominalDigitization, m_nominalNoise_thresh)/1e3;
155 float L2ClusterET37 = L2clusET( ithCell, 7, 3, SCs, idHelper, m_nominalDigitization, m_nominalNoise_thresh)/1e3;
156
157 float ithREtaL12{-1};
158 if (m_use_REtaL12) {
162 }
163 result.push_back(AlgResult{ithEta, ithPhi, clustET, ithREta, ithRHad, ithL1Width, HadET, L2ClusterET33, L2ClusterET37, ithREtaL12});
164 }
165 }
166 return result;
167}
168
172
173float
174LVL1::EFexEMClusterTool::CaloCellET(const CaloCell* const &inputCell, float digitScale, float digitThreshold) const
175{
176 if (inputCell==nullptr) return 0.;
177 // Check that timing is correct
178 if ( m_useProvenance ) {
179 bool correctProv = (inputCell->provenance() & m_qualBitMask);
180 if (!correctProv) return 0.;
181 }
182 // Calculates the ET (before digitization)
183 float inputCell_energy = inputCell->energy();
184 float inputCell_eta = inputCell->eta();
185 float inputCell_ET = inputCell_energy / cosh(inputCell_eta);
186 // Check to see if negative ET values are allowed
187 bool allowNegs = false;
188 if (digitScale < 0.){
189 digitScale = std::abs(digitScale);
190 allowNegs = true;
191 }
192 if (inputCell_ET==0) return 0.;
193 else if (digitScale==0) return inputCell_ET;
194 if (allowNegs || inputCell_ET>0.){
195 // Split up ET into magnitude & whether it's positive or negative
196 float posOrNeg = inputCell_ET / std::abs(inputCell_ET);
197 inputCell_ET = std::abs(inputCell_ET);
198 // If no digitisation, return ET following noise cut
199 if (digitScale == 0){
200 if (inputCell_ET>digitThreshold) return inputCell_ET*posOrNeg;
201 else return 0.;
202 }
203 // Apply digitization & then noise cut
204 else {
205 float divET = inputCell_ET / digitScale;
206 int roundET = divET;
207 float result = digitScale * roundET;
208 if (digitThreshold == 0) return result*posOrNeg;
209 else if (result >= digitThreshold) return result*posOrNeg;
210 else return 0;
211 }
212 }
213 else return 0.;
214}
215
216bool
217LVL1::EFexEMClusterTool::SameTT(const CaloCell* inputCell1, const CaloCell* inputCell2, const CaloCell_SuperCell_ID* &idHelper) const
218{
219 const Identifier ID1 = inputCell1->ID();
220 int phi1 = idHelper->phi(ID1);
221 const Identifier ID2 = inputCell2->ID();
222 int phi2 = idHelper->phi(ID2);
223 if (phi1 != phi2) {
224 return false;
225 }
226 int pn1 = idHelper->pos_neg(ID1);
227 int pn2 = idHelper->pos_neg(ID2);
228 if (pn1 != pn2) {
229 return false;
230 }
231 // Is barrel
232 if (abs(pn1)==1) {
233 int reg1 = idHelper->region(ID1);
234 int reg2 = idHelper->region(ID2);
235 if (reg1 != reg2) {
236 return false;
237 }
238 int etaDiv1 = idHelper->eta(ID1)/4;
239 int etaDiv2 = idHelper->eta(ID2)/4;
240 if (etaDiv1 == etaDiv2) {
241 return true;
242 }
243 else {
244 return false;
245 }
246 }
247 // OW
248 else if (abs(pn1)==2){
249 int reg1 = idHelper->region(ID1);
250 int reg2 = idHelper->region(ID2);
251 int eta1 = idHelper->eta(ID1);
252 int eta2 = idHelper->eta(ID2);
253 if ((reg1 == 0 && reg2 == 1 && eta2 < 3 ) || (reg2 == 0 && reg1 == 1 && eta1 < 3 )) return true;
254 else {
255 if (reg1 != reg2) return false;
256 int etaDiv1 = (idHelper->eta(ID1) - 3)/4;
257 int etaDiv2 = (idHelper->eta(ID2) - 3)/4;
258 if (etaDiv1 == etaDiv2) return true;
259 else return false;
260 }
261 }
262 else return false;
263}
264
265bool
267 const CaloCell_SuperCell_ID* &idHelper, float digitScale, float digitThreshold) const
268{
269 return localMax(inputContainer, inputCell, 0, idHelper, digitScale, digitThreshold);
270}
271
272bool
273LVL1::EFexEMClusterTool::localMax(const CaloConstCellContainer* &inputContainer, const CaloCell* inputCell, int numOthers,
274 const CaloCell_SuperCell_ID* &idHelper, float digitScale, float digitThreshold) const
275{
276 if (inputCell == nullptr) return false;
277 // Get ID info
278 const Identifier inputID = inputCell->ID();
279 const int sub_calo = idHelper->sub_calo(inputID);
280 const int pos_neg = idHelper->pos_neg(inputID);
281 if (!(sub_calo == 0 || sub_calo == 1) || !(abs(pos_neg) < 4)){
282 ATH_MSG_DEBUG ( "Issue with local max logic");
283 return false;
284 }
285 double seedCandidateEnergy = CaloCellET(inputCell, digitScale, digitThreshold);
286 int nCellsMoreEnergetic = 0;
287 const CaloCell* leftCell = NextEtaCell(inputCell, true, inputContainer, idHelper);
288 if (leftCell != nullptr){
289 double leftEnergy = CaloCellET(leftCell, digitScale, 0.);
290 if (leftEnergy>seedCandidateEnergy) nCellsMoreEnergetic++;
291 }
292 const CaloCell* rightCell = NextEtaCell(inputCell, false, inputContainer, idHelper);
293 if (rightCell != nullptr){
294 double rightEnergy = CaloCellET(rightCell, digitScale, 0.);
295 if (rightEnergy>=seedCandidateEnergy) nCellsMoreEnergetic++;
296 }
297 const CaloCell* upCell = NextPhiCell(inputCell, true, inputContainer, idHelper);
298 if (upCell != nullptr){
299 double upEnergy = CaloCellET(upCell, digitScale, 0.);
300 if (upEnergy>=seedCandidateEnergy) nCellsMoreEnergetic++;
301 }
302 const CaloCell* downCell = NextPhiCell(inputCell, false, inputContainer, idHelper);
303 if (downCell != nullptr){
304 double downEnergy = CaloCellET(downCell, digitScale, 0.);
305 if (downEnergy>seedCandidateEnergy) nCellsMoreEnergetic++;
306 }
307 if (upCell != nullptr){
308 const CaloCell* upRightCell = NextEtaCell(upCell, false, inputContainer, idHelper);
309 if (upRightCell != nullptr){
310 double upRightEnergy = CaloCellET(upRightCell, digitScale, 0.);
311 if (upRightEnergy>=seedCandidateEnergy) nCellsMoreEnergetic++;
312 }
313 const CaloCell* upLeftCell = NextEtaCell(upCell, true, inputContainer, idHelper);
314 if (upLeftCell != nullptr){
315 double upLeftEnergy = CaloCellET(upLeftCell, digitScale, 0.);
316 if (upLeftEnergy>=seedCandidateEnergy) nCellsMoreEnergetic++;
317 }
318 }
319 if (downCell != nullptr){
320 const CaloCell* downRightCell = NextEtaCell(downCell, false, inputContainer, idHelper);
321 if (downRightCell != nullptr){
322 double downRightEnergy = CaloCellET(downRightCell, digitScale, 0.);
323 if (downRightEnergy>seedCandidateEnergy) nCellsMoreEnergetic++;
324 }
325 const CaloCell* downLeftCell = NextEtaCell(downCell, true, inputContainer, idHelper);
326 if (downLeftCell != nullptr){
327 double downLeftEnergy = CaloCellET(downLeftCell, digitScale, 0.);
328 if (downLeftEnergy>seedCandidateEnergy) nCellsMoreEnergetic++;
329 }
330 }
331 // If candidate is more energetic than all of neighbours, it is a local max
332 if (nCellsMoreEnergetic <= numOthers) return true;
333 else return false;
334}
335
336void
337LVL1::EFexEMClusterTool::addOnce(const CaloCell* inputCell, std::vector<const CaloCell*> &outputVector) const
338{
339 if (inputCell==nullptr) return;
340 bool alreadyThere = false;
341 for (auto oCell : outputVector){
342 if (oCell==nullptr) ATH_MSG_WARNING ( "nullptr cell in vector");
343 else if (inputCell->ID() == oCell->ID()) alreadyThere=true;
344 }
345 if (!alreadyThere) outputVector.push_back(inputCell);
346}
347
348double
349LVL1::EFexEMClusterTool::EMClusET(const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
350 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh) const
351{
352 // Sums the ET of the vector
353 std::vector<const CaloCell*> fullClus = TDR_Clus(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale,digitThresh);
354 double EMcomp = sumVectorET(fullClus, digitScale, digitThresh);
355 bool EMcheck = checkDig(EMcomp, digitScale, digitThresh);
356 if (!EMcheck) ATH_MSG_WARNING ( "EMcomp not digitised " << EMcomp << " " << digitScale << " " << digitThresh);
357 double total = EMcomp;
358 return total;
359}
360
361double
362LVL1::EFexEMClusterTool::REta(const CaloCell* centreCell, int etaWidth1, int phiWidth1, int etaWidth2, int phiWidth2,
363 const CaloConstCellContainer* scells, const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh) const
364{
365 // Check windows sizes are right way round
366 if (etaWidth1 > etaWidth2) ATH_MSG_WARNING ( "REta: eta1 = " << etaWidth1 << ", eta2 = " << etaWidth2);
367 if (phiWidth1 > phiWidth2) ATH_MSG_WARNING ( "Rphi: phi1 = " << phiWidth1 << ", phi2 = " << phiWidth2);
368 // Finds ET of windows
369 double inner_ET = L2clusET(centreCell, etaWidth1, phiWidth1, scells, idHelper, digitScale, digitThresh);
370 double outer_ET = L2clusET(centreCell, etaWidth2, phiWidth2, scells, idHelper, digitScale, digitThresh);
371 // Find normal value of REta & changes it to my version
372 double normal_REta;
373 if (inner_ET != 0. && outer_ET==0.) normal_REta = 0.;
374 else if (inner_ET==0.) normal_REta = 0.;
375 else normal_REta = inner_ET / outer_ET;
376 if (normal_REta < 0) normal_REta = 0.;
377 double my_REta = 1-normal_REta;
378 return my_REta;
379}
380
381double
382LVL1::EFexEMClusterTool::RHad(const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
383 const xAOD::TriggerTowerContainer* &TTContainer, const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh, float &HadET) const
384{
385 std::vector<const CaloCell*> fullClus = TDR_Clus(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale, digitThresh);
386 double EMcomp = sumVectorET(fullClus, digitScale, digitThresh);
387 double HCALcomp = HadronicET(L2cluster(centreCell, m_etaHadWidth_RHadIsolation, m_phiHadWidth_RHadIsolation, scells, idHelper, digitScale, digitThresh), scells, TTContainer, idHelper, digitScale, digitThresh);
388 HadET = HCALcomp/1e3;
389 double result = HCALcomp/(EMcomp+HCALcomp);
390 if (result < 0. || result > 1.){
391 ATH_MSG_WARNING ( "RHAD -> " << etaWidth << " * " << phiWidth);
392 ATH_MSG_WARNING ( "fullClus count = " << fullClus.size() << ", EMcomp = " << EMcomp << ", HCALcomp = " << HCALcomp);
393 }
394 return result;
395}
396
397void
398LVL1::EFexEMClusterTool::checkTileCell(const TileCell* &inputCell, std::vector<const TileCell*> &tileCellVector, bool &isAlreadyThere) const
399{
400 for (auto ithCell : tileCellVector){
401 if (ithCell->ID() == inputCell->ID()) isAlreadyThere = true;
402 }
403 if (!isAlreadyThere) tileCellVector.push_back(inputCell);
404}
405
406double
407LVL1::EFexEMClusterTool::tileCellEnergyCalib(float eIn, float etaIn, float tileNoiseThresh) const
408{
409 if (eIn <= 0) return 0.;
410 float eOut = eIn/cosh(etaIn);
411 if (tileNoiseThresh == 0.) return eOut;
412 else {
413 if (eOut > tileNoiseThresh) return eOut;
414 else return 0.;
415 }
416}
417
418int
420{
421 float pos_neg = inEta/std::abs(inEta);
422 // Right PMT : inPos = 0, Left PMT : inPos = 1, Both PMTs : inPos = 2
423 int inPos = -1;
424 // True if even, false if odd
425 bool isEven = false;
426 if (((int)(std::abs(inEta)*10)) % 2 == 0) isEven = true;
427 if (pos_neg > 0){
428 // A side of TileCal
429 if (inEta < 0.1) inPos = 0;
430 else if (inEta > 0.8 && inEta < 0.9) inPos = 2;
431 else {
432 if (isEven) inPos = 0;
433 else inPos = 1;
434 }
435 }
436 else {
437 // C side of TileCal
438 if (inEta > -0.1) inPos = 1;
439 else if (inEta > -0.9 && inEta < -0.8) inPos = 2;
440 else {
441 if (isEven) inPos = 1;
442 else inPos = 0;
443 }
444 }
445 return inPos;
446}
447
448double
449LVL1::EFexEMClusterTool::L1Width(const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
450 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh) const
451{
452 // Finds a L2 cluster and the corresponding L1 cells
453 std::vector<const CaloCell*> L2cells = L2cluster(centreCell, etaWidth, phiWidth, scells, idHelper,digitScale, digitThresh);
458
459 float oldPhi = centreCell->phi();
460 int counter = 0;
461 std::vector<int> offsets;
462 std::vector<const CaloCell*> frontLayerCells;
463 for (auto ithL2Cell : L2cells){
464 // How many cells added already?
465 unsigned int oldsize = frontLayerCells.size();
466 // Add cells matching this L2 cell
467 fromLayer2toLayer1(scells, ithL2Cell, frontLayerCells, idHelper);
468 // HoW many were added?
469 unsigned int additions = frontLayerCells.size() - oldsize;
470 // Reset counter if phi has changed significantly
471 float dPhi = std::abs(ithL2Cell->phi() - oldPhi);
472 if (dPhi > M_PI) dPhi = 2*M_PI - dPhi;
473 if (dPhi > 0.09) {
474 counter = 0;
475 oldPhi = ithL2Cell->phi();
476 }
477 // Try storing signed offsets
478 int sign = (ithL2Cell->eta()-centreCell->eta() > 0 ? 1 : -1);
479 // Store current eta offset value for all added cells
480 for (unsigned int adds = 0; adds < additions; ++adds) offsets.push_back(sign*((counter+1)/2));
481 counter++;
482 }
483
484 // Finds the 'width' for the cluster, based on eta offsets found above
485 float sumET = 0, sumET_Eta2=0;
486 unsigned int cellCount = 0;
487 //for (auto ithCell : frontLayerCells){
488 for (std::vector<const CaloCell*>::iterator ithCell = frontLayerCells.begin(); ithCell != frontLayerCells.end(); ++ithCell){
489
490 // Find offset. As a precaution ignore cells where this can't be found, but warn user
491 int offset = (cellCount < offsets.size() ? offsets[cellCount] : -999);
492 if (offset < -2 || offset > 2) {
493 ATH_MSG_WARNING("Offset out of range, cell skipped");
494 offset = 0; // This will result in a weight of zero for the cell
495 }
496
497 // Is this one of the cells between 1.8-2.0 that will be divided?
498 Identifier cellID = (*ithCell)->ID();
499 int pos_neg = idHelper->pos_neg(cellID);
500 int region = idHelper->region(cellID);
501 int eta_index = idHelper->eta(cellID);
502 bool halfCell = false;
503 if (abs(pos_neg) == 2 && region == 3 && (eta_index == 1 || eta_index == 4 || eta_index == 7 || eta_index == 10)) halfCell = true;
504
505 // Total and weighted ET sums (integer weights to match firmware)
506 float ithET = CaloCellET((*ithCell), digitScale, digitThresh);
507 sumET += ithET;
508
509 // 4 cells will be shared with neighbours. Jiggery-pokery required here:
510 if (halfCell) {
511 sumET_Eta2 += 0.5*ithET*pow(offset,2);
512 // Now what should be the offset for the other half?
513 // Is this one shared with the previous cell?
514 // If so, which cell is shares with depends on which side of that cell it is
515 if ((int)cellCount-1 >= 0 && offsets[cellCount-1] == offset) {
516 auto ithPrev = std::prev(ithCell,1);
517 int sign = ((*ithCell)->eta() > (*ithPrev)->eta() ? 1 : -1);
518 int nextOffset = offset+sign;
519 if (abs(nextOffset) <= 2) sumET_Eta2 += 0.5*ithET*pow(nextOffset,2);
520 }
521 }
522 // Alternatively may be shared with next cell
523 else if (cellCount+1 < offsets.size() && offsets[cellCount+1] == offset) {
524 auto ithNext = std::next(ithCell,1);
525 int sign = ((*ithCell)->eta() > (*ithNext)->eta() ? 1 : -1);
526 int nextOffset = offset+sign;
527 if (abs(nextOffset) <= 2) sumET_Eta2 += 0.5*ithET*pow(nextOffset,2);
528 }
529 // For everything else just add cell with weight to the second sum
530 else {
531 sumET_Eta2 += ithET*pow(offset,2);
532 }
533 cellCount++;
534 }
535
538 float result = 4.;
539 if (sumET > 0.) result = sumET_Eta2/sumET;
540 return result;
541}
542
543double
544LVL1::EFexEMClusterTool::L2clusET(const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
545 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh) const
546{
547 return sumVectorET(L2cluster(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale, digitThresh), digitScale, digitThresh);
548}
549
550double
551LVL1::EFexEMClusterTool::RHadTile(const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
552 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh, const TileID* tileIDHelper,
553 const CaloConstCellContainer* tileCellCon, float tileNoiseThresh, float &HadronicET) const
554{
555 std::vector<float> outVec;
556 double HadET = 0.;
557 std::vector<const CaloCell*> L2Cells = L2cluster(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale, digitThresh);
558 std::vector<const CaloCell*> fullClus = TDR_Clus(centreCell, m_etaHadWidth_RHadIsolation, m_phiHadWidth_RHadIsolation, scells, idHelper, digitScale, digitThresh);
559 // Last Tile cell boundary: eta = 1.6
560 // Last outer wheel SC seed that still falls into Tile boundary: eta = 1.5625
561 if (std::abs(centreCell->eta()) < 1.57){
562 const int barrel_ec = idHelper->pos_neg(centreCell->ID());
563 bool isOW = false;
564 if (std::abs(barrel_ec) == 2) isOW = true;
565 std::vector<double> energyPerLayer = EnergyPerTileLayer(L2Cells, tileCellCon, tileIDHelper, isOW, tileNoiseThresh);
566 if (energyPerLayer.size() > 0){
567 for (auto ithLayerEnergy : energyPerLayer){
568 HadET += ithLayerEnergy;
569 }
570 }
571 }
572 else {
573 std::vector<const CaloCell*> HCAL_LAr_vector;
574 for (auto ithCell : L2Cells){
575 if (std::abs(ithCell->eta()) > 2.5) continue;
576 const CaloCell* tempLArHad = matchingHCAL_LAr(ithCell, scells, idHelper);
577 if (tempLArHad != nullptr) HCAL_LAr_vector.push_back(tempLArHad);
578 }
579 for (auto ithSC : HCAL_LAr_vector){
580 HadET += CaloCellET(ithSC, digitScale, digitThresh);
581 }
582 }
583 HadronicET = HadET/1e3;
584 double EMcomp = sumVectorET(fullClus, digitScale, digitThresh);
585 if (EMcomp+HadET == 0.)[[unlikely]]{
586 ATH_MSG_WARNING ( "EMcomp+HadET == 0. ");
587 return 1.;
588 }
589 double result = HadET/(EMcomp+HadET);
590 if (result < 0. || result > 1.){
591 ATH_MSG_WARNING ( "RHADTILE -> " << etaWidth << " * " << phiWidth);
592 ATH_MSG_WARNING ( "fullClus count = " << fullClus.size() << ", EMcomp = " << EMcomp << ", HCALcomp = " << HadET);
593 return 1.;
594 }
595 return result;
596}
597
598double
599LVL1::EFexEMClusterTool::REtaL12(const CaloCell* centreCell, int etaWidth1, int phiWidth1, int etaWidth2, int phiWidth2,
600 const CaloConstCellContainer* scells, const CaloCell_SuperCell_ID* idHelper,
601 float digitScale, float digitThresh) const
602{
603 // Check windows sizes are right way round
604 if (etaWidth1 > etaWidth2) ATH_MSG_WARNING ( "REta: eta1 = " << etaWidth1 << ", eta2 = " << etaWidth2);
605 if (phiWidth1 > phiWidth2) ATH_MSG_WARNING ( "Rphi: phi1 = " << phiWidth1 << ", phi2 = " << phiWidth2);
606 // Finds ET of windows
607 double inner_ET = L2clusET(centreCell, etaWidth1, phiWidth1, scells, idHelper, digitScale, digitThresh);
608 double outer_ET = L2clusET(centreCell, etaWidth2, phiWidth2, scells, idHelper, digitScale, digitThresh);
609 // Find corresponding L1 cells, calculate the L1 ET and add them to L2 ET
610 std::vector<const CaloCell*> L2cells_inner = L2cluster(centreCell, etaWidth1, phiWidth1, scells, idHelper,digitScale, digitThresh);
611 std::vector<const CaloCell*> L1cells_inner;
612 for (auto ithL2Cell : L2cells_inner){
613 fromLayer2toLayer1(scells, ithL2Cell, L1cells_inner, idHelper);
614 }
615 inner_ET += sumVectorET(L1cells_inner, digitScale, digitThresh);
616 std::vector<const CaloCell*> L2cells_outer = L2cluster(centreCell, etaWidth2, phiWidth2, scells, idHelper,digitScale, digitThresh);
617 std::vector<const CaloCell*> L1cells_outer;
618 for (auto ithL2Cell : L2cells_outer){
619 fromLayer2toLayer1(scells, ithL2Cell, L1cells_outer, idHelper);
620 }
621 outer_ET += sumVectorET(L1cells_outer, digitScale, digitThresh);
622 // Find normal value of REta & changes it to my version
623 double normal_REta;
624 if (inner_ET != 0. && outer_ET==0.) normal_REta = 0.;
625 else if (inner_ET==0.) normal_REta = 0.;
626 else normal_REta = inner_ET / outer_ET;
627 if (normal_REta < 0) normal_REta = 0.;
628 double my_REta = 1-normal_REta;
629 return my_REta;
630}
631
632void
634 std::vector<const CaloCell*> &outputVector, const CaloCell_SuperCell_ID* &idHelper) const
635{
636 if (inputCell==nullptr) return;
637 // Gets ID info
638 Identifier inputID = inputCell->ID();
639 int sampling = idHelper->sampling(inputID);
640 const int sub_calo = idHelper->sub_calo(inputID);
641 int pos_neg = idHelper->pos_neg(inputID);
642 int region = idHelper->region(inputID);
643 int eta_index = idHelper->eta(inputID);
644 const int phi_index = idHelper->phi(inputID);
645 int tracker = 0;
646 if (sampling != 2) return;
647 // Default values are same as input
648 int outputRegion = region;
649 int outputEta = eta_index;
650 bool oneCell = false; // True if layer 2 SC only matches to a single layer 1 SC
651 // Barrel reg 0 (which is a simple one)
652 if ((abs(pos_neg) == 1)&&(region == 0)){
653 oneCell = true;
654 }
655 // Barrel reg 1: 3 layer 1 SCs for 1 layer 2 SC
656 // But we should map one of these onto the barrel SC, the other 2 onto EC SCs
657 else if ((abs(pos_neg) == 1)&&(region == 1)){
658 tracker = 2;
659 outputRegion = 1;
660 outputEta = 0;
661 oneCell = true;
662 /* This code produces a one-to-many matching, which is not how things work
663 for (unsigned int i = 0; i < 3; i++){
664 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, region, i, phi_index);
665 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
666 addOnce(resultCell,outputVector);
667 }
668 */
669 }
672 else if (abs(pos_neg)==2 && region == 0) {
673 tracker = -1;
674 }
677 else if (abs(pos_neg)==2&&((region==1 && eta_index < 2))){
678 tracker = 3;
679 outputRegion = 1;
680 outputEta = eta_index + 1;
681 pos_neg /= abs(pos_neg);
682 oneCell = true;
683 }
685 else if (abs(pos_neg)==2&&((region==1 && eta_index == 2))){
686 tracker = 4;
687 outputRegion = 0;
688 outputEta = 0;
689 oneCell = true;
690 }
692 else if (abs(pos_neg)==2&&region==1 && eta_index <= 14){
693 // OW region 1 (on doc): 1:1 match
694 tracker = 5;
695 outputRegion = 2;
696 outputEta = eta_index - 3;
697 oneCell = true;
698 }
700 else if (abs(pos_neg) == 2 && region == 1 && eta_index <= 22){
701 // In this region there are 6 L1 supercells for every 4 L2 ones
702 // The code below groups them 2:1:1:2 2:1:1:2, which is an old proposal
703 // This is not what is actually done, but the structure of this code
704 // makes it impossible to do this correctly.
705 outputRegion = 3;
706 // Middle 2 layer cells match central 2 layer 1 cells
707 if (eta_index%4 == 0 || eta_index%4 ==1){
708 tracker = 6;
709 oneCell = true;
710 if (eta_index < 20) outputEta = eta_index -14;
711 else outputEta = eta_index - 12;
712 }
713 // Edges have a 2:1 ratio. 2 L1s for each L2
714 else {
715 tracker = 7;
716 int offset = 0;
717 if (eta_index == 15) offset = 15;
718 else if (eta_index == 18) offset = 14;
719 else if (eta_index == 19) offset = 13;
720 else if (eta_index == 22) offset = 12;
721 else {
722 ATH_MSG_DEBUG ( "ISSUE with: " << __LINE__);
723 }
724 for (unsigned int i = 0; i < 2; i++){
725 outputEta = i+eta_index - offset;
726 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, outputRegion, outputEta, phi_index);
727 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
728 addOnce(resultCell,outputVector);
729 }
730 }
731 }
733 else if (abs(pos_neg)==2 && region == 1 && eta_index <= 38){
734 // OW Reg 3 (on doc): 1:1 match
735 tracker = 8;
736 oneCell = true;
737 outputRegion = 4;
738 outputEta = eta_index - 23;
739 }
741 else if (abs(pos_neg)==2 && region == 1 && eta_index == 40){
742 // OW Reg 4 (on doc): 1 L1 for all 4 L2s
743 // But this must be mapped onto a specific cell: second one seems best
744 // Note: to try alternative mapping of this cell (to Layer 0) should return without adding cell here
745 tracker = 9;
746 oneCell = true;
747 outputEta = 0;
748 outputRegion = 5;
749 }
750
751 if (oneCell){
752 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, outputRegion, outputEta, phi_index);
753 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
754 addOnce(resultCell,outputVector);
755 }
756 ATH_MSG_DEBUG("L2->L1: sampling = " << sampling << ", region = " << region << ", eta = " << pos_neg*eta_index<< " tracker = " << tracker);
757}
758
759const CaloCell*
760LVL1::EFexEMClusterTool::fromLayer2toLayer3(const CaloConstCellContainer* &inputContainer, const CaloCell* inputCell, const CaloCell_SuperCell_ID* &idHelper) const
761{
762 // Gets ID info
763 int tracker = 0;
764 if ( inputCell == nullptr ) return nullptr;
765 const CaloCell* resultCell = nullptr;
766 Identifier inputID = inputCell->ID();
767 int sampling = idHelper->sampling(inputID);
768 const int sub_calo = idHelper->sub_calo(inputID);
769 const int pos_neg = idHelper->pos_neg(inputID);
770 int region = idHelper->region(inputID);
771 int eta_index = idHelper->eta(inputID);
772 const int phi_index = idHelper->phi(inputID);
773 if (sampling != 2) return nullptr;
774 else if (abs(pos_neg)==1 && ((region==0 && eta_index>53)||region==1)) return nullptr;
775 else if ((abs(pos_neg)==2) && (region == 0 || (region == 1 && eta_index < 3))) return nullptr;
776 else if (abs(pos_neg)==3) return nullptr;
777 // Default values are same as input
778 int outputRegion = region;
779 int outputEta = eta_index;
780 // Is barrel Reg 0
781 if (abs(pos_neg)==1 && region ==0){
782 int outputEta = eta_index/4;
783 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 3, outputRegion, outputEta, phi_index);
784 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
785 tracker = 1;
786 }
788 else if (abs(pos_neg)==1 && region ==1) {
789 int output_pos_neg = pos_neg*2;
790 outputRegion = 0;
791 int outputEta = 0;
792 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, output_pos_neg, 2, outputRegion, outputEta, phi_index);
793 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
794 tracker = 2;
795 }
797 else if (abs(pos_neg)==2 && region ==1){
798 outputEta = (eta_index - 3)/4;
799 outputRegion = 0;
800 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 3, outputRegion, outputEta, phi_index);
801 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
802 tracker = 3;
803 }
804 ATH_MSG_DEBUG("L2->L3: sampling = " << sampling << ", region = " << region << ", eta = " << pos_neg*eta_index<< " tracker = " << tracker);
805 return resultCell;
806}
807
808const CaloCell*
809LVL1::EFexEMClusterTool::fromLayer2toPS(const CaloConstCellContainer* & inputContainer, const CaloCell* inputCell, const CaloCell_SuperCell_ID* &idHelper) const
810{
811 // Gets ID info
812 if (inputCell==nullptr) return nullptr;
813 const CaloCell* resultCell = nullptr;
814 Identifier inputID = inputCell->ID();
815 int sampling = idHelper->sampling(inputID);
816 const int sub_calo = idHelper->sub_calo(inputID);
817 const int pos_neg = idHelper->pos_neg(inputID);
818 int region = idHelper->region(inputID);
819 int eta_index = idHelper->eta(inputID);
820 const int phi_index = idHelper->phi(inputID);
821 if (sampling != 2) return nullptr;
822 if (abs(pos_neg)==2 && (eta_index<3 || eta_index>14)) return nullptr;
823 if (abs(pos_neg)==3) return nullptr;
824 // Default values are same as input
825 int outputRegion = region;
826 int outputEta = eta_index;
827 // Is barrel Reg 0
828 if (abs(pos_neg)==1 && region ==0){
829 int outputEta = eta_index/4;
830 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, outputRegion, outputEta, phi_index);
831 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
832 }
833 else if (abs(pos_neg)==1 && region ==1){
834 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, 0, 14, phi_index);
835 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
836 }
837 else if (abs(pos_neg)==2 && region ==1){
838 outputEta = (eta_index - 3)/4;
839 outputRegion = 0;
840 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, outputRegion, outputEta, phi_index);
841 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
842 }
843 return resultCell;
844}
845
846std::vector<const CaloCell*>
847LVL1::EFexEMClusterTool::L2cluster( const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
848 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh ) const
849{
850 // Forms the central band of cells, spread in phi
851 std::vector<const CaloCell*> centCells;
852 centCells.push_back(centreCell);
853 const CaloCell* upPhiCell = NextPhiCell(centreCell,true,scells,idHelper);
854 const CaloCell* downPhiCell = NextPhiCell(centreCell,false,scells,idHelper);
855 const CaloCell* energeticPhiCell;
856 // Finds the most energetic phi neighbour, defaulting to the 'down' side if they are equal
857 if ( CaloCellET(upPhiCell, digitScale, digitThresh) > CaloCellET(downPhiCell, digitScale, digitThresh)) energeticPhiCell = upPhiCell;
858 else energeticPhiCell = downPhiCell;
859 if (phiWidth == 2) addOnce(energeticPhiCell, centCells); //centCells.push_back(energeticPhiCell);
860 else if (phiWidth == 3){
861 addOnce(upPhiCell, centCells); //centCells.push_back(upPhiCell);
862 addOnce(downPhiCell, centCells); //centCells.push_back(downPhiCell);
863 }
864 else if (phiWidth > 3) {
865 ATH_MSG_DEBUG ( "phiWidth not 2 or 3!!!");
866 }
867 // Forms the main cluster. Starts with each SC in the central band and spreads outward in eta
868 std::vector<const CaloCell*> clusCells;
869 int halfEtaWidth = (etaWidth-1)/2;
870 int backToEta = (2*halfEtaWidth)+1;
871 if (backToEta != etaWidth) {
872 ATH_MSG_DEBUG ( "Eta width doesn't match! " << backToEta << " -> " << halfEtaWidth << " -> " << etaWidth << " " << __LINE__);
873 }
874 for (auto ithCentCell : centCells){
875 addOnce(ithCentCell, clusCells); //clusCells.push_back(ithCentCell);
876 if (etaWidth > 1){
877 const CaloCell* tempRightCell = NextEtaCell(ithCentCell,true,scells,idHelper);
878 const CaloCell* tempLeftCell = NextEtaCell(ithCentCell,false,scells,idHelper);
879 addOnce(tempRightCell, clusCells); //clusCells.push_back(tempRightCell);
880 addOnce(tempLeftCell, clusCells); //clusCells.push_back(tempLeftCell);
881 for (int i = 1; i < halfEtaWidth; i++){
882 tempRightCell = NextEtaCell(tempRightCell,true,scells,idHelper);
883 tempLeftCell = NextEtaCell(tempLeftCell,false,scells,idHelper);
884 addOnce(tempRightCell, clusCells); //clusCells.push_back(tempRightCell);
885 addOnce(tempLeftCell, clusCells); //clusCells.push_back(tempLeftCell);
886 }
887 }
888 }
889 return clusCells;
890}
891
892std::vector<double>
893LVL1::EFexEMClusterTool::EnergyPerTileLayer( const std::vector<const CaloCell*> & inputSCVector, const CaloConstCellContainer* CellCon,
894 const TileID* tileIDHelper, bool isOW, float tileNoiseThresh) const
895{
896 std::vector<double> layerEnergy;
897 if (CellCon==nullptr) return layerEnergy;
898 if (CellCon->size()==0) return layerEnergy;
899 if (inputSCVector.size()==0) return layerEnergy;
900 double ELayer0 = 0, ELayer1 = 0, ELayer2 = 0;
901 std::vector<const TileCell*> tileCellVector;
902 for (auto ithSC : inputSCVector){
903 float ithSCEta = ithSC->eta();
904 float ithSCPhi = ithSC->phi();
905 int matchingCells = 0;
908 for ( ; fCell != lCell; ++fCell){
909 const TileCell* tileCell = static_cast<const TileCell*>(*fCell);
910 if (!tileCell){
911 ATH_MSG_WARNING ( "Failed to cast from CaloCell to TileCell");
912 return layerEnergy;
913 }
914 int layer = tileIDHelper->sample(tileCell->ID());
915 float ithdR = dR(tileCell->eta(), tileCell->phi(), ithSCEta, ithSCPhi);
916 if (layer < 2){
917 float matchingDistance = 0.;
918 if (isOW && (std::abs(ithSCEta) > 1.38 && std::abs(ithSCEta) < 1.42)) matchingDistance = 0.065;
919 else matchingDistance = 0.05;
920 if (ithdR <= matchingDistance){
921 bool isAlreadyThere = false;
922 checkTileCell(tileCell, tileCellVector, isAlreadyThere);
923 if (isAlreadyThere) continue;
924 matchingCells++;
925 if (layer == 0) ELayer0 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
926 if (layer == 1) ELayer1 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
927 }
928 }
929 else if (layer == 2){
930 float matchingDistance = 0.;
931 if (std::abs(ithSCEta) > 0.7 && std::abs(ithSCEta) < 0.8) matchingDistance = 0.05;
932 else if (std::abs(ithSCEta) > 0.9 && std::abs(ithSCEta) < 1.0) matchingDistance = 0.05;
933 else matchingDistance = 0.09;
934 if (ithdR < matchingDistance){
935 bool isAlreadyThere = false;
936 checkTileCell(tileCell, tileCellVector, isAlreadyThere);
937 if (isAlreadyThere) continue;
938 matchingCells++;
939 int tempPos = detRelPos(ithSCEta);
940 // Unknown : tempPos = -1, Right PMT : tempPos = 0, Left PMT : tempPos = 1, Both PMTs : tempPos = 2
941 if (tempPos < 0){
942 ATH_MSG_WARNING ( "Unknown behaviour matching Tile cells to the SC");
943 layerEnergy.clear();
944 return layerEnergy;
945 }
946 else if (tempPos == 0) ELayer2 += tileCellEnergyCalib(tileCell->ene2(), tileCell->eta(), tileNoiseThresh);
947 else if (tempPos == 1) ELayer2 += tileCellEnergyCalib(tileCell->ene1(), tileCell->eta(), tileNoiseThresh);
948 else ELayer2 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
949 }
950 }
951 }
952 if ((matchingCells > 3 && !isOW) || (matchingCells > 3 && isOW && std::abs(ithSCEta) > 1.42) || (matchingCells > 4 && isOW && std::abs(ithSCEta) < 1.42)){
953 ATH_MSG_WARNING ( matchingCells << " matching Tile cells:");
954 ATH_MSG_WARNING ( "Input SC: (eta,phi) = (" << ithSCEta << "," << ithSCPhi << ")");
955 for (auto cell : tileCellVector){
956 ATH_MSG_WARNING ( "Tile cell: (eta,phi) = (" << cell->eta() << "," << cell->phi() << ")" << " dR = " << dR(cell->eta(), cell->phi(), ithSCEta, ithSCPhi) << " layer = " << tileIDHelper->sample(cell->ID()));
957 }
958 layerEnergy.clear();
959 return layerEnergy;
960 }
961 }
962 layerEnergy = {ELayer0, ELayer1, ELayer2};
963 return layerEnergy;
964}
965
966double
968{
969 if (inputTower == nullptr){
970 ATH_MSG_WARNING ( "Tower is nullptr in phi transformation!");
971 return 0.;
972 }
973 else {
974 double phi = inputTower->phi();
975 if (phi > M_PI) phi = phi - 2*M_PI;
976 return phi;
977 }
978}
979
980double
981LVL1::EFexEMClusterTool::dR(double eta1, double phi1, double eta2, double phi2) const
982{
983 double etaDif = eta1 - eta2;
984 double phiDif = std::abs(phi1 - phi2);
985 if (phiDif > M_PI) phiDif = phiDif - (2*M_PI);
986 double result = std::sqrt(pow(etaDif,2)+pow(phiDif,2));
987 return result;
988}
989
992{
993 std::vector<const xAOD::TriggerTower*> matchingTTs;
994 if (TTContainer==nullptr) return nullptr;
995 if (TTContainer->size()==0) return nullptr;
996 if (inputCell==nullptr) return nullptr;
997 for (auto ithTT : *TTContainer){
998 if (ithTT->sampling()==1){
999 float ithTT_eta = ithTT->eta();
1000 float ithTT_phi = TT_phi(ithTT);
1001 float ithdR = dR(ithTT_eta, ithTT_phi, inputCell->eta(), inputCell->phi());
1002 if (ithdR < 0.05) matchingTTs.push_back(ithTT);
1003 }
1004 }
1005 if (matchingTTs.size()==1) return matchingTTs[0];
1006 else if (matchingTTs.size()!=0){
1007 ATH_MSG_WARNING ( "More than one matching HCAL TT!!! (Returned Null)");
1008 }
1009 return nullptr;
1010}
1011
1012const CaloCell*
1013LVL1::EFexEMClusterTool::matchingHCAL_LAr(const CaloCell* &inputCell, const CaloConstCellContainer* &SCContainer, const CaloCell_SuperCell_ID* &idHelper) const
1014{
1015 std::vector<const CaloCell*> matchingCells;
1016 if (inputCell==nullptr) return nullptr;
1017 for (auto ithSC : *SCContainer){
1018 Identifier ithID = ithSC->ID();
1019 int ithSub_calo = idHelper->sub_calo(ithID);
1020 if (ithSub_calo == 1){
1021 double ithdR = dR(inputCell->eta(), inputCell->phi(), ithSC->eta(), ithSC->phi());
1022 if (ithdR < 0.05) matchingCells.push_back(ithSC);
1023 }
1024 }
1025
1026 if (matchingCells.size()==1)
1027 return matchingCells[0];
1028
1029
1030 if (matchingCells.size()==0){
1031
1032 ATH_MSG_WARNING ( "No match betweem LAr ECAL SC and LAr HCAL SC!!! Input coords: " << inputCell->eta() << ", " << inputCell->phi());
1033
1034 } else if (matchingCells.size()!=0) {
1035
1036 ATH_MSG_WARNING ( "More than one matching LAr HCAL SC!!! (Returned Null)");
1037 ATH_MSG_WARNING ( "Input cell coords: " << inputCell->eta() << " x " << inputCell->phi());
1038 for (auto ithMatch : matchingCells){
1039 ATH_MSG_WARNING ( " " << ithMatch->eta() << " x " << ithMatch->phi() << ", dR = "
1040 << dR(inputCell->eta(), inputCell->phi(), ithMatch->eta(), ithMatch->phi()));
1041 }
1042 }
1043 return nullptr;
1044}
1045
1046double
1048{
1049 if (inputTower == nullptr){
1050 ATH_MSG_WARNING ( "Tower is nullptr!");
1051 return 0.;
1052 }
1053 else if (inputTower->cpET() < 0.) {
1054 return 0;
1055 } else {
1056 return 500*inputTower->cpET();
1057 }
1058}
1059
1060std::vector<const CaloCell*>
1061LVL1::EFexEMClusterTool::TDR_Clus( const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
1062 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh ) const
1063{
1064 // Find the L2 cells
1065 std::vector<const CaloCell*> L2cells = L2cluster(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale, digitThresh);
1066 // Forms a vector of the centre L2 cells (to be used to find L0/3 SCs)
1067 std::vector<const CaloCell*> centCells;
1068 centCells.push_back(centreCell);
1069 const CaloCell* upPhiCell = NextPhiCell(centreCell,true,scells,idHelper);
1070 const CaloCell* downPhiCell = NextPhiCell(centreCell,false,scells,idHelper);
1071 const CaloCell* energeticPhiCell;
1072 // If the phi width is 2, the most energetic neighbour is chosen (defaulting to the 'down' side)
1073 // If the phi width is 3, both neighbours are added
1074 if (phiWidth > 1){
1075 if (CaloCellET(upPhiCell, digitScale, digitThresh) > CaloCellET(downPhiCell, digitScale, digitThresh)) energeticPhiCell = upPhiCell;
1076 else energeticPhiCell = downPhiCell;
1077 if (phiWidth == 2) addOnce(energeticPhiCell, centCells); //centCells.push_back(energeticPhiCell);
1078 else if (phiWidth == 3){
1079 addOnce(upPhiCell, centCells); //centCells.push_back(upPhiCell);
1080 addOnce(downPhiCell, centCells); //centCells.push_back(downPhiCell);
1081 }
1082 else if (phiWidth > 3) ATH_MSG_WARNING ( "phiWidth not 2 or 3!!!. Value = " << phiWidth);
1083 }
1084 // The actual cluster is initialised
1085 std::vector<const CaloCell*> fullClus;
1086 // The L1&2 SCs are added that match the full width
1087 for (auto ithL2Cell : L2cells){
1088 fullClus.push_back(ithL2Cell);
1089 fromLayer2toLayer1(scells, ithL2Cell, fullClus, idHelper);
1090 }
1091 // The L0&3 SCs are added that match the central L2 cells
1092 for (auto ithL2CentCell : centCells){
1093 addOnce( fromLayer2toPS( scells, ithL2CentCell, idHelper),fullClus);
1094 addOnce( fromLayer2toLayer3( scells, ithL2CentCell, idHelper),fullClus);
1095 }
1096 return fullClus;
1097}
1098
1099double
1100LVL1::EFexEMClusterTool::sumVectorET(const std::vector<const CaloCell*> &inputVector, float digitScale, float digitThreshold) const
1101{
1102 double TotalET=0.0;
1103 for (auto ithCell : inputVector){
1104 if (ithCell!=nullptr) TotalET += CaloCellET(ithCell, digitScale, digitThreshold);
1105 }
1106 return TotalET;
1107}
1108
1109bool
1110LVL1::EFexEMClusterTool::checkDig(float EM_ET, float digitScale, float digitThresh) const
1111{
1112 if (EM_ET == 0 || digitScale == 0) return true;
1113 else {
1114 int div = EM_ET / digitScale;
1115 if (div * digitScale == EM_ET) return true;
1116 else {
1117 ATH_MSG_WARNING ( "ET = " << EM_ET << ", digitThresh = " << digitThresh << " digitScale = " << digitScale << " div = " << div << " " << " -> div * digitScale");
1118 return false;
1119 }
1120 }
1121}
1122
1123double
1124LVL1::EFexEMClusterTool::HadronicET( const std::vector<const CaloCell*> & inputVector, const CaloConstCellContainer* scells,
1125 const xAOD::TriggerTowerContainer* &TTContainer, const CaloCell_SuperCell_ID* idHelper,
1126 float digitScale, float digitThresh) const
1127{
1128 // Finds the HCAL SCs & TTs matching the input cluster
1129 std::vector<const CaloCell*> HCAL_LAr_vector;
1130 std::vector<const xAOD::TriggerTower*> HCAL_TT_vector;
1131 for (auto ithCell : inputVector){
1132 if (std::abs(ithCell->eta())<1.5){
1133 const xAOD::TriggerTower* tempTT = matchingHCAL_TT(ithCell, TTContainer);
1134 if (tempTT != nullptr) HCAL_TT_vector.push_back(tempTT);
1135 }
1136 else if (std::abs(ithCell->eta())<2.5){
1137 const CaloCell* tempLArHad = matchingHCAL_LAr(ithCell, scells, idHelper);
1138 if (tempLArHad != nullptr) HCAL_LAr_vector.push_back(tempLArHad);
1139 }
1140 }
1141 // Sums the ET in the HCAL
1142 double HadET = 0.;
1143 for (auto ithTT : HCAL_TT_vector) {HadET += TT_ET(ithTT);}
1144 for (auto ithSC : HCAL_LAr_vector) {HadET += CaloCellET(ithSC, digitScale, digitThresh);}
1145 return HadET;
1146}
1147
1148
1152const CaloCell*
1154{
1155 const CaloCell* isCell = cellContainer->findCell(idHelper->CaloCell_SuperCell_ID::calo_cell_hash(inputID));
1156 if (isCell) return isCell;
1157 else return nullptr;
1158}
1159
1160const CaloCell*
1161LVL1::EFexEMClusterTool::NextEtaCell( const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1162 const CaloCell_SuperCell_ID* &idHelper) const
1163{
1164 if (inputCell==nullptr) return nullptr;
1165 Identifier ithID = inputCell->ID();
1166 int ithSub_calo = idHelper->sub_calo(ithID);
1167 int ithPos_neg = idHelper->pos_neg(ithID);
1168 const CaloCell* tempCell = nullptr;
1169 // Only works for LArEM
1170 if (ithSub_calo==0){
1171 // Barrel regions
1172 if (abs(ithPos_neg)==1) tempCell = NextEtaCell_Barrel(inputCell, upwards, cellContainer, idHelper);
1173 // EC OW
1174 else if (abs(ithPos_neg)==2) tempCell = NextEtaCell_OW(inputCell, upwards, cellContainer, idHelper);
1175 // EC IW
1176 else if (abs(ithPos_neg)==3) tempCell = NextEtaCell_IW(inputCell, upwards, cellContainer, idHelper);
1177 // Not barrel or end cap
1178 else {
1179 ATH_MSG_WARNING ( "Layer 2 cell not passed to specific method at" << inputCell->eta() << " , " << inputCell->phi());
1180 return nullptr;
1181 }
1182 return tempCell;
1183 }
1184 // Is FCAL
1185 else {
1186 ATH_MSG_WARNING ( "Next eta cell called for non-EM SC!");
1187 return nullptr;
1188 }
1189}
1190
1191const CaloCell*
1192LVL1::EFexEMClusterTool::NextEtaCell_Barrel(const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1193 const CaloCell_SuperCell_ID* &idHelper) const
1194{
1195 const Identifier ithID = inputCell->ID();
1196 const int ithEta_index = idHelper->eta(ithID);
1197 const int ithPhi_index = idHelper->phi(ithID);
1198 const int ithSampling = idHelper->sampling(ithID);
1199 const int ithSub_calo = idHelper->sub_calo(ithID);
1200 const int ithPos_neg = idHelper->pos_neg(ithID);
1201 const int ithRegion = idHelper->region(ithID);
1202
1203 // Extreme indices of each region
1204 int maxEta_index = 0;
1205 int minEta_index = 0;
1206 if (ithRegion==0){
1207 if (ithSampling == 0) maxEta_index = 14;
1208 else if (ithSampling == 1 || ithSampling == 2) maxEta_index = 55;
1209 else if (ithSampling == 3) maxEta_index = 13;
1210 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1211 }
1212 else if (ithRegion==1){
1213 if (ithSampling == 1) maxEta_index =2;
1214 else if (ithSampling == 2) maxEta_index=0;
1215 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1216 }
1217 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1218 // Declare next values, default initialisation is the same as cell
1219 int nextEta_index = ithEta_index;
1220 // Phi shouldn't change!
1221 // One special case where sampling does change, otherwise stays same
1222 int nextSampling = ithSampling;
1223 int nextSub_calo = ithSub_calo;
1224 int nextPos_neg = ithPos_neg;
1225 int nextRegion = ithRegion;
1226
1227 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1228 int incrementEta;
1229 if (upwards) incrementEta = ithPos_neg;
1230 else incrementEta = -1*ithPos_neg;
1231
1232 int tracker = 0;
1233
1234 // If first cell in region & moving more inwards
1235 if (ithEta_index==minEta_index && incrementEta==-1){
1236 if (ithRegion == 0){
1237 nextEta_index = 0;
1238 nextPos_neg = ithPos_neg * -1;
1239 tracker = 1;
1240 }
1241 else if (ithRegion == 1){
1242 nextEta_index = 55;
1243 nextRegion = 0;
1244 tracker = 2;
1245 }
1246 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1247 }
1248
1249 // If last cell in region & moving outwards
1250 else if ((ithEta_index == maxEta_index) && (incrementEta == 1)) {
1251 // Reg 0, Layers 1 & 2 go to barrel region 1
1252 if ((ithRegion == 0)&&(ithSampling == 1 || ithSampling == 2)){
1253 nextRegion = 1;
1254 nextEta_index = 0;
1255 tracker = 3;
1256 }
1257 // Reg 0, Layer 0 goes to OW region 0
1258 else if ((ithRegion == 0)&&(ithSampling == 0)){
1259 nextEta_index = 0;
1260 nextRegion = 0;
1261 nextPos_neg = 2*ithPos_neg;
1262 tracker = 4;
1263 }
1264 // Reg 0, Layer 3 goes to OW Layer 2 region 0 (change by ATW)
1265 else if ((ithRegion == 0)&&(ithSampling == 3)){
1266 nextSampling = 2;
1267 nextEta_index = 0;
1268 nextRegion = 0;
1269 nextPos_neg = 2*ithPos_neg;
1270 tracker = 5;
1271 }
1272 // Reg 1, Layer 1 go to OW region 0 (change by ATW)
1273 else if ((ithRegion == 1)&&(ithSampling == 1)){
1274 nextEta_index=0;
1275 nextRegion = 0;
1276 nextPos_neg = 2 * ithPos_neg;
1277 tracker = 6;
1278 }
1279 // Reg 1, Layer 2 goes to OW region 1
1280 else if ((ithRegion == 1)&&(ithSampling == 2)){
1281 nextEta_index=0;
1282 nextRegion = 1;
1283 nextPos_neg = 2 * ithPos_neg;
1284 tracker = 7;
1285 }
1286 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1287 }
1288 // Otherwise 'simply' next cell along
1289 else {
1290 nextEta_index = ithEta_index + incrementEta;
1291 tracker = 8;
1292 }
1293 //ATH_MSG_DEBUG ( "B Tracker = " << tracker);
1294 // Form identifier, find cell & return it
1295 // sub_calo, left_pos_neg, 2, region, eta_index, down_phi_index
1296 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, nextSampling, nextRegion, nextEta_index, ithPhi_index);
1297 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1298 if (nextCell == nullptr) {
1299 ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1300 ATH_MSG_DEBUG ( "Barrel Tracker = " << tracker);
1301 ATH_MSG_DEBUG ( "from nextCellID: "<<idHelper->sub_calo(nextCellID)<<", "<<idHelper->pos_neg(nextCellID)<<", "<<idHelper->sampling(nextCellID)<<", "<<idHelper->region(nextCellID)<<", "<<idHelper->eta(nextCellID)<<", "<<idHelper->phi(nextCellID)<<", "<<idHelper->calo_cell_hash(nextCellID)<<", "<<nextCellID);
1302 }
1303 else {
1304 Identifier newID = nextCell->ID();
1305 int IDsample = idHelper->sampling(nextCell->ID());
1307 if (IDsample!=ithSampling){
1308 ATH_MSG_DEBUG ( "Layer has changed " << " tracker = " << tracker);
1309 ATH_MSG_DEBUG ( "from nextCellID: "<<idHelper->sub_calo(nextCellID)<<", "<<idHelper->pos_neg(nextCellID)<<", "<<idHelper->sampling(nextCellID)<<", "<<idHelper->region(nextCellID)<<", "<<idHelper->eta(nextCellID)<<", "<<idHelper->phi(nextCellID)<<", "<<idHelper->calo_cell_hash(nextCellID)<<", "<<nextCellID);
1310 ATH_MSG_DEBUG ( "from ID from new cell: "<<idHelper->sub_calo(newID)<<", "<<idHelper->pos_neg(newID)<<", "<<idHelper->sampling(newID)<<", "<<idHelper->region(newID)<<", "<<idHelper->eta(newID)<<", "<<idHelper->phi(newID)<<", "<<idHelper->calo_cell_hash(newID)<<", "<<newID);
1311 ATH_MSG_DEBUG ( "comp indices: "<< (nextCellID == newID));
1312 }
1313 }
1314 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__ << " does not match");
1315 return nextCell;
1316}
1317
1318const CaloCell*
1319LVL1::EFexEMClusterTool::NextEtaCell_OW( const CaloCell*inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1320 const CaloCell_SuperCell_ID* &idHelper) const
1321{
1322 Identifier ithID = inputCell->ID();
1323 int ithEta_index = idHelper->eta(ithID);
1324 const int ithPhi_index = idHelper->phi(ithID);
1325 const int ithSampling = idHelper->sampling(ithID);
1326 int ithSub_calo = idHelper->sub_calo(ithID);
1327 int ithPos_neg = idHelper->pos_neg(ithID);
1328 int ithRegion = idHelper->region(ithID);
1329 // Declare next values, default initialisation is the same as cell
1330 int nextEta_index = ithEta_index;
1331 int nextPhi_index = ithPhi_index;
1332 // Sampling may change in a couple of special cases (transition tower)
1333 int nextSampling = ithSampling;
1334 int nextSub_calo = ithSub_calo;
1335 int nextPos_neg = ithPos_neg;
1336 int nextRegion = ithRegion;
1337 // Maximum indices for barrel region 0:
1338 int maxEta_index = 0;
1339 int minEta_index = 0;
1340 // Set max / min values based on ithRegion
1341 if (ithSampling==0) maxEta_index = 2;
1342 else if (ithSampling==2 && ithRegion==0) maxEta_index = 0;
1343 else if (ithSampling==2 && ithRegion==1) maxEta_index = 42;
1344 else if (ithSampling==3) maxEta_index=9;
1345 else if (ithSampling==1) {
1346 switch(ithRegion){
1347 case 0:
1348 maxEta_index=0;
1349 break;
1350 case 1:
1351 ATH_MSG_DEBUG ( "ISSUE " << __LINE__);
1352 break;
1353 case 2:
1354 maxEta_index=11;
1355 break;
1356 case 3:
1357 maxEta_index=11;// Should this be 11? - it was 7
1358 break;
1359 case 4:
1360 maxEta_index=15;
1361 break;
1362 case 5:
1363 maxEta_index=0;
1364 break;
1365 default:
1366 ATH_MSG_WARNING ( "OW region is not covered: " << ithRegion);
1367 }
1368 }
1369 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__ );
1370
1371 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1372 int incrementEta = upwards ? 1 : -1;
1373
1374 int ithSide{};
1375 if (auto denom = std::abs(ithPos_neg); denom!=0){
1376 ithSide = ithPos_neg / denom;
1377 }
1378 incrementEta *= ithSide;
1379 int tracker = 0;
1380 // Lower end of OW, going inwards
1381 if (ithEta_index==minEta_index && ithRegion==0 && incrementEta==-1){
1382 nextPos_neg = ithSide;
1383 if (ithSampling==0){
1384 nextRegion = 0;
1385 nextEta_index = 14;
1386 tracker = 1;
1387 }
1388 else if (ithSampling==1){
1389 nextRegion = 1;
1390 nextEta_index = 2;
1391 tracker = 2;
1392 }
1394 else if (ithSampling==2){
1395 nextRegion = 0;
1396 nextSampling = 2;
1397 nextEta_index = 13;
1398 tracker = 3;
1399 }
1401 else if (ithSampling==3){
1402 nextRegion = 0;
1403 nextSampling = 2;
1404 nextEta_index = 0;
1405 nextPos_neg = ithPos_neg;
1406 tracker = 4;
1407 }
1408 }
1409 // Higher end of OW, going outwards
1410 else if (ithEta_index==maxEta_index && incrementEta==1){
1411 // Layers 0 & 3 aren't in IW
1412 if (ithSampling==0 || ithSampling==3) return nullptr;
1413 else if (ithSampling==2 && ithRegion==0){
1414 nextRegion = 1;
1415 nextEta_index = 0;
1416 tracker = 5;
1417 }
1418 else if ((ithSampling==2 && ithRegion==1)||(ithSampling==1 && ithRegion==5)){
1419 // Reaches IW
1420 nextEta_index=0;
1421 nextRegion=0;
1422 nextPhi_index=ithPhi_index/2;
1423 nextPos_neg=3*ithSide;
1424 tracker=6;
1425 }
1426 else if (ithSampling==1 && ithRegion==0){
1427 // Unsure what to do??
1428 nextRegion = 2;
1429 nextEta_index = 0;
1430 tracker = 7;
1431 }
1432 else if (ithSampling==1){
1433 nextRegion=ithRegion + 1;
1434 nextEta_index=0;
1435 tracker = 8;
1436 }
1437 }
1438 // Lower end of region in OW, going inwards
1439 else if (ithEta_index==minEta_index && incrementEta==-1){
1440 // Shouldn't apply to layers 0 & 3
1441 // Only case for layer 2 should be in region 1
1442 // But this one is special because we want to step into barrel (ATW)
1443 if (ithSampling==2){
1444 nextRegion = 1;
1445 nextEta_index = 0;
1446 nextPos_neg = ithPos_neg;
1447 tracker = 9;
1448 }
1449 else if (ithSampling==1){
1450 tracker = 11;
1451 // Layer one has muliple regions
1452 nextRegion = ithRegion-1;
1453 if (nextRegion==0) {
1454 nextEta_index=0;
1455 ATH_MSG_DEBUG ( "ISSUE: "<< __LINE__);
1456 }
1457 else if (nextRegion==1) {
1458 nextRegion = 0;
1459 nextEta_index= 0;
1460 }
1461 else if (nextRegion==2) nextEta_index=11;
1462 else if (nextRegion==3) nextEta_index=7;
1463 else if (nextRegion==4) nextEta_index=15;
1464 }
1465 }
1466 // Middle of region in middle of endcap
1467 else {
1468 nextEta_index = ithEta_index+incrementEta;
1469 tracker = 12;
1470 }
1471 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, nextSampling, nextRegion, nextEta_index, nextPhi_index);
1472 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1473 if (nextCell == nullptr) {
1474 ATH_MSG_DEBUG ( "ISSUE: "<<__LINE__);
1475 ATH_MSG_DEBUG ( "OW Tracker = "<<tracker);
1476 ATH_MSG_DEBUG ( "from nextCellID: "<<idHelper->sub_calo(nextCellID)<<", "<<idHelper->pos_neg(nextCellID)<<", "<<idHelper->sampling(nextCellID)<<", "<<idHelper->region(nextCellID)<<", "<<idHelper->eta(nextCellID)<<", "<<idHelper->phi(nextCellID)<<", "<<idHelper->calo_cell_hash(nextCellID)<<", "<<nextCellID);
1477 ATH_MSG_DEBUG ( "Increment eta = "<<incrementEta<<", max_eta = "<<maxEta_index<<", min_eta = "<<minEta_index);
1478 }
1479 else {
1480 Identifier newID = nextCell->ID();
1481 int IDsample = idHelper->sampling(nextCell->ID());
1482 if (IDsample!=ithSampling){
1483 ATH_MSG_DEBUG ( "Layer has changed "<<" tracker = "<<tracker);
1484 ATH_MSG_DEBUG ( "from nextCellID: "<<idHelper->sub_calo(nextCellID)<<", "<<idHelper->pos_neg(nextCellID)<<", "<<idHelper->sampling(nextCellID)<<", "<<idHelper->region(nextCellID)<<", "<<idHelper->eta(nextCellID)<<", "<<idHelper->phi(nextCellID)<<", "<<idHelper->calo_cell_hash(nextCellID)<<", "<<nextCellID);
1485 ATH_MSG_DEBUG ( "from ID from new cell: "<<idHelper->sub_calo(newID)<<", "<<idHelper->pos_neg(newID)<<", "<<idHelper->sampling(newID)<<", "<<idHelper->region(newID)<<", "<<idHelper->eta(newID)<<", "<<idHelper->phi(newID)<<", "<<idHelper->calo_cell_hash(newID)<<", "<<newID);
1486 ATH_MSG_DEBUG ( "comp indices: "<<(nextCellID == newID));
1487 }
1488 }
1489 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__<< " does not match");
1490 return nextCell;
1491}
1492
1493const CaloCell*
1494LVL1::EFexEMClusterTool::NextEtaCell_IW( const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1495 const CaloCell_SuperCell_ID* &idHelper) const
1496{
1497 const Identifier ithID = inputCell->ID();
1498 const int ithEta_index = idHelper->eta(ithID);
1499 const int ithPhi_index = idHelper->phi(ithID);
1500 const int ithSampling = idHelper->sampling(ithID);
1501 const int ithSub_calo = idHelper->sub_calo(ithID);
1502 const int ithPos_neg = idHelper->pos_neg(ithID);
1503 const int ithRegion = idHelper->region(ithID);
1504 //int tracker =0;
1505 // Declare next values, default initialisation is the same as cell
1506 int nextEta_index = ithEta_index;
1507 int nextPhi_index = ithPhi_index;
1508 // Sampling shouldn't change!
1509 int nextSub_calo = ithSub_calo;
1510 int nextPos_neg = ithPos_neg;
1511 int nextRegion = ithRegion;
1512
1513 // Maximum indices for barrel region 0:
1514 int maxEta_index = 0;
1515 int minEta_index = 0;
1516
1517 if (ithRegion==0){
1518 maxEta_index=2;
1519 minEta_index=0;
1520 }
1521 else if (ithRegion!=1) ATH_MSG_DEBUG ( "ISSUE: " <<__LINE__);
1522
1523 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1524 int incrementEta{};
1525 int ithSide{};
1526 if (ithPos_neg != 0){
1527 ithSide = ithPos_neg / std::abs(ithPos_neg);
1528 }
1529 if (upwards) incrementEta = ithSide;
1530 else incrementEta = ithSide * -1;
1531 // Lower end of region IW, going inwards
1532 if (ithEta_index==minEta_index&& incrementEta==-1){
1533 // Goes to OW
1534 if (ithRegion == 0){
1535 nextPos_neg = 2*ithSide;
1536 nextPhi_index=2*ithPhi_index;
1537 if (ithSampling==1){
1538 // tracker=1;
1539 nextRegion=5;
1540 nextEta_index=0;
1541 }
1542 else if (ithSampling==2){
1543 // tracker=2;
1544 nextRegion=1;
1545 nextEta_index=42;
1546 }
1547 else ATH_MSG_DEBUG ( "ISSUE: " <<__LINE__);
1548 }
1549 // Goes to IW region 0
1550 else if (ithRegion == 1){
1551 // tracker=3;
1552 nextRegion=0;
1553 nextEta_index=2;
1554 }
1555 }
1556 // Upper end of region in IW
1557 else if (ithEta_index==maxEta_index && incrementEta==1){
1558 // Goes to region 1
1559 if (ithRegion==0){
1560 // tracker=4;
1561 nextRegion=1;
1562 nextEta_index=0;
1563 }
1564 // Reaches FCAL
1565 else if (ithRegion==1) return nullptr;
1566 }
1567 // Increment eta like normal
1568 else {
1569 // tracker=5;
1570 nextEta_index=ithEta_index+incrementEta;
1571 }
1572 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, ithSampling, nextRegion, nextEta_index, nextPhi_index);
1573 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1574 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__<<" does not match");
1575 return nextCell;
1576}
1577
1578int
1579LVL1::EFexEMClusterTool::restrictPhiIndex(int input_index, bool is64) const
1580{
1581 if (is64&&input_index<0) return input_index+64;
1582 else if (is64&&input_index>63) return input_index-64;
1583 else if (!(is64)&&input_index<0) return input_index+32;
1584 else if (!(is64)&&input_index>31) return input_index-32;
1585 else return input_index;
1586}
1587
1588const CaloCell*
1589LVL1::EFexEMClusterTool::NextPhiCell( const CaloCell * inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1590 const CaloCell_SuperCell_ID* &idHelper) const
1591{
1592 if (inputCell==nullptr)
1593 return nullptr;
1594
1595 const Identifier ithID = inputCell->ID();
1596 const int ithEta_index = idHelper->eta(ithID);
1597 const int ithPhi_index = idHelper->phi(ithID);
1598 const int ithSampling = idHelper->sampling(ithID);
1599 const int ithSub_calo = idHelper->sub_calo(ithID);
1600 const int ithPos_neg = idHelper->pos_neg(ithID);
1601 const int ithRegion = idHelper->region(ithID);
1602
1603 bool is64;
1604 if (abs(ithPos_neg)==3) is64 = false;
1605 else is64 = true;
1606
1607 int incrementPhi;
1608 if (upwards==true) incrementPhi=1;
1609 else incrementPhi=-1;
1610
1611 const int nextPhi_index = restrictPhiIndex(ithPhi_index+incrementPhi, is64);
1612 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(ithSub_calo, ithPos_neg, ithSampling, ithRegion, ithEta_index, nextPhi_index);
1613 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1614 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__ << " does not match");
1615 if (nextCell == nullptr) ATH_MSG_DEBUG ( "Next phi cell is nullptr at " << __LINE__);
1616 return nextCell;
1617}
#define M_PI
Scalar phi() const
phi method
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
int sign(int a)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
int phi(const Identifier id) const
LAr field values (NOT_VALID == invalid request).
int sampling(const Identifier id) const
LAr field values (NOT_VALID == invalid request).
int sub_calo(const Identifier id) const
returns an int taken from SUBCALO enum and describing the subCalo to which the Id belongs.
int region(const Identifier id) const
LAr field values (NOT_VALID == invalid request).
int pos_neg(const Identifier id) const
LAr field values (NOT_VALID == invalid request).
int eta(const Identifier id) const
LAr field values (NOT_VALID == invalid request).
IdentifierHash calo_cell_hash(const Identifier cellId) const
create hash id from 'global' cell id
Helper class for offline supercell identifiers.
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
virtual double e() const override final
get energy (data member) (synonym to method energy()
Definition CaloCell.h:333
virtual double phi() const override final
get phi (through CaloDetDescrElement)
Definition CaloCell.h:375
double energy() const
get energy (data member)
Definition CaloCell.h:327
uint16_t provenance() const
get provenance (data member)
Definition CaloCell.h:354
virtual double eta() const override final
get eta (through CaloDetDescrElement)
Definition CaloCell.h:382
Identifier ID() const
get ID (from cached data member) non-virtual and inline for fast access
Definition CaloCell.h:295
CaloCellContainer that can accept const cell pointers.
::CaloCellContainer::const_iterator beginConstCalo(CaloCell_ID::SUBCALO caloNum) const
get const begin iterator on cell of just one calo
const CaloCell * findCell(IdentifierHash theHash) const
fast find method given identifier hash.
::CaloCellContainer::const_iterator endConstCalo(CaloCell_ID::SUBCALO caloNum) const
get const begin iterator on cell of just one calo
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
size_type size() const noexcept
Returns the number of elements in the collection.
void checkTileCell(const TileCell *&inputCell, std::vector< const TileCell * > &tileCellVector, bool &isAlreadyThere) const
determine if Tile cell has already been taken into account
double RHadTile(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh, const TileID *m_tileIDHelper, const CaloConstCellContainer *tileCellCon, float tileNoiseThresh, float &HadronicET) const
calculate the hadronic isolation for a seed cell using TileCal cells
int m_etaWidth_TDRCluster
eta width of the TDR cluster formation given in number of SCs (including the central cell),...
int detRelPos(const float inEta) const
determine the PMT position of the Tile cell to be matched
float m_clustET_looseAlg_thresh
threshold for minimum cluster energy for the loose eFEX algorithm
float m_nominalNoise_thresh
noise threshold
float m_eta_dropL1Width
max eta for applying cut on L1Width (baseline selection)
int m_etaWidth_REtaIsolation_den
eta width for REta isolation given in number of SCs (denominator of fraction)
double HadronicET(const std::vector< const CaloCell * > &inputVector, const CaloConstCellContainer *scells, const xAOD::TriggerTowerContainer *&TTContainer, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate the energy in the HCAL (LAr + Tile) for SC/TT that match the EM cluster cells of L2
const CaloCell * NextEtaCell_IW(const CaloCell *inputCell, bool upwards, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
returns the SC left/right to the input cell for the IW
void fromLayer2toLayer1(const CaloConstCellContainer *&inputContainer, const CaloCell *inputCell, std::vector< const CaloCell * > &outputVector, const CaloCell_SuperCell_ID *&idHelper) const
match SCs from the cluster in L2 to L1
const CaloCell * NextEtaCell_OW(const CaloCell *inputCell, bool upwards, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
returns the SC left/right to the input cell for the OW
double TT_ET(const xAOD::TriggerTower *&inputTower) const
calculate the energy of an input TT
double L1Width(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate the lateral isolation aorund the central cell
double sumVectorET(const std::vector< const CaloCell * > &inputVector, float digitScale=0., float digitThreshold=0.) const
calculate cluster energy from all SCs in PS, L1, L2, L3
std::vector< const CaloCell * > TDR_Clus(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
form the cluster around the central SC
float m_clustET_thresh
threshold for minimum cluster energy (baseline selection)
int m_etaHadWidth_RHadIsolation
hadronic eta width for RHad isolation given in number of SCs
int m_etaEMWidth_RHadIsolation
EM eta width for RHad isolation given in number of SCs.
double tileCellEnergyCalib(float eIn, float etaIn, float tileNoiseThresh) const
determine transverse energy and apply noise threshold to Tile cells
int m_phiWidth_wstotIsolation
phi width for wstot isolation given in number of SCs
const CaloCell * fromLayer2toPS(const CaloConstCellContainer *&inputContainer, const CaloCell *inputCell, const CaloCell_SuperCell_ID *&idHelper) const
match SCs from the cluster in L2 to one cell of PS
EFexEMClusterTool(const std::string &type, const std::string &name, const IInterface *parent)
Name : EFexEMClusterTool.cxx PACKAGE : Trigger/TrigT1/TrigT1CaloFexPerf AUTHOR : Denis Oliveira Damaz...
int m_phiEMWidth_RHadIsolation
EM phi width for RHad isolation given in number of SCs.
std::vector< AlgResult > clusterAlg(bool applyBaselineCuts, const CaloConstCellContainer *scells, const xAOD::TriggerTowerContainer *TTs, const CaloCell_SuperCell_ID *idHelper, const TileID *m_tileIDHelper, const CaloConstCellContainer *tileCellCon) const
find cluster and associated variables using a user defined selection
const CaloCell * NextEtaCell_Barrel(const CaloCell *inputCell, bool upwards, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
returns the SC left/right to the input cell for the barrel
bool checkDig(float EM_ET, float digitScale, float digitThresh) const
check if conversion from ET to energy after digitization was performed successfully
double EMClusET(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate cluster energy
std::vector< double > EnergyPerTileLayer(const std::vector< const CaloCell * > &inputSCVector, const CaloConstCellContainer *CellCon, const TileID *tileIDHelper, bool isOW, float tileNoiseThresh) const
match all Tile cells to a given L2Cluster and determine the summed energy per Tile layer
double RHad(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const xAOD::TriggerTowerContainer *&TTContainer, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh, float &HadronicET) const
calculate the hadronic isolation of the central cell
int m_qualBitMask
Configurable quality bitmask.
const CaloCell * matchingHCAL_LAr(const CaloCell *&inputCell, const CaloConstCellContainer *&SCContainer, const CaloCell_SuperCell_ID *&idHelper) const
Match each SC from L2 to one corresponding HCAL SC.
float m_tileNoise_tresh
TileCal cell noise threshold.
int m_phiHadWidth_RHadIsolation
hadronic phi width for RHad isolation given in number of SCs
float m_REta_thresh
threshold for isolation REta (baseline selection)
int m_phiWidth_REtaIsolation_num
phi width for REta isolation given in number of SCs (numerator of fraction)
float m_L1Width_thresh
threshold for isolation L1Width (wstot) (baseline selection)
bool localMax(const CaloConstCellContainer *&inputContainer, const CaloCell *inputCell, const CaloCell_SuperCell_ID *&idHelper, float digitScale, float digitThreshold) const
helper function calling localMax()
int restrictPhiIndex(int input_index, bool is64) const
manager function for the phi index
const CaloCell * NextEtaCell(const CaloCell *inputCell, bool upwards, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
helper function calling NextEtaCell_Barrel(), NextEtaCell_OW(), NextEtaCell_IW() according to positio...
double dR(double eta1, double phi1, double eta2, double phi2) const
calculate deltaR between two points in eta/phi space
float m_nominalDigitization
value of nominal digitisation
double REtaL12(const CaloCell *centreCell, int etaWidth1, int phiWidth1, int etaWidth2, int phiWidth2, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate the energy isolation of the central cell along eta using Layer 1 and Layer 2
const xAOD::TriggerTower * matchingHCAL_TT(const CaloCell *&inputCell, const xAOD::TriggerTowerContainer *&TTContainer) const
Match each SC from L2 to one corresponding TT.
float m_RHad_thresh
threshold for isolation RHad (baseline selection)
int m_etaWidth_REtaIsolation_num
eta width for REta isolation given in number of SCs (numerator of fraction)
bool SameTT(const CaloCell *inputCell1, const CaloCell *inputCell2, const CaloCell_SuperCell_ID *&idHelper) const
check if both input cells belong to the same TT
const CaloCell * fromLayer2toLayer3(const CaloConstCellContainer *&inputContainer, const CaloCell *inputCell, const CaloCell_SuperCell_ID *&idHelper) const
match SCs from the cluster in L2 to one cell of L3
float CaloCellET(const CaloCell *const &inputCell, float digitScale, float digitThreshold) const
private algorithms
double REta(const CaloCell *centreCell, int etaWidth1, int phiWidth1, int etaWidth2, int phiWidth2, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate the energy isolation of the central cell along eta
const CaloCell * returnCellFromCont(Identifier inputID, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
helper functions to find neighbouring cells
std::vector< const CaloCell * > L2cluster(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
form the cluster from cells of the second layer L2
bool m_use_tileCells
boolean for using Tile cells instead of Tile TT
int m_etaWidth_wstotIsolation
eta width for wstot isolation given in number of SCs
bool m_use_REtaL12
boolean for caluclating REta using Layer 1 in addition to Layer 2
float m_clustET_NoIso_thresh
threshold for applying cluster isolation cuts (baseline selection)
int m_phiWidth_TDRCluster
phi width of the TDR cluster formation given in number of SCs (including the central cell),...
const CaloCell * NextPhiCell(const CaloCell *inputCell, bool upwards, const CaloConstCellContainer *&cellContainer, const CaloCell_SuperCell_ID *&idHelper) const
returns the SC above/below the input cell
int m_phiWidth_REtaIsolation_den
phi width for REta isolation given in number of SCs (denominator of fraction)
void addOnce(const CaloCell *inputCell, std::vector< const CaloCell * > &outputVector) const
adds SC to vector if the SC is not part of this vector yet
double TT_phi(const xAOD::TriggerTower *&inputTower) const
convert the TT phi to match the definition of SC phi
double L2clusET(const CaloCell *centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer *scells, const CaloCell_SuperCell_ID *idHelper, float digitScale, float digitThresh) const
calculate cluster energy of cells in L2 around the central cell in a given eta/phi width
std::vector< AlgResult > looseAlg(const CaloConstCellContainer *SCs, const xAOD::TriggerTowerContainer *TTs, const CaloCell_SuperCell_ID *idHelper, const TileID *m_tileIDHelper, const CaloConstCellContainer *tileCellCon) const
algorithm fors cluster building
float ene1(void) const
get energy of first PMT
Definition TileCell.h:187
float ene2(void) const
get energy of second PMT
Definition TileCell.h:189
Helper class for TileCal offline identifiers.
Definition TileID.h:67
int sample(const Identifier &id) const
uint8_t cpET() const
get cpET from peak of lut_cp
virtual double phi() const final
The azimuthal angle ( ) of the particle.
TriggerTowerContainer_v2 TriggerTowerContainer
Define the latest version of the TriggerTower container.
TriggerTower_v2 TriggerTower
Define the latest version of the TriggerTower class.
#define unlikely(x)