205Bool_t
Measure(std::vector<RawHit> &hits,
const std::vector<Int_t> &group_of,
206 Result &res,
const TString &file_label) {
207 res.
n_hits = Long64_t(hits.size());
210 Bool_t sorted = kTRUE;
211 for (
size_t j = 1; j < hits.size() && sorted; j++)
212 sorted = hits[j].timestamp >= hits[j - 1].timestamp;
215 std::stable_sort(hits.begin(), hits.end(),
216 [](
const RawHit &a,
const RawHit &b) {
217 return a.timestamp < b.timestamp;
224 const Int_t guard0 = IndexOfName(
"Strip0");
226 std::cerr <<
" " << file_label
227 <<
": pulse history: no reference channel in the map"
234 const Int_t nidx = Int_t(group_of.size());
235 const Int_t n_amp = TMath::Max(
239 std::vector<Int_t> fit_ch, long_ch;
240 for (Int_t i = 0; i < nidx; i++) {
241 if (group_of[i] ==
kNone)
245 long_ch.push_back(i);
255 const Int_t nb = 128;
256 std::vector<std::vector<Long64_t>> spec(nidx, std::vector<Long64_t>(nb, 0));
257 for (
const RawHit &h : hits) {
258 const Int_t i = HitIndex(h);
259 if (i < 0 || i >= nidx || group_of[i] ==
kNone)
261 const Int_t b = Int_t(Double_t(h.energy) / emax * nb);
262 if (b >= 0 && b < nb)
265 res.
mode.assign(nidx, 0.0);
266 for (Int_t i : fit_ch) {
268 for (Int_t b = nb / 16; b < nb; b++)
269 if (best < 0 || spec[i][b] > spec[i][best])
271 res.
mode[i] = best >= 0 ? (best + 0.5) * emax / nb : 0.0;
273 const std::vector<Double_t> &mode = res.
mode;
284 std::vector<size_t> seeds[
kNGroups];
285 std::vector<Double_t> mean(nidx, 0.0);
286 std::vector<Double_t> ev_e(nidx, 0.0);
289 auto lookahead = [&](
size_t i0) {
290 for (Int_t c : fit_ch)
292 Bool_t guard_fired = guard0 < 0;
293 const ULong64_t t0 = hits[i0].timestamp;
294 for (
size_t j = i0 + 1;
295 j < hits.size() && hits[j].timestamp - t0 < window_ps; j++) {
296 const Int_t i = HitIndex(hits[j]);
297 if (i == guard0 && hits[j].energy > 0)
299 if (i < 0 || i >= nidx || group_of[i] ==
kNone)
301 if (Double_t(hits[j].energy) > ev_e[i])
302 ev_e[i] = Double_t(hits[j].energy);
306 auto beam_for = [&](Int_t g) {
307 const Int_t chain =
ChainOf(g);
308 for (Int_t c : long_ch) {
309 if (!(mode[c] > 0.0))
311 const Double_t r = ev_e[c] / mode[c];
312 const Bool_t own = chain >= 0 &&
ChainOf(group_of[c]) == chain;
313 if (own ? (r < olo || r > ohi) : (r < blo || r > bhi))
318 std::vector<Long64_t> nmean(nidx, 0);
319 for (
size_t j = 0; j < hits.size(); j++) {
320 const RawHit &h = hits[j];
321 if (HitIndex(h) != ref)
323 if (Double_t(h.energy) < ref_lo || Double_t(h.energy) > ref_hi)
328 for (Int_t g = 1; g <
kNGroups; g++) {
331 seeds[g].push_back(j);
332 for (Int_t c : fit_ch)
333 if (group_of[c] == g && ev_e[c] > 0.0) {
340 for (Int_t g = 1; g <
kNGroups; g++)
344 std::cerr <<
" " << file_label <<
": pulse history: only "
349 for (Int_t c : fit_ch)
350 mean[c] = nmean[c] ? mean[c] / Double_t(nmean[c]) : 0.0;
357 const Int_t np = 1 + n_amp *
kNBins;
358 const Double_t keep_ps = TMath::Power(10.0,
kLogHi) * 1.0e12;
359 std::vector<Double_t> x(np, 0.0);
360 auto scan = [&](Int_t g,
361 const std::function<void(Int_t,
const std::vector<Double_t> &,
362 Double_t, Double_t)> &fn) {
363 std::vector<std::deque<Past>> past(nidx);
364 size_t next_seed = 0;
365 for (
size_t j = 0; j < hits.size(); j++) {
366 if (next_seed < seeds[g].size() && seeds[g][next_seed] == j) {
368 const Double_t tg = Double_t(hits[j].timestamp);
370 for (Int_t c : fit_ch) {
372 if (group_of[c] != g || !(ev_e[c] > 0.0))
374 std::deque<Past> &d = past[c];
375 while (!d.empty() && d.front().t < tg - keep_ps)
377 std::fill(x.begin(), x.end(), 0.0);
379 for (
const Past &p : d) {
380 const Int_t b =
BinOf((tg - p.t) * 1.0e-12);
382 x[Feat(
AmpBinOf(p.e, mode[c], n_amp), b)] += p.e;
384 const Double_t dt_prev =
385 d.empty() ? -1.0 : (tg - d.back().t) * 1.0e-12;
386 fn(c, x, ev_e[c] - mean[c], dt_prev);
389 const Int_t i = HitIndex(hits[j]);
390 if (i >= 0 && i < nidx && group_of[i] == g)
392 {Double_t(hits[j].timestamp), Double_t(hits[j].energy)});
401 for (Int_t g = 0; g <
kNGroups; g++) {
402 A[g].ResizeTo(np, np);
407 for (Int_t g = 1; g <
kNGroups; g++)
408 scan(g, [&](Int_t,
const std::vector<Double_t> &xx, Double_t y, Double_t) {
409 for (Int_t a = 0; a < np; a++) {
412 bv[g][a] += xx[a] * y;
413 for (Int_t b = 0; b < np; b++)
414 A[g](a, b) += xx[a] * xx[b];
421 for (Int_t g = 1; g <
kNGroups; g++) {
425 K.
n_beam = Long64_t(seeds[g].size());
429 std::vector<Int_t> keep;
430 for (Int_t a = 0; a < np; a++)
431 if (a == 0 || A[g](a, a) > 0.0)
433 const Int_t nk = Int_t(keep.size());
436 for (Int_t a = 0; a < nk; a++) {
437 bk[a] = bv[g][keep[a]];
438 for (Int_t b = 0; b < nk; b++)
439 Ak(a, b) = A[g](keep[a], keep[b]);
446 for (Int_t a = 0; a < nk; a++)
447 scale[a] = Ak(a, a) > 0.0 ? 1.0 / TMath::Sqrt(Ak(a, a)) : 1.0;
450 for (Int_t a = 0; a < nk; a++) {
451 bs[a] = bk[a] * scale[a];
452 for (Int_t b = 0; b < nk; b++)
453 As(a, b) = Ak(a, b) * scale[a] * scale[b];
457 Bool_t solved = kFALSE;
458 TVectorD ps = svd.Solve(bs, solved);
462 for (Int_t a = 0; a < nk; a++)
463 p[a] = ps[a] * scale[a];
464 Double_t ss_res = syy[g];
465 for (Int_t a = 0; a < nk; a++)
466 ss_res -= p[a] * bk[a];
467 const Double_t ybar = sy[g] / ng[g];
468 const Double_t ss_tot = syy[g] - ng[g] * ybar * ybar;
469 if (!(ss_tot > 0.0) || !std::isfinite(ss_res))
471 for (Int_t a = 0; a < nk; a++) {
477 K.
r2 = 1.0 - ss_res / ss_tot;
479 K.
rms_after = TMath::Sqrt(TMath::Max(0.0, ss_res) / ng[g]);
489 const TString tag = file_label;
491 for (Int_t g = 1; g <
kNGroups; g++) {
494 Form(
"h_ph_dev_vs_pred_%s_%s", gn, tag.Data()),
495 ";Predicted Deviation from Mean [ADC];#splitline{Measured}{Deviation from Mean [ADC]}",
496 120, -600.0, 600.0, 120, -600.0, 600.0);
498 Form(
"h_ph_dev_before_%s_%s", gn, tag.Data()),
499 Form(
";%s #minus Mean %s [ADC];Events", gn, gn), 240, -600.0, 600.0);
501 Form(
"h_ph_dev_after_%s_%s", gn, tag.Data()),
502 Form(
";%s #minus Mean %s [ADC];Events", gn, gn), 240, -600.0, 600.0);
504 Form(
"p_ph_dtprev_before_%s_%s", gn, tag.Data()),
505 Form(
";log_{10}(#Deltat [#mus]);%s #minus Mean %s [ADC]", gn, gn), 48,
508 Form(
"p_ph_dtprev_after_%s_%s", gn, tag.Data()),
509 Form(
";log_{10}(#Deltat [#mus]);%s #minus Mean %s [ADC]", gn, gn), 48,
511 res.
shift[g] =
new TH1D(Form(
"h_ph_shift_%s_%s", gn, tag.Data()),
512 ";Applied Shift [ADC];Hits", 240, -600.0, 600.0);
513 for (TH1 *h : {
static_cast<TH1 *
>(res.
dev_vs_pred[g]),
518 static_cast<TH1 *
>(res.
shift[g])})
519 h->SetDirectory(
nullptr);
521 for (Int_t g = 1; g <
kNGroups; g++) {
525 scan(g, [&](Int_t,
const std::vector<Double_t> &xx, Double_t y,
528 for (Int_t a = 0; a < n_amp; a++)
529 for (Int_t b = 0; b <
kNBins; b++)
530 pred += K.
k[a][b] * xx[Feat(a, b)];
531 const Double_t after = y - pred;
536 const Double_t l = TMath::Log10(dt_prev * 1.0e6);
621 const TString subdir =
"pulse_history/" + file_label;
622 const Int_t colors[
kMaxAmpBins] = {kBlack, kRed + 1, kAzure + 1,
623 kGreen + 2, kOrange + 7, kMagenta + 1};
626 for (Int_t g = 1; g <
kNGroups; g++) {
630 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
631 Double_t ylo = 0.0, yhi = 0.0;
632 for (Int_t a = 0; a < K.
n_amp; a++)
633 for (Int_t b = 0; b <
kNBins; b++) {
634 ylo = TMath::Min(ylo, K.
k[a][b]);
635 yhi = TMath::Max(yhi, K.
k[a][b]);
637 TH1F *frame = c->DrawFrame(xlo, ylo - 0.02, xhi, yhi + 0.02);
638 frame->SetTitle(
";log_{10}(#Deltat [#mus]);"
639 "Relative Amplitude Shift");
640 TLegend *leg =
nullptr;
642 leg = PlottingUtils::AddLegend(0.55, 0.89, 0.15, 0.40);
644 for (Int_t a = 0; a < K.
n_amp; a++) {
645 TGraph *gr =
new TGraph();
646 for (Int_t b = 0; b <
kNBins; b++)
647 gr->SetPoint(b, xlo + (b + 0.5) * (xhi - xlo) /
kNBins, K.
k[a][b]);
648 gr->SetMarkerStyle(20);
654 leg->AddEntry(gr, Form(
"Previous pulse ~%d#times beam", a),
"pl");
660 TLine *zero =
new TLine(xlo, 0.0, xhi, 0.0);
661 zero->SetLineStyle(2);
663 PlottingUtils::SaveFigure(c, Form(
"kernel_%s",
GroupTag(g)), subdir,
664 PlotSaveOptions::kLINEAR);
667 for (Int_t g = 1; g <
kNGroups; g++) {
670 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
672 PlottingUtils::ConfigureAndDraw2DHistogram(res.
dev_vs_pred[g], c);
673 TLine *diag =
new TLine(-600.0, -600.0, 600.0, 600.0);
674 diag->SetLineColor(kRed + 1);
675 diag->SetLineStyle(2);
677 PlottingUtils::SaveFigure(c, Form(
"deviation_vs_predicted_%s", gn),
678 subdir, PlotSaveOptions::kLINEAR);
682 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kTRUE);
683 PlottingUtils::ConfigureAndDrawHistogram(res.
dev_before[g], kBlack);
684 res.
dev_after[g]->SetLineColor(kRed + 1);
687 TLegend *leg = PlottingUtils::AddLegend(0.62, 0.89, 0.72, 0.88);
693 PlottingUtils::SaveFigure(c, Form(
"deviation_before_after_%s", gn),
694 subdir, PlotSaveOptions::kLOG);
698 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
701 PlottingUtils::ConfigureAndDrawHistogram(res.
dtprev_before[g], kBlack);
706 TLegend *leg = PlottingUtils::AddLegend(0.62, 0.89, 0.15, 0.30);
710 PlottingUtils::SaveFigure(c, Form(
"deviation_vs_dt_previous_%s", gn),
711 subdir, PlotSaveOptions::kLINEAR);
714 if (res.
shift[g] && res.
shift[g]->GetEntries() > 0) {
715 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kTRUE);
716 PlottingUtils::ConfigureAndDrawHistogram(res.
shift[g], kBlack);
717 PlottingUtils::SaveFigure(c, Form(
"applied_shift_%s", gn), subdir,
718 PlotSaveOptions::kLOG);
722 for (Int_t g = 0; g <
kNGroups; g++) {
TString Report(const Result &res, const TString &file_label)
Format the pass as a human-readable report.
const char * GroupTag(Int_t g)
Short tag for filenames: L, R, Ls, Rs, S0, S17.
void Apply(std::vector< RawHit > &hits, const std::vector< Int_t > &group_of, Result &res)
Apply the measured kernels to the hit stream, in place.
Bool_t Measure(std::vector< RawHit > &hits, const std::vector< Int_t > &group_of, Result &res, const TString &file_label)
Measure the kernels on this subfile's beam-like events.
void SavePlots(Result &res, const TString &file_label)
Draw and save the diagnostics, then free them.
Int_t AmpBinOf(Double_t e_prev, Double_t mode, Int_t n_amp)
Amplitude band of a previous pulse.
void WriteToEventsFile(const TString &events_subpath, const Result &res)
Record the kernels and counters alongside a subfile's events.