15 const std::vector<Double_t> &ref_y,
16 const std::vector<Double_t> &gr_x,
17 const std::vector<Double_t> &gr_y,
18 Double_t shift_min_s, Double_t shift_max_s,
19 Double_t shift_step_s, Double_t thresh_dt_us,
20 const TString &label) {
24 if (shift_step_s <= 0) {
25 std::cerr << label <<
": shift_step_s <= 0 (" << shift_step_s
26 <<
"), skipping scan." << std::endl;
30 if (shift_min_s > shift_max_s) {
31 std::cerr << label <<
": shift_min_s > shift_max_s (" << shift_min_s
32 <<
" > " << shift_max_s <<
"), skipping scan." << std::endl;
36 Int_t candidate_count =
static_cast<Int_t
>(std::floor(
37 (shift_max_s - shift_min_s) / shift_step_s)) +
40 if (candidate_count >
Constants::cfg.TIMING_SHIFT_MAX_SCAN_CANDIDATES) {
41 std::cerr << label <<
": candidate count " << candidate_count
44 <<
", skipping scan." << std::endl;
48 std::cout <<
" " << label <<
" range: [" << shift_min_s <<
", "
49 << shift_max_s <<
"] s ([" << shift_min_s * 1e6 <<
", "
50 << shift_max_s * 1e6 <<
"] us)" << std::endl;
51 std::cout <<
" " << label <<
" step: " << shift_step_s <<
" s ("
52 << shift_step_s * 1e6 <<
" us)" << std::endl;
53 std::cout <<
" " << label <<
" candidates: " << candidate_count << std::endl;
55 result.
shifts.reserve(candidate_count);
58 for (Int_t i = 0; i < candidate_count; i++) {
59 Double_t shift = shift_min_s + i * shift_step_s;
67 Double_t inv_nsd2 = 1.0 / nsd2;
68 result.
shifts.push_back(shift);
79#if MUSIC_HOT_PATH_LOGGING
80 if (i % 50000 == 0 && i > 0)
81 std::cout <<
" Progress: " << i <<
"/" << candidate_count << std::endl;
89 const std::vector<Double_t> &ref_y,
90 const std::vector<Double_t> &gr_x,
91 const std::vector<Double_t> &gr_y, Double_t shift,
92 Double_t thresh_dt_us, Int_t &npts, Double_t &nsd2) {
96 Double_t tmin_gr = gr_x.empty() ? 0 : gr_x.front() - shift;
97 Double_t tmax_gr = gr_x.empty() ? 0 : gr_x.back() - shift;
98 Double_t tmin_ref = ref_x.empty() ? 0 : ref_x.front();
99 Double_t tmax_ref = ref_x.empty() ? 0 : ref_x.back();
101 Double_t tmin = TMath::Max(tmin_ref, tmin_gr);
102 Double_t tmax = TMath::Min(tmax_ref, tmax_gr);
106 for (Int_t p = 0; p < Int_t(ref_x.size()); p++) {
107 Double_t tref = ref_x[p];
108 Double_t dtref = ref_y[p];
110 if (tref < tmin || tref > tmax || dtref <= thresh_dt_us)
113 Double_t tref_shifted = tref + shift;
115 while (gr_idx < Int_t(gr_x.size()) - 1 && gr_x[gr_idx + 1] < tref_shifted)
118 if (gr_idx >= Int_t(gr_x.size()) - 1)
121 Double_t x0 = gr_x[gr_idx];
122 Double_t x1 = gr_x[gr_idx + 1];
123 Double_t y0 = gr_y[gr_idx];
124 Double_t y1 = gr_y[gr_idx + 1];
126 Double_t dt = y0 + (y1 - y0) * (tref_shifted - x0) / (x1 - x0);
127 nsd2 += pow(dt - dtref, 2);
131 if (nsd2 > 0 && npts > 0) {
132 nsd2 = sqrt(nsd2) / npts;
139 if (name ==
"Strip0" || name ==
"Strip17")
141 if (name.Length() < 2)
143 Char_t side = name[0];
144 if (side !=
'L' && side !=
'R')
150 Int_t n = num.Atoi();
151 if (side ==
'L' && (n % 2 == 1))
153 if (side ==
'R' && (n % 2 == 0))
165 std::vector<LongChan> list;
166 std::map<std::pair<Int_t, Int_t>, TString>::const_iterator it;
172 lc.
board =
static_cast<UShort_t
>(it->first.first);
173 lc.
channel =
static_cast<UShort_t
>(it->first.second);
174 lc.
name = it->second;
182 TH2F *h_before_zoom, TH2F *h_after_zoom,
183 const TString &file_label) {
185 TString subdir =
"timing/" + file_label;
187 TCanvas *c_before = PlottingUtils::GetConfiguredCanvas(kFALSE);
188 PlottingUtils::ConfigureAndDraw2DHistogram(h_before, c_before);
189 c_before->SetLogz(kFALSE);
191 PlottingUtils::SaveFigure(c_before,
"extreme_events_before", subdir,
192 PlotSaveOptions::kLINEAR);
195 TCanvas *c_after = PlottingUtils::GetConfiguredCanvas(kFALSE);
196 PlottingUtils::ConfigureAndDraw2DHistogram(h_after, c_after);
197 c_after->SetLogz(kFALSE);
199 PlottingUtils::SaveFigure(c_after,
"extreme_events_after", subdir,
200 PlotSaveOptions::kLINEAR);
203 Int_t n = gStyle->GetNumberOfColors();
204 std::vector<Int_t> old_palette;
205 old_palette.reserve(n);
207 for (Int_t i = 0; i < n; i++) {
208 old_palette.push_back(gStyle->GetColorPalette(i));
212 palette[0] = TColor::GetColor(
"#FFFFFF");
213 palette[1] = TColor::GetColor(
"#D62728");
216 TCanvas *c_before_zoom = PlottingUtils::GetConfiguredCanvas(kFALSE);
217 PlottingUtils::Configure2DHistogram(h_before_zoom, c_before_zoom);
219 gStyle->SetPalette(2, palette);
220 h_before_zoom->SetMinimum(0);
221 h_before_zoom->SetMaximum(1);
222 c_before_zoom->SetLogz(kFALSE);
223 h_before_zoom->Draw();
224 c_before_zoom->SetRightMargin(0.07);
226 PlottingUtils::SaveFigure(c_before_zoom,
"extreme_events_before_zoom_us",
227 subdir, PlotSaveOptions::kLINEAR);
228 delete c_before_zoom;
232 TCanvas *c_after_zoom = PlottingUtils::GetConfiguredCanvas(kFALSE);
233 PlottingUtils::Configure2DHistogram(h_after_zoom, c_after_zoom);
235 gStyle->SetPalette(2, palette);
236 h_after_zoom->SetMinimum(0);
237 h_after_zoom->SetMaximum(1);
238 c_after_zoom->SetLogz(kFALSE);
239 h_after_zoom->Draw();
240 c_after_zoom->SetRightMargin(0.07);
242 PlottingUtils::SaveFigure(c_after_zoom,
"extreme_events_after_zoom_us",
243 subdir, PlotSaveOptions::kLINEAR);
246 if (!old_palette.empty()) {
247 gStyle->SetPalette(
static_cast<Int_t
>(old_palette.size()),
253 const std::vector<Double_t> &inv_nsd2_values,
254 Double_t best_shift, UShort_t ref_board,
255 UShort_t board,
const TString &file_label,
256 const TString &tag) {
259 std::vector<std::pair<Double_t, Double_t>> points;
260 points.reserve(shifts.size());
261 for (Int_t i = 0; i < Int_t(shifts.size()); i++) {
262 points.push_back(std::make_pair(shifts[i], inv_nsd2_values[i]));
264 std::sort(points.begin(), points.end());
266 TGraph *g =
new TGraph();
268 for (Int_t i = 0; i < Int_t(points.size()); i++) {
269 g->SetPoint(g->GetN(), points[i].first, points[i].second);
270 if (points[i].second > y_max)
271 y_max = points[i].second;
274 TCanvas *canvas = PlottingUtils::GetConfiguredCanvas(kFALSE);
275 PlottingUtils::ConfigureGraph(
277 Form(
"Cost landscape Board %d-%d;Candidate shift [s];1/NSD^{2}",
279 g->SetLineWidth(PlottingUtils::GetLineWidth());
282 TLine *best =
new TLine(best_shift, 0, best_shift, 1.05 * y_max);
283 best->SetLineColor(kRed + 1);
284 best->SetLineStyle(2);
285 best->SetLineWidth(PlottingUtils::GetLineWidth());
288 PlottingUtils::AddText(Form(
"best shift = %.6f s", best_shift), 0.85, 0.85);
291 PlottingUtils::SaveFigure(
292 canvas, Form(
"cost_landscape_board_%d%s", board, tag.Data()),
293 "timing/" + file_label, PlotSaveOptions::kLINEAR);
298 Double_t overlap_tmax_s, Double_t thresh_dt_us,
299 UShort_t ref_board, UShort_t board,
300 const TString &file_label) {
302 std::vector<Double_t> ref_x(ref->GetN()), ref_y(ref->GetN());
303 std::vector<Double_t> gr_x(gr->GetN()), gr_y(gr->GetN());
305 std::cout <<
"Caching graph data..." << std::endl;
306 for (Int_t i = 0; i < ref->GetN(); i++) {
307 ref->GetPoint(i, ref_x[i], ref_y[i]);
309 for (Int_t i = 0; i < gr->GetN(); i++) {
310 gr->GetPoint(i, gr_x[i], gr_y[i]);
313 const Double_t coarse_step_s =
315 const Double_t fine_step_s =
Constants::cfg.TIMING_SHIFT_FINE_STEP_US * 1e-6;
316 const Double_t fine_half_width_s =
319 const Double_t scan_min_s = -
Constants::cfg.TIMING_MAX_ABS_SHIFT_S;
320 const Double_t scan_max_s =
Constants::cfg.TIMING_MAX_ABS_SHIFT_S;
322 std::cout <<
"Looking for timeshift between " << overlap_tmin_s <<
" - "
323 << overlap_tmax_s <<
" sec" << std::endl;
324 std::cout <<
"Max absolute shift range: [" << scan_min_s <<
", " << scan_max_s
325 <<
"] s ([" << scan_min_s * 1e6 <<
", " << scan_max_s * 1e6
326 <<
"] us)" << std::endl;
327 std::cout <<
"Coarse step: " << coarse_step_s <<
" s ("
330 std::cout <<
"Fine step: " << fine_step_s <<
" s ("
331 <<
Constants::cfg.TIMING_SHIFT_FINE_STEP_US <<
" us)" << std::endl;
332 std::cout <<
"Fine half-width: " << fine_half_width_s <<
" s ("
338 coarse_step_s, thresh_dt_us,
"Coarse");
340 Double_t final_shift = 0.0;
341 Double_t final_inv_nsd2 = 0.0;
346 std::cout <<
"Coarse best: shift = " << coarse.
best_shift <<
" s ("
349 <<
", npts = " << coarse.
best_npts << std::endl;
351 Double_t fine_min_s = coarse.
best_shift - fine_half_width_s;
352 Double_t fine_max_s = coarse.
best_shift + fine_half_width_s;
354 if (fine_min_s < scan_min_s)
355 fine_min_s = scan_min_s;
356 if (fine_max_s > scan_max_s)
357 fine_max_s = scan_max_s;
359 fine =
ScanShiftRange(ref_x, ref_y, gr_x, gr_y, fine_min_s, fine_max_s,
360 fine_step_s, thresh_dt_us,
"Fine");
365 std::cout <<
"Fine best: shift = " << fine.
best_shift <<
" s ("
368 <<
", npts = " << fine.
best_npts << std::endl;
372 std::cout <<
"Fine scan found no valid candidate; falling back to coarse "
377 std::cerr <<
"WARNING: Coarse scan found no valid candidate. Returning 0.0 "
384 ComputeNSD2(ref_x, ref_y, gr_x, gr_y, 0.0, thresh_dt_us, npts0, nsd2_0);
385 Double_t inv_nsd2_zero =
386 (npts0 >
Constants::cfg.TIMING_SHIFT_MIN_NPTS) ? 1.0 / nsd2_0 : 0.0;
388 std::cout <<
"No-shift : 0 s (1/NSD2 = " << inv_nsd2_zero
389 <<
", npts=" << npts0 <<
")" << std::endl;
390 if (inv_nsd2_zero > 0 && final_inv_nsd2 > 0)
391 std::cout <<
" Improvement vs no-shift: " << final_inv_nsd2 / inv_nsd2_zero
394 std::cout <<
"Final selected shift: " << final_shift <<
" s ("
395 << final_shift * 1e6 <<
" us)" << std::endl;
399 board, file_label,
"_fine");
400 if (!coarse.
shifts.empty())
402 coarse.
best_shift, ref_board, board, file_label,
404 }
else if (!coarse.
shifts.empty()) {
406 ref_board, board, file_label,
"_coarse");
413 const std::vector<RawHit> &hits,
const std::vector<LongChan> &channels,
414 Double_t min_energy, Double_t max_energy, Double_t tmin_s, Double_t tmax_s,
415 Double_t thresh_dt_us) {
417 std::map<std::pair<Int_t, Int_t>, Int_t> chan_to_idx;
418 for (Int_t i = 0; i < Int_t(channels.size()); i++) {
419 chan_to_idx[std::pair<Int_t, Int_t>(channels[i].board,
420 channels[i].channel)] = i;
423 std::vector<std::vector<ULong64_t>> per_chan_ts(channels.size());
424 for (Int_t i = 0; i < Int_t(channels.size()); i++) {
425 per_chan_ts[i].reserve(10000);
428 Long64_t n_entries = Long64_t(hits.size());
429 std::cout <<
"Single-pass extraction across " << channels.size()
430 <<
" long channels (in-memory, " << n_entries <<
" hits)..."
433 for (Long64_t i = 0; i < n_entries; i++) {
434 const RawHit &h = hits[i];
435 if (h.energy < min_energy || h.energy > max_energy)
437 Double_t time_s = h.timestamp / 1e12;
438 if (time_s < tmin_s || time_s > tmax_s)
441 std::map<std::pair<Int_t, Int_t>, Int_t>::const_iterator it =
442 chan_to_idx.find(std::pair<Int_t, Int_t>(h.board, h.channel));
443 if (it == chan_to_idx.end())
446 per_chan_ts[it->second].push_back(h.timestamp);
448#if MUSIC_HOT_PATH_LOGGING
449 if (i % 10000000 == 0)
450 std::cout <<
" Progress: " << i <<
"/" << n_entries << std::endl;
454 std::vector<TGraph *> graphs;
455 graphs.reserve(channels.size());
456 for (Int_t c = 0; c < Int_t(channels.size()); c++) {
457 TGraph *g =
new TGraph();
458 const std::vector<ULong64_t> &ts = per_chan_ts[c];
459 for (Int_t i = 0; i + 1 < Int_t(ts.size()); i++) {
460 Double_t dt_us = (ts[i + 1] - ts[i]) / 1e6;
461 if (dt_us > thresh_dt_us) {
462 Double_t time_s = ts[i] / 1e12;
463 g->SetPoint(g->GetN(), time_s, dt_us);
466 std::cout <<
" " << channels[c].name <<
" (B" << channels[c].board <<
"C"
467 << channels[c].channel <<
"): " << ts.size() <<
" hits, "
468 << g->GetN() <<
" extreme events" << std::endl;
484static FileSpan MeasureFileSpan(
const std::vector<RawHit> &hits,
485 Double_t overlap_margin_s) {
486 ULong64_t ts_min = hits[0].timestamp;
487 ULong64_t ts_max = hits[0].timestamp;
488 for (Int_t i = 1; i < Int_t(hits.size()); i++) {
489 if (hits[i].timestamp < ts_min)
490 ts_min = hits[i].timestamp;
491 if (hits[i].timestamp > ts_max)
492 ts_max = hits[i].timestamp;
495 span.
tmin_s = ts_min / 1e12;
496 span.
tmax_s = ts_max / 1e12;
499 std::cout <<
"File span [" << span.
tmin_s <<
", " << span.
tmax_s
507static std::map<UShort_t, Int_t>
508RefIndexPerBoard(
const std::vector<LongChan> &long_channels,
509 const std::vector<UShort_t> &board_channels) {
510 std::map<UShort_t, Int_t> board_to_ref_idx;
511 for (Int_t i = 0; i < Int_t(long_channels.size()); i++) {
512 if (long_channels[i].channel == board_channels[long_channels[i].board])
513 board_to_ref_idx[long_channels[i].board] = i;
515 return board_to_ref_idx;
520static void MeasureBoardShifts(
521 const std::map<UShort_t, Int_t> &board_to_ref_idx,
522 const std::vector<TGraph *> &long_graphs, TGraph *ref_graph,
523 UShort_t ref_board,
const std::vector<UShort_t> &board_channels,
524 const FileSpan &span, Double_t thresh_dt_us,
const TString &file_label,
527 if (board == ref_board)
530 std::map<UShort_t, Int_t>::const_iterator it = board_to_ref_idx.find(board);
531 if (it == board_to_ref_idx.end()) {
532 std::cout <<
"WARNING: Board " << board
533 <<
" ref channel not in long-channel list" << std::endl;
537 TGraph *board_graph = long_graphs[it->second];
538 if (board_graph->GetN() < 10) {
539 std::cout <<
"WARNING: Not enough data points for Board " << board
544 std::cout <<
"Processing Board " << board <<
" Channel "
545 << board_channels[board] << std::endl;
548 ref_graph, board_graph,
551 thresh_dt_us, ref_board, board, file_label);
553 board_shifts_s[board] = shift_s;
554 Long64_t shift_ps =
static_cast<Long64_t
>(shift_s * 1e12);
557 std::cout <<
"Board " << ref_board <<
"-" << board <<
" shift: " << shift_s
558 <<
" s (" << shift_ps <<
" ps)" << std::endl;
564static void FillExtremeHistograms(TH2F *h_extreme_before, TH2F *h_extreme_after,
565 const std::vector<TGraph *> &long_graphs,
566 const std::vector<LongChan> &long_channels,
567 const std::vector<Double_t> &board_shifts_s,
568 std::vector<Double_t> &extreme_times_after) {
569 for (Int_t c = 0; c < Int_t(long_channels.size()); c++) {
570 TGraph *g = long_graphs[c];
571 Double_t shift_s = board_shifts_s[long_channels[c].board];
573 for (Int_t k = 0; k < g->GetN(); k++) {
575 g->GetPoint(k, x, y);
577 Double_t x_before_s = x;
578 Double_t x_after_s = x - shift_s;
580 h_extreme_before->Fill(x_before_s, Double_t(c));
581 h_extreme_after->Fill(x_after_s, Double_t(c));
583 extreme_times_after.push_back(x_after_s);
589static void LabelChannelAxes(TH2F *h_extreme_before, TH2F *h_extreme_after,
590 TH2F *h_extreme_before_zoom,
591 TH2F *h_extreme_after_zoom,
592 const std::vector<LongChan> &long_channels) {
593 for (Int_t b = 0; b < Int_t(long_channels.size()); b++) {
595 Form(
"B%d %s", long_channels[b].board, long_channels[b].name.Data());
597 h_extreme_before->GetYaxis()->SetBinLabel(b + 1, label);
598 h_extreme_after->GetYaxis()->SetBinLabel(b + 1, label);
600 h_extreme_before_zoom->GetYaxis()->SetBinLabel(b + 1, label);
601 h_extreme_after_zoom->GetYaxis()->SetBinLabel(b + 1, label);
607static void FillZoomHistograms(TH2F *h_extreme_before_zoom,
608 TH2F *h_extreme_after_zoom,
609 const std::vector<TGraph *> &long_graphs,
610 const std::vector<LongChan> &long_channels,
611 const std::vector<Double_t> &board_shifts_s,
612 Double_t before_zoom_t0_s,
613 Double_t after_zoom_t0_s, Double_t zoom_width_us,
614 Int_t &n_zoom_before, Int_t &n_zoom_after) {
615 for (Int_t c = 0; c < Int_t(long_channels.size()); c++) {
616 TGraph *g = long_graphs[c];
617 Double_t shift_s = board_shifts_s[long_channels[c].board];
619 for (Int_t k = 0; k < g->GetN(); k++) {
621 g->GetPoint(k, x, y);
623 Double_t x_before_s = x;
624 Double_t x_after_s = x - shift_s;
626 Double_t x_before_zoom_us = (x_before_s - before_zoom_t0_s) * 1e6;
627 Double_t x_after_zoom_us = (x_after_s - after_zoom_t0_s) * 1e6;
629 if (x_before_zoom_us >= 0.0 && x_before_zoom_us <= zoom_width_us) {
630 h_extreme_before_zoom->Fill(x_before_zoom_us, Double_t(c));
634 if (x_after_zoom_us >= 0.0 && x_after_zoom_us <= zoom_width_us) {
635 h_extreme_after_zoom->Fill(x_after_zoom_us, Double_t(c));
644 UShort_t ref_board) {
645 std::cout <<
"RESULTS (ref board = " << ref_board <<
")" << std::endl;
647 if (board == ref_board)
649 std::cout <<
" Board " << ref_board <<
"-" << board <<
": "
650 << result.
board_shifts[board] * 1e-12 <<
" s" << std::endl;
655 const std::vector<RawHit> &hits,
const TString &file_label,
656 UShort_t ref_board,
const std::vector<UShort_t> &board_channels,
657 Double_t min_energy, Double_t max_energy, Double_t overlap_margin_s,
658 Double_t thresh_dt_us) {
666 std::cout <<
"Board sync disabled for this dataset; skipping timeshift "
667 "calculation (all board shifts = 0)."
673 std::cerr <<
"CalcTimeShiftsBeamMethodFromHits: empty hits vector"
678 const FileSpan span = MeasureFileSpan(hits, overlap_margin_s);
685 const std::map<UShort_t, Int_t> board_to_ref_idx =
686 RefIndexPerBoard(long_channels, board_channels);
688 std::map<UShort_t, Int_t>::const_iterator ref_it =
689 board_to_ref_idx.find(ref_board);
690 if (ref_it == board_to_ref_idx.end()) {
691 std::cerr <<
"Reference board " << ref_board
692 <<
" ref channel is not in long-channel list" << std::endl;
693 for (Int_t k = 0; k < Int_t(long_graphs.size()); k++)
694 delete long_graphs[k];
697 TGraph *ref_graph = long_graphs[ref_it->second];
700 MeasureBoardShifts(board_to_ref_idx, long_graphs, ref_graph, ref_board,
701 board_channels, span, thresh_dt_us, file_label,
702 board_shifts_s, result);
704 Int_t time_bins = TMath::Min(
706 TMath::Max(100,
static_cast<Int_t
>((span.
tmax_s - span.
tmin_s) * 50.0)));
707 Int_t n_y =
static_cast<Int_t
>(long_channels.size());
709 TH2F *h_extreme_before =
710 new TH2F(
"hExtremeBefore",
";Time [s];", time_bins, span.
tmin_s,
711 span.
tmax_s, n_y, -0.5, n_y - 0.5);
713 TH2F *h_extreme_after =
714 new TH2F(
"hExtremeAfter",
";Time [s];", time_bins, span.
tmin_s,
715 span.
tmax_s, n_y, -0.5, n_y - 0.5);
717 std::vector<Double_t> extreme_times_after;
719 extreme_times_after.reserve(10000);
720 FillExtremeHistograms(h_extreme_before, h_extreme_after, long_graphs,
721 long_channels, board_shifts_s, extreme_times_after);
723 const Double_t zoom_width_us = 1000.0;
724 const Double_t zoom_width_s = zoom_width_us * 1e-6;
728 TMath::Min(2000, TMath::Max(100,
static_cast<Int_t
>(zoom_width_us)));
733 extreme_times_after, zoom_width_s, span.
tmin_s);
735 Double_t before_zoom_t0_s = after_zoom_t0_s;
737 std::cout <<
"Zoom window before: [" << before_zoom_t0_s <<
", "
738 << before_zoom_t0_s + zoom_width_s <<
"] s" << std::endl;
740 std::cout <<
"Zoom window after : [" << after_zoom_t0_s <<
", "
741 << after_zoom_t0_s + zoom_width_s <<
"] s" << std::endl;
743 TH2F *h_extreme_before_zoom =
744 new TH2F(
"hExtremeBeforeZoom",
";Time [#mus];", zoom_bins, 0.0,
745 zoom_width_us, n_y, -0.5, n_y - 0.5);
747 TH2F *h_extreme_after_zoom =
748 new TH2F(
"hExtremeAfterZoom",
";Time [#mus];", zoom_bins, 0.0,
749 zoom_width_us, n_y, -0.5, n_y - 0.5);
752 LabelChannelAxes(h_extreme_before, h_extreme_after, h_extreme_before_zoom,
753 h_extreme_after_zoom, long_channels);
757 Int_t n_zoom_before = 0;
758 Int_t n_zoom_after = 0;
759 FillZoomHistograms(h_extreme_before_zoom, h_extreme_after_zoom, long_graphs,
760 long_channels, board_shifts_s, before_zoom_t0_s,
761 after_zoom_t0_s, zoom_width_us, n_zoom_before,
764 std::cout <<
"Zoom plot entries before correction: " << n_zoom_before
766 std::cout <<
"Zoom plot entries after correction : " << n_zoom_after
770 h_extreme_after_zoom, file_label);
771 PrintBoardShifts(result, ref_board);
773 delete h_extreme_before;
774 delete h_extreme_after;
775 delete h_extreme_before_zoom;
776 delete h_extreme_after_zoom;
778 for (Int_t k = 0; k < Int_t(long_graphs.size()); k++)
779 delete long_graphs[k];
785 const std::vector<Long64_t> &board_shifts) {
786 for (Int_t i = 0; i < Int_t(hits.size()); i++) {
787 Long64_t board_shift = (hits[i].board < UShort_t(board_shifts.size()))
788 ? board_shifts[hits[i].board]
790 hits[i].timestamp = hits[i].timestamp + board_shift;
800 std::cerr <<
"[GPU] Sort failed (rc=" << rc <<
"), falling back to CPU."
803 std::sort(hits.begin(), hits.end(), [](
const RawHit &a,
const RawHit &b) {
804 return a.timestamp < b.timestamp;
809 Double_t window_width_s,
810 Double_t fallback_start_s) {
811 if (times.empty() || window_width_s <= 0)
812 return fallback_start_s;
814 std::sort(times.begin(), times.end());
817 Long64_t best_count = 0;
820 for (Long64_t i = 0; i < Long64_t(times.size()); i++) {
824 while (j < Long64_t(times.size()) && times[j] <= times[i] + window_width_s)
827 Long64_t count = j - i;
828 if (count > best_count) {
836 return times[best_i] - 0.05 * window_width_s;
std::mutex g_plot_mutex
Serialises all plotting and canvas work.
ShiftScanResult ScanShiftRange(const std::vector< Double_t > &ref_x, const std::vector< Double_t > &ref_y, const std::vector< Double_t > &gr_x, const std::vector< Double_t > &gr_y, Double_t shift_min_s, Double_t shift_max_s, Double_t shift_step_s, Double_t thresh_dt_us, const TString &label)
Aligning the clocks of independent digitiser boards.
static Bool_t TryAcquireSortSlot()
Claim one of the concurrent GPU sort slots.
static void ReleaseSortSlot()
Give back a slot claimed by TryAcquireSortSlot().
static SortFunc GetSort()
The resolved sort entry point.
static Bool_t Available()
Whether the kernel loaded successfully.
static Double_t FindDensestTimeWindowStartS(std::vector< Double_t > times, Double_t window_width_s, Double_t fallback_start_s)
Start of the busiest window of a given width.
static TimeShiftResult CalcTimeShiftsBeamMethodFromHits(const std::vector< RawHit > &hits, const TString &file_label, UShort_t ref_board, const std::vector< UShort_t > &board_channels, Double_t min_energy, Double_t max_energy, Double_t overlap_margin_s, Double_t thresh_dt_us)
Measure every board's offset against a reference board.
static void SortHitsByTimestamp(std::vector< RawHit > &hits)
Sort hits into ascending timestamp order, in place.
static void ComputeNSD2(const std::vector< Double_t > &ref_x, const std::vector< Double_t > &ref_y, const std::vector< Double_t > &gr_x, const std::vector< Double_t > &gr_y, Double_t shift, Double_t thresh_dt_us, Int_t &npts, Double_t &nsd2)
Normalised squared deviation between two timing structures at a shift.
static void ApplyShiftsInPlace(std::vector< RawHit > &hits, const std::vector< Long64_t > &board_shifts)
Add the measured offsets to the hits, in place.
static void PlotExtremeEvents2D(TH2F *h_before, TH2F *h_after, TH2F *h_before_zoom, TH2F *h_after_zoom, const TString &file_label)
Save the before-and-after alignment diagnostic figures.
static std::vector< LongChan > BuildLongChannelList()
Every long-end channel in the active map, in stable order.
static Bool_t LongChanOrder(const LongChan &a, const LongChan &b)
Ordering predicate giving a stable channel sequence.
static std::vector< TGraph * > ExtractAllChannelsTimingStructureFromHits(const std::vector< RawHit > &hits, const std::vector< LongChan > &channels, Double_t min_energy, Double_t max_energy, Double_t tmin_s, Double_t tmax_s, Double_t thresh_dt_us)
Build the beam timing structure for each channel.
static void PlotCostLandscape(const std::vector< Double_t > &shifts, const std::vector< Double_t > &inv_nsd2_values, Double_t best_shift, UShort_t ref_board, UShort_t board, const TString &file_label, const TString &tag)
Save the shift-search cost landscape for one board pair.
static Bool_t IsLongChannel(const TString &name)
Whether a channel name denotes a long end.
static Double_t FindShiftBeam(TGraph *ref, TGraph *gr, Double_t overlap_tmin_s, Double_t overlap_tmax_s, Double_t thresh_dt_us, UShort_t ref_board, UShort_t board, const TString &file_label)
Best shift aligning one board's beam structure to the reference's.
Bool_t ActiveDoBoardSync()
Whether to run the multi-board timing alignment.
Bool_t SavePlots()
FileInSample(), by the name the plot call sites use.
const std::map< std::pair< Int_t, Int_t >, TString > & ActiveChannelMap()
The channel map in force.
Int_t ActiveNBoards()
Boards in the active epoch's setup.
const DatasetConfig & cfg
The active dataset's configuration, flat block.
One long-end channel, used as a timing reference.
UShort_t channel
Channel on that board.
TString name
Channel name from the active map.
std::vector< Double_t > inv_nsd2_values
std::vector< Double_t > shifts
Per-board timing offsets, indexed by board number.
std::vector< Long64_t > board_shifts
Offset to add to each board's timestamps, in picoseconds.