Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooUnitTest.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2  * Project: RooFit *
3  * Package: RooFitCore *
4  * @(#)root/roofitcore:$Id$
5  * Authors: *
6  * WV, Wouter Verkerke, NIKHEF, verkerke@nikhef.nl *
7  * *
8  * Copyright (c) 2000-2011, Regents of the University of California *
9  * and Stanford University. All rights reserved. *
10  * *
11  * Redistribution and use in source and binary forms, *
12  * with or without modification, are permitted according to the terms *
13  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
14  *****************************************************************************/
15 
16 /**
17 \file RooUnitTest.cxx
18 \class RooUnitTest
19 \ingroup Roofitcore
20 
21 RooUnit test is an abstract base class for unit regression tests for
22 RooFit and RooStats tests performed in stressRooFit and stressRooStats
23 Implementations of this class must implement abstract method testCode()
24 which defines the regression test to be performed. Inside testCode()
25 the regression test can define objects on which the regression is performed.
26 These are:
27 Object | function
28 ----------------|------------
29  RooPlot | regPlot()
30  RooFitResult | regResult()
31  Double_t | regValue()
32  RooTable | regTable()
33  TH1/2/3 | regTH()
34  RooWorkspace | regWS()
35 **/
36 
37 #include "RooFit.h"
38 #include "RooUnitTest.h"
39 #include "TROOT.h"
40 #include "TClass.h"
41 #include "TSystem.h"
42 #include "RooHist.h"
43 #include "RooMsgService.h"
44 #include "RooDouble.h"
45 #include "RooTrace.h"
46 #include "RooRandom.h"
47 #include <math.h>
48 
49 ClassImp(RooUnitTest);
50 ;
51 
52 using namespace std;
53 
54 TDirectory* RooUnitTest::gMemDir = 0 ;
55 
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 RooUnitTest::RooUnitTest(const char* name, TFile* refFile, Bool_t writeRef, Int_t verbose) : TNamed(name,name),
60  _refFile(refFile), _debug(kFALSE), _write(writeRef), _verb(verbose)
61 {
62 }
63 
64 
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 
68 RooUnitTest::~RooUnitTest()
69 {
70 }
71 
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 
75 void RooUnitTest::regPlot(RooPlot* frame, const char* refName)
76 {
77  if (_refFile) {
78  string refNameStr(refName) ;
79  frame->SetName(refName) ;
80  _regPlots.push_back(make_pair(frame,refNameStr)) ;
81  } else {
82  delete frame ;
83  }
84 }
85 
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 
89 void RooUnitTest::regResult(RooFitResult* r, const char* refName)
90 {
91  if (_refFile) {
92  string refNameStr(refName) ;
93  _regResults.push_back(make_pair(r,refNameStr)) ;
94  } else {
95  delete r ;
96  }
97 }
98 
99 
100 ////////////////////////////////////////////////////////////////////////////////
101 
102 void RooUnitTest::regValue(Double_t d, const char* refName)
103 {
104  if (_refFile) {
105  string refNameStr(refName) ;
106  _regValues.push_back(make_pair(d,refNameStr)) ;
107  }
108 }
109 
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 
113 void RooUnitTest::regTable(RooTable* t, const char* refName)
114 {
115  if (_refFile) {
116  string refNameStr(refName) ;
117  _regTables.push_back(make_pair(t,refNameStr)) ;
118  } else {
119  delete t ;
120  }
121 }
122 
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 
126 void RooUnitTest::regWS(RooWorkspace* ws, const char* refName)
127 {
128  if (_refFile) {
129  string refNameStr(refName) ;
130  _regWS.push_back(make_pair(ws,refNameStr)) ;
131  } else {
132  delete ws ;
133  }
134 }
135 
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 
139 void RooUnitTest::regTH(TH1* th, const char* refName)
140 {
141  if (_refFile) {
142  string refNameStr(refName) ;
143  _regTH.push_back(make_pair(th,refNameStr)) ;
144  } else {
145  delete th ;
146  }
147 }
148 
149 
150 ////////////////////////////////////////////////////////////////////////////////
151 
152 RooWorkspace* RooUnitTest::getWS(const char* refName)
153 {
154  RooWorkspace* ws = dynamic_cast<RooWorkspace*>(_refFile->Get(refName)) ;
155  if (!ws) {
156  cout << "RooUnitTest ERROR: cannot retrieve RooWorkspace " << refName
157  << " from reference file, skipping " << endl ;
158  return 0 ;
159  }
160 
161  return ws ;
162 }
163 
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 
167 Bool_t RooUnitTest::areTHidentical(TH1* htest, TH1* href)
168 {
169  if (htest->GetDimension() != href->GetDimension()) {
170  return kFALSE ;
171  }
172 
173  // Use Kolmogorov distance as metric rather than probability
174  // because we expect histograms to be identical rather
175  // than drawn from the same parent distribution
176  Double_t kmax = htest->KolmogorovTest(href,"M") ;
177 
178  if (kmax>htol()) {
179 
180  cout << "KS distances = " << kmax << endl ;
181 
182  Int_t ntest = htest->GetNbinsX() +2 ;
183  Int_t nref = href->GetNbinsX() +2 ;
184  if (htest->GetDimension()>1) {
185  ntest *= htest->GetNbinsY() + 2 ;
186  nref *= href->GetNbinsY() + 2 ;
187  }
188  if (htest->GetDimension()>2) {
189  ntest *= htest->GetNbinsZ() + 2 ;
190  nref *= href->GetNbinsZ() + 2 ;
191  }
192 
193  if (ntest != nref) {
194  return kFALSE ;
195  }
196 
197  for (Int_t i=0 ; i<ntest ; i++) {
198  if (fabs(htest->GetBinContent(i)-href->GetBinContent(i))>htol()) {
199  cout << "htest[" << i << "] = " << htest->GetBinContent(i) << " href[" << i << "] = " << href->GetBinContent(i) << endl;
200  }
201  }
202 
203  return kFALSE ;
204  }
205 
206  return kTRUE ;
207 }
208 
209 
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 
213 Bool_t RooUnitTest::runCompTests()
214 {
215  Bool_t ret = kTRUE ;
216 
217  list<pair<RooPlot*, string> >::iterator iter = _regPlots.begin() ;
218  while (iter!=_regPlots.end()) {
219 
220  if (!_write) {
221 
222  // Comparison mode
223 
224  // Retrieve benchmark
225  RooPlot* bmark = dynamic_cast<RooPlot*>(_refFile->Get(iter->second.c_str())) ;
226  if (!bmark) {
227  cout << "RooUnitTest ERROR: cannot retrieve RooPlot " << iter->second << " from reference file, skipping " << endl ;
228  ret = kFALSE ;
229  ++iter ;
230  continue ;
231  }
232 
233  if (_verb) {
234  cout << "comparing RooPlot " << iter->first << " to benchmark " << iter->second << " = " << bmark << endl ;
235  cout << "reference: " ; iter->first->Print() ;
236  cout << "benchmark: " ; bmark->Print() ;
237  }
238 
239  RooPlot* compPlot = _debug ? iter->first->emptyClone(Form("%s_comparison",iter->first->GetName())) : 0 ;
240  Bool_t anyFail=kFALSE ;
241 
242  Stat_t nItems = iter->first->numItems() ;
243  for (Stat_t i=0 ; i<nItems ; i++) {
244  // coverity[NULL_RETURNS]
245  TObject* obj = iter->first->getObject((Int_t)i) ;
246 
247  // Retrieve corresponding object from reference frame
248  TObject* objRef = bmark->findObject(obj->GetName()) ;
249 
250  if (!objRef) {
251  cout << "RooUnitTest ERROR: cannot retrieve object " << obj->GetName() << " from reference RooPlot " << iter->second << ", skipping" << endl ;
252  ret = kFALSE ;
253  break ;
254  }
255 
256  // Histogram comparisons
257  if (obj->IsA()==RooHist::Class()) {
258  RooHist* testHist = static_cast<RooHist*>(obj) ;
259  RooHist* refHist = static_cast<RooHist*>(objRef) ;
260  if (!testHist->isIdentical(*refHist,htol())) {
261  cout << "RooUnitTest ERROR: comparison of object " << obj->IsA()->GetName() << "::" << obj->GetName()
262  << " fails comparison with counterpart in reference RooPlot " << bmark->GetName() << endl ;
263 
264  if (compPlot) {
265  compPlot->addPlotable((RooHist*)testHist->Clone(),"P") ;
266  compPlot->getAttLine()->SetLineColor(kRed) ;
267  compPlot->getAttMarker()->SetMarkerColor(kRed) ;
268  compPlot->getAttLine()->SetLineWidth(1) ;
269 
270  compPlot->addPlotable((RooHist*)refHist->Clone(),"P") ;
271  compPlot->getAttLine()->SetLineColor(kBlue) ;
272  compPlot->getAttMarker()->SetMarkerColor(kBlue) ;
273  compPlot->getAttLine()->SetLineWidth(1) ;
274  }
275 
276  anyFail=kTRUE ;
277  ret = kFALSE ;
278  }
279  } else if (obj->IsA()==RooCurve::Class()) {
280  RooCurve* testCurve = static_cast<RooCurve*>(obj) ;
281  RooCurve* refCurve = static_cast<RooCurve*>(objRef) ;
282  if (!testCurve->isIdentical(*refCurve,ctol())) {
283  cout << "RooUnitTest ERROR: comparison of object " << obj->IsA()->GetName() << "::" << obj->GetName()
284  << " fails comparison with counterpart in reference RooPlot " << bmark->GetName() << endl ;
285 
286  if (compPlot) {
287  compPlot->addPlotable((RooCurve*)testCurve->Clone()) ;
288  compPlot->getAttLine()->SetLineColor(kRed) ;
289  compPlot->getAttLine()->SetLineWidth(1) ;
290  compPlot->getAttLine()->SetLineStyle(kSolid) ;
291 
292  compPlot->addPlotable((RooCurve*)refCurve->Clone()) ;
293  compPlot->getAttLine()->SetLineColor(kBlue) ;
294  compPlot->getAttLine()->SetLineWidth(1) ;
295  compPlot->getAttLine()->SetLineStyle(kDashed) ;
296  }
297 
298  anyFail=kTRUE ;
299  ret = kFALSE ;
300  }
301 
302  }
303 
304  }
305 
306  if (anyFail && compPlot) {
307  cout << "RooUnitTest INFO: writing comparison plot " << compPlot->GetName() << " of failed test to RooUnitTest_DEBUG.root" << endl ;
308  TFile fdbg("RooUnitTest_DEBUG.root","UPDATE") ;
309  compPlot->Write() ;
310  fdbg.Close() ;
311  } else {
312  delete compPlot ;
313  }
314 
315  // Delete RooPlot when comparison is finished to avoid noise in leak checking
316  delete iter->first ;
317 
318  } else {
319 
320  // Writing mode
321 
322  cout <<"RooUnitTest: Writing reference RooPlot " << iter->first << " as benchmark " << iter->second << endl ;
323  _refFile->cd() ;
324  iter->first->Write(iter->second.c_str()) ;
325  gMemDir->cd() ;
326  }
327 
328  ++iter ;
329  }
330 
331 
332  list<pair<RooFitResult*, string> >::iterator iter2 = _regResults.begin() ;
333  while (iter2!=_regResults.end()) {
334 
335  if (!_write) {
336 
337  // Comparison mode
338 
339  // Retrieve benchmark
340  RooFitResult* bmark = dynamic_cast<RooFitResult*>(_refFile->Get(iter2->second.c_str())) ;
341  if (!bmark) {
342  cout << "RooUnitTest ERROR: cannot retrieve RooFitResult " << iter2->second << " from reference file, skipping " << endl ;
343  ++iter2 ;
344  ret = kFALSE ;
345  continue ;
346  }
347 
348  if (_verb) {
349  cout << "comparing RooFitResult " << iter2->first << " to benchmark " << iter2->second << " = " << bmark << endl ;
350  }
351 
352  if (!iter2->first->isIdentical(*bmark,fptol(),fctol())) {
353  cout << "RooUnitTest ERROR: comparison of object " << iter2->first->IsA()->GetName() << "::" << iter2->first->GetName()
354  << " from result " << iter2->second
355  << " fails comparison with counterpart in reference RooFitResult " << bmark->GetName() << endl ;
356  ret = kFALSE ;
357  }
358 
359  // Delete RooFitResult when comparison is finished to avoid noise in leak checking
360  delete iter2->first ;
361 
362 
363  } else {
364 
365  // Writing mode
366 
367  cout <<"RooUnitTest: Writing reference RooFitResult " << iter2->first << " as benchmark " << iter2->second << endl ;
368  _refFile->cd() ;
369  iter2->first->Write(iter2->second.c_str()) ;
370  gMemDir->cd() ;
371  }
372 
373  ++iter2 ;
374  }
375 
376  list<pair<Double_t, string> >::iterator iter3 = _regValues.begin() ;
377  while (iter3!=_regValues.end()) {
378 
379  if (!_write) {
380 
381  // Comparison mode
382 
383  // Retrieve benchmark
384  RooDouble* ref = dynamic_cast<RooDouble*>(_refFile->Get(iter3->second.c_str())) ;
385  if (!ref) {
386  cout << "RooUnitTest ERROR: cannot retrieve RooDouble " << iter3->second << " from reference file, skipping " << endl ;
387  ++iter3 ;
388  ret = kFALSE ;
389  continue ;
390  }
391 
392  if (_verb) {
393  cout << "comparing value " << iter3->first << " to benchmark " << iter3->second << " = " << (Double_t)(*ref) << endl ;
394  }
395 
396  if (fabs(iter3->first - (Double_t)(*ref))>vtol() ) {
397  cout << "RooUnitTest ERROR: comparison of value " << iter3->first << " fails comparison with reference " << ref->GetName() << endl ;
398  ret = kFALSE ;
399  }
400 
401 
402  } else {
403 
404  // Writing mode
405 
406  cout <<"RooUnitTest: Writing reference Double_t " << iter3->first << " as benchmark " << iter3->second << endl ;
407  _refFile->cd() ;
408  RooDouble* rd = new RooDouble(iter3->first) ;
409  rd->Write(iter3->second.c_str()) ;
410  gMemDir->cd() ;
411  }
412 
413  ++iter3 ;
414  }
415 
416 
417  list<pair<RooTable*, string> >::iterator iter4 = _regTables.begin() ;
418  while (iter4!=_regTables.end()) {
419 
420  if (!_write) {
421 
422  // Comparison mode
423 
424  // Retrieve benchmark
425  RooTable* bmark = dynamic_cast<RooTable*>(_refFile->Get(iter4->second.c_str())) ;
426  if (!bmark) {
427  cout << "RooUnitTest ERROR: cannot retrieve RooTable " << iter4->second << " from reference file, skipping " << endl ;
428  ++iter4 ;
429  ret = kFALSE ;
430  continue ;
431  }
432 
433  if (_verb) {
434  cout << "comparing RooTable " << iter4->first << " to benchmark " << iter4->second << " = " << bmark << endl ;
435  }
436 
437  if (!iter4->first->isIdentical(*bmark)) {
438  cout << "RooUnitTest ERROR: comparison of object " << iter4->first->IsA()->GetName() << "::" << iter4->first->GetName()
439  << " fails comparison with counterpart in reference RooTable " << bmark->GetName() << endl ;
440  ret = kFALSE ;
441  }
442 
443  // Delete RooTable when comparison is finished to avoid noise in leak checking
444  delete iter4->first ;
445 
446 
447  } else {
448 
449  // Writing mode
450 
451  cout <<"RooUnitTest: Writing reference RooTable " << iter4->first << " as benchmark " << iter4->second << endl ;
452  _refFile->cd() ;
453  iter4->first->Write(iter4->second.c_str()) ;
454  gMemDir->cd() ;
455  }
456 
457  ++iter4 ;
458  }
459 
460 
461  list<pair<RooWorkspace*, string> >::iterator iter5 = _regWS.begin() ;
462  while (iter5!=_regWS.end()) {
463 
464  if (_write) {
465 
466  // Writing mode
467 
468  cout <<"RooUnitTest: Writing reference RooWorkspace " << iter5->first << " as benchmark " << iter5->second << endl ;
469  _refFile->cd() ;
470  iter5->first->Write(iter5->second.c_str()) ;
471  gMemDir->cd() ;
472  }
473 
474  ++iter5 ;
475  }
476 
477  /////////////////
478  list<pair<TH1*, string> >::iterator iter6 = _regTH.begin() ;
479  while (iter6!=_regTH.end()) {
480 
481  if (!_write) {
482 
483  // Comparison mode
484 
485  // Retrieve benchmark
486  TH1* bmark = dynamic_cast<TH1*>(_refFile->Get(iter6->second.c_str())) ;
487  if (!bmark) {
488  cout << "RooUnitTest ERROR: cannot retrieve TH1 " << iter6->second << " from reference file, skipping " << endl ;
489  ++iter6 ;
490  ret = kFALSE ;
491  continue ;
492  }
493 
494  if (_verb) {
495  cout << "comparing TH1 " << iter6->first << " to benchmark " << iter6->second << " = " << bmark << endl ;
496  }
497 
498  if (!areTHidentical(iter6->first,bmark)) {
499  // coverity[NULL_RETURNS]
500  cout << "RooUnitTest ERROR: comparison of object " << iter6->first->IsA()->GetName() << "::" << iter6->first->GetName()
501  << " fails comparison with counterpart in reference TH1 " << bmark->GetName() << endl ;
502 
503 
504  if (_debug) {
505  cout << "RooUnitTest INFO: writing THx " << iter6->first->GetName() << " and " << bmark->GetName()
506  << " of failed test to RooUnitTest_DEBUG.root" << endl ;
507  TFile fdbg("RooUnitTest_DEBUG.root","UPDATE") ;
508  iter6->first->SetName(Form("%s_test",iter6->first->GetName())) ;
509  iter6->first->Write() ;
510  bmark->SetName(Form("%s_ref",bmark->GetName())) ;
511  bmark->Write() ;
512  fdbg.Close() ;
513  }
514 
515  ret = kFALSE ;
516  }
517 
518  // Delete TH1 when comparison is finished to avoid noise in leak checking
519  delete iter6->first ;
520 
521 
522  } else {
523 
524  // Writing mode
525 
526  cout <<"RooUnitTest: Writing reference TH1 " << iter6->first << " as benchmark " << iter6->second << endl ;
527  _refFile->cd() ;
528  iter6->first->Write(iter6->second.c_str()) ;
529  gMemDir->cd() ;
530  }
531 
532  ++iter6 ;
533  }
534 
535 
536  /////////////////
537 
538  return ret ;
539 }
540 
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 
544 void RooUnitTest::setSilentMode()
545 {
546  RooMsgService::instance().setSilentMode(kTRUE) ;
547  for (Int_t i=0 ; i<RooMsgService::instance().numStreams() ; i++) {
548  if (RooMsgService::instance().getStream(i).minLevel<RooFit::ERROR) {
549  RooMsgService::instance().setStreamStatus(i,kFALSE) ;
550  }
551  }
552 }
553 
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 
557 void RooUnitTest::clearSilentMode()
558 {
559  RooMsgService::instance().setSilentMode(kFALSE) ;
560  for (Int_t i=0 ; i<RooMsgService::instance().numStreams() ; i++) {
561  RooMsgService::instance().setStreamStatus(i,kTRUE) ;
562  }
563 }
564 
565 
566 
567 ////////////////////////////////////////////////////////////////////////////////
568 
569 Bool_t RooUnitTest::runTest()
570 {
571  gMemDir->cd() ;
572 
573  if (_verb<2) {
574  setSilentMode() ;
575  } else {
576  cout << "*** Begin of output of Unit Test at normal verbosity *************" << endl ;
577  }
578 
579  RooMsgService::instance().clearErrorCount() ;
580 
581  // Reset random generator seed to make results independent of test ordering
582  gRandom->SetSeed(12345) ;
583  RooRandom::randomGenerator()->SetSeed(12345) ;
584 
585  RooTrace::callgrind_zero() ;
586  if (!testCode()) return kFALSE ;
587  RooTrace::callgrind_dump() ;
588 
589  if (_verb<2) {
590  clearSilentMode() ;
591  } else {
592  cout << "*** End of output of Unit Test at normal verbosity ***************" << endl ;
593  }
594 
595  if (RooMsgService::instance().errorCount()>0) {
596  cout << "RooUnitTest: ERROR messages were logged, failing test" << endl ;
597  return kFALSE ;
598  }
599 
600  return runCompTests() ;
601 }
602 
603 
604 ////////////////////////////////////////////////////////////////////////////////
605 /// Set gMemDir to memDir
606 
607 void RooUnitTest::setMemDir(TDirectory* memDir) {
608  gMemDir = memDir ;
609 }