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 (i % 50000 == 0 && i > 0) {
80 std::cout <<
" Progress: " << i <<
"/" << candidate_count << std::endl;
88 const std::vector<Double_t> &ref_y,
89 const std::vector<Double_t> &gr_x,
90 const std::vector<Double_t> &gr_y, Double_t shift,
91 Double_t thresh_dt_us, Int_t &npts, Double_t &nsd2) {
95 Double_t tmin_gr = gr_x.empty() ? 0 : gr_x.front() - shift;
96 Double_t tmax_gr = gr_x.empty() ? 0 : gr_x.back() - shift;
97 Double_t tmin_ref = ref_x.empty() ? 0 : ref_x.front();
98 Double_t tmax_ref = ref_x.empty() ? 0 : ref_x.back();
100 Double_t tmin = TMath::Max(tmin_ref, tmin_gr);
101 Double_t tmax = TMath::Min(tmax_ref, tmax_gr);
105 for (Int_t p = 0; p < Int_t(ref_x.size()); p++) {
106 Double_t tref = ref_x[p];
107 Double_t dtref = ref_y[p];
109 if (tref < tmin || tref > tmax || dtref <= thresh_dt_us)
112 Double_t tref_shifted = tref + shift;
114 while (gr_idx < Int_t(gr_x.size()) - 1 && gr_x[gr_idx + 1] < tref_shifted)
117 if (gr_idx >= Int_t(gr_x.size()) - 1)
120 Double_t x0 = gr_x[gr_idx];
121 Double_t x1 = gr_x[gr_idx + 1];
122 Double_t y0 = gr_y[gr_idx];
123 Double_t y1 = gr_y[gr_idx + 1];
125 Double_t dt = y0 + (y1 - y0) * (tref_shifted - x0) / (x1 - x0);
126 nsd2 += pow(dt - dtref, 2);
130 if (nsd2 > 0 && npts > 0) {
131 nsd2 = sqrt(nsd2) / npts;
181 TH2F *h_before_zoom, TH2F *h_after_zoom,
182 const TString &file_label,
183 Double_t before_zoom_t0_s,
184 Double_t after_zoom_t0_s) {
186 TString subdir =
"timing/" + file_label;
188 TCanvas *c_before = PlottingUtils::GetConfiguredCanvas(kFALSE);
189 PlottingUtils::ConfigureAndDraw2DHistogram(h_before, c_before);
190 c_before->SetLogz(kFALSE);
192 PlottingUtils::SaveFigure(c_before,
"extreme_events_before", subdir,
193 PlotSaveOptions::kLINEAR);
196 TCanvas *c_after = PlottingUtils::GetConfiguredCanvas(kFALSE);
197 PlottingUtils::ConfigureAndDraw2DHistogram(h_after, c_after);
198 c_after->SetLogz(kFALSE);
200 PlottingUtils::SaveFigure(c_after,
"extreme_events_after", subdir,
201 PlotSaveOptions::kLINEAR);
204 Int_t n = gStyle->GetNumberOfColors();
205 std::vector<Int_t> old_palette;
206 old_palette.reserve(n);
208 for (Int_t i = 0; i < n; i++) {
209 old_palette.push_back(gStyle->GetColorPalette(i));
213 palette[0] = TColor::GetColor(
"#FFFFFF");
214 palette[1] = TColor::GetColor(
"#D62728");
217 TCanvas *c_before_zoom = PlottingUtils::GetConfiguredCanvas(kFALSE);
218 PlottingUtils::Configure2DHistogram(h_before_zoom, c_before_zoom);
220 gStyle->SetPalette(2, palette);
221 h_before_zoom->SetMinimum(0);
222 h_before_zoom->SetMaximum(1);
223 c_before_zoom->SetLogz(kFALSE);
224 h_before_zoom->Draw();
225 c_before_zoom->SetRightMargin(0.07);
227 PlottingUtils::SaveFigure(c_before_zoom,
"extreme_events_before_zoom_us",
228 subdir, PlotSaveOptions::kLINEAR);
229 delete c_before_zoom;
233 TCanvas *c_after_zoom = PlottingUtils::GetConfiguredCanvas(kFALSE);
234 PlottingUtils::Configure2DHistogram(h_after_zoom, c_after_zoom);
236 gStyle->SetPalette(2, palette);
237 h_after_zoom->SetMinimum(0);
238 h_after_zoom->SetMaximum(1);
239 c_after_zoom->SetLogz(kFALSE);
240 h_after_zoom->Draw();
241 c_after_zoom->SetRightMargin(0.07);
243 PlottingUtils::SaveFigure(c_after_zoom,
"extreme_events_after_zoom_us",
244 subdir, PlotSaveOptions::kLINEAR);
247 if (!old_palette.empty()) {
248 gStyle->SetPalette(
static_cast<Int_t
>(old_palette.size()),
254 const std::vector<Double_t> &inv_nsd2_values,
255 Double_t best_shift, UShort_t ref_board,
256 UShort_t board,
const TString &file_label,
257 const TString &tag) {
260 std::vector<std::pair<Double_t, Double_t>> points;
261 points.reserve(shifts.size());
262 for (Int_t i = 0; i < Int_t(shifts.size()); i++) {
263 points.push_back(std::make_pair(shifts[i], inv_nsd2_values[i]));
265 std::sort(points.begin(), points.end());
267 TGraph *g =
new TGraph();
269 for (Int_t i = 0; i < Int_t(points.size()); i++) {
270 g->SetPoint(g->GetN(), points[i].first, points[i].second);
271 if (points[i].second > y_max)
272 y_max = points[i].second;
275 TCanvas *canvas = PlottingUtils::GetConfiguredCanvas(kFALSE);
276 PlottingUtils::ConfigureGraph(
278 Form(
"Cost landscape Board %d-%d;Candidate shift [s];1/NSD^{2}",
280 g->SetLineWidth(PlottingUtils::GetLineWidth());
283 TLine *best =
new TLine(best_shift, 0, best_shift, 1.05 * y_max);
284 best->SetLineColor(kRed + 1);
285 best->SetLineStyle(2);
286 best->SetLineWidth(PlottingUtils::GetLineWidth());
289 PlottingUtils::AddText(Form(
"best shift = %.6f s", best_shift), 0.85, 0.85);
292 PlottingUtils::SaveFigure(
293 canvas, Form(
"cost_landscape_board_%d%s", board, tag.Data()),
294 "timing/" + file_label, PlotSaveOptions::kLINEAR);
299 Double_t overlap_tmax_s, Double_t thresh_dt_us,
300 UShort_t ref_board, UShort_t board,
301 const TString &file_label) {
303 std::vector<Double_t> ref_x(ref->GetN()), ref_y(ref->GetN());
304 std::vector<Double_t> gr_x(gr->GetN()), gr_y(gr->GetN());
306 std::cout <<
"Caching graph data..." << std::endl;
307 for (Int_t i = 0; i < ref->GetN(); i++) {
308 ref->GetPoint(i, ref_x[i], ref_y[i]);
310 for (Int_t i = 0; i < gr->GetN(); i++) {
311 gr->GetPoint(i, gr_x[i], gr_y[i]);
314 const Double_t coarse_step_s =
316 const Double_t fine_step_s =
Constants::cfg.TIMING_SHIFT_FINE_STEP_US * 1e-6;
317 const Double_t fine_half_width_s =
320 const Double_t scan_min_s = -
Constants::cfg.TIMING_MAX_ABS_SHIFT_S;
321 const Double_t scan_max_s =
Constants::cfg.TIMING_MAX_ABS_SHIFT_S;
323 std::cout <<
"Looking for timeshift between " << overlap_tmin_s <<
" - "
324 << overlap_tmax_s <<
" sec" << std::endl;
325 std::cout <<
"Max absolute shift range: [" << scan_min_s <<
", " << scan_max_s
326 <<
"] s ([" << scan_min_s * 1e6 <<
", " << scan_max_s * 1e6
327 <<
"] us)" << std::endl;
328 std::cout <<
"Coarse step: " << coarse_step_s <<
" s ("
331 std::cout <<
"Fine step: " << fine_step_s <<
" s ("
332 <<
Constants::cfg.TIMING_SHIFT_FINE_STEP_US <<
" us)" << std::endl;
333 std::cout <<
"Fine half-width: " << fine_half_width_s <<
" s ("
339 coarse_step_s, thresh_dt_us,
"Coarse");
341 Double_t final_shift = 0.0;
342 Double_t final_inv_nsd2 = 0.0;
347 std::cout <<
"Coarse best: shift = " << coarse.
best_shift <<
" s ("
350 <<
", npts = " << coarse.
best_npts << std::endl;
352 Double_t fine_min_s = coarse.
best_shift - fine_half_width_s;
353 Double_t fine_max_s = coarse.
best_shift + fine_half_width_s;
355 if (fine_min_s < scan_min_s)
356 fine_min_s = scan_min_s;
357 if (fine_max_s > scan_max_s)
358 fine_max_s = scan_max_s;
360 fine =
ScanShiftRange(ref_x, ref_y, gr_x, gr_y, fine_min_s, fine_max_s,
361 fine_step_s, thresh_dt_us,
"Fine");
366 std::cout <<
"Fine best: shift = " << fine.
best_shift <<
" s ("
369 <<
", npts = " << fine.
best_npts << std::endl;
373 std::cout <<
"Fine scan found no valid candidate; falling back to coarse "
378 std::cerr <<
"WARNING: Coarse scan found no valid candidate. Returning 0.0 "
385 ComputeNSD2(ref_x, ref_y, gr_x, gr_y, 0.0, thresh_dt_us, npts0, nsd2_0);
386 Double_t inv_nsd2_zero =
387 (npts0 >
Constants::cfg.TIMING_SHIFT_MIN_NPTS) ? 1.0 / nsd2_0 : 0.0;
389 std::cout <<
"No-shift : 0 s (1/NSD2 = " << inv_nsd2_zero
390 <<
", npts=" << npts0 <<
")" << std::endl;
391 if (inv_nsd2_zero > 0 && final_inv_nsd2 > 0)
392 std::cout <<
" Improvement vs no-shift: " << final_inv_nsd2 / inv_nsd2_zero
395 std::cout <<
"Final selected shift: " << final_shift <<
" s ("
396 << final_shift * 1e6 <<
" us)" << std::endl;
400 board, file_label,
"_fine");
401 if (!coarse.
shifts.empty())
403 coarse.
best_shift, ref_board, board, file_label,
405 }
else if (!coarse.
shifts.empty()) {
407 ref_board, board, file_label,
"_coarse");
414 const std::vector<RawHit> &hits,
const std::vector<LongChan> &channels,
415 Double_t min_energy, Double_t max_energy, Double_t tmin_s, Double_t tmax_s,
416 Double_t thresh_dt_us) {
418 std::map<std::pair<Int_t, Int_t>, Int_t> chan_to_idx;
419 for (Int_t i = 0; i < Int_t(channels.size()); i++) {
420 chan_to_idx[std::pair<Int_t, Int_t>(channels[i].board,
421 channels[i].channel)] = i;
424 std::vector<std::vector<ULong64_t>> per_chan_ts(channels.size());
425 for (Int_t i = 0; i < Int_t(channels.size()); i++) {
426 per_chan_ts[i].reserve(10000);
429 Long64_t n_entries = Long64_t(hits.size());
430 std::cout <<
"Single-pass extraction across " << channels.size()
431 <<
" long channels (in-memory, " << n_entries <<
" hits)..."
434 for (Long64_t i = 0; i < n_entries; i++) {
435 const RawHit &h = hits[i];
436 if (h.energy < min_energy || h.energy > max_energy)
438 Double_t time_s = h.timestamp / 1e12;
439 if (time_s < tmin_s || time_s > tmax_s)
442 std::map<std::pair<Int_t, Int_t>, Int_t>::const_iterator it =
443 chan_to_idx.find(std::pair<Int_t, Int_t>(h.board, h.channel));
444 if (it == chan_to_idx.end())
447 per_chan_ts[it->second].push_back(h.timestamp);
449#if MUSIC_HOT_PATH_LOGGING
450 if (i % 10000000 == 0)
451 std::cout <<
" Progress: " << i <<
"/" << n_entries << std::endl;
455 std::vector<TGraph *> graphs;
456 graphs.reserve(channels.size());
457 for (Int_t c = 0; c < Int_t(channels.size()); c++) {
458 TGraph *g =
new TGraph();
459 const std::vector<ULong64_t> &ts = per_chan_ts[c];
460 for (Int_t i = 0; i + 1 < Int_t(ts.size()); i++) {
461 Double_t dt_us = (ts[i + 1] - ts[i]) / 1e6;
462 if (dt_us > thresh_dt_us) {
463 Double_t time_s = ts[i] / 1e12;
464 g->SetPoint(g->GetN(), time_s, dt_us);
467 std::cout <<
" " << channels[c].name <<
" (B" << channels[c].board <<
"C"
468 << channels[c].channel <<
"): " << ts.size() <<
" hits, "
469 << g->GetN() <<
" extreme events" << std::endl;
477 const std::vector<RawHit> &hits,
const TString &file_label,
478 UShort_t ref_board,
const std::vector<UShort_t> &board_channels,
479 Double_t min_energy, Double_t max_energy, Double_t overlap_margin_s,
480 Double_t thresh_dt_us) {
489 std::cout <<
"Board sync disabled for this dataset; skipping timeshift "
490 "calculation (all board shifts = 0)."
496 std::cerr <<
"CalcTimeShiftsBeamMethodFromHits: empty hits vector"
501 ULong64_t ts_min = hits[0].timestamp;
502 ULong64_t ts_max = hits[0].timestamp;
503 for (Int_t i = 1; i < Int_t(hits.size()); i++) {
504 if (hits[i].timestamp < ts_min)
505 ts_min = hits[i].timestamp;
506 if (hits[i].timestamp > ts_max)
507 ts_max = hits[i].timestamp;
509 Double_t file_tmin_s = ts_min / 1e12;
510 Double_t file_tmax_s = ts_max / 1e12;
511 Double_t overlap_tmin_s = file_tmin_s + overlap_margin_s;
512 Double_t overlap_tmax_s = file_tmax_s - overlap_margin_s;
513 std::cout <<
"File span [" << file_tmin_s <<
", " << file_tmax_s
514 <<
"] s, using overlap [" << overlap_tmin_s <<
", "
515 << overlap_tmax_s <<
"] s" << std::endl;
519 hits, long_channels, min_energy, max_energy, overlap_tmin_s,
520 overlap_tmax_s, thresh_dt_us);
522 std::map<UShort_t, Int_t> board_to_ref_idx;
523 for (Int_t i = 0; i < Int_t(long_channels.size()); i++) {
524 if (long_channels[i].channel == board_channels[long_channels[i].board])
525 board_to_ref_idx[long_channels[i].board] = i;
528 std::map<UShort_t, Int_t>::const_iterator ref_it =
529 board_to_ref_idx.find(ref_board);
530 if (ref_it == board_to_ref_idx.end()) {
531 std::cerr <<
"Reference board " << ref_board
532 <<
" ref channel is not in long-channel list" << std::endl;
533 for (Int_t k = 0; k < Int_t(long_graphs.size()); k++)
534 delete long_graphs[k];
537 TGraph *ref_graph = long_graphs[ref_it->second];
542 if (board == ref_board)
545 std::map<UShort_t, Int_t>::const_iterator it = board_to_ref_idx.find(board);
546 if (it == board_to_ref_idx.end()) {
547 std::cout <<
"WARNING: Board " << board
548 <<
" ref channel not in long-channel list" << std::endl;
552 TGraph *board_graph = long_graphs[it->second];
553 if (board_graph->GetN() < 10) {
554 std::cout <<
"WARNING: Not enough data points for Board " << board
559 std::cout <<
"Processing Board " << board <<
" Channel "
560 << board_channels[board] << std::endl;
564 overlap_tmin_s + 0.1 * (overlap_tmax_s - overlap_tmin_s),
565 overlap_tmax_s - 0.1 * (overlap_tmax_s - overlap_tmin_s),
566 thresh_dt_us, ref_board, board, file_label);
568 board_shifts_s[board] = shift_s;
569 Long64_t shift_ps =
static_cast<Long64_t
>(shift_s * 1e12);
572 std::cout <<
"Board " << ref_board <<
"-" << board <<
" shift: " << shift_s
573 <<
" s (" << shift_ps <<
" ps)" << std::endl;
576 Int_t time_bins = TMath::Min(
578 TMath::Max(100,
static_cast<Int_t
>((file_tmax_s - file_tmin_s) * 50.0)));
579 Int_t n_y =
static_cast<Int_t
>(long_channels.size());
581 TH2F *h_extreme_before =
582 new TH2F(
"hExtremeBefore",
";Time [s];", time_bins, file_tmin_s,
583 file_tmax_s, n_y, -0.5, n_y - 0.5);
585 TH2F *h_extreme_after =
586 new TH2F(
"hExtremeAfter",
";Time [s];", time_bins, file_tmin_s,
587 file_tmax_s, n_y, -0.5, n_y - 0.5);
589 std::vector<Double_t> extreme_times_before;
590 std::vector<Double_t> extreme_times_after;
592 extreme_times_before.reserve(10000);
593 extreme_times_after.reserve(10000);
595 for (Int_t c = 0; c < Int_t(long_channels.size()); c++) {
596 TGraph *g = long_graphs[c];
597 Double_t shift_s = board_shifts_s[long_channels[c].board];
599 for (Int_t k = 0; k < g->GetN(); k++) {
601 g->GetPoint(k, x, y);
603 Double_t x_before_s = x;
604 Double_t x_after_s = x - shift_s;
606 h_extreme_before->Fill(x_before_s, Double_t(c));
607 h_extreme_after->Fill(x_after_s, Double_t(c));
609 extreme_times_before.push_back(x_before_s);
610 extreme_times_after.push_back(x_after_s);
614 const Double_t zoom_width_us = 1000.0;
615 const Double_t zoom_width_s = zoom_width_us * 1e-6;
619 TMath::Min(2000, TMath::Max(100,
static_cast<Int_t
>(zoom_width_us)));
624 extreme_times_after, zoom_width_s, file_tmin_s);
626 Double_t before_zoom_t0_s = after_zoom_t0_s;
628 std::cout <<
"Zoom window before: [" << before_zoom_t0_s <<
", "
629 << before_zoom_t0_s + zoom_width_s <<
"] s" << std::endl;
631 std::cout <<
"Zoom window after : [" << after_zoom_t0_s <<
", "
632 << after_zoom_t0_s + zoom_width_s <<
"] s" << std::endl;
634 TH2F *h_extreme_before_zoom =
635 new TH2F(
"hExtremeBeforeZoom",
";Time [#mus];", zoom_bins, 0.0,
636 zoom_width_us, n_y, -0.5, n_y - 0.5);
638 TH2F *h_extreme_after_zoom =
639 new TH2F(
"hExtremeAfterZoom",
";Time [#mus];", zoom_bins, 0.0,
640 zoom_width_us, n_y, -0.5, n_y - 0.5);
643 for (Int_t b = 0; b < n_y; b++) {
645 Form(
"B%d %s", long_channels[b].board, long_channels[b].name.Data());
647 h_extreme_before->GetYaxis()->SetBinLabel(b + 1, label);
648 h_extreme_after->GetYaxis()->SetBinLabel(b + 1, label);
650 h_extreme_before_zoom->GetYaxis()->SetBinLabel(b + 1, label);
651 h_extreme_after_zoom->GetYaxis()->SetBinLabel(b + 1, label);
656 Int_t n_zoom_before = 0;
657 Int_t n_zoom_after = 0;
659 for (Int_t c = 0; c < Int_t(long_channels.size()); c++) {
660 TGraph *g = long_graphs[c];
661 Double_t shift_s = board_shifts_s[long_channels[c].board];
663 for (Int_t k = 0; k < g->GetN(); k++) {
665 g->GetPoint(k, x, y);
667 Double_t x_before_s = x;
668 Double_t x_after_s = x - shift_s;
670 Double_t x_before_zoom_us = (x_before_s - before_zoom_t0_s) * 1e6;
671 Double_t x_after_zoom_us = (x_after_s - after_zoom_t0_s) * 1e6;
673 if (x_before_zoom_us >= 0.0 && x_before_zoom_us <= zoom_width_us) {
674 h_extreme_before_zoom->Fill(x_before_zoom_us, Double_t(c));
678 if (x_after_zoom_us >= 0.0 && x_after_zoom_us <= zoom_width_us) {
679 h_extreme_after_zoom->Fill(x_after_zoom_us, Double_t(c));
685 std::cout <<
"Zoom plot entries before correction: " << n_zoom_before
687 std::cout <<
"Zoom plot entries after correction : " << n_zoom_after
691 h_extreme_after_zoom, file_label, before_zoom_t0_s,
693 std::cout <<
"RESULTS (ref board = " << ref_board <<
")" << std::endl;
695 if (board == ref_board)
697 std::cout <<
" Board " << ref_board <<
"-" << board <<
": "
698 << result.
board_shifts[board] * 1e-12 <<
" s" << std::endl;
701 delete h_extreme_before;
702 delete h_extreme_after;
703 delete h_extreme_before_zoom;
704 delete h_extreme_after_zoom;
706 for (Int_t k = 0; k < Int_t(long_graphs.size()); k++)
707 delete long_graphs[k];