// Author: Gero Flucke <mailto:gero.flucke@desy.de>
//______________________________________________
// class for fitting D0 distributions
//
//

#include "D0Fitter.h"

#include <TH1.h>
#include <TH2.h>
#include <TH3.h>
#include <TMath.h>
#include <TDatabasePDG.h>
#include <TROOT.h>
#include <TF1.h>
#include <TError.h>

#include <iostream>

using namespace std;

 Double_t D0Fitter::D0ExpBackgr(Double_t *x, Double_t *par)
{
  // background function:
  // par[0]: normalisation
  // par[1]: decay constant
  // x[0]:   deltaM
  const Double_t norm = par[1] ?
    (TMath::Exp(fgUpFitLimit * par[1]) - TMath::Exp(fgLowFitLimit * par[1])) / par[1] :
    (fgUpFitLimit - fgLowFitLimit);
  return (norm ? (par[0] * TMath::Exp(x[0] * par[1]) * fgBinSize / norm) : 0.);
}

//_____________________________________
 Double_t D0Fitter::D0LinearBackgr(Double_t *x, Double_t *par)
{
  // FIXME: Not used, to be adjusted to give normalisation etc.
  //
  // background function:
  // par[0]: constant term
  // par[1]: linear term
  // x[0]:   deltaM
  return (par[0] + x[0] * par[1]) * fgBinSize;

}

// //********************************************************

 Double_t D0Fitter::D0FitFct(Double_t* x, Double_t* par)
{
  // fit function:
  // par[0]: background normalisation
  // par[1]: background decay constant
  // par[2]: gauss' mean
  // par[3]: gauss' sigma
  // par[4]: N(D0)
  // x[0]:   mass(D0)
  if(par[3] == 0.) {
    ::Warning("D0Fitter::D0FitFct", "width = 0, reject point");
    TF1::RejectPoint();
    return 0.; // no width ==> senseless!
  }

  // fgBinSize is a static member of D0Fitter 
  // and should be determined before every fit (&Integral)
  // to ensure that it has the value of the histogram's
  // binSize (and not that of another histogram that is 
  // fitted by another instance of D0Fitter)!

  const Double_t dx = (x[0]-par[2]) / par[3];
  const Double_t gaus = 1./(D0Fitter::kSqrtOf2Pi*par[3]) * fgBinSize * par[4]
    * TMath::Exp(-dx*dx / 2.);

  return gaus + D0ExpBackgr(x, par);
}

ClassImp(D0Fitter)

const Double_t D0Fitter::kSqrtOf2Pi = TMath::Sqrt(2.*TMath::Pi());
const Double_t D0Fitter::fgBackgrSlopeDefault = -1.2;
const Double_t D0Fitter::fgSigmaDefault = .03;
const Double_t D0Fitter::fgMeanDefault = 
                         TDatabasePDG::Instance()->GetParticle(421)->Mass();
const Double_t D0Fitter::fgUpFitLimitDefault = D0Fitter::fgMeanDefault+ .25; 
// const Double_t D0Fitter::fgLowFitLimitDefault = D0Fitter::fgMeanDefault-.25;
const Double_t D0Fitter::fgLowFitLimitDefault = 1.7;
Double_t D0Fitter::fgUpFitLimit  = D0Fitter::fgUpFitLimitDefault;
Double_t D0Fitter::fgLowFitLimit = D0Fitter::fgLowFitLimitDefault;
Double_t D0Fitter::fgBinSize = 0.01;//-1.0;

//*********************************************************

 D0Fitter::D0Fitter(TH1* hist) :fFitOption("ERI") // "M" leads to endless loop in ROOT < 4.X
{
  // default ctor

/*
fitoption
= "W"  Set all errors to 1
= "I" Use integral of function in bin instead of value at bin
                    center
= "L" Use Loglikelihood method (default is chisquare method)
= "U" Use a User specified fitting algorithm (via SetFCN)
= "Q" Quiet mode (minimum printing)
= "V" Verbose mode (default is between Q and V)
= "E" Perform better Errors estimation using Minos technique
= "M" More. Improve fit results
= "B" Take care of initial values of parameter, even for
                    predefined fcts as gaus, pol1,...
= "R" Use the Range specified in the function range
= "N" Do not store the graphics function, do not draw
= "0" Do not plot the result of the fit. By default the
             fitted function is drawn unless the
             option"N" above is specified.
= "+" Add this new fitted function to the list of fitted
             functions (by default, any previous function
             is deleted)
*/

  fLowFitLimit = fgLowFitLimitDefault;
  fUpFitLimit = fgUpFitLimitDefault;

  fFixMean = fFixSigma = fFixBackgrSlope = kFALSE;

  // FIXME
//   fD0FitFormu = new TF1("fGleichUmbenennen!", "expo(0) + gaus(2)",
// 			fLowFitLimit, fUpFitLimit);
  fD0FitFormu = new TF1("D0FitFormu", D0FitFct, fLowFitLimit, fUpFitLimit,5);
  gROOT->GetListOfFunctions()->Remove(fD0FitFormu);
  fD0FitFormu->SetBit(TFormula::kNotGlobal);

  this->SetHist(hist, kTRUE); // default fit values are set!
}

//___________________________________________
 D0Fitter::~D0Fitter()
{
  delete fD0FitFormu;
}

//___________________________________________
 void D0Fitter::Fit(Int_t mode)
{
  
  if(!fHist) {
    this->Error("Fit","No histogram! Fit canceled!");
    return;
  }

  Double_t backgrNormStart = this->DetermBackgrStartParam();
  Double_t nD0Start = this->DetermNDstarStart(backgrNormStart);
  this->DetermFitMode(mode); // which parameter should be fixed?
  this->DoTheFit(backgrNormStart, nD0Start);
  // add background function to hist:
  this->AddBackgrToHist();
}

//_______________________________________________
 void D0Fitter::DoTheFit(Double_t backgrNormStart, 
				    Double_t nD0Start)
{
  // does the fit having found startvalues

  TF1* f = new TF1("fGleichUmbenennen!", D0FitFct,
		   fLowFitLimit, fUpFitLimit, 5);
//   TF1* f = new TF1("fGleichUmbenennen!", "expo(0) + gaus(2)",
// 		   fLowFitLimit, fUpFitLimit);
  gROOT->GetListOfFunctions()->Remove(f);
  f->SetBit(TFormula::kNotGlobal);
  f->SetParameters(backgrNormStart, this->GetBackgrSlope(),
 		   this->GetMean(), this->GetSigma(), nD0Start);
  f->SetParNames("U_{n}","U_{s}", "#mu","#sigma","N(D^{0})");
  delete fD0FitFormu;
  fD0FitFormu = f;
  fD0FitFormu->SetName("D0FitFormu");

  if(fFixBackgrSlope) fD0FitFormu->SetParLimits(1,1,1);
  if(fFixMean)        fD0FitFormu->SetParLimits(2,1,1);
  if(fFixSigma)       fD0FitFormu->SetParLimits(3,1,1);

  fgBinSize = GetHistBinSize(); // important!!!!!!!!!!
  fgLowFitLimit = fLowFitLimit; // ...used in 
  fgUpFitLimit  = fUpFitLimit;  // ... backgrfct

  fHist->Fit(fD0FitFormu, 
	     this->UseLikelihoodOption(fHist) ? 
	     (fFitOption+"0l") : (fFitOption+'0'));
  if(!fFitOption.Contains("0")) {
    fHist->GetFunction("D0FitFormu")->ResetBit(1<<9);
  }
}

//*********************************************************

 const char* D0Fitter::GetHistName() const
{
  // returns name of the histogram that should be fitted
  if(fHist) return fHist->GetName();
  else {
    this->Warning("GetHistName","There is no histogram!");
    return "There is no histogram!";
  }
  
}

//******************************************************

 Double_t D0Fitter::GetHistBinSize() const
{
  // evaluates the bin size of the histogram
  // and prints warnings if it's not constant
  if(!fHist){
    this->Error("GetHistBinSize","There is no histogram! Return 100.");
    return 100.;
  }
  Int_t ind = fHist->FindBin(fgMeanDefault);
  Double_t binSize = fHist->GetBinLowEdge(ind+1) - fHist->GetBinLowEdge(ind);
  
  // I don't check binSize not to be 0,
  // but I do check that it's more or less constant:
  Int_t nBins = fHist->GetNbinsX();
  for(Int_t i = 1; i <= nBins; i++){
    Double_t actBinSize = 
      Double_t(fHist->GetBinLowEdge(i+1) - fHist->GetBinLowEdge(i));
    if(TMath::Abs(binSize - actBinSize)/binSize >0.0001){//0.01% deviat.
      this->Error("GetHistBinSize",
		  "histogram does NOT have constant binSize!");
      break;
    }
  }
  return binSize;
}

//_____________________________________
 void D0Fitter::SetHist(TH1* hist,
		       Bool_t defaultSigmaMeanBackgr)
{
  // interface to set a TH1* hist (may not be a TH2* or TH3*!)
  // if defaultSigmaMeanBack is kTRUE (its default is kFALSE),
  //     default values are set 
  //     for Sigma, Mean, amd background parameters
  // else they are taken as they are (e.g. from the last fit)
  // ??????
  // by default defaultSigmaMeanBackgr is kFALSE, if kTRUE, 
  // Sigma, Mean and background parameters are set to the default.

  fHist = hist;

  if(defaultSigmaMeanBackgr){ // sets defaults, 
    fD0FitFormu->SetParameters(10000., this->GetBackgrSlopeDefault(),
			       this->GetMeanDefault(), 
			       this->GetSigmaDefault(), 100.);
  } // else last values are used for next fit

  if(!hist) {
    return;
    //     this->Warning("SetHist", "No histogram set!");
  }  else if(hist->InheritsFrom(TH2::Class())||hist->InheritsFrom(TH3::Class())){
    this->Error("SetHist","Histogram given to fit is a TH2 or a TH3!");
  }

  cout << "Fitted histogram is " << fHist->GetName()  << endl;
}

//********************************************************

 Double_t D0Fitter::DetermBackgrStartParam()
{
  // determines start parameter for background fit
  Double_t startBackgr = 
    fHist->Integral() - 
    0.25 * fHist->Integral(fHist->FindBin(this->GetMean() - 2.5 * this->GetSigma()),// S/U = 1:3
			   fHist->FindBin(this->GetMean() + 2.5 * this->GetSigma()));
  cout << "Start parameter for backgr norm: " << startBackgr
       << endl;
  return startBackgr;
}

//________________________________
 Double_t D0Fitter::DetermNDstarStart(Double_t backgrNormStart)
{
  // determines start value of N(D0)
  Double_t signalLow = this->GetMean() - 2. * this->GetSigma();
  Double_t signalUp  = signalLow       + 4. * this->GetSigma();
  Int_t binD0Low = fHist->FindBin(signalLow);
  Int_t binD0Up = fHist->FindBin(signalUp);
  Double_t integral = fHist->Integral(binD0Low, binD0Up);

  TF1 backGr("backGrD0tmp", D0ExpBackgr, fLowFitLimit, fUpFitLimit, 2);
  backGr.SetParameters(backgrNormStart, this->GetBackgrSlope());

  fgBinSize = this->GetHistBinSize(); // fgBinSize is used in BackgrFct!
  fgLowFitLimit = fLowFitLimit; // dito used in 
  fgUpFitLimit  = fUpFitLimit;  // ... backgrfct

  Double_t backgrIntegr = 
    backGr.Integral(signalLow, signalUp) / fgBinSize;
  
  Double_t nD0Start = integral-backgrIntegr;
  if(nD0Start < 0.) nD0Start = 30.;
  cout << "Start parameter for N(D0): " << nD0Start
       << endl;
  return nD0Start;
}

//********************************************************

 void D0Fitter::AddBackgrToHist()
{
  TF1* backGr = new TF1("backGrD0", D0ExpBackgr, 
			fLowFitLimit, fUpFitLimit, 2);
  backGr->SetParameters(this->GetBackgrNorm(), this->GetBackgrSlope());
  backGr->SetParent(fHist);
  gROOT->GetListOfFunctions()->Remove(backGr);
  backGr->SetBit(TFormula::kNotGlobal);
  backGr->SetLineStyle(2);
  backGr->SetLineWidth(2);
  backGr->SetFillStyle(0); // no filling: Why do we need to set it here...? Since 3.04_02!
  TList* hFuncList = fHist->GetListOfFunctions();
  hFuncList->Add(backGr); // now fHist is responsible for 
  //                    deleting backGr
}

//********************************************************

 Bool_t D0Fitter::UseLikelihoodOption(TH1* hist)
{
  // determine use of likelihood option in fit
  // false if hists filled with weights
  // true if more than 1 bin from lowfitlimit to upfitlimit <= 5 entries

  if(hist->GetSumw2N()){ // hist has some error values stored...
    for(Int_t i = 1; i <= hist->GetNbinsX(); ++i){
      const Double_t error = hist->GetBinError(i);
      if(TMath::Abs(TMath::Abs(hist->GetBinContent(i)) - error*error) > 1.e-10){
#if ROOT_VERSION_CODE > ROOT_VERSION(3,3,0)
        this->Info("UseLikelihoodOption", "No likelihood (weights!)");
#else
        this->Warning("UseLikelihoodOption", "No likelihood (weights!)");
#endif
        return kFALSE;
      }
    }
  }

  Int_t numLowStatBins = 0;
  const Int_t lastBin = TMath::Min(hist->FindBin(this->GetUpFitLimit()), hist->GetNbinsX());
  for(Int_t i = TMath::Max(1, hist->FindBin(this->GetLowFitLimit())); i < lastBin; ++i){
    if(hist->GetBinContent(i) <= 5) {
      if(++numLowStatBins > 1) {
	cout << "Switched to likelihood!" << endl;
	return kTRUE;
      }
    }
  }

  return kFALSE;
}

//******************************************************

 void D0Fitter::DetermFitMode(Int_t mode)
{
  //interprets mode and saves the result in the foreseen Bool_t's
  fFixMean        =  mode        % 10;
  fFixSigma       = (mode /= 10) % 10;
  fFixBackgrSlope = (mode /= 10) % 10;
}

//******************************************************

 Double_t D0Fitter::GetBackgrNorm() const
{
  // get 
  return fD0FitFormu->GetParameter(0);
}

//******************************************************

 Double_t D0Fitter::GetBackgrSlope() const
{
  // get 
  return fD0FitFormu->GetParameter(1);
}

//******************************************************

 Double_t D0Fitter::GetMean() const
{
  // get mean of D0-Peak
  return fD0FitFormu->GetParameter(2);
}

//******************************************************

 Double_t D0Fitter::GetSigma() const
{
  // get sigma of D0-peak
  return fD0FitFormu->GetParameter(3);
}

//**********************************************

 Double_t D0Fitter::GetND0() const
{
  // get N(D0)
  return fD0FitFormu->GetParameter(4);
}

//******************************************************

 Double_t D0Fitter::GetND0Err() const
{
  // get sigma(N(D*))
  return fD0FitFormu->GetParError(4);
}

//******************************************************

 void D0Fitter::SetBackgrSlope(Double_t m)
{
  // set 
  fD0FitFormu->SetParameter(1, m);
}

//******************************************************

 void D0Fitter::SetMean(Double_t m)
{
  // set mean of D0-Peak
  fD0FitFormu->SetParameter(2, m);
}

//******************************************************

 void D0Fitter::SetSigma(Double_t s)
{
  // set sigma of D0-peak
  fD0FitFormu->SetParameter(3, s);
}



ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.