diff --git a/CMakeLists.txt b/CMakeLists.txt index 7014f9d5..1a2ad4d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -500,9 +500,8 @@ endif() add_custom_target( check-format COMMAND - find \\ (-name "*.cpp" -o -name "*.hpp" \\) -not -path "./build/*" | xargs - -I {} -n 1 -P 10 bash -c - "clang-format -Werror -style=\"file:.clang-format\" {} | diff {} -" + bash -c + [=[ find \( -name "*.cpp" -o -name "*.hpp" \) -not -path "./build/*" | xargs -I {} -n 1 -P 10 bash -c "clang-format -Werror -style=\"file:.clang-format\" {} | diff {} -" ]=] WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Checking code formatting with clang-format" VERBATIM) @@ -510,8 +509,8 @@ add_custom_target( add_custom_target( format-files COMMAND - find \\ (-name "*.cpp" -o -name "*.hpp" \\) -not -path "./build/*" | xargs - -I {} -n 1 -P 10 bash -c "clang-format -i -style=\"file:.clang-format\" {}" + bash -c + [=[ find \( -name "*.cpp" -o -name "*.hpp" \) -not -path "./build/*" | xargs -I {} -n 1 -P 10 bash -c "clang-format -i -style=\"file:.clang-format\" {}" ]=] WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Formatting with clang-format" VERBATIM) @@ -526,18 +525,9 @@ endif() add_custom_target( clang-tidy COMMAND - find \\ (-path - "./src/*" - -a - -not - -path - "./src/python/*" - -a - \\ - (-name "*.cpp" -not -name "*.test.cpp" \\) - \\) -not -name "CircularFifo.hpp" -not -name - "ProducerConsumerQueue.hpp" -not -name "VariableSizeClusterFinder.hpp" | - xargs -I {} -n 1 -P 10 bash -c + find -path "./src/*" -not -path "./src/python/*" -not -name "*.test.cpp" + -not -name "CircularFifo.hpp" -not -name "ProducerConsumerQueue.hpp" -not + -name "VariableSizeClusterFinder.hpp" | xargs -I {} -n 1 -P 10 bash -c "${CLANG_TIDY_COMMAND} --config-file=.clang-tidy -p build {}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "linting with clang-tidy" diff --git a/RELEASE.md b/RELEASE.md index 9739ab2e..74d799b1 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -12,6 +12,9 @@ evaluators. Model objects are callable and provide the replacement, for example ``Gaussian()(x, par)``. +### Bugfixes: +- Fixed broken reading of old (pre reordering) Moench03 + ## 2026.7.2 diff --git a/include/aare/NDArray.hpp b/include/aare/NDArray.hpp index 079915d6..43964028 100644 --- a/include/aare/NDArray.hpp +++ b/include/aare/NDArray.hpp @@ -506,12 +506,13 @@ class NDArray : public ArrayExpr, Ndim> { return *this; } - /** - * @brief Create a view of the NDArray. - * - * @return NDView - */ - NDView view() const { return NDView{data_, shape_}; } + /** @brief Create a mutable view of the NDArray. */ + NDView view() { return NDView{data_, shape_}; } + + /** @brief Create a read-only view of a const NDArray. */ + NDView view() const { + return NDView{data_, shape_}; + } private: /** diff --git a/include/aare/Pedestal.hpp b/include/aare/Pedestal.hpp index 6ea6a6fb..48bb6568 100644 --- a/include/aare/Pedestal.hpp +++ b/include/aare/Pedestal.hpp @@ -45,7 +45,7 @@ template class Pedestal { NDArray mean() { return m_mean; } - const NDView view() const { return m_mean.view(); } + NDView view() const { return m_mean.view(); } SUM_TYPE mean(const uint32_t row, const uint32_t col) const { return m_mean(row, col); @@ -221,4 +221,4 @@ template class Pedestal { m_mean(row, col) = m_sum(row, col) / m_samples; } }; -} // namespace aare \ No newline at end of file +} // namespace aare diff --git a/include/aare/hist/PixelHistogramImpl.hpp b/include/aare/hist/PixelHistogramImpl.hpp index 715537f6..30b468b9 100644 --- a/include/aare/hist/PixelHistogramImpl.hpp +++ b/include/aare/hist/PixelHistogramImpl.hpp @@ -42,7 +42,7 @@ template class PixelHistogramImpl { // Zero-copy view of the underlying [rows x cols x n_bins] storage. // Lifetime is tied to *this. Use for low-level merge/stitching paths; // prefer values() for the public API where you want an owned copy. - NDView view() const; + NDView view() const; NDArray bin_centers() const; NDArray bin_edges() const; }; @@ -122,7 +122,7 @@ NDArray PixelHistogramImpl::values() const { } template -NDView PixelHistogramImpl::view() const { +NDView PixelHistogramImpl::view() const { return m_values.view(); } diff --git a/src/NDArray.test.cpp b/src/NDArray.test.cpp index e2609d27..3a3cafc0 100644 --- a/src/NDArray.test.cpp +++ b/src/NDArray.test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using aare::NDArray; using aare::NDView; @@ -71,6 +72,20 @@ TEST_CASE("Accessing a const object") { REQUIRE(img.shape(2) == 5); } +TEST_CASE("A const NDArray returns a read-only view") { + NDArray mutable_array({2, 3}, 1); + const auto &const_array = mutable_array; + + static_assert( + std::is_same_v>); + static_assert( + std::is_same_v>); + + auto view = const_array.view(); + static_assert(std::is_same_v); + REQUIRE(view(1, 2) == 1); +} + TEST_CASE("Indexing of a 2D image") { std::array shape{{3, 7}}; NDArray img(shape, 5); diff --git a/src/RawMasterFile.cpp b/src/RawMasterFile.cpp index d399c25d..9eff0d26 100644 --- a/src/RawMasterFile.cpp +++ b/src/RawMasterFile.cpp @@ -303,18 +303,31 @@ void RawMasterFile::parse_json(std::istream &is) { } // ---------------------------------------------------------------- - // Special treatment of analog flag because of Moench03 - m_analog_flag = v < 8.0 && (m_type == DetectorType::Moench); + // Special treatment of analog flag because of Moench03. + // Before SW 8.0.0 (NOT json file version v8!) Moench03 had Analog Samples + // but no Analog Flag. Therefore we need to set analog flag to true and try + // to read analog samples The detector type is later set depending on analog + // samples and number of pixels. - try { - m_analog_flag = static_cast(j.at("Analog Flag").get()); - if (m_analog_flag) { - m_analog_samples = j.at("Analog Samples"); + if (m_type == DetectorType::Moench) { + if (auto it = j.find("Analog Samples"); it != j.end()) { + m_analog_flag = true; + m_analog_samples = it->get(); + } else { + m_analog_flag = false; + } + } else { + if (auto it = j.find("Analog Flag"); it != j.end()) { + m_analog_flag = static_cast(it->get()); + if (m_analog_flag) { + m_analog_samples = j.at("Analog Samples"); + } + } else { + m_analog_flag = false; } - } catch (const json::out_of_range &e) { - // keep the optional empty } //----------------------------------------------------------------- + try { m_quad = j.at("Quad"); } catch (const json::out_of_range &e) { diff --git a/src/RawMasterFile.test.cpp b/src/RawMasterFile.test.cpp index 5d077ce9..59efed71 100644 --- a/src/RawMasterFile.test.cpp +++ b/src/RawMasterFile.test.cpp @@ -411,6 +411,10 @@ TEST_CASE("Parse EIGER 7.2 master from string stream") { REQUIRE(f.frame_padding() == 1); REQUIRE(f.total_frames_expected() == 3); + REQUIRE(f.quad() == 0); + REQUIRE(f.number_of_rows() == 256); + REQUIRE(f.n_modules() == 4); + REQUIRE(f.bitdepth() == 32); REQUIRE(f.frames_in_file() == 3); @@ -489,9 +493,473 @@ TEST_CASE("Parse JUNGFRAU 7.2 master from string stream") { REQUIRE(f.number_of_rows() == 512); REQUIRE(f.frames_in_file() == 10); + REQUIRE(f.quad() == 0); + REQUIRE(f.n_modules() == 2); REQUIRE(f.udp_interfaces_per_module() == xy{2, 1}); } +TEST_CASE( + "Parse CTB 7.2 master (SW 7.0.3) with analog samples from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 09:45:29 2026", + "Detector Type": "ChipTestBoard", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 192000, + "Pixels": { + "x": 32, + "y": 1 + }, + "Max Frames Per File": 20000, + "Frame Discard Policy": "nodiscard", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "0ns", + "Period": "1ms", + "Ten Giga": 0, + "ADC Mask": "0xffffffff", + "Analog Flag": 1, + "Analog Samples": 3000, + "Digital Flag": 0, + "Digital Samples": 2000, + "Dbit Offset": 0, + "Dbit Bitset": 0, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::ChipTestBoard); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 192000); + REQUIRE(f.pixels_x() == 32); + REQUIRE(f.pixels_y() == 1); + REQUIRE(f.max_frames_per_file() == 20000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::nanoseconds(0)); + REQUIRE(f.period() == std::chrono::milliseconds(1)); + REQUIRE(f.analog_samples() == 3000); + REQUIRE(f.digital_samples() == std::nullopt); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.frames_in_file() == 1); +} + +TEST_CASE( + "Parse CTB 7.2 master (SW 7.0.3) with digital samples from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 09:48:34 2026", + "Detector Type": "ChipTestBoard", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 16000, + "Pixels": { + "x": 64, + "y": 1 + }, + "Max Frames Per File": 20000, + "Frame Discard Policy": "nodiscard", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "0ns", + "Period": "1ms", + "Ten Giga": 0, + "ADC Mask": "0xffffffff", + "Analog Flag": 0, + "Analog Samples": 3000, + "Digital Flag": 1, + "Digital Samples": 2000, + "Dbit Offset": 0, + "Dbit Bitset": 0, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::ChipTestBoard); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 16000); + REQUIRE(f.pixels_x() == 64); + REQUIRE(f.pixels_y() == 1); + REQUIRE(f.max_frames_per_file() == 20000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::nanoseconds(0)); + REQUIRE(f.period() == std::chrono::milliseconds(1)); + REQUIRE(f.analog_samples() == std::nullopt); + REQUIRE(f.digital_samples() == 2000); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.frames_in_file() == 1); +} + +TEST_CASE("Parse Moench 7.2 master (SW 7.0.3) from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 10:32:06 2026", + "Detector Type": "Moench", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 320000, + "Pixels": { + "x": 400, + "y": 400 + }, + "Max Frames Per File": 100000, + "Frame Discard Policy": "nodiscard", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "20us", + "Period": "2ms", + "Ten Giga": 0, + "ADC Mask": "0xffffffff", + "Analog Samples": 5000, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::Moench03_old); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 320000); + REQUIRE(f.pixels_x() == 400); + REQUIRE(f.pixels_y() == 400); + REQUIRE(f.max_frames_per_file() == 100000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::microseconds(20)); + REQUIRE(f.period() == std::chrono::milliseconds(2)); + REQUIRE(f.analog_samples() == 5000); + REQUIRE(f.digital_samples() == std::nullopt); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.frames_in_file() == 1); +} + +TEST_CASE("Parse Moench 7.2 master (SW 8.0.0) from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 09:54:53 2026", + "Detector Type": "Moench", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 320000, + "Pixels": { + "x": 400, + "y": 400 + }, + "Max Frames Per File": 100000, + "Frame Discard Policy": "discardpartial", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "10us", + "Period": "2ms", + "Number of UDP Interfaces": 1, + "Number of rows": 400, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::Moench03); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 320000); + REQUIRE(f.pixels_x() == 400); + REQUIRE(f.pixels_y() == 400); + REQUIRE(f.max_frames_per_file() == 100000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::DiscardPartial); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::microseconds(10)); + REQUIRE(f.period() == std::chrono::milliseconds(2)); + REQUIRE(f.number_of_rows() == 400); + REQUIRE(f.frames_in_file() == 1); + REQUIRE(f.analog_samples() == std::nullopt); + REQUIRE(f.digital_samples() == std::nullopt); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.udp_interfaces_per_module() == xy{1, 1}); +} + +TEST_CASE("Parse CTB 7.2 master (SW 8.0.0) from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 09:56:30 2026", + "Detector Type": "ChipTestBoard", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 192000, + "Pixels": { + "x": 32, + "y": 1 + }, + "Max Frames Per File": 20000, + "Frame Discard Policy": "nodiscard", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "0ns", + "Period": "1ms", + "Ten Giga": 0, + "ADC Mask": "0xffffffff", + "Analog Flag": 1, + "Analog Samples": 3000, + "Digital Flag": 0, + "Digital Samples": 2000, + "Dbit Offset": 0, + "Dbit Bitset": 0, + "Transceiver Mask": "0x3", + "Transceiver Flag": 0, + "Transceiver Samples": 1, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::ChipTestBoard); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 192000); + REQUIRE(f.pixels_x() == 32); + REQUIRE(f.pixels_y() == 1); + REQUIRE(f.max_frames_per_file() == 20000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::nanoseconds(0)); + REQUIRE(f.period() == std::chrono::milliseconds(1)); + REQUIRE(f.analog_samples() == 3000); + REQUIRE(f.digital_samples() == std::nullopt); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.frames_in_file() == 1); +} + +TEST_CASE( + "Parse CTB 7.2 master (SW 8.0.0) with digital samples from string stream") { + std::string master_content = R"({ + "Version": 7.2, + "Timestamp": "Wed Aug 19 09:58:22 2026", + "Detector Type": "ChipTestBoard", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 16000, + "Pixels": { + "x": 64, + "y": 1 + }, + "Max Frames Per File": 20000, + "Frame Discard Policy": "nodiscard", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "0ns", + "Period": "1ms", + "Ten Giga": 0, + "ADC Mask": "0xffffffff", + "Analog Flag": 0, + "Analog Samples": 3000, + "Digital Flag": 1, + "Digital Samples": 2000, + "Dbit Offset": 0, + "Dbit Bitset": 0, + "Transceiver Mask": "0x3", + "Transceiver Flag": 0, + "Transceiver Samples": 1, + "Frames in File": 1, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +})"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.2"); + REQUIRE(f.detector_type() == DetectorType::ChipTestBoard); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry() == xy{1, 1}); + REQUIRE(f.image_size_in_bytes() == 16000); + REQUIRE(f.pixels_x() == 64); + REQUIRE(f.pixels_y() == 1); + REQUIRE(f.max_frames_per_file() == 20000); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.total_frames_expected() == 1); + REQUIRE(f.exptime() == std::chrono::nanoseconds(0)); + REQUIRE(f.period() == std::chrono::milliseconds(1)); + REQUIRE(f.analog_samples() == std::nullopt); + REQUIRE(f.digital_samples() == 2000); + REQUIRE(f.transceiver_samples() == std::nullopt); + REQUIRE(f.frames_in_file() == 1); +} + TEST_CASE("Parse a CTB file from stream") { std::string master_content = R"({ "Version": 8.0, @@ -738,4 +1206,83 @@ TEST_CASE("Parse a v7.1 Mythen3 from stream") { // Period is ok though REQUIRE(f.period() == std::chrono::milliseconds(2)); -} \ No newline at end of file +} + +TEST_CASE("Parse old Moench03 from stream") { + std::string master_content = R"( + { + "Version": 7.1, + "Timestamp": "Mon Mar 25 10:07:02 2024", + "Detector Type": "Moench", + "Timing Mode": "auto", + "Geometry": { + "x": 1, + "y": 1 + }, + "Image Size in bytes": 320000, + "Pixels": { + "x": 400, + "y": 400 + }, + "Max Frames Per File": 100000, + "Frame Discard Policy": "discardpartial", + "Frame Padding": 1, + "Scan Parameters": "[disabled]", + "Total Frames": 1000000, + "Receiver Roi": { + "xmin": 4294967295, + "xmax": 4294967295, + "ymin": 4294967295, + "ymax": 4294967295 + }, + "Exptime": "50us", + "Period": "600us", + "Ten Giga": 1, + "ADC Mask": "0xffffffff", + "Analog Samples": 5000, + "Additional Json Header": "{detectorMode: analog, frameMode: newPedestal}", + "Frames in File": 999995, + "Frame Header Format": { + "Frame Number": "8 bytes", + "SubFrame Number/ExpLength": "4 bytes", + "Packet Number": "4 bytes", + "Bunch ID": "8 bytes", + "Timestamp": "8 bytes", + "Module Id": "2 bytes", + "Row": "2 bytes", + "Column": "2 bytes", + "Reserved": "2 bytes", + "Debug": "4 bytes", + "Round Robin Number": "2 bytes", + "Detector Type": "1 byte", + "Header Version": "1 byte", + "Packets Caught Mask": "64 bytes" + } +} + +)"; + + std::istringstream iss(master_content); + RawMasterFile f(iss, "test_master_0.json"); + + REQUIRE(f.version() == "7.1"); + REQUIRE(f.detector_type() == DetectorType::Moench03_old); + REQUIRE(f.timing_mode() == TimingMode::Auto); + REQUIRE(f.geometry().col == 1); + REQUIRE(f.geometry().row == 1); + REQUIRE(f.image_size_in_bytes() == 320000); + REQUIRE(f.pixels_x() == 400); + REQUIRE(f.pixels_y() == 400); + REQUIRE(f.max_frames_per_file() == 100000); + REQUIRE((f.total_frames_expected() == + 1000000)); // This is Total Frames in the master file + REQUIRE(f.frames_in_file() == 999995); + REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::DiscardPartial); + REQUIRE(f.frame_padding() == 1); + REQUIRE(f.n_modules() == 1); + REQUIRE(f.quad() == 0); + REQUIRE(f.bitdepth() == 16); + REQUIRE(f.exptime() == std::chrono::microseconds(50)); + REQUIRE(f.period() == std::chrono::microseconds(600)); + REQUIRE(f.analog_samples() == 5000); +}