/***************************************************************************** * Project: RooFit * * Package: RooFitCore * * @(#)root/roofitcore:$Id$ * Authors: * * WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu * * DK, David Kirkby, UC Irvine, dkirkby@uci.edu * * * * Copyright (c) 2000-2005, Regents of the University of California * * and Stanford University. All rights reserved. * * * * Redistribution and use in source and binary forms, * * with or without modification, are permitted according to the terms * * listed in LICENSE (http://roofit.sourceforge.net/license.txt) * *****************************************************************************/ ////////////////////////////////////////////////////////////////////////////// // // Begin_Html // // This tool has now been superceded by RooSimWSTool // //

// RooSimPdfBuilder is a powerful tool to build RooSimultaneous // PDFs that are defined in terms component PDFs that are identical in // structure, but have different parameters. //

// //

Example

// //

// The following example demonstrates the essence of RooSimPdfBuilder: // Given a dataset D with a RooRealVar X and a RooCategory C that has // state C1 and C2. //

//

//

// Coding this example directly with RooFit classes gives // (we assume dataset D and variables C and X have been declared previously) //

//
// RooRealVar m("m","mean of gaussian",-10,10) ;
// RooRealVar s_C1("s_C1","sigma of gaussian C1",0,20) ;
// RooRealVar s_C2("s_C2","sigma of gaussian C2",0,20) ;
// RooGaussian gauss_C1("gauss_C1","gaussian C1",X,m,s_C1) ;
// RooGaussian gauss_C2("gauss_C2","gaussian C2",X,m,s_C2) ;
//
// RooRealVar k_C1("k_C1","ArgusBG kappa parameter C1",-50,0) ;
// RooRealVar k_C2("k_C2","ArgusBG kappa parameter C2",-50,0) ;
// RooRealVar xm("xm","ArgusBG cutoff point",5.29) ;
// RooArgusBG argus_C1("argus_C1","argus background C1",X,k_C1,xm) ;
// RooArgusBG argus_C2("argus_C2","argus background C2",X,k_C2,xm) ;
//
// RooRealVar gfrac("gfrac","fraction of gaussian",0.,1.) ;
// RooAddPdf pdf_C1("pdf_C1","gauss+argus_C1",RooArgList(gauss_C1,argus_C1),gfrac) ;
// RooAddPdf pdf_C2("pdf_C2","gauss+argus_C2",RooArgList(gauss_C2,argus_C2),gfrac) ;
//
// RooSimultaneous simPdf("simPdf","simPdf",C) ;   
// simPdf.addPdf(pdf_C1,"C1") ;
// simPdf.addPdf(pdf_C2,"C2") ;
//  
//

// Coding this example with RooSimPdfBuilder gives //

//
// RooRealVar m("m","mean of gaussian",-10,10) ;
// RooRealVar s("s","sigma of gaussian",0,20) ;
// RooGaussian gauss("gauss","gaussian",X,m,s) ;
//
// RooRealVar k("k","ArgusBG kappa parameter",-50,0) ;
// RooRealVar xm("xm","ArgusBG cutoff point",5.29) ;
// RooArgusBG argus("argus","argus background",X,k,xm) ;
//
// RooRealVar gfrac("gfrac","fraction of gaussian",0.,1.) ;
// RooAddPdf pdf("pdf","gauss+argus",RooArgList(gauss,argus),gfrac) ;
//
// RooSimPdfBuilder builder(pdf) ;
// RooArgSet* config = builder.createProtoBuildConfig() ;
// (*config)["physModels"] = "pdf" ;      // Name of the PDF we are going to work with
// (*config)["splitCats"]  = "C" ;        // Category used to differentiate sub-datasets
// (*config)["pdf"]        = "C : k,s" ;  // Prescription to taylor PDF parameters k and s 
//                                        // for each data subset designated by C states
// RooSimultaneous* simPdf = builder.buildPdf(*config,&D) ;
//  
//

// The above snippet of code demonstrates the concept of RooSimPdfBuilder: // the user defines a single 'prototype' PDF that defines the structure of all // PDF components of the RooSimultaneous PDF to be built. RooSimPdfBuilder // then takes this prototype and replicates it as a component // PDF for each state of the C index category. //

//

// In the above example RooSimPdfBuilder // will first replicate k and s into // k_C1,k_C2 and s_C1,s_C2, as prescribed in the // configuration. Then it will recursively replicate all PDF nodes that depend on // the 'split' parameter nodes: gauss into gauss_C1,C2, argus // into argus_C1,C2 and finally pdf into pdf_C1,pdf_C2. // When PDFs for all states of C have been replicated // they are assembled into a RooSimultaneous PDF, which is returned by the buildPdf() // method. //

//

// Although in this very simple example the use of RooSimPdfBuilder doesn't // reduce the amount of code much, it is already easier to read and maintain // because there is no duplicate code. As the complexity of the RooSimultaneous // to be built increases, the advantages of RooSimPdfBuilder will become more and // more apparent. //

// // //

Builder configuration rules for a single prototype PDF

//

// Each builder configuration needs at minumum two lines, physModels and splitCats, which identify // the ingredients of the build. In this section we only explain the building rules for // builds from a single prototype PDF. In that case the physModels line always reads //

//
//  physModels = {pdfName}
//  
//

// The second line, splitCats, indicates which categories are going to be used to // differentiate the various subsets of the 'master' input data set. You can enter // a single category here, or multiple if necessary: //

//
// splitCats = {catName} [{catName} ...]
//  
//

// All listed splitcats must be RooCategories that appear in the dataset provided to // RooSimPdfBuilder::buildPdf() //

//

// The parameter splitting prescriptions, the essence of each build configuration // can be supplied in a third line carrying the name of the pdf listed in physModels //

//
// pdfName = {splitCat} : {parameter} [,{parameter},....]
//  
//

// Each pdf can have only one line with splitting rules, but multiple rules can be // supplied in each line, e.g. //

//
// pdfName = {splitCat} : {parameter} [,{parameter},....] 
//           {splitCat} : {parameter} [,{parameter},....]
//  
//

// Conversely, each parameter can only have one splitting prescription, but it may be split // by multiple categories, e.g. //

//
// pdfName = {splitCat1},{splitCat2} : {parameter}
//  
//

// instructs RooSimPdfBuilder to build a RooSuperCategory // of {splitCat1} and {splitCat2} // and split {parameter} with that RooSuperCategory //

//

// Here is an example of a builder configuration that uses several of the options discussed // above: //

//
//   physModels = pdf
//   splitCats  = tagCat runBlock
//   pdf        = tagCat          : signalRes,bkgRes 
//                runBlock        : fudgeFactor      
//                tagCat,runBlock : kludgeParam
//  
// //

How to enter configuration data

// //

// The prototype builder configuration returned by // RooSimPdfBuilder::createProtoBuildConfig() is a pointer to a RooArgSet filled with // initially blank RooStringVars named physModels,splitCats and one additional for each // PDF supplied to the RooSimPdfBuilders constructor (with the same name) //

//

// In macro code, the easiest way to assign new values to these RooStringVars // is to use RooArgSets array operator and the RooStringVars assignment operator, e.g. //

//
// (*config)["physModels"] = "Blah" ;
//  
//

// To enter multiple splitting rules simply separate consecutive rules by whitespace // (not newlines), e.g. //

//
// (*config)["physModels"] = "Blah " // << note trailing space here
//                          "Blah 2" ;
//  
//

// In this example, the C++ compiler will concatenate the two string literals (without inserting // any whitespace), so the extra space after 'Blah' is important here. //

//

// Alternatively, you can read the configuration from an ASCII file, as you can // for any RooArgSet using RooArgSet::readFromFile(). In that case the ASCII file // can follow the syntax of the examples above and the '\\' line continuation // sequence can be used to fold a long splitting rule over multiple lines. //

//
// RooArgSet* config = builder.createProtoBuildConfig() ;
// config->readFromFile("config.txt") ;
//
// --- config.txt ----------------    
// physModels = pdf
// splitCats  = tagCat
// pdf        = tagCat : bogusPar
// -------------------------------
//  
// // //

Working with multiple prototype PDFs

//

// It is also possible to build a RooSimultaneous PDF from multiple PDF prototypes. // This is appropriate for cases where the input prototype PDF would otherwise be // a RooSimultaneous PDF by itself. In such cases we don't feed a single // RooSimultaneous PDF into RooSimPdfBuilder, instead we feed it its ingredients and // add a prescription to the builder configuration that corresponds to the // PDF-category state mapping of the prototype RooSimultaneous. //

//

// The constructor of the RooSimPdfBuilder will look as follows: //

//
//  RooSimPdfBuilder builder(RooArgSet(pdfA,pdfB,...)) ;
//  
//

// The physModels line is now expanded to carry the pdf->state mapping information // that the prototype RooSimultaneous would have. I.e. //

//
// physModels = mode : pdfA=modeA  pdfB=modeB
//  
//

// is equivalent to a prototype RooSimultaneous constructed as //

//
// RooSimultanous simPdf("simPdf","simPdf",mode);
// simPdf.addPdf(pdfA,"modeA") ;
// simPdf.addPdf(pdfB,"modeB") ;
//  
//

// The rest of the builder configuration works the same, except that // each prototype PDF now has its own set of splitting rules, e.g. //

//
// physModels = mode : pdfA=modeA  pdfB=modeB
// splitCats  = tagCat
// pdfA       = tagCat : bogusPar
// pdfB       = tagCat : fudgeFactor   
//  
//

// Please note that //

// // In the following case: //

//
//    physModels = mode : pdfA=modeA  pdfB=modeB  pdfA=modeC  pdfB=modeD
//  
//

// there are still only 2 sets of splitting rules: one for pdfA and one // for pdfB. However, you can differentiate between modeA and modeC in // the above example. The technique is to use mode as splitting category, e.g. //

//
//    physModels = mode : pdfA=modeA  pdfB=modeB  pdfA=modeC  pdfB=modeD
//    splitCats = tagCat
//    pdfA      = tagCat : bogusPar 
//                mode   : funnyPar
//    pdfB      = mode   : kludgeFactor
//  
//

// will result in an individual set of funnyPar parameters for modeA and modeC // labeled funnyPar_modeA and funnyPar_modeB and an individual set of // kludgeFactor parameters for pdfB, kludgeFactor_modeB and kludgeFactor_modeD. // Please note that for splits in the master index category (mode) only the // applicable states are built (A,C for pdfA, B,D for pdfB) //

// // //

Advanced options

// //

Partial splits

//

// You can request to limit the list of states of each splitCat that // will be considered in the build. This limitation is requested in the // each build as follows: //

//
// splitCats = tagCat(Lep,Kao) RunBlock(Run1)
//  
//

// In this example the splitting of tagCat is limited to states Lep,Kao // and the splitting of runBlock is limited to Run1. The splits apply // globally to each build, i.e. every parameter split requested in this // build will be limited according to these specifications. //

//

// NB: Partial builds have no pdf associated with the unbuilt states of the // limited splits. Running such a pdf on a dataset that contains data with // unbuilt states will result in this data being ignored completely. //

// // //

Non-trivial splits

//

// It is possible to make non-trivial parameter splits with RooSimPdfBuilder. // Trivial splits are considered simple splits in one (fundamental) category // in the dataset or a split in a RooSuperCategory 'product' of multiple // fundamental categories in the dataset. Non-trivial splits can be performed // using an intermediate 'category function' (RooMappedCategory, // RooGenericCategory,RooThresholdCategory etc), i.e. any RooAbsCategory // derived objects that calculates its output as function of one or more // input RooRealVars and/or RooCategories. //

//

// Such 'function categories' objects must be constructed by the user prior // to building the PDF. In the RooSimPdfBuilder::buildPdf() function these // objects can be passed in an optional RooArgSet called 'auxiliary categories': //

//
//   const RooSimultaneous* buildPdf(const RooArgSet& buildConfig, const RooAbsData* dataSet, 
//                                   const RooArgSet& auxSplitCats, Bool_t verbose=kFALSE) {
//                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//  
//

// Objects passed in this argset can subsequently be used in the build configuration, e.g. //

//
// RooMappedCategory tagMap("tagMap","Mapped tagging category",tagCat,"CutBased") ;
// tagMap.map("Lep","CutBased") ;
// tagMap.map("Kao","CutBased") ;
// tagMap.map("NT*","NeuralNet") ;                                                                                          
// ...
// builder.buildPdf(config,D,tagMap) ;
//                          ^^^^^^
//
//   physModels = pdf
//   splitCats  = tagCat runBlock
//   pdf        = tagCat          : signalRes 
//                tagMap          : fudgeFactor      
//                ^^^^^^
//  
//

// In the above example signalRes will be split in signalRes_Kao,signalRes_Lep, // signalRes_NT1,signalRes_NT2, while fudgeFactor will be split in fudgeFactor_CutBased // and fudgeFactor_NeuralNet. //

//

// Category functions passed in the auxSplitCats RooArgSet can be used regularly // in the splitting configuration. They should not be listed in splitCats, // but must be able to be expressed completely in terms of the splitCats that // are listed. //

// // //

Multiple connected builds

//

// Sometimes you want to build multiple PDFs for independent consecutive fits // that share some of their parameters. For example, we have two prototype PDFs // pdfA(x;p,q) and pdfB(x;p,r) that have a common parameter p. // We want to build a RooSimultaneous for both pdfA and B, // which involves a split of parameter p and we would like to build the // simultaneous pdfs simA and simB such that still share their (now split) parameters // p_XXX. This is accomplished by letting a single instance of RooSimPdfBuilder handle // the builds of both pdfA and pdfB, as illustrated in this example: //

//
// RooSimPdfBuilder builder(RooArgSet(pdfA,pdfB)) ;
//
// RooArgSet* configA = builder.createProtoBuildConfig() ;
// (*configA)["physModels"] = "pdfA" ;     
// (*configA)["splitCats"]  = "C" ;        
// (*configA)["pdf"]        = "C : p" ;  
// RooSimultaneous* simA = builder.buildPdf(*configA,&D) ;
//
// RooArgSet* configB = builder.createProtoBuildConfig() ;
// (*configA)["physModels"] = "pdfB" ;     
// (*configA)["splitCats"]  = "C" ;        
// (*configA)["pdf"]        = "C : p" ;  
// RooSimultaneous* simB = builder.buildPdf(*configB,&D) ;
//  
// //

Ownership of constructed PDFs

//

// The RooSimPdfBuilder instance owns all the objects it creates, including the top-level // RooSimultaneous returned by buildPdf(). Therefore the builder instance should // exist as long as the constructed PDFs needs to exist. //

// // End_Html // #include "RooFit.h" #include #include #ifndef _WIN32 #include #else static char *strtok_r(char *s1, const char *s2, char **lasts) { char *ret; if (s1 == NULL) s1 = *lasts; while(*s1 && strchr(s2, *s1)) ++s1; if(*s1 == '\0') return NULL; ret = s1; while(*s1 && !strchr(s2, *s1)) ++s1; if(*s1) *s1++ = '\0'; *lasts = s1; return ret; } #endif #include "Riostream.h" #include "RooSimPdfBuilder.h" #include "RooRealVar.h" #include "RooFormulaVar.h" #include "RooAbsCategory.h" #include "RooCategory.h" #include "RooStringVar.h" #include "RooMappedCategory.h" #include "RooRealIntegral.h" #include "RooDataSet.h" #include "RooArgSet.h" #include "RooPlot.h" #include "RooAddPdf.h" #include "RooLinearVar.h" #include "RooTruthModel.h" #include "RooAddModel.h" #include "RooProdPdf.h" #include "RooCustomizer.h" #include "RooThresholdCategory.h" #include "RooMultiCategory.h" #include "RooSuperCategory.h" #include "RooSimultaneous.h" #include "RooTrace.h" #include "RooFitResult.h" #include "RooDataHist.h" #include "RooGenericPdf.h" #include "RooMsgService.h" using namespace std ; ClassImp(RooSimPdfBuilder) ; //////////////////////////////////////////////////////////////////////////////// RooSimPdfBuilder::RooSimPdfBuilder(const RooArgSet& protoPdfSet) : _protoPdfSet(protoPdfSet) { _compSplitCatSet.setHashTableSize(1000) ; _splitNodeList.setHashTableSize(10000) ; _splitNodeListOwned.setHashTableSize(10000) ; } //////////////////////////////////////////////////////////////////////////////// /// Make RooArgSet of configuration objects RooArgSet* RooSimPdfBuilder::createProtoBuildConfig() { RooArgSet* buildConfig = new RooArgSet ; buildConfig->addOwned(* new RooStringVar("physModels","List and mapping of physics models to include in build","",4096)) ; buildConfig->addOwned(* new RooStringVar("splitCats","List of categories used for splitting","",1024)) ; TIterator* iter = _protoPdfSet.createIterator() ; RooAbsPdf* proto ; while ((proto=(RooAbsPdf*)iter->Next())) { buildConfig->addOwned(* new RooStringVar(proto->GetName(),proto->GetName(),"",4096)) ; } delete iter ; return buildConfig ; } //////////////////////////////////////////////////////////////////////////////// void RooSimPdfBuilder::addSpecializations(const RooArgSet& specSet) { _splitNodeList.add(specSet) ; } //////////////////////////////////////////////////////////////////////////////// /// Initialize needed components RooSimultaneous* RooSimPdfBuilder::buildPdf(const RooArgSet& buildConfig, const RooArgSet& dependents, const RooArgSet* auxSplitCats, Bool_t verbose) { const char* spaceChars = " \t" ; // Retrieve physics index category Int_t buflen = strlen(((RooStringVar*)buildConfig.find("physModels"))->getVal())+1 ; char *buf = new char[buflen] ; strlcpy(buf,((RooStringVar*)buildConfig.find("physModels"))->getVal(),buflen) ; RooAbsCategoryLValue* physCat(0) ; if (strstr(buf," : ")) { const char* physCatName = strtok(buf,spaceChars) ; physCat = dynamic_cast(dependents.find(physCatName)) ; if (!physCat) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR physics index category " << physCatName << " not found in dataset variables" << endl ; delete[] buf ; return 0 ; } coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: category indexing physics model: " << physCatName << endl ; } // Create list of physics models to be built char *physName ; RooArgSet physModelSet ; if (physCat) { // Absorb colon token strtok(0,spaceChars) ; physName = strtok(0,spaceChars) ; } else { physName = strtok(buf,spaceChars) ; } if (!physName) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR: No models specified, nothing to do!" << endl ; delete[] buf ; return 0 ; } Bool_t first(kTRUE) ; RooArgSet stateMap ; while(physName) { char *stateName(0) ; // physName may be = or just is state and pdf have identical names if (strchr(physName,'=')) { // Must have a physics category for mapping to make sense if (!physCat) { coutW(ObjectHandling) << "RooSimPdfBuilder::buildPdf: WARNING: without physCat specification " << "= association is meaningless" << endl ; } stateName = physName ; physName = strchr(stateName,'=') ; if (physName) { *(physName++) = 0 ; } } else { stateName = physName ; } RooAbsPdf* physModel = (RooAbsPdf*) (physName ? _protoPdfSet.find(physName) : 0 ); if (!physModel) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR requested physics model " << (physName?physName:"(null)") << " is not defined" << endl ; delete[] buf ; return 0 ; } // Check if state mapping has already been defined if (stateMap.find(stateName)) { coutW(InputArguments) << "RooSimPdfBuilder::buildPdf: WARNING: multiple PDFs specified for state " << stateName << ", only first will be used" << endl ; continue ; } // Add pdf to list of models to be processed physModelSet.add(*physModel,kTRUE) ; // silence duplicate insertion warnings // Store state->pdf mapping stateMap.addOwned(* new RooStringVar(stateName,stateName,physName)) ; // Continue with next mapping physName = strtok(0,spaceChars) ; if (first) { first = kFALSE ; } else if (physCat==0) { coutW(InputArguments) << "RooSimPdfBuilder::buildPdf: WARNING: without physCat specification, only the first model will be used" << endl ; break ; } } coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: list of physics models " << physModelSet << endl ; // Create list of dataset categories to be used in splitting TList splitStateList ; RooArgSet splitCatSet ; delete[] buf ; buflen = strlen(((RooStringVar*)buildConfig.find("splitCats"))->getVal())+1 ; buf = new char[buflen] ; strlcpy(buf,((RooStringVar*)buildConfig.find("splitCats"))->getVal(),buflen) ; char *catName = strtok(buf,spaceChars) ; char *stateList(0) ; while(catName) { // Chop off optional list of selected states char* tokenPtr(0) ; if (strchr(catName,'(')) { catName = strtok_r(catName,"(",&tokenPtr) ; stateList = strtok_r(0,")",&tokenPtr) ; } else { stateList = 0 ; } RooCategory* splitCat = catName ? dynamic_cast(dependents.find(catName)) : 0 ; if (!splitCat) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR requested split category " << (catName?catName:"(null)") << " is not a RooCategory in the dataset" << endl ; delete[] buf ; return 0 ; } splitCatSet.add(*splitCat) ; // Process optional state list if (stateList) { coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: splitting of category " << catName << " restricted to states (" << stateList << ")" << endl ; // Create list named after this splitCat holding its selected states TList* slist = new TList ; slist->SetName(catName) ; splitStateList.Add(slist) ; char* stateLabel = strtok_r(stateList,",",&tokenPtr) ; while(stateLabel) { // Lookup state label and require it exists const RooCatType* type = splitCat->lookupType(stateLabel) ; if (!type) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR splitCat " << splitCat->GetName() << " doesn't have a state named " << stateLabel << endl ; splitStateList.Delete() ; delete[] buf ; return 0 ; } slist->Add((TObject*)type) ; stateLabel = strtok_r(0,",",&tokenPtr) ; } } catName = strtok(0,spaceChars) ; } if (physCat) splitCatSet.add(*physCat) ; RooSuperCategory masterSplitCat("masterSplitCat","Master splitting category",splitCatSet) ; coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: list of splitting categories " << splitCatSet << endl ; // Clone auxiliary split cats and attach to splitCatSet RooArgSet auxSplitSet ; RooArgSet* auxSplitCloneSet(0) ; if (auxSplitCats) { // Deep clone auxililary split cats auxSplitCloneSet = (RooArgSet*) auxSplitCats->snapshot(kTRUE) ; if (!auxSplitCloneSet) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf(" << GetName() << ") Couldn't deep-clone set auxiliary splitcats, abort." << endl ; delete[] buf ; return 0 ; } TIterator* iter = auxSplitCats->createIterator() ; RooAbsArg* arg ; while((arg=(RooAbsArg*)iter->Next())) { // Find counterpart in cloned set RooAbsArg* aux = auxSplitCats->find(arg->GetName()) ; // Check that there is no fundamental splitCat in the dataset with the bane of the auxiliary split if (splitCatSet.find(aux->GetName())) { coutW(InputArguments) << "RooSimPdfBuilder::buildPdf: WARNING: dataset contains a fundamental splitting category " << endl << " with the same name as an auxiliary split function (" << aux->GetName() << "). " << endl << " Auxiliary split function will be ignored" << endl ; continue ; } // Check that all servers of this aux cat are contained in splitCatSet RooArgSet* parSet = aux->getParameters(splitCatSet) ; if (parSet->getSize()>0) { coutW(InputArguments) << "RooSimPdfBuilder::buildPdf: WARNING: ignoring auxiliary category " << aux->GetName() << " because it has servers that are not listed in splitCatSet: " << *parSet << endl ; delete parSet ; continue ; } // Redirect servers to splitCatSet aux->recursiveRedirectServers(splitCatSet) ; // Add top level nodes to auxSplitSet auxSplitSet.add(*aux) ; } delete iter ; coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: list of auxiliary splitting categories " << auxSplitSet << endl ; } TList* customizerList = new TList ; // Loop over requested physics models and build components TIterator* physIter = physModelSet.createIterator() ; RooAbsPdf* physModel ; while((physModel=(RooAbsPdf*)physIter->Next())) { coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: processing physics model " << physModel->GetName() << endl ; RooCustomizer* physCustomizer = new RooCustomizer(*physModel,masterSplitCat,_splitNodeList) ; customizerList->Add(physCustomizer) ; // Parse the splitting rules for this physics model RooStringVar* ruleStr = (RooStringVar*) buildConfig.find(physModel->GetName()) ; if (ruleStr) { delete[] buf ; buflen = strlen(ruleStr->getVal())+1 ; buf = new char[buflen] ; strlcpy(buf,ruleStr->getVal(),buflen) ; char *tokenPtr(0) ; char* token = strtok_r(buf,spaceChars,&tokenPtr) ; enum Mode { SplitCat, Colon, ParamList } ; Mode mode(SplitCat) ; char* splitCatName ; RooAbsCategory* splitCat(0) ; while(token) { switch (mode) { case SplitCat: { splitCatName = token ; if (strchr(splitCatName,',')) { // Composite splitting category // Check if already instantiated splitCat = (RooAbsCategory*) _compSplitCatSet.find(splitCatName) ; TString origCompCatName(splitCatName) ; if (!splitCat) { // Build now char *tokptr = 0; char *catName2 = strtok_r(token,",",&tokptr) ; RooArgSet compCatSet ; while(catName2) { RooAbsArg* cat = splitCatSet.find(catName2) ; // If not, check if it is an auxiliary splitcat if (!cat) { cat = (RooAbsCategory*) auxSplitSet.find(catName2) ; } if (!cat) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR " << catName2 << " not found in the primary or auxilary splitcat list" << endl ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } compCatSet.add(*cat) ; catName2 = strtok_r(0,",",&tokptr) ; } // check that any auxSplitCats in compCatSet do not depend on any other // fundamental or auxiliary splitting categories in the composite set. TIterator* iter = compCatSet.createIterator() ; RooAbsArg* arg ; while((arg=(RooAbsArg*)iter->Next())) { RooArgSet tmp(compCatSet) ; tmp.remove(*arg) ; if (arg->dependsOnValue(tmp)) { coutE(InputArguments) << "RooSimPdfBuilder::buildPDF: ERROR: Ill defined split: auxiliary splitting category " << arg->GetName() << " used in composite split " << compCatSet << " depends on one or more of the other splitting categories in the composite split" << endl ; // Cleanup and axit customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } } delete iter ; splitCat = new RooMultiCategory(origCompCatName,origCompCatName,compCatSet) ; _compSplitCatSet.addOwned(*splitCat) ; //cout << "composite splitcat: " << splitCat->GetName() ; } } else { // Simple splitting category // First see if it is a simple splitting category splitCat = (RooAbsCategory*) splitCatSet.find(splitCatName) ; // If not, check if it is an auxiliary splitcat if (!splitCat) { splitCat = (RooAbsCategory*) auxSplitSet.find(splitCatName) ; } if (!splitCat) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR splitting category " << splitCatName << " not found in the primary or auxiliary splitcat list" << endl ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } } mode = Colon ; break ; } case Colon: { if (strcmp(token,":")) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR in parsing, expected ':' after " << splitCat << ", found " << token << endl ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } mode = ParamList ; break ; } case ParamList: { // Verify the validity of the parameter list and build the corresponding argset RooArgSet splitParamList ; RooArgSet* paramList = physModel->getParameters(dependents) ; // wve -- add nodes to parameter list RooArgSet* compList = physModel->getComponents() ; paramList->add(*compList) ; delete compList ; Bool_t lastCharIsComma = (token[strlen(token)-1]==',') ; char *tokptr = 0 ; char *paramName = strtok_r(token,",",&tokptr) ; // Check for fractional split option 'param_name[remainder_state]' char *remainderState = 0 ; char *tokptr2 = 0 ; if (paramName && strtok_r(paramName,"[",&tokptr2)) { remainderState = strtok_r(0,"]",&tokptr2) ; } while(paramName) { // If fractional split is specified, check that remainder state is a valid state of this split cat if (remainderState) { if (!splitCat->lookupType(remainderState)) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR fraction split of parameter " << paramName << " has invalid remainder state name: " << remainderState << endl ; delete paramList ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } } RooAbsArg* param = paramList->find(paramName) ; if (!param) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR " << paramName << " is not a parameter of physics model " << physModel->GetName() << endl ; delete paramList ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } splitParamList.add(*param) ; // Build split leaf of fraction splits here if (remainderState) { // Check if we are splitting a real-valued parameter if (!dynamic_cast(param)) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR fraction split requested of non-real valued parameter " << param->GetName() << endl ; delete paramList ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } // Check if we are doing a restricted build TList* remStateSplitList = static_cast(splitStateList.FindObject(splitCat->GetName())) ; // If so, check if remainder state is actually being built. if (remStateSplitList && !remStateSplitList->FindObject(remainderState)) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR " << paramName << " remainder state " << remainderState << " in parameter split " << param->GetName() << " is not actually being built" << endl ; delete paramList ; customizerList->Delete() ; delete customizerList ; splitStateList.Delete() ; delete[] buf ; return 0 ; } TIterator* iter = splitCat->typeIterator() ; RooCatType* type ; RooArgList fracLeafList ; TString formExpr("1") ; Int_t i(0) ; while((type=(RooCatType*)iter->Next())) { // Skip remainder state if (!TString(type->GetName()).CompareTo(remainderState)) continue ; // If restricted build is requested, skip states of splitcat that are not built if (remStateSplitList && !remStateSplitList->FindObject(type->GetName())) { continue ; } // Construct name of split leaf TString splitLeafName(param->GetName()) ; splitLeafName.Append("_") ; splitLeafName.Append(type->GetName()) ; // Check if split leaf already exists RooAbsArg* splitLeaf = _splitNodeList.find(splitLeafName) ; if (!splitLeaf) { // If not create it now splitLeaf = (RooAbsArg*) param->clone(splitLeafName) ; _splitNodeList.add(*splitLeaf) ; _splitNodeListOwned.addOwned(*splitLeaf) ; } fracLeafList.add(*splitLeaf) ; formExpr.Append(Form("-@%d",i++)) ; } delete iter ; // Construct RooFormulaVar expresssing remainder of fraction TString remLeafName(param->GetName()) ; remLeafName.Append("_") ; remLeafName.Append(remainderState) ; // Check if no specialization was already specified for remainder state if (!_splitNodeList.find(remLeafName)) { RooAbsArg* remLeaf = new RooFormulaVar(remLeafName,formExpr,fracLeafList) ; _splitNodeList.add(*remLeaf) ; _splitNodeListOwned.addOwned(*remLeaf) ; coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: creating remainder fraction formula for " << remainderState << " specialization of split parameter " << param->GetName() << " " << formExpr << endl ; } } // Parse next parameter name paramName = strtok_r(0,",",&tokptr) ; if (paramName && strtok_r(paramName,"[",&tokptr2)) { remainderState = strtok_r(0,"]",&tokptr2) ; } } // Add the rule to the appropriate customizer ; physCustomizer->splitArgs(splitParamList,*splitCat) ; delete paramList ; if (!lastCharIsComma) mode = SplitCat ; break ; } } token = strtok_r(0,spaceChars,&tokenPtr) ; } if (mode!=SplitCat) { coutE(InputArguments) << "RooSimPdfBuilder::buildPdf: ERROR in parsing, expected " << (mode==Colon?":":"parameter list") << " after " << (token?token:"(null)") << endl ; } //RooArgSet* paramSet = physModel->getParameters(dependents) ; } else { coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: no splitting rules for " << physModel->GetName() << endl ; } } coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: configured customizers for all physics models" << endl ; if (oodologI((TObject*)0,ObjectHandling)) { customizerList->Print() ; } // Create fit category from physCat and splitCatList ; RooArgSet fitCatList ; if (physCat) fitCatList.add(*physCat) ; fitCatList.add(splitCatSet) ; TIterator* fclIter = fitCatList.createIterator() ; RooSuperCategory *fitCat = new RooSuperCategory("fitCat","fitCat",fitCatList) ; // Create master PDF RooSimultaneous* simPdf = new RooSimultaneous("simPdf","simPdf",*fitCat) ; // Add component PDFs to master PDF TIterator* fcIter = fitCat->typeIterator() ; RooCatType* fcState ; while((fcState=(RooCatType*)fcIter->Next())) { // Select fitCat state fitCat->setLabel(fcState->GetName()) ; // Check if this fitCat state is selected fclIter->Reset() ; RooAbsCategory* splitCat ; Bool_t select(kTRUE) ; while((splitCat=(RooAbsCategory*)fclIter->Next())) { // Find selected state list TList* slist = (TList*) splitStateList.FindObject(splitCat->GetName()) ; if (!slist) continue ; RooCatType* type = (RooCatType*) slist->FindObject(splitCat->getLabel()) ; if (!type) { select = kFALSE ; } } if (!select) continue ; // Select appropriate PDF for this physCat state RooCustomizer* physCustomizer ; if (physCat) { RooStringVar* physNameVar = (RooStringVar*) stateMap.find(physCat->getLabel()) ; if (!physNameVar) continue ; physCustomizer = (RooCustomizer*) customizerList->FindObject(physNameVar->getVal()); } else { physCustomizer = (RooCustomizer*) customizerList->First() ; } coutI(ObjectHandling) << "RooSimPdfBuilder::buildPdf: Customizing physics model " << physCustomizer->GetName() << " for mode " << fcState->GetName() << endl ; // Customizer PDF for current state and add to master simPdf RooAbsPdf* fcPdf = (RooAbsPdf*) physCustomizer->build(masterSplitCat.getLabel(),verbose) ; simPdf->addPdf(*fcPdf,fcState->GetName()) ; } delete fcIter ; // Move customizers (owning the cloned branch node components) to the attic _retiredCustomizerList.AddAll(customizerList) ; delete customizerList ; delete fclIter ; splitStateList.Delete() ; if (auxSplitCloneSet) delete auxSplitCloneSet ; delete physIter ; delete[] buf ; _simPdfList.push_back(simPdf) ; _fitCatList.push_back(fitCat) ; return simPdf ; } //////////////////////////////////////////////////////////////////////////////// RooSimPdfBuilder::~RooSimPdfBuilder() { _retiredCustomizerList.Delete() ; std::list::iterator iter = _simPdfList.begin() ; while(iter != _simPdfList.end()) { delete *iter ; ++iter ; } std::list::iterator iter2 = _fitCatList.begin() ; while(iter2 != _fitCatList.end()) { delete *iter2 ; ++iter2 ; } }