Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HistoToWorkspaceFactoryFast.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id: cranmer $
2// Author: Kyle Cranmer, Akira Shibata
3/*************************************************************************
4 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11////////////////////////////////////////////////////////////////////////////////
12
13/** \class RooStats::HistFactory::HistoToWorkspaceFactoryFast
14 * \ingroup HistFactory
15 * This class provides helper functions for creating likelihood models from histograms.
16 * It is used by RooStats::HistFactory::MakeModelAndMeasurementFast.
17 *
18 * A tutorial showing how to create a HistFactory model is hf001_example.C
19 */
20
21
22#include <RooAddition.h>
23#include <RooBinWidthFunction.h>
24#include <RooBinning.h>
25#include <RooCategory.h>
26#include <RooConstVar.h>
27#include <RooDataHist.h>
28#include <RooDataSet.h>
29#include <RooFit/ModelConfig.h>
30#include <RooFitResult.h>
31#include <RooFormulaVar.h>
32#include <RooGamma.h>
33#include <RooGaussian.h>
34#include <RooGlobalFunc.h>
35#include <RooHelpers.h>
36#include <RooHistFunc.h>
37#include <RooNumIntConfig.h>
38#include <RooPoisson.h>
39#include <RooPolyVar.h>
40#include <RooProdPdf.h>
41#include <RooProduct.h>
42#include <RooRandom.h>
43#include <RooRealSumPdf.h>
44#include <RooRealVar.h>
45#include <RooSimultaneous.h>
46#include <RooWorkspace.h>
47
52
53#include "HFMsgService.h"
54
55#include "TH1.h"
56
57// specific to this package
64
65#include <algorithm>
66#include <fstream>
67#include <iomanip>
68#include <memory>
69#include <set>
70#include <utility>
71
72constexpr double alphaLow = -5.0;
73constexpr double alphaHigh = 5.0;
74
75std::vector<double> histToVector(TH1 const &hist)
76{
77 // Must get the full size of the TH1 (No direct method to do this...)
78 int numBins = hist.GetNbinsX() * hist.GetNbinsY() * hist.GetNbinsZ();
79 std::vector<double> out(numBins);
80 int histIndex = 0;
81 for (int i = 0; i < numBins; ++i) {
82 while (hist.IsBinUnderflow(histIndex) || hist.IsBinOverflow(histIndex)) {
83 ++histIndex;
84 }
85 out[i] = hist.GetBinContent(histIndex);
86 ++histIndex;
87 }
88 return out;
89}
90
91// use this order for safety on library loading
92using namespace RooStats;
93using std::string, std::vector;
94
95using namespace RooStats::HistFactory::Detail;
97
98namespace RooStats::HistFactory {
99
104
106 Configuration const& cfg) :
107 fSystToFix( measurement.GetConstantParams() ),
108 fParamValues( measurement.GetParamValues() ),
109 fNomLumi( measurement.GetLumi() ),
110 fLumiError( measurement.GetLumi()*measurement.GetLumiRelErr() ),
111 fLowBin( measurement.GetBinLow() ),
112 fHighBin( measurement.GetBinHigh() ),
113 fCfg{cfg} {
114
115 // Set Preprocess functions
116 SetFunctionsToPreprocess( measurement.GetPreprocessFunctions() );
117
118 }
119
121
122 // Configure a workspace by doing any
123 // necessary post-processing and by
124 // creating a ModelConfig
125
126 // Make a ModelConfig and configure it
127 ModelConfig * proto_config = static_cast<ModelConfig *>(ws_single->obj("ModelConfig"));
128 if( proto_config == nullptr ) {
129 cxcoutFHF << "Error: Did not find 'ModelConfig' object in file: " << ws_single->GetName() << std::endl;
130 throw hf_exc();
131 }
132
133 if( measurement.GetPOIList().empty() ) {
134 cxcoutWHF << "No Parametetrs of interest are set" << std::endl;
135 }
136
137
138 std::stringstream sstream;
139 sstream << "Setting Parameter(s) of Interest as: ";
140 for(auto const& item : measurement.GetPOIList()) {
141 sstream << item << " ";
142 }
143 cxcoutIHF << sstream.str() << std::endl;
144
145 RooArgSet params;
146 for(auto const& poi_name : measurement.GetPOIList()) {
147 if(RooRealVar* poi = (RooRealVar*) ws_single->var(poi_name)){
148 params.add(*poi);
149 }
150 else {
151 cxcoutWHF << "WARNING: Can't find parameter of interest: " << poi_name
152 << " in Workspace. Not setting in ModelConfig." << std::endl;
153 // throw hf_exc();
154 }
155 }
156 proto_config->SetParametersOfInterest(params);
157
158 // Name of an 'edited' model, if necessary
159 std::string NewModelName = "newSimPdf"; // <- This name is hard-coded in HistoToWorkspaceFactoryFast::EditSyt. Probably should be changed to : std::string("new") + ModelName;
160
161 // Get the pdf
162 // Notice that we get the "new" pdf, this is the one that is
163 // used in the creation of these asimov datasets since they
164 // are fitted (or may be, at least).
165 RooAbsPdf* pdf = ws_single->pdf(NewModelName);
166 if( !pdf ) pdf = ws_single->pdf( ModelName );
167 const RooArgSet* observables = ws_single->set("observables");
168
169 // Set the ModelConfig's Params of Interest
170 if(!measurement.GetPOIList().empty()){
171 proto_config->GuessObsAndNuisance(*observables, RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::INFO));
172 }
173
174 // Now, let's loop over any additional asimov datasets
175 // that we need to make
176
177 // Create a SnapShot of the nominal values
178 std::string SnapShotName = "NominalParamValues";
179 ws_single->saveSnapshot(SnapShotName, ws_single->allVars());
180
181 for( unsigned int i=0; i<measurement.GetAsimovDatasets().size(); ++i) {
182
183 // Set the variable values and "const" ness with the workspace
184 RooStats::HistFactory::Asimov& asimov = measurement.GetAsimovDatasets().at(i);
185 std::string AsimovName = asimov.GetName();
186
187 cxcoutPHF << "Generating additional Asimov Dataset: " << AsimovName << std::endl;
189 std::unique_ptr<RooAbsData> asimov_dataset{AsymptoticCalculator::GenerateAsimovData(*pdf, *observables)};
190
191 cxcoutPHF << "Importing Asimov dataset" << std::endl;
192 bool failure = ws_single->import(*asimov_dataset, RooFit::Rename(AsimovName.c_str()));
193 if( failure ) {
194 cxcoutFHF << "Error: Failed to import Asimov dataset: " << AsimovName << std::endl;
195 throw hf_exc();
196 }
197
198 // Load the snapshot at the end of every loop iteration
199 // so we start each loop with a "clean" snapshot
200 ws_single->loadSnapshot(SnapShotName.c_str());
201 }
202
203 // Cool, we're done
204 return; // ws_single;
205 }
206
207
208 // We want to eliminate this interface and use the measurement directly
210
211 // This is a pretty light-weight wrapper function
212 //
213 // Take a fully configured measurement as well as
214 // one of its channels
215 //
216 // Return a workspace representing that channel
217 // Do this by first creating a vector of EstimateSummary's
218 // and this by configuring the workspace with any post-processing
219
220 // Get the channel's name
221 string ch_name = channel.GetName();
222
223 // Create a workspace for a SingleChannel from the Measurement Object
224 std::unique_ptr<RooWorkspace> ws_single{this->MakeSingleChannelWorkspace(measurement, channel)};
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;
228 throw hf_exc();
229 }
230
231 // Finally, configure that workspace based on
232 // properties of the measurement
234
235 return RooFit::makeOwningPtr(std::move(ws_single));
236
237 }
238
240
241 // This function takes a fully configured measurement
242 // which may contain several channels and returns
243 // a workspace holding the combined model
244 //
245 // This can be used, for example, within a script to produce
246 // a combined workspace on-the-fly
247 //
248 // This is a static function (for now) to make
249 // it a one-liner
250
251
252 Configuration config;
253 return MakeCombinedModel(measurement,config);
254 }
255
257
258 // This function takes a fully configured measurement
259 // which may contain several channels and returns
260 // a workspace holding the combined model
261 //
262 // This can be used, for example, within a script to produce
263 // a combined workspace on-the-fly
264 //
265 // This is a static function (for now) to make
266 // it a one-liner
267
269
270 // First, we create an instance of a HistFactory
272
273 // Loop over the channels and create the individual workspaces
274 std::vector<std::unique_ptr<RooWorkspace>> channel_workspaces;
275 std::vector<std::string> channel_names;
276
277 for(HistFactory::Channel& channel : measurement.GetChannels()) {
278
279 if( ! channel.CheckHistograms() ) {
280 cxcoutFHF << "MakeModelAndMeasurementsFast: Channel: " << channel.GetName()
281 << " has uninitialized histogram pointers" << std::endl;
282 throw hf_exc();
283 }
284
285 string ch_name = channel.GetName();
286 channel_names.push_back(ch_name);
287
288 // GHL: Renaming to 'MakeSingleChannelWorkspace'
289 channel_workspaces.emplace_back(histFactory.MakeSingleChannelModel(measurement, channel));
290 }
291
292
293 // Now, combine the individual channel workspaces to
294 // form the combined workspace
295 std::unique_ptr<RooWorkspace> ws{histFactory.MakeCombinedModel( channel_names, channel_workspaces )};
296
297
298 // Configure the workspace
300
301 // Done. Return the pointer
302 return RooFit::makeOwningPtr(std::move(ws));
303
304 }
305
306namespace {
307
308template <class Arg_t, typename... Args_t>
309Arg_t &emplace(RooWorkspace &ws, std::string const &name, Args_t &&...args)
310{
311 Arg_t arg{name.c_str(), name.c_str(), std::forward<Args_t>(args)...};
313 return *dynamic_cast<Arg_t *>(ws.arg(name));
314}
315
316
317/// Check whether all channel workspaces contain consistent datasets.
318///
319/// This function compares the datasets stored in each channel workspace against
320/// those in the first workspace.
321///
322/// \param chs Vector of channel workspaces to compare (first is the reference).
323/// \param ch_names Names of the channels, used for error reporting.
324/// \param allowedInconsistent Dataset names that are allowed to differ between channels.
325///
326/// \return A pair consisting of:
327/// - bool: true if all channels are consistent (after ignoring allowed datasets),
328/// false otherwise.
329/// - std::string: empty if consistent; otherwise, a detailed error message
330/// describing the inconsistencies.
331
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)
335{
336 // Collect the reference list of dataset names from the first workspace
337 std::set<std::string> referenceDataNames;
338 for (RooAbsData *data : chs[0]->allData()) {
339 referenceDataNames.insert(data->GetName());
340 }
341
342 // Check that all other workspaces have the same datasets
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());
347 }
348
349 // Find missing and extra datasets in this workspace
350 std::vector<std::string> missing;
351 std::vector<std::string> extra;
353 thisDataNames.end(), std::back_inserter(missing));
354 std::set_difference(thisDataNames.begin(), thisDataNames.end(), referenceDataNames.begin(),
355 referenceDataNames.end(), std::back_inserter(extra));
356
357 // Remove allowed inconsistencies
358 auto isAllowed = [&](std::string const &name) { return allowedInconsistent.count(name) != 0; };
359
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());
362
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";
368
369 if (!missing.empty()) {
370 errMsg << " Missing datasets:\n";
371 for (const auto &name : missing) {
372 errMsg << " - " << name << "\n";
373 }
374 }
375
376 if (!extra.empty()) {
377 errMsg << " Extra datasets:\n";
378 for (const auto &name : extra) {
379 errMsg << " - " << name << "\n";
380 }
381 }
382
383 errMsg << "All channel workspaces must contain exactly the same datasets.\n";
384 return {false, errMsg.str()};
385 }
386 }
387 return {true, ""};
388}
389
390} // namespace
391
392/// Create observables of type RooRealVar. Creates 1 to 3 observables, depending on the type of the histogram.
394 RooArgList observables;
395
396 for (unsigned int idx=0; idx < fObsNameVec.size(); ++idx) {
397 if (!proto.var(fObsNameVec[idx])) {
398 const TAxis *axis = (idx == 0) ? hist->GetXaxis() : (idx == 1 ? hist->GetYaxis() : hist->GetZaxis());
399 int nbins = axis->GetNbins();
400 // create observable
401 RooRealVar &obs = emplace<RooRealVar>(proto, fObsNameVec[idx], axis->GetXmin(), axis->GetXmax());
402 if(strlen(axis->GetTitle())>0) obs.SetTitle(axis->GetTitle());
403 obs.setBins(nbins);
404 if (axis->IsVariableBinSize()) {
405 RooBinning binning(nbins, axis->GetXbins()->GetArray());
406 obs.setBinning(binning);
407 }
408 }
409
410 observables.add(*proto.var(fObsNameVec[idx]));
411 }
412
413 return observables;
414}
415
416 /// Create the nominal hist function from `hist`, and register it in the workspace.
418 const RooArgList& observables) const {
419 if(hist) {
420 cxcoutI(HistFactory) << "processing hist " << hist->GetName() << std::endl;
421 } else {
422 cxcoutF(HistFactory) << "hist is empty" << std::endl;
423 R__ASSERT(hist != nullptr);
424 return nullptr;
425 }
426
427 // determine histogram dimensionality
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; }
433 R__ASSERT( histndim==fObsNameVec.size() );
434
435 prefix += "_Hist_alphanominal";
436
437 RooDataHist histDHist(prefix + "DHist","",observables,hist);
438
439 return &emplace<RooHistFunc>(proto, prefix, observables,histDHist,0);
440 }
441
442 namespace {
443
444 void makeGaussianConstraint(RooAbsArg& param, RooWorkspace& proto, bool isUniform,
445 std::vector<std::string> & constraintTermNames) {
446 std::string paramName = param.GetName();
447 std::string nomName = "nom_" + paramName;
448 std::string constraintName = paramName + "Constraint";
449
450 // do nothing if the constraint term already exists
451 if(proto.pdf(constraintName)) return;
452
453 // case systematic is uniform (assume they are like a Gaussian but with
454 // a large width (100 instead of 1)
455 const double gaussSigma = isUniform ? 100. : 1.0;
456 if (isUniform) {
457 cxcoutIHF << "Added a uniform constraint for " << paramName << " as a Gaussian constraint with a very large sigma " << std::endl;
458 }
459
463 nomParam.setConstant();
465 paramVar.setError(gaussSigma); // give param initial error to match gaussSigma
466 const_cast<RooArgSet*>(proto.set("globalObservables"))->add(nomParam);
467 }
468
469 /// Make list of abstract parameters that interpolate in space of variations.
471 RooArgList params( ("alpha_Hist") );
472
473 for(auto const& histoSys : histoSysList) {
474 params.add(getOrCreate<RooRealVar>(proto, "alpha_" + histoSys.GetName(), alphaLow, alphaHigh));
475 }
476
477 return params;
478 }
479
480 /// Create a linear interpolation object that holds nominal and systematics, import it into the workspace,
481 /// and return a pointer to it.
484 RooWorkspace& proto, const std::vector<HistoSys>& histoSysList,
485 const string& prefix,
486 const RooArgList& obsList) {
487
488 // now make function that linearly interpolates expectation between variations
489 // get low/high variations to interpolate between
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);
496
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));
502 }
503
504 // this is sigma(params), a piece-wise linear interpolation
506 interp.setPositiveDefinite();
507 interp.setAllInterpCodes(4); // LM: change to 4 (piece-wise linear to 6th order polynomial interpolation + linear extrapolation )
508 // KC: interpo codes 1 etc. don't have proper analytic integral.
510 interp.setBinIntegrator(obsSet);
511 interp.forceNumInt();
512
513 proto.import(interp, RooFit::RecycleConflictNodes()); // individual params have already been imported in first loop of this function
514
515 return proto.arg(prefix);
516 }
517
518 }
519
520 // GHL: Consider passing the NormFactor list instead of the entire sample
521 std::unique_ptr<RooProduct> HistoToWorkspaceFactoryFast::CreateNormFactor(RooWorkspace& proto, string& channel, string& sigmaEpsilon, Sample& sample, bool doRatio){
522
523 std::vector<string> prodNames;
524
525 vector<NormFactor> normList = sample.GetNormFactorList();
528
529 string overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_scaleFactors";
530 auto sigEps = proto.arg(sigmaEpsilon);
531 assert(sigEps);
532 auto normFactor = std::make_unique<RooProduct>(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(), RooArgList(*sigEps));
533
534 if(!normList.empty()){
535
536 for(NormFactor &norm : normList) {
537 string varname = norm.GetName();
538 if(doRatio) {
539 varname += "_" + channel;
540 }
541
542 // GHL: Check that the NormFactor doesn't already exist
543 // (it may have been created as a function expression
544 // during preprocessing)
545 std::stringstream range;
546 range << "[" << norm.GetVal() << "," << norm.GetLow() << "," << norm.GetHigh() << "]";
547
548 if( proto.obj(varname) == nullptr) {
549 cxcoutI(HistFactory) << "making normFactor: " << norm.GetName() << std::endl;
550 // remove "doRatio" and name can be changed when ws gets imported to the combined model.
551 emplace<RooRealVar>(proto, varname, norm.GetVal(), norm.GetLow(), norm.GetHigh());
552 proto.var(varname)->setError(0); // ensure factor is assigned an initial error, even if its zero
553 }
554
555 prodNames.push_back(varname);
556 rangeNames.push_back(range.str());
557 normFactorNames.push_back(varname);
558 }
559
560
561 for (const auto& name : prodNames) {
562 auto arg = proto.arg(name);
563 assert(arg);
564 normFactor->addTerm(arg);
565 }
566
567 }
568
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;
576 }
577 ++rangeIndex;
578 }
579
580 return normFactor;
581 }
582
584 string interpName,
585 std::vector<OverallSys>& systList,
588
589 // add variables for all the relative overall uncertainties we expect
590 totSystTermNames.push_back(prefix);
591
592 RooArgSet params(prefix.c_str());
595
596 std::map<std::string, double>::iterator itconstr;
597 for(unsigned int i = 0; i < systList.size(); ++i) {
598
599 OverallSys& sys = systList.at(i);
600 std::string strname = sys.GetName();
601 const char * name = strname.c_str();
602
603 // case of no systematic (is it possible)
604 if (meas.GetNoSyst().count(sys.GetName()) > 0 ) {
605 cxcoutI(HistFactory) << "HistoToWorkspaceFast::AddConstraintTerm - skip systematic " << sys.GetName() << std::endl;
606 continue;
607 }
608 // case systematic is a gamma constraint
609 if (meas.GetGammaSyst().count(sys.GetName()) > 0 ) {
610 double relerr = meas.GetGammaSyst().find(sys.GetName() )->second;
611 if (relerr <= 0) {
612 cxcoutI(HistFactory) << "HistoToWorkspaceFast::AddConstraintTerm - zero uncertainty assigned - skip systematic " << sys.GetName() << std::endl;
613 continue;
614 }
615 const double tauVal = 1./(relerr*relerr);
616 const double sqtau = 1./relerr;
617 RooRealVar &beta = emplace<RooRealVar>(proto, "beta_" + strname, 1., 0., 10.);
618 // the global observable (y_s)
619 RooRealVar &yvar = emplace<RooRealVar>(proto, "nom_" + std::string{beta.GetName()}, tauVal, 0., 10.);
620 // the rate of the gamma distribution (theta)
621 RooRealVar &theta = emplace<RooRealVar>(proto, "theta_" + strname, 1./tauVal);
622 // find alpha as function of beta
624
625 // add now the constraint itself Gamma_beta_constraint(beta, y+1, tau, 0 )
626 // build the gamma parameter k = as y_s + 1
627 RooAddition &kappa = emplace<RooAddition>(proto, "k_" + std::string{yvar.GetName()}, RooArgList{yvar, 1.0});
628 RooGamma &gamma = emplace<RooGamma>(proto, std::string{beta.GetName()} + "Constraint", beta, kappa, theta, RooFit::RooConst(0.0));
630 alphaOfBeta.Print("t");
631 gamma.Print("t");
632 }
633 constraintTermNames.push_back(gamma.GetName());
634 // set global observables
635 yvar.setConstant(true);
636 const_cast<RooArgSet*>(proto.set("globalObservables"))->add(yvar);
637
638 // add alphaOfBeta in the list of params to interpolate
639 params.add(alphaOfBeta);
640 cxcoutI(HistFactory) << "Added a gamma constraint for " << name << std::endl;
641
642 }
643 else {
644 RooRealVar& alpha = getOrCreate<RooRealVar>(proto, prefix + sys.GetName(), 0, alphaLow, alphaHigh);
645 // add the Gaussian constraint part
646 const bool isUniform = meas.GetUniformSyst().count(sys.GetName()) > 0;
648
649 // check if exists a log-normal constraint
650 if (meas.GetLogNormSyst().count(sys.GetName()) == 0 && meas.GetGammaSyst().count(sys.GetName()) == 0 ) {
651 // just add the alpha for the parameters of the FlexibleInterpVar function
652 params.add(alpha);
653 }
654 // case systematic is a log-normal constraint
655 if (meas.GetLogNormSyst().count(sys.GetName()) > 0 ) {
656 // log normal constraint for parameter
657 const double relerr = meas.GetLogNormSyst().find(sys.GetName() )->second;
658
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});
663
664 cxcoutI(HistFactory) << "Added a log-normal constraint for " << name << std::endl;
666 alphaOfBeta.Print("t");
667 }
668 params.add(alphaOfBeta);
669 }
670
671 }
672 // add low/high vectors
673 lowVec.push_back(sys.GetLow());
674 highVec.push_back(sys.GetHigh());
675
676 } // end sys loop
677
678 if(!systList.empty()){
679 // this is epsilon(alpha_j), a piece-wise linear interpolation
680 // LinInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
681
682 assert(!params.empty());
683 assert(lowVec.size() == params.size());
684
685 FlexibleInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
686 interp.setAllInterpCodes(4); // LM: change to 4 (piece-wise exponential to 6th order polynomial interpolation + exponential extrapolation )
687 //interp.setAllInterpCodes(0); // simple linear interpolation
688 proto.import(interp); // params have already been imported in first loop of this function
689 } else{
690 // some strange behavior if params,lowVec,highVec are empty.
691 //cout << "WARNING: No OverallSyst terms" << std::endl;
692 emplace<RooConstVar>(proto, interpName, 1.); // params have already been imported in first loop of this function
693 }
694 }
695
696
699 assert(sampleScaleFactors.size() == sampleHistFuncs.size());
700
701 // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
702
703 if (fObsNameVec.empty() && !fObsName.empty())
704 throw std::logic_error("HistFactory didn't process the observables correctly. Please file a bug report.");
705
706 auto firstHistFunc = dynamic_cast<const RooHistFunc*>(sampleHistFuncs.front().front());
707 if (!firstHistFunc) {
708 auto piecewiseInt = dynamic_cast<const PiecewiseInterpolation*>(sampleHistFuncs.front().front());
709 firstHistFunc = dynamic_cast<const RooHistFunc*>(piecewiseInt->nominalHist());
710 }
712
713 // Prepare a function to divide all bin contents by bin width to get a density:
714 auto &binWidth = emplace<RooBinWidthFunction>(proto, totName + "_binWidth", *firstHistFunc, true);
715
716 // Loop through samples and create products of their functions:
717 RooArgSet coefList;
719 for (unsigned int i=0; i < sampleHistFuncs.size(); ++i) {
720 assert(!sampleHistFuncs[i].empty());
721 coefList.add(*sampleScaleFactors[i]);
722
723 std::vector<RooAbsArg*>& thisSampleHistFuncs = sampleHistFuncs[i];
724 thisSampleHistFuncs.push_back(&binWidth);
725
726 if (thisSampleHistFuncs.size() == 1) {
727 // Just one function. Book it.
728 shapeList.add(*thisSampleHistFuncs.front());
729 } else {
730 // Have multiple functions. We need to multiply them.
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";
737 }
738
741 shapeList.add(*proto.function(name));
742 }
743 }
744
745 // Sum all samples
746 RooRealSumPdf tot(totName.c_str(), totName.c_str(), shapeList, coefList, true);
747 tot.specialIntegratorConfig(true)->method1D().setLabel("RooBinIntegrator") ;
748 tot.specialIntegratorConfig(true)->method2D().setLabel("RooBinIntegrator") ;
749 tot.specialIntegratorConfig(true)->methodND().setLabel("RooBinIntegrator") ;
750 tot.forceNumInt();
751
752 // for mixed generation in RooSimultaneous
753 tot.setAttribute("GenerateBinned"); // for use with RooSimultaneous::generate in mixed mode
754
755 // Enable the binned likelihood optimization
756 if(fCfg.binnedFitOptimization) {
757 tot.setAttribute("BinnedLikelihood");
758 }
759
761 }
762
763 //////////////////////////////////////////////////////////////////////////////
764
766
767 std::ofstream covFile(filename);
768
769 covFile << " ";
770 for (auto const *myargi : static_range_cast<RooRealVar *>(*params)) {
771 if (myargi->isConstant())
772 continue;
773 covFile << " & " << myargi->GetName();
774 }
775 covFile << "\\\\ \\hline \n";
776 for (auto const *myargi : static_range_cast<RooRealVar *>(*params)) {
777 if(myargi->isConstant()) continue;
778 covFile << myargi->GetName();
779 for (auto const *myargj : static_range_cast<RooRealVar *>(*params)) {
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;
784 }
785 std::cout << std::endl;
786 covFile << " \\\\\n";
787 }
788
789 covFile.close();
790 }
791
792
793 ///////////////////////////////////////////////
795
796 // check inputs (see JIRA-6890 )
797
798 if (channel.GetSamples().empty()) {
799 Error("MakeSingleChannelWorkspace",
800 "The input Channel does not contain any sample - return a nullptr");
801 return nullptr;
802 }
803
804 const TH1* channel_hist_template = channel.GetSamples().front().GetHisto();
805 if (channel_hist_template == nullptr) {
806 channel.CollectHistograms();
807 channel_hist_template = channel.GetSamples().front().GetHisto();
808 }
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());
815 return nullptr;
816 }
817
818 if( ! channel.CheckHistograms() ) {
819 cxcoutFHF << "MakeSingleChannelWorkspace: Channel: " << channel.GetName()
820 << " has uninitialized histogram pointers" << std::endl;
821 throw hf_exc();
822 }
823
824
825
826 // Set these by hand inside the function
827 vector<string> systToFix = measurement.GetConstantParams();
828 bool doRatio=false;
829
830 //ES// string channel_name=summary[0].channel;
831 string channel_name = channel.GetName();
832
833 /// MB: reset observable names for each new channel.
834 fObsNameVec.clear();
835
836 /// MB: label observables x,y,z, depending on histogram dimensionality
837 /// GHL: Give it the first sample's nominal histogram as a template
838 /// since the data histogram may not be present
840
841 for ( unsigned int idx=0; idx<fObsNameVec.size(); ++idx ) {
842 fObsNameVec[idx] = "obs_" + fObsNameVec[idx] + "_" + channel_name ;
843 }
844
845 if (fObsNameVec.empty()) {
846 fObsName= "obs_" + channel_name; // set name ov observable
847 fObsNameVec.push_back( fObsName );
848 }
849
850 if (fObsNameVec.empty() || fObsNameVec.size() > 3) {
851 throw hf_exc("HistFactory is limited to 1- to 3-dimensional histograms.");
852 }
853
854 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
855 << "\tStarting to process '"
856 << channel_name << "' channel with " << fObsNameVec.size() << " observables"
857 << "\n-----------------------------------------\n" << std::endl;
858
859 //
860 // our main workspace that we are using to construct the model
861 //
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);
865
866 // preprocess functions
867 for(auto const& func : fPreprocessFunctions){
868 cxcoutI(HistFactory) << "will preprocess this line: " << func << std::endl;
869 proto.factory(func);
870 proto.Print();
871 }
872
873 RooArgSet likelihoodTerms("likelihoodTerms");
874 RooArgSet constraintTerms("constraintTerms");
878 // All histogram functions to be multiplied in each sample
879 std::vector<std::vector<RooAbsArg*>> allSampleHistFuncs;
880 std::vector<RooProduct*> sampleScaleFactors;
881
882 std::vector<std::pair<string, string>> statNamePairs;
883 std::vector<std::pair<const TH1 *, std::unique_ptr<TH1>>> statHistPairs; // <nominal, error>
884 const std::string statFuncName = "mc_stat_" + channel_name;
885
886 string prefix;
887 string range;
888
889 /////////////////////////////
890 // shared parameters
891 // this is ratio of lumi to nominal lumi. We will include relative uncertainty in model
892 auto &lumiVar = getOrCreate<RooRealVar>(proto, "Lumi", fNomLumi, 0.0, 10 * fNomLumi);
893
894 // only include a lumiConstraint if there's a lumi uncert, otherwise just set the lumi constant
895 if(fLumiError != 0) {
896 auto &nominalLumiVar = emplace<RooRealVar>(proto, "nominalLumi", fNomLumi, 0., fNomLumi + 10. * fLumiError);
898 proto.var("Lumi")->setError(fLumiError/fNomLumi); // give initial error value
899 proto.var("nominalLumi")->setConstant();
900 proto.defineSet("globalObservables","nominalLumi");
901 //likelihoodTermNames.push_back("lumiConstraint");
902 constraintTermNames.push_back("lumiConstraint");
903 } else {
904 proto.var("Lumi")->setConstant();
905 proto.defineSet("globalObservables",RooArgSet()); // create empty set as is assumed it exists later
906 }
907 ///////////////////////////////////
908 // loop through estimates, add expectation, floating bin predictions,
909 // and terms that constrain floating to expectation via uncertainties
910 // GHL: Loop over samples instead, which doesn't contain the data
911 for (Sample& sample : channel.GetSamples()) {
912 string overallSystName = sample.GetName() + "_" + channel_name + "_epsilon";
913
914 string systSourcePrefix = "alpha_";
915
916 // constraintTermNames and totSystTermNames are vectors that are passed
917 // by reference and filled by this method
919 sample.GetOverallSysList(), constraintTermNames , totSystTermNames);
920
921 allSampleHistFuncs.emplace_back();
922 std::vector<RooAbsArg*>& sampleHistFuncs = allSampleHistFuncs.back();
923
924 // GHL: Consider passing the NormFactor list instead of the entire sample
927
928 // Create the string for the object
929 // that is added to the RooRealSumPdf
930 // for this channel
931// string syst_x_expectedPrefix = "";
932
933 // get histogram
934 //ES// TH1* nominal = it->nominal;
935 const TH1* nominal = sample.GetHisto();
936
937 // MB : HACK no option to have both non-hist variations and hist variations ?
938 // get histogram
939 // GHL: Okay, this is going to be non-trivial.
940 // We will loop over histosys's, which contain both
941 // the low hist and the high hist together.
942
943 // Logic:
944 // - If we have no HistoSys's, do part A
945 // - else, if the histo syst's don't match, return (we ignore this case)
946 // - finally, we take the syst's and apply the linear interpolation w/ constraint
947 string expPrefix = sample.GetName() + "_" + channel_name;
948 // create roorealvar observables
949 RooArgList observables = createObservables(sample.GetHisto(), proto);
952
953 if(sample.GetHistoSysList().empty()) {
954 // If no HistoSys
955 cxcoutI(HistFactory) << sample.GetName() + "_" + channel_name + " has no variation histograms " << std::endl;
956
958 } else {
959 // If there ARE HistoSys(s)
960 // name of source for variation
961 string constraintPrefix = sample.GetName() + "_" + channel_name + "_Hist_alpha";
962
963 // make list of abstract parameters that interpolate in space of variations
965
966 // next, create the constraint terms
967 for(std::size_t i = 0; i < interpParams.size(); ++i) {
968 bool isUniform = measurement.GetUniformSyst().count(sample.GetHistoSysList()[i].GetName()) > 0;
970 }
971
972 // finally, create the interpolated function
974 sample.GetHistoSysList(), constraintPrefix, observables) );
975 }
976
977 sampleHistFuncs.front()->SetTitle( (nominal && strlen(nominal->GetTitle())>0) ? nominal->GetTitle() : sample.GetName().c_str() );
978
979 ////////////////////////////////////
980 // Add StatErrors to this Channel //
981 ////////////////////////////////////
982
983 if( sample.GetStatError().GetActivate() ) {
984
985 if( fObsNameVec.size() > 3 ) {
986 cxcoutFHF << "Cannot include Stat Error for histograms of more than 3 dimensions." << std::endl;
987 throw hf_exc();
988 } else {
989
990 // If we are using StatUncertainties, we multiply this object
991 // by the ParamHistFunc and then pass that to the
992 // RooRealSumPdf by appending it's name to the list
993
994 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " to be included in Stat Error "
995 << "for channel " << channel_name
996 << std::endl;
997
998 string UncertName = sample.GetName() + "_" + channel_name + "_StatAbsolUncert";
999 std::unique_ptr<TH1> statErrorHist;
1000
1001 if( sample.GetStatError().GetErrorHist() == nullptr ) {
1002 // Make the absolute stat error
1003 cxcoutI(HistFactory) << "Making Statistical Uncertainty Hist for "
1004 << " Channel: " << channel_name
1005 << " Sample: " << sample.GetName()
1006 << std::endl;
1008 } else {
1009 // clone the error histograms because in case the sample has not error hist
1010 // it is created in MakeAbsolUncertainty
1011 // we need later to clean statErrorHist
1012 statErrorHist.reset(static_cast<TH1*>(sample.GetStatError().GetErrorHist()->Clone()));
1013 // We assume the (relative) error is provided.
1014 // We must turn it into an absolute error
1015 // using the nominal histogram
1016 cxcoutI(HistFactory) << "Using external histogram for Stat Errors for "
1017 << "\tChannel: " << channel_name
1018 << "\tSample: " << sample.GetName()
1019 << "\tError Histogram: " << statErrorHist->GetName() << std::endl;
1020 // Multiply the relative stat uncertainty by the
1021 // nominal to get the overall stat uncertainty
1022 statErrorHist->Multiply( nominal );
1023 statErrorHist->SetName( UncertName.c_str() );
1024 }
1025
1026 // Save the nominal and error hists
1027 // for the building of constraint terms
1028 statHistPairs.emplace_back(nominal, std::move(statErrorHist));
1029
1030 // To do the 'conservative' version, we would need to do some
1031 // intervention here. We would probably need to create a different
1032 // ParamHistFunc for each sample in the channel. The would nominally
1033 // use the same gamma's, so we haven't increased the number of parameters
1034 // However, if a bin in the 'nominal' histogram is 0, we simply need to
1035 // change the parameter in that bin in the ParamHistFunc for this sample.
1036 // We also need to add a constraint term.
1037 // Actually, we'd probably not use the ParamHistFunc...?
1038 // we could remove the dependence in this ParamHistFunc on the ith gamma
1039 // and then create the poisson term: Pois(tau | n_exp)Pois(data | n_exp)
1040
1041
1042 // Next, try to get the common ParamHistFunc (it may have been
1043 // created by another sample in this channel)
1044 // or create it if it doesn't yet exist:
1045 RooAbsReal* paramHist = dynamic_cast<ParamHistFunc*>(proto.function(statFuncName) );
1046 if( paramHist == nullptr ) {
1047
1048 // Get a RooArgSet of the observables:
1049 // Names in the list fObsNameVec:
1051 std::vector<std::string>::iterator itr = fObsNameVec.begin();
1052 for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
1053 theObservables.add( *proto.var(*itr) );
1054 }
1055
1056 // Create the list of terms to
1057 // control the bin heights:
1058 std::string ParamSetPrefix = "gamma_stat_" + channel_name;
1063
1066
1068
1069 paramHist = proto.function( statFuncName);
1070 }
1071
1072 // apply stat function to sample
1073 sampleHistFuncs.push_back(paramHist);
1074 }
1075 } // END: if DoMcStat
1076
1077
1078 ///////////////////////////////////////////
1079 // Create a ShapeFactor for this channel //
1080 ///////////////////////////////////////////
1081
1082 if( !sample.GetShapeFactorList().empty() ) {
1083
1084 if( fObsNameVec.size() > 3 ) {
1085 cxcoutFHF << "Cannot include Stat Error for histograms of more than 3 dimensions." << std::endl;
1086 throw hf_exc();
1087 } else {
1088
1089 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " in channel: " << channel_name
1090 << " to be include a ShapeFactor."
1091 << std::endl;
1092
1093 for(ShapeFactor& shapeFactor : sample.GetShapeFactorList()) {
1094
1095 std::string funcName = channel_name + "_" + shapeFactor.GetName() + "_shapeFactor";
1096 RooAbsArg *paramHist = proto.function(funcName);
1097 if( paramHist == nullptr ) {
1098
1100 for(std::string const& varName : fObsNameVec) {
1101 theObservables.add( *proto.var(varName) );
1102 }
1103
1104 // Create the Parameters
1105 std::string funcParams = "gamma_" + shapeFactor.GetName();
1106
1107 // GHL: Again, we are putting hard ranges on the gamma's
1108 // We should change this to range from 0 to /inf
1110 funcParams,
1112
1113 // Create the Function
1116
1117 // Set an initial shape, if requested
1118 if( shapeFactor.GetInitialShape() != nullptr ) {
1119 TH1* initialShape = static_cast<TH1*>(shapeFactor.GetInitialShape()->Clone());
1120 cxcoutI(HistFactory) << "Setting Shape Factor: " << shapeFactor.GetName()
1121 << " to have initial shape from hist: "
1122 << initialShape->GetName()
1123 << std::endl;
1124 shapeFactorFunc.setShape( initialShape );
1125 }
1126
1127 // Set the variables constant, if requested
1128 if( shapeFactor.IsConstant() ) {
1129 cxcoutI(HistFactory) << "Setting Shape Factor: " << shapeFactor.GetName()
1130 << " to be constant" << std::endl;
1131 shapeFactorFunc.setConstant(true);
1132 }
1133
1135 paramHist = proto.function(funcName);
1136
1137 } // End: Create ShapeFactor ParamHistFunc
1138
1139 sampleHistFuncs.push_back(paramHist);
1140 } // End loop over ShapeFactor Systematics
1141 }
1142 } // End: if ShapeFactorName!=""
1143
1144
1145 ////////////////////////////////////////
1146 // Create a ShapeSys for this channel //
1147 ////////////////////////////////////////
1148
1149 if( !sample.GetShapeSysList().empty() ) {
1150
1151 if( fObsNameVec.size() > 3 ) {
1152 cxcoutFHF << "Cannot include Stat Error for histograms of more than 3 dimensions.\n";
1153 throw hf_exc();
1154 }
1155
1156 // List of ShapeSys ParamHistFuncs
1157 std::vector<string> ShapeSysNames;
1158
1159 for(RooStats::HistFactory::ShapeSys& shapeSys : sample.GetShapeSysList()) {
1160
1161 // Create the ParamHistFunc's
1162 // Create their constraint terms and add them
1163 // to the list of constraint terms
1164
1165 // Create a single RooProduct over all of these
1166 // paramHistFunc's
1167
1168 // Send the name of that product to the RooRealSumPdf
1169
1170 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " in channel: " << channel_name
1171 << " to include a ShapeSys." << std::endl;
1172
1173 std::string funcName = channel_name + "_" + shapeSys.GetName() + "_ShapeSys";
1174 ShapeSysNames.push_back( funcName );
1175 auto paramHist = static_cast<ParamHistFunc*>(proto.function(funcName));
1176 if( paramHist == nullptr ) {
1177
1178 //std::string funcParams = "gamma_" + it->shapeFactorName;
1179 //paramHist = CreateParamHistFunc( proto, fObsNameVec, funcParams, funcName );
1180
1182 for(std::string const& varName : fObsNameVec) {
1183 theObservables.add( *proto.var(varName) );
1184 }
1185
1186 // Create the Parameters
1187 std::string funcParams = "gamma_" + shapeSys.GetName();
1189 funcParams,
1191
1192 // Create the Function
1195
1197 paramHist = static_cast<ParamHistFunc*>(proto.function(funcName));
1198
1199 } // End: Create ShapeFactor ParamHistFunc
1200
1201 // Create the constraint terms and add
1202 // them to the workspace (proto)
1203 // as well as the list of constraint terms (constraintTermNames)
1204
1205 // The syst should be a fractional error
1206 const TH1* shapeErrorHist = shapeSys.GetErrorHist();
1207
1208 // Constraint::Type shapeConstraintType = Constraint::Gaussian;
1209 Constraint::Type systype = shapeSys.GetConstraintType();
1212 }
1213 if( systype == Constraint::Poisson ) {
1215 }
1216
1218 paramHist->paramList(), histToVector(*shapeErrorHist),
1220 systype);
1221 for (auto const& term : shapeConstraintsInfo.constraints) {
1223 constraintTermNames.emplace_back(term->GetName());
1224 }
1225 // Add the "observed" value to the list of global observables:
1226 RooArgSet *globalSet = const_cast<RooArgSet *>(proto.set("globalObservables"));
1227 for (RooAbsArg * glob : shapeConstraintsInfo.globalObservables) {
1228 globalSet->add(*proto.var(glob->GetName()));
1229 }
1230
1231
1232 } // End: Loop over ShapeSys vector in this EstimateSummary
1233
1234 // Now that we have the list of ShapeSys ParamHistFunc names,
1235 // we create the total RooProduct
1236 // we multiply the expected function
1237
1238 for(std::string const& name : ShapeSysNames) {
1239 sampleHistFuncs.push_back(proto.function(name));
1240 }
1241
1242 } // End: !GetShapeSysList.empty()
1243
1244
1245 // GHL: This was pretty confusing before,
1246 // hopefully using the measurement directly
1247 // will improve it
1248 RooAbsArg *lumi = proto.arg("Lumi");
1249 if( !sample.GetNormalizeByTheory() ) {
1250 if (!lumi) {
1251 lumi = &emplace<RooRealVar>(proto, "Lumi", measurement.GetLumi());
1252 } else {
1253 static_cast<RooAbsRealLValue*>(lumi)->setVal(measurement.GetLumi());
1254 }
1255 }
1256 assert(lumi);
1257 normFactors->addTerm(lumi);
1258
1259 // Append the name of the "node"
1260 // that is to be summed with the
1261 // RooRealSumPdf
1263 auto normFactorsInWS = dynamic_cast<RooProduct*>(proto.arg(normFactors->GetName()));
1265
1267 } // END: Loop over EstimateSummaries
1268
1269 // If a non-zero number of samples call for
1270 // Stat Uncertainties, create the statFactor functions
1271 if(!statHistPairs.empty()) {
1272
1273 // Create the histogram of (binwise)
1274 // stat uncertainties:
1275 std::unique_ptr<TH1> fracStatError(
1276 MakeScaledUncertaintyHist(channel_name + "_StatUncert" + "_RelErr", statHistPairs));
1277 if( fracStatError == nullptr ) {
1278 cxcoutFHF << "Error: Failed to make ScaledUncertaintyHist for: " << channel_name + "_StatUncert" + "_RelErr\n";
1279 throw hf_exc();
1280 }
1281
1282 // Using this TH1* of fractinal stat errors,
1283 // create a set of constraint terms:
1284 auto chanStatUncertFunc = static_cast<ParamHistFunc*>(proto.function( statFuncName ));
1285 cxcoutI(HistFactory) << "About to create Constraint Terms from: "
1286 << chanStatUncertFunc->GetName()
1287 << " params: " << chanStatUncertFunc->paramList()
1288 << std::endl;
1289
1290 // Get the constraint type and the
1291 // rel error threshold from the (last)
1292 // EstimateSummary looped over (but all
1293 // should be the same)
1294
1295 // Get the type of StatError constraint from the channel
1298 cxcoutI(HistFactory) << "Using Gaussian StatErrors in channel: " << channel.GetName() << std::endl;
1299 }
1301 cxcoutI(HistFactory) << "Using Poisson StatErrors in channel: " << channel.GetName() << std::endl;
1302 }
1303
1309 for (auto const& term : statConstraintsInfo.constraints) {
1311 constraintTermNames.emplace_back(term->GetName());
1312 }
1313 // Add the "observed" value to the list of global observables:
1314 RooArgSet *globalSet = const_cast<RooArgSet *>(proto.set("globalObservables"));
1315 for (RooAbsArg * glob : statConstraintsInfo.globalObservables) {
1316 globalSet->add(*proto.var(glob->GetName()));
1317 }
1318
1319 } // END: Loop over stat Hist Pairs
1320
1321
1322 ///////////////////////////////////
1323 // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
1326 likelihoodTermNames.push_back(channel_name+"_model");
1327
1328 //////////////////////////////////////
1329 // fix specified parameters
1330 for(unsigned int i=0; i<systToFix.size(); ++i){
1331 RooRealVar* temp = proto.var(systToFix.at(i));
1332 if(!temp) {
1333 cxcoutW(HistFactory) << "could not find variable " << systToFix.at(i)
1334 << " could not set it to constant" << std::endl;
1335 } else {
1336 // set the parameter constant
1337 temp->setConstant();
1338 }
1339 }
1340
1341 //////////////////////////////////////
1342 // final proto model
1343 for(unsigned int i=0; i<constraintTermNames.size(); ++i){
1345 if( proto_arg==nullptr ) {
1346 cxcoutFHF << "Error: Cannot find arg set: " << constraintTermNames.at(i)
1347 << " in workspace: " << proto.GetName() << std::endl;
1348 throw hf_exc();
1349 }
1350 constraintTerms.add( *proto_arg );
1351 // constraintTerms.add(* proto_arg(proto.arg(constraintTermNames[i].c_str())) );
1352 }
1353 for(unsigned int i=0; i<likelihoodTermNames.size(); ++i){
1355 if( proto_arg==nullptr ) {
1356 cxcoutFHF << "Error: Cannot find arg set: " << likelihoodTermNames.at(i)
1357 << " in workspace: " << proto.GetName() << std::endl;
1358 throw hf_exc();
1359 }
1360 likelihoodTerms.add( *proto_arg );
1361 }
1362 proto.defineSet("constraintTerms",constraintTerms);
1363 proto.defineSet("likelihoodTerms",likelihoodTerms);
1364
1365 // list of observables
1366 RooArgList observables;
1367 std::string observablesStr;
1368
1369 for(std::string const& name : fObsNameVec) {
1370 observables.add( *proto.var(name) );
1371 if (!observablesStr.empty()) { observablesStr += ","; }
1373 }
1374
1375 // We create two sets, one for backwards compatibility
1376 // The other to make a consistent naming convention
1377 // between individual channels and the combined workspace
1378 proto.defineSet("observables", observablesStr.c_str());
1379 proto.defineSet("observablesSet", observablesStr.c_str());
1380
1381 // Create the ParamHistFunc
1382 // after observables have been made
1383 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1384 << "\timport model into workspace"
1385 << "\n-----------------------------------------\n" << std::endl;
1386
1387 auto model = std::make_unique<RooProdPdf>(
1388 ("model_" + channel_name).c_str(), // MB : have changed this into conditional pdf. Much faster for toys!
1389 "product of Poissons across bins for a single channel", constraintTerms,
1390 RooFit::Conditional(likelihoodTerms, observables));
1391 // can give channel a title by setting title of corresponding data histogram
1392 if (channel.GetData().GetHisto() && strlen(channel.GetData().GetHisto()->GetTitle())>0) {
1393 model->SetTitle(channel.GetData().GetHisto()->GetTitle());
1394 }
1395 proto.import(*model,RooFit::RecycleConflictNodes());
1396
1397 proto_config->SetPdf(*model);
1398 proto_config->SetObservables(observables);
1399 proto_config->SetGlobalObservables(*proto.set("globalObservables"));
1400 // proto.writeToFile(("results/model_"+channel+".root").c_str());
1401 // fill out nuisance parameters in model config
1402 // proto_config->GuessObsAndNuisance(*proto.data("asimovData"));
1403 proto.import(*proto_config,proto_config->GetName());
1404 proto.importClassCode();
1405
1406 ///////////////////////////
1407 // make data sets
1408 // THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
1409 // New Asimov Generation: Use the code in the Asymptotic calculator
1410 // Need to get the ModelConfig...
1411 int asymcalcPrintLevel = 0;
1415 if (fCfg.createPerRegionWorkspaces) {
1416 // Creating the per-channel asimov dataset is only meaningful if we
1417 // actually create the files with the stored per-channel workspaces.
1418 // Otherwise, we just spend time calculating something that gets thrown
1419 // away anyway (for the combined workspace, we'll create a new Asimov).
1420 std::unique_ptr<RooAbsData> asimov_dataset(AsymptoticCalculator::GenerateAsimovData(*model, observables));
1421 proto.import(*asimov_dataset, RooFit::Rename("asimovData"));
1422 }
1423
1424 // GHL: Determine to use data if the hist isn't 'nullptr'
1425 if(TH1 const* mnominal = channel.GetData().GetHisto()) {
1426 // This works and is natural, but the memory size of the simultaneous
1427 // dataset grows exponentially with channels.
1428 std::unique_ptr<RooDataSet> dataset;
1429 if(!fCfg.storeDataError){
1430 dataset = std::make_unique<RooDataSet>("obsData","",*proto.set("observables"), RooFit::WeightVar("weightVar"));
1431 } else {
1432 const char* weightErrName="weightErr";
1433 proto.factory(TString::Format("%s[0,-1e10,1e10]",weightErrName));
1434 dataset = std::make_unique<RooDataSet>("obsData","",*proto.set("observables"), RooFit::WeightVar("weightVar"), RooFit::StoreError(*proto.var(weightErrName)));
1435 }
1437 proto.import(*dataset);
1438 } // End: Has non-null 'data' entry
1439
1440
1441 for(auto const& data : channel.GetAdditionalData()) {
1442 if(data.GetName().empty()) {
1443 cxcoutFHF << "Error: Additional Data histogram for channel: " << channel.GetName()
1444 << " has no name! The name always needs to be set for additional datasets, "
1445 << "either via the \"Name\" tag in the XML or via RooStats::HistFactory::Data::SetName().\n";
1446 throw hf_exc();
1447 }
1448 std::string const& dataName = data.GetName();
1449 TH1 const* mnominal = data.GetHisto();
1450 if( !mnominal ) {
1451 cxcoutFHF << "Error: Additional Data histogram for channel: " << channel.GetName()
1452 << " with name: " << dataName << " is nullptr\n";
1453 throw hf_exc();
1454 }
1455
1456 // THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
1457 RooDataSet dataset{dataName, "", *proto.set("observables"), RooFit::WeightVar("weightVar")};
1459 proto.import(dataset);
1460
1461 }
1462
1463 if (RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::INFO)) {
1464 proto.Print();
1465 }
1466
1467 return protoOwner;
1468 }
1469
1470
1472 TH1 const& mnominal,
1474 std::vector<std::string> const& obsNameVec) {
1475
1476 // Take a RooDataSet and fill it with the entries
1477 // from a TH1*, using the observable names to
1478 // determine the columns
1479
1480 if (obsNameVec.empty() ) {
1481 Error("ConfigureHistFactoryDataset","Invalid input - return");
1482 return;
1483 }
1484
1485 TAxis const* ax = mnominal.GetXaxis();
1486 TAxis const* ay = mnominal.GetYaxis();
1487 TAxis const* az = mnominal.GetZaxis();
1488
1489 // check whether the dataset needs the errors stored explicitly
1490 const bool storeWeightErr = obsDataUnbinned.weightVar()->getAttribute("StoreError");
1491
1492 for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension
1493
1494 double xval = ax->GetBinCenter(i);
1495 proto.var( obsNameVec[0] )->setVal( xval );
1496
1497 if(obsNameVec.size()==1) {
1498 double fval = mnominal.GetBinContent(i);
1499 double ferr = storeWeightErr ? mnominal.GetBinError(i) : 0.;
1500 obsDataUnbinned.add( *proto.set("observables"), fval, ferr );
1501 } else { // 2 or more dimensions
1502
1503 for(int j=1; j<=ay->GetNbins(); ++j) {
1504 double yval = ay->GetBinCenter(j);
1505 proto.var( obsNameVec[1] )->setVal( yval );
1506
1507 if(obsNameVec.size()==2) {
1508 double fval = mnominal.GetBinContent(i,j);
1509 double ferr = storeWeightErr ? mnominal.GetBinError(i, j) : 0.;
1510 obsDataUnbinned.add( *proto.set("observables"), fval, ferr );
1511 } else { // 3 dimensions
1512
1513 for(int k=1; k<=az->GetNbins(); ++k) {
1514 double zval = az->GetBinCenter(k);
1515 proto.var( obsNameVec[2] )->setVal( zval );
1516 double fval = mnominal.GetBinContent(i,j,k);
1517 double ferr = storeWeightErr ? mnominal.GetBinError(i, j, k) : 0.;
1518 obsDataUnbinned.add( *proto.set("observables"), fval, ferr );
1519 }
1520 }
1521 }
1522 }
1523 }
1524 }
1525
1527 {
1528 fObsNameVec = std::vector<string>{"x", "y", "z"};
1529 fObsNameVec.resize(hist->GetDimension());
1530 }
1531
1532
1535 std::vector<std::unique_ptr<RooWorkspace>> &chs)
1536 {
1538
1539 // check first the inputs (see JIRA-6890)
1540 if (ch_names.empty() || chs.empty() ) {
1541 Error("MakeCombinedModel","Input vectors are empty - return a nullptr");
1542 return nullptr;
1543 }
1544 if (chs.size() < ch_names.size() ) {
1545 Error("MakeCombinedModel","Input vector of workspace has an invalid size - return a nullptr");
1546 return nullptr;
1547 }
1548 std::set<std::string> ch_names_set{ch_names.begin(), ch_names.end()};
1549 if (ch_names.size() != ch_names_set.size()) {
1550 Error("MakeCombinedModel", "Input vector of channel names has duplicate names - return a nullptr");
1551 return nullptr;
1552 }
1553
1554 //
1555 /// These things were used for debugging. Maybe useful in the future
1556 //
1557
1558 std::map<string, RooAbsPdf *> pdfMap;
1560
1562 for (unsigned int i = 0; i < ch_names.size(); ++i) {
1563 obsList.add(*static_cast<ModelConfig *>(chs[i]->obj("ModelConfig"))->GetObservables());
1564 }
1565 cxcoutI(HistFactory) <<"full list of observables:\n" << obsList << std::endl;
1566
1568 std::map<std::string, int> channelMap;
1569 for(unsigned int i = 0; i< ch_names.size(); ++i){
1570 string channel_name=ch_names[i];
1571 if (i == 0 && isdigit(channel_name[0])) {
1572 throw std::invalid_argument("The first channel name for HistFactory cannot start with a digit. Got " + channel_name);
1573 }
1574 if (channel_name.find(',') != std::string::npos) {
1575 throw std::invalid_argument("Channel names for HistFactory cannot contain ','. Got " + channel_name);
1576 }
1577
1579 RooWorkspace * ch=chs[i].get();
1580
1581 RooAbsPdf* model = ch->pdf("model_"+channel_name);
1582 if (!model) {
1583 cxcoutFHF << "failed to find model for channel\n";
1584 throw hf_exc();
1585 }
1586 models.push_back(model);
1587 auto &modelConfig = *static_cast<ModelConfig *>(chs[i]->obj("ModelConfig"));
1588 // silent because observables might exist in other channel:
1589 globalObs.add(*modelConfig.GetGlobalObservables(), /*silent=*/true);
1590
1591 // constrainedParams->add( * ch->set("constrainedParams") );
1592 pdfMap[channel_name]=model;
1593 }
1594
1595 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1596 << "\tEntering combination"
1597 << "\n-----------------------------------------\n" << std::endl;
1598 auto combined = std::make_unique<RooWorkspace>("combined");
1599
1600
1602
1603 auto simPdf= std::make_unique<RooSimultaneous>("simPdf","",pdfMap, channelCat);
1604 auto combined_config = std::make_unique<ModelConfig>("ModelConfig", combined.get());
1605 combined_config->SetWorkspace(*combined);
1606 // combined_config->SetNuisanceParameters(*constrainedParams);
1607
1608 combined->import(globalObs);
1609 combined->defineSet("globalObservables",globalObs);
1610 combined_config->SetGlobalObservables(*combined->set("globalObservables"));
1611
1612 combined->defineSet("observables",{obsList, channelCat}, /*importMissing=*/true);
1613 combined_config->SetObservables(*combined->set("observables"));
1614
1615 // Check if the channel datasets are consistent
1616 {
1617 bool isConsistent = false;
1618 std::string errMsg;
1619 std::set<std::string> allowedInconsistent{"asimovData"};
1621 if (!isConsistent) {
1622 cxcoutFHF << errMsg;
1623 throw hf_exc();
1624 }
1625 }
1626
1627 // Now merge the observable datasets across the channels
1628 for(RooAbsData * data : chs[0]->allData()) {
1629 // We are excluding the Asimov data, because it needs to be regenerated
1630 // later after the parameter values are set.
1631 if(std::string("asimovData") == data->GetName()) {
1632 continue;
1633 }
1634 // Loop through channels, get their individual datasets,
1635 // and add them to the combined dataset
1636 std::map<std::string, RooAbsData*> dataMap;
1637 for(unsigned int i = 0; i < ch_names.size(); ++i){
1638 dataMap[ch_names[i]] = chs[i]->data(data->GetName());
1639 }
1640 combined->import(RooDataSet{data->GetName(), "", obsList, RooFit::Index(channelCat),
1641 RooFit::WeightVar("weightVar"), RooFit::Import(dataMap)});
1642 }
1643
1644
1646 combined->Print();
1647
1648 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1649 << "\tImporting combined model"
1650 << "\n-----------------------------------------\n" << std::endl;
1652
1653 for(auto const& param_itr : fParamValues) {
1654 // make sure they are fixed
1655 std::string paramName = param_itr.first;
1656 double paramVal = param_itr.second;
1657
1658 if(RooRealVar* temp = combined->var( paramName )) {
1659 temp->setVal( paramVal );
1660 cxcoutI(HistFactory) <<"setting " << paramName << " to the value: " << paramVal << std::endl;
1661 } else
1662 cxcoutE(HistFactory) << "could not find variable " << paramName << " could not set its value" << std::endl;
1663 }
1664
1665
1666 for(unsigned int i=0; i<fSystToFix.size(); ++i){
1667 // make sure they are fixed
1668 if(RooRealVar* temp = combined->var(fSystToFix[i])) {
1669 temp->setConstant();
1670 cxcoutI(HistFactory) <<"setting " << fSystToFix.at(i) << " constant" << std::endl;
1671 } else
1672 cxcoutE(HistFactory) << "could not find variable " << fSystToFix.at(i) << " could not set it to constant" << std::endl;
1673 }
1674
1675 ///
1676 /// writing out the model in graphViz
1677 ///
1678 // RooAbsPdf* customized=combined->pdf("simPdf");
1679 //combined_config->SetPdf(*customized);
1680 combined_config->SetPdf(*simPdf);
1681 // combined_config->GuessObsAndNuisance(*simData);
1682 // customized->graphVizTree(("results/"+fResultsPrefixStr.str()+"_simul.dot").c_str());
1683 combined->import(*combined_config,combined_config->GetName());
1684 combined->importClassCode();
1685 // combined->writeToFile("results/model_combined.root");
1686
1687
1688 ////////////////////////////////////////////
1689 // Make toy simultaneous dataset
1690 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1691 << "\tcreate toy data"
1692 << "\n-----------------------------------------\n" << std::endl;
1693
1694
1695 // now with weighted datasets
1696 // First Asimov
1697
1698 // Create Asimov data for the combined dataset
1700 *combined->pdf("simPdf"),
1701 obsList)};
1702 if( asimov_combined ) {
1703 combined->import( *asimov_combined, RooFit::Rename("asimovData"));
1704 }
1705 else {
1706 cxcoutFHF << "Error: Failed to create combined asimov dataset\n";
1707 throw hf_exc();
1708 }
1709
1710 return RooFit::makeOwningPtr(std::move(combined));
1711 }
1712
1713
1715
1716 // Take a nominal TH1* and create
1717 // a TH1 representing the binwise
1718 // errors (taken from the nominal TH1)
1719
1720 auto ErrorHist = static_cast<TH1*>(Nominal->Clone( Name.c_str() ));
1721 ErrorHist->Reset();
1722
1723 int numBins = Nominal->GetNbinsX()*Nominal->GetNbinsY()*Nominal->GetNbinsZ();
1724 int binNumber = 0;
1725
1726 // Loop over bins
1727 for( int i_bin = 0; i_bin < numBins; ++i_bin) {
1728
1729 binNumber++;
1730 // Ignore underflow / overflow
1731 while( Nominal->IsBinUnderflow(binNumber) || Nominal->IsBinOverflow(binNumber) ){
1732 binNumber++;
1733 }
1734
1735 double histError = Nominal->GetBinError( binNumber );
1736
1737 // Check that histError != NAN
1738 if( histError != histError ) {
1739 cxcoutFHF << "Warning: In histogram " << Nominal->GetName() << " bin error for bin " << i_bin
1740 << " is NAN. Not using Error!!!\n";
1741 throw hf_exc();
1742 // histError = sqrt( histContent );
1743 // histError = 0;
1744 }
1745
1746 // Check that histError ! < 0
1747 if( histError < 0 ) {
1748 cxcoutWHF << "Warning: In histogram " << Nominal->GetName() << " bin error for bin " << binNumber
1749 << " is < 0. Setting Error to 0" << std::endl;
1750 // histError = sqrt( histContent );
1751 histError = 0;
1752 }
1753
1754 ErrorHist->SetBinContent( binNumber, histError );
1755
1756 }
1757
1758 return ErrorHist;
1759
1760 }
1761
1762 // Take a list of < nominal, absolError > TH1* pairs
1763 // and construct a single histogram representing the
1764 // total fractional error as:
1765
1766 // UncertInQuad(bin i) = Sum: absolUncert*absolUncert
1767 // Total(bin i) = Sum: Value
1768 //
1769 // TotalFracError(bin i) = Sqrt( UncertInQuad(i) ) / TotalBin(i)
1770 std::unique_ptr<TH1> HistoToWorkspaceFactoryFast::MakeScaledUncertaintyHist( const std::string& Name, std::vector< std::pair<const TH1*, std::unique_ptr<TH1>> > const& HistVec ) const {
1771
1772
1773 unsigned int numHists = HistVec.size();
1774
1775 if( numHists == 0 ) {
1776 cxcoutE(HistFactory) << "Warning: Empty Hist Vector, cannot create total uncertainty" << std::endl;
1777 return nullptr;
1778 }
1779
1780 const TH1* HistTemplate = HistVec.at(0).first;
1781 int numBins = HistTemplate->GetNbinsX()*HistTemplate->GetNbinsY()*HistTemplate->GetNbinsZ();
1782
1783 // Check that all histograms
1784 // have the same bins
1785 for( unsigned int i = 0; i < HistVec.size(); ++i ) {
1786
1787 const TH1* nominal = HistVec.at(i).first;
1788 const TH1* error = HistVec.at(i).second.get();
1789
1790 if( nominal->GetNbinsX()*nominal->GetNbinsY()*nominal->GetNbinsZ() != numBins ) {
1791 cxcoutE(HistFactory) << "Error: Provided hists have unequal bins" << std::endl;
1792 return nullptr;
1793 }
1794 if( error->GetNbinsX()*error->GetNbinsY()*error->GetNbinsZ() != numBins ) {
1795 cxcoutE(HistFactory) << "Error: Provided hists have unequal bins" << std::endl;
1796 return nullptr;
1797 }
1798 }
1799
1800 std::vector<double> TotalBinContent( numBins, 0.0);
1801 std::vector<double> HistErrorsSqr( numBins, 0.0);
1802
1803 int binNumber = 0;
1804
1805 // Loop over bins
1806 for( int i_bins = 0; i_bins < numBins; ++i_bins) {
1807
1808 binNumber++;
1809 while( HistTemplate->IsBinUnderflow(binNumber) || HistTemplate->IsBinOverflow(binNumber) ){
1810 binNumber++;
1811 }
1812
1813 for( unsigned int i_hist = 0; i_hist < numHists; ++i_hist ) {
1814
1815 const TH1* nominal = HistVec.at(i_hist).first;
1816 const TH1* error = HistVec.at(i_hist).second.get();
1817
1818 //int binNumber = i_bins + 1;
1819
1820 double histValue = nominal->GetBinContent( binNumber );
1821 double histError = error->GetBinContent( binNumber );
1822
1823 if( histError != histError ) {
1824 cxcoutFHF << "In histogram " << error->GetName() << " bin error for bin " << binNumber
1825 << " is NAN. Not using error!!";
1826 throw hf_exc();
1827 }
1828
1830 HistErrorsSqr.at(i_bins) += histError*histError; // Add in quadrature
1831
1832 }
1833 }
1834
1835 binNumber = 0;
1836
1837 // Creat the output histogram
1838 TH1* ErrorHist = static_cast<TH1*>(HistTemplate->Clone( Name.c_str() ));
1839 ErrorHist->Reset();
1840
1841 // Fill the output histogram
1842 for( int i = 0; i < numBins; ++i) {
1843
1844 // int binNumber = i + 1;
1845 binNumber++;
1846 while( ErrorHist->IsBinUnderflow(binNumber) || ErrorHist->IsBinOverflow(binNumber) ){
1847 binNumber++;
1848 }
1849
1850 double ErrorsSqr = HistErrorsSqr.at(i);
1851 double TotalVal = TotalBinContent.at(i);
1852
1853 if( TotalVal <= 0 ) {
1854 cxcoutW(HistFactory) << "Warning: Sum of histograms for bin: " << binNumber
1855 << " is <= 0. Setting error to 0"
1856 << std::endl;
1857
1858 ErrorHist->SetBinContent( binNumber, 0.0 );
1859 continue;
1860 }
1861
1862 double RelativeError = sqrt(ErrorsSqr) / TotalVal;
1863
1864 // If we otherwise get a NAN
1865 // it's an error
1866 if( RelativeError != RelativeError ) {
1867 cxcoutE(HistFactory) << "Error: bin " << i << " error is NAN\n"
1868 << " HistErrorsSqr: " << ErrorsSqr
1869 << " TotalVal: " << TotalVal;
1870 throw hf_exc();
1871 }
1872
1873 // 0th entry in vector is
1874 // the 1st bin in TH1
1875 // (we ignore underflow)
1876
1877 // Error and bin content are interchanged because for some reason, the other functions
1878 // use the bin content to convey the error ...
1879 ErrorHist->SetBinError(binNumber, TotalVal);
1880 ErrorHist->SetBinContent(binNumber, RelativeError);
1881
1882 cxcoutI(HistFactory) << "Making Total Uncertainty for bin " << binNumber
1883 << " Error = " << sqrt(ErrorsSqr)
1884 << " CentralVal = " << TotalVal
1885 << " RelativeError = " << RelativeError << "\n";
1886
1887 }
1888
1889 return std::unique_ptr<TH1>(ErrorHist);
1890}
1891
1892} // namespace RooStats::HistFactory
#define cxcoutPHF
#define cxcoutFHF
#define cxcoutIHF
#define cxcoutWHF
std::vector< double > histToVector(TH1 const &hist)
constexpr double alphaHigh
constexpr double alphaLow
#define cxcoutI(a)
#define cxcoutW(a)
#define cxcoutF(a)
#define cxcoutE(a)
#define cxcoutP(a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
char name[80]
Definition TGX11.cxx:110
const char * proto
Definition civetweb.c:18822
A class which maps the current values of a RooRealVar (or a set of RooRealVars) to one of a number of...
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.
The PiecewiseInterpolation is a class that can morph distributions into each other,...
const_iterator begin() const
const_iterator end() const
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:56
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
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...
Definition RooAbsReal.h:63
Calculates the sum of a set of RooAbsReal terms, or when constructed with two sets,...
Definition RooAddition.h:27
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Implements a RooAbsBinning in terms of an array of boundary values, posing no constraints on the choi...
Definition RooBinning.h:27
Object to represent discrete states.
Definition RooCategory.h:28
Container class to hold N-dimensional binned data.
Definition RooDataHist.h:40
Container class to hold unbinned data.
Definition RooDataSet.h:32
RooFitResult is a container class to hold the input and output of a PDF fit to a dataset.
A RooFormulaVar is a generic implementation of a real-valued object, which takes a RooArgList of serv...
Implementation of the Gamma PDF for RooFit/RooStats.
Definition RooGamma.h:20
Switches the message service to a different level while the instance is alive.
Definition RooHelpers.h:37
A real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:31
static RooMsgService & instance()
Return reference to singleton instance.
A RooAbsReal implementing a polynomial in terms of a list of RooAbsReal coefficients.
Definition RooPolyVar.h:25
Represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
Implements a PDF constructed from a sum of functions:
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setBinning(const RooAbsBinning &binning, const char *name=nullptr)
Add given binning under name 'name' with this variable.
void setBins(Int_t nBins, const char *name=nullptr)
Create a uniform binning under name 'name' for 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
std::vector< RooStats::HistFactory::Sample > & GetSamples()
get vector of samples for this channel
std::string GetName() const
get name of channel
This class provides helper functions for creating likelihood models from histograms.
std::unique_ptr< RooProduct > CreateNormFactor(RooWorkspace &proto, std::string &channel, std::string &sigmaEpsilon, Sample &sample, bool doRatio)
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
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)
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)
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)
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...
Configuration for an un- constrained overall systematic to scale sample normalisations.
Definition Measurement.h:69
Configuration for a constrained overall systematic to scale sample normalisations.
Definition Measurement.h:45
*Un*constrained bin-by-bin variation of affected histogram.
Constrained bin-by-bin variation of affected histogram.
Constraint::Type GetConstraintType() const
< A class that holds configuration information for a model using a workspace as a store
Definition ModelConfig.h:34
Persistable container for RooFit projects.
RooAbsPdf * pdf(RooStringView name) const
Retrieve p.d.f (RooAbsPdf) with given name. A null pointer is returned if not found.
RooAbsArg * arg(RooStringView name) const
Return RooAbsArg with given name. A null pointer is returned if none is found.
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.
Class to manage histogram axis.
Definition TAxis.h:32
Bool_t IsVariableBinSize() const
Definition TAxis.h:144
const char * GetTitle() const override
Returns title of object.
Definition TAxis.h:137
const TArrayD * GetXbins() const
Definition TAxis.h:138
Double_t GetXmax() const
Definition TAxis.h:142
Double_t GetXmin() const
Definition TAxis.h:141
Int_t GetNbins() const
Definition TAxis.h:127
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:109
TAxis * GetZaxis()
Definition TH1.h:573
virtual Int_t GetNbinsY() const
Definition TH1.h:542
virtual Int_t GetNbinsZ() const
Definition TH1.h:543
virtual Int_t GetDimension() const
Definition TH1.h:527
TAxis * GetXaxis()
Definition TH1.h:571
virtual Int_t GetNbinsX() const
Definition TH1.h:541
TAxis * GetYaxis()
Definition TH1.h:572
Bool_t IsBinUnderflow(Int_t bin, Int_t axis=0) const
Return true if the bin is underflow.
Definition TH1.cxx:5234
Bool_t IsBinOverflow(Int_t bin, Int_t axis=0) const
Return true if the bin is overflow.
Definition TH1.cxx:5202
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5081
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1088
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2384
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...
Definition Config.h:35
@ ObjectHandling
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:40
CreateGammaConstraintsOutput createGammaConstraints(RooArgList const &paramList, std::span< const double > relSigmas, double minSigma, Constraint::Type type)
Namespace for the RooStats classes.
Definition CodegenImpl.h:61