24 std::vector<Domain const *> sorted;
25 sorted.reserve(domains.size());
26 for (
Domain const &domain : domains) {
27 sorted.push_back(&domain);
29 std::stable_sort(sorted.begin(), sorted.end(), [](
Domain const *
l,
Domain const *
r) { return l->name < r->name; });
30 const bool hasDefault =
31 std::any_of(domains.begin(), domains.end(), [](
Domain const &
d) { return d.name == defaultDomainName; });
33 for (
Domain const *domain : sorted) {
35 std::map<std::string, DomainAxis const *> axes;
36 for (
auto const &axis : domain->axes) {
37 if (
auto const *continuous = std::get_if<DomainAxis>(&axis)) {
38 axes[continuous->name] = continuous;
39 _names.insert(continuous->name);
43 _ranges.insert(axes.begin(), axes.end());
51 return found !=
_ranges.end() ? found->second :
nullptr;
58 return std::visit([](
auto const &
m) -> std::string
const & {
return m.name; },
modifier);
64 overloaded{[](NormFactor
const &) {
return "normfactor"; }, [](NormSys
const &) {
return "normsys"; },
65 [](HistoSys
const &) {
return "histosys"; }, [](ShapeSys
const &) {
return "shapefactor"; },
66 [](StatError
const &) {
return "staterror"; }, [](CustomModifier
const &) {
return "custom"; }},
71template <
class Modifier_t>
72char const *differences(Modifier_t
const &
l, Modifier_t
const &
r)
74 if (!(
l.constraint ==
r.constraint)) {
75 return "constraint metadata differs";
77 if (
l.parameter.name !=
r.parameter.name) {
78 return "parameter metadata differs";
80 if (
l.interpolation !=
r.interpolation) {
81 return "interpolation behaviours differ";
87char const *combine(NormSys &merged, NormSys
const &
modifier, std::vector<double>
const &)
89 if (
char const *reason = differences(merged,
modifier)) {
97 if (merged.interpolation != multiplicativePiecewiseExponential &&
98 merged.interpolation != multiplicativePolynomialExponential) {
99 return "multiplicative combination is only valid for log-space interpolation";
106char const *combine(HistoSys &merged, HistoSys
const &
modifier, std::vector<double>
const &nominal)
108 if (
char const *reason = differences(merged,
modifier)) {
111 if (merged.interpolation != additivePolynomialLinear) {
112 return "this interpolation cannot currently be combined for duplicate histosys modifiers";
114 const std::size_t nBins = nominal.size();
115 auto fits = [&](HistoSysVariation
const &variation) {
return variation.contents.size() == nBins; };
116 if (!fits(merged.lo) || !fits(merged.hi) || !fits(
modifier.lo) || !fits(
modifier.hi)) {
117 return "histogram binning differs";
119 for (std::size_t bin = 0; bin < nBins; ++bin) {
120 merged.lo.contents[bin] +=
modifier.lo.contents[bin] - nominal[bin];
121 merged.hi.contents[bin] +=
modifier.hi.contents[bin] - nominal[bin];
130 for (
Sample &sample : dist.samples) {
133 "cannot combine duplicate modifier '" + nameOf(
modifier) +
"' of type '" +
134 typeOf(
modifier) +
"' in sample '" + sample.name +
"' of channel '" + channel +
139 std::vector<Modifier> merged;
140 std::size_t count = 0;
142 auto warnIfCombined = [&]() {
143 if (count > 1 && !failed) {
145 "combined " + std::to_string(count) +
" duplicate modifiers named '" +
146 nameOf(merged.back()) +
"' of type '" + typeOf(merged.back()) +
"' in sample '" +
147 sample.name +
"' of channel '" + channel +
"'"});
151 Modifier *last = merged.empty() ? nullptr : &merged.back();
152 const bool combinable =
153 std::holds_alternative<NormSys>(
modifier) || std::holds_alternative<HistoSys>(
modifier);
154 if (combinable && last && last->index() ==
modifier.index() && nameOf(*last) == nameOf(
modifier)) {
155 char const *reason =
nullptr;
156 if (
auto *normSys = std::get_if<NormSys>(last)) {
157 reason = combine(*normSys, std::get<NormSys>(
modifier), sample.contents);
159 reason = combine(std::get<HistoSys>(*last), std::get<HistoSys>(
modifier), sample.contents);
169 merged.push_back(std::move(
modifier));
174 sample.modifiers = std::move(merged);
176 std::set<std::pair<std::string, std::string>> seen;
179 error(
modifier,
"this modifier type cannot be combined without changing its meaning");
187 auto forEachInterpolation = [&](
auto &&fn) {
188 for (
Sample &sample : dist.samples) {
190 if (
auto *normSys = std::get_if<NormSys>(&
modifier)) {
191 fn(normSys->interpolation);
192 }
else if (
auto *histoSys = std::get_if<HistoSys>(&
modifier)) {
193 fn(histoSys->interpolation);
199 std::map<Interpolation, std::size_t> counts;
200 forEachInterpolation([&](std::optional<Interpolation> &interpolation) {
202 ++counts[*interpolation];
205 if (counts.empty()) {
209 auto best = counts.begin();
210 for (
auto current = std::next(counts.begin()); current != counts.end(); ++current) {
211 if (current->second > best->second ||
212 (current->second == best->second && current->first == multiplicativePolynomialExponential &&
213 best->first != multiplicativePolynomialExponential)) {
217 dist.defaultInterpolation = best->first;
218 forEachInterpolation([&](std::optional<Interpolation> &interpolation) {
219 if (interpolation == dist.defaultInterpolation) {
220 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...