works for hdf5, needs refactoring

This commit is contained in:
maliakal_d 2024-12-04 00:52:36 +01:00
parent 4233509615
commit b23e697e26
2 changed files with 190 additions and 62 deletions

View File

@ -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<H5::DataSpace> memspace{nullptr};
std::vector<hsize_t>dims;
std::vector<hsize_t> count;
std::vector<hsize_t> 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<H5::DataSpace>(H5S_SCALAR);
}
// data dataset
else {
hsize_t dimsm[2] = {dims[1], dims[2]};
memspace = std::make_unique<H5::DataSpace>(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<hsize_t>(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<H5::H5File> file{nullptr};
std::unique_ptr<H5::DataSet> dataset{nullptr};
std::unique_ptr<H5::DataSpace> 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<std::string> header_dataset_names;
std::unique_ptr<H5Handles> m_data_file{nullptr};
std::vector<std::unique_ptr<H5Handles>> m_header_files;
void open_data_file();
void open_header_files();
};
} // namespace aare

View File

@ -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<std::unique_ptr<H5Handles>> handles;
try {
for (size_t i = 0; i != header_dataset_names.size(); ++i) {
handles.push_back(std::make_unique<H5Handles>(fname.string(), metadata_group_name+ header_dataset_names[i], 1));
}
handles[0]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.frameNumber)));
handles[1]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.expLength)));
handles[2]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.packetNumber)));
handles[3]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.bunchId)));
handles[4]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.timestamp)));
handles[5]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.modId)));
handles[6]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.row)));
handles[7]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.column)));
handles[8]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.reserved)));
handles[9]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.debug)));
handles[10]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.roundRNumber)));
handles[11]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.detType)));
handles[12]->get_frame_into(0, reinterpret_cast<std::byte *>(&(h.version)));
handles[13]->get_frame_into(0, reinterpret_cast<std::byte *>(&(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<hsize_t>(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<std::byte *>(&(header->frameNumber)));
m_header_files[1]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->expLength)));
m_header_files[2]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->packetNumber)));
m_header_files[3]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->bunchId)));
m_header_files[4]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->timestamp)));
m_header_files[5]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->modId)));
m_header_files[6]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->row)));
m_header_files[7]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->column)));
m_header_files[8]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->reserved)));
m_header_files[9]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->debug)));
m_header_files[10]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->roundRNumber)));
m_header_files[11]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->detType)));
m_header_files[12]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->version)));
m_header_files[13]->get_frame_into(frame_index, reinterpret_cast<std::byte *>(&(header->packetMask)));
fmt::print("Read 1D header for frame {}\n", frame_index);
}
}
std::vector<Frame> Hdf5File::read_n(size_t n_frames) {
// TODO: implement this in a more efficient way
std::vector<Frame> frames;
@ -146,48 +183,45 @@ std::vector<Frame> 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<std::byte *>(&fnum));
return fnum;
}
Hdf5File::~Hdf5File() {}
const std::string Hdf5File::metadata_group_name = "/entry/data/";
const std::vector<std::string> 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<H5::H5File>(m_master.master_fname().string(),
H5F_ACC_RDONLY);
dataset = std::make_unique<H5::DataSet>(
file->openDataSet(metadata_group_name + "/data"));
dataspace = std::make_unique<H5::DataSpace>(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<H5Handles>(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<H5Handles>(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