ATLAS Offline Software
Loading...
Searching...
No Matches
CaloClusterKineHelper.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef SIMULATIONBASE
6#ifndef XAOD_ANALYSIS
7
9#include "CaloGeoHelpers/CaloSampling.h"
14
15#include <cmath>
16#include <limits>
17
18namespace {
19
20
21// This is factored out in order to allow instantiating the cell loop
22// in versions that both use and do not use cell weights. In the no-weights
23// case, the weight is a compile-time constant of 1, so all operations
24// involving it will be optimized away.
25
26
27struct CellAccum
28{
29 CellAccum (double& the_posNorm,
30 std::array<double,CaloSampling::Unknown>& the_posSamNorm,
31 int& the_nBarrel,
32 int& the_nEndcap,
33 double& the_timeNorm,
34 const bool useGPUCriteria = false)
35 : EnergyInSample(),
36 // NCellsInSample(), // will be collected in moment maker
37 EtaInSample(),
38 PhiInSample(),
39 MaxEnergyInSample(),
40 EtaMaxEnergyInSample(),
41 PhiMaxEnergyInSample(),
42 PresenceInSample(),
43 theNewEnergy(0),
44 theNewTime(0),
45 theNewSecondTime(0),
46 theNewEta(0),
47 theNewPhi(0),
48 phi0(-999),
49 maxCell(-1),
50 posNorm (the_posNorm),
51 posSamNorm (the_posSamNorm),
52 nBarrel (the_nBarrel),
53 nEndcap (the_nEndcap),
54 timeNorm (the_timeNorm)
55 {
56 if (useGPUCriteria) {
57 for (size_t i = 0; i < (size_t) CaloSampling::Unknown; ++i) {
58 MaxEnergyInSample[i] = std::numeric_limits<double>::lowest();
59 }
60 }
61 }
62 double EnergyInSample[CaloSampling::Unknown];
63 // int NCellsInSample[CaloSampling::Unknown];
64 double EtaInSample[CaloSampling::Unknown];
65 double PhiInSample[CaloSampling::Unknown];
66 double MaxEnergyInSample[CaloSampling::Unknown];
67 double EtaMaxEnergyInSample[CaloSampling::Unknown];
68 double PhiMaxEnergyInSample[CaloSampling::Unknown];
69 bool PresenceInSample[CaloSampling::Unknown];
70 double theNewEnergy;
71 double theNewTime;
72 double theNewSecondTime;
73 double theNewEta;
74 double theNewPhi;
75 double phi0;
76 int maxCell;
77
78 double& posNorm;
79 std::array<double,CaloSampling::Unknown>& posSamNorm;
80 int& nBarrel;
81 int& nEndcap;
82 double& timeNorm;
83};
84
85
86struct AccumWeight {
87 double operator() (const CaloClusterCellLink::const_iterator& it) const {return it.weight();}
88};
89
90
91struct AccumNoWeight
92{
93 double operator() (const CaloClusterCellLink::const_iterator&) const { return 1; }
94};
95
96
97
98 //FIXME: Compute layer values only if requested
99 //FIXME: The template-base optimizaiton might be unnecessary b/c getting the weight of cell is now CPU-cheap
100template <class WEIGHT>
101inline
102void accumCell (const CaloClusterCellLink::const_iterator& cellIt, CellAccum& accum, const WEIGHT& w, const bool useGPUCriteria = false)
103{
104 const CaloCell& cell=**cellIt;
105 const CaloDetDescrElement* dde = cell.caloDDE();
106 if (!dde) return;
107 double weight = w (cellIt);
108 double fabsweight = fabs (weight);
109
110 double theEnergyNoWeight = cell.e();
111 double theEnergy = weight * theEnergyNoWeight;
112 // weight might be negative for removing cells
113 // therefore the AbsEnergy can be negative ...
114 double theAbsEnergy = weight * fabs(theEnergyNoWeight);
115
116 CaloSampling::CaloSample sam = cell.caloDDE()->getSampling();
117 accum.PresenceInSample[sam] = true;
118 double cellEta = dde->eta();
119 double cellPhi = dde->phi();
120
121 accum.EnergyInSample[sam] += theEnergy;
122 accum.theNewEnergy += theEnergy;
123 // accum.NCellsInSample[sam] += 1;
124 double thePhi;
125 if (accum.phi0 < -900) {
126 thePhi = accum.phi0 = cellPhi;
127 }
128 else
129 thePhi = proxim (cellPhi, accum.phi0);
130
131 accum.theNewEta += theAbsEnergy * cellEta;
132 accum.theNewPhi += theAbsEnergy * thePhi;
133 if (useGPUCriteria) {
134 if ( accum.MaxEnergyInSample[sam] < theEnergy || (accum.MaxEnergyInSample[sam] == theEnergy && accum.maxCell < (int) cellIt.index()) ) {
135 accum.MaxEnergyInSample[sam] = theEnergy;
136 accum.EtaMaxEnergyInSample[sam] = cellEta;
137 accum.PhiMaxEnergyInSample[sam] = cellPhi;
138 accum.maxCell = (int) cellIt.index();
139 }
140 }
141 else {
142 if ( accum.MaxEnergyInSample[sam] < theEnergy ) {
143 accum.MaxEnergyInSample[sam] = theEnergy;
144 accum.EtaMaxEnergyInSample[sam] = cellEta;
145 accum.PhiMaxEnergyInSample[sam] = cellPhi;
146 }
147 }
148
149 accum.posSamNorm[sam] += theAbsEnergy;
150 accum.posNorm += theAbsEnergy;
151
152 accum.EtaInSample[sam] += theAbsEnergy * cellEta;
153 accum.PhiInSample[sam] += theAbsEnergy * thePhi;
154
155 if ( theEnergy != 0 && weight != 0)
156 {
157 // count cells in endcap
158 switch(sam) {
159 case CaloSampling::PreSamplerE:
160 case CaloSampling::EME1:
161 case CaloSampling::EME2:
162 case CaloSampling::EME3:
163 case CaloSampling::HEC0:
164 case CaloSampling::HEC1:
165 case CaloSampling::HEC2:
166 case CaloSampling::HEC3:
167 case CaloSampling::FCAL0:
168 case CaloSampling::FCAL1:
169 case CaloSampling::FCAL2:
170 case CaloSampling::MINIFCAL0:
171 case CaloSampling::MINIFCAL1:
172 case CaloSampling::MINIFCAL2:
173 case CaloSampling::MINIFCAL3:
174 accum.nEndcap++;
175 break;
176 //Everything else is barrel
177 default:
178 accum.nBarrel++;
179 break;
180 }
181
182 if (sam != CaloSampling::PreSamplerB &&
183 sam != CaloSampling::PreSamplerE)
184 {
185 unsigned int pmask = dde->is_tile() ? 0x8080 : 0x2000;
186
187 // Is time defined?
188 if ( cell.provenance() & pmask ) {
189 // keep the sign of weight for the time norm in case a cell is removed
190 double theTimeNorm = fabsweight * theEnergy * theEnergyNoWeight;
191 accum.theNewTime += theTimeNorm * cell.time();
192 accum.theNewSecondTime += theTimeNorm * cell.time() * cell.time();
193 accum.timeNorm += theTimeNorm;
194 }
195 }
196 }
197}
198
199
200template <class WEIGHT>
201inline
202void accumCells (const CaloClusterCellLink* cccl, CellAccum& accum, const WEIGHT& w, const bool useGPUCriteria = false) {
203
204
207
208 for (;it!=it_e;++it)
210
211 //Reset start iterator
212 it=cccl->begin();
213 for (;it!=it_e;++it) {
214 CaloPrefetch::nextDDE(it, it_e);
215 accumCell(it,accum,w, useGPUCriteria);
216 }
217
218}
219
220}//end namespace
221
222
223void CaloClusterKineHelper::calculateKine(xAOD::CaloCluster* clu, const bool useweight, const bool updateLayers, const bool useGPUCriteria) {
224 //static CaloPhiRange range;
225
226 // update global kinematics
227 //
228 // for the update of the position the normalization is not a trival
229 // thing. The previous implementation used the sum of weighted
230 // energies as normalization. This leads to unphysical eta and phi
231 // values in case negative energies are added in. The new algorithm
232 // takes therefore |E| instead of E which gives the same eta and phi
233 // as before for the 2 cases where all cells are negative or all
234 // cells are positive. In the mixed case it will give the direction
235 // of activity in the calorimeter.
236
237 const CaloClusterCellLink* cccl=clu->getCellLinks();
238 if (!cccl || cccl->size()==0) return; //Do nothing if no cells
239
240 double posNorm = 0;
241 int nBarrel = 0;
242 int nEndcap = 0;
243 double timeNorm = 0.;
244
245 std::array<double,CaloSampling::Unknown> posSamNorm{};
246
247 CellAccum accum (posNorm, posSamNorm, nBarrel, nEndcap, timeNorm, useGPUCriteria);
248 //accum.theNewPhi = clu->phi(); //????
249 if (useweight)
250 accumCells (cccl, accum, AccumWeight(), useGPUCriteria);
251 else
252 accumCells (cccl, accum, AccumNoWeight(), useGPUCriteria);
253
254 if ( posNorm != 0. ) {
255 double inorm = 1 / posNorm;
256 clu->setEta(accum.theNewEta * inorm);
257 clu->setPhi(CaloPhiRange::fix(accum.theNewPhi * inorm));
258 }
259 else {
260 clu->setEta(0);
261 clu->setPhi(0);
262 }
263
264 clu->setE(accum.theNewEnergy);
265 clu->setM(0.0);
266
267 if ( timeNorm != 0. ) {
268 clu->setTime(accum.theNewTime/timeNorm);
269 // note that standard deviation of cell time distribution is >= 0.
270 // (no particular accommodation for <x^2> < <x><x>!)
271 // clu->setSecondTime(std::sqrt(std::max(accum.theNewSecondTime/timeNorm-clu->time()*clu->time(),0.)));
272 // consistency with other second moments: store variance!
273 clu->setSecondTime(accum.theNewSecondTime/timeNorm-clu->time()*clu->time());
274 } else {
275 clu->setTime(0.);
276 clu->setSecondTime(0.);
277 }
278
279
280 //Set Sampling pattern:
281 uint32_t samplingPattern=0;
282 for(int i=0;i<(int)CaloSampling::Unknown;i++) {
283 if (accum.PresenceInSample[i])
284 samplingPattern |= (0x1U<<i);
285 }
286 if (samplingPattern!=clu->samplingPattern()) {
287 //Clear sampling data (if there is any): Invalidated if the sampling pattern has changed
288 clu->clearSamplingData();
289 clu->setSamplingPattern(samplingPattern);
290 }
291
293 // Check Sampling Variable Updates //
295
296 if ( !updateLayers ) return;
297
298 //First loop over samplings
299 for(int i=0;i<(int)CaloSampling::Unknown;i++) {
300 if ( !accum.PresenceInSample[i] ) continue; // check sampling bit
301 if ( posSamNorm[i] != 0 ) {
302 const double inorm = 1 / posSamNorm[i];
303 accum.EtaInSample[i] *= inorm;
304 accum.PhiInSample[i] = CaloPhiRange::fix (accum.PhiInSample[i] * inorm);
305 }
306 }//End loop over sampling
307
308 //Second loop over samplings
309 //Set(Engery/Eta/Phi) methods only allowed once m_samplingPattern is final!
310 for(int i=0;i<(int)CaloSampling::Unknown;i++) {
311 if ( !accum.PresenceInSample[i] ) continue;
312 // check sampling bit
314 clu->setEnergy(sam,accum.EnergyInSample[i]);
315 // clu->setNCellsPerSampling(sam, accum.NCellsInSample[i]);
316 clu->setEta(sam,accum.EtaInSample[i]);
317 clu->setPhi(sam,accum.PhiInSample[i]);
318
319 clu->setEmax(sam,accum.MaxEnergyInSample[i]);
320 clu->setEtamax(sam,accum.EtaMaxEnergyInSample[i]);
321 clu->setPhimax(sam,accum.PhiMaxEnergyInSample[i]);
322 }
323
324 }
325
326#endif //not XAOD_ANALYSIS
327#endif //not SIMULATIONBASE
328
CaloPhiRange class declaration.
#define maxCell
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
static void calculateKine(xAOD::CaloCluster *clu, const bool useweight=true, const bool updateLayers=true, const bool useGPUCriteria=false)
Helper class to calculate cluster kinematics based on cells.
This class groups all DetDescr information related to a CaloCell.
static double fix(double phi)
void setSecondTime(flt_t stime)
Set second moment of cell timing distribution.
bool setPhi(const CaloSample sampling, const float phi)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version)
flt_t time() const
Access cluster time.
void setTime(flt_t)
Set cluster time.
bool setPhimax(const CaloSample sampling, const float phiMax)
Set the phi of the cell with the highest energy in a particular sampling.
bool setEta(const CaloSample sampling, const float eta)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
bool setEmax(const CaloSample sampling, const float eMax)
Set the Energy of the cell with the highest energy in a particular sampling.
bool setEnergy(const CaloSample sampling, const float e)
Set energy for a given sampling. Returns false if the sample isn't part of the cluster.
void setSamplingPattern(const unsigned sp, const bool clearSamplingVars=false)
Set sampling pattern (one bit per sampling.
bool setEtamax(const CaloSample sampling, const float etaMax)
Set the eta of the cell with the highest energy in a particular sampling.
void clearSamplingData()
Clear the sampling data.
unsigned samplingPattern() const
Access to sampling pattern (one bit per sampling) (Method may be removed later)
void setM(flt_t)
Set Mass for the current signal state.
void nextDDE(Iter iter, Iter endIter)
Prefetch next CaloDDE.
void prefetchObj(const T *ptr)
Generic prefetch of the object of specific types (sizes).
Definition prefetch.h:108
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
double proxim(double b, double a)
Definition proxim.h:17