79 std::vector<double> out(numBins);
81 for (
int i = 0; i < numBins; ++i) {
93using std::string, std::vector;
107 fSystToFix( measurement.GetConstantParams() ),
110 fLumiError( measurement.GetLumi()*measurement.GetLumiRelErr() ),
111 fLowBin( measurement.GetBinLow() ),
112 fHighBin( measurement.GetBinHigh() ),
128 if( proto_config ==
nullptr ) {
129 cxcoutFHF <<
"Error: Did not find 'ModelConfig' object in file: " << ws_single->
GetName() << std::endl;
134 cxcoutWHF <<
"No Parametetrs of interest are set" << std::endl;
138 std::stringstream sstream;
139 sstream <<
"Setting Parameter(s) of Interest as: ";
140 for(
auto const& item : measurement.
GetPOIList()) {
141 sstream << item <<
" ";
146 for(
auto const& poi_name : measurement.
GetPOIList()) {
151 cxcoutWHF <<
"WARNING: Can't find parameter of interest: " << poi_name
152 <<
" in Workspace. Not setting in ModelConfig." << std::endl;
159 std::string NewModelName =
"newSimPdf";
166 if( !pdf ) pdf = ws_single->
pdf( ModelName );
167 const RooArgSet* observables = ws_single->
set(
"observables");
178 std::string SnapShotName =
"NominalParamValues";
185 std::string AsimovName = asimov.
GetName();
187 cxcoutPHF <<
"Generating additional Asimov Dataset: " << AsimovName << std::endl;
191 cxcoutPHF <<
"Importing Asimov dataset" << std::endl;
194 cxcoutFHF <<
"Error: Failed to import Asimov dataset: " << AsimovName << std::endl;
221 string ch_name = channel.
GetName();
225 if( ws_single ==
nullptr ) {
226 cxcoutFHF <<
"Error: Failed to make Single-Channel workspace for channel: " << ch_name
227 <<
" and measurement: " << measurement.
GetName() << std::endl;
274 std::vector<std::unique_ptr<RooWorkspace>> channel_workspaces;
275 std::vector<std::string> channel_names;
279 if( ! channel.CheckHistograms() ) {
280 cxcoutFHF <<
"MakeModelAndMeasurementsFast: Channel: " << channel.GetName()
281 <<
" has uninitialized histogram pointers" << std::endl;
285 string ch_name = channel.GetName();
286 channel_names.push_back(ch_name);
295 std::unique_ptr<RooWorkspace> ws{histFactory.
MakeCombinedModel( channel_names, channel_workspaces )};
308template <
class Arg_t,
typename... Args_t>
311 Arg_t arg{
name.c_str(),
name.c_str(), std::forward<Args_t>(args)...};
313 return *
dynamic_cast<Arg_t *
>(ws.
arg(
name));
332std::pair<bool, std::string> isChannelDataConsistent(std::vector<std::unique_ptr<RooWorkspace>>
const &chs,
333 std::vector<std::string>
const &ch_names,
334 std::set<std::string>
const &allowedInconsistent)
337 std::set<std::string> referenceDataNames;
339 referenceDataNames.insert(data->GetName());
343 for (std::size_t i = 1; i < chs.size(); ++i) {
344 std::set<std::string> thisDataNames;
345 for (RooAbsData *data : chs[i]->allData()) {
346 thisDataNames.insert(data->GetName());
350 std::vector<std::string> missing;
351 std::vector<std::string> extra;
352 std::set_difference(referenceDataNames.begin(), referenceDataNames.end(), thisDataNames.begin(),
353 thisDataNames.end(), std::back_inserter(missing));
354 std::set_difference(thisDataNames.begin(), thisDataNames.end(), referenceDataNames.begin(),
355 referenceDataNames.end(), std::back_inserter(extra));
358 auto isAllowed = [&](std::string
const &
name) {
return allowedInconsistent.count(
name) != 0; };
360 missing.erase(std::remove_if(missing.begin(), missing.end(), isAllowed), missing.end());
361 extra.erase(std::remove_if(extra.begin(), extra.end(), isAllowed), extra.end());
363 if (!missing.empty() || !extra.empty()) {
364 std::stringstream errMsg;
365 errMsg <<
"ERROR: Inconsistent datasets across channel workspaces.\n"
366 <<
"Workspace for channel \"" << ch_names[i] <<
"\" does not match "
367 <<
"the datasets in channel \"" << ch_names[0] <<
"\".\n";
369 if (!missing.empty()) {
370 errMsg <<
" Missing datasets:\n";
371 for (
const auto &
name : missing) {
372 errMsg <<
" - " <<
name <<
"\n";
376 if (!extra.empty()) {
377 errMsg <<
" Extra datasets:\n";
378 for (
const auto &
name : extra) {
379 errMsg <<
" - " <<
name <<
"\n";
383 errMsg <<
"All channel workspaces must contain exactly the same datasets.\n";
384 return {
false, errMsg.str()};
396 for (
unsigned int idx=0; idx <
fObsNameVec.size(); ++idx) {
428 unsigned int histndim(1);
429 std::string classname = hist->
ClassName();
430 if (classname.find(
"TH1")==0) { histndim=1; }
431 else if (classname.find(
"TH2")==0) { histndim=2; }
432 else if (classname.find(
"TH3")==0) { histndim=3; }
435 prefix +=
"_Hist_alphanominal";
437 RooDataHist histDHist(prefix +
"DHist",
"",observables,hist);
439 return &emplace<RooHistFunc>(
proto, prefix, observables,histDHist,0);
445 std::vector<std::string> & constraintTermNames) {
446 std::string paramName = param.
GetName();
447 std::string nomName =
"nom_" + paramName;
448 std::string constraintName = paramName +
"Constraint";
451 if(
proto.pdf(constraintName))
return;
455 const double gaussSigma = isUniform ? 100. : 1.0;
457 cxcoutIHF <<
"Added a uniform constraint for " << paramName <<
" as a Gaussian constraint with a very large sigma " << std::endl;
460 constraintTermNames.emplace_back(constraintName);
462 RooRealVar &nomParam = emplace<RooRealVar>(
proto, nomName, 0., -10., 10.);
464 emplace<RooGaussian>(
proto, constraintName, paramVar, nomParam, gaussSigma);
473 for(
auto const& histoSys : histoSysList) {
482 RooAbsArg* makeLinInterp(RooArgList
const& interpolationParams,
483 RooHistFunc* nominalFunc,
484 RooWorkspace&
proto,
const std::vector<HistoSys>& histoSysList,
485 const string& prefix,
486 const RooArgList& obsList) {
490 std::vector<double> low;
491 std::vector<double> high;
494 for(
unsigned int j=0; j<histoSysList.size(); ++j){
495 std::string str = prefix +
"_" + std::to_string(j);
497 const HistoSys& histoSys = histoSysList.at(j);
498 auto lowDHist = std::make_unique<RooDataHist>(str+
"lowDHist",
"",obsList, histoSys.GetHistoLow());
499 auto highDHist = std::make_unique<RooDataHist>(str+
"highDHist",
"",obsList, histoSys.GetHistoHigh());
500 lowSet.
addOwned(std::make_unique<RooHistFunc>((str+
"low").c_str(),
"",obsList,std::move(lowDHist),0));
501 highSet.
addOwned(std::make_unique<RooHistFunc>((str+
"high").c_str(),
"",obsList,std::move(highDHist),0));
505 PiecewiseInterpolation interp(prefix.c_str(),
"",*nominalFunc,lowSet,highSet,interpolationParams);
506 interp.setPositiveDefinite();
507 interp.setAllInterpCodes(4);
509 RooArgSet obsSet(obsList);
510 interp.setBinIntegrator(obsSet);
511 interp.forceNumInt();
515 return proto.arg(prefix);
523 std::vector<string> prodNames;
526 vector<string> normFactorNames;
527 vector<string> rangeNames;
529 string overallNorm_times_sigmaEpsilon = sample.
GetName() +
"_" + channel +
"_scaleFactors";
530 auto sigEps =
proto.arg(sigmaEpsilon);
532 auto normFactor = std::make_unique<RooProduct>(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(),
RooArgList(*sigEps));
534 if(!normList.empty()){
537 string varname = norm.GetName();
539 varname +=
"_" + channel;
545 std::stringstream range;
546 range <<
"[" << norm.GetVal() <<
"," << norm.GetLow() <<
"," << norm.GetHigh() <<
"]";
548 if(
proto.obj(varname) ==
nullptr) {
551 emplace<RooRealVar>(
proto, varname, norm.GetVal(), norm.GetLow(), norm.GetHigh());
552 proto.var(varname)->setError(0);
555 prodNames.push_back(varname);
556 rangeNames.push_back(range.str());
557 normFactorNames.push_back(varname);
561 for (
const auto&
name : prodNames) {
564 normFactor->addTerm(arg);
569 unsigned int rangeIndex=0;
570 for( vector<string>::iterator nit = normFactorNames.begin(); nit!=normFactorNames.end(); ++nit){
571 if( count (normFactorNames.begin(), normFactorNames.end(), *nit) > 1 ){
572 cxcoutI(
HistFactory) <<
"<NormFactor Name =\""<<*nit<<
"\"> is duplicated for <Sample Name=\""
573 << sample.
GetName() <<
"\">, but only one factor will be included. \n Instead, define something like"
574 <<
"\n\t<Function Name=\""<<*nit<<
"Squared\" Expression=\""<<*nit<<
"*"<<*nit<<
"\" Var=\""<<*nit<<rangeNames.at(rangeIndex)
575 <<
"\"> \nin your top-level XML's <Measurement> entry and use <NormFactor Name=\""<<*nit<<
"Squared\" in your channel XML file."<< std::endl;
585 std::vector<OverallSys>& systList,
586 vector<string>& constraintTermNames,
587 vector<string>& totSystTermNames) {
590 totSystTermNames.push_back(prefix);
593 vector<double> lowVec;
594 vector<double> highVec;
596 std::map<std::string, double>::iterator itconstr;
597 for(
unsigned int i = 0; i < systList.size(); ++i) {
600 std::string strname = sys.
GetName();
601 const char *
name = strname.c_str();
612 cxcoutI(
HistFactory) <<
"HistoToWorkspaceFast::AddConstraintTerm - zero uncertainty assigned - skip systematic " << sys.
GetName() << std::endl;
615 const double tauVal = 1./(relerr*relerr);
616 const double sqtau = 1./relerr;
617 RooRealVar &beta = emplace<RooRealVar>(
proto,
"beta_" + strname, 1., 0., 10.);
619 RooRealVar &yvar = emplace<RooRealVar>(
proto,
"nom_" + std::string{beta.GetName()}, tauVal, 0., 10.);
621 RooRealVar &theta = emplace<RooRealVar>(
proto,
"theta_" + strname, 1./tauVal);
630 alphaOfBeta.
Print(
"t");
633 constraintTermNames.push_back(gamma.GetName());
639 params.
add(alphaOfBeta);
647 makeGaussianConstraint(alpha,
proto, isUniform, constraintTermNames);
660 proto,
"alphaOfBeta_" + sys.
GetName(),
"x[0]*(pow(x[1],x[2])-1.)",
661 RooArgList{emplace<RooRealVar>(proto,
"tau_" + sys.GetName(), 1. / relerr),
662 emplace<RooRealVar>(proto,
"kappa_" + sys.GetName(), 1. + relerr), alpha});
666 alphaOfBeta.
Print(
"t");
668 params.
add(alphaOfBeta);
673 lowVec.push_back(sys.
GetLow());
674 highVec.push_back(sys.
GetHigh());
678 if(!systList.empty()){
682 assert(!params.
empty());
683 assert(lowVec.size() == params.
size());
685 FlexibleInterpVar interp( (interpName).c_str(),
"", params, 1., lowVec, highVec);
688 proto.import(interp);
692 emplace<RooConstVar>(
proto, interpName, 1.);
698 const vector<RooProduct*>& sampleScaleFactors, std::vector<vector<RooAbsArg*>>& sampleHistFuncs)
const {
699 assert(sampleScaleFactors.size() == sampleHistFuncs.size());
704 throw std::logic_error(
"HistFactory didn't process the observables correctly. Please file a bug report.");
706 auto firstHistFunc =
dynamic_cast<const RooHistFunc*
>(sampleHistFuncs.front().front());
707 if (!firstHistFunc) {
709 firstHistFunc =
dynamic_cast<const RooHistFunc*
>(piecewiseInt->nominalHist());
711 assert(firstHistFunc);
714 auto &binWidth = emplace<RooBinWidthFunction>(
proto, totName +
"_binWidth", *firstHistFunc,
true);
719 for (
unsigned int i=0; i < sampleHistFuncs.size(); ++i) {
720 assert(!sampleHistFuncs[i].empty());
721 coefList.
add(*sampleScaleFactors[i]);
723 std::vector<RooAbsArg*>& thisSampleHistFuncs = sampleHistFuncs[i];
724 thisSampleHistFuncs.push_back(&binWidth);
726 if (thisSampleHistFuncs.size() == 1) {
728 shapeList.
add(*thisSampleHistFuncs.front());
731 std::string
name = thisSampleHistFuncs.front()->GetName();
732 auto pos =
name.find(
"Hist_alpha");
733 if (pos != std::string::npos) {
734 name =
name.substr(0, pos) +
"shapes";
735 }
else if ( (pos =
name.find(
"nominal")) != std::string::npos) {
736 name =
name.substr(0, pos) +
"shapes";
739 RooProduct shapeProduct(
name.c_str(), thisSampleHistFuncs.front()->GetTitle(),
RooArgSet(thisSampleHistFuncs.begin(), thisSampleHistFuncs.end()));
746 RooRealSumPdf tot(totName.c_str(), totName.c_str(), shapeList, coefList,
true);
756 if(
fCfg.binnedFitOptimization) {
767 std::ofstream covFile(filename);
771 if (myargi->isConstant())
773 covFile <<
" & " << myargi->GetName();
775 covFile <<
"\\\\ \\hline \n";
777 if(myargi->isConstant())
continue;
778 covFile << myargi->GetName();
780 if(myargj->isConstant())
continue;
781 std::cout << myargi->GetName() <<
"," << myargj->GetName();
782 double corr = result->
correlation(*myargi, *myargj);
783 covFile <<
" & " << std::fixed << std::setprecision(2) << corr;
785 std::cout << std::endl;
786 covFile <<
" \\\\\n";
799 Error(
"MakeSingleChannelWorkspace",
800 "The input Channel does not contain any sample - return a nullptr");
804 const TH1* channel_hist_template = channel.
GetSamples().front().GetHisto();
805 if (channel_hist_template ==
nullptr) {
807 channel_hist_template = channel.
GetSamples().front().GetHisto();
809 if (channel_hist_template ==
nullptr) {
810 std::ostringstream stream;
811 stream <<
"The sample " << channel.
GetSamples().front().GetName()
812 <<
" in channel " << channel.
GetName() <<
" does not contain a histogram. This is the channel:\n";
813 channel.
Print(stream);
814 Error(
"MakeSingleChannelWorkspace",
"%s", stream.str().c_str());
820 <<
" has uninitialized histogram pointers" << std::endl;
831 string channel_name = channel.
GetName();
841 for (
unsigned int idx=0; idx<
fObsNameVec.size(); ++idx ) {
851 throw hf_exc(
"HistFactory is limited to 1- to 3-dimensional histograms.");
855 <<
"\tStarting to process '"
856 << channel_name <<
"' channel with " <<
fObsNameVec.size() <<
" observables"
857 <<
"\n-----------------------------------------\n" << std::endl;
862 auto protoOwner = std::make_unique<RooWorkspace>(channel_name.c_str(), (channel_name+
" workspace").c_str());
864 auto proto_config = std::make_unique<ModelConfig>(
"ModelConfig", &
proto);
873 RooArgSet likelihoodTerms(
"likelihoodTerms");
874 RooArgSet constraintTerms(
"constraintTerms");
875 vector<string> likelihoodTermNames;
876 vector<string> constraintTermNames;
877 vector<string> totSystTermNames;
879 std::vector<std::vector<RooAbsArg*>> allSampleHistFuncs;
880 std::vector<RooProduct*> sampleScaleFactors;
882 std::vector<std::pair<string, string>> statNamePairs;
883 std::vector<std::pair<const TH1 *, std::unique_ptr<TH1>>> statHistPairs;
884 const std::string statFuncName =
"mc_stat_" + channel_name;
897 emplace<RooGaussian>(
proto,
"lumiConstraint", lumiVar, nominalLumiVar,
fLumiError);
899 proto.var(
"nominalLumi")->setConstant();
900 proto.defineSet(
"globalObservables",
"nominalLumi");
902 constraintTermNames.push_back(
"lumiConstraint");
904 proto.var(
"Lumi")->setConstant();
912 string overallSystName = sample.GetName() +
"_" + channel_name +
"_epsilon";
914 string systSourcePrefix =
"alpha_";
919 sample.GetOverallSysList(), constraintTermNames , totSystTermNames);
921 allSampleHistFuncs.emplace_back();
922 std::vector<RooAbsArg*>& sampleHistFuncs = allSampleHistFuncs.back();
935 const TH1* nominal = sample.GetHisto();
947 string expPrefix = sample.
GetName() +
"_" + channel_name;
951 assert(nominalHistFunc);
953 if(sample.GetHistoSysList().empty()) {
955 cxcoutI(
HistFactory) << sample.GetName() +
"_" + channel_name +
" has no variation histograms " << std::endl;
957 sampleHistFuncs.push_back(nominalHistFunc);
961 string constraintPrefix = sample.GetName() +
"_" + channel_name +
"_Hist_alpha";
964 RooArgList interpParams = makeInterpolationParameters(sample.GetHistoSysList(),
proto);
967 for(std::size_t i = 0; i < interpParams.
size(); ++i) {
968 bool isUniform = measurement.
GetUniformSyst().count(sample.GetHistoSysList()[i].GetName()) > 0;
969 makeGaussianConstraint(interpParams[i],
proto, isUniform, constraintTermNames);
973 sampleHistFuncs.push_back( makeLinInterp(interpParams, nominalHistFunc,
proto,
974 sample.GetHistoSysList(), constraintPrefix, observables) );
977 sampleHistFuncs.front()->SetTitle( (nominal && strlen(nominal->
GetTitle())>0) ? nominal->
GetTitle() : sample.GetName().c_str() );
983 if( sample.GetStatError().GetActivate() ) {
986 cxcoutFHF <<
"Cannot include Stat Error for histograms of more than 3 dimensions." << std::endl;
994 cxcoutI(
HistFactory) <<
"Sample: " << sample.GetName() <<
" to be included in Stat Error "
995 <<
"for channel " << channel_name
998 string UncertName = sample.GetName() +
"_" + channel_name +
"_StatAbsolUncert";
999 std::unique_ptr<TH1> statErrorHist;
1001 if( sample.GetStatError().GetErrorHist() ==
nullptr ) {
1004 <<
" Channel: " << channel_name
1005 <<
" Sample: " << sample.GetName()
1012 statErrorHist.reset(
static_cast<TH1*
>(sample.GetStatError().GetErrorHist()->Clone()));
1017 <<
"\tChannel: " << channel_name
1018 <<
"\tSample: " << sample.GetName()
1019 <<
"\tError Histogram: " << statErrorHist->GetName() << std::endl;
1022 statErrorHist->Multiply( nominal );
1023 statErrorHist->SetName( UncertName.c_str() );
1028 statHistPairs.emplace_back(nominal, std::move(statErrorHist));
1046 if( paramHist ==
nullptr ) {
1052 theObservables.
add( *
proto.var(obsName) );
1057 std::string ParamSetPrefix =
"gamma_stat_" + channel_name;
1063 ParamHistFunc statUncertFunc(statFuncName.c_str(), statFuncName.c_str(),
1064 theObservables, statFactorParams );
1068 paramHist =
proto.function( statFuncName);
1072 sampleHistFuncs.push_back(paramHist);
1081 if( !sample.GetShapeFactorList().empty() ) {
1084 cxcoutFHF <<
"Cannot include Stat Error for histograms of more than 3 dimensions." << std::endl;
1088 cxcoutI(
HistFactory) <<
"Sample: " << sample.GetName() <<
" in channel: " << channel_name
1089 <<
" to be include a ShapeFactor."
1092 for(
ShapeFactor& shapeFactor : sample.GetShapeFactorList()) {
1094 std::string funcName = channel_name +
"_" + shapeFactor.GetName() +
"_shapeFactor";
1096 if( paramHist ==
nullptr ) {
1100 theObservables.
add( *
proto.var(varName) );
1104 std::string funcParams =
"gamma_" + shapeFactor.
GetName();
1113 ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
1114 theObservables, shapeFactorParams );
1117 if( shapeFactor.GetInitialShape() !=
nullptr ) {
1118 TH1* initialShape =
static_cast<TH1*
>(shapeFactor.GetInitialShape()->
Clone());
1120 <<
" to have initial shape from hist: "
1123 shapeFactorFunc.
setShape( initialShape );
1127 if( shapeFactor.IsConstant() ) {
1129 <<
" to be constant" << std::endl;
1134 paramHist =
proto.function(funcName);
1138 sampleHistFuncs.push_back(paramHist);
1148 if( !sample.GetShapeSysList().empty() ) {
1151 cxcoutFHF <<
"Cannot include Stat Error for histograms of more than 3 dimensions.\n";
1156 std::vector<string> ShapeSysNames;
1169 cxcoutI(
HistFactory) <<
"Sample: " << sample.GetName() <<
" in channel: " << channel_name
1170 <<
" to include a ShapeSys." << std::endl;
1172 std::string funcName = channel_name +
"_" + shapeSys.GetName() +
"_ShapeSys";
1173 ShapeSysNames.push_back( funcName );
1175 if( paramHist ==
nullptr ) {
1182 theObservables.
add( *
proto.var(varName) );
1186 std::string funcParams =
"gamma_" + shapeSys.
GetName();
1192 ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
1193 theObservables, shapeFactorParams );
1205 const TH1* shapeErrorHist = shapeSys.GetErrorHist();
1220 for (
auto const& term : shapeConstraintsInfo.constraints) {
1222 constraintTermNames.emplace_back(term->GetName());
1226 for (
RooAbsArg * glob : shapeConstraintsInfo.globalObservables) {
1237 for(std::string
const&
name : ShapeSysNames) {
1238 sampleHistFuncs.push_back(
proto.function(
name));
1248 if( !sample.GetNormalizeByTheory() ) {
1250 lumi = &emplace<RooRealVar>(
proto,
"Lumi", measurement.
GetLumi());
1256 normFactors->addTerm(lumi);
1262 auto normFactorsInWS =
dynamic_cast<RooProduct*
>(
proto.arg(normFactors->GetName()));
1263 assert(normFactorsInWS);
1265 sampleScaleFactors.push_back(normFactorsInWS);
1270 if(!statHistPairs.empty()) {
1274 std::unique_ptr<TH1> fracStatError(
1276 if( fracStatError ==
nullptr ) {
1277 cxcoutFHF <<
"Error: Failed to make ScaledUncertaintyHist for: " << channel_name +
"_StatUncert" +
"_RelErr\n";
1283 auto chanStatUncertFunc =
static_cast<ParamHistFunc*
>(
proto.function( statFuncName ));
1285 << chanStatUncertFunc->
GetName()
1286 <<
" params: " << chanStatUncertFunc->paramList()
1305 chanStatUncertFunc->paramList(),
histToVector(*fracStatError),
1306 statRelErrorThreshold,
1307 statConstraintType);
1308 for (
auto const& term : statConstraintsInfo.constraints) {
1310 constraintTermNames.emplace_back(term->GetName());
1314 for (
RooAbsArg * glob : statConstraintsInfo.globalObservables) {
1324 sampleScaleFactors, allSampleHistFuncs);
1325 likelihoodTermNames.push_back(channel_name+
"_model");
1329 for(
unsigned int i=0; i<systToFix.size(); ++i){
1333 <<
" could not set it to constant" << std::endl;
1336 temp->setConstant();
1342 for(
unsigned int i=0; i<constraintTermNames.size(); ++i){
1344 if( proto_arg==
nullptr ) {
1345 cxcoutFHF <<
"Error: Cannot find arg set: " << constraintTermNames.at(i)
1346 <<
" in workspace: " <<
proto.GetName() << std::endl;
1349 constraintTerms.
add( *proto_arg );
1352 for(
unsigned int i=0; i<likelihoodTermNames.size(); ++i){
1354 if( proto_arg==
nullptr ) {
1355 cxcoutFHF <<
"Error: Cannot find arg set: " << likelihoodTermNames.at(i)
1356 <<
" in workspace: " <<
proto.GetName() << std::endl;
1359 likelihoodTerms.
add( *proto_arg );
1361 proto.defineSet(
"constraintTerms",constraintTerms);
1362 proto.defineSet(
"likelihoodTerms",likelihoodTerms);
1366 std::string observablesStr;
1370 if (!observablesStr.empty()) { observablesStr +=
","; }
1371 observablesStr +=
name;
1377 proto.defineSet(
"observables", observablesStr.c_str());
1378 proto.defineSet(
"observablesSet", observablesStr.c_str());
1383 <<
"\timport model into workspace"
1384 <<
"\n-----------------------------------------\n" << std::endl;
1386 auto model = std::make_unique<RooProdPdf>(
1387 (
"model_" + channel_name).c_str(),
1388 "product of Poissons across bins for a single channel", constraintTerms,
1396 proto_config->SetPdf(*model);
1397 proto_config->SetObservables(observables);
1398 proto_config->SetGlobalObservables(*
proto.set(
"globalObservables"));
1402 proto.import(*proto_config,proto_config->GetName());
1403 proto.importClassCode();
1410 int asymcalcPrintLevel = 0;
1414 if (
fCfg.createPerRegionWorkspaces) {
1427 std::unique_ptr<RooDataSet> dataset;
1428 if(!
fCfg.storeDataError){
1429 dataset = std::make_unique<RooDataSet>(
"obsData",
"",*
proto.set(
"observables"),
RooFit::WeightVar(
"weightVar"));
1431 const char* weightErrName=
"weightErr";
1436 proto.import(*dataset);
1441 if(data.GetName().empty()) {
1442 cxcoutFHF <<
"Error: Additional Data histogram for channel: " << channel.
GetName()
1443 <<
" has no name! The name always needs to be set for additional datasets, "
1444 <<
"either via the \"Name\" tag in the XML or via RooStats::HistFactory::Data::SetName().\n";
1447 std::string
const& dataName = data.GetName();
1448 TH1 const* mnominal = data.GetHisto();
1450 cxcoutFHF <<
"Error: Additional Data histogram for channel: " << channel.
GetName()
1451 <<
" with name: " << dataName <<
" is nullptr\n";
1458 proto.import(dataset);
1471 TH1 const& mnominal,
1473 std::vector<std::string>
const& obsNameVec) {
1479 if (obsNameVec.empty() ) {
1480 Error(
"ConfigureHistFactoryDataset",
"Invalid input - return");
1491 for (
int i=1; i<=ax->GetNbins(); ++i) {
1493 double xval = ax->GetBinCenter(i);
1494 proto.var( obsNameVec[0] )->setVal( xval );
1496 if(obsNameVec.size()==1) {
1498 double ferr = storeWeightErr ? mnominal.
GetBinError(i) : 0.;
1499 obsDataUnbinned.
add( *
proto.set(
"observables"), fval, ferr );
1502 for(
int j=1; j<=ay->
GetNbins(); ++j) {
1504 proto.var( obsNameVec[1] )->setVal( yval );
1506 if(obsNameVec.size()==2) {
1508 double ferr = storeWeightErr ? mnominal.
GetBinError(i, j) : 0.;
1509 obsDataUnbinned.
add( *
proto.set(
"observables"), fval, ferr );
1512 for(
int k=1; k<=az->
GetNbins(); ++k) {
1514 proto.var( obsNameVec[2] )->setVal( zval );
1516 double ferr = storeWeightErr ? mnominal.
GetBinError(i, j, k) : 0.;
1517 obsDataUnbinned.
add( *
proto.set(
"observables"), fval, ferr );
1534 std::vector<std::unique_ptr<RooWorkspace>> &chs)
1539 if (ch_names.empty() || chs.empty() ) {
1540 Error(
"MakeCombinedModel",
"Input vectors are empty - return a nullptr");
1543 if (chs.size() < ch_names.size() ) {
1544 Error(
"MakeCombinedModel",
"Input vector of workspace has an invalid size - return a nullptr");
1547 std::set<std::string> ch_names_set{ch_names.begin(), ch_names.end()};
1548 if (ch_names.size() != ch_names_set.size()) {
1549 Error(
"MakeCombinedModel",
"Input vector of channel names has duplicate names - return a nullptr");
1557 std::map<string, RooAbsPdf *> pdfMap;
1558 vector<RooAbsPdf *> models;
1561 for (
unsigned int i = 0; i < ch_names.size(); ++i) {
1562 obsList.
add(*
static_cast<ModelConfig *
>(chs[i]->obj(
"ModelConfig"))->GetObservables());
1567 std::map<std::string, int> channelMap;
1568 for(
unsigned int i = 0; i< ch_names.size(); ++i){
1569 string channel_name=ch_names[i];
1570 if (i == 0 && isdigit(channel_name[0])) {
1571 throw std::invalid_argument(
"The first channel name for HistFactory cannot start with a digit. Got " + channel_name);
1573 if (channel_name.find(
',') != std::string::npos) {
1574 throw std::invalid_argument(
"Channel names for HistFactory cannot contain ','. Got " + channel_name);
1577 channelMap[channel_name] = i;
1582 cxcoutFHF <<
"failed to find model for channel\n";
1585 models.push_back(model);
1586 auto &modelConfig = *
static_cast<ModelConfig *
>(chs[i]->obj(
"ModelConfig"));
1588 globalObs.
add(*modelConfig.GetGlobalObservables(),
true);
1591 pdfMap[channel_name]=model;
1595 <<
"\tEntering combination"
1596 <<
"\n-----------------------------------------\n" << std::endl;
1597 auto combined = std::make_unique<RooWorkspace>(
"combined");
1600 RooCategory& channelCat = emplace<RooCategory>(*combined,
"channelCat", channelMap);
1602 auto simPdf= std::make_unique<RooSimultaneous>(
"simPdf",
"",pdfMap, channelCat);
1603 auto combined_config = std::make_unique<ModelConfig>(
"ModelConfig", combined.get());
1604 combined_config->SetWorkspace(*combined);
1607 combined->import(globalObs);
1608 combined->defineSet(
"globalObservables",globalObs);
1609 combined_config->SetGlobalObservables(*combined->set(
"globalObservables"));
1611 combined->defineSet(
"observables",{obsList, channelCat},
true);
1612 combined_config->SetObservables(*combined->set(
"observables"));
1616 bool isConsistent =
false;
1618 std::set<std::string> allowedInconsistent{
"asimovData"};
1619 std::tie(isConsistent, errMsg) = isChannelDataConsistent(chs, ch_names, allowedInconsistent);
1620 if (!isConsistent) {
1630 if(std::string(
"asimovData") == data->GetName()) {
1635 std::map<std::string, RooAbsData*> dataMap;
1636 for(
unsigned int i = 0; i < ch_names.size(); ++i){
1637 dataMap[ch_names[i]] = chs[i]->data(data->GetName());
1648 <<
"\tImporting combined model"
1649 <<
"\n-----------------------------------------\n" << std::endl;
1654 std::string paramName = param_itr.first;
1655 double paramVal = param_itr.second;
1657 if(
RooRealVar* temp = combined->var( paramName )) {
1658 temp->setVal( paramVal );
1659 cxcoutI(
HistFactory) <<
"setting " << paramName <<
" to the value: " << paramVal << std::endl;
1661 cxcoutE(
HistFactory) <<
"could not find variable " << paramName <<
" could not set its value" << std::endl;
1665 for(
unsigned int i=0; i<
fSystToFix.size(); ++i){
1668 temp->setConstant();
1679 combined_config->SetPdf(*simPdf);
1682 combined->import(*combined_config,combined_config->GetName());
1683 combined->importClassCode();
1690 <<
"\tcreate toy data"
1691 <<
"\n-----------------------------------------\n" << std::endl;
1699 *combined->pdf(
"simPdf"),
1701 if( asimov_combined ) {
1702 combined->import( *asimov_combined,
RooFit::Rename(
"asimovData"));
1705 cxcoutFHF <<
"Error: Failed to create combined asimov dataset\n";
1719 auto ErrorHist =
static_cast<TH1*
>(Nominal->
Clone( Name.c_str() ));
1726 for(
int i_bin = 0; i_bin < numBins; ++i_bin) {
1734 double histError = Nominal->
GetBinError( binNumber );
1737 if( histError != histError ) {
1738 cxcoutFHF <<
"Warning: In histogram " << Nominal->
GetName() <<
" bin error for bin " << i_bin
1739 <<
" is NAN. Not using Error!!!\n";
1746 if( histError < 0 ) {
1747 cxcoutWHF <<
"Warning: In histogram " << Nominal->
GetName() <<
" bin error for bin " << binNumber
1748 <<
" is < 0. Setting Error to 0" << std::endl;
1753 ErrorHist->SetBinContent( binNumber, histError );
1772 unsigned int numHists = HistVec.size();
1774 if( numHists == 0 ) {
1775 cxcoutE(
HistFactory) <<
"Warning: Empty Hist Vector, cannot create total uncertainty" << std::endl;
1779 const TH1* HistTemplate = HistVec.at(0).first;
1784 for(
unsigned int i = 0; i < HistVec.size(); ++i ) {
1786 const TH1* nominal = HistVec.at(i).first;
1787 const TH1* error = HistVec.at(i).second.get();
1799 std::vector<double> TotalBinContent( numBins, 0.0);
1800 std::vector<double> HistErrorsSqr( numBins, 0.0);
1805 for(
int i_bins = 0; i_bins < numBins; ++i_bins) {
1812 for(
unsigned int i_hist = 0; i_hist < numHists; ++i_hist ) {
1814 const TH1* nominal = HistVec.at(i_hist).first;
1815 const TH1* error = HistVec.at(i_hist).second.get();
1822 if( histError != histError ) {
1823 cxcoutFHF <<
"In histogram " << error->
GetName() <<
" bin error for bin " << binNumber
1824 <<
" is NAN. Not using error!!";
1828 TotalBinContent.at(i_bins) += histValue;
1829 HistErrorsSqr.at(i_bins) += histError*histError;
1837 TH1* ErrorHist =
static_cast<TH1*
>(HistTemplate->
Clone( Name.c_str() ));
1841 for(
int i = 0; i < numBins; ++i) {
1849 double ErrorsSqr = HistErrorsSqr.at(i);
1850 double TotalVal = TotalBinContent.at(i);
1852 if( TotalVal <= 0 ) {
1854 <<
" is <= 0. Setting error to 0"
1861 double RelativeError = sqrt(ErrorsSqr) / TotalVal;
1865 if( RelativeError != RelativeError ) {
1867 <<
" HistErrorsSqr: " << ErrorsSqr
1868 <<
" TotalVal: " << TotalVal;
1882 <<
" Error = " << sqrt(ErrorsSqr)
1883 <<
" CentralVal = " << TotalVal
1884 <<
" RelativeError = " << RelativeError <<
"\n";
1888 return std::unique_ptr<TH1>(ErrorHist);
std::vector< double > histToVector(TH1 const &hist)
constexpr double alphaHigh
constexpr double alphaLow
ROOT::RRangeCast< T, false, Range_t > static_range_cast(Range_t &&coll)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
void setConstant(bool constant)
static RooArgList createParamSet(RooWorkspace &w, const std::string &, const RooArgList &Vars)
Create the list of RooRealVar parameters which represent the height of the histogram bins.
void setShape(TH1 *shape)
The PiecewiseInterpolation is a class that can morph distributions into each other,...
Common abstract base class for objects that represent a value and a "shape" in RooFit.
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
bool getAttribute(const Text_t *name) const
Check if a named attribute is set. By default, all attributes are unset.
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
const char * GetName() const override
Returns name of object.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
virtual bool addOwned(RooAbsArg &var, bool silent=false)
Add an argument and transfer the ownership to the collection.
Abstract base class for binned and unbinned datasets.
Abstract interface for all probability density functions.
Abstract base class for objects that represent a real value that may appear on the left hand side of ...
void setConstant(bool value=true)
Abstract base class for objects that represent a real value and implements functionality common to al...
RooNumIntConfig * specialIntegratorConfig() const
Returns the specialized integrator configuration for this RooAbsReal.
virtual void forceNumInt(bool flag=true)
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Object to represent discrete states.
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
Container class to hold N-dimensional binned data.
Container class to hold unbinned data.
RooRealVar * weightVar() const
Returns a pointer to the weight variable (if set).
void add(const RooArgSet &row, double weight, double weightError)
Add one ore more rows of data.
RooFitResult is a container class to hold the input and output of a PDF fit to a dataset.
double correlation(const RooAbsArg &par1, const RooAbsArg &par2) const
Return correlation between par1 and par2.
Implementation of the Gamma PDF for RooFit/RooStats.
Switches the message service to a different level while the instance is alive.
A real-valued function sampled from a multidimensional histogram.
static RooMsgService & instance()
Return reference to singleton instance.
A RooAbsReal implementing a polynomial in terms of a list of RooAbsReal coefficients.
Represents the product of a given set of RooAbsReal objects.
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
void setError(double value)
void setBins(Int_t nBins, const char *name=nullptr, bool shared=true)
Create a uniform binning under name 'name' for this variable.
void setBinning(const RooAbsBinning &binning, const char *name=nullptr, bool shared=true)
Add given binning under name 'name' with this variable.
static void SetPrintLevel(int level)
set print level (static function)
static RooAbsData * GenerateAsimovData(const RooAbsPdf &pdf, const RooArgSet &observables)
generate the asimov data for the observables (not the global ones) need to deal with the case of a si...
TODO Here, we are missing some documentation.
void ConfigureWorkspace(RooWorkspace *)
This class encapsulates all information for the statistical interpretation of one experiment.
std::vector< RooStats::HistFactory::Data > & GetAdditionalData()
retrieve vector of additional data objects
void Print(std::ostream &=std::cout)
HistFactory::StatErrorConfig & GetStatErrorConfig()
get information about threshold for statistical uncertainties and constraint term
RooStats::HistFactory::Data & GetData()
get data object
bool CheckHistograms() const
std::vector< RooStats::HistFactory::Sample > & GetSamples()
get vector of samples for this channel
std::string GetName() const
get name of channel
void setAllInterpCodes(int code)
Configuration for a constrained, coherent shape variation of affected samples.
std::unique_ptr< RooProduct > CreateNormFactor(RooWorkspace &proto, std::string &channel, std::string &sigmaEpsilon, Sample &sample, bool doRatio)
void GuessObsNameVec(const TH1 *hist)
std::unique_ptr< RooWorkspace > MakeSingleChannelWorkspace(Measurement &measurement, Channel &channel)
void MakeTotalExpected(RooWorkspace &proto, const std::string &totName, const std::vector< RooProduct * > &sampleScaleFactors, std::vector< std::vector< RooAbsArg * > > &sampleHistFuncs) const
std::unique_ptr< TH1 > MakeScaledUncertaintyHist(const std::string &Name, std::vector< std::pair< const TH1 *, std::unique_ptr< TH1 > > > const &HistVec) const
std::vector< std::string > fPreprocessFunctions
RooHistFunc * MakeExpectedHistFunc(const TH1 *hist, RooWorkspace &proto, std::string prefix, const RooArgList &observables) const
Create the nominal hist function from hist, and register it in the workspace.
void SetFunctionsToPreprocess(std::vector< std::string > lines)
std::vector< std::string > fObsNameVec
RooFit::OwningPtr< RooWorkspace > MakeSingleChannelModel(Measurement &measurement, Channel &channel)
RooFit::OwningPtr< RooWorkspace > MakeCombinedModel(std::vector< std::string >, std::vector< std::unique_ptr< RooWorkspace > > &)
TH1 * MakeAbsolUncertaintyHist(const std::string &Name, const TH1 *Hist)
std::map< std::string, double > fParamValues
static void ConfigureWorkspaceForMeasurement(const std::string &ModelName, RooWorkspace *ws_single, Measurement &measurement)
void AddConstraintTerms(RooWorkspace &proto, Measurement &measurement, std::string prefix, std::string interpName, std::vector< OverallSys > &systList, std::vector< std::string > &likelihoodTermNames, std::vector< std::string > &totSystTermNames)
void ConfigureHistFactoryDataset(RooDataSet &obsData, TH1 const &nominal, RooWorkspace &proto, std::vector< std::string > const &obsNameVec)
static void PrintCovarianceMatrix(RooFitResult *result, RooArgSet *params, std::string filename)
std::vector< std::string > fSystToFix
HistoToWorkspaceFactoryFast()
RooArgList createObservables(const TH1 *hist, RooWorkspace &proto) const
Create observables of type RooRealVar. Creates 1 to 3 observables, depending on the type of the histo...
The RooStats::HistFactory::Measurement class can be used to construct a model by combining multiple R...
std::map< std::string, double > & GetGammaSyst()
std::map< std::string, double > & GetLogNormSyst()
std::map< std::string, double > & GetNoSyst()
std::vector< std::string > & GetPOIList()
get vector of PoI names
std::map< std::string, double > & GetUniformSyst()
std::vector< std::string > & GetConstantParams()
get vector of all constant parameters
std::vector< RooStats::HistFactory::Channel > & GetChannels()
std::vector< RooStats::HistFactory::Asimov > & GetAsimovDatasets()
get vector of defined Asimov Datasets
std::vector< std::string > GetPreprocessFunctions() const
Returns a list of defined preprocess function expressions.
double GetLumi()
retrieve integrated luminosity
Configuration for an un- constrained overall systematic to scale sample normalisations.
Configuration for a constrained overall systematic to scale sample normalisations.
const std::string & GetName() const
std::string GetName() const
get name of sample
std::vector< RooStats::HistFactory::NormFactor > & GetNormFactorList()
*Un*constrained bin-by-bin variation of affected histogram.
Constrained bin-by-bin variation of affected histogram.
double GetRelErrorThreshold() const
Constraint::Type GetConstraintType() const
< A class that holds configuration information for a model using a workspace as a store
void SetParametersOfInterest(const RooArgSet &set)
Specify parameters of interest.
void GuessObsAndNuisance(const RooArgSet &obsSet, bool printModelConfig=true)
Makes sensible guesses of observables, parameters of interest and nuisance parameters if one or multi...
Persistable container for RooFit projects.
TObject * obj(RooStringView name) const
Return any type of object (RooAbsArg, RooAbsData or generic object) with given name).
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooArgSet allVars() const
Return set with all variable objects.
const RooArgSet * set(RooStringView name)
Return pointer to previously defined named set with given nmame If no such set is found a null pointe...
bool saveSnapshot(RooStringView, const char *paramNames)
Save snapshot of values and attributes (including "Constant") of given parameters.
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
bool loadSnapshot(const char *name)
Load the values and attributes of the parameters in the snapshot saved with the given name.
bool import(const RooAbsArg &arg, const RooCmdArg &arg1={}, const RooCmdArg &arg2={}, const RooCmdArg &arg3={}, const RooCmdArg &arg4={}, const RooCmdArg &arg5={}, const RooCmdArg &arg6={}, const RooCmdArg &arg7={}, const RooCmdArg &arg8={}, const RooCmdArg &arg9={})
Import a RooAbsArg object, e.g.
const Double_t * GetArray() const
Class to manage histogram axis.
Bool_t IsVariableBinSize() const
const char * GetTitle() const override
Returns title of object.
virtual Double_t GetBinCenter(Int_t bin) const
Return center of bin.
const TArrayD * GetXbins() const
TH1 is the base class of all histogram classes in ROOT.
virtual Int_t GetNbinsY() const
virtual Double_t GetBinError(Int_t bin) const
Return value of error associated to bin number bin.
virtual Int_t GetNbinsZ() const
virtual Int_t GetDimension() const
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
virtual Int_t GetNbinsX() const
virtual void SetBinError(Int_t bin, Double_t error)
Set the bin Error Note that this resets the bin eror option to be of Normal Type and for the non-empt...
Bool_t IsBinUnderflow(Int_t bin, Int_t axis=0) const
Return true if the bin is underflow.
Bool_t IsBinOverflow(Int_t bin, Int_t axis=0) const
Return true if the bin is overflow.
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
TObject * Clone(const char *newname="") const override
Make a complete copy of the underlying object.
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
const char * GetName() const override
Returns name of object.
const char * GetTitle() const override
Returns title of object.
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
virtual const char * ClassName() const
Returns name of class to which the object belongs.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
RooCmdArg RecycleConflictNodes(bool flag=true)
RooCmdArg Rename(const char *suffix)
RooCmdArg Conditional(const RooArgSet &pdfSet, const RooArgSet &depSet, bool depsAreCond=false)
RooConstVar & RooConst(double val)
RooCmdArg Index(RooCategory &icat)
RooCmdArg StoreError(const RooArgSet &aset)
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Import(const char *state, TH1 &histo)
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
constexpr double defaultShapeSysGammaMax
constexpr double minShapeUncertainty
constexpr double defaultShapeFactorGammaMax
constexpr double defaultStatErrorGammaMax
constexpr double defaultGammaMin
Arg_t & getOrCreate(RooWorkspace &ws, std::string const &name, Params_t &&...params)
CreateGammaConstraintsOutput createGammaConstraints(RooArgList const ¶mList, std::span< const double > relSigmas, double minSigma, Constraint::Type type)
Namespace for the RooStats classes.
Configuration settings for HistFactory behavior.