// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include #include "HDF5DataFile.h" #include "../compression/JFJochCompressor.h" #include "HDF5DataFilePluginAzInt.h" #include "HDF5DataFilePluginMX.h" #include "HDF5DataFilePluginXFEL.h" #include "HDF5DataFilePluginJUNGFRAU.h" #include "HDF5DataFilePluginROI.h" #include "../include/spdlog/fmt/fmt.h" #include "HDF5NXmx.h" HDF5DataFile::HDF5DataFile(const StartMessage &msg, uint64_t in_file_number) { file_number = in_file_number; xpixel = 0; ypixel = 0; max_image_number = 0; nimages = 0; filename = HDF5Metadata::DataFileName(msg, file_number); image_low = file_number * msg.images_per_file; tmp_filename = fmt::format("{}.tmp{:8x}", filename, std::chrono::system_clock::now().time_since_epoch().count()); plugins.emplace_back(std::make_unique()); plugins.emplace_back(std::make_unique()); plugins.emplace_back(std::make_unique(msg.az_int_bin_to_q)); plugins.emplace_back(std::make_unique()); plugins.emplace_back(std::make_unique(msg.max_spot_count)); } std::optional HDF5DataFile::Close() { if (!data_file) return {}; HDF5Group group_exp(*data_file, "/entry/detector"); group_exp.NXClass("NXcollection"); group_exp.SaveVector("timestamp", timestamp); group_exp.SaveVector("exptime", exptime); group_exp.SaveVector("number", number); for (auto &p: plugins) p->WriteFinal(*data_file); if (data_set) { data_set ->Attr("image_nr_low", (int32_t) (image_low + 1)) .Attr("image_nr_high", (int32_t) (image_low + 1 + max_image_number)); data_set.reset(); } data_file.reset(); if (!std::filesystem::exists(filename.c_str())) std::rename(tmp_filename.c_str(), filename.c_str()); closed = true; HDF5DataFileStatistics ret; ret.max_image_number = max_image_number; ret.total_images = nimages; ret.filename = filename; ret.file_number = file_number + 1; return ret; } HDF5DataFile::~HDF5DataFile() { if (data_file) { try { Close(); } catch (...) {} } } void HDF5DataFile::CreateFile(const DataMessage& msg) { HDF5Dcpl dcpl; HDF5DataType data_type(msg.image.pixel_depth_bytes, msg.image.pixel_is_signed); xpixel = msg.image.xpixel; ypixel = msg.image.ypixel; dcpl.SetCompression(msg.image.algorithm, msg.image.pixel_depth_bytes, JFJochBitShuffleCompressor::DefaultBlockSize); dcpl.SetChunking( {1, ypixel, xpixel}); if (msg.image.pixel_is_signed) { if (msg.image.pixel_depth_bytes == 2) dcpl.SetFillValue16(INT16_MIN); else dcpl.SetFillValue32(INT32_MIN); } data_file = std::make_unique(tmp_filename); chmod(tmp_filename.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); // default permissions HDF5Group(*data_file, "/entry").NXClass("NXentry"); HDF5Group(*data_file, "/entry/data").NXClass("NXdata"); HDF5DataSpace data_space({1, ypixel, xpixel}, {H5S_UNLIMITED, ypixel, xpixel}); data_set = std::make_unique(*data_file, "/entry/data/data", data_type, data_space, dcpl); for (auto &p: plugins) p->OpenFile(*data_file, msg); } void HDF5DataFile::Write(const DataMessage &msg, uint64_t image_number) { if (closed) return; bool new_file = false; if (!data_file) { CreateFile(msg); new_file = true; } if (new_file || (static_cast(image_number) > max_image_number)) { max_image_number = image_number; data_set->SetExtent({max_image_number+1, ypixel, xpixel}); timestamp.resize(max_image_number + 1); exptime.resize(max_image_number + 1); number.resize(max_image_number + 1); } nimages++; data_set->WriteDirectChunk(msg.image.data, msg.image.size, {image_number, 0, 0}); for (auto &p: plugins) p->Write(msg, image_number); timestamp[image_number] = msg.timestamp; exptime[image_number] = msg.exptime; number[image_number] = (msg.original_number) ? msg.original_number.value() : msg.number; } size_t HDF5DataFile::GetNumImages() const { return nimages; }