2 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
5 //NB: Could use negative numbers in the errors slot to indicate specials.
7 #define LW_STORE_ERRORS_AS_IN_ROOT 0
9 // When LW_STORE_ERRORS_AS_IN_ROOT is set to 1, we keep three float
12 // 1) Entries: Sum(weight)
13 // 2) Contents: Sum(weight*profpar)
14 // 3) Errors: Sum(weight*profpar^2)
16 // When LW_STORE_ERRORS_AS_IN_ROOT is set to 0, the third parameter is
17 // replaced by the following:
19 // 3) T: ( Sum(weight*profpar^2)*Sum(weight)-Sum(weight*profpar)^2 ) / Sum(weight)
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):
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
29 // Where E and C are the (previous) values of Entries and Contents respectively.
31 // To calculate an actual "error" from the three values, one does
32 // (Entries==0 => 0 in both cases):
34 // LW_STORE_ERRORS_AS_IN_ROOT == 1:
36 // sqrt(fabs(ERR/E - (C/E)^2)/E);
38 // (E, C and ERR are the three stored parameters)
40 // LW_STORE_ERRORS_AS_IN_ROOT == 0:
44 // (E and T are the first and third stored parameter)
47 //____________________________________________________________________
48 inline FlexProfileArray::FlexProfileArray( unsigned nbins )
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]));
58 //____________________________________________________________________
59 inline FlexProfileArray::~FlexProfileArray()
64 //____________________________________________________________________
65 inline void FlexProfileArray::fill(unsigned bin, const double& profiledpar)
68 float * f = getPtr(bin);
69 #if LW_STORE_ERRORS_AS_IN_ROOT
71 *(f++) += profiledpar;//contents
72 *f += profiledpar*profiledpar;//errors
77 *(f++) += profiledpar;//contents
79 double tmp(cont/ent-profiledpar);
80 *f += tmp*tmp*(ent/(1.0+ent));
85 //____________________________________________________________________
86 inline void FlexProfileArray::fill(unsigned bin, const double& profiledpar, const double& weight)
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);
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
107 //____________________________________________________________________
108 inline double FlexProfileArray::getBinEntries(unsigned bin) const
111 float * f = getPtrNoAlloc(bin);
112 return f ? f[0] : 0.0;
115 //____________________________________________________________________
116 inline double FlexProfileArray::getBinContent(unsigned bin) const
119 float * f = getPtrNoAlloc(bin);
120 return f ? (*f?f[1]/(*f):0.0) : 0.0;
123 //____________________________________________________________________
124 inline double FlexProfileArray::getBinError(unsigned bin) const
127 float * f = getPtrNoAlloc(bin);
128 return f ? computeBinError(f) : 0.0;
131 //____________________________________________________________________
132 inline double FlexProfileArray::computeBinError(float*f) const
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)!!
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)
152 if (m_errOpt==ERRORSPREADI) {
153 return eprim2 ? sqrt(eprim2/sum) : invsqrt12/sqrt(sum);
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);
171 assert(m_errOpt==ERRORSPREADG);
172 return 1.0/sqrt(fabs(sum));//doesn't depend on eprim2 or t
175 //____________________________________________________________________
176 inline void FlexProfileArray::setErrorOptionFromString(const char *opt)
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
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;
190 setErrorOption(ERRORMEAN);
194 setErrorOption(ERRORSPREAD);
198 setErrorOption(ERRORSPREADI);
202 setErrorOption(ERRORSPREADG);
205 std::cout<<"LW Profile histogram ERROR: Ignoring badly formatted error option: \""<<opt<<"\""<<std::endl;
210 //____________________________________________________________________
211 inline const char* FlexProfileArray::getErrorOptionAsString() const
214 case ERRORSPREAD: return "s";
215 case ERRORSPREADI: return "i";
216 case ERRORSPREADG: return "g";
222 //____________________________________________________________________
223 inline void FlexProfileArray::getBinInfo(unsigned bin, double&entries, double& content, double& error ) const
226 float * f = getPtrNoAlloc(bin);
228 error = computeBinError(f);
230 content = entries ? *f/entries : 0.0;
238 //____________________________________________________________________
239 inline void FlexProfileArray::setBinEntries(unsigned bin, const double& e)
245 f = getPtrNoAlloc(bin);
251 #if LW_STORE_ERRORS_AS_IN_ROOT
252 *f = fabs(e);//We always assume positive!
259 //Need to update T also to keep Sum(weight*profpar^2) constant, like in ROOT.
261 *(f+2)=fabs(cont*cont*(1.0/double(*f)-1.0/fabs(e)));
268 //____________________________________________________________________
269 inline void FlexProfileArray::setBinContent(unsigned bin, const double&c)
275 f = getPtrNoAlloc(bin);
281 #if LW_STORE_ERRORS_AS_IN_ROOT
284 //Need to update T also to keep Sum(weight*profpar^2) constant, like in ROOT.
288 *f += ent ? (cont_old*cont_old-c*c)/ent : 0;
293 //____________________________________________________________________
294 inline void FlexProfileArray::setBinError(unsigned bin, const double& e)
300 f = getPtrNoAlloc(bin);
306 #if LW_STORE_ERRORS_AS_IN_ROOT
310 //Need to set T to e*e - C^2/E. Special case: if E=0, we just set T to 0 also.
312 const double cont(*(f+1));
313 *(f+2)= e*e-cont*cont/(*f);
320 //____________________________________________________________________
321 inline void FlexProfileArray::setBinInfo(unsigned bin, const double& entries, const double& content, const double& error )
325 if (entries==0&&content==0&&error==0) {
327 f = getPtrNoAlloc(bin);
333 *(f++) = fabs(entries);//require >=0
335 #if LW_STORE_ERRORS_AS_IN_ROOT
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;
343 //____________________________________________________________________
344 inline float* FlexProfileArray::allocateGroup()
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));
352 //____________________________________________________________________
353 inline void FlexProfileArray::deallocateGroup(float* f)
356 LWPools::release<float,FLEXPROFILEARRAY_NBINSPERGROUP*3>(f);
359 //____________________________________________________________________
360 inline void FlexProfileArray::reset()
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]));
368 //____________________________________________________________________
369 inline float * FlexProfileArray::getPtr(unsigned ibin) {
370 const unsigned igroup(groupIndex(ibin));
371 float ** gr = &(m_groups[igroup]);
373 *gr = allocateGroup();
375 return &((*gr)[indexInGroup(ibin)]);
378 //____________________________________________________________________
379 inline float * FlexProfileArray::getPtrNoAlloc(unsigned ibin) const
381 const unsigned igroup(groupIndex(ibin));
382 float * gr = m_groups[igroup];
383 return gr ? &(gr[indexInGroup(ibin)]) : 0;
386 //____________________________________________________________________
387 inline double FlexProfileArray::integral() const
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) {
397 float * fE = f + (gr==grLast?nbinsInLastGroup():FLEXPROFILEARRAY_NBINSPERGROUP)*3;
398 for (;f!=fE; f += 3 )
399 sum += (*f?f[1]/(*f):0.0);
404 //____________________________________________________________________
405 inline void FlexProfileArray::copyContents(double* entries, double*contents, double*errors) const
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;
414 for (float ** gr = m_groups;gr!=grE;++gr) {
416 ibin += FLEXPROFILEARRAY_NBINSPERGROUP;
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++);
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;