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 const SummaryHistConfig &cfg) {
6 TString musicTitle =
7 "MUSIC strip energies (complete events);Strip;#DeltaE [" +
8 cfg.unit_label + "]";
9 h.h_music =
10 new TH2F(PlottingUtils::GetRandomName().Data(), musicTitle, 18, -0.5,
11 17.5, cfg.music_energy_bins, cfg.strip_e_min, cfg.strip_e_max);
12 h.h_mult =
13 new TH1F(PlottingUtils::GetRandomName().Data(),
14 "Event multiplicity (complete events);Multiplicity;Counts", 36,
15 -0.5, 35.5);
16
17 for (Int_t s = 1; s <= 16; s++) {
18 Double_t lMax = cfg.strip_e_max;
19 Double_t rMax = cfg.strip_e_max;
20 if (cfg.odd_even_split) {
21 lMax = (s % 2 == 0) ? cfg.left_even_max : cfg.left_odd_max;
22 rMax = (s % 2 == 0) ? cfg.right_even_max : cfg.right_odd_max;
23 }
24 // Plotted as long vs short rather than R vs L: which physical end is long
25 // alternates with strip parity (L on odd, R on even), so the R-vs-L view
26 // swaps axes every strip and the two parities cannot be compared by eye.
27 const Bool_t lIsLong = (s % 2) != 0;
28 Double_t shortMax = lIsLong ? rMax : lMax;
29 Double_t longMax = lIsLong ? lMax : rMax;
30 // The four per-side maxima default to the full ADC span, which puts both
31 // axes on the same scale and squashes the short end into the axis. When
32 // they are left at that default, fall back to the tuned strip maximum for
33 // the long end and a quarter of it for the short end -- the short end is
34 // on its own preamp and only picks up a minority share, so it never
35 // approaches the long end's range.
36 if (shortMax == longMax) {
37 longMax = cfg.strip_e_max;
38 shortMax = 0.25 * cfg.strip_e_max;
39 }
40 TString rlTitle =
41 Form(";Strip %d Short (%c) #DeltaE [", s, lIsLong ? 'R' : 'L') +
42 cfg.unit_label + "];" +
43 Form("Strip %d Long (%c) #DeltaE [", s, lIsLong ? 'L' : 'R') +
44 cfg.unit_label + "]";
45 h.h2_long_vs_short[s] =
46 new TH2F(PlottingUtils::GetRandomName().Data(), rlTitle, 300,
47 cfg.strip_e_min, shortMax, 300, cfg.strip_e_min, longMax);
48 }
49
51 h.h1_cathode = new TH1F(PlottingUtils::GetRandomName().Data(),
52 ";Cathode #DeltaE [" + cfg.unit_label + "];Counts",
53 400, 0.0, cfg.cathode_max);
54 if (Constants::cfg.HAS_STRIP17)
55 h.h1_strip17 = new TH1F(PlottingUtils::GetRandomName().Data(),
56 ";Strip17 #DeltaE [" + cfg.unit_label + "];Counts",
57 400, cfg.strip_e_min, cfg.strip_e_max);
58
59 if (Constants::cfg.HAS_STRIP0 && Constants::cfg.HAS_GRID) {
61 new TH2F(PlottingUtils::GetRandomName().Data(),
62 ";Grid #DeltaE [" + cfg.unit_label + "];Strip0 #DeltaE [" +
63 cfg.unit_label + "]",
64 200, 0.0, cfg.grid_max, 200, cfg.strip_e_min, cfg.strip0_max);
65 } else if (Constants::cfg.HAS_STRIP0) {
66 h.h1_strip0 = new TH1F(PlottingUtils::GetRandomName().Data(),
67 ";Strip0 #DeltaE [" + cfg.unit_label + "];Counts",
68 400, cfg.strip_e_min, cfg.strip0_max);
69 } else if (Constants::cfg.HAS_GRID) {
70 h.h1_grid = new TH1F(PlottingUtils::GetRandomName().Data(),
71 ";Grid #DeltaE [" + cfg.unit_label + "];Counts", 400,
72 0.0, cfg.grid_max);
73 }
74}
75
77 const TString &subdir,
78 const TString &plot_suffix) {
79 TString musicName = "music_strip_energies" + plot_suffix;
80 TString multName = "multiplicity" + plot_suffix;
81 TString cathName = "cathode" + plot_suffix;
82 TString strip17Name = "strip17" + plot_suffix;
83 TString s0gName = "strip0_vs_grid" + plot_suffix;
84 TString s0Name = "strip0" + plot_suffix;
85 TString gName = "grid" + plot_suffix;
86
87 TCanvas *c_music = PlottingUtils::GetConfiguredCanvas(kFALSE);
88 c_music->cd();
89 PlottingUtils::ConfigureAndDraw2DHistogram(h.h_music, c_music);
90 h.h_music->GetYaxis()->SetTitleOffset(1.4);
91 c_music->SetLeftMargin(0.18);
92 if (Constants::cfg.SAVE_PLOTS)
93 PlottingUtils::SaveFigure(c_music, musicName, subdir,
94 PlotSaveOptions::kLINEAR);
95 out_file->cd();
96 c_music->Write(h.h_music->GetName(), TObject::kOverwrite);
97 delete c_music;
98
99 TCanvas *c_mult = PlottingUtils::GetConfiguredCanvas(kFALSE);
100 c_mult->cd();
101 PlottingUtils::ConfigureAndDrawHistogram(h.h_mult, kBlue + 1);
102 if (Constants::cfg.SAVE_PLOTS)
103 PlottingUtils::SaveFigure(c_mult, multName, subdir, PlotSaveOptions::kLOG);
104 delete c_mult;
105
106 for (Int_t s = 1; s <= 16; s++) {
107 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
108 c->cd();
109 PlottingUtils::ConfigureAndDraw2DHistogram(h.h2_long_vs_short[s], c);
110 h.h2_long_vs_short[s]->GetYaxis()->SetTitleOffset(1.3);
111 // Normed only: the charge-sharing line long + short = 1 a.u. (for a beam
112 // event the two ends carry the full deposit between them). Drawn as the
113 // y = -x + 1 gridline, i.e. short=0,long=1 -> short=1,long=0. Detached from
114 // the pad before deletion so the pad does not double-free it on c->Delete.
115 TLine *ridge = nullptr;
116 if (plot_suffix == "_normed") {
117 ridge = new TLine(1.0, 0.0, 0.0, 1.0);
118 ridge->SetLineColor(kRed + 1);
119 ridge->SetLineStyle(2);
120 ridge->SetLineWidth(2);
121 ridge->Draw("SAME");
122 }
123 if (Constants::cfg.SAVE_PLOTS)
124 PlottingUtils::SaveFigure(c, TString("long_vs_short_s") + s + plot_suffix,
125 subdir, PlotSaveOptions::kLINEAR);
126 out_file->cd();
127 c->Write(h.h2_long_vs_short[s]->GetName(), TObject::kOverwrite);
128 if (ridge) {
129 if (TVirtualPad *p = c->GetPad(0))
130 p->GetListOfPrimitives()->Remove(ridge);
131 delete ridge;
132 }
133 delete c;
134 }
135
136 if (h.h1_cathode) {
137 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
138 c->cd();
139 PlottingUtils::ConfigureAndDrawHistogram(h.h1_cathode, kBlue + 1);
140 if (Constants::cfg.SAVE_PLOTS)
141 PlottingUtils::SaveFigure(c, cathName, subdir, PlotSaveOptions::kLOG);
142 out_file->cd();
143 h.h1_cathode->Write(h.h1_cathode->GetName(), TObject::kOverwrite);
144 delete c;
145 }
146
147 if (h.h1_strip17) {
148 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
149 c->cd();
150 PlottingUtils::ConfigureAndDrawHistogram(h.h1_strip17, kBlue + 1);
151 if (Constants::cfg.SAVE_PLOTS)
152 PlottingUtils::SaveFigure(c, strip17Name, subdir, PlotSaveOptions::kLOG);
153 out_file->cd();
154 h.h1_strip17->Write(h.h1_strip17->GetName(), TObject::kOverwrite);
155 delete c;
156 }
157
158 if (h.h2_strip0_vs_grid) {
159 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
160 c->cd();
161 PlottingUtils::ConfigureAndDraw2DHistogram(h.h2_strip0_vs_grid, c);
162 h.h2_strip0_vs_grid->GetYaxis()->SetTitleOffset(1.3);
163 if (Constants::cfg.SAVE_PLOTS)
164 PlottingUtils::SaveFigure(c, s0gName, subdir, PlotSaveOptions::kLINEAR);
165 out_file->cd();
166 c->Write(h.h2_strip0_vs_grid->GetName(), TObject::kOverwrite);
167 delete c;
168 }
169 if (h.h1_strip0) {
170 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
171 c->cd();
172 PlottingUtils::ConfigureAndDrawHistogram(h.h1_strip0, kBlue + 1);
173 if (Constants::cfg.SAVE_PLOTS)
174 PlottingUtils::SaveFigure(c, s0Name, subdir, PlotSaveOptions::kLOG);
175 out_file->cd();
176 h.h1_strip0->Write(h.h1_strip0->GetName(), TObject::kOverwrite);
177 delete c;
178 }
179 if (h.h1_grid) {
180 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
181 c->cd();
182 PlottingUtils::ConfigureAndDrawHistogram(h.h1_grid, kBlue + 1);
183 if (Constants::cfg.SAVE_PLOTS)
184 PlottingUtils::SaveFigure(c, gName, subdir, PlotSaveOptions::kLOG);
185 out_file->cd();
186 h.h1_grid->Write(h.h1_grid->GetName(), TObject::kOverwrite);
187 delete c;
188 }
189
190 for (Int_t s = 1; s <= 16; s++)
191 delete h.h2_long_vs_short[s];
192 delete h.h_music;
193 delete h.h_mult;
194 delete h.h1_cathode;
195 delete h.h1_strip17;
196 delete h.h2_strip0_vs_grid;
197 delete h.h1_strip0;
198 delete h.h1_grid;
199 h.h_music = nullptr;
200 h.h_mult = nullptr;
201 h.h1_cathode = nullptr;
202 h.h1_strip17 = nullptr;
203 h.h2_strip0_vs_grid = nullptr;
204 h.h1_strip0 = nullptr;
205 h.h1_grid = nullptr;
206}
207
208void EventsSummary::SaveSampleTraces(const std::vector<TGraph *> &traces,
209 const TString &save_name,
210 const TString &subdir, Double_t y_min,
211 Double_t y_max, const char *y_title) {
212 if (traces.empty())
213 return;
214
215 Int_t s_lo = Constants::cfg.IGNORE_STRIP_0 ? 1 : 0;
216 Int_t s_hi = Constants::cfg.IGNORE_STRIP_17 ? 16 : 17;
217 TH2F *frame = new TH2F(PlottingUtils::GetRandomName().Data(),
218 Form(";Strip;%s", y_title), s_hi - s_lo + 1,
219 s_lo - 0.5, s_hi + 0.5, 100, y_min, y_max);
220 frame->SetStats(0);
221 TCanvas *c = PlottingUtils::GetConfiguredCanvas(kFALSE);
222 c->cd();
223 frame->Draw();
224
225 for (Int_t i = 0; i < Int_t(traces.size()); i++) {
226 traces[i]->SetLineColor(kBlack);
227 traces[i]->SetLineWidth(1);
228 traces[i]->Draw("L SAME");
229 }
230
231 if (Constants::cfg.SAVE_PLOTS)
232 PlottingUtils::SaveFigure(c, save_name, subdir, PlotSaveOptions::kLINEAR);
233 delete c;
234 delete frame;
235}
236
237void EventsSummary::BuildNormedSummaryHistograms(const TString &input_filename,
238 const TString &file_label) {
239 TString input_filepath = input_filename + ".root";
240
241 TFile *input_file = IO::OpenForWriting(input_filepath, "UPDATE");
242 if (!input_file || input_file->IsZombie()) {
243 std::cerr << "[" << file_label
244 << "] cannot open UPDATE for normed summary: " << input_filepath
245 << std::endl;
246 if (input_file)
247 delete input_file;
248 return;
249 }
250 TTree *input_tree = static_cast<TTree *>(input_file->Get("events"));
251 if (!input_tree) {
252 std::cerr << "[" << file_label << "] no events tree for normed summary"
253 << std::endl;
254 input_file->Close();
255 delete input_file;
256 return;
257 }
258 EnergyView ev;
259 ev.Attach(input_tree);
260 if (!ev.is_normed) {
261 std::cout
262 << "[" << file_label
263 << "] no calibration in events file; skipping normed summary build"
264 << std::endl;
265 input_file->Close();
266 delete input_file;
267 return;
268 }
269
270 const Double_t strip_e_min = Constants::cfg.STRIP_DE_MIN_NORMED;
271 const Double_t strip_e_max = Constants::cfg.STRIP_DE_MAX_NORMED;
272
274 cfg.unit_label = "a.u.";
275 cfg.strip_e_min = strip_e_min;
276 cfg.strip_e_max = strip_e_max;
277 cfg.odd_even_split = kFALSE;
278 cfg.left_odd_max = strip_e_max;
279 cfg.left_even_max = strip_e_max;
280 cfg.right_odd_max = strip_e_max;
281 cfg.right_even_max = strip_e_max;
282 cfg.cathode_max = 1.0;
283 cfg.strip17_max = strip_e_max;
284 cfg.grid_max = 1.0;
285 cfg.strip0_max = strip_e_max;
286 cfg.music_energy_bins = 400;
287
290
291 Long64_t n_entries = input_tree->GetEntries();
292 std::cout << "[" << file_label << "] building normed summary over "
293 << n_entries << " events..." << std::endl;
294
295 // Sample traces for overlay plot
296 std::vector<TGraph *> sample_traces;
297 Long64_t sample_stride = 0;
298 if (Constants::cfg.SAVE_SAMPLE_TRACES > 0) {
299 sample_stride = n_entries / Long64_t(Constants::cfg.SAVE_SAMPLE_TRACES);
300 if (sample_stride < 1)
301 sample_stride = 1;
302 }
303
304 for (Long64_t j = 0; j < n_entries; j++) {
305 input_tree->GetEntry(j);
306 ev.Decode();
307
308 for (Int_t s = 0; s < 18; s++)
309 h.h_music->Fill(Double_t(s), ev.total[s]);
310
311 for (Int_t s = 1; s <= 16; s++) {
312 const Bool_t lIsLong = (s % 2) != 0;
313 h.h2_long_vs_short[s]->Fill(lIsLong ? ev.right[s] : ev.left[s],
314 lIsLong ? ev.left[s] : ev.right[s]);
315 }
316
317 if (h.h1_cathode && ev.cathode > 0.0)
318 h.h1_cathode->Fill(ev.cathode);
319
320 if (h.h1_strip17)
321 h.h1_strip17->Fill(ev.total[17]);
322
323 if (h.h2_strip0_vs_grid)
324 h.h2_strip0_vs_grid->Fill(ev.grid, ev.total[0]);
325
326 if (h.h1_strip0)
327 h.h1_strip0->Fill(ev.total[0]);
328
329 if (h.h1_grid)
330 h.h1_grid->Fill(ev.grid);
331
332 Int_t mult = 0;
333 for (Int_t k = 0; k < Constants::N_ARR_SLOTS; k++)
334 mult += ev.hits_adc[k];
335 h.h_mult->Fill(Double_t(mult));
336
337 // Collect sample traces
338 if (sample_stride > 0 && j % sample_stride == 0 &&
339 Int_t(sample_traces.size()) < Constants::cfg.SAVE_SAMPLE_TRACES) {
340 sample_traces.push_back(EventsSummary::BuildTraceFromTotals(ev.total));
341 }
342 }
343
344 {
345 std::lock_guard<std::mutex> lock(g_plot_mutex);
346 TString subdir = "events_summary_normed/" + file_label;
347 SaveAndDeleteSummaryHistograms(h, input_file, subdir, "_normed");
348
349 // Sample traces overlay
350 if (!sample_traces.empty()) {
351 SaveSampleTraces(sample_traces, "sample_traces_normed", subdir,
352 strip_e_min, strip_e_max, "#DeltaE [a.u.]");
353 }
354 }
355
356 for (Int_t i = 0; i < Int_t(sample_traces.size()); i++)
357 delete sample_traces[i];
358
359 input_file->Close();
360 delete input_file;
361}
362
363TGraph *EventsSummary::BuildTraceFromTotals(const Double_t *total) {
364 Int_t s_lo = Constants::cfg.IGNORE_STRIP_0 ? 1 : 0;
365 Int_t s_hi = Constants::cfg.IGNORE_STRIP_17 ? 16 : 17;
366 Int_t n_pts = s_hi - s_lo + 1;
367 TGraph *g = new TGraph(n_pts);
368 for (Int_t k = 0; k < n_pts; k++)
369 g->SetPoint(k, s_lo + k, total[s_lo + k]);
370 return g;
371}
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.
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.
const Int_t N_ARR_SLOTS
Length of the per-event channel arrays.
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.
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[18]
Summed energy per strip, after strip_factor.
Bool_t is_normed
Whether a calibration tree was found.
Double_t right[18]
Right-side energy per strip.
Double_t left[18]
Left-side energy per strip.
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.
TH1F * h_mult
Hit multiplicity per event.
TH1F * h1_strip17
Strip 17 energy.
TH2F * h2_long_vs_short[18]
Long against short gate, per strip.
TH1F * h1_grid
Grid energy.