7 TString full = IO::GetRootFilesBaseDir() +
"/" + subpath;
8 return !gSystem->AccessPathName(full);
11Double_t
FusedSecSince(
const std::chrono::steady_clock::time_point &t0) {
12 return std::chrono::duration<Double_t>(std::chrono::steady_clock::now() - t0)
22 std::ifstream statm(
"/proc/self/statm");
24 statm >> dummy >> rss;
25 Double_t rss_gb = rss * 4096.0 / (1024.0 * 1024.0 * 1024.0);
27 std::cout <<
"[MEM] " << label <<
": " << rss_gb <<
" GB RSS" << std::endl;
37 Bool_t found = kFALSE;
38 for (Int_t k = 0; k < Int_t(suffixes.size()); k++) {
43 if (gSystem->AccessPathName(sol_path))
47 if (!reader.Open(sol_path.Data()))
49 if (!reader.ReadEvent()) {
53 header = reader.GetCurrentEvent().block_header;
59 std::cerr <<
"SOL header gather FAILED for run " << run
60 <<
" (no accessible files)" << std::endl;
69 std::pair<std::vector<RawHit>, UShort_t> p =
70 InitUtils::ConvertCoMPASSBinToHits(bin_path, 0);
82 const std::vector<ChannelCal> &chans) {
84 std::chrono::steady_clock::time_point t_total =
85 std::chrono::steady_clock::now();
86 std::chrono::steady_clock::time_point t0;
87 Double_t t_parse = 0, t_timing = 0, t_apply = 0, t_events = 0, t_cal = 0,
90 Bool_t history_done = kFALSE;
95 const Bool_t skip_processing =
99 if (skip_processing) {
102 <<
" events exist; re-making plots only" << std::endl;
111 if (gSystem->AccessPathName(bin_path)) {
113 std::cerr <<
"[fail] " << file_label
115 <<
" missing: " << bin_path << std::endl;
119 PrintMemUsage((TString(
"before binary read ") + file_label).Data());
121 t0 = std::chrono::steady_clock::now();
122 std::vector<RawHit> hits;
127 SOLReader sol_reader;
128 sol_reader.SetSkipTraces(kTRUE);
129 if (!sol_reader.Open(bin_path.Data())) {
131 std::cerr <<
"[fail] " << file_label <<
" cannot open SOL file"
136 hits.reserve(1048576);
137 while (sol_reader.ReadEvent())
142 UShort_t use_header = (spec.
suffix ==
"") ? 0 : run_header;
143 std::pair<std::vector<RawHit>, UShort_t> parsed =
144 InitUtils::ConvertCoMPASSBinToHits(bin_path, use_header);
151 PrintMemUsage((TString(
"after binary read ") + file_label).Data());
155 std::cerr <<
"[fail] " << file_label <<
" parse produced no hits"
161 t0 = std::chrono::steady_clock::now();
170 PrintMemUsage((TString(
"after timing ") + file_label).Data());
172 t0 = std::chrono::steady_clock::now();
178 PrintMemUsage((TString(
"after apply+sort ") + file_label).Data());
181 std::cout <<
"[skip-timing] " << file_label
182 <<
" board sync and sort both disabled; skipping to event "
191 t0 = std::chrono::steady_clock::now();
196 history_done = kTRUE;
203 t0 = std::chrono::steady_clock::now();
208 PrintMemUsage((TString(
"after event build ") + file_label).Data());
210 std::vector<RawHit>().swap(hits);
212 PrintMemUsage((TString(
"after hits free ") + file_label).Data());
216 std::cerr <<
"[fail] " << file_label <<
" event build failed"
228 t0 = std::chrono::steady_clock::now();
231 PrintMemUsage((TString(
"after calibration ") + file_label).Data());
236 t0 = std::chrono::steady_clock::now();
242 std::cout <<
" normed summary: " << t_normed <<
"s" << std::endl;
249 std::cout << std::fixed << std::setprecision(1) <<
"[done] " << file_label
250 <<
" total=" << total <<
"s parse=" << t_parse
251 <<
" timing=" << t_timing <<
" apply=" << t_apply
252 <<
" history=" << t_history <<
" events=" << t_events
253 <<
" cal=" << t_cal << std::endl;
262static void RunActiveSelection() {
264 Int_t n_specs = Int_t(specs.size());
266 std::set<Int_t> unique_runs;
267 for (Int_t k = 0; k < n_specs; k++)
268 unique_runs.insert(specs[k].run);
273 std::set<Int_t> runs_needing_header;
274 for (Int_t k = 0; k < n_specs; k++) {
278 runs_needing_header.insert(specs[k].run);
281 std::cout <<
"Phase A: gathering global headers for "
282 << runs_needing_header.size() <<
" run(s)..." << std::endl;
283 std::map<Int_t, UShort_t> run_headers;
284 for (std::set<Int_t>::const_iterator it = runs_needing_header.begin();
285 it != runs_needing_header.end(); ++it) {
288 std::cerr <<
"Header gather FAILED for run " << *it << std::endl;
291 run_headers[*it] = h;
292 std::cout <<
" Run " << *it <<
" header 0x" << std::hex << h << std::dec
301 TMath::Min(Int_t(std::thread::hardware_concurrency()), n_specs);
302 n_workers = TMath::Min(n_workers,
Constants::cfg.MAX_FUSED_WORKERS);
303 std::cout <<
"Phase B: fused pipeline on " << n_specs <<
" files with "
304 << n_workers <<
" workers." << std::endl;
306 std::queue<Int_t> work;
307 for (Int_t k = 0; k < n_specs; k++)
309 std::mutex work_mutex;
311 std::vector<std::thread> workers;
312 for (Int_t w = 0; w < n_workers; w++) {
313 workers.emplace_back([&]() {
317 std::lock_guard<std::mutex> lk(work_mutex);
325 run_headers.count(spec.
run) ? run_headers[spec.
run] : UShort_t(0);
336 for (Int_t w = 0; w < Int_t(workers.size()); w++)
339 std::cout <<
"All fused pipelines complete." << std::endl;
341 std::cout <<
"Phase C: per-run ridge-ratio aggregation" << std::endl;
342 for (std::set<Int_t>::const_iterator it = unique_runs.begin();
343 it != unique_runs.end(); ++it) {
344 std::vector<FileSpec> run_specs;
345 for (Int_t k = 0; k < n_specs; k++)
346 if (specs[k].run == *it)
347 run_specs.push_back(specs[k]);
354 ROOT::EnableThreadSafety();
357 InitUtils::SetROOTPreferences(PlotSaveFormat::kPNG,
361 TString log_path = project_root +
"/pipeline_fused.log";
362 std::ofstream log_file(log_path.Data());
363 std::streambuf *saved_cout = std::cout.rdbuf(log_file.rdbuf());
364 std::streambuf *saved_cerr = std::cerr.rdbuf(log_file.rdbuf());
365 Int_t saved_error_level = gErrorIgnoreLevel;
366 gErrorIgnoreLevel = kError;
369 RunActiveSelection();
375 std::cout << std::endl;
376 std::cout <<
"=== epoch " << epoch.
name <<
" ("
378 << epoch.
runs.size() <<
" run(s), " << epoch.
n_boards <<
"x"
379 << epoch.
n_channels <<
" ch) ===" << std::endl;
381 RunActiveSelection();
386 std::cout.rdbuf(saved_cout);
387 std::cerr.rdbuf(saved_cerr);
388 gErrorIgnoreLevel = saved_error_level;
390 std::cout <<
"Fused pipeline finished. Output logged to " << log_path
RawHit SOLHitToRawHit(const SOLData &sol)
Adapt one SOLARIS hit into the pipeline's RawHit.
Bool_t FusedExists(const TString &subpath)
Double_t FusedSecSince(const std::chrono::steady_clock::time_point &t0)
void PrintMemUsage(const char *label)
Bool_t RunFusedPipelineForFile(FileSpec spec, UShort_t run_header, const EventBuilder::SlotMap &slot_map, const std::vector< ChannelCal > &chans)
std::mutex fused_log_mutex
Bool_t EnsureRunHeaderFused(Int_t run, UShort_t &header)
Pole-zero pulse-history correction on the raw hit stream.
static void WriteHeaderFile(Int_t run, UShort_t header)
Write a run's global header to its file.
static Bool_t ReadHeaderFile(Int_t run, UShort_t &header)
Read a run's global header back from its file.
static void CalibrateBeamOneSubfile(const FileSpec &spec, const std::vector< ChannelCal > &chans_template)
Calibrate one subfile end to end.
static std::vector< ChannelCal > BuildChannels()
One ChannelCal per readout channel in the active channel map.
static void AggregateRidgeRatiosForRun(Int_t run, const std::vector< FileSpec > &specs)
Replace each subfile's ridge ratio and short-end offset with the run-level medians.
static SlotMap BuildSlotMap()
Build the board/channel to slot lookup for this dataset.
static Bool_t BuildEventsFromSortedHits(const std::vector< RawHit > &hits, const SlotMap &slot_map, const TString &output_name, const TString &file_label)
Build every event in a subfile and write them to a ROOT tree.
std::vector< Int_t > SlotMap
Board/channel to array slot lookup, indexed as BuildSlotMap() defines.
static void BuildNormedSummaryHistograms(const TString &input_filename, const TString &file_label)
Build the calibrated summary histograms for one events file.
static TString EventsName(const FileSpec &s)
Filename of the built-events ROOT file for a subfile.
static std::vector< TString > DiscoverSolRunSuffixes(Int_t run)
Subfile suffixes present on disk for a SOLARIS run.
static TString FileLabel(const FileSpec &s)
Human-readable label identifying a subfile.
static TString CompassBinPath(const FileSpec &s)
Path to a CoMPASS binary subfile.
static std::vector< FileSpec > BuildRawOrProcessedFileSpecs()
The union of raw and processed subfiles, without duplicates.
static TString SolBinPath(const FileSpec &s)
Path to a SOLARIS .sol subfile.
static Bool_t Init()
Load the GPU library and resolve the sort symbol.
static TString DatasetDir()
Absolute path to the active dataset directory, analysis/<iso>.
static TString ResultsDir()
Absolute path to the directory receiving generated output.
static void PrintLogo()
Print the project wordmark.
static void Run()
Run the whole pipeline over the configured subfiles.
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 ApplyShiftsInPlace(std::vector< RawHit > &hits, const std::vector< Long64_t > &board_shifts)
Add the measured offsets to the hits, in place.
UShort_t ActiveTimingRefBoard()
Board the others are timing-aligned against.
Bool_t ActiveDoBoardSync()
Whether to run the multi-board timing alignment.
Bool_t ActiveDoSort()
Whether to time-sort hits before event building.
Bool_t InPlotSample(Int_t k)
Whether the k-th file (0-based, in file order) of an epoch's list is in the plot sample.
const std::vector< UShort_t > & ActiveTimingRefBoardChannels()
Reference channel per board, for the alignment.
std::ostream & Detail()
std::cout for a file in the sample, a stream that discards otherwise: the per-file detail lines (per ...
Bool_t FileInSample()
Whether the file this thread is processing is in the per-file sample: every file with SAVE_FULL_PLOTS...
const DatasetConfig & cfg
The active dataset's configuration, flat block.
void SetPlotsThisFile(Bool_t on)
Mark the file this thread is about to process as in (or out of) the plot sample.
void SetActiveEpoch(const RunEpoch *epoch)
Set the epoch the Active*() accessors read from.
Bool_t ActiveUseSolarisData()
Whether this era's data is SOLARIS rather than CoMPASS.
const PulseHistoryGroups & ActivePulseHistoryGroups()
The pulse-history groups in force: the active epoch's set, or the flat PULSE_HISTORY_GROUPS when no e...
std::vector< Int_t > BuildGroupMap()
Group lookup for every (board, channel) under the active map.
void Apply(std::vector< RawHit > &hits, const std::vector< Int_t > &group_of, Result &res)
Apply the measured kernels to the hit stream, in place.
Bool_t Measure(std::vector< RawHit > &hits, const std::vector< Int_t > &group_of, Result &res, const TString &file_label)
Measure the kernels on this subfile's beam-like events.
void SavePlots(Result &res, const TString &file_label)
Draw and save the diagnostics, then free them.
void WriteToEventsFile(const TString &events_subpath, const Result &res)
Record the kernels and counters alongside a subfile's events.
TString Report(const Result &res, const TString &file_label, Bool_t detail=kTRUE)
Format the pass as a human-readable report.
One input file: a run number and the subfile suffix within it.
TString suffix
Subfile suffix, empty for the first subfile.
Everything one subfile's pulse-history pass produced.
One acquisition period of a dataset.
std::vector< Int_t > runs
Run numbers belonging to this epoch.
TString name
Epoch name, used in logs and plot paths.
Bool_t enabled
Whether this epoch participates in the analysis.
Int_t n_boards
Boards in this era's setup.
RunSource source
Acquisition system for this era.
Int_t n_channels
Channels per board.
Per-board timing offsets, indexed by board number.
std::vector< Long64_t > board_shifts
Offset to add to each board's timestamps, in picoseconds.