void readmcsample(TH1D &nom, TH1D &rw, TH1D &nomratio, bool doGen){
 cout<<"reading data for "<<File_Signal_reco<<endl;
  TChain* t;
  if (!doGen) t= new TChain(reco_name.c_str(),reco_name.c_str());
  else t= new TChain(gen_name.c_str(),gen_name.c_str());
  int nfiles;
  if (!doGen) nfiles=t->Add(File_Signal_reco.c_str());
  else nfiles=t->Add(File_Signal_gen.c_str());

  TBranch *b_reco=t->GetBranch("reco");
  TBranch *b_truth=t->GetBranch("truth");
  TLeaf *l_mass=b_reco->GetLeaf("z_y");
  if (doMass) l_mass=b_reco->GetLeaf("z_m");
  if (doGen) {
    l_mass=b_truth->GetLeaf("z_y");
    if (doMass) l_mass=b_truth->GetLeaf("z_m");
  }
  TLeaf *l_phistar=b_reco->GetLeaf("z_phistar_dressed");
  TLeaf *l_phistar_true=b_truth->GetLeaf("z_phistar_dressed");
  int nweights;
  t->SetBranchAddress("weight_size",&nweights);
  t->GetEntry(0);
  cout<<"The sample has nweights: "<<nweights<<endl;
  double weights[nweights];
  int weightid[nweights];
  t->SetBranchAddress("weights",&weights);
  t->SetBranchAddress("weight_ids",&weightid);
  
  // TFile f_zy("ratio_y.root");
  // ratio = (TH1F*)f_zy.Get("ratio");
  // f_zy.Close();
  TFile f_zm("ratio_zmass.root");
  TH1F *ratio = (TH1F*)f_zm.Get("ratio_histo");
  cout<<"Entries: "<<t->GetEntries()<<endl;
  for (int i=0; i<t->GetEntries();i++){
    t->GetEntry(i);
    double phistar=l_phistar->GetValue();
    double mass=l_mass->GetValue();
    double phistar_true=l_phistar_true->GetValue();
    double weight =1;
    for (int w=0; w<nweights;w++){
      if (weightid[w]==1 || weightid[w]==2 || weightid[w]==12 || weightid[w]==13 || weightid[w]==20 || weightid[w]==30) {weight=weight*weights[w];}
    }
    int idx=ratio->GetXaxis()->FindBin(mass);
    if (ratio->GetBinContent(idx)!=0){
     if (!doGen){
	nom.Fill(phistar,weight);
	nomratio.Fill(phistar,weight);
	weight=weight*ratio->GetBinContent(idx);
	rw.Fill(phistar,weight);
     }
      else{
	nom.Fill(phistar_true,weight);
	nomratio.Fill(phistar_true,weight);
	weight=weight*ratio->GetBinContent(idx);
	rw.Fill(phistar_true,weight);
      }
    }
  }
}
Exemple #2
0
TH1D* GetDataPhiStar() {
    cout << "reading data" << endl;
    vector<std::string> File_Data = Get_File_Data();
    TH1D* h_phistar = new TH1D("phistar", "phistar", nphistar, phistarBins);
    //TH1D *h_phistar= new TH1D("phistar","phistar",160,50,130);
    h_phistar->Sumw2();
    TChain* t = new TChain(reco_name.c_str(), reco_name.c_str());
    int nfiles;
    for (int i = 0; i < File_Data.size(); i++) {
        nfiles = t->Add(File_Data[i].c_str());
    }
    TBranch* b_reco = t->GetBranch("reco");
    TLeaf* l_m = b_reco->GetLeaf("z_m");
    TLeaf* l_phistar = b_reco->GetLeaf("z_phistar_dressed");
    TLeaf* l_e0_q = b_reco->GetLeaf("e_charge0");
    TLeaf* l_e1_q = b_reco->GetLeaf("e_charge1");
    cout << "Entries: " << t->GetEntries() << endl;
    for (int i = 0; i < t->GetEntries(); i++) {
        t->GetEntry(i);
        double E0_q = l_e0_q->GetValue();
        double E1_q = l_e1_q->GetValue();
        //if (E0_q!=E1_q) continue;
        h_phistar->Fill(l_phistar->GetValue(), 1);
        //h_phistar->Fill(l_m->GetValue(),1);
    }
    cout << "filled data phistar histogram" << endl;
    return h_phistar;
}
int Fitter::Save_sWeights()
{
	struct NameValTuple {string name; double val;};
	TFile* pFile = new TFile(outputSweights.c_str(), "RECREATE");
	TChain* pChain = new TChain;
	TTree* pTree = NULL;
	Long64_t nEntries = 0, iEntry=0;
	BranchProxy<double> bp;
	vector<NameValTuple> nameValTuples;
	
	if(!pFile){ cerr << "Error creating file" << endl; return 1; }
	if(InitChain(pChain)) return 1;	
	
	// Deactivate branches that would have the same name as the added branches
	for(auto& pVec_pdfs : {&sigPdfs, &bkgPdfs})
	for(auto& pdf : *pVec_pdfs)
	{
		NameValTuple nv = {pdf.GetYld().GetName()};
		string swBranchName = nv.name+"_sw";
		if(pChain->GetBranch(swBranchName.c_str()))
			pChain->SetBranchStatus(swBranchName.c_str(), 0);
		nameValTuples.push_back(nv);
	}
	
	pTree = pChain->CloneTree(0);
	bp.Connect(pChain, branchName.c_str());
	nEntries = pChain->GetEntries();
	
	for(auto& nv : nameValTuples)
	{
		string swBranchName = nv.name + "_sw";
		string branchTitle = swBranchName + "/D";
		
		pTree->Branch(swBranchName.c_str(), &nv.val, branchTitle.c_str());	
	}
	
	for(Long64_t i=0; i<nEntries; ++i)
	{
		pChain->GetEntry(i);
		if(!range.In(bp)) continue;
		
		for(auto& nv : nameValTuples) 
			nv.val = pSPlot->GetSWeight(iEntry, (nv.name+"_sw").c_str());
		
		++iEntry;
		pTree->Fill();
	}
	pTree->AutoSave();
	
	delete pFile;
	delete pChain;
	
	return 0;
}
Exemple #4
0
TH1D* GetBGPhiStar(std::string FileName, double sampleweight) {
    TH1D* phistartemp = new TH1D("phistar", "phistar", nphistar, phistarBins);
    //TH1D *phistartemp= new TH1D("phistar","phistar",160,50,130);
    phistartemp->Sumw2();

    gErrorIgnoreLevel = kError;
    cout << "reading data for " << FileName << endl;
    TChain* t = new TChain(reco_name.c_str(), reco_name.c_str());
    int nfiles;
    nfiles = t->Add(FileName.c_str());

    TBranch* b_reco = t->GetBranch("reco");
    TLeaf* l_phistar = b_reco->GetLeaf("z_phistar_dressed");
    TLeaf* l_m = b_reco->GetLeaf("z_m");
    TLeaf* l_e0_q = b_reco->GetLeaf("e_charge0");
    TLeaf* l_e1_q = b_reco->GetLeaf("e_charge1");
    int nweights;
    t->SetBranchAddress("weight_size", &nweights);
    t->GetEntry(0);
    cout << "The sample has nweights: " << nweights << endl;
    double weights[nweights];
    int weightid[nweights];
    t->SetBranchAddress("weights", &weights);
    t->SetBranchAddress("weight_ids", &weightid);

    cout << "reading data for " << FileName << endl;
    cout << "Entries: " << t->GetEntries() << endl;
    for (int i = 0; i < t->GetEntries(); i++) {
        t->GetEntry(i);
        double E0_q = l_e0_q->GetValue();
        double E1_q = l_e1_q->GetValue();
        //cout<<E0_q<<" "<<E1_q<<endl;
        //if (E0_q!=E1_q) continue;
        double phistar = l_phistar->GetValue();
        double weight = sampleweight;
        for (int w = 0; w < nweights; w++) {
            if (weightid[w] == 1 || weightid[w] == 2 || weightid[w] == 12
                    || weightid[w] == 13 || weightid[w] == 20 || weightid[w] == 30) {
                weight = weight * weights[w];
            }
        }
        phistartemp->Fill(phistar, weight);
        //phistartemp->Fill(l_m->GetValue(),weight);
    }
    cout << "done reading data for " << FileName << endl;
    return phistartemp;
}
void GetGen(double sampleweight, TH1D* &h_phistar, vector<TH1D*> &h_cteq, vector<TH1D*> &h_fsr_pileup) {
  gErrorIgnoreLevel = kError;
  cout << "reading signal gen" << endl;
  h_phistar = new TH1D("phistar", "phistar", nbins, 0, nbins);
  h_phistar->Sumw2();
  TChain* t = new TChain(gen_name.c_str(), gen_name.c_str());
  if (doMG) {
    if (elec == 0) t->Add(File_Signal_gen.c_str());
    else if (elec == 1) t->Add(File_Signal_gen_born.c_str());
    else t->Add(File_Signal_gen_bare.c_str());
  } else {
    if (elec == 0) t->Add(File_Powheg_gen.c_str());
    else if (elec == 1) t->Add(File_Powheg_gen_born.c_str());
    else t->Add(File_Powheg_gen_bare.c_str());
  }
  ///t->SetBranchStatus("event_info", 0); //to disable all branches
  //  t->SetBranchStatus("reco", 0); //to disable all branches
  TBranch *b_truth = t->GetBranch("truth");
  TBranch *b_reco = t->GetBranch("reco");
  TLeaf * l_ZY = b_truth->GetLeaf("z_y");
  if (elec == 1) l_ZY = b_reco->GetLeaf("z_yBorn"); //TO BE CHANGED
  if (elec == 2) l_ZY = b_reco->GetLeaf("z_yNaked");
  TLeaf *l_phistar = b_truth->GetLeaf("z_phistar_dressed");
  if (elec == 1) l_phistar = b_truth->GetLeaf("z_phistar_born");
  if (elec == 2) l_phistar = b_truth->GetLeaf("z_phistar_naked");
  int nweights;
  int nwcteq;
  t->SetBranchAddress("weight_size", &nweights);
  t->SetBranchAddress("weight_cteq_size", &nwcteq);
  t->GetEntry(0);
  double weights[nweights];
  int weightid[nweights];
  double weights_cteq[nwcteq];
  t->SetBranchAddress("weights", &weights);
  t->SetBranchAddress("weight_ids", &weightid);
  t->SetBranchAddress("weights_cteq", &weights_cteq);
  double weight_fsr;
  t->SetBranchAddress("weight_fsr", &weight_fsr);
  cout << "Entries: " << t->GetEntries() << endl;
  h_cteq = EmptyHVec(nwcteq);
  h_fsr_pileup = EmptyHVec(3);

  TH1D* h_PDFWeight = new TH1D("h_PDFWeight", "h_PDFWeight", 10000, 0, 100);
  h_PDFWeight->Sumw2();
  // cout << "Nweightcteq=" << nwcteq << endl;

  for (int i = 0; i < t->GetEntries(); i++) {
    // for (int i=0; i<50000;i++){
    t->GetEntry(i);
    double weight = sampleweight;
    double pdfnorm = weights_cteq[0];
    double weightpu_0 = 0;
    double weightpu_p = 0;
    double weightpu_m = 0;
    double phistar = l_phistar->GetValue();
    double Z_Y = l_ZY->GetValue();
    int bin=GetBin(phistar,Z_Y);
    //cout<<pdfnorm<<" "<<weights_cteq[0]<<endl;
    for (int w = 0; w < nweights; w++) {
      if (weightid[w] == 1 || weightid[w] == 2) {
        weight = weight * weights[w];
      }
      //if (weightid[w]==1) {weight=weight*weights[w];}
      if (weightid[w] == 2) weightpu_0 = weights[w];
      if (weightid[w] == 3) weightpu_p = weights[w];
      if (weightid[w] == 4) weightpu_m = weights[w];
    }
    // if (weightpu_0 == 0 || weightpu_p == 0 || weightpu_m == 0) cout << "pile-up weights not there" << endl;
    h_phistar->Fill(bin, weight);
    if (pdfnorm != 0) {
      for (int w = 0; w < nwcteq; w++) {
        h_cteq[w] ->Fill(bin, weight * weights_cteq[w] / pdfnorm);
        if (w != 0) {
          h_PDFWeight->Fill(weights_cteq[w] / pdfnorm, 1);
          // cout<<weights_cteq[w] / pdfnorm<<endl;
        }
      }
    }
    if (doMG) weight_fsr = 1;
    h_fsr_pileup[0]->Fill(bin, weight * weight_fsr);
    if (weightpu_0 != 0) {
      h_fsr_pileup[1]->Fill(bin, weight * weightpu_p / weightpu_0);
      h_fsr_pileup[2]->Fill(bin, weight * weightpu_m / weightpu_0);
    }
  }
  cout << "done reading signal gen" << endl;
  delete t;
  return;
}
int main(int argc, char** argv){//main  

  //Input output and config options
  std::string cfg;
  bool concept;
  //size of signal region to perform Chi2 position fit.
  //in units of 2.5mm cells to accomodate different granularities
  unsigned nSR;
  //maximum value of residuals to use in error matrix: discard positions that are too far away 
  double residualMax;//mm
  unsigned pNevts;
  std::string filePath;
  std::string digifilePath;
  unsigned nRuns;
  std::string simFileName;
  std::string recoFileName;
  std::string outPath;
  unsigned nSiLayers;
  //0:do just the energies, 1:do fit+energies, 2: do zpos+fit+energies
  unsigned redoStep;
  unsigned debug;
  bool applyPuMixFix;

  po::options_description preconfig("Configuration"); 
  preconfig.add_options()("cfg,c",po::value<std::string>(&cfg)->required());
  po::variables_map vm;
  po::store(po::command_line_parser(argc, argv).options(preconfig).allow_unregistered().run(), vm);
  po::notify(vm);
  po::options_description config("Configuration");
  config.add_options()
    //Input output and config options //->required()
    ("concept",        po::value<bool>(&concept)->default_value(true))
    ("nSR",            po::value<unsigned>(&nSR)->default_value(3))
    ("residualMax",    po::value<double>(&residualMax)->default_value(25))
    ("pNevts,n",       po::value<unsigned>(&pNevts)->default_value(0))
    ("filePath,i",     po::value<std::string>(&filePath)->required())
    ("digifilePath", po::value<std::string>(&digifilePath)->default_value(""))
    ("nRuns",        po::value<unsigned>(&nRuns)->default_value(0))
    ("simFileName,s",  po::value<std::string>(&simFileName)->required())
    ("recoFileName,r", po::value<std::string>(&recoFileName)->required())
    ("outPath,o",      po::value<std::string>(&outPath)->required())
    ("nSiLayers",      po::value<unsigned>(&nSiLayers)->default_value(2))
    ("redoStep",       po::value<unsigned>(&redoStep)->default_value(0))
    ("debug,d",        po::value<unsigned>(&debug)->default_value(0))
    ("applyPuMixFix",  po::value<bool>(&applyPuMixFix)->default_value(false))
    ;

  // ("output_name,o",            po::value<std::string>(&outputname)->default_value("tmp.root"))

  po::store(po::command_line_parser(argc, argv).options(config).allow_unregistered().run(), vm);
  po::store(po::parse_config_file<char>(cfg.c_str(), config), vm);
  po::notify(vm);



  std::string inFilePath = filePath+simFileName;

  size_t end=outPath.find_last_of(".");
  std::string outFolder = outPath.substr(0,end);


  std::cout << " -- Input parameters: " << std::endl
	    << " -- Input file path: " << filePath << std::endl
	    << " -- Digi Input file path: " << digifilePath << std::endl
	    << " -- Output file path: " << outPath << std::endl
	    << " -- Output folder: " << outFolder << std::endl
	    << " -- Requiring " << nSiLayers << " si layers." << std::endl
	    << " -- Number cells in signal region for fit: " << nSR << " cells" << std::endl
	    << " -- Residual max considered for filling matrix and fitting: " << residualMax << " mm" << std::endl
	    << " -- Apply PUMix fix? " << applyPuMixFix << std::endl
	    << " -- Processing ";
  if (pNevts == 0) std::cout << "all events." << std::endl;
  else std::cout << pNevts << " events." << std::endl;

  TRandom3 lRndm(1);
  std::cout << " -- Random number seed: " << lRndm.GetSeed() << std::endl;

  /////////////////////////////////////////////////////////////
  //input
  /////////////////////////////////////////////////////////////

  std::ostringstream inputsim;
  inputsim << filePath << "/" << simFileName;
  std::ostringstream inputrec;
  if (digifilePath.size()==0)
    inputrec << filePath << "/" << recoFileName;
  else 
    inputrec << digifilePath << "/" << recoFileName;

  //std::cout << inputsim.str() << " " << inputrec.str() << std::endl;

  HGCSSInfo * info;

  TChain *lSimTree = new TChain("HGCSSTree");
  TChain *lRecTree = 0;
  
  TFile * simFile = 0;
  TFile * recFile = 0;

  if (recoFileName.find("Digi") != recoFileName.npos) 
    lRecTree = new TChain("RecoTree");
  else lRecTree = new TChain("PUTree");

  if (nRuns == 0){
    if (!testInputFile(inputsim.str(),simFile)) return 1;
    lSimTree->AddFile(inputsim.str().c_str());
    if (!testInputFile(inputrec.str(),recFile)) return 1;
    lRecTree->AddFile(inputrec.str().c_str());
  }
  else {
    for (unsigned i(0);i<nRuns;++i){
      std::ostringstream lstr;
      lstr << inputsim.str() << "_run" << i << ".root";
      if (testInputFile(lstr.str(),simFile)){  
	if (simFile) info =(HGCSSInfo*)simFile->Get("Info");
	else {
	  std::cout << " -- Error in getting information from simfile!" << std::endl;
	  return 1;
	}
      }
      else continue;
      lSimTree->AddFile(lstr.str().c_str());
      lstr.str("");
      lstr << inputrec.str() << "_run" << i << ".root";
      if (!testInputFile(lstr.str(),recFile)) continue;
      lRecTree->AddFile(lstr.str().c_str());
    }
  }

  if (!lSimTree){
    std::cout << " -- Error, tree HGCSSTree cannot be opened. Exiting..." << std::endl;
    return 1;
  }

  if (!lRecTree){
    std::cout << " -- Error, tree RecoTree cannot be opened. Exiting..." << std::endl;
    return 1;
  }


  /////////////////////////////////////////////////////////////
  //Info
  /////////////////////////////////////////////////////////////

  const double cellSize = info->cellSize();
  const unsigned versionNumber = info->version();
  const unsigned model = info->model();
  
  //models 0,1 or 3.
  //bool isTBsetup = (model != 2);
  bool isCaliceHcal = versionNumber==23;//inFilePath.find("version23")!=inFilePath.npos || inFilePath.find("version_23")!=inFilePath.npos;

  //extract input energy

  std::cout << " -- Version number is : " << versionNumber 
	    << ", model = " << model
	    << ", cellSize = " << cellSize
	    << std::endl;


  //initialise detector
  HGCSSDetector & myDetector = theDetector();
 
  myDetector.buildDetector(versionNumber,concept,isCaliceHcal);

  const unsigned nLayers = myDetector.nLayers();
  const unsigned nSections = myDetector.nSections();

  std::cout << " -- N layers = " << nLayers << std::endl
	    << " -- N sections = " << nSections << std::endl;


  HGCSSGeometryConversion geomConv(inFilePath,model,cellSize);
  //set granularity to get cellsize for PU subtraction
  std::vector<unsigned> granularity;
  granularity.resize(nLayers,4);
  geomConv.setGranularity(granularity);

  //////////////////////////////////////////////////
  //////////////////////////////////////////////////
  ///////// Output File // /////////////////////////
  //////////////////////////////////////////////////
  //////////////////////////////////////////////////

  TFile *outputFile = TFile::Open(outPath.c_str(),"RECREATE");
  
  if (!outputFile) {
    std::cout << " -- Error, output file " << outPath << " cannot be opened. Please create output directory. Exiting..." << std::endl;
    return 1;
  }
  else {
    std::cout << " -- output file " << outputFile->GetName() << " successfully opened." << std::endl;
  }
  outputFile->cd();


  ///initialise PU density object

  HGCSSPUenergy puDensity("data/EnergyDensity.dat");


    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    ///////// positionFit /////////////////////////////
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
  
  const unsigned nEvts = ((pNevts > lSimTree->GetEntries() || pNevts==0) ? static_cast<unsigned>(lSimTree->GetEntries()) : pNevts) ;
  

  PositionFit lChi2Fit(nSR,residualMax,nLayers,nSiLayers,applyPuMixFix,debug);
  lChi2Fit.initialise(outputFile,"PositionFit",outFolder,geomConv,puDensity);

  //try getting z position from input file, if doesn't exit,
  //perform first loop over simhits to find z positions of layers
  if ((redoStep<2 && !lChi2Fit.getZpositions(versionNumber)) || redoStep>1)
    lChi2Fit.getZpositions(versionNumber,lSimTree,nEvts);
  
  //perform second loop over events to find positions to fit and get energies
  SignalRegion SignalEnergy(outFolder, nLayers, nEvts, geomConv, puDensity,applyPuMixFix,versionNumber);
  SignalEnergy.initialise(outputFile,"Energies");

  //initialise
  bool dofit = redoStep>0 || !SignalEnergy.initialiseFitPositions();
  if (!dofit && redoStep==0) std::cout << " -- Info: fit positions taken from file on disk." << std::endl;
  else std::cout << " -- Info: redoing least square fit." << std::endl;

  if (redoStep>0 || (redoStep==0 && dofit)){
    lChi2Fit.getInitialPositions(lSimTree,lRecTree,nEvts);
    lChi2Fit.finaliseErrorMatrix();
    lChi2Fit.initialiseLeastSquareFit();
  }
  
  //loop on events
  HGCSSEvent * event = 0;
  std::vector<HGCSSSamplingSection> * ssvec = 0;
  std::vector<HGCSSSimHit> * simhitvec = 0;
  std::vector<HGCSSRecoHit> * rechitvec = 0;
  std::vector<HGCSSGenParticle> * genvec = 0;
  unsigned nPuVtx = 0;

  lSimTree->SetBranchAddress("HGCSSEvent",&event);
  lSimTree->SetBranchAddress("HGCSSSamplingSectionVec",&ssvec);
  lSimTree->SetBranchAddress("HGCSSSimHitVec",&simhitvec);
  lSimTree->SetBranchAddress("HGCSSGenParticleVec",&genvec);

  lRecTree->SetBranchAddress("HGCSSRecoHitVec",&rechitvec);
  if (lRecTree->GetBranch("nPuVtx")) lRecTree->SetBranchAddress("nPuVtx",&nPuVtx);
  const unsigned nRemove = 12;
  std::vector<unsigned> lToRemove;
  unsigned list[nRemove] = {25,27,15,1,10,3,18,5,12,7,23,20};

  for (unsigned ievt(0); ievt<nEvts; ++ievt){//loop on entries
    if (debug) std::cout << "... Processing entry: " << ievt << std::endl;
    else if (ievt%50 == 0) std::cout << "... Processing entry: " << ievt << std::endl;

    lSimTree->GetEntry(ievt);
    lRecTree->GetEntry(ievt);
    if (dofit) {
      bool found = lChi2Fit.setTruthInfo(genvec,1);
      if (!found) continue;
      //mask layers in turn
      lToRemove.clear();
      for (unsigned r(0); r<nRemove+1;++r){
	FitResult fit;
	if ( lChi2Fit.performLeastSquareFit(ievt,fit,lToRemove)==0 ){
	  //SignalEnergy.fillEnergies(ievt,(*ssvec),(*simhitvec),(*rechitvec),nPuVtx,fit);
	}
	else std::cout << " -- remove " << r << " Fit failed." << std::endl;
	if (r<nRemove) lToRemove.push_back(list[r]);
      }

    }
    else SignalEnergy.fillEnergies(ievt,(*ssvec),(*simhitvec),(*rechitvec),nPuVtx);

  }//loop on entries

  //finalise

  if (dofit) lChi2Fit.finaliseFit();
  SignalEnergy.finalise();

  outputFile->Write();
  //outputFile->Close();
  
  std::cout << " - End of egammaResolution program." << std::endl;

  return 0;
  

}//main
Exemple #7
0
int main(int argc, char *argv[])
{
	TString runNumber, runType, filename;
	Int_t barrelCode, retCode;
	Int_t iModule;
	TCanvas *chi, *clo;
	struct stat statBuf;

	//cout << getenv("PATH") << endl;
	//cout << getenv("ROOTSYS") << endl;

	if (argc < 3)
	{
		//cout << "Usage:"<< endl << "    ./checkPulseHeight <runNumber> <runType> [<filename>]" << endl;
		results.addError("Usage:\n    ./checkPulseHeight <runNumber> <runType> [<filename>]");
		return 0;
	}

	runNumber = argv[1];
	runType = argv[2];

	if (argc > 3)
		filename = argv[3];
	else
	{
		filename  = "tiletb_";
		filename += runNumber;
		filename += "_";
		filename += runType;
		filename += ".0.root";
		TString dir = "/work/tiletransfer/wis/";
		TString aux = dir + filename;
		retCode = stat((char*)aux.Data(), &statBuf);
		if (retCode < 0)
		{
			dir = "/castor/cern.ch/user/t/tilebeam/commissioning/";
			aux = dir + filename;
			retCode = rfio_stat((char*)aux.Data(), &statBuf);
			if (retCode < 0)
			{
				//cout << "<h3>Ntuple does not exist in CASTOR default directory.</h3>" << endl;
				results.addError("Ntuple does not exist in CASTOR default directory.");
				return 0;
			}
			else
				filename = "rfio:" + aux;
		}
		else
		{
			filename = aux;
		}
	}
	//cout<<filename<<endl;
	TChain *t = new TChain("TileRec/h1000");
	t->Add(filename);

	Int_t nevt = t->GetEntries();

	results.setMacroName("Pulse Height");
	results.setParameter("Run Number", runNumber);
	results.setParameter("Number of Events", nevt);

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

	Int_t i, j, k;

    /******************* Set names ********************/
	TString moduleName[Nmodules];
	TString barrelName[Nbarrels];

	// barrel names
	barrelName[0] = "A";
	barrelName[1] = "C";
	barrelName[2] = "EBA";
	barrelName[3] = "EBC";

	// module names
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 64; j++)
		{
			moduleName[i*64 + j] = barrelName[i];
			moduleName[i*64 + j] += (j + 1);
		}
	}
	/**************************************************/

	Int_t SampleHi[Nmodules][48][7];
	Int_t SampleLo[Nmodules][48][7];
	TBranch *b_SampleHi[Nmodules];
	TBranch *b_SampleLo[Nmodules];
	bool moduleInNtuple[Nmodules];

	TString branchName;
	for (iModule = 0; iModule < Nmodules; iModule++)
	{
		branchName = "Sample" + moduleName[iModule] + "hi";
		t->SetBranchAddress(branchName, SampleHi[iModule]);
		b_SampleHi[iModule] = t->GetBranch(branchName.Data());

		branchName = "Sample" + moduleName[iModule] + "lo";
		t->SetBranchAddress(branchName, SampleLo[iModule]);
		b_SampleLo[iModule] = t->GetBranch(branchName.Data());

		if (!b_SampleHi[iModule])
			moduleInNtuple[iModule] = false;
		else
			moduleInNtuple[iModule] = true;
	}

	TH1F *hhi[Nmodules][48];
	TH1F *hlo[Nmodules][48];
	TString hnamehi, htitlehi, hnamelo, htitlelo;

	for (j = 0; j < 48; j++)
	{
		for (iModule = 0; iModule < Nmodules; iModule++)
		{
			if (!moduleInNtuple[iModule])
				continue;
	
			hnamehi = "chhi";
			hnamehi +=  j;
			hnamehi += moduleName[iModule];
			htitlehi = "Chanhi ";
			htitlehi += j;
			htitlehi += " " + moduleName[iModule];
	
			hhi[iModule][j]=new TH1F(hnamehi, htitlehi, 1024, 0, 1023);
	
			hnamelo = "chlo";
			hnamelo += j;
			hnamelo += moduleName[iModule];
			htitlelo = "Chanlo ";
			htitlelo += j;
			htitlelo += " " + moduleName[iModule];
		
			hlo[iModule][j]=new TH1F(hnamelo, htitlelo, 1024, 0, 1023);
		}
	}

	Int_t minevt = 16000;
	for (i = 16000; i < nevt; i++)
	{
		t->GetEntry(i);

		for (iModule = 0; iModule < Nmodules; iModule++)
		{
			if (!moduleInNtuple[iModule])
				continue;

			for (j = 0; j < 48; j++)
			{
				for (k = 0; k < 7; k++)
				{
					hhi[iModule][j]->Fill(SampleHi[iModule][j][k]);
					hlo[iModule][j]->Fill(SampleLo[iModule][j][k]);
				}
			}
		}
	}
	for (iModule = 0; iModule < Nmodules; iModule++)
	{
		if (!moduleInNtuple[iModule])
			continue;

		chi = new TCanvas("chi", "High Gain", 900, 900);
		chi->Divide(6,8);

		clo = new TCanvas("clo", "Low Gain", 900, 900);
		clo->Divide(6,8);

		for(j = 0; j < 48; j++)
		{
			chi->cd(j+1);
			gPad->SetLogy();
			hhi[iModule][j]->Draw();
			clo->cd(j+1);
			gPad->SetLogy();
			hlo[iModule][j]->Draw();
		}

		TString outFilePShi = outputDir + "CIS/LB" + moduleName[iModule] + "/r" + runNumber + "_" + "LB" + moduleName[iModule] + "_hi_PulseHeight.ps";
		TString outFilePSlo = outputDir + "CIS/LB" + moduleName[iModule] + "/r" + runNumber + "_" + "LB" + moduleName[iModule] + "_lo_PulseHeight.ps";
		TString outFilePNGhi= outputDir + "CIS/LB" + moduleName[iModule] + "/r" + runNumber + "_" + "LB" + moduleName[iModule] + "_hi_PulseHeight.png";
		TString outFilePNGlo= outputDir + "CIS/LB" + moduleName[iModule] + "/r" + runNumber + "_" + "LB" + moduleName[iModule] + "_lo_PulseHeight.png";

		chi->Print(outFilePShi);
		clo->Print(outFilePSlo);

		chi->Print(outFilePNGhi);
		clo->Print(outFilePNGlo);
		
		TString plotTitle;
		TString plotFilename;

		TString completeModuleName = "LB" + moduleName[iModule];

		plotTitle = "Module LB" + moduleName[iModule] + " High Gain:";
		plotFilename = outputWebDir + "CIS/" + completeModuleName + "/" + basename(outFilePNGhi.Data());
		results.addPlot(plotTitle, plotFilename);

	//	wis2Tilecomm(runNumber.Data(), completeModuleName.Data(), plotFilename.Data(), results);
		plotFilename = outputWebDir + "CIS/" + completeModuleName + "/" + basename(outFilePShi.Data());
	//	wis2Tilecomm(runNumber.Data(), completeModuleName.Data(), plotFilename.Data(), results);

	//	plotTitle = "Module LB" + moduleName[iModule] + " Low Gain:";
		plotFilename = outputWebDir + "CIS/" + completeModuleName + "/" + basename(outFilePNGlo.Data());
	//	results.addPlot(plotTitle, plotFilename);

	//	wis2Tilecomm(runNumber.Data(), completeModuleName.Data(), plotFilename.Data(), results);
		plotFilename = outputWebDir + "CIS/" + completeModuleName + "/" + basename(outFilePSlo.Data());
	//	wis2Tilecomm(runNumber.Data(), completeModuleName.Data(), plotFilename.Data(), results);

		delete chi;
		delete clo;
	}

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

	results.out();
	
	return 0;
}
void GetBinM(vector<RooUnfoldResponse*> &BinM, vector<TH1D*> &h_gen, vector<TH1D*> &h_reco, bool madgraph=1, int elec=0){

  TH2D* BinMigration=new TH2D("BinMigration","BinMigration",nphistar,phistarBins,nphistar,phistarBins);
  BinMigration->Sumw2();
  TH1D* Gen=new TH1D("Gen","gen",nphistar,phistarBins);
  Gen->Sumw2();
  TH1D* Reco=new TH1D("Reco","Reco",nphistar,phistarBins);
  Reco->Sumw2();

  TChain* t = new TChain(reco_name.c_str(),reco_name.c_str());
  int nfiles;
  if (madgraph)  nfiles=t->Add(File_Signal_reco.c_str());
  else nfiles=t->Add(File_Powheg_reco.c_str());

  TBranch *b_reco=t->GetBranch("reco");
  TBranch *b_truth=t->GetBranch("truth");
  TBranch *b_event=t->GetBranch("event_info");
  TLeaf *l_phistar=b_reco->GetLeaf("z_phistar_dressed");
  TLeaf *l_phistar_true=b_truth->GetLeaf("z_phistar_dressed");
  TLeaf *l_en=b_event->GetLeaf("event_number");
  if (elec==1) l_phistar_true=b_truth->GetLeaf("z_phistar_born");
  if (elec==2) l_phistar_true=b_truth->GetLeaf("z_phistar_naked");
  int nweights;
  t->SetBranchAddress("weight_size",&nweights);
  t->GetEntry(0);
  cout<<"The sample has nweights: "<<nweights<<endl;
  double weights[nweights];
  int weightid[nweights];
  t->SetBranchAddress("weights",&weights);
  t->SetBranchAddress("weight_ids",&weightid);

  cout<<"Entries: "<<t->GetEntries()<<endl;
  cout<<"reading signal reco "<<endl;
  for (int i=0; i<t->GetEntries();i++){
    // if (!madgraph && (i>N_MC+50000 || i<50000) &&N_MC!=-1) continue;
    if (!madgraph && i>N_MC &&N_MC!=-1) continue;
    //for (int i=0; i<50000;i++){
    t->GetEntry(i);
    double phistar=l_phistar->GetValue();
    double phistar_true=l_phistar_true->GetValue();
    double weight =1;
    double eventn=l_en->GetValue();
    // else en=eventn;
    for (int w=0; w<nweights;w++){
      if (weightid[w]==1 || weightid[w]==2 || weightid[w]==12 || weightid[w]==13 || weightid[w]==20 || weightid[w]==30) {weight=weight*weights[w];}
    }
    Gen ->Fill(phistar_true,weight);
    Reco->Fill(phistar,weight);
    BinMigration->Fill(phistar,phistar_true,weight); 
  }
  if (!madgraph){
    TCanvas* BM = new TCanvas("BM","BM",800,900);
    BinMigration->GetXaxis()->SetRangeUser(0.001,3.2);
    BinMigration->GetXaxis()->SetTitle("#phi^{*}(reconstructed)");
    BinMigration->GetXaxis()->SetTitleOffset(0.8);
    BinMigration->GetXaxis()->SetTitleSize(0.04);
    BinMigration->GetXaxis()->SetLabelOffset(-0.01);
    BinMigration->GetXaxis()->SetLabelSize(0.04);
    BinMigration->GetYaxis()->SetTitleOffset(1.05);
    BinMigration->GetYaxis()->SetTitleSize(0.04);
    BinMigration->GetYaxis()->SetLabelSize(0.04);
    BinMigration->GetYaxis()->SetRangeUser(0.001,3.2);
    BinMigration->GetYaxis()->SetTitle("#phi^{*}(generated)");
    BinMigration->GetZaxis()->SetTitleOffset(-0.004);
    BinMigration->SetStats(0);
    BinMigration->SetBit( TH2::kNoTitle, true );
    BM->SetLogx();
    BM->SetLogy();
    BM->SetLogz();
    BinMigration->Draw("COLZ");
    TLatex mark;
    mark.SetTextSize(0.04);
    mark.SetTextFont(42);
    mark.SetNDC(true);
    mark.DrawLatex(0.19,0.80,"Powheg");
  }
  RooUnfoldResponse* BinM1  =new RooUnfoldResponse (Reco,Gen,BinMigration);
  BinM.push_back(BinM1);
  h_gen.push_back(Gen);
  h_reco.push_back(Reco);
  for (int i=0; i<N_TOY; i++){
    TH1D* Recotemp=new TH1D("Reco","Reco",nphistar,phistarBins);
    Recotemp->Sumw2();
    TH2D* BinMigrationtemp=new TH2D("BinMigration","BinMigration",nphistar,phistarBins,nphistar,phistarBins);
    BinMigrationtemp->Sumw2();
    for (int j=0; j<nphistar; j++){
      double x=gRandom->Gaus(Reco->GetBinContent(j+1),Reco->GetBinError(j+1));
      Recotemp->SetBinContent(j+1,x);
      Recotemp->SetBinError(j+1,Reco->GetBinError(j+1));
      for (int k=0; k<nphistar; k++){
	double mean=BinMigration->GetBinContent(j+1,k+1);
	if (mean==0) continue;
	double error=BinMigration->GetBinError(j+1,k+1);
	if (mean/error<5){
	  x=gRandom->Poisson(mean);
	}
	else{
	  x=gRandom->Gaus(mean,error);
	}
	BinMigrationtemp->SetBinContent(j+1,k+1,x);
	BinMigrationtemp->SetBinError(j+1,k+1,error);
      }
    }
    TH1D* recotemp=BinMigrationtemp->ProjectionX();
    TH1D* gentemp=BinMigrationtemp->ProjectionY();
    RooUnfoldResponse* BinM1temp  =new RooUnfoldResponse (recotemp,gentemp,BinMigrationtemp);
    BinM.push_back(BinM1temp);
    h_reco.push_back(Recotemp);
  }

  cout<<"done reading data for "<<File_Signal_reco<<"  "<<reco_name<<endl;
  return;
}
void photonRaaSkim(const TString configFile, const TString inputFile, const TString outputFile, COLL::TYPE colli)
{
    std::cout<<"running photonRaaSkim()"<<std::endl;
    std::cout<<"configFile  = "<< configFile.Data() <<std::endl;
    std::cout<<"inputFile   = "<< inputFile.Data() <<std::endl;
    std::cout<<"outputFile  = "<< outputFile.Data() <<std::endl;

    InputConfiguration configInput = InputConfigurationParser::Parse(configFile.Data());
    CutConfiguration configCuts = CutConfigurationParser::Parse(configFile.Data());

    // input configuration
/*    int collisionType;
    if (configInput.isValid) {
        collisionType = configInput.proc[INPUT::kSKIM].i[INPUT::k_collisionType];
    }
    else {
        collisionType = COLL::kPP;
    }
*/
    // verbose about input configuration
    int collisionType = colli;
    std::cout<<"Input Configuration :"<<std::endl;
    std::cout << "collisionType = " << collisionType << std::endl;
    const char* collisionName =  getCollisionTypeName((COLL::TYPE)collisionType).c_str();
    std::cout << "collision = " << collisionName << std::endl;

    // cut configuration
    float cut_vz;
    int cut_pcollisionEventSelection;
    int cut_pPAprimaryVertexFilter;
    int cut_pBeamScrapingFilter;

    float cutPhoEt;
    float cutPhoEta;

    if (configCuts.isValid) {
        cut_vz = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].f[CUTS::EVT::k_vz];
        cut_pcollisionEventSelection = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pcollisionEventSelection];
        cut_pPAprimaryVertexFilter = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pPAprimaryVertexFilter];
        cut_pBeamScrapingFilter = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pBeamScrapingFilter];

        cutPhoEt = configCuts.proc[CUTS::kSKIM].obj[CUTS::kPHOTON].f[CUTS::PHO::k_et];
        cutPhoEta = configCuts.proc[CUTS::kSKIM].obj[CUTS::kPHOTON].f[CUTS::PHO::k_eta];

    }
    else {
        cut_vz = 15;
        cut_pcollisionEventSelection = 1;
        cut_pPAprimaryVertexFilter = 1;
        cut_pBeamScrapingFilter = 1;

        cutPhoEt = 15;
        cutPhoEta = 1.44;
    }

    bool isMC = collisionIsMC((COLL::TYPE)collisionType);
    bool isHI = collisionIsHI((COLL::TYPE)collisionType);
    bool isPP = collisionIsPP((COLL::TYPE)collisionType);

    // verbose about cut configuration
    std::cout<<"Cut Configuration :"<<std::endl;
    std::cout<<"cut_vz = "<< cut_vz <<std::endl;
    if (isHI) {
        std::cout<<"cut_pcollisionEventSelection = "<< cut_pcollisionEventSelection <<std::endl;
    }
    else {   // PP
        std::cout<<"cut_pPAprimaryVertexFilter = "<< cut_pPAprimaryVertexFilter <<std::endl;
        std::cout<<"cut_pBeamScrapingFilter = "<< cut_pBeamScrapingFilter <<std::endl;
    }

    std::cout<<"cutPhoEt  = "<<cutPhoEt<<std::endl;
    std::cout<<"cutPhoEta = "<<cutPhoEta<<std::endl;

    std::vector<std::string> inputFiles = InputConfigurationParser::ParseFiles(inputFile.Data());
    std::cout<<"input ROOT files : num = "<<inputFiles.size()<< std::endl;
    std::cout<<"#####"<< std::endl;
    for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
        std::cout<<(*it).c_str()<< std::endl;
    }
    std::cout<<"##### END #####"<< std::endl;

    TChain* treeHLT   = new TChain("hltanalysis/HltTree");
    TChain* treeggHiNtuplizer  = new TChain("ggHiNtuplizer/EventTree");
    TChain* treeHiEvt = new TChain("hiEvtAnalyzer/HiTree");
    TChain* treeSkim  = new TChain("skimanalysis/HltTree");
    TChain* treeHiForestInfo = new TChain("HiForest/HiForestInfo");
    TChain* treeGen=0;
    if(isMC) treeGen  = new TChain("HiGenParticleAna/hi");

    // pthatWeight Calculation block! 
    int nPthat = 5;
    float pthatCut[nPthat+1];
    const char* lowestPthatFileName="";
    int nfiles = 0;
    for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
        treeHLT->Add((*it).c_str());
        treeggHiNtuplizer->Add((*it).c_str());
        treeHiEvt->Add((*it).c_str());
        treeSkim->Add((*it).c_str());
        treeHiForestInfo->Add((*it).c_str());
        if(isMC) treeGen->Add((*it).c_str());
        if(isMC && (nfiles==0)) { 
            lowestPthatFileName = (*it).c_str(); 
            TString str(lowestPthatFileName);
            cout << "lowestPthatFileName = " << lowestPthatFileName << endl;
            if(str.Contains("15")) {
                float temp[] = {15,30,50,80,120,9999};          
                for(int j=0;j<nPthat+1;j++){
                    pthatCut[j] = temp[j];
                }
            } else if(str.Contains("30")) {
                float temp[] = {30,50,80,120,170,9999};          
                for(int j=0;j<nPthat+1;j++){
                    pthatCut[j] = temp[j];
                }
            }
        }
        nfiles++;
    }

    float tmpWeight[nPthat];
    if(isMC) {
        for(int j=0; j<nPthat ; j++){
            tmpWeight[j] = xSecCal(lowestPthatFileName,treeHiEvt, pthatCut[j], pthatCut[j+1]);
            cout << collisionName << ", pthatWeight of " << pthatCut[j] << " to " << pthatCut[j+1] << " = " << tmpWeight[j] << endl;
        }
    }
/*
    HiForestInfoController hfic(treeHiForestInfo);
    std::cout<<"### HiForestInfo Tree ###"<< std::endl;
    hfic.printHiForestInfo();
    std::cout<<"###"<< std::endl;
*/
    treeHLT->SetBranchStatus("*",0);     // disable all branches
    treeHLT->SetBranchStatus("HLT_HI*SinglePhoton*Eta*",1);     // enable photon branches
    treeHLT->SetBranchStatus("HLT_HI*DoublePhoton*Eta*",1);     // enable photon branches

    float vz;
    Int_t hiBin;
    UInt_t run, lumis;
    ULong64_t event;
    float pthat, pthatWeight;
    treeHiEvt->SetBranchAddress("vz",&vz);
    treeHiEvt->SetBranchAddress("hiBin",&hiBin);
    treeHiEvt->SetBranchAddress("run", &run);
    treeHiEvt->SetBranchAddress("evt", &event);
    treeHiEvt->SetBranchAddress("lumi", &lumis);
    if(isMC) {
        //treeHiEvt->Branch("pthatWeight", &pthatWeight, "pthatWeight/F");
        treeHiEvt->SetBranchAddress("pthat", &pthat);
    }   

    // specify explicitly which branches to store, do not use wildcard
    treeSkim->SetBranchStatus("*",0);

    Int_t pcollisionEventSelection;  // this filter is used for HI.
    if (isHI) {
        treeSkim->SetBranchStatus("pcollisionEventSelection",1);
        if (treeSkim->GetBranch("pcollisionEventSelection")) {
            treeSkim->SetBranchAddress("pcollisionEventSelection",&pcollisionEventSelection);
        }
        else {   // overwrite to default
            pcollisionEventSelection = 1;
            std::cout<<"could not get branch : pcollisionEventSelection"<<std::endl;
            std::cout<<"set to default value : pcollisionEventSelection = "<<pcollisionEventSelection<<std::endl;
        }
    }
    else {
        pcollisionEventSelection = 0;    // default value if the collision is not HI, will not be used anyway.
    }
    Int_t pPAprimaryVertexFilter;    // this filter is used for PP.
    if (isPP) {
        treeSkim->SetBranchStatus("pPAprimaryVertexFilter",1);
        if (treeSkim->GetBranch("pPAprimaryVertexFilter")) {
            treeSkim->SetBranchAddress("pPAprimaryVertexFilter",&pPAprimaryVertexFilter);
        }
        else {   // overwrite to default
            pPAprimaryVertexFilter = 1;
            std::cout<<"could not get branch : pPAprimaryVertexFilter"<<std::endl;
            std::cout<<"set to default value : pPAprimaryVertexFilter = "<<pPAprimaryVertexFilter<<std::endl;
        }
    }
    else {
        pPAprimaryVertexFilter = 0;      // default value if the collision is not PP, will not be used anyway.
    }
    Int_t pBeamScrapingFilter;   // this filter is used for PP.
    if (isPP) {
        treeSkim->SetBranchStatus("pBeamScrapingFilter",1);
        if (treeSkim->GetBranch("pBeamScrapingFilter")) {
            treeSkim->SetBranchAddress("pBeamScrapingFilter",&pBeamScrapingFilter);
        }
        else {   // overwrite to default
            pBeamScrapingFilter = 1;
            std::cout<<"could not get branch : pBeamScrapingFilter"<<std::endl;
            std::cout<<"set to default value : pBeamScrapingFilter = "<<pBeamScrapingFilter<<std::endl;
        }
    }
    else {
        pBeamScrapingFilter = 0;     // default value if the collision is not PP, will not be used anyway.
    }

    // objects for z-jet correlations
    ggHiNtuplizer ggHi;
    ggHi.setupTreeForReading(treeggHiNtuplizer);    // treeggHiNtuplizer is input
    treeggHiNtuplizer->SetBranchStatus("*",0);
    treeggHiNtuplizer->SetBranchStatus("run",1);
    treeggHiNtuplizer->SetBranchStatus("event",1);
    treeggHiNtuplizer->SetBranchStatus("lumis",1);
    treeggHiNtuplizer->SetBranchStatus("nPho",1);
    treeggHiNtuplizer->SetBranchStatus("pho*",1);
    treeggHiNtuplizer->SetBranchStatus("pf*",1);
    //treeggHiNtuplizer->SetBranchStatus("tower*",1);
    if(isMC) treeggHiNtuplizer->SetBranchStatus("mc*",1);



    TFile* output = TFile::Open(outputFile,"RECREATE");
    TTree* configTree = setupConfigurationTreeForWriting(configCuts);

    // output tree variables
    TTree *outputTreeHLT=0, *outputTreeggHiNtuplizer=0, 
          *outputTreeHiEvt=0, *outputTreeSkim=0, *outputTreeHiForestInfo=0, *outputTreeGen=0;

    // output tree variables
    outputTreeHLT    = treeHLT->CloneTree(0);
    outputTreeggHiNtuplizer = treeggHiNtuplizer->CloneTree(0);
    outputTreeHiEvt = treeHiEvt->CloneTree(0);
    outputTreeSkim   = treeSkim->CloneTree(0);
    outputTreeHiForestInfo = treeHiForestInfo->CloneTree(0);
    if(isMC) outputTreeGen = treeGen ->CloneTree(0);

    outputTreeSkim->SetName("skimTree");
    outputTreeHLT->SetMaxTreeSize(MAXTREESIZE);
    outputTreeggHiNtuplizer->SetMaxTreeSize(MAXTREESIZE);
    outputTreeHiEvt->SetMaxTreeSize(MAXTREESIZE);
    outputTreeSkim->SetMaxTreeSize(MAXTREESIZE);
    outputTreeHiForestInfo->SetMaxTreeSize(MAXTREESIZE);
    if(isMC) outputTreeGen->SetMaxTreeSize(MAXTREESIZE);

    if(isMC) outputTreeHiEvt->Branch("pthatWeight", &pthatWeight, "pthatWeight/F");
  

    /////// Event Matching for DATA ///////
    EventMatcher* em = new EventMatcher();
    Long64_t duplicateEntries = 0;
    Long64_t entriesPassedEventSelection =0;
    Long64_t entriesAnalyzed =0;
    Long64_t entriesSpikeRejected=0;
    Long64_t entries = treeggHiNtuplizer->GetEntries();
    std::cout << "entries = " << entries << std::endl;
    std::cout<< "Loop : ggHiNtuplizer/EventTree" <<std::endl;
    //for (Long64_t j_entry=10000; j_entry<10100; ++j_entry)
    for (Long64_t j_entry=0; j_entry<entries; ++j_entry)
    {
        if (j_entry % 2000 == 0)  {
            std::cout << "current entry = " <<j_entry<<" out of "<<entries<<" : "<<std::setprecision(2)<<(double)j_entry/entries*100<<" %"<<std::endl;
        }

        treeHLT->GetEntry(j_entry);
        treeggHiNtuplizer->GetEntry(j_entry);
        treeSkim->GetEntry(j_entry);
        treeHiEvt->GetEntry(j_entry);
        treeHiForestInfo->GetEntry(j_entry);
        if(isMC) treeGen->GetEntry(j_entry);

        bool eventAdded = em->addEvent(run,lumis,event,j_entry);
        //std::cout << run << " " << lumis << " " << event << " " << j_entry << std::endl;
        if(!eventAdded) // this event is duplicate, skip this one.
        {
            duplicateEntries++;
            continue;
        }

        if(isMC) {
            if((pthat>=pthatCut[0]) && (pthat<pthatCut[1])) pthatWeight = tmpWeight[0];
            else if((pthat>=pthatCut[1]) && (pthat<pthatCut[2])) pthatWeight = tmpWeight[1];
            else if((pthat>=pthatCut[2]) && (pthat<pthatCut[3])) pthatWeight = tmpWeight[2];
            else if((pthat>=pthatCut[3]) && (pthat<pthatCut[4])) pthatWeight = tmpWeight[3];
            else if((pthat>=pthatCut[4]) && (pthat<pthatCut[5])) pthatWeight = tmpWeight[4];
            else continue;
        }
        // event selection
        if (!(TMath::Abs(vz) < cut_vz))  continue;
        if (isHI) {
            if ((pcollisionEventSelection < cut_pcollisionEventSelection))  continue;
        }
        else {
            if (pPAprimaryVertexFilter < cut_pPAprimaryVertexFilter || pBeamScrapingFilter < cut_pBeamScrapingFilter)  continue;
        }
        entriesPassedEventSelection++;

        // photon block
        // find leading photon
        int phoIdx = -1;     // index of the leading photon
        double maxPhoEt = -1;
        for(int i=0; i<ggHi.nPho; ++i)
        {
            bool failedEtCut  = (ggHi.phoEt->at(i) < cutPhoEt) ;
            bool failedEtaCut = (TMath::Abs(ggHi.phoEta->at(i)) > cutPhoEta) ;
            bool failedSpikeRejection;
            bool failedHotSpotRejection;
            //if (isHI) {
            failedSpikeRejection =( (ggHi.phoEta->at(i)<1.44) && 
                    (ggHi.phoSigmaIEtaIEta->at(i) < 0.002 ||
                     ggHi.pho_swissCrx->at(i)     > 0.9   ||
                     TMath::Abs(ggHi.pho_seedTime->at(i)) > 3) );
            // }
            // else {
            //     failedSpikeRejection = (ggHi.phoSigmaIEtaIEta->at(i) < 0.002);
            // }

            failedHotSpotRejection = (
                (ggHi.phoE3x3->at(i)/ggHi.phoE5x5->at(i) > 2./3.-0.03 && ggHi.phoE3x3->at(i)/ggHi.phoE5x5->at(i) < 2./3.+0.03) &&
                (ggHi.phoE1x5->at(i)/ggHi.phoE5x5->at(i) > 1./3.-0.03 && ggHi.phoE1x5->at(i)/ggHi.phoE5x5->at(i) < 1./3.+0.03) &&
                (ggHi.phoE2x5->at(i)/ggHi.phoE5x5->at(i) > 2./3.-0.03 && ggHi.phoE2x5->at(i)/ggHi.phoE5x5->at(i) < 2./3.+0.03) );
            
            bool failedHoverE = (ggHi.phoHoverE->at(i) > 0.2);      // <0.1 cut is applied after corrections
            //               bool failedEnergyRatio = ((float)ggHi.phoSCRawE->at(i)/ggHi.phoE->at(i) < 0.5);

            if (failedEtCut)          continue;
            if (failedEtaCut)         continue;
            if (failedSpikeRejection) continue;
            if (failedHotSpotRejection) {entriesSpikeRejected++; continue;}
            if (failedHoverE)         continue;
            //               if (failedEnergyRatio)    continue;    // actually applied after corrections

            if (ggHi.phoEt->at(i) > maxPhoEt)
            {
                maxPhoEt = ggHi.phoEt->at(i);
                phoIdx = i;
            }
        }
        if (phoIdx == -1) continue;
        entriesAnalyzed++;

        outputTreeHLT->Fill();
        outputTreeggHiNtuplizer->Fill();
        outputTreeHiEvt->Fill();
        outputTreeSkim->Fill();
        outputTreeHiForestInfo->Fill();
        if(isMC) outputTreeGen->Fill();
    }// event loop closed here

    std::cout<<  "Loop ENDED : ggHiNtuplizer/EventTree" <<std::endl;
    std::cout << "entries            = " << entries << std::endl;
    std::cout << "duplicateEntries   = " << duplicateEntries << std::endl;
    std::cout << "entriesPassedEventSelection   = " << entriesPassedEventSelection << std::endl;
    std::cout << "entriesAnalyzed               = " << entriesAnalyzed << std::endl;
    std::cout << "entriesSpikeRejected          = " << entriesSpikeRejected << std::endl;
    std::cout << "outputTreeHLT->GetEntries()   = " << outputTreeHLT->GetEntries() << std::endl;
    std::cout << "outputTreeggHiNtuplizer->GetEntries()   = " << outputTreeggHiNtuplizer->GetEntries() << std::endl;
    std::cout << "outputTreeSkim->GetEntries()  = " << outputTreeSkim->GetEntries() << std::endl;
    std::cout << "outputTreeHiEvt->GetEntries() = " << outputTreeHiEvt->GetEntries() << std::endl;
    std::cout << "outputTreeHiForestInfo->GetEntries() = " << outputTreeHiForestInfo->GetEntries() << std::endl;
    if(isMC) std::cout << "outputTreeGen->GetEntries() = " << outputTreeGen->GetEntries() << std::endl;


    output->cd();
    configTree->Write("",TObject::kOverwrite);
    output->Write("",TObject::kOverwrite);
    output->Close();
}
void readTree(TString filelist="/global/project/projectdirs/star/pwg/starhf/zamiller/minBiasTemplates101015/Trees.list",TString outFile="/global/project/projectdirs/star/pwg/starhf/zamiller/minBiasTemplates101015/readTreeOutSubmitTEST.root")
{

  //TString filelist=Form("%s/%s",localDir,fileIn);
  //TString outFile=Form("%s/%s",outDir,fileOut);

  TFile fout(outFile,"RECREATE");
  TH1F::SetDefaultSumw2(); 
  TH1D::SetDefaultSumw2(); 

  for(Int_t c=0; c< numPtBins; c++)
  {
    lowpt[c] = anaConst::lpt[c];
    highpt[c] = anaConst::hpt[c];
  }
  for(Int_t ptbin = 0; ptbin < numPtBins; ptbin++)
  {
    hdEtaRawce[ptbin] = new TH1D(Form("hdEtaRawce_%i",ptbin),"hdEtaRawce",100, -5,5);
    hdEtaRawbe[ptbin] = new TH1D(Form("hdEtaRawbe_%i",ptbin),"hdEtaRawbe",100, -5,5);
    hEventTallyce[ptbin] = new TH1D(Form("ceEventTally_%i",ptbin),"ceEvent Tally",1,0,1);
    hEventTallybe[ptbin] = new TH1D(Form("beEventTally_%i",ptbin),"beEvent Tally",1,0,1);
    hEventTallybce[ptbin] = new TH1D(Form("bceEventTally_%i",ptbin),"bceEvent Tally",1,0,1);
    hdPhiRawce[ptbin] = new TH1D(Form("hdPhiRawce_%i",ptbin),"hdPhiRawce",Phibin, -10,10);
    hdPhiRawbe[ptbin] = new TH1D(Form("hdPhiRawbe_%i",ptbin),"hdPhiRawbe",Phibin, -10,10);
    hdPhiRawbce[ptbin] = new TH1D(Form("hdPhiRawbce_%i",ptbin),"hdPhiRawbce",Phibin, -10,10);
    hept[ptbin] = new TH1D(Form("hept_%i",ptbin),"hept",200,0.,20.);
  }

  // Make Chain
  TChain* chain = new TChain("tree");
  int nfile = 0;
  /*  nfile += chain->Add("Oct30_set13/pythia_tree_Oct30_13.root");
      nfile += chain->Add("Oct30_set14/pythia_tree_Oct30_14.root");
      nfile += chain->Add("Oct30_set15/pythia_tree_Oct30_15.root");
      nfile += chain->Add("Oct30_set16/pythia_tree_Oct30_16.root");
      nfile += chain->Add("Oct30_set17/pythia_tree_Oct30_17.root");
  //  nfile += chain->Add("Oct30_set12/pythia_tree_Oct30_12.root");
  //  nfile += chain->Add("Oct26_set3/pythia_tree_Oct26_3.root");
  // nfile += chain->Add("Oct18_set4/pythia_tree_Oct18_4.root");
  //nfile += chain->Add("liweiTemplate_part2.root");*/
  char filename[1000];
  ifstream fstream(filelist.Data());
  int ifile = 0;
  while (fstream >> filename)
  {
    nfile+= chain->Add(filename);
    std::cout << "Got File: " << filename << std::endl;
  }

  std::cout <<"Added "<<nfile<<" files"<<std::endl;
  std::cout<<"# entries in chain: "<<chain->GetEntries()<<std::endl;
  if (chain == 0) return;

  int ceNtrigger=0;
  int beNtrigger=0;
  int bceNtrigger=0;
  int ptbin,maxptbin;

  //define variables
  Int_t   Event, numberofcElectrons, numberofbElectrons,numberofbcElectrons, numberofHadrons, noTracks;   //
  Float_t celectron_id,celectron_status,celectron_pt,celectron_pz,celectron_phi,celectron_eta,celectron_y;                //track info
  Float_t belectron_id,belectron_status,belectron_pt,belectron_pz,belectron_phi,belectron_eta,belectron_y;
  Float_t bcelectron_id,bcelectron_status,bcelectron_pt,bcelectron_pz,bcelectron_phi,bcelectron_eta,bcelectron_y;
  Float_t assoh_id,assoh_status,assoh_pt,assoh_pz,assoh_phi,assoh_eta,assoh_y;

  int goodEvent = 0;


  Long64_t nentries = chain->GetEntriesFast();
  int x = 0; int n = nentries; int w = 25;

  for(int i = 0; i < nentries; i++){
    Long64_t ientry = chain->LoadTree(i);
    if (ientry < 0) break;
    TBranch *b_destep = chain->GetBranch("hf2eDecay");

    TLeaf* leaf_Event_id            = b_destep->GetLeaf("Event_id");
    TLeaf* leaf_refMult             = b_destep->GetLeaf("refMult");
    TLeaf* leaf_numberofcElectrons  = b_destep->GetLeaf("numberofcElectrons");
    TLeaf* leaf_numberofbElectrons  = b_destep->GetLeaf("numberofbElectrons");
    TLeaf* leaf_numberofbcElectrons = b_destep->GetLeaf("numberofbcElectrons");
    TLeaf* leaf_numberofHadrons     = b_destep->GetLeaf("numberofHadrons");
    TLeaf* leaf_noTracks            = b_destep->GetLeaf("noTracks");

    TLeaf* leaf_ce_id               = b_destep->GetLeaf("ce_id");
    TLeaf* leaf_ce_status           = b_destep->GetLeaf("ce_status");
    TLeaf* leaf_ce_pt               = b_destep->GetLeaf("ce_pt");
    TLeaf* leaf_ce_pz               = b_destep->GetLeaf("ce_pz");
    TLeaf* leaf_ce_phi              = b_destep->GetLeaf("ce_phi");
    TLeaf* leaf_ce_eta              = b_destep->GetLeaf("ce_eta");
    TLeaf* leaf_ce_y                = b_destep->GetLeaf("ce_y");

    TLeaf* leaf_be_id               = b_destep->GetLeaf("be_id");
    TLeaf* leaf_be_status           = b_destep->GetLeaf("be_status");
    TLeaf* leaf_be_pt               = b_destep->GetLeaf("be_pt");
    TLeaf* leaf_be_pz               = b_destep->GetLeaf("be_pz");
    TLeaf* leaf_be_phi              = b_destep->GetLeaf("be_phi");
    TLeaf* leaf_be_eta              = b_destep->GetLeaf("be_eta");
    TLeaf* leaf_be_y                = b_destep->GetLeaf("be_y");

    TLeaf* leaf_bce_id              = b_destep->GetLeaf("bce_id");
    TLeaf* leaf_bce_status          = b_destep->GetLeaf("bce_status");
    TLeaf* leaf_bce_pt              = b_destep->GetLeaf("bce_pt");
    TLeaf* leaf_bce_pz              = b_destep->GetLeaf("bce_pz");
    TLeaf* leaf_bce_phi             = b_destep->GetLeaf("bce_phi");
    TLeaf* leaf_bce_eta             = b_destep->GetLeaf("bce_eta");
    TLeaf* leaf_bce_y               = b_destep->GetLeaf("bce_y");

    TLeaf* leaf_hadron_id           = b_destep->GetLeaf("hadron_id");
    TLeaf* leaf_hadron_status       = b_destep->GetLeaf("hadron_status");
    TLeaf* leaf_hadron_pt           = b_destep->GetLeaf("hadron_pt");
    TLeaf* leaf_hadron_pz           = b_destep->GetLeaf("hadron_pz");
    TLeaf* leaf_hadron_phi          = b_destep->GetLeaf("hadron_phi");
    TLeaf* leaf_hadron_eta          = b_destep->GetLeaf("hadron_eta");
    TLeaf* leaf_hadron_y            = b_destep->GetLeaf("hadron_y");

    x = i+1;
    // Process Completion bar
    if ( (x != n) && (x % (n/100) == 0) )
    {
      float ratio  =  (float)x/(float)n;
      int   c      =  ratio * w;

      if(ratio < 1){
        std::cout << (int)(ratio*100) << "% [";
        for (int x=0; x<c; x++) std::cout << "=";
        for (int x=c; x<w; x++) std::cout << " ";
        std::cout << "]\r" << std::flush ;
      }
    }


    // if(i%10000 == 0)
    //   std::cout <<"Entry: "<< i << std::endl;
    chain->GetEntry(i);

    Event   = (int)leaf_Event_id->GetValue(0);
    numberofcElectrons = (int)leaf_numberofcElectrons->GetValue(0);
    // std::cout << numberofcElectrons << " ";
    numberofbElectrons = (int)leaf_numberofbElectrons->GetValue(0);
    numberofbcElectrons = (int)leaf_numberofbcElectrons->GetValue(0);
    numberofHadrons = (int)leaf_numberofHadrons->GetValue(0);
    // std::cout << "numHad: " << numberofHadrons << std::endl;
    noTracks        = leaf_noTracks->GetValue(0);
    hrefmult -> Fill(noTracks);

    //loop through matched primary tracks electron find c decayed electron
    int ceNtrigcount=0;
    maxptbin = 0;
    for(int trki = 0; trki < numberofcElectrons; trki++){
      celectron_id      = (int)leaf_ce_id->GetValue(trki);
      celectron_status  = (int)leaf_ce_status->GetValue(trki);
      celectron_pt      = leaf_ce_pt->GetValue(trki);
      celectron_pz      = leaf_ce_pz->GetValue(trki);
      celectron_phi     = leaf_ce_phi->GetValue(trki);
      celectron_eta     = leaf_ce_eta->GetValue(trki);
      celectron_y       = leaf_ce_y->GetValue(trki);
      if(celectron_eta > EtaCut || celectron_eta < -EtaCut) continue;
      ptbin = getPtBin(celectron_pt);
      if(ptbin == -99) continue;
      if(ptbin > maxptbin)
        maxptbin = ptbin;
      hept[ptbin]->Fill(celectron_pt);
      hEventTallyce[maxptbin]->Fill(0.5); //fill for each NPE

      for(int trkj = 0; trkj < numberofHadrons; trkj++){

        assoh_id = (int)leaf_hadron_id->GetValue(trkj);
        assoh_status  = (int)leaf_hadron_status->GetValue(trkj);
        assoh_pt      = leaf_hadron_pt->GetValue(trkj);
        assoh_pz      = leaf_hadron_pz->GetValue(trkj);
        assoh_phi     = leaf_hadron_phi->GetValue(trkj);
        assoh_eta     = leaf_hadron_eta->GetValue(trkj);
        assoh_y       = leaf_hadron_y->GetValue(trkj);
        if(assoh_eta > hEtaCut || assoh_eta < -hEtaCut) continue;

        float deltPhi = assoh_phi - celectron_phi;
        float deltEta = assoh_eta - celectron_eta;
        if(deltPhi < -PI)  deltPhi += 2*PI;
        if(deltPhi >  PI) deltPhi -= 2*PI;
        if(abs(deltEta) > deletacut) continue;
        if(assoh_pt>hptCut)
        {
          hdPhiRawce[ptbin]->Fill(deltPhi); 
          hdEtaRawce[ptbin]->Fill(deltEta);
          ceNtrigcount++;
        }
      }
    }
    //if(ceNtrigcount>0)hEventTallyce[maxptbin]->Fill(0.5);
    //if(ceNtrigcount>0)ceNtrigger++;

    //b decayed electron-------------------------------------------------- 
    int beNtrigcount=0;
    maxptbin = 0;
    for(int trki = 0; trki < numberofbElectrons; trki++){
      belectron_id = (int)leaf_be_id->GetValue(trki);
      belectron_status  = (int)leaf_be_status->GetValue(trki);
      belectron_pt      = leaf_be_pt->GetValue(trki);
      belectron_pz      = leaf_be_pz->GetValue(trki);
      belectron_phi     = leaf_be_phi->GetValue(trki);
      belectron_eta     = leaf_be_eta->GetValue(trki);
      belectron_y        = leaf_be_y->GetValue(trki);
      if(belectron_eta > EtaCut || belectron_eta < -EtaCut) continue;
      ptbin = getPtBin(belectron_pt);
      if(ptbin == -99) continue;
      if(ptbin > maxptbin)
        maxptbin = ptbin;
      hept[ptbin]->Fill(belectron_pt);
      hEventTallybe[maxptbin]->Fill(0.5); //fill for each NPE
      for(int trkj = 0; trkj < numberofHadrons; trkj++){

        assoh_id = (int)leaf_hadron_id->GetValue(trkj);
        assoh_status  = (int)leaf_hadron_status->GetValue(trkj);
        assoh_pt      = leaf_hadron_pt->GetValue(trkj);
        assoh_pz      = leaf_hadron_pz->GetValue(trkj);
        assoh_phi     = leaf_hadron_phi->GetValue(trkj);
        assoh_eta     = leaf_hadron_eta->GetValue(trkj);
        assoh_y       = leaf_hadron_y->GetValue(trkj);
        if(assoh_eta > hEtaCut || assoh_eta < -hEtaCut) continue;

        float deltPhi = assoh_phi - belectron_phi;
        float deltEta = assoh_eta - belectron_eta;
        if(deltPhi < -PI)  deltPhi += 2*PI;
        if(deltPhi >  PI) deltPhi -= 2*PI;
        if(abs(deltEta) > deletacut) continue;
        if(assoh_pt>hptCut)
        {
          hdPhiRawbe[ptbin]->Fill(deltPhi);
          hdEtaRawbe[ptbin]->Fill(deltEta);  
          beNtrigcount++;
        }
      }
    }
    //    if(beNtrigcount>0)hEventTallybe[maxptbin]->Fill("be non photonic electron",1);
    //    if(beNtrigcount>0)beNtrigger++;
    //bce decayed electron-----------------------------------------------------------------                                                                                           
    int bceNtrigcount=0;
    maxptbin = 0;
    for(int trki = 0; trki < numberofbcElectrons; trki++){
      bcelectron_id = (int)leaf_bce_id->GetValue(trki);
      bcelectron_status  = (int)leaf_bce_status->GetValue(trki);
      bcelectron_pt      = leaf_bce_pt->GetValue(trki);
      bcelectron_pz      = leaf_bce_pz->GetValue(trki);
      bcelectron_phi     = leaf_bce_phi->GetValue(trki);
      bcelectron_eta     = leaf_bce_eta->GetValue(trki);
      bcelectron_y       = leaf_bce_y->GetValue(trki);
      if(bcelectron_eta > EtaCut || bcelectron_eta < -EtaCut) continue;
      ptbin = getPtBin(bcelectron_pt);
      if(ptbin == -99) continue;
      if(ptbin > maxptbin)
        maxptbin = ptbin;
      hept[ptbin]->Fill(bcelectron_pt);
      hEventTallybe[maxptbin]->Fill(0.5); //fill for each NPE
      for(int trkj = 0; trkj < numberofHadrons; trkj++){

        assoh_id = (int)leaf_hadron_id->GetValue(trkj);
        assoh_status  = (int)leaf_hadron_status->GetValue(trkj);
        assoh_pt      = leaf_hadron_pt->GetValue(trkj);
        assoh_pz      = leaf_hadron_pz->GetValue(trkj);
        assoh_phi     = leaf_hadron_phi->GetValue(trkj);
        assoh_eta     = leaf_hadron_eta->GetValue(trkj);
        assoh_y       = leaf_hadron_y->GetValue(trkj);
        if(assoh_eta > hEtaCut || assoh_eta < -hEtaCut) continue;

        float deltPhi = assoh_phi - bcelectron_phi;
        float deltEta = assoh_eta - celectron_eta;
        if(deltPhi < -PI)  deltPhi += 2*PI;
        if(deltPhi >  PI) deltPhi -= 2*PI;
        if(abs(deltEta) > deletacut) continue;
        if(assoh_pt>hptCut)
        {
          hdPhiRawbe[ptbin]->Fill(deltPhi);
          hdEtaRawbe[ptbin]->Fill(deltEta);  
          bceNtrigcount++;
        }
      }
    }
    //    if(bceNtrigcount>0)hEventTallybe[maxptbin]->Fill("be non photonic electron",1);
    //    if(bceNtrigcount>0)beNtrigger++;


    /* if(ceNtrigger+bceNtrigger+beNtrigger > 0){
       std::cout<<"ce Trigger electron number = "<<ceNtrigger<<std::endl;
       std::cout<<"be Trigger electron number = "<<beNtrigger<<std::endl;
       std::cout<<"bce Trigger electron number = "<<bceNtrigger<<std::endl;
       }*/
  }

  // After Fill Manipulations
  for(int qq = 0; qq < numPtBins; qq++)
  {
    hdPhiRawceN[qq] = (TH1D*)hdPhiRawce[qq]->Clone();
    hdPhiRawceN[qq] -> SetName(Form("hdPhiRawceN_%i",qq));
    hdPhiRawceN[qq] -> Sumw2();
    hdPhiRawceN[qq] -> Scale(1./(Double_t)hEventTallyce[qq]->GetBinContent(1));
    hdPhiRawbeN[qq] = (TH1D*)hdPhiRawbe[qq]->Clone();
    hdPhiRawbeN[qq] -> SetName(Form("hdPhiRawbeN_%i",qq));
    hdPhiRawbeN[qq] -> Sumw2();
    hdPhiRawbeN[qq] -> Scale(1./(Double_t)hEventTallybe[qq]->GetBinContent(1));
  }

  std::cout << "100% [";
  for (int x=0; x<w; x++) std::cout << "=";
  std::cout << "]" << std::endl;
  fout.Write();
  fout.Close();
  delete chain;
}
void GetBinM(RooUnfoldResponse* &BinM, TH1D* &h_gen, TH1D* &h_reco, RooUnfoldResponse* &BinM_1, TH1D* &h_gen_1, TH1D* &h_reco_1, RooUnfoldResponse* &BinM_2, TH1D* &h_gen_2, TH1D* &h_reco_2, bool madgraph=1, int elec=0){

  TH2D* BinMigration=new TH2D("BinMigration","BinMigration",nbins,0,nbins,nbins,0,nbins);
  BinMigration->Sumw2();
  TH1D* Dphistar=new TH1D("Dphistar","Dphistar",2000,-1,1);
  Dphistar->Sumw2();
  TH1D* Dy=new TH1D("Dy","Dy",2000,-1,1);
  Dy->Sumw2();
  TChain* t = new TChain(reco_name.c_str(),reco_name.c_str());
  int nfiles;
  if (madgraph){
    if (elec==0) nfiles=t->Add(File_Signal_reco_d.c_str());
    if (elec==1) nfiles=t->Add(File_Signal_reco_b.c_str());
    if (elec==2) nfiles=t->Add(File_Signal_reco_n.c_str());
  }
  else {
    if (elec==0) nfiles=t->Add(File_Powheg_reco_d.c_str());
    if (elec==1) nfiles=t->Add(File_Powheg_reco_b.c_str());
    if (elec==2) nfiles=t->Add(File_Powheg_reco_n.c_str());
  }

  TBranch *b_reco=t->GetBranch("reco");
  TBranch *b_truth=t->GetBranch("truth");
  TLeaf *l_phistar=b_reco->GetLeaf("z_phistar_dressed");
  TLeaf *l_phistar_true=b_truth->GetLeaf("z_phistar_dressed");
  if (elec==1) l_phistar_true=b_truth->GetLeaf("z_phistar_born");
  if (elec==2) l_phistar_true=b_truth->GetLeaf("z_phistar_naked");
  TLeaf *l_y=b_reco->GetLeaf("z_y");
  TLeaf *l_y_true=b_truth->GetLeaf("z_y");
  if (elec==1) l_y_true=b_reco->GetLeaf("z_yBorn");
  if (elec==2) l_y_true=b_reco->GetLeaf("z_yNaked");
  int nweights;
  t->SetBranchAddress("weight_size",&nweights);
  t->GetEntry(0);
  cout<<"The sample has nweights: "<<nweights<<endl;
  double weights[nweights];
  int weightid[nweights];
  t->SetBranchAddress("weights",&weights);
  t->SetBranchAddress("weight_ids",&weightid);

  cout<<"Entries: "<<t->GetEntries()<<endl;
  h_gen   = new TH1D("phistar","phistar",nbins,0,nbins);
  h_gen->Sumw2();
  h_reco  = new TH1D("phistar","phistar",nbins,0,nbins);
  h_reco->Sumw2();
  h_gen_1 = new TH1D("phistar","phistar",nbins,0,nbins);
  h_gen_1->Sumw2();
  h_reco_1= new TH1D("phistar","phistar",nbins,0,nbins);
  h_reco_1->Sumw2();
  h_gen_2 = new TH1D("phistar","phistar",nbins,0,nbins);
  h_gen_2->Sumw2();
  h_reco_2= new TH1D("phistar","phistar",nbins,0,nbins);
  h_reco_2->Sumw2();
  BinM  =new RooUnfoldResponse (h_reco,h_gen);
  BinM_1=new RooUnfoldResponse (h_reco,h_gen);
  BinM_2=new RooUnfoldResponse (h_reco,h_gen);

  cout<<"reading signal reco "<<endl;
  for (int i=0; i<t->GetEntries();i++){
    // if (i>20000) continue;
    //for (int i=0; i<50000;i++){
    t->GetEntry(i);
    double weight =1;
    for (int w=0; w<nweights;w++){
      if (weightid[w]==1 || weightid[w]==2 || weightid[w]==12 || weightid[w]==13 || weightid[w]==20 || weightid[w]==30) {weight=weight*weights[w];}
    }
    double phistar=l_phistar->GetValue();
    double phistar_true=l_phistar_true->GetValue();
    Dphistar->Fill((phistar_true-phistar)/phistar_true,weight);
    double y=l_y->GetValue();
    double y_true=l_y_true->GetValue();
    Dy->Fill((y_true-y)/y_true,weight);

    int bin=GetBin(phistar,y);
    int bin_true=GetBin(phistar_true,y_true);

    h_gen ->Fill(bin_true,weight);
    h_reco->Fill(bin,weight);
    if (N_MC==-1 || i<N_MC) BinM  ->Fill(bin,bin_true,weight); 
    BinMigration->Fill(bin,bin_true,weight);
    if (i%2==0){
      h_gen_1 ->Fill(bin_true,weight);
      h_reco_1->Fill(bin,weight);
      if (N_MC==-1 || i<N_MC) BinM_1  ->Fill(bin,bin_true,weight); 
    }
    else{
      h_gen_2 ->Fill(bin_true,weight);
      h_reco_2->Fill(bin,weight);
      if (N_MC==-1 || i<N_MC) BinM_2  ->Fill(bin,bin_true,weight); 
    }
  }
////////////////////////////here is where I left.
  TLatex mark;
  mark.SetTextSize(0.04);
  mark.SetTextFont(42);
  mark.SetNDC(true);

//  BinMigration->GetXaxis()->SetRangeUser(0.001,3.2);
  BinMigration->GetXaxis()->SetTitle("(#phi*,y) bin (reconstructed)");
  BinMigration->GetXaxis()->SetTitleOffset(0.8);
  BinMigration->GetXaxis()->SetTitleSize(0.04);
  BinMigration->GetXaxis()->SetLabelOffset(0);
  BinMigration->GetXaxis()->SetLabelSize(0.03);
  BinMigration->GetYaxis()->SetTitleOffset(1.05);
  BinMigration->GetYaxis()->SetTitleSize(0.04);
  BinMigration->GetYaxis()->SetLabelSize(0.03);
//  BinMigration->GetYaxis()->SetRangeUser(0.001,3.2);
  BinMigration->GetYaxis()->SetTitle("(#phi*,y) bin (generated)");
  BinMigration->GetZaxis()->SetTitleOffset(-0.004);
  BinMigration->SetStats(0);
  BinMigration->SetBit( TH2::kNoTitle, true );

  Dphistar->GetXaxis()->SetTitle("(#phi*(generated) - #phi*(reconstructed)/#phi*(generated)");
  Dphistar->GetXaxis()->SetTitleOffset(1.0);
  Dphistar->GetXaxis()->SetTitleSize(0.04);
  Dphistar->GetXaxis()->SetLabelOffset(0.0);
  Dphistar->GetXaxis()->SetLabelSize(0.04);
  Dphistar->GetYaxis()->SetTitleOffset(1.05);
  Dphistar->GetYaxis()->SetTitleSize(0.04);
  Dphistar->GetYaxis()->SetLabelSize(0.04);
  Dphistar->GetYaxis()->SetTitle("a.u.");
  Dphistar->SetMarkerStyle(20);
  Dphistar->SetMarkerColor(1);
  Dphistar->SetLineColor(1);
  Dphistar->SetStats(0);
  Dphistar->SetBit( TH2::kNoTitle, true );

  Dy->GetXaxis()->SetTitle("(Z(y)(generated) - Z(y)(reconstructed)/Z(y) (generated)");
  Dy->GetXaxis()->SetTitleOffset(1.0);
  Dy->GetXaxis()->SetTitleSize(0.04);
  Dy->GetXaxis()->SetLabelOffset(0.0);
  Dy->GetXaxis()->SetLabelSize(0.04);
  Dy->GetYaxis()->SetTitleOffset(1.05);
  Dy->GetYaxis()->SetTitleSize(0.04);
  Dy->GetYaxis()->SetLabelSize(0.04);
  Dy->GetYaxis()->SetTitle("a.u.");
  Dy->SetMarkerStyle(20);
  Dy->SetMarkerColor(1);
  Dy->SetLineColor(1);
  Dy->SetStats(0);
  Dy->SetBit( TH2::kNoTitle, true );
   
  std::string plotname = "Plots/BinM_";
  if (elec==0) plotname+="Dressed_";
  if (elec==1) plotname+="Born_";
  if (elec==2) plotname+="Naked_";
  if (madgraph)plotname+="MG_";
  else         plotname+="PH_";

  if (madgraph){
    TCanvas* BinM_M = new TCanvas("BinM_M","BinM_M",800,900);
    BinM_M->cd();
    // BinM_M->SetLogx();
    // BinM_M->SetLogy();
    BinM_M->SetLogz();
    BinMigration->Draw("COLZ");
    mark.DrawLatex(0.19,0.80,"MadGraph");
    BinM_M->SaveAs((plotname+"res"+FileType).c_str());
    TCanvas* Dp_M = new TCanvas("Dp_M","Dp_M",800,900);
    Dp_M->cd();
    Dp_M->SetLogy();
    Dphistar->Draw();
    mark.DrawLatex(0.19,0.80,"MadGraph");
    Dp_M->SaveAs((plotname+"Dphistar"+FileType).c_str());
    TCanvas* Dy_M = new TCanvas("Dy_M","Dy_M",800,900);
    Dy_M->cd();
    Dy_M->SetLogy();
    Dy->Draw();
    mark.DrawLatex(0.19,0.80,"MadGraph");
    Dy_M->SaveAs((plotname+"Dy"+FileType).c_str());
  }
  else{
    TCanvas* BinM_P = new TCanvas("BinM_P","BinM_P",800,900);
    BinM_P->cd();
    // BinM_P->SetLogx();
    // BinM_P->SetLogy();
    BinM_P->SetLogz();
    BinMigration->Draw("COLZ");
    mark.DrawLatex(0.19,0.80,"Powheg");
    BinM_P->SaveAs((plotname+"res"+FileType).c_str());
    TCanvas* Dp_P = new TCanvas("Dp_P","Dp_P",800,900);
    Dp_P->cd();
    Dp_P->SetLogy();
    Dphistar->Draw();
    mark.DrawLatex(0.19,0.80,"Powheg");
    Dp_P->SaveAs((plotname+"Dphistar"+FileType).c_str());
    TCanvas* Dy_P = new TCanvas("Dy_P","Dy_P",800,900);
    Dy_P->cd();
    Dy_P->SetLogy();
    Dy->Draw();
    mark.DrawLatex(0.19,0.80,"Powheg");
    Dy_P->SaveAs((plotname+"Dy"+FileType).c_str());
  }

  double weighted_events= BinMigration->GetSumOfWeights();  
  double diagonal=0;
  for (uint i=0; i<nbins; i++){
    diagonal+=BinMigration->GetBinContent(i+1,i+1);
  }
  cout<<weighted_events<<" of which diagonal "<<diagonal<<" non diagonal faction:"<<(weighted_events-diagonal)/weighted_events<<endl;
  //Find amount of bin migration of Y
  double InTheY=0;//Gets values in the Same Y region 
  for (uint i=1; i<=nphistar; i++){
      for (uint j=1; j<=nphistar; j++){
          InTheY+=BinMigration->GetBinContent(i,j);
          InTheY+=BinMigration->GetBinContent(i+nphistar,j+nphistar);
          InTheY+=BinMigration->GetBinContent(i+nphistar*2,j+nphistar*2);
          InTheY+=BinMigration->GetBinContent(i+nphistar*3,j+nphistar*3);
          InTheY+=BinMigration->GetBinContent(i+nphistar*4,j+nphistar*4);
          InTheY+=BinMigration->GetBinContent(i+nphistar*5,j+nphistar*5);
      }
      
  }
  cout<<"Percent mig Y axis: "<<100*(weighted_events-InTheY)/weighted_events<<std::endl<<std::endl;
  
  cout<<"done reading data "<<endl;

  for (uint i=0; i<nbins;i++){
    h_gen->SetBinError(i+1,0);
    h_gen_1->SetBinError(i+1,0);
    h_gen_2->SetBinError(i+1,0);
  }
  return;
}
void dimuonSkim(const TString configFile, const TString inputFile, const TString outputFile)
{
       std::cout<<"running dimuonSkim()"   <<std::endl;
       std::cout<<"configFile  = "<< configFile.Data() <<std::endl;
       std::cout<<"inputFile   = "<< inputFile.Data() <<std::endl;
       std::cout<<"outputFile  = "<< outputFile.Data() <<std::endl;

       InputConfiguration configInput = InputConfigurationParser::Parse(configFile.Data());
       CutConfiguration configCuts = CutConfigurationParser::Parse(configFile.Data());

       if (!configInput.isValid) {
           std::cout << "Input configuration is invalid." << std::endl;
           std::cout << "exiting" << std::endl;
           return;
       }
       if (!configCuts.isValid) {
           std::cout << "Cut configuration is invalid." << std::endl;
           std::cout << "exiting" << std::endl;
           return;
       }

       // input configuration
       int collisionType = configInput.proc[INPUT::kSKIM].i[INPUT::k_collisionType];
       std::string treePath = configInput.proc[INPUT::kSKIM].s[INPUT::k_treePath];

       // set default values
       if (treePath.size() == 0)  treePath = "ggHiNtuplizer/EventTree";

       // verbose about input configuration
       std::cout<<"Input Configuration :"<<std::endl;
       std::cout << "collisionType = " << collisionType << std::endl;
       const char* collisionName =  getCollisionTypeName((COLL::TYPE)collisionType).c_str();
       std::cout << "collision = " << collisionName << std::endl;
       std::cout << "treePath = " << treePath.c_str() << std::endl;

       // cut configuration
       float cut_vz = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].f[CUTS::EVT::k_vz];
       int cut_pcollisionEventSelection = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pcollisionEventSelection];
       int cut_pPAprimaryVertexFilter = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pPAprimaryVertexFilter];
       int cut_pBeamScrapingFilter = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pBeamScrapingFilter];

       int cut_nMu = configCuts.proc[CUTS::kSKIM].obj[CUTS::kMUON].i[CUTS::MUO::k_nMu];

       // bool isMC = collisionIsMC((COLL::TYPE)collisionType);
       bool isHI = collisionIsHI((COLL::TYPE)collisionType);
       bool isPP = collisionIsPP((COLL::TYPE)collisionType);

       // verbose about cut configuration
       std::cout<<"Cut Configuration :"<<std::endl;
       std::cout<<"cut_vz = "<< cut_vz <<std::endl;
       if (isHI) {
           std::cout<<"cut_pcollisionEventSelection = "<< cut_pcollisionEventSelection <<std::endl;
       }
       else {   // PP
           std::cout<<"cut_pPAprimaryVertexFilter = "<< cut_pPAprimaryVertexFilter <<std::endl;
           std::cout<<"cut_pBeamScrapingFilter = "<< cut_pBeamScrapingFilter <<std::endl;
       }

       std::cout<<"cut_nMu = "<<cut_nMu<<std::endl;

       std::vector<std::string> inputFiles = InputConfigurationParser::ParseFiles(inputFile.Data());

       std::cout<<"input ROOT files : num = "<<inputFiles.size()<< std::endl;
       std::cout<<"#####"<< std::endl;
       for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
           std::cout<<(*it).c_str()<< std::endl;
       }
       std::cout<<"##### END #####"<< std::endl;

       TChain* treeHLT   = new TChain("hltanalysis/HltTree");
       TChain* treeggHiNtuplizer  = new TChain("ggHiNtuplizer/EventTree");
       TChain* treeHiEvt = new TChain("hiEvtAnalyzer/HiTree");
       TChain* treeSkim  = new TChain("skimanalysis/HltTree");
       TChain* treeHiForestInfo = new TChain("HiForest/HiForestInfo");

       for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
          treeHLT->Add((*it).c_str());
          treeggHiNtuplizer->Add((*it).c_str());
          treeHiEvt->Add((*it).c_str());
          treeSkim->Add((*it).c_str());
          treeHiForestInfo->Add((*it).c_str());
       }

       HiForestInfoController hfic(treeHiForestInfo);
       std::cout<<"### HiForestInfo Tree ###"<< std::endl;
       hfic.printHiForestInfo();
       std::cout<<"###"<< std::endl;

       treeHLT->SetBranchStatus("*",0);     // disable all branches
       treeHLT->SetBranchStatus("HLT_HI*SinglePhoton*Eta*",1);     // enable photon branches
       treeHLT->SetBranchStatus("HLT_HI*DoublePhoton*Eta*",1);     // enable photon branches
       treeHLT->SetBranchStatus("*DoubleMu*",1);                      // enable muon branches
       treeHLT->SetBranchStatus("HLT_HIL1Mu*",1);                     // enable muon branches
       treeHLT->SetBranchStatus("HLT_HIL2Mu*",1);                     // enable muon branches
       treeHLT->SetBranchStatus("HLT_HIL3Mu*",1);                     // enable muon branches
       
       // specify explicitly which branches to store, do not use wildcard
       treeHiEvt->SetBranchStatus("*",1);

       // specify explicitly which branches to store, do not use wildcard
       treeSkim->SetBranchStatus("*",0);

       Int_t pcollisionEventSelection;  // this filter is used for HI.
       if (isHI) {
           treeSkim->SetBranchStatus("pcollisionEventSelection",1);
           if (treeSkim->GetBranch("pcollisionEventSelection")) {
               treeSkim->SetBranchAddress("pcollisionEventSelection",&pcollisionEventSelection);
           }
           else {   // overwrite to default
               pcollisionEventSelection = 1;
               std::cout<<"could not get branch : pcollisionEventSelection"<<std::endl;
               std::cout<<"set to default value : pcollisionEventSelection = "<<pcollisionEventSelection<<std::endl;
           }
       }
       else {
           pcollisionEventSelection = 0;    // default value if the collision is not HI, will not be used anyway.
       }
       Int_t pPAprimaryVertexFilter;    // this filter is used for PP.
       if (isPP) {
           treeSkim->SetBranchStatus("pPAprimaryVertexFilter",1);
           if (treeSkim->GetBranch("pPAprimaryVertexFilter")) {
               treeSkim->SetBranchAddress("pPAprimaryVertexFilter",&pPAprimaryVertexFilter);
           }
           else {   // overwrite to default
               pPAprimaryVertexFilter = 1;
               std::cout<<"could not get branch : pPAprimaryVertexFilter"<<std::endl;
               std::cout<<"set to default value : pPAprimaryVertexFilter = "<<pPAprimaryVertexFilter<<std::endl;
           }
       }
       else {
           pPAprimaryVertexFilter = 0;      // default value if the collision is not PP, will not be used anyway.
       }
       Int_t pBeamScrapingFilter;   // this filter is used for PP.
       if (isPP) {
           treeSkim->SetBranchStatus("pBeamScrapingFilter",1);
           if (treeSkim->GetBranch("pBeamScrapingFilter")) {
               treeSkim->SetBranchAddress("pBeamScrapingFilter",&pBeamScrapingFilter);
           }
           else {   // overwrite to default
               pBeamScrapingFilter = 1;
               std::cout<<"could not get branch : pBeamScrapingFilter"<<std::endl;
               std::cout<<"set to default value : pBeamScrapingFilter = "<<pBeamScrapingFilter<<std::endl;
           }
       }
       else {
           pBeamScrapingFilter = 0;     // default value if the collision is not PP, will not be used anyway.
       }

       ggHiNtuplizer ggHi;
       ggHi.setupTreeForReading(treeggHiNtuplizer);
       
       hiEvt hiEvt;
       hiEvt.setupTreeForReading(treeHiEvt);

       TFile* output = new TFile(outputFile,"RECREATE");
       TTree *configTree = setupConfigurationTreeForWriting(configCuts);

       // output tree variables
       TTree *outputTreeHLT           = treeHLT->CloneTree(0);
       outputTreeHLT->SetName("hltTree");
       outputTreeHLT->SetTitle("subbranches of hltanalysis/HltTree");
       TTree *outputTreeggHiNtuplizer = treeggHiNtuplizer->CloneTree(0);
       TTree *outputTreeHiEvt = treeHiEvt->CloneTree(0);
       outputTreeHiEvt->SetName("HiEvt");
       outputTreeHiEvt->SetTitle("subbranches of hiEvtAnalyzer/HiTree");
       TTree* outputTreeSkim  = treeSkim->CloneTree(0);
       outputTreeSkim->SetName("skim");
       outputTreeSkim->SetTitle("subbranches of skimanalysis/HltTree");
       TTree* outputTreeHiForestInfo = treeHiForestInfo->CloneTree(0);
       outputTreeHiForestInfo->SetName("HiForestInfo");
       outputTreeHiForestInfo->SetTitle("first entry of HiForest/HiForestInfo");
       
       outputTreeHLT->SetMaxTreeSize(MAXTREESIZE);
       outputTreeggHiNtuplizer->SetMaxTreeSize(MAXTREESIZE);
       outputTreeHiEvt->SetMaxTreeSize(MAXTREESIZE);
       outputTreeHiForestInfo->SetMaxTreeSize(MAXTREESIZE);

       // write HiForestInfo
       treeHiForestInfo->GetEntry(0);
       outputTreeHiForestInfo->Fill();

       TTree *diMuonTree = new TTree("dimuon","muon pairs");
       diMuonTree->SetMaxTreeSize(MAXTREESIZE);

       dimuon diMu;
       diMu.branchDiMuonTree(diMuonTree);

       EventMatcher* em = new EventMatcher();
       Long64_t duplicateEntries = 0;

       Long64_t entries = treeggHiNtuplizer->GetEntries();
       Long64_t entriesPassedEventSelection = 0;
       Long64_t entriesAnalyzed = 0;
       std::cout << "entries = " << entries << std::endl;
       std::cout<< "Loop : " << treePath.c_str() <<std::endl;
       for (Long64_t j_entry=0; j_entry<entries; ++j_entry)
       {
           if (j_entry % 20000 == 0)  {
             std::cout << "current entry = " <<j_entry<<" out of "<<entries<<" : "<<std::setprecision(2)<<(double)j_entry/entries*100<<" %"<<std::endl;
           }

           treeHLT->GetEntry(j_entry);
           treeggHiNtuplizer->GetEntry(j_entry);
           treeHiEvt->GetEntry(j_entry);
           treeSkim->GetEntry(j_entry);

           bool eventAdded = em->addEvent(ggHi.run,ggHi.lumis,ggHi.event,j_entry);
           if(!eventAdded) // this event is duplicate, skip this one.
           {
               duplicateEntries++;
               continue;
           }

           // event selection
           if (!(TMath::Abs(hiEvt.vz) < cut_vz))  continue;
           if (isHI) {
               if ((pcollisionEventSelection < cut_pcollisionEventSelection))  continue;
           }
           else {
               if (pPAprimaryVertexFilter < cut_pPAprimaryVertexFilter || pBeamScrapingFilter < cut_pBeamScrapingFilter)  continue;
           }
           entriesPassedEventSelection++;

           // skip if there are no muon pairs to study
           if(ggHi.nMu < cut_nMu)  continue;
           entriesAnalyzed++;

           diMu.makeDiMuonPairs(ggHi);

           outputTreeHLT->Fill();
           outputTreeggHiNtuplizer->Fill();
           outputTreeHiEvt->Fill();
           outputTreeSkim->Fill();
           diMuonTree->Fill();
       }
       std::cout<< "Loop ENDED : " << treePath.c_str() <<std::endl;
       std::cout << "entries            = " << entries << std::endl;
       std::cout << "duplicateEntries   = " << duplicateEntries << std::endl;
       std::cout << "entriesPassedEventSelection   = " << entriesPassedEventSelection << std::endl;
       std::cout << "entriesAnalyzed    = " << entriesAnalyzed << std::endl;
       std::cout << "outputTreeHLT->GetEntries()           = " << outputTreeHLT->GetEntries() << std::endl;
       std::cout << "outputTreeggHiNtuplizer->GetEntries() = " << outputTreeggHiNtuplizer->GetEntries() << std::endl;
       std::cout << "outputTreeHiEvt->GetEntries() = " << outputTreeHiEvt->GetEntries() << std::endl;
       std::cout << "outputTreeSkim->GetEntries()  = " << outputTreeSkim->GetEntries() << std::endl;
       std::cout << "diMuonTree->GetEntries()          = " << diMuonTree->GetEntries() << std::endl;

       // overwrite existing trees
       outputTreeHLT->Write("", TObject::kOverwrite);
       outputTreeggHiNtuplizer->Write("", TObject::kOverwrite);
       outputTreeHiEvt->Write("", TObject::kOverwrite);
       diMuonTree->Write("", TObject::kOverwrite);

       configTree->Write("", TObject::kOverwrite);

       output->Write("", TObject::kOverwrite);
       output->Close();

       std::cout<<"dimuonSkim() - END"   <<std::endl;
}
void plotPFRandomCone(TString str = "forest.root", Int_t nRCPerEvent = 1, int maxEvents = -1) {

  // gStyle->SetOptStat(0000);
  // gStyle->SetOptTitle(0);

  double minEta = -1.5;
  double maxEta = 1.5;
  double minPhi = -TMath::Pi();
  double maxPhi = TMath::Pi();
  double radiusRC = 0.4;
  
  TChain *fChain = new TChain("hiEvtAnalyzer/HiTree");
  TChain *pfTree = new TChain("pfcandAnalyzer/pfTree");
  TChain *skimTree = new TChain("skimanalysis/HltTree");
  TChain *hltTree = new TChain("hltanalysis/HltTree");
  //  TFile *f = TFile::Open(str.Data());
  fChain->Add(str.Data());
  pfTree->Add(str.Data());
  skimTree->Add(str.Data());
  hltTree->Add(str.Data());
  fChain->AddFriend(pfTree);
  fChain->AddFriend(skimTree);
  fChain->AddFriend(hltTree);
  
  if(!fChain) {
    Printf("Couldn't find pfTree. Aborting!");
    return;
  }

  Int_t MinBiasTriggerBit;
  Int_t phfCoincFilter;
  
  Int_t           hiBin;
  TBranch        *b_hiBin;   //!
  fChain->SetBranchAddress("hiBin", &hiBin, &b_hiBin);
  fChain->SetBranchAddress("HLT_HIL1MinimumBiasHF1ANDExpress_v1",&MinBiasTriggerBit);
  fChain->SetBranchAddress("phfCoincFilter3",&phfCoincFilter);
  
  ForestPFs                    fPFs;              //!PFs in tree
  if (fChain->GetBranch("nPFpart"))
    fChain->SetBranchAddress("nPFpart", &fPFs.nPFpart, &fPFs.b_nPFpart);
  if (fChain->GetBranch("pfId"))
    fChain->SetBranchAddress("pfId", fPFs.pfId, &fPFs.b_pfId);
  if (fChain->GetBranch("pfPt"))
    fChain->SetBranchAddress("pfPt", fPFs.pfPt, &fPFs.b_pfPt);
  if (fChain->GetBranch("pfVsPtInitial"))
    fChain->SetBranchAddress("pfVsPtInitial", fPFs.pfVsPt, &fPFs.b_pfVsPt);
  if (fChain->GetBranch("pfEta"))
    fChain->SetBranchAddress("pfEta", fPFs.pfEta, &fPFs.b_pfEta);
  if (fChain->GetBranch("pfPhi"))
    fChain->SetBranchAddress("pfPhi", fPFs.pfPhi, &fPFs.b_pfPhi);

  //Printf("nentries: %d",(Int_t)fChain->GetEntries());

  TList *fOutput =  new TList();
  TH1::SetDefaultSumw2();
  
  TH3D *h2CentPtRCEta = new TH3D("h2CentPtRCEta","h2CentPtRCEta;centrality;p_{T,RC};#eta",100,0,100,250,-50.,200.,60,-6,6);
  fOutput->Add(h2CentPtRCEta);
  TH3D *h2CentPtRCEtaVS = new TH3D("h2CentPtRCEtaVS","h2CentPtRCEtaVS;centrality;p_{T,RC}^{VS};#eta",100,0,100,250,-50.,200.,60,-6,6);
  fOutput->Add(h2CentPtRCEtaVS);

  TH3D *h2MultPtRCEta = new TH3D("h2MultPtRCEta","h2MultPtRCEta;centrality;p_{T,RC};#eta",3000,0,6000,150,-50.,100.,60,-6,6);
  fOutput->Add(h2MultPtRCEta);
  TH3D *h2MultPtRCEtaVS = new TH3D("h2MultPtRCEtaVS","h2MultPtRCEtaVS;centrality;p_{T,RC}^{VS};#eta",3000,0,6000,150,-50.,100.,60,-6,6);
  fOutput->Add(h2MultPtRCEtaVS);
  Printf("histos defined");

  Int_t startEntry = 0;
  Int_t lastEntry = fChain->GetEntries();//100;
  Printf("events in chain: %d",lastEntry);
  if(maxEvents<lastEntry)
    lastEntry = maxEvents;
  Printf("lastEntry: %d",lastEntry);

  TRandom3 *rnd = new TRandom3();
 
  for (int j=startEntry; j<lastEntry; j++) {
    fChain->GetEntry(j);
    if(j%100==0) std::cout << "entry: "<< j << std::endl;
    //if(!MinBiasTriggerBit) continue;
    if(!phfCoincFilter) continue;
    
    double etaRC = rnd->Rndm() * (maxEta - minEta) + minEta;
    double phiRC = rnd->Rndm() * (maxPhi - minPhi) + minPhi;

    double ptRC = 0.;
    double ptRCVS = 0.;
    Int_t pfCount = 0;
    for(Int_t i = 0; i<fPFs.nPFpart; i++) {
      double pt = fPFs.pfPt[i];
      double ptVS = fPFs.pfVsPt[i];
      double phi = fPFs.pfPhi[i];
      double eta = fPFs.pfEta[i];

      double dr = deltaR(phi,phiRC,eta,etaRC);
      if(dr<radiusRC) {
        ptRC+=pt;
        ptRCVS+=ptVS;
      }

      if(abs(eta)<2.) pfCount++;
      
    }
    Double_t cent = (Double_t)hiBin/2.;
    h2CentPtRCEta->Fill(cent,ptRC,etaRC);
    h2CentPtRCEtaVS->Fill(cent,ptRCVS,etaRC);

    h2MultPtRCEta->Fill(pfCount,ptRC,etaRC);
    h2MultPtRCEtaVS->Fill(pfCount,ptRCVS,etaRC);
  }

  TFile *fout = new TFile("RandomCones.root","RECREATE");
  fOutput->Write();
  fout->Write();
  fout->Close();
}
void minBiasJetSkim(const TString configFile, const TString inputFile, const TString outputFile)
{
       std::cout<<"running minBiasJetSkim()"<<std::endl;
       std::cout<<"configFile  = "<< configFile.Data() <<std::endl;
       std::cout<<"inputFile   = "<< inputFile.Data() <<std::endl;
       std::cout<<"outputFile  = "<< outputFile.Data() <<std::endl;

       InputConfiguration configInput = InputConfigurationParser::Parse(configFile.Data());
       CutConfiguration configCuts = CutConfigurationParser::Parse(configFile.Data());

       if (!configInput.isValid) {
           std::cout << "Input configuration is invalid." << std::endl;
           std::cout << "exiting" << std::endl;
           return;
       }
       if (!configCuts.isValid) {
           std::cout << "Cut configuration is invalid." << std::endl;
           std::cout << "exiting" << std::endl;
           return;
       }

       // cut configuration
       float cut_vz = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].f[CUTS::EVT::k_vz];
       int cut_pcollisionEventSelection = configCuts.proc[CUTS::kSKIM].obj[CUTS::kEVENT].i[CUTS::EVT::k_pcollisionEventSelection];

       std::vector<std::string> jetCollections = ConfigurationParser::ParseList(configCuts.proc[CUTS::kSKIM].obj[CUTS::kJET].s[CUTS::JET::k_jetCollection]);
       int nMaxEvents_minBiasMixing = configCuts.proc[CUTS::kSKIM].obj[CUTS::kGAMMAJET].i[CUTS::GJT::k_nMaxEvents_minBiasMixing];
       int nCentralityBins = configCuts.proc[CUTS::kSKIM].obj[CUTS::kGAMMAJET].i[CUTS::GJT::k_nCentralityBins];
       int nVertexBins = configCuts.proc[CUTS::kSKIM].obj[CUTS::kGAMMAJET].i[CUTS::GJT::k_nVertexBins];
       int nEventPlaneBins = configCuts.proc[CUTS::kSKIM].obj[CUTS::kGAMMAJET].i[CUTS::GJT::k_nEventPlaneBins];

       int nJetCollections = jetCollections.size();

       // verbose about cut configuration
       std::cout<<"Cut Configuration :"<<std::endl;
       std::cout<<"cut_vz = "<< cut_vz <<std::endl;
       std::cout<<"cut_pcollisionEventSelection = "<< cut_pcollisionEventSelection <<std::endl;

       std::cout<<"nJetCollections = "<< nJetCollections <<std::endl;
       for (int i=0; i<nJetCollections; ++i) {
           std::cout << Form("jetCollections[%d] = %s", i, jetCollections.at(i).c_str()) << std::endl;
       }
       std::cout<<"nMaxEvents_minBiasMixing = "<< nMaxEvents_minBiasMixing <<std::endl;
       std::cout<<"nCentralityBins          = "<< nCentralityBins <<std::endl;
       std::cout<<"nVertexBins              = "<< nVertexBins <<std::endl;
       std::cout<<"nEventPlaneBins          = "<< nEventPlaneBins <<std::endl;

       std::vector<std::string> inputFiles = InputConfigurationParser::ParseFiles(inputFile.Data());

       std::cout<<"input ROOT files : num = "<<inputFiles.size()<< std::endl;
       std::cout<<"#####"<< std::endl;
       for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
           std::cout<<(*it).c_str()<< std::endl;
       }
       std::cout<<"##### END #####"<< std::endl;

       TChain* treeHLT   = new TChain("hltanalysis/HltTree");
       TChain* treeEvent = new TChain("ggHiNtuplizer/EventTree");
       TChain* treeJets[nJetCollections];
       for (int i=0; i<nJetCollections; ++i) {
           treeJets[i] = new TChain(Form("%s/t", jetCollections.at(i).c_str()));
       }
       TChain* treeHiEvt = new TChain("hiEvtAnalyzer/HiTree");
       TChain* treeSkim  = new TChain("skimanalysis/HltTree");
       TChain* treeHiForestInfo = new TChain("HiForest/HiForestInfo");

       for (std::vector<std::string>::iterator it = inputFiles.begin() ; it != inputFiles.end(); ++it) {
          treeHLT->Add((*it).c_str());
          treeEvent->Add((*it).c_str());
          for (int i=0; i<nJetCollections; ++i) {
              treeJets[i]->Add((*it).c_str());
          }
          treeHiEvt->Add((*it).c_str());
          treeSkim->Add((*it).c_str());
          if (it == inputFiles.begin())  treeHiForestInfo->Add((*it).c_str());
       }

       HiForestInfoController hfic(treeHiForestInfo);
       std::cout<<"### HiForestInfo Tree ###"<< std::endl;
       hfic.printHiForestInfo();
       std::cout<<"###"<< std::endl;

       treeHLT->SetBranchStatus("*",0);     // disable all branches

       treeEvent->SetBranchStatus("*",0);
       treeEvent->SetBranchStatus("run",1);
       treeEvent->SetBranchStatus("event",1);
       treeEvent->SetBranchStatus("lumis",1);

       for (int i=0; i<nJetCollections; ++i) {
           treeJets[i]->SetBranchStatus("*",0);        // disable all branches
           treeJets[i]->SetBranchStatus("nref",1);     // enable jet branches
           treeJets[i]->SetBranchStatus("rawpt",1);    // enable jet branches
           treeJets[i]->SetBranchStatus("jtpt",1);     // enable jet branches
           treeJets[i]->SetBranchStatus("jteta",1);    // enable jet branches
           treeJets[i]->SetBranchStatus("jtphi",1);    // enable jet branches
           treeJets[i]->SetBranchStatus("jty",1);      // enable jet branches
           treeJets[i]->SetBranchStatus("jtpu",1);     // enable jet branches
           treeJets[i]->SetBranchStatus("jtm",1);      // enable jet branches
           treeJets[i]->SetBranchStatus("track*",1);
           treeJets[i]->SetBranchStatus("charged*",1);
           treeJets[i]->SetBranchStatus("photon*",1);
           treeJets[i]->SetBranchStatus("neutral*",1);
           treeJets[i]->SetBranchStatus("eMax*",1);
           treeJets[i]->SetBranchStatus("eSum*",1);
           treeJets[i]->SetBranchStatus("eN*",1);
           treeJets[i]->SetBranchStatus("muMax*",1);
           treeJets[i]->SetBranchStatus("muSum*",1);
           treeJets[i]->SetBranchStatus("muN*",1);
       }

       // specify explicitly which branches to store, do not use wildcard
       treeHiEvt->SetBranchStatus("*",0);
       treeHiEvt->SetBranchStatus("run",1);
       treeHiEvt->SetBranchStatus("evt",1);
       treeHiEvt->SetBranchStatus("lumi",1);
       treeHiEvt->SetBranchStatus("vz",1);
       treeHiEvt->SetBranchStatus("hiBin",1);
       treeHiEvt->SetBranchStatus("hiHF",1);
       treeHiEvt->SetBranchStatus("hiHFplus",1);
       treeHiEvt->SetBranchStatus("hiHFminus",1);
       treeHiEvt->SetBranchStatus("hiHFplusEta4",1);
       treeHiEvt->SetBranchStatus("hiHFminusEta4",1);
      //  treeHiEvt->SetBranchStatus("hiNevtPlane",1);

       float vz;
       Int_t hiBin;
       Float_t         hiEvtPlanes[29];   //[hiNevtPlane]
       treeHiEvt->SetBranchAddress("hiEvtPlanes",&hiEvtPlanes);

       treeHiEvt->SetBranchAddress("vz",&vz);
       treeHiEvt->SetBranchAddress("hiBin",&hiBin);

       // specify explicitly which branches to store, do not use wildcard
       treeSkim->SetBranchStatus("*",0);
       treeSkim->SetBranchStatus("ana_step",1);
       treeSkim->SetBranchStatus("pcollisionEventSelection",1);
       treeSkim->SetBranchStatus("pHBHENoiseFilterResultProducer",1);
       treeSkim->SetBranchStatus("HBHENoiseFilterResultRun1",1);
       treeSkim->SetBranchStatus("HBHENoiseFilterResultRun2Loose",1);
       treeSkim->SetBranchStatus("HBHENoiseFilterResultRun2Tight",1);
       treeSkim->SetBranchStatus("HBHENoiseFilterResult",1);
       treeSkim->SetBranchStatus("HBHEIsoNoiseFilterResult",1);

       Int_t pcollisionEventSelection;

       if (treeSkim->GetBranch("pcollisionEventSelection")) {
           treeSkim->SetBranchAddress("pcollisionEventSelection",&pcollisionEventSelection);
       }
       else {   // overwrite to default
           pcollisionEventSelection = 1;
           std::cout<<"could not get branch : pcollisionEventSelection"<<std::endl;
           std::cout<<"set to default value : pcollisionEventSelection = "<<pcollisionEventSelection<<std::endl;
       }

       // event information
       UInt_t run, lumis;
       ULong64_t event;
       treeEvent->SetBranchAddress("run", &run);
       treeEvent->SetBranchAddress("event", &event);
       treeEvent->SetBranchAddress("lumis", &lumis);

       TFile* output = new TFile(outputFile,"RECREATE");

       TTree *configTree = setupConfigurationTreeForWriting(configCuts);

       int centBinWidth = 200/nCentralityBins;  // number of "hiBin"s that a centrality bin covers
       int vertexBinWidth = 30/nVertexBins;     // number of "vz"s    that a vertex     bin covers
       float eventPlaneBinWidth = TMath::Pi()/nEventPlaneBins;     // number of "vz"s    that a vertex     bin covers
                                                // accepted vz range is -15 to 15.

       TTree *outputTreesHLT[nCentralityBins][nVertexBins][nEventPlaneBins];
       TTree *outputTreesEvent[nCentralityBins][nVertexBins][nEventPlaneBins];
       TTree *outputTreesJet[nCentralityBins][nVertexBins][nEventPlaneBins][nJetCollections];
       TTree *outputTreesHiEvt[nCentralityBins][nVertexBins][nEventPlaneBins];
       TTree *outputTreesSkim[nCentralityBins][nVertexBins][nEventPlaneBins];

       Long64_t nEntriesFilled[nCentralityBins][nVertexBins][nEventPlaneBins];    // number of events read for a centrality bin
       for(int i=0; i<nCentralityBins; ++i)
       {
           for(int j=0; j<nVertexBins; ++j){
             for(int l=0; l<nEventPlaneBins; ++l) {

               nEntriesFilled[i][j][l] = 0;

               outputTreesHLT[i][j][l] = treeHLT->CloneTree(0);
               outputTreesHLT[i][j][l]->SetName(Form("hltTree_centBin%d_vzBin%d_evPlaneBin%d", i, j, l));
               outputTreesHLT[i][j][l]->SetTitle(Form("subbranches of hltanalysis/HltTree for centrality bin %d vz bin %d evPlane Bin %d", i, j, l));
               outputTreesHLT[i][j][l]->SetMaxTreeSize(MAXTREESIZE);

               outputTreesEvent[i][j][l] = treeEvent->CloneTree(0);
               outputTreesEvent[i][j][l]->SetName(Form("EventTree_centBin%d_vzBin%d_evPlaneBin%d", i, j, l));
               outputTreesEvent[i][j][l]->SetTitle(Form("subbranches of ggHiNtuplizer/EventTree for centrality bin %d vz bin %d evPlane Bin %d", i, j, l));
               outputTreesEvent[i][j][l]->SetMaxTreeSize(MAXTREESIZE);

               for(int k=0; k<nJetCollections; ++k){
                   std::string jetCollectionName = jetCollections.at(k).c_str();
                   outputTreesJet[i][j][l][k] = treeJets[k]->CloneTree(0);
                   outputTreesJet[i][j][l][k]->SetName(Form("%s_centBin%d_vzBin%d_evPlaneBin%d", jetCollectionName.c_str(), i, j, l));
                   outputTreesJet[i][j][l][k]->SetTitle(Form("subbranches of %s/t for centrality bin %d vz bin %d evPlane Bin %d", jetCollectionName.c_str(), i, j, l));
                   outputTreesJet[i][j][l][k]->SetMaxTreeSize(MAXTREESIZE);
               }

               outputTreesHiEvt[i][j][l] = treeHiEvt->CloneTree(0);
               outputTreesHiEvt[i][j][l]->SetName(Form("HiEvt_centBin%d_vzBin%d_evPlaneBin%d", i, j, l));
               outputTreesHiEvt[i][j][l]->SetTitle(Form("subbranches of hiEvtAnalyzer/HiTree for centrality bin %d vz bin %d evPlane Bin %d", i, j, l));
               outputTreesHiEvt[i][j][l]->SetMaxTreeSize(MAXTREESIZE);

               outputTreesSkim[i][j][l] = treeSkim->CloneTree(0);
               outputTreesSkim[i][j][l]->SetName(Form("skim_centBin%d_vzBin%d_evPlaneBin%d", i, j, l));
               outputTreesSkim[i][j][l]->SetTitle(Form("subbranches of skimanalysis/HltTree for centrality bin %d vz bin %d evPlane Bin %d", i, j, l));
               outputTreesSkim[i][j][l]->SetMaxTreeSize(MAXTREESIZE);
             }
           }
       }
//       TTree* outputTreeHiForestInfo = treeHiForestInfo->CloneTree(0);
//       outputTreeHiForestInfo->SetName("HiForestInfo");
//       outputTreeHiForestInfo->SetTitle("first entry of HiForest/HiForestInfo");
//
//       outputTreeHiForestInfo->SetMaxTreeSize(MAXTREESIZE);
//
//       // write HiForestInfo
//       treeHiForestInfo->GetEntry(0);
//       outputTreeHiForestInfo->Fill();

       EventMatcher* em = new EventMatcher();
       Long64_t duplicateEntries = 0;

       Long64_t entries = treeEvent->GetEntries();
       Long64_t entriesAnalyzed = 0;
       std::cout << "entries         = " << entries << std::endl;
       std::cout<< "Loop : ggHiNtuplizer/EventTree" <<std::endl;
       for (Long64_t j_entry=0; j_entry<entries; ++j_entry)
       {
           if (j_entry % 20000 == 0)  {
             std::cout << "current entry = " <<j_entry<<" out of "<<entries<<" : "<<std::setprecision(2)<<(double)j_entry/entries*100<<" %"<<std::endl;
           }

           treeHLT->GetEntry(j_entry);
           treeEvent->GetEntry(j_entry);
           for (int i = 0; i<nJetCollections; ++i) {
               treeJets[i]->GetEntry(j_entry);
           }
           treeHiEvt->GetEntry(j_entry);
           treeSkim->GetEntry(j_entry);

           bool eventAdded = em->addEvent(run,lumis,event,j_entry);
           if(!eventAdded) // this event is duplicate, skip this one.
           {
               duplicateEntries++;
               continue;
           }

           // event selection
           if(!(TMath::Abs(vz) < cut_vz)) continue;
           if(pcollisionEventSelection < cut_pcollisionEventSelection) continue;
           entriesAnalyzed++;

           int centBin = hiBin / centBinWidth;
           int vzBin   = (vz+15) / vertexBinWidth;
           int evplaneBin = (hiEvtPlanes[8]+(TMath::Pi()/2.)) / eventPlaneBinWidth;
          //  std::cout<<evplaneBin<< " bin " << eventPlaneBinWidth << " value " << hiEvtPlanes[8]+(TMath::Pi()/2.) << std::endl;
           if (nEntriesFilled[centBin][vzBin][evplaneBin] > nMaxEvents_minBiasMixing) continue;

           outputTreesHLT[centBin][vzBin][evplaneBin]->Fill();
           outputTreesEvent[centBin][vzBin][evplaneBin]->Fill();
           for (int i = 0; i<nJetCollections; ++i) {
               outputTreesJet[centBin][vzBin][evplaneBin][i]->Fill();
           }
           outputTreesHiEvt[centBin][vzBin][evplaneBin]->Fill();
           outputTreesSkim[centBin][vzBin][evplaneBin]->Fill();

           nEntriesFilled[centBin][vzBin][evplaneBin]++;
       }
       std::cout<<  "Loop ENDED : ggHiNtuplizer/EventTree" <<std::endl;
       std::cout << "entries            = " << entries << std::endl;
       std::cout << "duplicateEntries   = " << duplicateEntries << std::endl;
       std::cout << "entriesAnalyzed    = " << entriesAnalyzed << std::endl;

       for(int i=0; i<nCentralityBins; ++i){
           for(int j=0; j<nVertexBins; ++j){
             for(int l=0; l<nEventPlaneBins; ++l){
                 std::cout<<Form("outputTreesJet[%d][%d][%d]->GetEntries() = %lld", i, j, l, outputTreesEvent[i][j][l]->GetEntries())<<std::endl;
                 if (outputTreesEvent[i][j][l]->GetEntries() < 100) {
                     std::cout<< "Be careful : less than 100 events were put into centBin = "<<i<<" , vertexBin = "<<j<<" , EventPlaneBin = "<<l<<std::endl;
                 }
             }
          }
       }

       configTree->Write("",TObject::kOverwrite);

       output->Write("",TObject::kOverwrite);
       output->Close();

       std::cout<<"minBiasJetSkim() - END"<<std::endl;
}