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 double result = HadET/(EMcomp+HadET);
586 if (result < 0. || result > 1.){
587 ATH_MSG_WARNING ( "RHADTILE -> " << etaWidth << " * " << phiWidth);
588 ATH_MSG_WARNING ( "fullClus count = " << fullClus.size() << ", EMcomp = " << EMcomp << ", HCALcomp = " << HadET);
589 return 1.;
590 }
591 return result;
592}
593
594double
595LVL1::EFexEMClusterTool::REtaL12(const CaloCell* centreCell, int etaWidth1, int phiWidth1, int etaWidth2, int phiWidth2,
596 const CaloConstCellContainer* scells, const CaloCell_SuperCell_ID* idHelper,
597 float digitScale, float digitThresh) const
598{
599 // Check windows sizes are right way round
600 if (etaWidth1 > etaWidth2) ATH_MSG_WARNING ( "REta: eta1 = " << etaWidth1 << ", eta2 = " << etaWidth2);
601 if (phiWidth1 > phiWidth2) ATH_MSG_WARNING ( "Rphi: phi1 = " << phiWidth1 << ", phi2 = " << phiWidth2);
602 // Finds ET of windows
603 double inner_ET = L2clusET(centreCell, etaWidth1, phiWidth1, scells, idHelper, digitScale, digitThresh);
604 double outer_ET = L2clusET(centreCell, etaWidth2, phiWidth2, scells, idHelper, digitScale, digitThresh);
605 // Find corresponding L1 cells, calculate the L1 ET and add them to L2 ET
606 std::vector<const CaloCell*> L2cells_inner = L2cluster(centreCell, etaWidth1, phiWidth1, scells, idHelper,digitScale, digitThresh);
607 std::vector<const CaloCell*> L1cells_inner;
608 for (auto ithL2Cell : L2cells_inner){
609 fromLayer2toLayer1(scells, ithL2Cell, L1cells_inner, idHelper);
610 }
611 inner_ET += sumVectorET(L1cells_inner, digitScale, digitThresh);
612 std::vector<const CaloCell*> L2cells_outer = L2cluster(centreCell, etaWidth2, phiWidth2, scells, idHelper,digitScale, digitThresh);
613 std::vector<const CaloCell*> L1cells_outer;
614 for (auto ithL2Cell : L2cells_outer){
615 fromLayer2toLayer1(scells, ithL2Cell, L1cells_outer, idHelper);
616 }
617 outer_ET += sumVectorET(L1cells_outer, digitScale, digitThresh);
618 // Find normal value of REta & changes it to my version
619 double normal_REta;
620 if (inner_ET != 0. && outer_ET==0.) normal_REta = 0.;
621 else if (inner_ET==0.) normal_REta = 0.;
622 else normal_REta = inner_ET / outer_ET;
623 if (normal_REta < 0) normal_REta = 0.;
624 double my_REta = 1-normal_REta;
625 return my_REta;
626}
627
628void
630 std::vector<const CaloCell*> &outputVector, const CaloCell_SuperCell_ID* &idHelper) const
631{
632 if (inputCell==nullptr) return;
633 // Gets ID info
634 Identifier inputID = inputCell->ID();
635 int sampling = idHelper->sampling(inputID);
636 const int sub_calo = idHelper->sub_calo(inputID);
637 int pos_neg = idHelper->pos_neg(inputID);
638 int region = idHelper->region(inputID);
639 int eta_index = idHelper->eta(inputID);
640 const int phi_index = idHelper->phi(inputID);
641 int tracker = 0;
642 if (sampling != 2) return;
643 // Default values are same as input
644 int outputRegion = region;
645 int outputEta = eta_index;
646 bool oneCell = false; // True if layer 2 SC only matches to a single layer 1 SC
647 // Barrel reg 0 (which is a simple one)
648 if ((abs(pos_neg) == 1)&&(region == 0)){
649 oneCell = true;
650 }
651 // Barrel reg 1: 3 layer 1 SCs for 1 layer 2 SC
652 // But we should map one of these onto the barrel SC, the other 2 onto EC SCs
653 else if ((abs(pos_neg) == 1)&&(region == 1)){
654 tracker = 2;
655 outputRegion = 1;
656 outputEta = 0;
657 oneCell = true;
658 /* This code produces a one-to-many matching, which is not how things work
659 for (unsigned int i = 0; i < 3; i++){
660 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, region, i, phi_index);
661 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
662 addOnce(resultCell,outputVector);
663 }
664 */
665 }
668 else if (abs(pos_neg)==2 && region == 0) {
669 tracker = -1;
670 }
673 else if (abs(pos_neg)==2&&((region==1 && eta_index < 2))){
674 tracker = 3;
675 outputRegion = 1;
676 outputEta = eta_index + 1;
677 pos_neg /= abs(pos_neg);
678 oneCell = true;
679 }
681 else if (abs(pos_neg)==2&&((region==1 && eta_index == 2))){
682 tracker = 4;
683 outputRegion = 0;
684 outputEta = 0;
685 oneCell = true;
686 }
688 else if (abs(pos_neg)==2&&region==1 && eta_index <= 14){
689 // OW region 1 (on doc): 1:1 match
690 tracker = 5;
691 outputRegion = 2;
692 outputEta = eta_index - 3;
693 oneCell = true;
694 }
696 else if (abs(pos_neg) == 2 && region == 1 && eta_index <= 22){
697 // In this region there are 6 L1 supercells for every 4 L2 ones
698 // The code below groups them 2:1:1:2 2:1:1:2, which is an old proposal
699 // This is not what is actually done, but the structure of this code
700 // makes it impossible to do this correctly.
701 outputRegion = 3;
702 // Middle 2 layer cells match central 2 layer 1 cells
703 if (eta_index%4 == 0 || eta_index%4 ==1){
704 tracker = 6;
705 oneCell = true;
706 if (eta_index < 20) outputEta = eta_index -14;
707 else outputEta = eta_index - 12;
708 }
709 // Edges have a 2:1 ratio. 2 L1s for each L2
710 else {
711 tracker = 7;
712 int offset = 0;
713 if (eta_index == 15) offset = 15;
714 else if (eta_index == 18) offset = 14;
715 else if (eta_index == 19) offset = 13;
716 else if (eta_index == 22) offset = 12;
717 else {
718 ATH_MSG_DEBUG ( "ISSUE with: " << __LINE__);
719 }
720 for (unsigned int i = 0; i < 2; i++){
721 outputEta = i+eta_index - offset;
722 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, outputRegion, outputEta, phi_index);
723 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
724 addOnce(resultCell,outputVector);
725 }
726 }
727 }
729 else if (abs(pos_neg)==2 && region == 1 && eta_index <= 38){
730 // OW Reg 3 (on doc): 1:1 match
731 tracker = 8;
732 oneCell = true;
733 outputRegion = 4;
734 outputEta = eta_index - 23;
735 }
737 else if (abs(pos_neg)==2 && region == 1 && eta_index == 40){
738 // OW Reg 4 (on doc): 1 L1 for all 4 L2s
739 // But this must be mapped onto a specific cell: second one seems best
740 // Note: to try alternative mapping of this cell (to Layer 0) should return without adding cell here
741 tracker = 9;
742 oneCell = true;
743 outputEta = 0;
744 outputRegion = 5;
745 }
746
747 if (oneCell){
748 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 1, outputRegion, outputEta, phi_index);
749 const CaloCell* resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
750 addOnce(resultCell,outputVector);
751 }
752 ATH_MSG_DEBUG("L2->L1: sampling = " << sampling << ", region = " << region << ", eta = " << pos_neg*eta_index<< " tracker = " << tracker);
753}
754
755const CaloCell*
756LVL1::EFexEMClusterTool::fromLayer2toLayer3(const CaloConstCellContainer* &inputContainer, const CaloCell* inputCell, const CaloCell_SuperCell_ID* &idHelper) const
757{
758 // Gets ID info
759 int tracker = 0;
760 if ( inputCell == nullptr ) return nullptr;
761 const CaloCell* resultCell = nullptr;
762 Identifier inputID = inputCell->ID();
763 int sampling = idHelper->sampling(inputID);
764 const int sub_calo = idHelper->sub_calo(inputID);
765 const int pos_neg = idHelper->pos_neg(inputID);
766 int region = idHelper->region(inputID);
767 int eta_index = idHelper->eta(inputID);
768 const int phi_index = idHelper->phi(inputID);
769 if (sampling != 2) return nullptr;
770 else if (abs(pos_neg)==1 && ((region==0 && eta_index>53)||region==1)) return nullptr;
771 else if ((abs(pos_neg)==2) && (region == 0 || (region == 1 && eta_index < 3))) return nullptr;
772 else if (abs(pos_neg)==3) return nullptr;
773 // Default values are same as input
774 int outputRegion = region;
775 int outputEta = eta_index;
776 // Is barrel Reg 0
777 if (abs(pos_neg)==1 && region ==0){
778 int outputEta = eta_index/4;
779 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 3, outputRegion, outputEta, phi_index);
780 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
781 tracker = 1;
782 }
784 else if (abs(pos_neg)==1 && region ==1) {
785 int output_pos_neg = pos_neg*2;
786 outputRegion = 0;
787 int outputEta = 0;
788 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, output_pos_neg, 2, outputRegion, outputEta, phi_index);
789 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
790 tracker = 2;
791 }
793 else if (abs(pos_neg)==2 && region ==1){
794 outputEta = (eta_index - 3)/4;
795 outputRegion = 0;
796 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 3, outputRegion, outputEta, phi_index);
797 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
798 tracker = 3;
799 }
800 ATH_MSG_DEBUG("L2->L3: sampling = " << sampling << ", region = " << region << ", eta = " << pos_neg*eta_index<< " tracker = " << tracker);
801 return resultCell;
802}
803
804const CaloCell*
805LVL1::EFexEMClusterTool::fromLayer2toPS(const CaloConstCellContainer* & inputContainer, const CaloCell* inputCell, const CaloCell_SuperCell_ID* &idHelper) const
806{
807 // Gets ID info
808 if (inputCell==nullptr) return nullptr;
809 const CaloCell* resultCell = nullptr;
810 Identifier inputID = inputCell->ID();
811 int sampling = idHelper->sampling(inputID);
812 const int sub_calo = idHelper->sub_calo(inputID);
813 const int pos_neg = idHelper->pos_neg(inputID);
814 int region = idHelper->region(inputID);
815 int eta_index = idHelper->eta(inputID);
816 const int phi_index = idHelper->phi(inputID);
817 if (sampling != 2) return nullptr;
818 if (abs(pos_neg)==2 && (eta_index<3 || eta_index>14)) return nullptr;
819 if (abs(pos_neg)==3) return nullptr;
820 // Default values are same as input
821 int outputRegion = region;
822 int outputEta = eta_index;
823 // Is barrel Reg 0
824 if (abs(pos_neg)==1 && region ==0){
825 int outputEta = eta_index/4;
826 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, outputRegion, outputEta, phi_index);
827 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
828 }
829 else if (abs(pos_neg)==1 && region ==1){
830 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, 0, 14, phi_index);
831 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
832 }
833 else if (abs(pos_neg)==2 && region ==1){
834 outputEta = (eta_index - 3)/4;
835 outputRegion = 0;
836 Identifier resultID = idHelper->CaloCell_SuperCell_ID::cell_id(sub_calo, pos_neg, 0, outputRegion, outputEta, phi_index);
837 resultCell = returnCellFromCont(resultID, inputContainer, idHelper);
838 }
839 return resultCell;
840}
841
842std::vector<const CaloCell*>
843LVL1::EFexEMClusterTool::L2cluster( const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
844 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh ) const
845{
846 // Forms the central band of cells, spread in phi
847 std::vector<const CaloCell*> centCells;
848 centCells.push_back(centreCell);
849 const CaloCell* upPhiCell = NextPhiCell(centreCell,true,scells,idHelper);
850 const CaloCell* downPhiCell = NextPhiCell(centreCell,false,scells,idHelper);
851 const CaloCell* energeticPhiCell;
852 // Finds the most energetic phi neighbour, defaulting to the 'down' side if they are equal
853 if ( CaloCellET(upPhiCell, digitScale, digitThresh) > CaloCellET(downPhiCell, digitScale, digitThresh)) energeticPhiCell = upPhiCell;
854 else energeticPhiCell = downPhiCell;
855 if (phiWidth == 2) addOnce(energeticPhiCell, centCells); //centCells.push_back(energeticPhiCell);
856 else if (phiWidth == 3){
857 addOnce(upPhiCell, centCells); //centCells.push_back(upPhiCell);
858 addOnce(downPhiCell, centCells); //centCells.push_back(downPhiCell);
859 }
860 else if (phiWidth > 3) {
861 ATH_MSG_DEBUG ( "phiWidth not 2 or 3!!!");
862 }
863 // Forms the main cluster. Starts with each SC in the central band and spreads outward in eta
864 std::vector<const CaloCell*> clusCells;
865 int halfEtaWidth = (etaWidth-1)/2;
866 int backToEta = (2*halfEtaWidth)+1;
867 if (backToEta != etaWidth) {
868 ATH_MSG_DEBUG ( "Eta width doesn't match! " << backToEta << " -> " << halfEtaWidth << " -> " << etaWidth << " " << __LINE__);
869 }
870 for (auto ithCentCell : centCells){
871 addOnce(ithCentCell, clusCells); //clusCells.push_back(ithCentCell);
872 if (etaWidth > 1){
873 const CaloCell* tempRightCell = NextEtaCell(ithCentCell,true,scells,idHelper);
874 const CaloCell* tempLeftCell = NextEtaCell(ithCentCell,false,scells,idHelper);
875 addOnce(tempRightCell, clusCells); //clusCells.push_back(tempRightCell);
876 addOnce(tempLeftCell, clusCells); //clusCells.push_back(tempLeftCell);
877 for (int i = 1; i < halfEtaWidth; i++){
878 tempRightCell = NextEtaCell(tempRightCell,true,scells,idHelper);
879 tempLeftCell = NextEtaCell(tempLeftCell,false,scells,idHelper);
880 addOnce(tempRightCell, clusCells); //clusCells.push_back(tempRightCell);
881 addOnce(tempLeftCell, clusCells); //clusCells.push_back(tempLeftCell);
882 }
883 }
884 }
885 return clusCells;
886}
887
888std::vector<double>
889LVL1::EFexEMClusterTool::EnergyPerTileLayer( const std::vector<const CaloCell*> & inputSCVector, const CaloConstCellContainer* CellCon,
890 const TileID* tileIDHelper, bool isOW, float tileNoiseThresh) const
891{
892 std::vector<double> layerEnergy;
893 if (CellCon==nullptr) return layerEnergy;
894 if (CellCon->size()==0) return layerEnergy;
895 if (inputSCVector.size()==0) return layerEnergy;
896 double ELayer0 = 0, ELayer1 = 0, ELayer2 = 0;
897 std::vector<const TileCell*> tileCellVector;
898 for (auto ithSC : inputSCVector){
899 float ithSCEta = ithSC->eta();
900 float ithSCPhi = ithSC->phi();
901 int matchingCells = 0;
904 for ( ; fCell != lCell; ++fCell){
905 const TileCell* tileCell = static_cast<const TileCell*>(*fCell);
906 if (!tileCell){
907 ATH_MSG_WARNING ( "Failed to cast from CaloCell to TileCell");
908 return layerEnergy;
909 }
910 int layer = tileIDHelper->sample(tileCell->ID());
911 float ithdR = dR(tileCell->eta(), tileCell->phi(), ithSCEta, ithSCPhi);
912 if (layer < 2){
913 float matchingDistance = 0.;
914 if (isOW && (std::abs(ithSCEta) > 1.38 && std::abs(ithSCEta) < 1.42)) matchingDistance = 0.065;
915 else matchingDistance = 0.05;
916 if (ithdR <= matchingDistance){
917 bool isAlreadyThere = false;
918 checkTileCell(tileCell, tileCellVector, isAlreadyThere);
919 if (isAlreadyThere) continue;
920 matchingCells++;
921 if (layer == 0) ELayer0 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
922 if (layer == 1) ELayer1 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
923 }
924 }
925 else if (layer == 2){
926 float matchingDistance = 0.;
927 if (std::abs(ithSCEta) > 0.7 && std::abs(ithSCEta) < 0.8) matchingDistance = 0.05;
928 else if (std::abs(ithSCEta) > 0.9 && std::abs(ithSCEta) < 1.0) matchingDistance = 0.05;
929 else matchingDistance = 0.09;
930 if (ithdR < matchingDistance){
931 bool isAlreadyThere = false;
932 checkTileCell(tileCell, tileCellVector, isAlreadyThere);
933 if (isAlreadyThere) continue;
934 matchingCells++;
935 int tempPos = detRelPos(ithSCEta);
936 // Unknown : tempPos = -1, Right PMT : tempPos = 0, Left PMT : tempPos = 1, Both PMTs : tempPos = 2
937 if (tempPos < 0){
938 ATH_MSG_WARNING ( "Unknown behaviour matching Tile cells to the SC");
939 layerEnergy.clear();
940 return layerEnergy;
941 }
942 else if (tempPos == 0) ELayer2 += tileCellEnergyCalib(tileCell->ene2(), tileCell->eta(), tileNoiseThresh);
943 else if (tempPos == 1) ELayer2 += tileCellEnergyCalib(tileCell->ene1(), tileCell->eta(), tileNoiseThresh);
944 else ELayer2 += tileCellEnergyCalib(tileCell->e(), tileCell->eta(), tileNoiseThresh);
945 }
946 }
947 }
948 if ((matchingCells > 3 && !isOW) || (matchingCells > 3 && isOW && std::abs(ithSCEta) > 1.42) || (matchingCells > 4 && isOW && std::abs(ithSCEta) < 1.42)){
949 ATH_MSG_WARNING ( matchingCells << " matching Tile cells:");
950 ATH_MSG_WARNING ( "Input SC: (eta,phi) = (" << ithSCEta << "," << ithSCPhi << ")");
951 for (auto cell : tileCellVector){
952 ATH_MSG_WARNING ( "Tile cell: (eta,phi) = (" << cell->eta() << "," << cell->phi() << ")" << " dR = " << dR(cell->eta(), cell->phi(), ithSCEta, ithSCPhi) << " layer = " << tileIDHelper->sample(cell->ID()));
953 }
954 layerEnergy.clear();
955 return layerEnergy;
956 }
957 }
958 layerEnergy = {ELayer0, ELayer1, ELayer2};
959 return layerEnergy;
960}
961
962double
964{
965 if (inputTower == nullptr){
966 ATH_MSG_WARNING ( "Tower is nullptr in phi transformation!");
967 return 0.;
968 }
969 else {
970 double phi = inputTower->phi();
971 if (phi > M_PI) phi = phi - 2*M_PI;
972 return phi;
973 }
974}
975
976double
977LVL1::EFexEMClusterTool::dR(double eta1, double phi1, double eta2, double phi2) const
978{
979 double etaDif = eta1 - eta2;
980 double phiDif = std::abs(phi1 - phi2);
981 if (phiDif > M_PI) phiDif = phiDif - (2*M_PI);
982 double result = std::sqrt(pow(etaDif,2)+pow(phiDif,2));
983 return result;
984}
985
988{
989 std::vector<const xAOD::TriggerTower*> matchingTTs;
990 if (TTContainer==nullptr) return nullptr;
991 if (TTContainer->size()==0) return nullptr;
992 if (inputCell==nullptr) return nullptr;
993 for (auto ithTT : *TTContainer){
994 if (ithTT->sampling()==1){
995 float ithTT_eta = ithTT->eta();
996 float ithTT_phi = TT_phi(ithTT);
997 float ithdR = dR(ithTT_eta, ithTT_phi, inputCell->eta(), inputCell->phi());
998 if (ithdR < 0.05) matchingTTs.push_back(ithTT);
999 }
1000 }
1001 if (matchingTTs.size()==1) return matchingTTs[0];
1002 else if (matchingTTs.size()!=0){
1003 ATH_MSG_WARNING ( "More than one matching HCAL TT!!! (Returned Null)");
1004 }
1005 return nullptr;
1006}
1007
1008const CaloCell*
1009LVL1::EFexEMClusterTool::matchingHCAL_LAr(const CaloCell* &inputCell, const CaloConstCellContainer* &SCContainer, const CaloCell_SuperCell_ID* &idHelper) const
1010{
1011 std::vector<const CaloCell*> matchingCells;
1012 if (inputCell==nullptr) return nullptr;
1013 for (auto ithSC : *SCContainer){
1014 Identifier ithID = ithSC->ID();
1015 int ithSub_calo = idHelper->sub_calo(ithID);
1016 if (ithSub_calo == 1){
1017 double ithdR = dR(inputCell->eta(), inputCell->phi(), ithSC->eta(), ithSC->phi());
1018 if (ithdR < 0.05) matchingCells.push_back(ithSC);
1019 }
1020 }
1021
1022 if (matchingCells.size()==1)
1023 return matchingCells[0];
1024
1025
1026 if (matchingCells.size()==0){
1027
1028 ATH_MSG_WARNING ( "No match betweem LAr ECAL SC and LAr HCAL SC!!! Input coords: " << inputCell->eta() << ", " << inputCell->phi());
1029
1030 } else if (matchingCells.size()!=0) {
1031
1032 ATH_MSG_WARNING ( "More than one matching LAr HCAL SC!!! (Returned Null)");
1033 ATH_MSG_WARNING ( "Input cell coords: " << inputCell->eta() << " x " << inputCell->phi());
1034 for (auto ithMatch : matchingCells){
1035 ATH_MSG_WARNING ( " " << ithMatch->eta() << " x " << ithMatch->phi() << ", dR = "
1036 << dR(inputCell->eta(), inputCell->phi(), ithMatch->eta(), ithMatch->phi()));
1037 }
1038 }
1039 return nullptr;
1040}
1041
1042double
1044{
1045 if (inputTower == nullptr){
1046 ATH_MSG_WARNING ( "Tower is nullptr!");
1047 return 0.;
1048 }
1049 else if (inputTower->cpET() < 0.) {
1050 return 0;
1051 } else {
1052 return 500*inputTower->cpET();
1053 }
1054}
1055
1056std::vector<const CaloCell*>
1057LVL1::EFexEMClusterTool::TDR_Clus( const CaloCell* centreCell, int etaWidth, int phiWidth, const CaloConstCellContainer* scells,
1058 const CaloCell_SuperCell_ID* idHelper, float digitScale, float digitThresh ) const
1059{
1060 // Find the L2 cells
1061 std::vector<const CaloCell*> L2cells = L2cluster(centreCell, etaWidth, phiWidth, scells, idHelper, digitScale, digitThresh);
1062 // Forms a vector of the centre L2 cells (to be used to find L0/3 SCs)
1063 std::vector<const CaloCell*> centCells;
1064 centCells.push_back(centreCell);
1065 const CaloCell* upPhiCell = NextPhiCell(centreCell,true,scells,idHelper);
1066 const CaloCell* downPhiCell = NextPhiCell(centreCell,false,scells,idHelper);
1067 const CaloCell* energeticPhiCell;
1068 // If the phi width is 2, the most energetic neighbour is chosen (defaulting to the 'down' side)
1069 // If the phi width is 3, both neighbours are added
1070 if (phiWidth > 1){
1071 if (CaloCellET(upPhiCell, digitScale, digitThresh) > CaloCellET(downPhiCell, digitScale, digitThresh)) energeticPhiCell = upPhiCell;
1072 else energeticPhiCell = downPhiCell;
1073 if (phiWidth == 2) addOnce(energeticPhiCell, centCells); //centCells.push_back(energeticPhiCell);
1074 else if (phiWidth == 3){
1075 addOnce(upPhiCell, centCells); //centCells.push_back(upPhiCell);
1076 addOnce(downPhiCell, centCells); //centCells.push_back(downPhiCell);
1077 }
1078 else if (phiWidth > 3) ATH_MSG_WARNING ( "phiWidth not 2 or 3!!!. Value = " << phiWidth);
1079 }
1080 // The actual cluster is initialised
1081 std::vector<const CaloCell*> fullClus;
1082 // The L1&2 SCs are added that match the full width
1083 for (auto ithL2Cell : L2cells){
1084 fullClus.push_back(ithL2Cell);
1085 fromLayer2toLayer1(scells, ithL2Cell, fullClus, idHelper);
1086 }
1087 // The L0&3 SCs are added that match the central L2 cells
1088 for (auto ithL2CentCell : centCells){
1089 addOnce( fromLayer2toPS( scells, ithL2CentCell, idHelper),fullClus);
1090 addOnce( fromLayer2toLayer3( scells, ithL2CentCell, idHelper),fullClus);
1091 }
1092 return fullClus;
1093}
1094
1095double
1096LVL1::EFexEMClusterTool::sumVectorET(const std::vector<const CaloCell*> &inputVector, float digitScale, float digitThreshold) const
1097{
1098 double TotalET=0.0;
1099 for (auto ithCell : inputVector){
1100 if (ithCell!=nullptr) TotalET += CaloCellET(ithCell, digitScale, digitThreshold);
1101 }
1102 return TotalET;
1103}
1104
1105bool
1106LVL1::EFexEMClusterTool::checkDig(float EM_ET, float digitScale, float digitThresh) const
1107{
1108 if (EM_ET == 0 || digitScale == 0) return true;
1109 else {
1110 int div = EM_ET / digitScale;
1111 if (div * digitScale == EM_ET) return true;
1112 else {
1113 ATH_MSG_WARNING ( "ET = " << EM_ET << ", digitThresh = " << digitThresh << " digitScale = " << digitScale << " div = " << div << " " << " -> div * digitScale");
1114 return false;
1115 }
1116 }
1117}
1118
1119double
1120LVL1::EFexEMClusterTool::HadronicET( const std::vector<const CaloCell*> & inputVector, const CaloConstCellContainer* scells,
1121 const xAOD::TriggerTowerContainer* &TTContainer, const CaloCell_SuperCell_ID* idHelper,
1122 float digitScale, float digitThresh) const
1123{
1124 // Finds the HCAL SCs & TTs matching the input cluster
1125 std::vector<const CaloCell*> HCAL_LAr_vector;
1126 std::vector<const xAOD::TriggerTower*> HCAL_TT_vector;
1127 for (auto ithCell : inputVector){
1128 if (std::abs(ithCell->eta())<1.5){
1129 const xAOD::TriggerTower* tempTT = matchingHCAL_TT(ithCell, TTContainer);
1130 if (tempTT != nullptr) HCAL_TT_vector.push_back(tempTT);
1131 }
1132 else if (std::abs(ithCell->eta())<2.5){
1133 const CaloCell* tempLArHad = matchingHCAL_LAr(ithCell, scells, idHelper);
1134 if (tempLArHad != nullptr) HCAL_LAr_vector.push_back(tempLArHad);
1135 }
1136 }
1137 // Sums the ET in the HCAL
1138 double HadET = 0.;
1139 for (auto ithTT : HCAL_TT_vector) {HadET += TT_ET(ithTT);}
1140 for (auto ithSC : HCAL_LAr_vector) {HadET += CaloCellET(ithSC, digitScale, digitThresh);}
1141 return HadET;
1142}
1143
1144
1148const CaloCell*
1150{
1151 const CaloCell* isCell = cellContainer->findCell(idHelper->CaloCell_SuperCell_ID::calo_cell_hash(inputID));
1152 if (isCell) return isCell;
1153 else return nullptr;
1154}
1155
1156const CaloCell*
1157LVL1::EFexEMClusterTool::NextEtaCell( const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1158 const CaloCell_SuperCell_ID* &idHelper) const
1159{
1160 if (inputCell==nullptr) return nullptr;
1161 Identifier ithID = inputCell->ID();
1162 int ithSub_calo = idHelper->sub_calo(ithID);
1163 int ithPos_neg = idHelper->pos_neg(ithID);
1164 const CaloCell* tempCell = nullptr;
1165 // Only works for LArEM
1166 if (ithSub_calo==0){
1167 // Barrel regions
1168 if (abs(ithPos_neg)==1) tempCell = NextEtaCell_Barrel(inputCell, upwards, cellContainer, idHelper);
1169 // EC OW
1170 else if (abs(ithPos_neg)==2) tempCell = NextEtaCell_OW(inputCell, upwards, cellContainer, idHelper);
1171 // EC IW
1172 else if (abs(ithPos_neg)==3) tempCell = NextEtaCell_IW(inputCell, upwards, cellContainer, idHelper);
1173 // Not barrel or end cap
1174 else {
1175 ATH_MSG_WARNING ( "Layer 2 cell not passed to specific method at" << inputCell->eta() << " , " << inputCell->phi());
1176 return nullptr;
1177 }
1178 return tempCell;
1179 }
1180 // Is FCAL
1181 else {
1182 ATH_MSG_WARNING ( "Next eta cell called for non-EM SC!");
1183 return nullptr;
1184 }
1185}
1186
1187const CaloCell*
1188LVL1::EFexEMClusterTool::NextEtaCell_Barrel(const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1189 const CaloCell_SuperCell_ID* &idHelper) const
1190{
1191 const Identifier ithID = inputCell->ID();
1192 const int ithEta_index = idHelper->eta(ithID);
1193 const int ithPhi_index = idHelper->phi(ithID);
1194 const int ithSampling = idHelper->sampling(ithID);
1195 const int ithSub_calo = idHelper->sub_calo(ithID);
1196 const int ithPos_neg = idHelper->pos_neg(ithID);
1197 const int ithRegion = idHelper->region(ithID);
1198
1199 // Extreme indices of each region
1200 int maxEta_index = 0;
1201 int minEta_index = 0;
1202 if (ithRegion==0){
1203 if (ithSampling == 0) maxEta_index = 14;
1204 else if (ithSampling == 1 || ithSampling == 2) maxEta_index = 55;
1205 else if (ithSampling == 3) maxEta_index = 13;
1206 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1207 }
1208 else if (ithRegion==1){
1209 if (ithSampling == 1) maxEta_index =2;
1210 else if (ithSampling == 2) maxEta_index=0;
1211 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1212 }
1213 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1214 // Declare next values, default initialisation is the same as cell
1215 int nextEta_index = ithEta_index;
1216 // Phi shouldn't change!
1217 // One special case where sampling does change, otherwise stays same
1218 int nextSampling = ithSampling;
1219 int nextSub_calo = ithSub_calo;
1220 int nextPos_neg = ithPos_neg;
1221 int nextRegion = ithRegion;
1222
1223 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1224 int incrementEta;
1225 if (upwards) incrementEta = ithPos_neg;
1226 else incrementEta = -1*ithPos_neg;
1227
1228 int tracker = 0;
1229
1230 // If first cell in region & moving more inwards
1231 if (ithEta_index==minEta_index && incrementEta==-1){
1232 if (ithRegion == 0){
1233 nextEta_index = 0;
1234 nextPos_neg = ithPos_neg * -1;
1235 tracker = 1;
1236 }
1237 else if (ithRegion == 1){
1238 nextEta_index = 55;
1239 nextRegion = 0;
1240 tracker = 2;
1241 }
1242 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1243 }
1244
1245 // If last cell in region & moving outwards
1246 else if ((ithEta_index == maxEta_index) && (incrementEta == 1)) {
1247 // Reg 0, Layers 1 & 2 go to barrel region 1
1248 if ((ithRegion == 0)&&(ithSampling == 1 || ithSampling == 2)){
1249 nextRegion = 1;
1250 nextEta_index = 0;
1251 tracker = 3;
1252 }
1253 // Reg 0, Layer 0 goes to OW region 0
1254 else if ((ithRegion == 0)&&(ithSampling == 0)){
1255 nextEta_index = 0;
1256 nextRegion = 0;
1257 nextPos_neg = 2*ithPos_neg;
1258 tracker = 4;
1259 }
1260 // Reg 0, Layer 3 goes to OW Layer 2 region 0 (change by ATW)
1261 else if ((ithRegion == 0)&&(ithSampling == 3)){
1262 nextSampling = 2;
1263 nextEta_index = 0;
1264 nextRegion = 0;
1265 nextPos_neg = 2*ithPos_neg;
1266 tracker = 5;
1267 }
1268 // Reg 1, Layer 1 go to OW region 0 (change by ATW)
1269 else if ((ithRegion == 1)&&(ithSampling == 1)){
1270 nextEta_index=0;
1271 nextRegion = 0;
1272 nextPos_neg = 2 * ithPos_neg;
1273 tracker = 6;
1274 }
1275 // Reg 1, Layer 2 goes to OW region 1
1276 else if ((ithRegion == 1)&&(ithSampling == 2)){
1277 nextEta_index=0;
1278 nextRegion = 1;
1279 nextPos_neg = 2 * ithPos_neg;
1280 tracker = 7;
1281 }
1282 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1283 }
1284 // Otherwise 'simply' next cell along
1285 else {
1286 nextEta_index = ithEta_index + incrementEta;
1287 tracker = 8;
1288 }
1289 //ATH_MSG_DEBUG ( "B Tracker = " << tracker);
1290 // Form identifier, find cell & return it
1291 // sub_calo, left_pos_neg, 2, region, eta_index, down_phi_index
1292 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, nextSampling, nextRegion, nextEta_index, ithPhi_index);
1293 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1294 if (nextCell == nullptr) {
1295 ATH_MSG_DEBUG ( "ISSUE: " << __LINE__);
1296 ATH_MSG_DEBUG ( "Barrel Tracker = " << tracker);
1297 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);
1298 }
1299 else {
1300 Identifier newID = nextCell->ID();
1301 int IDsample = idHelper->sampling(nextCell->ID());
1303 if (IDsample!=ithSampling){
1304 ATH_MSG_DEBUG ( "Layer has changed " << " tracker = " << tracker);
1305 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);
1306 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);
1307 ATH_MSG_DEBUG ( "comp indices: "<< (nextCellID == newID));
1308 }
1309 }
1310 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__ << " does not match");
1311 return nextCell;
1312}
1313
1314const CaloCell*
1315LVL1::EFexEMClusterTool::NextEtaCell_OW( const CaloCell*inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1316 const CaloCell_SuperCell_ID* &idHelper) const
1317{
1318 Identifier ithID = inputCell->ID();
1319 int ithEta_index = idHelper->eta(ithID);
1320 const int ithPhi_index = idHelper->phi(ithID);
1321 const int ithSampling = idHelper->sampling(ithID);
1322 int ithSub_calo = idHelper->sub_calo(ithID);
1323 int ithPos_neg = idHelper->pos_neg(ithID);
1324 int ithRegion = idHelper->region(ithID);
1325 // Declare next values, default initialisation is the same as cell
1326 int nextEta_index = ithEta_index;
1327 int nextPhi_index = ithPhi_index;
1328 // Sampling may change in a couple of special cases (transition tower)
1329 int nextSampling = ithSampling;
1330 int nextSub_calo = ithSub_calo;
1331 int nextPos_neg = ithPos_neg;
1332 int nextRegion = ithRegion;
1333 // Maximum indices for barrel region 0:
1334 int maxEta_index = 0;
1335 int minEta_index = 0;
1336 // Set max / min values based on ithRegion
1337 if (ithSampling==0) maxEta_index = 2;
1338 else if (ithSampling==2 && ithRegion==0) maxEta_index = 0;
1339 else if (ithSampling==2 && ithRegion==1) maxEta_index = 42;
1340 else if (ithSampling==3) maxEta_index=9;
1341 else if (ithSampling==1) {
1342 switch(ithRegion){
1343 case 0:
1344 maxEta_index=0;
1345 break;
1346 case 1:
1347 ATH_MSG_DEBUG ( "ISSUE " << __LINE__);
1348 break;
1349 case 2:
1350 maxEta_index=11;
1351 break;
1352 case 3:
1353 maxEta_index=11;// Should this be 11? - it was 7
1354 break;
1355 case 4:
1356 maxEta_index=15;
1357 break;
1358 case 5:
1359 maxEta_index=0;
1360 break;
1361 default:
1362 ATH_MSG_WARNING ( "OW region is not covered: " << ithRegion);
1363 }
1364 }
1365 else ATH_MSG_DEBUG ( "ISSUE: " << __LINE__ );
1366
1367 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1368 int incrementEta = upwards ? 1 : -1;
1369
1370 int ithSide{};
1371 if (auto denom = std::abs(ithPos_neg); denom!=0){
1372 ithSide = ithPos_neg / denom;
1373 }
1374 incrementEta *= ithSide;
1375 int tracker = 0;
1376 // Lower end of OW, going inwards
1377 if (ithEta_index==minEta_index && ithRegion==0 && incrementEta==-1){
1378 nextPos_neg = ithSide;
1379 if (ithSampling==0){
1380 nextRegion = 0;
1381 nextEta_index = 14;
1382 tracker = 1;
1383 }
1384 else if (ithSampling==1){
1385 nextRegion = 1;
1386 nextEta_index = 2;
1387 tracker = 2;
1388 }
1390 else if (ithSampling==2){
1391 nextRegion = 0;
1392 nextSampling = 2;
1393 nextEta_index = 13;
1394 tracker = 3;
1395 }
1397 else if (ithSampling==3){
1398 nextRegion = 0;
1399 nextSampling = 2;
1400 nextEta_index = 0;
1401 nextPos_neg = ithPos_neg;
1402 tracker = 4;
1403 }
1404 }
1405 // Higher end of OW, going outwards
1406 else if (ithEta_index==maxEta_index && incrementEta==1){
1407 // Layers 0 & 3 aren't in IW
1408 if (ithSampling==0 || ithSampling==3) return nullptr;
1409 else if (ithSampling==2 && ithRegion==0){
1410 nextRegion = 1;
1411 nextEta_index = 0;
1412 tracker = 5;
1413 }
1414 else if ((ithSampling==2 && ithRegion==1)||(ithSampling==1 && ithRegion==5)){
1415 // Reaches IW
1416 nextEta_index=0;
1417 nextRegion=0;
1418 nextPhi_index=ithPhi_index/2;
1419 nextPos_neg=3*ithSide;
1420 tracker=6;
1421 }
1422 else if (ithSampling==1 && ithRegion==0){
1423 // Unsure what to do??
1424 nextRegion = 2;
1425 nextEta_index = 0;
1426 tracker = 7;
1427 }
1428 else if (ithSampling==1){
1429 nextRegion=ithRegion + 1;
1430 nextEta_index=0;
1431 tracker = 8;
1432 }
1433 }
1434 // Lower end of region in OW, going inwards
1435 else if (ithEta_index==minEta_index && incrementEta==-1){
1436 // Shouldn't apply to layers 0 & 3
1437 // Only case for layer 2 should be in region 1
1438 // But this one is special because we want to step into barrel (ATW)
1439 if (ithSampling==2){
1440 nextRegion = 1;
1441 nextEta_index = 0;
1442 nextPos_neg = ithPos_neg;
1443 tracker = 9;
1444 }
1445 else if (ithSampling==1){
1446 tracker = 11;
1447 // Layer one has muliple regions
1448 nextRegion = ithRegion-1;
1449 if (nextRegion==0) {
1450 nextEta_index=0;
1451 ATH_MSG_DEBUG ( "ISSUE: "<< __LINE__);
1452 }
1453 else if (nextRegion==1) {
1454 nextRegion = 0;
1455 nextEta_index= 0;
1456 }
1457 else if (nextRegion==2) nextEta_index=11;
1458 else if (nextRegion==3) nextEta_index=7;
1459 else if (nextRegion==4) nextEta_index=15;
1460 }
1461 }
1462 // Middle of region in middle of endcap
1463 else {
1464 nextEta_index = ithEta_index+incrementEta;
1465 tracker = 12;
1466 }
1467 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, nextSampling, nextRegion, nextEta_index, nextPhi_index);
1468 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1469 if (nextCell == nullptr) {
1470 ATH_MSG_DEBUG ( "ISSUE: "<<__LINE__);
1471 ATH_MSG_DEBUG ( "OW Tracker = "<<tracker);
1472 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);
1473 ATH_MSG_DEBUG ( "Increment eta = "<<incrementEta<<", max_eta = "<<maxEta_index<<", min_eta = "<<minEta_index);
1474 }
1475 else {
1476 Identifier newID = nextCell->ID();
1477 int IDsample = idHelper->sampling(nextCell->ID());
1478 if (IDsample!=ithSampling){
1479 ATH_MSG_DEBUG ( "Layer has changed "<<" tracker = "<<tracker);
1480 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);
1481 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);
1482 ATH_MSG_DEBUG ( "comp indices: "<<(nextCellID == newID));
1483 }
1484 }
1485 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__<< " does not match");
1486 return nextCell;
1487}
1488
1489const CaloCell*
1490LVL1::EFexEMClusterTool::NextEtaCell_IW( const CaloCell* inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1491 const CaloCell_SuperCell_ID* &idHelper) const
1492{
1493 const Identifier ithID = inputCell->ID();
1494 const int ithEta_index = idHelper->eta(ithID);
1495 const int ithPhi_index = idHelper->phi(ithID);
1496 const int ithSampling = idHelper->sampling(ithID);
1497 const int ithSub_calo = idHelper->sub_calo(ithID);
1498 const int ithPos_neg = idHelper->pos_neg(ithID);
1499 const int ithRegion = idHelper->region(ithID);
1500 //int tracker =0;
1501 // Declare next values, default initialisation is the same as cell
1502 int nextEta_index = ithEta_index;
1503 int nextPhi_index = ithPhi_index;
1504 // Sampling shouldn't change!
1505 int nextSub_calo = ithSub_calo;
1506 int nextPos_neg = ithPos_neg;
1507 int nextRegion = ithRegion;
1508
1509 // Maximum indices for barrel region 0:
1510 int maxEta_index = 0;
1511 int minEta_index = 0;
1512
1513 if (ithRegion==0){
1514 maxEta_index=2;
1515 minEta_index=0;
1516 }
1517 else if (ithRegion!=1) ATH_MSG_DEBUG ( "ISSUE: " <<__LINE__);
1518
1519 // Calculate the increment for eta: it depends on whether we are moving 'up' & which side we are on
1520 int incrementEta{};
1521 int ithSide{};
1522 if (ithPos_neg != 0){
1523 ithSide = ithPos_neg / std::abs(ithPos_neg);
1524 }
1525 if (upwards) incrementEta = ithSide;
1526 else incrementEta = ithSide * -1;
1527 // Lower end of region IW, going inwards
1528 if (ithEta_index==minEta_index&& incrementEta==-1){
1529 // Goes to OW
1530 if (ithRegion == 0){
1531 nextPos_neg = 2*ithSide;
1532 nextPhi_index=2*ithPhi_index;
1533 if (ithSampling==1){
1534 // tracker=1;
1535 nextRegion=5;
1536 nextEta_index=0;
1537 }
1538 else if (ithSampling==2){
1539 // tracker=2;
1540 nextRegion=1;
1541 nextEta_index=42;
1542 }
1543 else ATH_MSG_DEBUG ( "ISSUE: " <<__LINE__);
1544 }
1545 // Goes to IW region 0
1546 else if (ithRegion == 1){
1547 // tracker=3;
1548 nextRegion=0;
1549 nextEta_index=2;
1550 }
1551 }
1552 // Upper end of region in IW
1553 else if (ithEta_index==maxEta_index && incrementEta==1){
1554 // Goes to region 1
1555 if (ithRegion==0){
1556 // tracker=4;
1557 nextRegion=1;
1558 nextEta_index=0;
1559 }
1560 // Reaches FCAL
1561 else if (ithRegion==1) return nullptr;
1562 }
1563 // Increment eta like normal
1564 else {
1565 // tracker=5;
1566 nextEta_index=ithEta_index+incrementEta;
1567 }
1568 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(nextSub_calo, nextPos_neg, ithSampling, nextRegion, nextEta_index, nextPhi_index);
1569 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1570 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__<<" does not match");
1571 return nextCell;
1572}
1573
1574int
1575LVL1::EFexEMClusterTool::restrictPhiIndex(int input_index, bool is64) const
1576{
1577 if (is64&&input_index<0) return input_index+64;
1578 else if (is64&&input_index>63) return input_index-64;
1579 else if (!(is64)&&input_index<0) return input_index+32;
1580 else if (!(is64)&&input_index>31) return input_index-32;
1581 else return input_index;
1582}
1583
1584const CaloCell*
1585LVL1::EFexEMClusterTool::NextPhiCell( const CaloCell * inputCell, bool upwards, const CaloConstCellContainer* &cellContainer,
1586 const CaloCell_SuperCell_ID* &idHelper) const
1587{
1588 if (inputCell==nullptr)
1589 return nullptr;
1590
1591 const Identifier ithID = inputCell->ID();
1592 const int ithEta_index = idHelper->eta(ithID);
1593 const int ithPhi_index = idHelper->phi(ithID);
1594 const int ithSampling = idHelper->sampling(ithID);
1595 const int ithSub_calo = idHelper->sub_calo(ithID);
1596 const int ithPos_neg = idHelper->pos_neg(ithID);
1597 const int ithRegion = idHelper->region(ithID);
1598
1599 bool is64;
1600 if (abs(ithPos_neg)==3) is64 = false;
1601 else is64 = true;
1602
1603 int incrementPhi;
1604 if (upwards==true) incrementPhi=1;
1605 else incrementPhi=-1;
1606
1607 const int nextPhi_index = restrictPhiIndex(ithPhi_index+incrementPhi, is64);
1608 Identifier nextCellID = idHelper->CaloCell_SuperCell_ID::cell_id(ithSub_calo, ithPos_neg, ithSampling, ithRegion, ithEta_index, nextPhi_index);
1609 const CaloCell* nextCell = returnCellFromCont(nextCellID, cellContainer, idHelper);
1610 if (nextCell && (nextCell->ID() != nextCellID)) ATH_MSG_DEBUG ( __LINE__ << " does not match");
1611 if (nextCell == nullptr) ATH_MSG_DEBUG ( "Next phi cell is nullptr at " << __LINE__);
1612 return nextCell;
1613}
#define M_PI
Scalar phi() const
phi method
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(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.