void output_histograms(sampler *samp, char matlab_hist, char gnuplot_hist){
    /*
     Compute histograms for the given sampler.
     Number of bins in this script is always 100.
     Bin locations are picked dynamically to not lose samples.

     Input:
          sampler *samp            Sampler object with sampler already run.
          char matlab_hist         If true, will write matlab format data files.
          char gnuplot_hist        If true, will write gnuplot format data files.

     Output:
          Write data files for histograms.
     */

    int n_bins = 100;
    double tau;

    float *centers = (float *) malloc(n_bins * sizeof(float));
    if(!centers){ perror("Allocation failure Histogram"); abort(); }
    float *f_hat = (float *) malloc(n_bins * sizeof(float));
    if(!f_hat){ perror("Allocation failure Histogram"); abort(); }
    float *X = (float *) malloc(samp->total_samples * sizeof(float));
    if(!X){ perror("Allocation failure Histogram"); abort(); }

    for(int i=0; i<samp->num_to_save; i++){

        for(int j=0; j < samp->total_samples; j++)
            X[j] = samp->samples_host[i + j*(samp->num_to_save)];

        tau = samp->acor_times[i];
        histogram_data(n_bins, X, samp->total_samples, tau, centers, f_hat);

        if(matlab_hist)
            histogram_to_matlab(n_bins, centers, f_hat, (samp->indices_to_save_host[i])+1); // add one for matlab index
        if(gnuplot_hist)
            histogram_to_gnuplot(n_bins, centers, f_hat, samp->indices_to_save_host[i]);
    }

    free(centers);
    free(f_hat);
    free(X);

}
void fit(TH1* histogram, double xMin, double xMax, double massValue, std::vector<fitParameterType>& fitParameter)
{
  // create fit variable
  TAxis* xAxis = histogram->GetXaxis();
  if ( xMin < 0. ) xMin = xAxis->GetXmin(); 
  if ( xMax < 0. ) xMax = xAxis->GetXmax(); 
  std::string fitVariableName = Form("%s_fitVariable", histogram->GetName());
  RooRealVar fitVariable(fitVariableName.data(), fitVariableName.data(), xMin, xMax);
   
  // convert histogram to RooFit format
  std::string histogramName_data = Form("%s_data", histogram->GetName());
  RooDataHist histogram_data(histogramName_data.data(), histogramName_data.data(), fitVariable, histogram, 1.0);

  // create product of linear * Heaviside * Gaussian Error function
  std::string svFitLineShapeName_slope = Form("%s_svFitLineShape_slope", histogram->GetName());
  RooRealVar svFitLineShape_slope(svFitLineShapeName_slope.data(), svFitLineShapeName_slope.data(), 2./(massValue*massValue), 0., 1.);
  std::string svFitLineShapeName_offset = Form("%s_svFitLineShape_offset", histogram->GetName());
  RooRealVar svFitLineShape_offset(svFitLineShapeName_offset.data(), svFitLineShapeName_offset.data(), 0., -1., +1.);

  std::string heavisideName_threshold = Form("%s_heaviside_threshold", histogram->GetName());
  RooRealVar heaviside_threshold(heavisideName_threshold.data(), heavisideName_threshold.data(), 0.2*massValue, 1.e-2*massValue, 0.5*massValue);

  std::string sculptingName_bias = Form("%s_sculpting_bias", histogram->GetName());
  RooRealVar sculpting_bias(sculptingName_bias.data(), sculptingName_bias.data(), 0.25*massValue, 0.*massValue, 0.9*massValue);
  std::string sculptingName_width = Form("%s_sculpting_width", histogram->GetName());
  RooRealVar sculpting_width(sculptingName_width.data(), sculptingName_width.data(), 0.1*massValue, 1.e-2*massValue, 1.0*massValue);

  std::string svFitLineShapeName = Form("%s_svFitLineShape", histogram->GetName());
  std::string svFitLineShapeFormula = "(@0*@1 + @2)*0.5*(1.0 + TMath::Sign(+1, @0 - @3))*0.5*(1.0 + TMath::Erf((@0 - @4)/@5))";
  RooArgList svFitLineShapeArgs(fitVariable, 
				svFitLineShape_slope,
				svFitLineShape_offset,
				heaviside_threshold,
				sculpting_bias,
				sculpting_width);
  RooGenericPdf svFitLineShape(svFitLineShapeName.data(), svFitLineShapeName.data(), svFitLineShapeFormula.data(), svFitLineShapeArgs);

  // create Gaussian 
  std::string gaussianName_mean = Form("%s_gaussian_mean", histogram->GetName());
  RooConstVar gaussian_mean(gaussianName_mean.data(), gaussianName_mean.data(), 0.);
  std::string gaussianName_sigma = Form("%s_gaussian_sigma", histogram->GetName());
  RooRealVar gaussian_sigma(gaussianName_sigma.data(), gaussianName_sigma.data(), 0.2*massValue, 1.e-2*massValue, 0.5*massValue);
  std::string gaussianName = Form("%s_gaussian", histogram->GetName());
  RooGaussian gaussian(gaussianName.data(), gaussianName.data(), fitVariable, gaussian_mean, gaussian_sigma);

  // numerically convolute both PDFs using fast Fourier transform
  std::string fitFunctionName = Form("%s_fitFunction", histogram->GetName());
  RooFFTConvPdf fitFunction(fitFunctionName.data(), fitFunctionName.data(), fitVariable, svFitLineShape, gaussian);

  // fit histogram
  fitFunction.fitTo(histogram_data);

  // save fit parameter
  fitParameter.resize(6);
  fitParameter[0] = fitParameterType(&svFitLineShape_slope);
  fitParameter[1] = fitParameterType(&svFitLineShape_offset);
  fitParameter[2] = fitParameterType(&gaussian_sigma);
  fitParameter[3] = fitParameterType(&heaviside_threshold);
  fitParameter[4] = fitParameterType(&sculpting_bias);
  fitParameter[5] = fitParameterType(&sculpting_width);

  // create control plot
  std::string frameTitle = Form("%s_frame", histogram->GetName());
  RooPlot* frame = fitVariable.frame(RooFit::Title(frameTitle.data()));
  histogram_data.plotOn(frame);
  fitFunction.plotOn(frame, RooFit::LineColor(kRed));
  
  std::string canvasName = Form("%s_canvas", histogram->GetName());
  TCanvas* canvas = new TCanvas(canvasName.data(), canvasName.data(), 800, 600);
  gPad->SetLeftMargin(0.15); 
  frame->GetYaxis()->SetTitleOffset(1.4);
  frame->Draw();
    
  std::string outputFileName_plot = Form("svFitPerformance_%s_fit", histogram->GetName());
  canvas->Print(std::string(outputFileName_plot).append(".eps").data());
  canvas->Print(std::string(outputFileName_plot).append(".png").data());
  canvas->Print(std::string(outputFileName_plot).append(".pdf").data());
  
  delete canvas;
}
    virtual bool run()
    {
        const std::vector<sd::core::ViewNode *> &parents = this->getPreviousViewNodes();
	sd::core::ImageView_<T> *image = static_cast<sd::core::ImageView_<T>*>(parents[0]);

        if (parents.size() != 1)
        {
            std::cout << "\tExpecting 1 parent exactly, found " << parents.size() << ". Abort!\n";
            return false;
        }
        
        sd::frontend::Parameter pchannel;
        this->getParams("channel", pchannel);
        std::string wanted_channel = pchannel.getString();
        std::cout << "SELECTED channel: " << wanted_channel << std::endl;
	
	sd::frontend::Parameter pNbTiles;
	this->getParams("nbTiles", pNbTiles);
	int nbTiles = pNbTiles.getInteger();

        /* RGBA: R is 0, G is 1...*/
        int channel_id = 0;
        if(wanted_channel == "Red")
            channel_id = 0;
        else if(wanted_channel == "Green")
            channel_id = 1;
        else if(wanted_channel == "Blue")
            channel_id = 2;
        else if(wanted_channel == "Alpha")
            channel_id = 3;
        else
            std::cout << "Error on channel, default: red" << std::endl;	
	
	std::vector<float> histogram_data_1(256, 0);
	std::vector<float> histogram_data(nbTiles, 0);
	int loop_count = 0;  
        int value = 0;  
	for(auto source_it = image->begin(); source_it != image->end(); ++source_it){
            value = (float)source_it(channel_id);
            histogram_data_1[value]++;
            loop_count++;
	}
	
	int coef = 256/nbTiles;
    for(int i=0; i<nbTiles; i++){
	   for(int j=0; j<coef; j++){
	       histogram_data[i] += histogram_data_1[(i+1)*coef+j];
	  }
    }
	
	float maxHeight = 0;
	for(int i=0; i<=nbTiles; i++){
	  if(maxHeight < histogram_data[i]){
	    maxHeight = histogram_data[i];
	  }
	}
	
	if(maxHeight != 0){
	  for(int i=0; i<=nbTiles; i++){
        histogram_data[i] = (histogram_data[i]*256)/maxHeight;
	  }
	}
	
	int sizeX = nbTiles;
	int sizeY = nbTiles;
	sd::Size result_size(sizeX, sizeY);
	sd::core::ImageViewInfo info(sd::GRAYLEVEL, sd::Z_AXIS, result_size);
	this->init(info);
	T* resultData = this->getData();
	std::fill(resultData, resultData+result_size.dataSize(), 255);
	this->setMinMax(0, 255);

    auto itR = this->begin();
    for(int i = 0; i < nbTiles; i++){
        for(int j = 0; j < nbTiles; j++, itR++){
            for(int k = 0; k < 4; k++){
                if((i) < (int)(nbTiles-histogram_data[j]))
                    itR(k) = 255;
                else
                    itR(k) = 0;
            }
        }
    }

    return true;
    }