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 "RooGlobalFunc.h"
23#include "RooDataSet.h"
24#include "RooRealVar.h"
25#include "RooConstVar.h"
26#include "RooProduct.h"
27#include "RooProdPdf.h"
28#include "RooGaussian.h"
29#include "RooPoisson.h"
30#include "RooRandom.h"
31#include "RooCategory.h"
32#include "RooSimultaneous.h"
33#include "RooMultiVarGaussian.h"
34#include "RooNumIntConfig.h"
35#include "RooProfileLL.h"
36#include "RooFitResult.h"
37#include "RooDataHist.h"
38#include "RooHistFunc.h"
39#include "RooRealSumPdf.h"
40#include "RooWorkspace.h"
41#include "RooHelpers.h"
42#include "RooBinning.h"
43#include "RooBinWidthFunction.h"
44#include "RooFit/ModelConfig.h"
45
50
51#include "HFMsgService.h"
52
53#include "TH1.h"
54#include "TStopwatch.h"
55#include "TVectorD.h"
56#include "TMatrixDSym.h"
57
58// specific to this package
65
66#include <algorithm>
67#include <memory>
68#include <utility>
69
70constexpr double alphaLow = -5.0;
71constexpr double alphaHigh = 5.0;
72
73std::vector<double> histToVector(TH1 const &hist)
74{
75 // Must get the full size of the TH1 (No direct method to do this...)
76 int numBins = hist.GetNbinsX() * hist.GetNbinsY() * hist.GetNbinsZ();
77 std::vector<double> out(numBins);
78 int histIndex = 0;
79 for (int i = 0; i < numBins; ++i) {
80 while (hist.IsBinUnderflow(histIndex) || hist.IsBinOverflow(histIndex)) {
81 ++histIndex;
82 }
83 out[i] = hist.GetBinContent(histIndex);
84 ++histIndex;
85 }
86 return out;
87}
88
89// use this order for safety on library loading
90using namespace RooStats ;
91using namespace std ;
92
93using namespace RooStats::HistFactory::Detail;
95
97
98namespace RooStats{
99namespace HistFactory{
100
103
105 Configuration const& cfg) :
106 fSystToFix( measurement.GetConstantParams() ),
107 fParamValues( measurement.GetParamValues() ),
108 fNomLumi( measurement.GetLumi() ),
109 fLumiError( measurement.GetLumi()*measurement.GetLumiRelErr() ),
110 fLowBin( measurement.GetBinLow() ),
111 fHighBin( measurement.GetBinHigh() ),
112 fCfg{cfg} {
113
114 // Set Preprocess functions
116
117 }
118
119 void HistoToWorkspaceFactoryFast::ConfigureWorkspaceForMeasurement( const std::string& ModelName, RooWorkspace* ws_single, Measurement& measurement ) {
120
121 // Configure a workspace by doing any
122 // necessary post-processing and by
123 // creating a ModelConfig
124
125 // Make a ModelConfig and configure it
126 ModelConfig * proto_config = (ModelConfig *) ws_single->obj("ModelConfig");
127 if( proto_config == nullptr ) {
128 std::cout << "Error: Did not find 'ModelConfig' object in file: " << ws_single->GetName()
129 << 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() << 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 std::cout << "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 // Set the ModelConfig's Params of Interest
162 RooAbsData* expData = ws_single->data("asimovData");
163 if( !expData ) {
164 std::cout << "Error: Failed to find dataset: " << expData
165 << " in workspace" << std::endl;
166 throw hf_exc();
167 }
168 if(!measurement.GetPOIList().empty()){
169 proto_config->GuessObsAndNuisance(*expData, RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::INFO));
170 }
171
172 // Now, let's loop over any additional asimov datasets
173 // that we need to make
174
175 // Get the pdf
176 // Notice that we get the "new" pdf, this is the one that is
177 // used in the creation of these asimov datasets since they
178 // are fitted (or may be, at least).
179 RooAbsPdf* pdf = ws_single->pdf(NewModelName);
180 if( !pdf ) pdf = ws_single->pdf( ModelName );
181 const RooArgSet* observables = ws_single->set("observables");
182
183 // Create a SnapShot of the nominal values
184 std::string SnapShotName = "NominalParamValues";
185 ws_single->saveSnapshot(SnapShotName, ws_single->allVars());
186
187 for( unsigned int i=0; i<measurement.GetAsimovDatasets().size(); ++i) {
188
189 // Set the variable values and "const" ness with the workspace
190 RooStats::HistFactory::Asimov& asimov = measurement.GetAsimovDatasets().at(i);
191 std::string AsimovName = asimov.GetName();
192
193 cxcoutPHF << "Generating additional Asimov Dataset: " << AsimovName << std::endl;
194 asimov.ConfigureWorkspace(ws_single);
195 std::unique_ptr<RooAbsData> asimov_dataset{AsymptoticCalculator::GenerateAsimovData(*pdf, *observables)};
196
197 cxcoutPHF << "Importing Asimov dataset" << std::endl;
198 bool failure = ws_single->import(*asimov_dataset, RooFit::Rename(AsimovName.c_str()));
199 if( failure ) {
200 std::cout << "Error: Failed to import Asimov dataset: " << AsimovName
201 << std::endl;
202 throw hf_exc();
203 }
204
205 // Load the snapshot at the end of every loop iteration
206 // so we start each loop with a "clean" snapshot
207 ws_single->loadSnapshot(SnapShotName.c_str());
208 }
209
210 // Cool, we're done
211 return; // ws_single;
212 }
213
214
215 // We want to eliminate this interface and use the measurement directly
217
218 // This is a pretty light-weight wrapper function
219 //
220 // Take a fully configured measurement as well as
221 // one of its channels
222 //
223 // Return a workspace representing that channel
224 // Do this by first creating a vector of EstimateSummary's
225 // and this by configuring the workspace with any post-processing
226
227 // Get the channel's name
228 string ch_name = channel.GetName();
229
230 // Create a workspace for a SingleChannel from the Measurement Object
231 std::unique_ptr<RooWorkspace> ws_single{this->MakeSingleChannelWorkspace(measurement, channel)};
232 if( ws_single == nullptr ) {
233 cxcoutF(HistFactory) << "Error: Failed to make Single-Channel workspace for channel: " << ch_name
234 << " and measurement: " << measurement.GetName() << std::endl;
235 throw hf_exc();
236 }
237
238 // Finally, configure that workspace based on
239 // properties of the measurement
240 HistoToWorkspaceFactoryFast::ConfigureWorkspaceForMeasurement( "model_"+ch_name, ws_single.get(), measurement );
241
242 return RooFit::Detail::owningPtr(std::move(ws_single));
243
244 }
245
247
248 // This function takes a fully configured measurement
249 // which may contain several channels and returns
250 // a workspace holding the combined model
251 //
252 // This can be used, for example, within a script to produce
253 // a combined workspace on-the-fly
254 //
255 // This is a static function (for now) to make
256 // it a one-liner
257
259
260 // First, we create an instance of a HistFactory
261 HistoToWorkspaceFactoryFast factory( measurement );
262
263 // Loop over the channels and create the individual workspaces
264 vector<std::unique_ptr<RooWorkspace>> channel_workspaces;
265 vector<string> channel_names;
266
267 for(HistFactory::Channel& channel : measurement.GetChannels()) {
268
269 if( ! channel.CheckHistograms() ) {
270 cxcoutFHF << "MakeModelAndMeasurementsFast: Channel: " << channel.GetName()
271 << " has uninitialized histogram pointers" << std::endl;
272 throw hf_exc();
273 }
274
275 string ch_name = channel.GetName();
276 channel_names.push_back(ch_name);
277
278 // GHL: Renaming to 'MakeSingleChannelWorkspace'
279 channel_workspaces.emplace_back(factory.MakeSingleChannelModel(measurement, channel));
280 }
281
282
283 // Now, combine the individual channel workspaces to
284 // form the combined workspace
285 std::unique_ptr<RooWorkspace> ws{factory.MakeCombinedModel( channel_names, channel_workspaces )};
286
287
288 // Configure the workspace
290
291 // Done. Return the pointer
292 return RooFit::Detail::owningPtr(std::move(ws));
293
294 }
295
296namespace {
297
298template <class Arg_t = RooAbsArg, typename... Args_t>
299Arg_t *factory(RooWorkspace &ws, const char *expr, Args_t &&...args)
300{
301 return static_cast<Arg_t *>(ws.factory(TString::Format(expr, std::forward<Args_t>(args)...).Data()));
302}
303
304} // namespace
305
306/// Create observables of type RooRealVar. Creates 1 to 3 observables, depending on the type of the histogram.
308 RooArgList observables;
309
310 for (unsigned int idx=0; idx < fObsNameVec.size(); ++idx) {
311 if (!proto.var(fObsNameVec[idx])) {
312 const TAxis *axis = (idx == 0) ? hist->GetXaxis() : (idx == 1 ? hist->GetYaxis() : hist->GetZaxis());
313 int nbins = axis->GetNbins();
314 // create observable
315 auto obs = factory<RooRealVar>(proto, "%s[%f,%f]", fObsNameVec[idx].c_str(), axis->GetXmin(), axis->GetXmax());
316 if(strlen(axis->GetTitle())>0) obs->SetTitle(axis->GetTitle());
317 obs->setBins(nbins);
318 if (axis->IsVariableBinSize()) {
319 RooBinning binning(nbins, axis->GetXbins()->GetArray());
320 obs->setBinning(binning);
321 }
322 }
323
324 observables.add(*proto.var(fObsNameVec[idx]));
325 }
326
327 return observables;
328}
329
330 /// Create the nominal hist function from `hist`, and register it in the workspace.
332 const RooArgList& observables) const {
333 if(hist) {
334 cxcoutI(HistFactory) << "processing hist " << hist->GetName() << endl;
335 } else {
336 cxcoutF(HistFactory) << "hist is empty" << endl;
337 R__ASSERT(hist != nullptr);
338 return nullptr;
339 }
340
341 // determine histogram dimensionality
342 unsigned int histndim(1);
343 std::string classname = hist->ClassName();
344 if (classname.find("TH1")==0) { histndim=1; }
345 else if (classname.find("TH2")==0) { histndim=2; }
346 else if (classname.find("TH3")==0) { histndim=3; }
347 R__ASSERT( histndim==fObsNameVec.size() );
348
349 prefix += "_Hist_alphanominal";
350
351 RooDataHist histDHist(prefix + "DHist","",observables,hist);
352
353 proto.import(RooHistFunc(prefix.c_str(),"",observables,histDHist,0), RooFit::RecycleConflictNodes());
354 return static_cast<RooHistFunc*>(proto.arg(prefix));
355 }
356
357 namespace {
358
359 void makeGaussianConstraint(RooAbsArg& param, RooWorkspace& proto, bool isUniform,
360 std::vector<std::string> & constraintTermNames) {
361 std::string paramName = param.GetName();
362 std::string constraintName = paramName + "Constraint";
363
364 // do nothing if the constraint term already exists
365 if(proto.pdf(constraintName)) return;
366
367 // case systematic is uniform (assume they are like a Gaussian but with
368 // a large width (100 instead of 1)
369 const double gaussSigma = isUniform ? 100. : 1.0;
370 if (isUniform) {
371 cxcoutIHF << "Added a uniform constraint for " << paramName << " as a Gaussian constraint with a very large sigma " << std::endl;
372 }
373
374 std::stringstream command;
375 command << "Gaussian::" << constraintName << "(" << paramName << ",nom_" << paramName << "[0.,-10,10],"
376 << gaussSigma << ")";
377 constraintTermNames.emplace_back(proto.factory(command.str())->GetName());
378 proto.var(paramName)->setError(gaussSigma); // give param initial error to match gaussSigma
379 auto * normParam = proto.var(std::string("nom_") + paramName);
380 normParam->setConstant();
381 const_cast<RooArgSet*>(proto.set("globalObservables"))->add(*normParam);
382 }
383
384 /// Make list of abstract parameters that interpolate in space of variations.
385 RooArgList makeInterpolationParameters(std::vector<HistoSys> const& histoSysList, RooWorkspace& proto) {
386 RooArgList params( ("alpha_Hist") );
387
388 for(auto const& histoSys : histoSysList) {
389 params.add(getOrCreate<RooRealVar>(proto, "alpha_" + histoSys.GetName(), alphaLow, alphaHigh));
390 }
391
392 return params;
393 }
394
395 /// Create a linear interpolation object that holds nominal and systematics, import it into the workspace,
396 /// and return a pointer to it.
397 RooAbsArg* makeLinInterp(RooArgList const& interpolationParams,
398 RooHistFunc* nominalFunc,
399 RooWorkspace& proto, const std::vector<HistoSys>& histoSysList,
400 const string& prefix,
401 const RooArgList& obsList) {
402
403 // now make function that linearly interpolates expectation between variations
404 // get low/high variations to interpolate between
405 std::vector<double> low;
406 std::vector<double> high;
407 RooArgSet lowSet;
408 RooArgSet highSet;
409 for(unsigned int j=0; j<histoSysList.size(); ++j){
410 std::string str = prefix + "_" + std::to_string(j);
411
412 const HistoSys& histoSys = histoSysList.at(j);
413 auto lowDHist = std::make_unique<RooDataHist>(str+"lowDHist","",obsList, histoSys.GetHistoLow());
414 auto highDHist = std::make_unique<RooDataHist>(str+"highDHist","",obsList, histoSys.GetHistoHigh());
415 lowSet.addOwned(std::make_unique<RooHistFunc>((str+"low").c_str(),"",obsList,std::move(lowDHist),0));
416 highSet.addOwned(std::make_unique<RooHistFunc>((str+"high").c_str(),"",obsList,std::move(highDHist),0));
417 }
418
419 // this is sigma(params), a piece-wise linear interpolation
420 PiecewiseInterpolation interp(prefix.c_str(),"",*nominalFunc,lowSet,highSet,interpolationParams);
421 interp.setPositiveDefinite();
422 interp.setAllInterpCodes(4); // LM: change to 4 (piece-wise linear to 6th order polynomial interpolation + linear extrapolation )
423 // KC: interpo codes 1 etc. don't have proper analytic integral.
424 RooArgSet obsSet(obsList);
425 interp.setBinIntegrator(obsSet);
426 interp.forceNumInt();
427
428 proto.import(interp, RooFit::RecycleConflictNodes()); // individual params have already been imported in first loop of this function
429
430 return proto.arg(prefix);
431 }
432
433 }
434
435 // GHL: Consider passing the NormFactor list instead of the entire sample
436 std::unique_ptr<RooProduct> HistoToWorkspaceFactoryFast::CreateNormFactor(RooWorkspace& proto, string& channel, string& sigmaEpsilon, Sample& sample, bool doRatio){
437
438 std::vector<string> prodNames;
439
440 vector<NormFactor> normList = sample.GetNormFactorList();
441 vector<string> normFactorNames, rangeNames;
442
443
444 string overallNorm_times_sigmaEpsilon = sample.GetName() + "_" + channel + "_scaleFactors";
445 auto sigEps = proto.arg(sigmaEpsilon);
446 assert(sigEps);
447 auto normFactor = std::make_unique<RooProduct>(overallNorm_times_sigmaEpsilon.c_str(), overallNorm_times_sigmaEpsilon.c_str(), RooArgList(*sigEps));
448
449 if(!normList.empty()){
450
451 for(NormFactor &norm : normList) {
452 string varname = norm.GetName();
453 if(doRatio) {
454 varname += "_" + channel;
455 }
456
457 // GHL: Check that the NormFactor doesn't already exist
458 // (it may have been created as a function expression
459 // during preprocessing)
460 std::stringstream range;
461 range << "[" << norm.GetVal() << "," << norm.GetLow() << "," << norm.GetHigh() << "]";
462
463 if( proto.obj(varname) == nullptr) {
464 cxcoutI(HistFactory) << "making normFactor: " << norm.GetName() << endl;
465 // remove "doRatio" and name can be changed when ws gets imported to the combined model.
466 proto.factory(varname + range.str());
467 }
468
469 prodNames.push_back(varname);
470 rangeNames.push_back(range.str());
471 normFactorNames.push_back(varname);
472 }
473
474
475 for (const auto& name : prodNames) {
476 auto arg = proto.arg(name);
477 assert(arg);
478 normFactor->addTerm(arg);
479 }
480
481 }
482
483 unsigned int rangeIndex=0;
484 for( vector<string>::iterator nit = normFactorNames.begin(); nit!=normFactorNames.end(); ++nit){
485 if( count (normFactorNames.begin(), normFactorNames.end(), *nit) > 1 ){
486 cxcoutI(HistFactory) <<"<NormFactor Name =\""<<*nit<<"\"> is duplicated for <Sample Name=\""
487 << sample.GetName() << "\">, but only one factor will be included. \n Instead, define something like"
488 << "\n\t<Function Name=\""<<*nit<<"Squared\" Expression=\""<<*nit<<"*"<<*nit<<"\" Var=\""<<*nit<<rangeNames.at(rangeIndex)
489 << "\"> \nin your top-level XML's <Measurement> entry and use <NormFactor Name=\""<<*nit<<"Squared\" in your channel XML file."<< endl;
490 }
491 ++rangeIndex;
492 }
493
494 return normFactor;
495 }
496
498 string interpName,
499 std::vector<OverallSys>& systList,
500 vector<string>& constraintTermNames,
501 vector<string>& totSystTermNames) {
502
503 // add variables for all the relative overall uncertainties we expect
504 totSystTermNames.push_back(prefix);
505
506 RooArgSet params(prefix.c_str());
507 vector<double> lowVec, highVec;
508
509 std::map<std::string, double>::iterator itconstr;
510 for(unsigned int i = 0; i < systList.size(); ++i) {
511
512 OverallSys& sys = systList.at(i);
513 std::string strname = sys.GetName();
514 const char * name = strname.c_str();
515
516 // case of no systematic (is it possible)
517 if (meas.GetNoSyst().count(sys.GetName()) > 0 ) {
518 cxcoutI(HistFactory) << "HistoToWorkspaceFast::AddConstraintTerm - skip systematic " << sys.GetName() << std::endl;
519 continue;
520 }
521 // case systematic is a gamma constraint
522 if (meas.GetGammaSyst().count(sys.GetName()) > 0 ) {
523 double relerr = meas.GetGammaSyst().find(sys.GetName() )->second;
524 if (relerr <= 0) {
525 cxcoutI(HistFactory) << "HistoToWorkspaceFast::AddConstraintTerm - zero uncertainty assigned - skip systematic " << sys.GetName() << std::endl;
526 continue;
527 }
528 double tauVal = 1./(relerr*relerr);
529 double sqtau = 1./relerr;
530 RooAbsArg * beta = factory(proto, "beta_%s[1,0,10]", name);
531 // the global observable (y_s)
532 RooAbsArg * yvar = factory(proto, "nom_%s[%f,0,10]",beta->GetName(),tauVal);
533 // the rate of the gamma distribution (theta)
534 RooAbsArg * theta = factory(proto, "theta_%s[%f]",name,1./tauVal);
535 // find alpha as function of beta
536 RooAbsArg* alphaOfBeta = factory(proto, "PolyVar::alphaOfBeta_%s(beta_%s,{%f,%f})",name,name,-sqtau,sqtau);
537
538 // add now the constraint itself Gamma_beta_constraint(beta, y+1, tau, 0 )
539 // build the gamma parameter k = as y_s + 1
540 RooAbsArg * kappa = factory(proto, "sum::k_%s(%s,1.)",name,yvar->GetName());
541 RooAbsArg * gamma = factory(proto, "Gamma::%sConstraint(%s, %s, %s, 0.0)",beta->GetName(),beta->GetName(), kappa->GetName(), theta->GetName());
543 alphaOfBeta->Print("t");
544 gamma->Print("t");
545 }
546 constraintTermNames.push_back(gamma->GetName());
547 // set global observables
548 RooRealVar * gobs = dynamic_cast<RooRealVar*>(yvar); assert(gobs);
549 gobs->setConstant(true);
550 const_cast<RooArgSet*>(proto.set("globalObservables"))->add(*yvar);
551
552 // add alphaOfBeta in the list of params to interpolate
553 params.add(*alphaOfBeta);
554 cxcoutI(HistFactory) << "Added a gamma constraint for " << name << std::endl;
555
556 }
557 else {
558 RooRealVar* alpha = &getOrCreate<RooRealVar>(proto, prefix + sys.GetName(), 0, alphaLow, alphaHigh);
559 // add the Gaussian constraint part
560 const bool isUniform = meas.GetUniformSyst().count(sys.GetName()) > 0;
561 makeGaussianConstraint(*alpha, proto, isUniform, constraintTermNames);
562
563 // check if exists a log-normal constraint
564 if (meas.GetLogNormSyst().count(sys.GetName()) == 0 && meas.GetGammaSyst().count(sys.GetName()) == 0 ) {
565 // just add the alpha for the parameters of the FlexibleInterpVar function
566 params.add(*alpha);
567 }
568 // case systematic is a log-normal constraint
569 if (meas.GetLogNormSyst().count(sys.GetName()) > 0 ) {
570 // log normal constraint for parameter
571 double relerr = meas.GetLogNormSyst().find(sys.GetName() )->second;
572 double tauVal = 1./relerr;
573 std::string tauName = "tau_" + sys.GetName();
574 factory(proto, "%s[%f]",tauName.c_str(),tauVal);
575 double kappaVal = 1. + relerr;
576 std::string kappaName = "kappa_" + sys.GetName();
577 factory(proto, "%s[%f]",kappaName.c_str(),kappaVal);
578 const char * alphaName = alpha->GetName();
579
580 std::string alphaOfBetaName = "alphaOfBeta_" + sys.GetName();
581 RooAbsArg * alphaOfBeta = factory(proto, "expr::%s('%s*(pow(%s,%s)-1.)',%s,%s,%s)",alphaOfBetaName.c_str(),
582 tauName.c_str(),kappaName.c_str(),alphaName,
583 tauName.c_str(),kappaName.c_str(),alphaName);
584
585 cxcoutI(HistFactory) << "Added a log-normal constraint for " << name << std::endl;
587 alphaOfBeta->Print("t");
588 params.add(*alphaOfBeta);
589 }
590
591 }
592 // add low/high vectors
593 double low = sys.GetLow();
594 double high = sys.GetHigh();
595 lowVec.push_back(low);
596 highVec.push_back(high);
597
598 } // end sys loop
599
600 if(!systList.empty()){
601 // this is epsilon(alpha_j), a piece-wise linear interpolation
602 // LinInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
603
604 assert(!params.empty());
605 assert(int(lowVec.size()) == params.getSize() );
606
607 FlexibleInterpVar interp( (interpName).c_str(), "", params, 1., lowVec, highVec);
608 interp.setAllInterpCodes(4); // LM: change to 4 (piece-wise linear to 6th order polynomial interpolation + linear extrapolation )
609 //interp.setAllInterpCodes(0); // simple linear interpolation
610 proto.import(interp); // params have already been imported in first loop of this function
611 } else{
612 // some strange behavior if params,lowVec,highVec are empty.
613 //cout << "WARNING: No OverallSyst terms" << endl;
614 RooConstVar interp( (interpName).c_str(), "", 1.);
615 proto.import(interp); // params have already been imported in first loop of this function
616 }
617 }
618
619
621 const vector<RooProduct*>& sampleScaleFactors, std::vector<vector<RooAbsArg*>>& sampleHistFuncs) const {
622 assert(sampleScaleFactors.size() == sampleHistFuncs.size());
623
624 // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
625
626 if (fObsNameVec.empty() && !fObsName.empty())
627 throw std::logic_error("HistFactory didn't process the observables correctly. Please file a bug report.");
628
629 auto firstHistFunc = dynamic_cast<const RooHistFunc*>(sampleHistFuncs.front().front());
630 if (!firstHistFunc) {
631 auto piecewiseInt = dynamic_cast<const PiecewiseInterpolation*>(sampleHistFuncs.front().front());
632 firstHistFunc = dynamic_cast<const RooHistFunc*>(piecewiseInt->nominalHist());
633 }
634 assert(firstHistFunc);
635
636 // Prepare a function to divide all bin contents by bin width to get a density:
637 const std::string binWidthFunctionName = totName + "_binWidth";
638 RooBinWidthFunction binWidth(binWidthFunctionName.c_str(), "Divide by bin width to obtain probability density", *firstHistFunc, true);
639 proto.import(binWidth);
640 auto binWidthWS = proto.function(binWidthFunctionName);
641 assert(binWidthWS);
642
643 // Loop through samples and create products of their functions:
644 RooArgSet coefList;
645 RooArgSet shapeList;
646 for (unsigned int i=0; i < sampleHistFuncs.size(); ++i) {
647 assert(!sampleHistFuncs[i].empty());
648 coefList.add(*sampleScaleFactors[i]);
649
650 std::vector<RooAbsArg*>& thisSampleHistFuncs = sampleHistFuncs[i];
651 thisSampleHistFuncs.push_back(binWidthWS);
652
653 if (thisSampleHistFuncs.size() == 1) {
654 // Just one function. Book it.
655 shapeList.add(*thisSampleHistFuncs.front());
656 } else {
657 // Have multiple functions. We need to multiply them.
658 std::string name = thisSampleHistFuncs.front()->GetName();
659 auto pos = name.find("Hist_alpha");
660 if (pos != std::string::npos) {
661 name = name.substr(0, pos) + "shapes";
662 } else if ( (pos = name.find("nominal")) != std::string::npos) {
663 name = name.substr(0, pos) + "shapes";
664 }
665
666 RooProduct shapeProduct(name.c_str(), thisSampleHistFuncs.front()->GetTitle(), RooArgSet(thisSampleHistFuncs.begin(), thisSampleHistFuncs.end()));
667 proto.import(shapeProduct, RooFit::RecycleConflictNodes());
668 shapeList.add(*proto.function(name));
669 }
670 }
671
672 // Sum all samples
673 RooRealSumPdf tot(totName.c_str(), totName.c_str(), shapeList, coefList, true);
674 tot.specialIntegratorConfig(true)->method1D().setLabel("RooBinIntegrator") ;
675 tot.specialIntegratorConfig(true)->method2D().setLabel("RooBinIntegrator") ;
676 tot.specialIntegratorConfig(true)->methodND().setLabel("RooBinIntegrator") ;
677 tot.forceNumInt();
678
679 // for mixed generation in RooSimultaneous
680 tot.setAttribute("GenerateBinned"); // for use with RooSimultaneous::generate in mixed mode
681
682 // Enable the binned likelihood optimization
684 tot.setAttribute("BinnedLikelihood");
685 }
686
687 proto.import(tot, RooFit::RecycleConflictNodes());
688 }
689
690 //////////////////////////////////////////////////////////////////////////////
691
693
694 FILE* covFile = fopen ((filename).c_str(),"w");
695 fprintf(covFile," ") ;
696 for (auto const *myargi : static_range_cast<RooRealVar *>(*params)) {
697 if(myargi->isConstant()) continue;
698 fprintf(covFile," & %s", myargi->GetName());
699 }
700 fprintf(covFile,"\\\\ \\hline \n" );
701 for (auto const *myargi : static_range_cast<RooRealVar *>(*params)) {
702 if(myargi->isConstant()) continue;
703 fprintf(covFile,"%s", myargi->GetName());
704 for (auto const *myargj : static_range_cast<RooRealVar *>(*params)) {
705 if(myargj->isConstant()) continue;
706 cout << myargi->GetName() << "," << myargj->GetName();
707 fprintf(covFile, " & %.2f", result->correlation(*myargi, *myargj));
708 }
709 cout << endl;
710 fprintf(covFile, " \\\\\n");
711 }
712 fclose(covFile);
713
714 }
715
716
717 ///////////////////////////////////////////////
718 std::unique_ptr<RooWorkspace> HistoToWorkspaceFactoryFast::MakeSingleChannelWorkspace(Measurement& measurement, Channel& channel) {
719
720 // check inputs (see JIRA-6890 )
721
722 if (channel.GetSamples().empty()) {
723 Error("MakeSingleChannelWorkspace",
724 "The input Channel does not contain any sample - return a nullptr");
725 return nullptr;
726 }
727
728 const TH1* channel_hist_template = channel.GetSamples().front().GetHisto();
729 if (channel_hist_template == nullptr) {
730 channel.CollectHistograms();
731 channel_hist_template = channel.GetSamples().front().GetHisto();
732 }
733 if (channel_hist_template == nullptr) {
734 std::ostringstream stream;
735 stream << "The sample " << channel.GetSamples().front().GetName()
736 << " in channel " << channel.GetName() << " does not contain a histogram. This is the channel:\n";
737 channel.Print(stream);
738 Error("MakeSingleChannelWorkspace", "%s", stream.str().c_str());
739 return nullptr;
740 }
741
742 if( ! channel.CheckHistograms() ) {
743 std::cout << "MakeSingleChannelWorkspace: Channel: " << channel.GetName()
744 << " has uninitialized histogram pointers" << std::endl;
745 throw hf_exc();
746 }
747
748
749
750 // Set these by hand inside the function
751 vector<string> systToFix = measurement.GetConstantParams();
752 bool doRatio=false;
753
754 // to time the macro
755 TStopwatch t;
756 t.Start();
757 //ES// string channel_name=summary[0].channel;
758 string channel_name = channel.GetName();
759
760 /// MB: reset observable names for each new channel.
761 fObsNameVec.clear();
762
763 /// MB: label observables x,y,z, depending on histogram dimensionality
764 /// GHL: Give it the first sample's nominal histogram as a template
765 /// since the data histogram may not be present
766 if (fObsNameVec.empty()) { GuessObsNameVec(channel_hist_template); }
767
768 for ( unsigned int idx=0; idx<fObsNameVec.size(); ++idx ) {
769 fObsNameVec[idx] = "obs_" + fObsNameVec[idx] + "_" + channel_name ;
770 }
771
772 if (fObsNameVec.empty()) {
773 fObsName= "obs_" + channel_name; // set name ov observable
774 fObsNameVec.push_back( fObsName );
775 }
776
777 if (fObsNameVec.empty() || fObsNameVec.size() > 3) {
778 throw hf_exc("HistFactory is limited to 1- to 3-dimensional histograms.");
779 }
780
781 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
782 << "\tStarting to process '"
783 << channel_name << "' channel with " << fObsNameVec.size() << " observables"
784 << "\n-----------------------------------------\n" << endl;
785
786 //
787 // our main workspace that we are using to construct the model
788 //
789 auto protoOwner = std::make_unique<RooWorkspace>(channel_name.c_str(), (channel_name+" workspace").c_str());
790 RooWorkspace &proto = *protoOwner;
791 auto proto_config = make_unique<ModelConfig>("ModelConfig", &proto);
792 proto_config->SetWorkspace(proto);
793
794 // preprocess functions
795 for(auto const& func : fPreprocessFunctions){
796 cxcoutI(HistFactory) << "will preprocess this line: " << func <<endl;
797 proto.factory(func);
798 proto.Print();
799 }
800
801 RooArgSet likelihoodTerms("likelihoodTerms"), constraintTerms("constraintTerms");
802 vector<string> likelihoodTermNames, constraintTermNames, totSystTermNames;
803 // All histogram functions to be multiplied in each sample
804 std::vector<std::vector<RooAbsArg*>> allSampleHistFuncs;
805 std::vector<RooProduct*> sampleScaleFactors;
806
807 std::vector< pair<string,string> > statNamePairs;
808 std::vector< pair<const TH1*, std::unique_ptr<TH1>> > statHistPairs; // <nominal, error>
809 const std::string statFuncName = "mc_stat_" + channel_name;
810
811 string prefix, range;
812
813 /////////////////////////////
814 // shared parameters
815 // this is ratio of lumi to nominal lumi. We will include relative uncertainty in model
816 getOrCreate<RooRealVar>(proto, "Lumi", fNomLumi, 0.0, 10 * fNomLumi);
817
818 // only include a lumiConstraint if there's a lumi uncert, otherwise just set the lumi constant
819 if(fLumiError != 0) {
820 std::stringstream lumiErrorStr;
821 lumiErrorStr << "nominalLumi["<<fNomLumi << ",0,"<<fNomLumi+10*fLumiError<<"]," << fLumiError ;
822 proto.factory("Gaussian::lumiConstraint(Lumi,"+lumiErrorStr.str()+")");
823 proto.var("Lumi")->setError(fLumiError/fNomLumi); // give initial error value
824 proto.var("nominalLumi")->setConstant();
825 proto.defineSet("globalObservables","nominalLumi");
826 //likelihoodTermNames.push_back("lumiConstraint");
827 constraintTermNames.push_back("lumiConstraint");
828 } else {
829 proto.var("Lumi")->setConstant();
830 proto.defineSet("globalObservables",RooArgSet()); // create empty set as is assumed it exists later
831 }
832 //proto.factory("SigXsecOverSM[1.,0.5,1..8]");
833 ///////////////////////////////////
834 // loop through estimates, add expectation, floating bin predictions,
835 // and terms that constrain floating to expectation via uncertainties
836 // GHL: Loop over samples instead, which doesn't contain the data
837 for (Sample& sample : channel.GetSamples()) {
838 string overallSystName = sample.GetName() + "_" + channel_name + "_epsilon";
839
840 string systSourcePrefix = "alpha_";
841
842 // constraintTermNames and totSystTermNames are vectors that are passed
843 // by reference and filled by this method
844 AddConstraintTerms(proto,measurement, systSourcePrefix, overallSystName,
845 sample.GetOverallSysList(), constraintTermNames , totSystTermNames);
846
847 allSampleHistFuncs.emplace_back();
848 std::vector<RooAbsArg*>& sampleHistFuncs = allSampleHistFuncs.back();
849
850 // GHL: Consider passing the NormFactor list instead of the entire sample
851 auto normFactors = CreateNormFactor(proto, channel_name, overallSystName, sample, doRatio);
852 assert(normFactors);
853
854 // Create the string for the object
855 // that is added to the RooRealSumPdf
856 // for this channel
857// string syst_x_expectedPrefix = "";
858
859 // get histogram
860 //ES// TH1* nominal = it->nominal;
861 const TH1* nominal = sample.GetHisto();
862
863 // MB : HACK no option to have both non-hist variations and hist variations ?
864 // get histogram
865 // GHL: Okay, this is going to be non-trivial.
866 // We will loop over histosys's, which contain both
867 // the low hist and the high hist together.
868
869 // Logic:
870 // - If we have no HistoSys's, do part A
871 // - else, if the histo syst's don't match, return (we ignore this case)
872 // - finally, we take the syst's and apply the linear interpolation w/ constraint
873 string expPrefix = sample.GetName() + "_" + channel_name;
874 // create roorealvar observables
875 RooArgList observables = createObservables(sample.GetHisto(), proto);
876 RooHistFunc* nominalHistFunc = MakeExpectedHistFunc(sample.GetHisto(), proto, expPrefix, observables);
877 assert(nominalHistFunc);
878
879 if(sample.GetHistoSysList().empty()) {
880 // If no HistoSys
881 cxcoutI(HistFactory) << sample.GetName() + "_" + channel_name + " has no variation histograms " << endl;
882
883 sampleHistFuncs.push_back(nominalHistFunc);
884 } else {
885 // If there ARE HistoSys(s)
886 // name of source for variation
887 string constraintPrefix = sample.GetName() + "_" + channel_name + "_Hist_alpha";
888
889 // make list of abstract parameters that interpolate in space of variations
890 RooArgList interpParams = makeInterpolationParameters(sample.GetHistoSysList(), proto);
891
892 // next, create the constraint terms
893 for(std::size_t i = 0; i < interpParams.size(); ++i) {
894 bool isUniform = measurement.GetUniformSyst().count(sample.GetHistoSysList()[i].GetName()) > 0;
895 makeGaussianConstraint(interpParams[i], proto, isUniform, constraintTermNames);
896 }
897
898 // finally, create the interpolated function
899 sampleHistFuncs.push_back( makeLinInterp(interpParams, nominalHistFunc, proto,
900 sample.GetHistoSysList(), constraintPrefix, observables) );
901 }
902
903 sampleHistFuncs.front()->SetTitle( (nominal && strlen(nominal->GetTitle())>0) ? nominal->GetTitle() : sample.GetName().c_str() );
904
905 ////////////////////////////////////
906 // Add StatErrors to this Channel //
907 ////////////////////////////////////
908
909 if( sample.GetStatError().GetActivate() ) {
910
911 if( fObsNameVec.size() > 3 ) {
912 cxcoutF(HistFactory) << "Cannot include Stat Error for histograms of more than 3 dimensions."
913 << std::endl;
914 throw hf_exc();
915 } else {
916
917 // If we are using StatUncertainties, we multiply this object
918 // by the ParamHistFunc and then pass that to the
919 // RooRealSumPdf by appending it's name to the list
920
921 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " to be included in Stat Error "
922 << "for channel " << channel_name
923 << std::endl;
924
925 string UncertName = sample.GetName() + "_" + channel_name + "_StatAbsolUncert";
926 std::unique_ptr<TH1> statErrorHist;
927
928 if( sample.GetStatError().GetErrorHist() == nullptr ) {
929 // Make the absolute stat error
930 cxcoutI(HistFactory) << "Making Statistical Uncertainty Hist for "
931 << " Channel: " << channel_name
932 << " Sample: " << sample.GetName()
933 << std::endl;
934 statErrorHist.reset(MakeAbsolUncertaintyHist( UncertName, nominal));
935 } else {
936 // clone the error histograms because in case the sample has not error hist
937 // it is created in MakeAbsolUncertainty
938 // we need later to clean statErrorHist
939 statErrorHist.reset(static_cast<TH1*>(sample.GetStatError().GetErrorHist()->Clone()));
940 // We assume the (relative) error is provided.
941 // We must turn it into an absolute error
942 // using the nominal histogram
943 cxcoutI(HistFactory) << "Using external histogram for Stat Errors for "
944 << "\tChannel: " << channel_name
945 << "\tSample: " << sample.GetName()
946 << "\tError Histogram: " << statErrorHist->GetName() << std::endl;
947 // Multiply the relative stat uncertainty by the
948 // nominal to get the overall stat uncertainty
949 statErrorHist->Multiply( nominal );
950 statErrorHist->SetName( UncertName.c_str() );
951 }
952
953 // Save the nominal and error hists
954 // for the building of constraint terms
955 statHistPairs.emplace_back(nominal, std::move(statErrorHist));
956
957 // To do the 'conservative' version, we would need to do some
958 // intervention here. We would probably need to create a different
959 // ParamHistFunc for each sample in the channel. The would nominally
960 // use the same gamma's, so we haven't increased the number of parameters
961 // However, if a bin in the 'nominal' histogram is 0, we simply need to
962 // change the parameter in that bin in the ParamHistFunc for this sample.
963 // We also need to add a constraint term.
964 // Actually, we'd probably not use the ParamHistFunc...?
965 // we could remove the dependence in this ParamHistFunc on the ith gamma
966 // and then create the poisson term: Pois(tau | n_exp)Pois(data | n_exp)
967
968
969 // Next, try to get the common ParamHistFunc (it may have been
970 // created by another sample in this channel)
971 // or create it if it doesn't yet exist:
972 RooAbsReal* paramHist = dynamic_cast<ParamHistFunc*>( proto.function(statFuncName) );
973 if( paramHist == nullptr ) {
974
975 // Get a RooArgSet of the observables:
976 // Names in the list fObsNameVec:
977 RooArgList theObservables;
978 std::vector<std::string>::iterator itr = fObsNameVec.begin();
979 for (int idx=0; itr!=fObsNameVec.end(); ++itr, ++idx ) {
980 theObservables.add( *proto.var(*itr) );
981 }
982
983 // Create the list of terms to
984 // control the bin heights:
985 std::string ParamSetPrefix = "gamma_stat_" + channel_name;
987 ParamSetPrefix,
988 theObservables,
990
991 ParamHistFunc statUncertFunc(statFuncName.c_str(), statFuncName.c_str(),
992 theObservables, statFactorParams );
993
994 proto.import( statUncertFunc, RooFit::RecycleConflictNodes() );
995
996 paramHist = proto.function( statFuncName);
997 }
998
999 // apply stat function to sample
1000 sampleHistFuncs.push_back(paramHist);
1001 }
1002 } // END: if DoMcStat
1003
1004
1005 ///////////////////////////////////////////
1006 // Create a ShapeFactor for this channel //
1007 ///////////////////////////////////////////
1008
1009 if( !sample.GetShapeFactorList().empty() ) {
1010
1011 if( fObsNameVec.size() > 3 ) {
1012 cxcoutF(HistFactory) << "Cannot include Stat Error for histograms of more than 3 dimensions."
1013 << std::endl;
1014 throw hf_exc();
1015 } else {
1016
1017 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " in channel: " << channel_name
1018 << " to be include a ShapeFactor."
1019 << std::endl;
1020
1021 for(ShapeFactor& shapeFactor : sample.GetShapeFactorList()) {
1022
1023 std::string funcName = channel_name + "_" + shapeFactor.GetName() + "_shapeFactor";
1024 RooAbsArg *paramHist = proto.function(funcName);
1025 if( paramHist == nullptr ) {
1026
1027 RooArgList theObservables;
1028 for(std::string const& varName : fObsNameVec) {
1029 theObservables.add( *proto.var(varName) );
1030 }
1031
1032 // Create the Parameters
1033 std::string funcParams = "gamma_" + shapeFactor.GetName();
1034
1035 // GHL: Again, we are putting hard ranges on the gamma's
1036 // We should change this to range from 0 to /inf
1038 funcParams,
1040
1041 // Create the Function
1042 ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
1043 theObservables, shapeFactorParams );
1044
1045 // Set an initial shape, if requested
1046 if( shapeFactor.GetInitialShape() != nullptr ) {
1047 TH1* initialShape = static_cast<TH1*>(shapeFactor.GetInitialShape()->Clone());
1048 cxcoutI(HistFactory) << "Setting Shape Factor: " << shapeFactor.GetName()
1049 << " to have initial shape from hist: "
1050 << initialShape->GetName()
1051 << std::endl;
1052 shapeFactorFunc.setShape( initialShape );
1053 }
1054
1055 // Set the variables constant, if requested
1056 if( shapeFactor.IsConstant() ) {
1057 cxcoutI(HistFactory) << "Setting Shape Factor: " << shapeFactor.GetName()
1058 << " to be constant" << std::endl;
1059 shapeFactorFunc.setConstant(true);
1060 }
1061
1062 proto.import( shapeFactorFunc, RooFit::RecycleConflictNodes() );
1063 paramHist = proto.function(funcName);
1064
1065 } // End: Create ShapeFactor ParamHistFunc
1066
1067 sampleHistFuncs.push_back(paramHist);
1068 } // End loop over ShapeFactor Systematics
1069 }
1070 } // End: if ShapeFactorName!=""
1071
1072
1073 ////////////////////////////////////////
1074 // Create a ShapeSys for this channel //
1075 ////////////////////////////////////////
1076
1077 if( !sample.GetShapeSysList().empty() ) {
1078
1079 if( fObsNameVec.size() > 3 ) {
1080 cxcoutF(HistFactory) << "Cannot include Stat Error for histograms of more than 3 dimensions."
1081 << std::endl;
1082 throw hf_exc();
1083 }
1084
1085 // List of ShapeSys ParamHistFuncs
1086 std::vector<string> ShapeSysNames;
1087
1088 for(RooStats::HistFactory::ShapeSys& shapeSys : sample.GetShapeSysList()) {
1089
1090 // Create the ParamHistFunc's
1091 // Create their constraint terms and add them
1092 // to the list of constraint terms
1093
1094 // Create a single RooProduct over all of these
1095 // paramHistFunc's
1096
1097 // Send the name of that product to the RooRealSumPdf
1098
1099 cxcoutI(HistFactory) << "Sample: " << sample.GetName() << " in channel: " << channel_name
1100 << " to include a ShapeSys." << std::endl;
1101
1102 std::string funcName = channel_name + "_" + shapeSys.GetName() + "_ShapeSys";
1103 ShapeSysNames.push_back( funcName );
1104 auto paramHist = static_cast<ParamHistFunc*>(proto.function(funcName));
1105 if( paramHist == nullptr ) {
1106
1107 //std::string funcParams = "gamma_" + it->shapeFactorName;
1108 //paramHist = CreateParamHistFunc( proto, fObsNameVec, funcParams, funcName );
1109
1110 RooArgList theObservables;
1111 for(std::string const& varName : fObsNameVec) {
1112 theObservables.add( *proto.var(varName) );
1113 }
1114
1115 // Create the Parameters
1116 std::string funcParams = "gamma_" + shapeSys.GetName();
1118 funcParams,
1119 theObservables, defaultGammaMin, defaultShapeSysGammaMax);
1120
1121 // Create the Function
1122 ParamHistFunc shapeFactorFunc( funcName.c_str(), funcName.c_str(),
1123 theObservables, shapeFactorParams );
1124
1125 proto.import( shapeFactorFunc, RooFit::RecycleConflictNodes() );
1126 paramHist = static_cast<ParamHistFunc*>(proto.function(funcName));
1127
1128 } // End: Create ShapeFactor ParamHistFunc
1129
1130 // Create the constraint terms and add
1131 // them to the workspace (proto)
1132 // as well as the list of constraint terms (constraintTermNames)
1133
1134 // The syst should be a fractional error
1135 const TH1* shapeErrorHist = shapeSys.GetErrorHist();
1136
1137 // Constraint::Type shapeConstraintType = Constraint::Gaussian;
1138 Constraint::Type systype = shapeSys.GetConstraintType();
1139 if( systype == Constraint::Gaussian) {
1140 systype = Constraint::Gaussian;
1141 }
1142 if( systype == Constraint::Poisson ) {
1143 systype = Constraint::Poisson;
1144 }
1145
1146 auto shapeConstraintsInfo = createGammaConstraints(
1147 paramHist->paramList(), histToVector(*shapeErrorHist),
1149 systype);
1150 for (auto const& term : shapeConstraintsInfo.constraints) {
1151 proto.import(*term, RooFit::RecycleConflictNodes());
1152 constraintTermNames.emplace_back(term->GetName());
1153 }
1154 // Add the "observed" value to the list of global observables:
1155 RooArgSet *globalSet = const_cast<RooArgSet *>(proto.set("globalObservables"));
1156 for (RooAbsArg * glob : shapeConstraintsInfo.globalObservables) {
1157 globalSet->add(*proto.var(glob->GetName()));
1158 }
1159
1160
1161 } // End: Loop over ShapeSys vector in this EstimateSummary
1162
1163 // Now that we have the list of ShapeSys ParamHistFunc names,
1164 // we create the total RooProduct
1165 // we multiply the expected function
1166
1167 for(std::string const& name : ShapeSysNames) {
1168 sampleHistFuncs.push_back(proto.function(name));
1169 }
1170
1171 } // End: !GetShapeSysList.empty()
1172
1173
1174 // GHL: This was pretty confusing before,
1175 // hopefully using the measurement directly
1176 // will improve it
1177 RooAbsArg *lumi = proto.arg("Lumi");
1178 if( !sample.GetNormalizeByTheory() ) {
1179 if (!lumi) {
1180 lumi = proto.factory("Lumi[" + std::to_string(measurement.GetLumi()) + "]");
1181 } else {
1182 static_cast<RooAbsRealLValue*>(lumi)->setVal(measurement.GetLumi());
1183 }
1184 }
1185 assert(lumi);
1186 normFactors->addTerm(lumi);
1187
1188 // Append the name of the "node"
1189 // that is to be summed with the
1190 // RooRealSumPdf
1191 proto.import(*normFactors, RooFit::RecycleConflictNodes());
1192 auto normFactorsInWS = dynamic_cast<RooProduct*>(proto.arg(normFactors->GetName()));
1193 assert(normFactorsInWS);
1194
1195 sampleScaleFactors.push_back(normFactorsInWS);
1196 } // END: Loop over EstimateSummaries
1197
1198 // If a non-zero number of samples call for
1199 // Stat Uncertainties, create the statFactor functions
1200 if(!statHistPairs.empty()) {
1201
1202 // Create the histogram of (binwise)
1203 // stat uncertainties:
1204 unique_ptr<TH1> fracStatError( MakeScaledUncertaintyHist( channel_name + "_StatUncert" + "_RelErr", statHistPairs) );
1205 if( fracStatError == nullptr ) {
1206 cxcoutE(HistFactory) << "Error: Failed to make ScaledUncertaintyHist for: "
1207 << channel_name + "_StatUncert" + "_RelErr" << std::endl;
1208 throw hf_exc();
1209 }
1210
1211 // Using this TH1* of fractinal stat errors,
1212 // create a set of constraint terms:
1213 auto chanStatUncertFunc = static_cast<ParamHistFunc*>(proto.function( statFuncName ));
1214 cxcoutI(HistFactory) << "About to create Constraint Terms from: "
1215 << chanStatUncertFunc->GetName()
1216 << " params: " << chanStatUncertFunc->paramList()
1217 << std::endl;
1218
1219 // Get the constraint type and the
1220 // rel error threshold from the (last)
1221 // EstimateSummary looped over (but all
1222 // should be the same)
1223
1224 // Get the type of StatError constraint from the channel
1225 Constraint::Type statConstraintType = channel.GetStatErrorConfig().GetConstraintType();
1226 if( statConstraintType == Constraint::Gaussian) {
1227 cxcoutI(HistFactory) << "Using Gaussian StatErrors in channel: " << channel.GetName() << std::endl;
1228 }
1229 if( statConstraintType == Constraint::Poisson ) {
1230 cxcoutI(HistFactory) << "Using Poisson StatErrors in channel: " << channel.GetName() << std::endl;
1231 }
1232
1233 double statRelErrorThreshold = channel.GetStatErrorConfig().GetRelErrorThreshold();
1234 auto statConstraintsInfo = createGammaConstraints(
1235 chanStatUncertFunc->paramList(), histToVector(*fracStatError),
1236 statRelErrorThreshold,
1237 statConstraintType);
1238 for (auto const& term : statConstraintsInfo.constraints) {
1239 proto.import(*term, RooFit::RecycleConflictNodes());
1240 constraintTermNames.emplace_back(term->GetName());
1241 }
1242 // Add the "observed" value to the list of global observables:
1243 RooArgSet *globalSet = const_cast<RooArgSet *>(proto.set("globalObservables"));
1244 for (RooAbsArg * glob : statConstraintsInfo.globalObservables) {
1245 globalSet->add(*proto.var(glob->GetName()));
1246 }
1247
1248 } // END: Loop over stat Hist Pairs
1249
1250
1251 ///////////////////////////////////
1252 // for ith bin calculate totN_i = lumi * sum_j expected_j * syst_j
1253 MakeTotalExpected(proto, channel_name+"_model",
1254 sampleScaleFactors, allSampleHistFuncs);
1255 likelihoodTermNames.push_back(channel_name+"_model");
1256
1257 //////////////////////////////////////
1258 // fix specified parameters
1259 for(unsigned int i=0; i<systToFix.size(); ++i){
1260 RooRealVar* temp = proto.var(systToFix.at(i));
1261 if(!temp) {
1262 cxcoutW(HistFactory) << "could not find variable " << systToFix.at(i)
1263 << " could not set it to constant" << endl;
1264 } else {
1265 // set the parameter constant
1266 temp->setConstant();
1267 }
1268 }
1269
1270 //////////////////////////////////////
1271 // final proto model
1272 for(unsigned int i=0; i<constraintTermNames.size(); ++i){
1273 RooAbsArg* proto_arg = proto.arg(constraintTermNames[i]);
1274 if( proto_arg==nullptr ) {
1275 cxcoutF(HistFactory) << "Error: Cannot find arg set: " << constraintTermNames.at(i)
1276 << " in workspace: " << proto.GetName() << std::endl;
1277 throw hf_exc();
1278 }
1279 constraintTerms.add( *proto_arg );
1280 // constraintTerms.add(* proto_arg(proto.arg(constraintTermNames[i].c_str())) );
1281 }
1282 for(unsigned int i=0; i<likelihoodTermNames.size(); ++i){
1283 RooAbsArg* proto_arg = (proto.arg(likelihoodTermNames[i]));
1284 if( proto_arg==nullptr ) {
1285 cxcoutF(HistFactory) << "Error: Cannot find arg set: " << likelihoodTermNames.at(i)
1286 << " in workspace: " << proto.GetName() << std::endl;
1287 throw hf_exc();
1288 }
1289 likelihoodTerms.add( *proto_arg );
1290 }
1291 proto.defineSet("constraintTerms",constraintTerms);
1292 proto.defineSet("likelihoodTerms",likelihoodTerms);
1293
1294 // list of observables
1295 RooArgList observables;
1296 std::string observablesStr;
1297
1298 for(std::string const& name : fObsNameVec) {
1299 observables.add( *proto.var(name) );
1300 if (!observablesStr.empty()) { observablesStr += ","; }
1301 observablesStr += name;
1302 }
1303
1304 // We create two sets, one for backwards compatibility
1305 // The other to make a consistent naming convention
1306 // between individual channels and the combined workspace
1307 proto.defineSet("observables", observablesStr.c_str());
1308 proto.defineSet("observablesSet", observablesStr.c_str());
1309
1310 // Create the ParamHistFunc
1311 // after observables have been made
1312 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1313 << "\timport model into workspace"
1314 << "\n-----------------------------------------\n" << endl;
1315
1316 auto model = make_unique<RooProdPdf>(
1317 ("model_"+channel_name).c_str(), // MB : have changed this into conditional pdf. Much faster for toys!
1318 "product of Poissons across bins for a single channel",
1319 constraintTerms, RooFit::Conditional(likelihoodTerms,observables));
1320 // can give channel a title by setting title of corresponding data histogram
1321 if (channel.GetData().GetHisto() && strlen(channel.GetData().GetHisto()->GetTitle())>0) {
1322 model->SetTitle(channel.GetData().GetHisto()->GetTitle());
1323 }
1324 proto.import(*model,RooFit::RecycleConflictNodes());
1325
1326 proto_config->SetPdf(*model);
1327 proto_config->SetObservables(observables);
1328 proto_config->SetGlobalObservables(*proto.set("globalObservables"));
1329 // proto.writeToFile(("results/model_"+channel+".root").c_str());
1330 // fill out nuisance parameters in model config
1331 // proto_config->GuessObsAndNuisance(*proto.data("asimovData"));
1332 proto.import(*proto_config,proto_config->GetName());
1333 proto.importClassCode();
1334
1335 ///////////////////////////
1336 // make data sets
1337 // THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
1338 // New Asimov Generation: Use the code in the Asymptotic calculator
1339 // Need to get the ModelConfig...
1340 int asymcalcPrintLevel = 0;
1341 if (RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::INFO)) asymcalcPrintLevel = 1;
1342 if (RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::DEBUG)) asymcalcPrintLevel = 2;
1343 AsymptoticCalculator::SetPrintLevel(asymcalcPrintLevel);
1344 unique_ptr<RooAbsData> asimov_dataset(AsymptoticCalculator::GenerateAsimovData(*model, observables));
1345 proto.import(*asimov_dataset, RooFit::Rename("asimovData"));
1346
1347 // GHL: Determine to use data if the hist isn't 'nullptr'
1348 if(TH1 const* mnominal = channel.GetData().GetHisto()) {
1349 // This works and is natural, but the memory size of the simultaneous
1350 // dataset grows exponentially with channels.
1351 RooDataSet dataset{"obsData","",*proto.set("observables"), RooFit::WeightVar("weightVar")};
1352 ConfigureHistFactoryDataset( dataset, *mnominal, proto, fObsNameVec );
1353 proto.import(dataset);
1354 } // End: Has non-null 'data' entry
1355
1356
1357 for(auto const& data : channel.GetAdditionalData()) {
1358 if(data.GetName().empty()) {
1359 cxcoutF(HistFactory) << "Error: Additional Data histogram for channel: " << channel.GetName()
1360 << " has no name! The name always needs to be set for additional datasets, "
1361 << "either via the \"Name\" tag in the XML or via RooStats::HistFactory::Data::SetName()." << std::endl;
1362 throw hf_exc();
1363 }
1364 std::string const& dataName = data.GetName();
1365 TH1 const* mnominal = data.GetHisto();
1366 if( !mnominal ) {
1367 cxcoutF(HistFactory) << "Error: Additional Data histogram for channel: " << channel.GetName()
1368 << " with name: " << dataName << " is nullptr" << std::endl;
1369 throw hf_exc();
1370 }
1371
1372 // THis works and is natural, but the memory size of the simultaneous dataset grows exponentially with channels
1373 RooDataSet dataset{dataName, "", *proto.set("observables"), RooFit::WeightVar("weightVar")};
1374 ConfigureHistFactoryDataset( dataset, *mnominal, proto, fObsNameVec );
1375 proto.import(dataset);
1376
1377 }
1378
1379 if (RooMsgService::instance().isActive(nullptr, RooFit::HistFactory, RooFit::INFO)) {
1380 proto.Print();
1381 }
1382
1383 return protoOwner;
1384 }
1385
1386
1388 TH1 const& mnominal,
1390 std::vector<std::string> const& obsNameVec) {
1391
1392 // Take a RooDataSet and fill it with the entries
1393 // from a TH1*, using the observable names to
1394 // determine the columns
1395
1396 if (obsNameVec.empty() ) {
1397 Error("ConfigureHistFactoryDataset","Invalid input - return");
1398 return;
1399 }
1400
1401 TAxis const* ax = mnominal.GetXaxis();
1402 TAxis const* ay = mnominal.GetYaxis();
1403 TAxis const* az = mnominal.GetZaxis();
1404
1405 for (int i=1; i<=ax->GetNbins(); ++i) { // 1 or more dimension
1406
1407 double xval = ax->GetBinCenter(i);
1408 proto.var( obsNameVec[0] )->setVal( xval );
1409
1410 if(obsNameVec.size()==1) {
1411 double fval = mnominal.GetBinContent(i);
1412 obsDataUnbinned.add( *proto.set("observables"), fval );
1413 } else { // 2 or more dimensions
1414
1415 for(int j=1; j<=ay->GetNbins(); ++j) {
1416 double yval = ay->GetBinCenter(j);
1417 proto.var( obsNameVec[1] )->setVal( yval );
1418
1419 if(obsNameVec.size()==2) {
1420 double fval = mnominal.GetBinContent(i,j);
1421 obsDataUnbinned.add( *proto.set("observables"), fval );
1422 } else { // 3 dimensions
1423
1424 for(int k=1; k<=az->GetNbins(); ++k) {
1425 double zval = az->GetBinCenter(k);
1426 proto.var( obsNameVec[2] )->setVal( zval );
1427 double fval = mnominal.GetBinContent(i,j,k);
1428 obsDataUnbinned.add( *proto.set("observables"), fval );
1429 }
1430 }
1431 }
1432 }
1433 }
1434 }
1435
1437 {
1438 fObsNameVec = std::vector<string>{"x", "y", "z"};
1439 fObsNameVec.resize(hist->GetDimension());
1440 }
1441
1442
1444 HistoToWorkspaceFactoryFast::MakeCombinedModel(std::vector<std::string> ch_names,
1445 std::vector<std::unique_ptr<RooWorkspace>> &chs)
1446 {
1448
1449 // check first the inputs (see JIRA-6890)
1450 if (ch_names.empty() || chs.empty() ) {
1451 Error("MakeCombinedModel","Input vectors are empty - return a nullptr");
1452 return nullptr;
1453 }
1454 if (chs.size() < ch_names.size() ) {
1455 Error("MakeCombinedModel","Input vector of workspace has an invalid size - return a nullptr");
1456 return nullptr;
1457 }
1458
1459 //
1460 /// These things were used for debugging. Maybe useful in the future
1461 //
1462
1463 map<string, RooAbsPdf*> pdfMap;
1464 vector<RooAbsPdf*> models;
1465
1466 RooArgList obsList;
1467 for(unsigned int i = 0; i< ch_names.size(); ++i){
1468 obsList.add(*static_cast<ModelConfig *>(chs[i]->obj("ModelConfig"))->GetObservables());
1469 }
1470 cxcoutI(HistFactory) <<"full list of observables:\n" << obsList << std::endl;
1471
1472 RooArgSet globalObs;
1473 stringstream channelString;
1474 channelString << "channelCat[";
1475 for(unsigned int i = 0; i< ch_names.size(); ++i){
1476 string channel_name=ch_names[i];
1477 if (i == 0 && isdigit(channel_name[0])) {
1478 throw std::invalid_argument("The first channel name for HistFactory cannot start with a digit. Got " + channel_name);
1479 }
1480 if (channel_name.find(',') != std::string::npos) {
1481 throw std::invalid_argument("Channel names for HistFactory cannot contain ','. Got " + channel_name);
1482 }
1483
1484 if (i == 0) channelString << channel_name ;
1485 else channelString << ',' << channel_name ;
1486 RooWorkspace * ch=chs[i].get();
1487
1488 RooAbsPdf* model = ch->pdf("model_"+channel_name);
1489 if(!model) cout <<"failed to find model for channel"<<endl;
1490 // cout << "int = " << model->createIntegral(*obsN)->getVal() << endl;;
1491 models.push_back(model);
1492 globalObs.add(*ch->set("globalObservables"), /*silent=*/true); // silent because observables might exist in other channel.
1493
1494 // constrainedParams->add( * ch->set("constrainedParams") );
1495 pdfMap[channel_name]=model;
1496 }
1497 channelString << "]";
1498
1499 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1500 << "\tEntering combination"
1501 << "\n-----------------------------------------\n" << endl;
1502 auto combined = std::make_unique<RooWorkspace>("combined");
1503
1504
1505 RooCategory* channelCat = dynamic_cast<RooCategory*>( combined->factory(channelString.str()) );
1506 if (!channelCat) throw std::runtime_error("Unable to construct a category from string " + channelString.str());
1507
1508 auto simPdf= std::make_unique<RooSimultaneous>("simPdf","",pdfMap, *channelCat);
1509 auto combined_config = std::make_unique<ModelConfig>("ModelConfig", combined.get());
1510 combined_config->SetWorkspace(*combined);
1511 // combined_config->SetNuisanceParameters(*constrainedParams);
1512
1513 combined->import(globalObs);
1514 combined->defineSet("globalObservables",globalObs);
1515 combined_config->SetGlobalObservables(*combined->set("globalObservables"));
1516
1517 combined->defineSet("observables",{obsList, *channelCat}, /*importMissing=*/true);
1518 combined_config->SetObservables(*combined->set("observables"));
1519
1520
1521 // Now merge the observable datasets across the channels
1522 for(RooAbsData * data : chs[0]->allData()) {
1523 // We are excluding the Asimov data, because it needs to be regenerated
1524 // later after the parameter values are set.
1525 if(std::string("asimovData") == data->GetName()) {
1526 continue;
1527 }
1528 // Loop through channels, get their individual datasets,
1529 // and add them to the combined dataset
1530 std::map<std::string, RooAbsData*> dataMap;
1531 for(unsigned int i = 0; i < ch_names.size(); ++i){
1532 dataMap[ch_names[i]] = chs[i]->data(data->GetName());
1533 }
1534 combined->import(RooDataSet{data->GetName(), "", obsList, RooFit::Index(*channelCat),
1535 RooFit::WeightVar("weightVar"), RooFit::Import(dataMap)});
1536 }
1537
1538
1540 combined->Print();
1541
1542 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1543 << "\tImporting combined model"
1544 << "\n-----------------------------------------\n" << endl;
1545 combined->import(*simPdf,RooFit::RecycleConflictNodes());
1546
1547 for(auto const& param_itr : fParamValues) {
1548 // make sure they are fixed
1549 std::string paramName = param_itr.first;
1550 double paramVal = param_itr.second;
1551
1552 if(RooRealVar* temp = combined->var( paramName )) {
1553 temp->setVal( paramVal );
1554 cxcoutI(HistFactory) <<"setting " << paramName << " to the value: " << paramVal << endl;
1555 } else
1556 cxcoutE(HistFactory) << "could not find variable " << paramName << " could not set its value" << endl;
1557 }
1558
1559
1560 for(unsigned int i=0; i<fSystToFix.size(); ++i){
1561 // make sure they are fixed
1562 if(RooRealVar* temp = combined->var(fSystToFix[i])) {
1563 temp->setConstant();
1564 cxcoutI(HistFactory) <<"setting " << fSystToFix.at(i) << " constant" << endl;
1565 } else
1566 cxcoutE(HistFactory) << "could not find variable " << fSystToFix.at(i) << " could not set it to constant" << endl;
1567 }
1568
1569 ///
1570 /// writing out the model in graphViz
1571 ///
1572 // RooAbsPdf* customized=combined->pdf("simPdf");
1573 //combined_config->SetPdf(*customized);
1574 combined_config->SetPdf(*simPdf);
1575 // combined_config->GuessObsAndNuisance(*simData);
1576 // customized->graphVizTree(("results/"+fResultsPrefixStr.str()+"_simul.dot").c_str());
1577 combined->import(*combined_config,combined_config->GetName());
1578 combined->importClassCode();
1579 // combined->writeToFile("results/model_combined.root");
1580
1581
1582 ////////////////////////////////////////////
1583 // Make toy simultaneous dataset
1584 cxcoutP(HistFactory) << "\n-----------------------------------------\n"
1585 << "\tcreate toy data for " << channelString.str()
1586 << "\n-----------------------------------------\n" << endl;
1587
1588
1589 // now with weighted datasets
1590 // First Asimov
1591
1592 // Create Asimov data for the combined dataset
1593 std::unique_ptr<RooAbsData> asimov_combined{AsymptoticCalculator::GenerateAsimovData(
1594 *combined->pdf("simPdf"),
1595 obsList)};
1596 if( asimov_combined ) {
1597 combined->import( *asimov_combined, RooFit::Rename("asimovData"));
1598 }
1599 else {
1600 std::cout << "Error: Failed to create combined asimov dataset" << std::endl;
1601 throw hf_exc();
1602 }
1603
1604 return RooFit::Detail::owningPtr(std::move(combined));
1605 }
1606
1607
1608 TH1* HistoToWorkspaceFactoryFast::MakeAbsolUncertaintyHist( const std::string& Name, const TH1* Nominal ) {
1609
1610 // Take a nominal TH1* and create
1611 // a TH1 representing the binwise
1612 // errors (taken from the nominal TH1)
1613
1614 auto ErrorHist = static_cast<TH1*>(Nominal->Clone( Name.c_str() ));
1615 ErrorHist->Reset();
1616
1617 int numBins = Nominal->GetNbinsX()*Nominal->GetNbinsY()*Nominal->GetNbinsZ();
1618 int binNumber = 0;
1619
1620 // Loop over bins
1621 for( int i_bin = 0; i_bin < numBins; ++i_bin) {
1622
1623 binNumber++;
1624 // Ignore underflow / overflow
1625 while( Nominal->IsBinUnderflow(binNumber) || Nominal->IsBinOverflow(binNumber) ){
1626 binNumber++;
1627 }
1628
1629 double histError = Nominal->GetBinError( binNumber );
1630
1631 // Check that histError != NAN
1632 if( histError != histError ) {
1633 std::cout << "Warning: In histogram " << Nominal->GetName()
1634 << " bin error for bin " << i_bin
1635 << " is NAN. Not using Error!!!"
1636 << std::endl;
1637 throw hf_exc();
1638 //histError = sqrt( histContent );
1639 //histError = 0;
1640 }
1641
1642 // Check that histError ! < 0
1643 if( histError < 0 ) {
1644 std::cout << "Warning: In histogram " << Nominal->GetName()
1645 << " bin error for bin " << binNumber
1646 << " is < 0. Setting Error to 0"
1647 << std::endl;
1648 //histError = sqrt( histContent );
1649 histError = 0;
1650 }
1651
1652 ErrorHist->SetBinContent( binNumber, histError );
1653
1654 }
1655
1656 return ErrorHist;
1657
1658 }
1659
1660 // Take a list of < nominal, absolError > TH1* pairs
1661 // and construct a single histogram representing the
1662 // total fractional error as:
1663
1664 // UncertInQuad(bin i) = Sum: absolUncert*absolUncert
1665 // Total(bin i) = Sum: Value
1666 //
1667 // TotalFracError(bin i) = Sqrt( UncertInQuad(i) ) / TotalBin(i)
1668 std::unique_ptr<TH1> HistoToWorkspaceFactoryFast::MakeScaledUncertaintyHist( const std::string& Name, std::vector< std::pair<const TH1*, std::unique_ptr<TH1>> > const& HistVec ) const {
1669
1670
1671 unsigned int numHists = HistVec.size();
1672
1673 if( numHists == 0 ) {
1674 cxcoutE(HistFactory) << "Warning: Empty Hist Vector, cannot create total uncertainty" << std::endl;
1675 return nullptr;
1676 }
1677
1678 const TH1* HistTemplate = HistVec.at(0).first;
1679 int numBins = HistTemplate->GetNbinsX()*HistTemplate->GetNbinsY()*HistTemplate->GetNbinsZ();
1680
1681 // Check that all histograms
1682 // have the same bins
1683 for( unsigned int i = 0; i < HistVec.size(); ++i ) {
1684
1685 const TH1* nominal = HistVec.at(i).first;
1686 const TH1* error = HistVec.at(i).second.get();
1687
1688 if( nominal->GetNbinsX()*nominal->GetNbinsY()*nominal->GetNbinsZ() != numBins ) {
1689 cxcoutE(HistFactory) << "Error: Provided hists have unequal bins" << std::endl;
1690 return nullptr;
1691 }
1692 if( error->GetNbinsX()*error->GetNbinsY()*error->GetNbinsZ() != numBins ) {
1693 cxcoutE(HistFactory) << "Error: Provided hists have unequal bins" << std::endl;
1694 return nullptr;
1695 }
1696 }
1697
1698 std::vector<double> TotalBinContent( numBins, 0.0);
1699 std::vector<double> HistErrorsSqr( numBins, 0.0);
1700
1701 int binNumber = 0;
1702
1703 // Loop over bins
1704 for( int i_bins = 0; i_bins < numBins; ++i_bins) {
1705
1706 binNumber++;
1707 while( HistTemplate->IsBinUnderflow(binNumber) || HistTemplate->IsBinOverflow(binNumber) ){
1708 binNumber++;
1709 }
1710
1711 for( unsigned int i_hist = 0; i_hist < numHists; ++i_hist ) {
1712
1713 const TH1* nominal = HistVec.at(i_hist).first;
1714 const TH1* error = HistVec.at(i_hist).second.get();
1715
1716 //int binNumber = i_bins + 1;
1717
1718 double histValue = nominal->GetBinContent( binNumber );
1719 double histError = error->GetBinContent( binNumber );
1720
1721 if( histError != histError ) {
1722 cxcoutE(HistFactory) << "In histogram " << error->GetName()
1723 << " bin error for bin " << binNumber
1724 << " is NAN. Not using error!!";
1725 throw hf_exc();
1726 }
1727
1728 TotalBinContent.at(i_bins) += histValue;
1729 HistErrorsSqr.at(i_bins) += histError*histError; // Add in quadrature
1730
1731 }
1732 }
1733
1734 binNumber = 0;
1735
1736 // Creat the output histogram
1737 TH1* ErrorHist = (TH1*) HistTemplate->Clone( Name.c_str() );
1738 ErrorHist->Reset();
1739
1740 // Fill the output histogram
1741 for( int i = 0; i < numBins; ++i) {
1742
1743 // int binNumber = i + 1;
1744 binNumber++;
1745 while( ErrorHist->IsBinUnderflow(binNumber) || ErrorHist->IsBinOverflow(binNumber) ){
1746 binNumber++;
1747 }
1748
1749 double ErrorsSqr = HistErrorsSqr.at(i);
1750 double TotalVal = TotalBinContent.at(i);
1751
1752 if( TotalVal <= 0 ) {
1753 cxcoutW(HistFactory) << "Warning: Sum of histograms for bin: " << binNumber
1754 << " is <= 0. Setting error to 0"
1755 << std::endl;
1756
1757 ErrorHist->SetBinContent( binNumber, 0.0 );
1758 continue;
1759 }
1760
1761 double RelativeError = sqrt(ErrorsSqr) / TotalVal;
1762
1763 // If we otherwise get a NAN
1764 // it's an error
1765 if( RelativeError != RelativeError ) {
1766 cxcoutE(HistFactory) << "Error: bin " << i << " error is NAN\n"
1767 << " HistErrorsSqr: " << ErrorsSqr
1768 << " TotalVal: " << TotalVal;
1769 throw hf_exc();
1770 }
1771
1772 // 0th entry in vector is
1773 // the 1st bin in TH1
1774 // (we ignore underflow)
1775
1776 // Error and bin content are interchanged because for some reason, the other functions
1777 // use the bin content to convey the error ...
1778 ErrorHist->SetBinError(binNumber, TotalVal);
1779 ErrorHist->SetBinContent(binNumber, RelativeError);
1780
1781 cxcoutI(HistFactory) << "Making Total Uncertainty for bin " << binNumber
1782 << " Error = " << sqrt(ErrorsSqr)
1783 << " CentralVal = " << TotalVal
1784 << " RelativeError = " << RelativeError << "\n";
1785
1786 }
1787
1788 return std::unique_ptr<TH1>(ErrorHist);
1789}
1790
1791
1792} // namespace RooStats
1793} // namespace HistFactory
1794
#define cxcoutPHF
#define cxcoutFHF
#define cxcoutIHF
#define cxcoutWHF
std::vector< double > histToVector(TH1 const &hist)
constexpr double alphaHigh
constexpr double alphaLow
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define cxcoutI(a)
#define cxcoutW(a)
#define cxcoutF(a)
#define cxcoutE(a)
#define cxcoutP(a)
#define ClassImp(name)
Definition Rtypes.h:377
#define R__ASSERT(e)
Definition TError.h:118
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:17536
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.
Definition RooAbsArg.h:79
void Print(Option_t *options=nullptr) const override
Print the object to the defaultPrintStream().
Definition RooAbsArg.h:322
void setAttribute(const Text_t *name, bool value=true)
Set (default) or clear a named boolean attribute of this object.
Int_t getSize() const
Return the number of elements in the collection.
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.
const_iterator begin() const
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:57
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:40
RooAbsRealLValue is the common abstract base class for objects that represent a real value that may a...
void setConstant(bool value=true)
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:59
RooNumIntConfig * specialIntegratorConfig() const
Returns the specialized integrator configuration for this RooAbsReal.
virtual void forceNumInt(bool flag=true)
Definition RooAbsReal.h:169
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:55
RooBinWidthFunction is a class that returns the bin width (or volume) given a RooHistFunc.
Class RooBinning is an implements RooAbsBinning in terms of an array of boundary values,...
Definition RooBinning.h:27
Object to represent discrete states.
Definition RooCategory.h:28
bool setLabel(const char *label, bool printError=true) override
Set value by specifying the name of the desired state.
RooConstVar represent a constant real-valued object.
Definition RooConstVar.h:23
The RooDataHist is a container class to hold N-dimensional binned data.
Definition RooDataHist.h:39
RooDataSet is a container class to hold unbinned data.
Definition RooDataSet.h:57
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.
Switches the message service to a different level while the instance is alive.
Definition RooHelpers.h:37
RooHistFunc implements a real-valued function sampled from a multidimensional histogram.
Definition RooHistFunc.h:31
static RooMsgService & instance()
Return reference to singleton instance.
bool isActive(T self, RooFit::MsgTopic topic, RooFit::MsgLevel level)
Check if logging is active for given object/topic/RooFit::MsgLevel combination.
RooCategory & method2D()
RooCategory & methodND()
RooCategory & method1D()
A RooProduct represents the product of a given set of RooAbsReal objects.
Definition RooProduct.h:29
Implements a PDF constructed from a sum of functions:
RooRealVar represents a variable that can be changed from the outside.
Definition RooRealVar.h:37
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.
Definition Asimov.h:22
void ConfigureWorkspace(RooWorkspace *)
Definition Asimov.cxx:22
This class encapsulates all information for the statistical interpretation of one experiment.
Definition Channel.h:30
std::vector< RooStats::HistFactory::Data > & GetAdditionalData()
retrieve vector of additional data objects
Definition Channel.h:65
void Print(std::ostream &=std::cout)
Definition Channel.cxx:75
HistFactory::StatErrorConfig & GetStatErrorConfig()
get information about threshold for statistical uncertainties and constraint term
Definition Channel.h:72
RooStats::HistFactory::Data & GetData()
get data object
Definition Channel.h:59
std::vector< RooStats::HistFactory::Sample > & GetSamples()
get vector of samples for this channel
Definition Channel.h:77
std::string GetName() const
get name of channel
Definition Channel.h:43
Configuration for a constrained, coherent shape variation of affected samples.
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...
Definition Measurement.h:31
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
Definition Measurement.h:51
std::map< std::string, double > & GetUniformSyst()
std::vector< std::string > & GetConstantParams()
get vector of all constant parameters
Definition Measurement.h:60
std::vector< RooStats::HistFactory::Channel > & GetChannels()
std::vector< RooStats::HistFactory::Asimov > & GetAsimovDatasets()
get vector of defined Asimov Datasets
Definition Measurement.h:80
std::vector< std::string > GetPreprocessFunctions() const
Returns a list of defined preprocess function expressions.
double GetLumi()
retrieve integrated luminosity
Definition Measurement.h:89
Configuration for an un- constrained overall systematic to scale sample normalisations.
Definition Systematics.h:62
Configuration for a constrained overall systematic to scale sample normalisations.
Definition Systematics.h:34
const std::string & GetName() const
Definition Systematics.h:41
std::string GetName() const
get name of sample
Definition Sample.h:82
std::vector< RooStats::HistFactory::NormFactor > & GetNormFactorList()
Definition Sample.h:109
*Un*constrained bin-by-bin variation of affected histogram.
Constrained bin-by-bin variation of affected histogram.
Constraint::Type GetConstraintType() const
ModelConfig is a simple class that holds configuration information specifying how a model should be u...
Definition ModelConfig.h:35
void GuessObsAndNuisance(const RooAbsData &data, bool printModelConfig=true)
Makes sensible guesses of observables, parameters of interest and nuisance parameters if one or multi...
virtual void SetParametersOfInterest(const RooArgSet &set)
Specify parameters of interest.
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.
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.
RooFactoryWSTool & factory()
Return instance to factory tool.
RooRealVar * var(RooStringView name) const
Retrieve real-valued variable (RooRealVar) with given name. A null pointer is returned if not found.
RooAbsData * data(RooStringView name) const
Retrieve dataset (binned or unbinned) 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.
const Double_t * GetArray() const
Definition TArrayD.h:43
Class to manage histogram axis.
Definition TAxis.h:31
Bool_t IsVariableBinSize() const
Definition TAxis.h:142
const char * GetTitle() const override
Returns title of object.
Definition TAxis.h:135
virtual Double_t GetBinCenter(Int_t bin) const
Return center of bin.
Definition TAxis.cxx:478
const TArrayD * GetXbins() const
Definition TAxis.h:136
Double_t GetXmax() const
Definition TAxis.h:140
Double_t GetXmin() const
Definition TAxis.h:139
Int_t GetNbins() const
Definition TAxis.h:125
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:58
TAxis * GetZaxis()
Definition TH1.h:324
virtual Int_t GetNbinsY() const
Definition TH1.h:296
virtual Double_t GetBinError(Int_t bin) const
Return value of error associated to bin number bin.
Definition TH1.cxx:8980
virtual Int_t GetNbinsZ() const
Definition TH1.h:297
virtual Int_t GetDimension() const
Definition TH1.h:281
virtual void Reset(Option_t *option="")
Reset this histogram: contents, errors, etc.
Definition TH1.cxx:7098
TAxis * GetXaxis()
Definition TH1.h:322
virtual Int_t GetNbinsX() const
Definition TH1.h:295
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...
Definition TH1.cxx:9123
TAxis * GetYaxis()
Definition TH1.h:323
Bool_t IsBinUnderflow(Int_t bin, Int_t axis=0) const
Return true if the bin is underflow.
Definition TH1.cxx:5185
Bool_t IsBinOverflow(Int_t bin, Int_t axis=0) const
Return true if the bin is overflow.
Definition TH1.cxx:5153
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...
Definition TH1.cxx:9139
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5032
TObject * Clone(const char *newname="") const override
Make a complete copy of the underlying object.
Definition TH1.cxx:2734
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:207
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:987
Stopwatch class.
Definition TStopwatch.h:28
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
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:2356
RooCmdArg RecycleConflictNodes(bool flag=true)
RooCmdArg Rename(const char *suffix)
RooCmdArg Conditional(const RooArgSet &pdfSet, const RooArgSet &depSet, bool depsAreCond=false)
RooCmdArg Index(RooCategory &icat)
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg Import(const char *state, TH1 &histo)
OwningPtr< T > owningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:50
@ ObjectHandling
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:43
CreateGammaConstraintsOutput createGammaConstraints(RooArgList const &paramList, std::span< const double > relSigmas, double minSigma, Constraint::Type type)
Namespace for the RooStats classes.
Definition Asimov.h:19