Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HistFactoryJSONTool.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * Carsten D. Burgard, DESY/ATLAS, Dec 2021
5 *
6 * Copyright (c) 2022, CERN
7 *
8 * Redistribution and use in source and binary forms,
9 * with or without modification, are permitted according to the terms
10 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
11 */
12
16
20
21#include "Domains.h"
22
23#include "TH1.h"
24
27
28namespace {
29
30bool checkRegularBins(const TAxis &ax)
31{
32 double w = ax.GetXmax() - ax.GetXmin();
33 double bw = w / ax.GetNbins();
34 for (int i = 0; i <= ax.GetNbins(); ++i) {
35 if (std::abs(ax.GetBinUpEdge(i) - (ax.GetXmin() + (bw * i))) > w * 1e-6)
36 return false;
37 }
38 return true;
39}
40
41inline void writeAxis(JSONNode &axis, const TAxis &ax)
42{
43 bool regular = (!ax.IsVariableBinSize()) || checkRegularBins(ax);
44 axis.set_map();
45 if (regular) {
46 axis["nbins"] << ax.GetNbins();
47 axis["min"] << ax.GetXmin();
48 axis["max"] << ax.GetXmax();
49 } else {
50 auto &bounds = axis["bounds"];
51 bounds.set_seq();
52 for (int i = 0; i <= ax.GetNbins(); ++i) {
53 bounds.append_child() << ax.GetBinUpEdge(i);
54 }
55 }
56}
57
58std::vector<std::string> getObsnames(RooStats::HistFactory::Channel const &c)
59{
60 std::vector<std::string> obsnames{"obs_x_" + c.GetName(), "obs_y_" + c.GetName(), "obs_z_" + c.GetName()};
61 obsnames.resize(c.GetData().GetHisto()->GetDimension());
62 return obsnames;
63}
64
65void writeObservables(const TH1 &h, JSONNode &n, const std::vector<std::string> &varnames)
66{
67 // axes need to be ordered, so this is a sequence and not a map
68 auto &observables = n["axes"].set_seq();
69 auto &x = observables.append_child().set_map();
70 x["name"] << varnames[0];
71 writeAxis(x, *h.GetXaxis());
72 if (h.GetDimension() > 1) {
73 auto &y = observables.append_child().set_map();
74 y["name"] << varnames[1];
75 writeAxis(y, *(h.GetYaxis()));
76 if (h.GetDimension() > 2) {
77 auto &z = observables.append_child().set_map();
78 z["name"] << varnames[2];
79 writeAxis(z, *(h.GetZaxis()));
80 }
81 }
82}
83
84void exportHistogram(const TH1 &histo, JSONNode &node, const std::vector<std::string> &varnames,
85 const TH1 *errH = nullptr, bool doWriteObservables = true, bool writeErrors = true)
86{
87 node.set_map();
88 auto &weights = node["contents"].set_seq();
89 JSONNode *errors = nullptr;
90 if (writeErrors) {
91 errors = &node["errors"].set_seq();
92 }
93 if (doWriteObservables) {
94 writeObservables(histo, node, varnames);
95 }
96 const int nBins = histo.GetNbinsX() * histo.GetNbinsY() * histo.GetNbinsZ();
97 for (int i = 1; i <= nBins; ++i) {
98 const double val = histo.GetBinContent(i);
99 weights.append_child() << val;
100 if (writeErrors) {
101 const double err = errH ? val * errH->GetBinContent(i) : histo.GetBinError(i);
102 errors->append_child() << err;
103 }
104 }
105}
106
107void exportSample(const RooStats::HistFactory::Sample &sample, JSONNode &channelNode,
108 std::vector<std::string> const &obsnames)
109{
110 auto &s = RooJSONFactoryWSTool::appendNamedChild(channelNode["samples"], sample.GetName());
111
112 if (!sample.GetOverallSysList().empty()) {
113 auto &modifiers = s["modifiers"];
114 for (const auto &sys : sample.GetOverallSysList()) {
115 auto &node = RooJSONFactoryWSTool::appendNamedChild(modifiers, sys.GetName());
116 node["type"] << "normsys";
117 auto &data = node["data"];
118 data.set_map();
119 data["lo"] << sys.GetLow();
120 data["hi"] << sys.GetHigh();
121 }
122 }
123
124 if (!sample.GetNormFactorList().empty()) {
125 auto &modifiers = s["modifiers"];
126 for (const auto &nf : sample.GetNormFactorList()) {
127 RooJSONFactoryWSTool::appendNamedChild(modifiers, nf.GetName())["type"] << "normfactor";
128 }
129 auto &mod = RooJSONFactoryWSTool::appendNamedChild(modifiers, "Lumi");
130 mod["type"] << "normfactor";
131 mod["constraint_name"] << "lumiConstraint";
132 }
133
134 if (!sample.GetHistoSysList().empty()) {
135 auto &modifiers = s["modifiers"];
136 for (size_t i = 0; i < sample.GetHistoSysList().size(); ++i) {
137 auto &sys = sample.GetHistoSysList()[i];
138 auto &node = RooJSONFactoryWSTool::appendNamedChild(modifiers, sys.GetName());
139 node["type"] << "histosys";
140 auto &data = node["data"].set_map();
141 exportHistogram(*(sys.GetHistoLow()), data["lo"], obsnames, nullptr, false);
142 exportHistogram(*(sys.GetHistoHigh()), data["hi"], obsnames, nullptr, false);
143 }
144 }
145
146 auto &tags = s["dict"].set_map();
147 tags["normalizeByTheory"] << sample.GetNormalizeByTheory();
148
149 if (sample.GetStatError().GetActivate()) {
151 }
152
153 auto &data = s["data"];
154 const bool useStatError = sample.GetStatError().GetActivate() && sample.GetStatError().GetUseHisto();
155 TH1 const *errH = useStatError ? sample.GetStatError().GetErrorHist() : nullptr;
156
157 if (!channelNode.has_child("axes")) {
158 writeObservables(*sample.GetHisto(), channelNode, obsnames);
159 }
160 exportHistogram(*sample.GetHisto(), data, obsnames, errH, false);
161}
162
163void exportChannel(const RooStats::HistFactory::Channel &c, JSONNode &ch)
164{
165 ch["type"] << "histfactory_dist";
166
167 auto &staterr = ch["statError"].set_map();
168 staterr["relThreshold"] << c.GetStatErrorConfig().GetRelErrorThreshold();
169 staterr["constraint"] << RooStats::HistFactory::Constraint::Name(c.GetStatErrorConfig().GetConstraintType());
170
171 const std::vector<std::string> obsnames = getObsnames(c);
172
173 for (const auto &s : c.GetSamples()) {
174 exportSample(s, ch, obsnames);
175 }
176}
177
178void exportMeasurement(RooStats::HistFactory::Measurement &measurement, JSONNode &n,
180{
181 using namespace RooStats::HistFactory;
182
183 for (const auto &ch : measurement.GetChannels()) {
184 if (!ch.CheckHistograms())
185 throw std::runtime_error("unable to export histograms, please call CollectHistograms first");
186 }
187
188 // collect information
189 std::map<std::string, RooStats::HistFactory::Constraint::Type> constraints;
190 std::map<std::string, NormFactor> normfactors;
191 for (const auto &ch : measurement.GetChannels()) {
192 for (const auto &s : ch.GetSamples()) {
193 for (const auto &sys : s.GetOverallSysList()) {
194 constraints[sys.GetName()] = RooStats::HistFactory::Constraint::Gaussian;
195 }
196 for (const auto &sys : s.GetHistoSysList()) {
197 constraints[sys.GetName()] = RooStats::HistFactory::Constraint::Gaussian;
198 }
199 for (const auto &sys : s.GetShapeSysList()) {
200 constraints[sys.GetName()] = sys.GetConstraintType();
201 }
202 for (const auto &norm : s.GetNormFactorList()) {
203 normfactors[norm.GetName()] = norm;
204 }
205 }
206 }
207
208 // preprocess functions
209 if (!measurement.GetFunctionObjects().empty()) {
210 auto &funclist = n["functions"];
211 for (const auto &func : measurement.GetFunctionObjects()) {
212 auto &f = RooJSONFactoryWSTool::appendNamedChild(funclist, func.GetName());
213 f["name"] << func.GetName();
214 f["expression"] << func.GetExpression();
215 f["dependents"] << func.GetDependents();
216 f["command"] << func.GetCommand();
217 }
218 }
219
220 auto &pdflist = n["distributions"];
221
222 auto &analysisNode = RooJSONFactoryWSTool::appendNamedChild(n["analyses"], "simPdf");
223 analysisNode["domains"].set_seq().append_child() << "default_domain";
224
225 auto &analysisPois = analysisNode["parameters_of_interest"].set_seq();
226
227 for (const auto &poi : measurement.GetPOIList()) {
228 analysisPois.append_child() << poi;
229 }
230
231 analysisNode["likelihood"] << measurement.GetName();
232
233 auto &likelihoodNode = RooJSONFactoryWSTool::appendNamedChild(n["likelihoods"], measurement.GetName());
234 likelihoodNode["distributions"].set_seq();
235 likelihoodNode["data"].set_seq();
236
237 // the simpdf
238 for (const auto &c : measurement.GetChannels()) {
239
240 auto pdfName = std::string("model_") + c.GetName();
241
242 likelihoodNode["distributions"].append_child() << pdfName;
243 likelihoodNode["data"].append_child() << std::string("obsData_") + c.GetName();
244 exportChannel(c, RooJSONFactoryWSTool::appendNamedChild(pdflist, pdfName));
245 }
246
247 struct VariableInfo {
248 double val = 0.0;
249 double minVal = -5.0;
250 double maxVal = 5.0;
251 bool isConstant = false;
252 bool writeDomain = true;
253 };
254 std::unordered_map<std::string, VariableInfo> variables;
255
256 for (const auto &channel : measurement.GetChannels()) {
257 for (const auto &sample : channel.GetSamples()) {
258 for (const auto &norm : sample.GetNormFactorList()) {
259 auto &info = variables[norm.GetName()];
260 info.val = norm.GetVal();
261 info.minVal = norm.GetLow();
262 info.maxVal = norm.GetHigh();
263 }
264 for (const auto &sys : sample.GetOverallSysList()) {
265 variables[std::string("alpha_") + sys.GetName()] = VariableInfo{};
266 }
267 }
268 }
269 for (const auto &sys : measurement.GetConstantParams()) {
270 auto &info = variables[sys];
271 info.isConstant = true;
272 bool isGamma = sys.find("gamma_") != std::string::npos;
273 // Gammas are 1.0 by default, alphas are 0.0
274 info.val = isGamma ? 1.0 : 0.0;
275 // For the gamma parameters, HistFactory will figure out the ranges
276 // itself based on the template bin contents and errors.
277 info.writeDomain = !isGamma;
278 }
279
280 // the lumi variables
281 {
282 double nominal = measurement.GetLumi();
283 double error = measurement.GetLumi() * measurement.GetLumiRelErr();
284
285 auto &info1 = variables["Lumi"];
286 info1.val = nominal;
287 info1.minVal = 0;
288 info1.maxVal = 10 * nominal;
289 info1.isConstant = true;
290
291 auto &info2 = variables["nominalLumi"];
292 info2.val = nominal;
293 info2.minVal = 0;
294 info2.maxVal = nominal + 10 * error;
295 info2.isConstant = true;
296 }
297
299 for (auto const &item : variables) {
300 std::string const &parname = item.first;
301 VariableInfo const &info = item.second;
302
303 auto &v = RooJSONFactoryWSTool::appendNamedChild(varlist, parname);
304 v["value"] << info.val;
305 if (info.isConstant)
306 v["const"] << true;
307 if (info.writeDomain) {
308 domains.readVariable(parname.c_str(), info.minVal, info.maxVal);
309 }
310 }
311
312 // the data
313 auto &child1 = n.get("misc", "ROOT_internal", "combined_datas").set_map()["obsData"].set_map();
314 auto &child2 = n.get("misc", "ROOT_internal", "combined_distributions").set_map()["simPdf"].set_map();
315
316 child1["index_cat"] << "channelCat";
317 auto &labels1 = child1["labels"].set_seq();
318 auto &indices1 = child1["indices"].set_seq();
319
320 child2["index_cat"] << "channelCat";
321 auto &labels2 = child2["labels"].set_seq();
322 auto &indices2 = child2["indices"].set_seq();
323 auto &pdfs2 = child2["distributions"].set_seq();
324
325 std::vector<std::string> channelNames;
326 for (const auto &c : measurement.GetChannels()) {
327 labels1.append_child() << c.GetName();
328 indices1.append_child() << int(channelNames.size());
329 labels2.append_child() << c.GetName();
330 indices2.append_child() << int(channelNames.size());
331 pdfs2.append_child() << (std::string("model_") + c.GetName());
332
333 JSONNode &dataOutput = RooJSONFactoryWSTool::appendNamedChild(n["data"], std::string("obsData_") + c.GetName());
334 dataOutput["type"] << "binned";
335
336 exportHistogram(*c.GetData().GetHisto(), dataOutput, getObsnames(c));
337 channelNames.push_back(c.GetName());
338 }
339
340 auto &modelConfigAux = RooJSONFactoryWSTool::getRooFitInternal(n, "ModelConfigs", "simPdf").set_map();
341 modelConfigAux["combined_data_name"] << "obsData";
342 modelConfigAux["pdfName"] << "simPdf";
343 modelConfigAux["mcName"] << "ModelConfig";
344
345 // Finally write lumi constraint
346 auto &lumiConstraint = RooJSONFactoryWSTool::appendNamedChild(pdflist, "lumiConstraint");
347 lumiConstraint["mean"] << "nominalLumi";
348 lumiConstraint["sigma"] << (measurement.GetLumi() * measurement.GetLumiRelErr());
349 lumiConstraint["type"] << "gaussian_dist";
350 lumiConstraint["x"] << "Lumi";
351}
352
353} // namespace
354
356{
357 std::unique_ptr<RooFit::Detail::JSONTree> tree = RooJSONFactoryWSTool::createNewJSONTree();
358 auto &n = tree->rootnode();
360 exportMeasurement(_measurement, n, domains);
361 domains.writeJSON(n["domains"]);
362 n.writeJSON(os);
363}
365{
366 std::ofstream out(filename);
367 this->PrintJSON(out);
368}
369
371{
372 std::unique_ptr<RooFit::Detail::JSONTree> tree = RooJSONFactoryWSTool::createNewJSONTree();
373 auto &n = tree->rootnode().set_map();
375 exportMeasurement(_measurement, n, domains);
376 domains.writeJSON(n["domains"]);
377 n.writeYML(os);
378}
379
381{
382 std::ofstream out(filename);
383 this->PrintYAML(out);
384}
385
387{
388 auto &node = RooJSONFactoryWSTool::appendNamedChild(sampleNode["modifiers"], "mcstat");
389 node["type"] << "staterror";
390}
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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
virtual JSONNode & set_map()=0
virtual JSONNode & append_child()=0
virtual JSONNode & set_seq()=0
virtual bool has_child(std::string const &) const =0
void readVariable(const char *name, double min, double max)
Definition Domains.cxx:25
void writeJSON(RooFit::Detail::JSONNode &) const
Definition Domains.cxx:42
static RooFit::Detail::JSONNode & appendNamedChild(RooFit::Detail::JSONNode &node, std::string const &name)
static RooFit::Detail::JSONNode & getRooFitInternal(RooFit::Detail::JSONNode &node, Keys_t const &...keys)
static std::unique_ptr< RooFit::Detail::JSONTree > createNewJSONTree()
Create a new JSON tree with version information.
static RooFit::Detail::JSONNode & makeVariablesNode(RooFit::Detail::JSONNode &rootNode)
This class encapsulates all information for the statistical interpretation of one experiment.
Definition Channel.h:30
void PrintYAML(std::ostream &os=std::cout)
RooStats::HistFactory::Measurement & _measurement
void PrintJSON(std::ostream &os=std::cout)
static void activateStatError(RooFit::Detail::JSONNode &sampleNode)
The RooStats::HistFactory::Measurement class can be used to construct a model by combining multiple R...
Definition Measurement.h:31
double GetLumiRelErr()
retrieve relative uncertainty on luminosity
Definition Measurement.h:91
std::vector< RooStats::HistFactory::PreprocessFunction > & GetFunctionObjects()
get vector of defined function objects
Definition Measurement.h:75
double GetLumi()
retrieve integrated luminosity
Definition Measurement.h:89
std::vector< RooStats::HistFactory::OverallSys > & GetOverallSysList()
Definition Sample.h:108
std::string GetName() const
get name of sample
Definition Sample.h:82
const TH1 * GetHisto() const
Definition Sample.cxx:88
RooStats::HistFactory::StatError & GetStatError()
Definition Sample.h:124
std::vector< RooStats::HistFactory::NormFactor > & GetNormFactorList()
Definition Sample.h:109
std::vector< RooStats::HistFactory::HistoSys > & GetHistoSysList()
Definition Sample.h:110
bool GetNormalizeByTheory() const
does the normalization scale with luminosity
Definition Sample.h:78
const TH1 * GetErrorHist() const
Class to manage histogram axis.
Definition TAxis.h:30
Bool_t IsVariableBinSize() const
Definition TAxis.h:137
Double_t GetXmax() const
Definition TAxis.h:135
Double_t GetXmin() const
Definition TAxis.h:134
Int_t GetNbins() const
Definition TAxis.h:121
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition TAxis.cxx:528
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:58
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:8929
virtual Int_t GetNbinsZ() const
Definition TH1.h:297
virtual Int_t GetNbinsX() const
Definition TH1.h:295
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:5025
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
std::string Name(Type type)
void variables(TString dataset, TString fin="TMVA.root", TString dirName="InputVariables_Id", TString title="TMVA Input Variables", Bool_t isRegression=kFALSE, Bool_t useTMVAStyle=kTRUE)
Definition tree.py:1