int ScanChain( TChain* chain, bool fast = true, int nEvents = -1, string skimFilePrefix = "test") {

  //load PUweights
  TFile *fPU = new TFile("puWeights.root","READ");
  TH1D *puWeight     = (TH1D*)fPU->Get("puWeight");
  TH1D *puWeightUp   = (TH1D*)fPU->Get("puWeightUp");
  TH1D *puWeightDown = (TH1D*)fPU->Get("puWeightDown");

  TFile *fxsec = new TFile("xsec_stop_13TeV.root","READ");
  TH1D *hxsec     = (TH1D*)fxsec->Get("stop");

  TFile *f_el_SF       = new TFile("lepsf/kinematicBinSFele.root", "read");
  TFile *f_mu_SF_id    = new TFile("lepsf/TnP_MuonID_NUM_MediumID_DENOM_generalTracks_VAR_map_pt_eta.root", "read");
  TFile *f_mu_SF_iso   = new TFile("lepsf/TnP_MuonID_NUM_MiniIsoTight_DENOM_LooseID_VAR_map_pt_eta.root");
  TFile *f_mu_SF_veto_id  = new TFile("lepsf/TnP_MuonID_NUM_LooseID_DENOM_generalTracks_VAR_map_pt_eta.root", "read");
  TFile *f_mu_SF_veto_iso = new TFile("lepsf/TnP_MuonID_NUM_MiniIsoTight_DENOM_LooseID_VAR_map_pt_eta.root");
  //TFile *f_mu_SF_veto_iso = new TFile("lepsf/TnP_MuonID_NUM_MiniIsoLoose_DENOM_LooseID_VAR_map_pt_eta.root");
  //TFile *f_vetoLep_eff = new TFile("lepsf/lepeff__ttbar_powheg_pythia8_25ns.root", "read");
  TFile *f_vetoLep_eff = new TFile("lepsf/lepeff__ttbar_powheg_pythia8_25ns__SRcuts.root", "read");  
  TH2D *h_el_SF_id_temp      = (TH2D*)f_el_SF->Get("CutBasedMedium");
  TH2D *h_el_SF_iso_temp     = (TH2D*)f_el_SF->Get("MiniIso0p1_vs_AbsEta");
  TH2D *h_el_SF_veto_id_temp  = (TH2D*)f_el_SF->Get("CutBasedVeto");
  TH2D *h_el_SF_veto_iso_temp = (TH2D*)f_el_SF->Get("MiniIso0p4_vs_AbsEta");
  TH2D *h_mu_SF_id_temp      = (TH2D*)f_mu_SF_id->Get("pt_abseta_PLOT_pair_probeMultiplicity_bin0_&_tag_combRelIsoPF04dBeta_bin0_&_tag_pt_bin0_&_tag_IsoMu20_pass");
  TH2D *h_mu_SF_iso_temp     = (TH2D*)f_mu_SF_iso->Get("pt_abseta_PLOT_pair_probeMultiplicity_bin0_&_tag_combRelIsoPF04dBeta_bin0_&_tag_pt_bin0_&_PF_pass_&_tag_IsoMu20_pass");
  TH2D *h_mu_SF_veto_id_temp  = (TH2D*)f_mu_SF_veto_id->Get("pt_abseta_PLOT_pair_probeMultiplicity_bin0_&_tag_combRelIsoPF04dBeta_bin0_&_tag_pt_bin0_&_tag_IsoMu20_pass");
  TH2D *h_mu_SF_veto_iso_temp = (TH2D*)f_mu_SF_veto_iso->Get("pt_abseta_PLOT_pair_probeMultiplicity_bin0_&_tag_combRelIsoPF04dBeta_bin0_&_tag_pt_bin0_&_PF_pass_&_tag_IsoMu20_pass");
  //TH2D *h_el_vetoLepEff_temp = (TH2D*)f_vetoLep_eff->Get("h2_lepEff_vetoSel_Eff_el");
  //TH2D *h_mu_vetoLepEff_temp = (TH2D*)f_vetoLep_eff->Get("h2_lepEff_vetoSel_Eff_mu");
  TH2D *h_el_vetoLepEff_temp = (TH2D*)f_vetoLep_eff->Get("h2_lepEff_vetoSel_rebin_Eff_el");
  TH2D *h_mu_vetoLepEff_temp = (TH2D*)f_vetoLep_eff->Get("h2_lepEff_vetoSel_rebin_Eff_mu");
  TH2D *h_el_SF_id  = (TH2D*)h_el_SF_id_temp->Clone("h_el_SF_id");
  TH2D *h_el_SF_iso = (TH2D*)h_el_SF_iso_temp->Clone("h_el_SF_iso");
  TH2D *h_mu_SF_id  = (TH2D*)h_mu_SF_id_temp->Clone("h_mu_SF_id");
  TH2D *h_mu_SF_iso = (TH2D*)h_mu_SF_iso_temp->Clone("h_mu_SF_iso");
  TH2D *h_el_SF_veto_id  = (TH2D*)h_el_SF_veto_id_temp->Clone("h_el_SF_veto_id");
  TH2D *h_el_SF_veto_iso = (TH2D*)h_el_SF_veto_iso_temp->Clone("h_el_SF_veto_iso");
  TH2D *h_mu_SF_veto_id  = (TH2D*)h_mu_SF_veto_id_temp->Clone("h_mu_SF_veto_id");
  TH2D *h_mu_SF_veto_iso = (TH2D*)h_mu_SF_veto_iso_temp->Clone("h_mu_SF_veto_iso");
  //This is are the important ones
  TH2D *h_el_vetoLepEff = (TH2D*)h_el_vetoLepEff_temp->Clone("h_el_vetoLepEff");
  TH2D *h_mu_vetoLepEff = (TH2D*)h_mu_vetoLepEff_temp->Clone("h_mu_vetoLepEff");
  TH2D *h_el_SF = (TH2D*)h_el_SF_id->Clone("h_el_SF");
  h_el_SF->Multiply(h_el_SF_iso);
  TH2D *h_el_SF_veto = (TH2D*)h_el_SF_veto_id->Clone("h_el_SF_veto");
  TH2D *h_mu_SF = (TH2D*)h_mu_SF_id->Clone("h_mu_SF");
  h_mu_SF->Multiply(h_mu_SF_iso);
  TH2D *h_mu_SF_veto = (TH2D*)h_mu_SF_veto_id->Clone("h_mu_SF_veto");
  h_mu_SF_veto->Multiply(h_mu_SF_veto_iso);
  TFile *f_el_FS_ID       = new TFile("lepsf/sf_el_mediumCB.root", "read");
  TFile *f_el_FS_Iso      = new TFile("lepsf/sf_el_mini01.root", "read");
  TFile *f_mu_FS_ID       = new TFile("lepsf/sf_mu_mediumID.root", "read");
  TFile *f_mu_FS_Iso      = new TFile("lepsf/sf_mu_mini02.root", "read");
  TH2D *h_el_FS_ID_temp  = (TH2D*)f_el_FS_ID ->Get("histo2D");
  //TH2D *h_el_FS_ID       = (TH2D*)h_el_FS_ID_temp ->Clone("h_el_FS_ID");
  TH2D *h_el_FS          = (TH2D*)h_el_FS_ID_temp ->Clone("h_el_FS");
  TH2D *h_el_FS_Iso_temp = (TH2D*)f_el_FS_Iso->Get("histo2D");
  //TH2D *h_el_FS_Iso      = (TH2D*)h_el_FS_Iso_temp->Clone("h_el_FS_Iso");
  h_el_FS->Multiply(h_el_FS_Iso_temp);
  TH2D *h_mu_FS_ID_temp  = (TH2D*)f_mu_FS_ID ->Get("histo2D");
  //TH2D *h_mu_FS_ID       = (TH2D*)h_mu_FS_ID_temp ->Clone("h_mu_FS_ID");
  TH2D *h_mu_FS          = (TH2D*)h_mu_FS_ID_temp ->Clone("h_mu_FS");
  TH2D *h_mu_FS_Iso_temp = (TH2D*)f_mu_FS_Iso->Get("histo2D");
  //TH2D *h_mu_FS_Iso      = (TH2D*)h_mu_FS_Iso_temp->Clone("h_mu_FS_ID");
  h_mu_FS->Multiply(h_mu_FS_Iso_temp);

  
  // Benchmark
  TBenchmark *bmark = new TBenchmark();
  bmark->Start("benchmark");

  // Example Histograms
  TDirectory *rootdir = gDirectory->GetDirectory("Rint:");


  map<string, TH3D*> histos;//use D histos as weights can vary a lot among the signal
  vector<string> histonames; histonames.clear();
  //  vector<int> hbins; hbins.clear();
  //  vector<float> hlow; hlow.clear();
  //  vector<float> hup; hup.clear();

  //lumi, trigger, stats done
  histonames.push_back("SRyield");
  histonames.push_back("SR_Bup_HF");//done
  histonames.push_back("SR_Bdown_HF");
  histonames.push_back("SR_Bup_LF");//done
  histonames.push_back("SR_Bdown_LF");
  histonames.push_back("SR_JESup");
  histonames.push_back("SR_JESdown");
  histonames.push_back("SR_muRFup");
  histonames.push_back("SR_muRFdown");
  //histonames.push_back("SR_PDFup");
  //histonames.push_back("SR_PDFdown");
  histonames.push_back("SR_ISRup");//done preliminary
  histonames.push_back("SR_ISRdown");
  histonames.push_back("SR_PUup");//done preliminary
  histonames.push_back("SR_PUdown");
  histonames.push_back("SR_LepEffup");//done - I guess we need no renormalization - no fastsim in, no vetoSF
  histonames.push_back("SR_LepEffdown");
  histonames.push_back("SR_LepEffFSup");//done - I guess we need no renormalization - no fastsim in, no vetoSF
  histonames.push_back("SR_LepEffFSdown");
  histonames.push_back("SR_Xsecup");//done
  histonames.push_back("SR_Xsecdown");
  histonames.push_back("CR1l_sigcontamination");//scaled to signalreg yield
  histonames.push_back("CR2l_sigcontamination");//scaled to signalreg yield
  /*
  histonames.push_back("eventsum");
  histonames.push_back("rawweightsum");
  histonames.push_back("totweightsum");
  histonames.push_back("ISRsum");
  histonames.push_back("BSFsum");
  histonames.push_back("PUweightsum");
  histonames.push_back("xsecsum");
  histonames.push_back("nevtsum");
  histonames.push_back("lepsum");
  histonames.push_back("lepSFsum");
  */
  for(unsigned int i = 0; i<histonames.size(); ++i){
    string mapname = histonames[i];
    if(histos.count(mapname) == 0 ) histos[mapname] = new TH3D(mapname.c_str(), "", 37,99,1024, 19,-1,474, 13, -0.5,12.5);
    //mStop 100-1000, mLSP 0-450, SR 1-12, 9200 bins, SR 0 is non-SR - in case it it needed!!
      histos[mapname]->Sumw2(); histos[mapname]->SetDirectory(rootdir);
    }

  
  
  // Loop over events to Analyze
  unsigned int nEventsTotal = 0;
  unsigned int nEventsChain = chain->GetEntries();
  if( nEvents >= 0 ) nEventsChain = nEvents;
  TObjArray *listOfFiles = chain->GetListOfFiles();
  TIter fileIter(listOfFiles);
  TFile *currentFile = 0;

  //get the reweighting histograms
  TIter fileIterFirst(listOfFiles);
  TFile *currentFileFirst = 0;
  TH3D* counterhistSig;
  TH2F* histNEvts;
  bool thisisfirst = true;
  // File Loop for adding correct histograms
  while ( (currentFileFirst = (TFile*)fileIterFirst.Next()) ) {
    TFile *file = new TFile( currentFileFirst->GetTitle() );
    file->cd();
    if(thisisfirst){
      counterhistSig = (TH3D*)file->Get("h_counterSMS");
      counterhistSig->SetDirectory(0); 
      histNEvts = (TH2F*)file->Get("histNEvts");
      histNEvts->SetDirectory(0);
      thisisfirst = false;
    } else {
      TH3D *tempcounterhistSig = (TH3D*)file->Get("h_counterSMS");
      tempcounterhistSig->SetDirectory(0); 
      TH2F *temphistNEvts = (TH2F*)file->Get("histNEvts");
      temphistNEvts->SetDirectory(0);
      counterhistSig->Add(tempcounterhistSig);
      histNEvts->Add(temphistNEvts);
      tempcounterhistSig->Delete();
      temphistNEvts->Delete();
    }
    file->Close();
    delete file;
  }

  // File Loop
  while ( (currentFile = (TFile*)fileIter.Next()) ) {

    // Get File Content
    TFile *file = new TFile( currentFile->GetTitle() );
    TTree *tree = (TTree*)file->Get("t");
    if(fast) TTreeCache::SetLearnEntries(10);
    if(fast) tree->SetCacheSize(128*1024*1024);
    cms3.Init(tree);
    
    // Loop over Events in current file
    if( nEventsTotal >= nEventsChain ) continue;
    unsigned int nEventsTree = tree->GetEntriesFast();
    for( unsigned int event = 0; event < nEventsTree; ++event) {
 
      // Get Event Content
      if( nEventsTotal >= nEventsChain ) continue;
      if(fast) tree->LoadTree(event);
      cms3.GetEntry(event);
      ++nEventsTotal;
    
      // Progress
      CMS3::progress( nEventsTotal, nEventsChain );

      // Analysis Code

      float mStop = mass_stop();
      float mLSP = mass_lsp();
      float mCharg = mass_chargino();
      //float xVal = mass_lsp();
      int Nevts = histNEvts->GetBinContent(histNEvts->FindBin(mStop,mLSP));
      double nevts = double(Nevts);
      //float weight = cms3.scale1fb()*2.11;
      double PUweight     = puWeight    ->GetBinContent(puWeight    ->FindBin(pu_ntrue() ) );
      double PUweightUp   = puWeightUp  ->GetBinContent(puWeightUp  ->FindBin(pu_ntrue() ) );
      double PUweightDown = puWeightDown->GetBinContent(puWeightDown->FindBin(pu_ntrue() ) );
      PUweightUp = 1; PUweightDown = PUweight; PUweight = 1; //now PU syst is applying vs not applying
     double ISRnorm = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,19));
      double ISRnormup = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,20));
      double ISRnormdown = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,21));
      double ISRweight = weight_ISR();
      double BSFnorm = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,14));
      double BSFnormHup = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,15));
      double BSFnormLup = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,16));
      double BSFnormHdown = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,17));
      double BSFnormLdown = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,18));
      double BSFweight = weight_btagsf();
      double muRFnorm = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,1));
      double muRFnormup = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,5));
      double muRFnormdown = counterhistSig->GetBinContent(counterhistSig->FindBin(mStop,mLSP,9));
      if(ISRnorm>0) ISRweight*=nevts/ISRnorm;
      if(ISRnorm<=0||ISRnormup<=0||ISRnormdown<=0){ ISRnormdown=1.; ISRnormup=1.; ISRnorm=1.;}
      if(ISRweight!=weight_ISR()) cout << "ISRw " << ISRweight << " wISR " << weight_ISR() << " nevts " << nevts << " ISRn " << ISRnorm << endl;
      if(BSFnorm>0) BSFweight *=nevts/BSFnorm;
      if(BSFnorm<=0||BSFnormHup<=0||BSFnormLup<=0||BSFnormHdown<=0||BSFnormLdown<=0){
	BSFnorm=1; BSFnormHup=1; BSFnormLup=1; BSFnormHdown=1; BSFnormLdown=1;
      }
      if(muRFnorm<=0||muRFnormup<=0||muRFnormdown<=0){ muRFnormdown=1; muRFnormup=1; muRFnorm=1; }
      //lepSF is done below
      double xsection = hxsec->GetBinContent(hxsec->FindBin(mStop));
      double xsectionerr = hxsec->GetBinError(hxsec->FindBin(mStop));
      //double rawweight = xsec()*2260./nevts;
      //double weight = xsec()*2260./nevts*PUweight*ISRweight*BSFweight;//xsec given in pb
      double rawweight = xsection*2260./nevts;
      double weight = xsection*2260./nevts*PUweight*ISRweight*BSFweight;//xsec given in pb
      //did put ISRweight which should be ==1
      if(ISRweight!=1) cout << "ISRw " << ISRweight << endl;
      if(event==0) cout << "weight " << weight << " nEvents " << nEventsTree << " filename " << currentFile->GetTitle() << endl;

      int NSLeps = 0;
      int NAddVetoLeps = 0;
      if(lep1_is_mu()){
	if(lep1_pt()>20&&fabs(lep1_eta())<2.4) {++NSLeps;}
      } else if (lep1_is_el()){
	if(lep1_pt()>20&&fabs(lep1_eta())<1.4442) {++NSLeps; }
      } if(lep2_is_mu()){
	if(lep2_pt()>20&&fabs(lep2_eta())<2.4) {++NSLeps;}
      } else if (lep2_is_el()){
	if(lep2_pt()>20&&fabs(lep2_eta())<1.4442) {++NSLeps; }
      }
      if(lep2_is_mu()){
	if(lep2_pt()>10&&fabs(lep2_eta())<2.4) {++NAddVetoLeps;}
      } else if (lep2_is_el()){
	if(lep2_pt()>10&&fabs(lep2_eta())<2.4) {++NAddVetoLeps; }
      }
      if(NSLeps<1) continue;//temp
      float lepSF_pt_cutoff = 100.0;
      float lepSF_pt_min    = 10.0;
      double lepSF    = 1.0;
      double lepSF_Up = 1.0;
      double lepSF_Dn = 1.0;
      float lepSF_FS_pt_cutoff = 200.0;
      double lepSF_FS    = 1.0;
      double lepSF_FS_Up = 1.0;
      double lepSF_FS_Dn = 1.0;	
      if(lep1_is_el()){
	int binX = h_el_SF->GetXaxis()->FindBin( std::min(lepSF_pt_cutoff, (float)lep1_p4().Pt()) );
	int binY = h_el_SF->GetYaxis()->FindBin( fabs(lep1_p4().Eta()) );
	lepSF    = h_el_SF->GetBinContent( binX, binY );
	lepSF_Up = lepSF + h_el_SF->GetBinError( binX, binY );
	lepSF_Dn = lepSF - h_el_SF->GetBinError( binX, binY );
	int bin = h_el_FS->FindBin(  std::min(lepSF_FS_pt_cutoff, (float)lep1_p4().Pt()), fabs(lep1_p4().Eta()) );
	lepSF_FS = h_el_FS->GetBinContent(bin);
	lepSF_FS_Up = lepSF_FS + h_el_FS->GetBinError(bin);
	lepSF_FS_Dn = lepSF_FS + h_el_FS->GetBinError(bin);
      }
      if(lep1_is_mu()){
	int binX = h_mu_SF->GetXaxis()->FindBin( std::min(lepSF_pt_cutoff, (float)lep1_p4().Pt()) );
	int binY = h_mu_SF->GetYaxis()->FindBin( fabs(lep1_p4().Eta()) );
	lepSF    = h_mu_SF->GetBinContent( binX, binY );
	lepSF_Up = lepSF + h_mu_SF->GetBinError( binX, binY );
	lepSF_Dn = lepSF - h_mu_SF->GetBinError( binX, binY );
	int bin = h_mu_FS->FindBin(  std::min(lepSF_FS_pt_cutoff, (float)lep1_p4().Pt()), fabs(lep1_p4().Eta()) );
	lepSF_FS = h_mu_FS->GetBinContent(bin);
	lepSF_FS_Up = lepSF_FS + h_mu_FS->GetBinError(bin);
	lepSF_FS_Dn = lepSF_FS + h_mu_FS->GetBinError(bin);
      }
      weight *= (lepSF*lepSF_FS);

      
      if(nvtxs()<0)               continue;
      if(ngoodleps()<1)           continue;//accomodate 2l-CR
      if(nvetoleps()<1)           continue;//accomodate 2l-CR
    //if(!PassTrackVeto_v3())     continue;//accomodate 2l-CR
    //if(!PassTauVeto())          continue;//accomodate 2l-CR
      if(ngoodjets()<2)           continue;
      if(ngoodbtags()<0)          continue;//accomodate 1l-CR
      if(pfmet()<250)             continue;
      if(mt_met_lep()<150)        continue;
      if(mindphi_met_j1_j2()<0.8) continue;


      int SR = -1;
      int compressedSR = -1;
      if(ngoodleps()==1&&nvetoleps()==1&&PassTrackVeto_v3()&&PassTauVeto()&&ngoodbtags()>=1){//basis for SR 1l, >=1b
	if(ngoodjets()>=4){
	  if(MT2W()<=200){
	    if(pfmet()>325) SR = 2;
	    else SR = 1;
	  } else { //high MT2W
	    if(pfmet()>450) SR = 5;
	    else if(pfmet()>350) SR = 4;
	    else SR = 3;
	  }
	} else if(ngoodjets()==3 && MT2W()>200 && pfmet()>350) {
	  SR = 6;
	} else if(MT2W()>200&&topnessMod()>(-3)) { //2 or 3 jets
	  if(ngoodbtags()==1){
	    if(pfmet()>400) SR = 8;
	    else SR = 7;
	  } else {//ge2 jets
	    if(pfmet()>400) SR = 10;
	    else SR = 9;
	  }
	}
	//compressed region (jets are sorted by pt
	if(ngoodjets()>=5&&ak4pfjets_passMEDbtag()[0]==false&&ak4pfjets_pt()[0]>200.){
	  if(MT2W()<=200) compressedSR = 11;
	  else compressedSR = 12;
	}
      }

      //CR-1l
      int CR1l = -1;
      if(ngoodleps()==1&&nvetoleps()==1&&PassTrackVeto_v3()&&PassTauVeto()&&ngoodbtags()==0&&ngoodjets()>=3&&MT2W()>200){
	if(ngoodjets()==3){
	  CR1l = 1;
	} else {
	  CR1l = 2;
	}
      }
      //CR1l  1 --> SR  6
      //CR1l  2 --> SR  3-5
      float CR1l_1_6 = 0.37*0.18;
      float CR1l_2_3 = 0.55*0.15;
      float CR1l_2_4 = 0.25*0.29;
      float CR1l_2_5 = 0.20*0.40;

      //CR2l = -1;
      int lepind = -1;
      if(ngoodleps()>=2&&NSLeps==2) lepind = 5;
      else if(ngoodleps()==2&&NSLeps==2) lepind = 4;//exactly two leptons,CR4
      else if(ngoodleps()==1&&NSLeps==1&&NAddVetoLeps>=1) lepind = 3;//one lepton, but more than 1 add. loose,1l,>2l
      //else if(ngoodleps()==1&&NSLeps==1&&nvetoleps()==2) lepind = 2;//one lepton + 1 add. loose,CR5
      else if(ngoodleps()==1&&NSLeps==1&&nvetoleps()==0&&(!PassTrackVeto_v3()||!PassTauVeto())) lepind = 1;//exactly one lepton, but do not pass track/tau veto - i.e. one additional track or tau, CR6
      int CR2l = -1;
      if((lepind==4||lepind==3||lepind==1)&&ngoodjets()>=3&&ngoodbtags()>=1){
	if(MT2W()<=200) CR2l = 1;
	else CR2l = 2;
      }
      float CR2l_1_1 = 0.61*0.48;
      float CR2l_1_2 = 0.61*0.19;
      float CR2l_2_3 = 0.44*0.39;
      float CR2l_2_4 = 0.44*0.11;
      float CR2l_2_5 = 0.44*0.07;
      float CR2l_2_6 = 0.44*0.11;

      if(SR==(-1)&&CR1l==(-1)&&CR2l==(-1)&&compressedSR==(-1)) continue;
      //implement some sanity checks
      if(CR1l!=(-1)&&CR2l!=(-1)) cout << "WTF CR1l " << CR1l << " CR2l " << CR2l << endl;
      if(SR!=(-1)&&CR1l!=(-1)) cout << "WTF SR " << SR << " CR1l " << CR1l << endl;
      if(SR!=(-1)&&CR2l!=(-1)) cout << "WTF SR " << SR << " CR2l " << CR2l << endl;

      //ISR reweighting, get stop pair using last copy:
      double ISRup = weight_ISRup()/weight_ISR()*ISRnorm/ISRnormup;
      double ISRdown = weight_ISRdown()/weight_ISR()*ISRnorm/ISRnormdown;
      //double XSup = (xsec()+xsec_uncert())/xsec();
      //double XSdown = (xsec()-xsec_uncert())/xsec();
      double XSup = (xsection+xsectionerr)/xsection;
      double XSdown = (xsection-xsectionerr)/xsection;
      double PUup = PUweightUp/PUweight;
      double PUdown = PUweightDown/PUweight;
      double lEffup = lepSF_Up/lepSF;
      double lEffdown = lepSF_Dn/lepSF;
      double lEffFSup = lepSF_FS_Up/lepSF_FS;
      double lEffFSdown = lepSF_FS_Dn/lepSF_FS;
      double BSFHup = weight_btagsf_heavy_UP()/weight_btagsf()*BSFnorm/BSFnormHup;
      double BSFLup = weight_btagsf_light_UP()/weight_btagsf()*BSFnorm/BSFnormHup;
      double BSFHdown = weight_btagsf_heavy_DN()/weight_btagsf()*BSFnorm/BSFnormHup;
      double BSFLdown = weight_btagsf_light_DN()/weight_btagsf()*BSFnorm/BSFnormHup;
      double muRFup = genweights().at(4)/genweights().at(0)*muRFnorm/muRFnormup;
      double muRFdown = genweights().at(8)/genweights().at(0)*muRFnorm/muRFnormdown;
      //cout << genweights().at(0) << " " << genweights().at(4) << " " << genweights().at(8) << " " << mStop << " " << mLSP << endl;

      if(CR1l>0){
	if(ngoodleps()!=1) cout << __LINE__ << " " << ngoodleps() << endl;
	if(NSLeps!=1) cout << __LINE__ << " " << NSLeps << endl;
	if(nvetoleps()!=1) cout << __LINE__ << " " << nvetoleps() << endl;
	if(ngoodbtags()>=1) cout << __LINE__ << " " << ngoodbtags() << endl;
	//signal contamination in 0b control region, do correlations later during datacard making
	if(CR1l==1){
	  histos["CR1l_sigcontamination"]->Fill(mStop,mLSP,6,weight*CR1l_1_6);
	} else if(CR1l==2){
	  histos["CR1l_sigcontamination"]->Fill(mStop,mLSP,3,weight*CR1l_2_3);
	  histos["CR1l_sigcontamination"]->Fill(mStop,mLSP,4,weight*CR1l_2_4);
	  histos["CR1l_sigcontamination"]->Fill(mStop,mLSP,5,weight*CR1l_2_5);
	}
      } else if(CR2l>0){
	if(nvetoleps()<=1||(nvetoleps()==1&&(!PassTrackVeto_v3()||!PassTauVeto()))) cout << __LINE__ << " " << nvetoleps() << " " << PassTrackVeto_v3() << " " << PassTauVeto() << endl;
	if(ngoodbtags()<1) cout << __LINE__ << " " << ngoodbtags() << endl;
	//signal contamination in 2l control region, do correlations later during datacard making
	if(CR2l==1){
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,1,weight*CR2l_1_1);
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,2,weight*CR2l_1_2);
	} else if(CR2l==2){
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,3,weight*CR2l_2_3);
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,4,weight*CR2l_2_4);
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,5,weight*CR2l_2_5);
	  histos["CR2l_sigcontamination"]->Fill(mStop,mLSP,6,weight*CR2l_2_6);

	}
      } else if(SR>0){
	if(ngoodleps()!=1) cout << __LINE__ << " " << ngoodleps() << endl;
	if(NSLeps!=1) cout << __LINE__ << " " << NSLeps << endl;
	if(nvetoleps()!=1) cout << __LINE__ << " " << nvetoleps() << endl;
	if(!PassTrackVeto_v3())  cout << __LINE__ << endl;
	if(!PassTauVeto())  cout << __LINE__ << endl;
	if(SR<=6&&ngoodjets()<3) cout << __LINE__ << " " << ngoodjets() << endl;
	if(ngoodbtags()<1) cout << __LINE__ << " " << ngoodbtags() << endl;
	/*
	histos["eventsum"]->Fill(mStop,mLSP,SR,1.);
	histos["rawweightsum"]->Fill(mStop,mLSP,SR,rawweight);
	histos["totweightsum"]->Fill(mStop,mLSP,SR,weight);
	histos["ISRsum"]->Fill(mStop,mLSP,SR,ISRweight);
	histos["BSFsum"]->Fill(mStop,mLSP,SR,BSFweight);
	histos["PUweightsum"]->Fill(mStop,mLSP,SR,PUweight);
	histos["xsecsum"]->Fill(mStop,mLSP,SR,xsection);
	histos["nevtsum"]->Fill(mStop,mLSP,SR,nevts);
	histos["lepsum"]->Fill(mStop,mLSP,SR,lepSF);
	histos["lepSFsum"]->Fill(mStop,mLSP,SR,lepSF_FS);
	*/
	//finally - do signal regions!
	histos["SRyield"]->Fill(mStop,mLSP,SR,weight);
	histos["SR_ISRup"]->Fill(mStop,mLSP,SR,weight*ISRup);
	histos["SR_ISRdown"]->Fill(mStop,mLSP,SR,weight*ISRdown);
	histos["SR_Xsecup"]->Fill(mStop,mLSP,SR,weight*XSup);
	histos["SR_Xsecdown"]->Fill(mStop,mLSP,SR,weight*XSdown);
	histos["SR_PUup"]->Fill(mStop,mLSP,SR,weight*PUup);
	histos["SR_PUdown"]->Fill(mStop,mLSP,SR,weight*PUdown);
	histos["SR_Bup_HF"]->Fill(mStop,mLSP,SR,weight*BSFHup);
	histos["SR_Bup_LF"]->Fill(mStop,mLSP,SR,weight*BSFLup);
	histos["SR_Bdown_HF"]->Fill(mStop,mLSP,SR,weight*BSFHdown);
	histos["SR_Bdown_LF"]->Fill(mStop,mLSP,SR,weight*BSFLdown);
	histos["SR_LepEffup"]->Fill(mStop,mLSP,SR,weight*lEffup);
	histos["SR_LepEffdown"]->Fill(mStop,mLSP,SR,weight*lEffdown);
	histos["SR_LepEffFSup"]->Fill(mStop,mLSP,SR,weight*lEffFSup);
	histos["SR_LepEffFSdown"]->Fill(mStop,mLSP,SR,weight*lEffFSdown);
	histos["SR_muRFup"]->Fill(mStop,mLSP,SR,weight*muRFup);
	histos["SR_muRFdown"]->Fill(mStop,mLSP,SR,weight*muRFdown);
      }
      if(compressedSR>0){
	if(compressedSR<=6) cout << __LINE__ << " " << compressedSR << endl;
	//compressedSR is defined to not overlap with SR - can use same histogram!
	histos["SRyield"]->Fill(mStop,mLSP,compressedSR,weight);
	histos["SR_ISRup"]->Fill(mStop,mLSP,compressedSR,weight*ISRup);
	histos["SR_ISRdown"]->Fill(mStop,mLSP,compressedSR,weight*ISRdown);
	histos["SR_Xsecup"]->Fill(mStop,mLSP,compressedSR,weight*XSup);
	histos["SR_Xsecdown"]->Fill(mStop,mLSP,compressedSR,weight*XSdown);
	histos["SR_PUup"]->Fill(mStop,mLSP,compressedSR,weight*PUup);
	histos["SR_PUdown"]->Fill(mStop,mLSP,compressedSR,weight*PUdown);
	histos["SR_Bup_HF"]->Fill(mStop,mLSP,compressedSR,weight*BSFHup);
	histos["SR_Bup_LF"]->Fill(mStop,mLSP,compressedSR,weight*BSFLup);
	histos["SR_Bdown_HF"]->Fill(mStop,mLSP,compressedSR,weight*BSFHdown);
	histos["SR_Bdown_LF"]->Fill(mStop,mLSP,compressedSR,weight*BSFLdown);
	histos["SR_LepEffup"]->Fill(mStop,mLSP,compressedSR,weight*lEffup);
	histos["SR_LepEffdown"]->Fill(mStop,mLSP,compressedSR,weight*lEffdown);
	histos["SR_LepEffFSup"]->Fill(mStop,mLSP,compressedSR,weight*lEffFSup);
	histos["SR_LepEffFSdown"]->Fill(mStop,mLSP,compressedSR,weight*lEffFSdown);
	histos["SR_muRFup"]->Fill(mStop,mLSP,compressedSR,weight*muRFup);
	histos["SR_muRFdown"]->Fill(mStop,mLSP,compressedSR,weight*muRFdown);
      }

    }//event loop
  
    // Clean Up
    delete tree;
    file->Close();
    delete file;
  }//file loop
  if ( nEventsChain != nEventsTotal ) {
    cout << Form( "ERROR: number of events from files (%d) is not equal to total number of events (%d)", nEventsChain, nEventsTotal ) << endl;
  }
  
  // Example Histograms
  // samplehisto->Draw();

  /*
  for(map<string,TH3D*>::iterator h=histos.begin(); h!=histos.end();++h){
    //add overflow
    //h->second->SetBinContent(h->second->GetNbinsX(), h->second->GetBinContent(h->second->GetNbinsX() )+ h->second->GetBinContent(h->second->GetNbinsX()+1) );
    //h->second->SetBinError(h->second->GetNbinsX(), sqrt(pow(h->second->GetBinError(h->second->GetNbinsX() ),2)+pow(h->second->GetBinError(h->second->GetNbinsX()+1),2) ) );
    //add underfloe
    //h->second->SetBinContent(1, h->second->GetBinContent(1)+ h->second->GetBinContent(0) );
    //h->second->SetBinError(1, sqrt(pow(h->second->GetBinError(1),2)+pow(h->second->GetBinError(0),2) ) );
  }
  */
  string filename = "rootfiles/signalyields/Histos_"+skimFilePrefix+".root";
  TFile *f = new TFile(filename.c_str(),"RECREATE");
  f->cd();
  for(map<string,TH3D*>::iterator h=    histos.begin(); h!=    histos.end();++h) h->second->Write();
  f->Close();
  cout << "Saved histos in " << f->GetName() << endl;

  f_el_SF->Close();
  f_mu_SF_id->Close();
  f_mu_SF_iso->Close();
  f_mu_SF_veto_id->Close();
  f_mu_SF_veto_iso->Close();
  f_vetoLep_eff->Close();
  f_el_FS_ID->Close();
  f_el_FS_Iso->Close();
  f_mu_FS_ID->Close();
  f_mu_FS_Iso->Close();
  // return
  bmark->Stop("benchmark");
  cout << endl;
  cout << nEventsTotal << " Events Processed" << endl;
  cout << "------------------------------" << endl;
  cout << "CPU  Time:	" << Form( "%.01f", bmark->GetCpuTime("benchmark")  ) << endl;
  cout << "Real Time:	" << Form( "%.01f", bmark->GetRealTime("benchmark") ) << endl;
  cout << endl;
  delete bmark;
  delete fPU;//delete PU file
  delete f_el_SF;
  delete f_mu_SF_id;
  delete f_mu_SF_iso;
  delete f_mu_SF_veto_id;
  delete f_mu_SF_veto_iso;
  delete f_vetoLep_eff;
  delete f_el_FS_ID;
  delete f_el_FS_Iso;
  delete f_mu_FS_ID;
  delete f_mu_FS_Iso;
  return 0;
}
void RPCChambersCluster::variousStudyExperimentalFunction(TFile * fileToSave,TH1F * histo[10],const int & eventNum){
  
  // Save file is used to save all the reconstructed graphs with tracks in order to inspect them
  
  RPCChamber * currentChamberObj;
  RPCChamber * triggerObj;
  RPCLinkBoardChannel * currentChannelObj;
  int numberOfChambers = this->getNumberOfChambers();
  triggerObj = this->getTriggerObjectNumber(1);
  TGraphErrors * graphToFit;
  //currentChamberObj = this->getChamberNumber(1);
  int numberOfReferenceChambers = 0; // change this value for the three cases - CERN, Ghent and BARC
  vector<int> tempCluster;
  
  TH1F * hist1,* hist2,* hist3,* hist4, * numberOfClustersHisto, * topMinusEachChamberAvg, * bottomMinusEachChamberAvg,*clsSize ,
  * numberOfClustersInSamePartitions, * histClustersPartitionDistr, * SingleMultiHits;
  
  hist1 = histo[0];
  hist2 = histo[1];
  hist3 = histo[2];
  hist4 = histo[3];
  numberOfClustersHisto = histo[4];
  topMinusEachChamberAvg = histo[5];
  bottomMinusEachChamberAvg = histo[6];
  clsSize = histo[7];
  histClustersPartitionDistr = histo[8];
  SingleMultiHits = histo[9];
  
  int timeReference = 0;
  int timeWindow = 0;
  int firstScintilatorTime = 0 ;
  int secondScintilatorTime = 0;
  int difference_reference = 0;
  int coincidence_time = 0 ;
  if (triggerObj->getChannel(32)->hasHit()){
    coincidence_time = triggerObj->getChannel(32)->getHits().at(0);
  }
  
  ESiteFileType siteType = kIsCERNrawFile; // later make the method to take file type argument and to use it in here
  
  //TH1F * firstTriggerEntries  = new TH1F("ScintStats1","ScintStats1",0,500,500);
  //firstTriggerEntries->SetLineColor(kBlue);
  //firstTriggerEntries->SetFillColor(kBlue);
  
  switch (siteType) 
  {
    case kIsCERNrawFile:
      
      timeWindow = 500;
      
      numberOfReferenceChambers = 3;
      
      int countTwoHits=0;
      for (int i = 0 ; i < 13 ; i++){
	if(triggerObj->getChannel(i+1)->hasHit() ){
	  
	  if ( difference_reference == 0 || ( coincidence_time - triggerObj->getChannel(i+1)->getHits().at(0) ) < difference_reference ) {
	    
	    difference_reference = coincidence_time - triggerObj->getChannel(i+1)->getHits().at(0);
	    firstScintilatorTime = triggerObj->getChannel(i+1)->getHits().at(0);
	    
	  }
	}
      }
      
      difference_reference = 0;
      
      for (int i = 13 ; i < 31 ; i++) {
	if(triggerObj->getChannel(i+1)->hasHit() ){
	  
	  if ( difference_reference == 0 || ( coincidence_time - triggerObj->getChannel(i+1)->getHits().at(0) ) < difference_reference ) {
	    
	    difference_reference = coincidence_time - triggerObj->getChannel(i+1)->getHits().at(0);
	    secondScintilatorTime = triggerObj->getChannel(i+1)->getHits().at(0);
	    
	  }
	}
      }
      
      //timeReference = timeReference/2;
      /*
    case kIsGENTrawFile:
      timeWindow = 20;
      for(int i = 0 ; i < 32 ; i++){
	if(triggerObj->getChannel(i+1)->hasHit()) {
	  triggerObj->getChannel(i+1)->getHits().at(0);
	}
	break;
      }
    case kIsBARCrawFile:
      timeWindow = 0; 
      timeReference = 0;
      */
      
  }
  
  timeReference = (firstScintilatorTime+secondScintilatorTime)/2;
  
  //cout << " time reference : " << timeReference << endl;
  //cout << " trigger entries : ";
  for (int i=0; i < 32 ; i++){
    if (triggerObj->getChannel(i+1)->hasHit()){
//       cout << " trig channel : " << i+1 << " " << triggerObj->getChannel(i+1)->getHits().at(0) << " ";
    }
  }
  
  cout << endl;
//   cout << " most close trigger entries : top " << firstScintilatorTime << " bottom : " << secondScintilatorTime;
//   cout << endl;
  
  
  hist1->Fill(abs(firstScintilatorTime-secondScintilatorTime));
  hist2->Fill(coincidence_time - firstScintilatorTime);
  hist3->Fill(coincidence_time - secondScintilatorTime);
  
//   cout << "difference : " << firstScintilatorTime-secondScintilatorTime << endl;
  
  for (int totalChambers = 0 ; totalChambers < numberOfChambers ; totalChambers++){
    
    currentChamberObj = this->getChamberNumber(totalChambers+1);
     cout << "Chamber " << totalChambers+1 ;
    for (int j=0 ; j < 96 ;j++){
      
      currentChamberObj = this->getChamberNumber(totalChambers+1);
      currentChannelObj = currentChamberObj->getChannel(j+1);      
      if (currentChannelObj->hasHit()){
 	cout << " channel " << currentChannelObj->getOnlineNumber() << " time " << currentChannelObj->getHits().at(0);
      }
    }
     cout << endl;
    currentChamberObj->findAllClustersForTriggerTimeReferenceAndTimeWindow(timeReference,timeWindow);    
    // now check the clusterization methods
    // fill number of cluster when there is at least one
    if(currentChamberObj->getNumberOfClusters()){
      numberOfClustersHisto->Fill(currentChamberObj->getNumberOfClusters());
    }
  }
  
  cout << "-------------------" << endl;
//   cout << "Check new cluster methods" << endl;
  
  
  for (int totalChambers = 0 ; totalChambers < numberOfChambers ; totalChambers++){
    
    currentChamberObj = this->getChamberNumber(totalChambers+1);
//     cout << "Chamber " << totalChambers+1 ;
    for (int i = 0 ; i < currentChamberObj->getNumberOfClusters() ; i++){
      
      // make the difference to get the tolerance within one cluster 
      
      int smallestTime = 0;
      int biggestTime = 0;
      int currentValue = 0;
      int sizeOfCurrentCluster = currentChamberObj->getClusterNumber(i+1).size();
      tempCluster = currentChamberObj->getClusterNumber(i+1);
      int numberOfHits = 0 ;
      for (int j = 0 ; j < sizeOfCurrentCluster; j++){
	// Fill the size here
	SingleMultiHits->Fill(currentChamberObj->getStrip(tempCluster.at(j))->getHits().size());
	
      }
      
      clsSize->Fill(sizeOfCurrentCluster);
      
      for (int j = 0 ; j < sizeOfCurrentCluster ; j++ ){
	
	currentValue = currentChamberObj->getStripsHitsTimesForCluster(i+1).at(j);
	
	if ( j == 0 ) {
	  // init the values
	  smallestTime = currentChamberObj->getStripsHitsTimesForCluster(i+1).at(j);
	  biggestTime = currentChamberObj->getStripsHitsTimesForCluster(i+1).at(j);
	}
	else{
	  
	  if ( smallestTime >= currentValue ){
	    smallestTime = currentValue;
	  }
	  if( biggestTime <= currentValue){
	    biggestTime = currentValue;
	  } 
	}
      }
      
      if (biggestTime - smallestTime != 0){
	hist4->Fill(biggestTime-smallestTime);
      }
      int avgTimeForCluster = currentChamberObj->getAverageTimeForCluster(i+1);
      topMinusEachChamberAvg->Fill(abs(firstScintilatorTime - avgTimeForCluster));
      bottomMinusEachChamberAvg->Fill(abs(secondScintilatorTime - avgTimeForCluster));
      
//       cout << endl << "Cluster " << i+1 << " toptime " << biggestTime << " leasttime " << smallestTime ;
      
    }
    
//     cout << endl;
  }
  
//   cout << "-------Second check done-----------" << endl;
  
  // try with single cluster per chamber 
  
  vector<int> vectorOfReferenceChambers;
  
  for (int i=0; i < this->getNumberOfChambers() ; i ++){
    currentChamberObj = this->getChamberNumber(i+1);
    if (currentChamberObj->isReferenceChamber() && !currentChamberObj->getNumberOfClusters()){
      // the reference chamber does not have a hit (cluster), probably inefficient (or else) , skip the execution
      
      break;
    }
  }
  
  // remove the following when the configuration object is introduced // done, change the implementation
  vectorOfReferenceChambers.push_back(1); vectorOfReferenceChambers.push_back(4); vectorOfReferenceChambers.push_back(6);
  
  /** Determination of track starts here */ // Move this part in separated method 
  
  //TFile * goodTracks = new TFile("GoodTracks.root","UPDATE");
  //TFile * badTracks = new TFile("BadTracks.root","UPDATE");
  int globalCount = 1;
  for ( int i = 0 ; i < this->getChamberNumber(vectorOfReferenceChambers[0])->getNumberOfClusters() ; i++ ){
    for( int j = 0 ; j < this->getChamberNumber(vectorOfReferenceChambers[1])->getNumberOfClusters() ; j++ ){
      for( int k = 0 ; k < this->getChamberNumber(vectorOfReferenceChambers[2])->getNumberOfClusters() ; k++ ){
	
	// check the multiplicity. use 5 as upper limit number
	// with the test run 2202 - CERN channel 33 is noisy so there is a condition only for it here TO DO - remove the channel 33 condition // old function
	
	/** Hits : first , use the time to distinguish useless crap - like noisy channels 
	 *  
	 * 2. Check the partition plane (YZ plane) for vertical tracks. If the track is vertical don't search for consecutiveness and don't fill the YZ histo
	 * 3. Check the partitions plane for consecutiveness - one could not expect track that passes 3 -> 1 -> 3 partitions
	 * 
	*/ 
	
	if(this->getChamberNumber(vectorOfReferenceChambers[0])->getSizeOfCluster(i+1) > 5 ||
	  this->getChamberNumber(vectorOfReferenceChambers[1])->getSizeOfCluster(j+1) > 5 ||
	  this->getChamberNumber(vectorOfReferenceChambers[2])->getSizeOfCluster(k+1) > 5
	  ) continue;
	
	// the partition logic start  here - track could pass more than one partition
	int direction = 0 ; // direction should describe how the partition changes from one reference chamber to another. It 
	int RefChamberClusterPartition[3] ;
	int currentDifference = 0;
	bool positive = false;
	bool negative = false;
	int partitionPenetrated = 1;
	// the Y coordinate is the partition number ( 1 2 or 3 - A B or C)
	
	RefChamberClusterPartition[0] = this->getChamberNumber(vectorOfReferenceChambers[0])->getXYCoordinatesOfCluster(i+1).at(1);
	RefChamberClusterPartition[1] = this->getChamberNumber(vectorOfReferenceChambers[1])->getXYCoordinatesOfCluster(j+1).at(1);
	RefChamberClusterPartition[2] = this->getChamberNumber(vectorOfReferenceChambers[2])->getXYCoordinatesOfCluster(k+1).at(1);
	
	for ( int ii = 0; ii < 2 ; ii++ ){
	  direction = (RefChamberClusterPartition[ii] - RefChamberClusterPartition[ii+1]);
	  if (direction != 0) { 
	    direction = direction/abs(direction); 
	    partitionPenetrated++;
	  } // get only the sign ( +1 or -1)
	  if (direction && direction == -1)  positive = true;
	  if (direction && direction == 1 )  negative = true;
	  
	}
	
	// cannot have a track that goes in both direction
	// partition logic end here
	stringstream ss;
	ss << globalCount;
	string histoCounter = ss.str();
	
	
	TH2F * histXZ = new TH2F(histoCounter.c_str(),"XZ plane",110,0,110,68,0,34);
	
	
	histXZ->SetMarkerColor(kBlue);
	histXZ->SetMarkerStyle(kOpenTriangleDown); //  - open triangle down not found on noise server ? 
	
	double * xc = new double[3];
	double * yc = new double[3];
	double * zc = new double[3];
	
	vector<double> coordinates ;
	double xCoordinate = 0;
	int yCoordinate = 0;
	int zCoorinate = 0;
	
	coordinates = this->getChamberNumber(1)->getXYCoordinatesOfCluster(i+1);
	xCoordinate = coordinates.at(0);
	yCoordinate = coordinates.at(1);
	zCoorinate = 10*vectorOfReferenceChambers[0];
	
	int prevPartition = yCoordinate;
	xc[0] = xCoordinate;
	yc[0] = yCoordinate;
	zc[0] = 1*10;
	
	histXZ->Fill(zc[0],xCoordinate);
	cout << xCoordinate << " " << yCoordinate << endl;
	
	coordinates = this->getChamberNumber(4)->getXYCoordinatesOfCluster(j+1);
	xCoordinate = coordinates.at(0);
	yCoordinate = coordinates.at(1);
	
	xc[1] = xCoordinate;
	yc[1] = yCoordinate;
	zc[1] = 4*10;
	
	histXZ->Fill(zc[1],xCoordinate);
	prevPartition = yCoordinate;
	
	cout << xCoordinate << " " << yCoordinate << endl;	
	coordinates = this->getChamberNumber(6)->getXYCoordinatesOfCluster(k+1);
	xCoordinate = coordinates.at(0);
	yCoordinate = coordinates.at(1);
	
	xc[2] = xCoordinate;
	yc[2] = yCoordinate;
	zc[2] = 6*10;
	
	histXZ->Fill(zc[2],xCoordinate);
	cout << xCoordinate << " " << yCoordinate << endl;
	
	if ( positive && negative ) continue;
	
	TF1 * fitfunc = new TF1("FitTrack","[0]+x*[1]",0,100);
	Double_t * params = new Double_t[2];
	histXZ->Fit(fitfunc);
	fitfunc->GetParameters(params);
	cout << "par1 " << params[0] << " par2 " << params[1] << " chi2 " << fitfunc->GetChisquare() << endl;
	double channelToSearchHitIn ;
	
	for (int jj = 0 ; jj < this->getNumberOfChambers() ; jj++){
	  if (jj+1 != vectorOfReferenceChambers[0] || jj+1 != vectorOfReferenceChambers[1] || jj+1 != vectorOfReferenceChambers[1])
	    // add additional rule that the chamber should exist in the calibration object 
	  {
	    
	    channelToSearchHitIn = fitfunc->Eval((jj+1)*10);
	    cout << "Evaluated for chamber number " << jj+1 << " value : " << channelToSearchHitIn << endl;
	    
	  }
	  
	}
	// now here - what to return, and how to get the hits in the chambers under test from the function
	
	
	
	if (fitfunc->GetChisquare() > 20) continue; // cut the execution 
	if(fitfunc->GetChisquare() < 20){
	  //goodTracks->Write(trackHistoName.c_str());
	  histClustersPartitionDistr->Fill(partitionPenetrated);
	  //histXZ->SaveAs((trackHistoName+".root").c_str());  
	  // here search for hits in the chambers under test  
	  
	}
	
	/*
	else{
	  badTracks->Write(trackHistoName.c_str());
	}	
	*/
	
	//trackHistoName+=".root";
	//histXZ->SaveAs(trackHistoName.c_str());
	
	histXZ->Delete();
	
      }
    }
  }
//   badTracks->Close("R");
//   badTracks->Delete();
//   goodTracks->Close("R");
//   goodTracks->Delete();

}
Exemple #3
0
int main(int argc, char** argv){//main  

  if (argc < 7) {
    std::cout << " Usage: " 
	      << argv[0] << " <nEvts to process (0=all)>"
	      << " <path to input files>"
	      << " <name of input sim file>"
	      << " <name of input reco file>"
	      << " <full path to output file>"
	      << " <number of si layers to consider: 1,2 or 3>" 
      //<< " <generated E>"
	      << " <optional: debug (default=0)>"
	      << std::endl;
    return 1;
  }

  //////////////////////////////////////////////////////////
  //// Hardcoded config ////////////////////////////////////
  //////////////////////////////////////////////////////////
  bool concept = true;

  //for xvsy plots
  double minX=-1700,maxX=1700;
  double minY=-1700,maxY=1700;
  double minZ=3170,maxZ=3370;
  //double minX=-510,maxX=510;
  //double minY=-510,maxY=510;
  //double minZ=-1000,maxZ=1000;

  unsigned nX=(maxX-minX)/10,nY=(maxY-minY)/10;
  unsigned nZ=maxZ-minZ;

  //size of signal region to perform Chi2 position fit.
  //in units of 2.5mm cells to accomodate different granularities
  unsigned nSR = 12;

  //maximum value of residuals to use in error matrix: discard positions that are too far away 
  double residualMax = 25;//mm

  //////////////////////////////////////////////////////////
  //// End Hardcoded config ////////////////////////////////////
  //////////////////////////////////////////////////////////

  const unsigned pNevts = atoi(argv[1]);
  std::string filePath = argv[2];
  std::string simFileName = argv[3];
  std::string recoFileName = argv[4];

  std::string inFilePath = filePath+simFileName;

  std::string outPath = argv[5];
  unsigned nSiLayers = 2;
  nSiLayers = atoi(argv[6]);

  //unsigned genEn;
  //genEn = atoi(argv[7]);

  unsigned debug = 0;
  if (argc >7) debug = atoi(argv[7]);

  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
	    << " -- Output file path: " << outPath << std::endl
	    << " -- Output folder: " << outFolder << std::endl
    //<< " -- Generated energy: " << genEn << std::endl
	    << " -- Requiring " << nSiLayers << " si layers." << std::endl
	    << " -- Number cells in signal region for fit: " << nSR << " *2.5*2.5 mm^2 cells" << 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 input;
  input << filePath << "/" << simFileName;

  TFile *simFile = TFile::Open(input.str().c_str());

  if (!simFile) {
    std::cout << " -- Error, input file " << input.str() << " cannot be opened. Exiting..." << std::endl;
    return 1;
  }
  else std::cout << " -- input file " << simFile->GetName() << " successfully opened." << std::endl;
  
  TTree *lSimTree = (TTree*)simFile->Get("HGCSSTree");
  if (!lSimTree){
    std::cout << " -- Error, tree HGCSSTree cannot be opened. Exiting..." << std::endl;
    return 1;
  }

  input.str("");
  input << filePath << "/" << recoFileName;
  
  TFile *recFile = TFile::Open(input.str().c_str());

  if (!recFile) {
    std::cout << " -- Error, input file " << input.str() << " cannot be opened. Exiting..." << std::endl;
    return 1;
  }
  else std::cout << " -- input file " << recFile->GetName() << " successfully opened." << std::endl;

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


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

  HGCSSInfo * info=(HGCSSInfo*)simFile->Get("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);

  //initialise calibration class
  HGCSSCalibration mycalib(inFilePath);
  HGCSSDigitisation myDigitiser;
  myDigitiser.setRandomSeed(lRndm.GetSeed());

  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);
  //assemble in 7.5*7.5 to fill maxE
  std::vector<unsigned> granularity;
  granularity.resize(nLayers,4);
  geomConv.setGranularity(granularity);
  geomConv.initialiseHistos(false,"_10");

  //////////////////////////////////////////////////
  //////////////////////////////////////////////////
  ///////// Output histos  /////////////////////////
  //////////////////////////////////////////////////
  //////////////////////////////////////////////////

  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();
  TH1F *p_nSimHits = new TH1F("p_nSimHits","n(SimHits)",
			      1000,0,500000);
  p_nSimHits->StatOverflows();
  
  TH1F *p_nRecHits = new TH1F("p_nRecHits","n(RecHits)",
			      1000,0,5000);
  p_nRecHits->StatOverflows();

  TH1F *p_EsimTotal = new TH1F("p_EsimTotal",";Esim (MIPs)",5000,0,50000);
  TH1F *p_ErecoTotal = new TH1F("p_ErecoTotal",";Ereco (MIPs)",5000,0,50000);
  p_EsimTotal->StatOverflows();
  p_ErecoTotal->StatOverflows();

  TH2F *p_genxy[nLayers];
  TH2F *p_xy[nLayers];
  TH2F *p_recoxy[nLayers];

  TH1F *p_residuals_x = new TH1F("p_residuals_x",";xreco-xtruth (mm)",1000,-50,50);
  TH1F *p_residuals_y = new TH1F("p_residuals_y",";yreco-ytruth (mm)",1000,-50,50);
  p_residuals_x->StatOverflows();
  p_residuals_y->StatOverflows();

  std::ostringstream lName;
  for (unsigned iL(0); iL<nLayers; ++iL){
    lName.str("");
    lName << "p_genxy_" << iL;
    p_genxy[iL] = new TH2F(lName.str().c_str(),";x(mm);y(mm)",
			   nX*10,minX,maxX,
			   nY*10,minY,maxY);
    lName.str("");
    lName << "p_xy_" << iL;
    p_xy[iL] = new TH2F(lName.str().c_str(),";x(mm);y(mm)",
   			nX,minX,maxX,
   			nY,minY,maxY);
    lName.str("");
    lName << "p_recoxy_" << iL;
    p_recoxy[iL] = new TH2F(lName.str().c_str(),";x(mm);y(mm)",
   			    nX,minX,maxX,
   			    nY,minY,maxY);
  }

    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    ///////// Event loop /////////////////////////////
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////

  HGCSSEvent * event = 0;
  std::vector<HGCSSSamplingSection> * ssvec = 0;
  std::vector<HGCSSSimHit> * simhitvec = 0;
  std::vector<HGCSSRecoHit> * rechitvec = 0;
  std::vector<HGCSSGenParticle> * genvec = 0;
  
  lSimTree->SetBranchAddress("HGCSSEvent",&event);
  lSimTree->SetBranchAddress("HGCSSSamplingSectionVec",&ssvec);
  lSimTree->SetBranchAddress("HGCSSSimHitVec",&simhitvec);
  lSimTree->SetBranchAddress("HGCSSGenParticleVec",&genvec);
  
  lRecTree->SetBranchAddress("HGCSSRecoHitVec",&rechitvec);

  const unsigned nEvts = ((pNevts > lSimTree->GetEntries() || pNevts==0) ? static_cast<unsigned>(lSimTree->GetEntries()) : pNevts) ;
  
  std::cout << "- Processing = " << nEvts  << " events out of " << lSimTree->GetEntries() << std::endl;
  
  //Initialise histos
  //necessary to have overflows ?
  gStyle->SetOptStat(1111111);
  double EtotSim[nLayers];
  double EtotRec[nLayers];
  //initialisation for error matrix
  double mean[2][nLayers];//sum residuals for x and y
  double sigma[2][nLayers][nLayers];//sum square
  unsigned nL_mean[nLayers];//number of valid layers
  unsigned nL_sigma[nLayers][nLayers];

  std::vector<double> avgZ;
  avgZ.resize(nLayers,0);


  for (unsigned iL(0);iL<nLayers;++iL){
    EtotSim[iL] = 0;
    EtotRec[iL] = 0;
    nL_mean[iL] = 0;
    mean[0][iL] = 0;
    mean[1][iL] = 0;
    for (unsigned jL(0);jL<nLayers;++jL){
      nL_sigma[iL][jL] = 0;
      sigma[0][iL][jL] = 0;
      sigma[1][iL][jL] = 0;
    }
  }



  bool firstEvent = true;

  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 (debug){
      std::cout << "... Size of hit vectors: sim = " <<  (*simhitvec).size() << ", reco = " << (*rechitvec).size()<< std::endl;
    }

    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    //////// output files to save position for chi2 fit //////////
    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////

    std::ofstream fout;
    std::ostringstream foutname;
    foutname << outFolder << "_initialPos_evt" << ievt << ".dat";
    fout.open(foutname.str());
    if (!fout.is_open()){
      std::cout << " Cannot open outfile " << foutname.str() << " for writing ! Exiting..." << std::endl;
      return 1;
    }


    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    ///////// SimHits ////////////////////////////////
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////

    //loop on simhits
    double etotmips = 0;
    unsigned prevLayer = 10000;
    DetectorEnum type = DetectorEnum::FECAL;
    unsigned subdetLayer=0;

    TH2F *etavsphi = new TH2F("etavsphi",";#phi;#eta;hits",150,-3.1416,3.1416,160,1.4,3.0);

    for (unsigned iH(0); iH<(*simhitvec).size(); ++iH){//loop on hits
      HGCSSSimHit lHit = (*simhitvec)[iH];

      //discard some si layers...
      if (lHit.silayer() >= nSiLayers) continue; 

      unsigned layer = lHit.layer();

      if (layer >= nLayers) {
	//std::cout << " WARNING! SimHits with layer " << layer << " outside of detector's definition range ! Please fix the digitiser or the detector definition used here. Ignoring..." << std::endl;
	continue;
      }
      if (layer != prevLayer){
	const HGCSSSubDetector & subdet = myDetector.subDetectorByLayer(layer);
	type = subdet.type;
	subdetLayer = layer-subdet.layerIdMin;
	prevLayer = layer;
	if (debug > 1) std::cout << " - layer " << layer << " " << subdet.name << " " << subdetLayer << std::endl;
      }     

      //unsigned sec =  myDetector.getSection(layer);

      double posx = lHit.get_x(cellSize);
      double posy = lHit.get_y(cellSize);
      double posz = lHit.get_z();
      //double radius = sqrt(posx*posx+posy*posy);
      double lRealTime = mycalib.correctTime(lHit.time(),posx,posy,posz);
      double energy = lHit.energy()*mycalib.MeVToMip(layer);

      //if (energy>1) std::cout << "Hit " << layer << " " << posx << " " << posy << " " << posz << " " << energy << std::endl;

      if (type == DetectorEnum::FECAL ||
	  type == DetectorEnum::MECAL ||
	  type == DetectorEnum::BECAL){
	//correct for si thickness
	//default for 200um
	energy *= 2./nSiLayers;
      }
      
      geomConv.fill(type,subdetLayer,energy,lRealTime,posx,posy,posz);

      bool passTime = myDigitiser.passTimeCut(type,lRealTime);
      if (!passTime) continue;

      if (debug>1) {
	std::cout << " --  SimHit " << iH << "/" << (*simhitvec).size() << " --" << std::endl
		  << " --  position x,y " << posx << "," << posy << std::endl;
	lHit.Print(std::cout);
      }

      EtotSim[layer] += energy;
      p_xy[layer]->Fill(posx,posy,energy);

      ROOT::Math::XYZVector pos(posx,posy,posz);
      etavsphi->Fill(pos.phi(),pos.eta(),energy);

      //double absweight = myDetector.subDetectorByLayer(layer).absWeight;
      double absweight = (*ssvec)[layer].volX0trans()/(*ssvec)[1].volX0trans();

      //if (versionNumber==12){
	//absweight = layer%2==0 ?
	//(*ssvec)[layer].volX0trans()/refThicknessEven : 
	//(*ssvec)[layer].volX0trans()/refThicknessOdd;
	//}
      etotmips += energy*absweight;
      
    }//loop on hits

    p_nSimHits->Fill((*simhitvec).size());
 
    if (debug)  std::cout << std::endl;


    //get position of maximum E tower
    int maxbin = etavsphi->GetMaximumBin();
    int binx,biny,binz;
    etavsphi->GetBinXYZ(maxbin,binx,biny,binz);
    double phimax =etavsphi->GetXaxis()->GetBinCenter(binx); 
    double etamax =etavsphi->GetYaxis()->GetBinCenter(biny); 

    //std::cout << " MaxE cell eta,phi = " << etamax << " " << phimax << std::endl;
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    ///////// GenParticles////////////////////////////
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////

    //get truth position

    std::vector<ROOT::Math::XYPoint> truthPos;
    truthPos.resize(nLayers,ROOT::Math::XYPoint());

    for (unsigned iP(0); iP<(*genvec).size(); ++iP){//loop on gen particles    
      //if ((*genvec).size()!= 1) (*genvec)[iP].Print(std::cout);
      if ((*genvec)[iP].trackID()==1){
	double x0 = (*genvec)[iP].x();
	double y0 = (*genvec)[iP].y();
	double z0 = (*genvec)[iP].z();
	double p = sqrt(pow((*genvec)[iP].px(),2)+pow((*genvec)[iP].py(),2)+pow((*genvec)[iP].pz(),2));
	//double energy = sqrt(pow((*genvec)[iP].mass(),2)+pow(p,2));
	//p_genxy[0]->Fill(x0,y0,energy);
	//std::cout << "init : " << x0 << " " << y0 << " " << z0 << std::endl;
	//fill layers by propagating with momentum
	ROOT::Math::XYZVector unit((*genvec)[iP].px()/p,(*genvec)[iP].py()/p,(*genvec)[iP].pz()/p);

	//std::cout << " Gen particle eta,phi = " << unit.eta() << " " << unit.phi() << std::endl;

	for (unsigned iL(0); iL<nLayers; ++iL){
	  if (avgZ[iL]<z0) avgZ[iL] = geomConv.getAverageZ(iL);
	  if (avgZ[iL]>z0) {
	    double xy = (avgZ[iL]-z0)/sinh(unit.eta());
	    double x = xy*cos(unit.phi())+x0;
	    double y = xy*sin(unit.phi())+y0;
	    
	    //std::cout << "Lay " << iL << ": " << x << " " << y << " " << avgZ[iL] << std::endl;
	    p_genxy[iL]->Fill(x,y,1);
	    truthPos[iL] = ROOT::Math::XYPoint(x,y);
	  }
	}

      }

      //p_genPartId->Fill((*genvec)[iP].pdgid());
    }//loop on gen particles

    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    ///////// RecHits ////////////////////////////////
    //////////////////////////////////////////////////
    //////////////////////////////////////////////////

    double Etotcal = 0;
    std::vector<double> xmax;
    xmax.resize(nLayers,0);
    std::vector<double> ymax;
    ymax.resize(nLayers,0);
    std::vector<double> dRmin;
    dRmin.resize(nLayers,10);

    for (unsigned iH(0); iH<(*rechitvec).size(); ++iH){//loop on rechits
      HGCSSRecoHit lHit = (*rechitvec)[iH];
      if (debug>1) {
	std::cout << " --  RecoHit " << iH << "/" << (*rechitvec).size() << " --" << std::endl
		  << " --  position x,y " << lHit.get_x() << "," << lHit.get_y() << std::endl;
	lHit.Print(std::cout);
      }
      
      double energy = lHit.energy();//in MIP already...
      unsigned layer = lHit.layer();

      if (layer >= nLayers) {
	std::cout << " WARNING! RecoHits with layer " << layer << " outside of detector's definition range ! Please fix the digitiser or the detector definition used here. Ignoring..." << std::endl;
	continue;
      }

      double posx = lHit.get_x();
      double posy = lHit.get_y();
      double posz = lHit.get_z();
      ROOT::Math::XYZVector pos(posx,posy,posz);
      double deta = fabs(pos.eta()-etamax);
      double dphi = fabs(pos.phi()-phimax);
      double dR = sqrt(pow(deta,2)+pow(dphi,2));
      if (dR<dRmin[layer]) {
	dRmin[layer] = dR;
	xmax[layer] = posx;
	ymax[layer] = posy;
      }


      //unsigned sec =  myDetector.getSection(layer);
      
      p_recoxy[layer]->Fill(posx,posy,energy);
      EtotRec[layer] += energy;

      if (debug>1) std::cout << "-hit" << iH << "-" << layer << " " << energy << " " << EtotRec[layer];

      double absweight = (*ssvec)[layer].volX0trans()/(*ssvec)[1].volX0trans();

      Etotcal += energy*absweight;
    }//loop on rechits
    
    p_nRecHits->Fill((*rechitvec).size());

    p_EsimTotal->Fill(etotmips);
    p_ErecoTotal->Fill(Etotcal);
    
    //for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
      //p_EsimvsLayer->Fill(iL,EtotSim[iL]);
      // p_ErecovsLayer->Fill(iL,EtotRec[iL]);
      //}

    //get energy-weighted position around maximum
    std::vector<ROOT::Math::XYPoint> recoPos;
    recoPos.resize(nLayers,ROOT::Math::XYPoint(0,0));
    std::vector<double> eSum;
    eSum.resize(nLayers,0);
    std::vector<unsigned> nHits;
    nHits.resize(nLayers,0);
    for (unsigned iH(0); iH<(*rechitvec).size(); ++iH){//loop on rechits
      HGCSSRecoHit lHit = (*rechitvec)[iH];
      double energy = lHit.energy();//in MIP already...
      unsigned layer = lHit.layer();
      double posx = lHit.get_x();
      double posy = lHit.get_y();
      double posz = lHit.get_z();
      double step = cellSize*nSR/2.+0.1;//+0.1 to accomodate double precision
      if (fabs(posx-xmax[layer]) < step && 
	  fabs(posy-ymax[layer]) < step){
	recoPos[layer].SetX(recoPos[layer].X() + posx*energy);
	recoPos[layer].SetY(recoPos[layer].Y() + posy*energy);
	eSum[layer] += energy;
	if (energy>0) nHits[layer]++;
      }

    }//loop on rechits


    //fill error matrix
    if (debug) std::cout << " Summary of reco and truth positions:" << std::endl;
    for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
      if (nHits[iL]==0) continue;
      recoPos[iL].SetX(recoPos[iL].X()/eSum[iL]);
      recoPos[iL].SetY(recoPos[iL].Y()/eSum[iL]);
      if (debug) std::cout << iL << " nHits=" << nHits[iL] << " Max=(" << xmax[iL] << "," << ymax[iL] << ")\t Reco=(" << recoPos[iL].X() << "," << recoPos[iL].Y() << ")\t Truth=(" << truthPos[iL].X() << "," << truthPos[iL].Y() << ")" << std::endl;
      fout << iL << " " << recoPos[iL].X() << " " << recoPos[iL].Y() << " " << avgZ[iL] << " " << truthPos[iL].X() << " " << truthPos[iL].Y() << std::endl;
    }
    for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
      if (nHits[iL]==0) continue;
      double residual_xi = recoPos[iL].X()-truthPos[iL].X();
      double residual_yi = recoPos[iL].Y()-truthPos[iL].Y();
      p_residuals_x->Fill(residual_xi);
      p_residuals_y->Fill(residual_yi);
      if (fabs(residual_xi)>residualMax || fabs(residual_yi)>residualMax) continue;
      mean[0][iL] += residual_xi;
      mean[1][iL] += residual_yi;
      ++nL_mean[iL];
      for (unsigned jL(0);jL<nLayers;++jL){//loop on layers
	if (nHits[jL]==0) continue;
	double residual_xj = recoPos[jL].X()-truthPos[jL].X();
	double residual_yj = recoPos[jL].Y()-truthPos[jL].Y();
	if (fabs(residual_xj)>residualMax || fabs(residual_yj)>residualMax) continue;
	double sigma_x = residual_xi*residual_xj;
	double sigma_y = residual_yi*residual_yj;
	sigma[0][iL][jL] += sigma_x;
	sigma[1][iL][jL] += sigma_y;
	++nL_sigma[iL][jL];
      }//loop on layers
    }//loop on layers

    geomConv.initialiseHistos();
    etavsphi->Delete();

    fout.close();

    firstEvent = false;
  }//loop on entries
  std::cout << " -- Total Esim in MIPS: "
	    <<  p_EsimTotal->GetEntries() 
	    << " mean " << p_EsimTotal->GetMean() 
	    << " rms " << p_EsimTotal->GetRMS() 
	    << " rms/mean " << p_EsimTotal->GetRMS()/p_EsimTotal->GetMean()
	    << " underflows " << p_EsimTotal->GetBinContent(0)
	    << " overflows " << p_EsimTotal->GetBinContent(p_EsimTotal->GetNbinsX()+1)
	    << std::endl;
  
  std::cout << " -- Total Ereco in MIPS: "
	    <<  p_ErecoTotal->GetEntries() 
	    << " mean " << p_ErecoTotal->GetMean() 
	    << " rms " << p_ErecoTotal->GetRMS() 
	    << " rms/mean " << p_ErecoTotal->GetRMS()/p_ErecoTotal->GetMean()
	    << " underflows " << p_ErecoTotal->GetBinContent(0)
	    << " overflows " << p_ErecoTotal->GetBinContent(p_ErecoTotal->GetNbinsX()+1)
	    << std::endl;
  

  //finalise error matrix
  std::ofstream fmatrix;
  std::ostringstream fmatrixname;
  fmatrixname << outFolder << "_errorMatrix_ref.dat";
  fmatrix.open(fmatrixname.str());
  if (!fmatrix.is_open()){
    std::cout << " Cannot open outfile " << fmatrixname.str() << " for writing ! Exiting..." << std::endl;
    exit(1);
  }



  TMatrixD matrix(nLayers,nLayers);
  outputFile->cd();
  TH2F *p_errorMatrix = new TH2F("p_errorMatrix",";i;j;M_{ij}",
			    nLayers,0,nLayers,
			    nLayers,0,nLayers);
  TH2F *p_corrMatrix = new TH2F("p_corrMatrix",";i;j;M_{ij}",
				nLayers,0,nLayers,
				nLayers,0,nLayers);

  for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
    mean[0][iL] = mean[0][iL]/nL_mean[iL];
    mean[1][iL] = mean[1][iL]/nL_mean[iL];
  }
  for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
    for (unsigned jL(0);jL<nLayers;++jL){//loop on layers
      sigma[0][iL][jL] = sigma[0][iL][jL]/nL_sigma[iL][jL];
      sigma[1][iL][jL] = sigma[1][iL][jL]/nL_sigma[iL][jL];
      //consider average of both x and y in one matrix
      matrix[iL][jL] = 0.5*(sigma[0][iL][jL]-mean[0][iL]*mean[0][jL]+
			    sigma[1][iL][jL]-mean[1][iL]*mean[1][jL]);
      //matrix[jL][iL] = matrix[iL][jL];
      p_errorMatrix->Fill(iL,jL,matrix[iL][jL]);
 
      fmatrix << iL << " " << jL << " " << std::setprecision(17) << matrix[iL][jL] << std::endl;

      //if (iL!=jL){
      //p_matrix->Fill(jL,iL,matrix[iL][jL]);
      //}
    }
  }
  fmatrix.close();

  //fill correlation matrix
  for (unsigned iL(0);iL<nLayers;++iL){//loop on layers
    for (unsigned jL(0);jL<nLayers;++jL){//loop on layers
      if (matrix[iL][iL]!=0 && matrix[jL][jL]!= 0) 
	p_corrMatrix->Fill(iL,jL,matrix[iL][jL]/sqrt(matrix[iL][iL]*matrix[jL][jL]));
    }
  }

  //get back data for each event and perform chi2 fit:
  std::cout << " -- Performing chi2 fit for each event" << std::endl;

  unsigned nInvalidFits=0;
  TH1F *p_chi2[2];
  TH1F *p_chi2overNDF[2];

  p_chi2[0] = new TH1F("p_chi2",";#chi^{2};n_{events}",100,0,500);
  p_chi2overNDF[0] = new TH1F("p_chi2overNDF",";#chi^{2}/NDF;n_{events}",100,0,10);
  p_chi2[1] = new TH1F("p_chi2_truth",";#chi^{2};n_{events}",100,0,500);
  p_chi2overNDF[1] = new TH1F("p_chi2overNDF_truth",";#chi^{2}/NDF;n_{events}",100,0,10);
  for (unsigned rt(0); rt<2;++rt){
  p_chi2[rt]->StatOverflows();
  p_chi2overNDF[rt]->StatOverflows();
  }

  TH1F *p_impactX[2];
  p_impactX[0] = new TH1F("p_impactX",";x front face impact (mm);n_{events}",200,-500,500);
  p_impactX[1] = new TH1F("p_impactX_truth",";x front face impact (mm);n_{events}",200,-500,500);
  TH1F *p_impactY[2];
  p_impactY[0] = new TH1F("p_impactY",";y front face impact (mm);n_{events}",240,300,1500);
  p_impactY[1] = new TH1F("p_impactY_truth",";y front face impact (mm);n_{events}",240,300,1500);
  TH1F *p_angleX[2];
  p_angleX[0] = new TH1F("p_angleX",";x direction angle (rad);n_{events}",150,-3.1416,3.1416);
  p_angleX[1] = new TH1F("p_angleX_truth",";x direction angle (rad);n_{events}",150,-3.1416,3.1416);
  TH1F *p_angleY[2];
  p_angleY[0] = new TH1F("p_angleY",";y direction angle (rad);n_{events}",150,-3.1416,3.1416);
  p_angleY[1] = new TH1F("p_angleY_truth",";y direction angle (rad);n_{events}",150,-3.1416,3.1416);

  TH1F *p_positionReso[2];
  TH1F *p_angularReso[2];
  p_positionReso[0] = new TH1F("p_positionResoX",";#sigma_{x,y} (mm);n_{events}",100,0,20);
  p_positionReso[1] = new TH1F("p_positionResoY",";#sigma_{x,y} (mm);n_{events}",100,0,20);
  p_angularReso[0] = new TH1F("p_angularResoX",";#sigma_{#theta} (rad);n_{events}",100,0,1);
  p_angularReso[1] = new TH1F("p_angularResoY",";#sigma_{#theta} (rad);n_{events}",100,0,1);

  //open new file to save accurate positions
  std::ofstream fout;
  std::ostringstream foutname;
  foutname << outFolder << "_accuratePos.dat";
  fout.open(foutname.str());
  if (!fout.is_open()){
    std::cout << " Cannot open outfile " << foutname.str() << " for writing ! Exiting..." << std::endl;
    return 1;
  }

  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;

    std::ifstream fin;
    std::ostringstream finname;
    finname << outFolder << "_initialPos_evt" << ievt << ".dat";
    fin.open(finname.str());
    if (!fin.is_open()){
      std::cout << " Cannot open input file " << finname.str() << "! Exiting..." << std::endl;
      return 1;
    }

    std::vector<unsigned> layerId;
    std::vector<double> posx;
    std::vector<double> posy;
    std::vector<double> posz;
    std::vector<double> posxtruth;
    std::vector<double> posytruth;
    layerId.reserve(nLayers);
    posx.reserve(nLayers);
    posy.reserve(nLayers);
    posz.reserve(nLayers);
    posxtruth.reserve(nLayers);
    posytruth.reserve(nLayers);

    while (!fin.eof()){
      unsigned l=nLayers;
      double xr=0,yr=0,z=0,xt=0,yt=0;
      fin>>l>>xr>>yr>>z>>xt>>yt;
      if (l<nLayers){
	layerId.push_back(l);
	posx.push_back(xr);
	posy.push_back(yr);
	posz.push_back(z);
	posxtruth.push_back(xt);
	posytruth.push_back(yt);	
      }
    }

    fin.close();

    const unsigned nL = layerId.size();

    //for (unsigned iL(0); iL<nL;++iL){
      //std::cout << layerId[iL] << " " << posx[iL] << " " << posy[iL] << " " << posz[iL] << std::endl;
    //}

    //if less than 3 valid layers: no point doing a fit !!
    if (nL<3){
      nInvalidFits++;
      continue;
    }

    //number of points: x and y per layer minus number of parameters: 2 for x + 2 for y.
    double ndf = 2*nL-4;

    //Get error matrix removing lines with zero hits
    TMatrixDSym e(nL);
    TVectorD u(nL),z(nL),x(nL),y(nL);
    
    for(unsigned i(0);i<nL;++i) {
      u(i)=1.0;
      z(i)=posz[i];
      //std::cout << "fit() z(" << i << ") = " << z(i) << std::endl;
      
      for(unsigned j(i);j<nL;++j) {
	e(i,j)=matrix(layerId[i],layerId[j]);
	e(j,i)=matrix(layerId[j],layerId[i]);
      }
    }

    e.Invert();

    
    //do fit for reco and truth

    for (unsigned rt(0); rt<2;++rt){
      if (debug) {
	std::cout << "... Processing ";
	if (rt==0) std::cout << " fit to reco position.";
	else std::cout << " fit to truth position.";
	std::cout << std::endl;
      }
      double chiSq(0.0);
      double position[2];
      double positionFF[2];
      double TanAngle[2];
      
      TMatrixD fitMatrix(4,4);
      
      //resolve equation for x and y separately
      for(unsigned xy(0);xy<2;xy++) {//loop on x or y
	if (debug) {
	  std::cout << "... Processing ";
	  if (xy==0) std::cout << " fit to x position.";
	  else std::cout << " fit to y position.";
	  std::cout << std::endl;
	}
	for(unsigned i(0);i<nL;i++) {
	  x(i)= rt==0 ? ((xy==0) ? posx[i] : posy[i]) : ((xy==0) ? posxtruth[i] : posytruth[i]);
	  //std::cout << "fit() x(" << i << ") = " << x(i) << std::endl;
	}
	
	TMatrixD w(2,2);
	TVectorD v(2),p(2);
	
	w(0,0)=u*(e*u);
	w(0,1)=u*(e*z);
	w(1,0)=z*(e*u);
	w(1,1)=z*(e*z);

	v(0)=u*(e*x);
	v(1)=z*(e*x);
	
	w.Invert();
	
	p=w*v;
	if (debug) {
	  std::cout << "fit() w(0,0) = " << w(0,0) << std::endl;
	  std::cout << "fit() w(0,1) = " << w(0,1) << std::endl;
	  std::cout << "fit() w(1,0) = " << w(1,0) << std::endl;
	  std::cout << "fit() w(1,1) = " << w(1,1) << std::endl;	
	  std::cout << "fit() p(0) = " << p(0) << std::endl;
	  std::cout << "fit() p(1) = " << p(1) << std::endl;
	}

	position[xy] = p(0);
	positionFF[xy] = p(0)+p(1)*posz[0];
	TanAngle[xy] = p(1);
	
	fitMatrix[2*xy][2*xy]=w(0,0);
	fitMatrix[2*xy][2*xy+1]=w(0,1);
	fitMatrix[2*xy+1][2*xy]=w(1,0);
	fitMatrix[2*xy+1][2*xy+1]=w(1,1);
	
	
	TVectorD dp(nL);
	for(unsigned i(0);i<nL;i++) {
	  dp(i)=x(i)-p(0)-p(1)*z(i);
	}
	
	chiSq+=dp*(e*dp);
      }//loop on x or y
      
      p_chi2[rt]->Fill(chiSq);
      p_chi2overNDF[rt]->Fill(chiSq/ndf);
      p_impactX[rt]->Fill(positionFF[0]);
      p_angleX[rt]->Fill(atan(TanAngle[0]));
      p_impactY[rt]->Fill(positionFF[1]);
      p_angleY[rt]->Fill(atan(TanAngle[1]));

      if (rt==0) {
	p_positionReso[0]->Fill(sqrt(fabs(fitMatrix[0][0])));
	p_positionReso[1]->Fill(sqrt(fabs(fitMatrix[2][2])));
	p_angularReso[0]->Fill(sqrt(fabs(fitMatrix[1][1])));
	p_angularReso[1]->Fill(sqrt(fabs(fitMatrix[3][3])));

	fout << ievt << " " 
	     << position[0] << " " 
	     << sqrt(fabs(fitMatrix[0][0])) << " " 
	     << TanAngle[0] << " " 
	     << sqrt(fabs(fitMatrix[1][1])) << " "
	     << position[1] << " " 
	     << sqrt(fabs(fitMatrix[2][2])) << " "
	     << TanAngle[1] << " "
	     << sqrt(fabs(fitMatrix[3][3]))
	     << std::endl;
      }

    }//reco or truth

  }//loop on entries
  
  fout.close();    


  std::cout << " -- Number of invalid fits: " << nInvalidFits << std::endl;


  outputFile->Write();
  //outputFile->Close();
  
  return 0;


}//main