示例#1
0
文件: h.cpp 项目: jpoveda/trtgarfx
void ProcessSignal()
{
  signal.Scale(3);
  signal.WriteHSpiceSignalInclude("../ASDBLR/hspice.inc","isource","n1a","0");

  system("hspice ../ASDBLR/ASDSigs.hsp >hspice.out");

  Signals::Signal Ternary(0.5);
  std::vector<std::string> TernaryVar;
  TernaryVar.push_back("ternary");
  TernaryVar.push_back("");
  TernaryVar.push_back("");
  Ternary.ReadSignalFromHSpicelis("hspice.out",TernaryVar);
  Ternary.Shift(-Ternary.GetSignalBin(0));
  Signals::Discriminate disc(0.5,0.4);
  Signals::Rebin rebin(25);
  Signals::Discriminate lowdisc(0.5,0.1);
  Signals::Rebin lowrebin(3.125);
  Ternary>>disc>>rebin;
  Ternary>>lowdisc>>lowrebin;
  std::cout<<"FirstBins:"<<rebin.FirstBinBlock()<<std::endl;
  std::cout<<"LowFirstBins:"<<lowrebin.FirstBinBlock()<<std::endl;
  std::cout<<"Ternary"<<Ternary.IntegralBelow(0)<<std::endl;
  std::cout<<lowdist<<std::endl;
  lowdist->Fill(lowrebin.FirstBinBlock());
  std::cout<<highdist<<std::endl;
  highdist->Fill(rebin.FirstBinBlock());
  std::cout<<"FILL//"<<std::endl;
}
示例#2
0
/**
 * Reacts to the user selecting the BinMD algorithm
 */
void StandardView::onRebin() {
  if (QAction *action = dynamic_cast<QAction *>(sender())) {
    // split always returns a list of at least one element
    QString algName = getAlgNameFromMenuLabel(action->text());
    emit rebin(algName.toStdString());
  }
}
示例#3
0
文件: cs.cpp 项目: jpoveda/trtgarfx
unsigned int ProcessSignal(Signals::Signal& signal,std::string signalid)
{
  signal.Graph()->Draw("AL");
  canvas->Update();
  canvas->Print(("debs/"+signalid+"sig.pdf").c_str());
  signal.WriteHSpiceSignalInclude("../ASDBLR/hspice.inc","isource","n1a","0");

  system("hspice ../ASDBLR/ASDSigs.hsp >hspice.out");

  Signals::Signal Ternary(0.5);
  std::vector<std::string> TernaryVar;
  TernaryVar.push_back("ternary");
  TernaryVar.push_back("");
  TernaryVar.push_back("");
  Ternary.ReadSignalFromHSpicelis("hspice.out",TernaryVar);
  Ternary.Shift(-Ternary.GetSignalBin(0));
  Ternary.Graph()->Draw("AL");
  canvas->Update();
  canvas->Print(("debs/"+signalid+"ter.pdf").c_str());
  Signals::Discriminate disc(0.5,0.4);
  Signals::Rebin rebin(25);
  Signals::Discriminate lowdisc(0.5,0.1);
  Signals::Rebin lowrebin(3.125);
  Ternary>>disc>>rebin;
  Ternary>>lowdisc>>lowrebin;
  leadingb=disc.LeadingBin()*disc.GetSignalBinTime();
  trailingb=disc.TrailingBin()*disc.GetSignalBinTime();
  lastbinblock=disc.LastBinBlock()*disc.GetSignalBinTime();
  return disc.FirstBinBlock()*disc.GetSignalBinTime();
}
TH2F* smoothtemplates(TH2F* inputdata, int sampleIndex){
  if(sampleIndex<3){
    rebin(inputdata,sampleIndex);
  }
  else if(sampleIndex>2){
    rebin_lowstatistics(inputdata,sampleIndex);
  }

  return inputdata;
}
示例#5
0
void vegas(double regn[], int ndim, double (*fxn)(double [], double), int init,
	unsigned long ncall, int itmx, int nprn, double *tgral, double *sd,
	double *chi2a)
{
	double ran2(long *idum);
	void rebin(double rc, int nd, double r[], double xin[], double xi[]);
	static int i,it,j,k,mds,nd,ndo,ng,npg,ia[MXDIM+1],kg[MXDIM+1];
	static double calls,dv2g,dxg,f,f2,f2b,fb,rc,ti,tsi,wgt,xjac,xn,xnd,xo;
	static double d[NDMX+1][MXDIM+1],di[NDMX+1][MXDIM+1],dt[MXDIM+1],
		dx[MXDIM+1], r[NDMX+1],x[MXDIM+1],xi[MXDIM+1][NDMX+1],xin[NDMX+1];
	static double schi,si,swgt;

	if (init <= 0) {
		mds=ndo=1;
		for (j=1;j<=ndim;j++) xi[j][1]=1.0;
	}
	if (init <= 1) si=swgt=schi=0.0;
	if (init <= 2) {
		nd=NDMX;
		ng=1;
		if (mds) {
			ng=(int)pow(ncall/2.0+0.25,1.0/ndim);
			mds=1;
			if ((2*ng-NDMX) >= 0) {
				mds = -1;
				npg=ng/NDMX+1;
				nd=ng/npg;
				ng=npg*nd;
			}
		}
		for (k=1,i=1;i<=ndim;i++) k *= ng;
		npg=IMAX(ncall/k,2);
		calls=(double)npg * (double)k;
		dxg=1.0/ng;
		for (dv2g=1,i=1;i<=ndim;i++) dv2g *= dxg;
		dv2g=SQR(calls*dv2g)/npg/npg/(npg-1.0);
		xnd=nd;
		dxg *= xnd;
		xjac=1.0/calls;
		for (j=1;j<=ndim;j++) {
			dx[j]=regn[j+ndim]-regn[j];
			xjac *= dx[j];
		}
		if (nd != ndo) {
			for (i=1;i<=IMAX(nd,ndo);i++) r[i]=1.0;
			for (j=1;j<=ndim;j++) rebin(ndo/xnd,nd,r,xin,xi[j]);
			ndo=nd;
		}
		if (nprn >= 0) {
//			printf("%s:  ndim= %3d  ncall= %8.0f\n",
//				" Input parameters for vegas",ndim,calls);
//			printf("%28s  it=%5d  itmx=%5d\n"," ",it,itmx);
//			printf("%28s  nprn=%3d  ALPH=%5.2f\n"," ",nprn,ALPH);
//			printf("%28s  mds=%3d  nd=%4d\n"," ",mds,nd);
//			for (j=1;j<=ndim;j++) {
//				printf("%30s xl[%2d]= %11.4g xu[%2d]= %11.4g\n",
//					" ",j,regn[j],j,regn[j+ndim]);
//			}
		}
	}
	for (it=1;it<=itmx;it++) {
		ti=tsi=0.0;
		for (j=1;j<=ndim;j++) {
			kg[j]=1;
			for (i=1;i<=nd;i++) d[i][j]=di[i][j]=0.0;
		}
		for (;;) {
			fb=f2b=0.0;
			for (k=1;k<=npg;k++) {
				wgt=xjac;
				for (j=1;j<=ndim;j++) {
					xn=(kg[j]-ran2(&idum))*dxg+1.0;
					ia[j]=IMAX(IMIN((int)(xn),NDMX),1);
					if (ia[j] > 1) {
						xo=xi[j][ia[j]]-xi[j][ia[j]-1];
						rc=xi[j][ia[j]-1]+(xn-ia[j])*xo;
					} else {
						xo=xi[j][ia[j]];
						rc=(xn-ia[j])*xo;
					}
					x[j]=regn[j]+rc*dx[j];
					wgt *= xo*xnd;
				}
				f=wgt*(*fxn)(x,wgt);
				f2=f*f;
				fb += f;
				f2b += f2;
				for (j=1;j<=ndim;j++) {
					di[ia[j]][j] += f;
					if (mds >= 0) d[ia[j]][j] += f2;
				}
			}
			f2b=sqrt(f2b*npg);
			f2b=(f2b-fb)*(f2b+fb);
			if (f2b <= 0.0) f2b=TINY;
			ti += fb;
			tsi += f2b;
			if (mds < 0) {
				for (j=1;j<=ndim;j++) d[ia[j]][j] += f2b;
			}
			for (k=ndim;k>=1;k--) {
				kg[k] %= ng;
				if (++kg[k] != 1) break;
			}
			if (k < 1) break;
		}
		tsi *= dv2g;
		wgt=1.0/tsi;
		si += wgt*ti;
		schi += wgt*ti*ti;
		swgt += wgt;
		*tgral=si/swgt;
		*chi2a=(schi-si*(*tgral))/(it-0.9999);
		if (*chi2a < 0.0) *chi2a = 0.0;
		*sd=sqrt(1.0/swgt);
		tsi=sqrt(tsi);
		if (nprn >= 0) {
//			printf("%s %3d : integral = %14.7g +/-  %9.2g\n",
//				" iteration no.",it,ti,tsi);
//			printf("%s integral =%14.7g+/-%9.2g chi**2/IT n = %9.2g\n",
//				" all iterations:  ",*tgral,*sd,*chi2a);
			if (nprn) {
				for (j=1;j<=ndim;j++) {
//					printf(" DATA FOR axis  %2d\n",j);
//					printf("%6s%13s%11s%13s%11s%13s\n",
//						"X","delta i","X","delta i","X","delta i");
					for (i=1+nprn/2;i<=nd;i += nprn+2) {
//						printf("%8.5f%12.4g%12.5f%12.4g%12.5f%12.4g\n",
//							xi[j][i],di[i][j],xi[j][i+1],
//							di[i+1][j],xi[j][i+2],di[i+2][j]);
					}
				}
			}
		}
		for (j=1;j<=ndim;j++) {
			xo=d[1][j];
			xn=d[2][j];
			d[1][j]=(xo+xn)/2.0;
			dt[j]=d[1][j];
			for (i=2;i<nd;i++) {
				rc=xo+xn;
				xo=xn;
				xn=d[i+1][j];
				d[i][j] = (rc+xn)/3.0;
				dt[j] += d[i][j];
			}
			d[nd][j]=(xo+xn)/2.0;
			dt[j] += d[nd][j];
		}
		for (j=1;j<=ndim;j++) {
			rc=0.0;
			for (i=1;i<=nd;i++) {
				if (d[i][j] < TINY) d[i][j]=TINY;
				r[i]=pow((1.0-d[i][j]/dt[j])/
					(log(dt[j])-log(d[i][j])),ALPH);
				rc += r[i];
			}
			rebin(rc/xnd,nd,r,xin,xi[j]);
		}
	}
}
示例#6
0
/** Executes the regroup algorithm
 *
 *  @throw runtime_error Thrown if
 */
void Regroup::exec()
{
  // retrieve the properties
  std::vector<double> rb_params=getProperty("Params");

  // Get the input workspace
  MatrixWorkspace_const_sptr inputW = getProperty("InputWorkspace");

  // can work only if all histograms have the same boundaries
  if (!API::WorkspaceHelpers::commonBoundaries(inputW))
  {
    g_log.error("Histograms with different boundaries");
    throw std::runtime_error("Histograms with different boundaries");
  }

  bool dist = inputW->isDistribution();

  int histnumber = static_cast<int>(inputW->getNumberHistograms());
  MantidVecPtr XValues_new;
  const MantidVec & XValues_old = inputW->readX(0);
  std::vector<int> xoldIndex;// indeces of new x in XValues_old
  // create new output X axis
  int ntcnew = newAxis(rb_params,XValues_old,XValues_new.access(),xoldIndex);

  // make output Workspace the same type is the input, but with new length of signal array
  API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(inputW,histnumber,ntcnew,ntcnew-1);

  int progress_step = histnumber / 100;
  if (progress_step == 0) progress_step = 1;
  for (int hist=0; hist <  histnumber;hist++)
  {
    // get const references to input Workspace arrays (no copying)
    const MantidVec& XValues = inputW->readX(hist);
    const MantidVec& YValues = inputW->readY(hist);
    const MantidVec& YErrors = inputW->readE(hist);

    //get references to output workspace data (no copying)
    MantidVec& YValues_new=outputW->dataY(hist);
    MantidVec& YErrors_new=outputW->dataE(hist);

    // output data arrays are implicitly filled by function
    rebin(XValues,YValues,YErrors,xoldIndex,YValues_new,YErrors_new, dist);

    outputW->setX(hist,XValues_new);

    if (hist % progress_step == 0)
    {
        progress(double(hist)/histnumber);
        interruption_point();
    }
  }

  outputW->isDistribution(dist);

  // Copy units
  if (outputW->getAxis(0)->unit().get())
    outputW->getAxis(0)->unit() = inputW->getAxis(0)->unit();
  try
  {
    if (inputW->getAxis(1)->unit().get())
      outputW->getAxis(1)->unit() = inputW->getAxis(1)->unit();
   }
  catch(Exception::IndexError) {
    // OK, so this isn't a Workspace2D
  }

  // Assign it to the output workspace property
  setProperty("OutputWorkspace",outputW);

  return;
}
示例#7
0
int image2xy_run(simplexy_t* s,
				 int downsample, int downsample_as_required) {
	int newW, newH;
	anbool free_fimage = FALSE;
	// the factor by which to downsample.
	int S = downsample ? downsample : 1;
	int jj;
    anbool tryagain;
    int rtn = -1;

	if (downsample && downsample > 1) {
		logmsg("Downsampling by %i...\n", S);
        if (!s->image) {
            s->image = upconvert(s->image_u8, s->nx, s->ny);
            free_fimage = TRUE;
        }
		if (!s->image)
			goto bailout;
		rebin(&s->image, s->nx, s->ny, S, &newW, &newH);
		s->nx = newW;
		s->ny = newH;
	}

	do {
		simplexy_run(s);

		tryagain = FALSE;
		if (s->npeaks == 0 &&
			downsample_as_required) {
			logmsg("Downsampling by 2...\n");
			if (s->image_u8) {
				s->image = upconvert(s->image_u8, s->nx, s->ny);
				if (!s->image)
					goto bailout;
				free_fimage = TRUE;
				s->image_u8 = NULL;
			}
			rebin(&s->image, s->nx, s->ny, 2, &newW, &newH);
			s->nx = newW;
			s->ny = newH;
			S *= 2;
			tryagain = TRUE;
			downsample_as_required--;
		}
	} while (tryagain);

	for (jj=0; jj<s->npeaks; jj++) {
		assert(isfinite((s->x)[jj]));
		assert(isfinite((s->y)[jj]));
		// shift the origin to the FITS standard: 
		// center of the lower-left pixel is (1,1).
		(s->x)[jj] = ((s->x)[jj] + 0.5) * (double)S + 0.5;
		(s->y)[jj] = ((s->y)[jj] + 0.5) * (double)S + 0.5;
	}

	dselip_cleanup();
    rtn = 0;
 bailout:
	if (free_fimage) {
		free(s->image);
        s->image = NULL;
    }
	return rtn;
}
/** Calculate a workspace that contains the result of the fit to the
* transmission fraction that was calculated
*  @param raw [in] the workspace with the unfitted transmission ratio data
*  @param rebinParams [in] the parameters for rebinning
*  @param fitMethod [in] string can be Log, Linear, Poly2, Poly3, Poly4, Poly5,
* Poly6
*  @return a workspace that contains the evaluation of the fit
*  @throw runtime_error if the Linear or ExtractSpectrum algorithm fails during
* execution
*/
API::MatrixWorkspace_sptr
CalculateTransmission::fit(API::MatrixWorkspace_sptr raw,
                           std::vector<double> rebinParams,
                           const std::string fitMethod) {
  MatrixWorkspace_sptr output =
      this->extractSpectra(raw, std::vector<size_t>(1, 0));

  Progress progress(this, m_done, 1.0, 4);
  progress.report("CalculateTransmission: Performing fit");

  // these are calculated by the call to fit below
  double grad(0.0), offset(0.0);
  std::vector<double> coeficients;
  const bool logFit = (fitMethod == "Log");
  if (logFit) {
    g_log.debug("Fitting to the logarithm of the transmission");

    MantidVec &Y = output->dataY(0);
    MantidVec &E = output->dataE(0);
    double start = m_done;
    Progress prog2(this, start, m_done += 0.1, Y.size());
    for (size_t i = 0; i < Y.size(); ++i) {
      // Take the log of each datapoint for fitting. Recalculate errors
      // remembering that d(log(a))/da  = 1/a
      E[i] = std::abs(E[i] / Y[i]);
      Y[i] = std::log10(Y[i]);
      progress.report("Fitting to the logarithm of the transmission");
    }

    // Now fit this to a straight line
    output = fitData(output, grad, offset);
  }                                 // logFit true
  else if (fitMethod == "Linear") { // Linear fit
    g_log.debug("Fitting directly to the data (i.e. linearly)");
    output = fitData(output, grad, offset);
  } else { // fitMethod Polynomial
    int order = getProperty("PolynomialOrder");
    std::stringstream info;
    info << "Fitting the transmission to polynomial order=" << order;
    g_log.information(info.str());
    output = fitPolynomial(output, order, coeficients);
  }

  progress.report("CalculateTransmission: Performing fit");

  // if no rebin parameters were set the output workspace will have the same
  // binning as the input ones, otherwise rebin
  if (!rebinParams.empty()) {
    output = rebin(rebinParams, output);
  }
  progress.report("CalculateTransmission: Performing fit");

  // if there was rebinnning or log fitting we need to recalculate the Ys,
  // otherwise we can just use the workspace kicked out by the fitData()'s call
  // to Linear
  if ((!rebinParams.empty()) || logFit) {
    const MantidVec &X = output->readX(0);
    MantidVec &Y = output->dataY(0);
    if (logFit) {
      // Need to transform back to 'unlogged'
      const double m(std::pow(10, grad));
      const double factor(std::pow(10, offset));

      MantidVec &E = output->dataE(0);
      for (size_t i = 0; i < Y.size(); ++i) {
        // the relationship between the grad and interspt of the log fit and the
        // un-logged value of Y contain this dependence on the X (bin center
        // values)
        Y[i] = factor * (std::pow(m, 0.5 * (X[i] + X[i + 1])));
        E[i] = std::abs(E[i] * Y[i]);
        progress.report();
      }
    } // end logFit
    else if (fitMethod == "Linear") {
      // the simpler linear situation
      for (size_t i = 0; i < Y.size(); ++i) {
        Y[i] = (grad * 0.5 * (X[i] + X[i + 1])) + offset;
      }
    } else { // the polynomial fit
      for (size_t i = 0; i < Y.size(); ++i) {
        double aux = 0;
        double x_v = 0.5 * (X[i] + X[i + 1]);

        for (int j = 0; j < static_cast<int>(coeficients.size()); ++j) {
          aux += coeficients[j] * std::pow(x_v, j);
        }
        Y[i] = aux;
      }
    }
  }
  progress.report("CalculateTransmission: Performing fit");

  return output;
}
示例#9
0
文件: createPDF.C 项目: cms-jet/QGDev
// Main function to create the pdf's
int main(int argc, char**argv){
  TString version = "80X";

  // Define binning for pdfs (details and more options in binningConfigurations.h)
  binClass bins;
  if(version.Contains("v2")) 		bins = getV2Binning();
  if(version.Contains("80X")) 		bins = get76XBinning();
  else return 1;

  // For different jet types (if _antib is added bTag is applied)
  for(TString jetType : {"AK4chs","AK4chs_antib"}){ //,"AK4","AK4_antib"}){
    std::cout << "Building pdf's for " << jetType << "..." << std::endl;

    treeLooper t("QCD_AllPtBins", jetType);										// Init tree (third argument is the directory path, if other than default in treeLooper.h)
    bins.setReference("pt",  &t.pt);											// Give the binning class a pointer to the variables used to bin in
    bins.setReference("eta", &t.eta);
    bins.setReference("rho", &t.rho);

    // Creation of the pdfs
    std::map<TString, TH1D*> pdfs;
    for(TString binName : bins.getAllBinNames()){
      for(TString type : {"quark","gluon"}){
        TString histName = "_" + type + "_" + binName;
        pdfs["axis2" + histName] = new TH1D("axis2" + histName, "axis2" + histName, 100, 0, 8);				// Has been 200 bins before, but seemed to have a bit too much fluctuations still
        pdfs["mult"  + histName] = new TH1D("mult"  + histName, "mult"  + histName, 140, 2.5, 142.5);
        pdfs["ptD"   + histName] = new TH1D("ptD"   + histName, "ptD"   + histName, 100, 0, 1);				// Also 200 before
      }
    }


    // Fill pdfs
    TString binName;
    while(t.next()){
      if(!bins.getBinName(binName)) 								continue;		// Find bin and return false if outside ranges
      if(t.jetIdLevel < 3) 									continue;		// Select tight jets
      if(!t.matchedJet) 								 	continue; 		// Only matched jets
      if(t.nGenJetsInCone != 1 || t.nJetsForGenParticle != 1 || t.nGenJetsForGenParticle != 1) 	continue;		// Use only jets matched to exactly one gen jet and gen particle, and no other jet candidates
      if((fabs(t.partonId) > 3 && t.partonId != 21)) 						continue; 		// Keep only udsg
      if(t.bTag) 										continue;		// Anti-b tagging (always false if jetType does not contain "antib")
      if(!t.balanced) 										continue;		// Take only two leading jets with pt3 < 0.15*(pt1+pt2)  (surpresses small radiated jets with pt <<< pthat)
      if(t.mult < 3)										continue;		// Avoid jets with less than 3 particles (otherwise axis2=0)
      TString type = (t.partonId == 21? "gluon" : "quark");								// Define q/g
      TString histName = "_" + type + "_" + binName;

      pdfs["axis2" + histName]->Fill(t.axis2, t.weight);								// "axis2" already contains the log
      pdfs["mult"  + histName]->Fill(t.mult,  t.weight);
      pdfs["ptD"   + histName]->Fill(t.ptD,   t.weight);
    }

    // Try to add statistics from neighbours (first make copy, so you don't get an iterative effect)
    std::map<TString, TH1D*> pdfsCopy;
    for(auto& pdf : pdfs) pdfsCopy[pdf.first] = (TH1D*) pdf.second->Clone(pdf.first + "clone");
    for(TString binName : bins.getAllBinNames()){
      for(TString var : {"axis2","mult","ptD"}){
        for(TString neighbour : bins.getNeighbourBins(binName, var)){							// If neighbours are defined: add their statistics
          for(TString type : {"quark","gluon"}){
            pdfs[var + "_" + type + "_" + binName]->Add(pdfsCopy[var + "_" + type + "_" + neighbour]);
          }
        }
      }
    }
    for(auto& copy : pdfsCopy) delete copy.second;

    // Store the mean and RMS of the original histogram (because they could be changed by rebinning operations)
    std::map<TString, float> mean;
    std::map<TString, float> rms;
    for(auto& pdf : pdfs){
      if(pdf.second->GetEntries() == 0){ std::cout << "Error: no entries in " << pdf.first << std::endl; exit(1);}	// Force to exit when no entries in pdfs: the binning configuration should be altered to avoid this
      mean[pdf.first] = pdf.second->GetMean();
      rms[pdf.first]  = pdf.second->GetRMS();
    }


    // Check "smoothness" of the pdf: if fluctuations seem really big, we do a rebinning
    std::map<TString, int> rebinFactor;
    for(auto& pdf : pdfs){
      bool isBelow      = (mean[pdf.first] < mean[switchQG(pdf.first)]);						// Define region between low(meanQ, meanG) - RMS <--> high(meanQ, meanG) + RMS
      TString low	= isBelow? pdf.first : switchQG(pdf.first);							// Most events will be within those borders, so we should not allow empty bins here
      TString high	= isBelow? switchQG(pdf.first) : pdf.first;							// (an empty bin for 1 of the three variables already results in L = 0 or 1)
      int leftBin	= pdf.second->FindBin(mean[low] - rms[low]) - 1;
      int rightBin	= pdf.second->FindBin(mean[high] + rms[high]) + 1;
     
      int leftBin2      = 0;												// Define region of the peak: most extreme bins which exceed 80% of the maximum
      int rightBin2     = 0;												// We will check for bins within this region which go below 70%
      for(int bin = 1; bin < pdf.second->GetNbinsX(); ++bin){								// In such cases the fluctuations are really high and a larger bin width is preferred
        if(pdf.second->GetBinContent(bin) > pdf.second->GetMaximum()*0.8){						// (Maybe the thresholds could still be optimized a bit more though)
          if(!leftBin2) leftBin2  = bin;
          else          rightBin2 = bin;
        }
      }


      int leftBin3      = 0;												// Define region of the peak: most extreme bins which exceed 90% of the maximum
      int rightBin3     = 0;												// We will check for bins within this region which go below 80%
      for(int bin = 1; bin < pdf.second->GetNbinsX(); ++bin){								// In such cases the fluctuations are really high and a larger bin width is preferred
        if(pdf.second->GetBinContent(bin) > pdf.second->GetMaximum()*0.9){						// (Maybe the thresholds could still be optimized a bit more though)
          if(!leftBin3) leftBin3  = bin;
          else          rightBin3 = bin;
        }
      }

      int emptyBins     = 0;
      int maxEmptyBins  = 0;
      for(int bin = 1; bin < pdf.second->GetNbinsX(); ++bin){
        if(     bin >= leftBin  && bin <= rightBin  && pdf.second->GetBinContent(bin) <= 0)                            ++emptyBins;
        else if(bin >= leftBin2 && bin <= rightBin2 && pdf.second->GetBinContent(bin) <= pdf.second->GetMaximum()*0.7) ++emptyBins;
        else if(bin >= leftBin3 && bin <= rightBin3 && pdf.second->GetBinContent(bin) <= pdf.second->GetMaximum()*0.8) ++emptyBins;
        else {
          if(emptyBins > maxEmptyBins) maxEmptyBins = emptyBins;
          emptyBins = 0;
        }
      }
      rebinFactor[pdf.first] = std::max(maxEmptyBins, emptyBins);
    }

    for(auto& pdf : pdfs) rebinFactor[pdf.first] = std::max(rebinFactor[pdf.first], rebinFactor[switchQG(pdf.first)]);	// Use same rebin factor in quark and gluon pdf (otherwise bias if second derivate of pdf is non-zero)
    
    for(auto& pdf : pdfs){
      if(rebinFactor[pdf.first] > 19)     std::cout << "This pdf has a lot of emtpy bins and fluctuations:" << std::endl;
      if(rebinFactor[pdf.first] > 9)      rebin(pdf.second, 20);
      else if(rebinFactor[pdf.first] > 4) rebin(pdf.second, 10);
      else if(rebinFactor[pdf.first] > 3) rebin(pdf.second, 5);
      else if(rebinFactor[pdf.first] > 1) rebin(pdf.second, 4);
      else if(rebinFactor[pdf.first] > 0) rebin(pdf.second, 2);
    }


    // Normalization of the pdf's
    for(auto& pdf : pdfs) pdf.second->Scale(1./pdf.second->Integral(0, pdf.second->GetNbinsX() + 1));			// Scale to integral=1 (also include underflow/overflow)


    // Try to average out leftover fluctuations and empty bins
    for(auto& pdf : pdfs){
      if(pdf.first.Contains("gluon")) continue;

      TH1* tempQ = (TH1*) pdf.second->Clone();
      TH1* tempG = (TH1*) pdfs[switchQG(pdf.first)]->Clone();
      for(int i = 1; i < pdf.second->GetNbinsX() + 1; ++i){								// Do not consider underflow/overflow
        float contentQ = tempQ->GetBinContent(i);
        float contentG = tempG->GetBinContent(i);
        float width    = tempQ->GetBinWidth(i);

        if((1.5*contentQ < tempQ->GetBinContent(i-1) && 1.5*contentQ < tempQ->GetBinContent(i+1)) ||			// Try to average out some extreme fluctuations (i.e. only allow a difference of max 50% between two neighbouring bins)
           (1.5*contentG < tempG->GetBinContent(i-1) && 1.5*contentG < tempG->GetBinContent(i+1)) ||
           (contentQ < 1.5*tempQ->GetBinContent(i-1) && contentQ < 1.5*tempQ->GetBinContent(i+1)) ||
           (contentG < 1.5*tempG->GetBinContent(i-1) && contentG < 1.5*tempG->GetBinContent(i+1))){
          if(i-1 > 0 && i+1 < pdf.second->GetNbinsX() + 1){
            contentQ += tempQ->GetBinContent(i-1) + tempQ->GetBinContent(i+1);
            contentG += tempG->GetBinContent(i-1) + tempG->GetBinContent(i+1);
            width    += tempQ->GetBinWidth(i-1)   + tempQ->GetBinWidth(i+1);
          }
        }

        int j = 1;
        while(contentQ <= 0 || contentG <= 0){										// Average empty bins
          if(tempQ->Integral(0, i-j) <= 0) break;									// but not when surpassing the extreme edges of the pdf (see next part)
          if(tempG->Integral(0, i-j) <= 0) break;
          if(tempQ->Integral(i+j, tempQ->GetNbinsX()+1) <= 0) break;
          if(tempG->Integral(i+j, tempG->GetNbinsX()+1) <= 0) break;
          if(i-j == 0) break;
          if(i+j == pdf.second->GetNbinsX()) break;
          contentQ += tempQ->GetBinContent(i-j) + tempQ->GetBinContent(i+j);
          contentG += tempG->GetBinContent(i-j) + tempG->GetBinContent(i+j);
          width    += tempQ->GetBinWidth(i-j)   + tempQ->GetBinWidth(i+j);
          ++j;
        }

        pdf.second->SetBinContent(i, contentQ/width);
        pdfs[switchQG(pdf.first)]->SetBinContent(i, contentG/width);
      }
      delete tempQ;
      delete tempG;
    }


    // Now there are still empty bins left on the edges of the pdf, for which we assign extreme values to avoid a 0
    // (relative though, so it does not dominate the pdf's when we want to inspect them in the ROOT file; 0.000001/0.000999 has the same effect as 0.001/0.999)
    for(auto& pdf : pdfs){
      if(pdf.first.Contains("gluon")) continue;
      for(int i = 0; i <= pdf.second->GetNbinsX() + 1; ++i){
        if(pdf.second->GetBinContent(i) <= 0 || pdfs[switchQG(pdf.first)]->GetBinContent(i) <= 0){
          bool isBelow = (mean[pdf.first] < mean[switchQG(pdf.first)]);
          if(isBelow == pdf.second->GetBinCenter(i) < mean[pdf.first]){
            pdf.second->SetBinContent(i, 0.000999);
            pdfs[switchQG(pdf.first)]->SetBinContent(i, 0.000001);
          } else {
            pdf.second->SetBinContent(i, 0.000001);
            pdfs[switchQG(pdf.first)]->SetBinContent(i, 0.000999);
          }
        }
      }
    }


    // Apply the likelihood weight
    for(auto& pdf : pdfs){
      TString thisBin = pdf.first(pdf.first.Index(TRegexp("eta")), pdf.first.Length());
      TString thisVar = pdf.first(0, pdf.first.Index(TRegexp("_")));
      for(int i = 0; i < pdf.second->GetNbinsX() + 1; ++i){
        pdf.second->SetBinContent(i, std::pow(pdf.second->GetBinContent(i), bins.getWeight(thisBin, (thisVar == "mult"? 0 : (thisVar == "ptD" ? 1 : 2 )))));
      }
    }


    // Make file and write binnings
    TFile *pdfFile = new TFile("pdfQG_"+jetType + "_13TeV_" + version + ".root","RECREATE");
    pdfFile->cd();
    bins.writeBinsToFile();

    // Write to file
    for(TString var : {"axis2","ptD","mult"}) pdfFile->mkdir(var);
    for(auto& pdf : pdfs){
      for(TString var: {"axis2","ptD","mult"}) if(pdf.first.Contains(var)) pdfFile->cd(var);
      pdf.second->SetTitle(pdf.first);
      pdf.second->Write();

      TString thisBin = pdf.first(pdf.first.Index(TRegexp("eta")), pdf.first.Length());
      for(auto i : bins.getLinkedBins(thisBin)){									// Store copies for merged bins
        TString copyBin = pdf.first;
        copyBin.ReplaceAll(thisBin, i);
        pdf.second->Write(copyBin);
      }
    }

    for(auto& pdf : pdfs) delete pdf.second;
    for(auto& file : {pdfFile}){ file->Close(); delete file;}
  }
  return 0;
}
示例#10
0
 /* MARKUS: weight wgt has been added to the argument list of fxn*/
void vegas_mpi_(double regn[], int *ndim_in, void (*fxn)(double x[], double *wgt,double f[]),
           int *init_in, int *ncall_in, int *itmx_in, int *nprn_in,
           int *fcns_in, int *pdim_in, int *wrks_in,
           double tgral[], double sd[], double chi2a[])
{
  int ndim,init,ncall,itmx,nprn,fcns,pdim,wrks;
  static int ndo;            /*                                    (ndo)     */
  int it;                    /* iteration counter                  (it)      */
  static int ittot;          /* iteration counter across init>1              */
  double calls;              /* real total number of calls to fxn  (calls)   */
  double dv2g;               /*                                    (dv2g)    */
  double xin[NDMX];          /* aux. variable for rebinning        (xin[])   */
  typedef struct {
    double Wgt;              /* weight                             (wgt)     */
    double sWgt;             /* cumulative sum for weights         (swgt)    */
    double sChi;             /* cumulative sum for chi^2           (schi)    */
    double sInt;             /* cumulative sum for integral        (si)      */
  } iterAccu;                /* accumulator for stuff at end of iteration... */
  static iterAccu Ai[FNMX];  /* ...one for each integrand                    */
  double dt[MXDIM];          /*                                    (dt[])    */
  double r[NDMX];            /*                                    (r[])     */
  int i, j, k;               /* counters                           (i, j, k) */
  int whodunit;              /* who returned the result to master?           */
  double rc;                 /*                                    (rc)      */
  double xn;                 /*                                    (xn)      */
  double xo;                 /*                                    (xo)      */
  double wgt;                /* weight                             (wgt)     */
  int wmax;                  /* for computing limit, if wrks too large       */
  
  ndim=(*ndim_in);   /* MARKUS: restoring original arguments */
  init=(*init_in);
  ncall=(*ncall_in);
  itmx=(*itmx_in);
  nprn=(*nprn_in);
  fcns=(*fcns_in);
  pdim=(*pdim_in);
  wrks=(*wrks_in);

  ReducedCHistogram CMasterHisto[NUMHISTO];  /* MARKUS: these are the master histograms containing results from all slaves */
  
  
//  printf("\n arg check %10.4f %10.4f %10.4f %10.4f \n",regn[0],regn[2],regn[1],regn[3]);
//  printf("\n arg check %i %i %i %i %i \n",ndim,init,ncall,itmx,wrks);

  MPI_Status recv_status;
#if (REPRO != 0)
  unsigned long i_rep;       /* number of RNs to skip                        */
#endif
  
  MPI_Comm_rank(MPI_COMM_WORLD, &p_rank);  // gets the rank
  MPI_Comm_size(MPI_COMM_WORLD, &p_size);  // gets the number of nodes 
  
  
// MARKUS: define MPI_HISTO for receiving C histogram structs
  MPI_Datatype MPI_HISTO, oldtypes[2]; 
  int blockcounts[2];
  MPI_Aint offsets[2], extent;
  offsets[0] = 0;
  oldtypes[0] = MPI_DOUBLE;
  blockcounts[0] = 2*MXHISTOBINS;
  MPI_Type_extent(MPI_DOUBLE, &extent);
  offsets[1] = blockcounts[0] * extent;
  oldtypes[1] = MPI_INT;
  blockcounts[1] = 1*MXHISTOBINS; 
  MPI_Type_struct(2, blockcounts, offsets, oldtypes, &MPI_HISTO);
  MPI_Type_commit(&MPI_HISTO);   
  
  

  wrks = (wrks<1) ? 1 : ((MXWORK<wrks) ? MXWORK : wrks);
  if (wrks>=p_size) wrks = p_size-1;
  gndim = ndim; 
  if (NDIM_PAR == 0)
    ndim_par = ndim/2;
  else
    ndim_par = NDIM_PAR;
  functions = (fcns<FNMX) ? (fcns) : (FNMX);


  for (i=0; i<ndim_par; i++) kgl[i] = 1;
  p_fxn = fxn;
  for (j=0; j<ndim; j++) gregn[j] = regn[j];
  
#if (REPRO != 0)
  if (gfsr_not_initialized) gfsr_init(REPRO);
#else
  if (gfsr_not_initialized) gfsr_init((long)time(NULL));
#endif
  if (init <= 0) {    /* entry for cold start        */
    mds = ndo = 1;    /* Careful with that Axe, Eugene!    */
                      /* mds=0 will trash parallelization. */
    for (j=0; j<ndim; j++) xi[j][0] = 1.0;
  }
  if (init <= 1) {    /* inherit the previous grid   */
    for (j=0; j<functions; j++) {
      Ai[j].sInt = 0.0;
      Ai[j].sWgt = 0.0;
      Ai[j].sChi = 0.0;
    }
    ittot = 1;
  }
  if (init <= 2) {    /* inherit grid and results    */
    nd = NDMX;
    ng = 1;
    if (mds) {
      ng = (int)pow(ncall/2.0+0.25,1.0/ndim);
      if( ng==1 ) printf("WARNING: ng=1! You might want to increase ncall.\n");

// printf("MARKUS: nodes: %i %20.9f\n",ng,pow(ncall/2.0+0.25,1.0/ndim));
// MARKUS:: if workers is forced one, then ng is probably one. increase ncall!

      mds = 1;
      if ((2*ng-NDMX) >= 0) {
        mds = -1;
        npg = ng/NDMX+1;
        nd = ng/npg;
        ng = npg*nd;
      }
    }
    wmax = 1; 


    for (i=0; i<ndim_par; i++) wmax *= ng;

    if (wrks>wmax) wrks = wmax;
    for (k=1,i=0; i<ndim; i++) k *= ng;
    npg = (ncall/k>2) ? (ncall/k) : (2);
    calls = (double)npg * (double)k;
    dxg = 1.0/ng;
    for (dv2g=1,i=0; i<ndim; i++) dv2g *= dxg;
    dv2g = calls*calls*dv2g*dv2g/npg/npg/(npg-1.0);
    xnd = nd;
    dxg *= xnd;
    xJac = 1.0/calls;
    for (j=0; j<ndim; j++) {
      dx[j] = regn[j+ndim]-regn[j];
      xJac *= dx[j];
    }
    if (nd != ndo) {
      for (i=0; i<(nd>ndo?nd:ndo); i++) r[i] = 1.0;
      for (j=0; j<ndim; j++) rebin(ndo/xnd,nd,r,xin,xi[j]);
      ndo = nd;
    }

    if (!p_rank && nprn & NPRN_INPUT) {
      printf("%s:  ndim= %3d  ncall= %8.0f   %3d+1/%3d CPU(s)\n",
             "\n\n Input parameters for vegas",ndim,calls,wrks,p_size);
      printf("%28s  ittot=%5d  itmx=%5d    %5d^%1d hypercubes\n"," ",ittot,itmx,ng,ndim_par);
      printf("%28s  nprn=0x%04x  ALPH=%5.2f\n"," ",nprn,ALPH);
      printf("%28s  mds=%3d  nd=%4d%15s npg=%d\n"," ",mds,nd," ",npg);
      for (j=0; j<ndim; j++) {
        printf("%30s xl[%2d]= %11.4g xu[%2d]= %11.4g\n",
               " ",j,regn[j],j,regn[j+ndim]);
      }
    }
  }
  
  
  
  ReducedCHistogram CHisto_tmp[NUMHISTO];   /* MARKUS: temporary histograms from the slaves  */
  ReducedCHistogram CHisto_tmp2[NUMHISTO];  /* MARKUS: temporary histograms to sum up the slave histograms  */
  for (j=0; j<NUMHISTO; j++) {   /* MARKUS: initialize C master histograms */
       for (i=0; i<MXHISTOBINS; i++) { CMasterHisto[j].Value[i]=0.0; CMasterHisto[j].Value2[i]=0.0; CMasterHisto[j].Hits[i]=0;  }
  }
  
  /*  ========== begin iterations ========== */
  for (it=ittot; it<=itmx+ittot-1; it++) {  /* starting the iteration loop */
    kgl[0] = 1;  /* kgl[0] is also used to determine if we are done yet */
    for (i=0; i<ndim_par; i++) 
      if (kgl[i]!=1) {
        kgl[i] = 1;
      }
    for (j=0; j<functions; j++) {
      Ab[j].ti = Ab[j].tsi = 0.0;
    }
    for (j=0; j<gndim; j++) {
      for (i=0; i<nd; i++) d[i][j] = di[i][j] = 0.0;
    }    
     
   
    if (p_rank == 0) { /* ============= master ============= */
      

      do {
        MPI_Recv(&whodunit, 1, MPI_INT, MPI_ANY_SOURCE, 0, MPI_COMM_WORLD, &recv_status);
        for (j=0; j<ndim_par; j++) kgl_buf[j] = kgl[j];
        MPI_Send(kgl_buf, ndim_par, MPI_INT, whodunit, 0, MPI_COMM_WORLD);
        for (j=ndim_par; j>=1; j--) {
          kgl[j-1] %= ng;
          if (++kgl[j-1] != 1) break;
        }
        if (j < 1) kgl[0] = 0;  /* we are done! */
      } while (kgl[0] != 0);
      /* Send a final kgl (zeroed) to everyone */
      for (j=1; j<=wrks; j++) {
        MPI_Send(&kgl, ndim_par, MPI_INT, j, 0, MPI_COMM_WORLD);
      }
      
      for (j=0; j<NUMHISTO; j++) {   /* MARKUS: empty C temp histograms in each iteration*/
      for (i=0; i<MXHISTOBINS; i++) { 
            CHisto_tmp2[j].Value[i]  = 0.0; 
            CHisto_tmp2[j].Value2[i] = 0.0; 
            CHisto_tmp2[j].Hits[i]   = 0;  
      };
      };      
      /* Now wait for all the results to come in */
      for (k=0; k<wrks; k++) {
        
        // MARKUS: Require to receive from rank k+1. This means that we have to wait until k is finished before receiving from k+1. But we have to wait for all of them anyways.
        MPI_Recv(&result_buf, (2*functions + 2*(gndim*nd)), MPI_DOUBLE, k+1, 1, MPI_COMM_WORLD, &recv_status);
        MPI_Recv(CHisto_tmp,NUMHISTO,MPI_HISTO,k+1,2,MPI_COMM_WORLD, &recv_status);   /* MARKUS: receive array of C histogram structs */
        if( k==0 ) { printf(" Master has received histograms from workers %i",k+1); }
        else       { printf(", %i",k+1); };
        if( k==wrks-1 ) printf("\n");

        for (j=0; j<NUMHISTO; j++) {     /* MARKUS: Sum histograms from slaves and save in  CHisto_tmp2    */
        for (i=0; i<MXHISTOBINS; i++) {     
              CHisto_tmp2[j].Value[i]  += CHisto_tmp[j].Value[i];
              CHisto_tmp2[j].Value2[i] += CHisto_tmp[j].Value2[i];
              CHisto_tmp2[j].Hits[i]   += CHisto_tmp[j].Hits[i];
        };
        };
                      
	for (j=0; j<functions; j++)        /* disassemble result_buf */
	  Ab[j].ti += result_buf[j];
	for (j=0; j<functions; j++) 
	  Ab[j].tsi += result_buf[j+functions];
        for (j=0; j<gndim; j++) {
          for (i=0; i<nd; i++) 
	    d[i][j] += result_buf[2*functions + j*nd + i];
          for (i=0; i<nd; i++) 
	    di[i][j] += result_buf[2*functions + gndim*nd + j*nd + i];
        } 
      }
      
      for (j=0; j<functions; j++)     /* assemble the send-buffer */
	result_buf[j] = Ab[j].ti;
      for (j=0; j<functions; j++) 
	result_buf[j+functions] = Ab[j].tsi;
      for (j=0; j<gndim; j++) {
        for (i=0; i<nd; i++) 
	  result_buf[2*functions + j*nd + i] = d[i][j];
        for (i=0; i<nd; i++) 
	  result_buf[2*functions + gndim*nd + j*nd + i] = di[i][j];
      }
      for (j=1; j<p_size; j++) {
        MPI_Send(&result_buf, (2*functions + 2*(ndim*nd)), MPI_DOUBLE, j, 2, MPI_COMM_WORLD);
      }
      
       
        for (j=0; j<NUMHISTO; j++) {    /* MARKUS: Save results of this iteration in the master histograms  */
           for (i=0; i<MXHISTOBINS; i++) { 
               CMasterHisto[j].Value[i] = CMasterHisto[j].Value[i]  + CHisto_tmp2[j].Value[i] ; 
               CMasterHisto[j].Value2[i]= CMasterHisto[j].Value2[i] + CHisto_tmp2[j].Value2[i];
               CMasterHisto[j].Hits[i] += CHisto_tmp2[j].Hits[i];  
           };
           int NHisto=j+1;
           modkinematics_mp_transferhisto_(&CMasterHisto[j],&NHisto);   /* MARKUS: Send it to TOPAZ */ 
        };
        

//        printf("Printing final CMAsterHistograms");
//        for (j=0; j<NUMHISTO; j++) { 
//        for (i=0; i<MXHISTOBINS; i++) {
//            printf(" %i %i %20.8e \n",j+1,i+1,CMasterHisto[j].Value[i]);
//        };
//        };
    
       
    }   /* end master */
    
    
    
    else {  /* ============= slave ============= */
      


      modkinematics_mp_clearredhisto_();  /* MARKUS: Empty fortran histograms in each iteration */
      
      if (p_rank<=wrks) p_vegasloop(NULL);
#if (REPRO != 0)       /* Now advance the remaining RNGs in case the */
      if (p_rank>wrks) {           /* next call runs on more CPUs */
        for (i_rep=0;i_rep<calls*ndim;i_rep++) 
          gfsr_rand(gfsr_m,&gfsr_k);
      }
#endif
      MPI_Recv(&result_buf, (2*functions + 2*(ndim*nd)), MPI_DOUBLE, 0, 2, MPI_COMM_WORLD, &recv_status);
      for (j=0; j<functions; j++)        /* disassemble result_buf */
	Ab[j].ti = result_buf[j];
      for (j=0; j<functions; j++) 
	Ab[j].tsi = result_buf[j+functions];
      for (j=0; j<gndim; j++) {
        for (i=0; i<nd; i++) 
	  d[i][j] = result_buf[2*functions + j*nd + i];
        for (i=0; i<nd; i++) 
	  di[i][j] = result_buf[2*functions + gndim*nd + j*nd + i];
      }
    }  /* end slave */
    
    
    
    for (j=0; j<functions; j++) {
      Ab[j].tsi *= dv2g;
      Ai[j].Wgt = 1.0/Ab[j].tsi;
      Ai[j].sInt += Ai[j].Wgt*Ab[j].ti;
      Ai[j].sChi += Ai[j].Wgt*Ab[j].ti*Ab[j].ti;
      Ai[j].sWgt += Ai[j].Wgt;
      tgral[j] = Ai[j].sInt/Ai[j].sWgt;
      chi2a[j] = (Ai[j].sChi-Ai[j].sInt*tgral[j])/(it-0.9999);
      if (chi2a[j] < 0.0) chi2a[j] = 0.0;
      sd[j] = sqrt(1.0/Ai[j].sWgt);
      Ab[j].tsi = sqrt(Ab[j].tsi);
    }
    wgt = Ai[0].Wgt;
    if (!p_rank && nprn & NPRN_RESULT) {
      printf("%s %3d : integral = %16.7e +/-  %13.4e\n", " iteration no.",it,Ab[0].ti,Ab[0].tsi);
      printf("%s integral = %16.7e +/-  %13.4e    chi^2/it = %9.2g\n",  " all iterations:    ",tgral[0],sd[0],chi2a[0]);
    }
#if ( _WriteTmpHisto==1 )
    if( !p_rank ) {
        double time=0.0;
        int histounit=14,itfix=1;
//        printf("Writing intermediate histograms \n");
        writehisto_(&histounit,&it,&Ab[0].ti,&Ab[0].tsi,&tgral[0],&sd[0],&chi2a[0],&time);
    };
#endif
    if (!p_rank && nprn & NPRN_SECRES) {
      for (i=1; i<functions; i++) {
        printf("   %4d%s%14.7g +/-%9.2g  chi^2/it = %9.2g\n",
               i,".additional integral= ",tgral[i],sd[i],chi2a[i]);
      }
    }
    if (!p_rank && nprn & (NPRN_GRID | NPRN_GRID_2 | NPRN_GRID_4 | NPRN_GRID_8)) {
      for (j=0; j<ndim; j++) {
        printf(" data for axis  %2d\n",j);
        printf("%6s%13s%11s%13s%11s%13s\n", 
               "X","delta i","X","delta i","X","delta i");
        for (i=0; i<nd; i += 3) {
          for (k=0; k<3 && i+k<nd; k++) {
            printf("%8.5f%12.4g    ",xi[j][i+k],di[i+k][j]);
          }
          printf("\n");
          if (nprn & NPRN_GRID_8) k = 3*(8-1);
          if (nprn & NPRN_GRID_4) k = 3*(4-1);
          if (nprn & NPRN_GRID_2) k = 3*(2-1);
          if (nprn & NPRN_GRID) k = 3*(1-1);
          i += k;
        }
      }
    }
    if (!p_rank ) printf("\n");
    for (j=0; j<ndim; j++) {
      xo = d[0][j];
      xn = d[1][j];
      d[0][j] = (xo+xn)/2.0;
      dt[j] = d[0][j];
      for (i=1; i<nd-1; i++) {
        rc = xo+xn;
        xo = xn;
        xn = d[i+1][j];
        d[i][j] = (rc+xn)/3.0;
        dt[j] += d[i][j];
      }
      d[nd-1][j] = (xo+xn)/2.0;
      dt[j] += d[nd-1][j];
    }
    for (j=0; j<ndim; j++) {
      rc = 0.0;
      for (i=0; i<nd; i++) {
        if (d[i][j] < TINY) d[i][j] = TINY;
        r[i] = pow((1.0-d[i][j]/dt[j])/
		   (log(dt[j])-log(d[i][j])),ALPH);
        rc += r[i];
      }
      rebin(rc/xnd,nd,r,xin,xi[j]);
    }


  } /*  ========== end iterations ========== */
  ittot += itmx;
    
  return;
}
void addNuisanceWithToys(std::string iFileName,std::string iChannel,std::string iBkg,std::string iEnergy,std::string iName,std::string iDir,bool iRebin=true,bool iVarBin=false,int iFitModel=1,int iFitModel1=1,double iFirst=150,double iLast=1500,std::string iSigMass="800",double iSigScale=0.1,int iNToys=1000) { 
  std::cout << "======> " << iDir << "/" << iBkg << " -- " << iFileName << std::endl;  
  if(iVarBin) std::cout << "option not implemented yet!";
  if(iVarBin) return;
  //double lFirst = 200;
  //double lLast  = 1500;
  double lFirst = iFirst;
  double lLast  = iLast;

  std::cout << "===================================================================================================================================================" <<std::endl;
  std::cout << "Using Initial fit model: " << iFitModel << ", fitting range: " << iFirst << "-" << iLast << " , using alternative fit model: " << iFitModel1 << std::endl; 
  std::cout << "===================================================================================================================================================" <<std::endl;

  TFile *lFile = new TFile(iFileName.c_str());
  TH1F  *lH0   = (TH1F*) lFile->Get((iDir+"/"+iBkg).c_str());
  TH1F  *lData = (TH1F*) lFile->Get((iDir+"/data_obs").c_str());
  TH1F  *lSig = 0;

  // for now, use bbH signal for testing in b-tag and ggH in no-btag
  if(iDir.find("_btag") != std::string::npos) lSig = (TH1F*)lFile->Get((iDir+"/bbH"+iSigMass+"_fine_binning").c_str());
  else lSig = (TH1F*)lFile->Get((iDir+"/ggH"+iSigMass+"_fine_binning").c_str());

  TH1F *lH0Clone = (TH1F*)lH0->Clone("lH0Clone");     // binning too fine as of now? start by rebinning
  TH1F *lDataClone = (TH1F*)lData->Clone("lDataClone");   
  TH1F *lSigClone = (TH1F*)lSig->Clone("lSigClone");  
 // lH0Clone->Rebin(2);
 // lDataClone->Rebin(2);
 // lSigClone->Rebin(2);

  lSig->Rebin(10);  

  //Define the fit function
  RooRealVar lM("m","m" ,0,5000);
  lM.setRange(lFirst,lLast);
  RooRealVar lA("a","a" ,50,  0.1,200);
  RooRealVar lB("b","b" ,0.0 , -10.5,10.5);
  RooRealVar lA1("a1","a1" ,50,  0.1,1000);
  RooRealVar lB1("b1","b1" ,0.0 , -10.5,10.5);

  RooDataHist *pH0  =  new RooDataHist("Data","Data" ,RooArgList(lM),lH0);
  double lNB0 = lH0->Integral(lH0->FindBin(lFirst),lH0->FindBin(lLast));
  double lNSig0 = lSig->Integral(lSig->FindBin(lFirst),lSig->FindBin(lLast));
 //lNB0=500;
// lNSig0=500;
 lSig->Scale(iSigScale*lNB0/lNSig0);                                         // scale signal to iSigScale*(Background yield), could try other options
 lNSig0 = lSig->Integral(lSig->FindBin(lFirst),lSig->FindBin(lLast));        // readjust norm of signal hist   
  
  //Generate the "default" fit model 

  RooGenericPdf *lFit  = 0; lFit = new RooGenericPdf("genPdf","exp(-m/(a+b*m))",RooArgList(lM,lA,lB));
  if(iFitModel == 1) lFit = new RooGenericPdf("genPdf","exp(-a*pow(m,b))",RooArgList(lM,lA,lB));
  if(iFitModel == 1) {lA.setVal(0.3); lB.setVal(0.5);}
  if(iFitModel == 2) lFit = new RooGenericPdf("genPdf","a*exp(b*m)",RooArgList(lM,lA,lB));
  if(iFitModel == 2) {lA.setVal(0.01); lA.setRange(0,10); }
  if(iFitModel == 3) lFit = new RooGenericPdf("genPdf","a/pow(m,b)",RooArgList(lM,lA,lB));
 
  // Generate the alternative model
  
  RooGenericPdf *lFit1  = 0; lFit1 = new RooGenericPdf("genPdf","exp(-m/(a1+b1*m))",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 1) lFit1 = new RooGenericPdf("genPdf","exp(-a1*pow(m,b1))",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 1) {lA1.setVal(0.3); lB1.setVal(0.5);}
  if(iFitModel1 == 2) lFit1 = new RooGenericPdf("genPdf","a1*exp(b1*m)",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 2) {lA1.setVal(0.01); lA1.setRange(0,10); }
  if(iFitModel1 == 3) lFit1 = new RooGenericPdf("genPdf","a1/pow(m,b1)",RooArgList(lM,lA1,lB1));
  
  //=============================================================================================================================================
  //Perform the tail fit and generate the shift up and down histograms
  //=============================================================================================================================================

  RooFitResult  *lRFit = 0;
  lRFit = lFit->fitTo(*pH0,RooFit::Save(kTRUE),RooFit::Range(lFirst,lLast),RooFit::Strategy(0)); 
  TMatrixDSym lCovMatrix   = lRFit->covarianceMatrix(); 
  TMatrixD  lEigVecs(2,2);    lEigVecs = TMatrixDSymEigen(lCovMatrix).GetEigenVectors();
  TVectorD  lEigVals(2);      lEigVals = TMatrixDSymEigen(lCovMatrix).GetEigenValues();
  cout << " Ve---> " << lEigVecs(0,0) << " -- " << lEigVecs(1,0) << " -- " << lEigVecs(0,1) << " -- " << lEigVecs(1,1) << endl;
  cout << " Co---> " << lCovMatrix(0,0) << " -- " << lCovMatrix(1,0) << " -- " << lCovMatrix(0,1) << " -- " << lCovMatrix(1,1) << endl;
  double lACentral = lA.getVal();
  double lBCentral = lB.getVal();
  lEigVals(0) = sqrt(lEigVals(0));
  lEigVals(1) = sqrt(lEigVals(1));
  cout << "===> " << lEigVals(0) << " -- " << lEigVals(1) << endl;
  
  TH1F* lH     = (TH1F*) lFit->createHistogram("fit" ,lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  lA.setVal(lACentral + lEigVals(0)*lEigVecs(0,0));
  lB.setVal(lBCentral + lEigVals(0)*lEigVecs(1,0));
  TH1F* lHUp   = (TH1F*) lFit->createHistogram("Up"  ,lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  lA.setVal(lACentral - lEigVals(0)*lEigVecs(0,0));
  lB.setVal(lBCentral - lEigVals(0)*lEigVecs(1,0));
  TH1F* lHDown = (TH1F*) lFit->createHistogram("Down",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  lA.setVal(lACentral + lEigVals(1)*lEigVecs(0,1));
  lB.setVal(lBCentral + lEigVals(1)*lEigVecs(1,1));
  TH1F* lHUp1   = (TH1F*) lFit->createHistogram("Up1",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  lA.setVal(lACentral - lEigVals(1)*lEigVecs(0,1));
  lB.setVal(lBCentral - lEigVals(1)*lEigVecs(1,1));
  TH1F* lHDown1 = (TH1F*) lFit->createHistogram("Down1",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  std::string lNuisance1 =  iBkg+"_"+"CMS_"+iName+"1_" + iChannel + "_" + iEnergy;
  std::string lNuisance2 =  iBkg+"_"+"CMS_"+iName+"2_" + iChannel + "_" + iEnergy;
  lHUp    = merge(lNuisance1 + "Up"   ,lFirst,lH0,lHUp);
  lHDown  = merge(lNuisance1 + "Down" ,lFirst,lH0,lHDown);
  lHUp1   = merge(lNuisance2 + "Up"   ,lFirst,lH0,lHUp1);
  lHDown1 = merge(lNuisance2 + "Down" ,lFirst,lH0,lHDown1);
  lH      = merge(lH0->GetName()      ,lFirst,lH0,lH);

  //=============================================================================================================================================
  //=============================================================================================================================================
  
  //Set the variables A and B to the final central values from the tail fit

  lA.setVal(lACentral);
  lB.setVal(lBCentral);
 // lA.removeRange();
 // lB.removeRange();
 
  //Generate the background pdf corresponding to the final result of the tail fit
 
 RooGenericPdf *lFitFinal  = 0; lFitFinal = new RooGenericPdf("genPdf","exp(-m/(a+b*m))",RooArgList(lM,lA,lB));
  if(iFitModel == 1) lFitFinal = new RooGenericPdf("genPdf","exp(-a*pow(m,b))",RooArgList(lM,lA,lB));
  if(iFitModel == 2) lFitFinal = new RooGenericPdf("genPdf","a*exp(b*m)",RooArgList(lM,lA,lB));
  if(iFitModel == 3) lFitFinal = new RooGenericPdf("genPdf","a/pow(m,b)",RooArgList(lM,lA,lB));



  //=============================================================================================================================================
  //Perform the tail fit with the alternative fit function (once initially, before allowing tail fit to float in toy fit).
  //=============================================================================================================================================

  RooFitResult  *lRFit1 = 0;
 //lRFit1=lFit1->fitTo(*pH0,RooFit::Save(kTRUE),RooFit::Range(iFirst,iLast),RooFit::Strategy(0));  
 lRFit1=lFit1->fitTo(*pH0,RooFit::Save(kTRUE),RooFit::Range(200,1500),RooFit::Strategy(0));  
  
  //Generate the background pdf corresponding to the result of the alternative tail fit

  RooGenericPdf *lFit1Final  = 0; lFit1Final = new RooGenericPdf("genPdf","exp(-m/(a1+b1*m))",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 1) lFit1Final = new RooGenericPdf("genPdf","exp(-a1*pow(m,b1))",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 2) lFit1Final = new RooGenericPdf("genPdf","a1*exp(b1*m)",RooArgList(lM,lA1,lB1));
  if(iFitModel1 == 3) lFit1Final = new RooGenericPdf("genPdf","a1/pow(m,b1)",RooArgList(lM,lA1,lB1));

 // lA1.removeRange();
 // lB1.removeRange();
  
  //=============================================================================================================================================

  //Define RooRealVar for the normalization of the signal and background, starting from the initial integral of the input histograms

  lM.setRange(300,1500);  

  RooRealVar lNB("nb","nb",lNB0,0,10000);
  RooRealVar lNSig("nsig","nsig",lNSig0,-1000,1000);

  //Define a PDF for the signal histogram lSig
  
  RooDataHist  *pS      = new RooDataHist("sigH","sigH",RooArgList(lM),lSig);
  RooHistPdf   *lSPdf   = new RooHistPdf ("sigPdf","sigPdf",lM,*pS);
 
  //Define generator and fit functions for the RooMCStudy

  RooAddPdf    *lGenMod = new RooAddPdf  ("genmod","genmod",RooArgList(*lFitFinal ,*lSPdf),RooArgList(lNB,lNSig));
  RooAddPdf    *lFitMod = new RooAddPdf  ("fitmod","fitmod",RooArgList(*lFit1Final,*lSPdf),RooArgList(lNB,lNSig));

  //Generate plot of the signal and background models going into the toy generation   

  RooPlot* plot=lM.frame();
  lGenMod->plotOn(plot);
  lGenMod->plotOn(plot,RooFit::Components(*lSPdf),RooFit::LineColor(2));
  TCanvas* lC11 = new TCanvas("pdf","pdf",600,600) ;
  lC11->cd();
  plot->Draw();
  lC11->SaveAs(("SBModel_"+iBkg+"_" + iDir + "_" + iEnergy+".pdf").c_str());

  std::cout << "===================================================================================================================================================" <<std::endl;
  std::cout << "FIT PARAMETERS BEFORE ROOMCSTUDY: lA: " << lA.getVal() << " lB: " << lB.getVal() << " lA1: " << lA1.getVal() << " lB1: " << lB1.getVal() << std::endl;  
  std::cout << "===================================================================================================================================================" <<std::endl;


  RooMCStudy   *lToy    = new RooMCStudy(*lGenMod,lM,RooFit::FitModel(*lFitMod),RooFit::Binned(kTRUE),RooFit::Silence(),RooFit::Extended(kTRUE),RooFit::Verbose(kTRUE),RooFit::FitOptions(RooFit::Save(kTRUE),RooFit::Strategy(0)));

  // Generate and fit iNToys toy samples
  
  std::cout << "Number of background events: " << lNB0 << " Number of signal events: " << lNSig0 << " Sum: " << lNB0+lNSig0 << std::endl;
  
  //=============================================================================================================================================
  // Generate and fit toys
  //============================================================================================================================================= 
    
  lToy->generateAndFit(iNToys,lNB0+lNSig0,kTRUE);
 
  std::cout << "===================================================================================================================================================" <<std::endl;
  std::cout << "FIT PARAMETERS AFTER ROOMCSTUDY: lA: " << lA.getVal() << " lB: " << lB.getVal() << " lA1: " << lA1.getVal() << " lB1: " << lB1.getVal() << std::endl;  
  std::cout << "===================================================================================================================================================" <<std::endl;
  

  //=============================================================================================================================================
  // Generate plots relevant to the toy fit
  //=============================================================================================================================================

  RooPlot* lFrame1 = lToy->plotPull(lNSig,-5,5,100,kTRUE);
  lFrame1->SetTitle("distribution of pulls on signal yield from toys");
  lFrame1->SetXTitle("N_{sig} pull");
  
  TCanvas* lC00 = new TCanvas("pulls","pulls",600,600) ;
  lC00->cd();
  lFrame1->GetYaxis()->SetTitleOffset(1.2); 
  lFrame1->GetXaxis()->SetTitleOffset(1.0); 
  lFrame1->Draw() ;
  lC00->SaveAs(("sig_pulls_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());

  RooPlot* lFrame2 = lToy->plotParam(lA1);
  lFrame2->SetTitle("distribution of values of parameter 1 (a) after toy fit");
  lFrame2->SetXTitle("Parameter 1 (a)");
  TCanvas* lC01 = new TCanvas("valA","valA",600,600) ;
  lFrame2->Draw() ;
  lC01->SaveAs(("valA_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());

  RooPlot* lFrame3 = lToy->plotParam(lB1);
  lFrame3->SetTitle("distribution of values of parameter 2 (b) after toy fit");
  lFrame3->SetXTitle("Parameter 2 (b)");
  TCanvas* lC02 = new TCanvas("valB","valB",600,600) ;
  lFrame3->Draw() ;
  lC02->SaveAs(("valB_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());
  
  RooPlot* lFrame6 = lToy->plotNLL(0,1000,100);
  lFrame6->SetTitle("-log(L)");
  lFrame6->SetXTitle("-log(L)");
  TCanvas* lC05 = new TCanvas("logl","logl",600,600) ;
  lFrame6->Draw() ;
  lC05->SaveAs(("logL_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());

  RooPlot* lFrame7 = lToy->plotParam(lNSig);
  lFrame7->SetTitle("distribution of values of N_{sig} after toy fit");
  lFrame7->SetXTitle("N_{sig}");
  TCanvas* lC06 = new TCanvas("Nsig","Nsig",600,600) ;
  lFrame7->Draw() ;
  lC06->SaveAs(("NSig_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());
  
  RooPlot* lFrame8 = lToy->plotParam(lNB);
  lFrame8->SetTitle("distribution of values of N_{bkg} after toy fit");
  lFrame8->SetXTitle("N_{bkg}");
  TCanvas* lC07 = new TCanvas("Nbkg","Nbkg",600,600) ;
  lFrame8->Draw() ;
  lC07->SaveAs(("Nbkg_toyfits_"+iBkg+"_" + iDir + "_" + iEnergy+".png").c_str());
 

  if(iRebin) { 
    const int lNBins = lData->GetNbinsX();
    double *lAxis    = getAxis(lData);
    lH0     = rebin(lH0    ,lNBins,lAxis);
    lH      = rebin(lH     ,lNBins,lAxis);
    lHUp    = rebin(lHUp   ,lNBins,lAxis);
    lHDown  = rebin(lHDown ,lNBins,lAxis);
    lHUp1   = rebin(lHUp1  ,lNBins,lAxis);
    lHDown1 = rebin(lHDown1,lNBins,lAxis);
  }

  // we dont need this bin errors since we do not use them (fit tails replaces bin-by-bin error!), therefore i set all errors to 0, this also saves us from modifying the add_bbb_error.py script in which I otherwise would have to include a option for adding bbb only in specific ranges
  int lMergeBin = lH->GetXaxis()->FindBin(iFirst);
  for(int i0 = lMergeBin; i0 < lH->GetNbinsX()+1; i0++){
    lH->SetBinError  (i0,0);
    lHUp->SetBinError  (i0,0);
    lHDown->SetBinError  (i0,0);
    lHUp1->SetBinError  (i0,0);
    lHDown1->SetBinError  (i0,0);
  }


  TFile *lOutFile =new TFile("Output.root","RECREATE");
  cloneFile(lOutFile,lFile,iDir+"/"+iBkg);
  lOutFile->cd(iDir.c_str());
  lH     ->Write();
  lHUp   ->Write(); 
  lHDown ->Write(); 
  lHUp1  ->Write(); 
  lHDown1->Write(); 

  // Debug Plots
  lH0->SetStats(0);
  lH->SetStats(0);
  lHUp->SetStats(0);
  lHDown->SetStats(0);
  lHUp1->SetStats(0);
  lHDown1->SetStats(0);
  lH0    ->SetLineWidth(1); lH0->SetMarkerStyle(kFullCircle);
  lH     ->SetLineColor(kGreen);
  lHUp   ->SetLineColor(kRed);
  lHDown ->SetLineColor(kRed);
  lHUp1  ->SetLineColor(kBlue);
  lHDown1->SetLineColor(kBlue);
  TCanvas *lC0 = new TCanvas("Can","Can",800,600);
  lC0->Divide(1,2); lC0->cd();  lC0->cd(1)->SetPad(0,0.2,1.0,1.0); gPad->SetLeftMargin(0.2) ; 
  lH0->Draw();
  lH     ->Draw("hist sames");
  lHUp   ->Draw("hist sames");
  lHDown ->Draw("hist sames");
  lHUp1  ->Draw("hist sames");
  lHDown1->Draw("hist sames");
  gPad->SetLogy();
  
  TLegend* leg1;
  /// setup the CMS Preliminary
  leg1 = new TLegend(0.7, 0.80, 1, 1); 
  leg1->SetBorderSize( 0 );
  leg1->SetFillStyle ( 1001 );
  leg1->SetFillColor (kWhite);
  leg1->AddEntry( lH0 , "orignal",  "PL" );
  leg1->AddEntry( lH , "cental fit",  "L" );
  leg1->AddEntry( lHUp , "shift1 up",  "L" );
  leg1->AddEntry( lHDown , "shift1 down",  "L" );
  leg1->AddEntry( lHUp1 , "shift2 up",  "L" );
  leg1->AddEntry( lHDown1 , "shift2 down",  "L" );
  leg1->Draw("same");


  lC0->cd(2)->SetPad(0,0,1.0,0.2); gPad->SetLeftMargin(0.2) ;
  drawDifference(lH0,lH,lHUp,lHDown,lHUp1,lHDown1);
  lH0->SetStats(0);
  lC0->Update();
  lC0->SaveAs((iBkg+"_"+"CMS_"+iName+"1_" + iDir + "_" + iEnergy+".png").c_str());
  //lFile->Close();
  return;
}
void addNuisance(std::string iFileName,std::string iChannel,std::string iBkg,std::string iEnergy,std::string iName,std::string iDir,bool iRebin=true,bool iVarBin=false,int iFitModel=1,double iFirst=150,double iLast=1500) { 
  std::cout << "======> " << iDir << "/" << iBkg << " -- " << iFileName << std::endl;  
  if(iVarBin) addVarBinNuisance(iFileName,iChannel,iBkg,iEnergy,iName,iDir,iRebin,iFitModel,iFirst,iLast);
  if(iVarBin) return;

  TFile *lFile = new TFile(iFileName.c_str());
  TH1F  *lH0   = (TH1F*) lFile->Get((iDir+"/"+iBkg).c_str());
  TH1F  *lData = (TH1F*) lFile->Get((iDir+"/data_obs").c_str());

  //Define the fit function
  RooRealVar lM("m","m" ,0,5000);   //lM.setBinning(lBinning);
  RooRealVar lA("a","a" ,50,  0.1,100);
  RooRealVar lB("b","b" ,0.0 , -10.5,10.5); //lB.setConstant(kTRUE);
  RooDataHist *pH0  =  new RooDataHist("Data","Data" ,RooArgList(lM),lH0);
  RooGenericPdf *lFit  = 0; lFit = new RooGenericPdf("genPdf","exp(-m/(a+b*m))",RooArgList(lM,lA,lB));
  if(iFitModel == 1) lFit = new RooGenericPdf("genPdf","exp(-a*pow(m,b))",RooArgList(lM,lA,lB));
  if(iFitModel == 1) {lA.setVal(0.3); lB.setVal(0.5);}
  if(iFitModel == 2) lFit = new RooGenericPdf("genPdf","a*exp(b*m)",RooArgList(lM,lA,lB));
  if(iFitModel == 3) lFit = new RooGenericPdf("genPdf","a/pow(m,b)",RooArgList(lM,lA,lB));
  RooFitResult  *lRFit = 0;
  double lFirst = iFirst;
  double lLast  = iLast;
  //lRFit = lFit->chi2FitTo(*pH0,RooFit::Save(kTRUE),RooFit::Range(lFirst,lLast));
  lRFit = lFit->fitTo(*pH0,RooFit::Save(kTRUE),RooFit::Range(lFirst,lLast),RooFit::Strategy(0)); 
  TMatrixDSym lCovMatrix   = lRFit->covarianceMatrix(); 
  TMatrixD  lEigVecs(2,2);    lEigVecs = TMatrixDSymEigen(lCovMatrix).GetEigenVectors();
  TVectorD  lEigVals(2);      lEigVals = TMatrixDSymEigen(lCovMatrix).GetEigenValues();
  cout << " Ve---> " << lEigVecs(0,0) << " -- " << lEigVecs(1,0) << " -- " << lEigVecs(0,1) << " -- " << lEigVecs(1,1) << endl;
  cout << " Co---> " << lCovMatrix(0,0) << " -- " << lCovMatrix(1,0) << " -- " << lCovMatrix(0,1) << " -- " << lCovMatrix(1,1) << endl;
  double lACentral = lA.getVal();
  double lBCentral = lB.getVal();
  lEigVals(0) = sqrt(lEigVals(0));
  lEigVals(1) = sqrt(lEigVals(1));
  cout << "===> " << lEigVals(0) << " -- " << lEigVals(1) << endl;
  
  TH1F* lH     = (TH1F*) lFit->createHistogram("fit" ,lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));
  lA.setVal(lACentral + lEigVals(0)*lEigVecs(0,0));
  lB.setVal(lBCentral + lEigVals(0)*lEigVecs(1,0));
  TH1F* lHUp   = (TH1F*) lFit->createHistogram("Up"  ,lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));
  lA.setVal(lACentral - lEigVals(0)*lEigVecs(0,0));
  lB.setVal(lBCentral - lEigVals(0)*lEigVecs(1,0));
  TH1F* lHDown = (TH1F*) lFit->createHistogram("Down",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  lA.setVal(lACentral + lEigVals(1)*lEigVecs(0,1));
  lB.setVal(lBCentral + lEigVals(1)*lEigVecs(1,1));
  TH1F* lHUp1   = (TH1F*) lFit->createHistogram("Up1",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));
  lA.setVal(lACentral - lEigVals(1)*lEigVecs(0,1));
  lB.setVal(lBCentral - lEigVals(1)*lEigVecs(1,1));
  TH1F* lHDown1 = (TH1F*) lFit->createHistogram("Down1",lM,RooFit::Binning(lH0->GetNbinsX(),lH0->GetXaxis()->GetXmin(),lH0->GetXaxis()->GetXmax()));

  std::string lNuisance1 =  iBkg+"_"+"CMS_"+iName+"1_" + iChannel + "_" + iEnergy;
  std::string lNuisance2 =  iBkg+"_"+"CMS_"+iName+"2_" + iChannel + "_" + iEnergy;
  lHUp    = merge(lNuisance1 + "Up"   ,lFirst,lH0,lHUp);
  lHDown  = merge(lNuisance1 + "Down" ,lFirst,lH0,lHDown);
  lHUp1   = merge(lNuisance2 + "Up"   ,lFirst,lH0,lHUp1);
  lHDown1 = merge(lNuisance2 + "Down" ,lFirst,lH0,lHDown1);
  lH      = merge(lH0->GetName()      ,lFirst,lH0,lH);

  if(iRebin) { 
    const int lNBins = lData->GetNbinsX();
    double *lAxis    = getAxis(lData);
    lH0     = rebin(lH0    ,lNBins,lAxis);
    lH      = rebin(lH     ,lNBins,lAxis);
    lHUp    = rebin(lHUp   ,lNBins,lAxis);
    lHDown  = rebin(lHDown ,lNBins,lAxis);
    lHUp1   = rebin(lHUp1  ,lNBins,lAxis);
    lHDown1 = rebin(lHDown1,lNBins,lAxis);
  }

  // we dont need this bin errors since we do not use them (fit tails replaces bin-by-bin error!), therefore i set all errors to 0, this also saves us from modifying the add_bbb_error.py script in which I otherwise would have to include a option for adding bbb only in specific ranges
  int lMergeBin = lH->GetXaxis()->FindBin(iFirst);
  for(int i0 = lMergeBin; i0 < lH->GetNbinsX()+1; i0++){
    lH->SetBinError  (i0,0);
    lHUp->SetBinError  (i0,0);
    lHDown->SetBinError  (i0,0);
    lHUp1->SetBinError  (i0,0);
    lHDown1->SetBinError  (i0,0);
  }


  TFile *lOutFile =new TFile("Output.root","RECREATE");
  cloneFile(lOutFile,lFile,iDir+"/"+iBkg);
  lOutFile->cd(iDir.c_str());
  lH     ->Write();
  lHUp   ->Write(); 
  lHDown ->Write(); 
  lHUp1  ->Write(); 
  lHDown1->Write(); 

  // Debug Plots
  lH0->SetStats(0);
  lH->SetStats(0);
  lHUp->SetStats(0);
  lHDown->SetStats(0);
  lHUp1->SetStats(0);
  lHDown1->SetStats(0);
  lH0    ->SetLineWidth(1); lH0->SetMarkerStyle(kFullCircle);
  lH     ->SetLineColor(kGreen);
  lHUp   ->SetLineColor(kRed);
  lHDown ->SetLineColor(kRed);
  lHUp1  ->SetLineColor(kBlue);
  lHDown1->SetLineColor(kBlue);
  TCanvas *lC0 = new TCanvas("Can","Can",800,600);
  lC0->Divide(1,2); lC0->cd();  lC0->cd(1)->SetPad(0,0.2,1.0,1.0); gPad->SetLeftMargin(0.2) ; 
  lH0->Draw();
  lH     ->Draw("hist sames");
  lHUp   ->Draw("hist sames");
  lHDown ->Draw("hist sames");
  lHUp1  ->Draw("hist sames");
  lHDown1->Draw("hist sames");
  gPad->SetLogy();
  
  TLegend* leg1;
  /// setup the CMS Preliminary
  leg1 = new TLegend(0.7, 0.80, 1, 1); 
  leg1->SetBorderSize( 0 );
  leg1->SetFillStyle ( 1001 );
  leg1->SetFillColor (kWhite);
  leg1->AddEntry( lH0 , "orignal",  "PL" );
  leg1->AddEntry( lH , "cental fit",  "L" );
  leg1->AddEntry( lHUp , "shift1 up",  "L" );
  leg1->AddEntry( lHDown , "shift1 down",  "L" );
  leg1->AddEntry( lHUp1 , "shift2 up",  "L" );
  leg1->AddEntry( lHDown1 , "shift2 down",  "L" );
  leg1->Draw("same");


  lC0->cd(2)->SetPad(0,0,1.0,0.2); gPad->SetLeftMargin(0.2) ;
  drawDifference(lH0,lH,lHUp,lHDown,lHUp1,lHDown1);
  lH0->SetStats(0);
  lC0->Update();
  lC0->SaveAs((iBkg+"_"+"CMS_"+iName+"1_" + iDir + "_" + iEnergy+".png").c_str());
  //lFile->Close();
  return;
}
//I would recommend to use the other version of the fit code
void addVarBinNuisance(std::string iFileName,std::string iChannel,std::string iBkg,std::string iEnergy,std::string iName,std::string iDir,bool iRebin=true,int iFitModel=0,double iFirst=200,double iLast=1500) { 
  std::cout << "======> " << iDir << "/" << iBkg << " -- " << iFileName << std::endl;  
  TFile *lFile = new TFile(iFileName.c_str());
  TH1F  *lH0   = (TH1F*) lFile->Get((iDir+"/"+iBkg).c_str());
  TH1F  *lData = (TH1F*) lFile->Get((iDir+"/data_obs").c_str());
  
  for(int i0 = 0; i0 < lH0->GetNbinsX()+1; i0++) lH0->SetBinContent(i0,lH0->GetBinContent(i0)/lH0->GetXaxis()->GetBinWidth(i0));
  for(int i0 = 0; i0 < lH0->GetNbinsX()+1; i0++) lH0->SetBinError  (i0,lH0->GetBinError  (i0)/lH0->GetXaxis()->GetBinWidth(i0));
  //Define the fit function
  double lFirst = iFirst;
  double lLast  = iLast;
  //TF1 *lFit = new TF1("Fit","[2]*exp(-x/([0]+[1]*x))",0,5000);
  TF1 *lFit = new TF1("expspec","[2]*exp(-x/([0]+[1]*x))",0,5000);
  if(iFitModel == 1) lFit  = new TF1("expspec","[2]*exp(-[0]*pow(x,[1]))",0,5000);
  lFit->SetParLimits(2,0,10000000); lFit->SetParameter(2,lH0->Integral()); 
  lFit->SetParLimits(0,  0,100);    lFit->SetParameter(0,20);
  lFit->SetParLimits(1,-10,10);     lFit->SetParameter(1,0);
  if(iFitModel == 1) lFit->SetParameter(0,0.3);
  if(iFitModel == 2) lFit->SetParameter(1,0.5);
  
  //TFitResultPtr  lFitPtr = lH0->Fit("expspec","SEWL","IR",lFirst,lLast);
  TFitResultPtr  lFitPtr = lH0->Fit("expspec","SER","R",lFirst,lLast);
  TMatrixDSym lCovMatrix   = lFitPtr->GetCovarianceMatrix();
  TMatrixD  lEigVecs(3,3);    lEigVecs = TMatrixDSymEigen(lCovMatrix).GetEigenVectors();
  TVectorD  lEigVals(3);      lEigVals = TMatrixDSymEigen(lCovMatrix).GetEigenValues();
  double lACentral = lFit->GetParameter(0); 
  double lBCentral = lFit->GetParameter(1);
  lEigVals(0) = sqrt(lEigVals(1));
  lEigVals(1) = sqrt(lEigVals(2));

  for(int i0 = 0; i0 < lH0->GetNbinsX()+1; i0++) lH0->SetBinContent(i0,lH0->GetBinContent(i0)*lH0->GetXaxis()->GetBinWidth(i0));
  for(int i0 = 0; i0 < lH0->GetNbinsX()+1; i0++) lH0->SetBinError  (i0,lH0->GetBinError  (i0)*lH0->GetXaxis()->GetBinWidth(i0));

  lEigVecs(0,0) = lEigVecs(0,1);
  lEigVecs(1,0) = lEigVecs(1,1);
  lEigVecs(0,1) = lEigVecs(0,2);
  lEigVecs(1,1) = lEigVecs(1,2);
  
  TH1F* lH     = makeHist(lFit,lH0,"Def");
  lFit->SetParameter(0,lACentral + lEigVals(0)*lEigVecs(0,0));
  lFit->SetParameter(1,lBCentral + lEigVals(0)*lEigVecs(1,0));
  TH1F* lHUp   = makeHist(lFit,lH0,"Up");
  lFit->SetParameter(0,lACentral - lEigVals(0)*lEigVecs(0,0));
  lFit->SetParameter(1,lBCentral - lEigVals(0)*lEigVecs(1,0));
  TH1F* lHDown = makeHist(lFit,lH0,"Down");

  lFit->SetParameter(0,lACentral + lEigVals(1)*lEigVecs(0,1));
  lFit->SetParameter(1,lBCentral + lEigVals(1)*lEigVecs(1,1));
  TH1F* lHUp1   = makeHist(lFit,lH0,"Up1");
  lFit->SetParameter(0,lACentral - lEigVals(1)*lEigVecs(0,1));
  lFit->SetParameter(1,lBCentral - lEigVals(1)*lEigVecs(1,1));
  TH1F* lHDown1 = makeHist(lFit,lH0,"Down1");
  
  //lFirst = 200;
  std::string lNuisance1 =  iBkg+"_"+"CMS_"+iName+"1_" + iChannel + "_" + iEnergy;
  std::string lNuisance2 =  iBkg+"_"+"CMS_"+iName+"2_" + iChannel + "_" + iEnergy;
  lHUp    = merge(lNuisance1 + "Up"   ,lFirst,lH0,lHUp);
  lHDown  = merge(lNuisance1 + "Down" ,lFirst,lH0,lHDown);
  lHUp1   = merge(lNuisance2 + "Up"   ,lFirst,lH0,lHUp1);
  lHDown1 = merge(lNuisance2 + "Down" ,lFirst,lH0,lHDown1);
  lH      = merge(lH0->GetName()      ,lFirst,lH0,lH);  
  if(iRebin) { 
    const int lNBins = lData->GetNbinsX();
    double *lAxis    = getAxis(lData);
    lH0     = rebin(lH0    ,lNBins,lAxis);
    lH      = rebin(lH     ,lNBins,lAxis);
    lHUp    = rebin(lHUp   ,lNBins,lAxis);
    lHDown  = rebin(lHDown ,lNBins,lAxis);
    lHUp1   = rebin(lHUp1  ,lNBins,lAxis);
    lHDown1 = rebin(lHDown1,lNBins,lAxis);
  }
  TFile *lOutFile =new TFile("Output.root","RECREATE");
  cloneFile(lOutFile,lFile,iDir+"/"+iBkg);
  lOutFile->cd(iDir.c_str());
  lH     ->Write();
  lHUp   ->Write(); 
  lHDown ->Write(); 
  lHUp1  ->Write(); 
  lHDown1->Write(); 

  // Debug Plots
  lH0    ->SetLineWidth(1); lH0->SetMarkerStyle(kFullCircle);
  lH     ->SetLineColor(kGreen);
  lHUp   ->SetLineColor(kRed);
  lHDown ->SetLineColor(kRed);
  lHUp1  ->SetLineColor(kBlue);
  lHDown1->SetLineColor(kBlue);
  TCanvas *lC0 = new TCanvas("Can","Can",800,600);
  lC0->Divide(1,2); lC0->cd();  lC0->cd(1)->SetPad(0,0.2,1.0,1.0); gPad->SetLeftMargin(0.2) ;  
  lH0->Draw();
  lH     ->Draw("hist sames");
  lHUp   ->Draw("hist sames");
  lHDown ->Draw("hist sames");
  lHUp1  ->Draw("hist sames");
  lHDown1->Draw("hist sames");
  gPad->SetLogy();
  lC0->cd(2)->SetPad(0,0,1.0,0.2); gPad->SetLeftMargin(0.2) ;
  drawDifference(lH0,lH,lHUp,lHDown,lHUp1,lHDown1);
  lC0->SaveAs((iBkg+"_"+"CMS_"+iName+"1_" + iDir + "_" + iEnergy+".png").c_str());
  //lFile->Close();
  return;
}