ATLAS Offline Software
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"
11 #include "CaloGeoHelpers/proxim.h"
13 #include "CaloEvent/CaloPrefetch.h"
14 
15 #include <cmath>
16 #include <limits>
17 
18 namespace {
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 
27 struct 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 
86 struct AccumWeight {
87  double operator() (const CaloClusterCellLink::const_iterator& it) const {return it.weight();}
88 };
89 
90 
91 struct 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
100 template <class WEIGHT>
101 inline
102 void 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) {
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 &&
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 
200 template <class WEIGHT>
201 inline
202 void 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 
223 void 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 
CaloClusterKineHelper.h
xAOD::CaloCluster_v1::time
flt_t time() const
Access cluster time.
GetLCDefs::Unknown
@ Unknown
Definition: GetLCDefs.h:21
CaloPrefetch.h
ReadCellNoiseFromCool.cell
cell
Definition: ReadCellNoiseFromCool.py:53
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
InDetAccessor::phi0
@ phi0
Definition: InDetAccessor.h:33
xAOD::CaloCluster_v1::clearSamplingData
void clearSamplingData()
Clear the sampling data.
Definition: CaloCluster_v1.cxx:717
CaloDetDescrElement
This class groups all DetDescr information related to a CaloCell. Provides a generic interface for al...
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:66
proxim
double proxim(double b, double a)
Definition: proxim.h:17
skel.it
it
Definition: skel.GENtoEVGEN.py:423
CaloCell_ID_FCS::FCAL1
@ FCAL1
Definition: FastCaloSim_CaloCell_ID.h:41
CaloCell_ID_FCS::HEC2
@ HEC2
Definition: FastCaloSim_CaloCell_ID.h:29
xAOD::CaloCluster_v1::setSamplingPattern
void setSamplingPattern(const unsigned sp, const bool clearSamplingVars=false)
Set sampling pattern (one bit per sampling.
Definition: CaloCluster_v1.cxx:81
xAOD::CaloCluster_v1::setEnergy
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.
Definition: CaloCluster_v1.cxx:526
xAOD::CaloCluster_v1::setTime
void setTime(flt_t)
Set cluster time.
xAOD::CaloCluster_v1::setEmax
bool setEmax(const CaloSample sampling, const float eMax)
Set the Energy of the cell with the highest energy in a particular sampling.
Definition: CaloCluster_v1.cxx:571
dqt_zlumi_pandas.weight
int weight
Definition: dqt_zlumi_pandas.py:200
xAOD::CaloCluster_v1::setSecondTime
void setSecondTime(flt_t stime)
Set second moment of cell timing distribution.
Definition: CaloCluster_v1.cxx:985
proxim.h
xAOD::CaloCluster_v1::setE
void setE(flt_t)
Definition: CaloCluster_v1.cxx:375
xAOD::CaloCluster_v1::setPhimax
bool setPhimax(const CaloSample sampling, const float phiMax)
Set the phi of the cell with the highest energy in a particular sampling.
Definition: CaloCluster_v1.cxx:597
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
CaloCell_ID_FCS::HEC1
@ HEC1
Definition: FastCaloSim_CaloCell_ID.h:28
lumiFormat.i
int i
Definition: lumiFormat.py:92
CaloSampling::CaloSample
CaloSample
Definition: Calorimeter/CaloGeoHelpers/CaloGeoHelpers/CaloSampling.h:22
constants.EME1
int EME1
Definition: Calorimeter/CaloClusterCorrection/python/constants.py:55
CaloPhiRange.h
CaloPhiRange class declaration.
PowhegPythia8EvtGen_jetjet.theEnergy
int theEnergy
Definition: PowhegPythia8EvtGen_jetjet.py:12
CaloPhiRange::fix
static double fix(double phi)
Definition: CaloPhiRange.cxx:14
xAOD::CaloCluster_v1::getCellLinks
const CaloClusterCellLink * getCellLinks() const
Get a pointer to the CaloClusterCellLink object (const version)
Definition: CaloCluster_v1.cxx:905
CaloDetDescrElement::is_tile
bool is_tile() const
cell belongs to Tile
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:442
CaloCell_ID_FCS::EME3
@ EME3
Definition: FastCaloSim_CaloCell_ID.h:26
CaloCell_ID_FCS::HEC0
@ HEC0
Definition: FastCaloSim_CaloCell_ID.h:27
CxxUtils::prefetchObj
void prefetchObj(const T *ptr)
Generic prefetch of the object of specific types (sizes).
Definition: prefetch.h:108
CaloCell
Data object for each calorimeter readout cell.
Definition: CaloCell.h:57
CaloCell_ID_FCS::PreSamplerE
@ PreSamplerE
Definition: FastCaloSim_CaloCell_ID.h:23
CaloCell_ID_FCS::PreSamplerB
@ PreSamplerB
Definition: FastCaloSim_CaloCell_ID.h:19
xAOD::CaloCluster_v1::setPhi
bool setPhi(const CaloSample sampling, const float phi)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
Definition: CaloCluster_v1.cxx:556
CaloClusterKineHelper::calculateKine
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.
Definition: CaloClusterKineHelper.cxx:223
xAOD::CaloCluster_v1::setEtamax
bool setEtamax(const CaloSample sampling, const float etaMax)
Set the eta of the cell with the highest energy in a particular sampling.
Definition: CaloCluster_v1.cxx:584
CaloCell_ID_FCS::FCAL2
@ FCAL2
Definition: FastCaloSim_CaloCell_ID.h:42
CaloDetDescrElement::eta
float eta() const
cell eta
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:344
CaloDetDescrElement::phi
float phi() const
cell phi
Definition: Calorimeter/CaloDetDescr/CaloDetDescr/CaloDetDescrElement.h:346
xAOD::CaloCluster_v1::setEta
bool setEta(const CaloSample sampling, const float eta)
Set in a given sampling. Returns false if the sample isn't part of the cluster.
Definition: CaloCluster_v1.cxx:541
python.IoTestsLib.w
def w
Definition: IoTestsLib.py:200
CaloCell_ID_FCS::HEC3
@ HEC3
Definition: FastCaloSim_CaloCell_ID.h:30
xAOD::CaloCluster_v1::samplingPattern
unsigned samplingPattern() const
Access to sampling pattern (one bit per sampling) (Method may be removed later)
Definition: CaloCluster_v1.h:864
CaloCell_ID_FCS::FCAL0
@ FCAL0
Definition: FastCaloSim_CaloCell_ID.h:40
maxCell
#define maxCell
CaloPrefetch::nextDDE
void nextDDE(Iter iter, Iter endIter)
Prefetch next CaloDDE.
Definition: CaloPrefetch.h:47
constants.EME2
int EME2
Definition: Calorimeter/CaloClusterCorrection/python/constants.py:56
xAOD::CaloCluster_v1::setM
void setM(flt_t)
Set Mass for the current signal state.
Definition: CaloCluster_v1.cxx:424