10 "tagged",
"upstream beam",
"jump",
"reac level",
11 "tail rise",
"re-rise",
"post above",
"beam crossing",
12 "end strip",
"cliff",
"other strip"};
14 "reached tag",
"all strips",
"beam gate",
"pileup",
15 "noise",
"smoothness",
"both mult"};
20TString AxisTag(Int_t axis) {
21 return axis ==
GATE_AXIS_GRID ? TString(
"grid") : TString(Form(
"s%d", axis));
23TString AxisName(Int_t axis) {
25 : TString(Form(
"strip %d", axis));
28TString AxisTitle(Int_t axis) {
30 : TString(Form(
"Strip%d", axis));
33void EntranceAxes(Int_t &sx, Int_t &sy) {
51 for (Int_t i = 0; i < 64; i++) {
66 m_cutCounts.assign(m_tagged.size() *
kNTAGCUTS, 0);
70 std::map<Int_t, TH2F *>::iterator it;
71 for (it = m_scatter.begin(); it != m_scatter.end(); ++it)
76Int_t StripSumScatter::ReacIndex(Int_t reac) {
77 return reac -
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.REACTION_STRIP_MIN;
88 return TMath::Max(hi, reac + 1);
91Double_t StripSumScatter::s_stripSigma[18] = {0.0};
92Double_t StripSumScatter::s_stripMean[18] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
93 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
94 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
97 return (strip >= 0 && strip < 18) ? s_stripSigma[strip] : 0.0;
101 return (strip >= 0 && strip < 18) ? s_stripMean[strip] : 1.0;
105 const Double_t *sigma) {
106 for (Int_t s = 0; s < 18; s++) {
107 s_stripMean[s] = mean ? mean[s] : 1.0;
108 s_stripSigma[s] = sigma[s];
134std::vector<std::pair<TString, TagThresholds>>
137 std::vector<std::pair<TString, TagThresholds>> out;
181 for (
size_t v = 0; v <
sizeof(vars) /
sizeof(vars[0]); v++) {
182 if (!vars[v].on || !(vars[v].step > 0.0))
184 for (Int_t dir = +1; dir >= -1; dir -= 2) {
186 T.*(vars[v].field) = nom.*(vars[v].field) + dir * vars[v].step;
189 if (!vars[v].any_sign && !(T.*(vars[v].field) > 0.0))
192 std::make_pair(TString(vars[v].name) + (dir > 0 ?
"+" :
"-"), T));
203Bool_t StripSumScatter::BeamUpstreamOf(
const EnergyView &ev, Int_t reac,
207 for (Int_t s = 1; s < reac; s++)
214Bool_t StripSumScatter::BeamUpstreamOf(
const EnergyView &ev, Int_t reac) {
250 const Int_t end_strip =
252 Constants::cfg.STRIP_SUM_SCATTER_CONFIG.REQUIRE_STRIP_16_BELOW_BEAM)
259 return BeamUpstreamOf(ev, reac, T);
268 for (Int_t s = start; s <= kLast; s++)
277 for (Int_t s = reac + 1; s <= TMath::Min(
YHiOf(reac), kLast); s++)
280 Bool_t returned = kFALSE;
281 for (Int_t s = peak + 1; s <= kLast; s++) {
305 for (Int_t s = reac + 1; s <= upto; s++)
313 return ev.
Total(end_strip) <
318 if (!(end_strip - 1 > reac))
320 Double_t peak = ev.
Total(reac);
321 for (Int_t s = reac + 1; s < end_strip; s++)
322 peak = TMath::Max(peak, ev.
Total(s));
323 const Double_t fall = peak - ev.
Total(end_strip);
324 const Double_t last = ev.
Total(end_strip - 1) - ev.
Total(end_strip);
325 return !(fall > 0.0 && last / fall > T.
cliff_max);
355 const std::vector<Bool_t> &pass) {
356 const Int_t kReacMin =
359 Double_t best_jump = -1.0e9;
360 for (Int_t k = 0; k < Int_t(pass.size()); k++) {
363 const Int_t reac = kReacMin + k;
368 const Double_t jump =
369 (ev.
Total(reac) - ev.
Total(reac - 1)) / (sig > 0.0 ? sig : 1.0);
370 if (jump > best_jump) {
382void AddSelectionStep(std::vector<SelectionStep> &out,
384 const char *name,
const TString &detail, Bool_t on,
385 Int_t pre_cut, Int_t tag_cut) {
398TString FewerStrips(Int_t n) {
399 return n <= 1 ? TString(
"none") : TString(Form(
"fewer than %d", n));
411 const Int_t last = ign17 ? 16 : 17;
413 std::vector<SelectionStep> out;
415 Int_t ent_x = 0, ent_y = 1;
416 EntranceAxes(ent_x, ent_y);
417 const TString entrance = AxisName(ent_x) +
" vs " + AxisName(ent_y);
421 Form(
"E(s) = strip total in beam units (beam = 1)%s; beam gates fitted "
428 Form(
"beam mean and σ per strip from the first %s's pure-beam sample: "
429 "every strip fired, inside the entrance (%s) and exit (%s) "
430 "ellipses at %.1f σ, 3σ-clipped",
432 entrance.Data(), ign17 ?
"strips 15 vs 16" :
"strips 16 vs 17",
440 Form(
"every strip %d-%d read above zero", req0 ? 0 : 1, last), kTRUE,
442 const TString gates =
444 ? TString(Form(
"strip %d within %.1f σ of its fitted beam peak",
446 : TString(
"no beam gate");
451 Form(
"%s of strips 1-16 at or above beam + %.1f σ",
456 Form(
"%s of strips 1-16 at or below beam − %.1f σ",
461 Form(
"every step between strips 1-%d within %.1f σ of the later "
462 "strip's spread, the single largest rise excepted",
468 Form(
"at most %d of strips 1-%d with both ends fired (raw ADC)",
478 "every strip is tested on its own; the first failing condition ends "
483 Form(
"every strip 1..reac−1 within %.1f σ of the beam",
488 Form(
"E(reac) − E(reac−1) > %.1f σ(reac)", C.
REAC_JUMP_NSIGMA), kTRUE, -1,
496 Form(
"no step up above %.1f σ from strip max(reac, %d)+1 to %d",
502 Form(
"once back within %.1f σ of the beam after the peak, never above "
503 "beam + %.1f σ again",
508 Form(
"strips reac+1 to reac+%d all above beam + %.1f σ",
514 Form(
"strips reac+1 through %d all at or above the beam mean: the "
515 "residue reaches strip %d before crossing the beam",
524 Form(
"the last step, strip %d to %d, at most %.0f%% of the fall from "
531 ?
"one tag per event: the first strip that passes takes it"
532 :
"one tag per event: the passing strip with the largest jump takes "
538 "a reaction at reac; one strip per event", kTRUE, -1,
542 "events past the event-level cuts with beam upstream of reac and no "
543 "tag before it: the beam incident on reac, the denominator",
546 TString sys =
"no cut variation";
548 sys = Form(
"systematic: each beam-selection and identification "
549 "condition shifted ±%.1f σ (cliff ±%.2f), one at a time, "
550 "largest change of σ per condition in quadrature, with the "
551 "gas pressure uncertainty",
555 "σ(reac) = tagged / (beam count × target atoms per strip); " + sys,
560 Form(
"scatter x = ΣE(%d..%d), y = ΣE(reac+1..reac+%d)%s; bivariate "
561 "Gaussian mixture per strip, (a,n) = reaction component within "
562 "%.1f σ, count as attributed by the fit",
573static Double_t ClippedWidth(
const std::vector<Double_t> &values,
574 Double_t *mean_out =
nullptr) {
575 const Int_t kClipPasses = 3;
576 const Double_t kClipNSigma = 3.0;
579 const Double_t kKeptVar =
580 1.0 - 2.0 * kClipNSigma * TMath::Gaus(kClipNSigma, 0.0, 1.0, kTRUE) /
581 TMath::Erf(kClipNSigma / TMath::Sqrt2());
584 if (values.size() < 2)
586 std::vector<Double_t> sorted(values);
587 std::sort(sorted.begin(), sorted.end());
588 Double_t mean = sorted[sorted.size() / 2];
589 for (
size_t k = 0; k < sorted.size(); k++)
590 sorted[k] = TMath::Abs(sorted[k] - mean);
591 std::sort(sorted.begin(), sorted.end());
592 Double_t width = 1.4826 * sorted[sorted.size() / 2];
595 for (Int_t pass = 0; pass < kClipPasses; pass++) {
596 Double_t sum = 0.0, sum2 = 0.0;
598 for (Int_t k = 0; k < Int_t(values.size()); k++) {
599 const Double_t v = values[k];
600 if (TMath::Abs(v - mean) > kClipNSigma * width)
608 mean = sum / Double_t(kept);
609 width = TMath::Sqrt(TMath::Max(0.0, sum2 / Double_t(kept) - mean * mean) /
617Bool_t StripSumScatter::MeasureBeamNoise(TChain *chain,
const BeamEllipses &be,
618 Double_t *strip_mean,
619 Double_t *strip_sigma) {
622 const Long64_t kMaxGated = 100000;
623 const Long64_t kMinEvents = 1000;
624 for (Int_t s = 0; s < 18; s++) {
626 strip_sigma[s] = 0.0;
628 if (!chain || !be.
ok)
633 EnableEventBranches(chain);
634 const Long64_t n = chain->GetEntries();
635 std::vector<std::vector<Double_t>> deposit(18);
636 for (Long64_t j = 0; j < n && Long64_t(deposit[1].size()) < kMaxGated; j++) {
641 if (!IsPureBeam(ev, be))
643 for (Int_t s = 0; s < 18; s++)
644 deposit[s].push_back(ev.
Total(s));
646 chain->ResetBranchAddresses();
647 if (Long64_t(deposit[1].size()) < kMinEvents)
652 for (Int_t s = 0; s < 18; s++) {
654 strip_sigma[s] = ClippedWidth(deposit[s], &mean);
656 strip_mean[s] = mean;
658 for (Int_t s = 1; s <= 16; s++)
659 if (!(strip_sigma[s] > 0.0))
664void StripSumScatter::EnableEventBranches(TChain *chain) {
665 chain->SetBranchStatus(
"*", 0);
666 chain->SetBranchStatus(
"LeftdE", 1);
667 chain->SetBranchStatus(
"RightdE", 1);
668 chain->SetBranchStatus(
"Strip0dE", 1);
669 chain->SetBranchStatus(
"Strip17dE", 1);
670 chain->SetBranchStatus(
"Cathode", 1);
671 chain->SetBranchStatus(
"Grid", 1);
673 if (chain->GetBranch(
"SeedTs"))
674 chain->SetBranchStatus(
"SeedTs", 1);
677Bool_t StripSumScatter::AllStripsFired(
const EnergyView &ev) {
683 for (Int_t s = 1; s <= 16; s++)
684 if (!(ev.
Total(s) > 0.0))
689Bool_t StripSumScatter::IsPureBeam(
const EnergyView &ev,
693 if (!AllStripsFired(ev))
700 if (!PassesEllipse(be.
s1_s2, ev, 1, 2, n))
708 if (!PassesEllipse(be.
s0_s1, ev, 0, 1, n))
712 if (!PassesEllipse(be.
s15_s16, ev, 15, 16, n))
715 if (!PassesEllipse(be.
s16_s17, ev, 16, 17, n))
726 const Int_t kMinStrips =
728 if (!(kNSigma > 0.0))
733 for (Int_t s = 1; s <= 16; s++)
746 const Int_t kMinStrips =
748 if (!(kNSigma > 0.0))
751 for (Int_t s = 1; s <= 16; s++)
762 Double_t worst = 0.0, best_rise = 0.0, second_rise = 0.0;
763 for (Int_t s = 2; s <= kLast; s++) {
770 second_rise = best_rise;
772 }
else if (d > second_rise) {
775 }
else if (-d > worst) {
779 return TMath::Max(worst, second_rise);
786Double_t StripSumScatter::SumRange(
const Double_t *total, Int_t lo, Int_t hi) {
788 for (Int_t s = lo; s <= hi; s++)
797 y = SumRange(total,
YLoOf(reac),
YHiOf(reac));
800 if (
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.Y_RATIO_TO_UPSTREAM && reac > 1) {
801 const Double_t up = SumRange(total, 1, reac - 1) / Double_t(reac - 1);
810 TString name =
"StripSumScatter_cache";
818 Int_t strip, Double_t nsigma) {
821 const Double_t v = ev.
Axis(strip);
822 if (!(v > 0.0) || !gate.
ok)
824 return TMath::Abs(v - gate.
mu) < nsigma * gate.
sigma;
827Bool_t StripSumScatter::PassesEllipse(
const BeamFit2D &gate,
830 Double_t g0 = ev.
Axis(sx);
831 Double_t g1 = ev.
Axis(sy);
832 if (!(g0 > 0.0 && g1 > 0.0))
837BeamFit2D StripSumScatter::FindBeamGate(TChain *chain, Int_t sx, Int_t sy,
839 const TString &subdir,
845 const Int_t kSeedHalfBins =
847 const Long64_t kSampleMaxPoints =
853 EnableEventBranches(chain);
855 new TH2F(Form(
"h2_beamgate_%s_%s_%s", AxisTag(sx).Data(),
856 AxisTag(sy).Data(), tag.Data()),
857 Form(
";%s #DeltaE [a.u.];%s #DeltaE [a.u.]",
858 AxisTitle(sx).Data(), AxisTitle(sy).Data()),
859 kGateBins, kGateMin, kGateMax, kGateBins, kGateMin, kGateMax);
860 h->SetDirectory(
nullptr);
861 Long64_t n = chain->GetEntries();
864 std::vector<std::pair<Float_t, Float_t>> pts;
865 pts.reserve(std::min(n, kSampleMaxPoints > 0 ? kSampleMaxPoints : n));
866 for (Long64_t j = 0; j < n; j += stride) {
869 Double_t x = ev.
Axis(sx);
870 Double_t y = ev.
Axis(sy);
871 if (x > 0.0 && y > 0.0) {
873 pts.push_back(std::make_pair(Float_t(x), Float_t(y)));
876 if (h->GetEntries() < 100) {
892 <<
" " << tag <<
": "
894 :
"CLIPPED MOMENTS (fit failed)")
896 <<
") rho=" << out.
rho <<
" chi2/ndf=" << spot.
chi2_ndf
907 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
908 PlottingUtils::ConfigureAndDraw2DHistogram(h, c);
913 PlottingUtils::SaveFigure(
914 c, Form(
"beam_gate_%s_%s", AxisTag(sx).Data(), AxisTag(sy).Data()),
915 subdir, PlotSaveOptions::kLINEAR);
922BeamGate1D StripSumScatter::FindStripGate(TChain *chain, Int_t strip,
924 const TString &subdir,
925 Double_t nsigma, Double_t center) {
927 const Double_t kSpotWindow = 4.0;
928 const Double_t kFitWindow = 2.0;
929 const Int_t kSpotBins = 160;
930 const Int_t kMinEvents = 100;
934 EnableEventBranches(chain);
935 TH1F *h =
new TH1F(Form(
"h1_gate_s%d_%s", strip, tag.Data()),
936 Form(
";%s #DeltaE [a.u.];Events", AxisTitle(strip).Data()),
938 h->SetDirectory(
nullptr);
939 const Long64_t n = chain->GetEntries();
941 std::vector<Double_t> values;
944 for (Long64_t j = 0; j < n; j += stride) {
947 const Double_t v = ev.
Axis(strip);
953 if (Int_t(values.size()) < kMinEvents) {
958 const Double_t width = ClippedWidth(values, &mean);
959 if (!(width > 0.0)) {
967 TH1F *hf =
new TH1F(Form(
"%s_fit", h->GetName()),
"", kSpotBins,
968 mean - kSpotWindow * width, mean + kSpotWindow * width);
969 hf->SetDirectory(
nullptr);
970 for (Int_t k = 0; k < Int_t(values.size()); k++)
972 Double_t chi2_ndf = -1.0;
973 Double_t fit_mu = mean;
974 Double_t fit_sigma = width;
976 hf, mean, width, kFitWindow, center > 0.0, fit_mu, fit_sigma, &chi2_ndf);
978 out.
mu = fit_ok ? fit_mu : mean;
979 out.
sigma = fit_ok ? fit_sigma : width;
984 << (fit_ok ?
"fit" :
"CLIPPED WIDTH (fit failed)")
985 <<
" mu=" << out.
mu <<
" sigma=" << out.
sigma
986 <<
" chi2/ndf=" << chi2_ndf << std::endl;
990 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kTRUE);
991 PlottingUtils::ConfigureAndDrawHistogram(h, kBlue + 1);
992 const Double_t top = h->GetMaximum();
993 TLine *lo =
new TLine(out.
mu - nsigma * out.
sigma, 0.0,
994 out.
mu - nsigma * out.
sigma, top);
995 TLine *hi =
new TLine(out.
mu + nsigma * out.
sigma, 0.0,
996 out.
mu + nsigma * out.
sigma, top);
997 lo->SetLineColor(kRed + 1);
998 hi->SetLineColor(kRed + 1);
1000 hi->SetLineWidth(2);
1003 PlottingUtils::SaveFigure(c, Form(
"beam_gate_s%d", strip), subdir);
1012void StripSumScatter::DrawTraceSet(
const std::vector<TGraph *> &traces,
1014 for (Int_t i = 0; i < Int_t(traces.size()); i++) {
1015 traces[i]->SetLineColor(color);
1016 traces[i]->SetLineWidth(1);
1017 traces[i]->Draw(
"L SAME");
1021TGraph *StripSumScatter::TraceFromTotal(
const Double_t *total) {
1025void StripSumScatter::DrawRegionTraces(
1026 const TString &save_name,
const TString &subdir,
1027 const std::vector<TGraph *> &beam,
const std::vector<TGraph *> &aa,
1028 const std::vector<TGraph *> &an, Double_t y_min, Double_t y_max,
1029 const char *y_title, Bool_t beam_sigma_measured,
const char *an_label) {
1030 std::vector<TraceClass> classes;
1033 c_aa.label =
"(#alpha,#alpha')";
1034 c_aa.color = SimClassColor(
"aa");
1035 classes.push_back(c_aa);
1038 c_an.label = an_label ? an_label :
"(#alpha,n)";
1039 c_an.color = SimClassColor(
"an");
1040 classes.push_back(c_an);
1041 DrawRegionTraces(save_name, subdir, beam, classes, y_min, y_max, y_title,
1042 beam_sigma_measured);
1045Int_t StripSumScatter::SimClassColor(
const TString &base) {
1053 return kMagenta + 2;
1061static TGraphErrors *TraceMeanBand(
const std::vector<TGraph *> &traces) {
1062 const Int_t npts = traces[0]->GetN();
1063 std::vector<Double_t> mean(npts, 0.0), m2(npts, 0.0);
1064 for (Int_t t = 0; t < Int_t(traces.size()); t++) {
1065 const Double_t *yv = traces[t]->GetY();
1066 for (Int_t p = 0; p < npts; p++) {
1068 m2[p] += yv[p] * yv[p];
1071 const Double_t nt = Double_t(traces.size());
1072 const Double_t *xv = traces[0]->GetX();
1073 TGraphErrors *ge =
new TGraphErrors(npts);
1074 for (Int_t p = 0; p < npts; p++) {
1076 const Double_t var = m2[p] / nt - mean[p] * mean[p];
1077 ge->SetPoint(p, xv[p], mean[p]);
1078 ge->SetPointError(p, 0.0, var > 0.0 ? TMath::Sqrt(var) : 0.0);
1083void StripSumScatter::DrawRegionTraces(
const TString &save_name,
1084 const TString &subdir,
1085 const std::vector<TGraph *> &beam,
1086 const std::vector<TraceClass> &classes,
1087 Double_t y_min, Double_t y_max,
1088 const char *y_title,
1089 Bool_t beam_sigma_measured) {
1094 new TH2F(
"h_region_trace_frame", Form(
";Strip;%s", y_title),
1095 s_hi - s_lo + 1, s_lo - 0.5, s_hi + 0.5, 100, y_min, y_max);
1097 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
1102 TGraphErrors *beam_band =
nullptr;
1103 if (!beam.empty()) {
1104 beam_band = TraceMeanBand(beam);
1107 if (beam_sigma_measured) {
1108 for (Int_t p = 0; p < beam_band->GetN(); p++) {
1109 const Double_t measured =
1110 StripSigma(Int_t(TMath::Nint(beam_band->GetX()[p]))) *
1111 beam_band->GetY()[p];
1113 beam_band->SetPointError(p, 0.0, measured);
1117 beam_band->SetLineColor(kGray + 3);
1118 beam_band->SetLineWidth(3);
1119 beam_band->SetFillColorAlpha(kGray + 1, 0.35);
1120 beam_band->Draw(
"3 SAME");
1122 for (
size_t k = 0; k < classes.size(); k++)
1123 DrawTraceSet(classes[k].traces, classes[k].color);
1125 beam_band->Draw(
"LX SAME");
1129 std::vector<TGraph *> proxies;
1130 TLegend *leg = PlottingUtils::AddLegend(0.71, 0.88, 0.70, 0.86);
1132 leg->AddEntry(beam_band,
"Beam #pm 1#sigma",
"lf");
1133 for (
size_t k = 0; k < classes.size(); k++) {
1134 if (classes[k].traces.empty())
1136 TGraph *p =
new TGraph(1);
1137 p->SetPoint(0, -1e9, -1e9);
1138 p->SetLineColor(classes[k].color);
1140 proxies.push_back(p);
1141 leg->AddEntry(p, classes[k].label,
"l");
1145 PlottingUtils::SaveFigure(c, save_name, subdir, PlotSaveOptions::kLINEAR);
1149void StripSumScatter::DrawRegionMeanTraces(
const TString &save_name,
1150 const TString &subdir,
1151 const std::vector<TGraph *> &beam,
1152 const std::vector<TGraph *> &aa,
1153 const std::vector<TGraph *> &an,
1154 Double_t y_min, Double_t y_max,
1155 const char *y_title) {
1157 TH2F *frame =
new TH2F(
"h_region_mean_frame", Form(
";Strip;%s", y_title), 18,
1158 -0.5, 17.5, 100, y_min, y_max);
1160 frame->SetDirectory(
nullptr);
1161 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
1164 const std::vector<TGraph *> *regions[3] = {&beam, &aa, &an};
1166 Int_t colors[3] = {kGray + 3, kAzure + 3, kRed + 2};
1167 Int_t bands[3] = {kGray + 1, kAzure + 1, kRed - 7};
1168 const char *labels[3] = {
"Beam",
"(#alpha,#alpha')",
"(#alpha,n)"};
1169 std::vector<TGraphErrors *> means;
1170 TLegend *leg = PlottingUtils::AddLegend(0.725, 0.875, 0.70, 0.86);
1172 for (Int_t r = 0; r < 3; r++) {
1173 const std::vector<TGraph *> &tr = *regions[r];
1176 TGraphErrors *ge = TraceMeanBand(tr);
1177 ge->SetLineColor(colors[r]);
1178 ge->SetLineWidth(3);
1179 ge->SetFillColorAlpha(bands[r], 0.35);
1181 means.push_back(ge);
1182 leg->AddEntry(ge, labels[r],
"lf");
1185 for (Int_t i = 0; i < Int_t(means.size()); i++)
1186 means[i]->Draw(
"LX SAME");
1189 PlottingUtils::SaveFigure(c, save_name, subdir, PlotSaveOptions::kLINEAR);
1190 for (Int_t i = 0; i < Int_t(means.size()); i++)
1197void StripSumScatter::TraceYRange(
const std::vector<TGraph *> &beam,
1198 const std::vector<TGraph *> &aa,
1199 const std::vector<TGraph *> &an,
1200 Double_t &y_min, Double_t &y_max) {
1201 y_min = std::numeric_limits<Double_t>::max();
1202 y_max = -std::numeric_limits<Double_t>::max();
1203 const std::vector<TGraph *> *sets[3] = {&beam, &aa, &an};
1204 for (Int_t si = 0; si < 3; si++) {
1205 const std::vector<TGraph *> &v = *sets[si];
1206 for (Int_t i = 0; i < Int_t(v.size()); i++) {
1207 Double_t x = 0.0, y = 0.0;
1208 for (Int_t k = 0; k < v[i]->GetN(); k++) {
1209 v[i]->GetPoint(k, x, y);
1210 if (x < 0.5 || x > 16.5)
1219 if (y_min > y_max) {
1223 Double_t pad = 0.05 * (y_max - y_min);
1230TCutG *StripSumScatter::PromptCut(TCanvas *c,
const char *name,
1231 const char *label) {
1232 std::cout <<
" >>> draw the " << label
1233 <<
" region: left-click vertices, double-click to close"
1236 TCutG *cut =
static_cast<TCutG *
>(c->WaitPrimitive(
"CUTG",
"CutG"));
1238 std::cerr <<
" no " << label <<
" cut drawn" << std::endl;
1242 cut->SetLineColor(kBlack);
1243 cut->SetLineWidth(2);
1255void StripSumScatter::SaveRegionCuts(Int_t reac, TCutG *cut_an, TCutG *cut_aa) {
1259TCutG *StripSumScatter::LoadRegionCut(
const char *name, Int_t reac) {
1268void StripSumScatter::SavitzkyGolay(
const Double_t *in, Double_t *out) {
1269 static const Int_t K = 2;
1273 static const Double_t sg_coeff[2 * K + 1] = {
1281 for (Int_t s = 0; s < 18; s++) {
1282 Int_t lo = TMath::Max(0, s - K);
1283 Int_t hi = TMath::Min(17, s + K);
1285 Double_t wsum = 0.0;
1288 for (Int_t t = lo; t <= hi; t++) {
1289 Int_t offset = t - s + K;
1290 val += sg_coeff[offset] * in[t];
1291 wsum += sg_coeff[offset];
1295 out[s] = (wsum != 0.0) ? val / wsum : in[s];
1300TGraph *StripSumScatter::SmoothedTraceFromTotal(
const Double_t *total) {
1302 SavitzkyGolay(total, sgd);
1307 const Int_t kReacMin =
1309 const Int_t kReacMax =
1311 const Double_t kReacJumpNSigma =
1313 const Double_t kSmoothNSigma =
1315 const Double_t kEndStripMax =
1318 const Double_t kGateNSigma =
1320 const Double_t kGateCenter =
1333 Form(
"v45 reac[%d,%d] short=%d bmult[%d,%d] pileup=%.2fsig,%d "
1335 "jump=%.2fsig smooth=%.2fsig "
1336 "end=%.2fsig gate[s%d,%.2f,c%.4f,%d,%.3f,%.3f]",
1344 kReacJumpNSigma, kSmoothNSigma, kEndStripMax, kGateStrip,
1345 kGateNSigma, kGateCenter, kGateBins, kGateMin, kGateMax);
1348 " req[s0=%d,s17=%d]",
1352 s += Form(
" one=%d",
1354 s += Form(
" pure=%d,%.2fsig",
1361 s += Form(
" tail[fall=%d,%.2fsig above=%d,%.2fsig rerise=%.2fsig,%.2fsig "
1362 "cross=%d cliff=%.2f]",
1371 for (Int_t strip = 1; strip <= 17; strip++)
1372 s += Form(
"%s%.4f/%.4f", strip == 1 ?
"" :
",",
StripMean(strip),
1379 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
1380 s += Form(
"%s%.4f", reac == kReacMin ?
"" :
",",
JumpMin(reac));
1384 s += Form(
" up=%d,%.2fsig[",
1386 .REQUIRE_BEAM_UPSTREAM_OF_REAC),
1388 for (Int_t strip = 1; strip < kReacMax; strip++)
1389 s += Form(
"%s%.4f", strip == 1 ?
"" :
",",
1395 for (Int_t i = 0; i < Int_t(groups.
order.size()); i++) {
1396 const Int_t key = groups.
order[i];
1397 s += Form(
" %s:%lld", groups.
label.find(key)->second.Data(),
1398 groups.
chain.find(key)->second->GetEntries());
1404 Form(
"buildx[%.3f,%.3f] buildy[%.3f,%.3f] bins[%d,%d] x[%d,%d]",
1410 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
1412 Form(
"%s%d-%d", reac == kReacMin ?
"[" :
",",
YLoOf(reac),
YHiOf(reac));
1416 Int_t(
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.Y_RATIO_TO_UPSTREAM));
1417 return s +
" | " + plane;
1422static TString TagPart(
const TString &fingerprint) {
1423 const Ssiz_t bar = fingerprint.Index(
" | ");
1424 return bar < 0 ? TString(
"") : TString(fingerprint(0, bar));
1431void StripSumScatter::YBounds(Double_t *y_lo, Double_t *y_hi) {
1432 const Int_t kReacMin =
1434 const Int_t kReacMax =
1436 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
1437 Int_t ri = reac - kReacMin;
1438 std::map<Int_t, std::pair<Double_t, Double_t>>::const_iterator it =
1440 if (it !=
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.Y_DISPLAY_RANGE.end()) {
1441 y_lo[ri] = it->second.first;
1442 y_hi[ri] = it->second.second;
1450TString StripSumScatter::PrettyLabel(
const TString &tag) {
1453 return "(#alpha,#alpha')";
1455 return "(#alpha,n)";
1457 return "(#alpha,p)";
1459 return "(#alpha,2n)";
1461 return "(#alpha,#gamma)";
1475Bool_t StripSumScatter::SimBeamGains(Double_t *gain) {
1476 const Long64_t kSampleMaxPoints =
1479 for (Int_t s = 0; s < 18; s++)
1485 for (Int_t i = 0; i < Int_t(specs.size()); i++) {
1491 if (file.Length() == 0)
1494 TFile *f = IO::OpenForReading(file);
1495 if (!f || f->IsZombie()) {
1496 std::cerr <<
"strip-sum-scatter: cannot open sim beam file " << file
1497 <<
"; sim overlay stays in raw sim units." << std::endl;
1502 TTree *t =
static_cast<TTree *
>(f->Get(
"events_MeV"));
1504 std::cerr <<
"strip-sum-scatter: no events_MeV tree in sim beam file "
1505 << file <<
"; sim overlay stays in raw sim units." << std::endl;
1516 Long64_t n = t->GetEntries();
1518 Double_t sum[18] = {0};
1519 Long64_t cnt[18] = {0};
1523 for (Int_t s = 0; s < 18; s++)
1525 for (Long64_t j = 0; j < n; j += stride) {
1528 SimTotal(e, unit, total);
1529 for (Int_t s = 0; s < 18; s++)
1530 if (total[s] > 0.0) {
1538 for (Int_t s = 0; s < 18; s++) {
1539 if (cnt[s] > 0 && sum[s] > 0.0) {
1540 gain[s] = 1.0 / (sum[s] / Double_t(cnt[s]));
1546 std::cout <<
"strip-sum-scatter: sim per-strip beam normalization to 1 a.u. ("
1547 << n_set <<
" strips)." << std::endl;
1551void StripSumScatter::SimTotal(
const RemixSim::Event &e,
const Double_t *gain,
1553 for (Int_t s = 0; s < 18; s++)
1554 total[s] = gain[s] * e.
Total(s);
1556 for (Int_t s = 1; s <= 16; s++)
1557 total[s] = gain[s] * ((s % 2) != 0 ? e.
Left(s) : e.
Right(s));
1560TGraph *StripSumScatter::SimPopScatter(
const TString &file, Int_t reac,
1561 const Double_t *gain,
1562 Long64_t max_points) {
1566 TFile *f = IO::OpenForReading(file);
1567 if (!f || f->IsZombie()) {
1572 TTree *t =
static_cast<TTree *
>(f->Get(
"events_MeV"));
1574 std::cerr <<
" no events_MeV tree in " << file << std::endl;
1579 Int_t y_lo = reac + 1;
1580 Int_t y_hi = TMath::Min(reac + 6, 17);
1587 Long64_t n = t->GetEntries();
1589 TGraph *g =
new TGraph();
1591 for (Long64_t j = 0; j < n; j += stride) {
1594 SimTotal(e, gain, total);
1595 Double_t x = SumRange(total, kXLo, kXHi);
1596 Double_t y = SumRange(total, y_lo, y_hi);
1598 g->SetPoint(k++, x, y);
1610std::vector<TGraph *> StripSumScatter::SimPopTraces(
const TString &file,
1611 const Double_t *gain,
1612 Long64_t max_traces) {
1613 std::vector<TGraph *> traces;
1614 TFile *f = IO::OpenForReading(file);
1615 if (!f || f->IsZombie()) {
1620 TTree *t =
static_cast<TTree *
>(f->Get(
"events_MeV"));
1632 Long64_t n = t->GetEntries();
1634 for (Long64_t j = 0; j < n && Int_t(traces.size()) < max_traces;
1638 SimTotal(e, gain, total);
1648static Int_t CountBothEnds(
const EnergyView &ev, Int_t hi) {
1650 for (Int_t s = 1; s <= hi; s++)
1660 const Int_t nReac = kReacMax - kReacMin + 1;
1671 std::vector<SimClass> classes;
1672 for (Int_t i = 0; i < Int_t(specs.size()); i++) {
1677 if (c.base !=
"beam" && (c.strip < kReacMin || c.strip > kReacMax))
1679 classes.push_back(c);
1682 if (!SimBeamGains(gain))
1683 for (Int_t s = 0; s < 18; s++)
1686 std::ostringstream out;
1687 out << Form(
"strip-sum-scatter: the data selection over the simulated "
1688 "populations (%s), against the measured beam spread; the beam "
1689 "gate is not applied (fitted on data), the rest is the fill's "
1693 out <<
"Event level: sequential (all strips, pileup, noise, smoothness, "
1694 "both mult). Own strip: the first failing tag condition, sequential; "
1695 "tagged = passed them all. One tag: where the event's single tag "
1696 "went under the one-tag rule (own, an earlier strip, a later strip, "
1700 for (
size_t k = 0; k < classes.size(); k++) {
1701 const SimClass &c = classes[k];
1702 TFile *fl = IO::OpenForReading(c.file);
1703 if (!fl || fl->IsZombie()) {
1705 out << Form(
"%s: cannot open %s", c.base.Data(), c.file.Data())
1709 TTree *t =
static_cast<TTree *
>(fl->Get(
"events_MeV"));
1711 if (!t || !e.
Attach(t)) {
1712 out << Form(
"%s: no events_MeV in %s", c.base.Data(), c.file.Data())
1718 const Long64_t n = t->GetEntries();
1719 std::vector<Long64_t> pre(
kNPRECUTS, 0);
1720 std::vector<Long64_t> own(
kNTAGCUTS, 0);
1721 Long64_t tag_own = 0, tag_earlier = 0, tag_later = 0, tag_none = 0;
1722 std::vector<Long64_t> tag_at(nReac, 0);
1724 std::vector<Bool_t> pass(nReac, kFALSE);
1725 for (Long64_t j = 0; j < n; j++) {
1729 for (Int_t s = 1; s <= 16; s++) {
1730 ev.
left[s - 1] = gain[s] * e.
Left(s);
1733 const Double_t tot = gain[s] * e.
Total(s);
1734 ev.
left[s - 1] = (s % 2) != 0 ? tot : 0.0;
1735 ev.
right[s - 1] = (s % 2) != 0 ? 0.0 : tot;
1743 if (!AllStripsFired(ev)) {
1767 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
1769 pass[ReacIndex(reac)] = why ==
kTAG_PASS;
1770 if (reac == c.strip)
1777 tag_at[ReacIndex(won)]++;
1780 else if (won < c.strip)
1789 out << Form(
"%s%s: %lld events (%s)", PrettyLabel(c.base).Data(),
1790 c.strip >= 0 ? Form(
" at strip %d", c.strip) :
"", n,
1791 gSystem->BaseName(c.file))
1793 TString line =
" event level:";
1796 line += Form(
" %s %lld,",
kPreCutName[p], pre[p]);
1797 line += Form(
" reached the tag %lld (%.1f%%)", pre[
kPRE_PASS],
1798 n > 0 ? 100.0 * pre[
kPRE_PASS] / n : 0.0);
1799 out << line << std::endl;
1801 line = Form(
" own strip %d:", c.strip);
1804 line += Form(
" %s %lld,",
kTagCutName[w], own[w]);
1805 line += Form(
" tagged %lld (%.1f%% of events, %.1f%% of those reaching "
1810 out << line << std::endl;
1811 out << Form(
" one tag: own %lld, earlier strip %lld, later strip %lld, "
1813 tag_own, tag_earlier, tag_later, tag_none)
1816 line =
" tagged at:";
1817 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
1818 line += Form(
" s%d %lld", reac, tag_at[ReacIndex(reac)]);
1819 line += Form(
" (none %lld)", tag_none);
1820 out << line << std::endl;
1823 const std::string text = out.str();
1826 gSystem->mkdir(dir, kTRUE);
1827 std::ofstream fo((dir +
"/sim_tag_report.txt").Data());
1836void StripSumScatter::SimTraceOverlay() {
1837 const Int_t kReacMin =
1839 const Int_t kReacMax =
1841 const Int_t kTracesPerRegion =
1849 std::vector<TString> bases;
1850 std::map<TString, std::map<Int_t, TString>> files;
1851 std::vector<TString> beam_files;
1852 for (Int_t i = 0; i < Int_t(specs.size()); i++) {
1856 if (base ==
"beam") {
1857 beam_files.push_back(file);
1858 }
else if (strip >= kReacMin && strip <= kReacMax) {
1859 if (!files.count(base))
1860 bases.push_back(base);
1861 files[base][strip] = file;
1866 if (!SimBeamGains(gain))
1867 for (Int_t s = 0; s < 18; s++)
1870 std::vector<TGraph *> beam_traces;
1871 for (Int_t i = 0; i < Int_t(beam_files.size()) &&
1872 Int_t(beam_traces.size()) < kTracesPerRegion;
1874 std::vector<TGraph *> t = SimPopTraces(
1875 beam_files[i], gain, kTracesPerRegion - Int_t(beam_traces.size()));
1876 for (Int_t k = 0; k < Int_t(t.size()); k++)
1877 beam_traces.push_back(t[k]);
1880 for (Int_t r = kReacMin; r <= kReacMax; r++) {
1881 std::vector<TraceClass> classes;
1882 Bool_t any = kFALSE;
1883 for (
size_t b = 0; b < bases.size(); b++) {
1885 cl.label = PrettyLabel(bases[b]);
1886 cl.color = SimClassColor(bases[b]);
1887 if (files[bases[b]].count(r))
1888 cl.traces = SimPopTraces(files[bases[b]][r], gain, kTracesPerRegion);
1889 any = any || !cl.traces.empty();
1890 classes.push_back(cl);
1894 DrawRegionTraces(Form(
"sim_region_traces_reac%d", r),
"sim_scatter",
1895 beam_traces, classes, 0.6, 1.6,
"#DeltaE [a.u.]");
1896 for (
size_t b = 0; b < classes.size(); b++)
1897 for (Int_t i = 0; i < Int_t(classes[b].traces.size()); i++)
1898 delete classes[b].traces[i];
1900 for (Int_t i = 0; i < Int_t(beam_traces.size()); i++)
1901 delete beam_traces[i];
1907TString StripSumScatter::SimFingerprint(
1908 const std::vector<RemixSim::SimFileSpec> &specs) {
1911 const Int_t kReacMin =
1913 const Int_t kReacMax =
1920 TString s = Form(
"v4 reac[%d,%d] x[%d,%d]", kReacMin, kReacMax, kXLo, kXHi);
1921 for (Int_t i = 0; i < Int_t(specs.size()); i++) {
1923 Long_t
id = 0, flags = 0, mtime = 0;
1925 if (gSystem->GetPathInfo(f, &
id, &size, &flags, &mtime) != 0) {
1929 s += Form(
" %s:%lld:%ld", specs[i].tag.Data(), size, mtime);
1937Bool_t StripSumScatter::LoadSimCache(
1938 const TString &fp, std::map<Int_t, std::vector<TGraph *>> &by_strip) {
1939 TString full = IO::GetRootFilesBaseDir() + TString(
"/") +
1940 "StripSumScatter_simcache.root";
1941 if (gSystem->AccessPathName(full))
1943 TFile *f = IO::OpenForReading(
"StripSumScatter_simcache.root");
1944 if (!f || f->IsZombie()) {
1949 TNamed *cfp =
static_cast<TNamed *
>(f->Get(
"sim_fingerprint"));
1950 if (!cfp || fp != cfp->GetTitle()) {
1955 TIter next(f->GetListOfKeys());
1957 while ((key =
static_cast<TKey *
>(next()))) {
1958 TString name = key->GetName();
1959 if (!name.BeginsWith(
"simg_r"))
1961 TString rest = name(6, name.Length() - 6);
1962 Int_t us = rest.Index(
"_p");
1965 Int_t r = TString(rest(0, us)).Atoi();
1966 TGraph *g =
static_cast<TGraph *
>(f->Get(name));
1969 by_strip[r].push_back(
static_cast<TGraph *
>(g->Clone()));
1976void StripSumScatter::WriteSimCache(
1977 const TString &fp,
const std::map<Int_t, std::vector<TGraph *>> &by_strip) {
1978 TFile *out = IO::OpenForWriting(
"StripSumScatter_simcache.root",
"RECREATE");
1979 if (!out || out->IsZombie()) {
1985 TNamed cfp(
"sim_fingerprint", fp.Data());
1987 std::map<Int_t, std::vector<TGraph *>>::const_iterator it;
1988 for (it = by_strip.begin(); it != by_strip.end(); ++it)
1989 for (Int_t i = 0; i < Int_t(it->second.size()); i++)
1990 it->second[i]->Write(Form(
"simg_r%d_p%d", it->first, Int_t(i)));
2001void StripSumScatter::SimOverlay() {
2002 const Int_t kReacMin =
2004 const Int_t kReacMax =
2010 if (specs.empty()) {
2012 <<
"strip-sum-scatter: no sim control files; skipping sim overlay."
2016 TString fp = SimFingerprint(specs);
2018 std::map<Int_t, std::vector<TGraph *>>
2020 Bool_t loaded = LoadSimCache(fp, by_strip);
2023 std::map<std::pair<TString, Int_t>, std::pair<SimPop, Bool_t>> chosen;
2024 for (Int_t i = 0; i < Int_t(specs.size()); i++) {
2027 std::pair<TString, Int_t> key(base, strip);
2030 p.
label = PrettyLabel(specs[i].tag);
2031 chosen[key] = std::make_pair(p, kTRUE);
2033 std::map<Int_t, std::vector<SimPop>> reacted;
2034 std::vector<SimPop> refs;
2035 for (std::map<std::pair<TString, Int_t>,
2036 std::pair<SimPop, Bool_t>>::const_iterator it =
2038 it != chosen.end(); ++it) {
2039 if (it->first.second < 0)
2040 refs.push_back(it->second.first);
2042 reacted[it->first.second].push_back(it->second.first);
2045 if (!SimBeamGains(gain))
2046 for (Int_t s = 0; s < 18; s++)
2048 const Long64_t kSimMaxPoints = 25000;
2049 for (Int_t r = kReacMin; r <= kReacMax; r++) {
2050 std::vector<SimPop> group = reacted[r];
2051 for (Int_t i = 0; i < Int_t(refs.size()); i++)
2052 group.push_back(refs[i]);
2053 for (Int_t i = 0; i < Int_t(group.size()); i++) {
2054 TGraph *g = SimPopScatter(group[i].file, r, gain, kSimMaxPoints);
2055 if (!g || g->GetN() == 0) {
2060 g->SetTitle(group[i].label);
2061 by_strip[r].push_back(g);
2065 std::map<Int_t, std::vector<TGraph *>>::const_iterator cit;
2066 for (cit = by_strip.begin(); cit != by_strip.end(); ++cit)
2067 n_graphs += Int_t(cit->second.size());
2068 if (n_graphs == 0) {
2069 std::cerr <<
"strip-sum-scatter: no sim data found (regenerate "
2070 "sim_root_files); skipping sim overlay."
2074 WriteSimCache(fp, by_strip);
2075 std::cout <<
"strip-sum-scatter: built + cached sim overlay (" << n_graphs
2076 <<
" population graphs)." << std::endl;
2079 <<
"strip-sum-scatter: loaded cached sim overlay (fingerprint match)."
2083 std::map<Int_t, std::vector<TGraph *>>::iterator it;
2084 for (it = by_strip.begin(); it != by_strip.end(); ++it) {
2085 Int_t r = it->first;
2086 std::map<Int_t, TH2F *>::const_iterator sit = m_scatter.find(r);
2087 if (sit == m_scatter.end())
2090 TH2F *ref = sit->second;
2092 new TH2F(Form(
"sim_frame_r%d", r),
"", 10, ref->GetXaxis()->GetXmin(),
2093 ref->GetXaxis()->GetXmax(), 10, ref->GetYaxis()->GetXmin(),
2094 ref->GetYaxis()->GetXmax());
2096 frame->GetXaxis()->SetTitle(ref->GetXaxis()->GetTitle());
2097 frame->GetYaxis()->SetTitle(ref->GetYaxis()->GetTitle());
2098 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
2099 c->SetLeftMargin(0.18);
2102 TLegend *leg = PlottingUtils::AddLegend(0.725, 0.875, 0.70, 0.86);
2103 for (Int_t i = 0; i < Int_t(it->second.size()); i++) {
2104 TGraph *g = it->second[i];
2107 TString lab = g->GetTitle();
2108 Int_t color = kBlack;
2111 else if (lab ==
"(#alpha,#alpha')")
2113 else if (lab ==
"(#alpha,n)")
2115 g->SetMarkerStyle(20);
2116 g->SetMarkerSize(0.3);
2117 g->SetMarkerColorAlpha(color, 0.35);
2118 g->SetLineColor(color);
2120 leg->AddEntry(g, g->GetTitle(),
"p");
2123 PlottingUtils::SaveFigure(c,
2124 Form(
"sim_normsumE_reac%d_s%d_%d_vs_s%d_%d", r,
2126 "sim_scatter", PlotSaveOptions::kLINEAR);
2132 std::map<Int_t, std::vector<TGraph *>>::iterator dit;
2133 for (dit = by_strip.begin(); dit != by_strip.end(); ++dit)
2134 for (Int_t i = 0; i < Int_t(dit->second.size()); i++)
2135 delete dit->second[i];
2138Bool_t StripSumScatter::TryLoadCache(
const TString &cacheName,
2139 const TString &fingerprint) {
2140 const Int_t kReacMin =
2142 const Int_t kReacMax =
2145 TString cache_full = IO::GetRootFilesBaseDir() + TString(
"/") + cacheName;
2146 if (gSystem->AccessPathName(cache_full)) {
2147 std::cout <<
"strip-sum-scatter: no cache file found; will rebuild."
2152 TFile *cf = IO::OpenForReading(cacheName);
2153 if (!cf || cf->IsZombie()) {
2156 std::cout <<
"strip-sum-scatter: cache file unreadable; rebuilding."
2161 TNamed *fp =
static_cast<TNamed *
>(cf->Get(
"fingerprint"));
2162 const Bool_t exact = fp && fingerprint == fp->GetTitle();
2165 const Bool_t reproject = !exact && fp && !TagPart(fingerprint).IsNull() &&
2166 TagPart(fingerprint) == TagPart(fp->GetTitle());
2167 if (!exact && !reproject) {
2168 std::cout <<
"strip-sum-scatter: cache present but stale; rebuilding."
2170 std::cout <<
" cached: " << (fp ? fp->GetTitle() :
"(none)") << std::endl;
2171 std::cout <<
" wanted: " << fingerprint << std::endl;
2178 for (Int_t reac = kReacMin; reac <= kReacMax && ok && exact; reac++) {
2179 TH2F *h =
static_cast<TH2F *
>(cf->Get(Form(
"scatter_r%d", reac)));
2184 TH2F *hc =
static_cast<TH2F *
>(h->Clone());
2185 hc->SetDirectory(
nullptr);
2186 m_scatter[reac] = hc;
2190 if (TParameter<Long64_t> *p =
2191 dynamic_cast<TParameter<Long64_t> *
>(cf->Get(
"n_seen")))
2192 m_nSeen = p->GetVal();
2193 if (TParameter<Long64_t> *p =
2194 dynamic_cast<TParameter<Long64_t> *
>(cf->Get(
"n_normed")))
2195 m_nNormed = p->GetVal();
2196 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2197 if (TParameter<Long64_t> *p =
dynamic_cast<TParameter<Long64_t> *
>(
2198 cf->Get(Form(
"n_normed_r%d", reac))))
2199 m_normedAt[ReacIndex(reac)] = p->GetVal();
2200 if (TParameter<Long64_t> *p =
dynamic_cast<TParameter<Long64_t> *
>(
2201 cf->Get(Form(
"n_tagged_r%d", reac))))
2202 m_tagged[ReacIndex(reac)] = p->GetVal();
2206 m_variantNames.clear();
2207 m_taggedVar.clear();
2208 m_normedVar.clear();
2209 if (TNamed *vn =
dynamic_cast<TNamed *
>(cf->Get(
"cut_variants"))) {
2210 TString names = vn->GetTitle();
2213 while (names.Tokenize(tok, from,
",")) {
2216 m_variantNames.push_back(tok);
2217 std::vector<Long64_t> counts(m_tagged.size(), 0),
2218 normed(m_tagged.size(), 0);
2219 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2220 if (TParameter<Long64_t> *p =
dynamic_cast<TParameter<Long64_t> *
>(
2221 cf->Get(Form(
"n_tagged_r%d_%s", reac, tok.Data()))))
2222 counts[ReacIndex(reac)] = p->GetVal();
2223 if (TParameter<Long64_t> *p =
dynamic_cast<TParameter<Long64_t> *
>(
2224 cf->Get(Form(
"n_normed_r%d_%s", reac, tok.Data()))))
2225 normed[ReacIndex(reac)] = p->GetVal();
2227 m_taggedVar.push_back(counts);
2228 m_normedVar.push_back(normed);
2232 TTree *tt =
static_cast<TTree *
>(cf->Get(
"traces"));
2233 if (reproject && !tt)
2237 tt->SetBranchAddress(
"leftdE", e.
leftdE);
2238 tt->SetBranchAddress(
"rightdE", e.
rightdE);
2239 tt->SetBranchAddress(
"strip0dE", &e.
strip0dE);
2240 tt->SetBranchAddress(
"strip17dE", &e.
strip17dE);
2241 tt->SetBranchAddress(
"leftdE_adc", e.
leftdE_adc);
2242 tt->SetBranchAddress(
"rightdE_adc", e.
rightdE_adc);
2243 tt->SetBranchAddress(
"strip0_adc", &e.
strip0_adc);
2244 tt->SetBranchAddress(
"strip17_adc", &e.
strip17_adc);
2245 tt->SetBranchAddress(
"reac_mask", &e.
reac_mask);
2246 tt->SetBranchAddress(
"beam_flat", &e.
beam_flat);
2247 tt->SetBranchAddress(
"both_mult", &e.
both_mult);
2249 if (tt->GetBranch(
"seed_ts"))
2250 tt->SetBranchAddress(
"seed_ts", &e.
seed_ts);
2251 Long64_t nt = tt->GetEntries();
2252 m_reservoir.reserve(nt);
2253 for (Long64_t j = 0; j < nt; j++) {
2255 m_reservoir.push_back(e);
2263 std::cout <<
"strip-sum-scatter: cache partially corrupt; rebuilding."
2265 m_reservoir.clear();
2269 std::cout <<
"strip-sum-scatter: cache tagging matches but the plane "
2270 "changed; re-projecting "
2271 << m_reservoir.size() <<
" reservoir events." << std::endl;
2273 ReprojectFromReservoir();
2274 WriteCache(cacheName, fingerprint);
2276 std::cout <<
"strip-sum-scatter: loaded cached scatters + "
2277 << m_reservoir.size() <<
" reservoir events (fingerprint match)."
2283void StripSumScatter::WriteCache(
const TString &cacheName,
2284 const TString &fingerprint) {
2285 const Int_t kReacMin =
2287 const Int_t kReacMax =
2290 TFile *out = IO::OpenForWriting(cacheName,
"RECREATE");
2291 if (!out || out->IsZombie()) {
2297 TNamed fp(
"fingerprint", fingerprint.Data());
2301 TParameter<Long64_t>(
"n_seen", m_nSeen).Write();
2302 TParameter<Long64_t>(
"n_normed", m_nNormed).Write();
2304 for (Int_t s = 0; s < 18; s++) {
2305 TParameter<Double_t>(Form(
"strip_mean_s%d", s), s_stripMean[s]).Write();
2306 TParameter<Double_t>(Form(
"strip_sigma_s%d", s), s_stripSigma[s]).Write();
2308 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2309 TParameter<Long64_t>(Form(
"n_normed_r%d", reac),
2310 m_normedAt[ReacIndex(reac)])
2312 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2313 TParameter<Long64_t>(Form(
"n_tagged_r%d", reac), m_tagged[ReacIndex(reac)])
2319 for (
size_t v = 0; v < m_variantNames.size(); v++)
2320 names += (v ?
"," :
"") + m_variantNames[v];
2321 TNamed(
"cut_variants", names.Data()).Write();
2322 for (
size_t v = 0; v < m_variantNames.size(); v++)
2323 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2324 TParameter<Long64_t>(
2325 Form(
"n_tagged_r%d_%s", reac, m_variantNames[v].Data()),
2326 m_taggedVar[v][ReacIndex(reac)])
2328 TParameter<Long64_t>(
2329 Form(
"n_normed_r%d_%s", reac, m_variantNames[v].Data()),
2330 m_normedVar[v][ReacIndex(reac)])
2334 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2335 m_scatter[reac]->
Write(Form(
"scatter_r%d", reac));
2337 TTree *tt =
new TTree(
"traces",
"strip-sum trace reservoir");
2339 tt->Branch(
"leftdE", e.
leftdE,
"leftdE[16]/F");
2340 tt->Branch(
"rightdE", e.
rightdE,
"rightdE[16]/F");
2341 tt->Branch(
"strip0dE", &e.
strip0dE,
"strip0dE/F");
2342 tt->Branch(
"strip17dE", &e.
strip17dE,
"strip17dE/F");
2343 tt->Branch(
"leftdE_adc", e.
leftdE_adc,
"leftdE_adc[16]/F");
2344 tt->Branch(
"rightdE_adc", e.
rightdE_adc,
"rightdE_adc[16]/F");
2345 tt->Branch(
"strip0_adc", &e.
strip0_adc,
"strip0_adc/F");
2346 tt->Branch(
"strip17_adc", &e.
strip17_adc,
"strip17_adc/F");
2347 tt->Branch(
"reac_mask", &e.
reac_mask,
"reac_mask/i");
2348 tt->Branch(
"beam_flat", &e.
beam_flat,
"beam_flat/O");
2349 tt->Branch(
"both_mult", &e.
both_mult,
"both_mult/I");
2350 tt->Branch(
"seed_ts", &e.
seed_ts,
"seed_ts/l");
2351 for (Int_t k = 0; k < Int_t(m_reservoir.size()); k++) {
2358 std::cout <<
"strip-sum-scatter: wrote cache " << cacheName << std::endl;
2367 const TString run = label;
2368 SingleRunFitResult res;
2369 if (!chain || chain->GetEntries() == 0)
2376 const TString tag = label;
2377 const TString subdir =
"strip_sum_scatter/" + label;
2378 Int_t ent_sx = 0, ent_sy = 1;
2379 EntranceAxes(ent_sx, ent_sy);
2380 const TString ent_tag = AxisTag(ent_sx) +
"/" + AxisTag(ent_sy);
2381 const Double_t kPure =
2383 BeamFit2D ent_ell = FindBeamGate(chain, ent_sx, ent_sy, tag, subdir, kPure);
2386 else if (ent_sx == 0)
2393 <<
": mu=(" << ent_ell.
mu_x <<
"," << ent_ell.
mu_y
2394 <<
")" << std::endl;
2397 std::cerr <<
" " << run <<
" beam ellipse " << ent_tag
2398 <<
" failed; skipping run" << std::endl;
2403 be.
s15_s16 = FindBeamGate(chain, 15, 16, tag, subdir, kPure);
2407 <<
" " << run <<
" beam ellipse s15/s16: mu=(" << be.
s15_s16.
mu_x
2411 std::cerr <<
" " << run <<
" beam ellipse s15/s16 failed; skipping run"
2417 be.
s16_s17 = FindBeamGate(chain, 16, 17, tag, subdir, kPure);
2421 <<
" " << run <<
" beam ellipse s16/s17: mu=(" << be.
s16_s17.
mu_x
2425 std::cerr <<
" " << run <<
" beam ellipse s16/s17 failed; skipping run"
2437 FindStripGate(chain, C.
GATE_STRIP, label,
"strip_sum_scatter/" + label,
2441 std::cerr <<
" " << run <<
" strip gate s" << C.
GATE_STRIP
2442 <<
" failed; skipping run" << std::endl;
2450static void VariantMovesEventLevel(
2451 const std::vector<std::pair<TString, TagThresholds>> &variants,
2452 const TagThresholds &nominal, std::vector<Bool_t> &varies_event) {
2453 varies_event.assign(variants.size(), kFALSE);
2454 for (
size_t v = 0; v < variants.size(); v++) {
2465 UInt_t mask, Bool_t beam) {
2466 for (Int_t k = 0; k < 16; k++) {
2479 for (Int_t s = 1; s <= 16; s++) {
2491StripSumScatter::EventLevelVerdict
2493 Int_t gate_strip, Double_t step_z,
2495 EventLevelVerdict v;
2496 v.gate = PassesGate(gate, ev, gate_strip, T.
gate_nsigma);
2500 v.event = v.gate && !v.pileup && !v.noise;
2508 else if (!v.smooth_ok)
2513Bool_t StripSumScatter::AnyVariantKeeps(
2515 const std::vector<std::pair<TString, TagThresholds>> &variants,
2516 const std::vector<Bool_t> &varies_event, Bool_t nom_event,
2517 std::vector<Bool_t> &var_event) {
2520 var_event.assign(variants.size(), nom_event);
2521 for (
size_t v = 0; v < variants.size(); v++)
2522 if (varies_event[v]) {
2523 const TagThresholds &T = variants[v].second;
2524 var_event[v] = PassesGate(gate, ev, gate_strip, T.
gate_nsigma) &&
2528 Bool_t any_event = nom_event;
2529 for (
size_t v = 0; !any_event && v < variants.size(); v++)
2530 any_event = var_event[v];
2534void StripSumScatter::TagUnderVariants(
2535 const EnergyView &ev, Double_t step_z, Int_t kReacMin, Int_t kReacMax,
2536 const std::vector<std::pair<TString, TagThresholds>> &variants,
2537 const std::vector<Bool_t> &var_event, std::vector<Bool_t> &pass,
2539 for (
size_t v = 0; v < variants.size(); v++) {
2540 const TagThresholds &T = variants[v].second;
2543 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2548 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2549 if ((won < 0 || reac <= won) && BeamUpstreamOf(ev, reac, T))
2554Int_t StripSumScatter::TagNominal(
const EnergyView &ev,
2555 const Double_t totals[18], Int_t kReacMin,
2556 Int_t kReacMax, Int_t nReacStrips,
2557 std::vector<Bool_t> &pass,
2559 std::vector<TagCut> why(nReacStrips,
kTAG_PASS);
2560 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2562 pass[ReacIndex(reac)] = why[ReacIndex(reac)] ==
kTAG_PASS;
2565 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2566 TagCut w = why[ReacIndex(reac)];
2572 mask |= (1u << ReacIndex(won));
2573 res.
tagged[ReacIndex(won)]++;
2574 Double_t x = 0.0, y = 0.0;
2576 res.
scatters[ReacIndex(won)]->Fill(x, y);
2578 for (Int_t reac = kReacMin; reac <= kReacMax; reac++)
2579 if ((won < 0 || reac <= won) && BeamUpstreamOf(ev, reac))
2584void StripSumScatter::AllocateRunScatters(Int_t run, Int_t kReacMin,
2585 Int_t kReacMax, Int_t kXBins,
2587 std::vector<TH2F *> &scatters) {
2590 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2592 new TH2F(Form(
"scatter_r%d_run%d", reac, run),
"", kXBins,
2595 h->SetDirectory(
nullptr);
2596 scatters[ReacIndex(reac)] = h;
2604StripSumScatter::FillRunScatters(Int_t key,
const TString &label, TChain *chain,
2607 const Int_t run = key;
2608 const Int_t kReacMin =
2610 const Int_t kReacMax =
2615 const Int_t kBeamReservoirCap =
2617 const Int_t nReacStrips = kReacMax - kReacMin + 1;
2619 SingleRunFillResult res;
2620 res.
scatters.assign(nReacStrips,
nullptr);
2623 AllocateRunScatters(run, kReacMin, kReacMax, kXBins, kYBins, res.
scatters);
2624 Long64_t totalGated = 0, totalSeen = 0, totalNormed = 0;
2625 res.
tagged.assign(nReacStrips, 0);
2631 const std::vector<std::pair<TString, TagThresholds>> variants =
2634 res.
tagged_var.assign(variants.size(), std::vector<Long64_t>(nReacStrips, 0));
2635 res.
normed_var.assign(variants.size(), std::vector<Long64_t>(nReacStrips, 0));
2636 std::vector<Bool_t> variesEvent;
2637 VariantMovesEventLevel(variants, nominal, variesEvent);
2638 Int_t nBeamKept = 0;
2641 EnableEventBranches(chain);
2642 ULong64_t seed_ts_in = 0;
2643 if (chain->GetBranch(
"SeedTs"))
2644 chain->SetBranchAddress(
"SeedTs", &seed_ts_in);
2645 Long64_t n = chain->GetEntries();
2649 <<
" reaction-strip scatters over " << n <<
" events..."
2653 for (Long64_t j = 0; j < n; j++) {
2660 if (!AllStripsFired(ev)) {
2667 const EventLevelVerdict nom =
2668 JudgeEventLevel(gate, ev, kGateStrip, step_z, nominal);
2669 if (nom.pre_cut >= 0)
2671 std::vector<Bool_t> var_event;
2672 if (!AnyVariantKeeps(gate, ev, kGateStrip, variants, variesEvent, nom.event,
2677 if (
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.BOTH_MULT_MAX >= 0) {
2678 const Int_t hi = TMath::Min(
2680 if (CountBothEnds(ev, hi) >
2684 if (nom.event && nom.smooth_ok)
2695 Double_t totals[18];
2697 std::vector<Bool_t> pass(nReacStrips, kFALSE);
2698 TagUnderVariants(ev, step_z, kReacMin, kReacMax, variants, var_event, pass,
2700 if (nom.event && nom.smooth_ok) {
2705 TagNominal(ev, totals, kReacMin, kReacMax, nReacStrips, pass, res, mask);
2710 if (!nom.event || !nom.smooth_ok)
2712 Bool_t beam = (mask == 0) && IsPureBeam(ev, runBeam);
2713 if (mask == 0 && !(beam && nBeamKept < kBeamReservoirCap))
2719 FillTraceEvt(e, ev, seed_ts_in, mask, beam);
2724 res.
gated = totalGated;
2725 res.
seen = totalSeen;
2726 res.
normed = totalNormed;
2731void StripSumScatter::RunIndexedParallel(
2732 Int_t n, Int_t workers,
const std::function<
void(Int_t)> &task) {
2733 std::queue<Int_t> work;
2734 for (Int_t i = 0; i < n; i++)
2736 std::mutex work_mutex;
2737 std::vector<std::thread> pool;
2738 for (Int_t w = 0; w < workers; w++) {
2739 pool.emplace_back([&]() {
2743 std::lock_guard<std::mutex> lk(work_mutex);
2753 for (Int_t w = 0; w < Int_t(pool.size()); w++)
2757void StripSumScatter::AllocateScatters() {
2758 const Int_t kReacMin =
2760 const Int_t kReacMax =
2766 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2768 new TH2F(Form(
"scatter_r%d", reac),
2769 Form(
";norm. #DeltaE strips %d#rightarrow%d [a.u.];norm. "
2770 "#DeltaE strips %d#rightarrow%d [a.u.]",
2774 h->SetDirectory(
nullptr);
2776 m_scatter[reac] = h;
2780void StripSumScatter::ReprojectFromReservoir() {
2781 const Int_t kReacMin =
2783 const Int_t kReacMax =
2785 Long64_t nFilled = 0;
2786 for (Int_t k = 0; k < Int_t(m_reservoir.size()); k++) {
2787 const TraceEvt &e = m_reservoir[k];
2792 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2793 if (!(e.
reac_mask & (1u << ReacIndex(reac))))
2795 Double_t x = 0.0, y = 0.0;
2797 m_scatter[reac]->Fill(x, y);
2801 std::cout <<
"strip-sum-scatter: re-projected " << nFilled
2802 <<
" tagged entries." << std::endl;
2807void StripSumScatter::FitGateRun(Int_t i, std::vector<SingleRunFitResult> &fits,
2808 const std::vector<Int_t> &runOrder,
2809 const std::vector<TString> &labelVec,
2810 const std::vector<TChain *> &chainVec) {
2812 fits[i] = FitRunGates(runOrder[i], labelVec[i], chainVec[i]);
2817void StripSumScatter::MergeRunFill(Int_t t,
2818 std::vector<SingleRunFillResult> &fills,
2819 Int_t &nBeamKept, Long64_t &totalGated,
2820 Long64_t &totalSeen) {
2821 const Int_t kReacMin =
2823 const Int_t kReacMax =
2825 const Int_t kBeamReservoirCap =
2827 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
2828 Int_t ri = ReacIndex(reac);
2829 if (ri < Int_t(fills[t].scatters.size()) && fills[t].scatters[ri])
2830 m_scatter[reac]->Add(fills[t].scatters[ri]);
2832 for (Int_t k = 0; k < Int_t(fills[t].reservoir.size()); k++) {
2833 const TraceEvt &e = fills[t].reservoir[k];
2835 if (nBeamKept >= kBeamReservoirCap)
2839 m_reservoir.push_back(e);
2841 totalGated += fills[t].gated;
2842 totalSeen += fills[t].seen;
2843 m_nNormed += fills[t].normed;
2844 for (Int_t k = 0; k < Int_t(fills[t].normed_at.size()); k++)
2845 m_normedAt[k] += fills[t].normed_at[k];
2846 for (Int_t k = 0; k < Int_t(fills[t].tagged.size()); k++)
2847 m_tagged[k] += fills[t].tagged[k];
2848 if (m_taggedVar.size() == fills[t].tagged_var.size())
2849 for (
size_t v = 0; v < m_taggedVar.size(); v++)
2850 for (Int_t k = 0; k < Int_t(fills[t].tagged_var[v].size()); k++) {
2851 m_taggedVar[v][k] += fills[t].tagged_var[v][k];
2852 m_normedVar[v][k] += fills[t].normed_var[v][k];
2854 for (Int_t k = 0; k < Int_t(fills[t].cut_counts.size()); k++)
2855 m_cutCounts[k] += fills[t].cut_counts[k];
2856 for (Int_t k = 0; k < Int_t(fills[t].pre_counts.size()); k++)
2857 m_preCounts[k] += fills[t].pre_counts[k];
2858 for (Int_t k = 0; k < Int_t(fills[t].scatters.size()); k++)
2859 delete fills[t].scatters[k];
2860 fills[t].scatters.clear();
2861 std::vector<TraceEvt>().swap(fills[t].reservoir);
2866void StripSumScatter::FillScatterFile(
2867 Int_t t,
const std::vector<FillTask> &tasks,
2868 const std::vector<Int_t> &runOrder,
const std::vector<TString> &labelVec,
2869 const std::vector<SingleRunFitResult> &fits, FillPhase &phase) {
2870 const Int_t i = tasks[t].run_idx;
2874 TChain ch(
"events");
2875 ch.Add(tasks[t].path);
2876 if (ch.GetEntries() > 0)
2877 phase.fills[t] = FillRunScatters(runOrder[i], labelVec[i], &ch,
2878 fits[i].gate, fits[i].pure_beam);
2880 std::lock_guard<std::mutex> lk(phase.merge_mutex);
2881 phase.filled[t] = kTRUE;
2882 const Int_t nTasks = Int_t(tasks.size());
2883 while (phase.next_merge < nTasks && phase.filled[phase.next_merge]) {
2884 MergeRunFill(phase.next_merge, phase.fills, phase.nBeamKept,
2885 phase.totalGated, phase.totalSeen);
2891 const std::vector<Int_t> &runOrder = groups.
order;
2896 const std::vector<std::pair<TString, TagThresholds>> variants =
2898 m_variantNames.clear();
2899 m_taggedVar.assign(variants.size(),
2900 std::vector<Long64_t>(m_tagged.size(), 0));
2901 m_normedVar.assign(variants.size(),
2902 std::vector<Long64_t>(m_tagged.size(), 0));
2903 for (
size_t v = 0; v < variants.size(); v++)
2904 m_variantNames.push_back(variants[v].first);
2909 const Int_t nRuns = Int_t(runOrder.size());
2910 std::vector<TChain *> chainVec(nRuns);
2911 std::vector<TString> labelVec(nRuns);
2912 for (Int_t i = 0; i < nRuns; i++) {
2913 chainVec[i] = groups.
chain.find(runOrder[i])->second;
2914 labelVec[i] = groups.
label.find(runOrder[i])->second;
2918 TMath::Min(Int_t(std::thread::hardware_concurrency()), nRuns);
2919 n_workers = TMath::Min(
2920 n_workers,
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.MAX_STRIP_SUM_WORKERS);
2923 std::cout <<
"strip-sum-scatter: " << nRuns <<
" gate groups on " << n_workers
2924 <<
" workers" << std::endl;
2927 std::vector<SingleRunFitResult> fits(nRuns);
2928 RunIndexedParallel(nRuns, n_workers, [&](Int_t i) {
2929 FitGateRun(i, fits, runOrder, labelVec, chainVec);
2934 std::vector<FillTask> tasks;
2936 std::map<Int_t, Int_t> idx_of_run;
2937 for (Int_t i = 0; i < nRuns; i++)
2938 idx_of_run[runOrder[i]] = i;
2940 for (Int_t k = 0; k < Int_t(specs.size()); k++) {
2942 std::map<TString, Int_t>::const_iterator kit =
2944 if (kit == groups.
key_of.end())
2946 std::map<Int_t, Int_t>::const_iterator it = idx_of_run.find(kit->second);
2947 if (it == idx_of_run.end() || !fits[it->second].ok)
2949 TString full = IO::GetRootFilesBaseDir() +
"/" +
2951 if (gSystem->AccessPathName(full))
2954 t.run_idx = it->second;
2959 Int_t nTasks = Int_t(tasks.size());
2960 Int_t fill_workers =
2961 TMath::Min(Int_t(std::thread::hardware_concurrency()), nTasks);
2963 TMath::Min(fill_workers,
2965 if (fill_workers < 1)
2967 std::cout <<
"strip-sum-scatter: filling " << nTasks <<
" files on "
2968 << fill_workers <<
" workers" << std::endl;
2973 phase.fills.resize(nTasks);
2974 phase.filled.assign(nTasks, kFALSE);
2975 RunIndexedParallel(nTasks, fill_workers, [&](Int_t t) {
2976 FillScatterFile(t, tasks, runOrder, labelVec, fits, phase);
2978 m_nSeen = phase.totalSeen;
2979 std::cout <<
"strip-sum-scatter: " << phase.totalGated
2980 <<
" reaction-tagged of " << phase.totalSeen <<
" events ("
2981 << m_nNormed <<
" past every pre-tag cut); reservoir "
2982 << m_reservoir.size() << std::endl;
2991void StripSumScatter::WriteCutReport()
const {
3000 pre_active[c] = kTRUE;
3002 for (
size_t i = 0; i < steps.size(); i++) {
3003 if (steps[i].tag_cut >= 0)
3004 active[steps[i].tag_cut] = steps[i].on;
3005 if (steps[i].pre_cut >= 0)
3006 pre_active[steps[i].pre_cut] = steps[i].on;
3009 std::ostringstream out;
3010 out << Form(
"strip-sum-scatter tag cuts: %s, %lld events seen",
3013 out <<
"Sequential counts: each condition counts the events that passed "
3014 "everything before it."
3017 out <<
"Event-level cuts (before any reaction is asked about):" << std::endl;
3020 out << Form(
" %-14s off",
kPreCutName[c]) << std::endl;
3022 out << Form(
" %-14s %12lld (%6.2f%% of seen)",
kPreCutName[c],
3024 m_nSeen > 0 ? 100.0 * m_preCounts[c] / m_nSeen : 0.0)
3029 m_nSeen > 0 ? 100.0 * m_preCounts[
kPRE_PASS] / m_nSeen : 0.0)
3033 out <<
"Tag conditions per reaction strip (events past the event-level "
3034 "cuts; % of those):"
3040 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
3041 const Long64_t *row = &m_cutCounts[ReacIndex(reac) *
kNTAGCUTS];
3045 out << Form(
"%4d", reac);
3048 out << Form(
" | %13s",
"off");
3050 out << Form(
" | %13s", Form(
"%lld (%.2f%%)", row[c],
3051 total > 0 ? 100.0 * row[c] / total : 0.0));
3053 out << Form(
" | %13s",
3055 total > 0 ? 100.0 * row[
kTAG_PASS] / total : 0.0))
3058 std::cout << out.str();
3062 if (!m_variantNames.empty()) {
3064 out <<
"Cut variation (tagged events per strip with one threshold "
3065 "shifted; nominal first):"
3067 out <<
"reac | nominal";
3068 for (
size_t v = 0; v < m_variantNames.size(); v++)
3069 out << Form(
" | %9s", m_variantNames[v].Data());
3071 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
3072 out << Form(
"%4d | %13lld", reac, m_tagged[ReacIndex(reac)]);
3073 for (
size_t v = 0; v < m_variantNames.size(); v++)
3074 out << Form(
" | %9lld", m_taggedVar[v][ReacIndex(reac)]);
3080 gSystem->mkdir(dir, kTRUE);
3081 const TString path = dir +
"/tag_cuts.txt";
3082 std::ofstream f(path.Data());
3084 std::cerr <<
"strip-sum-scatter: cannot write " << path << std::endl;
3089 std::cout <<
"strip-sum-scatter: tag-cut report written to " << path
3093void StripSumScatter::PlotScatters() {
3096 YBounds(m_yLo, m_yHi);
3099 const Int_t kReacMin =
3101 const Int_t kReacMax =
3105 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
3106 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
3109 Int_t ri = ReacIndex(reac);
3110 m_scatter[reac]->GetXaxis()->SetRangeUser(
3113 m_scatter[reac]->GetYaxis()->SetRangeUser(m_yLo[ri], m_yHi[ri]);
3114 PlottingUtils::ConfigureAndDraw2DHistogram(m_scatter[reac], c);
3115 m_scatter[reac]->GetYaxis()->SetTitleOffset(1.3);
3116 c->SetLeftMargin(0.18);
3117 PlottingUtils::SaveFigure(c,
3118 Form(
"normsumE_reac%d_s%d_%d_vs_s%d_%d", reac,
3120 "strip_sum_scatter", PlotSaveOptions::kLINEAR);
3125void StripSumScatter::InteractiveOverlay(Int_t reac) {
3126 const Int_t kReacMin =
3128 const Int_t kReacMax =
3130 const Int_t kTracesPerRegion =
3133 if (reac < kReacMin || reac > kReacMax) {
3134 std::cerr <<
"strip-sum-scatter: candidate reaction strip " << reac
3135 <<
" outside [" << kReacMin <<
"," << kReacMax
3136 <<
"]; skipping interactive overlay." << std::endl;
3141 TCutG *cutAn =
nullptr;
3142 TCutG *cutAa =
nullptr;
3145 if (!
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.REGION_CUT_REDRAW) {
3146 cutAn = LoadRegionCut(
"region_an", reac);
3147 cutAa = LoadRegionCut(
"region_aa", reac);
3149 TCanvas *cutCanvas =
nullptr;
3153 static Int_t app_argc = 1;
3154 static char app_arg0[] =
"strip-sum-scatter";
3155 static char *app_argv[] = {app_arg0};
3157 if (cutAn && cutAa) {
3158 std::cout <<
" [region] loaded saved cuts for reac " << reac << std::endl;
3164 if (!gSystem->Getenv(
"DISPLAY")) {
3165 std::cerr <<
"strip-sum-scatter: no saved region cuts for reac " << reac
3166 <<
" and no DISPLAY to draw them; skipping interactive "
3167 "region-trace overlay (scatters already saved)."
3172 new TApplication(
"strip-sum-scatter", &app_argc, app_argv);
3173 gROOT->SetBatch(kFALSE);
3175 cutCanvas =
new TCanvas(
"c_strip_sum_regions",
3176 "Draw (a,n) then (a,a') regions", 900, 700);
3177 cutCanvas->SetLogz(kTRUE);
3178 m_scatter[reac]->Draw(
"COLZ");
3179 cutCanvas->Update();
3180 cutAn = PromptCut(cutCanvas,
"region_an",
"(a,n)");
3181 cutAa = PromptCut(cutCanvas,
"region_aa",
"(a,a')");
3182 SaveRegionCuts(reac, cutAn, cutAa);
3184 cutCanvas->GetListOfPrimitives()->Remove(cutAn);
3185 cutCanvas->GetListOfPrimitives()->Remove(cutAa);
3186 gROOT->SetEditorMode();
3187 gSystem->ProcessEvents();
3191 gSystem->ProcessEvents();
3194 std::vector<TGraph *> tr_an, tr_aa, tr_beam;
3197 std::vector<TGraph *> tr_an_adc, tr_aa_adc, tr_beam_adc;
3200 const Bool_t kSkipSg =
3202 std::vector<TGraph *> tr_an_sg, tr_aa_sg, tr_beam_sg;
3203 UInt_t bit = (1u << ReacIndex(reac));
3205 for (Int_t k = 0; k < Int_t(m_reservoir.size()); k++) {
3206 if (Int_t(tr_an.size()) >= kTracesPerRegion &&
3207 Int_t(tr_aa.size()) >= kTracesPerRegion &&
3208 Int_t(tr_beam.size()) >= kTracesPerRegion)
3210 const TraceEvt &e = m_reservoir[k];
3211 Double_t td[18], td_adc[18];
3214 if (e.
beam_flat && Int_t(tr_beam.size()) < kTracesPerRegion) {
3215 tr_beam.push_back(TraceFromTotal(td));
3216 tr_beam_adc.push_back(TraceFromTotal(td_adc));
3218 tr_beam_sg.push_back(SmoothedTraceFromTotal(td));
3223 Double_t x = 0.0, y = 0.0;
3225 if (cutAn && Int_t(tr_an.size()) < kTracesPerRegion &&
3226 cutAn->IsInside(x, y)) {
3227 tr_an.push_back(TraceFromTotal(td));
3228 tr_an_adc.push_back(TraceFromTotal(td_adc));
3230 tr_an_sg.push_back(SmoothedTraceFromTotal(td));
3231 }
else if (cutAa && Int_t(tr_aa.size()) < kTracesPerRegion &&
3232 cutAa->IsInside(x, y)) {
3233 tr_aa.push_back(TraceFromTotal(td));
3234 tr_aa_adc.push_back(TraceFromTotal(td_adc));
3236 tr_aa_sg.push_back(SmoothedTraceFromTotal(td));
3240 std::cout <<
"Sampled traces: beam=" << tr_beam.size()
3241 <<
" (a,a')=" << tr_aa.size() <<
" (a,n)=" << tr_an.size()
3243 DrawRegionTraces(Form(
"region_traces_reac%d", reac),
"strip_sum_scatter",
3244 tr_beam, tr_aa, tr_an, 0.6, 1.6,
"#DeltaE [a.u.]");
3245 const Bool_t kMeanTraces =
3248 DrawRegionMeanTraces(Form(
"region_mean_traces_reac%d", reac),
3249 "strip_sum_scatter", tr_beam, tr_aa, tr_an, 0.6, 1.6,
3252 Double_t adc_y_lo = 0.0, adc_y_hi = 0.0;
3253 TraceYRange(tr_beam_adc, tr_aa_adc, tr_an_adc, adc_y_lo, adc_y_hi);
3254 DrawRegionTraces(Form(
"region_traces_reac%d_adc", reac),
3255 "strip_sum_scatter", tr_beam_adc, tr_aa_adc, tr_an_adc,
3256 adc_y_lo, adc_y_hi,
"#DeltaE [ADC]");
3258 DrawRegionMeanTraces(Form(
"region_mean_traces_reac%d_adc", reac),
3259 "strip_sum_scatter", tr_beam_adc, tr_aa_adc,
3260 tr_an_adc, adc_y_lo, adc_y_hi,
"#DeltaE [ADC]");
3263 DrawRegionTraces(Form(
"region_traces_reac%d_sg", reac),
"strip_sum_scatter",
3264 tr_beam_sg, tr_aa_sg, tr_an_sg, 0.6, 1.6,
"#DeltaE [a.u.]",
3267 DrawRegionMeanTraces(Form(
"region_mean_traces_reac%d_sg", reac),
3268 "strip_sum_scatter", tr_beam_sg, tr_aa_sg, tr_an_sg,
3269 0.7, 1.3,
"#DeltaE [a.u.]");
3272 for (Int_t i = 0; i < Int_t(tr_an.size()); i++)
3274 for (Int_t i = 0; i < Int_t(tr_aa.size()); i++)
3276 for (Int_t i = 0; i < Int_t(tr_beam.size()); i++)
3278 for (Int_t i = 0; i < Int_t(tr_an_adc.size()); i++)
3279 delete tr_an_adc[i];
3280 for (Int_t i = 0; i < Int_t(tr_aa_adc.size()); i++)
3281 delete tr_aa_adc[i];
3282 for (Int_t i = 0; i < Int_t(tr_beam_adc.size()); i++)
3283 delete tr_beam_adc[i];
3284 for (Int_t i = 0; i < Int_t(tr_an_sg.size()); i++)
3286 for (Int_t i = 0; i < Int_t(tr_aa_sg.size()); i++)
3288 for (Int_t i = 0; i < Int_t(tr_beam_sg.size()); i++)
3289 delete tr_beam_sg[i];
3297 ROOT::EnableThreadSafety();
3298 InitUtils::SetROOTPreferences(PlotSaveFormat::kPNG,
3301 gROOT->SetBatch(kTRUE);
3310 " event selection");
3315 const std::vector<Int_t> &run_order = groups.
order;
3316 std::map<Int_t, TChain *> &chain_by_run = groups.
chain;
3317 if (run_order.empty()) {
3318 std::cerr <<
"strip-sum-scatter: no runs found" << std::endl;
3321 const TString first_label = groups.
label[run_order[0]];
3325 Double_t strip_mean[18], strip_sigma[18];
3329 FitRunGates(run_order[0], first_label, chain_by_run[run_order[0]]);
3331 !MeasureBeamNoise(chain_by_run[run_order[0]], first.
pure_beam,
3332 strip_mean, strip_sigma)) {
3333 std::cerr <<
"strip-sum-scatter: cannot measure the beam on "
3334 << first_label << std::endl;
3335 for (Int_t i = 0; i < Int_t(run_order.size()); i++)
3336 delete chain_by_run[run_order[i]];
3342 const Int_t kReacMin =
3344 const Int_t kReacMax =
3346 TString line = Form(
"strip-sum-scatter: beam mean (sigma) from the gated "
3348 first_label.Data());
3349 for (Int_t strip = 1; strip <= 17; strip++)
3350 line += Form(
" s%d %.4f (%.4f)", strip, strip_mean[strip],
3351 strip_sigma[strip]);
3352 std::cout << line << std::endl;
3353 std::cout << Form(
"strip-sum-scatter: jump gate %.2f sigma -> %.4f at "
3354 "strip %d, %.4f at strip %d",
3361 TString fingerprint = BuildFingerprint(groups);
3364 Bool_t loaded = TryLoadCache(cache_name, fingerprint);
3367 FillScatters(groups);
3368 WriteCache(cache_name, fingerprint);
3376 for (Int_t i = 0; i < Int_t(run_order.size()); i++)
3377 delete chain_by_run[run_order[i]];
3393 Int_t reac =
Constants::cfg.STRIP_SUM_SCATTER_CONFIG.CANDIDATE_REAC_STRIP;
3394 InteractiveOverlay(reac);
3398 const Int_t kReacMin =
3400 const Int_t kReacMax =
3402 const Int_t kTracesPerRegion =
3404 const Bool_t kMeanTraces =
3408 const Bool_t kSkipSg =
3410 const std::vector<TGraph *> none;
3413 std::vector<TGraph *> tr_beam, tr_beam_adc, tr_beam_sg;
3414 for (Int_t k = 0; k < Int_t(m_reservoir.size()) &&
3415 Int_t(tr_beam.size()) < kTracesPerRegion;
3417 const TraceEvt &e = m_reservoir[k];
3420 Double_t td[18], td_adc[18];
3423 tr_beam.push_back(TraceFromTotal(td));
3424 tr_beam_adc.push_back(TraceFromTotal(td_adc));
3426 tr_beam_sg.push_back(SmoothedTraceFromTotal(td));
3429 for (Int_t reac = kReacMin; reac <= kReacMax; reac++) {
3430 const UInt_t bit = (1u << ReacIndex(reac));
3431 std::vector<TGraph *> tr_tag, tr_tag_adc, tr_tag_sg;
3434 for (Int_t k = 0; k < Int_t(m_reservoir.size()); k++) {
3435 const TraceEvt &e = m_reservoir[k];
3438 Double_t td[18], td_adc[18];
3441 tr_tag.push_back(TraceFromTotal(td));
3442 tr_tag_adc.push_back(TraceFromTotal(td_adc));
3444 tr_tag_sg.push_back(SmoothedTraceFromTotal(td));
3446 std::cout <<
" reac " << reac <<
": " << tr_tag.size()
3447 <<
" tagged traces drawn against " << tr_beam.size()
3448 <<
" beam traces" << std::endl;
3449 DrawRegionTraces(Form(
"all_tagged_traces_reac%d", reac), subdir, tr_beam,
3450 none, tr_tag, 0.6, 1.6,
"#DeltaE [a.u.]", kTRUE,
"Tagged");
3452 DrawRegionMeanTraces(Form(
"all_tagged_mean_traces_reac%d", reac), subdir,
3453 tr_beam, none, tr_tag, 0.6, 1.6,
"#DeltaE [a.u.]");
3455 Double_t adc_y_lo = 0.0, adc_y_hi = 0.0;
3456 TraceYRange(tr_beam_adc, none, tr_tag_adc, adc_y_lo, adc_y_hi);
3457 DrawRegionTraces(Form(
"all_tagged_traces_reac%d_adc", reac), subdir,
3458 tr_beam_adc, none, tr_tag_adc, adc_y_lo, adc_y_hi,
3459 "#DeltaE [ADC]", kTRUE,
"Tagged");
3461 DrawRegionMeanTraces(Form(
"all_tagged_mean_traces_reac%d_adc", reac),
3462 subdir, tr_beam_adc, none, tr_tag_adc, adc_y_lo,
3463 adc_y_hi,
"#DeltaE [ADC]");
3466 DrawRegionTraces(Form(
"all_tagged_traces_reac%d_sg", reac), subdir,
3467 tr_beam_sg, none, tr_tag_sg, 0.6, 1.6,
"#DeltaE [a.u.]",
3470 DrawRegionMeanTraces(Form(
"all_tagged_mean_traces_reac%d_sg", reac),
3471 subdir, tr_beam_sg, none, tr_tag_sg, 0.7, 1.3,
3474 for (Int_t i = 0; i < Int_t(tr_tag.size()); i++)
3476 for (Int_t i = 0; i < Int_t(tr_tag_adc.size()); i++)
3477 delete tr_tag_adc[i];
3478 for (Int_t i = 0; i < Int_t(tr_tag_sg.size()); i++)
3479 delete tr_tag_sg[i];
3481 for (Int_t i = 0; i < Int_t(tr_beam.size()); i++)
3483 for (Int_t i = 0; i < Int_t(tr_beam_adc.size()); i++)
3484 delete tr_beam_adc[i];
3485 for (Int_t i = 0; i < Int_t(tr_beam_sg.size()); i++)
3486 delete tr_beam_sg[i];
const Int_t GATE_AXIS_GRID
Options which govern the reaction search in the 2D histograms (strip-sum-scatter).
std::mutex g_plot_mutex
Serialises all plotting and canvas work.
std::mutex g_log_mutex
Serialises multi-line progress logging from worker threads.
Block diagram of the event selection, generated from the configuration.
The reaction search: strip-sum scatters, beam gating and tagging.
TagCut
The conditions of the reaction tag, in the order they are applied.
@ kCUT_CLIFF
The fall happened in the last step (TAIL_CLIFF_*).
@ kCUT_UPSTREAM
A strip before the reaction was not beam-like.
@ kCUT_TAIL_RISE
A rise in the tail (TAIL_RISE_NSIGMA).
@ kCUT_CROSS
Read below the beam before POST_CROSS_MIN_STRIP.
@ kCUT_RERISE
Back at the beam, then above it again (TAIL_RERISE_*).
@ kCUT_POST_ABOVE
The excess did not persist (POST_ABOVE_*).
@ kCUT_END_STRIP
The end strip not END_STRIP_NSIGMA below the beam.
@ kCUT_JUMP
Jump at the reaction strip below the gate.
@ kCUT_OTHER_TAG
Passed, but the event's one tag went to another strip.
@ kCUT_REAC_LEVEL
Reaction-strip deposit below 1 + the gate.
@ kPRE_ALL_STRIPS
A strip did not fire.
@ kPRE_BOTH_MULT
Both-ends multiplicity (BOTH_MULT_MAX).
@ kPRE_SMOOTH
A strip-to-strip step above SMOOTHNESS_NSIGMA.
@ kPRE_GATE
Failed a beam gate.
const char *const kPreCutName[kNPRECUTS]
Short labels for PreCut, indexed by it.
const char *const kTagCutName[kNTAGCUTS]
Short labels for TagCut, indexed by it.
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 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,...
StripSumScatterConfig STRIP_SUM_SCATTER_CONFIG
Bool_t IGNORE_STRIP_0
Drop strip 0 / strip 17 from the analysis altogether: not required for a complete event,...
static TGraph * BuildTraceFromTotals(const Double_t *total)
Build a trace graph from one event's per-strip totals.
static TString EventsName(const FileSpec &s)
Filename of the built-events ROOT file for a subfile.
static GateGroups GroupEventsForGating()
Build the gate groups; see GateGroups.
static std::vector< FileSpec > BuildProcessedFileSpecs()
Every subfile that already has processed output.
static Long64_t SampleStride(Long64_t n_total, Long64_t max_points)
Stride that visits at most max_points of n_total entries.
static TString DatasetName()
The dataset's isotope name, e.g.
static TString DatasetDir()
Absolute path to the active dataset directory, analysis/<iso>.
static TString ResultsDir()
Absolute path to the directory receiving generated output.
static TString SimRootPath(const SimFileSpec &s)
Absolute path to a simulation's ROOT file.
static Int_t ReactionStripOf(const TString &tag)
Which strip a simulated reaction occurs on.
static TString TagWithoutStrip(const TString &tag)
The tag with any trailing _s<N> reaction-strip token removed.
static std::vector< SimFileSpec > BuildFileSpecs()
Every simulation this dataset defines.
static TString CacheName()
Filename of the scatter cache for this configuration.
static Bool_t IsNoise(const EnergyView &ev)
static Int_t YLoOf(Int_t reac)
First strip of the post-trigger window summed onto y.
static Int_t YHiOf(Int_t reac)
Last strip of the post-trigger window, inclusive.
static TagThresholds NominalThresholds()
The thresholds the configuration sets.
static void SetStripNoise(const Double_t *mean, const Double_t *sigma)
Install the per-strip beam means and sigmas.
static Bool_t IsPileup(const EnergyView &ev)
The event-level pileup and noise cuts (PILEUP_* / NOISE_*), in sigma of the measured beam spread.
static Bool_t IsSmooth(const EnergyView &ev, Double_t nsigma)
The event-level smoothness cut: MaxStepNSigma() at or under nsigma, or the cut is off (nsigma <= 0).
static Double_t JumpMin(Int_t reac)
Minimum jump for a tag: REAC_JUMP_NSIGMA * StripSigma(reac).
static Double_t StripSigma(Int_t strip)
Width of the beam's deposit on a strip, from the gated beam sample of the first run (MeasureBeamNoise...
void Run()
Build or load the scatters, tag reactions, and draw everything.
static std::vector< SelectionStep > DescribeSelection()
The whole selection as the configuration sets it, in order.
static TagCut TailReason(const EnergyView &ev, Int_t reac, const TagThresholds &T)
The tail-shape part of RejectReason: kTAG_PASS or the first failing tail condition,...
void DrawAllTaggedTraces(const TString &subdir)
Region-trace overlays of every tagged event, one figure per reaction strip, against the beam band.
StripSumScatter()
Construct with empty scatters and no cache loaded.
static Int_t ResolveTag(const EnergyView &ev, const std::vector< Bool_t > &pass)
The one strip an event is tagged at, among those whose tag passed (pass[ReacIndex]),...
~StripSumScatter()
Frees the scatters and the reservoir.
static Bool_t Condition(TagCut c, const EnergyView &ev, Int_t reac, const TagThresholds &T)
One tag condition on its own: whether c passes for reac under T, true where it does not apply at that...
static Bool_t ConditionActive(TagCut c, const TagThresholds &T)
Whether the configuration has condition c in force.
static TagCut RejectReason(const EnergyView &ev, Int_t reac)
Which condition of the tag an event fails first at a strip.
Bool_t Prepare()
Measure the beam, then load the scatter cache or build it.
static Double_t MaxStepNSigma(const EnergyView &ev)
The largest strip-to-strip step of the trace, |E(s) - E(s-1)| over strips 2 to the last in sigma of s...
static Double_t StripMean(Int_t strip)
Mean of the beam's deposit on a strip over the same sample; the level every cut measures from.
static void PlaneXY(const Double_t *total, Int_t reac, Double_t &x, Double_t &y)
Where an event sits in the scatter plane for a given reaction strip.
void SimTagReport()
Run the data selection over every simulated population: the event-level cuts (all but the beam gate,...
static std::vector< std::pair< TString, TagThresholds > > ThresholdVariants()
The cut-variation set: each active threshold shifted up and down by its configured step (CUT_VARIATIO...
const RunEpoch * GetActiveEpoch()
The currently active epoch, or null when none is set.
Bool_t ActiveIgnoreShortStrips()
Whether the decode keeps the long end only: the active epoch's setting; with none active,...
Bool_t SavePlots()
FileInSample(), by the name the plot call sites use.
Bool_t InPlotSample(Int_t k)
Whether the k-th file (0-based, in file order) of an epoch's list is in the plot sample.
std::ostream & Detail()
std::cout for a file in the sample, a stream that discards otherwise: the per-file detail lines (per ...
const TString & ActiveFileTag()
Output-name prefix of the active epoch.
const DatasetConfig & cfg
The active dataset's configuration, flat block.
void SetPlotsThisFile(Bool_t on)
Mark the file this thread is about to process as in (or out of) the plot sample.
Bool_t ActiveUseSolarisData()
Whether this era's data is SOLARIS rather than CoMPASS.
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.
TCutG * Load(const char *name, Int_t reac)
Load a cut from its per-cut file.
const Double_t kXMin
Lower x bound of the build window.
const Double_t kXMax
Upper x bound; x sums 16 strips.
const Double_t kYMin
Lower y bound.
const Double_t kYMax
Upper y bound; y sums the post-trigger strips only.
void Write(const std::vector< SelectionStep > &steps, const TString &dir, const TString &title)
Write selection.dot and selection.mmd under dir, and render the DOT to selection.png and selection....
The classification ellipses defining a pure-beam event.
BeamFit2D s15_s16
Alternative exit ellipse.
BeamFit2D s1_grid
Alternative entrance ellipse on strip 1 and the grid.
BeamFit2D s0_s1
Entrance ellipse on strips 0 and 1.
Bool_t ok
Whether the fits succeeded.
Bool_t use_s15_s16
Which exit ellipse is in force.
BeamFit2D s16_s17
Exit ellipse on strips 16 and 17.
BeamFit2D s1_s2
Alternative entrance ellipse, per PURE_BEAM_GATE.
A fitted 2-D Gaussian beam spot.
Double_t rho
Correlation coefficient, in [-1, 1].
Double_t sigma_y
Widths along each axis.
Bool_t ok
Whether the fit converged.
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.
The event-level gate: one strip's fitted beam peak and width.
A view over one event's energies, decoding raw ADC into calibrated units.
UShort_t rightdE_adc[16]
Right end of strips 1-16, index strip - 1.
Double_t strip17
Strip 17.
void Decode()
Decode the currently loaded entry into the value members.
Bool_t Attach(TTree *t)
Bind to an events tree and set up the branch addresses.
Double_t Total(Int_t strip) const
A strip's deposit: the sum of its ends, or the unsegmented value.
Double_t left[16]
Left end of strips 1-16, index strip - 1.
Double_t Axis(Int_t axis) const
The value on a beam-gate axis: a strip's deposit, or the grid (GATE_AXIS_GRID) over its anchor.
void Totals(Double_t *out) const
Every strip's deposit at once, for code that wants an array.
UShort_t leftdE_adc[16]
Left end of strips 1-16, index strip - 1.
UShort_t strip17_adc
Strip 17, unsegmented.
UShort_t strip0_adc
Strip 0, unsegmented.
Double_t right[16]
Right end of strips 1-16, index strip - 1.
The events files grouped into the units the beam gates are fitted on.
std::map< Int_t, TChain * > chain
Chain per key. Caller owns..
std::map< TString, Int_t > key_of
Group key per EventsName().
std::map< Int_t, TString > label
Label per key, for logs and plots.
std::vector< Int_t > order
Group keys in processing order.
Double_t weight
Total weight included; zero means the range held nothing above threshold.
One entry of a simulation's events_MeV tree.
Double_t Left(Int_t s) const
Left end of strip s (1-16), or the whole of strip 0 or 17.
Float_t strip17
Strip 17, unsegmented.
Double_t Total(Int_t s) const
The strip's deposit, Left(s) + Right(s).
Bool_t Attach(TTree *t)
Bind to an events_MeV tree and set up the branch addresses.
Float_t strip0
Strip 0, unsegmented.
Double_t Right(Int_t s) const
Right end of strip s (1-16); zero for strips 0 and 17.
One step of the event selection, as StripSumScatter::DescribeSelection lists them: in the order the c...
Int_t tag_cut
The TagCut it counts under, or -1.
TString id
Node identifier, [a-z0-9_].
Bool_t on
False when the configuration switches the step off.
Stage
Where in the selection the step sits.
Int_t pre_cut
The PreCut it counts under, or -1.
TString detail
One line: the condition to pass, with the numbers in.
TString name
Short name, as in the cut report.
TString label
Legend label.
TString file
Simulation ROOT file.
One run's filled scatters, reservoir and normalisation counts.
std::vector< Long64_t > normed_at
Per-strip denominator: beam particles incident on that strip.
std::vector< std::vector< Long64_t > > tagged_var
Events tagged under each threshold variant, [variant][ReacIndex], in the order of StripSumScatter::Th...
Long64_t seen
Events examined.
Long64_t normed
Events surviving every cut applied before reaction tagging: the beam gates, the pileup,...
std::vector< Long64_t > cut_counts
Sequential per-condition counts, [ReacIndex(reac) * kNTAGCUTS + cut], for the tag-cut report.
Long64_t gated
Events passing the beam gates.
std::vector< Long64_t > tagged
Events tagged at each reaction strip, indexed the same way.
std::vector< Long64_t > pre_counts
Sequential event-level counts, indexed by PreCut.
std::vector< std::vector< Long64_t > > normed_var
The per-strip denominator under each variant, indexed the same way: a variant of the beam selection m...
std::vector< TH2F * > scatters
Private clones, one per reaction strip.
std::vector< TraceEvt > reservoir
Tagged events from this run.
One run's fitted beam gates.
Bool_t ok
Whether the fits succeeded.
BeamGate1D gate
The strip gate.
BeamEllipses pure_beam
Entrance and exit ellipses.
Long64_t SAMPLE_MAX_POINTS
Double_t CUT_VARIATION_CLIFF_STEP
Double_t SMOOTHNESS_NSIGMA
Event-level smoothness: every strip-to-strip step of the trace, from strips 1-2 to the last pair,...
Double_t PURE_BEAM_NSIGMA
Mahalanobis level of the pure-beam entrance and exit ellipses; separate from GATE_NSIGMA so the beam ...
Double_t TAIL_RETURN_NSIGMA
After the post-window peak, once the trace has come back down to within TAIL_RETURN_NSIGMA x StripSig...
AnRegionMode AN_REGION_MODE
Int_t TAIL_FALL_FROM_STRIP
From TAIL_FALL_FROM_STRIP to the last strip, allow no strip-to-strip rise above TAIL_RISE_NSIGMA x St...
Int_t POST_CROSS_MIN_STRIP
The trace may not read below the beam mean before this strip: strips reac+1 .
Int_t POST_WINDOW_LAST_STRIP
Int_t POST_TRIGGER_SUM_STRIPS
Number of strips summed onto the scatter y-axis after the trigger strip: y spans reac+1 .
Bool_t REQUIRE_STRIP_16_BELOW_BEAM
Bool_t SKIP_SAVGOL_PLOTS
Leave out the Savitzky-Golay-smoothed copies of the trace overlays (the _sg figures and cluster-varia...
@ TAG_RESOLVE_FIRST_STRIP
Double_t REAC_JUMP_NSIGMA
Minimum jump at the reaction strip for a tag, in sigma of the measured beam spread of that strip (Str...
Bool_t PLOT_REGION_MEAN_TRACES
Also draw the per-region mean traces with RMS bands (the region_mean_traces_* figures) next to the tr...
Bool_t REQUIRE_BEAM_UPSTREAM_OF_REAC
How close to require strips to be to beam prior to the reaction, in sigma of each strip's measured be...
Double_t TAIL_CLIFF_MAX_FRACTION
A residue stops gradually; the beam nucleus after a large-angle elastic scatter keeps its excess to t...
Double_t END_STRIP_NSIGMA
The end strip (17, or 16 with REQUIRE_STRIP_16_BELOW_BEAM or IGNORE_STRIP_17) must read below the bea...
Double_t POST_ABOVE_NSIGMA
Every strip from reac+1 to reac+ POST_ABOVE_STRIPS (capped at the last strip) must sit more than POST...
Double_t GATE_CENTER
The peak to fit, in beam units; zero lets the fit find it.
Double_t TAIL_RERISE_NSIGMA
Double_t AN_REGION_NSIGMA
compute-regions: the (a,n) region is the reaction component's AN_REGION_NSIGMA Mahalanobis ellipse fr...
Int_t GATE_STRIP
The event-level beam gate: one strip, within GATE_NSIGMA of its fitted beam peak per gate group.
Bool_t CUT_VARIATION
Cut-variation systematic, after the published 87Rb analysis: every condition that selects the beam or...
Double_t BEAM_UPSTREAM_NSIGMA
Double_t CUT_VARIATION_NSIGMA_STEP
Bool_t Y_RATIO_TO_UPSTREAM
Normalize the partial dE sum on y axis by the event's own mean deposit over strips 1 .
std::map< Int_t, std::pair< Double_t, Double_t > > Y_DISPLAY_RANGE
Per-reaction-strip y-axis display windows, overriding Y_DISPLAY_MIN/MAX for individual strips (displa...
Int_t BOTH_MULT_MAX
Use the segmentation of strips to reject an event when more than MAX strips in 1.....
Double_t TAIL_RISE_NSIGMA
Double_t PILEUP_NSIGMA
Event-level cuts before any reaction is asked about, in sigma of each strip's measured beam spread (S...
Every threshold the tag applies, as one value set.
Double_t noise_nsigma
NOISE_NSIGMA; 0 = off.
Double_t smooth_nsigma
Event level; 0 = off.
Int_t tail_fall_from_strip
Double_t post_above_nsigma
Double_t end_strip_nsigma
Double_t tail_rise_nsigma
Double_t gate_nsigma
GATE_NSIGMA; 0 = off.
Double_t pileup_nsigma
PILEUP_NSIGMA; 0 = off.
Double_t tail_return_nsigma
Double_t tail_rerise_nsigma
Double_t cross_min_strip
The strip the trace must reach without reading below the beam; an absolute strip index held as a doub...
One tagged event, kept in the reservoir.
Float_t leftdE[16]
Left end of strips 1-16, index strip - 1.
Float_t rightdE[16]
Right end of strips 1-16, index strip - 1.
Int_t both_mult
Split strips (1-16) with both ends above threshold.
Float_t strip0dE
Strip 0, unsegmented.
void TotalsAdc(Double_t *out) const
Every strip's raw ADC deposit, for code that wants an array of 18.
ULong64_t seed_ts
Timestamp of the grid hit that seeded the event, from the events tree.
Bool_t beam_flat
Whether the trace looked flat, i.e. beam-like.
Float_t strip17dE
Strip 17, unsegmented.
UInt_t reac_mask
Bit per reaction strip this event was tagged at.
void Totals(Double_t *out) const
Every strip's deposit, for code that wants an array of 18.