// // /* class SobIter: root implementation of the S/B Iterative method for selection tuning Version 2.0 Released 30 April 09 Further Information/Inquiries: Nikolaos.Rompotis@Cern.ch Nikolaos Rompotis - 23 March 2009 - initial release 26 March 09: Detector specific tuning implemented 03 April 09: bug corrected in TChain implementation that was stopping the code when more than one files for bkg were specified 30 April 09: version 2.0 This implementation gives identical results with the previous version, but has some more flexibility in the definition of signal and bkg. Instead of giving a signal and bkg files a signal filter and a bkg filter is defined in the input configuration and the electrons are read from a single dataset 11 May 09: version 2.1 enables to use an artificially lower cut in any variable that we want 22 June 09: version 3.1 bug is corrected in sig/bkg mc values code extended to receive many different types as input 22 Sept 09: modification for the october exersize 15 Marc 10: met type chosen in cfg, preselection option in cfg some refinements in order to be able to calculate the S/B init old cfg still work, but the numbers may not have the same interpretation TO BE DONE: proper integration of Zee tuning, inverted cuts */ #include #include #include "TString.h" #include "TTree.h" #include "TBranch.h" #include "TFile.h" #include "TGraph.h" #include "TMath.h" #include "TH1F.h" #include "TChain.h" #include "TDatime.h" #include "TCanvas.h" #include "TROOT.h" using namespace std; struct Filter { // this structure allows the application of a filter to an event // the filter contains ET cut, MET cut and particular type of event cut // see function PassFilter in SobIter class double ET; bool ET_LESS; double MET; bool MET_LESS; vector TYPE; bool TYPE_EQUAL; bool EXCLUDE; TString NAME; }; class SobIter { public: SobIter( double step, bool relative, double lowest_eff, double min_step, vector barrel_vars, vector endcaps_vars, vector barrel_names, vector endcaps_names, vector barrel_initcuts, vector endcaps_initcuts, vector barrel_mins, vector endcaps_mins, vector barrel_points, vector endcaps_points, double *weights, int nw, vector files, Filter signalfilter, Filter bkgfilter, vector lowerBarrel, vector lowerEndcaps, TString metType = "event_MET", int preSelType = 0); void Analysis(); private: bool RELATIVE_STEP_; double LOWEST_EFF_; vector InitCuts_barrel_; vector InitCuts_endcaps_; vector Mins_barrel_; vector Mins_endcaps_; vector Points_barrel_; vector Points_endcaps_; vector Branches_barrel_; vector Branches_endcaps_; vector Branches_; vector BranchToVariable_; vector Names_barrel_; vector Names_endcaps_; vector LowerAllowedBarrel_; vector LowerAllowedEndcaps_; vector DATAFILES_; double minStep_; double *w_; int Nw_; double Step_; bool isAlive_; Filter SignalFilter_; Filter BkgFilter_; // vector CurrentCutsBarrel_; vector CurrentCutsEndcaps_; int n_barrel_; int n_endcaps_; int n_variables_; TString metType_; bool UseExtraPreselection_; int preSelType_; // bool CheckCuts( double *values, double eta); bool PassFilter(Filter myfilter, double et, double met, short int type, short int exclusion); void PrintFilter(Filter filter); int FindName(TString name, vector vec); vector ReturnSeffForSoB (double target, TH1F* h_signal, TH1F* h_bkg, double rest_signal, double rest_bkg, double SIGNAL_INIT, double tolerance); double SobIter::Bisection (TGraph *g, double a_, double b_, double target, double tolerance); }; SobIter::SobIter( double step, bool relative, double lowest_eff, double min_step, vector barrel_vars, vector endcaps_vars, vector barrel_names, vector endcaps_names, vector barrel_initcuts, vector endcaps_initcuts, vector barrel_mins, vector endcaps_mins, vector barrel_points, vector endcaps_points, double *weights, int nw, vector files, Filter signalfilter, Filter bkgfilter, vector lowerBarrel, vector lowerEndcaps, TString metType, int preSelType) { isAlive_ =true; // check for consistency int n = (int) barrel_vars.size(); if (n != (int) barrel_initcuts.size() || n != (int) barrel_mins.size() || n != (int) barrel_points.size() || n != (int) barrel_names.size() ) { cout << "Inconsistent Number: Barrel Variables " << endl; cout << "branches: " << n << endl; cout << "init cuts: " << (int) barrel_initcuts.size() << endl; cout << "min cuts: " << (int) barrel_mins.size() << endl; cout << "points cuts: " << (int) barrel_points.size() << endl; isAlive_ = false; return; } // int n1 = (int) endcaps_vars.size(); if (n1 != (int) endcaps_initcuts.size() || n1 != (int) endcaps_mins.size() || n1 != (int) endcaps_points.size() || n1 != (int) endcaps_names.size()) { cout << "Inconsistent Number: Endcap Variables " << endl; cout << "branches: " << n1 << endl; cout << "init cuts: " << (int) endcaps_initcuts.size() << endl; cout << "min cuts: " << (int) endcaps_mins.size() << endl; cout << "points cuts: " << (int) endcaps_points.size() << endl; isAlive_ = false; return; } // if ( (int) files.size() == 0){ cout << "You must have at least one sample" << endl; isAlive_ = false; return; } if (nw == 0) { cout << "You should insert at least one weight" << endl; isAlive_ = false; return; } if (n1 == 0 && n ==0) { cout << "You should have at least one variable" << endl; isAlive_ = false; return; } InitCuts_barrel_ = barrel_initcuts; InitCuts_endcaps_ = endcaps_initcuts; Mins_barrel_ = barrel_mins; Mins_endcaps_ = endcaps_mins; Points_barrel_ = barrel_points; Points_endcaps_ = endcaps_points; Branches_barrel_ = barrel_vars; Branches_endcaps_ = endcaps_vars; Names_barrel_ = barrel_names; Names_endcaps_ = endcaps_names; LowerAllowedBarrel_ = lowerBarrel; LowerAllowedEndcaps_ = lowerEndcaps; metType_ = metType; preSelType_ = preSelType; if (preSelType_ > 0) UseExtraPreselection_ = true; else UseExtraPreselection_ = false; w_ = weights; Nw_ = nw; DATAFILES_ = files; Step_ = step; RELATIVE_STEP_ = relative; LOWEST_EFF_ = lowest_eff; minStep_ = min_step; n_barrel_ = (int) Names_barrel_.size(); n_endcaps_ = (int) Names_endcaps_.size(); /// now find the common set of branches for (int i=0; i< n_barrel_; ++i) { Branches_.push_back(Branches_barrel_[i]); BranchToVariable_.push_back(i); } int counter = 0; for (int i=0; i SOB; vector SOB_MC; vector SEFF; vector SEFF_MC; vector SOB_ERROR; vector SOB_MC_ERROR; vector SELECTION; // // prepare the input files TChain tree("probe_tree"); vector::iterator it = DATAFILES_.begin(); for ( ; it != DATAFILES_.end(); ++it) { tree.Add(*it); } // // const int N_signal = tree.GetEntries(); //cout << "Signal sample contains " << N_signal << " electrons" << endl; //return; // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ///////////////////////////////////////////////////////////////// // ////////////////////// // Sig/Bkg Branches ...........................////////////// // ..................................................//////////// // Common branch: double probe_sc_eta; // eta of the supercluster double probe_sc_et; double event_MET; short int type; // type of the event short int exclusion; // ==1 when electron belongs to event with 2 elecs // tree.SetBranchAddress("probe_sc_eta", &probe_sc_eta); tree.SetBranchAddress("probe_sc_et", &probe_sc_et); // met default case: // tree.SetBranchAddress("event_MET", &event_MET); tree.SetBranchAddress(metType_, &event_MET); // extra preselection // preSelType_ = 0 nothing extra // = 1 Valid first PXB // = 2 Dcot Dist - prechosen values // = 3 expected missing hits (Not yet implemented) // = 12 both 1 and 2 // to be replaced with biwise operators // int probe_ele_validHitInFirstPixelBarrel; double probe_ele_dist, probe_ele_dcot; if (UseExtraPreselection_) { if (preSelType_ == 1 || preSelType_ == 12) tree.SetBranchAddress("probe_ele_validHitInFirstPixelBarrel", &probe_ele_validHitInFirstPixelBarrel); if (preSelType_ == 2 || preSelType_ == 12) { tree.SetBranchAddress("probe_ele_dist", &probe_ele_dist); tree.SetBranchAddress("probe_ele_dcot", &probe_ele_dcot); } } tree.SetBranchAddress("type", &type); tree.SetBranchAddress("exclude", &exclusion); // // Signal and Bkg branches double *vars = new double[n_variables_]; for (int i =0; i< n_variables_; ++i) { tree.SetBranchAddress(Branches_[i], &vars[i]); } ////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////// /////////////////////////////////////////// //////////////////////////////////// //////////////////////// // // ITERATION LOOP // ^^^^^^^^^^^^^^ // // double signal_init = 0; // needed for the efficiency definition double signal_init_barrel = 0; double signal_init_endcaps = 0; double signal_init_mc = 0; double bkg_init_mc = 0; double bkg_init = 0; double signal_init2 = 0, bkg_init2 = 0; double signal_init_mc2 = 0, bkg_init_mc2 = 0; double sob_previous=-1; double sobInit = 0, sobInitMC = 0; double sobInitError = 0, sobInitMCError = 0; // ..................... for (int Iter = 0; Iter<100000; ++Iter) { // S/B Iteration loop // define your histograms ......................................... // barrel vector h_barrel; // signal vector b_barrel; // bkg for (int i=0; i h_endcaps; // signal vector b_endcaps; // bkg for (int i=0; i= 2) { bool pass_ConvPartner = true; if (probe_ele_dcot < 990) { pass_ConvPartner = fabs(probe_ele_dcot) > 0.02 && fabs(probe_ele_dist) > 0.02; } if (preSelType_ == 2) pass = pass && pass_ConvPartner; else if (preSelType_ == 12) { pass = pass && pass_ConvPartner && probe_ele_validHitInFirstPixelBarrel == 1; } } } bool in_barrel = fabs(probe_sc_eta) < 1.479&& n_barrel_>0; bool in_endcaps = fabs(probe_sc_eta) > 1.479&& n_endcaps_>0; bool somewhere = in_barrel || in_endcaps; // ///////// this is signal related if (PassFilter(SignalFilter_, probe_sc_et, event_MET, type, exclusion)) { ///////////////////////////////////////////////////////////// //cout << "met=" << event_MET << ", et=" << probe_sc_et if (Iter == 0) { if (in_barrel || in_endcaps) { signal_init2 += (w_[type]*w_[type]); if (in_barrel) signal_init_barrel += w_[type]; if (in_endcaps) signal_init_endcaps += w_[type]; } } // if (pass && in_barrel) { current_signal_barrel += w_[type]; dS2 += w_[type]*w_[type]; if (type == 0) current_signal_in_sigSample_eb += w_[type]; for (int i=0; i SignalFilter_.ET && Ex && somewhere) { if (type == 0) { if (Iter==0) { signal_init_mc += w_[type]; signal_init_mc2+=(w_[type]*w_[type]); } if (pass) { current_actual_signal += w_[type]; dS2_mc += w_[type]*w_[type]; } } // if (type >=1 && type <=13) { else { // all the rest are bkg if (Iter==0) { bkg_init_mc += w_[type]; bkg_init_mc2 += (w_[type]*w_[type]); } if (pass) { current_actual_bkg += w_[type]; dB2_mc += w_[type]*w_[type]; } } } ////////////////////////////////////////////////////////////////////// } // end loop over the samples // ................................................................... // ------------------------------------------------------------------- // List of the counters that you have available now ------------------ // ................................................................... // signal_init_barrel signal sample contents at Iter == 0 // signal_init_endcaps, signal_init // ................................................................... // signal_init_mc number of events with type == 0 that // pass the kinematic restrictions of the // signal sample (ET, fiducial, exclusion) // at Iter == 0 // bkg_init_mc number of events with type != 0 + // signal sample kinematic restrictions // >> may need to be modified for Zee-driven // ................................................................... // current_signal_barrel number of events in signal sample that // current_signal_endcaps pass kinematics+selection // current_bkg_barrel number of events in bkg sample that pass // current_bkg_endcaps kinematics+selection // ................................................................... // current_actual_signal number of events that pass the kinematics // current_actual_bkg + selection of the signal sample // ................................................................... // current_signal_in_sigSample number of events with type == 0 in the // current_signal_in_bkgSample signal and bkg sample // ................................................................... // to be done - slight redefinitions needed for the Zee-driven tuning // ------------------------------------------------------------------- if (Iter==0) { signal_init = signal_init_barrel + signal_init_endcaps; sobInit = signal_init/bkg_init; sobInitError = sobInit * sqrt(signal_init2/(signal_init*signal_init)+ bkg_init2/(bkg_init*bkg_init)); sobInitMC = signal_init_mc/bkg_init_mc; sobInitMCError = sobInitMC * sqrt(signal_init_mc2/(signal_init_mc*signal_init_mc)+ bkg_init_mc2/(bkg_init_mc*bkg_init_mc)); } current_signal = current_signal_barrel + current_signal_endcaps; current_bkg = current_bkg_barrel + current_bkg_endcaps; if (current_bkg == 0 || current_signal == 0) break; double sob = current_signal / current_bkg; double sob_error = sob * sqrt(dS2/(current_signal*current_signal)+ dB2/(current_bkg*current_bkg)); double sob_barrel = (current_bkg_barrel>0)?(current_signal_barrel/current_bkg_barrel):0; double sob_endcaps = (current_bkg_endcaps>0)?(current_signal_endcaps/current_bkg_endcaps):0; if (Iter==0) { // this is in order to be able to have available the S/B after presel cout << "initial S/B= " << sobInit << " +- " << sobInitError << " fromMC: " << sobInitMC << " +- " << sobInitMCError << endl; cout << "Current signal = " << current_signal << " Current bkg = " << current_bkg << ", init=" << signal_init << " sigMC=" << current_actual_signal << ", bkgMC=" << bkg_init_mc << ", sigInitMC="<0) selection += CurrentCutsBarrel_[n_barrel_-1]; else selection += "(no barrel variables)"; selection += " // "; for (int i=0; i0) selection += CurrentCutsEndcaps_[n_endcaps_-1]; else selection += "(no endcap variables)"; selection += ")"; // if (Iter == 0) { cout << "Initial Iteration: S/B=" << sob << " Initial Signal=" << signal_init << " in EB: " << signal_init_barrel << " in EE: " << signal_init_endcaps << ", Initial Conditions: " << selection << endl; } else { cout << "Iteration #" << Iter << " S/B=" << sob << "+/-" << sob_error << "; seff=" << seff << "; S="<< current_signal << "; B=" << current_bkg << "; BARREL: S/B=" << sob_barrel << "; seff=" << seff_barrel << "; ENDCAPS: S/B=" << sob_endcaps << "; seff=" << seff_endcaps << "; Cuts: " << selection << endl; } SOB.push_back(sob); SEFF.push_back(seff); SOB_ERROR.push_back(sob_error); SELECTION.push_back(selection); SOB_MC.push_back(sob_mc); SEFF_MC.push_back(seff_mc); SOB_MC_ERROR.push_back(sob_mc_error); // ----------------------------------------------------------------------- // variable tuning to be performed here -------------------------------- // // set the S/B target .................................................... double abs_step; if (RELATIVE_STEP_) { abs_step = Step_ * sob; ///if (Iter == 0) abs_step = 0.01; if (abs_step > minStep_) abs_step = minStep_; } else abs_step = Step_; double target = sob + abs_step; double tolerance = abs_step/100.; cout << "Targeting S/B " << target << ", S/B step is " << abs_step << endl; // // for each of the variables calculate the seff for the target S/B double *tmp_cuts = new double[n_barrel_+n_endcaps_]; double *tmp_seffs = new double[n_barrel_+n_endcaps_]; double *tmp_sobs = new double[n_barrel_+n_endcaps_]; double error_flag = 0; // run over the barrel variables for (int i=0; i< n_barrel_; ++i) { cout << "Working on Barrel " << Names_barrel_[i] << endl; vector a = ReturnSeffForSoB (target, &h_barrel[i], &b_barrel[i], current_signal_endcaps, current_bkg_endcaps, signal_init, tolerance); tmp_cuts[i] = a[0]; tmp_seffs[i] = a[1]; tmp_sobs[i] = a[2]; error_flag += a[3]; if (a[0]< LowerAllowedBarrel_[i]) { cout << "Cut Value Lower than Limit: cut will not be moved..."<< endl; tmp_seffs[i] = 0.; } } // run over the endcap variables for (int i=0; i< n_endcaps_; ++i) { cout << "Working on Endcaps " << Names_endcaps_[i] << endl; vector a = ReturnSeffForSoB (target, &h_endcaps[i], &b_endcaps[i], current_signal_barrel, current_bkg_barrel, signal_init, tolerance); tmp_cuts[i+n_barrel_] = a[0]; tmp_seffs[i+n_barrel_] = a[1]; tmp_sobs[i+n_barrel_] = a[2]; error_flag += a[3]; // check whether you are below a certain limit if (a[0]< LowerAllowedEndcaps_[i]) { cout << "Cut Value Lower than Limit: cut will not be moved..."<< endl; tmp_seffs[i+n_barrel_] = 0.; } } // find the maximim efficiency int imax = TMath::LocMax(n_barrel_ + n_endcaps_, tmp_seffs); double movement; if (imax tmp; tmp = CurrentCutsBarrel_; CurrentCutsBarrel_.clear(); for (int i=0; i< n_barrel_; ++i) { double cut = tmp[i]; if (i == imax) cut = tmp_cuts[imax]; CurrentCutsBarrel_.push_back(cut); } cout << "Iter #" << Iter << ": Variable Chosen: EB " << Names_barrel_[imax] << " to " << tmp_cuts[imax] << " moved by " << movement << endl; } else { vector tmp; tmp = CurrentCutsEndcaps_; CurrentCutsEndcaps_.clear(); for (int i=0; i< n_endcaps_; ++i) { double cut = tmp[i]; if (i == (imax-n_barrel_)) cut = tmp_cuts[imax]; CurrentCutsEndcaps_.push_back(cut); } cout << "Iter #" << Iter << ": Variable Chosen: EE " << Names_endcaps_[imax-n_barrel_] << " to " << tmp_cuts[imax] << " moved by " << movement << endl; } //for (int i=0; i< n_endcaps_; ++i) // cout << CurrentCutsEndcaps_[i] << endl; // release memory: delete [] tmp_cuts; delete [] tmp_seffs; delete [] tmp_sobs; // ----------------------------------------------------------------------- //cout << "Current Signal is: " << current_signal << endl // << "Current Bkg is: " << current_bkg << endl; if (seff < LOWEST_EFF_) break; if (movement == 0) break; if (sob_previous == sob || sob_previous > sob || error_flag != 0) break; sob_previous = sob; } // end S/B Iteration loop // // print out the summary of the method: const int Niter = (int) SOB.size(); cout << "Tuning Summary: " << endl; cout << "Cuts appear in the following order (BARREL/ENDCAPS): " << endl; for (int i=0; i0) cout << Names_barrel_[n_barrel_-1] << " / "; else cout << "(no barrel variables)" << " / "; for (int i=0; i0) cout << Names_endcaps_[n_endcaps_-1] << endl; else cout << "(no endcap variables)" << endl; cout << "double sob[" << Niter << "], seff[" << Niter << "], sob_mc[" << Niter << "], seff_mc[" << Niter << "]," << "sob_error[" << Niter << "], sob_mc_error[" << Niter << "];" << endl; for (int i=0;iGetBinLowEdge(i) + h_signal->GetBinWidth(i); if (sob[RealPoints-1] > max_sob && sob[RealPoints-1] < 1000. ) { // for more stable results max_sob = sob[RealPoints-1]; max_cut = cut[RealPoints-1];} if (sob[RealPoints-1] < min_sob) { min_sob = sob[RealPoints-1];} } TGraph g_sob(RealPoints, cut, sob); // this is to store the sob TGraph g_seff(RealPoints, cut, seff); // this is to store the sob // // bisection now to find the needed cut value int error_flag = 0; if (max_sob > 1000){ cout << "ERROR: Your lower limit in this variable" << " is too low: max sob > 1000!!!!!" << endl; error_flag = 1; } // if (sob[0] target) { cout << "ERROR: min S/B is "<< min_sob <<" > target "<< target << endl; cout << "Last Bin: Cut["<< RealPoints-1 <<"] = " << cut[RealPoints-1] << " Seff["<< RealPoints-1 <<"] = " << seff[RealPoints-1] << " S/B["<< RealPoints-1 <<"] = " << sob[RealPoints-1] << endl; error_flag = 2; } // // // // what happens if the target is too big if (max_sob < target) { if ( sob[0] < max_sob ) { cout << "NOTICE: S/B maximum "<< max_sob <<" is located at cut " << max_cut << " and it is smaller than the target " << target << endl; } else { cout << "ERROR: S/B max is "<< max_sob <<" < target " << target << endl; cout << "First Bin: Cut[0] = " << cut[0] << " Seff[0] = " << seff[0] << " S/B[0] = " << sob[0] << endl; } error_flag = 3; } // double tolerance = target / 1000.; ==> inserted as an argument double working_point = (error_flag == 2)?cut[RealPoints-1]:Bisection(&g_sob, max_cut, cut[RealPoints-1], target, tolerance); double working_seff = g_seff.Eval(working_point,0,"S"); if (working_seff>1. && error_flag == 0) { cout << "SERIOUS ERROR: Fitting/Bisection gives efficiency " << working_seff << " manual replacement to 1" << endl; working_seff = 1.; } double working_sob = g_sob.Eval(working_point,0,"S"); // // release memory: delete [] sob; delete [] seff; delete [] cut; vector res; res.push_back(working_point); // first entry if (error_flag == 2) { cout << "Serious Error detected: program will exit..." << endl; res.push_back(-1.); } else if (error_flag == 3) { res.push_back(-3.); cout << "No active cut here " << endl; } else if (working_point > 999.) { cout << "Your actual values is seff = " << working_seff << " but this working point will be excluded because" << " the output is 1000 - Bisection Failure!!!!" << endl; res.push_back(-1.); } else { res.push_back(working_seff); // sendond entry cout << "Working cut "<< working_point << " Working seff is " << working_seff << " Working Sob is " << working_sob << endl; } res.push_back(working_sob); // 3rd entry if (error_flag == 2) { res.push_back(1); // 4th entry } else res.push_back(0); return res; } // // this function is Bisection_Method2 from SelectionOptimizer class // written by NR - December 08 // // the meaning of tolerance is wrt the target value // i.e. if |f(c) - Target| < tolerance => stop double SobIter::Bisection (TGraph *g, double a_, double b_, double target, double tolerance) { double a = a_; double b = b_; double c = (a+b)/2.; double fa = g->Eval(a,0,"S") - target; double fb = g->Eval(b,0,"S") - target; if (fa*fb < 0) { for (int i =0; i < 100000; ++i) { c = (a + b)/2.; double fc = g->Eval(c,0,"S") - target; if (fabs(fc) < tolerance) break; if (fc*fa < 0) { fb = fc; b =c; } else if (fc*fb < 0) {fa = fc; a=c;} else break; } } else if (fa*fb == 0) return (fa == 0.0 ? a:b); else return 10000; return c; } // // // bool SobIter::PassFilter (Filter myfilter, double et, double met, short int t, short int exclusion) { // check the ET cut if (myfilter.ET>=0) { if (myfilter.ET_LESS) { // passes if et < ET if ((et < myfilter.ET) == false) return false; } else { // passes if et > ET if ((et > myfilter.ET) == false) return false; } } // check the MET cut if (myfilter.MET>=0) { if (myfilter.MET_LESS) { // passes if met < MET if ((met < myfilter.MET) == false) return false; } else { // passes if met > MET if ((met > myfilter.MET) == false) return false; } } // check the type cut vector mytypes = myfilter.TYPE; int ntypes = mytypes.size(); bool skip = false; if (ntypes == 1) { if (mytypes[0] <0) skip = true; } if (ntypes>=0 && (not skip)) { if (myfilter.TYPE_EQUAL) { // passes if t == TYPE // for at least one of the specified types bool res = false; // use logical OR: if one equality is true, then // the variable res will become true for (int i=0; i=0) { if (filter.ET_LESS) cout << "Cuts: et<" << filter.ET << endl; else cout << "Cuts: et>" << filter.ET << endl; } if (filter.MET >=0) { if (filter.MET_LESS) cout << "Cuts: met<" << filter.MET << endl; else cout << "Cuts: met>" << filter.MET << endl; } if (filter.TYPE_EQUAL) cout << "Event type =";// << filter.TYPE << endl; else cout << "Event type!=";// << filter.TYPE << endl; vector mytypes= filter.TYPE; for (int i=0; i< (int) mytypes.size(); ++i) { cout << mytypes[i] << " "; } cout << endl; if (filter.EXCLUDE) cout << "Events with a second electron are excluded" << endl; else cout << "All electrons included " << endl; cout << "End Summary for filter " << filter.NAME << endl; }