void analysisClass::loop(){

  //--------------------------------------------------------------------------------
  // Store important variables
  //--------------------------------------------------------------------------------

  for (int i_radius = 1; i_radius <= n_radii; ++i_radius){
    radii[i_radius-1] = min_radius + i_radius * (max_radius - min_radius) / double(n_radii);
  }
  
  //--------------------------------------------------------------------------------
  // Declare tree(s)
  //--------------------------------------------------------------------------------
  
  HgcalTupleTree * tree = getTree<HgcalTupleTree>("hgcal_tree");
  int n_events = tree -> fChain -> GetEntries();
  // int n_events = 200;
  
  std::vector<std::string> * rcut_values = new std::vector<std::string>();
  rcut_values -> push_back ("R5"); 
  rcut_values -> push_back ("R4"); 
  rcut_values -> push_back ("R3"); 
  rcut_values -> push_back ("R2"); 
  rcut_values -> push_back ("R1"); 
  rcut_values -> push_back ("R05"); 
  rcut_values -> push_back ("R04"); 
  rcut_values -> push_back ("R03"); 
  rcut_values -> push_back ("R02"); 
  rcut_values -> push_back ("R01"); 
  rcut_values -> push_back ("R008"); 
  rcut_values -> push_back ("R005"); 
  rcut_values -> push_back ("R003"); 
  rcut_values -> push_back ("R001");
  
  //--------------------------------------------------------------------------------
  // Likelihood getter
  //--------------------------------------------------------------------------------

  int n_rcut_variables = rcut_values -> size();

  std::vector<std::string> likelihood_variables;
  likelihood_variables.push_back ( "nDaught" );
  likelihood_variables.push_back ( "width"   );
  likelihood_variables.push_back ( "multi"   );
  likelihood_variables.push_back ( "ptd"     );
  likelihood_variables.push_back ( "nsubj"   );
  likelihood_variables.push_back ( "mass"    );
  likelihood_variables.push_back ( "profile50" );
  likelihood_variables.push_back ( "leadCoreJetFraction" );
  likelihood_variables.push_back ("leadCoreJetDR");
  
  std::string file_name ("likelihood_hists_fromWJet.root");

  std::vector<likelihoodGetter> likelihoods;

  for (int ircut = 0; ircut < n_rcut_variables; ++ircut){
    std::string signal("quarkPruned");
    signal = signal + (*rcut_values)[ircut];
    signal = signal + std::string("Jets");
    std::vector<std::string> signals;
    signals.push_back ( signal );
    likelihoodGetter l ( file_name,(*rcut_values)[ircut] , likelihood_variables, signals );
    likelihoods.push_back (l);
  }
  
  //--------------------------------------------------------------------------------
  // Make histograms
  //--------------------------------------------------------------------------------

  TH2F * all_tau_ptVsPull      = makeTH2F("all_tau_ptVsPull" ,  100, 0, 500,  100, -2, 2);
  TH2F * fid_tau_ptVsPull      = makeTH2F("fid_tau_ptVsPull" ,  100, 0, 500,  100, -2, 2);
  TH2F * all_vbfq_ptVsPull     = makeTH2F("all_vbfq_ptVsPull",  100, 0, 500,   100, -2, 2);
  TH2F * fid_vbfq_ptVsPull     = makeTH2F("fid_vbfq_ptVsPull",  100, 0, 500,   100, -2, 2);

  TH1F * all_vbfq_matchDR = makeTH1F( "all_vbfq_matchDR", 100, 0, 2 );
  TH1F * fid_vbfq_matchDR = makeTH1F( "fid_vbfq_matchDR", 100, 0, 2 );

  TH1F * all_recojet_matched_matchDR = makeTH1F("all_recojet_matched_matchDR", 100, 0, 2 );
  TH1F * all_recojet_matched_eta     = makeTH1F("all_recojet_matched_eta", 100, -5., 5.);
  TH1F * all_recojet_matched_pt      = makeTH1F("all_recojet_matched_pt", 100, 0, 200 );
	                             
  TH1F * fid_recojet_matched_matchDR = makeTH1F("fid_recojet_matched_matchDR", 100, 0, 2 );
  TH1F * fid_recojet_matched_eta     = makeTH1F("fid_recojet_matched_eta", 100, -5., 5.);
  TH1F * fid_recojet_matched_pt      = makeTH1F("fid_recojet_matched_pt", 100, 0, 200 );
  
  TH1F* all_tau_pull      = makeTH1F("all_tau_pull"     , 100, -2, 2);
  TH1F* fid_tau_pull      = makeTH1F("fid_tau_pull"     , 100, -2, 2);
  TH1F* all_vbfq_pull     = makeTH1F("all_vbfq_pull"     , 100, -2, 2);
  TH1F* fid_vbfq_pull     = makeTH1F("fid_vbfq_pull"     , 100, -2, 2);

  TH1F* all_tau_rawPull      = makeTH1F("all_tau_rawPull"     , 100, -2, 2);
  TH1F* fid_tau_rawPull      = makeTH1F("fid_tau_rawPull"     , 100, -2, 2);
  TH1F* all_vbfq_rawPull     = makeTH1F("all_vbfq_rawPull"     , 100, -2, 2);
  TH1F* fid_vbfq_rawPull     = makeTH1F("fid_vbfq_rawPull"     , 100, -2, 2);
  
  TH1F* all_tau_gen_pt    = makeTH1F("all_tau_gen_pt"   , 100, 0, 500);
  TH1F* all_tau_reco_pt   = makeTH1F("all_tau_reco_pt"  , 100, 0, 500);
  TH1F* fid_tau_gen_pt    = makeTH1F("fid_tau_gen_pt"   , 100, 0, 500);
  TH1F* fid_tau_reco_pt   = makeTH1F("fid_tau_reco_pt"  , 100, 0, 500);

  TH1F* all_vbfq_gen_pt   = makeTH1F("all_vbfq_gen_pt"  , 100, 0, 500);
  TH1F* all_vbfq_reco_pt  = makeTH1F("all_vbfq_reco_pt" , 100, 0, 500);
  TH1F* fid_vbfq_gen_pt   = makeTH1F("fid_vbfq_gen_pt"  , 100, 0, 500);
  TH1F* fid_vbfq_reco_pt  = makeTH1F("fid_vbfq_reco_pt" , 100, 0, 500);

  TH1F* all_tau_gen_eta   = makeTH1F("all_tau_gen_eta"  , 100, -5., 5.);
  TH1F* all_tau_reco_eta  = makeTH1F("all_tau_reco_eta" , 100, -5., 5.);
  TH1F* fid_tau_gen_eta   = makeTH1F("fid_tau_gen_eta"  , 100, -5., 5.);
  TH1F* fid_tau_reco_eta  = makeTH1F("fid_tau_reco_eta" , 100, -5., 5.);

  TH1F* all_vbfq_gen_eta  = makeTH1F("all_vbfq_gen_eta" , 100, -5., 5.);
  TH1F* all_vbfq_reco_eta = makeTH1F("all_vbfq_reco_eta", 100, -5., 5.);
  TH1F* fid_vbfq_gen_eta  = makeTH1F("fid_vbfq_gen_eta" , 100, -5., 5.);
  TH1F* fid_vbfq_reco_eta = makeTH1F("fid_vbfq_reco_eta", 100, -5., 5.);

  TH1F * fid_vbfq_reco_chargedFraction = makeTH1F("fid_vbfq_reco_chargedFraction", 100, 0, 1.);
  TH1F * fid_vbfq_reco_neutralFraction = makeTH1F("fid_vbfq_reco_neutralFraction", 100, 0, 1.);

  std::vector<TH1F*> th1_templates;
  th1_templates.push_back ( makeTH1F ("nsubj"                 , 20  ,  0. ,     1.  )); // 0
  th1_templates.push_back ( makeTH1F ("mass"                  , 40 ,  0. , 200000.  )); // 1
  th1_templates.push_back ( makeTH1F ("nDaught"               , 50  , -0.5,    49.5 )); // 2
  th1_templates.push_back ( makeTH1F ("multi"                 , 100 , -0.5,   999.5 ));	// 3
  th1_templates.push_back ( makeTH1F ("width"                 , 200 ,  0. ,     1.  ));	// 4
  th1_templates.push_back ( makeTH1F ("chargedWidth"          , 200 ,  0. ,     1.  ));	// 5
  th1_templates.push_back ( makeTH1F ("neutralWidth"          , 200 ,  0. ,     1.  ));	// 6
  th1_templates.push_back ( makeTH1F ("depth"                 , 200 ,  0. ,  1000.  ));	// 7
  th1_templates.push_back ( makeTH1F ("depth_noEE"            , 200 ,  0. ,  1000.  ));	// 8
  th1_templates.push_back ( makeTH1F ("ptd"                   ,  20 ,  0. ,     1.  ));	// 9
  th1_templates.push_back ( makeTH1F ("like"                  , 100 ,  0. ,     1.1 ));	// 10
  th1_templates.push_back ( makeTH1F ("ee_energy_fraction"    , 100 ,  0. ,     1.  ));	// 11
  th1_templates.push_back ( makeTH1F ("ee015_energy_fraction" , 100 ,  0. ,     1.  ));	// 12
  th1_templates.push_back ( makeTH1F ("ee1631_energy_fraction", 100 ,  0. ,     1.  )); // 13
  th1_templates.push_back ( makeTH1F ("heb_energy_fraction"   , 100 ,  0. ,     1.  ));	// 14
  th1_templates.push_back ( makeTH1F ("hef_energy_fraction"   , 100 ,  0. ,     1.  ));	// 15
  th1_templates.push_back ( makeTH1F ("hef11_energy_fraction" , 100 ,  0. ,     1.  ));	// 16
  th1_templates.push_back ( makeTH1F ("hef22_energy_fraction" , 100 ,  0. ,     1.  ));	// 17
  th1_templates.push_back ( makeTH1F ("hef34_energy_fraction" , 100 ,  0. ,     1.  ));	// 18
  th1_templates.push_back ( makeTH1F ("hef56_energy_fraction" , 100 ,  0. ,     1.  ));	// 19
  th1_templates.push_back ( makeTH1F ("hef712_energy_fraction", 100 ,  0. ,     1.  )); // 20
  th1_templates.push_back ( makeTH1F ("profile"               , n_radii + 1 ,  min_radius, max_radius )); // 21
  th1_templates.push_back ( makeTH1F ("profile50"             , n_radii + 1 ,  min_radius, max_radius )); // 22
  th1_templates.push_back ( makeTH1F ("profile90"             , n_radii + 1 ,  min_radius, max_radius )); // 23
  th1_templates.push_back ( makeTH1F ("profile95"             , n_radii + 1 ,  min_radius, max_radius )); // 24
  th1_templates.push_back ( makeTH1F ("profile99"             , n_radii + 1 ,  min_radius, max_radius )); // 25
  th1_templates.push_back ( makeTH1F ("nCoreJets"             , 10, -0.5, 9.5 )); // 26
  th1_templates.push_back ( makeTH1F ("leadCoreJetDR"         , 100, 0., 0.4 )); // 27
  th1_templates.push_back ( makeTH1F ("leadCoreJetFraction"   , 100, 0., 1.  )); // 28
  th1_templates.push_back ( makeTH1F ("volume"                , 100, -10, 10)); // 29
  th1_templates.push_back ( makeTH1F ("length"                , 100, -10, 10)); // 30
  
  std::vector<TH2F*> th2_templates;
  th2_templates.push_back ( makeTH2F ("jetPt_vs_depth"      , 100, 0, 250, 200 ,  0. ,  1000.  ));
  th2_templates.push_back ( makeTH2F ("jetPt_vs_maxRHDepth" , 100, 0, 250, 200 ,  0. ,  1000.  ));
  th2_templates.push_back ( makeTH2F ("NPFCands_vs_NSubJets", 51 , -0.5, 50.5, 5 , -0.5, 4.5 ));

  std::map<std::string, std::vector<TH1F*> > m_quark_rcut_th1;
  std::map<std::string, std::vector<TH1F*> > m_gluon_rcut_th1;
  std::map<std::string, std::vector<TH2F*> > m_quark_rcut_th2;
  std::map<std::string, std::vector<TH2F*> > m_gluon_rcut_th2;
  
  int n_th1_templates = th1_templates.size();
  int n_th2_templates = th2_templates.size();
  int n_rcutValues    = rcut_values -> size();
  char quark_hist_name[100];
  char gluon_hist_name[100];

  for (int i_th1_template = 0; i_th1_template < n_th1_templates; ++i_th1_template){
    for (int i_rcutValue = 0; i_rcutValue < n_rcutValues; ++i_rcutValue ){
      
      TH1F * hist_template = th1_templates[i_th1_template];
      
      sprintf(quark_hist_name, "%s_quarkPruned%sJets", hist_template -> GetName(), (*rcut_values)[i_rcutValue].c_str());
      sprintf(gluon_hist_name, "%s_gluonPruned%sJets", hist_template -> GetName(), (*rcut_values)[i_rcutValue].c_str());
      
      TH1F * quark_hist = makeTH1F(quark_hist_name, 
				   hist_template -> GetNbinsX(), 
				   hist_template -> GetXaxis() -> GetXmin(),
				   hist_template -> GetXaxis() -> GetXmax() );
				   
      TH1F * gluon_hist = makeTH1F(gluon_hist_name, 
				   hist_template -> GetNbinsX(), 
				   hist_template -> GetXaxis() -> GetXmin(),
				   hist_template -> GetXaxis() -> GetXmax() );

      m_quark_rcut_th1[(*rcut_values)[i_rcutValue]].push_back(quark_hist);
      m_gluon_rcut_th1[(*rcut_values)[i_rcutValue]].push_back(gluon_hist);
      
    }
  }

  
  for (int i_th2_template = 0; i_th2_template < n_th2_templates; ++i_th2_template){
    for (int i_rcutValue = 0; i_rcutValue < n_rcutValues; ++i_rcutValue ){
      
      TH2F * hist_template = th2_templates[i_th2_template];
      
      sprintf(quark_hist_name, "%s_quarkPruned%sJets", hist_template -> GetName(), (*rcut_values)[i_rcutValue].c_str());
      sprintf(gluon_hist_name, "%s_gluonPruned%sJets", hist_template -> GetName(), (*rcut_values)[i_rcutValue].c_str());
      
      TH2F * quark_hist = makeTH2F(quark_hist_name, 
				   hist_template -> GetNbinsX(), 
				   hist_template -> GetXaxis() -> GetXmin(),
				   hist_template -> GetXaxis() -> GetXmax(),
				   hist_template -> GetNbinsY(), 
				   hist_template -> GetYaxis() -> GetXmin(),
				   hist_template -> GetYaxis() -> GetXmax());
				   
      TH2F * gluon_hist = makeTH2F(gluon_hist_name, 
				   hist_template -> GetNbinsX(), 
				   hist_template -> GetXaxis() -> GetXmin(),
				   hist_template -> GetXaxis() -> GetXmax(),
				   hist_template -> GetNbinsY(), 
				   hist_template -> GetYaxis() -> GetXmin(),
				   hist_template -> GetYaxis() -> GetXmax());
				   
      m_quark_rcut_th2[(*rcut_values)[i_rcutValue]].push_back(quark_hist);
      m_gluon_rcut_th2[(*rcut_values)[i_rcutValue]].push_back(gluon_hist);
      
    }
  }

  
  
  //--------------------------------------------------------------------------------
  // Loop over the events
  //--------------------------------------------------------------------------------
  
  for (int iEvent = 0; iEvent < n_events; ++iEvent){

    //--------------------------------------------------------------------------------
    // Tell the user where we are
    //--------------------------------------------------------------------------------

    if ( (iEvent + 1) <= 10 || (iEvent + 1) % 100 == 0 ) 
      std::cout << "Processing event " << (iEvent + 1) << "/" << n_events << std::endl;
    
    //--------------------------------------------------------------------------------
    // Get each entry in the event
    //--------------------------------------------------------------------------------

    tree -> GetEntry (iEvent);

    //--------------------------------------------------------------------------------
    // GEN particle collections
    //--------------------------------------------------------------------------------
    
    // All GEN particles
    CollectionPtr c_gen_all  ( new Collection(*tree, tree -> GenParticlePt -> size()));

    // std::cout << "------------------------------------------------------------" << std::endl;
    // c_gen_all ->  examine <GenParticle> ( "All GEN particles" );
    // 
    // continue;

    // GEN particles for jet matching
    CollectionPtr c_partons  = c_gen_all -> SkimByID<GenParticle>(GEN_PARTICLE_IS_FINAL_STATE_PARTON);
    CollectionPtr c_gen_vbfq = c_gen_all -> SkimByID<GenParticle>(GEN_PARTICLE_IS_HARD_SCATTER_VBF_QUARK);
    CollectionPtr c_gen_tau  = c_gen_all -> SkimByID<GenParticle>(GEN_PARTICLE_IS_HARD_SCATTER_TAU);

    //--------------------------------------------------------------------------------
    // PFJet collections
    //--------------------------------------------------------------------------------

    CollectionPtr c_pfjet_all  ( new Collection(*tree, tree -> PFCA4JetPt -> size()));
    CollectionPtr c_pfjet_minPt       = c_pfjet_all   -> SkimByMinPt<PFPrunedJet> ( pfjet_pt_minimum ) ;
    CollectionPtr c_pfjet_fid         = c_pfjet_all   -> SkimByAbsEtaRange<PFPrunedJet> ( HGCAL_abseta_min, HGCAL_abseta_max );
    CollectionPtr c_pfjet_minPtAndFid = c_pfjet_minPt -> SkimByAbsEtaRange<PFPrunedJet> ( HGCAL_abseta_min, HGCAL_abseta_max );

    CollectionPtr c_pfcorejet_all  ( new Collection(*tree, tree -> PFAK1p5JetPt -> size()));
    CollectionPtr c_pfcorejet_minPt       = c_pfcorejet_all   -> SkimByMinPt<PFCoreJet> ( pfcorejet_pt_minimum ) ;
    CollectionPtr c_pfcorejet_minPtAndFid = c_pfcorejet_minPt -> SkimByAbsEtaRange<PFCoreJet> ( HGCAL_abseta_min, HGCAL_abseta_max );

    //--------------------------------------------------------------------------------
    // Clusters
    //--------------------------------------------------------------------------------

    CollectionPtr c_hgceeClusters_all  ( new Collection (*tree, tree -> HGCEEPFClusterPt  -> size()));
    CollectionPtr c_hgchefClusters_all ( new Collection (*tree, tree -> HGCHEFPFClusterPt -> size()));
    CollectionPtr c_hgchebClusters_all ( new Collection (*tree, tree -> HGCHEBPFClusterPt -> size()));
    
    //--------------------------------------------------------------------------------
    // GenJet collections
    //--------------------------------------------------------------------------------

    /*
    CollectionPtr c_genjet_all ( new Collection(*tree, tree -> GenJetPt -> size()));
    int n_genjet = c_genjet_all -> GetSize();

    for (int i_genjet = 0; i_genjet < n_genjet; ++i_genjet){
      GenJet genjet = c_genjet_all -> GetConstituent<GenJet>(i_genjet);
      int flavor = getFlavor( genjet, c_partons );
      if ( flavor == 0 ) continue;
      PFPrunedJet jet_matched_reco = c_pfjet_all -> GetClosestInDR<PFPrunedJet, GenJet>(genjet);
      double deltaR = jet_matched_reco.DeltaR( &genjet );
      double eta    = jet_matched_reco.Eta();
      double pt     = jet_matched_reco.Pt();
      
      all_recojet_matched_matchDR  -> Fill ( deltaR );
      all_recojet_matched_eta      -> Fill ( eta    );
      all_recojet_matched_pt       -> Fill ( pt     );
                                  
      if ( abs(genjet.Eta()) > HGCAL_abseta_min && 
	   abs(genjet.Eta()) < HGCAL_abseta_max ){
	
	fid_recojet_matched_matchDR -> Fill ( deltaR ) ;
	fid_recojet_matched_eta     -> Fill ( eta    ) ;
	fid_recojet_matched_pt      -> Fill ( pt     ) ;
      }
    }
    */

    //--------------------------------------------------------------------------------
    // Match PFJets 
    //--------------------------------------------------------------------------------

    int n_gen_vbfq = c_gen_vbfq -> GetSize();

    for (int i_gen_vbfq = 0; i_gen_vbfq < n_gen_vbfq; ++i_gen_vbfq){

      GenParticle vbfq_gen  = c_gen_vbfq    -> GetConstituent<GenParticle> (i_gen_vbfq);
      PFPrunedJet vbfq_reco = c_pfjet_minPt -> GetClosestInDR<PFPrunedJet, GenParticle>(vbfq_gen);      

      if ( vbfq_reco.GetRawIndex() < 0 ) continue;
      double pull, rawPull;
      if ( vbfq_gen.Pt() > 0. ) pull    = (vbfq_reco.Pt()    - vbfq_gen.Pt()) / vbfq_gen.Pt();
      if ( vbfq_gen.Pt() > 0. ) rawPull = (vbfq_reco.PtRaw() - vbfq_gen.Pt()) / vbfq_gen.Pt();
      else continue;
      
      bool isFid = ( fabs(vbfq_gen.Eta()) >= HGCAL_abseta_min &&
		     fabs(vbfq_gen.Eta()) <= HGCAL_abseta_max );

      double deltaR = vbfq_reco.DeltaR(&vbfq_gen);
      if ( deltaR > maximum_deltaR_match ) continue;

      all_vbfq_ptVsPull -> Fill ( vbfq_gen.Pt(), pull );
      all_vbfq_pull     -> Fill ( pull );
      all_vbfq_rawPull  -> Fill ( rawPull );
      all_vbfq_gen_pt   -> Fill ( vbfq_gen.Pt() );
      all_vbfq_reco_pt  -> Fill ( vbfq_reco.Pt() );
      all_vbfq_gen_eta  -> Fill ( vbfq_gen.Eta() );
      all_vbfq_reco_eta -> Fill ( vbfq_reco.Eta() );
      all_vbfq_matchDR  -> Fill ( deltaR );

      if ( isFid ){
	fid_vbfq_reco_chargedFraction -> Fill ( vbfq_reco.getChargedFraction() );
	fid_vbfq_reco_neutralFraction -> Fill ( vbfq_reco.getNeutralFraction() );
	fid_vbfq_ptVsPull -> Fill ( vbfq_gen.Pt(), pull );
	fid_vbfq_pull     -> Fill ( pull );
	fid_vbfq_rawPull  -> Fill ( rawPull );
	fid_vbfq_gen_pt   -> Fill ( vbfq_gen.Pt() );
	fid_vbfq_reco_pt  -> Fill ( vbfq_reco.Pt() );
	fid_vbfq_gen_eta  -> Fill ( vbfq_gen.Eta() );
	fid_vbfq_reco_eta -> Fill ( vbfq_reco.Eta() );
	fid_vbfq_matchDR  -> Fill ( vbfq_reco.DeltaR(&vbfq_gen));
      }
    }

    int n_gen_tau = c_gen_tau -> GetSize();
    for (int i_gen_tau = 0; i_gen_tau < n_gen_tau; ++i_gen_tau){
      GenParticle tau_gen  = c_gen_tau  -> GetConstituent<GenParticle> (i_gen_tau);
      PFPrunedJet tau_reco = c_pfjet_all -> GetClosestInDR<PFPrunedJet, GenParticle>(tau_gen);
      if ( tau_reco.GetRawIndex() < 0 ) continue;
      double pull, rawPull;
      if ( tau_gen.Pt() > 0. ) pull    = (tau_reco.Pt()    - tau_gen.Pt()) / tau_gen.Pt();
      if ( tau_gen.Pt() > 0. ) rawPull = (tau_reco.PtRaw() - tau_gen.Pt()) / tau_gen.Pt();
      bool isFid = ( fabs(tau_gen.Eta()) >= HGCAL_abseta_min &&
		     fabs(tau_gen.Eta()) <= HGCAL_abseta_max );


      all_tau_ptVsPull -> Fill ( tau_gen.Pt(), pull );
      all_tau_pull     -> Fill ( pull );
      all_tau_rawPull  -> Fill ( rawPull );
      all_tau_gen_pt   -> Fill ( tau_gen.Pt() );
      all_tau_reco_pt  -> Fill ( tau_reco.Pt() );
      all_tau_gen_eta   -> Fill ( tau_gen.Eta() );
      all_tau_reco_eta  -> Fill ( tau_reco.Eta() );

      if ( isFid ){
	fid_tau_ptVsPull -> Fill ( tau_gen.Pt(), pull );
	fid_tau_pull     -> Fill ( pull );
	fid_tau_rawPull  -> Fill ( rawPull );
	fid_tau_gen_pt   -> Fill ( tau_gen.Pt() );
	fid_tau_reco_pt  -> Fill ( tau_reco.Pt() );
	fid_tau_gen_eta   -> Fill ( tau_gen.Eta() );
	fid_tau_reco_eta  -> Fill ( tau_reco.Eta() );
      }
    }

    //--------------------------------------------------------------------------------
    // Loop over rcut values
    //--------------------------------------------------------------------------------

    for (int i_rcutValue = 0; i_rcutValue < n_rcutValues; ++i_rcutValue){

      fillPlots<PFPrunedJet> ( c_pfjet_minPtAndFid, c_pfcorejet_minPtAndFid , c_partons,
			       c_hgceeClusters_all, c_hgchefClusters_all, c_hgchebClusters_all, 
			       likelihoods[i_rcutValue], i_rcutValue,
    			       m_quark_rcut_th1[(*rcut_values)[i_rcutValue]], 
    			       m_gluon_rcut_th1[(*rcut_values)[i_rcutValue]], 
    			       m_quark_rcut_th2[(*rcut_values)[i_rcutValue]], 
    			       m_gluon_rcut_th2[(*rcut_values)[i_rcutValue]] );
      
    }
    // end loop over r-cut values
  } // end loop over events
} // end loop function
void analysisClass::Loop(){

  std::cout << "analysisClass::Loop() begins" <<std::endl;   
  if (fChain == 0) return;
  
  //--------------------------------------------------------------------------
  // Verbose? Or not?
  //--------------------------------------------------------------------------
  
  bool verbose = !true;
  
  //--------------------------------------------------------------------------
  // Decide which plots to save (default is to save everything)
  //--------------------------------------------------------------------------
  
  fillSkim                         ( !true  ) ;
  fillAllPreviousCuts              ( !true  ) ;
  fillAllOtherCuts                 ( !true  ) ;
  fillAllSameLevelAndLowerLevelCuts( !true  ) ;
  fillAllCuts                      ( !true  ) ;

  /*//------------------------------------------------------------------
   *
   *
   *      
   *      Get all Pre-cut values!
   *
   *
   *
   *///-----------------------------------------------------------------

  //--------------------------------------------------------------------------
  // Cuts for physics objects selection
  //--------------------------------------------------------------------------

  // jet cuts
  double jet_PtCut               = getPreCutValue1("jet_PtCut");
  double jet_EtaCut              = getPreCutValue1("jet_EtaCut");
  double jet_ele_DeltaRCut       = getPreCutValue1("jet_ele_DeltaRCut") ;
  double jet_muon_DeltaRCut      = getPreCutValue1("jet_muon_DeltaRCut");
  double jet_hltMatch_DeltaRCut  = getPreCutValue1("jet_hltMatch_DeltaRCut");

  // muon cuts
  double muon_EtaCut             = getPreCutValue1("muon_EtaCut");
  double muon_PtCut              = getPreCutValue1("muon_PtCut");
  double muon_hltMatch_DeltaRCut = getPreCutValue1("muon_hltMatch_DeltaRCut");

  // electron cuts
  double ele_PtCut    	         = getPreCutValue1("ele_PtCut");
  double ele_hltMatch_DeltaRCut  = getPreCutValue1("ele_hltMatch_DeltaRCut");

  //--------------------------------------------------------------------------
  // Tell the user how many entries we'll look at
  //--------------------------------------------------------------------------

  Long64_t nentries = fChain->GetEntries();
  // Long64_t nentries = 1000;
  std::cout << "analysisClass::Loop(): nentries = " << fChain -> GetEntries() << std::endl;   
  
  //--------------------------------------------------------------------------
  // Create HLT collections in advance (won't need all of them)
  //--------------------------------------------------------------------------
  
  // Signal
  CollectionPtr c_hltEle30_Signal_all;
  CollectionPtr c_hltPFJetNoPU25_Signal_all;
  CollectionPtr c_hltPFJetNoPU100_Signal_all;
  CollectionPtr c_hltDoubleEle_Signal_all;

  // Tag and probe
  CollectionPtr c_hltEle27WP80_all;

  //--------------------------------------------------------------------------
  // Create historgams
  //--------------------------------------------------------------------------

  CreateUserTH1D( "nEle_all"              , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_pass_ejj"         , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_pass_eejj_veto"   , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_pass_eejj_noveto" , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_pass_enujj_veto"  , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_pass_enujj_noveto", 6, -0.5, 5.5 );
  
  CreateUserTH1D( "nEle_ele1Pass"         , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_ele2Pass_eejj"    , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_passVeto_enujj"   , 6, -0.5, 5.5 );
  CreateUserTH1D( "nEle_passVeto_eejj"    , 6, -0.5, 5.5 );
  CreateUserTH1D( "nJet_jet1Pass"         , 17, -0.5, 16.5 );
  CreateUserTH1D( "nJet_jet2Pass"         , 17, -0.5, 16.5 );  
  CreateUserTH1D( "MET_metPass_enujj"     , 200, 0, 2000 );

  /*//------------------------------------------------------------------
   *
   *
   *      
   *      Start analysis loop!
   *
   *
   *
   *///-----------------------------------------------------------------
  
  Long64_t nbytes = 0, nb = 0;
  for (Long64_t jentry=0; jentry<nentries;jentry++) {
    Long64_t ientry = LoadTree(jentry);
    if (ientry < 0) break;
    nb = fChain->GetEntry(jentry);   nbytes += nb;
    
    //-----------------------------------------------------------------
    // Print progress
    //-----------------------------------------------------------------
    
    if(jentry < 10 || jentry%1000 == 0) std::cout << "analysisClass::Loop(): jentry = " << jentry << std::endl;   
    
    //-----------------------------------------------------------------
    // Get access to HLT decisions
    //-----------------------------------------------------------------

    getTriggers ( HLTKey, HLTInsideDatasetTriggerNames, HLTInsideDatasetTriggerDecisions,  HLTInsideDatasetTriggerPrescales ) ; 
        
    //-----------------------------------------------------------------
    // Get access to HLT filter objects
    //-----------------------------------------------------------------
    
    HLTFilterObjectCollectionHelper helper (*this);
    
    c_hltEle30_Signal_all        = helper.GetHLTFilterObjects("hltEle30CaloIdVTTrkIdTDphiFilter");
    c_hltPFJetNoPU25_Signal_all  = helper.GetHLTFilterObjects("hltEle30CaloIdVTTrkIdTDiCentralPFNoPUJet25EleCleaned");
    c_hltPFJetNoPU100_Signal_all = helper.GetHLTFilterObjects("hltEle30CaloIdVTTrkIdTDiCentralPFNoPUJet100EleCleaned");
    c_hltDoubleEle_Signal_all    = helper.GetHLTFilterObjects("hltDiEle33CaloIdLGsfTrkIdVLDPhiDoubleFilter");
    
    //-----------------------------------------------------------------
    // Define initial, inclusive collections for physics objects
    //-----------------------------------------------------------------
    
    CollectionPtr c_ele_all   ( new Collection(*this, ElectronPt -> size()));
    CollectionPtr c_muon_all  ( new Collection(*this, MuonPt     -> size()));
    CollectionPtr c_pfjet_all ( new Collection(*this, PFJetPt    -> size()));
    
    //-----------------------------------------------------------------
    // ID electrons
    //-----------------------------------------------------------------

    CollectionPtr c_ele_final;
    CollectionPtr c_ele_final_ptCut;
    
    CollectionPtr c_ele_HEEP  = c_ele_all -> SkimByID <Electron> ( HEEP );
    c_ele_final               = c_ele_HEEP;
    c_ele_final_ptCut         = c_ele_final -> SkimByMinPt<Electron>( ele_PtCut  );
    
    //-----------------------------------------------------------------
    // ID muons
    //-----------------------------------------------------------------
    
    CollectionPtr c_muon_eta2p1      = c_muon_all       -> SkimByEtaRange<Muon> ( -muon_EtaCut, muon_EtaCut );
    CollectionPtr c_muon_eta2p1_ID   = c_muon_eta2p1    -> SkimByID      <Muon> ( MUON_TIGHT_PFISO04 );
    CollectionPtr c_muon_final       = c_muon_eta2p1_ID;
    CollectionPtr c_muon_final_ptCut = c_muon_final     -> SkimByMinPt   <Muon> ( muon_PtCut );
    
    //-----------------------------------------------------------------
    // ID jets
    //-----------------------------------------------------------------
    
    CollectionPtr c_pfjet_central                     = c_pfjet_all                          -> SkimByEtaRange   <PFJet>          ( -jet_EtaCut, jet_EtaCut   );
    CollectionPtr c_pfjet_central_ID                  = c_pfjet_central                      -> SkimByID         <PFJet>          ( PFJET_LOOSE );    
    CollectionPtr c_pfjet_central_ID_noMuonOverlap    = c_pfjet_central_ID                   -> SkimByVetoDRMatch<PFJet, Muon>    ( c_muon_final_ptCut   , jet_ele_DeltaRCut  );
    CollectionPtr c_pfjet_central_ID_noLeptonOverlap  = c_pfjet_central_ID_noMuonOverlap     -> SkimByVetoDRMatch<PFJet, Electron>( c_ele_final_ptCut    , jet_muon_DeltaRCut );
    CollectionPtr c_pfjet_final                       = c_pfjet_central_ID_noLeptonOverlap;
    CollectionPtr c_pfjet_final_ptCut                 = c_pfjet_final                        -> SkimByMinPt      <PFJet>          ( jet_PtCut );
    
    //------------------------------------------------------------------
    // Map triggers to decisions and prescales
    //------------------------------------------------------------------

    getTriggers ( HLTKey, HLTInsideDatasetTriggerNames, HLTInsideDatasetTriggerDecisions,  HLTInsideDatasetTriggerPrescales ) ; 

    //------------------------------------------------------------------
    // Get JSON and trigger decisions
    //------------------------------------------------------------------
    
    bool passed_json = passJSON ( run, ls , isData );
    bool trigger_fired = triggerFired ( "HLT_Ele30_CaloIdVT_TrkIdT_PFNoPUJet100_PFNoPUJet25_v8" );
    
    //-----------------------------------------------------------------
    // How many ID'd objects are there?
    //-----------------------------------------------------------------
    
    int n_ele   = c_ele_final   -> GetSize();
    int n_jet   = c_pfjet_final -> GetSize();

    //-----------------------------------------------------------------
    // Get ready to fill variables 
    //-----------------------------------------------------------------

    resetCuts();
    
    //------------------------------------------------------------------
    // Fill cut values
    //------------------------------------------------------------------

    fillVariableWithValue ( "PassJSON"    , int ( passed_json    ) );
    fillVariableWithValue ( "PassTrigger" , int ( trigger_fired  ) );
        
    //-----------------------------------------------------------------
    // Evaluate the cuts
    //-----------------------------------------------------------------    
    
    evaluateCuts();

    //-----------------------------------------------------------------    
    // Did we pass the minimum?
    //-----------------------------------------------------------------    
    
    bool pass_minimum = passedCut( "PassJSON" ) && passedCut ( "PassTrigger" );

    //-----------------------------------------------------------------    
    // Declare purity requirements
    //-----------------------------------------------------------------    

    bool jet1_pass              = false;
    bool jet2_pass              = false;
    bool ele1_pass              = false;
    bool ele2_pass_eejj         = false;
    bool met_pass_enujj         = false;
    bool ele_pass_veto_enujj    = false;
    bool ele_pass_veto_eejj     = false;

    bool passAll_ejj            = false;
    bool passAll_eejj_veto      = false;
    bool passAll_eejj_noveto    = false;
    bool passAll_enujj_veto     = false;
    bool passAll_enujj_noveto   = false;
    
    //-----------------------------------------------------------------    
    // Evaluate purity requirements
    //-----------------------------------------------------------------    
    
    // electrons

    if ( n_ele >= 1 ) { 
      Electron ele1 = c_ele_final -> GetConstituent<Electron>(0);
      if ( ele1.Pt() > 45. ) { 
	ele1_pass  = true;
      }
    }

    if ( n_ele >= 2 ) { 
      Electron ele2 = c_ele_final -> GetConstituent<Electron>(1);
      if ( ele2.Pt() > 45. ) ele2_pass_eejj = true;
    }

    if ( n_ele == 1 ) ele_pass_veto_enujj = true;
    if ( n_ele == 2 ) ele_pass_veto_eejj  = true;
    
    // jets ( same for both analyses ) 
    

    if ( n_jet >= 1 ){
      PFJet jet1 = c_pfjet_final -> GetConstituent<PFJet>(0);
      if ( jet1.Pt () >= 125. ) jet1_pass = true;
    }
    
    if ( n_jet >= 2 ){
      PFJet jet2 = c_pfjet_final -> GetConstituent<PFJet>(1);
      if ( jet2.Pt () >= 45. ) jet2_pass = true;
    }

    if ( PFMETType01XYCor -> at (0) > 45. ) met_pass_enujj = true;

    //-----------------------------------------------------------------    
    // Combine eejj purity requirements
    //-----------------------------------------------------------------    
    
    if ( ele1_pass           &&
	 jet1_pass           && 
	 jet2_pass           ){
      passAll_ejj          = true;
    }

    if ( ele1_pass           &&
	 ele2_pass_eejj      && 
	 jet1_pass           && 
	 jet2_pass           ){
      passAll_eejj_noveto  = true;
    }

    if ( ele1_pass           &&
	 ele2_pass_eejj      && 
	 ele_pass_veto_eejj  && 
	 jet1_pass           && 
	 jet2_pass           ){
      passAll_eejj_veto    = true;
    }

    if ( ele1_pass           &&
	 met_pass_enujj      && 
	 jet1_pass           && 
	 jet2_pass           ){
      passAll_enujj_noveto = true;
    }

    if ( ele1_pass           &&
	 ele_pass_veto_enujj && 
	 met_pass_enujj      && 
	 jet1_pass           && 
	 jet2_pass           ){
      passAll_enujj_veto   = true;
    }
    
    //-----------------------------------------------------------------    
    // Act on outcome of purity requirements
    //-----------------------------------------------------------------    
    
    FillUserTH1D ( "nEle_all" , n_ele );
    
    if ( passAll_ejj          ) FillUserTH1D ( "nEle_pass_ejj"          , n_ele );
    if ( passAll_eejj_veto    ) FillUserTH1D ( "nEle_pass_eejj_veto"    , n_ele );
    if ( passAll_eejj_noveto  ) FillUserTH1D ( "nEle_pass_eejj_noveto"  , n_ele );
    if ( passAll_enujj_veto   ) FillUserTH1D ( "nEle_pass_enujj_veto"   , n_ele );
    if ( passAll_enujj_noveto ) FillUserTH1D ( "nEle_pass_enujj_noveto" , n_ele );
    					                               
    if ( met_pass_enujj       ) FillUserTH1D ( "MET_metPass_enujj"      , PFMETType01XYCor -> at (0) );
    if ( jet1_pass            ) FillUserTH1D ( "nJet_jet1Pass"          , n_jet );
    if ( jet2_pass            ) FillUserTH1D ( "nJet_jet2Pass"          , n_jet );
    if ( ele1_pass            ) FillUserTH1D ( "nEle_ele1Pass"          , n_ele );
    if ( ele2_pass_eejj       ) FillUserTH1D ( "nEle_ele2Pass_eejj"     , n_ele );
    if ( ele_pass_veto_enujj  ) FillUserTH1D ( "nEle_passVeto_enujj"    , n_ele ); 
    if ( ele_pass_veto_eejj   ) FillUserTH1D ( "nEle_passVeto_eejj"     , n_ele ); 
    
  }

  std::cout << "analysisClass::Loop() ends" <<std::endl;   
  
}