CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
SideBandSubtraction.cc
Go to the documentation of this file.
1 // Author: David Bjergaard
3 //
4 // Library for Generic Sideband Subtraction Methods.
5 //
6 // This library is designed to be a tool which serves two purposes.
7 // Its primary purpose is to provide a generic framework for doing
8 // sideband subtraction. It will also plug into current tag and probe
9 // modules to prevent code duplication and redundancy.
10 //
12 
14 // System includes
15 #include <iostream>
16 #include <cstdlib>
17 #include <sstream>
18 
19 // ROOT includes
20 #include <TCanvas.h>
21 #include <TFile.h>
22 #include <TF1.h>
23 #include <TH1F.h>
24 #include <TString.h>
25 #include <TKey.h>
26 #include <TClass.h>
27 
28 // RooFit includes
29 #include <RooFitResult.h>
30 #include <RooRealVar.h>
31 #include <RooAbsPdf.h>
32 #include <RooDataSet.h>
33 #include <RooPlot.h>
34 
35 using namespace RooFit;
36 using std::cout;
37 using std::cerr;
38 using std::endl;
39 using std::string;
40 using std::vector;
41 
42 template <class T>
43 inline std::string stringify(const T& t)
44 {
45  std::ostringstream o;
46  if (!(o << t))
47  return "err";
48  return o.str();
49 }
50 Double_t SideBandSubtract::getYield(std::vector<SbsRegion> Regions, RooAbsPdf *PDF)
51 {
52  if(PDF==NULL || SeparationVariable==NULL)
53  return 0.0;
54 
55  Double_t yield=0;
56  RooAbsReal* intPDF;
57  for(unsigned int i=0; i < Regions.size(); i++)
58  {
59  if(verbose)
60  cout<<"Integrating over Range: "<<Regions[i].RegionName<<" from "<<Regions[i].min<<" to "<<Regions[i].max<<endl;
61  intPDF = PDF->createIntegral(*SeparationVariable, Range(Regions[i].RegionName.c_str()));
62  yield += intPDF->getVal();
63  if(verbose)
64  cout<<"Current yield: "<<yield<<endl;
65  }
66  return yield;
67 }
68 static void setHistOptions(TH1F* histo, string name, string title, string axis_label)
69 {
70 
71  histo->SetName(name.c_str());
72  histo->SetTitle(title.c_str());
73  if(axis_label == "GeV/c^2")
74  axis_label = "Mass (" + axis_label + ")";
75  if(axis_label == "GeV/c")
76  axis_label = "Momentum (" + axis_label + ")";
77  histo->GetXaxis()->SetTitle(axis_label.c_str());
78 }
79 int SideBandSubtract::doSubtraction(RooRealVar* variable, Double_t stsratio,Int_t index) //stsratio -> signal to sideband ratio
80 {
81  if(Data==NULL || SeparationVariable==NULL)
82  {
83  cerr << "ERROR: Data or SeparationVariable is NULL returning now!\n";
84  return -1;
85  }
86  TH1F* SideBandHist = (TH1F*)BaseHistos[index]->Clone();
87  setHistOptions(SideBandHist,(string)variable->GetName()+"Sideband",(string)SideBandHist->GetTitle() + " Sideband",(string)variable->getUnit());
88 
89  TH1F* SignalHist = (TH1F*)BaseHistos[index]->Clone();
90  setHistOptions(SignalHist,(string)variable->GetName()+"SignalHist",(string)SignalHist->GetTitle() + " Raw Signal",(string)variable->getUnit());
91 
92  //Begin a loop over the data to fill our histograms. I should figure
93  //out how to do this in one shot to avoid a loop
94  //O(N_vars*N_events)...
95 
96  TIterator* iter = (TIterator*) Data->get()->createIterator();
97  RooAbsArg *var=NULL;
98  RooRealVar *sep_var=NULL;
99  while((var = (RooAbsArg*)iter->Next()))
100  {
101  if((string)var->GetName()==(string)SeparationVariable->GetName())
102  {
103  sep_var = (RooRealVar*)var;
104  break;
105  }
106  }
107  for(int i=0; i < Data->numEntries(); i++)
108  {
109  Data->get(i);
110  Double_t value = variable->getVal();
111  Double_t cutval = sep_var->getVal();
112 
113  for(unsigned int j=0; j < SideBandRegions.size(); j++) //UGLY! Find better solution!
114  {
115  if(cutval > SideBandRegions[j].min && cutval < SideBandRegions[j].max)
116  SideBandHist->Fill(value);
117  }
118  for(unsigned int j=0; j < SignalRegions.size(); j++)
119  {
120  if(cutval > SignalRegions[j].min && cutval < SignalRegions[j].max)
121  SignalHist->Fill(value);
122  }
123  }
124  //Save pre-subtracted histo
125  SignalHist->Sumw2(); SideBandHist->Sumw2();
126  //SignalHist->SetDirectory(0); SideBandHist->SetDirectory(0);
127  RawHistos.push_back(*SignalHist);
128 
129  SignalHist->Add(SideBandHist, -stsratio);
130 
131  SignalHist->SetTitle(((string)BaseHistos[index]->GetTitle() + " SBS Signal").c_str());
132  //Save subtracted histo
133  SBSHistos.push_back(*SignalHist);
134  //Save Sideband histo
135  SideBandHistos.push_back(*SideBandHist);
136 
137  if(SideBandHist) delete SideBandHist;
138  return 0;
139 }
140 static void print_histo(TH1F* plot, string outname)
141 {
142  TCanvas genericCanvas;
143  plot->Draw("E1P0");
144  outname = outname + ".eps";
145  genericCanvas.SaveAs(outname.c_str());
146  outname.replace(outname.size()-3,3,"gif");
147  genericCanvas.SaveAs(outname.c_str());
148 }
150 {//handles *all* printing
151  //spool over vectors of histograms and print them, then print
152  //separation variable plots and the results text file.
153  if(SeparationVariable==NULL)
154  {
155  cerr << "ERROR: printResults, SeparationVariable is NULL!\n";
156  return;
157  }
158  string filename; //output file name
159  for(unsigned int i=0; i < RawHistos.size(); ++i)
160  {
161  filename=prefix + "Raw_" + (string)RawHistos[i].GetName();
162  print_histo(&RawHistos[i], filename);
163  }
164  for(unsigned int i=0; i < SBSHistos.size(); ++i)
165  {
166  filename=prefix + "SBS_" + (string)RawHistos[i].GetName();
167  print_histo(&SBSHistos[i], filename);
168  }
169  if(verbose)
170  {
171  for(unsigned int i=0; i < SideBandHistos.size(); ++i)
172  {
173  filename=prefix + "SideBand_" + (string)RawHistos[i].GetName();
174  print_histo(&SideBandHistos[i], filename);
175  }
176  }
177 
178  string outname = prefix + (string)SeparationVariable->GetName() + "_fitted.eps";
179  if(Data!=NULL && ModelPDF!=NULL)
180  {
181  RooPlot *SepVarFrame = SeparationVariable->frame();
182  Data->plotOn(SepVarFrame);
183  ModelPDF->plotOn(SepVarFrame);
184  TCanvas Canvas;
185  SepVarFrame->Draw();
186  Canvas.SaveAs(outname.c_str());
187  outname.replace(outname.size()-3,3,"gif");
188  Canvas.SaveAs(outname.c_str());
189  }
190  else
191  cerr <<"ERROR: printResults, Data or ModelPDF is NULL!\n";
192 
193  string result_outname = prefix + "_fit_results.txt";
194  ofstream output(result_outname.c_str(),ios::out);
195  if(!output)
196  {
197  cout <<"ERROR: Could not open file for writing!\n";
198  return;
199  }
200 
201  if(fit_result!=NULL)
202  {
203 #if ROOT_VERSION_CODE <= ROOT_VERSION(5,19,0)
204  fit_result->printToStream(output,Verbose);
205 #else
206  fit_result->printMultiline(output,kTRUE);
207 #endif
208  }
209 }
210 
211 
212 void SideBandSubtract::saveResults(string outname)
213 {
214  //saves the ephemeral stuff to a root file for future
215  //use/modification (ie everything printed by printResults())
216 
217  TFile output(outname.c_str(),"UPDATE"); //open the output file,
218  //create it if it doesn't
219  //exist
220  //Since keys are only available from files on disk, we need to write
221  //out a new file. If the file already existed, then we opened to
222  //update, and are writing nothing new.
223  output.Write();
224  TString dirname;
225  TIter nextkey(output.GetListOfKeys());
226  TKey *key;
227  TDirectory* curDir=NULL;
228  while((key=(TKey*)nextkey.Next()))
229  {
230 
231  if(key==NULL)
232  break;
233  TObject *obj = key->ReadObj();
234  if(obj->IsA()->InheritsFrom("TDirectory"))
235  dirname=obj->GetName();
236 
237  }
238 
239  if(dirname=="")
240  {
241  //we didn't find any directories so, we'll make a new one
242  curDir = output.mkdir("run0","Run 0");
243  output.cd("run0");
244  }
245  else
246  {
247  //manipulate last dir string, make a new one, and get ready to fill
248  dirname.Remove(0,3);
249  Int_t run_num = dirname.Atoi();
250  run_num++;
251  dirname = "run" + stringify(run_num);
252  curDir = output.mkdir(dirname.Data(),("Run "+stringify(run_num)).c_str());
253  output.cd(dirname.Data());
254  }
255  if(curDir==NULL)
256  curDir = output.GetDirectory("",kTRUE,"");
257 
258  //these should all be the same size, but to be pedantic we'll loop
259  //over each one individually, also, we need to associate them with
260  //the directory because by default they "float" in memory to avoid
261  //conflicts with other root files the user has open. If they want to
262  //write to those files, they need to close their file, pass the name
263  //here, and then let us work.
264  for(unsigned int i=0; i < SideBandHistos.size(); ++i)
265  {
266  SideBandHistos[i].SetDirectory(curDir);
267  SideBandHistos[i].Write();
268  }
269  for(unsigned int i=0; i < RawHistos.size(); ++i)
270  {
271  RawHistos[i].SetDirectory(curDir);
272  RawHistos[i].Write();
273  }
274  for(unsigned int i=0; i < SBSHistos.size(); ++i)
275  {
276  SBSHistos[i].SetDirectory(curDir);
277  SBSHistos[i].Write();
278  }
279  if(Data!=NULL && ModelPDF!=NULL && BackgroundPDF!=NULL && SeparationVariable!=NULL)
280  {
281  RooPlot *sep_varFrame = SeparationVariable->frame();
282  Data->plotOn(sep_varFrame);
283  ModelPDF->plotOn(sep_varFrame);
284  BackgroundPDF->plotOn(sep_varFrame);
285  sep_varFrame->Write();
286  }
287  else
288  cerr <<"ERROR: saveResults, did not save RooPlot of data and fit\n";
289  output.Write();
290 
291 }
292 void SideBandSubtract::setDataSet(RooDataSet* newData)
293 {
294  if(newData!=NULL)
295  Data=newData;
296 }
297 void SideBandSubtract::print_plot(RooRealVar* printVar,string outname)
298 {
299  if(Data==NULL || ModelPDF==NULL)
300  {
301  cerr << "ERROR: print_plot, Data or ModelPDF are NULL\n";
302  return;
303  }
304 
305  RooPlot *genericFrame = printVar->frame();
306  Data->plotOn(genericFrame);
307  ModelPDF->plotOn(genericFrame);
308  TCanvas genericCanvas;
309  genericFrame->Draw();
310  outname = outname + ".eps";
311  genericCanvas.SaveAs(outname.c_str());
312  outname.replace(outname.size()-3,3,"gif");
313  genericCanvas.SaveAs(outname.c_str());
314 }
316  : BackgroundPDF(0),
317  ModelPDF(0),
318  Data(0),
319  SeparationVariable(0),
320  verbose(0),
321  SignalRegions(),
322  SideBandRegions(),
323  SideBandHistos(0),
324  RawHistos(0),
325  SBSHistos(0),
326  BaseHistos(0),
327  fit_result(0),
328  SignalSidebandRatio(0)
329 {
330  // Default constructor so we can do fast subtraction
331 }
332 SideBandSubtract::SideBandSubtract(RooAbsPdf *model_shape,
333  RooAbsPdf *bkg_shape,
334  RooDataSet* data,
335  RooRealVar* sep_var,
336  vector<TH1F*> base,
337  bool verb
338  )
339  : BackgroundPDF(bkg_shape),
340  ModelPDF(model_shape),
341  Data(data),
342  SeparationVariable(sep_var),
343  verbose(verb),
344  SignalRegions(),
345  SideBandRegions(),
346  SideBandHistos(),
347  RawHistos(),
348  SBSHistos(),
349  BaseHistos(base),
350  base_histo(0),
351  fit_result(0),
352  SignalSidebandRatio(0)
353 { }
354 /*
355 SideBandSubtract::SideBandSubtract(RooAbsPdf *model_shape,
356  RooAbsPdf *bkg_shape,
357  RooDataSet* data,
358  RooRealVar* sep_var,
359  bool verb
360  )
361  : BackgroundPDF(bkg_shape),
362  ModelPDF(model_shape),
363  Data(data),
364  SeparationVariable(sep_var),
365  verbose(verb),
366  SignalRegions(),
367  SideBandRegions(),
368  SideBandHistos(),
369  RawHistos(),
370  SBSHistos(),
371  BaseHistos(),
372  base_histo(0),
373  fit_result(0),
374  SignalSidebandRatio(0)
375 {
376  // Build BaseHistos from dataset
377  TIterator* iter = (TIterator*) Data->get()->createIterator();
378  RooAbsArg *var=NULL;
379  RooRealVar *variable=NULL;
380  cout <<"Starting while loop\n";
381  while((var = (RooAbsArg*)iter->Next()))
382  {
383  if((string)var->ClassName() != "RooRealVar")
384  continue;
385  variable = (RooRealVar*)var;
386  //we own the data this points to so we need to delete it at the end...
387  assert(variable!=NULL);
388  string title = "base_"+(string)variable->GetName();
389  base_histo = (TH1F*)Data->createHistogram(title.c_str(), *variable, Binning(variable->getBinning("default",verb,kTRUE)) );
390  //cout <<"Made histo with name: "<<base_histo->GetName()<<endl;
391  //base_histo->SetDirectory(0);
392  BaseHistos.push_back(*base_histo);
393  cout <<"Added histo to BaseHistos!\n Deleting local copy...";
394  if(base_histo) delete base_histo;
395  cout <<"Done!\n";
396  }
397 
398 }
399 */
401 {
402  //**WARNING**
403 
404  // We don't delete objects that we don't own (duh) so, all of our
405  // pointers just hang out and get handled by other people :)
406 
407  // We DO own the BaseHistos IFF the user didn't provide us with
408  // them and we constructed them from the dataset... in this case
409  // base_histo will be non-null and we want to delete the vector
410  // of histograms...
412  /*
413  if(base_histo!=NULL)
414  {
415  BaseHistos.clear();
416  }
417  */
418 }
419 void SideBandSubtract::addSignalRegion(Double_t min, Double_t max)
420 {
421  SbsRegion signal;
422  signal.min=min;
423  signal.max=max;
424  signal.RegionName="Signal" + stringify(SignalRegions.size());
426  SeparationVariable->setRange(signal.RegionName.c_str(),signal.min,signal.max);
427  SignalRegions.push_back(signal);
428  return;
429 }
431 {
432  SbsRegion sideband;
433  sideband.min=min;
434  sideband.max=max;
435  sideband.RegionName="SideBand" + stringify(SideBandRegions.size());
437  SeparationVariable->setRange(sideband.RegionName.c_str(),sideband.min,sideband.max);
438  SideBandRegions.push_back(sideband);
439  return;
440 }
442 {
443  if(verbose)
444  cout <<"Beginning SideBand Subtraction\n";
445 
447  {
448  fit_result = ModelPDF->fitTo(*Data,"r");
449  }
450  else
451  {
452  cerr <<"ERROR: doGobalFit, no ModelPDF, SeparationVariable or Data specified\n";
453  return -1;
454  }
455 
456  Double_t SideBandYield=getYield(SideBandRegions,BackgroundPDF);
457  Double_t BackgroundInSignal=getYield(SignalRegions,BackgroundPDF);
458 
459  SignalSidebandRatio = BackgroundInSignal/SideBandYield;
460  if(verbose)
461  {
462  cout <<"Finished fitting background!\n";
463  cout <<"Attained a Signal to Sideband ratio of: " << SignalSidebandRatio<<endl;
464  }
465  //I can't see a way around a double loop for each variable. Maybe I
466  //can get a C++/RooFit guru to save me the trouble here?
467 
468 
469  //need to grab sbs objects after each global fit, because they get reset
471  TIterator* iter = (TIterator*) Data->get()->createIterator();
472  RooAbsArg *variable;
473  while((variable = (RooAbsArg*)iter->Next()))
474  {
475  for(unsigned int i=0; i < BaseHistos.size(); i++)
476  {
477  if((string)variable->GetName()!=(string)SeparationVariable->GetName()
478  && (string)variable->GetName()==(string)BaseHistos[i]->GetName())
479  doSubtraction((RooRealVar*)variable,SignalSidebandRatio,i);
480  }
481  }
482 
483  // clean up our memory...
484  if(variable) delete variable;
485  if(iter) delete iter;
486  return 0;
487 }
488 void SideBandSubtract::doFastSubtraction(TH1F &Total, TH1F &Result, SbsRegion& leftRegion, SbsRegion& rightRegion)
489 {
490  Int_t binMin = Total.FindBin(leftRegion.max,0.0,0.0);
491  Int_t binMax = Total.FindBin(leftRegion.min,0.0,0.0);
492  double numLeft = Total.Integral( binMin, binMax );
493 
494  binMin = Total.FindBin(rightRegion.max,0.0,0.0);
495  binMax = Total.FindBin(rightRegion.min,0.0,0.0);
496  double numRight = Total.Integral( binMin, binMax );
497 
498  const unsigned int nbinsx = Total.GetNbinsX();
499  const double x1 = (leftRegion.max + leftRegion.min)/2.0;
500  const double x2 = (rightRegion.max + rightRegion.min)/2.0;
501 
502  const double y1 = numLeft/(leftRegion.max - leftRegion.min);
503  const double y2 = numRight/(rightRegion.max - rightRegion.min);
504 
505  const double Slope = (y2 - y1)/(x2 - x1);
506  const double Intercept = y1 - Slope*x1;
507  // Evantually we want to handle more complicated functions, but for
508  // now... just use a linear one
509  TF1 function("sbs_function_line", "[0]*x + [1]",Total.GetMinimum(), Total.GetMaximum());
510  for ( unsigned int binx = 1; binx <= nbinsx; ++binx )
511  {
512  double binWidth = Total.GetBinWidth(binx);
513  function.SetParameter(0,Slope*binWidth);
514  function.SetParameter(1,Intercept*binWidth);
515 
516  double xx = Total.GetBinCenter(binx);
517  double cu = Total.GetBinContent(binx) - function.Eval(xx);
518  // TODO: Propogate the error on the parameters in function.
519  double error1 = Total.GetBinError(binx);
520 
521  Result.SetBinContent(binx, cu);
522  Result.SetBinError(binx, error1);
523  }
524  Result.SetEntries(Result.Integral() );
525 }
527 {
528  return fit_result;
529 }
531 {
532  return BaseHistos;
533 }
535 {
536  return RawHistos;
537 }
539 {
540  return SBSHistos;
541 }
543 {
544  return SignalSidebandRatio;
545 }
547 {
548  //cout <<"Starting to reset products \n";
549 
550  if(!SideBandHistos.empty())
551  SideBandHistos.clear();
552 
553  if(!RawHistos.empty())
554  RawHistos.clear();
555  if(!SBSHistos.empty())
556  SBSHistos.clear();
557 }
tuple base
Main Program
Definition: newFWLiteAna.py:92
RooAbsPdf * BackgroundPDF
RooFitResult * getFitResult()
int i
Definition: DBlmapReader.cc:9
std::vector< TH1F > SideBandHistos
std::vector< TH1F > getSBSHistos()
void saveResults(std::string outname)
RooFitResult * fit_result
#define NULL
Definition: scimark2.h:8
#define min(a, b)
Definition: mlp_lapack.h:161
std::vector< TH1F > getRawHistos()
static void print_histo(TH1F *plot, string outname)
std::vector< TH1F * > getBaseHistos()
int doSubtraction(RooRealVar *variable, Double_t stsratio, Int_t index)
std::string stringify(const T &t)
Double_t getYield(std::vector< SbsRegion > Regions, RooAbsPdf *PDF)
static void setHistOptions(TH1F *histo, string name, string title, string axis_label)
std::vector< TH1F > SBSHistos
const T & max(const T &a, const T &b)
RooRealVar * SeparationVariable
std::string RegionName
std::vector< SbsRegion > SideBandRegions
int j
Definition: DBlmapReader.cc:9
void printResults(std::string prefix="")
tuple out
Definition: dbtoconf.py:99
void addSignalRegion(Double_t min, Double_t max)
PixelRecoRange< float > Range
std::vector< SbsRegion > SignalRegions
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
list key
Definition: combine.py:13
tuple filename
Definition: lut2db_cfg.py:20
void addSideBandRegion(Double_t min, Double_t max)
tuple cout
Definition: gather_cfg.py:121
void print_plot(RooRealVar *printVar, std::string outname)
void doFastSubtraction(TH1F &Total, TH1F &Result, SbsRegion &leftRegion, SbsRegion &rightRegion)
void setDataSet(RooDataSet *newData)
long double T
std::vector< TH1F * > BaseHistos
std::vector< TH1F > RawHistos