Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooSimGenContext.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, UC Santa Barbara, verkerke@slac.stanford.edu *
7  * DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
8  * *
9  * Copyright (c) 2000-2005, Regents of the University of California *
10  * and Stanford University. All rights reserved. *
11  * *
12  * Redistribution and use in source and binary forms, *
13  * with or without modification, are permitted according to the terms *
14  * listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
15  *****************************************************************************/
16 
17 /**
18 \file RooSimGenContext.cxx
19 \class RooSimGenContext
20 \ingroup Roofitcore
21 
22 RooSimGenContext is an efficient implementation of the generator context
23 specific for RooSimultaneous PDFs when generating more than one of the
24 component pdfs.
25 It runs in two modes:
26 - Proto data with category entries are given: An event from the same category as
27 in the proto data is created.
28 - No proto data: A category is chosen randomly.
29 \note This requires that the PDFs are extended, to determine the relative probabilities
30 that an event originates from a certain category.
31 **/
32 
33 #include "RooFit.h"
34 #include "Riostream.h"
35 
36 #include "RooSimGenContext.h"
37 #include "RooSimultaneous.h"
38 #include "RooRealProxy.h"
39 #include "RooDataSet.h"
40 #include "Roo1DTable.h"
41 #include "RooCategory.h"
42 #include "RooMsgService.h"
43 #include "RooRandom.h"
44 #include "RooGlobalFunc.h"
45 
46 using namespace RooFit ;
47 
48 #include <string>
49 
50 using namespace std;
51 
52 ClassImp(RooSimGenContext);
53 ;
54 
55 
56 ////////////////////////////////////////////////////////////////////////////////
57 /// Constructor of specialized generator context for RooSimultaneous p.d.f.s. This
58 /// context creates a dedicated context for each component p.d.f.s and delegates
59 /// generation of events to the appropriate component generator context
60 
61 RooSimGenContext::RooSimGenContext(const RooSimultaneous &model, const RooArgSet &vars,
62  const RooDataSet *prototype, const RooArgSet* auxProto, Bool_t verbose) :
63  RooAbsGenContext(model,vars,prototype,auxProto,verbose), _pdf(&model), _protoData(0)
64 {
65  // Determine if we are requested to generate the index category
66  RooAbsCategory *idxCat = (RooAbsCategory*) model._indexCat.absArg() ;
67  RooArgSet pdfVars(vars) ;
68 
69  RooArgSet allPdfVars(pdfVars) ;
70  if (prototype) allPdfVars.add(*prototype->get(),kTRUE) ;
71 
72  if (!idxCat->isDerived()) {
73  pdfVars.remove(*idxCat,kTRUE,kTRUE) ;
74  Bool_t doGenIdx = allPdfVars.find(idxCat->GetName())?kTRUE:kFALSE ;
75 
76  if (!doGenIdx) {
77  oocoutE(_pdf,Generation) << "RooSimGenContext::ctor(" << GetName() << ") ERROR: This context must"
78  << " generate the index category" << endl ;
79  _isValid = kFALSE ;
80  _numPdf = 0 ;
81  _haveIdxProto = kFALSE ;
82  return ;
83  }
84  } else {
85  TIterator* sIter = idxCat->serverIterator() ;
86  RooAbsArg* server ;
87  Bool_t anyServer(kFALSE), allServers(kTRUE) ;
88  while((server=(RooAbsArg*)sIter->Next())) {
89  if (vars.find(server->GetName())) {
90  anyServer=kTRUE ;
91  pdfVars.remove(*server,kTRUE,kTRUE) ;
92  } else {
93  allServers=kFALSE ;
94  }
95  }
96  delete sIter ;
97 
98  if (anyServer && !allServers) {
99  oocoutE(_pdf,Generation) << "RooSimGenContext::ctor(" << GetName() << ") ERROR: This context must"
100  << " generate all components of a derived index category" << endl ;
101  _isValid = kFALSE ;
102  _numPdf = 0 ;
103  _haveIdxProto = kFALSE ;
104  return ;
105  }
106  }
107 
108  // We must either have the prototype or extended likelihood to determined
109  // the relative fractions of the components
110  _haveIdxProto = prototype ? kTRUE : kFALSE ;
111  _idxCatName = idxCat->GetName() ;
112  if (!_haveIdxProto && !model.canBeExtended()) {
113  oocoutE(_pdf,Generation) << "RooSimGenContext::ctor(" << GetName() << ") ERROR: Need either extended mode"
114  << " or prototype data to calculate number of events per category" << endl ;
115  _isValid = kFALSE ;
116  _numPdf = 0 ;
117  return ;
118  }
119 
120  // Initialize fraction threshold array (used only in extended mode)
121  _numPdf = model._pdfProxyList.GetSize() ;
122  _fracThresh = new Double_t[_numPdf+1] ;
123  _fracThresh[0] = 0 ;
124 
125  // Generate index category and all registered PDFS
126  _proxyIter = model._pdfProxyList.MakeIterator() ;
127  _allVarsPdf.add(allPdfVars) ;
128  RooRealProxy* proxy ;
129  RooAbsPdf* pdf ;
130  Int_t i(1) ;
131  while((proxy=(RooRealProxy*)_proxyIter->Next())) {
132  pdf=(RooAbsPdf*)proxy->absArg() ;
133 
134  // Create generator context for this PDF
135  RooAbsGenContext* cx = pdf->genContext(pdfVars,prototype,auxProto,verbose) ;
136 
137  // Name the context after the associated state and add to list
138  cx->SetName(proxy->name()) ;
139  _gcList.push_back(cx) ;
140  _gcIndex.push_back(idxCat->lookupType(proxy->name())->getVal()) ;
141 
142  // Fill fraction threshold array
143  _fracThresh[i] = _fracThresh[i-1] + (_haveIdxProto?0:pdf->expectedEvents(&allPdfVars)) ;
144  i++ ;
145  }
146 
147  // Normalize fraction threshold array
148  if (!_haveIdxProto) {
149  for(i=0 ; i<_numPdf ; i++)
150  _fracThresh[i] /= _fracThresh[_numPdf] ;
151  }
152 
153 
154  // Clone the index category
155  _idxCatSet = (RooArgSet*) RooArgSet(model._indexCat.arg()).snapshot(kTRUE) ;
156  if (!_idxCatSet) {
157  oocoutE(_pdf,Generation) << "RooSimGenContext::RooSimGenContext(" << GetName() << ") Couldn't deep-clone index category, abort," << endl ;
158  throw std::string("RooSimGenContext::RooSimGenContext() Couldn't deep-clone index category, abort") ;
159  }
160 
161  _idxCat = (RooAbsCategoryLValue*) _idxCatSet->find(model._indexCat.arg().GetName()) ;
162 }
163 
164 
165 
166 ////////////////////////////////////////////////////////////////////////////////
167 /// Destructor. Delete all owned subgenerator contexts
168 
169 RooSimGenContext::~RooSimGenContext()
170 {
171  delete[] _fracThresh ;
172  delete _idxCatSet ;
173  for (vector<RooAbsGenContext*>::iterator iter = _gcList.begin() ; iter!=_gcList.end() ; ++iter) {
174  delete (*iter) ;
175  }
176  delete _proxyIter ;
177  if (_protoData) delete _protoData ;
178 }
179 
180 
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// Attach the index category clone to the given event buffer
184 
185 void RooSimGenContext::attach(const RooArgSet& args)
186 {
187  if (_idxCat->isDerived()) {
188  _idxCat->recursiveRedirectServers(args,kTRUE) ;
189  }
190 
191  // Forward initGenerator call to all components
192  for (vector<RooAbsGenContext*>::iterator iter = _gcList.begin() ; iter!=_gcList.end() ; ++iter) {
193  (*iter)->attach(args) ;
194  }
195 
196 }
197 
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// Perform one-time initialization of generator context
201 
202 void RooSimGenContext::initGenerator(const RooArgSet &theEvent)
203 {
204  // Attach the index category clone to the event
205  if (_idxCat->isDerived()) {
206  _idxCat->recursiveRedirectServers(theEvent,kTRUE) ;
207  } else {
208  _idxCat = (RooAbsCategoryLValue*) theEvent.find(_idxCat->GetName()) ;
209  }
210 
211  // Update fractions reflecting possible new parameter values
212  updateFractions() ;
213 
214  // Forward initGenerator call to all components
215  for (vector<RooAbsGenContext*>::iterator iter = _gcList.begin() ; iter!=_gcList.end() ; ++iter) {
216  (*iter)->initGenerator(theEvent) ;
217  }
218 
219 }
220 
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Create an empty dataset to hold the events that will be generated
224 
225 RooDataSet* RooSimGenContext::createDataSet(const char* name, const char* title, const RooArgSet& obs)
226 {
227 
228  // If the observables do not contain the index, make a plain dataset
229  if (!obs.contains(*_idxCat)) {
230  return new RooDataSet(name,title,obs) ;
231  }
232 
233  if (!_protoData) {
234  map<string,RooAbsData*> dmap ;
235  RooCatType* state ;
236  TIterator* iter = _idxCat->typeIterator() ;
237  while((state=(RooCatType*)iter->Next())) {
238  RooAbsPdf* slicePdf = _pdf->getPdf(state->GetName()) ;
239  RooArgSet* sliceObs = slicePdf->getObservables(obs) ;
240  std::string sliceName = Form("%s_slice_%s",name,state->GetName()) ;
241  std::string sliceTitle = Form("%s (index slice %s)",title,state->GetName()) ;
242  RooDataSet* dset = new RooDataSet(sliceName.c_str(),sliceTitle.c_str(),*sliceObs) ;
243  dmap[state->GetName()] = dset ;
244  delete sliceObs ;
245  }
246  delete iter ;
247  _protoData = new RooDataSet(name, title, obs, Index((RooCategory&)*_idxCat), Link(dmap), OwnLinked()) ;
248 
249 // RooDataSet* tmp = _protoData ;
250 // _protoData = 0 ;
251 // return tmp ;
252  }
253 
254  RooDataSet* emptyClone = new RooDataSet(*_protoData,name) ;
255 
256  return emptyClone ;
257 }
258 
259 
260 
261 
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Generate event appropriate for current index state.
265 /// The index state is taken either from the prototype
266 /// or is generated from the fraction threshold table.
267 
268 void RooSimGenContext::generateEvent(RooArgSet &theEvent, Int_t remaining)
269 {
270  if (_haveIdxProto) {
271 
272  // Lookup pdf from selected prototype index state
273  Int_t gidx(0), cidx =_idxCat->getIndex() ;
274  for (Int_t i=0 ; i<(Int_t)_gcIndex.size() ; i++) {
275  if (_gcIndex[i]==cidx) { gidx = i ; break ; }
276  }
277  RooAbsGenContext* cx = _gcList[gidx] ;
278  if (cx) {
279  cx->generateEvent(theEvent,remaining) ;
280  } else {
281  oocoutW(_pdf,Generation) << "RooSimGenContext::generateEvent: WARNING, no PDF to generate event of type " << cidx << endl ;
282  }
283 
284 
285  } else {
286 
287  // Throw a random number and select PDF from fraction threshold table
288  Double_t rand = RooRandom::uniform() ;
289  Int_t i=0 ;
290  for (i=0 ; i<_numPdf ; i++) {
291  if (rand>_fracThresh[i] && rand<_fracThresh[i+1]) {
292  RooAbsGenContext* gen=_gcList[i] ;
293  gen->generateEvent(theEvent,remaining) ;
294  //Write through to sub-categories because they might be written to dataset:
295  _idxCat->setIndex(_gcIndex[i]);
296  return ;
297  }
298  }
299 
300  }
301 }
302 
303 
304 
305 ////////////////////////////////////////////////////////////////////////////////
306 /// No action needed if we have a proto index
307 
308 void RooSimGenContext::updateFractions()
309 {
310  if (_haveIdxProto) return ;
311 
312  // Generate index category and all registered PDFS
313  RooRealProxy* proxy ;
314  RooAbsPdf* pdf ;
315  Int_t i(1) ;
316  _proxyIter->Reset() ;
317  while((proxy=(RooRealProxy*)_proxyIter->Next())) {
318  pdf=(RooAbsPdf*)proxy->absArg() ;
319 
320  // Fill fraction threshold array
321  _fracThresh[i] = _fracThresh[i-1] + (_haveIdxProto?0:pdf->expectedEvents(&_allVarsPdf)) ;
322  i++ ;
323  }
324 
325  // Normalize fraction threshold array
326  if (!_haveIdxProto) {
327  for(i=0 ; i<_numPdf ; i++)
328  _fracThresh[i] /= _fracThresh[_numPdf] ;
329  }
330 
331 }
332 
333 
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// Set the traversal order of the prototype data to that in the
337 /// given lookup table. This information is passed to all
338 /// component generator contexts
339 
340 void RooSimGenContext::setProtoDataOrder(Int_t* lut)
341 {
342  RooAbsGenContext::setProtoDataOrder(lut) ;
343 
344  for (vector<RooAbsGenContext*>::iterator iter = _gcList.begin() ; iter!=_gcList.end() ; ++iter) {
345  (*iter)->setProtoDataOrder(lut) ;
346  }
347 }
348 
349 
350 ////////////////////////////////////////////////////////////////////////////////
351 /// Detailed printing interface
352 
353 void RooSimGenContext::printMultiline(ostream &os, Int_t content, Bool_t verbose, TString indent) const
354 {
355  RooAbsGenContext::printMultiline(os,content,verbose,indent) ;
356  os << indent << "--- RooSimGenContext ---" << endl ;
357  os << indent << "Using PDF ";
358  _pdf->printStream(os,kName|kArgs|kClassName,kSingleLine,indent);
359  os << indent << "List of component generators" << endl ;
360 
361  TString indent2(indent) ;
362  indent2.Append(" ") ;
363 
364  for (vector<RooAbsGenContext*>::const_iterator iter = _gcList.begin() ; iter!=_gcList.end() ; ++iter) {
365  (*iter)->printMultiline(os,content,verbose,indent2);
366  }
367 }