// Class RooBinning is an implements RooAbsBinning in terms
// of an array of boundary values, posing no constraints on the choice
// of binning, thus allowing variable bin sizes. Various methods allow
// the user to add single bin boundaries, mirrored pairs, or sets of
// uniformly spaced boundaries.
// END_HTML
#include <cmath>
#include <algorithm>
#include "RooFit.h"
#include "Riostream.h"
#include "Riostream.h"
#include "RooBinning.h"
#include "RooDouble.h"
#include "RooAbsPdf.h"
#include "RooRealVar.h"
#include "RooNumber.h"
#include "RooMsgService.h"
#include "TList.h"
using namespace std;
ClassImp(RooBinning)
;
RooBinning::RooBinning(Double_t xlo, Double_t xhi, const char* name) :
RooAbsBinning(name),
_xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
_array(0), _blo(0)
{
setRange(xlo,xhi);
}
RooBinning::RooBinning(Int_t nbins, Double_t xlo, Double_t xhi, const char* name) :
RooAbsBinning(name),
_xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
_array(0), _blo(0)
{
_boundaries.reserve(1 + nbins);
setRange(xlo, xhi);
addUniform(nbins, xlo, xhi);
}
RooBinning::RooBinning(Int_t nbins, const Double_t* boundaries, const char* name) :
RooAbsBinning(name),
_xlo(0), _xhi(0), _ownBoundLo(kTRUE), _ownBoundHi(kTRUE),
_array(0), _blo(0)
{
_boundaries.reserve(1 + nbins);
setRange(boundaries[0], boundaries[nbins]);
while (nbins--) addBoundary(boundaries[nbins]);
}
RooBinning::RooBinning(const RooBinning& other, const char* name) :
RooAbsBinning(name), _xlo(other._xlo), _xhi(other._xhi),
_ownBoundLo(other._ownBoundLo), _ownBoundHi(other._ownBoundHi),
_nbins(other._nbins), _boundaries(other._boundaries), _array(0),
_blo(other._blo)
{
}
RooBinning::~RooBinning()
{
delete[] _array;
}
Bool_t RooBinning::addBoundary(Double_t boundary)
{
std::vector<Double_t>::iterator it =
std::lower_bound(_boundaries.begin(), _boundaries.end(), boundary);
if (_boundaries.end() != it && *it == boundary) {
if (boundary == _xlo) _ownBoundLo = kFALSE;
if (boundary == _xhi) _ownBoundHi = kFALSE;
return kFALSE;
}
_boundaries.insert(it, boundary);
updateBinCount();
return kTRUE;
}
void RooBinning::addBoundaryPair(Double_t boundary, Double_t mirrorPoint)
{
addBoundary(boundary);
addBoundary(2. * mirrorPoint - boundary);
}
Bool_t RooBinning::removeBoundary(Double_t boundary)
{
std::vector<Double_t>::iterator it = std::lower_bound(_boundaries.begin(),
_boundaries.end(), boundary);
if (_boundaries.end() != it && *it == boundary) {
_boundaries.erase(it);
if (_boundaries.empty()) {
_xlo = _xhi = 0.;
} else {
if (boundary == _xlo) _xlo = _boundaries.front();
if (boundary == _xhi) _xhi = _boundaries.back();
}
updateBinCount();
return kFALSE;
}
return kTRUE;
}
Bool_t RooBinning::hasBoundary(Double_t boundary)
{
return std::binary_search(_boundaries.begin(), _boundaries.end(), boundary);
}
void RooBinning::addUniform(Int_t nbins, Double_t xlo, Double_t xhi)
{
_boundaries.reserve(_boundaries.size() + nbins + 1);
for (Int_t i = 0; i <= nbins; ++i)
addBoundary((double(nbins - i) / double(nbins)) * xlo +
(double(i) / double(nbins)) * xhi);
}
Int_t RooBinning::binNumber(Double_t x) const
{
return std::max(0, std::min(_nbins, rawBinNumber(x) - _blo));
}
Int_t RooBinning::rawBinNumber(Double_t x) const
{
std::vector<Double_t>::const_iterator it = std::lower_bound(
_boundaries.begin(), _boundaries.end(), x);
while (_boundaries.begin() != it &&
(_boundaries.end() == it || _boundaries.end() == it + 1 || x < *it)) --it;
return it - _boundaries.begin();
}
Double_t RooBinning::nearestBoundary(Double_t x) const
{
Double_t xl, xh;
binEdges(binNumber(x), xl, xh);
return (std::abs(xl - x) < std::abs(xh - x)) ? xl : xh;
}
Double_t* RooBinning::array() const
{
delete[] _array;
_array = new Double_t[numBoundaries()];
std::copy(_boundaries.begin()+_blo, _boundaries.begin()+_blo+_nbins+1, _array);
return _array;
}
void RooBinning::setRange(Double_t xlo, Double_t xhi)
{
if (xlo > xhi) {
coutE(InputArguments) << "RooBinning::setRange: ERROR low bound > high bound" << endl;
return;
}
if (_ownBoundLo) removeBoundary(_xlo);
if (_ownBoundHi) removeBoundary(_xhi);
_ownBoundLo = addBoundary(xlo);
_ownBoundHi = addBoundary(xhi);
_xlo = xlo, _xhi = xhi;
updateBinCount();
}
void RooBinning::updateBinCount()
{
if (_boundaries.size() <= 1) {
_nbins = -1;
return;
}
_blo = rawBinNumber(_xlo);
std::vector<Double_t>::const_iterator it = std::lower_bound(
_boundaries.begin(), _boundaries.end(), _xhi);
if (_boundaries.begin() != it && (_boundaries.end() == it || _xhi < *it)) --it;
const Int_t bhi = it - _boundaries.begin();
_nbins = bhi - _blo;
}
Bool_t RooBinning::binEdges(Int_t bin, Double_t& xlo, Double_t& xhi) const
{
if (0 > bin || bin >= _nbins) {
coutE(InputArguments) << "RooBinning::binEdges ERROR: bin number must be in range (0," << _nbins << ")" << endl;
return kTRUE;
}
xlo = _boundaries[bin + _blo], xhi = _boundaries[bin + _blo + 1];
return kFALSE;
}
Double_t RooBinning::binCenter(Int_t bin) const
{
Double_t xlo, xhi;
if (binEdges(bin, xlo, xhi)) return 0;
return 0.5 * (xlo + xhi);
}
Double_t RooBinning::binWidth(Int_t bin) const
{
Double_t xlo, xhi;
if (binEdges(bin, xlo, xhi)) return 0;
return (xhi - xlo);
}
Double_t RooBinning::binLow(Int_t bin) const
{
Double_t xlo, xhi;
if (binEdges(bin, xlo, xhi)) return 0;
return xlo;
}
Double_t RooBinning::binHigh(Int_t bin) const
{
Double_t xlo, xhi;
if (binEdges(bin, xlo, xhi)) return 0;
return xhi;
}
void RooBinning::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
UInt_t R__s, R__c;
Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
switch (R__v) {
case 3:
case 2:
R__b.ReadClassBuffer(RooBinning::Class(), this, R__v, R__s, R__c);
break;
case 1:
{
RooAbsBinning::Streamer(R__b);
R__b >> _xlo;
R__b >> _xhi;
R__b >> _ownBoundLo;
R__b >> _ownBoundHi;
R__b >> _nbins;
_boundaries.clear();
TList tmp;
tmp.Streamer(R__b);
_boundaries.reserve(tmp.GetSize());
TIterator* it = tmp.MakeIterator();
for (RooDouble* el = (RooDouble*) it->Next(); el;
el = (RooDouble*) it->Next()) _boundaries.push_back(*el);
delete it;
}
R__b.CheckByteCount(R__s, R__c, RooBinning::IsA());
break;
default:
throw std::string("Unknown class version!");
}
if (_boundaries.size() > 2) {
std::sort(_boundaries.begin(), _boundaries.end());
_boundaries.erase(std::unique(_boundaries.begin(), _boundaries.end()),
_boundaries.end());
}
} else {
R__b.WriteClassBuffer(RooBinning::Class(),this);
}
}