added CtbRawFile

This commit is contained in:
Erik Fröjdh
2024-11-05 14:36:18 +01:00
parent b8a4498379
commit 80a39415de
24 changed files with 687 additions and 262 deletions

View File

@ -1,22 +1,72 @@
#include "aare/CtbRawFile.hpp"
#include <fmt/format.h>
namespace aare {
CtbRawFile::CtbRawFile(const std::filesystem::path &fname) : m_master(fname) {
namespace aare{
CtbRawFile::CtbRawFile(const std::filesystem::path &fname){
if (m_master.detector_type() != DetectorType::ChipTestBoard) {
throw std::runtime_error(LOCATION + "Not a Ctb file");
}
if(!std::filesystem::exists(fname)){
throw std::runtime_error(LOCATION + "File does not exist");
find_subfiles();
// open the first subfile
m_file.open(m_master.data_fname(0, 0), std::ios::binary);
}
size_t CtbRawFile::tell() const { return m_current_frame; }
void CtbRawFile::seek(size_t frame_number) {
if (auto index = sub_file_index(frame_number); index != m_current_subfile) {
open_data_file(index);
}
size_t frame_number_in_file = frame_number % m_master.max_frames_per_file();
m_file.seekg((sizeof(DetectorHeader)+m_master.image_size_in_bytes()) * frame_number_in_file);
m_current_frame = frame_number;
}
void CtbRawFile::find_subfiles() {
// we can semi safely assume that there is only one module for CTB
while (std::filesystem::exists(m_master.data_fname(0, m_num_subfiles)))
m_num_subfiles++;
fmt::print("Found {} subfiles\n", m_num_subfiles);
}
void CtbRawFile::open_data_file(size_t subfile_index) {
if (subfile_index >= m_num_subfiles) {
throw std::runtime_error(LOCATION + "Subfile index out of range");
}
m_current_subfile = subfile_index;
m_file = std::ifstream(m_master.data_fname(0, subfile_index), std::ios::binary); // only one module for CTB
if (!m_file.is_open()) {
throw std::runtime_error(LOCATION + "Could not open data file");
}
}
void CtbRawFile::read_into(std::byte *image_buf, DetectorHeader* header) {
if(m_current_frame >= m_master.frames_in_file()){
throw std::runtime_error(LOCATION + "End of file reached");
}
if(m_current_frame != 0 && m_current_frame % m_master.max_frames_per_file() == 0){
open_data_file(m_current_subfile+1);
}
m_fnc = parse_fname(fname);
if(!m_fnc.valid){
throw std::runtime_error(LOCATION + "Could not parse master file name");
if(header){
m_file.read(reinterpret_cast<char *>(header), sizeof(DetectorHeader));
}else{
m_file.seekg(sizeof(DetectorHeader), std::ios::cur);
}
m_file.read(reinterpret_cast<char *>(image_buf), m_master.image_size_in_bytes());
m_current_frame++;
}
} // namespace aare

View File

@ -45,8 +45,8 @@ void RawFile::open_subfiles() {
}
}
sls_detector_header RawFile::read_header(const std::filesystem::path &fname) {
sls_detector_header h{};
DetectorHeader RawFile::read_header(const std::filesystem::path &fname) {
DetectorHeader h{};
FILE *fp = fopen(fname.string().c_str(), "r");
if (!fp)
throw std::runtime_error(fmt::format("Could not open: {} for reading", fname.string()));

103
src/RawMasterFile.cpp Normal file
View File

@ -0,0 +1,103 @@
#include "aare/RawMasterFile.hpp"
namespace aare {
RawFileNameComponents::RawFileNameComponents(const std::filesystem::path &fname) {
m_base_path = fname.parent_path();
m_base_name = fname.stem();
m_ext = fname.extension();
//parse file index
try {
auto pos = m_base_name.rfind('_');
m_file_index = std::stoi(m_base_name.substr(pos + 1));
} catch (const std::invalid_argument &e) {
throw std::runtime_error(LOCATION + "Could not parse file index");
}
//remove master from base name
auto pos = m_base_name.find("_master_");
if (pos != std::string::npos) {
m_base_name.erase(pos);
}else{
throw std::runtime_error(LOCATION + "Could not find _master_ in file name");
}
}
void RawMasterFile::parse_json(const std::filesystem::path &fpath) {
std::ifstream ifs(fpath);
json j;
ifs >> j;
double v = j["Version"];
m_version = fmt::format("{:.1f}", v);
m_type = StringTo<DetectorType>(j["Detector Type"].get<std::string>());
m_timing_mode =
StringTo<TimingMode>(j["Timing Mode"].get<std::string>());
m_image_size_in_bytes = j["Image Size in bytes"];
m_frames_in_file = j["Frames in File"];
m_pixels_y = j["Pixels"]["y"];
m_pixels_x = j["Pixels"]["x"];
m_max_frames_per_file = j["Max Frames Per File"];
//Not all detectors write the bitdepth but in case
//its not there it is 16
try {
m_bitdepth = j.at("Dynamic Range");
} catch (const json::out_of_range &e) {
m_bitdepth = 16;
}
m_frame_padding = j["Frame Padding"];
m_frame_discard_policy = StringTo<FrameDiscardPolicy>(
j["Frame Discard Policy"].get<std::string>());
try {
m_analog_samples = j.at("Analog Samples");
}catch (const json::out_of_range &e) {
// m_analog_samples = 0;
}
// try{
// std::string adc_mask = j.at("ADC Mask");
// m_adc_mask = std::stoul(adc_mask, nullptr, 16);
// }catch (const json::out_of_range &e) {
// m_adc_mask = 0;
// }
try {
m_digital_samples = j.at("Digital Samples");
}catch (const json::out_of_range &e) {
// m_digital_samples = 0;
}
// //Update detector type for Moench
// //TODO! How does this work with old .raw master files?
// if (m_type == DetectorType::Moench && m_analog_samples == 0 &&
// m_subfile_rows == 400) {
// m_type = DetectorType::Moench03;
// }else if (m_type == DetectorType::Moench && m_subfile_rows == 400 &&
// m_analog_samples == 5000) {
// m_type = DetectorType::Moench03_old;
// }
// //Here we know we have a ChipTestBoard file update the geometry?
// //TODO! Carry on information about digtial, and transceivers
// if (m_type == DetectorType::ChipTestBoard) {
// subfile_rows = 1;
// subfile_cols = m_analog_samples*__builtin_popcount(m_adc_mask);
// }
// // only Eiger had quad
// if (m_type == DetectorType::Eiger) {
// quad = (j["Quad"] == 1);
// }
// m_geometry = {j["Geometry"]["y"], j["Geometry"]["x"]};
}
void RawMasterFile::parse_raw(const std::filesystem::path &fpath) {
throw std::runtime_error("Not implemented");
}
} // namespace aare

167
src/RawMasterFile.test.cpp Normal file
View File

@ -0,0 +1,167 @@
#include "aare/RawMasterFile.hpp"
#include <catch2/catch_test_macros.hpp>
#include "test_config.hpp"
using namespace aare;
TEST_CASE("Parse a master file fname"){
RawFileNameComponents m("test_master_1.json");
REQUIRE(m.base_name() == "test");
REQUIRE(m.ext() == ".json");
REQUIRE(m.file_index() == 1);
}
TEST_CASE("Construction of master file name and data files"){
RawFileNameComponents m("test_master_1.json");
REQUIRE(m.master_fname() == "test_master_1.json");
REQUIRE(m.data_fname(0, 0) == "test_d0_f0_1.raw");
REQUIRE(m.data_fname(1, 0) == "test_d1_f0_1.raw");
REQUIRE(m.data_fname(0, 1) == "test_d0_f1_1.raw");
REQUIRE(m.data_fname(1, 1) == "test_d1_f1_1.raw");
}
TEST_CASE("Parse a master file"){
auto fpath = test_data_path() / "jungfrau" / "jungfrau_single_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
// "Version": 7.2,
REQUIRE(f.version() == "7.2");
// "Timestamp": "Tue Feb 20 08:28:24 2024",
// "Detector Type": "Jungfrau",
REQUIRE(f.detector_type() == DetectorType::Jungfrau);
// "Timing Mode": "auto",
REQUIRE(f.timing_mode() == TimingMode::Auto);
// "Geometry": {
// "x": 1,
// "y": 1
// },
// "Image Size in bytes": 1048576,
REQUIRE(f.image_size_in_bytes() == 1048576);
// "Pixels": {
// "x": 1024,
REQUIRE(f.pixels_x() == 1024);
// "y": 512
REQUIRE(f.pixels_y() == 512);
// },
// "Max Frames Per File": 3,
REQUIRE(f.max_frames_per_file() == 3);
//Jungfrau doesn't write but it is 16
REQUIRE(f.bitdepth() == 16);
// "Frame Discard Policy": "nodiscard",
// "Frame Padding": 1,
// "Scan Parameters": "[disabled]",
// "Total Frames": 10,
// "Receiver Roi": {
// "xmin": 4294967295,
// "xmax": 4294967295,
// "ymin": 4294967295,
// "ymax": 4294967295
// },
// "Exptime": "10us",
// "Period": "1ms",
// "Number of UDP Interfaces": 1,
// "Number of rows": 512,
// "Frames in File": 10,
// "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"
// }
// }
REQUIRE_FALSE(f.analog_samples());
REQUIRE_FALSE(f.digital_samples());
}
TEST_CASE("Read eiger master file"){
auto fpath = test_data_path() / "eiger" / "eiger_500k_32bit_master_0.json";
REQUIRE(std::filesystem::exists(fpath));
RawMasterFile f(fpath);
// {
// "Version": 7.2,
REQUIRE(f.version() == "7.2");
// "Timestamp": "Tue Mar 26 17:24:34 2024",
// "Detector Type": "Eiger",
REQUIRE(f.detector_type() == DetectorType::Eiger);
// "Timing Mode": "auto",
REQUIRE(f.timing_mode() == TimingMode::Auto);
// "Geometry": {
// "x": 2,
// "y": 2
// },
// "Image Size in bytes": 524288,
REQUIRE(f.image_size_in_bytes() == 524288);
// "Pixels": {
// "x": 512,
REQUIRE(f.pixels_x() == 512);
// "y": 256
REQUIRE(f.pixels_y() == 256);
// },
// "Max Frames Per File": 10000,
REQUIRE(f.max_frames_per_file() == 10000);
// "Frame Discard Policy": "nodiscard",
REQUIRE(f.frame_discard_policy() == FrameDiscardPolicy::NoDiscard);
// "Frame Padding": 1,
REQUIRE(f.frame_padding() == 1);
// "Scan Parameters": "[disabled]",
// "Total Frames": 3,
// "Receiver Roi": {
// "xmin": 4294967295,
// "xmax": 4294967295,
// "ymin": 4294967295,
// "ymax": 4294967295
// },
// "Dynamic Range": 32,
// "Ten Giga": 0,
// "Exptime": "5s",
// "Period": "1s",
// "Threshold Energy": -1,
// "Sub Exptime": "2.62144ms",
// "Sub Period": "2.62144ms",
// "Quad": 0,
// "Number of rows": 256,
// "Rate Corrections": "[0, 0]",
// "Frames in File": 3,
// "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"
// }
// }
}

View File

@ -17,7 +17,7 @@ SubFile::SubFile(const std::filesystem::path &fname, DetectorType detector, size
}
if (std::filesystem::exists(fname)) {
n_frames = std::filesystem::file_size(fname) / (sizeof(sls_detector_header) + rows * cols * bitdepth / 8);
n_frames = std::filesystem::file_size(fname) / (sizeof(DetectorHeader) + rows * cols * bitdepth / 8);
} else {
n_frames = 0;
}
@ -42,7 +42,7 @@ 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(sls_detector_header) + (sizeof(sls_detector_header) + bytes_per_part()) * frame_index, // NOLINT
fseek(fp, sizeof(DetectorHeader) + (sizeof(DetectorHeader) + bytes_per_part()) * frame_index, // NOLINT
SEEK_SET);
if (pixel_map){
@ -63,11 +63,11 @@ size_t SubFile::get_part(std::byte *buffer, size_t frame_index) {
}
}
size_t SubFile::write_part(std::byte *buffer, sls_detector_header header, size_t frame_index) {
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<int64_t>((sizeof(sls_detector_header) + bytes_per_part()) * frame_index), SEEK_SET);
fseek(fp, static_cast<int64_t>((sizeof(DetectorHeader) + bytes_per_part()) * frame_index), SEEK_SET);
auto wc = fwrite(reinterpret_cast<char *>(&header), sizeof(header), 1, fp);
wc += fwrite(buffer, bytes_per_part(), 1, fp);
@ -75,8 +75,8 @@ size_t SubFile::write_part(std::byte *buffer, sls_detector_header header, size_t
}
size_t SubFile::frame_number(size_t frame_index) {
sls_detector_header h{};
fseek(fp, (sizeof(sls_detector_header) + bytes_per_part()) * frame_index, SEEK_SET); // NOLINT
DetectorHeader h{};
fseek(fp, (sizeof(DetectorHeader) + bytes_per_part()) * frame_index, SEEK_SET); // NOLINT
size_t const rc = fread(reinterpret_cast<char *>(&h), sizeof(h), 1, fp);
if (rc != 1)
throw std::runtime_error(LOCATION + "Could not read header from file");

View File

@ -68,6 +68,14 @@ template <> TimingMode StringTo(const std::string &arg) {
throw std::runtime_error("Could not decode timing mode from: \"" + arg + "\"");
}
template <> FrameDiscardPolicy StringTo(const std::string &arg) {
if (arg == "nodiscard")
return FrameDiscardPolicy::NoDiscard;
if (arg == "discard")
return FrameDiscardPolicy::Discard;
throw std::runtime_error("Could not decode frame discard policy from: \"" + arg + "\"");
}
// template <> TimingMode StringTo<TimingMode>(std::string mode);
} // namespace aare

View File

@ -1,33 +0,0 @@
#include "aare/file_utils.hpp"
namespace aare {
bool is_master_file(const std::filesystem::path &fpath) {
std::string const stem = fpath.stem().string();
return stem.find("_master_") != std::string::npos;
}
FileNameComponents parse_fname(const std::filesystem::path &fname) {
FileNameComponents fnc;
fnc.base_path = fname.parent_path();
fnc.base_name = fname.stem();
fnc.ext = fname.extension();
try {
auto pos = fnc.base_name.rfind('_');
fnc.findex = std::stoi(fnc.base_name.substr(pos + 1));
} catch (const std::invalid_argument &e) {
fnc.valid = false;
}
auto pos = fnc.base_name.find("_master_");
if (pos != std::string::npos) {
fnc.base_name.erase(pos);
}else{
fnc.valid = false;
}
fnc.valid = true;
return fnc;
}
} // namespace aare

View File

@ -1,20 +0,0 @@
#include "aare/file_utils.hpp"
#include <catch2/catch_test_macros.hpp>
using namespace aare;
TEST_CASE("Use filename to determine if it is a master file") {
REQUIRE(is_master_file("test_master_1.json"));
}
TEST_CASE("Parse a master file fname"){
auto fnc = parse_fname("test_master_1.json");
REQUIRE(fnc.base_name == "test");
REQUIRE(fnc.ext == ".json");
REQUIRE(fnc.findex == 1);
REQUIRE(fnc.master_fname() == "test_master_1.json");
REQUIRE(fnc.data_fname(1, 2) == "test_d2_f1_1.raw");
}