27#include <TGraphErrors.h>
34namespace owned = ::mist::hep::owned;
43[[nodiscard]]
inline std::pair<double, double>
44eval(
const TGraphErrors& g,
double x)
46 const int n = g.GetN();
47 const double nan = std::nan(
"");
48 if (n == 0)
return {
nan,
nan};
49 if (x < g.GetPointX(0) || x > g.GetPointX(n - 1))
return {
nan,
nan};
51 for (
int i = 1; i < n; ++i) {
52 const double x0 = g.GetPointX(i - 1);
53 const double x1 = g.GetPointX(i);
54 if (x >= x0 && x <= x1) {
55 if (x1 == x0)
return {g.GetPointY(i), g.GetErrorY(i)};
56 const double w1 = (x - x0) / (x1 - x0);
57 const double w0 = (x1 - x) / (x1 - x0);
58 const double y = w1 * g.GetPointY(i) + w0 * g.GetPointY(i - 1);
59 const double e1 = w1 * g.GetErrorY(i);
60 const double e0 = w0 * g.GetErrorY(i - 1);
61 return {y, std::sqrt(e0 * e0 + e1 * e1)};
71[[nodiscard]]
inline std::array<double, 2>
74 const auto [y, ey] =
eval(g, x_target);
83add(
const TGraphErrors& g,
double addend,
double addend_error = 0.0)
86 for (
int i = 0; i < g.GetN(); ++i) {
87 const double ey = g.GetErrorY(i);
88 out->SetPoint(i, g.GetPointX(i), g.GetPointY(i) + addend);
89 out->SetPointError(i, g.GetErrorX(i),
90 std::sqrt(ey * ey + addend_error * addend_error));
100offset(
const TGraphErrors& g, std::array<double, 2> add_value)
102 return add(g, add_value[0], add_value[1]);
111power(
const TGraphErrors& g,
double exponent)
114 for (
int i = 0; i < g.GetN(); ++i) {
115 const double y = g.GetPointY(i);
116 if (exponent < 0.0 && y == 0.0)
continue;
117 const double yp = std::pow(y, exponent);
118 const double ey = (y == 0.0) ? 0.0
119 : std::fabs(exponent) * std::fabs(yp / y) * g.GetErrorY(i);
120 const int n = out->GetN();
121 out->SetPoint(n, g.GetPointX(i), yp);
122 out->SetPointError(n, g.GetErrorX(i), ey);
137scale_values(
const TGraphErrors& g,
double factor,
double factor_error = 0.0)
140 for (
int i = 0; i < g.GetN(); ++i) {
141 const double y = g.GetPointY(i);
142 const double ey = g.GetErrorY(i);
143 const double y_new = factor * y;
145 if (factor_error == 0.0 || y == 0.0 || factor == 0.0) {
146 ey_new = std::fabs(factor) * ey;
148 const double rel_y = ey / y;
149 const double rel_f = factor_error / factor;
150 ey_new = std::fabs(y_new) * std::sqrt(rel_y * rel_y + rel_f * rel_f);
152 out->SetPoint(i, g.GetPointX(i), y_new);
153 out->SetPointError(i, g.GetErrorX(i), ey_new);
168 for (
int i = 0; i < g.GetN(); ++i) {
169 const double y = g.GetPointY(i);
170 if (y <= 0.0)
continue;
171 const int n = out->GetN();
172 out->SetPoint(n, g.GetPointX(i), std::log(y));
173 out->SetPointError(n, g.GetErrorX(i), g.GetErrorY(i) / y);
181 static const double ln10 = std::log(10.0);
183 for (
int i = 0; i < g.GetN(); ++i) {
184 const double y = g.GetPointY(i);
185 if (y <= 0.0)
continue;
186 const int n = out->GetN();
187 out->SetPoint(n, g.GetPointX(i), std::log10(y));
188 out->SetPointError(n, g.GetErrorX(i), g.GetErrorY(i) / (y * ln10));
202ratio(
const TGraphErrors& numerator,
const TGraphErrors& denominator,
203 bool propagate_error =
true)
206 for (
int i = 0; i < numerator.GetN(); ++i) {
207 const double x = numerator.GetPointX(i);
208 const double yn = numerator.GetPointY(i);
209 const auto [yd, eyd] =
eval(denominator, x);
210 if (std::isnan(yd) || yd == 0.0 || yn == 0.0)
continue;
211 const double eyn = numerator.GetErrorY(i);
212 const double r = yn / yd;
214 if (propagate_error) {
215 const double rel_n = eyn / yn;
216 const double rel_d = eyd / yd;
217 er = std::fabs(r) * std::sqrt(rel_n * rel_n + rel_d * rel_d);
221 const int n = out->GetN();
222 out->SetPoint(n, x, r);
223 out->SetPointError(n, numerator.GetErrorX(i), er);
233product(
const TGraphErrors& a,
const TGraphErrors& b,
234 bool propagate_error =
true)
237 for (
int i = 0; i < a.GetN(); ++i) {
238 const double x = a.GetPointX(i);
239 const double ya = a.GetPointY(i);
240 const auto [yb, eyb] =
eval(b, x);
241 if (std::isnan(yb) || ya == 0.0 || yb == 0.0)
continue;
242 const double eya = a.GetErrorY(i);
243 const double p = ya * yb;
245 if (propagate_error) {
246 const double rel_a = eya / ya;
247 const double rel_b = eyb / yb;
248 ep = std::fabs(p) * std::sqrt(rel_a * rel_a + rel_b * rel_b);
252 const int n = out->GetN();
253 out->SetPoint(n, x, p);
254 out->SetPointError(n, a.GetErrorX(i), ep);
265 bool propagate_error =
true)
268 for (
int i = 0; i < a.GetN(); ++i) {
269 const double x = a.GetPointX(i);
270 const auto [yb, eyb] =
eval(b, x);
271 if (std::isnan(yb))
continue;
272 const double eya = a.GetErrorY(i);
273 const double ed = propagate_error ? std::sqrt(eya * eya + eyb * eyb) : eya;
274 const int n = out->GetN();
275 out->SetPoint(n, x, a.GetPointY(i) - yb);
276 out->SetPointError(n, a.GetErrorX(i), ed);
290 auto& fn =
const_cast<TF1&
>(f);
291 for (
int i = 0; i < g.GetN(); ++i) {
292 const double x = g.GetPointX(i);
293 out->SetPoint(i, x, g.GetPointY(i) - fn.Eval(x));
294 out->SetPointError(i, g.GetErrorX(i), g.GetErrorY(i));
304trim(
const TGraphErrors& g,
double min_x,
double max_x)
307 for (
int i = 0; i < g.GetN(); ++i) {
308 const double x = g.GetPointX(i);
309 if (x < min_x || x > max_x)
continue;
310 const int n = out->GetN();
311 out->SetPoint(n, x, g.GetPointY(i));
312 out->SetPointError(n, g.GetErrorX(i), g.GetErrorY(i));
324mean_of(
const std::vector<TGraphErrors*>& graphs)
327 if (graphs.empty() || !graphs.front())
return out;
329 int n_points = graphs.front()->GetN();
330 for (
auto* g : graphs) {
332 n_points = std::min(n_points, g->GetN());
334 const double count =
static_cast<double>(graphs.size());
336 for (
int i = 0; i < n_points; ++i) {
338 for (
auto* g : graphs) sum += g->GetPointY(i);
339 const double mean = sum / count;
342 for (
auto* g : graphs) {
343 const double d = g->GetPointY(i) - mean;
347 const double sem = std::sqrt(var / count);
349 out->SetPoint(i, graphs.front()->GetPointX(i), mean);
350 out->SetPointError(i, 0.0, sem);
366average_rms(
const TGraphErrors& g,
int n_bins,
double x_min,
double x_max)
369 if (n_bins <= 0 || !(x_max > x_min))
return out;
371 TProfile profile(
"",
"", n_bins, x_min, x_max,
"S");
372 profile.SetDirectory(
nullptr);
373 for (
int i = 0; i < g.GetN(); ++i)
374 profile.Fill(g.GetPointX(i), g.GetPointY(i));
376 for (
int b = 1; b <= profile.GetNbinsX(); ++b)
378 if (profile.GetBinEntries(b) <= 0.0)
continue;
379 const int n = out->GetN();
380 out->SetPoint(n, profile.GetBinCenter(b), profile.GetBinContent(b));
381 out->SetPointError(n, 0.0, profile.GetBinError(b));
399 for (
int i = 0; i + 1 < g.GetN(); ++i) {
400 const double x0 = g.GetPointX(i);
401 const double x1 = g.GetPointX(i + 1);
402 if (x1 == x0)
continue;
403 const double slope = factor * (g.GetPointY(i + 1) - g.GetPointY(i)) / (x1 - x0);
404 out->SetPoint(out->GetN(), 0.5 * (x0 + x1), slope);
owned::root_ptr< TGraphErrors > add(const TGraphErrors &g, double addend, double addend_error=0.0)
Definition algebra.h:83
owned::root_ptr< TGraphErrors > log10(const TGraphErrors &g)
Definition algebra.h:179
owned::root_ptr< TGraphErrors > power(const TGraphErrors &g, double exponent)
Definition algebra.h:111
std::pair< double, double > eval(const TGraphErrors &g, double x)
Definition algebra.h:44
owned::root_ptr< TGraphErrors > offset(const TGraphErrors &g, std::array< double, 2 > add_value)
Definition algebra.h:100
@ nan
Emit the point with a NaN y-value.
owned::root_ptr< TGraphErrors > difference(const TGraphErrors &a, const TGraphErrors &b, bool propagate_error=true)
Definition algebra.h:264
owned::root_ptr< TGraph > derivative(const TGraph &g, double factor=1.0)
Definition algebra.h:396
owned::root_ptr< TGraphErrors > log(const TGraphErrors &g)
Definition algebra.h:165
owned::root_ptr< TGraphErrors > product(const TGraphErrors &a, const TGraphErrors &b, bool propagate_error=true)
Definition algebra.h:233
owned::root_ptr< TGraphErrors > mean_of(const std::vector< TGraphErrors * > &graphs)
Definition algebra.h:324
owned::root_ptr< TGraphErrors > scale_values(const TGraphErrors &g, double factor, double factor_error=0.0)
Definition algebra.h:137
owned::root_ptr< TGraphErrors > ratio(const TGraphErrors &numerator, const TGraphErrors &denominator, bool propagate_error=true)
Definition algebra.h:202
owned::root_ptr< TGraphErrors > average_rms(const TGraphErrors &g, int n_bins, double x_min, double x_max)
Definition algebra.h:366
std::array< double, 2 > eval_with_errors(const TGraphErrors &g, double x_target)
Definition algebra.h:72
owned::root_ptr< TGraphErrors > trim(const TGraphErrors &g, double min_x, double max_x)
Definition algebra.h:304
std::unique_ptr< T, root_deleter > root_ptr
Definition owned.h:60
root_ptr< T > make(Args &&... args)
Definition owned.h:67