7Int_t ComputeCoMPASSRecordSize(UShort_t global_header) {
8 Int_t record_size = 16;
9 if (global_header & 0x0001)
11 if (global_header & 0x0002)
13 if (global_header & 0x0004)
20void ComputeCoMPASSFieldOffsets(UShort_t global_header, Long64_t &off_board,
21 Long64_t &off_channel, Long64_t &off_timestamp,
22 Long64_t &off_energy_ch,
23 Long64_t &off_energy_cal,
24 Long64_t &off_energy_short,
25 Long64_t &off_flags) {
26 Bool_t has_energy_ch = (global_header & 0x0001);
27 Bool_t has_energy_cal = (global_header & 0x0002);
28 Bool_t has_energy_short = (global_header & 0x0004);
35 off_energy_short = -1;
39 off_energy_ch = cursor;
43 off_energy_cal = cursor;
46 if (has_energy_short) {
47 off_energy_short = cursor;
55Bool_t LoadCoMPASSBulkBuffer(
const TString &input_filename,
56 Long64_t header_bytes_to_skip, Int_t record_size,
57 std::vector<char> &buf, Long64_t &n_events,
58 Long64_t &file_size) {
63 FILE *fp = std::fopen(input_filename.Data(),
"rb");
65 std::cout <<
"ERROR: Failed to open file for bulk read: " << input_filename
70 if (std::fseek(fp, 0, SEEK_END) != 0) {
71 std::cout <<
"ERROR: fseek to end failed on " << input_filename
76 Long64_t fsize = Long64_t(std::ftell(fp));
78 std::cout <<
"ERROR: ftell failed on " << input_filename << std::endl;
84 Long64_t data_bytes = file_size - header_bytes_to_skip;
88 Long64_t record_size_l = Long64_t(record_size);
89 if (data_bytes % record_size_l != 0) {
90 std::cout <<
"WARNING: File data section (" << data_bytes
91 <<
" bytes) is not a multiple of record size " << record_size
92 <<
"; truncating to floor." << std::endl;
94 n_events = data_bytes / record_size_l;
95 Long64_t want = n_events * record_size_l;
97 if (std::fseek(fp,
long(header_bytes_to_skip), SEEK_SET) != 0) {
98 std::cout <<
"ERROR: fseek to data start failed on " << input_filename
104 buf.resize(
size_t(want));
105 size_t got = (want > 0) ? std::fread(buf.data(), 1,
size_t(want), fp) : 0;
108 if (Long64_t(got) != want) {
109 std::cout <<
"ERROR: Short read on " << input_filename <<
" (got "
110 << Long64_t(got) <<
" of " << want <<
" bytes)" << std::endl;
121void PrintCoMPASSHeaderSummary(UShort_t global_header) {
122 Bool_t has_energy_ch = (global_header & 0x0001);
123 Bool_t has_energy_cal = (global_header & 0x0002);
124 Bool_t has_energy_short = (global_header & 0x0004);
126 std::cout <<
"CoMPASS event header..." << std::endl;
127 std::cout <<
"Header: 0x" << std::hex << global_header << std::dec
128 <<
" (Binary: " << std::bitset<16>(global_header) <<
")"
130 std::cout << std::endl;
131 std::cout <<
"Control bits..." << std::endl;
132 std::cout <<
"Energy (ch): " << (has_energy_ch ?
"YES" :
"NO")
134 std::cout <<
"Energy (cal): " << (has_energy_cal ?
"YES" :
"NO")
136 std::cout <<
"Energy (short): " << (has_energy_short ?
"YES" :
"NO")
138 std::cout <<
"Waveform: NO" << std::endl;
144void PrintCoMPASSConversionSummary(
145 Long64_t event_count, Long64_t bytes_read, Bool_t skip_bad_events,
146 Long64_t warning_fake, Long64_t warning_saturated, Long64_t warning_pileup,
147 Long64_t warning_memory_full, Long64_t warning_trigger_lost,
148 Long64_t warning_pll_loss, Long64_t warning_over_temp,
149 Long64_t warning_adc_shutdown) {
150 std::cout <<
"Conversion complete." << std::endl;
151 std::cout <<
"Total events processed: " << event_count << std::endl;
153 if (warning_fake > 0 || warning_saturated > 0 || warning_pileup > 0) {
154 std::cout <<
"Events with rejection-quality flags:" << std::endl;
155 if (warning_fake > 0) {
156 std::cout <<
" Fake events: " << warning_fake;
158 std::cout <<
" (rejected)";
159 std::cout << std::endl;
161 if (warning_saturated > 0) {
162 std::cout <<
" Saturated: " << warning_saturated;
164 std::cout <<
" (rejected)";
165 std::cout << std::endl;
167 if (warning_pileup > 0) {
168 std::cout <<
" Pileup: " << warning_pileup;
170 std::cout <<
" (rejected)";
171 std::cout << std::endl;
173 std::cout << std::endl;
176 if (warning_memory_full > 0) {
177 std::cout <<
"WARNING: " << warning_memory_full
178 <<
" events with memory full flag" << std::endl;
180 if (warning_trigger_lost > 0) {
181 std::cout <<
"WARNING: " << warning_trigger_lost
182 <<
" events with trigger lost flag" << std::endl;
184 if (warning_pll_loss > 0) {
185 std::cout <<
"WARNING: " << warning_pll_loss <<
" events with PLL lock loss"
188 if (warning_over_temp > 0) {
189 std::cout <<
"WARNING: " << warning_over_temp
190 <<
" events with over temperature" << std::endl;
192 if (warning_adc_shutdown > 0) {
193 std::cout <<
"WARNING: " << warning_adc_shutdown
194 <<
" events with ADC shutdown" << std::endl;
197 std::cout <<
"Total bytes read: " << bytes_read << std::endl;
202std::pair<std::vector<RawHit>, UShort_t>
203BulkReadCoMPASSHits(
const TString &input_filename, UShort_t global_header,
204 UShort_t global_header_override, Bool_t skip_bad_events) {
205 std::vector<RawHit> hits;
207 Int_t record_size = ComputeCoMPASSRecordSize(global_header);
208 Long64_t header_bytes_to_skip = (global_header_override != 0) ? 0 : 2;
210 std::vector<char> buf;
211 Long64_t n_events = 0;
212 Long64_t file_size = 0;
213 if (!LoadCoMPASSBulkBuffer(input_filename, header_bytes_to_skip, record_size,
214 buf, n_events, file_size)) {
215 return std::make_pair(hits,
static_cast<UShort_t
>(0));
218 Long64_t off_board = 0, off_channel = 0, off_timestamp = 0;
219 Long64_t off_energy_ch = -1, off_energy_cal = -1, off_energy_short = -1;
220 Long64_t off_flags = 0;
221 ComputeCoMPASSFieldOffsets(global_header, off_board, off_channel,
222 off_timestamp, off_energy_ch, off_energy_cal,
223 off_energy_short, off_flags);
225 Long64_t event_count = 0;
226 Long64_t warning_fake = 0;
227 Long64_t warning_saturated = 0;
228 Long64_t warning_pileup = 0;
229 Long64_t warning_memory_full = 0;
230 Long64_t warning_trigger_lost = 0;
231 Long64_t warning_pll_loss = 0;
232 Long64_t warning_over_temp = 0;
233 Long64_t warning_adc_shutdown = 0;
235 std::cout <<
"Reading events..." << std::endl;
236 if (skip_bad_events) {
238 <<
"Filtering enabled: skipping fake, saturated, and pileup events"
242 Bool_t header_printed = kFALSE;
244 hits.reserve(
size_t(n_events));
246 const char *ptr = buf.data();
247 Long64_t record_size_l = Long64_t(record_size);
249 for (Long64_t i = 0; i < n_events; i++) {
250 if (!header_printed) {
251 PrintCoMPASSHeaderSummary(global_header);
252 header_printed = kTRUE;
255 const char *rec = ptr + i * record_size_l;
258 std::memcpy(&flags_val, rec + off_flags, 4);
285 warning_memory_full++;
287 warning_trigger_lost++;
293 warning_adc_shutdown++;
296 std::memcpy(&hit.
board, rec + off_board, 2);
297 std::memcpy(&hit.
channel, rec + off_channel, 2);
298 std::memcpy(&hit.
timestamp, rec + off_timestamp, 8);
300 if (off_energy_ch >= 0)
301 std::memcpy(&hit.
energy, rec + off_energy_ch, 2);
302 hit.
flags = flags_val;
308 PrintCoMPASSConversionSummary(
309 event_count, file_size, skip_bad_events, warning_fake, warning_saturated,
310 warning_pileup, warning_memory_full, warning_trigger_lost,
311 warning_pll_loss, warning_over_temp, warning_adc_shutdown);
313 return std::make_pair(hits, global_header);
319 const TString &plots_dir,
320 const TString &root_files_dir,
323 gROOT->ForceStyle(kTRUE);
324 gROOT->SetBatch(kTRUE);
330 TH1::AddDirectory(kFALSE);
333 TString resolved_plots_dir = plots_dir;
334 if (resolved_plots_dir.Length() == 0) {
336 <<
"WARNING: InitUtils::SetROOTPreferences called without plots_dir; "
337 "defaulting to CWD-relative \"plots\". Pass an absolute path to "
338 "drive output into a project root."
340 resolved_plots_dir =
"plots";
344 TString resolved_root_files_dir = root_files_dir;
345 if (resolved_root_files_dir.Length() == 0) {
346 std::cout <<
"WARNING: InitUtils::SetROOTPreferences called without "
347 "root_files_dir; defaulting to CWD-relative \"root_files\"."
349 resolved_root_files_dir =
"root_files";
363 const TString output_name,
364 UShort_t global_header_override,
365 Bool_t skip_bad_events) {
367 if (gSystem->AccessPathName(base_dir)) {
368 gSystem->mkdir(base_dir, kTRUE);
371 if (gSystem->AccessPathName(input_filename)) {
372 std::cout <<
"ERROR: Input file does not exist: " << input_filename
377 TString output_subpath = output_name +
".root";
378 TString output_filename = base_dir +
"/" + output_subpath;
381 Bool_t open_success =
382 (global_header_override != 0)
383 ? reader.
Open(input_filename.Data(), global_header_override)
384 : reader.
Open(input_filename.Data());
387 std::cout <<
"ERROR: Failed to open CoMPASS binary file" << std::endl;
393 Bool_t has_energy_ch = (global_header & 0x0001);
394 Bool_t has_energy_cal = (global_header & 0x0002);
395 Bool_t has_energy_short = (global_header & 0x0004);
396 Bool_t has_waveform = (global_header & 0x0008);
398 TFile *outfile =
nullptr;
399 TTree *tree =
nullptr;
400 UShort_t board = 0, channel = 0, energy = 0, energy_short = 0;
401 ULong64_t timestamp = 0;
402 Double_t energy_cal = 0.0;
403 UInt_t flags = 0, num_samples = 0;
404 UChar_t waveform_code = 0;
405 TArrayS *samples =
nullptr;
411 if (!outfile || outfile->IsZombie()) {
412 std::cout <<
"ERROR: Could not create output file " << output_filename
418 tree =
new TTree(
"Data_R",
"CoMPASS Binary Data");
420 tree->Branch(
"Board", &board,
"Board/s");
421 tree->Branch(
"Channel", &channel,
"Channel/s");
422 tree->Branch(
"Timestamp", ×tamp,
"Timestamp/l");
425 tree->Branch(
"Energy", &energy,
"Energy/s");
426 std::cout <<
"Energy type: Channel (ADC counts)" << std::endl;
427 }
else if (has_energy_cal) {
428 tree->Branch(
"Energy", &energy_cal,
"Energy/D");
429 std::cout <<
"Energy type: Calibrated (keV/MeV)" << std::endl;
432 if (has_energy_short) {
433 tree->Branch(
"EnergyShort", &energy_short,
"EnergyShort/s");
436 tree->Branch(
"Flags", &flags,
"Flags/i");
439 samples =
new TArrayS();
440 tree->Branch(
"WaveformCode", &waveform_code,
"WaveformCode/b");
441 tree->Branch(
"NumSamples", &num_samples,
"NumSamples/i");
442 tree->Branch(
"Samples", &samples);
446 Long64_t event_count = 0;
447 Long64_t warning_fake = 0;
448 Long64_t warning_saturated = 0;
449 Long64_t warning_pileup = 0;
450 Long64_t warning_memory_full = 0;
451 Long64_t warning_trigger_lost = 0;
452 Long64_t warning_pll_loss = 0;
453 Long64_t warning_over_temp = 0;
454 Long64_t warning_adc_shutdown = 0;
455 Long64_t bytes_read_for_summary = 0;
457 std::cout <<
"Reading events..." << std::endl;
458 if (skip_bad_events) {
460 <<
"Filtering enabled: skipping fake, saturated, and pileup events"
467 <<
"Using bulk-read fast path (fixed-stride records, no waveform)."
471 Int_t record_size = ComputeCoMPASSRecordSize(global_header);
472 Long64_t header_bytes_to_skip = (global_header_override != 0) ? 0 : 2;
474 std::vector<char> buf;
475 Long64_t n_events = 0;
476 Long64_t file_size = 0;
478 LoadCoMPASSBulkBuffer(input_filename, header_bytes_to_skip, record_size,
479 buf, n_events, file_size);
486 bytes_read_for_summary = file_size;
488 Long64_t off_board = 0, off_channel = 0, off_timestamp = 0;
489 Long64_t off_energy_ch = -1, off_energy_cal = -1, off_energy_short = -1;
490 Long64_t off_flags = 0;
491 ComputeCoMPASSFieldOffsets(global_header, off_board, off_channel,
492 off_timestamp, off_energy_ch, off_energy_cal,
493 off_energy_short, off_flags);
495 Bool_t header_printed = kFALSE;
497 const char *ptr = buf.data();
498 Long64_t record_size_l = Long64_t(record_size);
500 for (Long64_t i = 0; i < n_events; i++) {
501 if (!header_printed) {
502 PrintCoMPASSHeaderSummary(global_header);
503 header_printed = kTRUE;
506 const char *rec = ptr + i * record_size_l;
509 std::memcpy(&flags_val, rec + off_flags, 4);
512 Bool_t is_saturated =
534 warning_memory_full++;
536 warning_trigger_lost++;
542 warning_adc_shutdown++;
544 std::memcpy(&board, rec + off_board, 2);
545 std::memcpy(&channel, rec + off_channel, 2);
546 std::memcpy(×tamp, rec + off_timestamp, 8);
547 if (off_energy_ch >= 0)
548 std::memcpy(&energy, rec + off_energy_ch, 2);
549 if (off_energy_cal >= 0)
550 std::memcpy(&energy_cal, rec + off_energy_cal, 8);
551 if (off_energy_short >= 0)
552 std::memcpy(&energy_short, rec + off_energy_short, 2);
563 if (event_count == 0) {
567 if (event.isFakeEvent()) {
572 if (event.isInputSaturating() || event.hasSaturation()) {
577 if (event.isPileup()) {
583 if (event.hasMemoryFull())
584 warning_memory_full++;
585 if (event.hasTriggerLost())
586 warning_trigger_lost++;
587 if (event.hasPLLLockLoss())
589 if (event.isOverTemperature())
591 if (event.isADCShutdown())
592 warning_adc_shutdown++;
595 channel =
event.channel;
596 timestamp =
event.timestamp;
600 energy =
event.energy_ch;
602 if (has_energy_cal) {
603 energy_cal =
event.energy_cal;
605 if (has_energy_short) {
606 energy_short =
event.energy_short_ch;
609 waveform_code =
event.waveform_code;
610 num_samples =
event.num_samples;
611 *samples =
event.samples;
620 PrintCoMPASSConversionSummary(
621 event_count, bytes_read_for_summary, skip_bad_events, warning_fake,
622 warning_saturated, warning_pileup, warning_memory_full,
623 warning_trigger_lost, warning_pll_loss, warning_over_temp,
624 warning_adc_shutdown);
629 tree->Write(
"", TObject::kOverwrite);
635 std::cout <<
"Output saved to: " << output_filename << std::endl;
637 return global_header;
640std::pair<std::vector<RawHit>, UShort_t>
642 UShort_t global_header_override,
643 Bool_t skip_bad_events) {
644 std::vector<RawHit> hits;
646 if (gSystem->AccessPathName(input_filename)) {
647 std::cout <<
"ERROR: Input file does not exist: " << input_filename
649 return std::make_pair(hits,
static_cast<UShort_t
>(0));
653 Bool_t open_success =
654 (global_header_override != 0)
655 ? reader.
Open(input_filename.Data(), global_header_override)
656 : reader.
Open(input_filename.Data());
659 std::cout <<
"ERROR: Failed to open CoMPASS binary file" << std::endl;
660 return std::make_pair(hits,
static_cast<UShort_t
>(0));
664 Bool_t has_energy_ch = (global_header & 0x0001);
665 Bool_t has_waveform = (global_header & 0x0008);
667 if (!has_energy_ch) {
668 std::cout <<
"WARNING: File has no channel-energy field; RawHit.energy "
669 "will be zero for every hit."
676 <<
"Using bulk-read fast path (fixed-stride records, no waveform)."
679 return BulkReadCoMPASSHits(input_filename, global_header,
680 global_header_override, skip_bad_events);
683 Long64_t event_count = 0;
684 Long64_t warning_fake = 0;
685 Long64_t warning_saturated = 0;
686 Long64_t warning_pileup = 0;
687 Long64_t warning_memory_full = 0;
688 Long64_t warning_trigger_lost = 0;
689 Long64_t warning_pll_loss = 0;
690 Long64_t warning_over_temp = 0;
691 Long64_t warning_adc_shutdown = 0;
693 std::cout <<
"Reading events..." << std::endl;
694 if (skip_bad_events) {
696 <<
"Filtering enabled: skipping fake, saturated, and pileup events"
702 if (event_count == 0) {
706 if (event.isFakeEvent()) {
711 if (event.isInputSaturating() || event.hasSaturation()) {
716 if (event.isPileup()) {
722 if (event.hasMemoryFull())
723 warning_memory_full++;
724 if (event.hasTriggerLost())
725 warning_trigger_lost++;
726 if (event.hasPLLLockLoss())
728 if (event.isOverTemperature())
730 if (event.isADCShutdown())
731 warning_adc_shutdown++;
734 hit.
board =
event.board;
736 hit.
energy =
event.energy_ch;
738 hit.
flags =
event.flags;
744 std::cout <<
"Conversion complete." << std::endl;
745 std::cout <<
"Total events processed: " << event_count << std::endl;
747 if (warning_fake > 0 || warning_saturated > 0 || warning_pileup > 0) {
748 std::cout <<
"Events with rejection-quality flags:" << std::endl;
749 if (warning_fake > 0) {
750 std::cout <<
" Fake events: " << warning_fake;
752 std::cout <<
" (rejected)";
753 std::cout << std::endl;
755 if (warning_saturated > 0) {
756 std::cout <<
" Saturated: " << warning_saturated;
758 std::cout <<
" (rejected)";
759 std::cout << std::endl;
761 if (warning_pileup > 0) {
762 std::cout <<
" Pileup: " << warning_pileup;
764 std::cout <<
" (rejected)";
765 std::cout << std::endl;
767 std::cout << std::endl;
770 if (warning_memory_full > 0) {
771 std::cout <<
"WARNING: " << warning_memory_full
772 <<
" events with memory full flag" << std::endl;
774 if (warning_trigger_lost > 0) {
775 std::cout <<
"WARNING: " << warning_trigger_lost
776 <<
" events with trigger lost flag" << std::endl;
778 if (warning_pll_loss > 0) {
779 std::cout <<
"WARNING: " << warning_pll_loss <<
" events with PLL lock loss"
782 if (warning_over_temp > 0) {
783 std::cout <<
"WARNING: " << warning_over_temp
784 <<
" events with over temperature" << std::endl;
786 if (warning_adc_shutdown > 0) {
787 std::cout <<
"WARNING: " << warning_adc_shutdown
788 <<
" events with ADC shutdown" << std::endl;
791 std::cout <<
"Total bytes read: " << reader.
GetBytesRead() << std::endl;
795 return std::make_pair(hits, global_header);
799 const TString output_name,
800 Bool_t corrections_enabled) {
802 if (gSystem->AccessPathName(base_dir)) {
803 gSystem->mkdir(base_dir, kTRUE);
806 if (gSystem->AccessPathName(input_filename)) {
807 std::cout <<
"ERROR: Input file does not exist: " << input_filename
812 TString output_subpath = output_name +
"_raw.root";
813 TString output_filename = base_dir +
"/" + output_subpath;
817 if (!reader.
Open(input_filename.Data())) {
818 std::cout <<
"ERROR: Failed to open WaveDump binary file" << std::endl;
822 std::cout <<
"Corrections: " << (corrections_enabled ?
"enabled" :
"disabled")
825 TFile *outfile =
nullptr;
826 TTree *tree =
nullptr;
827 UInt_t channel_br = 0, event_counter = 0, trigger_time_tag = 0;
828 TArrayS *samples =
nullptr;
834 if (!outfile || outfile->IsZombie()) {
835 std::cout <<
"ERROR: Could not create output file " << output_filename
841 tree =
new TTree(
"Data_R",
"WaveDump 742 Binary Data");
843 tree->Branch(
"Channel", &channel_br,
"Channel/i");
844 tree->Branch(
"EventCounter", &event_counter,
"EventCounter/i");
845 tree->Branch(
"TriggerTimeTag", &trigger_time_tag,
"TriggerTimeTag/i");
846 samples =
new TArrayS();
847 tree->Branch(
"Samples", &samples);
850 Long64_t event_count = 0;
852 std::cout <<
"Reading events..." << std::endl;
858 event_counter =
event.event_counter;
859 trigger_time_tag =
event.group_trigger_time_tag;
860 *samples =
event.samples;
866 std::cout <<
"Conversion complete." << std::endl;
867 std::cout <<
"Total events processed: " << event_count << std::endl;
868 std::cout <<
"Samples per event: "
869 << (event_count > 0 ? samples->GetSize() : 0) << std::endl;
870 std::cout <<
"Total bytes read: " << reader.
GetBytesRead() << std::endl;
875 tree->Write(
"", TObject::kOverwrite);
881 std::cout <<
"Output saved to: " << output_filename << std::endl;
887 const TString output_name) {
889 if (gSystem->AccessPathName(base_dir)) {
890 gSystem->mkdir(base_dir, kTRUE);
893 if (gSystem->AccessPathName(input_filename)) {
894 std::cout <<
"ERROR: Input file does not exist: " << input_filename
899 TString output_subpath = output_name +
".root";
900 TString output_filename = base_dir +
"/" + output_subpath;
903 if (!reader.
Open(input_filename.Data())) {
904 std::cout <<
"ERROR: Failed to open SOL binary file" << std::endl;
908 TFile *outfile =
nullptr;
909 TTree *tree =
nullptr;
912 Short_t channel_br = 0;
913 Short_t energy_br = 0;
914 Short_t energy_short_br = 0;
915 Long64_t timestamp_br = 0;
916 Short_t fine_timestamp_br = 0;
917 Short_t flags_high_br = 0;
918 Short_t flags_low_br = 0;
919 Short_t data_type_br = 0;
920 Char_t is_psd_br = 0;
921 Char_t down_sampling_br = 0;
922 Char_t board_fail_br = 0;
924 Short_t trigger_thr_br = 0;
925 Long64_t event_size_br = 0;
926 Int_t agg_counter_br = 0;
927 Long64_t block_id_br = 0;
928 Int_t trace_len_br = 0;
929 Char_t ana_probe_type0_br = 0xFF;
930 Char_t ana_probe_type1_br = 0xFF;
931 Char_t dig_probe_type0_br = 0xFF;
932 Char_t dig_probe_type1_br = 0xFF;
933 Char_t dig_probe_type2_br = 0xFF;
934 Char_t dig_probe_type3_br = 0xFF;
937 TArrayI *trace0 =
new TArrayI();
938 TArrayI *trace1 =
new TArrayI();
939 TArrayC *dig0 =
new TArrayC();
940 TArrayC *dig1 =
new TArrayC();
941 TArrayC *dig2 =
new TArrayC();
942 TArrayC *dig3 =
new TArrayC();
948 if (!outfile || outfile->IsZombie()) {
949 std::cout <<
"ERROR: Could not create output file " << output_filename
961 tree =
new TTree(
"Data_R",
"SOLARIS Binary Data");
963 tree->Branch(
"Channel", &channel_br,
"Channel/s");
964 tree->Branch(
"Energy", &energy_br,
"Energy/s");
965 tree->Branch(
"EnergyShort", &energy_short_br,
"EnergyShort/s");
966 tree->Branch(
"Timestamp", ×tamp_br,
"Timestamp/l");
967 tree->Branch(
"FineTimestamp", &fine_timestamp_br,
"FineTimestamp/s");
968 tree->Branch(
"FlagsHigh", &flags_high_br,
"FlagsHigh/s");
969 tree->Branch(
"FlagsLow", &flags_low_br,
"FlagsLow/s");
970 tree->Branch(
"DataType", &data_type_br,
"DataType/s");
971 tree->Branch(
"IsPSD", &is_psd_br,
"IsPSD/C");
972 tree->Branch(
"DownSampling", &down_sampling_br,
"DownSampling/C");
973 tree->Branch(
"BoardFail", &board_fail_br,
"BoardFail/C");
974 tree->Branch(
"Flush", &flush_br,
"Flush/C");
975 tree->Branch(
"TriggerThr", &trigger_thr_br,
"TriggerThr/s");
976 tree->Branch(
"EventSize", &event_size_br,
"EventSize/l");
977 tree->Branch(
"AggCounter", &agg_counter_br,
"AggCounter/I");
978 tree->Branch(
"BlockID", &block_id_br,
"BlockID/l");
979 tree->Branch(
"TraceLen", &trace_len_br,
"TraceLen/I");
980 tree->Branch(
"AnaProbeType0", &ana_probe_type0_br,
"AnaProbeType0/C");
981 tree->Branch(
"AnaProbeType1", &ana_probe_type1_br,
"AnaProbeType1/C");
982 tree->Branch(
"DigProbeType0", &dig_probe_type0_br,
"DigProbeType0/C");
983 tree->Branch(
"DigProbeType1", &dig_probe_type1_br,
"DigProbeType1/C");
984 tree->Branch(
"DigProbeType2", &dig_probe_type2_br,
"DigProbeType2/C");
985 tree->Branch(
"DigProbeType3", &dig_probe_type3_br,
"DigProbeType3/C");
986 tree->Branch(
"Trace0", &trace0);
987 tree->Branch(
"Trace1", &trace1);
988 tree->Branch(
"Dig0", &dig0);
989 tree->Branch(
"Dig1", &dig1);
990 tree->Branch(
"Dig2", &dig2);
991 tree->Branch(
"Dig3", &dig3);
994 Long64_t block_count = 0;
995 Long64_t blocks_with_traces = 0;
996 Long64_t blocks_without_traces = 0;
998 std::cout <<
"Reading SOL blocks..." << std::endl;
1003 channel_br =
static_cast<Short_t
>(
event.channel);
1004 energy_br =
static_cast<Short_t
>(
event.energy);
1005 energy_short_br =
static_cast<Short_t
>(
event.energy_short);
1007 fine_timestamp_br =
static_cast<Short_t
>(
event.fine_timestamp);
1008 flags_high_br =
static_cast<Short_t
>(
event.flags_high);
1009 flags_low_br =
static_cast<Short_t
>(
event.flags_low);
1010 data_type_br =
static_cast<Short_t
>(
event.data_type);
1011 is_psd_br =
static_cast<Char_t
>(
event.is_psd);
1012 down_sampling_br =
static_cast<Char_t
>(
event.down_sampling);
1013 board_fail_br =
static_cast<Char_t
>(
event.board_fail);
1014 flush_br =
static_cast<Char_t
>(
event.flush);
1015 trigger_thr_br =
static_cast<Short_t
>(
event.trigger_thr);
1016 event_size_br =
event.event_size;
1017 agg_counter_br =
static_cast<Int_t
>(
event.agg_counter);
1018 block_id_br =
event.block_id;
1019 trace_len_br =
static_cast<Int_t
>(
event.trace_len);
1020 ana_probe_type0_br =
static_cast<Char_t
>(
event.ana_probe_type[0]);
1021 ana_probe_type1_br =
static_cast<Char_t
>(
event.ana_probe_type[1]);
1022 dig_probe_type0_br =
static_cast<Char_t
>(
event.dig_probe_type[0]);
1023 dig_probe_type1_br =
static_cast<Char_t
>(
event.dig_probe_type[1]);
1024 dig_probe_type2_br =
static_cast<Char_t
>(
event.dig_probe_type[2]);
1025 dig_probe_type3_br =
static_cast<Char_t
>(
event.dig_probe_type[3]);
1027 if (event.hasTraces()) {
1029 UInt_t n_samples =
event.getSamples();
1030 const Int_t *a0 =
event.getAnalog0();
1031 const Int_t *a1 =
event.getAnalog1();
1032 const UChar_t *d0 =
event.getDigital(0);
1033 const UChar_t *d1 =
event.getDigital(1);
1034 const UChar_t *d2 =
event.getDigital(2);
1035 const UChar_t *d3 =
event.getDigital(3);
1037 trace0->Set(
static_cast<Int_t
>(n_samples));
1038 for (UInt_t i = 0; i < n_samples; i++) {
1039 trace0->SetAt(a0[i],
static_cast<Int_t
>(i));
1042 trace1->Set(
static_cast<Int_t
>(n_samples));
1043 for (UInt_t i = 0; i < n_samples; i++) {
1044 trace1->SetAt(a1[i],
static_cast<Int_t
>(i));
1047 dig0->Set(
static_cast<Int_t
>(n_samples));
1048 for (UInt_t i = 0; i < n_samples; i++) {
1049 dig0->SetAt(
static_cast<Short_t
>(d0[i]),
static_cast<Int_t
>(i));
1051 dig1->Set(
static_cast<Int_t
>(n_samples));
1052 for (UInt_t i = 0; i < n_samples; i++) {
1053 dig1->SetAt(
static_cast<Short_t
>(d1[i]),
static_cast<Int_t
>(i));
1055 dig2->Set(
static_cast<Int_t
>(n_samples));
1056 for (UInt_t i = 0; i < n_samples; i++) {
1057 dig2->SetAt(
static_cast<Short_t
>(d2[i]),
static_cast<Int_t
>(i));
1059 dig3->Set(
static_cast<Int_t
>(n_samples));
1060 for (UInt_t i = 0; i < n_samples; i++) {
1061 dig3->SetAt(
static_cast<Short_t
>(d3[i]),
static_cast<Int_t
>(i));
1065 UInt_t n_samples =
event.getSamples();
1066 const Int_t *ot =
event.getOneTrace();
1067 trace0->Set(
static_cast<Int_t
>(n_samples));
1068 for (UInt_t i = 0; i < n_samples; i++) {
1069 trace0->SetAt(ot[i],
static_cast<Int_t
>(i));
1077 blocks_with_traces++;
1085 blocks_without_traces++;
1092 if (block_count % 10000 == 0) {
1093 std::cout <<
" Processed " << block_count <<
" blocks..." << std::endl;
1097 std::cout <<
"Conversion complete." << std::endl;
1098 std::cout <<
"Total blocks processed: " << block_count << std::endl;
1099 std::cout <<
"Blocks with traces: " << blocks_with_traces << std::endl;
1100 std::cout <<
"Blocks without traces: " << blocks_without_traces << std::endl;
1101 std::cout <<
"Total bytes read: " << reader.
GetBytesRead() << std::endl;
1106 tree->Write(
"", TObject::kOverwrite);
1119 std::cout <<
"Output saved to: " << output_filename << std::endl;
1124std::pair<std::vector<SOLHit>, Long64_t>
1126 std::vector<SOLHit> hits;
1128 if (gSystem->AccessPathName(input_filename)) {
1129 std::cout <<
"ERROR: Input file does not exist: " << input_filename
1131 return std::make_pair(hits,
static_cast<Long64_t
>(0));
1135 if (!reader.
Open(input_filename.Data())) {
1136 std::cout <<
"ERROR: Failed to open SOL binary file" << std::endl;
1137 return std::make_pair(hits,
static_cast<Long64_t
>(0));
1140 Long64_t block_count = 0;
1141 Long64_t blocks_with_traces = 0;
1142 Long64_t blocks_without_traces = 0;
1144 std::cout <<
"Reading SOL blocks..." << std::endl;
1150 blocks_with_traces++;
1152 blocks_without_traces++;
1155 hits.push_back(hit);
1159 std::cout <<
"Conversion complete." << std::endl;
1160 std::cout <<
"Total blocks processed: " << block_count << std::endl;
1161 std::cout <<
"Blocks with traces: " << blocks_with_traces << std::endl;
1162 std::cout <<
"Blocks without traces: " << blocks_without_traces << std::endl;
1163 std::cout <<
"Total bytes read: " << reader.
GetBytesRead() << std::endl;
1167 return std::make_pair(hits, block_count);
PlotSaveFormat
Output file format for saved figures.
Long64_t GetBytesRead() const
Bytes consumed so far, for progress reporting.
virtual Bool_t Open(const char *fname)
Open a binary file for reading.
virtual void Close()
Close the file. Safe to call when nothing is open.
One decoded CoMPASS event, with header-bit and status-flag accessors.
static const UInt_t PLL_LOCK_LOSS
static const UInt_t MEMORY_FULL
UShort_t board
Digitiser board id.
static const UInt_t SATURATION_IN_GATE
static const UInt_t INPUT_SATURATING
static const UInt_t TRIGGER_LOST
static const UInt_t PILEUP
static const UInt_t FAKE_EVENT
static const UInt_t ADC_SHUTDOWN
static const UInt_t OVER_TEMPERATURE
Cursor over a CoMPASS binary file.
const CoMPASSData & GetCurrentEvent() const
The event most recently read.
Bool_t ReadEvent() override
Decode the next event into the current-event object.
UShort_t GetGlobalHeader() const
The global header in force, read from the file or overridden.
Bool_t Open(const char *fname) override
Open a file and read its global header.
RAII guard engaging the same lock used by the open helpers.
static Bool_t ConvertSOLBinToROOT(const TString input_filename, const TString output_name)
Convert a SOLARIS DAQ (SOL) binary file to a ROOT tree.
static UShort_t ConvertCoMPASSBinToROOT(const TString input_filename, const TString output_name, UShort_t global_header_override, Bool_t skip_bad_events=kFALSE)
Convert a CoMPASS binary file to a ROOT tree.
static std::pair< std::vector< SOLHit >, Long64_t > ConvertSOLBinToHits(const TString input_filename)
Read a SOL binary file into memory as lightweight hits.
static Bool_t ConvertWavedumpBinToROOT(const TString input_filename, const TString output_name, Bool_t corrections_enabled=kTRUE)
Convert a WaveDump binary file (DT5742 family) to a ROOT tree.
static std::pair< std::vector< RawHit >, UShort_t > ConvertCoMPASSBinToHits(const TString input_filename, UShort_t global_header_override=0, Bool_t skip_bad_events=kFALSE)
Read a CoMPASS binary file into memory, with no ROOT file I/O.
static void SetROOTPreferences(PlotSaveFormat save_format=PlotSaveFormat::kPNG, const TString &plots_dir="", const TString &root_files_dir="", Bool_t enable_mt=kTRUE)
Configure the ROOT environment and pin all output paths.
static void SetPlotsBaseDir(const TString &dir)
Set the base directory that saved figures are written under.
static void SetStylePreferences(PlotSaveFormat save_format=PlotSaveFormat::kPNG)
Install the global ROOT style and choose the output format.
static TString GetPlotsBaseDir()
Current base directory for saved figures, without trailing slash.
One decoded SOL block, optionally carrying its traces.
Bool_t hasTraces() const
Whether this block carries traces.
Cursor over a SOLARIS DAQ .sol file.
SOLHit ToHit() const
Copy the current block's header fields into a standalone SOLHit.
const SOLData & GetCurrentEvent() const
The block most recently read.
Bool_t ReadEvent() override
Decode the next record into the derived reader's current event.
One decoded WaveDump event from a DT5742-family digitiser.
UInt_t channel
Channel index.
Cursor over a WaveDump DT5742 binary file.
Bool_t ReadEvent() override
Decode the next record into the derived reader's current event.
const WaveDump742Data & GetCurrentEvent() const
The event most recently read.
TString GetRootFilesBaseDir()
Current base directory for relative subpaths, without trailing slash.
void SetRootFilesBaseDir(const TString &dir)
Set the base directory that relative subpaths resolve against.
void SetThreadSafe(Bool_t enabled=kTRUE)
Enable ROOT thread safety and serialise file opening.
TFile * OpenForWriting(const TString &subpath, const TString mode="RECREATE")
Open a ROOT file for writing, creating parent directories first.
Minimal CoMPASS hit: header fields only, no waveform.
UInt_t flags
CoMPASS status bits; see CoMPASSData's constants.
UShort_t energy
Energy in ADC channel units.
UShort_t board
Digitiser board id.
UShort_t channel
Channel index on that board.
ULong64_t timestamp
Acquisition timestamp, in picoseconds.
Lightweight SOL block: header fields only, traces stripped.