6#include <TFitResultPtr.h>
11 Double_t dx = x - b.
mu_x;
12 Double_t dy = y - b.
mu_y;
14 if (sx <= 0 || sy <= 0)
17 Double_t dx_s = dx / sx, dy_s = dy / sy;
18 Double_t r2 = rho * rho;
20 (dx_s * dx_s + dy_s * dy_s - 2.0 * rho * dx_s * dy_s) / (1.0 - r2);
28 Double_t sum = sxx + syy;
29 Double_t diff = sxx - syy;
30 Double_t det = TMath::Sqrt(diff * diff + 4.0 * sxy * sxy);
31 Double_t lambda1 = 0.5 * (sum + det);
32 Double_t lambda2 = 0.5 * (sum - det);
33 Double_t theta = 0.5 * TMath::ATan2(2.0 * sxy, diff) * 180.0 / TMath::Pi();
34 TEllipse *e =
new TEllipse(b.
mu_x, b.
mu_y, n * TMath::Sqrt(lambda1),
35 n * TMath::Sqrt(lambda2), 0, 360, theta);
37 e->SetLineColor(color);
43 Int_t lo_by, Int_t hi_by,
44 Double_t thresh, Double_t bw_x,
47 Double_t W = 0, Mx = 0, My = 0, Cxx = 0, Cyy = 0, Cxy = 0;
48 for (Int_t ix = lo_bx; ix <= hi_bx; ix++) {
49 Double_t x = h->GetXaxis()->GetBinCenter(ix);
50 for (Int_t iy = lo_by; iy <= hi_by; iy++) {
51 Double_t w = h->GetBinContent(ix, iy);
54 Double_t y = h->GetYaxis()->GetBinCenter(iy);
64 for (Int_t ix = lo_bx; ix <= hi_bx; ix++) {
65 Double_t x = h->GetXaxis()->GetBinCenter(ix);
66 for (Int_t iy = lo_by; iy <= hi_by; iy++) {
67 Double_t w = h->GetBinContent(ix, iy);
70 Double_t y = h->GetYaxis()->GetBinCenter(iy);
71 Double_t dx = x - Mx, dy = y - My;
82 m.
sigma_x = std::max(std::sqrt(std::max(Cxx, 0.0)), 2.0 * bw_x);
83 m.
sigma_y = std::max(std::sqrt(std::max(Cyy, 0.0)), 2.0 * bw_y);
95 const std::vector<std::pair<Float_t, Float_t>> &pts,
const Moments2D &seed,
97 const Int_t kMaxPasses = 50;
98 const Double_t kTolerance = 1.0e-4;
101 const Double_t e = std::exp(-0.5 * clip * clip);
102 const Double_t kept_var = 1.0 - 0.5 * clip * clip * e / (1.0 - e);
104 for (Int_t pass = 0; pass < kMaxPasses; pass++) {
107 Double_t W = 0, Sx = 0, Sy = 0, Sxx = 0, Syy = 0, Sxy = 0;
108 const Double_t one_minus_r2 = 1.0 - m.
rho * m.
rho;
109 for (
size_t k = 0; k < pts.size(); k++) {
110 const Double_t x = pts[k].first, y = pts[k].second;
113 if ((u * u + v * v - 2.0 * m.
rho * u * v) / one_minus_r2 >= clip * clip)
127 const Double_t cxx = std::max(Sxx / W - next.
mu_x * next.
mu_x, 0.0);
128 const Double_t cyy = std::max(Syy / W - next.
mu_y * next.
mu_y, 0.0);
129 const Double_t cxy = Sxy / W - next.
mu_x * next.
mu_y;
130 next.
sigma_x = std::sqrt(cxx / kept_var);
131 next.
sigma_y = std::sqrt(cyy / kept_var);
134 next.
rho = std::max(-0.95, std::min(0.95, cxy / std::sqrt(cxx * cyy)));
139 std::fabs(next.
rho - m.
rho) < kTolerance;
149 const Double_t kSeedFrac = 0.3;
150 const Double_t bw_x = h->GetXaxis()->GetBinWidth(1);
151 const Double_t bw_y = h->GetYaxis()->GetBinWidth(1);
153 h->GetMaximumBin(bx, by, bz);
154 const Double_t peak_val = h->GetBinContent(bx, by);
155 Int_t lo_bx = std::max(1, bx - seed_half_bins);
156 Int_t hi_bx = std::min(h->GetNbinsX(), bx + seed_half_bins);
157 Int_t lo_by = std::max(1, by - seed_half_bins);
158 Int_t hi_by = std::min(h->GetNbinsY(), by + seed_half_bins);
159 return ComputeMoments(h, lo_bx, hi_bx, lo_by, hi_by, kSeedFrac * peak_val,
165 std::vector<std::pair<Float_t, Float_t>> &pts,
173 const Double_t kSpotWindow = 4.0;
174 const Double_t kFitWindow = 2.0;
175 const Int_t kSpotBins = 160;
176 TH2F *hf =
new TH2F(Form(
"%s_fit", h->GetName()),
"", kSpotBins,
181 hf->SetDirectory(
nullptr);
182 for (
size_t k = 0; k < pts.size(); k++)
183 hf->Fill(pts[k].first, pts[k].second);
184 std::vector<std::pair<Float_t, Float_t>>().swap(pts);
195 h->GetMaximumBin(bx, by, bz);
196 out.
fit.
amp = h->GetBinContent(bx, by);
207 Double_t window_nsigma, Double_t *chi2_ndf) {
209 const Double_t kOffLimit = 1.0e-3;
210 const Double_t kSigmaLo = 0.2, kSigmaHi = 5.0;
217 const Double_t x_lo = seed.
mu_x - window_nsigma * seed.
sigma_x;
218 const Double_t x_hi = seed.
mu_x + window_nsigma * seed.
sigma_x;
219 const Double_t y_lo = seed.
mu_y - window_nsigma * seed.
sigma_y;
220 const Double_t y_hi = seed.
mu_y + window_nsigma * seed.
sigma_y;
221 const Double_t peak = TMath::Max(h->GetMaximum(), 1.0);
224 TF2 f(Form(
"beamspot_fit_%s", h->GetName()),
225 "[0]*exp(-0.5/(1.0-[5]*[5])*((x-[1])*(x-[1])/([2]*[2])"
226 "+(y-[3])*(y-[3])/([4]*[4])"
227 "-2.0*[5]*(x-[1])*(y-[3])/([2]*[4])))+[6]",
228 x_lo, x_hi, y_lo, y_hi);
230 TMath::Max(-0.9, TMath::Min(0.9, seed.
rho)), 0.0);
232 f.SetParLimits(0, 0.0, 1.0e3 * peak);
233 f.SetParLimits(1, x_lo, x_hi);
234 f.SetParLimits(2, kSigmaLo * seed.
sigma_x, kSigmaHi * seed.
sigma_x);
235 f.SetParLimits(3, y_lo, y_hi);
236 f.SetParLimits(4, kSigmaLo * seed.
sigma_y, kSigmaHi * seed.
sigma_y);
237 f.SetParLimits(5, -0.95, 0.95);
238 f.SetParLimits(6, 0.0, peak);
240 TFitResultPtr r = h->Fit(&f,
"QNRSL");
241 if (!r.Get() || !r->IsValid())
249 for (Int_t ix = 1; ix <= h->GetNbinsX(); ix++)
250 for (Int_t iy = 1; iy <= h->GetNbinsY(); iy++) {
251 const Double_t e = f.Eval(h->GetXaxis()->GetBinCenter(ix),
252 h->GetYaxis()->GetBinCenter(iy));
255 const Double_t o = h->GetBinContent(ix, iy);
256 chi2 += (o - e) * (o - e) / e;
260 *chi2_ndf = chi2 / Double_t(nbin - 7);
263 const Double_t sx = TMath::Abs(f.GetParameter(2));
264 const Double_t sy = TMath::Abs(f.GetParameter(4));
265 const Double_t mx = f.GetParameter(1), my = f.GetParameter(3);
266 const Double_t rho = f.GetParameter(5);
270 TMath::Finite(sx) && TMath::Finite(sy) && TMath::Finite(rho) &&
271 sx > (kSigmaLo + kOffLimit) * seed.
sigma_x &&
272 sx < (kSigmaHi - kOffLimit) * seed.
sigma_x &&
273 sy > (kSigmaLo + kOffLimit) * seed.
sigma_y &&
274 sy < (kSigmaHi - kOffLimit) * seed.
sigma_y && TMath::Abs(rho) < 0.94 &&
275 mx > x_lo && mx < x_hi && my > y_lo && my < y_hi;
279 out.
amp = f.GetParameter(0);
290 Double_t window_nsigma, Bool_t fix_mu,
291 Double_t &mu, Double_t &sigma,
292 Double_t *chi2_ndf) {
293 const Double_t kOffLimit = 1.0e-3;
294 const Double_t kSigmaLo = 0.2, kSigmaHi = 5.0;
297 if (!h || !(seed_sigma > 0.0))
299 const Double_t lo = seed_mu - window_nsigma * seed_sigma;
300 const Double_t hi = seed_mu + window_nsigma * seed_sigma;
301 const Double_t peak = TMath::Max(h->GetMaximum(), 1.0);
302 TF1 f(Form(
"beampeak_fit_%s", h->GetName()),
"gaus(0)+[3]", lo, hi);
303 f.SetParameters(peak, seed_mu, seed_sigma, 0.0);
304 f.SetParLimits(0, 0.0, 1.0e3 * peak);
305 f.SetParLimits(1, lo, hi);
306 f.SetParLimits(2, kSigmaLo * seed_sigma, kSigmaHi * seed_sigma);
307 f.SetParLimits(3, 0.0, peak);
309 f.FixParameter(1, seed_mu);
310 TFitResultPtr r = h->Fit(&f,
"QNRSL");
311 if (!r.Get() || !r->IsValid())
316 for (Int_t ix = 1; ix <= h->GetNbinsX(); ix++) {
317 const Double_t e = f.Eval(h->GetXaxis()->GetBinCenter(ix));
320 const Double_t o = h->GetBinContent(ix);
321 chi2 += (o - e) * (o - e) / e;
325 *chi2_ndf = chi2 / Double_t(nbin - 4);
327 const Double_t fit_mu = f.GetParameter(1);
328 const Double_t fit_sigma = TMath::Abs(f.GetParameter(2));
331 const Bool_t sane = TMath::Finite(fit_mu) && TMath::Finite(fit_sigma) &&
332 fit_sigma > (kSigmaLo + kOffLimit) * seed_sigma &&
333 fit_sigma < (kSigmaHi - kOffLimit) * seed_sigma &&
334 fit_mu > lo && fit_mu < hi;
static BeamFit2D FitSpot(TH2F *h, const Moments2D &seed, Double_t window_nsigma=2.0, Double_t *chi2_ndf=nullptr)
Fit a correlated 2-D Gaussian on a flat pedestal to h: ROOT's bigaus written out, Poisson likelihood,...
static SpotFit FitSpotFromPoints(TH2F *h, std::vector< std::pair< Float_t, Float_t > > &pts, const Moments2D &seed)
A beam spot from a coarse histogram and the same events unbinned: the sample's sigma-clipped moments ...
static Bool_t FitPeak(TH1F *h, Double_t seed_mu, Double_t seed_sigma, Double_t window_nsigma, Bool_t fix_mu, Double_t &mu, Double_t &sigma, Double_t *chi2_ndf=nullptr)
The 1-D counterpart: a Gaussian on a flat pedestal, fitted over window_nsigma of the seed and judged ...
static void DrawEllipse(const BeamFit2D &b, Double_t n, Color_t color)
Draw the n-sigma contour of a fitted spot on the current pad.
static Bool_t InEllipseXY(const BeamFit2D &b, Double_t x, Double_t y, Double_t n)
Whether a point lies inside the fitted ellipse at n sigma: the correlation-aware Mahalanobis chi2 bel...
static Moments2D ComputeMoments(TH2F *h, Int_t lo_bx, Int_t hi_bx, Int_t lo_by, Int_t hi_by, Double_t thresh, Double_t bw_x, Double_t bw_y)
Second moments of a histogram region above a threshold.
static Moments2D SeedSpotMoments(TH2F *h, Int_t seed_half_bins)
Second moments of a coarse spot histogram's seed window: the maximum bin, ± seed_half_bins around it,...
static Moments2D ClippedMoments(const std::vector< std::pair< Float_t, Float_t > > &pts, const Moments2D &seed, Double_t clip=3.0)
Sigma-clipped centroid and covariance of a point sample, the 2-D counterpart of the strip-width clip:...
A fitted 2-D Gaussian beam spot.
Double_t rho
Correlation coefficient, in [-1, 1].
Double_t sigma_y
Widths along each axis.
Double_t amp
Peak amplitude.
Bool_t ok
Whether the fit converged.
Result of a beam spot fit: the spot to use, and whether the Gaussian fit (rather than the clipped-mom...
Double_t chi2_ndf
The fit's reduced chi2; -1 when it did not run.
Bool_t fit_used
kTRUE when fit is the fit, not the fallback.
BeamFit2D fit
The spot to use; ok when usable.
Second moments of a 2-D distribution over a bin range.
Double_t rho
Correlation coefficient, in [-1, 1].
Double_t sigma_y
Weighted RMS widths.
Double_t mu_y
Weighted centroid.
Double_t weight
Total weight included; zero means the range held nothing above threshold.