Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
ModelInspector.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_roostats
3 /// RooStats Model Inspector
4 ///
5 /// Usage:
6 /// The usage is the same as the StandardXxxDemo.C macros.
7 /// The macro expects a root file containing a workspace with a ModelConfig and a dataset
8 ///
9 /// ~~~{.cpp}
10 /// $ root
11 /// .L ModelInspector.C+
12 /// ModelInspector(fileName, workspaceName, modelConfigName, dataSetName);
13 /// ~~~
14 ///
15 /// Drag the sliders to adjust the parameters of the model.
16 /// the min and max range of the sliders are used to define the upper & lower variation
17 /// the pointer position of the slider is the central blue curve.
18 ///
19 /// Click the FIT button to
20 ///
21 /// To Do:
22 /// - check boxes to specify which nuisance parameters used in making variation
23 /// - a button to make the profile inspector plots
24 /// - a check button to use MINOS errors
25 /// - have fit button show the covariance matrix from the fit
26 /// - a button to make the log likelihood plots
27 /// - a dialog to open the desired file
28 /// - ability to see the signal and background contributions?
29 ///
30 /// \macro_code
31 ///
32 /// - Version 1, October 2011
33 /// - based on tutorial macro by Bertrand Bellenot, Ilka Antcheva
34 /// - Version 2, November 2011
35 /// - fixes from Bertrand Bellenot for scrolling window for many parameters
36 ///
37 /// \author Kyle Cranmer
38 
39 #include "TGButton.h"
40 #include "TRootEmbeddedCanvas.h"
41 #include "TGLayout.h"
42 #include "TF1.h"
43 #include "TMath.h"
44 #include "TSystem.h"
45 #include "TCanvas.h"
46 #include "TGTextEntry.h"
47 #include "TGLabel.h"
48 #include "TGTripleSlider.h"
49 #include "RooWorkspace.h"
50 #include "RooStats/ModelConfig.h"
51 #include "TFile.h"
52 #include "RooArgSet.h"
53 #include "TList.h"
54 #include "RooAbsPdf.h"
55 #include "RooRealVar.h"
56 #include "RooPlot.h"
57 #include "TGButton.h"
58 #include <map>
59 #include "RooFitResult.h"
60 #include "TROOT.h"
61 #include <TApplication.h>
62 #include "RooSimultaneous.h"
63 #include "RooCategory.h"
64 
65 enum ETestCommandIdentifiers {
66  HId1,
67  HId2,
68  HId3,
69  HCId1,
70  HCId2,
71 
72  HSId1
73 };
74 
75 using namespace RooFit;
76 using namespace RooStats;
77 class ModelInspectorGUI : public TGMainFrame {
78 
79 private:
80  TRootEmbeddedCanvas *fCanvas;
81  TGLayoutHints *fLcan;
82  TF1 *fFitFcn;
83  RooPlot *fPlot;
84  RooWorkspace *fWS;
85  TFile *fFile;
86  ModelConfig *fMC;
87  RooAbsData *fData;
88  RooFitResult *fFitRes;
89 
90  TList fSliderList;
91  TList fFrameList;
92  vector<RooPlot *> fPlotList;
93  map<TGTripleHSlider *, const char *> fSliderMap;
94  map<TGTripleHSlider *, TGLabel *> fLabelMap;
95 
96  TGButton *fFitButton;
97  TGTextButton *fExitButton;
98 
99  // BB: a TGCanvas and a vertical frame are needed for using scrollbars
100  TGCanvas *fCan;
101  TGVerticalFrame *fVFrame;
102 
103  TGHorizontalFrame *fHframe0, *fHframe1, *fHframe2;
104  TGLayoutHints *fBly, *fBfly1, *fBfly2, *fBfly3;
105  TGTripleHSlider *fHslider1;
106  TGTextBuffer *fTbh1, *fTbh2, *fTbh3;
107  TGCheckButton *fCheck1, *fCheck2;
108 
109 public:
110  ModelInspectorGUI(RooWorkspace *, ModelConfig *, RooAbsData *);
111  virtual ~ModelInspectorGUI();
112 
113  void CloseWindow();
114  void DoText(const char *text);
115  void DoSlider();
116  void DoSlider(const char *);
117  void DoFit();
118  void DoExit();
119  void HandleButtons();
120 
121  ClassDef(ModelInspectorGUI, 0)
122 };
123 
124 //______________________________________________________________________________
125 ModelInspectorGUI::ModelInspectorGUI(RooWorkspace *w, ModelConfig *mc, RooAbsData *data)
126  : TGMainFrame(gClient->GetRoot(), 100, 100)
127 {
128 
129  RooMsgService::instance().getStream(1).removeTopic(RooFit::NumIntegration);
130  fWS = w;
131  fMC = mc;
132  fData = data;
133  RooSimultaneous *simPdf = NULL;
134  Int_t numCats = 1;
135  if (strcmp(fMC->GetPdf()->ClassName(), "RooSimultaneous") == 0) {
136  cout << "Is a simultaneous PDF" << endl;
137  simPdf = (RooSimultaneous *)(fMC->GetPdf());
138  RooCategory *channelCat = (RooCategory *)(&simPdf->indexCat());
139  cout << " with " << channelCat->numTypes() << " categories" << endl;
140  numCats = channelCat->numTypes();
141  } else {
142  cout << "Is not a simultaneous PDF" << endl;
143  }
144  fFitRes = 0;
145 
146  SetCleanup(kDeepCleanup);
147 
148  // Create an embedded canvas and add to the main frame, centered in x and y
149  // and with 30 pixel margins all around
150  fCanvas = new TRootEmbeddedCanvas("Canvas", this, 600, 400);
151  fLcan = new TGLayoutHints(kLHintsExpandX | kLHintsExpandY, 10, 10, 10, 10);
152  AddFrame(fCanvas, fLcan);
153  fPlotList.resize(numCats);
154  if (numCats > 1) {
155  fCanvas->GetCanvas()->Divide(numCats);
156  for (int i = 0; i < numCats; ++i) {
157  fCanvas->GetCanvas()->cd(i + 1)->SetBorderMode(0);
158  fCanvas->GetCanvas()->cd(i + 1)->SetGrid();
159  }
160  }
161 
162  fHframe0 = new TGHorizontalFrame(this, 0, 0, 0);
163 
164  fCheck1 = new TGCheckButton(fHframe0, "&Constrained", HCId1);
165  fCheck2 = new TGCheckButton(fHframe0, "&Relative", HCId2);
166  fCheck1->SetState(kButtonUp);
167  fCheck2->SetState(kButtonUp);
168  fCheck1->SetToolTipText("Pointer position constrained to slider sides");
169  fCheck2->SetToolTipText("Pointer position relative to slider position");
170 
171  fHframe0->Resize(200, 50);
172 
173  fHframe2 = new TGHorizontalFrame(this, 0, 0, 0);
174 
175  fFitButton = new TGTextButton(fHframe2, "Fit");
176  fFitButton->Connect("Clicked()", "ModelInspectorGUI", this, "DoFit()");
177  fExitButton = new TGTextButton(fHframe2, "Exit ");
178  fExitButton->Connect("Clicked()", "ModelInspectorGUI", this, "DoExit()");
179 
180  fCheck1->Connect("Clicked()", "ModelInspectorGUI", this, "HandleButtons()");
181  fCheck2->Connect("Clicked()", "ModelInspectorGUI", this, "HandleButtons()");
182 
183  fHframe2->Resize(100, 25);
184 
185  //--- layout for buttons: top align, equally expand horizontally
186  fBly = new TGLayoutHints(kLHintsTop | kLHintsExpandX, 5, 5, 5, 5);
187 
188  //--- layout for the frame: place at bottom, right aligned
189  fBfly1 = new TGLayoutHints(kLHintsTop | kLHintsCenterX, 5, 5, 5, 5);
190  fBfly2 = new TGLayoutHints(kLHintsTop | kLHintsLeft, 5, 5, 5, 5);
191  fBfly3 = new TGLayoutHints(kLHintsTop | kLHintsRight, 5, 5, 5, 5);
192 
193  fHframe2->AddFrame(fFitButton, fBfly2);
194  fHframe2->AddFrame(fExitButton, fBfly3);
195 
196  AddFrame(fHframe0, fBly);
197  AddFrame(fHframe2, fBly);
198 
199  // Loop over POI & NP, create slider
200  // need maps of NP->slider? or just slider->NP
201  RooArgSet parameters;
202  parameters.add(*fMC->GetParametersOfInterest());
203  parameters.add(*fMC->GetNuisanceParameters());
204  TIterator *it = parameters.createIterator();
205  RooRealVar *param = NULL;
206 
207  // BB: This is the part needed in order to have scrollbars
208  fCan = new TGCanvas(this, 100, 100, kFixedSize);
209  AddFrame(fCan, new TGLayoutHints(kLHintsExpandY | kLHintsExpandX));
210  fVFrame = new TGVerticalFrame(fCan->GetViewPort(), 10, 10);
211  fCan->SetContainer(fVFrame);
212  // And that't it!
213  // Obviously, the parent of other subframes is now fVFrame instead of "this"...
214 
215  while ((param = (RooRealVar *)it->Next())) {
216  cout << "Adding Slider for " << param->GetName() << endl;
217  TGHorizontalFrame *hframek = new TGHorizontalFrame(fVFrame, 0, 0, 0);
218 
219  TGLabel *hlabel =
220  new TGLabel(hframek, Form("%s = %.3f +%.3f", param->GetName(), param->getVal(), param->getError()));
221  TGTripleHSlider *hsliderk = new TGTripleHSlider(hframek, 190, kDoubleScaleBoth, HSId1, kHorizontalFrame,
222  GetDefaultFrameBackground(), kFALSE, kFALSE, kFALSE, kFALSE);
223  hsliderk->Connect("PointerPositionChanged()", "ModelInspectorGUI", this, "DoSlider()");
224  hsliderk->Connect("PositionChanged()", "ModelInspectorGUI", this, "DoSlider()");
225  hsliderk->SetRange(param->getMin(), param->getMax());
226 
227  hframek->Resize(200, 25);
228  fSliderList.Add(hsliderk);
229  fFrameList.Add(hframek);
230 
231  hsliderk->SetPosition(param->getVal() - param->getError(), param->getVal() + param->getError());
232  hsliderk->SetPointerPosition(param->getVal());
233 
234  hframek->AddFrame(hlabel, fBly);
235  hframek->AddFrame(hsliderk, fBly);
236  fVFrame->AddFrame(hframek, fBly);
237  fSliderMap[hsliderk] = param->GetName();
238  fLabelMap[hsliderk] = hlabel;
239  }
240 
241  // Set main frame name, map sub windows (buttons), initialize layout
242  // algorithm via Resize() and map main frame
243  SetWindowName("RooFit/RooStats Model Inspector");
244  MapSubwindows();
245  Resize(GetDefaultSize());
246  MapWindow();
247 
248  DoSlider();
249 }
250 
251 //______________________________________________________________________________
252 ModelInspectorGUI::~ModelInspectorGUI()
253 {
254  // Clean up
255 
256  Cleanup();
257 }
258 
259 //______________________________________________________________________________
260 void ModelInspectorGUI::CloseWindow()
261 {
262  // Called when window is closed via the window manager.
263 
264  delete this;
265 }
266 
267 //______________________________________________________________________________
268 void ModelInspectorGUI::DoText(const char * /*text*/)
269 {
270  // Handle text entry widgets.
271 
272  TGTextEntry *te = (TGTextEntry *)gTQSender;
273  Int_t id = te->WidgetId();
274 
275  switch (id) {
276  case HId1: fHslider1->SetPosition(atof(fTbh1->GetString()), fHslider1->GetMaxPosition()); break;
277  case HId2: fHslider1->SetPointerPosition(atof(fTbh2->GetString())); break;
278  case HId3: fHslider1->SetPosition(fHslider1->GetMinPosition(), atof(fTbh1->GetString())); break;
279  default: break;
280  }
281  DoSlider();
282 }
283 
284 //______________________________________________________________________________
285 void ModelInspectorGUI::DoFit()
286 {
287  fFitRes = fMC->GetPdf()->fitTo(*fData, Save());
288  map<TGTripleHSlider *, const char *>::iterator it;
289  ;
290  it = fSliderMap.begin();
291  for (; it != fSliderMap.end(); ++it) {
292  RooRealVar *param = fWS->var(it->second);
293  param = (RooRealVar *)fFitRes->floatParsFinal().find(it->second);
294  it->first->SetPosition(param->getVal() - param->getError(), param->getVal() + param->getError());
295  it->first->SetPointerPosition(param->getVal());
296  }
297  DoSlider();
298 }
299 
300 //______________________________________________________________________________
301 void ModelInspectorGUI::DoSlider(const char *text)
302 {
303  cout << "." << text << endl;
304 }
305 
306 //______________________________________________________________________________
307 void ModelInspectorGUI::DoSlider()
308 {
309  // Handle slider widgets.
310 
311  // char buf[32];
312 
313  RooSimultaneous *simPdf = NULL;
314  Int_t numCats = 0;
315  if (strcmp(fMC->GetPdf()->ClassName(), "RooSimultaneous") == 0) {
316  simPdf = (RooSimultaneous *)(fMC->GetPdf());
317  RooCategory *channelCat = (RooCategory *)(&simPdf->indexCat());
318  numCats = channelCat->numTypes();
319  } else {
320  }
321 
322  /////////////////////////////////////////////
323  if (!simPdf) {
324  /////////////////////////////////////////////
325  // if not SimPdf
326  /////////////////////////////////////////////
327 
328  // pre loop
329  map<TGTripleHSlider *, const char *>::iterator it;
330  ;
331  delete fPlot;
332  fPlot = ((RooRealVar *)fMC->GetObservables()->first())->frame();
333  fData->plotOn(fPlot);
334  double normCount;
335 
336  // high loop
337  it = fSliderMap.begin();
338  for (; it != fSliderMap.end(); ++it) {
339  const char *name = it->second;
340  fWS->var(name)->setVal(it->first->GetMaxPosition());
341  RooRealVar *param = fWS->var(name);
342  fLabelMap[it->first]->SetText(Form("%s = %.3f [%.3f,%.3f]", param->GetName(), it->first->GetPointerPosition(),
343  it->first->GetMinPosition(), it->first->GetMaxPosition()));
344  }
345  normCount = fMC->GetPdf()->expectedEvents(*fMC->GetObservables());
346  fMC->GetPdf()->plotOn(fPlot, LineColor(kRed), Normalization(normCount, RooAbsReal::NumEvent));
347 
348  // low loop
349  it = fSliderMap.begin();
350  for (; it != fSliderMap.end(); ++it) {
351  const char *name = it->second;
352  fWS->var(name)->setVal(it->first->GetMinPosition());
353  }
354  normCount = fMC->GetPdf()->expectedEvents(*fMC->GetObservables());
355  fMC->GetPdf()->plotOn(fPlot, LineColor(kGreen), Normalization(normCount, RooAbsReal::NumEvent));
356 
357  // central oop
358  it = fSliderMap.begin();
359  for (; it != fSliderMap.end(); ++it) {
360  const char *name = it->second;
361  fWS->var(name)->setVal(it->first->GetPointerPosition());
362  }
363  normCount = fMC->GetPdf()->expectedEvents(*fMC->GetObservables());
364  fMC->GetPdf()->plotOn(fPlot, LineColor(kBlue), Normalization(normCount, RooAbsReal::NumEvent));
365  fPlot->Draw();
366 
367  fCanvas->GetCanvas()->Modified();
368  fCanvas->GetCanvas()->Update();
369  ////////////////////////////////////////////////////////////////////////////
370  } else {
371  ////////////////////////////////////////////////////////////////////////////
372  // else (is simpdf)
373  ////////////////////////////////////////////////////////////////////////////
374  RooCategory *channelCat = (RooCategory *)(&simPdf->indexCat());
375  // TIterator* iter = simPdf->indexCat().typeIterator() ;
376  TIterator *iter = channelCat->typeIterator();
377  RooCatType *tt = NULL;
378  Int_t frameIndex = 0;
379  while ((tt = (RooCatType *)iter->Next())) {
380  ++frameIndex;
381  fCanvas->GetCanvas()->cd(frameIndex);
382 
383  // pre loop
384  RooAbsPdf *pdftmp = simPdf->getPdf(tt->GetName());
385  RooArgSet *obstmp = pdftmp->getObservables(*fMC->GetObservables());
386  RooRealVar *obs = ((RooRealVar *)obstmp->first());
387 
388  fPlot = fPlotList.at(frameIndex - 1);
389  if (fPlot)
390  delete fPlot;
391  fPlot = obs->frame();
392  fPlotList.at(frameIndex - 1) = fPlot;
393 
394  RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
395  RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
396  fData->plotOn(fPlot, MarkerSize(1),
397  Cut(Form("%s==%s::%s", channelCat->GetName(), channelCat->GetName(), tt->GetName())),
398  DataError(RooAbsData::None));
399  RooMsgService::instance().setGlobalKillBelow(msglevel);
400 
401  map<TGTripleHSlider *, const char *>::iterator it;
402  ;
403  double normCount;
404 
405  // high loop
406  it = fSliderMap.begin();
407  for (; it != fSliderMap.end(); ++it) {
408  const char *name = it->second;
409  fWS->var(name)->setVal(it->first->GetMaxPosition());
410  RooRealVar *param = fWS->var(name);
411  fLabelMap[it->first]->SetText(Form("%s = %.3f [%.3f,%.3f]", param->GetName(),
412  it->first->GetPointerPosition(), it->first->GetMinPosition(),
413  it->first->GetMaxPosition()));
414  }
415  normCount = pdftmp->expectedEvents(*obs);
416  pdftmp->plotOn(fPlot, LineColor(kRed), LineWidth(2.), Normalization(normCount, RooAbsReal::NumEvent));
417 
418  // low loop
419  it = fSliderMap.begin();
420  for (; it != fSliderMap.end(); ++it) {
421  const char *name = it->second;
422  fWS->var(name)->setVal(it->first->GetMinPosition());
423  RooRealVar *param = fWS->var(name);
424  fLabelMap[it->first]->SetText(Form("%s = %.3f [%.3f,%.3f]", param->GetName(),
425  it->first->GetPointerPosition(), it->first->GetMinPosition(),
426  it->first->GetMaxPosition()));
427  }
428  normCount = pdftmp->expectedEvents(*obs);
429  pdftmp->plotOn(fPlot, LineColor(kGreen), LineWidth(2.), Normalization(normCount, RooAbsReal::NumEvent));
430 
431  // central loop
432  it = fSliderMap.begin();
433  for (; it != fSliderMap.end(); ++it) {
434  const char *name = it->second;
435  fWS->var(name)->setVal(it->first->GetPointerPosition());
436  RooRealVar *param = fWS->var(name);
437  fLabelMap[it->first]->SetText(Form("%s = %.3f [%.3f,%.3f]", param->GetName(),
438  it->first->GetPointerPosition(), it->first->GetMinPosition(),
439  it->first->GetMaxPosition()));
440  }
441  normCount = pdftmp->expectedEvents(*obs);
442  if (!fFitRes)
443  pdftmp->plotOn(fPlot, LineColor(kBlue), LineWidth(2.), Normalization(normCount, RooAbsReal::NumEvent));
444  else {
445  pdftmp->plotOn(fPlot, Normalization(normCount, RooAbsReal::NumEvent),
446  VisualizeError(*fFitRes, *fMC->GetNuisanceParameters()), FillColor(kYellow));
447  pdftmp->plotOn(fPlot, LineColor(kBlue), LineWidth(2.), Normalization(normCount, RooAbsReal::NumEvent));
448  msglevel = RooMsgService::instance().globalKillBelow();
449  RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
450  fData->plotOn(fPlot, MarkerSize(1),
451  Cut(Form("%s==%s::%s", channelCat->GetName(), channelCat->GetName(), tt->GetName())),
452  DataError(RooAbsData::None));
453  RooMsgService::instance().setGlobalKillBelow(msglevel);
454  }
455  fPlot->Draw();
456  }
457  fCanvas->GetCanvas()->Modified();
458  fCanvas->GetCanvas()->Update();
459  ///////////////////////////////////////////
460  // end if(simPdf)
461  }
462 }
463 
464 //______________________________________________________________________________
465 void ModelInspectorGUI::HandleButtons()
466 {
467  // Handle different buttons.
468 
469  TGButton *btn = (TGButton *)gTQSender;
470  Int_t id = btn->WidgetId();
471 
472  switch (id) {
473  case HCId1: fHslider1->SetConstrained(fCheck1->GetState()); break;
474  case HCId2: fHslider1->SetRelative(fCheck2->GetState()); break;
475  default: break;
476  }
477 }
478 void ModelInspectorGUI::DoExit()
479 {
480  printf("Exit application...");
481  gApplication->Terminate(0);
482 }
483 
484 void ModelInspector(const char *infile = "", const char *workspaceName = "combined",
485  const char *modelConfigName = "ModelConfig", const char *dataName = "obsData")
486 {
487 
488  // -------------------------------------------------------
489  // First part is just to access a user-defined file
490  // or create the standard example file if it doesn't exist
491 
492  const char *filename = "";
493  if (!strcmp(infile, "")) {
494  filename = "results/example_combined_GaussExample_model.root";
495  bool fileExist = !gSystem->AccessPathName(filename); // note opposite return code
496  // if file does not exists generate with histfactory
497  if (!fileExist) {
498 #ifdef _WIN32
499  cout << "HistFactory file cannot be generated on Windows - exit" << endl;
500  return;
501 #endif
502  // Normally this would be run on the command line
503  cout << "will run standard hist2workspace example" << endl;
504  gROOT->ProcessLine(".! prepareHistFactory .");
505  gROOT->ProcessLine(".! hist2workspace config/example.xml");
506  cout << "\n\n---------------------" << endl;
507  cout << "Done creating example input" << endl;
508  cout << "---------------------\n\n" << endl;
509  }
510 
511  } else
512  filename = infile;
513 
514  // Try to open the file
515  TFile *file = TFile::Open(filename);
516 
517  // if input file was specified byt not found, quit
518  if (!file) {
519  cout << "StandardRooStatsDemoMacro: Input file " << filename << " is not found" << endl;
520  return;
521  }
522 
523  // -------------------------------------------------------
524  // Tutorial starts here
525  // -------------------------------------------------------
526 
527  // get the workspace out of the file
528  RooWorkspace *w = (RooWorkspace *)file->Get(workspaceName);
529  if (!w) {
530  cout << "workspace not found" << endl;
531  return;
532  }
533 
534  // get the modelConfig out of the file
535  ModelConfig *mc = (ModelConfig *)w->obj(modelConfigName);
536 
537  // get the modelConfig out of the file
538  RooAbsData *data = w->data(dataName);
539 
540  // make sure ingredients are found
541  if (!data || !mc) {
542  w->Print();
543  cout << "data or ModelConfig was not found" << endl;
544  return;
545  }
546 
547  new ModelInspectorGUI(w, mc, data);
548 }