33 #include "TEventList.h"
34 #include "TDirectory.h"
38 #include "TObjArray.h"
70 cout <<
"\nfindcuts: Tool to find good selection for signal vs bkg. Ranks variables according to maximum (S*ws)^2/(S*ws+B*wb) on optionally normalised distributions.\n";
71 cout <<
" Double click on a pad applies corresponding cut and re-iterates.\n\n";
72 cout <<
"USAGE:\nfindcuts(TTree *t, TString ctlvar, TString sigcut, TString bnames, TString precut, int numvars, double qaopt, double ws, double wb, int norm, int bins)\n";
73 cout <<
" t : tree containing signal and background; if given as only argument, list of available branches are printed.\n";
74 cout <<
" ctlvar : control variable to check signal quality (e.g. invariant mass); displayed in upper left pad; excluded from branch list.\n";
75 cout <<
" sigcut : cut to isolate signal; background is selected with !(sigcut).\n";
76 cout <<
" bnames : blank separated list of branch/alias variable names to be considered; can make use of name* / *name /*name*; !(*)name(*) excludes variables (default = \"*\").\n";
77 cout <<
" precut : cut to be applied before variable ranking is done (default = \"\").\n";
78 cout <<
" qaopt : optimisation mode; qaopt=0 : best S/sqrt(S+B); -1<qaopt<0 : best signal eff for fixed bkg reduction; 0<qaopt<1 : best bkg reduction for fixed signal eff. (default = 0).\n";
79 cout <<
" numvars : number of variables to be displayed (default = 9).\n";
80 cout <<
" ws, wb : weight factors for signal & background (default = 1.0); are applied to spectra and calculations after optional normalisation.\n";
81 cout <<
" norm : normalisation of distributions before ranking (-> pdf) (default = 1); double click in control variable pad toggles 'norm' and reruns.\n";
82 cout <<
" bins : number of histogram bins, precision depending on binning (default = 500).\n\n";
83 cout <<
"Example 0: Print all available branches/aliases in tree:\n";
84 cout <<
" root [0] findcuts(mytree)\n\n";
85 cout <<
"Example 1: Analyse all branches in TTree 'mytree', control variable 'mass', and signal cut 'issignal':\n";
86 cout <<
" root [0] findcuts(mytree, \"mass\", \"issignal\")\n\n";
87 cout <<
"Example 2: Analyse all branches expect 'evcnt', 'run', those ending with 'px', 'py', or 'pz' or containing the word 'fit', after precut 'goodtracks>6&&goodphotons>2'\n";
88 cout <<
" root [0] findcuts(mytree, \"mass\", \"issignal\", \"* !evcnt !run !*p[xyz] !*fit*\", \"goodtracks>6&&goodphotons>2\")\n\n";
97 TObjArray *tok = s.Tokenize(delim);
98 int N = tok->GetEntries();
101 TString token = (((TObjString*)tok->At(
i))->String()).Strip(TString::kBoth);
102 toks.push_back(token);
119 t->SetBranchStatus(
"*",0);
125 for (uint
i=0;
i<vecpatt.size();++
i)
126 if (vecpatt[
i].BeginsWith(
"!"))
t->SetBranchStatus(
TString(vecpatt[
i](1,1000)),0);
127 else t->SetBranchStatus(vecpatt[
i],1);
130 if (ctlvar!=
"")
t->SetBranchStatus(ctlvar,0);
133 TObjArray* blist =
t->GetListOfBranches();
134 for (
int i=0; i<=blist->GetLast(); ++
i)
136 TString name = ((TBranch*)blist->UncheckedAt(i))->GetName();
138 if (
t->GetBranchStatus(name)>0)
bnam.push_back(name);
142 if (ctlvar!=
"")
t->SetBranchStatus(ctlvar,1);
148 TList *alilist =
t->GetListOfAliases();
154 for (uint i=0;i<vecpatt.size();++
i)
158 patt.ReplaceAll(
"*",
".*");
160 if (patt.BeginsWith(
"!")) {toggle = 0; patt=patt(1,1000);}
161 TRegexp regali(patt);
165 for (
int j=0; j<=alilist->GetLast(); ++j)
167 TString aliname = ((TNamed*)alilist->At(j))->GetName();
168 if (aliname(regali)!=
"") alimap[aliname] = toggle;
174 while (it != alimap.end())
176 if (it->second) { vecali.push_back(it->first);
bnam.push_back(it->first); }
181 for (uint i=0;i<vecali.size();++
i)
184 TString fml =
t->GetAlias(vecali[i]);
186 TRegexp regvar(
"[A-Za-z_][A-Za-z_0-9]*");
187 while (fml(regvar)!=
"")
190 if (
t->GetBranch(sbr)) {
t->SetBranchStatus(sbr,1);}
191 fml.Replace(fml.Index(sbr),sbr.Length(),
"");
199 cout<<
"**** Name pattern: \""<<bnames<<
"\""<<endl;
200 cout<<
"**** "<<
bnam.size()<<
" branches/aliases found: \n";
201 for (uint i=0;i<
bnam.size();++
i)
214 int nsel =
t->Draw(var+
">>hhh",
"",
"goff");
217 if (nsel>500000) nsel=500000;
218 TH1F *
h = (TH1F*)gDirectory->Get(
"hhh");
220 if (h->GetEntries()==0)
return false;
224 min=100000., max=-100000.;
225 double *
x=
t->GetV1();
226 for (
int i=0;
i<nsel;++
i)
228 if (x[
i]>max) max=x[
i];
229 if (x[
i]<min) min=x[
i];
253 TH1F
h1(
"h1",
"",
BINS,xmin,xmax);
254 TH1F
h2(
"h2",
"",
BINS,xmin,xmax);
259 t->SetEventList(
els);
260 t->Draw(var+
">>h1",
"",
"goff");
263 t->SetEventList(
elb);
264 t->Draw(var+
">>h2",
"",
"goff");
269 h1.Scale(1./h1.GetEntries());
270 h2.Scale(1./h2.GetEntries());
274 if (
fabs(qaopt)<0.0001) {h1.Scale(
Wsig); h2.Scale(
Wbkg);}
275 double h1ent = h1.Integral(), h2ent = h2.Integral();
278 double rsums=0., lsums=0., rsumb=0., lsumb=0.;
279 double bestSr = 0., bestSl=0., bestCutl=0., bestCutr=0., besteffsl=0., besteffbl=0., besteffsr=0., besteffbr=0.;
285 lsums+=h1.GetBinContent(
i);
286 lsumb+=h2.GetBinContent(
i);
289 rsums+=h1.GetBinContent(
BINS-
i+1);
290 rsumb+=h2.GetBinContent(
BINS-
i+1);
296 Sl =
FCSfc(lsums,lsumb);
297 Sr =
FCSfc(rsums,rsumb);
302 if (lsumb<=(1.+qaopt)) Sl = lsums;
303 if (rsumb<=(1.+qaopt)) Sr = rsums;
308 if (lsums>=qaopt) Sl = 1.-lsumb;
309 if (rsumb>=qaopt) Sr = 1.-rsumb;
313 if (Sl>bestSl) {bestSl=Sl; besteffsl=lsums/h1ent; besteffbl=lsumb/h2ent; bestCutl=h1.GetBinLowEdge(
i+1);}
314 if (Sr>bestSr) {bestSr=Sr; besteffsr=rsums/h1ent; besteffbr=rsumb/h2ent; bestCutr=h1.GetBinLowEdge(
BINS-
i+1);}
318 TString lcut = TString::Format(
"%s<%f",var.Data(),bestCutl);
319 TString rcut = TString::Format(
"%s>%f",var.Data(),bestCutr);
322 double invqal = 1./bestSl, invqar = 1./bestSr;
327 while (
qamap.find(invqal)!=
qamap.end() && --maxsearch>0) invqal = 1./(1./invqal+0.0001);
330 while (
qamap.find(invqar)!=
qamap.end() && --maxsearch>0) invqar = 1./(1./invqar+0.0001);
333 qamap[invqal] = lcut;
334 qamap[invqar] = rcut;
351 gStyle->SetTitleFontSize(0.08);
352 gStyle->SetPadTopMargin(0.08);
353 gStyle->SetOptStat(0);
356 t->SetBranchStatus(
"*",1);
359 double plotdim = 250;
360 if (numvars>11) plotdim=200;
362 if (numvars>4) cx=(numvars+2)/2;
363 if (numvars>11) cx=5;
364 if (numvars>14) cx=6;
365 if (numvars>17) cx=7;
367 int cy = (numvars+1)/cx;
368 if ((numvars+1)%
cx) cy+=1;
371 c1=(TCanvas*)gROOT->FindObject(
"c1");
372 if (
c1==0)
c1 =
new TCanvas(
"c1",
"c1",5,5,1000,650);
375 c1->SetWindowSize(cx*plotdim, cy*plotdim*1.1);
378 els = (TEventList*)gROOT->FindObject(
"els");
379 if (
els==0)
els =
new TEventList(
"els");
381 elb = (TEventList*)gROOT->FindObject(
"elb");
382 if (
elb==0)
elb =
new TEventList(
"elb");
384 elpre = (TEventList*)gROOT->FindObject(
"elpre");
385 if (
elpre==0)
elpre =
new TEventList(
"elpre");
399 gPad->SetFrameFillColor(18);
401 gPad->AddExec(
"ex1",
"if (gPad->GetEvent()==kButton1Double) { cout<<endl<<\" -> Toggle normalize setting.\"<<endl;"+com+
";}");
413 TRegexp
r1(cutpart+
"[-]*[0-9]*.[0-9]*");
418 if (oldcut==
"") com.ReplaceAll(
"NEWCUT",
cut);
421 com.ReplaceAll(oldcut,
cut);
422 com.ReplaceAll(
"&&NEWCUT",
"");
423 com.ReplaceAll(
"NEWCUT",
"");
426 gPad->AddExec(
"ex1",
"if (gPad->GetEvent()==kButton1Double) { cout<<endl<<\" -> Applying '"+
cut+
"'\"<<endl;"+com+
";}");
431 if (title==
"") title=var;
435 ln.SetLineColor(6); ln.SetLineStyle(7); ln.SetLineWidth(2);
438 arr.SetAngle(40); arr.SetLineWidth(2); arr.SetLineColor(6); arr.SetFillColor(6);
440 bool drawcut = (
cut!=
"");
441 int cutdir =
cut.Contains(
"<") ? -1 : 1 ;
444 double cutval = drawcut ?
TString(
cut(
max(
cut.Index(
">"),
cut.Index(
"<"))+1,1000)).Atof() : -999.;
449 TH1F
h1(
"h1",title,
BINS,xmin,xmax);
450 TH1F
h2(
"h2",title,
BINS,xmin,xmax);
452 TH1F hs(
"hs",title,
BINS,xmin,xmax);
459 t->SetEventList(
els);
461 t->SetEventList(
elb);
467 h1.Scale(1./h1.GetEntries());
468 h2.Scale(1./h2.GetEntries());
473 if (!norm) {hs.Add(&h1);hs.Add(&h2);}
476 double maxi = 1.05*
max(h1.GetMaximum(), h2.GetMaximum());
477 if (!norm) maxi = hs.GetMaximum()*1.05;
481 if (!norm) hs.DrawCopy();
482 h1.DrawCopy(norm?
"":
"same");
488 ln.DrawLine(cutval,0,cutval,maxi*0.9);
489 arr.DrawArrow(cutval,maxi*0.9,cutval+0.1*(xmax-xmin)*cutdir,maxi*0.9,0.01,
"|>");
499 int findcuts(TTree *theTree=0,
TString ctlvar=
"",
TString sigcut=
"",
TString bnames=
"",
TString precut=
"",
int numvars=9,
double qaopt=0.,
double ws=1.,
double wb=1.,
int norm=1,
int bins=500)
506 if (qaopt<-1) qaopt=-1;
507 if (qaopt>1) qaopt=1;
508 cout <<
"\nOptimising for ";
509 if (qaopt<0) cout <<
"best signal effciency for given background reduction of "<<
fabs(qaopt)<<endl;
510 if (qaopt>0) cout <<
"best background reduction for given signal efficiency of "<<qaopt<<endl;
511 else cout <<
"best significance S/sqrt(S+B)"<<endl;
514 if (numvars==0) numvars = 9;
518 cout <<
"\nTTree : "<<tname<<
"\nEvents total : "<<
t->GetEntriesFast()<<
"\nBranches total : "<<
t->GetNbranches()<<
"\nAliases total : ";
519 cout<< (
t->GetListOfAliases() ?
t->GetListOfAliases()->GetSize() : 0) <<endl;
522 comcurrent = TString::Format(
"findcuts(%s,\"%s\",\"%s\",\"%s\",\"%s\",%d,%.3f,%.3f,%.3f,%%d,%d)",
523 tname.Data(),ctlvar.Data(), sigcut.Data(),bnames.Data(),precut.Data(),numvars, qaopt, ws, wb, bins);
526 comtemplate = TString::Format(
"findcuts(%s,\"%s\",\"%s\",\"%s\",\"%s%sNEWCUT\",%d,%.3f,%.3f,%.3f,%d,%d)",
527 tname.Data(), ctlvar.Data(), sigcut.Data(),bnames.Data(),precut.Data(),precut==
""?
"":
"&&",numvars, qaopt, ws, wb, norm, bins);
531 bool printonly = (sigcut==
"");
534 if (bnames==
"") bnames=
"*";
535 if (precut==
"") precut=
"1";
543 TString bkgcut =
"!("+sigcut+
")";
544 TString sfull = precut+
"&&"+sigcut;
545 TString bfull = precut+
"&&"+bkgcut;
553 t->Draw(
">>els",sfull);
554 t->Draw(
">>elb",bfull);
555 t->Draw(
">>elpre",precut);
559 N0s =
t->GetEntries(sigcut);
560 N0b =
t->GetEntries(bkgcut);
562 cout <<
"Events selected : "<<
elpre->GetN()<<endl;
570 if (printonly)
return;
572 if (
t->GetBranch(ctlvar)==0) {cout <<
"**** Unknown control variable: "<<ctlvar<<endl<<endl;
return;}
584 cout <<
"+-----------+-----------+\n";
588 for (uint
i=0;
i<
bnam.size();++
i)
592 while ((
double)i/(
double)
bnam.size()>ticks/25.) { cout <<
"#"<<flush; ticks++; }
600 while (it !=
qamap.end() && cnt++<numvars)
602 double qa = it->first;
607 printf(
"(%2d) %-25s : qa = %6.3f (eff_s = %5.3f, eff_b = %5.3f)\n", cnt, cut.Data(), 1./qa,
sigeff[
cut],
bkgeff[
cut]);
616 else cout <<
"\n**** No "<<(
Nb==0?
"background":
"signal")<<
" events left. No ranking possible."<<endl;
618 t->SetBranchStatus(
"*",1);
622 cout <<
"\nCommand:\n"<<TString::Format(comcurrent.Data(),
normalize)<<endl;
627 double pur =
normalize ? ws*effs/(ws*effs+wb*
effb) : ws*Ns/(ws*Ns+wb*Nb);
628 printf(
"\nEFF_S = %5.3f (%d/%d) EFF_B = %5.3f (%d/%d) PUR = %5.3f S/sqrt(S+B) %s= %6.3f\n",effs, Ns,
N0s, effb, Nb,
N0b, pur,
normalize?
"norm'd ":
"", qa);
630 c1->cd();
c1->Update();
int FCSplitString(TString s, TString delim, StrVec &toks)
printf("RealTime=%f seconds, CpuTime=%f seconds\n", rtime, ctime)
void FCPrepareTree(TString bnames, TString ctlvar)
friend F32vec4 sqrt(const F32vec4 &a)
bool FCFindLimits(TString var, double &min, double &max)
friend F32vec4 max(const F32vec4 &a, const F32vec4 &b)
std::map< TString, int > StrIntMap
int findcuts(TTree *theTree=0, TString ctlvar="", TString sigcut="", TString bnames="", TString precut="", int numvars=9, double qaopt=0., double ws=1., double wb=1., int norm=1, int bins=500)
std::map< int, double > effb
std::map< double, TString > DblStrMap
friend F32vec4 min(const F32vec4 &a, const F32vec4 &b)
friend F32vec4 fabs(const F32vec4 &a)
std::vector< TString > StrVec
std::map< TString, double > StrDblMap
void FCDrawVariable(TString var, int numpad, int norm=1, TString cut="")
std::map< int, double > effs
double FCQaVar(TString var, double qaopt=0)
double FCSfc(double S, double B)
std::map< double, TString >::iterator DblStrMapIt
std::map< TString, int >::iterator StrIntMapIt