00001 #include "../interface/ChannelCompatibilityCheck.h"
00002 #include <TFile.h>
00003 #include <RooRealVar.h>
00004 #include <RooArgSet.h>
00005 #include <RooRandom.h>
00006 #include <RooDataSet.h>
00007 #include <RooFitResult.h>
00008 #include <RooCustomizer.h>
00009 #include <RooSimultaneous.h>
00010 #include <RooStats/ModelConfig.h>
00011 #include "../interface/Combine.h"
00012 #include "../interface/ProfileLikelihood.h"
00013 #include "../interface/CloseCoutSentry.h"
00014 #include "../interface/RooSimultaneousOpt.h"
00015 #include "../interface/utils.h"
00016
00017
00018 #include <Math/MinimizerOptions.h>
00019
00020 using namespace RooStats;
00021
00022 float ChannelCompatibilityCheck::mu_ = 0.0;
00023 bool ChannelCompatibilityCheck::fixedMu_ = false;
00024 bool ChannelCompatibilityCheck::saveFitResult_ = true;
00025 bool ChannelCompatibilityCheck::runMinos_ = true;
00026 std::vector<std::string> ChannelCompatibilityCheck::groups_;
00027
00028 ChannelCompatibilityCheck::ChannelCompatibilityCheck() :
00029 FitterAlgoBase("ChannelCompatibilityCheck specific options")
00030 {
00031 options_.add_options()
00032 ("fixedSignalStrength", boost::program_options::value<float>(&mu_)->default_value(mu_), "Compute the compatibility for a fixed signal strength. If not specified, it's left floating")
00033 ("saveFitResult", "Save fit results in output file")
00034 ("group,g", boost::program_options::value<std::vector<std::string> >(&groups_), "Group together channels that contain a given name. Can be used multiple times.")
00035 ("runMinos", boost::program_options::value<bool>(&runMinos_)->default_value(runMinos_), "Compute also uncertainties using profile likeilhood (MINOS or robust variants of it)")
00036 ;
00037 }
00038
00039 void ChannelCompatibilityCheck::applyOptions(const boost::program_options::variables_map &vm)
00040 {
00041 applyOptionsBase(vm);
00042 fixedMu_ = !vm["fixedSignalStrength"].defaulted();
00043 saveFitResult_ = vm.count("saveFitResult");
00044 }
00045
00046 bool ChannelCompatibilityCheck::runSpecific(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint) {
00047
00048 RooRealVar *r = dynamic_cast<RooRealVar *>(mc_s->GetParametersOfInterest()->first());
00049 if (fixedMu_) { r->setVal(mu_); r->setConstant(true); }
00050 else { r->setVal(preFitValue_); r->setConstant(false); }
00051
00052 RooSimultaneous *sim = dynamic_cast<RooSimultaneous *>(mc_s->GetPdf());
00053 if (sim == 0) throw std::logic_error("Cannot use ChannelCompatibilityCheck if the pdf is not a RooSimultaneous");
00054
00055 RooAbsCategoryLValue *cat = (RooAbsCategoryLValue *) sim->indexCat().Clone();
00056 int nbins = cat->numBins((const char *)0);
00057 TString satname = TString::Format("%s_freeform", sim->GetName());
00058 std::auto_ptr<RooSimultaneous> newsim((typeid(*sim) == typeid(RooSimultaneousOpt)) ? new RooSimultaneousOpt(satname, "", *cat) : new RooSimultaneous(satname, "", *cat));
00059 std::map<std::string,std::string> rs;
00060 RooArgList minosVars, minosOneVar; if (runMinos_) minosOneVar.add(*r);
00061 for (int ic = 0, nc = nbins; ic < nc; ++ic) {
00062 cat->setBin(ic);
00063 RooAbsPdf *pdfi = sim->getPdf(cat->getLabel());
00064 if (pdfi == 0) continue;
00065 RooCustomizer customizer(*pdfi, "freeform");
00066 TString riName = TString::Format("_ChannelCompatibilityCheck_%s_%s", r->GetName(), nameForLabel(cat->getLabel()).c_str());
00067 rs.insert(std::pair<std::string,std::string>(nameForLabel(cat->getLabel()), riName.Data()));
00068 if (w->var(riName) == 0) {
00069 w->factory(TString::Format("%s[%g,%g]", riName.Data(), r->getMin(), r->getMax()));
00070 }
00071 customizer.replaceArg(*r, *w->var(riName));
00072 newsim->addPdf((RooAbsPdf&)*customizer.build(), cat->getLabel());
00073 if (runMinos_ && !minosVars.find(riName)) minosVars.add(*w->var(riName));
00074 }
00075
00076 CloseCoutSentry sentry(verbose < 2);
00077 const RooCmdArg &constCmdArg = withSystematics ? RooFit::Constrain(*mc_s->GetNuisanceParameters()) : RooFit::NumCPU(1);
00078 std::auto_ptr<RooFitResult> result_nominal (doFit( *sim, data, minosOneVar, constCmdArg, runMinos_));
00079 std::auto_ptr<RooFitResult> result_freeform(doFit(*newsim, data, minosVars, constCmdArg, runMinos_));
00080 sentry.clear();
00081
00082 if (result_nominal.get() == 0) return false;
00083 if (result_freeform.get() == 0) return false;
00084
00085 double nll_nominal = result_nominal->minNll();
00086 double nll_freeform = result_freeform->minNll();
00087 if (fabs(nll_nominal) > 1e10 || fabs(nll_freeform) > 1e10) return false;
00088 limit = 2*(nll_nominal-nll_freeform);
00089
00090 std::cout << "\n --- ChannelCompatibilityCheck --- " << std::endl;
00091 if (verbose) {
00092 if (fixedMu_) {
00093 printf("Nominal fit: %s fixed at %7.4f\n", r->GetName(), r->getVal());
00094 } else {
00095 RooRealVar *rNominal = (RooRealVar*) result_nominal->floatParsFinal().find(r->GetName());
00096 if (runMinos_ && do95_) {
00097 printf("Nominal fit : %s = %7.4f %+6.4f/%+6.4f (68%% CL)\n", r->GetName(), rNominal->getVal(), rNominal->getAsymErrorLo(), rNominal->getAsymErrorHi());
00098 printf(" %s = %7.4f %+6.4f/%+6.4f (95%% CL)\n", r->GetName(), rNominal->getVal(), rNominal->getMin("err95")-rNominal->getVal(), rNominal->getMax("err95")-rNominal->getVal());
00099 } else if (runMinos_) {
00100 printf("Nominal fit : %s = %7.4f %+6.4f/%+6.4f\n", r->GetName(), rNominal->getVal(), rNominal->getAsymErrorLo(), rNominal->getAsymErrorHi());
00101 } else {
00102 printf("Nominal fit : %s = %7.4f +/- %6.4f\n", r->GetName(), rNominal->getVal(), rNominal->getError());
00103 }
00104 }
00105 for (std::map<std::string,std::string>::const_iterator it = rs.begin(), ed = rs.end(); it != ed; ++it) {
00106 RooRealVar *ri = (RooRealVar*) result_freeform->floatParsFinal().find(it->second.c_str());
00107 if (runMinos_ && do95_) {
00108 printf("Alternate fit: %s = %7.4f %+6.4f/%+6.4f (68%% CL) in channel %s\n", r->GetName(), ri->getVal(), ri->getAsymErrorLo(), ri->getAsymErrorHi(), it->first.c_str());
00109 printf(" %s = %7.4f %+6.4f/%+6.4f (95%% CL) in channel %s\n", r->GetName(), ri->getVal(), ri->getMin("err95")-ri->getVal(), ri->getMax("err95")-ri->getVal(), it->first.c_str());
00110 } else if (runMinos_) {
00111 printf("Alternate fit: %s = %7.4f %+6.4f/%+6.4f in channel %s\n", r->GetName(), ri->getVal(), ri->getAsymErrorLo(), ri->getAsymErrorHi(), it->first.c_str());
00112 } else {
00113 printf("Alternate fit: %s = %7.4f +/- %6.4f in channel %s\n", r->GetName(), ri->getVal(), ri->getError(), it->first.c_str());
00114 }
00115 }
00116 }
00117 std::cout << "Chi2-like compatibility variable: " << limit << std::endl;
00118
00119 if (saveFitResult_) {
00120 writeToysHere->GetFile()->WriteTObject(result_nominal.release(), "fit_nominal" );
00121 writeToysHere->GetFile()->WriteTObject(result_freeform.release(), "fit_alternate");
00122 }
00123 return true;
00124 }
00125
00126 std::string ChannelCompatibilityCheck::nameForLabel(const char *label)
00127 {
00128 std::string ret(label);
00129 for (std::vector<std::string>::const_iterator it = groups_.begin(), ed = groups_.end(); it != ed; ++it) {
00130 if (ret.find(*it) != std::string::npos) { ret = *it; break; }
00131 }
00132 return ret;
00133 }
00134