
/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitBabar                                                      *
 * @(#)root/roofit:$Id$
 * Author:                                                                   *
 *    Tristan du Pree, Nikhef, Amsterdam, tdupree@nikhef.nl                  *
 *    Wouter Verkerke, Nikhef, Amsterdam, verkerke@nikhef.nl
 *                                                                           *
 * Copyright (c) 2009, NIKHEF. All rights reserved.                          *
 *
 * Redistribution and use in source and binary forms,                        *
 * with or without modification, are permitted according to the terms        *
 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
 *****************************************************************************/

/** \class RooStepFunction
    \ingroup Roofit

The  Step Function is a binned function whose parameters
are the heights of each bin.

This function may be used to describe oddly shaped distributions. A RooStepFunction
has free parameters. In particular, any statistical uncertainty
used to model this efficiency may be understood with these free parameters.

Note that in contrast to RooParametricStepFunction, a RooStepFunction is NOT a PDF,
but a not-normalized function (RooAbsReal)
**/

#include "RooFit.h"

#include "Riostream.h"
#include "TArrayD.h"
#include <math.h>

#include "RooStepFunction.h"
#include "RooAbsReal.h"
#include "RooRealVar.h"
#include "RooArgList.h"
#include "RooMsgService.h"
#include "RooMath.h"

using namespace std;

ClassImp(RooStepFunction);

////////////////////////////////////////////////////////////////////////////////
/// Constructor

RooStepFunction::RooStepFunction()
{
  _coefIter = _coefList.createIterator() ;
  _boundIter = _boundaryList.createIterator() ;
  _interpolate = kFALSE ;
}

////////////////////////////////////////////////////////////////////////////////
/// Constructor

RooStepFunction::RooStepFunction(const char* name, const char* title,
             RooAbsReal& x, const RooArgList& coefList, const RooArgList& boundaryList, Bool_t interpolate) :
  RooAbsReal(name, title),
  _x("x", "Dependent", this, x),
  _coefList("coefList","List of coefficients",this),
  _boundaryList("boundaryList","List of boundaries",this),
  _interpolate(interpolate)
{
  _coefIter = _coefList.createIterator() ;
  TIterator* coefIter = coefList.createIterator() ;
  RooAbsArg* coef ;
  while((coef = (RooAbsArg*)coefIter->Next())) {
    if (!dynamic_cast<RooAbsReal*>(coef)) {
      cout << "RooStepFunction::ctor(" << GetName() << ") ERROR: coefficient " << coef->GetName()
      << " is not of type RooAbsReal" << endl ;
      assert(0) ;
    }
    _coefList.add(*coef) ;
  }
  delete coefIter ;

  _boundIter = _boundaryList.createIterator() ;
  TIterator* boundaryIter = boundaryList.createIterator() ;
  RooAbsArg* boundary ;
  while((boundary = (RooAbsArg*)boundaryIter->Next())) {
    if (!dynamic_cast<RooAbsReal*>(boundary)) {
      cout << "RooStepFunction::ctor(" << GetName() << ") ERROR: boundary " << boundary->GetName()
      << " is not of type RooAbsReal" << endl ;
      assert(0) ;
    }
    _boundaryList.add(*boundary) ;
  }

  if (_boundaryList.getSize()!=_coefList.getSize()+1) {
    coutE(InputArguments) << "RooStepFunction::ctor(" << GetName() << ") ERROR: Number of boundaries must be number of coefficients plus 1" << endl ;
    throw string("RooStepFunction::ctor() ERROR: Number of boundaries must be number of coefficients plus 1") ;
  }

}

////////////////////////////////////////////////////////////////////////////////
/// Copy constructor

RooStepFunction::RooStepFunction(const RooStepFunction& other, const char* name) :
  RooAbsReal(other, name),
  _x("x", this, other._x),
  _coefList("coefList",this,other._coefList),
  _boundaryList("boundaryList",this,other._boundaryList),
  _interpolate(other._interpolate)
{
  _coefIter = _coefList.createIterator();
  _boundIter = _boundaryList.createIterator();
}

////////////////////////////////////////////////////////////////////////////////
/// Destructor

RooStepFunction::~RooStepFunction()
{
  delete _coefIter ;
  delete _boundIter ;
}

////////////////////////////////////////////////////////////////////////////////
/// Transfer contents to vector for use below

Double_t RooStepFunction::evaluate() const
{
  vector<double> b(_boundaryList.getSize()) ;
  vector<double> c(_coefList.getSize()+3) ;
  Int_t nb(0) ;
  _boundIter->Reset() ;
  RooAbsReal* boundary ;
  while ((boundary=(RooAbsReal*)_boundIter->Next())) {
    b[nb++] = boundary->getVal() ;
  }

  // Return zero if outside any boundaries
  if ((_x<b[0]) || (_x>b[nb-1])) return 0 ;

  if (!_interpolate) {

    // No interpolation -- Return values bin-by-bin
    for (Int_t i=0;i<nb-1;i++){
      if (_x>b[i]&&_x<=b[i+1]) {
   return ((RooAbsReal*)_coefList.at(i))->getVal() ;
      }
    }
    return 0 ;

  } else {

    // Interpolation

    // Make array of (b[0],bin centers,b[last])
    c[0] = b[0] ; c[nb] = b[nb-1] ;
    for (Int_t i=0 ; i<nb-1 ; i++) {
      c[i+1] = (b[i]+b[i+1])/2 ;
    }

    // Make array of (0,coefficient values,0)
    Int_t nc(0) ;
    _coefIter->Reset() ;
    RooAbsReal* coef ;
    vector<double> y(_coefList.getSize()+3) ;
    y[nc++] = 0 ;
    while ((coef=(RooAbsReal*)_coefIter->Next())) {
      y[nc++] = coef->getVal() ;
    }
    y[nc++] = 0 ;

    for (Int_t i=0;i<nc-1;i++){
      if (_x>c[i]&&_x<=c[i+1]) {
   Double_t xx[2] ; xx[0]=c[i] ; xx[1]=c[i+1] ;
   Double_t yy[2] ; yy[0]=y[i] ; yy[1]=y[i+1] ;
   return RooMath::interpolate(xx,yy,2,_x) ;
      }
    }
    return 0;
  }
}
