24 std::vector<Domain const *> sorted;
25 for (
Domain const &domain : domains) {
26 sorted.push_back(&domain);
28 std::stable_sort(sorted.begin(), sorted.end(), [](
Domain const *
l,
Domain const *
r) { return l->name < r->name; });
29 const bool hasDefault =
30 std::any_of(domains.begin(), domains.end(), [](
Domain const &
d) { return d.name == defaultDomainName; });
32 for (
Domain const *domain : sorted) {
34 std::map<std::string, DomainAxis const *> axes;
35 for (
auto const &axis : domain->axes) {
36 if (
auto const *continuous = std::get_if<DomainAxis>(&axis)) {
37 axes[continuous->name] = continuous;
38 _names.insert(continuous->name);
42 _ranges.insert(axes.begin(), axes.end());
50 return found !=
_ranges.end() ? found->second :
nullptr;
57 return std::visit([](
auto const &
m) -> std::string
const & {
return m.name; },
modifier);
63 overloaded{[](NormFactor
const &) {
return "normfactor"; }, [](NormSys
const &) {
return "normsys"; },
64 [](HistoSys
const &) {
return "histosys"; }, [](ShapeSys
const &) {
return "shapefactor"; },
65 [](StatError
const &) {
return "staterror"; }, [](CustomModifier
const &) {
return "custom"; }},
70template <
class Modifier_t>
71char const *differences(Modifier_t
const &
l, Modifier_t
const &
r)
73 if (!(
l.constraint ==
r.constraint)) {
74 return "constraint metadata differs";
76 if (
l.parameter.name !=
r.parameter.name) {
77 return "parameter metadata differs";
79 if (
l.interpolation !=
r.interpolation) {
80 return "interpolation behaviours differ";
86char const *combine(NormSys &merged, NormSys
const &
modifier, std::vector<double>
const &)
88 if (
char const *reason = differences(merged,
modifier)) {
96 if (merged.interpolation != multiplicativePiecewiseExponential &&
97 merged.interpolation != multiplicativePolynomialExponential) {
98 return "multiplicative combination is only valid for log-space interpolation";
105char const *combine(HistoSys &merged, HistoSys
const &
modifier, std::vector<double>
const &nominal)
107 if (
char const *reason = differences(merged,
modifier)) {
110 if (merged.interpolation != additivePolynomialLinear) {
111 return "this interpolation cannot currently be combined for duplicate histosys modifiers";
113 const std::size_t nBins = nominal.size();
114 auto fits = [&](HistoSysVariation
const &variation) {
return variation.contents.size() == nBins; };
115 if (!fits(merged.lo) || !fits(merged.hi) || !fits(
modifier.lo) || !fits(
modifier.hi)) {
116 return "histogram binning differs";
118 for (std::size_t bin = 0; bin < nBins; ++bin) {
119 merged.lo.contents[bin] +=
modifier.lo.contents[bin] - nominal[bin];
120 merged.hi.contents[bin] +=
modifier.hi.contents[bin] - nominal[bin];
129 for (
Sample &sample : dist.samples) {
132 "cannot combine duplicate modifier '" + nameOf(
modifier) +
"' of type '" +
133 typeOf(
modifier) +
"' in sample '" + sample.name +
"' of channel '" + channel +
138 std::vector<Modifier> merged;
139 std::size_t count = 0;
141 auto warnIfCombined = [&]() {
142 if (count > 1 && !failed) {
144 "combined " + std::to_string(count) +
" duplicate modifiers named '" +
145 nameOf(merged.back()) +
"' of type '" + typeOf(merged.back()) +
"' in sample '" +
146 sample.name +
"' of channel '" + channel +
"'"});
150 Modifier *last = merged.empty() ? nullptr : &merged.back();
151 const bool combinable =
152 std::holds_alternative<NormSys>(
modifier) || std::holds_alternative<HistoSys>(
modifier);
153 if (combinable && last && last->index() ==
modifier.index() && nameOf(*last) == nameOf(
modifier)) {
154 char const *reason =
nullptr;
155 if (
auto *normSys = std::get_if<NormSys>(last)) {
156 reason = combine(*normSys, std::get<NormSys>(
modifier), sample.contents);
158 reason = combine(std::get<HistoSys>(*last), std::get<HistoSys>(
modifier), sample.contents);
168 merged.push_back(std::move(
modifier));
173 sample.modifiers = std::move(merged);
175 std::set<std::pair<std::string, std::string>> seen;
178 error(
modifier,
"this modifier type cannot be combined without changing its meaning");
186 auto forEachInterpolation = [&](
auto &&fn) {
187 for (
Sample &sample : dist.samples) {
189 if (
auto *normSys = std::get_if<NormSys>(&
modifier)) {
190 fn(normSys->interpolation);
191 }
else if (
auto *histoSys = std::get_if<HistoSys>(&
modifier)) {
192 fn(histoSys->interpolation);
198 std::map<Interpolation, std::size_t> counts;
199 forEachInterpolation([&](std::optional<Interpolation> &interpolation) {
201 ++counts[*interpolation];
204 if (counts.empty()) {
208 auto best = counts.begin();
209 for (
auto current = std::next(counts.begin()); current != counts.end(); ++current) {
210 if (current->second > best->second ||
211 (current->second == best->second && current->first == multiplicativePolynomialExponential &&
212 best->first != multiplicativePolynomialExponential)) {
216 dist.defaultInterpolation = best->first;
217 forEachInterpolation([&](std::optional<Interpolation> &interpolation) {
218 if (interpolation == dist.defaultInterpolation) {
219 interpolation.reset();
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 r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t modifier
DomainAxis const * find(std::string const &name) const
The axis that defines the range of a variable, or null.
DomainRanges(std::vector< Domain > const &domains)
std::map< std::string, DomainAxis const * > _ranges
std::set< std::string > _names
Types that represent an HS3 document.
std::variant< NormFactor, NormSys, HistoSys, ShapeSys, StatError, CustomModifier > Modifier
constexpr char const * defaultDomainName
The domain in which RooFit writes the ranges of all variables. It is a convention of RooFit,...
void mergeDuplicateModifiers(HistFactoryDist &dist, std::string const &channel, Diagnostics &diagnostics)
Combines the modifiers of a sample that have the same type and name, which HistFactory models can hav...
void factorOutDefaultInterpolation(HistFactoryDist &dist)
Makes the most common interpolation of the modifiers the "default_interpolation", which they then don...
std::vector< Diagnostic > Diagnostics
overloaded(Ts...) -> overloaded< Ts... >
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...