Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooBinning.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 /**
18 \file RooBinning.cxx
19 \class RooBinning
20 \ingroup Roofitcore
21 
22 Class RooBinning is an implements RooAbsBinning in terms
23 of an array of boundary values, posing no constraints on the choice
24 of binning, thus allowing variable bin sizes. Various methods allow
25 the user to add single bin boundaries, mirrored pairs, or sets of
26 uniformly spaced boundaries.
27 **/
28 
29 #include "RooFit.h"
30 
31 #include "Riostream.h"
32 #include "RooBinning.h"
33 #include "RooDouble.h"
34 #include "RooAbsPdf.h"
35 #include "RooRealVar.h"
36 #include "RooNumber.h"
37 #include "RooMsgService.h"
38 #include "TBuffer.h"
39 #include "TList.h"
40 
41 #include <algorithm>
42 #include <cmath>
43 
44 using namespace std;
45 
46 ClassImp(RooBinning);
47 ;
48 
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Constructor for an initially empty binning defining the range [xlo,xhi]
52 
53 RooBinning::RooBinning(Double_t xlo, Double_t xhi, const char* name) :
54  RooAbsBinning(name),
55  _xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
56  _array(0), _blo(0)
57 {
58  setRange(xlo,xhi);
59 }
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 /// Constructor for a uniform binning in 'nbins' bins in the range [xlo,xhi]
63 
64 RooBinning::RooBinning(Int_t nbins, Double_t xlo, Double_t xhi, const char* name) :
65  RooAbsBinning(name),
66  _xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
67  _array(0), _blo(0)
68 {
69  _boundaries.reserve(1 + nbins);
70  setRange(xlo, xhi);
71  addUniform(nbins, xlo, xhi);
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Constructor for a binning in the range[xlo,xhi] with 'nbins' bin boundaries listed
76 /// array 'boundaries'
77 
78 RooBinning::RooBinning(Int_t nbins, const Double_t* boundaries, const char* name) :
79  RooAbsBinning(name),
80  _xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
81  _array(0), _blo(0)
82 {
83  // Variable bin size constructor
84  _boundaries.reserve(1 + nbins);
85  setRange(boundaries[0], boundaries[nbins]);
86  while (nbins--) addBoundary(boundaries[nbins]);
87 }
88 
89 ////////////////////////////////////////////////////////////////////////////////
90 /// Copy constructor
91 
92 RooBinning::RooBinning(const RooBinning& other, const char* name) :
93  RooAbsBinning(name), _xlo(other._xlo), _xhi(other._xhi),
94  _ownBoundLo(other._ownBoundLo), _ownBoundHi(other._ownBoundHi),
95  _nbins(other._nbins), _boundaries(other._boundaries), _array(0),
96  _blo(other._blo)
97 {
98 }
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 /// Destructor
102 
103 RooBinning::~RooBinning()
104 {
105  delete[] _array;
106 }
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// Add bin boundary at given value
110 
111 Bool_t RooBinning::addBoundary(Double_t boundary)
112 {
113  std::vector<Double_t>::iterator it =
114  std::lower_bound(_boundaries.begin(), _boundaries.end(), boundary);
115  if (_boundaries.end() != it && *it == boundary) {
116  // If boundary previously existed as range delimiter,
117  // convert to regular boundary now
118  if (boundary == _xlo) _ownBoundLo = kFALSE;
119  if (boundary == _xhi) _ownBoundHi = kFALSE;
120  return kFALSE;
121  }
122  // Add a new boundary
123  _boundaries.insert(it, boundary);
124  updateBinCount();
125  return kTRUE;
126 }
127 
128 ////////////////////////////////////////////////////////////////////////////////
129 /// Add pair of boundaries: one at 'boundary' and one at 2*mirrorPoint-boundary
130 
131 void RooBinning::addBoundaryPair(Double_t boundary, Double_t mirrorPoint)
132 {
133  addBoundary(boundary);
134  addBoundary(2. * mirrorPoint - boundary);
135 }
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Remove boundary at given value
139 
140 Bool_t RooBinning::removeBoundary(Double_t boundary)
141 {
142  std::vector<Double_t>::iterator it = std::lower_bound(_boundaries.begin(),
143  _boundaries.end(), boundary);
144  if (_boundaries.end() != it && *it == boundary) {
145  _boundaries.erase(it);
146  // if some moron deletes the boundaries corresponding to the current
147  // range, we need to make sure that we do not get into an undefined state,
148  // so _xlo and _xhi need to be set to some valid values
149  if (_boundaries.empty()) {
150  _xlo = _xhi = 0.;
151  } else {
152  if (boundary == _xlo) _xlo = _boundaries.front();
153  if (boundary == _xhi) _xhi = _boundaries.back();
154  }
155  updateBinCount();
156  return kFALSE;
157  }
158  // Return error status - no boundary found
159  return kTRUE;
160 }
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// Check if boundary exists at given value
164 
165 Bool_t RooBinning::hasBoundary(Double_t boundary)
166 {
167  return std::binary_search(_boundaries.begin(), _boundaries.end(), boundary);
168 }
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 /// Add array of nbins uniformly sized bins in range [xlo,xhi]
172 
173 void RooBinning::addUniform(Int_t nbins, Double_t xlo, Double_t xhi)
174 {
175  _boundaries.reserve(_boundaries.size() + nbins + 1);
176  for (Int_t i = 0; i <= nbins; ++i)
177  addBoundary((double(nbins - i) / double(nbins)) * xlo +
178  (double(i) / double(nbins)) * xhi);
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Return sequential bin number that contains value x where bin
183 /// zero is the first bin with an upper boundary above the lower bound
184 /// of the range
185 
186 Int_t RooBinning::binNumber(Double_t x) const
187 {
188  return std::max(0, std::min(_nbins, rawBinNumber(x) - _blo));
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 /// Return sequential bin number that contains value x where bin
193 /// zero is the first bin that is defined, regardless if that bin
194 /// is outside the current defined range
195 
196 Int_t RooBinning::rawBinNumber(Double_t x) const
197 {
198  std::vector<Double_t>::const_iterator it = std::lower_bound(
199  _boundaries.begin(), _boundaries.end(), x);
200  // always return valid bin number
201  while (_boundaries.begin() != it &&
202  (_boundaries.end() == it || _boundaries.end() == it + 1 || x < *it)) --it;
203  return it - _boundaries.begin();
204 }
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 /// Return the value of the nearest boundary to x
208 
209 Double_t RooBinning::nearestBoundary(Double_t x) const
210 {
211  Double_t xl, xh;
212  binEdges(binNumber(x), xl, xh);
213  return (std::abs(xl - x) < std::abs(xh - x)) ? xl : xh;
214 }
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Return array of boundary values
218 
219 Double_t* RooBinning::array() const
220 {
221  delete[] _array;
222  _array = new Double_t[numBoundaries()];
223  std::copy(_boundaries.begin()+_blo, _boundaries.begin()+_blo+_nbins+1, _array);
224  return _array;
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 /// Change the defined range associated with this binning.
229 /// Bins that lie outside the new range [xlo,xhi] will not be
230 /// removed, but will be 'inactive', i.e. the new 0 bin will
231 /// be the first bin with an upper boundarie > xlo
232 
233 void RooBinning::setRange(Double_t xlo, Double_t xhi)
234 {
235  if (xlo > xhi) {
236  coutE(InputArguments) << "RooBinning::setRange: ERROR low bound > high bound" << endl;
237  return;
238  }
239  // Remove previous boundaries
240  if (_ownBoundLo) removeBoundary(_xlo);
241  if (_ownBoundHi) removeBoundary(_xhi);
242  // Insert boundaries at range delimiter, if necessary
243  _ownBoundLo = addBoundary(xlo);
244  _ownBoundHi = addBoundary(xhi);
245  _xlo = xlo, _xhi = xhi;
246  // Count number of bins with new range
247  updateBinCount();
248 }
249 
250 ////////////////////////////////////////////////////////////////////////////////
251 /// Update the internal bin counter
252 
253 void RooBinning::updateBinCount()
254 {
255  if (_boundaries.size() <= 1) {
256  _nbins = -1;
257  return;
258  }
259  _blo = rawBinNumber(_xlo);
260  std::vector<Double_t>::const_iterator it = std::lower_bound(
261  _boundaries.begin(), _boundaries.end(), _xhi);
262  if (_boundaries.begin() != it && (_boundaries.end() == it || _xhi < *it)) --it;
263  const Int_t bhi = it - _boundaries.begin();
264  _nbins = bhi - _blo;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Return upper and lower bound of bin 'bin'. If the return value
269 /// is true an error occurred
270 
271 Bool_t RooBinning::binEdges(Int_t bin, Double_t& xlo, Double_t& xhi) const
272 {
273  if (0 > bin || bin >= _nbins) {
274  coutE(InputArguments) << "RooBinning::binEdges ERROR: bin number must be in range (0," << _nbins << ")" << endl;
275  return kTRUE;
276  }
277  xlo = _boundaries[bin + _blo], xhi = _boundaries[bin + _blo + 1];
278  return kFALSE;
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// Return the position of the center of bin 'bin'
283 
284 Double_t RooBinning::binCenter(Int_t bin) const
285 {
286  Double_t xlo, xhi;
287  if (binEdges(bin, xlo, xhi)) return 0;
288  return 0.5 * (xlo + xhi);
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 /// Return the width of the requested bin
293 
294 Double_t RooBinning::binWidth(Int_t bin) const
295 {
296  Double_t xlo, xhi;
297  if (binEdges(bin, xlo, xhi)) return 0;
298  return (xhi - xlo);
299 }
300 
301 ////////////////////////////////////////////////////////////////////////////////
302 /// Return the lower bound of the requested bin
303 
304 Double_t RooBinning::binLow(Int_t bin) const
305 {
306  Double_t xlo, xhi;
307  if (binEdges(bin, xlo, xhi)) return 0;
308  return xlo;
309 }
310 
311 ////////////////////////////////////////////////////////////////////////////////
312 /// Return the upper bound of the requested bin
313 
314 Double_t RooBinning::binHigh(Int_t bin) const
315 {
316  Double_t xlo, xhi;
317  if (binEdges(bin, xlo, xhi)) return 0;
318  return xhi;
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Custom streamer that provides backward compatibility to read v1 data
323 
324 void RooBinning::Streamer(TBuffer &R__b)
325 {
326  if (R__b.IsReading()) {
327 
328  UInt_t R__s, R__c;
329  Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
330  switch (R__v) {
331  case 3:
332  // current version - fallthrough intended
333  case 2:
334  // older version with std::set<Double_t> instead of
335  // std::vector<Double_t>, apparently ROOT is clever enough to not care
336  // about set vs vector
337  R__b.ReadClassBuffer(RooBinning::Class(), this, R__v, R__s, R__c);
338  break;
339  case 1:
340  {
341  RooAbsBinning::Streamer(R__b);
342  R__b >> _xlo;
343  R__b >> _xhi;
344  R__b >> _ownBoundLo;
345  R__b >> _ownBoundHi;
346  R__b >> _nbins;
347 
348  _boundaries.clear();
349  // Convert TList to std::vector<Double_t>
350  TList tmp;
351  tmp.Streamer(R__b);
352  _boundaries.reserve(tmp.GetSize());
353  TIterator* it = tmp.MakeIterator();
354  for (RooDouble* el = (RooDouble*) it->Next(); el;
355  el = (RooDouble*) it->Next()) _boundaries.push_back(*el);
356  delete it;
357  }
358  R__b.CheckByteCount(R__s, R__c, RooBinning::IsA());
359  break;
360  default:
361  throw std::string("Unknown class version!");
362  }
363  if (_boundaries.size() > 2) {
364  std::sort(_boundaries.begin(), _boundaries.end());
365  _boundaries.erase(std::unique(_boundaries.begin(), _boundaries.end()),
366  _boundaries.end());
367  }
368  } else {
369  R__b.WriteClassBuffer(RooBinning::Class(),this);
370  }
371 }