From b23e697e263f4493f95bd7990a6e717f0b8e8394 Mon Sep 17 00:00:00 2001 From: Dhanya Thattil Date: Wed, 4 Dec 2024 00:52:36 +0100 Subject: [PATCH] works for hdf5, needs refactoring --- include/aare/Hdf5File.hpp | 90 +++++++++++++++++++-- src/Hdf5File.cpp | 162 +++++++++++++++++++++++++------------- 2 files changed, 190 insertions(+), 62 deletions(-) diff --git a/include/aare/Hdf5File.hpp b/include/aare/Hdf5File.hpp index 5de50c8..3c011c9 100644 --- a/include/aare/Hdf5File.hpp +++ b/include/aare/Hdf5File.hpp @@ -8,6 +8,66 @@ namespace aare { +struct H5Handles { + std::string file_name{}; + std::string dataset_name{}; + H5::H5File file; + H5::DataSet dataset; + H5::DataSpace dataspace; + H5::DataType datatype; + std::unique_ptr memspace{nullptr}; + std::vectordims; + std::vector count; + std::vector offset; + + H5Handles(const std::string& fname, const std::string& dname, int rank): + file_name(fname), + dataset_name(dname), + file(fname, H5F_ACC_RDONLY), + dataset(file.openDataSet(dname)), + dataspace(dataset.getSpace()), + datatype(dataset.getDataType()) + { + if (dataspace.getSimpleExtentNdims() != rank) { + throw std::runtime_error(LOCATION + "Expected rank of " + dname + " dataset to be 1. Got " + std::to_string(rank)); + } + dims.resize(rank); + dataspace.getSimpleExtentDims(dims.data(), nullptr); + + // to slice 1 frame with hyperslab + count.push_back(1); + offset.push_back(0); + + // header datasets + if (rank == 1) { + memspace = std::make_unique(H5S_SCALAR); + } + // data dataset + else { + hsize_t dimsm[2] = {dims[1], dims[2]}; + memspace = std::make_unique(2, dimsm); + count.push_back(dims[1]); + count.push_back(dims[2]); + offset.push_back(0); + offset.push_back(0); + } + }; + + void seek(size_t frame_index) { + if (frame_index >= dims[0]) { + throw std::runtime_error(LOCATION + "Invalid frame number"); + } + offset[0] = static_cast(frame_index); + }; + + void get_frame_into(size_t frame_index, std::byte *frame_buffer) { + seek(frame_index); + dataspace.selectHyperslab(H5S_SELECT_SET, count.data(), offset.data()); + dataset.read(frame_buffer, datatype, *memspace, dataspace); + }; + +}; + /** * @brief Class to read .h5 files. The class will parse the master file * to find the correct geometry for the frames. @@ -21,11 +81,6 @@ class Hdf5File : public FileInterface { size_t m_total_frames{}; size_t m_rows{}; size_t m_cols{}; - H5::DataType m_datatype{}; - - std::unique_ptr file{nullptr}; - std::unique_ptr dataset{nullptr}; - std::unique_ptr dataspace{nullptr}; public: /** @@ -71,10 +126,23 @@ class Hdf5File : public FileInterface { * @param frame_number frame number to read * @param image_buf buffer to store the frame */ - void get_frame_into(size_t frame_index, std::byte *frame_buffer, DetectorHeader *header = nullptr); - + + /** + * @brief read the frame at the given frame index into the image buffer + * @param frame_index frame number to read + * @param frame_buffer buffer to store the frame + */ + void get_data_into(size_t frame_index, std::byte *frame_buffer); + + /** + * @brief read the header at the given frame index into the header buffer + * @param frame_index frame number to read + * @param header buffer to store the header + */ + void get_header_into(size_t frame_index, DetectorHeader *header); + /** * @brief get the frame at the given frame index * @param frame_number frame number to read @@ -90,7 +158,13 @@ class Hdf5File : public FileInterface { static DetectorHeader read_header(const std::filesystem::path &fname); static const std::string metadata_group_name; - void open_file(); + static const std::vector header_dataset_names; + + std::unique_ptr m_data_file{nullptr}; + std::vector> m_header_files; + + void open_data_file(); + void open_header_files(); }; } // namespace aare \ No newline at end of file diff --git a/src/Hdf5File.cpp b/src/Hdf5File.cpp index 0a29a51..33069ea 100644 --- a/src/Hdf5File.cpp +++ b/src/Hdf5File.cpp @@ -10,7 +10,8 @@ Hdf5File::Hdf5File(const std::filesystem::path &fname, const std::string &mode) : m_master(fname) { m_mode = mode; if (mode == "r") { - open_file(); + open_data_file(); + open_header_files(); } else { throw std::runtime_error(LOCATION + "Unsupported mode. Can only read Hdf5Files."); @@ -66,12 +67,9 @@ DetectorType Hdf5File::detector_type() const { } void Hdf5File::seek(size_t frame_index) { - // check if the frame number is greater than the total frames - // if frame_number == total_frames, then the next read will throw an error - if (frame_index > total_frames()) { - throw std::runtime_error( - fmt::format("frame number {} is greater than total frames {}", - frame_index, total_frames())); + m_data_file->seek(frame_index); + for (size_t i = 0; i != header_dataset_names.size(); ++i) { + m_header_files[i]->seek(frame_index); } m_current_frame = frame_index; }; @@ -86,6 +84,37 @@ xy Hdf5File::geometry() { return m_master.geometry(); } DetectorHeader Hdf5File::read_header(const std::filesystem::path &fname) { DetectorHeader h{}; + std::vector> handles; + try { + for (size_t i = 0; i != header_dataset_names.size(); ++i) { + handles.push_back(std::make_unique(fname.string(), metadata_group_name+ header_dataset_names[i], 1)); + } + handles[0]->get_frame_into(0, reinterpret_cast(&(h.frameNumber))); + handles[1]->get_frame_into(0, reinterpret_cast(&(h.expLength))); + handles[2]->get_frame_into(0, reinterpret_cast(&(h.packetNumber))); + handles[3]->get_frame_into(0, reinterpret_cast(&(h.bunchId))); + handles[4]->get_frame_into(0, reinterpret_cast(&(h.timestamp))); + handles[5]->get_frame_into(0, reinterpret_cast(&(h.modId))); + handles[6]->get_frame_into(0, reinterpret_cast(&(h.row))); + handles[7]->get_frame_into(0, reinterpret_cast(&(h.column))); + handles[8]->get_frame_into(0, reinterpret_cast(&(h.reserved))); + handles[9]->get_frame_into(0, reinterpret_cast(&(h.debug))); + handles[10]->get_frame_into(0, reinterpret_cast(&(h.roundRNumber))); + handles[11]->get_frame_into(0, reinterpret_cast(&(h.detType))); + handles[12]->get_frame_into(0, reinterpret_cast(&(h.version))); + handles[13]->get_frame_into(0, reinterpret_cast(&(h.packetMask))); + + fmt::print("Read 1D header for frame {}\n", 0); + } catch (const H5::Exception &e) { + handles.clear(); + fmt::print("Exception type: {}\n", typeid(e).name()); + e.printErrorStack(); + throw std::runtime_error( + LOCATION + "\nCould not to access header datasets in given file."); + } + + + FILE *fp = fopen(fname.string().c_str(), "r"); if (!fp) throw std::runtime_error( @@ -114,27 +143,35 @@ size_t Hdf5File::bytes_per_pixel() const { return m_master.bitdepth() / 8; } void Hdf5File::get_frame_into(size_t frame_index, std::byte *frame_buffer, DetectorHeader *header) { + get_data_into(frame_index, frame_buffer); + get_header_into(frame_index, header); +} - // Check if the frame number is valid - if (frame_index < 0 || frame_index >= m_total_frames) { - throw std::runtime_error(LOCATION + "Invalid frame number"); - } - - // Define the hyperslab to select the 2D slice for the given frame number - hsize_t offset[3] = {static_cast(frame_index), 0, 0}; - hsize_t count[3] = {1, m_rows, m_cols}; - dataspace->selectHyperslab(H5S_SELECT_SET, count, offset); - - // Define the memory space for the 2D slice - hsize_t dimsm[2] = {m_rows, m_cols}; - H5::DataSpace memspace(2, dimsm); - - // Read the data into the provided 2D array - dataset->read(frame_buffer, m_datatype, memspace, dataspace); - +void Hdf5File::get_data_into(size_t frame_index, std::byte *frame_buffer) { + m_data_file->get_frame_into(frame_index, frame_buffer); fmt::print("Read 2D data for frame {}\n", frame_index); } +void Hdf5File::get_header_into(size_t frame_index, DetectorHeader *header) { + if (header) { + m_header_files[0]->get_frame_into(frame_index, reinterpret_cast(&(header->frameNumber))); + m_header_files[1]->get_frame_into(frame_index, reinterpret_cast(&(header->expLength))); + m_header_files[2]->get_frame_into(frame_index, reinterpret_cast(&(header->packetNumber))); + m_header_files[3]->get_frame_into(frame_index, reinterpret_cast(&(header->bunchId))); + m_header_files[4]->get_frame_into(frame_index, reinterpret_cast(&(header->timestamp))); + m_header_files[5]->get_frame_into(frame_index, reinterpret_cast(&(header->modId))); + m_header_files[6]->get_frame_into(frame_index, reinterpret_cast(&(header->row))); + m_header_files[7]->get_frame_into(frame_index, reinterpret_cast(&(header->column))); + m_header_files[8]->get_frame_into(frame_index, reinterpret_cast(&(header->reserved))); + m_header_files[9]->get_frame_into(frame_index, reinterpret_cast(&(header->debug))); + m_header_files[10]->get_frame_into(frame_index, reinterpret_cast(&(header->roundRNumber))); + m_header_files[11]->get_frame_into(frame_index, reinterpret_cast(&(header->detType))); + m_header_files[12]->get_frame_into(frame_index, reinterpret_cast(&(header->version))); + m_header_files[13]->get_frame_into(frame_index, reinterpret_cast(&(header->packetMask))); + fmt::print("Read 1D header for frame {}\n", frame_index); + } +} + std::vector Hdf5File::read_n(size_t n_frames) { // TODO: implement this in a more efficient way std::vector frames; @@ -146,48 +183,45 @@ std::vector Hdf5File::read_n(size_t n_frames) { } size_t Hdf5File::frame_number(size_t frame_index) { - if (frame_index >= m_master.frames_in_file()) { - throw std::runtime_error(LOCATION + " Frame number out of range"); - } - size_t subfile_id = frame_index / m_master.max_frames_per_file(); - /*if (subfile_id >= subfiles.size()) { - throw std::runtime_error( - LOCATION + " Subfile out of range. Possible missing data."); - }*/ - return 1; // subfiles[subfile_id][0]->frame_number( - // frame_index % m_master.max_frames_per_file()); + uint64_t fnum{0}; + m_header_files[0]->get_frame_into(frame_index, reinterpret_cast(&fnum)); + return fnum; } Hdf5File::~Hdf5File() {} const std::string Hdf5File::metadata_group_name = "/entry/data/"; +const std::vector Hdf5File::header_dataset_names = { + "frame number", + "exp length or sub exposure time", + "packets caught", + "detector specific 1", + "timestamp", + "mod id", + "row", + "column", + "detector specific 2", + "detector specific 3", + "detector specific 4", + "detector type", + "detector header version", + "packets caught bit mask" +}; -void Hdf5File::open_file() { +void Hdf5File::open_data_file() { if (m_mode != "r") throw std::runtime_error(LOCATION + "Unsupported mode. Can only read Hdf5 files."); try { - file = std::make_unique(m_master.master_fname().string(), - H5F_ACC_RDONLY); - dataset = std::make_unique( - file->openDataSet(metadata_group_name + "/data")); - dataspace = std::make_unique(dataset->getSpace()); - int rank = dataspace->getSimpleExtentNdims(); - if (rank != 3) { - throw std::runtime_error( - LOCATION + "Expected rank of '/data' dataset to be 3. Got " + - std::to_string(rank)); - } - hsize_t dims[3]; - dataspace->getSimpleExtentDims(dims, nullptr); - m_total_frames = dims[0]; - m_rows = dims[1]; - m_cols = dims[2]; - m_datatype = dataset->getDataType(); - fmt::print("Dataset dimensions: frames = {}, rows = {}, cols = {}\n", + m_data_file = std::make_unique(m_master.master_fname().string(), metadata_group_name + "/data", 3); + + m_total_frames = m_data_file->dims[0]; + m_rows = m_data_file->dims[1]; + m_cols = m_data_file->dims[2]; + fmt::print("Data Dataset dimensions: frames = {}, rows = {}, cols = {}\n", m_total_frames, m_rows, m_cols); } catch (const H5::Exception &e) { - file->close(); + m_data_file.reset(); fmt::print("Exception type: {}\n", typeid(e).name()); e.printErrorStack(); throw std::runtime_error( @@ -195,4 +229,24 @@ void Hdf5File::open_file() { } } +void Hdf5File::open_header_files() { + if (m_mode != "r") + throw std::runtime_error(LOCATION + + "Unsupported mode. Can only read Hdf5 files."); + try { + for (size_t i = 0; i != header_dataset_names.size(); ++i) { + m_header_files.push_back(std::make_unique(m_master.master_fname().string(), metadata_group_name + header_dataset_names[i], 1)); + fmt::print("{} Dataset dimensions: size = {}\n", + header_dataset_names[i], m_header_files[i]->dims[0]); + } + } catch (const H5::Exception &e) { + m_header_files.clear(); + m_data_file.reset(); + fmt::print("Exception type: {}\n", typeid(e).name()); + e.printErrorStack(); + throw std::runtime_error( + LOCATION + "\nCould not to access header datasets in master file."); + } +} + } // namespace aare \ No newline at end of file