// @(#)root/roostats:$Id: cranmer $
// Author: Kyle Cranmer, Akira Shibata
/*************************************************************************
* Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//_________________________________________________
/*
BEGIN_HTML
END_HTML
*/
//
#ifndef __CINT__
#include "RooGlobalFunc.h"
#endif
#include "RooDataSet.h"
#include "RooRealVar.h"
#include "RooConstVar.h"
#include "RooAddition.h"
#include "RooProduct.h"
#include "RooProdPdf.h"
#include "RooAddPdf.h"
#include "RooGaussian.h"
#include "RooPoisson.h"
#include "RooExponential.h"
#include "RooRandom.h"
#include "RooCategory.h"
#include "RooSimultaneous.h"
#include "RooMultiVarGaussian.h"
#include "RooNumIntConfig.h"
#include "RooMinuit.h"
#include "RooNLLVar.h"
#include "RooProfileLL.h"
#include "RooFitResult.h"
#include "RooDataHist.h"
#include "RooHistFunc.h"
#include "RooHistPdf.h"
#include "RooRealSumPdf.h"
#include "RooProduct.h"
#include "RooWorkspace.h"
#include "RooCustomizer.h"
#include "RooPlot.h"
#include "RooMsgService.h"
#include "RooStats/RooStatsUtils.h"
#include "RooStats/ModelConfig.h"
#include "RooStats/HistFactory/PiecewiseInterpolation.h"
#include "RooStats/HistFactory/ParamHistFunc.h"
#include "RooStats/AsymptoticCalculator.h"
#include "TH2F.h"
#include "TH3F.h"
#include "TFile.h"
#include "TCanvas.h"
#include "TH1.h"
#include "TLine.h"
#include "TTree.h"
#include "TMarker.h"
#include "TStopwatch.h"
#include "TROOT.h"
#include "TStyle.h"
#include "TVectorD.h"
#include "TMatrixDSym.h"
// specific to this package
#include "RooStats/HistFactory/LinInterpVar.h"
#include "RooStats/HistFactory/FlexibleInterpVar.h"
#include "RooStats/HistFactory/HistoToWorkspaceFactoryFast.h"
#include "RooStats/HistFactory/Measurement.h"
#include "Helper.h"
#include
#define VERBOSE
#define alpha_Low "-5"
#define alpha_High "5"
#define NoHistConst_Low "0"
#define NoHistConst_High "2000"
// use this order for safety on library loading
using namespace RooFit ;
using namespace RooStats ;
using namespace std ;
ClassImp(RooStats::HistFactory::HistoToWorkspaceFactoryFast)
namespace RooStats{
namespace HistFactory{
HistoToWorkspaceFactoryFast::HistoToWorkspaceFactoryFast() :
fNomLumi(1.0), fLumiError(0),
fLowBin(0), fHighBin(0)
{}
HistoToWorkspaceFactoryFast::~HistoToWorkspaceFactoryFast(){
}
HistoToWorkspaceFactoryFast::HistoToWorkspaceFactoryFast(RooStats::HistFactory::Measurement& measurement ) :
fSystToFix( measurement.GetConstantParams() ),
fParamValues( measurement.GetParamValues() ),
fNomLumi( measurement.GetLumi() ),
fLumiError( measurement.GetLumi()*measurement.GetLumiRelErr() ),
fLowBin( measurement.GetBinLow() ),
fHighBin( measurement.GetBinHigh() ) {
// Set Preprocess functions
SetFunctionsToPreprocess( measurement.GetPreprocessFunctions() );
}
void HistoToWorkspaceFactoryFast::ConfigureWorkspaceForMeasurement( const std::string& ModelName, RooWorkspace* ws_single, Measurement& measurement ) {
// Configure a workspace by doing any
// necessary post-processing and by
// creating a ModelConfig
// Make a ModelConfig and configure it
ModelConfig * proto_config = (ModelConfig *) ws_single->obj("ModelConfig");
if( proto_config == NULL ) {
std::cout << "Error: Did not find 'ModelConfig' object in file: " << ws_single->GetName()
<< std::endl;
throw hf_exc();
}
std::vector poi_list = measurement.GetPOIList();
if( poi_list.size()==0 ) {
std::cout << "Warining: No Parametetrs of interest are set" << std::endl;
}
cout << "Setting Parameter(s) of Interest as: ";
for(unsigned int i = 0; i < poi_list.size(); ++i) {
cout << poi_list.at(i) << " ";
}
cout << endl;
RooArgSet * params= new RooArgSet;
for( unsigned int i = 0; i < poi_list.size(); ++i ) {
std::string poi_name = poi_list.at(i);
RooRealVar* poi = (RooRealVar*) ws_single->var( poi_name.c_str() );
if(poi){
params->add(*poi);
}
else {
std::cout << "WARNING: Can't find parameter of interest: " << poi_name
<< " in Workspace. Not setting in ModelConfig." << std::endl;
//throw hf_exc();
}
}
proto_config->SetParametersOfInterest(*params);
// Name of an 'edited' model, if necessary
std::string NewModelName = "newSimPdf"; // <- This name is hard-coded in HistoToWorkspaceFactoryFast::EditSyt. Probably should be changed to : std::string("new") + ModelName;
// Activate Additional Constraint Terms
if( measurement.GetGammaSyst().size() > 0
|| measurement.GetUniformSyst().size() > 0
|| measurement.GetLogNormSyst().size() > 0
|| measurement.GetNoSyst().size() > 0) {
HistoToWorkspaceFactoryFast::EditSyst( ws_single, (ModelName).c_str(),
measurement.GetGammaSyst(),
measurement.GetUniformSyst(),
measurement.GetLogNormSyst(),
measurement.GetNoSyst());
proto_config->SetPdf( *ws_single->pdf( "newSimPdf" ) );
}
// Set the ModelConfig's Params of Interest
RooAbsData* expData = ws_single->data("asimovData");
if( !expData ) {
std::cout << "Error: Failed to find dataset: " << expData
<< " in workspace" << std::endl;
throw hf_exc();
}
if(poi_list.size()!=0){
proto_config->GuessObsAndNuisance(*expData);
}
// Now, let's loop over any additional asimov datasets
// that we need to make
// Get the pdf
// Notice that we get the "new" pdf, this is the one that is
// used in the creation of these asimov datasets since they
// are fitted (or may be, at least).
RooAbsPdf* pdf = ws_single->pdf(NewModelName.c_str());
if( !pdf ) pdf = ws_single->pdf( ModelName.c_str() );
const RooArgSet* observables = ws_single->set("observables");
// Create a SnapShot of the nominal values
std::string SnapShotName = "NominalParamValues";
ws_single->saveSnapshot(SnapShotName.c_str(), ws_single->allVars());
for( unsigned int i=0; iimport(*asimov_dataset, Rename(AsimovName.c_str()));
if( failure ) {
std::cout << "Error: Failed to import Asimov dataset: " << AsimovName
<< std::endl;
throw hf_exc();
}
// Load the snapshot at the end of every loop iteration
// so we start each loop with a "clean" snapshot
ws_single->loadSnapshot(SnapShotName.c_str());
}
// Cool, we're done
return; // ws_single;
}
// We want to eliminate this interface and use the measurment directly
RooWorkspace* HistoToWorkspaceFactoryFast::MakeSingleChannelModel( Measurement& measurement, Channel& channel ) {
// This is a pretty light-weight wrapper function
//
// Take a fully configured measurement as well as
// one of its channels
//
// Return a workspace representing that channel
// Do this by first creating a vector of EstimateSummary's
// and this by configuring the workspace with any post-processing
// Get the channel's name
string ch_name = channel.GetName();
// Create a workspace for a SingleChannel from the Measurement Object
RooWorkspace* ws_single = this->MakeSingleChannelWorkspace(measurement, channel);
if( ws_single == NULL ) {
std::cout << "Error: Failed to make Single-Channel workspace for channel: " << ch_name
<< " and measurement: " << measurement.GetName() << std::endl;
throw hf_exc();
}
// Finally, configure that workspace based on
// properties of the measurement
HistoToWorkspaceFactoryFast::ConfigureWorkspaceForMeasurement( "model_"+ch_name, ws_single, measurement );
return ws_single;
}
RooWorkspace* HistoToWorkspaceFactoryFast::MakeCombinedModel( Measurement& measurement ) {
// This function takes a fully configured measurement
// which may contain several channels and returns
// a workspace holding the combined model
//
// This can be used, for example, within a script to produce
// a combined workspace on-the-fly
//
// This is a static function (for now) to make
// it a one-liner
// First, we create an instance of a HistFactory
HistoToWorkspaceFactoryFast factory( measurement );
// Loop over the channels and create the individual workspaces
vector channel_workspaces;
vector channel_names;
for( unsigned int chanItr = 0; chanItr < measurement.GetChannels().size(); ++chanItr ) {
HistFactory::Channel& channel = measurement.GetChannels().at( chanItr );
if( ! channel.CheckHistograms() ) {
std::cout << "MakeModelAndMeasurementsFast: Channel: " << channel.GetName()
<< " has uninitialized histogram pointers" << std::endl;
throw hf_exc();
}
string ch_name = channel.GetName();
channel_names.push_back(ch_name);
// GHL: Renaming to 'MakeSingleChannelWorkspace'
RooWorkspace* ws_single = factory.MakeSingleChannelModel( measurement, channel );
channel_workspaces.push_back(ws_single);
}
// Now, combine the individual channel workspaces to
// form the combined workspace
RooWorkspace* ws = factory.MakeCombinedModel( channel_names, channel_workspaces );
// Configure the workspace
HistoToWorkspaceFactoryFast::ConfigureWorkspaceForMeasurement( "simPdf", ws, measurement );
// Delete channel workspaces
for (vector::iterator iter = channel_workspaces.begin() ; iter != channel_workspaces.end() ; ++iter) {
delete *iter ;
}
// Done. Return the pointer
return ws;
}
void HistoToWorkspaceFactoryFast::ProcessExpectedHisto(TH1* hist,RooWorkspace* proto,
string prefix, string productPrefix,
string systTerm ) {
if(hist) {
cout << "processing hist " << hist->GetName() << endl;
} else {
cout << "hist is empty" << endl;
R__ASSERT(hist != 0);
return;
}
/// require dimension >=1 or <=3
if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); }
R__ASSERT( fObsNameVec.size()>=1 && fObsNameVec.size()<=3 );
/// determine histogram dimensionality
unsigned int histndim(1);
std::string classname = hist->ClassName();
if (classname.find("TH1")==0) { histndim=1; }
else if (classname.find("TH2")==0) { histndim=2; }
else if (classname.find("TH3")==0) { histndim=3; }
R__ASSERT( histndim==fObsNameVec.size() );
/// create roorealvar observables
RooArgList observables;
std::vector::iterator itr = fObsNameVec.begin();
for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
if ( !proto->var(itr->c_str()) ) {
TAxis* axis(0);
if (idx==0) { axis = hist->GetXaxis(); }
if (idx==1) { axis = hist->GetYaxis(); }
if (idx==2) { axis = hist->GetZaxis(); }
Int_t nbins = axis->GetNbins();
Double_t xmin = axis->GetXmin();
Double_t xmax = axis->GetXmax();
// create observable
proto->factory(Form("%s[%f,%f]",itr->c_str(),xmin,xmax));
proto->var(itr->c_str())->setBins(nbins);
}
observables.add( *proto->var(itr->c_str()) );
}
RooDataHist* histDHist = new RooDataHist((prefix+"nominalDHist").c_str(),"",observables,hist);
RooHistFunc* histFunc = new RooHistFunc((prefix+"_nominal").c_str(),"",observables,*histDHist,0) ;
proto->import(*histFunc);
/// now create the product of the overall efficiency times the sigma(params) for this estimate
proto->factory(("prod:"+productPrefix+"("+prefix+"_nominal,"+systTerm+")").c_str() );
}
void HistoToWorkspaceFactoryFast::AddMultiVarGaussConstraint(RooWorkspace* proto, string prefix,int lowBin, int highBin, vector& constraintTermNames){
// these are the nominal predictions: eg. the mean of some space of variations
// later fill these in a loop over histogram bins
TVectorD mean(highBin); //-lowBin); // MB: fix range
cout << "a" << endl;
for(Int_t i=lowBin; ivar((prefix+str.str()).c_str());
mean(i) = temp->getVal();
}
TMatrixDSym Cov(highBin-lowBin);
for(int i=lowBin; iset(prefix.c_str() ) ) );
RooMultiVarGaussian constraint((prefix+"Constraint").c_str(),"",
floating, mean, Cov);
proto->import(constraint);
constraintTermNames.push_back(constraint.GetName());
}
void HistoToWorkspaceFactoryFast::LinInterpWithConstraint(RooWorkspace* proto, TH1* nominal,
std::vector histoSysList,
string prefix, string productPrefix,
string systTerm,
vector& constraintTermNames){
// these are the nominal predictions: eg. the mean of some space of variations
// later fill these in a loop over histogram bins
// require dimension >=1 or <=3
if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); }
R__ASSERT( fObsNameVec.size()>=1 && fObsNameVec.size()<=3 );
// determine histogram dimensionality
unsigned int histndim(1);
std::string classname = nominal->ClassName();
if (classname.find("TH1")==0) { histndim=1; }
else if (classname.find("TH2")==0) { histndim=2; }
else if (classname.find("TH3")==0) { histndim=3; }
R__ASSERT( histndim==fObsNameVec.size() );
// cout <<"In LinInterpWithConstriants and histndim = " << histndim <::iterator itr = fObsNameVec.begin();
for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
if ( !proto->var(itr->c_str()) ) {
TAxis* axis(NULL);
if (idx==0) { axis = nominal->GetXaxis(); }
else if (idx==1) { axis = nominal->GetYaxis(); }
else if (idx==2) { axis = nominal->GetZaxis(); }
else {
std::cout << "Error: Too many observables. "
<< "HistFactory only accepts up to 3 observables (3d) "
<< std::endl;
throw hf_exc();
}
Int_t nbins = axis->GetNbins();
Double_t xmin = axis->GetXmin();
Double_t xmax = axis->GetXmax();
// create observable
proto->factory(Form("%s[%f,%f]",itr->c_str(),xmin,xmax));
proto->var(itr->c_str())->setBins(nbins);
}
observables.add( *proto->var(itr->c_str()) );
}
RooDataHist* nominalDHist = new RooDataHist((prefix+"nominalDHist").c_str(),"",observables,nominal);
RooHistFunc* nominalFunc = new RooHistFunc((prefix+"nominal").c_str(),"",observables,*nominalDHist,0) ;
// make list of abstract parameters that interpolate in space of variations
RooArgList params( ("alpha_Hist") );
// range is set using defined macro (see top of the page)
string range=string("[")+alpha_Low+","+alpha_High+"]";
// Loop over the HistoSys list
for(unsigned int j=0; jvar(("alpha_" + histoSysName).c_str());
if(!temp){
temp = (RooRealVar*) proto->factory(("alpha_" + histoSysName + range).c_str());
// now add a constraint term for these parameters
string command=("Gaussian::alpha_"+histoSysName+"Constraint(alpha_"+histoSysName+",nom_alpha_"+histoSysName+"[0.,-10,10],1.)");
cout << command << endl;
constraintTermNames.push_back( proto->factory( command.c_str() )->GetName() );
proto->var(("nom_alpha_"+histoSysName).c_str())->setConstant();
const_cast(proto->set("globalObservables"))->add(*proto->var(("nom_alpha_"+histoSysName).c_str()));
}
params.add(* temp );
}
// now make function that linearly interpolates expectation between variations
// get low/high variations to interpolate between
vector low, high;
RooArgSet lowSet, highSet;
//ES// for(unsigned int j=0; jimport(interp); // individual params have already been imported in first loop of this function
// now create the product of the overall efficiency times the sigma(params) for this estimate
proto->factory(("prod:"+productPrefix+"("+prefix+","+systTerm+")").c_str() );
}
// GHL: Consider passing the NormFactor list instead of the entire sample
string HistoToWorkspaceFactoryFast::AddNormFactor(RooWorkspace* proto, string& channel, string& sigmaEpsilon, Sample& sample, bool doRatio){
string overallNorm_times_sigmaEpsilon ;
string prodNames;
vector normList = sample.GetNormFactorList();
vector normFactorNames, rangeNames;
if(normList.size() > 0){
for(vector::iterator itr = normList.begin(); itr != normList.end(); ++itr){
NormFactor& norm = *itr;
string varname;
if(!prodNames.empty()) prodNames += ",";
if(doRatio) {
varname = norm.GetName() + "_" + channel;
}
else {
varname=norm.GetName();
}
// GHL: Check that the NormFactor doesn't already exist
// (it may have been created as a function expression
// during preprocessing)
std::stringstream range;
range << "[" << norm.GetVal() << "," << norm.GetLow() << "," << norm.GetHigh() << "]";
if( proto->obj(varname.c_str()) == NULL) {
cout << "making normFactor: " << norm.GetName() << endl;
// remove "doRatio" and name can be changed when ws gets imported to the combined model.
proto->factory((varname + range.str()).c_str());
}
if(norm.GetConst()) {
// proto->var(varname.c_str())->setConstant();
// cout <<"setting " << varname << " constant"< tag is deprecated, will ignore." <<
" Instead, add \n\t" << varname << "\n" <<
" to your top-level XML's entry" << endl;
}
prodNames+=varname;
rangeNames.push_back(range.str());
normFactorNames.push_back(varname);
}
overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_overallNorm_x_sigma_epsilon";
proto->factory(("prod::" + overallNorm_times_sigmaEpsilon + "(" + prodNames + "," + sigmaEpsilon + ")").c_str());
}
unsigned int rangeIndex=0;
for( vector::iterator nit = normFactorNames.begin(); nit!=normFactorNames.end(); ++nit){
if( count (normFactorNames.begin(), normFactorNames.end(), *nit) > 1 ){
cout <<"WARNING: is duplicated for , but only one factor will be included. \n Instead, define something like"
<< "\n\t \nin your top-level XML's entry and use & systList,
vector& constraintTermNames,
vector& totSystTermNames) {
// add variables for all the relative overall uncertainties we expect
// range is set using defined macro (see top of the page)
string range=string("[0,")+alpha_Low+","+alpha_High+"]";
totSystTermNames.push_back(prefix);
RooArgSet params(prefix.c_str());
vector lowVec, highVec;
for(unsigned int i = 0; i < systList.size(); ++i) {
OverallSys& sys = systList.at(i);
// add efficiency term
RooRealVar* temp = (RooRealVar*) proto->var((prefix + sys.GetName()).c_str());
if(!temp) {
temp = (RooRealVar*) proto->factory((prefix + sys.GetName() + range).c_str());
string command=("Gaussian::" + prefix + sys.GetName() +
"Constraint(" + prefix + sys.GetName() +
",nom_" + prefix + sys.GetName() + "[0.,-10,10],1.)");
cout << command << endl;
constraintTermNames.push_back( proto->factory( command.c_str() )->GetName() );
proto->var(("nom_" + prefix + sys.GetName()).c_str())->setConstant();
const_cast(proto->set("globalObservables"))->add(*proto->var(("nom_" + prefix + sys.GetName()).c_str()));
}
params.add(*temp);
// add constraint in terms of bifrucated gauss with low/high as sigmas
std::stringstream lowhigh;
double low = sys.GetLow();
double high = sys.GetHigh();
lowVec.push_back(low);
highVec.push_back(high);
}
if(systList.size() > 0){
// this is epsilon(alpha_j), a piece-wise linear interpolation
// LinInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
FlexibleInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
interp.setAllInterpCodes(4); // LM: change to 4 (piece-wise linear to 6th order polynomial interpolation + linear extrapolation )
proto->import(interp); // params have already been imported in first loop of this function
} else{
// some strange behavior if params,lowVec,highVec are empty.
//cout << "WARNING: No OverallSyst terms" << endl;
RooConstVar interp( (interpName).c_str(), "", 1.);
proto->import(interp); // params have already been imported in first loop of this function
}
}
void HistoToWorkspaceFactoryFast::MakeTotalExpected(RooWorkspace* proto, string totName,
vector& syst_x_expectedPrefixNames,
vector& normByNames){
// for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
string command;
string coeffList="";
string shapeList="";
string prepend="";
if (fObsNameVec.empty() && !fObsName.empty()) { fObsNameVec.push_back(fObsName); }
double binWidth(1.0);
std::string obsNameVecStr;
std::vector::iterator itr = fObsNameVec.begin();
for (; itr!=fObsNameVec.end(); ++itr) {
std::string obsName = *itr;
binWidth *= proto->var(obsName.c_str())->numBins()/(proto->var(obsName.c_str())->getMax() - proto->var(obsName.c_str())->getMin()) ; // MB: Note: requires fixed bin sizes
if (obsNameVecStr.size()>0) { obsNameVecStr += "_"; }
obsNameVecStr += obsName;
}
//vector::iterator it=syst_x_expectedPrefixNames.begin();
for(unsigned int j=0; jfactory(command.c_str());
proto->var(Form("binWidth_%s_%d",obsNameVecStr.c_str(),j))->setConstant();
coeffList+=prepend+"binWidth_"+obsNameVecStr+str.str();
command="prod::L_x_"+syst_x_expectedPrefixNames.at(j)+"("+normByNames.at(j)+","+syst_x_expectedPrefixNames.at(j)+")";
/*RooAbsReal* tempFunc =(RooAbsReal*) */
proto->factory(command.c_str());
shapeList+=prepend+"L_x_"+syst_x_expectedPrefixNames.at(j);
prepend=",";
// add to num int to product
// tempFunc->specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ;
// tempFunc->forceNumInt();
}
proto->defineSet("coefList",coeffList.c_str());
proto->defineSet("shapeList",shapeList.c_str());
// proto->factory(command.c_str());
RooRealSumPdf tot(totName.c_str(),totName.c_str(),*proto->set("shapeList"),*proto->set("coefList"),kTRUE);
tot.specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ;
tot.specialIntegratorConfig(kTRUE)->method2D().setLabel("RooBinIntegrator") ;
tot.specialIntegratorConfig(kTRUE)->methodND().setLabel("RooBinIntegrator") ;
tot.forceNumInt();
// for mixed generation in RooSimultaneous
tot.setAttribute("GenerateBinned"); // for use with RooSimultaneous::generate in mixed mode
// tot.setAttribute("GenerateUnbinned"); // we don't want that
/*
// Use binned numeric integration
int nbins = 0;
if( fObsNameVec.size() == 1 ) {
nbins = proto->var(fObsNameVec.at(0).c_str())->numBins();
cout <<"num bis for RooRealSumPdf = "<numBins();
tot.specialIntegratorConfig(kTRUE)->getConfigSection("RooBinIntegrator").setRealValue("numBins",nbins);
tot.forceNumInt();
} else {
cout << "Bin Integrator only supports 1-d. Will be slow." << std::endl;
}
*/
proto->import(tot);
}
void HistoToWorkspaceFactoryFast::AddPoissonTerms(RooWorkspace* proto, string prefix, string obsPrefix, string expPrefix, int lowBin, int highBin,
vector& likelihoodTermNames){
/////////////////////////////////
// Relate observables to expected for each bin
// later modify variable named expPrefix_i to be product of terms
RooArgSet Pois(prefix.c_str());
for(Int_t i=lowBin; ifactory( command.c_str() ) );
// output
cout << "Poisson Term " << command << endl;
((RooAbsPdf*) temp)->setEvalErrorLoggingMode(RooAbsReal::PrintErrors);
//cout << temp << endl;
likelihoodTermNames.push_back( temp->GetName() );
Pois.add(* temp );
}
proto->defineSet(prefix.c_str(),Pois); // add argset to workspace
}
void HistoToWorkspaceFactoryFast::SetObsToExpected(RooWorkspace* proto, string obsPrefix, string expPrefix, int lowBin, int highBin){
/////////////////////////////////
// set observed to expected
TTree* tree = new TTree();
Double_t* obsForTree = new Double_t[highBin-lowBin];
RooArgList obsList("obsList");
for(Int_t i=lowBin; ivar((obsPrefix+str.str()).c_str());
cout << "expected number of events called: " << expPrefix << endl;
RooAbsReal* exp = proto->function((expPrefix+str.str()).c_str());
if(obs && exp){
//proto->Print();
obs->setVal( exp->getVal() );
cout << "setting obs"+str.str()+" to expected = " << exp->getVal() << " check: " << obs->getVal() << endl;
// add entry to array and attach to tree
obsForTree[i] = exp->getVal();
tree->Branch((obsPrefix+str.str()).c_str(), obsForTree+i ,(obsPrefix+str.str()+"/D").c_str());
obsList.add(*obs);
}else{
cout << "problem retrieving obs or exp " << obsPrefix+str.str() << obs << " " << expPrefix+str.str() << exp << endl;
}
}
tree->Fill();
RooDataSet* data = new RooDataSet("expData","", tree, obsList); // one experiment
delete tree;
delete [] obsForTree;
proto->import(*data);
}
//_____________________________________________________________
void HistoToWorkspaceFactoryFast::EditSyst(RooWorkspace* proto, const char* pdfNameChar,
map gammaSyst,
map uniformSyst,
map logNormSyst,
map noSyst) {
string pdfName(pdfNameChar);
ModelConfig * combined_config = (ModelConfig *) proto->obj("ModelConfig");
if( combined_config==NULL ) {
std::cout << "Error: Failed to find object 'ModelConfig' in workspace: "
<< proto->GetName() << std::endl;
throw hf_exc();
}
// const RooArgSet * constrainedParams=combined_config->GetNuisanceParameters();
// RooArgSet temp(*constrainedParams);
string edit="EDIT::newSimPdf("+pdfName+",";
string editList;
string lastPdf=pdfName;
string precede="";
unsigned int numReplacements = 0;
unsigned int nskipped = 0;
map::iterator it;
// add gamma terms and their constraints
for(it=gammaSyst.begin(); it!=gammaSyst.end(); ++it) {
//cout << "edit for " << it->first << "with rel uncert = " << it->second << endl;
if(! proto->var(("alpha_"+it->first).c_str())){
//cout << "systematic not there" << endl;
nskipped++;
continue;
}
numReplacements++;
double relativeUncertainty = it->second;
double scale = 1/sqrt((1+1/pow(relativeUncertainty,2)));
// this is the Gamma PDF and in a form that doesn't have roundoff problems like the Poisson does
proto->factory(Form("beta_%s[1,0,10]",it->first.c_str()));
proto->factory(Form("y_%s[%f]",it->first.c_str(),1./pow(relativeUncertainty,2))) ;
proto->factory(Form("theta_%s[%f]",it->first.c_str(),pow(relativeUncertainty,2))) ;
proto->factory(Form("Gamma::beta_%sConstraint(beta_%s,sum::k_%s(y_%s,one[1]),theta_%s,zero[0])",
it->first.c_str(),
it->first.c_str(),
it->first.c_str(),
it->first.c_str(),
it->first.c_str())) ;
/*
// this has some problems because N in poisson is rounded to nearest integer
proto->factory(Form("Poisson::beta_%sConstraint(y_%s[%f],prod::taub_%s(taus_%s[%f],beta_%s[1,0,5]))",
it->first.c_str(),
it->first.c_str(),
1./pow(relativeUncertainty,2),
it->first.c_str(),
it->first.c_str(),
1./pow(relativeUncertainty,2),
it->first.c_str()
) ) ;
*/
// combined->factory(Form("expr::alphaOfBeta('(beta-1)/%f',beta)",scale));
// combined->factory(Form("expr::alphaOfBeta_%s('(beta_%s-1)/%f',beta_%s)",it->first.c_str(),it->first.c_str(),scale,it->first.c_str()));
proto->factory(Form("PolyVar::alphaOfBeta_%s(beta_%s,{%f,%f})",it->first.c_str(),it->first.c_str(),-1./scale,1./scale));
// set beta const status to be same as alpha
if(proto->var(Form("alpha_%s",it->first.c_str()))->isConstant()) {
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(true);
}
else {
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(false);
}
// set alpha const status to true
// proto->var(Form("alpha_%s",it->first.c_str()))->setConstant(true);
// replace alphas with alphaOfBeta and replace constraints
editList+=precede + "alpha_"+it->first+"Constraint=beta_" + it->first+ "Constraint";
precede=",";
editList+=precede + "alpha_"+it->first+"=alphaOfBeta_"+ it->first;
/*
if( proto->pdf(("alpha_"+it->first+"Constraint").c_str()) && proto->var(("alpha_"+it->first).c_str()) )
cout << " checked they are there" << proto->pdf(("alpha_"+it->first+"Constraint").c_str()) << " " << proto->var(("alpha_"+it->first).c_str()) << endl;
else
cout << "NOT THERE" << endl;
*/
// EDIT seems to die if the list of edits is too long. So chunck them up.
if(numReplacements%10 == 0 && numReplacements+nskipped!=gammaSyst.size()){
edit="EDIT::"+lastPdf+"_("+lastPdf+","+editList+")";
lastPdf+="_"; // append an underscore for the edit
editList=""; // reset edit list
precede="";
cout << "Going to issue this edit command\n" << edit<< endl;
proto->factory( edit.c_str() );
RooAbsPdf* newOne = proto->pdf(lastPdf.c_str());
if(!newOne)
cout << "\n\n ---------------------\n WARNING: failed to make EDIT\n\n" << endl;
}
}
// add uniform terms and their constraints
for(it=uniformSyst.begin(); it!=uniformSyst.end(); ++it) {
cout << "edit for " << it->first << "with rel uncert = " << it->second << endl;
if(! proto->var(("alpha_"+it->first).c_str())){
cout << "systematic not there" << endl;
nskipped++;
continue;
}
numReplacements++;
// this is the Uniform PDF
proto->factory(Form("beta_%s[1,0,10]",it->first.c_str()));
proto->factory(Form("Uniform::beta_%sConstraint(beta_%s)",it->first.c_str(),it->first.c_str()));
proto->factory(Form("PolyVar::alphaOfBeta_%s(beta_%s,{-1,1})",it->first.c_str(),it->first.c_str()));
// set beta const status to be same as alpha
if(proto->var(Form("alpha_%s",it->first.c_str()))->isConstant())
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(true);
else
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(false);
// set alpha const status to true
// proto->var(Form("alpha_%s",it->first.c_str()))->setConstant(true);
// replace alphas with alphaOfBeta and replace constraints
cout << "alpha_"+it->first+"Constraint=beta_" + it->first+ "Constraint" << endl;
editList+=precede + "alpha_"+it->first+"Constraint=beta_" + it->first+ "Constraint";
precede=",";
cout << "alpha_"+it->first+"=alphaOfBeta_"+ it->first << endl;
editList+=precede + "alpha_"+it->first+"=alphaOfBeta_"+ it->first;
if( proto->pdf(("alpha_"+it->first+"Constraint").c_str()) && proto->var(("alpha_"+it->first).c_str()) )
cout << " checked they are there" << proto->pdf(("alpha_"+it->first+"Constraint").c_str()) << " " << proto->var(("alpha_"+it->first).c_str()) << endl;
else
cout << "NOT THERE" << endl;
// EDIT seems to die if the list of edits is too long. So chunck them up.
if(numReplacements%10 == 0 && numReplacements+nskipped!=gammaSyst.size()){
edit="EDIT::"+lastPdf+"_("+lastPdf+","+editList+")";
lastPdf+="_"; // append an underscore for the edit
editList=""; // reset edit list
precede="";
cout << edit<< endl;
proto->factory( edit.c_str() );
RooAbsPdf* newOne = proto->pdf(lastPdf.c_str());
if(!newOne)
cout << "\n\n ---------------------\n WARNING: failed to make EDIT\n\n" << endl;
}
}
/////////////////////////////////////////
////////////////////////////////////
// add lognormal terms and their constraints
for(it=logNormSyst.begin(); it!=logNormSyst.end(); ++it) {
cout << "edit for " << it->first << "with rel uncert = " << it->second << endl;
if(! proto->var(("alpha_"+it->first).c_str())){
cout << "systematic not there" << endl;
nskipped++;
continue;
}
numReplacements++;
double relativeUncertainty = it->second;
double kappa = 1+relativeUncertainty;
// when transforming beta -> alpha, need alpha=1 to be +1sigma value.
// the P(beta>kappa*\hat(beta)) = 16%
// and \hat(beta) is 1, thus
double scale = relativeUncertainty;
//double scale = kappa;
// this is the LogNormal
proto->factory(Form("beta_%s[1,0,10]",it->first.c_str()));
proto->factory(Form("kappa_%s[%f]",it->first.c_str(),kappa));
proto->factory(Form("Lognormal::beta_%sConstraint(beta_%s,one[1],kappa_%s)",
it->first.c_str(),
it->first.c_str(),
it->first.c_str())) ;
proto->factory(Form("PolyVar::alphaOfBeta_%s(beta_%s,{%f,%f})",it->first.c_str(),it->first.c_str(),-1./scale,1./scale));
// proto->factory(Form("PolyVar::alphaOfBeta_%s(beta_%s,{%f,%f})",it->first.c_str(),it->first.c_str(),-1.,1./scale));
// set beta const status to be same as alpha
if(proto->var(Form("alpha_%s",it->first.c_str()))->isConstant())
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(true);
else
proto->var(Form("beta_%s",it->first.c_str()))->setConstant(false);
// set alpha const status to true
// proto->var(Form("alpha_%s",it->first.c_str()))->setConstant(true);
// replace alphas with alphaOfBeta and replace constraints
cout << "alpha_"+it->first+"Constraint=beta_" + it->first+ "Constraint" << endl;
editList+=precede + "alpha_"+it->first+"Constraint=beta_" + it->first+ "Constraint";
precede=",";
cout << "alpha_"+it->first+"=alphaOfBeta_"+ it->first << endl;
editList+=precede + "alpha_"+it->first+"=alphaOfBeta_"+ it->first;
if( proto->pdf(("alpha_"+it->first+"Constraint").c_str()) && proto->var(("alpha_"+it->first).c_str()) )
cout << " checked they are there" << proto->pdf(("alpha_"+it->first+"Constraint").c_str()) << " " << proto->var(("alpha_"+it->first).c_str()) << endl;
else
cout << "NOT THERE" << endl;
// EDIT seems to die if the list of edits is too long. So chunck them up.
if(numReplacements%10 == 0 && numReplacements+nskipped!=gammaSyst.size()){
edit="EDIT::"+lastPdf+"_("+lastPdf+","+editList+")";
lastPdf+="_"; // append an underscore for the edit
editList=""; // reset edit list
precede="";
cout << edit<< endl;
proto->factory( edit.c_str() );
RooAbsPdf* newOne = proto->pdf(lastPdf.c_str());
if(!newOne)
cout << "\n\n ---------------------\n WARNING: failed to make EDIT\n\n" << endl;
}
}
/////////////////////////////////////////
// MB: remove a systematic constraint
for(it=noSyst.begin(); it!=noSyst.end(); ++it) {
cout << "remove constraint for parameter" << it->first << endl;
if(! proto->var(("alpha_"+it->first).c_str()) || ! proto->pdf(("alpha_"+it->first+"Constraint").c_str()) ) {
cout << "systematic not there" << endl;
nskipped++;
continue;
}
numReplacements++;
// dummy replacement pdf
if ( !proto->var("one") ) { proto->factory("one[1.0]"); }
proto->var("one")->setConstant();
// replace constraints
cout << "alpha_"+it->first+"Constraint=one" << endl;
editList+=precede + "alpha_"+it->first+"Constraint=one";
precede=",";
// EDIT seems to die if the list of edits is too long. So chunck them up.
if(numReplacements%10 == 0 && numReplacements+nskipped!=gammaSyst.size()){
edit="EDIT::"+lastPdf+"_("+lastPdf+","+editList+")";
lastPdf+="_"; // append an underscore for the edit
editList=""; // reset edit list
precede="";
cout << edit << endl;
proto->factory( edit.c_str() );
RooAbsPdf* newOne = proto->pdf(lastPdf.c_str());
if(!newOne) { cout << "\n\n ---------------------\n WARNING: failed to make EDIT\n\n" << endl; }
}
}
/////////////////////////////////////////
// commit last bunch of edits
edit="EDIT::newSimPdf("+lastPdf+","+editList+")";
cout << edit<< endl;
proto->factory( edit.c_str() );
// proto->writeToFile(("results/model_"+fRowTitle+"_edited.root").c_str());
RooAbsPdf* newOne = proto->pdf("newSimPdf");
if(newOne){
// newOne->graphVizTree(("results/"+pdfName+"_"+fRowTitle+"newSimPdf.dot").c_str());
combined_config->SetPdf(*newOne);
}
else{
cout << "\n\n ---------------------\n WARNING: failed to make EDIT\n\n" << endl;
}
}
void HistoToWorkspaceFactoryFast::PrintCovarianceMatrix(RooFitResult* result, RooArgSet* params, string filename){
// Change-> Now a static utility
FILE* covFile = fopen ((filename).c_str(),"w");
TIter iti = params->createIterator();
TIter itj = params->createIterator();
RooRealVar *myargi, *myargj;
fprintf(covFile," ") ;
while ((myargi = (RooRealVar *)iti.Next())) {
if(myargi->isConstant()) continue;
fprintf(covFile," & %s", myargi->GetName());
}
fprintf(covFile,"\\\\ \\hline \n" );
iti.Reset();
while ((myargi = (RooRealVar *)iti.Next())) {
if(myargi->isConstant()) continue;
fprintf(covFile,"%s", myargi->GetName());
itj.Reset();
while ((myargj = (RooRealVar *)itj.Next())) {
if(myargj->isConstant()) continue;
cout << myargi->GetName() << "," << myargj->GetName();
fprintf(covFile, " & %.2f", result->correlation(*myargi, *myargj));
}
cout << endl;
fprintf(covFile, " \\\\\n");
}
fclose(covFile);
}
///////////////////////////////////////////////
RooWorkspace* HistoToWorkspaceFactoryFast::MakeSingleChannelWorkspace(Measurement& measurement, Channel& channel) {
// Set these by hand inside the function
vector systToFix = measurement.GetConstantParams();
bool doRatio=false;
// to time the macro
TStopwatch t;
t.Start();
//ES// string channel_name=summary[0].channel;
string channel_name = channel.GetName();
/// MB: reset observable names for each new channel.
fObsNameVec.clear();
/// MB: label observables x,y,z, depending on histogram dimensionality
/// GHL: Give it the first sample's nominal histogram as a template
/// since the data histogram may not be present
TH1* channel_hist_template = channel.GetSamples().at(0).GetHisto();
if (fObsNameVec.empty()) { GuessObsNameVec(channel_hist_template); }
for ( unsigned int idx=0; idx=1 && fObsNameVec.size()<=3 );
cout << "\n\n-------------------\nStarting to process " << channel_name << " channel with " << fObsNameVec.size() << " observables" << endl;
//
// our main workspace that we are using to construct the model
//
RooWorkspace* proto = new RooWorkspace(channel_name.c_str(), (channel_name+" workspace").c_str());
ModelConfig * proto_config = new ModelConfig("ModelConfig", proto);
proto_config->SetWorkspace(*proto);
// preprocess functions
vector::iterator funcIter = fPreprocessFunctions.begin();
for(;funcIter!= fPreprocessFunctions.end(); ++funcIter){
cout <<"will preprocess this line: " << *funcIter <factory(funcIter->c_str());
proto->Print();
}
RooArgSet likelihoodTerms("likelihoodTerms"), constraintTerms("constraintTerms");
vector likelihoodTermNames, constraintTermNames, totSystTermNames, syst_x_expectedPrefixNames, normalizationNames;
vector< pair > statNamePairs;
vector< pair > statHistPairs; //
std::string statFuncName; // the name of the ParamHistFunc
std::string statNodeName; // the name of the McStat Node
// Constraint::Type statConstraintType=Constraint::Gaussian;
// Double_t statRelErrorThreshold=0.0;
string prefix, range;
/////////////////////////////
// shared parameters
// this is ratio of lumi to nominal lumi. We will include relative uncertainty in model
std::stringstream lumiStr;
// lumi range
lumiStr<<"["<factory(("Lumi"+lumiStr.str()).c_str());
cout << "lumi str = " << lumiStr.str() << endl;
std::stringstream lumiErrorStr;
lumiErrorStr << "nominalLumi["<factory(("Gaussian::lumiConstraint(Lumi,"+lumiErrorStr.str()+")").c_str());
proto->var("nominalLumi")->setConstant();
proto->defineSet("globalObservables","nominalLumi");
//likelihoodTermNames.push_back("lumiConstraint");
constraintTermNames.push_back("lumiConstraint");
cout << "lumi Error str = " << lumiErrorStr.str() << endl;
//proto->factory((string("SigXsecOverSM[1.,0.5,1..8]").c_str()));
///////////////////////////////////
// loop through estimates, add expectation, floating bin predictions,
// and terms that constrain floating to expectation via uncertainties
// GHL: Loop over samples instead, which doesn't contain the data
vector::iterator it = channel.GetSamples().begin();
for(; it!=channel.GetSamples().end(); ++it) {
//ES// string overallSystName = it->name+"_"+it->channel+"_epsilon";
Sample& sample = (*it);
string overallSystName = sample.GetName() + "_" + channel_name + "_epsilon";
string systSourcePrefix = "alpha_";
// constraintTermNames and totSystTermNames are vectors that are passed
// by reference and filled by this method
AddEfficiencyTerms(proto,systSourcePrefix, overallSystName,
sample.GetOverallSysList(), constraintTermNames , totSystTermNames);
// GHL: Consider passing the NormFactor list instead of the entire sample
overallSystName = AddNormFactor(proto, channel_name, overallSystName, sample, doRatio);
// Create the string for the object
// that is added to the RooRealSumPdf
// for this channel
string syst_x_expectedPrefix = "";
// get histogram
//ES// TH1* nominal = it->nominal;
TH1* nominal = sample.GetHisto();
// MB : HACK no option to have both non-hist variations and hist variations ?
// get histogram
// GHL: Okay, this is going to be non-trivial.
// We will loop over histosys's, which contain both
// the low hist and the high hist together.
// Logic:
// - If we have no HistoSys's, do part A
// - else, if the histo syst's don't match, return (we ignore this case)
// - finally, we take the syst's and apply the linear interpolation w/ constraint
if(sample.GetHistoSysList().size() == 0) {
// If no HistoSys
cout << sample.GetName() + "_" + channel_name + " has no variation histograms " << endl;
string expPrefix = sample.GetName() + "_" + channel_name; //+"_expN";
syst_x_expectedPrefix = sample.GetName() + "_" + channel_name + "_overallSyst_x_Exp";
ProcessExpectedHisto(sample.GetHisto(), proto, expPrefix, syst_x_expectedPrefix,
overallSystName);
}
else {
// If there ARE HistoSys(s)
// name of source for variation
string constraintPrefix = sample.GetName() + "_" + channel_name + "_Hist_alpha";
syst_x_expectedPrefix = sample.GetName() + "_" + channel_name + "_overallSyst_x_HistSyst";
// constraintTermNames are passed by reference and appended to,
// overallSystName is a std::string for this sample
LinInterpWithConstraint(proto, nominal, sample.GetHistoSysList(),
constraintPrefix, syst_x_expectedPrefix, overallSystName,
constraintTermNames);
}
////////////////////////////////////
// Add StatErrors to this Channel //
////////////////////////////////////
if( sample.GetStatError().GetActivate() ) {
if( fObsNameVec.size() > 3 ) {
std::cout << "Cannot include Stat Error for histograms of more than 3 dimensions."
<< std::endl;
throw hf_exc();
} else {
// If we are using StatUncertainties, we multiply this object
// by the ParamHistFunc and then pass that to the
// RooRealSumPdf by appending it's name to the list
std::cout << "Sample: " << sample.GetName() << " to be included in Stat Error "
<< "for channel " << channel_name
<< std::endl;
/*
Constraint::Type type = channel.GetStatErrorConfig().GetConstraintType();
statConstraintType = Constraint::Gaussian;
if( type == Constraint::Gaussian) {
std::cout << "Using Gaussian StatErrors" << std::endl;
statConstraintType = Constraint::Gaussian;
}
if( type == Constraint::Poisson ) {
std::cout << "Using Poisson StatErrors" << std::endl;
statConstraintType = Constraint::Poisson;
}
*/
//statRelErrorThreshold = channel.GetStatErrorConfig().GetRelErrorThreshold();
// First, get the uncertainty histogram
// and push it back to our vectors
//if( sample.GetStatError().GetErrorHist() ) {
//statErrorHist = (TH1*) sample.GetStatError().GetErrorHist()->Clone();
//}
//if( statErrorHist == NULL ) {
// We need to get the *ABSOLUTE* uncertainty for use in Stat Uncertainties
// This can be done in one of two ways:
// - Use the built-in Errors in the TH1 itself (they are aboslute)
// - Take the supplied *RELATIVE* error and multiply by the nominal
string UncertName = syst_x_expectedPrefix + "_StatAbsolUncert";
TH1* statErrorHist = NULL;
if( sample.GetStatError().GetErrorHist() == NULL ) {
// Make the absolute stat error
std::cout << "Making Statistical Uncertainty Hist for "
<< " Channel: " << channel_name
<< " Sample: " << sample.GetName()
<< std::endl;
statErrorHist = MakeAbsolUncertaintyHist( UncertName, nominal );
} else {
statErrorHist = (TH1*) sample.GetStatError().GetErrorHist()->Clone();
// We assume the (relative) error is provided.
// We must turn it into an absolute error
// using the nominal histogram
std::cout << "Using external histogram for Stat Errors for "
<< " Channel: " << channel_name
<< " Sample: " << sample.GetName()
<< std::endl;
std::cout << "Error Histogram: " << statErrorHist->GetName() << std::endl;
// Multiply the relative stat uncertainty by the
// nominal to get the overall stat uncertainty
statErrorHist->Multiply( nominal );
statErrorHist->SetName( UncertName.c_str() );
}
// Save the nominal and error hists
// for the building of constraint terms
statHistPairs.push_back( pair(nominal, statErrorHist) );
// To do the 'conservative' version, we would need to do some
// intervention here. We would probably need to create a different
// ParamHistFunc for each sample in the channel. The would nominally
// use the same gamma's, so we haven't increased the number of parameters
// However, if a bin in the 'nominal' histogram is 0, we simply need to
// change the parameter in that bin in the ParamHistFunc for this sample.
// We also need to add a constraint term.
// Actually, we'd probably not use the ParamHistFunc...?
// we could remove the dependence in this ParamHistFunc on the ith gamma
// and then create the poisson term: Pois(tau | n_exp)Pois(data | n_exp)
// Next, try to get the ParamHistFunc (it may have been
// created by another sample in this channel)
// or create it if it doesn't yet exist:
statFuncName = "mc_stat_" + channel_name;
ParamHistFunc* paramHist = (ParamHistFunc*) proto->function( statFuncName.c_str() );
if( paramHist == NULL ) {
// Get a RooArgSet of the observables:
// Names in the list fObsNameVec:
RooArgList observables;
std::vector::iterator itr = fObsNameVec.begin();
for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
observables.add( *proto->var(itr->c_str()) );
}
// Create the list of terms to
// control the bin heights:
std::string ParamSetPrefix = "gamma_stat_" + channel_name;
Double_t gammaMin = 0.0;
Double_t gammaMax = 10.0;
RooArgList statFactorParams = ParamHistFunc::createParamSet(*proto,
ParamSetPrefix.c_str(),
observables,
gammaMin, gammaMax);
ParamHistFunc statUncertFunc(statFuncName.c_str(), statFuncName.c_str(),
observables, statFactorParams );
proto->import( statUncertFunc, RecycleConflictNodes() );
paramHist = (ParamHistFunc*) proto->function( statFuncName.c_str() );
} // END: If Statement: Create ParamHistFunc
// Create the node as a product
// of this function and the
// expected value from MC
statNodeName = sample.GetName() + "_" + channel_name + "_overallSyst_x_StatUncert";
RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() );
RooProduct nodeWithMcStat(statNodeName.c_str(), statNodeName.c_str(),
RooArgSet(*paramHist, *expFunc) );
proto->import( nodeWithMcStat, RecycleConflictNodes() );
// Push back the final name of the node
// to be used in the RooRealSumPdf
// (node to be created later)
syst_x_expectedPrefix = nodeWithMcStat.GetName();
}
} // END: if DoMcStat
///////////////////////////////////////////
// Create a ShapeFactor for this channel //
///////////////////////////////////////////
if( sample.GetShapeFactorList().size() > 0 ) {
if( fObsNameVec.size() > 3 ) {
std::cout << "Cannot include Stat Error for histograms of more than 3 dimensions."
<< std::endl;
throw hf_exc();
} else {
std::cout << "Sample: " << sample.GetName() << " in channel: " << channel_name
<< " to be include a ShapeFactor."
<< std::endl;
std::vector paramHistFuncList;
std::vector shapeFactorNameList;
for(unsigned int i=0; i < sample.GetShapeFactorList().size(); ++i) {
ShapeFactor& shapeFactor = sample.GetShapeFactorList().at(i);
std::string funcName = channel_name + "_" + shapeFactor.GetName() + "_shapeFactor";
ParamHistFunc* paramHist = (ParamHistFunc*) proto->function( funcName.c_str() );
if( paramHist == NULL ) {
RooArgList observables;
std::vector::iterator itr = fObsNameVec.begin();
for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
observables.add( *proto->var(itr->c_str()) );
}
// Create the Parameters
std::string funcParams = "gamma_" + shapeFactor.GetName();
// GHL: Again, we are putting hard ranges on the gamma's
// We should change this to range from 0 to /inf
RooArgList shapeFactorParams = ParamHistFunc::createParamSet(*proto,
funcParams.c_str(),
observables, 0, 1000);
// Create the Function
ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
observables, shapeFactorParams );
// Set an initial shape, if requested
if( shapeFactor.GetInitialShape() != NULL ) {
TH1* initialShape = shapeFactor.GetInitialShape();
std::cout << "Setting Shape Factor: " << shapeFactor.GetName()
<< " to have initial shape from hist: "
<< initialShape->GetName()
<< std::endl;
shapeFactorFunc.setShape( initialShape );
}
// Set the variables constant, if requested
if( shapeFactor.IsConstant() ) {
std::cout << "Setting Shape Factor: " << shapeFactor.GetName()
<< " to be constant" << std::endl;
shapeFactorFunc.setConstant(true);
}
proto->import( shapeFactorFunc, RecycleConflictNodes() );
paramHist = (ParamHistFunc*) proto->function( funcName.c_str() );
} // End: Create ShapeFactor ParamHistFunc
paramHistFuncList.push_back(paramHist);
shapeFactorNameList.push_back(funcName);
} // End loop over ShapeFactor Systematics
// Now that we have the right ShapeFactor,
// we multiply the expected function
//std::string shapeFactorNodeName = syst_x_expectedPrefix + "_x_" + funcName;
// Dynamically build the name as a long product
std::string shapeFactorNodeName = syst_x_expectedPrefix;
for( unsigned int i=0; i < shapeFactorNameList.size(); ++i) {
shapeFactorNodeName += "_x_" + shapeFactorNameList.at(i);
}
RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() );
RooArgSet nodesForProduct(*expFunc);
for( unsigned int i=0; i < paramHistFuncList.size(); ++i) {
nodesForProduct.add( *paramHistFuncList.at(i) );
}
//RooProduct nodeWithShapeFactor(shapeFactorNodeName.c_str(),
// shapeFactorNodeName.c_str(),
//RooArgSet(*paramHist, *expFunc) );
RooProduct nodeWithShapeFactor(shapeFactorNodeName.c_str(),
shapeFactorNodeName.c_str(),
nodesForProduct );
proto->import( nodeWithShapeFactor, RecycleConflictNodes() );
// Push back the final name of the node
// to be used in the RooRealSumPdf
// (node to be created later)
syst_x_expectedPrefix = nodeWithShapeFactor.GetName();
}
} // End: if ShapeFactorName!=""
////////////////////////////////////////
// Create a ShapeSys for this channel //
////////////////////////////////////////
if( sample.GetShapeSysList().size() != 0 ) {
if( fObsNameVec.size() > 3 ) {
std::cout << "Cannot include Stat Error for histograms of more than 3 dimensions."
<< std::endl;
throw hf_exc();
} else {
// List of ShapeSys ParamHistFuncs
std::vector ShapeSysNames;
for( unsigned int i = 0; i < sample.GetShapeSysList().size(); ++i) {
// Create the ParamHistFunc's
// Create their constraint terms and add them
// to the list of constraint terms
// Create a single RooProduct over all of these
// paramHistFunc's
// Send the name of that product to the RooRealSumPdf
RooStats::HistFactory::ShapeSys& shapeSys = sample.GetShapeSysList().at(i);
std::cout << "Sample: " << sample.GetName() << " in channel: " << channel_name
<< " to include a ShapeSys." << std::endl;
std::string funcName = channel_name + "_" + shapeSys.GetName() + "_ShapeSys";
ShapeSysNames.push_back( funcName );
ParamHistFunc* paramHist = (ParamHistFunc*) proto->function( funcName.c_str() );
if( paramHist == NULL ) {
//std::string funcParams = "gamma_" + it->shapeFactorName;
//paramHist = CreateParamHistFunc( proto, fObsNameVec, funcParams, funcName );
RooArgList observables;
std::vector::iterator itr = fObsNameVec.begin();
for(; itr!=fObsNameVec.end(); ++itr ) {
observables.add( *proto->var(itr->c_str()) );
}
// Create the Parameters
std::string funcParams = "gamma_" + shapeSys.GetName();
RooArgList shapeFactorParams = ParamHistFunc::createParamSet(*proto,
funcParams.c_str(),
observables, 0, 10);
// Create the Function
ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
observables, shapeFactorParams );
proto->import( shapeFactorFunc, RecycleConflictNodes() );
paramHist = (ParamHistFunc*) proto->function( funcName.c_str() );
} // End: Create ShapeFactor ParamHistFunc
// Create the constraint terms and add
// them to the workspace (proto)
// as well as the list of constraint terms (constraintTermNames)
// The syst should be a fractional error
TH1* shapeErrorHist = shapeSys.GetErrorHist();
// Constraint::Type shapeConstraintType = Constraint::Gaussian;
Constraint::Type systype = shapeSys.GetConstraintType();
if( systype == Constraint::Gaussian) {
systype = Constraint::Gaussian;
}
if( systype == Constraint::Poisson ) {
systype = Constraint::Poisson;
}
Double_t minShapeUncertainty = 0.0;
RooArgList shapeConstraints = createStatConstraintTerms(proto, constraintTermNames,
*paramHist, shapeErrorHist,
systype,
minShapeUncertainty);
} // End: Loop over ShapeSys vector in this EstimateSummary
// Now that we have the list of ShapeSys ParamHistFunc names,
// we create the total RooProduct
// we multiply the expected functio
std::string NodeName = syst_x_expectedPrefix;
RooArgList ShapeSysForNode;
RooAbsReal* expFunc = (RooAbsReal*) proto->function( syst_x_expectedPrefix.c_str() );
ShapeSysForNode.add( *expFunc );
for( unsigned int i = 0; i < ShapeSysNames.size(); ++i ) {
std::string ShapeSysName = ShapeSysNames.at(i);
ShapeSysForNode.add( *proto->function(ShapeSysName.c_str()) );
NodeName = NodeName + "_x_" + ShapeSysName;
}
// Create the name for this NEW Node
RooProduct nodeWithShapeFactor(NodeName.c_str(), NodeName.c_str(), ShapeSysForNode );
proto->import( nodeWithShapeFactor, RecycleConflictNodes() );
// Push back the final name of the node
// to be used in the RooRealSumPdf
// (node to be created later)
syst_x_expectedPrefix = nodeWithShapeFactor.GetName();
} // End: NumObsVar == 1
} // End: GetShapeSysList.size() != 0
// Append the name of the "node"
// that is to be summed with the
// RooRealSumPdf
syst_x_expectedPrefixNames.push_back(syst_x_expectedPrefix);
// GHL: This was pretty confusing before,
// hopefully using the measurement directly
// will improve it
if( sample.GetNormalizeByTheory() ) {
normalizationNames.push_back( "Lumi" );
}
else {
TString lumiParamString;
lumiParamString += measurement.GetLumi();
lumiParamString.ReplaceAll(' ', TString());
normalizationNames.push_back(lumiParamString.Data());
}
} // END: Loop over EstimateSummaries
// proto->Print();
// If a non-zero number of samples call for
// Stat Uncertainties, create the statFactor functions
if( statHistPairs.size() > 0 ) {
// Create the histogram of (binwise)
// stat uncertainties:
TH1* fracStatError = MakeScaledUncertaintyHist( statNodeName + "_RelErr", statHistPairs );
if( fracStatError == NULL ) {
std::cout << "Error: Failed to make ScaledUncertaintyHist for: "
<< statNodeName << std::endl;
throw hf_exc();
}
// Using this TH1* of fractinal stat errors,
// create a set of constraint terms:
ParamHistFunc* chanStatUncertFunc = (ParamHistFunc*) proto->function( statFuncName.c_str() );
std::cout << "About to create Constraint Terms from: "
<< chanStatUncertFunc->GetName()
<< " params: " << chanStatUncertFunc->paramList()
<< std::endl;
// Get the constraint type and the
// rel error threshold from the (last)
// EstimateSummary looped over (but all
// should be the same)
// Get the type of StatError constraint from the channel
Constraint::Type statConstraintType = channel.GetStatErrorConfig().GetConstraintType();
if( statConstraintType == Constraint::Gaussian) {
std::cout << "Using Gaussian StatErrors in channel: " << channel.GetName() << std::endl;
}
if( statConstraintType == Constraint::Poisson ) {
std::cout << "Using Poisson StatErrors in channel: " << channel.GetName() << std::endl;
}
double statRelErrorThreshold = channel.GetStatErrorConfig().GetRelErrorThreshold();
RooArgList statConstraints = createStatConstraintTerms(proto, constraintTermNames,
*chanStatUncertFunc, fracStatError,
statConstraintType,
statRelErrorThreshold);
} // END: Loop over stat Hist Pairs
///////////////////////////////////
// for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
//MakeTotalExpected(proto,channel_name+"_model",channel_name,"Lumi",fLowBin,fHighBin,
// syst_x_expectedPrefixNames, normalizationNames);
MakeTotalExpected(proto, channel_name+"_model", //channel_name,"Lumi",fLowBin,fHighBin,
syst_x_expectedPrefixNames, normalizationNames);
likelihoodTermNames.push_back(channel_name+"_model");
//////////////////////////////////////
// fix specified parameters
for(unsigned int i=0; ivar((systToFix.at(i)).c_str());
if(temp) {
// set the parameter constant
temp->setConstant();
// remove the corresponding auxiliary observable from the global observables
RooRealVar* auxMeas = NULL;
if(systToFix.at(i)=="Lumi"){
auxMeas = proto->var("nominalLumi");
} else {
auxMeas = proto->var(Form("nom_%s",temp->GetName()));
}
if(auxMeas){
const_cast(proto->set("globalObservables"))->remove(*auxMeas);
} else{
cout << "could not corresponding auxiliary measurement "
<< Form("nom_%s",temp->GetName()) << endl;
}
} else {
cout << "could not find variable " << systToFix.at(i)
<< " could not set it to constant" << endl;
}
}
//////////////////////////////////////
// final proto model
for(unsigned int i=0; iarg(constraintTermNames[i].c_str()));
if( proto_arg==NULL ) {
std::cout << "Error: Cannot find arg set: " << constraintTermNames.at(i)
<< " in workspace: " << proto->GetName() << std::endl;
throw hf_exc();
}
constraintTerms.add( *proto_arg );
// constraintTerms.add(* proto_arg(proto->arg(constraintTermNames[i].c_str())) );
}
for(unsigned int i=0; iarg(likelihoodTermNames[i].c_str()));
if( proto_arg==NULL ) {
std::cout << "Error: Cannot find arg set: " << constraintTermNames.at(i)
<< " in workspace: " << proto->GetName() << std::endl;
throw hf_exc();
}
likelihoodTerms.add( *proto_arg );
}
proto->defineSet("constraintTerms",constraintTerms);
proto->defineSet("likelihoodTerms",likelihoodTerms);
// proto->Print();
// list of observables
RooArgList observables;
std::string observablesStr;
std::vector::iterator itr = fObsNameVec.begin();
for(; itr!=fObsNameVec.end(); ++itr ) {
observables.add( *proto->var(itr->c_str()) );
if (!observablesStr.empty()) { observablesStr += ","; }
observablesStr += *itr;
}
// We create two sets, one for backwards compatability
// The other to make a consistent naming convention
// between individual channels and the combined workspace
proto->defineSet("observables", Form("%s",observablesStr.c_str()));
proto->defineSet("observablesSet", Form("%s",observablesStr.c_str()));
// Create the ParamHistFunc
// after observables have been made
cout <<"-----------------------------------------"<import(*model,RecycleConflictNodes());
proto_config->SetPdf(*model);
proto_config->SetObservables(observables);
proto_config->SetGlobalObservables(*proto->set("globalObservables"));
// proto->writeToFile(("results/model_"+channel+".root").c_str());
// fill out nuisance parameters in model config
// proto_config->GuessObsAndNuisance(*proto->data("asimovData"));
proto->import(*proto_config,proto_config->GetName());
proto->importClassCode();
///////////////////////////
// make data sets
// THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
const char* weightName="weightVar";
proto->factory(Form("%s[0,-1e10,1e10]",weightName));
proto->defineSet("obsAndWeight",Form("%s,%s",weightName,observablesStr.c_str()));
/* Old code for generating the asimov
Asimov generation is now done later...
RooAbsData* asimov_data = model->generateBinned(observables,ExpectedData());
/// Asimov dataset
RooDataSet* asimovDataUnbinned = new RooDataSet("asimovData","",*proto->set("obsAndWeight"),weightName);
for(int i=0; inumEntries(); ++i){
asimov_data->get(i)->Print("v");
//cout << "GREPME : " << i << " " << data->weight() <add( *asimov_data->get(i), asimov_data->weight() );
}
proto->import(*asimovDataUnbinned);
*/
// New Asimov Generation: Use the code in the Asymptotic calculator
// Need to get the ModelConfig...
RooDataSet* asimov_dataset = (RooDataSet*) AsymptoticCalculator::GenerateAsimovData(*model, observables);
proto->import(*asimov_dataset, Rename("asimovData"));
// GHL: Determine to use data if the hist isn't 'NULL'
if(channel.GetData().GetHisto() != NULL) {
Data& data = channel.GetData();
TH1* mnominal = data.GetHisto();
if( !mnominal ) {
std::cout << "Error: Data histogram for channel: " << channel.GetName()
<< " is NULL" << std::endl;
throw hf_exc();
}
// THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
RooDataSet* obsDataUnbinned = new RooDataSet("obsData","",*proto->set("obsAndWeight"),weightName);
ConfigureHistFactoryDataset( obsDataUnbinned, mnominal,
proto, fObsNameVec );
/*
//ES// TH1* mnominal = summary.at(0).nominal;
TH1* mnominal = data.GetHisto();
TAxis* ax = mnominal->GetXaxis();
TAxis* ay = mnominal->GetYaxis();
TAxis* az = mnominal->GetZaxis();
for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension
Double_t xval = ax->GetBinCenter(i);
proto->var( fObsNameVec[0].c_str() )->setVal( xval );
if (fObsNameVec.size()==1) {
Double_t fval = mnominal->GetBinContent(i);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 2 or more dimensions
for (int j=1; j<=ay->GetNbins(); ++j) {
Double_t yval = ay->GetBinCenter(j);
proto->var( fObsNameVec[1].c_str() )->setVal( yval );
if (fObsNameVec.size()==2) {
Double_t fval = mnominal->GetBinContent(i,j);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 3 dimensions
for (int k=1; k<=az->GetNbins(); ++k) {
Double_t zval = az->GetBinCenter(k);
proto->var( fObsNameVec[2].c_str() )->setVal( zval );
Double_t fval = mnominal->GetBinContent(i,j,k);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
}
}
}
}
}
*/
proto->import(*obsDataUnbinned);
} // End: Has non-null 'data' entry
for(unsigned int i=0; i < channel.GetAdditionalData().size(); ++i) {
Data& data = channel.GetAdditionalData().at(i);
std::string dataName = data.GetName();
TH1* mnominal = data.GetHisto();
if( !mnominal ) {
std::cout << "Error: Additional Data histogram for channel: " << channel.GetName()
<< " with name: " << dataName << " is NULL" << std::endl;
throw hf_exc();
}
// THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
RooDataSet* obsDataUnbinned = new RooDataSet(dataName.c_str(), dataName.c_str(),
*proto->set("obsAndWeight"), weightName);
ConfigureHistFactoryDataset( obsDataUnbinned, mnominal,
proto, fObsNameVec );
/*
//ES// TH1* mnominal = summary.at(0).nominal;
TH1* mnominal = data.GetHisto();
TAxis* ax = mnominal->GetXaxis();
TAxis* ay = mnominal->GetYaxis();
TAxis* az = mnominal->GetZaxis();
for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension
Double_t xval = ax->GetBinCenter(i);
proto->var( fObsNameVec[0].c_str() )->setVal( xval );
if (fObsNameVec.size()==1) {
Double_t fval = mnominal->GetBinContent(i);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 2 or more dimensions
for (int j=1; j<=ay->GetNbins(); ++j) {
Double_t yval = ay->GetBinCenter(j);
proto->var( fObsNameVec[1].c_str() )->setVal( yval );
if (fObsNameVec.size()==2) {
Double_t fval = mnominal->GetBinContent(i,j);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 3 dimensions
for (int k=1; k<=az->GetNbins(); ++k) {
Double_t zval = az->GetBinCenter(k);
proto->var( fObsNameVec[2].c_str() )->setVal( zval );
Double_t fval = mnominal->GetBinContent(i,j,k);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
}
}
}
}
}
*/
proto->import(*obsDataUnbinned);
} // End: Has non-null 'data' entry
proto->Print();
return proto;
}
void HistoToWorkspaceFactoryFast::ConfigureHistFactoryDataset( RooDataSet* obsDataUnbinned,
TH1* mnominal,
RooWorkspace* proto,
std::vector ObsNameVec) {
// Take a RooDataSet and fill it with the entries
// from a TH1*, using the observable names to
// determine the columns
//ES// TH1* mnominal = summary.at(0).nominal;
// TH1* mnominal = data.GetHisto();
TAxis* ax = mnominal->GetXaxis();
TAxis* ay = mnominal->GetYaxis();
TAxis* az = mnominal->GetZaxis();
for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension
Double_t xval = ax->GetBinCenter(i);
proto->var( ObsNameVec[0].c_str() )->setVal( xval );
if(ObsNameVec.size()==1) {
Double_t fval = mnominal->GetBinContent(i);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 2 or more dimensions
for(int j=1; j<=ay->GetNbins(); ++j) {
Double_t yval = ay->GetBinCenter(j);
proto->var( ObsNameVec[1].c_str() )->setVal( yval );
if(ObsNameVec.size()==2) {
Double_t fval = mnominal->GetBinContent(i,j);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
} else { // 3 dimensions
for(int k=1; k<=az->GetNbins(); ++k) {
Double_t zval = az->GetBinCenter(k);
proto->var( ObsNameVec[2].c_str() )->setVal( zval );
Double_t fval = mnominal->GetBinContent(i,j,k);
obsDataUnbinned->add( *proto->set("obsAndWeight"), fval );
}
}
}
}
}
}
void HistoToWorkspaceFactoryFast::GuessObsNameVec(TH1* hist)
{
fObsNameVec.clear();
// determine histogram dimensionality
unsigned int histndim(1);
std::string classname = hist->ClassName();
if (classname.find("TH1")==0) { histndim=1; }
else if (classname.find("TH2")==0) { histndim=2; }
else if (classname.find("TH3")==0) { histndim=3; }
for ( unsigned int idx=0; idx ch_names, vector chs)
{
//
/// These things were used for debugging. Maybe useful in the future
//
map pdfMap;
vector models;
stringstream ss;
RooArgList obsList;
for(unsigned int i = 0; i< ch_names.size(); ++i){
ModelConfig * config = (ModelConfig *) chs[i]->obj("ModelConfig");
obsList.add(*config->GetObservables());
}
cout <<"full list of observables:"<pdf(("model_"+channel_name).c_str());
if(!model) cout <<"failed to find model for channel"<createIntegral(*obsN)->getVal() << endl;;
models.push_back(model);
globalObs.add(*ch->set("globalObservables"));
// constrainedParams->add( * ch->set("constrainedParams") );
pdfMap[channel_name]=model;
}
//constrainedParams->Print();
cout << "\n\n------------------\n Entering combination" << endl;
RooWorkspace* combined = new RooWorkspace("combined");
// RooWorkspace* combined = chs[0];
RooCategory* channelCat = (RooCategory*) combined->factory(("channelCat["+ss.str()+"]").c_str());
RooSimultaneous * simPdf= new RooSimultaneous("simPdf","",pdfMap, *channelCat);
ModelConfig * combined_config = new ModelConfig("ModelConfig", combined);
combined_config->SetWorkspace(*combined);
// combined_config->SetNuisanceParameters(*constrainedParams);
combined->import(globalObs);
combined->defineSet("globalObservables",globalObs);
combined_config->SetGlobalObservables(*combined->set("globalObservables"));
////////////////////////////////////////////
// Make toy simultaneous dataset
cout <<"-----------------------------------------"<factory("weightVar[0,-1e10,1e10]");
obsList.add(*combined->var("weightVar"));
// Loop over channels and create the asimov
/*
for(unsigned int i = 0; i< ch_names.size(); ++i){
cout << "merging data for channel " << ch_names[i].c_str() << endl;
RooDataSet * tempData=new RooDataSet(ch_names[i].c_str(),"", obsList, Index(*channelCat),
WeightVar("weightVar"),
Import(ch_names[i].c_str(),*(RooDataSet*)chs[i]->data("asimovData")));
if(simData){
simData->append(*tempData);
delete tempData;
}else{
simData = tempData;
}
}
if (simData) combined->import(*simData,Rename("asimovData"));
*/
RooDataSet* asimov_combined = (RooDataSet*) AsymptoticCalculator::GenerateAsimovData(*simPdf,
obsList);
if( asimov_combined ) {
combined->import( *asimov_combined, Rename("asimovData"));
}
else {
std::cout << "Error: Failed to create combined asimov dataset" << std::endl;
throw hf_exc();
}
// Now merge the observable datasets across the channels
if(chs[0]->data("obsData") != NULL) {
MergeDataSets(combined, chs, ch_names, "obsData", obsList, channelCat);
}
/*
if(chs[0]->data("obsData") != NULL){
RooDataSet * simData=NULL;
//simData=NULL;
// Loop through channels, get their individual datasets,
// and add them to the combined dataset
for(unsigned int i = 0; i< ch_names.size(); ++i){
cout << "merging data for channel " << ch_names[i].c_str() << endl;
RooDataSet* obsDataInChannel = (RooDataSet*) chs[i]->data("obsData");
RooDataSet * tempData = new RooDataSet(ch_names[i].c_str(),"", obsList, Index(*channelCat),
WeightVar("weightVar"),
Import(ch_names[i].c_str(),*obsDataInChannel));
// *(RooDataSet*) chs[i]->data("obsData")));
if(simData) {
simData->append(*tempData);
delete tempData;
}
else {
simData = tempData;
}
} // End Loop Over Channels
// Check that we successfully created the dataset
// and import it into the workspace
if(simData) {
combined->import(*simData, Rename("obsData"));
}
else {
std::cout << "Error: Unable to merge observable datasets" << std::endl;
throw hf_exc();
}
} // End 'if' on data != NULL
*/
// Now, create any additional Asimov datasets that
// are configured in the measurement
// obsList.Print();
// combined->import(obsList);
// combined->Print();
obsList.add(*channelCat);
combined->defineSet("observables",obsList);
combined_config->SetObservables(*combined->set("observables"));
combined->Print();
cout << "\n\n----------------\n Importing combined model" << endl;
combined->import(*simPdf,RecycleConflictNodes());
//combined->import(*simPdf, RenameVariable("SigXsecOverSM","SigXsecOverSM_comb"));
// cout << "check pointer " << simPdf << endl;
// cout << "check val " << simPdf->getVal() << endl;
std::map< std::string, double>::iterator param_itr = fParamValues.begin();
for( ; param_itr != fParamValues.end(); ++param_itr ){
// make sure they are fixed
std::string paramName = param_itr->first;
double paramVal = param_itr->second;
RooRealVar* temp = combined->var( paramName.c_str() );
if(temp) {
temp->setVal( paramVal );
cout <<"setting " << paramName << " to the value: " << paramVal << endl;
} else
cout << "could not find variable " << paramName << " could not set its value" << endl;
}
for(unsigned int i=0; ivar((fSystToFix.at(i)).c_str());
if(temp) {
temp->setConstant();
cout <<"setting " << fSystToFix.at(i) << " constant" << endl;
} else
cout << "could not find variable " << fSystToFix.at(i) << " could not set it to constant" << endl;
}
///
/// writing out the model in graphViz
///
// RooAbsPdf* customized=combined->pdf("simPdf");
//combined_config->SetPdf(*customized);
combined_config->SetPdf(*simPdf);
// combined_config->GuessObsAndNuisance(*simData);
// customized->graphVizTree(("results/"+fResultsPrefixStr.str()+"_simul.dot").c_str());
combined->import(*combined_config,combined_config->GetName());
combined->importClassCode();
// combined->writeToFile("results/model_combined.root");
return combined;
}
RooDataSet* HistoToWorkspaceFactoryFast::MergeDataSets(RooWorkspace* combined,
std::vector wspace_vec,
std::vector channel_names,
std::string dataSetName,
RooArgList obsList,
RooCategory* channelCat) {
// Create the total dataset
RooDataSet* simData=NULL;
// Loop through channels, get their individual datasets,
// and add them to the combined dataset
for(unsigned int i = 0; i< channel_names.size(); ++i){
// Grab the dataset for the existing channel
std::cout << "Merging data for channel " << channel_names[i].c_str() << std::endl;
RooDataSet* obsDataInChannel = (RooDataSet*) wspace_vec[i]->data(dataSetName.c_str());
if( !obsDataInChannel ) {
std::cout << "Error: Can't find DataSet: " << dataSetName
<< " in channel: " << channel_names.at(i)
<< std::endl;
throw hf_exc();
}
// Create the new Dataset
RooDataSet * tempData = new RooDataSet(channel_names[i].c_str(),"",
obsList, Index(*channelCat),
WeightVar("weightVar"),
Import(channel_names[i].c_str(),*obsDataInChannel));
if(simData) {
simData->append(*tempData);
delete tempData;
}
else {
simData = tempData;
}
} // End Loop Over Channels
// Check that we successfully created the dataset
// and import it into the workspace
if(simData) {
combined->import(*simData, Rename(dataSetName.c_str()));
}
else {
std::cout << "Error: Unable to merge observable datasets" << std::endl;
throw hf_exc();
}
return simData;
}
TH1* HistoToWorkspaceFactoryFast::MakeAbsolUncertaintyHist( const std::string& Name, const TH1* Nominal ) {
// Take a nominal TH1* and create
// a TH1 representing the binwise
// errors (taken from the nominal TH1)
TH1* ErrorHist = (TH1*) Nominal->Clone( Name.c_str() );
ErrorHist->Reset();
Int_t numBins = Nominal->GetNbinsX()*Nominal->GetNbinsY()*Nominal->GetNbinsZ();
Int_t binNumber = 0;
// Loop over bins
for( Int_t i_bin = 0; i_bin < numBins; ++i_bin) {
binNumber++;
// Ignore underflow / overflow
while( Nominal->IsBinUnderflow(binNumber) || Nominal->IsBinOverflow(binNumber) ){
binNumber++;
}
Double_t histError = Nominal->GetBinError( binNumber );
// Check that histError != NAN
if( histError != histError ) {
std::cout << "Warning: In histogram " << Nominal->GetName()
<< " bin error for bin " << i_bin
<< " is NAN. Not using Error!!!"
<< std::endl;
throw hf_exc();
//histError = sqrt( histContent );
//histError = 0;
}
// Check that histError ! < 0
if( histError < 0 ) {
std::cout << "Warning: In histogram " << Nominal->GetName()
<< " bin error for bin " << binNumber
<< " is < 0. Setting Error to 0"
<< std::endl;
//histError = sqrt( histContent );
histError = 0;
}
ErrorHist->SetBinContent( binNumber, histError );
}
return ErrorHist;
}
TH1* HistoToWorkspaceFactoryFast::MakeScaledUncertaintyHist( const std::string& Name, std::vector< std::pair > HistVec ) {
// Take a list of < nominal, absolError > TH1* pairs
// and construct a single histogram representing the
// total fractional error as:
// UncertInQuad(bin i) = Sum: absolUncert*absolUncert
// Total(bin i) = Sum: Value
//
// TotalFracError(bin i) = Sqrt( UncertInQuad(i) ) / TotalBin(i)
unsigned int numHists = HistVec.size();
if( numHists == 0 ) {
std::cout << "Warning: Empty Hist Vector, cannot create total uncertainty" << std::endl;
return NULL;
}
TH1* HistTemplate = HistVec.at(0).first;
Int_t numBins = HistTemplate->GetNbinsX()*HistTemplate->GetNbinsY()*HistTemplate->GetNbinsZ();
// Check that all histograms
// have the same bins
for( unsigned int i = 0; i < HistVec.size(); ++i ) {
TH1* nominal = HistVec.at(i).first;
TH1* error = HistVec.at(i).second;
if( nominal->GetNbinsX()*nominal->GetNbinsY()*nominal->GetNbinsZ() != numBins ) {
std::cout << "Error: Provided hists have unequal bins" << std::endl;
return NULL;
}
if( error->GetNbinsX()*error->GetNbinsY()*error->GetNbinsZ() != numBins ) {
std::cout << "Error: Provided hists have unequal bins" << std::endl;
return NULL;
}
}
std::vector TotalBinContent( numBins, 0.0);
std::vector HistErrorsSqr( numBins, 0.0);
Int_t binNumber = 0;
// Loop over bins
for( Int_t i_bins = 0; i_bins < numBins; ++i_bins) {
binNumber++;
while( HistTemplate->IsBinUnderflow(binNumber) || HistTemplate->IsBinOverflow(binNumber) ){
binNumber++;
}
for( unsigned int i_hist = 0; i_hist < numHists; ++i_hist ) {
TH1* nominal = HistVec.at(i_hist).first;
TH1* error = HistVec.at(i_hist).second;
//Int_t binNumber = i_bins + 1;
Double_t histValue = nominal->GetBinContent( binNumber );
Double_t histError = error->GetBinContent( binNumber );
/*
std::cout << " Getting Bin content for Stat Uncertainty"
<< " Nom name: " << nominal->GetName()
<< " Err name: " << error->GetName()
<< " HistNumber: " << i_hist << " bin: " << binNumber
<< " Value: " << histValue << " Error: " << histError
<< std::endl;
*/
if( histError != histError ) {
std::cout << "Warning: In histogram " << error->GetName()
<< " bin error for bin " << binNumber
<< " is NAN. Not using error!!"
<< std::endl;
throw hf_exc();
//histError = 0;
}
TotalBinContent.at(i_bins) += histValue;
HistErrorsSqr.at(i_bins) += histError*histError; // Add in quadrature
}
}
binNumber = 0;
// Creat the output histogram
TH1* ErrorHist = (TH1*) HistTemplate->Clone( Name.c_str() );
ErrorHist->Reset();
// Fill the output histogram
for( Int_t i = 0; i < numBins; ++i) {
// Int_t binNumber = i + 1;
binNumber++;
while( ErrorHist->IsBinUnderflow(binNumber) || ErrorHist->IsBinOverflow(binNumber) ){
binNumber++;
}
Double_t ErrorsSqr = HistErrorsSqr.at(i);
Double_t TotalVal = TotalBinContent.at(i);
if( TotalVal <= 0 ) {
std::cout << "Warning: Sum of histograms for bin: " << binNumber
<< " is <= 0. Setting error to 0"
<< std::endl;
ErrorHist->SetBinContent( binNumber, 0.0 );
continue;
}
Double_t RelativeError = sqrt(ErrorsSqr) / TotalVal;
// If we otherwise get a NAN
// it's an error
if( RelativeError != RelativeError ) {
std::cout << "Error: bin " << i << " error is NAN" << std::endl;
std::cout << " HistErrorsSqr: " << ErrorsSqr
<< " TotalVal: " << TotalVal
<< std::endl;
throw hf_exc();
}
// 0th entry in vector is
// the 1st bin in TH1
// (we ignore underflow)
ErrorHist->SetBinContent( binNumber, RelativeError );
std::cout << "Making Total Uncertainty for bin " << binNumber
<< " Error = " << sqrt(ErrorsSqr)
<< " Val = " << TotalVal
<< " RelativeError = " << RelativeError
<< std::endl;
}
return ErrorHist;
}
RooArgList HistoToWorkspaceFactoryFast::
createStatConstraintTerms( RooWorkspace* proto, vector& constraintTermNames,
ParamHistFunc& paramHist, TH1* uncertHist,
Constraint::Type type, Double_t minSigma ) {
// Take a RooArgList of RooAbsReal's and
// create N constraint terms (one for
// each gamma) whose relative uncertainty
// is the value of the ith RooAbsReal
//
// The integer "type" controls the type
// of constraint term:
//
// type == 0 : NONE
// type == 1 : Gaussian
// type == 2 : Poisson
// type == 3 : LogNormal
RooArgList ConstraintTerms;
RooArgList paramSet = paramHist.paramList();
// Must get the full size of the TH1
// (No direct method to do this...)
Int_t numBins = uncertHist->GetNbinsX()*uncertHist->GetNbinsY()*uncertHist->GetNbinsZ();
Int_t numParams = paramSet.getSize();
// Int_t numBins = uncertHist->GetNbinsX()*uncertHist->GetNbinsY()*uncertHist->GetNbinsZ();
// Check that there are N elements
// in the RooArgList
if( numBins != numParams ) {
std::cout << "Error: In createStatConstraintTerms, encountered bad number of bins" << std::endl;
std::cout << "Given histogram with " << numBins << " bins,"
<< " but require exactly " << numParams << std::endl;
throw hf_exc();
}
Int_t TH1BinNumber = 0;
for( Int_t i = 0; i < paramSet.getSize(); ++i) {
TH1BinNumber++;
while( uncertHist->IsBinUnderflow(TH1BinNumber) || uncertHist->IsBinOverflow(TH1BinNumber) ){
TH1BinNumber++;
}
RooRealVar& gamma = (RooRealVar&) (paramSet[i]);
std::cout << "Creating constraint for: " << gamma.GetName()
<< ". Type of constraint: " << type << std::endl;
// Get the sigma from the hist
// (the relative uncertainty)
Double_t sigma = uncertHist->GetBinContent( TH1BinNumber );
// If the sigma is <= 0,
// do cont create the term
if( sigma <= 0 ){
std::cout << "Not creating constraint term for "
<< gamma.GetName()
<< " because sigma = " << sigma
<< " (sigma<=0)"
<< " (TH1 bin number = " << TH1BinNumber << ")"
<< std::endl;
gamma.setConstant(kTRUE);
continue;
}
// set reasonable ranges for gamma parameters
gamma.setMax( 1 + 5*sigma );
// gamma.setMin( TMath::Max(1. - 5*sigma, 0.) );
gamma.setMin( 0. );
// Make Constraint Term
std::string constrName = string(gamma.GetName()) + "_constraint";
std::string nomName = string("nom_") + gamma.GetName();
std::string sigmaName = string(gamma.GetName()) + "_sigma";
std::string poisMeanName = string(gamma.GetName()) + "_poisMean";
if( type == Constraint::Gaussian ) {
// Type 1 : RooGaussian
// Make sigma
RooConstVar constrSigma( sigmaName.c_str(), sigmaName.c_str(), sigma );
//proto->import( constrSigma, RecycleConflictNodes() );
//proto->import( constrSigma );
// Make "observed" value
RooRealVar constrNom(nomName.c_str(), nomName.c_str(), 1.0,0,10);
constrNom.setConstant( true );
// Make the constraint:
RooGaussian gauss( constrName.c_str(), constrName.c_str(),
constrNom, gamma, constrSigma );
proto->import( gauss, RecycleConflictNodes() );
//proto->import( gauss );
} else if( type == Constraint::Poisson ) {
Double_t tau = 1/sigma/sigma; // this is correct Poisson equivalent to a Gaussian with mean 1 and stdev sigma
// Make nominal "observed" value
RooRealVar constrNom(nomName.c_str(), nomName.c_str(), tau);
constrNom.setMin(0);
constrNom.setConstant( true );
// Make the scaling term
std::string scalingName = string(gamma.GetName()) + "_tau";
RooConstVar poissonScaling( scalingName.c_str(), scalingName.c_str(), tau);
// Make mean for scaled Poisson
RooProduct constrMean( poisMeanName.c_str(), poisMeanName.c_str(), RooArgSet(gamma, poissonScaling) );
//proto->import( constrSigma, RecycleConflictNodes() );
//proto->import( constrSigma );
// Type 2 : RooPoisson
RooPoisson pois(constrName.c_str(), constrName.c_str(), constrNom, constrMean);
pois.setNoRounding(true);
proto->import( pois, RecycleConflictNodes() );
} else {
std::cout << "Error: Did not recognize Stat Error constraint term type: "
<< type << " for : " << paramHist.GetName() << std::endl;
throw hf_exc();
}
// If the sigma value is less
// than a supplied threshold,
// set the variable to constant
if( sigma < minSigma ) {
std::cout << "Warning: Bin " << i << " = " << sigma
<< " and is < " << minSigma
<< ". Setting: " << gamma.GetName() << " to constant"
<< std::endl;
gamma.setConstant(kTRUE);
}
constraintTermNames.push_back( constrName );
ConstraintTerms.add( *proto->pdf(constrName.c_str()) );
// Add the "observed" value to the
// list of global observables:
RooArgSet* globalSet = const_cast(proto->set("globalObservables"));
RooRealVar* nomVarInWorkspace = proto->var(nomName.c_str());
if( ! globalSet->contains(*nomVarInWorkspace) ) {
globalSet->add( *nomVarInWorkspace );
}
} // end loop over parameters
return ConstraintTerms;
}
} // namespace RooStats
} // namespace HistFactory