From 13b2cb40b6f7f3ba1bad7415481306a9c8d309b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Fr=C3=B6jdh?= Date: Thu, 14 Nov 2024 07:41:50 +0100 Subject: [PATCH] docs and reorder --- include/aare/NDArray.hpp | 173 ++++++++++++++++++++++-------------- include/aare/NDView.hpp | 4 +- include/aare/PixelMap.hpp | 3 + include/aare/RawSubFile.hpp | 6 +- include/aare/SubFile.hpp | 80 ----------------- src/NDArray.test.cpp | 38 +------- src/PixelMap.cpp | 10 +++ src/RawFile.cpp | 6 +- src/RawSubFile.cpp | 13 +-- src/SubFile.cpp | 91 ------------------- 10 files changed, 142 insertions(+), 282 deletions(-) delete mode 100644 include/aare/SubFile.hpp delete mode 100644 src/SubFile.cpp diff --git a/include/aare/NDArray.hpp b/include/aare/NDArray.hpp index e65b136..75f4c1c 100644 --- a/include/aare/NDArray.hpp +++ b/include/aare/NDArray.hpp @@ -21,33 +21,62 @@ TODO! Add expression templates for operators namespace aare { template class NDArray { - public: - NDArray() : shape_(), strides_(c_strides(shape_)), data_(nullptr){}; + std::array shape_; + std::array strides_; + size_t size_{}; + T *data_; + public: + /** + * @brief Default constructor. Will construct an empty NDArray. + * + */ + NDArray() : shape_(), strides_(c_strides(shape_)), data_(nullptr) {}; + + /** + * @brief Construct a new NDArray object with a given shape. + * @note The data is uninitialized. + * + * @param shape shape of the new NDArray + */ explicit NDArray(std::array shape) : shape_(shape), strides_(c_strides(shape_)), - size_(std::accumulate(shape_.begin(), shape_.end(), 1, std::multiplies<>())), data_(new T[size_]){}; + size_(std::accumulate(shape_.begin(), shape_.end(), 1, + std::multiplies<>())), + data_(new T[size_]) {}; - NDArray(std::array shape, T value) : NDArray(shape) { this->operator=(value); } + /** + * @brief Construct a new NDArray object with a shape and value. + * + * @param shape shape of the new array + * @param value value to initialize the array with + */ + NDArray(std::array shape, T value) : NDArray(shape) { + this->operator=(value); + } - /* When constructing from a NDView we need to copy the data since - NDArray expect to own its data, and span is just a view*/ - explicit NDArray(NDView span) : NDArray(span.shape()) { - std::copy(span.begin(), span.end(), begin()); - // fmt::print("NDArray(NDView span)\n"); + /** + * @brief Construct a new NDArray object from a NDView. + * @note The data is copied from the view to the NDArray. + * + * @param v view of data to initialize the NDArray with + */ + explicit NDArray(const NDView v) : NDArray(v.shape()) { + std::copy(v.begin(), v.end(), begin()); } // Move constructor NDArray(NDArray &&other) noexcept - : shape_(other.shape_), strides_(c_strides(shape_)), size_(other.size_), data_(other.data_) { + : shape_(other.shape_), strides_(c_strides(shape_)), + size_(other.size_), data_(other.data_) { other.reset(); - // fmt::print("NDArray(NDArray &&other)\n"); } // Copy constructor NDArray(const NDArray &other) - : shape_(other.shape_), strides_(c_strides(shape_)), size_(other.size_), data_(new T[size_]) { + : shape_(other.shape_), strides_(c_strides(shape_)), + size_(other.size_), data_(new T[size_]) { std::copy(other.data_, other.data_ + size_, data_); // fmt::print("NDArray(const NDArray &other)\n"); } @@ -70,6 +99,7 @@ template class NDArray { NDArray &operator*=(const NDArray &other); NDArray operator/(const NDArray &other); // NDArray& operator/=(const NDArray& other); + template NDArray &operator/=(const NDArray &other) { // check shape if (shape_ == other.shape()) { @@ -106,15 +136,18 @@ template class NDArray { NDArray &operator++(); // pre inc - template std::enable_if_t operator()(Ix... index) { + template + std::enable_if_t operator()(Ix... index) { return data_[element_offset(strides_, index...)]; } - template std::enable_if_t operator()(Ix... index) const { + template + std::enable_if_t operator()(Ix... index) const { return data_[element_offset(strides_, index...)]; } - template std::enable_if_t value(Ix... index) { + template + std::enable_if_t value(Ix... index) { return data_[element_offset(strides_, index...)]; } @@ -129,15 +162,20 @@ template class NDArray { int64_t shape(int64_t i) const noexcept { return shape_[i]; } std::array strides() const noexcept { return strides_; } size_t bitdepth() const noexcept { return sizeof(T) * 8; } + std::array byte_strides() const noexcept { auto byte_strides = strides_; for (auto &val : byte_strides) val *= sizeof(T); return byte_strides; - // return strides_; } - NDView span() const { return NDView{data_, shape_}; } + /** + * @brief Create a view of the NDArray. + * + * @return NDView + */ + NDView view() const { return NDView{data_, shape_}; } void Print(); void Print_all(); @@ -149,16 +187,12 @@ template class NDArray { std::fill(shape_.begin(), shape_.end(), 0); std::fill(strides_.begin(), strides_.end(), 0); } - - private: - std::array shape_; - std::array strides_; - uint64_t size_{}; - T *data_; }; // Move assign -template NDArray &NDArray::operator=(NDArray &&other) noexcept { +template +NDArray & +NDArray::operator=(NDArray &&other) noexcept { if (this != &other) { delete[] data_; data_ = other.data_; @@ -170,12 +204,14 @@ template NDArray &NDArray::operator return *this; } -template NDArray NDArray::operator+(const NDArray &other) { +template +NDArray NDArray::operator+(const NDArray &other) { NDArray result(*this); result += other; return result; } -template NDArray &NDArray::operator+=(const NDArray &other) { +template +NDArray &NDArray::operator+=(const NDArray &other) { // check shape if (shape_ == other.shape_) { for (uint32_t i = 0; i < size_; ++i) { @@ -186,13 +222,15 @@ template NDArray &NDArray::operator throw(std::runtime_error("Shape of ImageDatas must match")); } -template NDArray NDArray::operator-(const NDArray &other) { +template +NDArray NDArray::operator-(const NDArray &other) { NDArray result{*this}; result -= other; return result; } -template NDArray &NDArray::operator-=(const NDArray &other) { +template +NDArray &NDArray::operator-=(const NDArray &other) { // check shape if (shape_ == other.shape_) { for (uint32_t i = 0; i < size_; ++i) { @@ -202,13 +240,15 @@ template NDArray &NDArray::operator } throw(std::runtime_error("Shape of ImageDatas must match")); } -template NDArray NDArray::operator*(const NDArray &other) { +template +NDArray NDArray::operator*(const NDArray &other) { NDArray result = *this; result *= other; return result; } -template NDArray &NDArray::operator*=(const NDArray &other) { +template +NDArray &NDArray::operator*=(const NDArray &other) { // check shape if (shape_ == other.shape_) { for (uint32_t i = 0; i < size_; ++i) { @@ -219,34 +259,22 @@ template NDArray &NDArray::operator throw(std::runtime_error("Shape of ImageDatas must match")); } -template NDArray NDArray::operator/(const NDArray &other) { +template +NDArray NDArray::operator/(const NDArray &other) { NDArray result = *this; result /= other; return result; } -template NDArray &NDArray::operator&=(const T &mask) { +template +NDArray &NDArray::operator&=(const T &mask) { for (auto it = begin(); it != end(); ++it) *it &= mask; return *this; } -// template -// NDArray& NDArray::operator/=(const NDArray& -// other) -// { -// //check shape -// if (shape_ == other.shape_) { -// for (int i = 0; i < size_; ++i) { -// data_[i] /= other.data_[i]; -// } -// return *this; -// } else { -// throw(std::runtime_error("Shape of ImageDatas must match")); -// } -// } - -template NDArray NDArray::operator>(const NDArray &other) { +template +NDArray NDArray::operator>(const NDArray &other) { if (shape_ == other.shape_) { NDArray result{shape_}; for (int i = 0; i < size_; ++i) { @@ -257,7 +285,8 @@ template NDArray NDArray::operat throw(std::runtime_error("Shape of ImageDatas must match")); } -template NDArray &NDArray::operator=(const NDArray &other) { +template +NDArray &NDArray::operator=(const NDArray &other) { if (this != &other) { delete[] data_; shape_ = other.shape_; @@ -269,7 +298,8 @@ template NDArray &NDArray::operator return *this; } -template bool NDArray::operator==(const NDArray &other) const { +template +bool NDArray::operator==(const NDArray &other) const { if (shape_ != other.shape_) return false; @@ -280,57 +310,68 @@ template bool NDArray::operator==(const NDAr return true; } -template bool NDArray::operator!=(const NDArray &other) const { +template +bool NDArray::operator!=(const NDArray &other) const { return !((*this) == other); } -template NDArray &NDArray::operator++() { +template +NDArray &NDArray::operator++() { for (uint32_t i = 0; i < size_; ++i) data_[i] += 1; return *this; } -template NDArray &NDArray::operator=(const T &value) { +template +NDArray &NDArray::operator=(const T &value) { std::fill_n(data_, size_, value); return *this; } -template NDArray &NDArray::operator+=(const T &value) { +template +NDArray &NDArray::operator+=(const T &value) { for (uint32_t i = 0; i < size_; ++i) data_[i] += value; return *this; } -template NDArray NDArray::operator+(const T &value) { +template +NDArray NDArray::operator+(const T &value) { NDArray result = *this; result += value; return result; } -template NDArray &NDArray::operator-=(const T &value) { +template +NDArray &NDArray::operator-=(const T &value) { for (uint32_t i = 0; i < size_; ++i) data_[i] -= value; return *this; } -template NDArray NDArray::operator-(const T &value) { +template +NDArray NDArray::operator-(const T &value) { NDArray result = *this; result -= value; return result; } -template NDArray &NDArray::operator/=(const T &value) { +template +NDArray &NDArray::operator/=(const T &value) { for (uint32_t i = 0; i < size_; ++i) data_[i] /= value; return *this; } -template NDArray NDArray::operator/(const T &value) { +template +NDArray NDArray::operator/(const T &value) { NDArray result = *this; result /= value; return result; } -template NDArray &NDArray::operator*=(const T &value) { +template +NDArray &NDArray::operator*=(const T &value) { for (uint32_t i = 0; i < size_; ++i) data_[i] *= value; return *this; } -template NDArray NDArray::operator*(const T &value) { +template +NDArray NDArray::operator*(const T &value) { NDArray result = *this; result *= value; return result; @@ -342,9 +383,8 @@ template void NDArray::Print() { Print_some(); } - template -std::ostream& operator <<(std::ostream& os, const NDArray& arr){ +std::ostream &operator<<(std::ostream &os, const NDArray &arr) { for (auto row = 0; row < arr.shape(0); ++row) { for (auto col = 0; col < arr.shape(1); ++col) { os << std::setw(3); @@ -355,7 +395,6 @@ std::ostream& operator <<(std::ostream& os, const NDArray& arr){ return os; } - template void NDArray::Print_all() { for (auto row = 0; row < shape_[0]; ++row) { for (auto col = 0; col < shape_[1]; ++col) { @@ -375,7 +414,8 @@ template void NDArray::Print_some() { } } -template void save(NDArray &img, std::string &pathname) { +template +void save(NDArray &img, std::string &pathname) { std::ofstream f; f.open(pathname, std::ios::binary); f.write(img.buffer(), img.size() * sizeof(T)); @@ -383,7 +423,8 @@ template void save(NDArray &img, std::string } template -NDArray load(const std::string &pathname, std::array shape) { +NDArray load(const std::string &pathname, + std::array shape) { NDArray img{shape}; std::ifstream f; f.open(pathname, std::ios::binary); diff --git a/include/aare/NDView.hpp b/include/aare/NDView.hpp index 906b215..e02b3b2 100644 --- a/include/aare/NDView.hpp +++ b/include/aare/NDView.hpp @@ -74,6 +74,8 @@ template class NDView { T *begin() { return buffer_; } T *end() { return buffer_ + size_; } + T const *begin() const { return buffer_; } + T const *end() const { return buffer_ + size_; } T &operator()(int64_t i) const { return buffer_[i]; } T &operator[](int64_t i) const { return buffer_[i]; } @@ -121,7 +123,7 @@ template class NDView { return *this; } - auto &shape() { return shape_; } + auto &shape() const { return shape_; } auto shape(int64_t i) const { return shape_[i]; } T *data() { return buffer_; } diff --git a/include/aare/PixelMap.hpp b/include/aare/PixelMap.hpp index 4838737..37fee95 100644 --- a/include/aare/PixelMap.hpp +++ b/include/aare/PixelMap.hpp @@ -8,8 +8,11 @@ namespace aare { NDArray GenerateMoench03PixelMap(); NDArray GenerateMoench05PixelMap(); +//Matterhorn02 NDArrayGenerateMH02SingleCounterPixelMap(); NDArray GenerateMH02FourCounterPixelMap(); +//Eiger +NDArrayGenerateEigerFlipRowsPixelMap(); } // namespace aare \ No newline at end of file diff --git a/include/aare/RawSubFile.hpp b/include/aare/RawSubFile.hpp index 5efa4b6..d5ff4f0 100644 --- a/include/aare/RawSubFile.hpp +++ b/include/aare/RawSubFile.hpp @@ -22,9 +22,11 @@ class RawSubFile { size_t m_cols{}; size_t m_bytes_per_frame{}; size_t n_frames{}; + uint32_t m_pos_row{}; + uint32_t m_pos_col{}; DetectorType m_detector_type; - std::optional> pixel_map; + std::optional> m_pixel_map; public: /** @@ -37,7 +39,7 @@ class RawSubFile { * @throws std::invalid_argument if the detector,type pair is not supported */ RawSubFile(const std::filesystem::path &fname, DetectorType detector, - size_t rows, size_t cols, size_t bitdepth); + size_t rows, size_t cols, size_t bitdepth, uint32_t pos_row = 0, uint32_t pos_col = 0); ~RawSubFile() = default; /** diff --git a/include/aare/SubFile.hpp b/include/aare/SubFile.hpp deleted file mode 100644 index 47cc07c..0000000 --- a/include/aare/SubFile.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once -#include "aare/Frame.hpp" -#include "aare/defs.hpp" - -#include -#include -#include -#include - - -namespace aare { - -/** - * @brief Class to read a subfile from a RawFile - */ -class SubFile { - public: - size_t write_part(std::byte *buffer, DetectorHeader header, size_t frame_index); - /** - * @brief SubFile constructor - * @param fname path to the subfile - * @param detector detector type - * @param rows number of rows in the subfile - * @param cols number of columns in the subfile - * @param bitdepth bitdepth of the subfile - * @throws std::invalid_argument if the detector,type pair is not supported - */ - SubFile(const std::filesystem::path &fname, DetectorType detector, size_t rows, size_t cols, size_t bitdepth, - const std::string &mode = "r"); - - /** - * @brief read the subfile into a buffer - * @param buffer pointer to the buffer to read the data into - * @return number of bytes read - */ - size_t read_impl_normal(std::byte *buffer); - - /** - * @brief read the subfile into a buffer with the bytes flipped - * @param buffer pointer to the buffer to read the data into - * @return number of bytes read - */ - template size_t read_impl_flip(std::byte *buffer); - - /** - * @brief read the subfile into a buffer with the bytes reordered - * @param buffer pointer to the buffer to read the data into - * @return number of bytes read - */ - template size_t read_impl_reorder(std::byte *buffer); - - /** - * @brief read the subfile into a buffer with the bytes reordered and flipped - * @param buffer pointer to the buffer to read the data into - * @param frame_number frame number to read - * @return number of bytes read - */ - size_t get_part(std::byte *buffer, size_t frame_index); - size_t frame_number(size_t frame_index); - - // TODO: define the inlines as variables and assign them in constructor - inline size_t bytes_per_part() const { return (m_bitdepth / 8) * m_rows * m_cols; } - inline size_t pixels_per_part() const { return m_rows * m_cols; } - - ~SubFile(); - - protected: - FILE *fp = nullptr; - size_t m_bitdepth; - std::filesystem::path m_fname; - size_t m_rows{}; - size_t m_cols{}; - std::string m_mode; - size_t n_frames{}; - int m_sub_file_index_{}; - DetectorType m_detector_type; - std::optional> pixel_map; -}; - -} // namespace aare \ No newline at end of file diff --git a/src/NDArray.test.cpp b/src/NDArray.test.cpp index 97aafa0..90a8d8e 100644 --- a/src/NDArray.test.cpp +++ b/src/NDArray.test.cpp @@ -12,7 +12,7 @@ TEST_CASE("Initial size is zero if no size is specified") { REQUIRE(a.shape() == Shape<2>{0, 0}); } -TEST_CASE("Construct from a DataSpan") { +TEST_CASE("Construct from an NDView") { std::vector some_data(9, 42); NDView view(some_data.data(), Shape<2>{3, 3}); @@ -168,42 +168,8 @@ TEST_CASE("Bitwise and on data") { REQUIRE(a(2) == 384); } -// TEST_CASE("Benchmarks") -// { -// NDArray img; -// std::array shape{ 512, 1024 }; -// BENCHMARK("Allocate 500k double image") -// { -// NDArrayim{ shape }; -// } -// BENCHMARK("Allocate 500k double image with initial value") -// { -// NDArrayim{ shape, 3.14 }; -// } -// NDArray a{ shape, 1.2 }; -// NDArray b{ shape, 53. }; -// auto c = a + b; -// c = a * b; -// BENCHMARK("Multiply two images") -// { -// c = a * b; -// } -// BENCHMARK("Divide two images") -// { -// c = a / b; -// } -// BENCHMARK("Add two images") -// { -// c = a + b; -// } -// BENCHMARK("Subtract two images") -// { -// c = a - b; -// } -// } - -TEST_CASE("Elementwise operatios on images") { +TEST_CASE("Elementwise operations on images") { std::array shape{5, 5}; double a_val = 3.0; double b_val = 8.0; diff --git a/src/PixelMap.cpp b/src/PixelMap.cpp index b8788c8..b1a6dc4 100644 --- a/src/PixelMap.cpp +++ b/src/PixelMap.cpp @@ -52,6 +52,16 @@ NDArray GenerateMoench05PixelMap() { return order_map; } +NDArrayGenerateEigerFlipRowsPixelMap(){ + NDArray order_map({256, 512}); + for(int row = 0; row < 256; row++){ + for(int col = 0; col < 512; col++){ + order_map(row, col) = 255*512-row*512 + col; + } + } + return order_map; +} + NDArrayGenerateMH02SingleCounterPixelMap(){ NDArray order_map({48, 48}); for(int row = 0; row < 48; row++){ diff --git a/src/RawFile.cpp b/src/RawFile.cpp index c1b9c52..dbb0ebe 100644 --- a/src/RawFile.cpp +++ b/src/RawFile.cpp @@ -97,10 +97,14 @@ void RawFile::open_subfiles() { for (size_t i = 0; i != n_subfiles; ++i) { auto v = std::vector(n_subfile_parts); for (size_t j = 0; j != n_subfile_parts; ++j) { + fmt::print("{} pos: {},{}\n", j,positions[j].row, positions[j].col); + auto pos = m_module_pixel_0[j]; + fmt::print("{} pos: {},{}\n", j,pos.y, pos.x); v[j] = new RawSubFile(m_master.data_fname(j, i), m_master.detector_type(), pos.height, - pos.width, m_master.bitdepth()); + pos.width, m_master.bitdepth(), + positions[j].row, positions[j].col); } subfiles.push_back(v); diff --git a/src/RawSubFile.cpp b/src/RawSubFile.cpp index c537007..4e322d2 100644 --- a/src/RawSubFile.cpp +++ b/src/RawSubFile.cpp @@ -8,12 +8,15 @@ namespace aare { RawSubFile::RawSubFile(const std::filesystem::path &fname, DetectorType detector, size_t rows, size_t cols, - size_t bitdepth) + size_t bitdepth, uint32_t pos_row, uint32_t pos_col) : m_bitdepth(bitdepth), m_fname(fname), m_rows(rows), m_cols(cols), m_detector_type(detector), - m_bytes_per_frame((m_bitdepth / 8) * m_rows * m_cols) { + m_bytes_per_frame((m_bitdepth / 8) * m_rows * m_cols), m_pos_row(pos_row), m_pos_col(pos_col) { if (m_detector_type == DetectorType::Moench03_old) { - pixel_map = GenerateMoench03PixelMap(); + m_pixel_map = GenerateMoench03PixelMap(); + }else if(m_detector_type == DetectorType::Eiger && m_pos_row % 2 == 0){ + m_pixel_map = GenerateEigerFlipRowsPixelMap(); + fmt::print("Flipping rows\n"); } if (std::filesystem::exists(fname)) { @@ -59,7 +62,7 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) { } //TODO! expand support for different bitdepths - if(pixel_map){ + if(m_pixel_map){ // read into a temporary buffer and then copy the data to the buffer // in the correct order // currently this only supports 16 bit data! @@ -68,7 +71,7 @@ void RawSubFile::read_into(std::byte *image_buf, DetectorHeader *header) { auto *data = reinterpret_cast(image_buf); auto *part_data = reinterpret_cast(part_buffer); for (size_t i = 0; i < pixels_per_frame(); i++) { - data[i] = part_data[(*pixel_map)(i)]; + data[i] = part_data[(*m_pixel_map)(i)]; } delete[] part_buffer; } else { diff --git a/src/SubFile.cpp b/src/SubFile.cpp deleted file mode 100644 index 314fec5..0000000 --- a/src/SubFile.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "aare/SubFile.hpp" -#include "aare/PixelMap.hpp" -#include // memcpy -#include -#include - - -namespace aare { - -SubFile::SubFile(const std::filesystem::path &fname, DetectorType detector, size_t rows, size_t cols, size_t bitdepth, - const std::string &mode) - : m_bitdepth(bitdepth), m_fname(fname), m_rows(rows), m_cols(cols), m_mode(mode), m_detector_type(detector) { - - - if (m_detector_type == DetectorType::Moench03_old) { - pixel_map = GenerateMoench03PixelMap(); - } - - if (std::filesystem::exists(fname)) { - n_frames = std::filesystem::file_size(fname) / (sizeof(DetectorHeader) + rows * cols * bitdepth / 8); - } else { - n_frames = 0; - } - - if (mode == "r") { - fp = fopen(m_fname.string().c_str(), "rb"); - } else { - throw std::runtime_error(LOCATION + "Unsupported mode. Can only read RawFiles."); - } - if (fp == nullptr) { - throw std::runtime_error(LOCATION + fmt::format("Could not open file {}", m_fname.string())); - } -#ifdef AARE_VERBOSE - fmt::print("Opened file: {} with {} frames\n", m_fname.string(), n_frames); - fmt::print("m_rows: {}, m_cols: {}, m_bitdepth: {}\n", m_rows, m_cols, m_bitdepth); -#endif -} - -size_t SubFile::get_part(std::byte *buffer, size_t frame_index) { - if (frame_index >= n_frames) { - throw std::runtime_error("Frame number out of range"); - } - fseek(fp, sizeof(DetectorHeader) + (sizeof(DetectorHeader) + bytes_per_part()) * frame_index, // NOLINT - SEEK_SET); - - if (pixel_map){ - // read into a temporary buffer and then copy the data to the buffer - // in the correct order - auto part_buffer = new std::byte[bytes_per_part()]; - auto wc = fread(part_buffer, bytes_per_part(), 1, fp); - auto *data = reinterpret_cast(buffer); - auto *part_data = reinterpret_cast(part_buffer); - for (size_t i = 0; i < pixels_per_part(); i++) { - data[i] = part_data[(*pixel_map)(i)]; - } - delete[] part_buffer; - return wc; - }else{ - // read directly into the buffer - return fread(buffer, this->bytes_per_part(), 1, this->fp); - } - -} -size_t SubFile::write_part(std::byte *buffer, DetectorHeader header, size_t frame_index) { - if (frame_index > n_frames) { - throw std::runtime_error("Frame number out of range"); - } - fseek(fp, static_cast((sizeof(DetectorHeader) + bytes_per_part()) * frame_index), SEEK_SET); - auto wc = fwrite(reinterpret_cast(&header), sizeof(header), 1, fp); - wc += fwrite(buffer, bytes_per_part(), 1, fp); - - return wc; -} - -size_t SubFile::frame_number(size_t frame_index) { - DetectorHeader h{}; - fseek(fp, (sizeof(DetectorHeader) + bytes_per_part()) * frame_index, SEEK_SET); // NOLINT - size_t const rc = fread(reinterpret_cast(&h), sizeof(h), 1, fp); - if (rc != 1) - throw std::runtime_error(LOCATION + "Could not read header from file"); - - return h.frameNumber; -} - -SubFile::~SubFile() { - if (fp) { - fclose(fp); - } -} - -} // namespace aare \ No newline at end of file