3#include "InitUtils.hpp"
6#include "PlottingUtils.hpp"
11#include <TGraphErrors.h>
15#include <TParameter.h>
31static const char *kFields[5] = {
"n_counted",
"eff",
"eff_err",
"migrate",
34static TString Key(
const TString &channel,
const char *field, Int_t reac) {
35 return Form(
"%s_%s_r%d", channel.Data(), field, reac);
38void Write(
const TString &channel,
39 const std::vector<TagEfficiencyRecord> &records,
40 const TString &method) {
41 TFile f(
Path(),
"UPDATE");
43 std::cerr <<
"tag-efficiency: cannot write " <<
Path() << std::endl;
47 TNamed(
"method", method.Data()).Write(
"method", TObject::kOverwrite);
50 for (TIter it(f.GetListOfKeys()); TObject *k = it();)
51 if (TString(k->GetName()).BeginsWith(channel +
"_"))
52 f.Delete(Form(
"%s;*", k->GetName()));
53 for (Int_t i = 0; i < Int_t(records.size()); i++) {
56 for (Int_t k = 0; k < 5; k++) {
57 const TString key = Key(channel, kFields[k], r.
reac);
58 TParameter<Double_t>(key, v[k]).Write(key, TObject::kOverwrite);
65 if (gSystem->AccessPathName(
Path()))
67 TFile f(
Path(),
"READ");
71 for (Int_t k = 0; k < 5; k++) {
72 TParameter<Double_t> *p =
dynamic_cast<TParameter<Double_t> *
>(
73 f.Get(Key(channel, kFields[k], reac)));
88 if (gSystem->AccessPathName(
Path()))
90 TFile f(
Path(),
"READ");
91 TNamed *m = f.IsZombie() ? nullptr :
dynamic_cast<TNamed *
>(f.Get(
"method"));
92 return m ? TString(m->GetTitle()) : TString(
"");
102const Long64_t kBootstrapTrials = 20000;
103const Double_t kMinEventsInCut = 20.0;
107Bool_t TagEfficiency::LoadSigmas(TFile &cache) {
108 Double_t jump[18] = {0}, strip[18] = {0};
110 for (Int_t s = 0; s < 18; s++) {
111 if (TParameter<Double_t> *p =
static_cast<TParameter<Double_t> *
>(
112 cache.Get(Form(
"jump_sigma_s%d", s)))) {
113 jump[s] = p->GetVal();
116 if (TParameter<Double_t> *p =
static_cast<TParameter<Double_t> *
>(
117 cache.Get(Form(
"strip_sigma_s%d", s))))
118 strip[s] = p->GetVal();
130void TagEfficiency::LoadDrawnCuts(
const TString ®ion) {
143void TagEfficiency::MeanTraces(TTree *tt) {
144 const Int_t kReacMin =
148 tt->SetBranchStatus(
"*", 0);
149 tt->SetBranchStatus(
"total", 1);
150 tt->SetBranchStatus(
"reac_mask", 1);
151 tt->SetBranchAddress(
"total", total);
152 tt->SetBranchAddress(
"reac_mask", &mask);
153 for (std::map<Int_t, Strip>::iterator it = strips_.begin();
154 it != strips_.end(); ++it) {
155 it->second.mean.assign(18, 0.0);
156 it->second.count = 0.0;
158 const Long64_t n = tt->GetEntries();
159 for (Long64_t i = 0; i < n; i++) {
164 for (Int_t s = 0; s < 18; s++)
166 for (std::map<Int_t, Strip>::iterator it = strips_.begin();
167 it != strips_.end(); ++it) {
168 const Int_t reac = it->first;
169 if (!(mask & (1u << (reac - kReacMin))))
173 if (!it->second.cut->IsInside(x, y))
175 for (Int_t s = 0; s < 18; s++)
176 it->second.mean[s] += td[s];
177 it->second.count += 1.0;
180 for (std::map<Int_t, Strip>::iterator it = strips_.begin();
181 it != strips_.end(); ++it)
182 if (it->second.count > 0.0)
183 for (Int_t s = 0; s < 18; s++)
184 it->second.mean[s] /= it->second.count;
185 tt->SetBranchStatus(
"*", 1);
191TagEfficiency::Outcome TagEfficiency::Bootstrap(Int_t reac, TH2F *plane) {
192 const Strip &st = strips_[reac];
193 TCutG *cut_next = strips_.count(reac + 1) ? strips_[reac + 1].cut :
nullptr;
194 TRandom3 rng(12345 + reac);
196 for (Long64_t t = 0; t < kBootstrapTrials; t++) {
198 for (Int_t s = 0; s < 18; s++)
201 for (Int_t s = 0; s < 18; s++)
202 ev.
total[s] = total[s];
210 if (st.cut->IsInside(x, y))
216 if (cut_next->IsInside(xn, yn))
223void TagEfficiency::DrawMeanTrace(
const TString &subdir, Int_t reac,
226 new TH2F(Form(
"h_eff_frame_%s_%d", subdir.Data(), reac),
227 ";Strip;#DeltaE [a.u.]", 18, -0.5, 17.5, 100, 0.6, 1.6);
229 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
231 TGraphErrors *band =
new TGraphErrors(18);
232 TGraph *line =
new TGraph(18);
233 for (Int_t s = 0; s < 18; s++) {
234 band->SetPoint(s, s, st.mean[s]);
236 line->SetPoint(s, s, st.mean[s]);
238 band->SetFillColorAlpha(kRed + 1, 0.25);
239 band->SetLineColor(kRed + 1);
240 band->Draw(
"3 SAME");
241 line->SetLineColor(kRed + 1);
242 line->SetLineWidth(2);
243 line->Draw(
"L SAME");
244 TLegend *leg = PlottingUtils::AddLegend(0.40, 0.875, 0.72, 0.86);
246 line, Form(
"Mean trace, %.0f events in the drawn cut", st.count),
"l");
247 leg->AddEntry(band,
"#pm1#sigma beam width per strip",
"f");
249 PlottingUtils::AddText(Form(
"reaction strip %d", reac), 0.875, 0.68);
250 PlottingUtils::SaveFigure(c, Form(
"mean_trace_reac%d", reac), subdir,
251 PlotSaveOptions::kLINEAR);
256void TagEfficiency::DrawPlane(
const TString &subdir, Int_t reac, TH2F *plane,
258 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
260 PlottingUtils::ConfigureAndDraw2DHistogram(
261 plane, c, Form(
"reac %d: bootstrap on the drawn cut", reac));
262 cut->SetLineColor(kBlack);
263 cut->SetLineWidth(2);
264 cut->SetFillStyle(0);
266 PlottingUtils::SaveFigure(c, Form(
"bootstrap_plane_reac%d", reac), subdir,
267 PlotSaveOptions::kLINEAR);
275 const TString region =
"region_" + ch.
name;
276 const TString subdir =
"tag_efficiency/" + ch.
name;
277 LoadDrawnCuts(region);
278 if (strips_.empty()) {
279 std::cerr <<
"tag-efficiency: channel " << ch.
name
280 <<
": no hand-drawn cuts (" << region
281 <<
"); draw them in strip-sum-scatter first" << std::endl;
284 std::cout <<
"tag-efficiency: channel " << ch.
name <<
": mean traces inside "
285 << region <<
" from " << reservoir->GetEntries()
287 <<
" sigma; " << kBootstrapTrials <<
" bootstrap trials per strip"
289 MeanTraces(reservoir);
291 std::vector<TagEfficiencyRecord> records;
292 std::cout << Form(
"%5s %10s %9s %9s %9s",
"strip",
"in cut",
"tag eff",
"eff",
296 if (strips_.find(reac) == strips_.end() ||
297 strips_[reac].count < kMinEventsInCut) {
298 std::cout << Form(
"%5d %10.0f no drawn cut or too few events", reac,
299 strips_.count(reac) ? strips_[reac].count : 0.0)
303 const Strip &st = strips_[reac];
304 TH2F *plane =
new TH2F(Form(
"h_boot_plane_%s_%d", ch.
name.Data(), reac),
305 ";norm. #DeltaE strips 1#rightarrow16 [a.u.];norm. "
306 "#DeltaE post window [a.u.]",
309 const Outcome o = Bootstrap(reac, plane);
311 TagEfficiencyRecord r;
314 r.
eff = Double_t(o.inside) / Double_t(o.n);
316 r.
eff_err = std::sqrt(r.
eff * (1.0 - r.
eff) / Double_t(o.n));
317 r.
migrate = Double_t(o.next_inside) / Double_t(o.n);
318 r.
tag_eff = Double_t(o.tagged) / Double_t(o.n);
319 records.push_back(r);
320 std::cout << Form(
"%5d %10.0f %9.3f %9.3f %9.3f", reac, r.
n_counted,
324 DrawMeanTrace(subdir, reac, st);
325 DrawPlane(subdir, reac, plane, st.cut);
329 return !records.empty();
335 std::cerr <<
"tag-efficiency: this dataset declares no CROSS_SECTION_CONFIG"
342 TFile cache(cache_path,
"READ");
343 if (cache.IsZombie()) {
344 std::cerr <<
"tag-efficiency: no scatter cache at " << cache_path
345 <<
"; run strip-sum-scatter first" << std::endl;
348 if (!LoadSigmas(cache)) {
349 std::cerr <<
"tag-efficiency: cache carries no per-strip noise sigmas; "
354 TTree *reservoir =
static_cast<TTree *
>(cache.Get(
"traces"));
356 std::cerr <<
"tag-efficiency: no reservoir in the cache" << std::endl;
360 for (Int_t c = 0; c < Int_t(X.
CHANNELS.size()); c++)
361 if (RunChannel(X.
CHANNELS[c], reservoir))
363 std::cout <<
"tag-efficiency: " << done <<
" of " << X.
CHANNELS.size()
The dataset configuration, and how it is layered.
The reaction search: strip-sum scatters, beam gating and tagging.
The tag-efficiency correction, and its contract with the cross section.
StripSumScatterConfig STRIP_SUM_SCATTER_CONFIG
CrossSectionConfig CROSS_SECTION_CONFIG
static TString ResultsDir()
Absolute path to the directory receiving generated output.
static TString CacheName()
Filename of the scatter cache for this configuration.
static void SetStripSigma(const Double_t *sigma)
Install the per-strip sigmas.
static Bool_t PassesReaction(const EnergyView &ev, Int_t reac)
Whether an event is tagged as a reaction at a given strip.
static Double_t StripSigma(Int_t strip)
Sigma of a strip's own deposit.
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.
static void SetJumpSigma(const Double_t *sigma)
Install the jump sigmas.
static const char * MethodLabel()
The label stamped into the store for this method.
Bool_t Run()
Measure every configured channel and write the store and figures.
const DatasetConfig & cfg
The active dataset's configuration, flat block.
TCutG * LoadDrawn(const char *name, Int_t reac)
Load only a hand-drawn cut, never a fitted one.
Persistence for the efficiency records.
Bool_t Load(const TString &channel, Int_t reac, TagEfficiencyRecord &record)
Read one record.
TString Method()
The method label stamped into the store.
TString Path()
Path to the store.
void Write(const TString &channel, const std::vector< TagEfficiencyRecord > &records, const TString &method)
Replace one channel's records, keeping every other channel's.
One reaction channel the cross section is extracted for.
TString name
Names the region cut (region_<name>), the tag-efficiency records and the output figure.
What the cross section needs about the experiment rather than the analysis.
Int_t XS_STRIP_MIN
Reaction strips to report a cross section for.
std::vector< CrossSectionChannel > CHANNELS
The reaction channels measured on this dataset.
Double_t total[18]
Summed energy per strip, after strip_factor.
Double_t X_DISPLAY_MIN
Display-only windows for the strip-sum scatters (a.u.): the histograms are built over the fixed Scatt...
Double_t REAC_JUMP_NSIGMA
Minimum jump at the reaction strip for a tag, in sigma of the measured strip-to-strip beam noise (Str...
One channel and strip's efficiency, as the cross section consumes it.
Int_t reac
Reaction strip index; -1 for an unset record.
Double_t migrate
Fraction of true reactions at this strip counted at strip reac + 1 instead, which the cross section u...
Double_t n_counted
The numerator this efficiency belongs to: the events counted at this strip by the same selection the ...
Double_t eff
Fraction of true reactions at this strip that end up in n_counted.
Double_t tag_eff
Of eff, the part the tag alone passes; the remainder is the region cut.
Double_t eff_err
Uncertainty on eff, or 0 when the method provides none.