//  
//  landauFit.C
//  Obtaining the MPV from a fit of the ADC counts distribution
//
//  Created by Christian Elsasser on 31.05.13.
//  University of Zurich, elsasser@cern.ch
//  Copyright only for commercial use
//
//  Compile with:
//  g++ -o landauFit landauFit.C `root-config --glibs --cflags` -lRooFit -lRooFitCore -lEG
//

//  General include
#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <stdlib.h>
#include <limits>
#include <string>
#include <time.h>


//  ROOT include
#include "../../include/incBasicROOT.h"
#include "../../include/incDrawROOT.h"
#include "../../include/incHistROOT.h"
#include "../../include/incIOROOT.h"
#include "../../include/incRooFit.h"


#include "../../include/basicROOTTools.h"
#include "../../include/basicRooFitTools.h"


#include "../../include/lhcbstyle.C"


#include "deplTool.h"


// -d detector (TT/IT)
// -l layer (TTaX,TTaU,TTbV,TTbX, T[1-3]{X1,U,V,X2})
// -s read-out sector number
// -f fill number
// -c Calibration step (Odin step) [0-65]
// -r consider only hit in a distance closer than r mm from the beam axis
// -v number of summed up strips
// -ns Do not save the value in the root file
// -ss Perform a temporary save


int landauFit(int argc, char* argv[]);


int main(int argc, char* argv[]){
  

  Printf("Starting...");

  // if i want to use this, set $LHCBSTYLE to either 0 or 1
  TStyle* style = lhcbStyle();
  
  int argc_copy = argc;
  
  TApplication* theApp = new TApplication("Analysis", &argc, argv);
  argc = theApp->Argc();
  argv = theApp->Argv();
  
  bool runBatch = false;
  
  for (int i = 1; i<argc; i++) {
    if (strcmp(argv[i],"-b")==0) {
      runBatch = true;
      gROOT->SetBatch();
      Printf("Set BATCH mode...");
    }
  }
  

  
  int exit = landauFit(argc,argv);
  
  
  
  Printf("End");
  if (!runBatch) {
    theApp->Run(!runBatch);
  }
  
  
  return exit;
}


//  Executable method
int landauFit(int argc, char* argv[]){
  
  TVectorD v_res(5);
  
  gStyle->SetPadLeftMargin(0.20);
  gStyle->SetTitleOffset(1.5,"Y");
  gStyle->SetTitleOffset(1.0,"X");

  // To point it to the right directory:
  // export DISK=/disk/data1/hep/elena
  const char* diskVar = std::getenv ("DISK");
  Printf("%s",diskVar);
  
  int fill      = 2083;
  TString det("TT");
  TString lay("TTaU");
  int sector    = 2634;
  int caliStep  = 0;
  int val       = 3;
  bool notSave  = false;
  bool temSave  = false;
  double radius = -10.0;
  
  for (int i=1; i<argc; i++) {
    if (strcmp(argv[i],"-d")==0 && i+1<argc) {
      det = argv[++i];
    }else if (strcmp(argv[i],"-l")==0 && i+1<argc) {
      lay = argv[++i];
    }else if (strcmp(argv[i],"-s")==0 && i+1<argc) {
      sector = std::atoi(argv[++i]);
    }else if (strcmp(argv[i],"-f")==0 && i+1<argc) {
      fill = std::atoi(argv[++i]);
    }else if (strcmp(argv[i],"-v")==0 && i+1<argc) {
      val = std::atoi(argv[++i]);
    }else if (strcmp(argv[i],"-c")==0 && i+1<argc) {
      caliStep = std::atoi(argv[++i]);
    }else if (strcmp(argv[i],"-r")==0 && i+1<argc) {
      radius = std::atof(argv[++i]);
    }else if (strcmp(argv[i],"-ns")==0) {
      notSave = true;
    }else if (strcmp(argv[i],"-ss")==0) {
      temSave = true;
    }
  }
  
  
  
  int voltStep  = caliStep/6;
  int timeStep  = caliStep%6;
  
  double time   = STTool::GetTime(caliStep);
  double volt   = 0.0;
  
  
  if (det.EqualTo("TT")) {
    volt = STTool::GetTTVoltage(caliStep);
  }else{
    volt = STTool::GetITVoltage(caliStep);
  }
  
  // Name of the vector where it is stored
  TString vn_result(Form("v_%d_val%d",caliStep,val));
  
  // Directory name and file names for the plots
  TString dn_graph(Form("%s/data/ST/graphics/%s/%s/%d/%d",
                        diskVar,det.Data(),lay.Data(),sector,fill));
  TString fn_graph_s(Form("%s/signal_%d_val%d",
                          dn_graph.Data(),caliStep,val));
  TString fn_graph_n(Form("%s/noise_%d_val%d",
                          dn_graph.Data(),caliStep,val));
  TString fn_graph_a(Form("%s/alt_%d_val%d",
                          dn_graph.Data(),caliStep,val));
  
  // Director name and file name for the data
  TString dn_output(Form("%s/data/ST/Aging",diskVar));
  TString fn_output(Form("%s/CCEScan.root",dn_output.Data()));
  Printf("%s", fn_output.Data());
  TString fn_dummy(Form("%s/check",dn_output.Data()));
  
  // Name if it is not directly written into the main file
  if (temSave) {
    fn_output= TString(Form("%s/temp_%s_%s_%d_%d_r%d.root",
                            dn_output.Data(),det.Data(),lay.Data(),
                            sector,fill,(int)radius));
  }

  
  // Set the radius to an irrelevant value
  if (radius<0.0) {
    radius = 2000.0;
  }else{
    vn_result  +=Form("_r%d",(int)radius);
    fn_graph_s +=Form("_r%d",(int)radius);
  }
  
  fn_graph_s += ".pdf";
  fn_graph_n += ".pdf";
  
  
  Printf("=========================================");
  Info("landauFit","Analyse: ");
  Printf("               Sector:    %d",sector);
  Printf("               Radius:    %4.2f mm",radius);
  Printf("               Fill:      %d",fill);
  Printf("               Detector:  %s",det.Data());
  Printf("               Layer:     %s",lay.Data());
  Printf("               Voltage:   %4.2f V",volt);
  Printf("               Time:      %4.2f ns",time);
  
  
  // Obtain directory, file and tree names for the ADC counts
  TString dn_data(Form("%s/data/ST/Aging_Tuples/%s/%s"
                        ,diskVar,det.Data(),lay.Data()));
  TString fn_data(Form("%s/%d.root",
                       dn_data.Data(),fill));
  TString tn_sig(Form("STADCTrackMonitor/HitInfo/%s",
                      lay.Data()));
  TString tn_bkg(Form("STADCTrackMonitor/NoiseInfo/%s",
                      lay.Data()));
  
  

  TFile* f_data       = TFile::Open(fn_data.Data());
  
  if (!f_data) {
    Error("landauFit","Data file does not exist!");
    Printf("=========================================\n");
    return EXIT_FAILURE;
  }
  
  TTree* t_sig = (TTree*)f_data->Get(tn_sig.Data());
  if (!t_sig) {
    Error("landauFit","Signal tree not found!");
    Printf("=========================================\n");
    return EXIT_FAILURE;
  }
  
  TTree* t_bkg = (TTree*)f_data->Get(tn_bkg.Data());
  if (!t_bkg) {
    Error("landauFit","Background tree not found!");
    Printf("=========================================\n");
    return EXIT_FAILURE;
  }
  
  TH1F* h_sig = new TH1F("h_sig","Signal histo",
                         208,-32.0,176.0);
  TH1F* h_bkg = new TH1F("h_bkg","Background histo",
                         208,-32.0,176.0);

  // Select calibration and read-out sector
  TCut cu_bkg(Form("(odinStep==%d) && (sector==%d)",
                   caliStep,sector));
  
  // Select only first run in fill if you consider calibration step 0
  if (caliStep==0) {
    cu_bkg = cu_bkg && TCut(Form("(runNumber==%d)",STTool::zeroRunMap[fill]));
  }
  
  // Select tracks based on their chi^2 and ghost prob
  TCut cu_sel = STTool::cu_track_TT;
  if (strcmp(det.Data(),"TT")==0) {
    cu_sel = STTool::cu_track_IT;
  }
  
  // Get full selection for signal tracks/hits including radius
  TCut cu_sig = cu_bkg && cu_sel && TCut(Form("(TMath::Sqrt(xHit*xHit+yHit*yHit)<%f)",radius));

  // Fill Histograms
  t_sig->Draw(Form("val%d>>h_sig",val),cu_sig,"goff");
  t_bkg->Draw(Form("val%d>>h_bkg",val),cu_bkg,"goff");
  
  
  delete t_sig;
  delete t_bkg;
  
  // Skip histogram if there are too few entries in the histograms
  if (h_sig->GetEntries()<10 || h_bkg->GetEntries()<10) {
    Error("landauFit","Too few entries in histograms. Skip this step!");
    return EXIT_FAILURE;
  }
  
  // ADC value
  RooRealVar* adc = new RooRealVar("adc","Signal height",
                                   h_sig->GetXaxis()->GetXmin(),
                                   h_sig->GetXaxis()->GetXmax(),
                                   "ADC value");
  
  // RooFit histograms
  RooDataHist* hr_bkg = new  RooDataHist("hr_bkg","Histogram of raw noise",
                                         *adc,RooFit::Import(*h_bkg));
  RooDataHist* hr_sig = new  RooDataHist("hr_sig","Histogram of raw signal",
                                         *adc,RooFit::Import(*h_sig));
  
  // PDF for noise
  RooRealVar* nMu   = new RooRealVar("nMu","Mean of raw noise distribution",0.0,-10.0,10.0,"");
  RooRealVar* nSig1 = new RooRealVar("nSig1","Sigma 1 of raw noise distribution",3.0,0.5,6.0,"");
  RooRealVar* nSig2 = new RooRealVar("nSig2","Sigma 2 of raw noise distribution",5.0,0.5,25.0,"");
  RooRealVar* nFrac = new RooRealVar("nFrac","Fractition of Gaussian 1 to total noise distribution",0.5,0.0,1.0);
  
  RooGaussian* nG1  = new RooGaussian("nG1","Gaussian 1 of raw noise distribution",*adc,*nMu,*nSig1);
  RooGaussian* nG2  = new RooGaussian("nG2","Gaussian 2 of raw noise distribution",*adc,*nMu,*nSig2);
  
  RooAddPdf* nPDF   = new RooAddPdf("nPDF","Total distribution of raw noise",
                                    RooArgList(*nG1,*nG2),
                                    RooArgList(*nFrac));
  
  // Fit and plot noise sample
  RooFitResult* nRes = nPDF->fitTo(*hr_bkg,RooFit::Save());
  RooPlot* nFrame    = adc->frame(RooFit::Title(Form("Noise distribution for %4.0f V and %4.1f ns",volt,time)));
  hr_bkg->plotOn(nFrame,RooFit::DataError(RooAbsData::SumW2),RooFit::DataError(RooAbsData::SumW2));
  nPDF->plotOn(nFrame,RooFit::LineColor(kBlue));
  
  
  // average noise value
  v_res(2)     = nSig1->getVal()*nFrac->getVal()+nSig2->getVal()*(1.0-nFrac->getVal());
  // uncertainty on average noise
  v_res(3)     = TMath::Sqrt(TMath::Power(nSig1->getError()*nFrac->getVal(),2.0)+
                             TMath::Power(nSig2->getError()*(1.0-nFrac->getVal()),2.0)+
                             TMath::Power((nSig1->getVal()-nSig2->getVal())*nFrac->getError(),2.0));
  
  
  // PDF for signal
  
  // Constrain parameters fixed in the noise fit
  nMu->setConstant(kTRUE);
  //nSig1->setConstant(kTRUE);
  //nSig2->setConstant(kTRUE);
  nFrac->setConstant(kTRUE);
  
  RooGaussian* sG1 = new RooGaussian("sG1","Gaussian 1",*adc,*nMu,*nSig1);
  RooGaussian* sG2 = new RooGaussian("sG2","Gaussian 2",*adc,*nMu,*nSig2);
  
  RooAddPdf* sG    = new RooAddPdf("sG","Gaussian smearing",
                                   RooArgList(*sG1,*sG2),
                                   RooArgList(*nFrac));
  
  RooAddPdf* nG    = new RooAddPdf("nG","Distribution of raw noise",
                                   RooArgList(*nG1,*nG2),
                                   RooArgList(*nFrac));
  
  
  RooRealVar* mpv  = new RooRealVar("mpv","Most probable ADC value",
                                    TMath::Max(10.0,h_sig->GetBinCenter(h_sig->GetMaximumBin()))
                                    ,1.0,60.0,"");
  RooRealVar* spread  = new RooRealVar("spread","Sigma of Landau distribution"
                                       ,3.0,0.1,10.0,"");
  
  RooRealVar* ampv = new RooRealVar("ampv","Most probable ADC value",
                                    TMath::Max(10.0,h_sig->GetBinCenter(h_sig->GetMaximumBin()))
                                    ,1.0,60.0,"");
  RooRealVar* aspread = new RooRealVar("aspread","Sigma of Landau distribution"
                                       ,3.0,0.1,10.0,"");
  
  // Variables for the Landau coming from photo conversion
  RooFormulaVar* scaledMpv    = new RooFormulaVar("scaledMpv","2*mpv",RooArgList(*mpv));
  RooFormulaVar* scaledSpread = new RooFormulaVar("scaledSpread","2*spread",RooArgList(*spread));
  
  
  RooLandau* landauDist       = new RooLandau("landauDist","Landau distribution of ADC values",*adc,*mpv,*spread);
  RooLandau* landauDistScaled = new RooLandau("landauDistScaled","Landau distribution of conversion",*adc,*scaledMpv,*scaledSpread);
  
  RooLandau* altlandauDist    = new RooLandau("altlandauDist","AlternativeLandau distribution of ADC values",*adc,*ampv,*aspread);
  
  RooRealVar* cFrac           = new RooRealVar("cFrac","Fraction of photo conversion",0.025);

  // Set fraction from photon conversion to zero
  if (det.EqualTo("IT")) {
    cFrac->setVal(0.0);
  }
  
  RooRealVar* sFrac           = new RooRealVar("sFrac","Fraction of signal hits",0.8,0.0,1.0);
  RooRealVar* aFrac           = new RooRealVar("aFrac","Fraction of signal hits",0.8,0.0,1.0);
  
  adc->setBins(10000,"cache") ;
  
  RooFFTConvPdf* landauConv         = new RooFFTConvPdf("landauConv","Landau (x) gauss",*adc,*landauDist,*sG);
  RooFFTConvPdf* landauConvPhoto    = new RooFFTConvPdf("landauConvPhoto","Landau Conv (x) gauss",*adc,*landauDistScaled,*sG);

  RooAddPdf* sTot             = new RooAddPdf("sTot","Total signal distribution",*landauConvPhoto,*landauConv,*cFrac);
  RooAddPdf* sPDF             = new RooAddPdf("sPDF","Total distribution",*sTot,*nG,*sFrac);
  
  // Alternative distribution only done from a single Landau
  RooFFTConvPdf* altlandauConv      = new RooFFTConvPdf("altlandauConv","Landau Conv (x) gauss",*adc,*altlandauDist,*sG);
  RooAddPdf* aPDF             = new RooAddPdf("aPDF","Alternative total distribution",*altlandauConv,*nG,*aFrac);
  
  
  // Fit the distribution
  RooFitResult* sRes = sPDF->fitTo(*hr_sig,RooFit::Save());
  
  
  
  Info("landauFit","Baseline result:");
  Printf("               mpv        = %8.4f+/-%8.4f",mpv->getVal(),mpv->getError());
  Printf("               spread     = %8.4f+/-%8.4f",spread->getVal(),spread->getError());
  Printf("               conv Frac  = %8.4f+/-%8.4f",cFrac->getVal(),cFrac->getError());
  Printf("               noise Frac = %8.4f+/-%8.4f",1.0 - sFrac->getVal(),sFrac->getError());
  
  // mpv value: 1st place in result vector
  v_res(0)     = mpv->getVal();
  // mpv uncertainty: 2nd place in result vector
  v_res(1)     = mpv->getError();
  
  
  
  
  RooPlot* sFrame = adc->frame(RooFit::Title(Form("Signal distribution for %4.0f V and %4.1f ns",volt,time)));
  hr_sig->plotOn(sFrame,RooFit::DataError(RooAbsData::SumW2),RooFit::DataError(RooAbsData::SumW2));
  sPDF->plotOn(sFrame,RooFit::LineColor(kBlue));
  sPDF->plotOn(sFrame,RooFit::Components(*nG),RooFit::LineColor(kBlue),RooFit::LineStyle(kDashed));
  sPDF->plotOn(sFrame,RooFit::Components(*landauConv),RooFit::LineColor(kRed),RooFit::LineStyle(9));
  sPDF->plotOn(sFrame,RooFit::Components(*landauConvPhoto),RooFit::LineColor(kRed),RooFit::LineStyle(kDashed));
  
  
  Info("landauFit","Results: ");
  Printf("   MPV:              %5.2f+/-%5.2f ADC counts",v_res(0),v_res(1));
  Printf("   Noise:            %5.2f+/-%5.2f ADC counts",v_res(2),v_res(3));
  
  if (nRes->status()==0) {
    Info("landauFit","Signal fit status: %d",nRes->status());
  }else{
    Warning("landauFit","Signal fit status: %d",nRes->status());
  }
  
  if (sRes->status()==0) {
    Info("landauFit","Noise fit status:  %d",sRes->status());
  }else{
    Warning("landauFit","Noise fit status:  %d",sRes->status());
  }
  

  // Plot the results
  
  TCanvas* c_sig = new TCanvas("c_sig","Signal Canvas",800,600);
  c_sig->SetLeftMargin(0.20);
  SwapParenthesis(sFrame);
  ReplaceSubstring(sFrame,"Events","Hits");
  ReplaceSubstring(sFrame,"1 ","");
  sFrame->GetYaxis()->SetTitleOffset(1.5);
  sFrame->Draw();
  
  TCanvas* c_bkg = new TCanvas("c_bkg","Background Canvas",800,600);
  c_bkg->SetLeftMargin(0.20);
  nFrame->GetXaxis()->SetLimits(-32.0,32.0);
  SwapParenthesis(nFrame);
  ReplaceSubstring(nFrame,"Events","Hits");
  ReplaceSubstring(nFrame,"1 ","");
  nFrame->GetYaxis()->SetTitleOffset(1.5);
  nFrame->Draw();
  

  // Save data and plots
  
  TFile* f_output;
  
  while (!gSystem->Exec(Form("ls %s &> /dev/null",fn_dummy.Data()))) {
    Info("landauFit","Waiting until file is closed");
    gSystem->Sleep(1000);
  }
  gSystem->Exec(Form("touch %s &> /dev/null",fn_dummy.Data()));
  
  f_output = new TFile(fn_output.Data(),"UPDATE");
  
  
  TString dn_result = TString::Format("%s/%s/%d/%d",
                                      det.Data(),
                                      lay.Data(),
                                      sector,
                                      fill);
  
  // Get right directory
  bool isThere = f_output->GetListOfKeys()->Contains(det.Data());
  if (!isThere) {
    f_output->mkdir(det.Data());
  }
  
  isThere = f_output->GetListOfKeys()->Contains(Form("%s/%s",
                                                     det.Data(),
                                                     lay.Data()));
  if (!isThere) {
    f_output->mkdir(Form("%s/%s",
                         det.Data(),
                         lay.Data()));
  }
  
  isThere = f_output->GetListOfKeys()->Contains(Form("%s/%s/%d",
                                                     det.Data(),
                                                     lay.Data(),
                                                     sector));
  if (!isThere) {
    f_output->mkdir(Form("%s/%s/%d",
                         det.Data(),
                         lay.Data(),
                         sector));
  }
  
  isThere = f_output->GetListOfKeys()->Contains(Form("%s/%s/%d/%d",
                                                    det.Data(),
                                                    lay.Data(),
                                                    sector,
                                                    fill));
  if (!isThere) {
    f_output->mkdir(Form("%s/%s/%d/%d",
                         det.Data(),
                         lay.Data(),
                         sector,
                         fill));
  }
  
  f_output->cd(Form("%s/%s/%d/%d",
                    det.Data(),
                    lay.Data(),
                    sector,
                    fill));
  if(!notSave){
    gDirectory->Delete(Form("%s;*",
                            vn_result.Data()));
    
    v_res.Write(Form("%s",
                     vn_result.Data()));
    
    Info("landauFit","Result written to %s",fn_output.Data());
  }
  
  f_output->Close();
  gSystem->Exec(Form("rm -f %s &> /dev/null",fn_dummy.Data()));
  
  if (!notSave) {
    // Save picture
    gSystem->Exec(Form("mkdir -p %s",dn_graph.Data()));
    gSystem->Exec(Form("rm %s &> /dev/null",fn_graph_s.Data()));
    gSystem->Exec(Form("rm %s &> /dev/null",fn_graph_n.Data()));
    c_sig->SaveAs(fn_graph_s.Data());
    c_bkg->SaveAs(fn_graph_n.Data());
  }
  
  
  Printf("=========================================\n");

  return EXIT_SUCCESS;
}


