Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RooSimultaneous.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 RooSimultaneous.cxx
19 \class RooSimultaneous
20 \ingroup Roofitcore
21 
22 RooSimultaneous facilitates simultaneous fitting of multiple PDFs
23 to subsets of a given dataset.
24 The class takes an index category, which is used as a selector
25 for PDFs, and a list of PDFs, each associated
26 with a state of the index category. RooSimultaneous always returns
27 the value of the PDF that is associated with the current value
28 of the index category.
29 
30 Extended likelihood fitting is supported if all components support
31 extended likelihood mode. The expected number of events by a RooSimultaneous
32 is that of the component p.d.f. selected by the index category.
33 
34 The index category can be accessed using indexCategory().
35 
36 ###Generating events
37 When generating events from a RooSimultaneous, the index category has to be added to
38 the dataset. Further, the PDF needs to know the relative probabilities of each category, i.e.,
39 how many events are in which category. This can be achieved in two ways:
40 - Generating with proto data that have category entries: An event from the same category as
41 in the proto data is created for each event in the proto data.
42 See RooAbsPdf::generate(const RooArgSet&,const RooDataSet&,Int_t,Bool_t,Bool_t,Bool_t) const.
43 - No proto data: A category is chosen randomly.
44 \note This requires that the PDFs building the simultaneous are extended. In this way,
45 the relative probability of each category can be calculated from the number of events
46 in each category.
47 **/
48 
49 #include "RooFit.h"
50 #include "Riostream.h"
51 
52 #include "TObjString.h"
53 #include "RooSimultaneous.h"
54 #include "RooAbsCategoryLValue.h"
55 #include "RooPlot.h"
56 #include "RooCurve.h"
57 #include "RooRealVar.h"
58 #include "RooAddPdf.h"
59 #include "RooAbsData.h"
60 #include "Roo1DTable.h"
61 #include "RooSimGenContext.h"
62 #include "RooSimSplitGenContext.h"
63 #include "RooDataSet.h"
64 #include "RooCmdConfig.h"
65 #include "RooNameReg.h"
66 #include "RooGlobalFunc.h"
67 #include "RooNameReg.h"
68 #include "RooMsgService.h"
69 #include "RooCategory.h"
70 #include "RooSuperCategory.h"
71 #include "RooDataHist.h"
72 #include "RooRandom.h"
73 #include "RooArgSet.h"
74 
75 using namespace std ;
76 
77 ClassImp(RooSimultaneous);
78 ;
79 
80 
81 
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Constructor with index category. PDFs associated with indexCat
85 /// states can be added after construction with the addPdf() function.
86 ///
87 /// RooSimultaneous can function without having a PDF associated
88 /// with every single state. The normalization in such cases is taken
89 /// from the number of registered PDFs, but getVal() will assert if
90 /// when called for an unregistered index state.
91 
92 RooSimultaneous::RooSimultaneous(const char *name, const char *title,
93  RooAbsCategoryLValue& inIndexCat) :
94  RooAbsPdf(name,title),
95  _plotCoefNormSet("!plotCoefNormSet","plotCoefNormSet",this,kFALSE,kFALSE),
96  _plotCoefNormRange(0),
97  _partIntMgr(this,10),
98  _indexCat("indexCat","Index category",this,inIndexCat),
99  _numPdf(0)
100 {
101 }
102 
103 
104 
105 ////////////////////////////////////////////////////////////////////////////////
106 /// Constructor from index category and full list of PDFs.
107 /// In this constructor form, a PDF must be supplied for each indexCat state
108 /// to avoid ambiguities. The PDFs are associated in order with the state of the
109 /// index category as listed by the index categories type iterator.
110 ///
111 /// PDFs may not overlap (i.e. share any variables) with the index category (function)
112 
113 RooSimultaneous::RooSimultaneous(const char *name, const char *title,
114  const RooArgList& inPdfList, RooAbsCategoryLValue& inIndexCat) :
115  RooAbsPdf(name,title),
116  _plotCoefNormSet("!plotCoefNormSet","plotCoefNormSet",this,kFALSE,kFALSE),
117  _plotCoefNormRange(0),
118  _partIntMgr(this,10),
119  _indexCat("indexCat","Index category",this,inIndexCat),
120  _numPdf(0)
121 {
122  if (inPdfList.getSize() != inIndexCat.numTypes()) {
123  coutE(InputArguments) << "RooSimultaneous::ctor(" << GetName()
124  << " ERROR: Number PDF list entries must match number of index category states, no PDFs added" << endl ;
125  return ;
126  }
127 
128  map<string,RooAbsPdf*> pdfMap ;
129  // Iterator over PDFs and index cat states and add each pair
130  TIterator* pIter = inPdfList.createIterator() ;
131  TIterator* cIter = inIndexCat.typeIterator() ;
132  RooAbsPdf* pdf ;
133  RooCatType* type(0) ;
134  while ((pdf=(RooAbsPdf*)pIter->Next())) {
135  type = (RooCatType*) cIter->Next() ;
136  pdfMap[string(type->GetName())] = pdf ;
137  }
138  delete pIter ;
139  delete cIter ;
140 
141  initialize(inIndexCat,pdfMap) ;
142 }
143 
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 
147 RooSimultaneous::RooSimultaneous(const char *name, const char *title,
148  map<string,RooAbsPdf*> pdfMap, RooAbsCategoryLValue& inIndexCat) :
149  RooAbsPdf(name,title),
150  _plotCoefNormSet("!plotCoefNormSet","plotCoefNormSet",this,kFALSE,kFALSE),
151  _plotCoefNormRange(0),
152  _partIntMgr(this,10),
153  _indexCat("indexCat","Index category",this,inIndexCat),
154  _numPdf(0)
155 {
156  initialize(inIndexCat,pdfMap) ;
157 }
158 
159 
160 
161 
162 // This class cannot be locally defined in initialize as it cannot be
163 // used as a template argument in that case
164 namespace RooSimultaneousAux {
165  struct CompInfo {
166  RooAbsPdf* pdf ;
167  RooSimultaneous* simPdf ;
168  const RooAbsCategoryLValue* subIndex ;
169  RooArgSet* subIndexComps ;
170  } ;
171 }
172 
173 void RooSimultaneous::initialize(RooAbsCategoryLValue& inIndexCat, std::map<std::string,RooAbsPdf*> pdfMap)
174 {
175  // First see if there are any RooSimultaneous input components
176  Bool_t simComps(kFALSE) ;
177  for (map<string,RooAbsPdf*>::iterator iter=pdfMap.begin() ; iter!=pdfMap.end() ; ++iter) {
178  if (dynamic_cast<RooSimultaneous*>(iter->second)) {
179  simComps = kTRUE ;
180  break ;
181  }
182  }
183 
184  // If there are no simultaneous component p.d.f. do simple processing through addPdf()
185  if (!simComps) {
186  bool failure = false;
187  for (map<string,RooAbsPdf*>::iterator iter=pdfMap.begin() ; iter!=pdfMap.end() ; ++iter) {
188  failure |= addPdf(*iter->second,iter->first.c_str()) ;
189  }
190 
191  if (failure) {
192  throw std::invalid_argument(std::string("At least one of the PDFs of the RooSimultaneous ")
193  + GetName() + " is invalid.");
194  }
195  return ;
196  }
197 
198  // Issue info message that we are about to do some rearraning
199  coutI(InputArguments) << "RooSimultaneous::initialize(" << GetName() << ") INFO: one or more input component of simultaneous p.d.f.s are"
200  << " simultaneous p.d.f.s themselves, rewriting composite expressions as one-level simultaneous p.d.f. in terms of"
201  << " final constituents and extended index category" << endl ;
202 
203 
204  RooArgSet allAuxCats ;
205  map<string,RooSimultaneousAux::CompInfo> compMap ;
206  for (map<string,RooAbsPdf*>::iterator iter=pdfMap.begin() ; iter!=pdfMap.end() ; ++iter) {
207  RooSimultaneousAux::CompInfo ci ;
208  ci.pdf = iter->second ;
209  RooSimultaneous* simComp = dynamic_cast<RooSimultaneous*>(iter->second) ;
210  if (simComp) {
211  ci.simPdf = simComp ;
212  ci.subIndex = &simComp->indexCat() ;
213  ci.subIndexComps = simComp->indexCat().isFundamental() ? new RooArgSet(simComp->indexCat()) : simComp->indexCat().getVariables() ;
214  allAuxCats.add(*(ci.subIndexComps),kTRUE) ;
215  } else {
216  ci.simPdf = 0 ;
217  ci.subIndex = 0 ;
218  ci.subIndexComps = 0 ;
219  }
220  compMap[iter->first] = ci ;
221  }
222 
223  // Construct the 'superIndex' from the nominal index category and all auxiliary components
224  RooArgSet allCats(inIndexCat) ;
225  allCats.add(allAuxCats) ;
226  string siname = Form("%s_index",GetName()) ;
227  RooSuperCategory* superIndex = new RooSuperCategory(siname.c_str(),siname.c_str(),allCats) ;
228  bool failure = false;
229 
230  // Now process each of original pdf/state map entries
231  for (map<string,RooSimultaneousAux::CompInfo>::iterator citer = compMap.begin() ; citer != compMap.end() ; ++citer) {
232 
233  RooArgSet repliCats(allAuxCats) ;
234  if (citer->second.subIndexComps) {
235  repliCats.remove(*citer->second.subIndexComps) ;
236  delete citer->second.subIndexComps ;
237  }
238  inIndexCat.setLabel(citer->first.c_str()) ;
239 
240  if (!citer->second.simPdf) {
241 
242  // Entry is a plain p.d.f. assign it to every state permutation of the repliCats set
243  RooSuperCategory repliSuperCat("tmp","tmp",repliCats) ;
244 
245  // Iterator over all states of repliSuperCat
246  for (const auto type : repliSuperCat) {
247  // Set value
248  repliSuperCat.setLabel(type->GetName()) ;
249  // Retrieve corresponding label of superIndex
250  string superLabel = superIndex->getLabel() ;
251  failure |= addPdf(*citer->second.pdf,superLabel.c_str()) ;
252  cxcoutD(InputArguments) << "RooSimultaneous::initialize(" << GetName()
253  << ") assigning pdf " << citer->second.pdf->GetName() << " to super label " << superLabel << endl ;
254  }
255  } else {
256 
257  // Entry is a simultaneous p.d.f
258 
259  if (repliCats.getSize()==0) {
260 
261  // Case 1 -- No replication of components of RooSim component are required
262 
263  for (const RooCatType* type : *citer->second.subIndex) {
264  const_cast<RooAbsCategoryLValue*>(citer->second.subIndex)->setLabel(type->GetName()) ;
265  string superLabel = superIndex->getLabel() ;
266  RooAbsPdf* compPdf = citer->second.simPdf->getPdf(type->GetName()) ;
267  if (compPdf) {
268  failure |= addPdf(*compPdf,superLabel.c_str()) ;
269  cxcoutD(InputArguments) << "RooSimultaneous::initialize(" << GetName()
270  << ") assigning pdf " << compPdf->GetName() << "(member of " << citer->second.pdf->GetName()
271  << ") to super label " << superLabel << endl ;
272  } else {
273  coutW(InputArguments) << "RooSimultaneous::initialize(" << GetName() << ") WARNING: No p.d.f. associated with label "
274  << type->GetName() << " for component RooSimultaneous p.d.f " << citer->second.pdf->GetName()
275  << "which is associated with master index label " << citer->first << endl ;
276  }
277  }
278 
279  } else {
280 
281  // Case 2 -- Replication of components of RooSim component are required
282 
283  // Make replication supercat
284  RooSuperCategory repliSuperCat("tmp","tmp",repliCats) ;
285 
286  for (const RooCatType* stype : *citer->second.subIndex) {
287  const_cast<RooAbsCategoryLValue*>(citer->second.subIndex)->setLabel(stype->GetName()) ;
288 
289  for (const RooCatType* rtype : repliSuperCat) {
290  repliSuperCat.setLabel(rtype->GetName()) ;
291  string superLabel = superIndex->getLabel() ;
292  RooAbsPdf* compPdf = citer->second.simPdf->getPdf(stype->GetName()) ;
293  if (compPdf) {
294  failure |= addPdf(*compPdf,superLabel.c_str()) ;
295  cxcoutD(InputArguments) << "RooSimultaneous::initialize(" << GetName()
296  << ") assigning pdf " << compPdf->GetName() << "(member of " << citer->second.pdf->GetName()
297  << ") to super label " << superLabel << endl ;
298  } else {
299  coutW(InputArguments) << "RooSimultaneous::initialize(" << GetName() << ") WARNING: No p.d.f. associated with label "
300  << stype->GetName() << " for component RooSimultaneous p.d.f " << citer->second.pdf->GetName()
301  << "which is associated with master index label " << citer->first << endl ;
302  }
303  }
304  }
305  }
306  }
307  }
308 
309  if (failure) {
310  throw std::invalid_argument(std::string("Failed to initialise RooSimultaneous ") + GetName());
311  }
312 
313  // Change original master index to super index and take ownership of it
314  _indexCat.setArg(*superIndex) ;
315  addOwnedComponents(*superIndex) ;
316 
317 }
318 
319 
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Copy constructor
323 
324 RooSimultaneous::RooSimultaneous(const RooSimultaneous& other, const char* name) :
325  RooAbsPdf(other,name),
326  _plotCoefNormSet("!plotCoefNormSet",this,other._plotCoefNormSet),
327  _plotCoefNormRange(other._plotCoefNormRange),
328  _partIntMgr(other._partIntMgr,this),
329  _indexCat("indexCat",this,other._indexCat),
330  _numPdf(other._numPdf)
331 {
332  // Copy proxy list
333  TIterator* pIter = other._pdfProxyList.MakeIterator() ;
334  RooRealProxy* proxy ;
335  while ((proxy=(RooRealProxy*)pIter->Next())) {
336  _pdfProxyList.Add(new RooRealProxy(proxy->GetName(),this,*proxy)) ;
337  }
338  delete pIter ;
339 }
340 
341 
342 
343 ////////////////////////////////////////////////////////////////////////////////
344 /// Destructor
345 
346 RooSimultaneous::~RooSimultaneous()
347 {
348  _pdfProxyList.Delete() ;
349 }
350 
351 
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 /// Return the p.d.f associated with the given index category name
355 
356 RooAbsPdf* RooSimultaneous::getPdf(const char* catName) const
357 {
358  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(catName) ;
359  return proxy ? ((RooAbsPdf*)proxy->absArg()) : 0 ;
360 }
361 
362 
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// Associate given PDF with index category state label 'catLabel'.
366 /// The name state must be already defined in the index category.
367 ///
368 /// RooSimultaneous can function without having a PDF associated
369 /// with every single state. The normalization in such cases is taken
370 /// from the number of registered PDFs, but getVal() will fail if
371 /// called for an unregistered index state.
372 ///
373 /// PDFs may not overlap (i.e. share any variables) with the index category (function).
374 /// \param[in] pdf PDF to be added.
375 /// \param[in] catLabel Name of the category state to be associated to the PDF.
376 /// \return `true` in case of failure.
377 
378 Bool_t RooSimultaneous::addPdf(const RooAbsPdf& pdf, const char* catLabel)
379 {
380  // PDFs cannot overlap with the index category
381  if (pdf.dependsOn(_indexCat.arg())) {
382  coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): PDF '" << pdf.GetName()
383  << "' overlaps with index category '" << _indexCat.arg().GetName() << "'."<< endl ;
384  return kTRUE ;
385  }
386 
387  // Each index state can only have one PDF associated with it
388  if (_pdfProxyList.FindObject(catLabel)) {
389  coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName() << "): index state '"
390  << catLabel << "' has already an associated PDF." << endl ;
391  return kTRUE ;
392  }
393 
394  const RooSimultaneous* simPdf = dynamic_cast<const RooSimultaneous*>(&pdf) ;
395  if (simPdf) {
396 
397  coutE(InputArguments) << "RooSimultaneous::addPdf(" << GetName()
398  << ") ERROR: you cannot add a RooSimultaneous component to a RooSimultaneous using addPdf()."
399  << " Use the constructor with RooArgList if input p.d.f.s or the map<string,RooAbsPdf&> instead." << endl ;
400  return kTRUE ;
401 
402  } else {
403 
404  // Create a proxy named after the associated index state
405  TObject* proxy = new RooRealProxy(catLabel,catLabel,this,(RooAbsPdf&)pdf) ;
406  _pdfProxyList.Add(proxy) ;
407  _numPdf += 1 ;
408  }
409 
410  return kFALSE ;
411 }
412 
413 
414 
415 
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// WVE NEEDS FIX
419 
420 RooAbsPdf::ExtendMode RooSimultaneous::extendMode() const
421 {
422  Bool_t allCanExtend(kTRUE) ;
423  Bool_t anyMustExtend(kFALSE) ;
424 
425  for (Int_t i=0 ; i<_numPdf ; i++) {
426  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(_indexCat.label()) ;
427  if (proxy) {
428 // cout << " now processing pdf " << pdf->GetName() << endl ;
429  RooAbsPdf* pdf = (RooAbsPdf*) proxy->absArg() ;
430  if (!pdf->canBeExtended()) {
431 // cout << "RooSim::extendedMode(" << GetName() << ") component " << pdf->GetName() << " cannot be extended" << endl ;
432  allCanExtend=kFALSE ;
433  }
434  if (pdf->mustBeExtended()) {
435  anyMustExtend=kTRUE;
436  }
437  }
438  }
439  if (anyMustExtend) {
440 // cout << "RooSim::extendedMode(" << GetName() << ") returning MustBeExtended" << endl ;
441  return MustBeExtended ;
442  }
443  if (allCanExtend) {
444 // cout << "RooSim::extendedMode(" << GetName() << ") returning CanBeExtended" << endl ;
445  return CanBeExtended ;
446  }
447 // cout << "RooSim::extendedMode(" << GetName() << ") returning CanNotBeExtended" << endl ;
448  return CanNotBeExtended ;
449 }
450 
451 
452 
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 /// Return the current value:
456 /// the value of the PDF associated with the current index category state
457 
458 Double_t RooSimultaneous::evaluate() const
459 {
460  // Retrieve the proxy by index name
461  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(_indexCat.label()) ;
462 
463  //assert(proxy!=0) ;
464  if (proxy==0) return 0 ;
465 
466  // Calculate relative weighting factor for sim-pdfs of all extendable components
467  Double_t catFrac(1) ;
468  if (canBeExtended()) {
469  Double_t nEvtCat = ((RooAbsPdf*)(proxy->absArg()))->expectedEvents(_normSet) ;
470 
471  Double_t nEvtTot(0) ;
472  TIterator* iter = _pdfProxyList.MakeIterator() ;
473  RooRealProxy* proxy2 ;
474  while((proxy2=(RooRealProxy*)iter->Next())) {
475  nEvtTot += ((RooAbsPdf*)(proxy2->absArg()))->expectedEvents(_normSet) ;
476  }
477  delete iter ;
478  catFrac=nEvtCat/nEvtTot ;
479  }
480 
481  // Return the selected PDF value, normalized by the number of index states
482  return ((RooAbsPdf*)(proxy->absArg()))->getVal(_normSet)*catFrac ;
483 }
484 
485 
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Return the number of expected events: If the index is in nset,
489 /// then return the sum of the expected events of all components,
490 /// otherwise return the number of expected events of the PDF
491 /// associated with the current index category state
492 
493 Double_t RooSimultaneous::expectedEvents(const RooArgSet* nset) const
494 {
495  if (nset->contains(_indexCat.arg())) {
496 
497  Double_t sum(0) ;
498 
499  TIterator* iter = _pdfProxyList.MakeIterator() ;
500  RooRealProxy* proxy ;
501  while((proxy=(RooRealProxy*)iter->Next())) {
502  sum += ((RooAbsPdf*)(proxy->absArg()))->expectedEvents(nset) ;
503  }
504  delete iter ;
505 
506  return sum ;
507 
508  } else {
509 
510  // Retrieve the proxy by index name
511  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(_indexCat.label()) ;
512 
513  //assert(proxy!=0) ;
514  if (proxy==0) return 0 ;
515 
516  // Return the selected PDF value, normalized by the number of index states
517  return ((RooAbsPdf*)(proxy->absArg()))->expectedEvents(nset);
518  }
519 }
520 
521 
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 /// Forward determination of analytical integration capabilities to component p.d.f.s
525 /// A unique code is assigned to the combined integration capabilities of all associated
526 /// p.d.f.s
527 
528 Int_t RooSimultaneous::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars,
529  const RooArgSet* normSet, const char* rangeName) const
530 {
531  // Declare that we can analytically integrate all requested observables
532  analVars.add(allVars) ;
533 
534  // Retrieve (or create) the required partial integral list
535  Int_t code ;
536 
537  // Check if this configuration was created before
538  CacheElem* cache = (CacheElem*) _partIntMgr.getObj(normSet,&analVars,0,RooNameReg::ptr(rangeName)) ;
539  if (cache) {
540  code = _partIntMgr.lastIndex() ;
541  return code+1 ;
542  }
543  cache = new CacheElem ;
544 
545  // Create the partial integral set for this request
546  TIterator* iter = _pdfProxyList.MakeIterator() ;
547  RooRealProxy* proxy ;
548  while((proxy=(RooRealProxy*)iter->Next())) {
549  RooAbsReal* pdfInt = proxy->arg().createIntegral(analVars,normSet,0,rangeName) ;
550  cache->_partIntList.addOwned(*pdfInt) ;
551  }
552  delete iter ;
553 
554  // Store the partial integral list and return the assigned code ;
555  code = _partIntMgr.setObj(normSet,&analVars,cache,RooNameReg::ptr(rangeName)) ;
556 
557  return code+1 ;
558 }
559 
560 
561 
562 ////////////////////////////////////////////////////////////////////////////////
563 /// Return analytical integration defined by given code
564 
565 Double_t RooSimultaneous::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* /*rangeName*/) const
566 {
567  // No integration scenario
568  if (code==0) {
569  return getVal(normSet) ;
570  }
571 
572  // Partial integration scenarios, rangeName already encoded in 'code'
573  CacheElem* cache = (CacheElem*) _partIntMgr.getObjByIndex(code-1) ;
574 
575  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(_indexCat.label()) ;
576  Int_t idx = _pdfProxyList.IndexOf(proxy) ;
577  return ((RooAbsReal*)cache->_partIntList.at(idx))->getVal(normSet) ;
578 }
579 
580 
581 
582 
583 
584 
585 ////////////////////////////////////////////////////////////////////////////////
586 /// Back-end for plotOn() implementation on RooSimultaneous which
587 /// needs special handling because a RooSimultaneous PDF cannot
588 /// project out its index category via integration, plotOn() will
589 /// abort if this is requested without providing a projection dataset
590 
591 RooPlot* RooSimultaneous::plotOn(RooPlot *frame, RooLinkedList& cmdList) const
592 {
593  // Sanity checks
594  if (plotSanityChecks(frame)) return frame ;
595 
596  // Extract projection configuration from command list
597  RooCmdConfig pc(Form("RooSimultaneous::plotOn(%s)",GetName())) ;
598  pc.defineString("sliceCatState","SliceCat",0,"",kTRUE) ;
599  pc.defineDouble("scaleFactor","Normalization",0,1.0) ;
600  pc.defineInt("scaleType","Normalization",0,RooAbsPdf::Relative) ;
601  pc.defineObject("sliceCatList","SliceCat",0,0,kTRUE) ;
602  pc.defineObject("projSet","Project",0) ;
603  pc.defineObject("sliceSet","SliceVars",0) ;
604  pc.defineObject("projDataSet","ProjData",0) ;
605  pc.defineObject("projData","ProjData",1) ;
606  pc.defineMutex("Project","SliceVars") ;
607  pc.allowUndefined() ; // there may be commands we don't handle here
608 
609  // Process and check varargs
610  pc.process(cmdList) ;
611  if (!pc.ok(kTRUE)) {
612  return frame ;
613  }
614 
615  const RooAbsData* projData = (const RooAbsData*) pc.getObject("projData") ;
616  const RooArgSet* projDataSet = (const RooArgSet*) pc.getObject("projDataSet") ;
617  const RooArgSet* sliceSetTmp = (const RooArgSet*) pc.getObject("sliceSet") ;
618  RooArgSet* sliceSet = sliceSetTmp ? ((RooArgSet*) sliceSetTmp->Clone()) : 0 ;
619  const RooArgSet* projSet = (const RooArgSet*) pc.getObject("projSet") ;
620  Double_t scaleFactor = pc.getDouble("scaleFactor") ;
621  ScaleType stype = (ScaleType) pc.getInt("scaleType") ;
622 
623 
624  // Look for category slice arguments and add them to the master slice list if found
625  const char* sliceCatState = pc.getString("sliceCatState",0,kTRUE) ;
626  const RooLinkedList& sliceCatList = pc.getObjectList("sliceCatList") ;
627  if (sliceCatState) {
628 
629  // Make the master slice set if it doesnt exist
630  if (!sliceSet) {
631  sliceSet = new RooArgSet ;
632  }
633 
634  // Prepare comma separated label list for parsing
635  char buf[1024] ;
636  strlcpy(buf,sliceCatState,1024) ;
637  const char* slabel = strtok(buf,",") ;
638 
639  // Loop over all categories provided by (multiple) Slice() arguments
640  TIterator* iter = sliceCatList.MakeIterator() ;
641  RooCategory* scat ;
642  while((scat=(RooCategory*)iter->Next())) {
643  if (slabel) {
644  // Set the slice position to the value indicate by slabel
645  scat->setLabel(slabel) ;
646  // Add the slice category to the master slice set
647  sliceSet->add(*scat,kFALSE) ;
648  }
649  slabel = strtok(0,",") ;
650  }
651  delete iter ;
652  }
653 
654  // Check if we have a projection dataset
655  if (!projData) {
656  coutE(InputArguments) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: must have a projection dataset for index category" << endl ;
657  return frame ;
658  }
659 
660  // Make list of variables to be projected
661  RooArgSet projectedVars ;
662  if (sliceSet) {
663  //cout << "frame->getNormVars() = " ; frame->getNormVars()->Print("1") ;
664 
665  makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,kTRUE) ;
666 
667  // Take out the sliced variables
668  TIterator* iter = sliceSet->createIterator() ;
669  RooAbsArg* sliceArg ;
670  while((sliceArg=(RooAbsArg*)iter->Next())) {
671  RooAbsArg* arg = projectedVars.find(sliceArg->GetName()) ;
672  if (arg) {
673  projectedVars.remove(*arg) ;
674  } else {
675  coutI(Plotting) << "RooAbsReal::plotOn(" << GetName() << ") slice variable "
676  << sliceArg->GetName() << " was not projected anyway" << endl ;
677  }
678  }
679  delete iter ;
680  } else if (projSet) {
681  makeProjectionSet(frame->getPlotVar(),projSet,projectedVars,kFALSE) ;
682  } else {
683  makeProjectionSet(frame->getPlotVar(),frame->getNormVars(),projectedVars,kTRUE) ;
684  }
685 
686  Bool_t projIndex(kFALSE) ;
687 
688  if (!_indexCat.arg().isDerived()) {
689  // *** Error checking for a fundamental index category ***
690  //cout << "RooSim::plotOn: index is fundamental" << endl ;
691 
692  // Check that the provided projection dataset contains our index variable
693  if (!projData->get()->find(_indexCat.arg().GetName())) {
694  coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") ERROR: Projection over index category "
695  << "requested, but projection data set doesn't contain index category" << endl ;
696  return frame ;
697  }
698 
699  if (projectedVars.find(_indexCat.arg().GetName())) {
700  projIndex=kTRUE ;
701  }
702 
703  } else {
704  // *** Error checking for a composite index category ***
705 
706  // Determine if any servers of the index category are in the projectedVars
707  TIterator* sIter = _indexCat.arg().serverIterator() ;
708  RooAbsArg* server ;
709  RooArgSet projIdxServers ;
710  Bool_t anyServers(kFALSE) ;
711  while((server=(RooAbsArg*)sIter->Next())) {
712  if (projectedVars.find(server->GetName())) {
713  anyServers=kTRUE ;
714  projIdxServers.add(*server) ;
715  }
716  }
717  delete sIter ;
718 
719  // Check that the projection dataset contains all the
720  // index category components we're projecting over
721 
722  // Determine if all projected servers of the index category are in the projection dataset
723  sIter = projIdxServers.createIterator() ;
724  Bool_t allServers(kTRUE) ;
725  while((server=(RooAbsArg*)sIter->Next())) {
726  if (!projData->get()->find(server->GetName())) {
727  allServers=kFALSE ;
728  }
729  }
730  delete sIter ;
731 
732  if (!allServers) {
733  coutE(Plotting) << "RooSimultaneous::plotOn(" << GetName()
734  << ") ERROR: Projection dataset doesn't contain complete set of index category dependents" << endl ;
735  return frame ;
736  }
737 
738  if (anyServers) {
739  projIndex = kTRUE ;
740  }
741  }
742 
743  // Calculate relative weight fractions of components
744  Roo1DTable* wTable = projData->table(_indexCat.arg()) ;
745 
746  // If we don't project over the index, just do the regular plotOn
747  if (!projIndex) {
748 
749  coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
750  << " represents a slice in the index category (" << _indexCat.arg().GetName() << ")" << endl ;
751 
752  // Reduce projData: take out fitCat (component) columns and entries that don't match selected slice
753  // Construct cut string to only select projection data event that match the current slice
754 
755  const RooAbsData* projDataTmp(projData) ;
756 
757  // Make list of categories columns to exclude from projection data
758  RooArgSet* indexCatComps = _indexCat.arg().getObservables(frame->getNormVars());
759 
760  // Make cut string to exclude rows from projection data
761  TString cutString ;
762  TIterator* compIter = indexCatComps->createIterator();
763  RooAbsCategory* idxComp ;
764  Bool_t first(kTRUE) ;
765  while((idxComp=(RooAbsCategory*)compIter->Next())) {
766  RooAbsArg* slicedComponent = nullptr;
767  if (sliceSet && (slicedComponent = sliceSet->find(*idxComp)) != nullptr) {
768  auto theCat = static_cast<const RooAbsCategory*>(slicedComponent);
769  auto idxCompLV = dynamic_cast<RooAbsCategoryLValue*>(idxComp);
770  if (idxCompLV)
771  idxCompLV->setIndex(theCat->getIndex(), false);
772  }
773 
774  if (!first) {
775  cutString.Append("&&") ;
776  } else {
777  first=kFALSE ;
778  }
779  cutString.Append(Form("%s==%d",idxComp->GetName(),idxComp->getIndex())) ;
780  }
781  delete compIter ;
782 
783  // Make temporary projData without RooSim index category components
784  RooArgSet projDataVars(*projData->get()) ;
785  projDataVars.remove(*indexCatComps,kTRUE,kTRUE) ;
786 
787  projDataTmp = ((RooAbsData*)projData)->reduce(projDataVars,cutString) ;
788  delete indexCatComps ;
789 
790  // Multiply scale factor with fraction of events in current state of index
791 
792 // RooPlot* retFrame = getPdf(_indexCat.arg().getLabel())->plotOn(frame,drawOptions,
793 // scaleFactor*wTable->getFrac(_indexCat.arg().getLabel()),
794 // stype,projDataTmp,projSet) ;
795 
796  // Override normalization and projection dataset
797  RooCmdArg tmp1 = RooFit::Normalization(scaleFactor*wTable->getFrac(_indexCat.arg().getLabel()),stype) ;
798  RooCmdArg tmp2 = RooFit::ProjWData(*projDataSet,*projDataTmp) ;
799 
800  // WVE -- do not adjust normalization for asymmetry plots
801  RooLinkedList cmdList2(cmdList) ;
802  if (!cmdList.find("Asymmetry")) {
803  cmdList2.Add(&tmp1) ;
804  }
805  cmdList2.Add(&tmp2) ;
806 
807  // Plot single component
808  RooPlot* retFrame = getPdf(_indexCat.arg().getLabel())->plotOn(frame,cmdList2) ;
809 
810  // Delete temporary dataset
811  delete projDataTmp ;
812 
813  delete wTable ;
814  delete sliceSet ;
815  return retFrame ;
816  }
817 
818  // If we project over the index, plot using a temporary RooAddPdf
819  // using the weights from the data as coefficients
820 
821  // Make a deep clone of our index category
822  RooArgSet* idxCloneSet = (RooArgSet*) RooArgSet(_indexCat.arg()).snapshot(kTRUE) ;
823  RooAbsCategoryLValue* idxCatClone = (RooAbsCategoryLValue*) idxCloneSet->find(_indexCat.arg().GetName()) ;
824 
825  // Build the list of indexCat components that are sliced
826  RooArgSet* idxCompSliceSet = _indexCat.arg().getObservables(frame->getNormVars()) ;
827  idxCompSliceSet->remove(projectedVars,kTRUE,kTRUE) ;
828  TIterator* idxCompSliceIter = idxCompSliceSet->createIterator() ;
829 
830  // Make a new expression that is the weighted sum of requested components
831  RooArgList pdfCompList ;
832  RooArgList wgtCompList ;
833 //RooAbsPdf* pdf ;
834  RooRealProxy* proxy ;
835  TIterator* pIter = _pdfProxyList.MakeIterator() ;
836  Double_t sumWeight(0) ;
837  while((proxy=(RooRealProxy*)pIter->Next())) {
838 
839  idxCatClone->setLabel(proxy->name()) ;
840 
841  // Determine if this component is the current slice (if we slice)
842  Bool_t skip(kFALSE) ;
843  idxCompSliceIter->Reset() ;
844  RooAbsCategory* idxSliceComp ;
845  while((idxSliceComp=(RooAbsCategory*)idxCompSliceIter->Next())) {
846  RooAbsCategory* idxComp = (RooAbsCategory*) idxCloneSet->find(idxSliceComp->GetName()) ;
847  if (idxComp->getIndex()!=idxSliceComp->getIndex()) {
848  skip=kTRUE ;
849  break ;
850  }
851  }
852  if (skip) continue ;
853 
854  // Instantiate a RRV holding this pdfs weight fraction
855  RooRealVar *wgtVar = new RooRealVar(proxy->name(),"coef",wTable->getFrac(proxy->name())) ;
856  wgtCompList.addOwned(*wgtVar) ;
857  sumWeight += wTable->getFrac(proxy->name()) ;
858 
859  // Add the PDF to list list
860  pdfCompList.add(proxy->arg()) ;
861  }
862 
863  TString plotVarName(GetName()) ;
864  RooAddPdf *plotVar = new RooAddPdf(plotVarName,"weighted sum of RS components",pdfCompList,wgtCompList) ;
865 
866  // Fix appropriate coefficient normalization in plot function
867  if (_plotCoefNormSet.getSize()>0) {
868  plotVar->fixAddCoefNormalization(_plotCoefNormSet) ;
869  }
870 
871  RooAbsData* projDataTmp(0) ;
872  RooArgSet projSetTmp ;
873  if (projData) {
874 
875  // Construct cut string to only select projection data event that match the current slice
876  TString cutString ;
877  if (idxCompSliceSet->getSize()>0) {
878  idxCompSliceIter->Reset() ;
879  RooAbsCategory* idxSliceComp ;
880  Bool_t first(kTRUE) ;
881  while((idxSliceComp=(RooAbsCategory*)idxCompSliceIter->Next())) {
882  if (!first) {
883  cutString.Append("&&") ;
884  } else {
885  first=kFALSE ;
886  }
887  cutString.Append(Form("%s==%d",idxSliceComp->GetName(),idxSliceComp->getIndex())) ;
888  }
889  }
890 
891  // Make temporary projData without RooSim index category components
892  RooArgSet projDataVars(*projData->get()) ;
893  RooArgSet* idxCatServers = _indexCat.arg().getObservables(frame->getNormVars()) ;
894 
895  projDataVars.remove(*idxCatServers,kTRUE,kTRUE) ;
896 
897  if (idxCompSliceSet->getSize()>0) {
898  projDataTmp = ((RooAbsData*)projData)->reduce(projDataVars,cutString) ;
899  } else {
900  projDataTmp = ((RooAbsData*)projData)->reduce(projDataVars) ;
901  }
902 
903 
904 
905  if (projSet) {
906  projSetTmp.add(*projSet) ;
907  projSetTmp.remove(*idxCatServers,kTRUE,kTRUE);
908  }
909 
910 
911  delete idxCatServers ;
912  }
913 
914 
915  if (_indexCat.arg().isDerived() && idxCompSliceSet->getSize()>0) {
916  coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
917  << " represents a slice in index category components " << *idxCompSliceSet << endl ;
918 
919  RooArgSet* idxCompProjSet = _indexCat.arg().getObservables(frame->getNormVars()) ;
920  idxCompProjSet->remove(*idxCompSliceSet,kTRUE,kTRUE) ;
921  if (idxCompProjSet->getSize()>0) {
922  coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
923  << " averages with data index category components " << *idxCompProjSet << endl ;
924  }
925  delete idxCompProjSet ;
926  } else {
927  coutI(Plotting) << "RooSimultaneous::plotOn(" << GetName() << ") plot on " << frame->getPlotVar()->GetName()
928  << " averages with data index category (" << _indexCat.arg().GetName() << ")" << endl ;
929  }
930 
931 
932  // Override normalization and projection dataset
933  RooLinkedList cmdList2(cmdList) ;
934 
935  RooCmdArg tmp1 = RooFit::Normalization(scaleFactor*sumWeight,stype) ;
936  RooCmdArg tmp2 = RooFit::ProjWData(*projDataSet,*projDataTmp) ;
937  // WVE -- do not adjust normalization for asymmetry plots
938  if (!cmdList.find("Asymmetry")) {
939  cmdList2.Add(&tmp1) ;
940  }
941  cmdList2.Add(&tmp2) ;
942 
943  RooPlot* frame2 ;
944  if (projSetTmp.getSize()>0) {
945  // Plot temporary function
946  RooCmdArg tmp3 = RooFit::Project(projSetTmp) ;
947  cmdList2.Add(&tmp3) ;
948  frame2 = plotVar->plotOn(frame,cmdList2) ;
949  } else {
950  // Plot temporary function
951  frame2 = plotVar->plotOn(frame,cmdList2) ;
952  }
953 
954  // Cleanup
955  delete sliceSet ;
956  delete pIter ;
957  delete wTable ;
958  delete idxCloneSet ;
959  delete idxCompSliceIter ;
960  delete idxCompSliceSet ;
961  delete plotVar ;
962 
963  if (projDataTmp) delete projDataTmp ;
964 
965  return frame2 ;
966 }
967 
968 
969 
970 ////////////////////////////////////////////////////////////////////////////////
971 /// OBSOLETE -- Retained for backward compatibility
972 
973 RooPlot* RooSimultaneous::plotOn(RooPlot *frame, Option_t* drawOptions, Double_t scaleFactor,
974  ScaleType stype, const RooAbsData* projData, const RooArgSet* projSet,
975  Double_t /*precision*/, Bool_t /*shiftToZero*/, const RooArgSet* /*projDataSet*/,
976  Double_t /*rangeLo*/, Double_t /*rangeHi*/, RooCurve::WingMode /*wmode*/) const
977 {
978  // Make command list
979  RooLinkedList cmdList ;
980  cmdList.Add(new RooCmdArg(RooFit::DrawOption(drawOptions))) ;
981  cmdList.Add(new RooCmdArg(RooFit::Normalization(scaleFactor,stype))) ;
982  if (projData) cmdList.Add(new RooCmdArg(RooFit::ProjWData(*projData))) ;
983  if (projSet) cmdList.Add(new RooCmdArg(RooFit::Project(*projSet))) ;
984 
985  // Call new method
986  RooPlot* ret = plotOn(frame,cmdList) ;
987 
988  // Cleanup
989  cmdList.Delete() ;
990  return ret ;
991 }
992 
993 
994 
995 ////////////////////////////////////////////////////////////////////////////////
996 /// Interface function used by test statistics to freeze choice of observables
997 /// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
998 /// works like a RooAddPdf when plotted
999 
1000 void RooSimultaneous::selectNormalization(const RooArgSet* normSet, Bool_t /*force*/)
1001 {
1002  _plotCoefNormSet.removeAll() ;
1003  if (normSet) _plotCoefNormSet.add(*normSet) ;
1004 }
1005 
1006 
1007 ////////////////////////////////////////////////////////////////////////////////
1008 /// Interface function used by test statistics to freeze choice of range
1009 /// for interpretation of fraction coefficients. Needed here because a RooSimultaneous
1010 /// works like a RooAddPdf when plotted
1011 
1012 void RooSimultaneous::selectNormalizationRange(const char* normRange2, Bool_t /*force*/)
1013 {
1014  _plotCoefNormRange = RooNameReg::ptr(normRange2) ;
1015 }
1016 
1017 
1018 
1019 
1020 ////////////////////////////////////////////////////////////////////////////////
1021 
1022 RooAbsGenContext* RooSimultaneous::autoGenContext(const RooArgSet &vars, const RooDataSet* prototype,
1023  const RooArgSet* auxProto, Bool_t verbose, Bool_t autoBinned, const char* binnedTag) const
1024 {
1025  const char* idxCatName = _indexCat.arg().GetName() ;
1026 
1027  if (vars.find(idxCatName) && prototype==0
1028  && (auxProto==0 || auxProto->getSize()==0)
1029  && (autoBinned || (binnedTag && strlen(binnedTag)))) {
1030 
1031  // Return special generator config that can also do binned generation for selected states
1032  return new RooSimSplitGenContext(*this,vars,verbose,autoBinned,binnedTag) ;
1033 
1034  } else {
1035 
1036  // Return regular generator config ;
1037  return genContext(vars,prototype,auxProto,verbose) ;
1038  }
1039 }
1040 
1041 
1042 
1043 ////////////////////////////////////////////////////////////////////////////////
1044 /// Return specialized generator context for simultaneous p.d.f.s
1045 
1046 RooAbsGenContext* RooSimultaneous::genContext(const RooArgSet &vars, const RooDataSet *prototype,
1047  const RooArgSet* auxProto, Bool_t verbose) const
1048 {
1049  const char* idxCatName = _indexCat.arg().GetName() ;
1050  const RooArgSet* protoVars = prototype ? prototype->get() : 0 ;
1051 
1052  if (vars.find(idxCatName) || (protoVars && protoVars->find(idxCatName))) {
1053 
1054  // Generating index category: return special sim-context
1055  return new RooSimGenContext(*this,vars,prototype,auxProto,verbose) ;
1056 
1057  } else if (_indexCat.arg().isDerived()) {
1058  // Generating dependents of a derived index category
1059 
1060  // Determine if we none,any or all servers
1061  Bool_t anyServer(kFALSE), allServers(kTRUE) ;
1062  if (prototype) {
1063  TIterator* sIter = _indexCat.arg().serverIterator() ;
1064  RooAbsArg* server ;
1065  while((server=(RooAbsArg*)sIter->Next())) {
1066  if (prototype->get()->find(server->GetName())) {
1067  anyServer=kTRUE ;
1068  } else {
1069  allServers=kFALSE ;
1070  }
1071  }
1072  delete sIter ;
1073  } else {
1074  allServers=kTRUE ;
1075  }
1076 
1077  if (allServers) {
1078  // Use simcontext if we have all servers
1079 
1080  return new RooSimGenContext(*this,vars,prototype,auxProto,verbose) ;
1081  } else if (!allServers && anyServer) {
1082  // Abort if we have only part of the servers
1083  coutE(Plotting) << "RooSimultaneous::genContext: ERROR: prototype must include either all "
1084  << " components of the RooSimultaneous index category or none " << endl ;
1085  return 0 ;
1086  }
1087  // Otherwise make single gencontext for current state
1088  }
1089 
1090  // Not generating index cat: return context for pdf associated with present index state
1091  RooRealProxy* proxy = (RooRealProxy*) _pdfProxyList.FindObject(_indexCat.arg().getLabel()) ;
1092  if (!proxy) {
1093  coutE(InputArguments) << "RooSimultaneous::genContext(" << GetName()
1094  << ") ERROR: no PDF associated with current state ("
1095  << _indexCat.arg().GetName() << "=" << _indexCat.arg().getLabel() << ")" << endl ;
1096  return 0 ;
1097  }
1098  return ((RooAbsPdf*)proxy->absArg())->genContext(vars,prototype,auxProto,verbose) ;
1099 }
1100 
1101 
1102 
1103 
1104 ////////////////////////////////////////////////////////////////////////////////
1105 
1106 RooDataHist* RooSimultaneous::fillDataHist(RooDataHist *hist,
1107  const RooArgSet* nset,
1108  Double_t scaleFactor,
1109  Bool_t correctForBinVolume,
1110  Bool_t showProgress) const
1111 {
1112  if (RooAbsReal::fillDataHist (hist, nset, scaleFactor,
1113  correctForBinVolume, showProgress) == 0)
1114  return 0;
1115 
1116  Double_t sum = 0;
1117  for (int i=0 ; i<hist->numEntries() ; i++) {
1118  hist->get(i) ;
1119  sum += hist->weight();
1120  }
1121  if (sum != 0) {
1122  for (int i=0 ; i<hist->numEntries() ; i++) {
1123  hist->get(i) ;
1124  hist->set (hist->weight() / sum);
1125  }
1126  }
1127 
1128  return hist;
1129 }
1130 
1131 
1132 
1133 
1134 ////////////////////////////////////////////////////////////////////////////////
1135 /// Special generator interface for generation of 'global observables' -- for RooStats tools
1136 
1137 RooDataSet* RooSimultaneous::generateSimGlobal(const RooArgSet& whatVars, Int_t nEvents)
1138 {
1139  // Make set with clone of variables (placeholder for output)
1140  RooArgSet* globClone = (RooArgSet*) whatVars.snapshot() ;
1141 
1142  RooDataSet* data = new RooDataSet("gensimglobal","gensimglobal",whatVars) ;
1143 
1144  // Construct iterator over index types
1145  TIterator* iter = indexCat().typeIterator() ;
1146 
1147  for (Int_t i=0 ; i<nEvents ; i++) {
1148  iter->Reset() ;
1149  RooCatType* tt ;
1150  while((tt=(RooCatType*) iter->Next())) {
1151 
1152  // Get pdf associated with state from simpdf
1153  RooAbsPdf* pdftmp = getPdf(tt->GetName()) ;
1154 
1155  // Generate only global variables defined by the pdf associated with this state
1156  RooArgSet* globtmp = pdftmp->getObservables(whatVars) ;
1157  RooDataSet* tmp = pdftmp->generate(*globtmp,1) ;
1158 
1159  // Transfer values to output placeholder
1160  *globClone = *tmp->get(0) ;
1161 
1162  // Cleanup
1163  delete globtmp ;
1164  delete tmp ;
1165  }
1166  data->add(*globClone) ;
1167  }
1168 
1169 
1170  delete iter ;
1171  delete globClone ;
1172  return data ;
1173 }
1174 
1175 
1176 
1177 
1178 
1179 
1180 
1181 
1182