Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HLFactory.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Danilo Piparo 25/08/2009
3
4
5/*************************************************************************
6 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13////////////////////////////////////////////////////////////////////////////////
14
15
16#include <iostream>
17#include <fstream>
18
19#include "RooStats/HLFactory.h"
20#include "TFile.h"
21#include "TObject.h"
22#include "TObjArray.h"
23#include "TObjString.h"
24
25#include "RooSimultaneous.h"
26
27/** \class RooStats::HLFactory
28 \ingroup Roostats
29
30HLFactory is an High Level model Factory allows you to
31describe your models in a configuration file
32(_datacards_) acting as an interface with the RooFactoryWSTool.
33Moreover it provides tools for the combination of models and datasets.
34
35*/
36
37
38
39using namespace RooStats;
40using namespace RooFit;
41
42////////////////////////////////////////////////////////////////////////////////
43/// Constructor with the name of the config file to interpret and the
44/// verbosity flag. The extension for the config files is assumed to
45/// be ".rs".
46
47HLFactory::HLFactory(const char *name, const char *fileName, bool isVerbose)
48 : TNamed(name, name), fVerbose(isVerbose), fOwnWs(true)
49{
51 wsName += "_ws";
52 fWs = new RooWorkspace(wsName);
53
57
58 // Start the parsing
59 fReadFile(fileName);
60}
61
62////////////////////////////////////////////////////////////////////////////////
63/// Constructor without a card but with an external workspace.
64
72
73////////////////////////////////////////////////////////////////////////////////
74
75HLFactory::HLFactory() : TNamed("hlfactory", "hlfactory"), fWs(new RooWorkspace("hlfactory_ws")), fOwnWs(true)
76{
80}
81
82////////////////////////////////////////////////////////////////////////////////
83/// destructor
84
86 if (fComboSigBkgPdf!=nullptr)
87 delete fComboSigBkgPdf;
88 if (fComboBkgPdf!=nullptr)
89 delete fComboBkgPdf;
90 if (fComboDataset!=nullptr)
91 delete fComboDataset;
92 if (fComboCat!=nullptr)
93 delete fComboCat;
94
95 if (fOwnWs)
96 delete fWs;
97}
98
99////////////////////////////////////////////////////////////////////////////////
100/// Add a channel to the combination. The channel can be specified as:
101/// - A signal plus background pdf
102/// - A background only pdf
103/// - A dataset
104/// Once the combination of the pdfs is done, no more channels should be
105/// added.
106
107int HLFactory::AddChannel(const char* label,
108 const char* SigBkgPdfName,
109 const char* BkgPdfName,
110 const char* DatasetName){
111 if (fCombinationDone){
112 std::cerr << "Cannot add anymore channels. "
113 << "Combination already carried out.\n";
114 return -1;
115 }
116
117 if (SigBkgPdfName!=nullptr){
118 if (fWs->pdf(SigBkgPdfName)==nullptr){
119 std::cerr << "Pdf " << SigBkgPdfName << " not found in workspace!\n";
120 return -1;
121 }
124 }
125
126 if (BkgPdfName!=nullptr){
127 if (fWs->pdf(BkgPdfName)==nullptr){
128 std::cerr << "Pdf " << BkgPdfName << " not found in workspace!\n";
129 return -1;
130 }
133 }
134
135 if (DatasetName!=nullptr){
136 if (fWs->data(DatasetName)==nullptr){
137 std::cerr << "Dataset " << DatasetName << " not found in workspace!\n";
138 return -1;
139 }
142 }
143
144 if (label!=nullptr){
145 TObjString* name = new TObjString(label);
147 }
148 return 0;
149
150}
151
152////////////////////////////////////////////////////////////////////////////////
153/// Return the combination of the signal plus background channels.
154/// The factory owns the object.
155
157 if (fSigBkgPdfNames.GetSize()==0)
158 return nullptr;
159
160 if (fComboSigBkgPdf!=nullptr)
161 return fComboSigBkgPdf;
162
164 return nullptr;
165
166 if (fSigBkgPdfNames.GetSize()==1){
168 return fComboSigBkgPdf;
169 }
170
171 if (!fCombinationDone)
173
174 RooArgList pdfs("pdfs");
175
177 pdfs.add( *(fWs->pdf(ostring->String().Data())) );
178 }
179
180 std::string name(GetName());
181 name+="_sigbkg";
182
183 std::string title(GetName());
184 title+="_sigbkg";
185
187 new RooSimultaneous(name.c_str(),
188 title.c_str(),
189 pdfs,
190 *fComboCat);
191
192 return fComboSigBkgPdf;
193
194}
195
196////////////////////////////////////////////////////////////////////////////////
197/// Return the combination of the background only channels.
198/// If no background channel is specified a nullptr pointer is returned.
199/// The factory owns the object.
200
202 if (fBkgPdfNames.GetSize()==0)
203 return nullptr;
204
205 if (fComboBkgPdf!=nullptr)
206 return fComboBkgPdf;
207
209 return nullptr;
210
211 if (fBkgPdfNames.GetSize()==1){
212 fComboBkgPdf=fWs->pdf(static_cast<TObjString*>(fBkgPdfNames.First())->String().Data());
213 return fComboBkgPdf;
214 }
215
216 if (!fCombinationDone)
218
219 RooArgList pdfs("pdfs");
220
222 pdfs.add( *fWs->pdf(ostring->String().Data()) );
223 }
224
226 name+="_bkg";
227
228 TString title(GetName());
229 title+="_bkg";
230
233 title,
234 pdfs,
235 *fComboCat);
236
237 return fComboBkgPdf;
238
239}
240
241////////////////////////////////////////////////////////////////////////////////
242/// Return the combination of the datasets.
243/// If no dataset is specified a nullptr pointer is returned.
244/// The factory owns the object.
245
247 if (fDatasetsNames.GetSize()==0)
248 return nullptr;
249
250 if (fComboDataset!=nullptr)
251 return fComboDataset;
252
254 return nullptr;
255
256 if (fDatasetsNames.GetSize()==1){
257 fComboDataset=static_cast<RooDataSet*>(fWs->data(static_cast<TObjString*>(fDatasetsNames.First())->String().Data()));
258 return fComboDataset;
259 }
260
261 if (!fCombinationDone)
263
264
265 auto it = fDatasetsNames.begin();
267 ostring = static_cast<TObjString*>(*it);
268 ++it;
269 fComboDataset = static_cast<RooDataSet*>(fWs->data(ostring->String().Data())) ;
270 if (!fComboDataset) return nullptr;
274 int catindex=0;
277 for(; it != fDatasetsNames.end() ; ++it) {
278 ostring = static_cast<TObjString*>(*it);
279 catindex++;
280 RooDataSet * data = static_cast<RooDataSet*>(fWs->data(ostring->String().Data()));
281 if (!data) return nullptr;
282 RooDataSet* dummy = new RooDataSet(*data,"");
284 fComboCat->Print();
285 dummy->addColumn(*fComboCat);
286 fComboDataset->append(*dummy);
287 delete dummy;
288 }
289
290 return fComboDataset;
291
292}
293
294////////////////////////////////////////////////////////////////////////////////
295/// Return the category.
296/// The factory owns the object.
297
299 if (fComboCat!=nullptr)
300 return fComboCat;
301
303 return nullptr;
304
305 if (!fCombinationDone)
307
308 return fComboCat;
309
310 }
311
312////////////////////////////////////////////////////////////////////////////////
313/// Process an additional configuration file
314
316 return fReadFile(filename,false);
317}
318
319////////////////////////////////////////////////////////////////////////////////
320/// Parses the configuration file. The objects can be specified following
321/// the rules of the RooFactoryWSTool, plus some more flexibility.
322///
323/// The official format for the datacards is ".rs".
324///
325/// All the instructions end with a ";" (like in C++).
326///
327/// Carriage returns and white lines are irrelevant but advised since they
328/// improve readability (like in C++).
329///
330/// The `(Roo)ClassName::objname(description)` can be replaced with the more
331/// "pythonic" `objname = (Roo)ClassName(description)`.
332///
333/// The comments can be specified with a "//" if on a single line or with
334/// "multiple lines" in C/C++ like comments.
335///
336/// The `"#include path/to/file.rs"` statement triggers the inclusion of a
337/// configuration fragment.
338///
339/// The `"import myobject:myworkspace:myrootfile"` will add to the Workspace
340/// the object myobject located in myworkspace recorded in myrootfile.
341/// Alternatively, one could choose the `"import myobject:myrootfile"` in case
342/// no Workspace is present.
343///
344/// The `"echo"` statement prompts a message on screen.
345
346int HLFactory::fReadFile(const char*fileName, bool is_included){
347 // Check the deepness of the inclusion
348 if (is_included) {
350 } else {
351 fInclusionLevel = 0;
352 }
353
354 const int maxDeepness=50;
356 TString warning("The inclusion stack is deeper than ");
357 warning+=maxDeepness;
358 warning+=". Is this a recursive inclusion?";
359 Warning("fReadFile", "%s", warning.Data());
360 }
361
362
363 // open the config file and go through it
364 std::ifstream ifile(fileName);
365
366 if(ifile.fail()){
367 TString error("File ");
368 error+=fileName;
369 error+=" could not be opened.";
370 Error("fReadFile", "%s", error.Data());
371 return -1;
372 }
373
375 ifileContent.ReadFile(ifile);
376 ifile.close();
377
378 // Tokenise the file using the "\n" char and parse it line by line to strip
379 // the comments.
381
382 std::unique_ptr<TObjArray> lines_array{ifileContent.Tokenize("\n")};
383
384 bool in_comment=false;
385
386 // Start iteration on lines array
387 for(TObject * line_o : *lines_array) {
388 TString line = (static_cast<TObjString*>(line_o))->GetString();
389
390 // Are we in a multiline comment?
391 if (in_comment) {
392 if (line.EndsWith("*/")){
393 in_comment=false;
394 if (fVerbose) Info("fReadFile","Out of multiline comment ...");
395
396 continue;
397 }
398 }
399
400 // Was line a single line comment?
401
402 if ((line.BeginsWith("/*") && line.EndsWith("*/")) ||
403 line.BeginsWith("//")){
404 if (fVerbose) Info("fReadFile","In single line comment ...");
405 continue;
406 }
407
408 // Did a multiline comment just begin?
409 if (line.BeginsWith("/*")){
410 in_comment=true;
411 if (fVerbose) Info("fReadFile","In multiline comment ...");
412 continue;
413 }
414
416 }
417
418 // Now proceed with the parsing of the stripped file
419
420 lines_array.reset(ifileContentStripped.Tokenize(";"));
421 in_comment=false;
422
423 const int nNeutrals=2;
424 TString neutrals[nNeutrals]={"\t"," "};
425
426 for(TObject * line_o : *lines_array) {
427
428 TString line = (static_cast<TObjString*>(line_o))->GetString();
429
430 // Strip spaces at the beginning and the end of the line
431 line.Strip(TString::kBoth,' ');
432
433 // Put the single statement in one single line
434 line.ReplaceAll("\n","");
435
436 // Do we have an echo statement? "A la RooFit"
437 if (line.BeginsWith("echo")){
438 line = line(5,line.Length()-1);
439 if (fVerbose)
440 std::cout << "Echoing line " << line.Data() << std::endl;
441 std::cout << "[" << GetName() << "] echo: "
442 << line.Data() << std::endl;
443 continue;
444 }
445
446 // Spaces and tabs at this point are not needed.
447 for (int i=0;i<nNeutrals;++i)
448 line.ReplaceAll(neutrals[i],"");
449
450
451 if (fVerbose) Info("fReadFile","Reading --> %s <--", line.Data());
452
453 // Was line a white space?
454 if (line == ""){
455 if (fVerbose) Info("fReadFile", "%s", "Empty line: skipping ...");
456 continue;
457 }
458
459 // Do we have an include statement?
460 // We treat this recursively.
461 if (line.BeginsWith("#include")){
462 line.ReplaceAll("#include","");
463 if (fVerbose) Info("fReadFile","Reading included file...");
464 fReadFile(line,true);
465 continue;
466 }
467
468 // We parse the line
469 if (fVerbose) Info("fReadFile","Parsing the line...");
471 }
472
473 return 0;
474}
475
476
477////////////////////////////////////////////////////////////////////////////////
478/// Builds the category necessary for the mutidimensional models. Its name
479/// will be `<HLFactory name>_category` and the types are specified by the
480/// model labels.
481
483 fCombinationDone=true;
484
486 name+="_category";
487
488 TString title(GetName());
489 title+="_category";
490
491 fComboCat=new RooCategory(name,title);
492
494 fComboCat->defineType(ostring->String());
495 }
496
497 }
498
499////////////////////////////////////////////////////////////////////////////////
500/// Check the number of entries in each list. If not the same and the list
501/// is not empty prompt an error.
502
507 return true;
508 } else {
509 std::cerr << "The number of datasets and models added as channels "
510 << " is not the same!\n";
511 return false;
512 }
513 }
514
515////////////////////////////////////////////////////////////////////////////////
516/// Parse a single line and puts the content in the RooWorkSpace
517
519 if (fVerbose) Info("fParseLine", "Parsing line: %s", line.Data());
520
521 TString new_line("");
522
523 const int nequals = line.CountChar('=');
524
525 // Build with the factory a var or cat, or pipe the command directly.
526
527 if (line.Contains("::") || // It is a ordinary statement
528 nequals==0 || //it is a RooRealVar or cat with 0,1,2,3.. indexes
529 (line.Contains("[") &&
530 line.Contains("]") &&
531 nequals>0 && // It is a cat like "tag[B0=1,B0bar=-1]"
532 ! line.Contains("(") &&
533 ! line.Contains(")"))) {
534 fWs->factory(line.Data());
535 return 0;
536 }
537
538 // Transform the line o_name = o_class(o_descr) in o_class::o_name(o_descr)
539 if (nequals==1 ||
540 (nequals > 1 && line.Contains("SIMUL"))){
541
542 // Divide the line in 3 components: o_name,o_class and o_descr
543 // assuming that o_name=o_class(o_descr)
544 const int equal_index=line.First('=');
545 const int par_index=line.First('(');
549
550 if (fVerbose) Info("fParseLine", "o_name=%s o_class=%s o_descr=%s",
551 o_name.Data(), o_class.Data(), o_descr.Data());
552
553 // Now two cases either we wanna produce an object or import something
554 // under a new name.
555 if (o_class =="import"){// import a generic TObject into the WS
556 // Now see if we have a workspace or not, according to the number of
557 // entries in the description..
558
559 TObjArray* descr_array = o_descr.Tokenize(",");
560
561 const int n_descr_parts=descr_array->GetEntries();
562
564 Error("fParseLine","Import wrong syntax: cannot process %s", o_descr.Data());
565
567 TString ws_name("");
568 TString rootfile_name (static_cast<TObjString*>(descr_array->At(0))->GetString());
569
570 std::unique_ptr<TFile> ifile{TFile::Open(rootfile_name)};
571 if (ifile==nullptr)
572 return 1;
573
574 if (n_descr_parts==3){// in presence of a Ws
575 o_descr.ReplaceAll(",",":");
577 }
578 else if(n_descr_parts==2){ // in presence of an object in rootfile
579 if (fVerbose) {
580 Info("fParseLine", "Importing %s from %s under the name of %s", obj_name.Data(), rootfile_name.Data(),
581 o_name.Data());
582 }
585 }
586 return 0;
587 } // end of import block
588
589 new_line=o_class+"::"+o_name+"("+o_descr+")";
590
591 if (fVerbose){
592 std::cout << "DEBUG: line: " << line.Data() << std::endl;
593 std::cout << "DEBUG: new_line: " << new_line.Data() << std::endl;
594 }
595
596 fWs->factory(new_line.Data());
597
598 return 0;
599 }
600
601 else { // In case we do not know what to do we pipe it..
602 fWs->factory(line.Data());
603 }
604
605 return 0;
606
607}
bool fOwnWs
Owns workspace.
Definition HLFactory.h:73
bool fVerbose
The verbosity flag.
Definition HLFactory.h:70
RooWorkspace * fWs
The RooWorkspace containing the models and variables.
Definition HLFactory.h:72
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
char name[80]
Definition TGX11.cxx:110
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
Definition RooAbsArg.h:263
void Print(Option_t *options=nullptr) const override
This method must be overridden when a class wants to print itself.
Definition RooAbsData.h:227
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
Object to represent discrete states.
Definition RooCategory.h:28
bool setIndex(Int_t index, bool printError=true) override
Set value by specifying the index code of the desired state.
bool defineType(const std::string &label)
Define a state with given name.
Container class to hold unbinned data.
Definition RooDataSet.h:34
virtual RooAbsArg * addColumn(RooAbsArg &var, bool adjustRange=true)
Add a column with the values of the given (function) argument to this dataset.
void append(RooDataSet &data)
Add all data points of given data set to this data set.
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
TList fSigBkgPdfNames
List of channels names to combine for the signal plus background pdfs.
Definition HLFactory.h:97
RooWorkspace * fWs
The RooWorkspace containing the models and variables.
Definition HLFactory.h:103
TList fBkgPdfNames
List of channels names to combine for the background pdfs.
Definition HLFactory.h:98
int fInclusionLevel
Keep trace of the inclusion deepness.
Definition HLFactory.h:102
RooAbsPdf * fComboBkgPdf
The background model combination.
Definition HLFactory.h:93
TList fLabelsNames
List of channels names to combine for the datasets.
Definition HLFactory.h:100
RooDataSet * GetTotDataSet()
Get the combined dataset.
int fParseLine(TString &line)
Parse a single line an puts the content in the RooWorkSpace.
HLFactory()
Default Constructor.
Definition HLFactory.cxx:75
RooCategory * fComboCat
The category of the combination.
Definition HLFactory.h:92
RooDataSet * fComboDataset
The datasets combination.
Definition HLFactory.h:95
TList fDatasetsNames
List of channels names to combine for the datasets.
Definition HLFactory.h:99
RooAbsPdf * GetTotBkgPdf()
Get the combined background pdf.
RooAbsPdf * fComboSigBkgPdf
The signal plus background model combination.
Definition HLFactory.h:94
bool fNamesListsConsistent()
Check the length of the lists.
bool fCombinationDone
Flag to keep trace of the status of the combination.
Definition HLFactory.h:96
RooAbsPdf * GetTotSigBkgPdf()
Get the combined signal plus background pdf.
int AddChannel(const char *label, const char *SigBkgPdfName, const char *BkgPdfName=nullptr, const char *datasetName=nullptr)
Add channel for the combination.
int ProcessCard(const char *filename)
Process a configuration file.
RooCategory * GetTotCategory()
Get the combined dataset.
bool fOwnWs
Owns workspace.
Definition HLFactory.h:104
~HLFactory() override
Default Destructor.
Definition HLFactory.cxx:85
void fCreateCategory()
Create the category for the combinations.
bool fVerbose
The verbosity flag.
Definition HLFactory.h:101
int fReadFile(const char *fileName, bool is_included=false)
Read the actual cfg file.
Persistable container for RooFit projects.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooFactoryWSTool & factory()
Return instance to factory tool.
RooAbsData * data(RooStringView name) const
Retrieve dataset (binned or unbinned) with given name. A null pointer is returned if not found.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
TIter end() const
TIter begin() const
virtual Int_t GetEntries() const
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:4130
void Add(TObject *obj) override
Definition TList.h:81
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:657
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:355
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
Collectable string class.
Definition TObjString.h:28
const TString & GetString() const
Definition TObjString.h:46
TString & String()
Definition TObjString.h:48
Mother of all ROOT objects.
Definition TObject.h:41
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1040
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1054
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:376
@ kBoth
Definition TString.h:276
TLine * line
std::ostream & Info()
Definition hadd.cxx:171
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:64
Namespace for the RooStats classes.
Definition CodegenImpl.h:58