30constexpr Version explicitInterpolationVersion{0, 3, 0};
32constexpr Version explicitConstraintVersion{0, 2, 0};
35constexpr Version namedConstraintVersion{0, 3, 0};
37using IsDistribution = std::function<
bool(std::string
const &)>;
44bool isConstraintType(std::string
const &
value)
50std::string canonicalConstraintType(std::string
const &
value)
52 return value ==
"Lognormal" ?
"LogNormal" :
value;
56bool eraseLegacyConstraints(
JSONNode &mod)
61 mod.
erase(
"constraint");
62 mod.
erase(
"constraint_name");
63 mod.
erase(
"constraint_type");
69void upgradeConstraint(
JSONNode &mod, IsDistribution
const &isDistribution)
71 if (eraseLegacyConstraints(mod)) {
75 mod.
erase(
"constraint");
76 mod.
erase(
"constraint_type");
80 mod.
erase(
"constraint_type");
81 JSONNode &constraint = mod[
"constraint"];
82 if (!isScalar(constraint)) {
85 const std::string
value = constraint.
val();
87 if (isDistribution(
value)) {
88 mod[
"constraint_name"] <<
value;
89 mod.
erase(
"constraint");
91 constraint << canonicalConstraintType(
value);
96 JSONNode &constraintType = mod[
"constraint_type"];
97 if (isScalar(constraintType)) {
98 mod[
"constraint"] << canonicalConstraintType(constraintType.
val());
100 mod.
erase(
"constraint_type");
106void upgradeGammaConstraint(
JSONNode &mod)
108 if (eraseLegacyConstraints(mod)) {
112 JSONNode &constraintType = mod[
"constraint_type"];
113 if (isScalar(constraintType)) {
114 mod[
"constraint"] << canonicalConstraintType(constraintType.
val());
116 mod.
erase(
"constraint_type");
117 }
else if (mod.
has_child(
"constraint") && isScalar(mod[
"constraint"])) {
118 mod[
"constraint"] << canonicalConstraintType(mod[
"constraint"].val());
123void upgradeInterpolationCode(
JSONNode &mod, InterpolationClass interpolationClass,
Cursor const &
c)
125 if (!mod.
has_child(
"interpolation") || mod[
"interpolation"].is_map()) {
128 JSONNode &node = mod[
"interpolation"];
144void upgradeMissingInterpolation(
JSONNode &mod, InterpolationClass interpolationClass, Version
const &version,
145 bool hasDefault, std::string
const &context, ChannelState &state,
Cursor const &
c)
147 if (mod.
has_child(
"interpolation") || hasDefault || !(version < explicitInterpolationVersion)) {
150 if (!state.warnedInterpolation) {
151 c.warning(context +
" is not given, and the channel has no \"default_interpolation\". Using the implicit default "
152 "of older RooFit versions (code 4), which is deprecated.");
153 state.warnedInterpolation =
true;
155 mod[
"interpolation"] << 4;
156 upgradeInterpolationCode(mod, interpolationClass,
c);
160bool isExplicitlyUnconstrained(
JSONNode const &constraints)
165void upgradeModifier(
JSONNode &mod, std::size_t
index, std::string
const &sampleName, Version
const &version,
166 bool hasDefaultInterpolation, IsDistribution
const &isDistribution, ChannelState &state,
169 if (!mod.
has_child(
"type") || !isScalar(mod[
"type"])) {
172 const std::string
type = mod[
"type"].
val();
173 const bool hasSingleParameter =
type ==
"normfactor" ||
type ==
"normsys" ||
type ==
"histosys";
176 std::string parameter;
177 if (hasSingleParameter && mod.
has_child(
"parameters")) {
178 mod.
erase(
"parameter");
179 JSONNode const ¶meters = mod[
"parameters"];
181 parameter = parameters.
child(0).
val();
183 }
else if (mod.
has_child(
"parameter") && isScalar(mod[
"parameter"])) {
184 parameter = mod[
"parameter"].
val();
190 mod[
"name"] << (!parameter.empty() ? parameter
191 : state.channelName +
"_" + sampleName +
"_syst_" + std::to_string(
index));
193 const std::string
name = isScalar(mod[
"name"]) ? mod[
"name"].
val() :
"";
195 if (hasSingleParameter && !mod.
has_child(
"parameter") && !mod.
has_child(
"parameters")) {
196 parameter =
type ==
"normfactor" ?
name :
"alpha_" +
name;
197 mod[
"parameter"] << parameter;
200 if (
type ==
"normfactor") {
201 upgradeConstraint(mod, isDistribution);
202 }
else if (
type ==
"normsys" ||
type ==
"histosys") {
203 upgradeConstraint(mod, isDistribution);
204 const bool constrained = mod.
has_child(
"constraint") || mod.
has_child(
"constraint_name") ||
205 (mod.
has_child(
"constraints") && !isExplicitlyUnconstrained(mod[
"constraints"]));
207 if (version < explicitConstraintVersion) {
208 mod.
erase(
"constraints");
209 mod[
"constraint"] <<
"Gauss";
210 }
else if (!state.warnedUnconstrained) {
211 c.warning(
"modifier '" +
name +
"' of sample '" + sampleName +
"' has no constraint, so its parameter '" +
213 "' is unconstrained. Older RooFit versions implied a unit Gaussian. Other modifiers of this "
214 "channel are not reported.");
215 state.warnedUnconstrained =
true;
219 const std::string context =
"interpolation for " +
type +
" modifier '" +
name +
"' in sample '" + sampleName +
220 "' of channel '" + state.channelName +
"'";
221 upgradeInterpolationCode(mod, interpolationClass,
c);
222 upgradeMissingInterpolation(mod, interpolationClass, version, hasDefaultInterpolation, context, state,
c);
223 }
else if (
type ==
"shapesys" ||
type ==
"shapefactor") {
224 if (
type ==
"shapesys" && !(version < namedConstraintVersion) && !state.warnedShapeSys) {
225 c.warning(
"the modifier type \"shapesys\" is deprecated, please use \"shapefactor\" instead.");
226 state.warnedShapeSys =
true;
228 upgradeGammaConstraint(mod);
230 if (version < namedConstraintVersion) {
232 mod[
"constraint"] <<
"Gauss";
233 }
else if (mod.
has_child(
"data") && mod[
"data"].is_map() && mod[
"data"].has_child(
"vals")) {
234 if (mod[
"data"][
"vals"].is_seq() && mod[
"data"][
"vals"].num_children() > 0) {
235 c.warning(
"the \"data.vals\" of modifier '" +
name +
"' of sample '" + sampleName +
236 "' are ignored, because it names no constraints, so its parameters are free");
238 mod[
"data"].
erase(
"vals");
241 }
else if (
type ==
"staterror") {
242 if (eraseLegacyConstraints(mod)) {
247 if (!mod.
has_child(
"constraint") && isScalar(mod[
"constraint_type"])) {
248 mod[
"constraint"] << mod[
"constraint_type"].
val();
250 mod.
erase(
"constraint_type");
255void upgradeHistFactory(
JSONNode &dist, Version
const &version, IsDistribution
const &isDistribution,
Cursor const &
c)
258 if (
dist.has_child(
"name") && isScalar(dist[
"name"])) {
259 state.channelName =
dist[
"name"].val();
260 if (state.channelName.rfind(
"model_", 0) == 0) {
261 state.channelName.erase(0, 6);
268 const bool legacyStatError = version < namedConstraintVersion;
269 if (legacyStatError && !
dist.has_child(
"staterror")) {
270 dist[
"staterror"].set_map();
272 if (
dist.has_child(
"staterror") && dist[
"staterror"].is_map()) {
274 upgradeGammaConstraint(config);
276 config[
"constraint"] <<
"Poisson";
278 if (legacyStatError) {
279 config[
"implied_poisson_errors"] <<
true;
283 if (!
dist.has_child(
"samples") || !dist[
"samples"].is_seq()) {
286 const bool hasDefaultInterpolation =
dist.has_child(
"default_interpolation");
289 std::size_t iSample = 0;
291 Cursor sampleCursor{sample, samples, iSample++};
292 if (!sample.is_map() || !sample.has_child(
"modifiers") || !sample[
"modifiers"].is_seq()) {
295 const std::string sampleName = sample.has_child(
"name") && isScalar(sample[
"name"]) ? sample[
"name"].val() :
"";
296 Cursor modifiers{sample[
"modifiers"], sampleCursor,
"modifiers"};
297 std::size_t iModifier = 0;
298 for (
JSONNode &mod : sample[
"modifiers"].children()) {
299 Cursor modCursor{mod, modifiers, iModifier};
301 upgradeModifier(mod, iModifier, sampleName, version, hasDefaultInterpolation, isDistribution, state,
313 if (!
data.has_child(
"axes") || !
data[
"axes"].is_seq()) {
317 if (!axis.is_map()) {
320 if (axis.has_child(
"edges") && axis[
"edges"].is_seq() && axis[
"edges"].num_children() > 0) {
324 if (!axis.has_child(
"min") && first.
is_number()) {
327 if (!axis.has_child(
"max") && last.
is_number()) {
336void upgradeData(
JSONNode &root, Version
const &version)
338 if (!root.
has_child(
"data") || !root[
"data"].is_seq() || !(version < explicitInterpolationVersion)) {
342 if (
data.is_map() &&
data.has_child(
"type") && isScalar(
data[
"type"]) &&
data[
"type"].val() ==
"unbinned") {
343 upgradeUnbinnedAxes(
data);
348Version documentVersion(
JSONNode const &root)
351 if (
JSONNode const *versionNode = root.
find(
"metadata",
"hs3_version")) {
352 if (isScalar(*versionNode)) {
366 const Version version = documentVersion(root);
367 upgradeData(root, version);
373 std::set<std::string> distributionNames;
375 if (dist.is_map() && dist.has_child(
"name") && isScalar(dist[
"name"])) {
376 distributionNames.insert(dist[
"name"].val());
380 const bool constraintCanBeName = version < explicitInterpolationVersion;
381 IsDistribution isDistribution = [&](std::string
const &
name) {
382 return constraintCanBeName && distributionNames.count(
name) > 0;
385 Cursor rootCursor{root, diagnostics};
386 Cursor distributions{root[
"distributions"], rootCursor,
"distributions"};
389 Cursor distCursor{dist, distributions, i++};
390 if (dist.is_map() && dist.has_child(
"type") && isScalar(dist[
"type"]) &&
391 dist[
"type"].val() ==
"histfactory_dist") {
392 upgradeHistFactory(dist, version, isDistribution, distCursor);
399 IsDistribution isDistribution = [](std::string
const &
name) {
400 return !isConstraintType(
name) &&
name !=
"Lognormal" &&
name !=
"Const";
402 upgradeHistFactory(distribution, version, isDistribution,
Cursor{distribution, diagnostics});
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 index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
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 Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
double val_double() const
void erase(std::string const &key)
Remove a child of a map, if it exists.
bool is_container() const
size_t num_children() const
JSONNode const * find(std::string const &key) const
bool has_child(std::string const &) const
JSONNode & child(size_t pos)
A position in the JSON tree.
double dist(Rotation3D const &r1, Rotation3D const &r2)
Types that represent an HS3 document.
void upgradeHistFactoryDist(Detail::JSONNode &distribution, Version const &version, Diagnostics &diagnostics)
Same as upgradeDocument(), but for a single HistFactory distribution that doesn't come with a documen...
std::optional< Interpolation > readInterpolationCode(Cursor const &c, InterpolationClass interpolationClass)
Reads an integer interpolation code, as older versions of RooFit wrote them.
std::vector< Diagnostic > Diagnostics
void writeInterpolation(Detail::JSONNode &node, Interpolation const &interpolation)
void upgradeDocument(Detail::JSONNode &root, Diagnostics &diagnostics, ParseOptions const &options={})
Rewrites everything that older versions of RooFit wrote in a way that is not part of the standard int...
bool parseVersion(std::string const &version, Version &out)
Reads the leading "MAJOR.MINOR" and the optional ".PATCH" of an HS3 version string.
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Options for upgradeDocument() and parseDocument().
bool typedHistFactory
If false, HistFactory distributions stay generic objects, because a user registered their own importe...