4#include "PlottingUtils.hpp"
10#include <TParameter.h>
21static TString Key(
const char *name, Int_t reac) {
22 return Form(
"%s_reac%d", name, reac);
29 (tag.Length() > 0 ?
"_" + tag : TString(
""));
32TString
Path(
const char *name, Int_t reac) {
33 return Dir() +
"/" + Key(name, reac) +
".root";
36static void WriteOne(
const char *name, Int_t reac, TCutG *cut,
37 Double_t n_assigned) {
40 TString path =
Path(name, reac);
41 TFile f(path,
"RECREATE");
43 std::cerr <<
" [region] cannot open " << path <<
" to save cut"
49 if (n_assigned >= 0.0)
50 TParameter<Double_t>(
"n_assigned", n_assigned).Write();
52 std::cout <<
" [region] saved " << name <<
" reac " << reac <<
" -> " << path
56void Save(Int_t reac, TCutG *cut_an, TCutG *cut_aa, Double_t n_an_assigned) {
57 gSystem->mkdir(
Dir(), kTRUE);
58 WriteOne(
"region_an", reac, cut_an, n_an_assigned);
59 WriteOne(
"region_aa", reac, cut_aa, -1.0);
62static const char *kFitKeys[14] = {
63 "fit_beam_amp",
"fit_beam_mx",
"fit_beam_sx",
"fit_beam_my",
"fit_beam_sy",
64 "fit_beam_rho",
"fit_reac_amp",
"fit_reac_mx",
"fit_reac_sx",
"fit_reac_my",
65 "fit_reac_sy",
"fit_reac_rho",
"fit_n_beam",
"fit_n_reac"};
67static void FitValues(
const RegionFit &fit, Double_t *v) {
68 const Gauss2D *g[2] = {&fit.
beam, &fit.
reac};
69 for (Int_t k = 0; k < 2; k++) {
70 v[6 * k + 0] = g[k]->
amp;
71 v[6 * k + 1] = g[k]->
mx;
72 v[6 * k + 2] = g[k]->
sx;
73 v[6 * k + 3] = g[k]->
my;
74 v[6 * k + 4] = g[k]->
sy;
75 v[6 * k + 5] = g[k]->
rho;
82 TString path =
Path(
"region_an", reac);
83 TFile f(path,
"UPDATE");
85 std::cerr <<
" [region] cannot open " << path <<
" to save the fit"
92 for (Int_t k = 0; k < 14; k++)
93 TParameter<Double_t>(kFitKeys[k], v[k])
94 .Write(kFitKeys[k], TObject::kOverwrite);
99 TString path =
Path(name, reac);
100 if (gSystem->AccessPathName(path))
102 TFile f(path,
"READ");
105 TParameter<Double_t> *p =
106 dynamic_cast<TParameter<Double_t> *
>(f.Get(
"n_assigned"));
107 const Double_t n = p ? p->GetVal() : -1.0;
112static TCutG *ReadFrom(
const TString &path,
const char *key,
const char *name) {
113 if (gSystem->AccessPathName(path))
115 TFile f(path,
"READ");
118 TCutG *stored =
dynamic_cast<TCutG *
>(f.Get(key));
124 TCutG *cut =
static_cast<TCutG *
>(stored->Clone(name));
129TCutG *
Load(
const char *name, Int_t reac) {
130 return ReadFrom(
Path(name, reac), name, name);
141Double_t Bigaus(
const Gauss2D &g, Double_t x, Double_t y) {
142 const Double_t dx = (x - g.
mx) / g.
sx, dy = (y - g.
my) / g.
sy;
143 const Double_t r2 = 1.0 - g.
rho * g.
rho;
145 std::exp(-0.5 / r2 * (dx * dx + dy * dy - 2.0 * g.
rho * dx * dy));
149Double_t Mahal2(
const Gauss2D &g, Double_t x, Double_t y) {
150 const Double_t dx = (x - g.
mx) / g.
sx, dy = (y - g.
my) / g.
sy;
151 return (dx * dx + dy * dy - 2.0 * g.
rho * dx * dy) / (1.0 - g.
rho * g.
rho);
156Double_t LogNorm(
const Gauss2D &g) {
157 return std::log(2.0 * TMath::Pi() * g.
sx * g.
sy *
158 std::sqrt(1.0 - g.
rho * g.
rho));
165Gauss2D MomentsToGauss(Double_t sw, Double_t sx, Double_t sy, Double_t sxx,
166 Double_t syy, Double_t sxy, Double_t bwx, Double_t bwy) {
170 const Double_t vx = sxx / sw - g.
mx * g.
mx, vy = syy / sw - g.
my * g.
my;
171 const Double_t cv = sxy / sw - g.
mx * g.
my;
172 g.
sx = std::sqrt(TMath::Max(vx, bwx * bwx));
173 g.
sy = std::sqrt(TMath::Max(vy, bwy * bwy));
174 g.
rho = TMath::Max(-0.95, TMath::Min(0.95, cv / (g.
sx * g.
sy)));
175 g.
amp = sw * bwx * bwy /
176 (2.0 * TMath::Pi() * g.
sx * g.
sy * std::sqrt(1.0 - g.
rho * g.
rho));
181Double_t WidthAtMax(TH1D *h, Double_t &at) {
182 Int_t b = h->GetMaximumBin();
183 Double_t c = h->GetBinContent(b);
184 at = h->GetBinCenter(b);
185 Int_t lo = b, hi = b;
186 while (lo > 1 && h->GetBinContent(lo) > 0.5 * c)
188 while (hi < h->GetNbinsX() && h->GetBinContent(hi) > 0.5 * c)
190 return TMath::Max(h->GetBinWidth(1),
191 (h->GetBinCenter(hi) - h->GetBinCenter(lo)) / 2.355);
200TH2F *ModelHist(TH2F *scatter,
const RegionFit &fit, Int_t reac) {
201 TH2F *m =
static_cast<TH2F *
>(scatter->Clone(Form(
"model_reac%d", reac)));
202 m->SetDirectory(
nullptr);
204 TAxis *ax = m->GetXaxis(), *ay = m->GetYaxis();
205 for (Int_t i = ax->FindBin(fit.
x_lo); i <= ax->FindBin(fit.
x_hi); i++)
206 for (Int_t j = ay->FindBin(fit.
y_lo); j <= ay->FindBin(fit.
y_hi); j++) {
207 Double_t x = ax->GetBinCenter(i), y = ay->GetBinCenter(j);
208 m->SetBinContent(i, j, Bigaus(fit.
beam, x, y) + Bigaus(fit.
reac, x, y));
218Bool_t BeamFromCore(TH2F *scatter, Int_t reac, Int_t bx0, Int_t bx1, Int_t by0,
219 Int_t by1,
Gauss2D &beam, TString &why) {
220 TAxis *ax = scatter->GetXaxis(), *ay = scatter->GetYaxis();
221 const Double_t bwx = ax->GetBinWidth(1), bwy = ay->GetBinWidth(1);
222 TH1D *px = scatter->ProjectionX(Form(
"rcf_px_%d", reac), by0, by1);
223 TH1D *py = scatter->ProjectionY(Form(
"rcf_py_%d", reac), bx0, bx1);
224 px->SetDirectory(
nullptr);
225 py->SetDirectory(
nullptr);
226 px->GetXaxis()->SetRange(bx0, bx1);
227 py->GetXaxis()->SetRange(by0, by1);
228 Double_t mx0 = 0.0, my0 = 0.0;
229 const Double_t sx0 = WidthAtMax(px, mx0), sy0 = WidthAtMax(py, my0);
232 Double_t sw = 0, sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0;
233 for (Int_t i = ax->FindBin(mx0 - 2 * sx0); i <= ax->FindBin(mx0 + 2 * sx0);
235 for (Int_t j = ay->FindBin(my0 - 2 * sy0); j <= ay->FindBin(my0 + 2 * sy0);
237 Double_t w = scatter->GetBinContent(i, j);
238 Double_t x = ax->GetBinCenter(i), y = ay->GetBinCenter(j);
247 why =
"empty beam core";
250 beam = MomentsToGauss(sw, sx, sy, sxx, syy, sxy, bwx, bwy);
259 Double_t y_lo, Double_t y_hi) {
265 TAxis *ax = scatter->GetXaxis(), *ay = scatter->GetYaxis();
266 const Int_t bx0 = ax->FindBin(x_lo), bx1 = ax->FindBin(x_hi);
267 const Int_t by0 = ay->FindBin(y_lo), by1 = ay->FindBin(y_hi);
268 const Double_t bwx = ax->GetBinWidth(1), bwy = ay->GetBinWidth(1);
271 if (!BeamFromCore(scatter, reac, bx0, bx1, by0, by1, beam, fit.
why))
276 TH1D hx(Form(
"rcf_hx_%d", reac),
"", 80, x_lo, x_hi);
277 hx.SetDirectory(
nullptr);
278 for (Int_t i = bx0; i <= bx1; i++)
279 for (Int_t j = by0; j <= by1; j++) {
280 const Double_t w = scatter->GetBinContent(i, j);
283 const Double_t x = ax->GetBinCenter(i), y = ay->GetBinCenter(j);
285 if (u > 3.0 && u < 15.0 && x > beam.
mx + 3.0 * beam.
sx)
288 const Int_t bpk = hx.GetMaximumBin();
289 const Double_t xpk = hx.GetBinCenter(bpk);
290 if (hx.GetBinContent(bpk) < 5.0) {
291 fit.
why =
"nothing above the ridge beyond +3 sigma_x of the beam";
294 Double_t s[6] = {0, 0, 0, 0, 0, 0};
295 for (Int_t i = bx0; i <= bx1; i++)
296 for (Int_t j = by0; j <= by1; j++) {
297 const Double_t w = scatter->GetBinContent(i, j);
300 const Double_t x = ax->GetBinCenter(i), y = ay->GetBinCenter(j);
302 if (u > 3.0 && u < 15.0 && std::fabs(x - xpk) < 2.0 * beam.
sx) {
312 fit.
why = Form(
"only %.0f events in the seed neighbourhood", s[0]);
316 reac_g.
mx = s[1] / s[0];
317 reac_g.
my = s[2] / s[0];
321 Double_t n_beam = 0.0, n_reac = 0.0;
322 Double_t total = 0.0;
323 for (Int_t i = bx0; i <= bx1; i++)
324 for (Int_t j = by0; j <= by1; j++)
325 total += scatter->GetBinContent(i, j);
326 Double_t prior_reac = 1.0e-3;
327 for (Int_t iter = 0; iter < 20; iter++) {
328 Double_t mb[6] = {0, 0, 0, 0, 0, 0}, mr[6] = {0, 0, 0, 0, 0, 0};
329 const Double_t lp_b = std::log(1.0 - prior_reac) - LogNorm(beam);
330 const Double_t lp_r = std::log(prior_reac) - LogNorm(reac_g);
331 for (Int_t i = bx0; i <= bx1; i++)
332 for (Int_t j = by0; j <= by1; j++) {
333 const Double_t w = scatter->GetBinContent(i, j);
336 const Double_t x = ax->GetBinCenter(i), y = ay->GetBinCenter(j);
337 const Double_t d2r = Mahal2(reac_g, x, y);
340 const Bool_t to_reac =
342 (lp_r - 0.5 * d2r) > (lp_b - 0.5 * Mahal2(beam, x, y));
343 Double_t *m = to_reac ? mr : mb;
352 fit.
why = Form(
"reaction component starved (%.0f events) at iteration %d",
357 MomentsToGauss(mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], bwx, bwy);
359 MomentsToGauss(mr[0], mr[1], mr[2], mr[3], mr[4], mr[5], bwx, bwy);
362 nr.
sx = TMath::Min(nr.
sx, 1.1 * nb.
sx);
363 nr.
sy = TMath::Min(nr.
sy, 1.1 * nb.
sy);
366 if (std::fabs(nr.
rho) > std::fabs(nb.
rho))
367 nr.
rho = nr.
rho < 0 ? -std::fabs(nb.
rho) : std::fabs(nb.
rho);
368 const Bool_t moved = std::fabs(nr.
mx - reac_g.
mx) > 0.1 * bwx ||
369 std::fabs(nr.
my - reac_g.
my) > 0.1 * bwy;
374 prior_reac = TMath::Max(1.0e-6, n_reac / total);
382 fit.
why =
"reaction component fell back onto the ridge";
386 fit.
why = Form(
"reaction component holds only %.0f events", n_reac);
396 return ((y - b.
my) - b.
rho * (b.
sy / b.
sx) * (x - b.
mx)) /
397 (b.
sy * std::sqrt(1.0 - b.
rho * b.
rho));
403 TCutG *c =
new TCutG(name, npts + 1);
404 const Double_t q = std::sqrt(1.0 - g.
rho * g.
rho);
405 for (Int_t i = 0; i <= npts; i++) {
406 Double_t t = 2.0 * TMath::Pi() * i / npts;
407 Double_t u = std::cos(t), v = std::sin(t);
408 c->SetPoint(i, g.
mx + nsigma * g.
sx * u,
409 g.
my + nsigma * g.
sy * (g.
rho * u + q * v));
411 c->SetLineColor(kBlack);
419 TAxis *ax = scatter->GetXaxis(), *ay = scatter->GetYaxis();
421 for (Int_t i = ax->FindBin(fit.
x_lo); i <= ax->FindBin(fit.
x_hi); i++)
422 for (Int_t j = ay->FindBin(fit.
y_lo); j <= ay->FindBin(fit.
y_hi); j++)
423 if (cut->IsInside(ax->GetBinCenter(i), ay->GetBinCenter(j)))
424 n += scatter->GetBinContent(i, j);
429 TCutG *aa,
const TString &subdir) {
430 scatter->GetXaxis()->SetRangeUser(fit.
x_lo, fit.
x_hi);
431 scatter->GetYaxis()->SetRangeUser(fit.
y_lo, fit.
y_hi);
432 const Int_t cReac = kRed + 1, cBeam = kAzure + 1;
437 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
439 PlottingUtils::ConfigureAndDraw2DHistogram(
441 Form(
"reac %d: fitted components (dashed 1,2,3#sigma) and regions "
444 std::vector<TCutG *> tmp;
445 for (Int_t k = 1; k <= 3; k++) {
447 eb->SetLineColor(cBeam);
453 er->SetLineColor(cReac);
460 aa->SetFillColorAlpha(cBeam, 0.15);
461 aa->SetLineColor(cBeam);
466 an->SetFillColorAlpha(cReac, 0.25);
467 an->SetLineColor(cReac);
472 PlottingUtils::SaveFigure(c, Form(
"regions_reac%d", reac), subdir,
473 PlotSaveOptions::kLINEAR);
475 for (Int_t k = 0; k < Int_t(tmp.size()); k++)
480 TH2F *model = ModelHist(scatter, fit, reac);
482 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
484 PlottingUtils::ConfigureAndDraw2DHistogram(
486 Form(
"reac %d: data with the fitted mixture's density", reac));
487 model->SetContour(10);
488 model->SetLineColor(cReac);
489 model->SetLineWidth(1);
490 model->Draw(
"CONT3 SAME");
491 PlottingUtils::SaveFigure(c, Form(
"regions_reac%d_model", reac), subdir,
492 PlotSaveOptions::kLINEAR);
497 TAxis *ax = scatter->GetXaxis(), *ay = scatter->GetYaxis();
498 const Int_t bx0 = ax->FindBin(fit.
x_lo), bx1 = ax->FindBin(fit.
x_hi);
499 const Int_t by0 = ay->FindBin(fit.
y_lo), by1 = ay->FindBin(fit.
y_hi);
500 for (Int_t which = 0; which < 2; which++) {
501 TH1D *d = which == 0 ? scatter->ProjectionX(Form(
"dpx_%d", reac), by0, by1)
502 : scatter->ProjectionY(Form(
"dpy_%d", reac), bx0, bx1);
503 TH1D *m = which == 0 ? model->ProjectionX(Form(
"mpx_%d", reac), by0, by1)
504 : model->ProjectionY(Form(
"mpy_%d", reac), bx0, bx1);
505 d->SetDirectory(
nullptr);
506 m->SetDirectory(
nullptr);
507 d->GetXaxis()->SetRange(which == 0 ? bx0 : by0, which == 0 ? bx1 : by1);
508 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kTRUE);
509 PlottingUtils::ConfigureAndDrawHistogram(
511 Form(
"reac %d: %s projection, data (black) and fitted mixture (red)",
512 reac, which == 0 ?
"x" :
"y"));
513 m->SetLineColor(cReac);
515 m->Draw(
"HIST SAME");
516 PlottingUtils::SaveFigure(
517 c, Form(
"regions_reac%d_proj%s", reac, which == 0 ?
"x" :
"y"), subdir,
518 PlotSaveOptions::kLOG);
static TString ResultsDir()
Absolute path to the directory receiving generated output.
const TString & ActiveFileTag()
Output-name prefix of the active epoch.
Finding regions by fitting a two-component mixture to the scatter.
RegionFit FitMixture(TH2F *scatter, Int_t reac, Double_t x_lo, Double_t x_hi, Double_t y_lo, Double_t y_hi)
Fit the two-component mixture to one strip's scatter.
TCutG * EllipseCut(const char *name, const Gauss2D &g, Double_t nsigma, Int_t npts=64)
Closed polygon of a component's Mahalanobis contour.
Double_t AboveRidge(const Gauss2D &beam, Double_t x, Double_t y)
How far a point sits above the beam ridge, in conditional sigma.
void SaveFigures(TH2F *scatter, Int_t reac, const RegionFit &fit, TCutG *an, TCutG *aa, const TString &subdir)
Save the diagnostic figures for a strip's regions.
Double_t CountInside(TH2F *scatter, TCutG *cut, const RegionFit &fit)
Count scatter events inside a cut.
On-disk home of the per-strip (a,n) and (a,a') region cuts.
TString Path(const char *name, Int_t reac)
Path to one cut's file.
void Save(Int_t reac, TCutG *cut_an, TCutG *cut_aa, Double_t n_an_assigned=-1.0)
Write a strip's two region cuts.
void SaveFit(Int_t reac, const RegionFit &fit)
Store the fitted components beside the (a,n) cut.
TString Dir()
Directory holding the region cut files.
TCutG * Load(const char *name, Int_t reac)
Load a cut from its per-cut file.
Double_t LoadAssigned(const char *name, Int_t reac)
The attributed count stored with a cut.
One bivariate Gaussian component of a strip's scatter.
Double_t rho
x-y correlation, in [-1, 1].
Result of fitting the two-component mixture to one strip's scatter.
Double_t n_beam
Events the mixture attributes to each component.
TString why
Why the fit failed; set only when ok is false.
Bool_t ok
Whether the fit succeeded. Check this first.
Gauss2D reac
The reaction population above the ridge.
Gauss2D beam
The beam-like population, pinned from its own core.