ATLAS Offline Software
FlexProfileArray.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 //NB: Could use negative numbers in the errors slot to indicate specials.
6 
7 #define LW_STORE_ERRORS_AS_IN_ROOT 0
8 
9 // When LW_STORE_ERRORS_AS_IN_ROOT is set to 1, we keep three float
10 // parameters:
11 //
12 // 1) Entries: Sum(weight)
13 // 2) Contents: Sum(weight*profpar)
14 // 3) Errors: Sum(weight*profpar^2)
15 //
16 // When LW_STORE_ERRORS_AS_IN_ROOT is set to 0, the third parameter is
17 // replaced by the following:
18 //
19 // 3) T: ( Sum(weight*profpar^2)*Sum(weight)-Sum(weight*profpar)^2 ) / Sum(weight)
20 //
21 // The reason being that the final error calculation is more resistant
22 // to numerical errors with this parameter (we use only floats). One
23 // can show that when filling with a new (profpar,weight) pair, the
24 // increment of T becomes (weight>=0):
25 //
26 // delta(T) = weight/(E*(E+weight))*(C-E*profpar)^2 (if E!=0, otherwise 0)
27 // = (C-E*profpar)^2/(E*(1+E)) when weight=1
28 //
29 // Where E and C are the (previous) values of Entries and Contents respectively.
30 //
31 // To calculate an actual "error" from the three values, one does
32 // (Entries==0 => 0 in both cases):
33 //
34 // LW_STORE_ERRORS_AS_IN_ROOT == 1:
35 //
36 // sqrt(fabs(ERR/E - (C/E)^2)/E);
37 //
38 // (E, C and ERR are the three stored parameters)
39 //
40 // LW_STORE_ERRORS_AS_IN_ROOT == 0:
41 //
42 // sqrt(T)/E
43 //
44 // (E and T are the first and third stored parameter)
45 //
46 
47 //____________________________________________________________________
48 inline FlexProfileArray::FlexProfileArray( unsigned nbins )
49  : m_nbins(nbins),
50  m_errOpt(ERRORMEAN)
51 {
52  unsigned n(nGroups(nbins));
53  // cppcheck-suppress invalidPointerCast
54  m_groups = reinterpret_cast<float**>(reinterpret_cast<char*>(this)+sizeof(*this));
55  memset(m_groups,0,n*sizeof(m_groups[0]));
56 }
57 
58 //____________________________________________________________________
59 inline FlexProfileArray::~FlexProfileArray()
60 {
61  reset();
62 }
63 
64 //____________________________________________________________________
65 inline void FlexProfileArray::fill(unsigned bin, const double& profiledpar)
66 {
67  assert(bin<m_nbins);
68  float * f = getPtr(bin);
69 #if LW_STORE_ERRORS_AS_IN_ROOT
70  ++(*(f++));//entries
71  *(f++) += profiledpar;//contents
72  *f += profiledpar*profiledpar;//errors
73 #else
74  double ent(*f);
75  ++(*(f++));//entries
76  double cont(*f);
77  *(f++) += profiledpar;//contents
78  if (ent) {
79  double tmp(cont/ent-profiledpar);
80  *f += tmp*tmp*(ent/(1.0+ent));
81  }
82 #endif
83 }
84 
85 //____________________________________________________________________
86 inline void FlexProfileArray::fill(unsigned bin, const double& profiledpar, const double& weight)
87 {
88  assert(bin<m_nbins);
89  if (!weight)
90  return;
91  //NB: root used to use fabs(weight) instead of weight in the formulas below
92  float * f = getPtr(bin);
93 #if not LW_STORE_ERRORS_AS_IN_ROOT
94  double deltaT = *f ? *(f+1)/double(*f)-profiledpar : 0;
95  deltaT *= deltaT*weight*(*f)/(*f+weight);
96 #endif
97  *(f++) += weight;//entries
98  double wp(weight*profiledpar);
99  *(f++) += wp;//contents
100 #if LW_STORE_ERRORS_AS_IN_ROOT
101  *f += profiledpar*wp;//errors
102 #else
103  *f += deltaT;//T
104 #endif
105 }
106 
107 //____________________________________________________________________
108 inline double FlexProfileArray::getBinEntries(unsigned bin) const
109 {
110  assert(bin<m_nbins);
111  float * f = getPtrNoAlloc(bin);
112  return f ? f[0] : 0.0;
113 }
114 
115 //____________________________________________________________________
116 inline double FlexProfileArray::getBinContent(unsigned bin) const
117 {
118  assert(bin<m_nbins);
119  float * f = getPtrNoAlloc(bin);
120  return f ? (*f?f[1]/(*f):0.0) : 0.0;
121 }
122 
123 //____________________________________________________________________
124 inline double FlexProfileArray::getBinError(unsigned bin) const
125 {
126  assert(bin<m_nbins);
127  float * f = getPtrNoAlloc(bin);
128  return f ? computeBinError(f) : 0.0;
129 }
130 
131 //____________________________________________________________________
132 inline double FlexProfileArray::computeBinError(float*f) const
133 {
134  //NB: It seems that newest root has "effective entries
135  //(sum(w)^2/sum(w^2) instead of sum several places below! Need to
136  //update this if possible when ATLAS move to a new root version
137  //(hopefully there is then an root version define to test against)!!
138 
139  assert(f);
140  double sum = *(f++);
141  if (sum == 0)
142  return 0;
143  sum=fabs(sum);
144  static const double invsqrt12 = 1.0/sqrt(12.0);
145 #if LW_STORE_ERRORS_AS_IN_ROOT
146  double contsum = *(f++)/sum;
147  double eprim2=fabs(*f/sum - contsum*contsum);
148  if (m_errOpt==ERRORMEAN)
149  return sqrt(eprim2/sum);
150  if (m_errOpt==ERRORSPREAD)
151  return sqrt(eprim2);
152  if (m_errOpt==ERRORSPREADI) {
153  return eprim2 ? sqrt(eprim2/sum) : invsqrt12/sqrt(sum);
154  }
155 #else
156  double t(fabs(*(f+1)));
157  //We do the fabs(t) because user might have called setBinContent, etc., in an inconsistent way.
158  if (m_errOpt==ERRORMEAN)
159  return sqrt(t)/sum;//sqrt(T)/E
160  if (m_errOpt==ERRORSPREAD)
161  return sqrt(t/sum);//sqrt(T/E)
162  if (m_errOpt==ERRORSPREADI) {
163  //NB : It seems there is a bug in root here, where something
164  //similar to t!=0 is also tested for. However, due to numerical
165  //problems there, that will almost certainly never happen. For
166  //this reason it will be almost impossible to be number-to-number
167  //compatible with root in this case.
168  return t ? sqrt(t)/sum : invsqrt12/sqrt(sum);
169  }
170 #endif
171  assert(m_errOpt==ERRORSPREADG);
172  return 1.0/sqrt(fabs(sum));//doesn't depend on eprim2 or t
173 }
174 
175 //____________________________________________________________________
176 inline void FlexProfileArray::setErrorOptionFromString(const char *opt)
177 {
178  //A bit annoying that we get option passed as a string. However, we
179  //only accept " ", "s", "S", "i", "I", "g" and "G". Anything else
180  //will be ignored.
181 
182  if (!opt||opt[0]=='\0'||opt[1]!='\0') {
183  //NULL ptr or string length not one.
184  std::cout<<"LW Profile histogram ERROR: Ignoring badly formatted error option: \""<<(opt?opt:"nullptr")<<"\""<<std::endl;
185  return;
186  }
187 
188  switch(opt[0]) {
189  case ' ':
190  setErrorOption(ERRORMEAN);
191  return;
192  case 's':
193  case 'S':
194  setErrorOption(ERRORSPREAD);
195  return;
196  case 'i':
197  case 'I':
198  setErrorOption(ERRORSPREADI);
199  return;
200  case 'g':
201  case 'G':
202  setErrorOption(ERRORSPREADG);
203  return;
204  default:
205  std::cout<<"LW Profile histogram ERROR: Ignoring badly formatted error option: \""<<opt<<"\""<<std::endl;
206  return;
207  }
208 }
209 
210 //____________________________________________________________________
211 inline const char* FlexProfileArray::getErrorOptionAsString() const
212 {
213  switch (m_errOpt) {
214  case ERRORSPREAD: return "s";
215  case ERRORSPREADI: return "i";
216  case ERRORSPREADG: return "g";
217  default:
218  return " ";
219  };
220 }
221 
222 //____________________________________________________________________
223 inline void FlexProfileArray::getBinInfo(unsigned bin, double&entries, double& content, double& error ) const
224 {
225  assert(bin<m_nbins);
226  float * f = getPtrNoAlloc(bin);
227  if (f) {
228  error = computeBinError(f);
229  entries = *(f++);
230  content = entries ? *f/entries : 0.0;
231  } else {
232  entries = 0.0;
233  content = 0.0;
234  error = 0.0;
235  }
236 }
237 
238 //____________________________________________________________________
239 inline void FlexProfileArray::setBinEntries(unsigned bin, const double& e)
240 {
241  assert(bin<m_nbins);
242  float * f;
243  if (e==0) {
244  //special case:
245  f = getPtrNoAlloc(bin);
246  if (!f)
247  return;
248  } else {
249  f = getPtr(bin);
250  }
251 #if LW_STORE_ERRORS_AS_IN_ROOT
252  *f = fabs(e);//We always assume positive!
253 #else
254  if (!e) {
255  *f = 0;
256  *(f+2)=0;//T
257  } else {
258  if (*f) {
259  //Need to update T also to keep Sum(weight*profpar^2) constant, like in ROOT.
260  double cont(*(f+1));
261  *(f+2)=fabs(cont*cont*(1.0/double(*f)-1.0/fabs(e)));
262  }
263  *f = fabs(e);
264  }
265 #endif
266 }
267 
268 //____________________________________________________________________
269 inline void FlexProfileArray::setBinContent(unsigned bin, const double&c)
270 {
271  assert(bin<m_nbins);
272  float * f;
273  if (c==0) {
274  //special case:
275  f = getPtrNoAlloc(bin);
276  if (!f)
277  return;
278  } else {
279  f = getPtr(bin);
280  }
281 #if LW_STORE_ERRORS_AS_IN_ROOT
282  *(++f) = c;
283 #else
284  //Need to update T also to keep Sum(weight*profpar^2) constant, like in ROOT.
285  double ent(*(f++));
286  double cont_old(*f);
287  *(f++) = c;
288  *f += ent ? (cont_old*cont_old-c*c)/ent : 0;
289  //assert(*f>=0);
290 #endif
291 }
292 
293 //____________________________________________________________________
294 inline void FlexProfileArray::setBinError(unsigned bin, const double& e)
295 {
296  assert(bin<m_nbins);
297  float * f;
298  if (e==0) {
299  //special case:
300  f = getPtrNoAlloc(bin);
301  if (!f)
302  return;
303  } else {
304  f = getPtr(bin);
305  }
306 #if LW_STORE_ERRORS_AS_IN_ROOT
307  ++f;
308  *(++f) = e*e;
309 #else
310  //Need to set T to e*e - C^2/E. Special case: if E=0, we just set T to 0 also.
311  if (*f) {
312  const double cont(*(f+1));
313  *(f+2)= e*e-cont*cont/(*f);
314  } else {
315  *(f+2)= 0;
316  }
317 #endif
318 }
319 
320 //____________________________________________________________________
321 inline void FlexProfileArray::setBinInfo(unsigned bin, const double& entries, const double& content, const double& error )
322 {
323  assert(bin<m_nbins);
324  float * f;
325  if (entries==0&&content==0&&error==0) {
326  //special case:
327  f = getPtrNoAlloc(bin);
328  if (!f)
329  return;
330  } else {
331  f = getPtr(bin);
332  }
333  *(f++) = fabs(entries);//require >=0
334  *(f++) = content;
335 #if LW_STORE_ERRORS_AS_IN_ROOT
336  *f = error*error;
337 #else
338  //Need to set T to error - C^2/E. Special case: if E=0, we just set T to 0 also.
339  *f = entries ? error*error-content*content/fabs(entries) : 0;
340 #endif
341 }
342 
343 //____________________________________________________________________
344 inline float* FlexProfileArray::allocateGroup()
345 {
346  //NB: we are potentially over-acquiring for the last group! (fixme?)
347  float * f = LWPools::acquire<float,FLEXPROFILEARRAY_NBINSPERGROUP*3>();
348  memset(f,0,sizeof(float)*(FLEXPROFILEARRAY_NBINSPERGROUP*3));
349  return f;
350 }
351 
352 //____________________________________________________________________
353 inline void FlexProfileArray::deallocateGroup(float* f)
354 {
355  if (f)
356  LWPools::release<float,FLEXPROFILEARRAY_NBINSPERGROUP*3>(f);
357 }
358 
359 //____________________________________________________________________
360 inline void FlexProfileArray::reset()
361 {
362  unsigned n(nGroups(m_nbins));
363  for (unsigned i=0;i<n;++i)
364  deallocateGroup(m_groups[i]);
365  memset(m_groups,0,n*sizeof(m_groups[0]));
366 }
367 
368 //____________________________________________________________________
369 inline float * FlexProfileArray::getPtr(unsigned ibin) {
370  const unsigned igroup(groupIndex(ibin));
371  float ** gr = &(m_groups[igroup]);
372  if (!*gr)
373  *gr = allocateGroup();
374  assert(*gr);
375  return &((*gr)[indexInGroup(ibin)]);
376 }
377 
378 //____________________________________________________________________
379 inline float * FlexProfileArray::getPtrNoAlloc(unsigned ibin) const
380 {
381  const unsigned igroup(groupIndex(ibin));
382  float * gr = m_groups[igroup];
383  return gr ? &(gr[indexInGroup(ibin)]) : 0;
384 }
385 
386 //____________________________________________________________________
387 inline double FlexProfileArray::integral() const
388 {
389  double sum(0.0);
390  unsigned ngroups(nGroups(m_nbins));
391  float ** grE(m_groups+ngroups);
392  float **grLast = grE-1;
393  for (float ** gr = m_groups;gr!=grE;++gr) {
394  if (!*gr)
395  continue;
396  float * f = *gr;
397  float * fE = f + (gr==grLast?nbinsInLastGroup():FLEXPROFILEARRAY_NBINSPERGROUP)*3;
398  for (;f!=fE; f += 3 )
399  sum += (*f?f[1]/(*f):0.0);
400  }
401  return sum;
402 }
403 
404 //____________________________________________________________________
405 inline void FlexProfileArray::copyContents(double* entries, double*contents, double*errors) const
406 {
407  memset(entries,0,m_nbins*sizeof(*entries));
408  memset(contents,0,m_nbins*sizeof(*contents));
409  memset(errors,0,m_nbins*sizeof(*errors));
410  unsigned ngroups(nGroups(m_nbins));
411  float ** grE(m_groups+ngroups);
412  float **grLast = grE-1;
413  unsigned ibin(0);
414  for (float ** gr = m_groups;gr!=grE;++gr) {
415  if (!*gr) {
416  ibin += FLEXPROFILEARRAY_NBINSPERGROUP;
417  continue;
418  }
419  float * f = *gr;
420  float * fE = f + (gr==grLast?nbinsInLastGroup():FLEXPROFILEARRAY_NBINSPERGROUP)*3;
421  for (;f!=fE;++ibin) {
422 #if LW_STORE_ERRORS_AS_IN_ROOT
423  entries[ibin] = *(f++);
424  contents[ibin] = *(f++);
425  errors[ibin] = *(f++);
426 #else
427  //errors = T+C^2/E (0 for E=0)
428  const double entr(*(f++));
429  entries[ibin] = entr;
430  const double cont(*(f++));
431  contents[ibin] = cont;
432  errors[ibin] = entr ? *f+cont*cont/entr : 0.0;
433  ++f;
434 #endif
435  }
436  }
437 }