CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_8_patch3/src/HiggsAnalysis/CombinedLimit/src/Combine.cc

Go to the documentation of this file.
00001 /**************************************
00002   Simple multiChannel significance & limit calculator
00003 ***************************************/
00004 #include "../interface/Combine.h"
00005 #include <cstring>
00006 #include <cerrno>
00007 #include <iostream>
00008 #include <cstdlib>
00009 #include <cmath>
00010 #include <vector>
00011 #include <string>
00012 #include <stdexcept>
00013 #include <algorithm>
00014 #include <unistd.h>
00015 #include <errno.h>
00016 
00017 #include <TCanvas.h>
00018 #include <TFile.h>
00019 #include <TGraphErrors.h>
00020 #include <TIterator.h>
00021 #include <TLine.h>
00022 #include <TMath.h>
00023 #include <TString.h>
00024 #include <TSystem.h>
00025 #include <TStopwatch.h>
00026 #include <TTree.h>
00027 
00028 #include <RooAbsData.h>
00029 #include <RooAbsPdf.h>
00030 #include <RooArgSet.h>
00031 #include <RooCustomizer.h>
00032 #include <RooDataHist.h>
00033 #include <RooDataSet.h>
00034 #include <RooFitResult.h>
00035 #include <RooMsgService.h>
00036 #include <RooPlot.h>
00037 #include <RooRandom.h>
00038 #include <RooRealVar.h>
00039 #include <RooUniform.h>
00040 #include <RooWorkspace.h>
00041 
00042 #include <RooStats/HLFactory.h>
00043 #include <RooStats/RooStatsUtils.h>
00044 #include <RooStats/ModelConfig.h>
00045 
00046 #include <boost/filesystem.hpp>
00047 #include <boost/program_options.hpp>
00048 
00049 
00050 #include "../interface/LimitAlgo.h"
00051 #include "../interface/utils.h"
00052 #include "../interface/CloseCoutSentry.h"
00053 #include "../interface/RooSimultaneousOpt.h"
00054 #include "../interface/ToyMCSamplerOpt.h"
00055 #include "../interface/AsimovUtils.h"
00056 
00057 using namespace RooStats;
00058 using namespace RooFit;
00059 
00060 LimitAlgo * algo, * hintAlgo;
00061 
00062 Float_t t_cpu_, t_real_;
00063 Float_t g_quantileExpected_ = -1.0;
00064 TDirectory *outputFile = 0;
00065 TDirectory *writeToysHere = 0;
00066 TDirectory *readToysFromHere = 0;
00067 int  verbose = 1;
00068 bool withSystematics = 1;
00069 bool doSignificance_ = 0;
00070 bool lowerLimit_ = 0;
00071 float cl = 0.95;
00072 TTree *Combine::tree_ = 0;
00073 
00074 
00075 Combine::Combine() :
00076     statOptions_("Common statistics options"),
00077     ioOptions_("Common input-output options"),
00078     miscOptions_("Common miscellaneous options"),
00079     rMin_(std::numeric_limits<float>::quiet_NaN()), 
00080     rMax_(std::numeric_limits<float>::quiet_NaN()) {
00081     namespace po = boost::program_options;
00082     statOptions_.add_options() 
00083       ("systematics,S", po::value<bool>(&withSystematics)->default_value(true), "Add systematic uncertainties")
00084       ("cl,C",   po::value<float>(&cl)->default_value(0.95), "Confidence Level")
00085       ("rMin",   po::value<float>(&rMin_), "Override minimum value for signal strength")
00086       ("rMax",   po::value<float>(&rMax_), "Override maximum value for signal strength")
00087       ("prior",  po::value<std::string>(&prior_)->default_value("flat"), "Prior to use, for methods that require it and if it's not already in the input file: 'flat' (default), '1/sqrt(r)'")
00088       ("significance", "Compute significance instead of upper limit (works only for some methods)")
00089       ("lowerLimit",   "Compute the lower limit instead of the upper limit (works only for some methods)")
00090       ("hintStatOnly", "Ignore systematics when computing the hint")
00091       ("toysNoSystematics", "Generate all toys with the central value of the nuisance parameters, without fluctuating them")
00092       ("toysFrequentist",   "Generate all toys in the frequentist way. Note that this affects the toys generated by option '-t' that happen in the main loop, not the ones within the Hybrid(New) algorithm.")
00093       ("expectSignal", po::value<float>(&expectSignal_)->default_value(0.), "If set to non-zero, generate *signal* toys instead of background ones, with the specified signal strength.")
00094       ("unbinned,U", "Generate unbinned datasets instead of binned ones (works only for extended pdfs)")
00095       ("generateBinnedWorkaround", "Make binned datasets generating unbinned ones and then binnning them. Workaround for a bug in RooFit.")
00096       ;
00097     ioOptions_.add_options()
00098       ("saveWorkspace", "Save workspace to output root file")
00099       ("workspaceName,w", po::value<std::string>(&workspaceName_)->default_value("w"), "Workspace name, when reading it from or writing it to a rootfile.")
00100       ("modelConfigName",  po::value<std::string>(&modelConfigName_)->default_value("ModelConfig"), "ModelConfig name, when reading it from or writing it to a rootfile.")
00101       ("modelConfigNameB", po::value<std::string>(&modelConfigNameB_)->default_value("%s_bonly"), "Name of the ModelConfig for b-only hypothesis.\n"
00102                                                                                                   "If not present, it will be made from the singal model taking zero signal strength.\n"
00103                                                                                                   "A '%s' in the name will be replaced with the modelConfigName.")
00104       ("validateModel,V", "Perform some sanity checks on the model and abort if they fail.")
00105       ("saveToys",   "Save results of toy MC in output file")
00106       ;
00107     miscOptions_.add_options()
00108       ("newGenerator", po::value<bool>(&newGen_)->default_value(true), "Use new generator code for toys, fixes all issues with binned and mixed generation (equivalent of --newToyMC but affects the top-level toys from option '-t' instead of the ones within the HybridNew)")
00109       ("optimizeSimPdf", po::value<bool>(&optSimPdf_)->default_value(true), "Turn on special optimizations of RooSimultaneous. On by default, you can turn it off if it doesn't work for your workspace.")
00110       ("rebuildSimPdf", po::value<bool>(&rebuildSimPdf_)->default_value(false), "Rebuild simultaneous pdf from scratch to make sure constraints are correct (not needed in CMS workspaces)")
00111       ("compile", "Compile expressions instead of interpreting them")
00112       ("tempDir", po::value<bool>(&makeTempDir_)->default_value(false), "Run the program from a temporary directory (automatically on for text datacards or if 'compile' is activated)")
00113       ("guessGenMode", "Guess if to generate binned or unbinned based on dataset");
00114       ; 
00115 }
00116 
00117 void Combine::applyOptions(const boost::program_options::variables_map &vm) {
00118   if(withSystematics) {
00119     std::cout << ">>> including systematics" << std::endl;
00120   } else {
00121     std::cout << ">>> no systematics included" << std::endl;
00122   } 
00123   unbinned_ = vm.count("unbinned");
00124   generateBinnedWorkaround_ = vm.count("generateBinnedWorkaround");
00125   if (unbinned_ && generateBinnedWorkaround_) throw std::logic_error("You can't set generateBinnedWorkaround and unbinned options at the same time");
00126   guessGenMode_ = vm.count("guessGenMode");
00127   compiledExpr_ = vm.count("compile"); if (compiledExpr_) makeTempDir_ = true;
00128   doSignificance_ = vm.count("significance");
00129   lowerLimit_     = vm.count("lowerLimit");
00130   hintUsesStatOnly_ = vm.count("hintStatOnly");
00131   saveWorkspace_ = vm.count("saveWorkspace");
00132   toysNoSystematics_ = vm.count("toysNoSystematics");
00133   toysFrequentist_ = vm.count("toysFrequentist");
00134   if (toysNoSystematics_ && toysFrequentist_) throw std::logic_error("You can't set toysNoSystematics and toysFrequentist options at the same time");
00135   if (modelConfigNameB_.find("%s") != std::string::npos) {
00136       char modelBName[1024]; 
00137       sprintf(modelBName, modelConfigNameB_.c_str(), modelConfigName_.c_str());
00138       modelConfigNameB_ = modelBName;
00139   }
00140   mass_ = vm["mass"].as<float>();
00141   saveToys_ = vm.count("saveToys");
00142   validateModel_ = vm.count("validateModel");
00143 }
00144 
00145 bool Combine::mklimit(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr) {
00146   TStopwatch timer;
00147   bool ret = false;
00148   try {
00149     double hint = 0, hintErr = 0; bool hashint = false;
00150     if (hintAlgo) {
00151         if (hintUsesStatOnly_ && withSystematics) {
00152             withSystematics = false;
00153             hashint = hintAlgo->run(w, mc_s, mc_b, data, hint, hintErr, 0);
00154             withSystematics = true;
00155         } else {
00156             hashint = hintAlgo->run(w, mc_s, mc_b, data, hint, hintErr, 0);
00157         } 
00158     }
00159     limitErr = 0; // start with 0, as some algorithms don't compute it
00160     ret = algo->run(w, mc_s, mc_b, data, limit, limitErr, (hashint ? &hint : 0));    
00161   } catch (std::exception &ex) {
00162     std::cerr << "Caught exception " << ex.what() << std::endl;
00163     return false;
00164   }
00165   /* if ((ret == false) && (verbose > 3)) {
00166     std::cout << "Failed for method " << algo->name() << "\n";
00167     std::cout << "  --- DATA ---\n";
00168     utils::printRAD(&data);
00169     std::cout << "  --- MODEL ---\n";
00170     w->Print("V");
00171   } */
00172   timer.Stop(); t_cpu_ = timer.CpuTime()/60.; t_real_ = timer.RealTime()/60.;
00173   printf("Done in %.2f min (cpu), %.2f min (real)\n", t_cpu_, t_real_);
00174   return ret;
00175 }
00176 
00177 namespace { 
00178     struct ToCleanUp {
00179         TFile *tfile; std::string file, path;
00180         ToCleanUp() : tfile(0), file(""), path("") {}
00181         ~ToCleanUp() {
00182             if (tfile) { tfile->Close(); delete tfile; }
00183             if (!file.empty()) {  
00184                 if (unlink(file.c_str()) == -1) std::cerr << "Failed to delete temporary file " << file << ": " << strerror(errno) << std::endl;
00185             }
00186             if (!path.empty()) {  boost::filesystem::remove_all(path); }
00187         }
00188     };
00189 }
00190 void Combine::run(TString hlfFile, const std::string &dataset, double &limit, double &limitErr, int &iToy, TTree *tree, int nToys) {
00191   ToCleanUp garbageCollect; // use this to close and delete temporary files
00192 
00193   TString tmpDir = "", tmpFile = "", pwd(gSystem->pwd());
00194   if (makeTempDir_) { 
00195       tmpDir = "roostats-XXXXXX"; tmpFile = "model";
00196       mkdtemp(const_cast<char *>(tmpDir.Data()));
00197       gSystem->cd(tmpDir.Data());
00198       garbageCollect.path = tmpDir.Data(); // request that we delete this dir when done
00199   } else if (!hlfFile.EndsWith(".hlf") && !hlfFile.EndsWith(".root")) {
00200       tmpFile = "roostats-XXXXXX";
00201       mktemp(const_cast<char *>(tmpFile.Data())); // somewhat unsafe, but I want to get a proper extension in the output file
00202   }
00203 
00204   bool isTextDatacard = false, isBinary = false;
00205   TString fileToLoad = (hlfFile[0] == '/' ? hlfFile : pwd+"/"+hlfFile);
00206   if (!boost::filesystem::exists(fileToLoad.Data())) throw std::invalid_argument(("File "+fileToLoad+" does not exist").Data());
00207   if (hlfFile.EndsWith(".hlf") ) {
00208     // nothing to do
00209   } else if (hlfFile.EndsWith(".root")) {
00210     isBinary = true;
00211   } else {
00212     TString txtFile = fileToLoad.Data();
00213     TString options = TString::Format(" -m %f -D %s", mass_, dataset.c_str());
00214     if (!withSystematics) options += " --stat ";
00215     if (compiledExpr_)    options += " --compiled ";
00216     if (verbose > 1)      options += TString::Format(" --verbose %d", verbose-1);
00217     //-- Text mode: old default
00218     //int status = gSystem->Exec("text2workspace.py "+options+" '"+txtFile+"' -o "+tmpFile+".hlf"); 
00219     //isTextDatacard = true; fileToLoad = tmpFile+".hlf";
00220     //-- Binary mode: new default 
00221     int status = gSystem->Exec("text2workspace.py "+options+" '"+txtFile+"' -b -o "+tmpFile+".root"); 
00222     isBinary = true; fileToLoad = tmpFile+".root";
00223     if (status != 0 || !boost::filesystem::exists(fileToLoad.Data())) {
00224         throw std::invalid_argument("Failed to convert the input datacard from LandS to RooStats format. The lines above probably contain more information about the error.");
00225     }
00226     garbageCollect.file = fileToLoad;
00227   }
00228 
00229   if (getenv("CMSSW_BASE")) {
00230       gSystem->AddIncludePath(TString::Format(" -I%s/src ", getenv("CMSSW_BASE")));
00231       if (verbose > 3) std::cout << "Adding " << getenv("CMSSW_BASE") << "/src to include path" << std::endl;
00232   }
00233   if (getenv("ROOFITSYS")) {
00234       gSystem->AddIncludePath(TString::Format(" -I%s/include ", getenv("ROOFITSYS")));
00235       if (verbose > 3) std::cout << "Adding " << getenv("ROOFITSYS") << "/include to include path" << std::endl;
00236   }
00237 
00238   if (verbose <= 2) RooMsgService::instance().setGlobalKillBelow(RooFit::ERROR);
00239   // Load the model, but going in a temporary directory to avoid polluting the current one with garbage from 'cexpr'
00240   RooWorkspace *w = 0; RooStats::ModelConfig *mc = 0, *mc_bonly = 0;
00241   std::auto_ptr<RooStats::HLFactory> hlf(0);
00242   if (isBinary) {
00243     TFile *fIn = TFile::Open(fileToLoad); 
00244     garbageCollect.tfile = fIn; // request that we close this file when done
00245 
00246     w = dynamic_cast<RooWorkspace *>(fIn->Get(workspaceName_.c_str()));
00247     if (w == 0) {  
00248         std::cerr << "Could not find workspace '" << workspaceName_ << "' in file " << fileToLoad << std::endl; fIn->ls(); 
00249         throw std::invalid_argument("Missing Workspace"); 
00250     }
00251     if (verbose > 3) { std::cout << "Input workspace '" << workspaceName_ << "': \n"; w->Print("V"); }
00252     RooRealVar *MH = w->var("MH");
00253     if (MH!=0) {
00254       if (verbose > 2) std::cerr << "Setting variable 'MH' in workspace to the higgs mass " << mass_ << std::endl;
00255       MH->setVal(mass_);
00256     }
00257     mc       = dynamic_cast<RooStats::ModelConfig *>(w->genobj(modelConfigName_.c_str()));
00258     mc_bonly = dynamic_cast<RooStats::ModelConfig *>(w->genobj(modelConfigNameB_.c_str()));
00259     if (mc == 0) {  
00260         std::cerr << "Could not find ModelConfig '" << modelConfigName_ << "' in workspace '" << workspaceName_ << "' in file " << fileToLoad << std::endl;
00261         throw std::invalid_argument("Missing ModelConfig"); 
00262     } else if (verbose > 3) { std::cout << "Workspace has a ModelConfig for signal called '" << modelConfigName_ << "', with contents:\n"; mc->Print("V"); }
00263     if (verbose > 3) { std::cout << "Input ModelConfig '" << modelConfigName_ << "': \n"; mc->Print("V"); }
00264     const RooArgSet *POI = mc->GetParametersOfInterest();
00265     if (POI == 0 || POI->getSize() == 0) throw std::invalid_argument("ModelConfig '"+modelConfigName_+"' does not define parameters of interest.");
00266     if (POI->getSize() > 1) std::cerr << "ModelConfig '" << modelConfigName_ << "' defines more than one parameter of interest. This is not supported in some statistical methods." << std::endl;
00267     if (mc->GetObservables() == 0) throw std::invalid_argument("ModelConfig '"+modelConfigName_+"' does not define observables.");
00268     if (mc->GetPdf() == 0) throw std::invalid_argument("ModelConfig '"+modelConfigName_+"' does not define a pdf.");
00269     if (rebuildSimPdf_ && typeid(*mc->GetPdf()) == typeid(RooSimultaneous)) {
00270         RooSimultaneous *newpdf = utils::rebuildSimPdf(*mc->GetObservables(), dynamic_cast<RooSimultaneous*>(mc->GetPdf()));
00271         w->import(*newpdf);
00272         mc->SetPdf(*newpdf);
00273     }
00274     if (optSimPdf_ && typeid(*mc->GetPdf()) == typeid(RooSimultaneous)) {
00275         RooSimultaneousOpt *optpdf = new RooSimultaneousOpt(static_cast<RooSimultaneous&>(*mc->GetPdf()), TString(mc->GetPdf()->GetName())+"_opt");
00276         w->import(*optpdf);
00277         mc->SetPdf(*optpdf);
00278     }
00279     if (mc_bonly == 0) {
00280         std::cerr << "Missing background ModelConfig '" << modelConfigNameB_ << "' in workspace '" << workspaceName_ << "' in file " << fileToLoad << std::endl;
00281         std::cerr << "Will make one from the signal ModelConfig '" << modelConfigName_ << "' setting signal strenth '" << POI->first()->GetName() << "' to zero"  << std::endl;
00282         w->factory("_zero_[0]");
00283         RooCustomizer make_model_s(*mc->GetPdf(),"_model_bonly_");
00284         make_model_s.replaceArg(*POI->first(), *w->var("_zero_"));
00285         RooAbsPdf *model_b = dynamic_cast<RooAbsPdf *>(make_model_s.build()); 
00286         model_b->SetName("_model_bonly_");
00287         w->import(*model_b);
00288         mc_bonly = new RooStats::ModelConfig(*mc);
00289         mc_bonly->SetPdf(*model_b);
00290     }
00291   } else {
00292     hlf.reset(new RooStats::HLFactory("factory", fileToLoad));
00293     w = hlf->GetWs();
00294     if (w == 0) {
00295         std::cerr << "Could not read HLF from file " <<  (hlfFile[0] == '/' ? hlfFile : pwd+"/"+hlfFile) << std::endl;
00296         return;
00297     }
00298     RooRealVar *MH = w->var("MH");
00299     if (MH==0) {
00300       std::cerr << "Could not find MH var in workspace '" << workspaceName_ << "' in file " << fileToLoad << std::endl;
00301       throw std::invalid_argument("Missing MH"); 
00302     }
00303     MH->setVal(mass_);
00304     if (w->set("observables") == 0) throw std::invalid_argument("The model must define a RooArgSet 'observables'");
00305     if (w->set("POI")         == 0) throw std::invalid_argument("The model must define a RooArgSet 'POI' for the parameters of interest");
00306     if (w->pdf("model_b")     == 0) throw std::invalid_argument("The model must define a RooAbsPdf 'model_b'");
00307     if (w->pdf("model_s")     == 0) throw std::invalid_argument("The model must define a RooAbsPdf 'model_s'");
00308 
00309     // create ModelConfig
00310     mc = new RooStats::ModelConfig(modelConfigName_.c_str(),"signal",w);
00311     mc->SetPdf(*w->pdf("model_s"));
00312     mc->SetObservables(*w->set("observables"));
00313     mc->SetParametersOfInterest(*w->set("POI"));
00314     if (w->set("nuisances"))         mc->SetNuisanceParameters(*w->set("nuisances"));
00315     if (w->set("globalObservables")) mc->SetGlobalObservables(*w->set("globalObservables"));
00316     if (w->pdf("prior")) mc->SetNuisanceParameters(*w->pdf("prior"));
00317     w->import(*mc, modelConfigName_.c_str());
00318 
00319     mc_bonly = new RooStats::ModelConfig(modelConfigNameB_.c_str(),"background",w);
00320     mc_bonly->SetPdf(*w->pdf("model_b"));
00321     mc_bonly->SetObservables(*w->set("observables"));
00322     mc_bonly->SetParametersOfInterest(*w->set("POI"));
00323     if (w->set("nuisances"))         mc_bonly->SetNuisanceParameters(*w->set("nuisances"));
00324     if (w->set("globalObservables")) mc_bonly->SetGlobalObservables(*w->set("globalObservables"));
00325     if (w->pdf("prior")) mc_bonly->SetNuisanceParameters(*w->pdf("prior"));
00326     w->import(*mc_bonly, modelConfigNameB_.c_str());
00327   }
00328   gSystem->cd(pwd);
00329 
00330   if (verbose <= 2) RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
00331 
00332   const RooArgSet * observables = mc->GetObservables();     // not null
00333   const RooArgSet * POI = mc->GetParametersOfInterest();     // not null
00334   const RooArgSet * nuisances = mc->GetNuisanceParameters(); // note: may be null
00335   if (dynamic_cast<RooRealVar*>(POI->first()) == 0) throw std::invalid_argument("First parameter of interest is not a RooRealVar");
00336 
00337   if (w->data(dataset.c_str()) == 0) {
00338     if (isTextDatacard) { // that's ok: the observables are pre-set to the observed values
00339       RooDataSet *data_obs = new RooDataSet(dataset.c_str(), dataset.c_str(), *observables); 
00340       data_obs->add(*observables);
00341       w->import(*data_obs);
00342     } else {
00343       std::cout << "Dataset " << dataset.c_str() << " not found." << std::endl;
00344     }
00345   }
00346 
00347   if (verbose < -1) {
00348       RooMsgService::instance().setStreamStatus(0,kFALSE);
00349       RooMsgService::instance().setStreamStatus(1,kFALSE);
00350       RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
00351   }
00352 
00353 
00354   if (!isnan(rMin_)) ((RooRealVar*)POI->first())->setMin(rMin_);
00355   if (!isnan(rMax_)) ((RooRealVar*)POI->first())->setMax(rMax_);
00356 
00357   if (mc->GetPriorPdf() == 0) {
00358       if (prior_ == "flat") {
00359           RooAbsPdf *prior = new RooUniform("prior","prior",*POI);
00360           w->import(*prior);
00361           mc->SetPriorPdf(*prior);
00362       } else if (prior_ == "1/sqrt(r)") {
00363           w->factory(TString::Format("EXPR::prior(\\\"1/sqrt(@0)\\\",%s)", POI->first()->GetName()));
00364           mc->SetPriorPdf(*w->pdf("prior"));
00365       } else if (!prior_.empty() && w->pdf(prior_.c_str()) != 0) {
00366           std::cout << "Will use prior '" << prior_ << "' in from the input workspace" << std::endl;
00367           mc->SetPriorPdf(*w->pdf(prior_.c_str()));
00368       } else {
00369           std::cerr << "Unknown prior '" << prior_ << "'. It's not 'flat' '1/sqrt(r)' or the name of a pdf in the model.\n" << std::endl;
00370           throw std::invalid_argument("Bad prior");
00371       }
00372   }
00373 
00374   if (withSystematics && nuisances == 0) {
00375       std::cout << "The signal model has no nuisance parameters. Please run the limit tool with no systematics (option -S 0)." << std::endl;
00376       std::cout << "To make things easier, I will assume you have done it." << std::endl;
00377       withSystematics = false;
00378   } else if (!withSystematics && nuisances != 0) {
00379     std::cout << "Will set nuisance parameters to constants: " ;
00380     utils::setAllConstant(*nuisances, true);
00381   }
00382 
00383   bool validModel = validateModel_ ? utils::checkModel(*mc, false) : true;
00384   if (validateModel_ && verbose) std::cout << "Sanity checks on the model: " << (validModel ? "OK" : "FAIL") << std::endl;
00385 
00386   // make sure these things are set consistently with what we expect
00387   if (mc->GetNuisanceParameters() && withSystematics) utils::setAllConstant(*mc->GetNuisanceParameters(), false);
00388   if (mc->GetGlobalObservables()) utils::setAllConstant(*mc->GetGlobalObservables(), true);
00389   if (mc_bonly->GetNuisanceParameters() && withSystematics) utils::setAllConstant(*mc_bonly->GetNuisanceParameters(), false);
00390   if (mc_bonly->GetGlobalObservables()) utils::setAllConstant(*mc_bonly->GetGlobalObservables(), true);
00391 
00392 
00393   w->saveSnapshot("clean", w->allVars());
00394 
00395   if (saveWorkspace_) {
00396     w->SetName(workspaceName_.c_str());
00397     outputFile->WriteTObject(w,workspaceName_.c_str());
00398   }
00399 
00400   tree_ = tree;
00401 
00402   bool isExtended = mc_bonly->GetPdf()->canBeExtended();
00403   RooAbsData *dobs = w->data(dataset.c_str());
00404   RooAbsPdf  *genPdf = expectSignal_ > 0 ? mc->GetPdf() : mc_bonly->GetPdf();
00405   toymcoptutils::SimPdfGenInfo newToyMC(*genPdf, *observables, !unbinned_); RooRealVar *weightVar_ = 0;
00406 
00407   if (guessGenMode_ && genPdf->InheritsFrom("RooSimultaneous") && (dobs != 0)) {
00408       utils::guessChannelMode(dynamic_cast<RooSimultaneous&>(*mc->GetPdf()), *dobs, verbose);
00409       utils::guessChannelMode(dynamic_cast<RooSimultaneous&>(*mc_bonly->GetPdf()), *dobs, 0);
00410   }
00411   if (expectSignal_ > 0) { 
00412       ((RooRealVar*)POI->first())->setVal(expectSignal_); 
00413   }
00414   if (nToys <= 0) { // observed or asimov
00415     iToy = nToys;
00416     if (iToy == -1) {   
00417         if (newGen_) {
00418             if (toysFrequentist_) {
00419                 w->saveSnapshot("reallyClean", w->allVars());
00420                 if (dobs == 0) throw std::invalid_argument("Frequentist Asimov datasets can't be generated without a real dataset to fit");
00421                 RooArgSet gobsAsimov;
00422                 dobs = asimovutils::asimovDatasetWithFit(mc, *dobs, gobsAsimov, expectSignal_, verbose);
00423                 if (mc->GetGlobalObservables()) {
00424                     RooArgSet gobs(*mc->GetGlobalObservables());
00425                     gobs = gobsAsimov;
00426                     utils::setAllConstant(*mc->GetParametersOfInterest(), false);
00427                     w->saveSnapshot("clean", w->allVars());
00428                 }
00429             } else {
00430                 dobs = newToyMC.generateAsimov(weightVar_); // as simple as that
00431             }
00432         } else if (isExtended) {
00433             if (unbinned_) {
00434                 throw std::invalid_argument("Asimov datasets can only be generated binned");
00435             } else {
00436                 dobs = genPdf->generateBinned(*observables,RooFit::Extended(),RooFit::Asimov());
00437             }
00438         } else {
00439           dobs = genPdf->generate(*observables,1,RooFit::Asimov());
00440         }
00441     } else if (dobs == 0) {
00442       std::cerr << "No observed data '" << dataset << "' in the workspace. Cannot compute limit.\n" << std::endl;
00443       return;
00444     }
00445     if (saveToys_) {
00446         writeToysHere->WriteTObject(dobs, TString::Format("toy_asimov%g", expectSignal_));
00447       }
00448     std::cout << "Computing limit starting from " << (iToy == 0 ? "observation" : "expected outcome") << std::endl;
00449     if (verbose > (isExtended ? 3 : 2)) utils::printRAD(dobs);
00450     if (mklimit(w,mc,mc_bonly,*dobs,limit,limitErr)) tree->Fill();
00451   }
00452   
00453   
00454   std::vector<double> limitHistory;
00455   std::auto_ptr<RooAbsPdf> nuisancePdf;
00456   if (nToys > 0) {
00457     double expLimit = 0;
00458     unsigned int nLimits = 0;
00459     w->loadSnapshot("clean");
00460     RooDataSet *systDs = 0;
00461     if (withSystematics && !toysNoSystematics_ && (readToysFromHere == 0)) {
00462       if (nuisances == 0) throw std::logic_error("Running with systematics enabled, but nuisances not defined.");
00463       nuisancePdf.reset(utils::makeNuisancePdf(expectSignal_ ? *mc : *mc_bonly));
00464       if (toysFrequentist_) {
00465           if (mc->GetGlobalObservables() == 0) throw std::logic_error("Cannot use toysFrequentist with no global observables");
00466           w->saveSnapshot("reallyClean", w->allVars());
00467           {
00468               if (dobs == 0) throw std::logic_error("Cannot use toysFrequentist with no input dataset");
00469               CloseCoutSentry sentry(verbose < 3);
00470               genPdf->fitTo(*dobs, RooFit::Save(1), RooFit::Minimizer("Minuit2","minimize"), RooFit::Strategy(0), RooFit::Hesse(0), RooFit::Constrain(*(expectSignal_ ?mc:mc_bonly)->GetNuisanceParameters()));
00471           }
00472           w->saveSnapshot("clean", w->allVars());
00473           systDs = nuisancePdf->generate(*mc->GetGlobalObservables(), nToys);
00474       } else {
00475           systDs = nuisancePdf->generate(*nuisances, nToys);
00476       } 
00477     }
00478     std::auto_ptr<RooArgSet> vars(genPdf->getVariables());
00479     algo->setNToys(nToys);
00480     for (iToy = 1; iToy <= nToys; ++iToy) {
00481       algo->setToyNumber(iToy-1);
00482       RooAbsData *absdata_toy = 0;
00483       if (readToysFromHere == 0) {
00484         w->loadSnapshot("clean");
00485         if (verbose > 3) utils::printPdf(*mc_bonly);
00486         if (withSystematics && !toysNoSystematics_) {
00487           *vars = *systDs->get(iToy-1);
00488           if (toysFrequentist_) w->saveSnapshot("clean", w->allVars());
00489           if (verbose > 3) utils::printPdf(*mc_bonly);
00490         }
00491         if (expectSignal_) ((RooRealVar*)POI->first())->setVal(expectSignal_);
00492         std::cout << "Generate toy " << iToy << "/" << nToys << std::endl;
00493         if (isExtended) {
00494           if (newGen_) {
00495               absdata_toy = newToyMC.generate(weightVar_); // as simple as that
00496           } else if (unbinned_) {
00497               absdata_toy = genPdf->generate(*observables,RooFit::Extended());
00498           } else if (generateBinnedWorkaround_) {
00499               std::auto_ptr<RooDataSet> unbinn(genPdf->generate(*observables,RooFit::Extended()));
00500               absdata_toy = new RooDataHist("toy","binned toy", *observables, *unbinn);
00501           } else {
00502               absdata_toy = genPdf->generateBinned(*observables,RooFit::Extended());
00503           }
00504         } else {
00505           RooDataSet *data_toy = genPdf->generate(*observables,1);
00506           absdata_toy = data_toy;
00507         }
00508       } else {
00509         absdata_toy = dynamic_cast<RooAbsData *>(readToysFromHere->Get(TString::Format("toys/toy_%d",iToy)));
00510         if (absdata_toy == 0) {
00511           std::cerr << "Toy toy_"<<iToy<<" not found in " << readToysFromHere->GetName() << ". List follows:\n";
00512           readToysFromHere->ls();
00513           return;
00514         }
00515       }
00516       if (verbose > (isExtended ? 3 : 2)) utils::printRAD(absdata_toy);
00517       w->loadSnapshot("clean");
00518       //if (verbose > 1) utils::printPdf(w, "model_b");
00519       if (mklimit(w,mc,mc_bonly,*absdata_toy,limit,limitErr)) {
00520         tree->Fill();
00521         ++nLimits;
00522         expLimit += limit; 
00523         limitHistory.push_back(limit);
00524       }
00525       if (saveToys_) {
00526         writeToysHere->WriteTObject(absdata_toy, TString::Format("toy_%d", iToy));
00527       }
00528       delete absdata_toy;
00529     }
00530     if (weightVar_) delete weightVar_;
00531     expLimit /= nLimits;
00532     double rms = 0;
00533     for (std::vector<double>::const_iterator itl = limitHistory.begin(); itl != limitHistory.end(); ++itl) {
00534         rms += pow(*itl-expLimit, 2);
00535     }
00536     if (nLimits > 1) {
00537         rms = sqrt(rms/(nLimits-1)/nLimits);
00538         cout << "mean   expected limit: r < " << expLimit << " +/- " << rms << " @ " << cl*100 << "%CL (" <<nLimits << " toyMC)" << endl;
00539     } else {
00540         cout << "mean   expected limit: r < " << expLimit << " @ " << cl*100 << "%CL (" <<nLimits << " toyMC)" << endl;
00541     }
00542     sort(limitHistory.begin(), limitHistory.end());
00543     if (nLimits > 0) {
00544         double medianLimit = (nLimits % 2 == 0 ? 0.5*(limitHistory[nLimits/2-1]+limitHistory[nLimits/2]) : limitHistory[nLimits/2]);
00545         cout << "median expected limit: r < " << medianLimit << " @ " << cl*100 << "%CL (" <<nLimits << " toyMC)" << endl;
00546         double hi68 = limitHistory[min<int>(nLimits-1,  ceil(0.84  * nLimits))];
00547         double lo68 = limitHistory[min<int>(nLimits-1, floor(0.16  * nLimits))];
00548         double hi95 = limitHistory[min<int>(nLimits-1,  ceil(0.975 * nLimits))];
00549         double lo95 = limitHistory[min<int>(nLimits-1, floor(0.025 * nLimits))];
00550         cout << "   68% expected band : " << lo68 << " < r < " << hi68 << endl;
00551         cout << "   95% expected band : " << lo95 << " < r < " << hi95 << endl;
00552     }
00553   }
00554 
00555 }
00556 
00557 void Combine::commitPoint(bool expected, float quantile) {
00558     Float_t saveQuantile =  g_quantileExpected_;
00559     g_quantileExpected_ = quantile;
00560     tree_->Fill();
00561     g_quantileExpected_ = saveQuantile;
00562 }
00563 
00564 void Combine::addBranch(const char *name, void *address, const char *leaflist) {
00565     tree_->Branch(name,address,leaflist);
00566 }