MUSIC unknown
Analysis for the MUSIC active-target ionization chamber
Loading...
Searching...
No Matches
EventsSummary.cpp
Go to the documentation of this file.
1#include "EventsSummary.hpp"
2#include <TLine.h>
3
5 return Constants::cfg.IGNORE_STRIP_0 || !Constants::cfg.REQUIRE_STRIP_0;
6}
7
9 const SummaryHistConfig &cfg) {
10 TString musicTitle =
11 "MUSIC strip energies (complete events);Strip;#DeltaE [" +
12 cfg.unit_label + "]";
13 h.h_music =
14 new TH2F(PlottingUtils::GetRandomName().Data(), musicTitle, 18, -0.5,
15 17.5, cfg.music_energy_bins, cfg.strip_e_min, cfg.strip_e_max);
16 h.h_mult =
17 new TH1F(PlottingUtils::GetRandomName().Data(),
18 "Event multiplicity (complete events);Multiplicity;Counts", 36,
19 -0.5, 35.5);
20
21 for (Int_t s = 1; s <= 16; s++) {
22 Double_t lMax = cfg.strip_e_max;
23 Double_t rMax = cfg.strip_e_max;
24 if (cfg.odd_even_split) {
25 lMax = (s % 2 == 0) ? cfg.left_even_max : cfg.left_odd_max;
26 rMax = (s % 2 == 0) ? cfg.right_even_max : cfg.right_odd_max;
27 }
28 // Plotted as long vs short, not R vs L: the long end alternates with strip
29 // parity (L on odd, R on even), so R-vs-L would swap axes per strip.
30 const Bool_t lIsLong = (s % 2) != 0;
31 Double_t shortMax = lIsLong ? rMax : lMax;
32 Double_t longMax = lIsLong ? lMax : rMax;
33 // Maxima default to the full ADC span; when both are at it, use the tuned
34 // strip max for long, a quarter for short (own preamp, minority share).
35 if (shortMax == longMax) {
36 longMax = cfg.strip_e_max;
37 shortMax = 0.25 * cfg.strip_e_max;
38 }
39 TString rlTitle =
40 Form(";Strip %d Short (%c) #DeltaE [", s, lIsLong ? 'R' : 'L') +
41 cfg.unit_label + "];" +
42 Form("Strip %d Long (%c) #DeltaE [", s, lIsLong ? 'L' : 'R') +
43 cfg.unit_label + "]";
44 h.h2_long_vs_short[s - 1] =
45 new TH2F(PlottingUtils::GetRandomName().Data(), rlTitle, 300,
46 cfg.strip_e_min, shortMax, 300, cfg.strip_e_min, longMax);
47 }
48
50 h.h1_cathode = new TH1F(PlottingUtils::GetRandomName().Data(),
51 ";Cathode #DeltaE [" + cfg.unit_label + "];Counts",
52 400, 0.0, cfg.cathode_max);
53 if (Constants::cfg.HAS_STRIP17)
54 h.h1_strip17 = new TH1F(PlottingUtils::GetRandomName().Data(),
55 ";Strip17 #DeltaE [" + cfg.unit_label + "];Counts",
56 400, cfg.strip_e_min, cfg.strip_e_max);
57
58 if (Constants::cfg.HAS_STRIP0 && Constants::cfg.HAS_GRID) {
59 const Bool_t s1 = SummaryGridPartnerIsStrip1();
60 h.h2_strip0_vs_grid = new TH2F(PlottingUtils::GetRandomName().Data(),
61 ";Grid #DeltaE [" + cfg.unit_label +
62 Form("];Strip%d #DeltaE [", s1 ? 1 : 0) +
63 cfg.unit_label + "]",
64 200, 0.0, cfg.grid_max, 200, cfg.strip_e_min,
65 s1 ? cfg.strip_e_max : cfg.strip0_max);
66 } else if (Constants::cfg.HAS_STRIP0) {
67 h.h1_strip0 = new TH1F(PlottingUtils::GetRandomName().Data(),
68 ";Strip0 #DeltaE [" + cfg.unit_label + "];Counts",
69 400, cfg.strip_e_min, cfg.strip0_max);
70 } else if (Constants::cfg.HAS_GRID) {
71 h.h1_grid = new TH1F(PlottingUtils::GetRandomName().Data(),
72 ";Grid #DeltaE [" + cfg.unit_label + "];Counts", 400,
73 0.0, cfg.grid_max);
74 }
75}
76
78 const TString &subdir,
79 const TString &plot_suffix) {
80 TString musicName = "music_strip_energies" + plot_suffix;
81 TString multName = "multiplicity" + plot_suffix;
82 TString cathName = "cathode" + plot_suffix;
83 TString strip17Name = "strip17" + plot_suffix;
84 TString s0gName = TString(SummaryGridPartnerIsStrip1() ? "strip1_vs_grid"
85 : "strip0_vs_grid") +
86 plot_suffix;
87 TString s0Name = "strip0" + plot_suffix;
88 TString gName = "grid" + plot_suffix;
89
90 TCanvas *c_music = PlottingUtils::GetConfiguredCanvas(kFALSE);
91 c_music->cd();
92 PlottingUtils::ConfigureAndDraw2DHistogram(h.h_music, c_music);
93 h.h_music->GetYaxis()->SetTitleOffset(1.4);
94 c_music->SetLeftMargin(0.18);
96 PlottingUtils::SaveFigure(c_music, musicName, subdir,
97 PlotSaveOptions::kLINEAR);
98 out_file->cd();
99 c_music->Write(h.h_music->GetName(), TObject::kOverwrite);
100 delete c_music;
101
102 TCanvas *c_mult = PlottingUtils::GetConfiguredCanvas(kFALSE);
103 c_mult->cd();
104 PlottingUtils::ConfigureAndDrawHistogram(h.h_mult, kBlue + 1);
106 PlottingUtils::SaveFigure(c_mult, multName, subdir, PlotSaveOptions::kLOG);
107 delete c_mult;
108
109 for (Int_t s = 1; s <= 16; s++) {
110 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
111 c->cd();
112 PlottingUtils::ConfigureAndDraw2DHistogram(h.h2_long_vs_short[s - 1], c);
113 h.h2_long_vs_short[s - 1]->GetYaxis()->SetTitleOffset(1.3);
114 // Normed only: charge sharing, long + short = 1 a.u. for a beam event;
115 // y = -x + 1 line; detached from the pad to avoid double-free on c->Delete.
116 TLine *ridge = nullptr;
117 if (plot_suffix == "_normed") {
118 ridge = new TLine(1.0, 0.0, 0.0, 1.0);
119 ridge->SetLineColor(kRed + 1);
120 ridge->SetLineStyle(2);
121 ridge->SetLineWidth(2);
122 ridge->Draw("SAME");
123 }
125 PlottingUtils::SaveFigure(c, TString("long_vs_short_s") + s + plot_suffix,
126 subdir, PlotSaveOptions::kLINEAR);
127 out_file->cd();
128 c->Write(h.h2_long_vs_short[s - 1]->GetName(), TObject::kOverwrite);
129 if (ridge) {
130 if (TVirtualPad *p = c->GetPad(0))
131 p->GetListOfPrimitives()->Remove(ridge);
132 delete ridge;
133 }
134 delete c;
135 }
136
137 if (h.h1_cathode) {
138 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
139 c->cd();
140 PlottingUtils::ConfigureAndDrawHistogram(h.h1_cathode, kBlue + 1);
142 PlottingUtils::SaveFigure(c, cathName, subdir, PlotSaveOptions::kLOG);
143 out_file->cd();
144 h.h1_cathode->Write(h.h1_cathode->GetName(), TObject::kOverwrite);
145 delete c;
146 }
147
148 if (h.h1_strip17) {
149 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
150 c->cd();
151 PlottingUtils::ConfigureAndDrawHistogram(h.h1_strip17, kBlue + 1);
153 PlottingUtils::SaveFigure(c, strip17Name, subdir, PlotSaveOptions::kLOG);
154 out_file->cd();
155 h.h1_strip17->Write(h.h1_strip17->GetName(), TObject::kOverwrite);
156 delete c;
157 }
158
159 if (h.h2_strip0_vs_grid) {
160 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
161 c->cd();
162 PlottingUtils::ConfigureAndDraw2DHistogram(h.h2_strip0_vs_grid, c);
163 h.h2_strip0_vs_grid->GetYaxis()->SetTitleOffset(1.3);
165 PlottingUtils::SaveFigure(c, s0gName, subdir, PlotSaveOptions::kLINEAR);
166 out_file->cd();
167 c->Write(h.h2_strip0_vs_grid->GetName(), TObject::kOverwrite);
168 delete c;
169 }
170 if (h.h1_strip0) {
171 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
172 c->cd();
173 PlottingUtils::ConfigureAndDrawHistogram(h.h1_strip0, kBlue + 1);
175 PlottingUtils::SaveFigure(c, s0Name, subdir, PlotSaveOptions::kLOG);
176 out_file->cd();
177 h.h1_strip0->Write(h.h1_strip0->GetName(), TObject::kOverwrite);
178 delete c;
179 }
180 if (h.h1_grid) {
181 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
182 c->cd();
183 PlottingUtils::ConfigureAndDrawHistogram(h.h1_grid, kBlue + 1);
185 PlottingUtils::SaveFigure(c, gName, subdir, PlotSaveOptions::kLOG);
186 out_file->cd();
187 h.h1_grid->Write(h.h1_grid->GetName(), TObject::kOverwrite);
188 delete c;
189 }
190
191 for (Int_t s = 1; s <= 16; s++)
192 delete h.h2_long_vs_short[s - 1];
193 delete h.h_music;
194 delete h.h_mult;
195 delete h.h1_cathode;
196 delete h.h1_strip17;
197 delete h.h2_strip0_vs_grid;
198 delete h.h1_strip0;
199 delete h.h1_grid;
200 h.h_music = nullptr;
201 h.h_mult = nullptr;
202 h.h1_cathode = nullptr;
203 h.h1_strip17 = nullptr;
204 h.h2_strip0_vs_grid = nullptr;
205 h.h1_strip0 = nullptr;
206 h.h1_grid = nullptr;
207}
208
209void EventsSummary::SaveSampleTraces(const std::vector<TGraph *> &traces,
210 const TString &save_name,
211 const TString &subdir, Double_t y_min,
212 Double_t y_max, const char *y_title) {
213 if (traces.empty())
214 return;
215
216 Int_t s_lo = Constants::cfg.IGNORE_STRIP_0 ? 1 : 0;
217 Int_t s_hi = Constants::cfg.IGNORE_STRIP_17 ? 16 : 17;
218 TH2F *frame = new TH2F(PlottingUtils::GetRandomName().Data(),
219 Form(";Strip;%s", y_title), s_hi - s_lo + 1,
220 s_lo - 0.5, s_hi + 0.5, 100, y_min, y_max);
221 frame->SetStats(0);
222 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
223 c->cd();
224 frame->Draw();
225
226 for (Int_t i = 0; i < Int_t(traces.size()); i++) {
227 traces[i]->SetLineColor(kBlack);
228 traces[i]->SetLineWidth(1);
229 traces[i]->Draw("L SAME");
230 }
231
233 PlottingUtils::SaveFigure(c, save_name, subdir, PlotSaveOptions::kLINEAR);
234 delete c;
235 delete frame;
236}
237
238void EventsSummary::BuildNormedSummaryHistograms(const TString &input_filename,
239 const TString &file_label) {
240 TString input_filepath = input_filename + ".root";
241
242 TFile *input_file = IO::OpenForWriting(input_filepath, "UPDATE");
243 if (!input_file || input_file->IsZombie()) {
244 std::cerr << "[" << file_label
245 << "] cannot open UPDATE for normed summary: " << input_filepath
246 << std::endl;
247 if (input_file)
248 delete input_file;
249 return;
250 }
251 TTree *input_tree = static_cast<TTree *>(input_file->Get("events"));
252 if (!input_tree) {
253 std::cerr << "[" << file_label << "] no events tree for normed summary"
254 << std::endl;
255 input_file->Close();
256 delete input_file;
257 return;
258 }
259 EnergyView ev;
260 ev.Attach(input_tree);
261 if (!ev.is_normed) {
262 std::cout
263 << "[" << file_label
264 << "] no calibration in events file; skipping normed summary build"
265 << std::endl;
266 input_file->Close();
267 delete input_file;
268 return;
269 }
270
271 const Double_t strip_e_min = Constants::cfg.STRIP_DE_MIN_NORMED;
272 const Double_t strip_e_max = Constants::cfg.STRIP_DE_MAX_NORMED;
273
275 cfg.unit_label = "a.u.";
276 cfg.strip_e_min = strip_e_min;
277 cfg.strip_e_max = strip_e_max;
278 cfg.odd_even_split = kFALSE;
279 cfg.left_odd_max = strip_e_max;
280 cfg.left_even_max = strip_e_max;
281 cfg.right_odd_max = strip_e_max;
282 cfg.right_even_max = strip_e_max;
283 cfg.cathode_max = 1.0;
284 // The grid reads 1.0 for a beam event once it has an anchor (GainGrid), so
285 // it takes the strip range rather than the full-scale fraction it once was.
286 cfg.grid_max = strip_e_max;
287 cfg.strip0_max = strip_e_max;
288 cfg.music_energy_bins = 400;
289
292
293 Long64_t n_entries = input_tree->GetEntries();
294 Constants::Detail() << "[" << file_label << "] building normed summary over "
295 << n_entries << " events..." << std::endl;
296
297 // Sample traces for overlay plot
298 std::vector<TGraph *> sample_traces;
299 Long64_t sample_stride = 0;
300 if (Constants::cfg.SAVE_SAMPLE_TRACES > 0) {
301 sample_stride = n_entries / Long64_t(Constants::cfg.SAVE_SAMPLE_TRACES);
302 if (sample_stride < 1)
303 sample_stride = 1;
304 }
305
306 for (Long64_t j = 0; j < n_entries; j++) {
307 input_tree->GetEntry(j);
308 ev.Decode();
309
310 for (Int_t s = 0; s < 18; s++)
311 h.h_music->Fill(Double_t(s), ev.Total(s));
312
313 for (Int_t s = 1; s <= 16; s++) {
314 const Bool_t lIsLong = (s % 2) != 0;
315 h.h2_long_vs_short[s - 1]->Fill(
316 lIsLong ? ev.right[s - 1] : ev.left[s - 1],
317 lIsLong ? ev.left[s - 1] : ev.right[s - 1]);
318 }
319
320 if (h.h1_cathode && ev.cathode > 0.0)
321 h.h1_cathode->Fill(ev.cathode);
322
323 if (h.h1_strip17)
324 h.h1_strip17->Fill(ev.strip17);
325
326 if (h.h2_strip0_vs_grid)
327 h.h2_strip0_vs_grid->Fill(
328 ev.grid, SummaryGridPartnerIsStrip1() ? ev.Total(1) : ev.strip0);
329
330 if (h.h1_strip0)
331 h.h1_strip0->Fill(ev.strip0);
332
333 if (h.h1_grid)
334 h.h1_grid->Fill(ev.grid);
335
336 Int_t mult = 0;
337 for (Int_t k = 0; k < Constants::N_ARR_SLOTS; k++)
338 mult += ev.hits_adc[k];
339 h.h_mult->Fill(Double_t(mult));
340
341 // Collect sample traces
342 if (sample_stride > 0 && j % sample_stride == 0 &&
343 Int_t(sample_traces.size()) < Constants::cfg.SAVE_SAMPLE_TRACES) {
344 Double_t td[18];
345 ev.Totals(td);
346 sample_traces.push_back(EventsSummary::BuildTraceFromTotals(td));
347 }
348 }
349
350 {
351 std::lock_guard<std::mutex> lock(g_plot_mutex);
352 TString subdir = "events_summary_normed/" + file_label;
353 SaveAndDeleteSummaryHistograms(h, input_file, subdir, "_normed");
354
355 // Sample traces overlay
356 if (!sample_traces.empty()) {
357 SaveSampleTraces(sample_traces, "sample_traces_normed", subdir,
358 strip_e_min, strip_e_max, "#DeltaE [a.u.]");
359 }
360 }
361
362 for (Int_t i = 0; i < Int_t(sample_traces.size()); i++)
363 delete sample_traces[i];
364
365 input_file->Close();
366 delete input_file;
367}
368
369TGraph *EventsSummary::BuildTraceFromTotals(const Double_t *total) {
370 Int_t s_lo = Constants::cfg.IGNORE_STRIP_0 ? 1 : 0;
371 Int_t s_hi = Constants::cfg.IGNORE_STRIP_17 ? 16 : 17;
372 Int_t n_pts = s_hi - s_lo + 1;
373 TGraph *g = new TGraph(n_pts);
374 for (Int_t k = 0; k < n_pts; k++)
375 g->SetPoint(k, s_lo + k, total[s_lo + k]);
376 return g;
377}
Bool_t SummaryGridPartnerIsStrip1()
Whether the grid's partner in the summary is strip 1 rather than strip 0: when strip 0 is ignored or ...
void CreateSummaryHistograms(SummaryHistograms &h, const SummaryHistConfig &cfg)
Allocate every histogram in the set.
void SaveAndDeleteSummaryHistograms(SummaryHistograms &h, TFile *out_file, const TString &subdir, const TString &plot_suffix)
Write the set to file, save the plots, then free every histogram.
Bool_t SummaryGridPartnerIsStrip1()
Whether the grid's partner in the summary is strip 1 rather than strip 0: when strip 0 is ignored or ...
void CreateSummaryHistograms(SummaryHistograms &h, const SummaryHistConfig &cfg)
Allocate every histogram in the set.
void SaveAndDeleteSummaryHistograms(SummaryHistograms &h, TFile *out_file, const TString &subdir, const TString &plot_suffix)
Write the set to file, save the plots, then free every histogram.
std::mutex g_plot_mutex
Serialises all plotting and canvas work.
Definition FileSet.cpp:3
static void SaveSampleTraces(const std::vector< TGraph * > &traces, const TString &save_name, const TString &subdir, Double_t y_min, Double_t y_max, const char *y_title)
Draw a set of traces overlaid on one frame and save it.
static void BuildNormedSummaryHistograms(const TString &input_filename, const TString &file_label)
Build the calibrated summary histograms for one events file.
static TGraph * BuildTraceFromTotals(const Double_t *total)
Build a trace graph from one event's per-strip totals.
Bool_t SavePlots()
FileInSample(), by the name the plot call sites use.
const Int_t N_ARR_SLOTS
Length of the per-event channel arrays.
std::ostream & Detail()
std::cout for a file in the sample, a stream that discards otherwise: the per-file detail lines (per ...
Bool_t ActiveHasCathode()
Whether this era instrumented the cathode.
const DatasetConfig & cfg
The active dataset's configuration, flat block.
A view over one event's energies, decoding raw ADC into calibrated units.
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.
Bool_t is_normed
Whether a calibration tree was found.
void Totals(Double_t *out) const
Every strip's deposit at once, for code that wants an array.
Double_t strip0
Strip 0.
Double_t right[16]
Right end of strips 1-16, index strip - 1.
UShort_t hits_adc[36]
Raw per-slot hit ADC values.
Double_t grid
Grid energy.
Double_t cathode
Cathode energy.
Axis ranges and labels for building a SummaryHistograms set.
The standard diagnostic histogram set for a subfile.
TH2F * h_music
Energy against strip index: the MUSIC plot.
TH1F * h1_strip0
Strip 0 energy.
TH1F * h1_cathode
Cathode energy.
TH2F * h2_strip0_vs_grid
Strip 0 against grid energy; strip 1 against the grid when strip 0 is not required of an event (Summa...
TH1F * h_mult
Hit multiplicity per event.
TH1F * h1_strip17
Strip 17 energy.
TH2F * h2_long_vs_short[16]
Long end against short end of the segmented strips 1-16, index strip - 1.
TH1F * h1_grid
Grid energy.