ROOT logo
void RebinSpectrum(TH1** hi,TH1** hf,TF1* f,int n=1,int dofit=0,TH1* ht=0){
  /* Author: Anders G. Knospe, The University of Texas at Austin
     Created: 9 May 2014

     This macro rebins histograms, including cases with incompatible bins.

     Input Parameters:
     hi: an array of 1-dimensional histograms containing the original distribution
     hf: an array of 1-dimensional histograms with the new desired binning
     f: a TF1 fit function that is used to estimate how to divide the contents of bins that must be split
     n: the size of the arrays hi and hf
     dofit: if dofit=1 the histogram hi[0] will be fit with function f; if dofit==0 it is assumed that function f already describes the distribution (i.e., the fit was done outside this macro)
     ht: a 1-dimensional histogram that will be used for fitting if dofit==1; it should include the total uncertainties (statistical plus systematic, but excluding uncertainties correlated between pT bins)

     hi and hf are arrays so that systematic uncertainties can be accounted for.  hi[0] should contain the central values and statistical uncertainties.  The other histograms in hi[*] (if any) should contain the systematic uncertainties (more than one type of systematic uncertainty is allowed).  The output histogram hf[0] will contain the rebinned central values and statistical uncertainties.  The other output histograms hf[*] (if any) will contain the systematic uncertainties.  Going from hi[0] to hf[0], the statistical uncertainties are added in quadrature.  For the other histograms, the systematic uncertainties are added linearly.  It is assumed that all of the histograms in hi and ht have the same binning, and that all of the histograms in hf have the same binning.

     Explanation: The macro rebins from the input histogram to the output histogram.  Let A be a bin in the input histogram and let B be a bin in the output histogram.  If A lies entirely within B, the situation is simple: the contents of bin A will be added to bin B.  If A is split by one (or both) of the edges of B, a fit function is used to determine the fraction of the content of bin A that will be added to bin B.  The fitting may be done externally, or this macro can be used to do the fit over a limited range (generally, the fit will be over A and the two bins adjacent to it).

     Suggested Usage:

       TH1F* hi[3];//input histogram array
       int n=3;//size of array hi
       hi[0]=new TH1F... //fill with central values and statistical uncertainties
       hi[1]=new TH1F... //fill with central values and first type of systematic uncertainties
       hi[2]=new TH1F... //fill with central values and second type of systematic uncertainties

       TH1F* hf[3];//output (rebinned) histogram array, define histograms with new binning
       hf[0]=new TH1F... //will be filled with rebinned central values and statistical uncertainties (added in quadrature)
       hi[1]=new TH1F... //will be filled with rebinned central values and first type of systematic uncertainties (added linearly)
       hi[2]=new TH1F... //will be filled with rebinned central values and second type of systematic uncertainties (added linearly)

       TH1F* ht=new TH1F...//the input histogram with total (uncorrelated) uncertainties, should have the central values of hi[0], the uncertainties should be the sum of the statistical and systematic uncertainties in hi, excluding sources that are correalted between pT bins, this is the histogram that will be fit if dofit==1 (if dofit==0, you can set ht=0)

       TF1* f=new TF1("fit","[0]*exp([1]*x)",0.,10.);//define a fit function
       f->SetParameters(1.,-1.);//initialize fit parameters
       //You can do the fit in your own code, or let RebinSpectrum do it over a limited range as needed (depending on the value of dofit).  This macro can be used even if no fit is needed, but a placeholder fit function will still need to be defined.
       int dofit=1;//let RebinSpectrum do the fit

       RebinSpectrum(hi,hf,f,n,dofit,ht);
       //hf now contains the rebinned histograms
  */

  int j,k,l;
  double ai,bi,di,e,af,bf,df,v[100],u[100],d;

  for(j=0;j<n;j++) if(!hi[j]){cerr<<"Error in RebinSpectrum(): missing input histogram "<<j<<endl; return;}
  for(j=0;j<n;j++) if(!hf[j]){cerr<<"Error in RebinSpectrum(): missing output histogram "<<j<<endl; return;}
  if(!f){cerr<<"Error in RebinSpectrum(): missing fit function"<<endl; return;}
  if(n<1 || n>99){cerr<<"Error in RebinSpectrum(): invalid value for n "<<n<<endl; return;}
  if(dofit && !ht){cerr<<"Error in RebinSpectrum(): missing fit histogram"<<endl; return;}

  if(dofit) cerr<<"Info in RebinSpectrum(): will do fit inside macro RebinSpectrum.C"<<endl;
  else cerr<<"Info in RebinSpectrum(): using external fit"<<endl;

  for(j=0;j<n;j++) for(l=0;l<=hf[j]->GetNbinsX()+1;l++){
      //clear the output histograms
      hf[j]->SetBinContent(l,0.);
      hf[j]->SetBinError(l,0.);
    }

  for(l=1;l<=hf[0]->GetNbinsX();l++){
    af=hf[0]->GetXaxis()->GetBinLowEdge(l);
    bf=hf[0]->GetXaxis()->GetBinLowEdge(l+1);
    df=hf[0]->GetXaxis()->GetBinWidth(l);
    e=1.e-5*df;

    for(j=0;j<n;j++) v[j]=u[j]=0.;

    for(k=1;k<=hi[0]->GetNbinsX();k++){
      ai=hi[0]->GetXaxis()->GetBinLowEdge(k);
      bi=hi[0]->GetXaxis()->GetBinLowEdge(k+1);
      di=hi[0]->GetXaxis()->GetBinWidth(k);

      if(bi<af+e || ai>bf-e) continue;//bin k of hi completely outside bin l of hf
      else if(ai>=af-e && bi<=bf+e){
	//bin k of hi completely contained within bin l of hf
	d=1.;
      }else if(ai<af-e || bi>bf-e){
	//bin k of hi is split by the edge(s) of bin l of hf
	cerr<<"Info in RebinSpectrum(): splitting hi("<<ai<<","<<bi<<") hf("<<af<<","<<bf<<")"<<endl;
	if(dofit){
	  if(k==1 || ht->GetBinContent(k-1)<1.e-30){
	    //k is the first non-empty bin of ht, fit bin k and the two following bins
	    f->SetRange(ht->GetBinLowEdge(k),ht->GetBinLowEdge(k+3));
	  }else if(k==ht->GetNbinsX() || ht->GetBinContent(k+1)<1.e-30){
	    //k is the last non-empty bin of ht, fit bin k and the two preceeding bins
	    f->SetRange(ht->GetBinLowEdge(k-2),ht->GetBinLowEdge(k+1));
	  }else{
	    //k is neither the first nor the last non-empty bin of ht
	    f->SetRange(ht->GetBinLowEdge(k-1),ht->GetBinLowEdge(k+2));
	  }

	  ht->Fit(f,"NR");
	}

	if(ai<af-e && bi<bf-e){
	  //bin k of hi is split by the low edge of bin l of hf
	  d=f->Integral(af,bi)/f->Integral(ai,bi);
	}else if(ai<bf-e && bi>bf+e){
	  //bin k of hi is split by the high edge of bin l of hf
	  d=f->Integral(ai,bf)/f->Integral(ai,bi);
	}else if(ai<af-e && bi>bf+e){
	  //bin k of hi completely contains bin l of hf
	  d=f->Integral(af,bf)/f->Integral(ai,bi);
	}else{
	  cerr<<"Error in RebinSpectrum(): undefined case: hi("<<ai<<","<<bi<<") hf("<<af<<","<<bf<<")"<<endl;
	  continue;
	}
      }

      for(j=0;j<n;j++){
	v[j]+=d*hi[j]->GetBinContent(k)*di;//add the content of bin k of hi[j] to the total
	if(!j) u[j]+=pow(d*hi[j]->GetBinError(k)*di,2);//add (in quadrature) the uncertainty of bin k of hi[0] to the total
	else u[j]+=d*hi[j]->GetBinError(k)*di;//add (linearly) the uncertainty of bin k of hi[j] to the total (for j>=1)
      }
    }

    for(j=0;j<n;j++){
      v[j]/=df;
      if(!j) u[j]=sqrt(u[j]);
      u[j]/=df;

      //fill the output histograms
      hf[j]->SetBinContent(l,v[j]);
      hf[j]->SetBinError(l,u[j]);
    }
  }

  return;
}
 RebinSpectrum.C:1
 RebinSpectrum.C:2
 RebinSpectrum.C:3
 RebinSpectrum.C:4
 RebinSpectrum.C:5
 RebinSpectrum.C:6
 RebinSpectrum.C:7
 RebinSpectrum.C:8
 RebinSpectrum.C:9
 RebinSpectrum.C:10
 RebinSpectrum.C:11
 RebinSpectrum.C:12
 RebinSpectrum.C:13
 RebinSpectrum.C:14
 RebinSpectrum.C:15
 RebinSpectrum.C:16
 RebinSpectrum.C:17
 RebinSpectrum.C:18
 RebinSpectrum.C:19
 RebinSpectrum.C:20
 RebinSpectrum.C:21
 RebinSpectrum.C:22
 RebinSpectrum.C:23
 RebinSpectrum.C:24
 RebinSpectrum.C:25
 RebinSpectrum.C:26
 RebinSpectrum.C:27
 RebinSpectrum.C:28
 RebinSpectrum.C:29
 RebinSpectrum.C:30
 RebinSpectrum.C:31
 RebinSpectrum.C:32
 RebinSpectrum.C:33
 RebinSpectrum.C:34
 RebinSpectrum.C:35
 RebinSpectrum.C:36
 RebinSpectrum.C:37
 RebinSpectrum.C:38
 RebinSpectrum.C:39
 RebinSpectrum.C:40
 RebinSpectrum.C:41
 RebinSpectrum.C:42
 RebinSpectrum.C:43
 RebinSpectrum.C:44
 RebinSpectrum.C:45
 RebinSpectrum.C:46
 RebinSpectrum.C:47
 RebinSpectrum.C:48
 RebinSpectrum.C:49
 RebinSpectrum.C:50
 RebinSpectrum.C:51
 RebinSpectrum.C:52
 RebinSpectrum.C:53
 RebinSpectrum.C:54
 RebinSpectrum.C:55
 RebinSpectrum.C:56
 RebinSpectrum.C:57
 RebinSpectrum.C:58
 RebinSpectrum.C:59
 RebinSpectrum.C:60
 RebinSpectrum.C:61
 RebinSpectrum.C:62
 RebinSpectrum.C:63
 RebinSpectrum.C:64
 RebinSpectrum.C:65
 RebinSpectrum.C:66
 RebinSpectrum.C:67
 RebinSpectrum.C:68
 RebinSpectrum.C:69
 RebinSpectrum.C:70
 RebinSpectrum.C:71
 RebinSpectrum.C:72
 RebinSpectrum.C:73
 RebinSpectrum.C:74
 RebinSpectrum.C:75
 RebinSpectrum.C:76
 RebinSpectrum.C:77
 RebinSpectrum.C:78
 RebinSpectrum.C:79
 RebinSpectrum.C:80
 RebinSpectrum.C:81
 RebinSpectrum.C:82
 RebinSpectrum.C:83
 RebinSpectrum.C:84
 RebinSpectrum.C:85
 RebinSpectrum.C:86
 RebinSpectrum.C:87
 RebinSpectrum.C:88
 RebinSpectrum.C:89
 RebinSpectrum.C:90
 RebinSpectrum.C:91
 RebinSpectrum.C:92
 RebinSpectrum.C:93
 RebinSpectrum.C:94
 RebinSpectrum.C:95
 RebinSpectrum.C:96
 RebinSpectrum.C:97
 RebinSpectrum.C:98
 RebinSpectrum.C:99
 RebinSpectrum.C:100
 RebinSpectrum.C:101
 RebinSpectrum.C:102
 RebinSpectrum.C:103
 RebinSpectrum.C:104
 RebinSpectrum.C:105
 RebinSpectrum.C:106
 RebinSpectrum.C:107
 RebinSpectrum.C:108
 RebinSpectrum.C:109
 RebinSpectrum.C:110
 RebinSpectrum.C:111
 RebinSpectrum.C:112
 RebinSpectrum.C:113
 RebinSpectrum.C:114
 RebinSpectrum.C:115
 RebinSpectrum.C:116
 RebinSpectrum.C:117
 RebinSpectrum.C:118
 RebinSpectrum.C:119
 RebinSpectrum.C:120
 RebinSpectrum.C:121
 RebinSpectrum.C:122
 RebinSpectrum.C:123
 RebinSpectrum.C:124
 RebinSpectrum.C:125
 RebinSpectrum.C:126
 RebinSpectrum.C:127
 RebinSpectrum.C:128
 RebinSpectrum.C:129
 RebinSpectrum.C:130
 RebinSpectrum.C:131