203 current_event.header = global_header;
205 file.read(
reinterpret_cast<char *
>(¤t_event.board),
sizeof(UShort_t));
206 file.read(
reinterpret_cast<char *
>(¤t_event.channel),
sizeof(UShort_t));
207 file.read(
reinterpret_cast<char *
>(¤t_event.timestamp),
209 bytes_read +=
sizeof(UShort_t) * 2 +
sizeof(ULong64_t);
211 if (current_event.hasEnergyCh()) {
212 file.read(
reinterpret_cast<char *
>(¤t_event.energy_ch),
217 if (current_event.hasEnergyCal()) {
218 file.read(
reinterpret_cast<char *
>(¤t_event.energy_cal),
223 if (current_event.hasEnergyShort()) {
224 file.read(
reinterpret_cast<char *
>(¤t_event.energy_short_ch),
229 file.read(
reinterpret_cast<char *
>(¤t_event.flags),
sizeof(UInt_t));
232 if (current_event.hasWaveform()) {
233 file.read(
reinterpret_cast<char *
>(¤t_event.waveform_code),
235 file.read(
reinterpret_cast<char *
>(¤t_event.num_samples),
237 bytes_read +=
sizeof(UChar_t) +
sizeof(UInt_t);
241 const UInt_t kMaxSamples = 1u << 20;
242 if (current_event.num_samples > kMaxSamples) {
243 std::cerr <<
"ERROR: implausible num_samples "
244 << current_event.num_samples <<
" at byte " <<
bytes_read
245 <<
" (treating as truncated)" << std::endl;
249 current_event.samples.Set(current_event.num_samples);
250 std::vector<UShort_t> sample_buf(current_event.num_samples);
251 file.read(
reinterpret_cast<char *
>(sample_buf.data()),
252 current_event.num_samples *
sizeof(UShort_t));
254 std::cerr <<
"WARNING: Incomplete waveform at byte " <<
bytes_read
255 <<
" (truncated file, event discarded)" << std::endl;
258 for (UInt_t i = 0; i < current_event.num_samples; i++) {
259 current_event.samples.SetAt(
static_cast<Short_t
>(sample_buf[i]), i);
261 bytes_read += current_event.num_samples *
sizeof(UShort_t);
294 file.read(
reinterpret_cast<char *
>(headers), 8 *
sizeof(UInt_t));
296 if (
file.gcount() > 0) {
297 std::cerr <<
"WARNING: Incomplete event header at byte " <<
bytes_read
298 <<
" (" <<
file.gcount() <<
" of " << 8 *
sizeof(UInt_t)
299 <<
" header bytes read, truncated file)" << std::endl;
305 current_event.event_size = headers[0];
306 current_event.board_id = headers[1];
307 current_event.pattern = headers[2];
308 current_event.channel = headers[3];
309 current_event.event_counter = headers[4];
310 current_event.group_trigger_time_tag = headers[5];
311 current_event.dc_offset = headers[6];
312 current_event.start_index_cell = headers[7];
315 UInt_t header_bytes = 8 *
sizeof(UInt_t);
316 if (current_event.event_size <= header_bytes) {
317 std::cerr <<
"ERROR: Invalid event_size " << current_event.event_size
318 <<
" at event " << current_event.event_counter << std::endl;
322 UInt_t sample_bytes = current_event.event_size - header_bytes;
323 UInt_t sample_size = sample_bytes /
sizeof(UInt_t);
325 current_event.samples.Set(sample_size);
327 if (corrections_enabled) {
328 std::vector<Float_t> float_samples(sample_size);
329 file.read(
reinterpret_cast<char *
>(float_samples.data()), sample_bytes);
331 std::cerr <<
"WARNING: Incomplete event at byte " <<
bytes_read
332 <<
" (truncated file, event " << current_event.event_counter
333 <<
" discarded)" << std::endl;
336 for (UInt_t i = 0; i < sample_size; i++) {
337 current_event.samples.SetAt(
static_cast<Short_t
>(float_samples[i]), i);
340 std::vector<UInt_t> int_samples(sample_size);
341 file.read(
reinterpret_cast<char *
>(int_samples.data()), sample_bytes);
343 std::cerr <<
"WARNING: Incomplete event at byte " <<
bytes_read
344 <<
" (truncated file, event " << current_event.event_counter
345 <<
" discarded)" << std::endl;
348 for (UInt_t i = 0; i < sample_size; i++) {
349 current_event.samples.SetAt(
static_cast<Short_t
>(int_samples[i] & 0xFFF),
513 const char *outputDir,
514 Double_t chunkSeconds,
516 Int_t &totalChunks) {
517 std::vector<TString> outputFiles;
521 gSystem->mkdir(outputDir, kTRUE);
523 TString baseName = TString(inputFile);
524 Int_t lastSlash = baseName.Last(
'/');
525 if (lastSlash >= 0) {
526 baseName = baseName(lastSlash + 1, baseName.Length() - lastSlash - 1);
528 Int_t dotPos = baseName.Last(
'.sol');
530 baseName = baseName(0, dotPos - 3);
533 std::ifstream inFile(inputFile, std::ios::binary);
534 if (!inFile.is_open()) {
535 std::cerr <<
"ERROR: Cannot open input file " << inputFile << std::endl;
539 TString outPath = TString(outputDir) +
"/" + baseName +
"_chunk%03d.sol";
540 TString currentOutPath = Form(outPath.Data(), 0);
541 std::ofstream outFile(currentOutPath.Data(), std::ios::binary);
543 if (!outFile.is_open()) {
544 std::cerr <<
"ERROR: Cannot open output file " << currentOutPath
550 Long64_t chunkEndTs = 0;
551 Int_t chunkIndex = 0;
552 Bool_t firstBlock = kTRUE;
559 const Int_t kBulkRead = 4 * 1024 * 1024;
560 const Int_t kBulkWrite = 4 * 1024 * 1024;
561 std::vector<char> ibuf(kBulkRead);
562 std::vector<char> obuf;
563 obuf.reserve(kBulkWrite);
566 Long64_t filePos = 0;
568 while (RefillInput(inFile, ibuf, iPos, iLen, 2)) {
569 UShort_t blockHeader;
570 std::memcpy(&blockHeader, ibuf.data() + iPos, 2);
571 if ((blockHeader & 0xAA00) != 0xAA00) {
572 std::cerr <<
"WARNING: Invalid block header 0x" << std::hex << blockHeader
573 << std::dec <<
" at position " << filePos + 2 << std::endl;
577 UChar_t dataType = blockHeader & 0xF;
578 Bool_t isPsd = ((blockHeader >> 4) & 0xF) != 0;
580 Long64_t headerSize = 0;
581 Long64_t timestamp = 0;
582 Bool_t hasTimestamp = kTRUE;
583 Long64_t dataBytes = 0;
586 headerSize = 1 + 2 + (isPsd ? 2 : 0) + 6 + 2 + 1 + 2 + 1 + 1 + 1 + 2 + 8 +
588 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
591 Int_t tsOffset = 2 + 1 + 2 + (isPsd ? 2 : 0);
592 timestamp = ReadLe6(ibuf.data() + iPos + tsOffset);
594 Int_t tlOffset = tsOffset + 6 + 2 + 1 + 2 + 1 + 1 + 1 + 2 + 8 + 4;
595 ULong64_t traceLen = ReadLe8(ibuf.data() + iPos + tlOffset);
597 dataBytes = traceLen * 12;
601 headerSize = 1 + 2 + (isPsd ? 2 : 0) + 6 + 2 + 1 + 2 + 8 + 1;
602 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
605 Int_t tsOffset = 2 + 1 + 2 + (isPsd ? 2 : 0);
606 timestamp = ReadLe6(ibuf.data() + iPos + tsOffset);
608 Int_t tlOffset = tsOffset + 6 + 2 + 1 + 2;
609 ULong64_t traceLen = ReadLe8(ibuf.data() + iPos + tlOffset);
611 dataBytes = traceLen *
sizeof(Int_t);
615 headerSize = 1 + 2 + (isPsd ? 2 : 0) + 6 + 2 + 1 + 2;
616 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
619 Int_t tsOffset = 2 + 1 + 2 + (isPsd ? 2 : 0);
620 timestamp = ReadLe6(ibuf.data() + iPos + tsOffset);
623 headerSize = 1 + 2 + (isPsd ? 2 : 0) + 6;
624 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
627 Int_t tsOffset = 2 + 1 + 2 + (isPsd ? 2 : 0);
628 timestamp = ReadLe6(ibuf.data() + iPos + tsOffset);
631 headerSize = 1 + 2 + (isPsd ? 2 : 0) + 6 + 2;
632 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
635 Int_t tsOffset = 2 + 1 + 2 + (isPsd ? 2 : 0);
636 timestamp = ReadLe6(ibuf.data() + iPos + tsOffset);
640 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize))
643 hasTimestamp = kFALSE;
644 dataBytes = ReadLe8(ibuf.data() + iPos + 2);
647 std::cerr <<
"ERROR: Unknown SOL data type 0x" << std::hex << dataType
648 << std::dec <<
" at position " << filePos << std::endl;
653 if (!RefillInput(inFile, ibuf, iPos, iLen, 2 + headerSize + dataBytes))
658 if (hasTimestamp && (firstBlock || timestamp >= chunkEndTs)) {
661 outFile.write(obuf.data(), obuf.size());
666 currentOutPath = Form(outPath.Data(), chunkIndex);
667 outFile.open(currentOutPath.Data(), std::ios::binary);
668 if (!outFile.is_open()) {
669 std::cerr <<
"ERROR: Cannot open output file " << currentOutPath
674 chunkEndTs = timestamp +
static_cast<Long64_t
>(chunkSeconds * 1e9);
676 outputFiles.push_back(currentOutPath);
678 }
else if (!hasTimestamp && firstBlock) {
680 outputFiles.push_back(currentOutPath);
685 const Int_t blockBytes = Int_t(2 + headerSize + dataBytes);
686 obuf.insert(obuf.end(), ibuf.begin() + iPos,
687 ibuf.begin() + iPos + blockBytes);
689 filePos += blockBytes;
690 if (Long64_t(obuf.size()) >= kBulkWrite) {
691 outFile.write(obuf.data(), obuf.size());
700 outFile.write(obuf.data(), obuf.size());
706 std::cout <<
"Split " << totalBlocks <<
" blocks into " << totalChunks
707 <<
" chunks in " << outputDir << std::endl;
719 UShort_t block_header;
720 file.read(
reinterpret_cast<char *
>(&block_header),
sizeof(UShort_t));
726 if ((block_header & 0xAA00) != 0xAA00) {
727 std::cerr <<
"WARNING: SOL block header mismatch at block " << block_id
728 <<
" (got 0x" << std::hex << block_header << std::dec
729 <<
", expected 0xAAxx)" << std::endl;
733 current_event.block_header = block_header;
734 current_event.data_type = block_header & 0xF;
735 current_event.is_psd = ((block_header >> 4) & 0xF) != 0;
738 Int_t header_bytes = 1 + 2 + (current_event.is_psd ? 2 : 0) + 6 + 2 + 1 +
739 2 + 1 + 1 + 1 + 2 + 8 + 4 + 8 + 2 + 4;
740 std::vector<char> hdr(header_bytes);
741 file.read(hdr.data(), header_bytes);
743 std::cerr <<
"WARNING: Incomplete ALL-format block at byte " <<
bytes_read
744 <<
" (truncated file)" << std::endl;
750 current_event.channel =
static_cast<UChar_t
>(hdr[off]);
752 std::memcpy(¤t_event.energy, hdr.data() + off, 2);
754 if (current_event.is_psd) {
755 std::memcpy(¤t_event.energy_short, hdr.data() + off, 2);
758 std::memcpy(¤t_event.timestamp, hdr.data() + off, 6);
760 std::memcpy(¤t_event.fine_timestamp, hdr.data() + off, 2);
762 current_event.flags_high =
static_cast<UChar_t
>(hdr[off]);
764 std::memcpy(¤t_event.flags_low, hdr.data() + off, 2);
766 current_event.down_sampling =
static_cast<UChar_t
>(hdr[off]);
768 current_event.board_fail =
static_cast<UChar_t
>(hdr[off]);
770 current_event.flush =
static_cast<UChar_t
>(hdr[off]);
772 std::memcpy(¤t_event.trigger_thr, hdr.data() + off, 2);
774 std::memcpy(¤t_event.event_size, hdr.data() + off, 8);
776 std::memcpy(¤t_event.agg_counter, hdr.data() + off, 4);
778 std::memcpy(¤t_event.trace_len, hdr.data() + off, 8);
780 std::memcpy(current_event.ana_probe_type, hdr.data() + off, 2);
782 std::memcpy(current_event.dig_probe_type, hdr.data() + off, 4);
784 if (current_event.trace_len > 0) {
785 ULong64_t n_samples = current_event.trace_len;
786 const ULong64_t kMaxTraceLen = 100000;
787 Long64_t trace_bytes = n_samples * 12;
789 if (n_samples > kMaxTraceLen) {
790 std::cerr <<
"WARNING: Implausible trace length " << n_samples
791 <<
" at block " << block_id <<
" (skipping trace data)"
793 file.seekg(trace_bytes, std::ios::cur);
795 }
else if (skip_traces) {
796 file.seekg(trace_bytes, std::ios::cur);
799 current_event.trace_data.resize(trace_bytes);
800 file.read(current_event.trace_data.data(), trace_bytes);
802 file.gcount() !=
static_cast<std::streamsize
>(trace_bytes)) {
803 std::cerr <<
"WARNING: Incomplete traces at block " << block_id
804 <<
" (truncated file)" << std::endl;
813 1 + 2 + (current_event.is_psd ? 2 : 0) + 6 + 2 + 1 + 2 + 8 + 1;
814 std::vector<char> hdr(header_bytes);
815 file.read(hdr.data(), header_bytes);
817 std::cerr <<
"WARNING: Incomplete OneTrace-format block at byte "
818 <<
bytes_read <<
" (truncated file)" << std::endl;
824 current_event.channel =
static_cast<UChar_t
>(hdr[off]);
826 std::memcpy(¤t_event.energy, hdr.data() + off, 2);
828 if (current_event.is_psd) {
829 std::memcpy(¤t_event.energy_short, hdr.data() + off, 2);
832 std::memcpy(¤t_event.timestamp, hdr.data() + off, 6);
834 std::memcpy(¤t_event.fine_timestamp, hdr.data() + off, 2);
836 current_event.flags_high =
static_cast<UChar_t
>(hdr[off]);
838 std::memcpy(¤t_event.flags_low, hdr.data() + off, 2);
840 std::memcpy(¤t_event.trace_len, hdr.data() + off, 8);
842 current_event.ana_probe_type[0] =
static_cast<UChar_t
>(hdr[off]);
844 if (current_event.trace_len > 0) {
845 ULong64_t n_samples = current_event.trace_len;
846 const ULong64_t kMaxTraceLen = 100000;
847 Long64_t trace_bytes = n_samples *
sizeof(Int_t);
849 if (n_samples > kMaxTraceLen) {
850 std::cerr <<
"WARNING: Implausible trace length " << n_samples
851 <<
" at block " << block_id <<
" (skipping trace data)"
853 file.seekg(trace_bytes, std::ios::cur);
855 }
else if (skip_traces) {
856 file.seekg(trace_bytes, std::ios::cur);
859 current_event.trace_data.resize(trace_bytes);
860 file.read(current_event.trace_data.data(), trace_bytes);
862 std::cerr <<
"WARNING: Incomplete trace at block " << block_id
863 <<
" (truncated file)" << std::endl;
872 1 + 2 + (current_event.is_psd ? 2 : 0) + 6 + 2 + 1 + 2 +
873 (current_event.is_psd ? 20 : 18) -
874 (1 + 2 + (current_event.is_psd ? 2 : 0) + 6 + 2 + 1 + 2);
875 std::vector<char> hdr(header_bytes);
876 file.read(hdr.data(), header_bytes);
878 std::cerr <<
"WARNING: Incomplete NoTrace-format block at byte "
879 <<
bytes_read <<
" (truncated file)" << std::endl;
885 current_event.channel =
static_cast<UChar_t
>(hdr[off]);
887 std::memcpy(¤t_event.energy, hdr.data() + off, 2);
889 if (current_event.is_psd) {
890 std::memcpy(¤t_event.energy_short, hdr.data() + off, 2);
893 std::memcpy(¤t_event.timestamp, hdr.data() + off, 6);
895 std::memcpy(¤t_event.fine_timestamp, hdr.data() + off, 2);
897 current_event.flags_high =
static_cast<UChar_t
>(hdr[off]);
899 std::memcpy(¤t_event.flags_low, hdr.data() + off, 2);
902 Int_t header_bytes = 1 + 2 + (current_event.is_psd ? 2 : 0) + 6 + 2;
903 std::vector<char> hdr(header_bytes);
904 file.read(hdr.data(), header_bytes);
906 std::cerr <<
"WARNING: Incomplete MiniWithFineTime block at byte "
907 <<
bytes_read <<
" (truncated file)" << std::endl;
913 current_event.channel =
static_cast<UChar_t
>(hdr[off]);
915 std::memcpy(¤t_event.energy, hdr.data() + off, 2);
917 if (current_event.is_psd) {
918 std::memcpy(¤t_event.energy_short, hdr.data() + off, 2);
921 std::memcpy(¤t_event.timestamp, hdr.data() + off, 6);
923 std::memcpy(¤t_event.fine_timestamp, hdr.data() + off, 2);
926 Int_t header_bytes = 1 + 2 + (current_event.is_psd ? 2 : 0) + 6;
927 std::vector<char> hdr(header_bytes);
928 file.read(hdr.data(), header_bytes);
930 std::cerr <<
"WARNING: Incomplete Minimum-format block at byte "
931 <<
bytes_read <<
" (truncated file)" << std::endl;
937 current_event.channel =
static_cast<UChar_t
>(hdr[off]);
939 std::memcpy(¤t_event.energy, hdr.data() + off, 2);
941 if (current_event.is_psd) {
942 std::memcpy(¤t_event.energy_short, hdr.data() + off, 2);
945 std::memcpy(¤t_event.timestamp, hdr.data() + off, 6);
949 file.read(
reinterpret_cast<char *
>(&data_size), 8);
951 std::cerr <<
"WARNING: Incomplete Raw-format block at byte " <<
bytes_read
952 <<
" (truncated file)" << std::endl;
958 file.seekg(data_size, std::ios::cur);
963 std::cerr <<
"ERROR: Unknown SOL data type 0x" << std::hex
964 << current_event.data_type << std::dec <<
" at block " << block_id
969 current_event.block_id = block_id;