mirror of
https://github.com/slsdetectorgroup/aare.git
synced 2025-06-08 13:40:39 +02:00
Merge pull request #15 from slsdetectorgroup/numpy
read numpy file: works
This commit is contained in:
commit
c38b46df59
5
.vscode/c_cpp_properties.json
vendored
5
.vscode/c_cpp_properties.json
vendored
@ -3,7 +3,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**",
|
"${workspaceFolder}/file_io/**",
|
||||||
|
"${workspaceFolder}/core/**",
|
||||||
|
"${workspaceFolder}/tests/**",
|
||||||
|
"${workspaceFolder}/tests/**",
|
||||||
"/usr/include"
|
"/usr/include"
|
||||||
],
|
],
|
||||||
"defines": [],
|
"defines": [],
|
||||||
|
@ -19,8 +19,10 @@ template <class DataType> class Frame {
|
|||||||
ssize_t m_bitdepth = sizeof(DataType) * 8;
|
ssize_t m_bitdepth = sizeof(DataType) * 8;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Frame(ssize_t rows, ssize_t cols);
|
||||||
Frame(std::byte *fp, ssize_t rows, ssize_t cols);
|
Frame(std::byte *fp, ssize_t rows, ssize_t cols);
|
||||||
DataType get(int row, int col);
|
DataType get(int row, int col);
|
||||||
|
std::vector<std::vector<DataType>> get_array();
|
||||||
ssize_t rows() const{
|
ssize_t rows() const{
|
||||||
return m_rows;
|
return m_rows;
|
||||||
}
|
}
|
||||||
@ -30,6 +32,9 @@ template <class DataType> class Frame {
|
|||||||
ssize_t bitdepth() const{
|
ssize_t bitdepth() const{
|
||||||
return m_bitdepth;
|
return m_bitdepth;
|
||||||
}
|
}
|
||||||
|
DataType* _get_data(){
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
~Frame() { delete[] m_data; }
|
~Frame() { delete[] m_data; }
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,13 @@ Frame<DataType>::Frame(std::byte* bytes, ssize_t rows, ssize_t cols):
|
|||||||
std::memcpy(m_data, bytes, m_rows*m_cols*sizeof(DataType));
|
std::memcpy(m_data, bytes, m_rows*m_cols*sizeof(DataType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename DataType>
|
||||||
|
Frame<DataType>::Frame(ssize_t rows, ssize_t cols):
|
||||||
|
m_rows(rows), m_cols(cols) {
|
||||||
|
m_data = new DataType[m_rows*m_cols];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename DataType>
|
template <typename DataType>
|
||||||
DataType Frame<DataType>::get(int row, int col) {
|
DataType Frame<DataType>::get(int row, int col) {
|
||||||
@ -18,5 +25,17 @@ DataType Frame<DataType>::get(int row, int col) {
|
|||||||
return m_data[row*m_cols + col];
|
return m_data[row*m_cols + col];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename DataType>
|
||||||
|
std::vector<std::vector<DataType>> Frame<DataType>::get_array() {
|
||||||
|
std::vector<std::vector<DataType>> array;
|
||||||
|
for (int i = 0; i < m_rows; i++) {
|
||||||
|
std::vector<DataType> row;
|
||||||
|
row.assign(m_data + i*m_cols, m_data + (i+1)*m_cols);
|
||||||
|
array.push_back(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template class Frame<uint16_t>;
|
template class Frame<uint16_t>;
|
||||||
|
BIN
data/test_numpy_file.npy
Normal file
BIN
data/test_numpy_file.npy
Normal file
Binary file not shown.
@ -1,25 +1,35 @@
|
|||||||
// Your First C++ Program
|
// Your First C++ Program
|
||||||
#include <iostream>
|
|
||||||
#include "aare/FileHandler.hpp"
|
#include "aare/FileHandler.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define AARE_ROOT_DIR_VAR "PROJECT_ROOT_DIR"
|
||||||
|
|
||||||
using JFileHandler = FileHandler<DetectorType::Jungfrau, uint16_t>;
|
using JFileHandler = FileHandler<DetectorType::Jungfrau, uint16_t>;
|
||||||
using JFile = File<DetectorType::Jungfrau, uint16_t>;
|
using JFile = File<DetectorType::Jungfrau, uint16_t>;
|
||||||
using JFrame = Frame<uint16_t>;
|
using JFrame = Frame<uint16_t>;
|
||||||
|
|
||||||
|
|
||||||
void test(JFileHandler *f, int frame_number) {
|
void test(JFileHandler *f, int frame_number) {
|
||||||
std::cout << "frame number: " << frame_number << std::endl;
|
std::cout << "frame number: " << frame_number << std::endl;
|
||||||
JFrame *frame = f->get_frame(frame_number);
|
JFrame *frame = f->get_frame(frame_number);
|
||||||
std::cout << frame->get(0,0) << ' ';
|
std::cout << frame->get(0, 0) << std::endl;
|
||||||
std::cout << frame->get(0,1) << ' ';
|
std::cout << frame->get(0, 1) << std::endl;
|
||||||
std::cout << frame->get(1,0) << ' ';
|
std::cout << frame->get(1, 0) << std::endl;
|
||||||
std::cout << frame->get(511,1023) << std::endl;
|
std::cout << frame->get(49, 49) << std::endl;
|
||||||
|
|
||||||
delete frame;
|
delete frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::filesystem::path fpath("/home/bb/github/aare/data/jungfrau_single_master_0.json");
|
auto PROJECT_ROOT_DIR = std::filesystem::path(getenv(AARE_ROOT_DIR_VAR));
|
||||||
|
// std::filesystem::path fpath("/home/bb/github/aare/data/jungfrau_single_master_0.json");
|
||||||
|
std::filesystem::path fpath(PROJECT_ROOT_DIR / "data" / "test_numpy_file.npy");
|
||||||
|
std::cout<<fpath<<std::endl;
|
||||||
|
|
||||||
|
|
||||||
auto fileHandler = new JFileHandler(fpath);
|
auto fileHandler = new JFileHandler(fpath);
|
||||||
|
test(fileHandler, 0);
|
||||||
|
test(fileHandler, 24);
|
||||||
|
|
||||||
delete fileHandler;
|
delete fileHandler;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ class File {
|
|||||||
virtual Frame<DataType>* get_frame(int frame_number) = 0;
|
virtual Frame<DataType>* get_frame(int frame_number) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
//comment
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~File() = default;
|
virtual ~File() = default;
|
||||||
|
@ -5,11 +5,10 @@ class JsonFileFactory: public FileFactory<detector,DataType>
|
|||||||
private:
|
private:
|
||||||
/* data */
|
/* data */
|
||||||
public:
|
public:
|
||||||
|
JsonFileFactory(std::filesystem::path fpath);
|
||||||
File<detector,DataType>* load_file() override;
|
File<detector,DataType>* load_file() override;
|
||||||
void parse_metadata(File<detector,DataType>*) override;
|
void parse_metadata(File<detector,DataType>*) override;
|
||||||
void parse_fname(File<detector,DataType>*) override;
|
void parse_fname(File<detector,DataType>*) override;
|
||||||
|
|
||||||
JsonFileFactory<detector,DataType>(std::filesystem::path fpath);
|
|
||||||
void open_subfiles(File<detector,DataType>*);
|
void open_subfiles(File<detector,DataType>*);
|
||||||
sls_detector_header read_header(const std::filesystem::path &fname);
|
sls_detector_header read_header(const std::filesystem::path &fname);
|
||||||
void find_geometry(File<detector,DataType>*);
|
void find_geometry(File<detector,DataType>*);
|
||||||
|
@ -1,9 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
#include "aare/File.hpp"
|
#include "aare/File.hpp"
|
||||||
#include "aare/defs.hpp"
|
#include "aare/defs.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
template <DetectorType detector, typename DataType>
|
using shape_t = std::vector<uint64_t>;
|
||||||
class NumpyFile : public File<detector, DataType>
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
struct dtype_t {
|
||||||
|
char byteorder;
|
||||||
|
char kind;
|
||||||
|
unsigned int itemsize;
|
||||||
|
std::string to_string() {
|
||||||
|
std::stringstream sstm;
|
||||||
|
sstm << byteorder << kind << itemsize;
|
||||||
|
return sstm.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct header_t {
|
||||||
|
dtype_t dtype;
|
||||||
|
bool fortran_order;
|
||||||
|
shape_t shape;
|
||||||
|
std::string to_string() {
|
||||||
|
std::stringstream sstm;
|
||||||
|
sstm << "dtype: " << dtype.to_string() << ", fortran_order: " << fortran_order << ' ';
|
||||||
|
|
||||||
|
sstm << "shape: (";
|
||||||
|
for (auto item : shape)
|
||||||
|
sstm << item << ',';
|
||||||
|
sstm << ')';
|
||||||
|
return sstm.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <DetectorType detector, typename DataType> class NumpyFile : public File<detector, DataType> {
|
||||||
|
FILE *fp = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NumpyFile(std::filesystem::path fname);
|
||||||
|
Frame<DataType> *get_frame(int frame_number) override;
|
||||||
|
header_t header{};
|
||||||
|
static constexpr std::array<char, 6> magic_str{'\x93', 'N', 'U', 'M', 'P', 'Y'};
|
||||||
|
uint8_t major_ver_{};
|
||||||
|
uint8_t minor_ver_{};
|
||||||
|
uint32_t header_len{};
|
||||||
|
uint8_t header_len_size{};
|
||||||
|
const uint8_t magic_string_length{6};
|
||||||
|
ssize_t header_size{};
|
||||||
|
inline ssize_t pixels_per_frame() {
|
||||||
|
return std::accumulate(header.shape.begin() + 1, header.shape.end(), 1, std::multiplies<uint64_t>());
|
||||||
|
};
|
||||||
|
inline ssize_t bytes_per_frame() { return header.dtype.itemsize * pixels_per_frame(); };
|
||||||
};
|
};
|
@ -1,29 +1,20 @@
|
|||||||
#include "aare/defs.hpp"
|
#pragma once
|
||||||
#include "aare/FileFactory.hpp"
|
#include "aare/FileFactory.hpp"
|
||||||
#include "aare/NumpyFile.hpp"
|
#include "aare/NumpyFile.hpp"
|
||||||
#include <algorithm>
|
#include "aare/defs.hpp"
|
||||||
#include <array>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
template <DetectorType detector, typename DataType> class NumpyFileFactory : public FileFactory<detector, DataType> {
|
template <DetectorType detector, typename DataType> class NumpyFileFactory : public FileFactory<detector, DataType> {
|
||||||
|
private:
|
||||||
|
std::ifstream f;
|
||||||
|
void read_data(File<detector, DataType> *_file);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NumpyFileFactory(std::filesystem::path fpath);
|
NumpyFileFactory(std::filesystem::path fpath);
|
||||||
void parse_metadata(File<detector, DataType> *_file) override;
|
void parse_metadata(File<detector, DataType> *_file) override;
|
||||||
void open_subfiles(File<detector, DataType> *_file) override;
|
|
||||||
File<detector, DataType> *load_file() override;
|
File<detector, DataType> *load_file() override;
|
||||||
|
void parse_fname(File<detector, DataType> *){};
|
||||||
|
|
||||||
uint8_t major_ver() const noexcept { return major_ver_; }
|
|
||||||
uint8_t minor_ver() const noexcept { return minor_ver_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr std::array<char, 6> magic_str{'\x93', 'N', 'U', 'M', 'P', 'Y'};
|
|
||||||
uint8_t major_ver_{};
|
|
||||||
uint8_t minor_ver_{};
|
|
||||||
uint32_t header_len{};
|
|
||||||
uint8_t header_len_size{};
|
|
||||||
const uint8_t magic_string_length{6};
|
|
||||||
};
|
};
|
146
file_io/include/aare/NumpyHelpers.hpp
Normal file
146
file_io/include/aare/NumpyHelpers.hpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
inline std::string parse_str(const std::string &in) {
|
||||||
|
if ((in.front() == '\'') && (in.back() == '\''))
|
||||||
|
return in.substr(1, in.length() - 2);
|
||||||
|
|
||||||
|
throw std::runtime_error("Invalid python string.");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
Removes leading and trailing whitespaces
|
||||||
|
*/
|
||||||
|
inline std::string trim(const std::string &str) {
|
||||||
|
const std::string whitespace = " \t\n";
|
||||||
|
auto begin = str.find_first_not_of(whitespace);
|
||||||
|
|
||||||
|
if (begin == std::string::npos)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
auto end = str.find_last_not_of(whitespace);
|
||||||
|
|
||||||
|
return str.substr(begin, end - begin + 1);
|
||||||
|
}
|
||||||
|
inline std::vector<std::string> parse_tuple(std::string in) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
const char seperator = ',';
|
||||||
|
|
||||||
|
in = trim(in);
|
||||||
|
|
||||||
|
if ((in.front() == '(') && (in.back() == ')'))
|
||||||
|
in = in.substr(1, in.length() - 2);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid Python tuple.");
|
||||||
|
|
||||||
|
std::istringstream iss(in);
|
||||||
|
|
||||||
|
for (std::string token; std::getline(iss, token, seperator);) {
|
||||||
|
v.push_back(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
inline bool parse_bool(const std::string &in) {
|
||||||
|
if (in == "True")
|
||||||
|
return true;
|
||||||
|
if (in == "False")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
throw std::runtime_error("Invalid python boolan.");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string get_value_from_map(const std::string &mapstr) {
|
||||||
|
size_t sep_pos = mapstr.find_first_of(":");
|
||||||
|
if (sep_pos == std::string::npos)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
std::string tmp = mapstr.substr(sep_pos + 1);
|
||||||
|
return trim(tmp);
|
||||||
|
}
|
||||||
|
std::unordered_map<std::string, std::string> parse_dict(std::string in, const std::vector<std::string> &keys) {
|
||||||
|
std::unordered_map<std::string, std::string> map;
|
||||||
|
if (keys.size() == 0)
|
||||||
|
return map;
|
||||||
|
|
||||||
|
in = trim(in);
|
||||||
|
|
||||||
|
// unwrap dictionary
|
||||||
|
if ((in.front() == '{') && (in.back() == '}'))
|
||||||
|
in = in.substr(1, in.length() - 2);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Not a Python dictionary.");
|
||||||
|
|
||||||
|
std::vector<std::pair<size_t, std::string>> positions;
|
||||||
|
|
||||||
|
for (auto const &value : keys) {
|
||||||
|
size_t pos = in.find("'" + value + "'");
|
||||||
|
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
throw std::runtime_error("Missing '" + value + "' key.");
|
||||||
|
|
||||||
|
std::pair<size_t, std::string> position_pair{pos, value};
|
||||||
|
positions.push_back(position_pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by position in dict
|
||||||
|
std::sort(positions.begin(), positions.end());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < positions.size(); ++i) {
|
||||||
|
std::string raw_value;
|
||||||
|
size_t begin{positions[i].first};
|
||||||
|
size_t end{std::string::npos};
|
||||||
|
|
||||||
|
std::string key = positions[i].second;
|
||||||
|
|
||||||
|
if (i + 1 < positions.size())
|
||||||
|
end = positions[i + 1].first;
|
||||||
|
|
||||||
|
raw_value = in.substr(begin, end - begin);
|
||||||
|
|
||||||
|
raw_value = trim(raw_value);
|
||||||
|
|
||||||
|
if (raw_value.back() == ',')
|
||||||
|
raw_value.pop_back();
|
||||||
|
|
||||||
|
map[key] = get_value_from_map(raw_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t N> inline bool in_array(T val, const std::array<T, N> &arr) {
|
||||||
|
return std::find(std::begin(arr), std::end(arr), val) != std::end(arr);
|
||||||
|
}
|
||||||
|
inline bool is_digits(const std::string &str) { return std::all_of(str.begin(), str.end(), ::isdigit); }
|
||||||
|
|
||||||
|
inline dtype_t parse_descr(std::string typestring) {
|
||||||
|
if (typestring.length() < 3) {
|
||||||
|
throw std::runtime_error("invalid typestring (length)");
|
||||||
|
}
|
||||||
|
|
||||||
|
char byteorder_c = typestring.at(0);
|
||||||
|
char kind_c = typestring.at(1);
|
||||||
|
std::string itemsize_s = typestring.substr(2);
|
||||||
|
|
||||||
|
if (!in_array(byteorder_c, endian_chars)) {
|
||||||
|
throw std::runtime_error("invalid typestring (byteorder)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!in_array(kind_c, numtype_chars)) {
|
||||||
|
throw std::runtime_error("invalid typestring (kind)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_digits(itemsize_s)) {
|
||||||
|
throw std::runtime_error("invalid typestring (itemsize)");
|
||||||
|
}
|
||||||
|
unsigned int itemsize = std::stoul(itemsize_s);
|
||||||
|
|
||||||
|
return {byteorder_c, kind_c, itemsize};
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
#include "aare/FileFactory.hpp"
|
#include "aare/FileFactory.hpp"
|
||||||
#include "aare/File.hpp"
|
#include "aare/File.hpp"
|
||||||
#include "aare/JsonFileFactory.hpp"
|
#include "aare/JsonFileFactory.hpp"
|
||||||
|
#include "aare/NumpyFileFactory.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
template <DetectorType detector, typename DataType>
|
template <DetectorType detector, typename DataType>
|
||||||
@ -20,7 +21,7 @@ FileFactory<detector, DataType> *FileFactory<detector, DataType>::get_factory(st
|
|||||||
// check if extension is numpy
|
// check if extension is numpy
|
||||||
else if (fpath.extension() == ".npy") {
|
else if (fpath.extension() == ".npy") {
|
||||||
std::cout << "Loading numpy file" << std::endl;
|
std::cout << "Loading numpy file" << std::endl;
|
||||||
throw std::runtime_error("Numpy file not implemented");
|
return new NumpyFileFactory<detector, DataType>(fpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Unsupported file type");
|
throw std::runtime_error("Unsupported file type");
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
template <DetectorType detector, typename DataType>
|
template <DetectorType detector, typename DataType>
|
||||||
Frame<DataType> *JsonFile<detector, DataType>::get_frame(int frame_number) {
|
Frame<DataType> *JsonFile<detector, DataType>::get_frame(int frame_number) {
|
||||||
|
if (frame_number > this->total_frames) {
|
||||||
|
throw std::runtime_error("Frame number out of range");
|
||||||
|
}
|
||||||
int subfile_id = frame_number / this->max_frames_per_file;
|
int subfile_id = frame_number / this->max_frames_per_file;
|
||||||
std::byte *buffer;
|
std::byte *buffer;
|
||||||
size_t frame_size = this->subfiles[subfile_id]->bytes_per_frame();
|
size_t frame_size = this->subfiles[subfile_id]->bytes_per_frame();
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#include "aare/NumpyFile.hpp"
|
||||||
|
|
||||||
|
template <DetectorType detector, typename DataType>
|
||||||
|
NumpyFile<detector, DataType>::NumpyFile(std::filesystem::path fname){
|
||||||
|
this->fname = fname;
|
||||||
|
fp = fopen(fname.c_str(), "rb");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <DetectorType detector, typename DataType>
|
||||||
|
Frame<DataType> *NumpyFile<detector, DataType>::get_frame(int frame_number) {
|
||||||
|
if (fp == nullptr) {
|
||||||
|
throw std::runtime_error("File not open");
|
||||||
|
}
|
||||||
|
if (frame_number > header.shape[0]) {
|
||||||
|
throw std::runtime_error("Frame number out of range");
|
||||||
|
}
|
||||||
|
Frame<DataType> *frame = new Frame<DataType>(header.shape[1], header.shape[2]);
|
||||||
|
fseek(fp, header_size + frame_number * bytes_per_frame(), SEEK_SET);
|
||||||
|
fread(frame->_get_data(), sizeof(DataType), pixels_per_frame(), fp);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
template class NumpyFile<DetectorType::Jungfrau, uint16_t>;
|
@ -1,173 +1,22 @@
|
|||||||
#include "aare/NumpyFileFactory.hpp"
|
#include "aare/NumpyFileFactory.hpp"
|
||||||
|
#include "aare/NumpyHelpers.hpp"
|
||||||
template <DetectorType detector, typename DataType>
|
template <DetectorType detector, typename DataType>
|
||||||
NumpyFileFactory<detector, DataType>::NumpyFileFactory(std::filesystem::path fpath) {
|
NumpyFileFactory<detector, DataType>::NumpyFileFactory(std::filesystem::path fpath) {
|
||||||
this->fpath = fpath;
|
this->m_fpath = fpath;
|
||||||
}
|
}
|
||||||
inline std::string parse_str(const std::string &in) {
|
|
||||||
if ((in.front() == '\'') && (in.back() == '\''))
|
|
||||||
return in.substr(1, in.length() - 2);
|
|
||||||
|
|
||||||
throw std::runtime_error("Invalid python string.");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
Removes leading and trailing whitespaces
|
|
||||||
*/
|
|
||||||
inline std::string trim(const std::string& str) {
|
|
||||||
const std::string whitespace = " \t";
|
|
||||||
auto begin = str.find_first_not_of(whitespace);
|
|
||||||
|
|
||||||
if (begin == std::string::npos)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
auto end = str.find_last_not_of(whitespace);
|
|
||||||
|
|
||||||
return str.substr(begin, end - begin + 1);
|
|
||||||
}
|
|
||||||
inline std::vector<std::string> parse_tuple(std::string in) {
|
|
||||||
std::vector<std::string> v;
|
|
||||||
const char seperator = ',';
|
|
||||||
|
|
||||||
in = trim(in);
|
|
||||||
|
|
||||||
if ((in.front() == '(') && (in.back() == ')'))
|
|
||||||
in = in.substr(1, in.length() - 2);
|
|
||||||
else
|
|
||||||
throw std::runtime_error("Invalid Python tuple.");
|
|
||||||
|
|
||||||
std::istringstream iss(in);
|
|
||||||
|
|
||||||
for (std::string token; std::getline(iss, token, seperator);) {
|
|
||||||
v.push_back(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
inline bool parse_bool(const std::string &in) {
|
|
||||||
if (in == "True")
|
|
||||||
return true;
|
|
||||||
if (in == "False")
|
|
||||||
return false;
|
|
||||||
|
|
||||||
throw std::runtime_error("Invalid python boolan.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline std::string get_value_from_map(const std::string &mapstr) {
|
|
||||||
size_t sep_pos = mapstr.find_first_of(":");
|
|
||||||
if (sep_pos == std::string::npos)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
std::string tmp = mapstr.substr(sep_pos + 1);
|
|
||||||
return trim(tmp);
|
|
||||||
}
|
|
||||||
std::unordered_map<std::string, std::string> parse_dict(std::string in, const std::vector<std::string> &keys) {
|
|
||||||
std::unordered_map<std::string, std::string> map;
|
|
||||||
|
|
||||||
if (keys.size() == 0)
|
|
||||||
return map;
|
|
||||||
|
|
||||||
in = trim(in);
|
|
||||||
|
|
||||||
// unwrap dictionary
|
|
||||||
if ((in.front() == '{') && (in.back() == '}'))
|
|
||||||
in = in.substr(1, in.length() - 2);
|
|
||||||
else
|
|
||||||
throw std::runtime_error("Not a Python dictionary.");
|
|
||||||
|
|
||||||
std::vector<std::pair<size_t, std::string>> positions;
|
|
||||||
|
|
||||||
for (auto const &value : keys) {
|
|
||||||
size_t pos = in.find("'" + value + "'");
|
|
||||||
|
|
||||||
if (pos == std::string::npos)
|
|
||||||
throw std::runtime_error("Missing '" + value + "' key.");
|
|
||||||
|
|
||||||
std::pair<size_t, std::string> position_pair{pos, value};
|
|
||||||
positions.push_back(position_pair);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort by position in dict
|
|
||||||
std::sort(positions.begin(), positions.end());
|
|
||||||
|
|
||||||
for (size_t i = 0; i < positions.size(); ++i) {
|
|
||||||
std::string raw_value;
|
|
||||||
size_t begin{positions[i].first};
|
|
||||||
size_t end{std::string::npos};
|
|
||||||
|
|
||||||
std::string key = positions[i].second;
|
|
||||||
|
|
||||||
if (i + 1 < positions.size())
|
|
||||||
end = positions[i + 1].first;
|
|
||||||
|
|
||||||
raw_value = in.substr(begin, end - begin);
|
|
||||||
|
|
||||||
raw_value = trim(raw_value);
|
|
||||||
|
|
||||||
if (raw_value.back() == ',')
|
|
||||||
raw_value.pop_back();
|
|
||||||
|
|
||||||
map[key] = get_value_from_map(raw_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
using shape_t = std::vector<uint64_t>;
|
|
||||||
|
|
||||||
struct dtype_t {
|
|
||||||
char byteorder;
|
|
||||||
char kind;
|
|
||||||
unsigned int itemsize;
|
|
||||||
};
|
|
||||||
struct header_t {
|
|
||||||
dtype_t dtype;
|
|
||||||
bool fortran_order;
|
|
||||||
shape_t shape;
|
|
||||||
};
|
|
||||||
template <typename T, size_t N> inline bool in_array(T val, const std::array<T, N> &arr) {
|
|
||||||
return std::find(std::begin(arr), std::end(arr), val) != std::end(arr);
|
|
||||||
}
|
|
||||||
inline bool is_digits(const std::string &str) { return std::all_of(str.begin(), str.end(), ::isdigit); }
|
|
||||||
|
|
||||||
inline dtype_t parse_descr(std::string typestring) {
|
|
||||||
if (typestring.length() < 3) {
|
|
||||||
throw std::runtime_error("invalid typestring (length)");
|
|
||||||
}
|
|
||||||
|
|
||||||
char byteorder_c = typestring.at(0);
|
|
||||||
char kind_c = typestring.at(1);
|
|
||||||
std::string itemsize_s = typestring.substr(2);
|
|
||||||
|
|
||||||
if (!in_array(byteorder_c, endian_chars)) {
|
|
||||||
throw std::runtime_error("invalid typestring (byteorder)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in_array(kind_c, numtype_chars)) {
|
|
||||||
throw std::runtime_error("invalid typestring (kind)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_digits(itemsize_s)) {
|
|
||||||
throw std::runtime_error("invalid typestring (itemsize)");
|
|
||||||
}
|
|
||||||
unsigned int itemsize = std::stoul(itemsize_s);
|
|
||||||
|
|
||||||
return {byteorder_c, kind_c, itemsize};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <DetectorType detector, typename DataType>
|
template <DetectorType detector, typename DataType>
|
||||||
void NumpyFileFactory<detector, DataType>::parse_metadata(File<detector, DataType> *_file) {
|
void NumpyFileFactory<detector, DataType>::parse_metadata(File<detector, DataType> *_file) {
|
||||||
auto file = dynamic_cast<NumpyFile<detector, DataType> *>(_file);
|
auto file = dynamic_cast<NumpyFile<detector, DataType> *>(_file);
|
||||||
// open ifsteam to file
|
// open ifsteam to file
|
||||||
std::ifstream f(file->fname, std::ios::binary);
|
f = std::ifstream(file->fname, std::ios::binary);
|
||||||
|
// check if file exists
|
||||||
if (!f.is_open()) {
|
if (!f.is_open()) {
|
||||||
throw std::runtime_error(fmt::format("Could not open: {} for reading", file->fname.c_str()));
|
throw std::runtime_error(fmt::format("Could not open: {} for reading", file->fname.c_str()));
|
||||||
}
|
}
|
||||||
// read magic number
|
// read magic number
|
||||||
std::array<char, 6> tmp{};
|
std::array<char, 6> tmp{};
|
||||||
f.read(tmp.data(), tmp.size());
|
f.read(tmp.data(), tmp.size());
|
||||||
if (tmp != NumpyFileFactory<detector, DataType>::magic_str) {
|
if (tmp != NumpyFile<detector, DataType>::magic_str) {
|
||||||
for (auto item : tmp)
|
for (auto item : tmp)
|
||||||
fmt::print("{}, ", int(item));
|
fmt::print("{}, ", int(item));
|
||||||
fmt::print("\n");
|
fmt::print("\n");
|
||||||
@ -175,29 +24,31 @@ void NumpyFileFactory<detector, DataType>::parse_metadata(File<detector, DataTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read version
|
// read version
|
||||||
f.read(reinterpret_cast<char *>(&major_ver_), 1);
|
f.read(reinterpret_cast<char *>(&file->major_ver_), 1);
|
||||||
f.read(reinterpret_cast<char *>(&minor_ver_), 1);
|
f.read(reinterpret_cast<char *>(&file->minor_ver_), 1);
|
||||||
|
|
||||||
if (major_ver_ == 1) {
|
if (file->major_ver_ == 1) {
|
||||||
header_len_size = 2;
|
file->header_len_size = 2;
|
||||||
} else if (major_ver_ == 2) {
|
} else if (file->major_ver_ == 2) {
|
||||||
header_len_size = 4;
|
file->header_len_size = 4;
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Unsupported numpy version");
|
throw std::runtime_error("Unsupported numpy version");
|
||||||
}
|
}
|
||||||
// read header length
|
// read header length
|
||||||
f.read(reinterpret_cast<char *>(&header_len), header_len_size);
|
f.read(reinterpret_cast<char *>(&file->header_len), file->header_len_size);
|
||||||
if ((magic_string_length + 2 + header_len_size + header_len) % 16 != 0) {
|
file->header_size = file->magic_string_length + 2 + file->header_len_size + file->header_len;
|
||||||
|
if (file->header_size % 16 != 0) {
|
||||||
fmt::print("Warning: header length is not a multiple of 16\n");
|
fmt::print("Warning: header length is not a multiple of 16\n");
|
||||||
}
|
}
|
||||||
// read header
|
// read header
|
||||||
auto buf_v = std::vector<char>(header_len);
|
auto buf_v = std::vector<char>(file->header_len);
|
||||||
f.read(buf_v.data(), header_len);
|
f.read(buf_v.data(), file->header_len);
|
||||||
std::string header(buf_v.data(), header_len);
|
std::string header(buf_v.data(), file->header_len);
|
||||||
|
|
||||||
// parse header
|
// parse header
|
||||||
|
|
||||||
std::vector<std::string> keys{"descr", "fortran_order", "shape"};
|
std::vector<std::string> keys{"descr", "fortran_order", "shape"};
|
||||||
|
std::cout << "original header: " << '"' << header << '"' << std::endl;
|
||||||
|
|
||||||
auto dict_map = parse_dict(header, keys);
|
auto dict_map = parse_dict(header, keys);
|
||||||
if (dict_map.size() == 0)
|
if (dict_map.size() == 0)
|
||||||
@ -220,6 +71,23 @@ void NumpyFileFactory<detector, DataType>::parse_metadata(File<detector, DataTyp
|
|||||||
auto dim = static_cast<unsigned long>(std::stoul(item));
|
auto dim = static_cast<unsigned long>(std::stoul(item));
|
||||||
shape.push_back(dim);
|
shape.push_back(dim);
|
||||||
}
|
}
|
||||||
|
file->header = {dtype, fortran_order, shape};
|
||||||
|
}
|
||||||
|
|
||||||
// {dtype, fortran_order, shape};
|
template <DetectorType detector, typename DataType>
|
||||||
|
File<detector, DataType>* NumpyFileFactory<detector, DataType>::load_file() {
|
||||||
|
NumpyFile<detector, DataType> *file = new NumpyFile<detector, DataType>(this->m_fpath);
|
||||||
|
parse_metadata(file);
|
||||||
|
NumpyFile<detector, DataType> *f = dynamic_cast<NumpyFile<detector, DataType> *>(file);
|
||||||
|
std::cout << "parsed header: " << f->header.to_string() << std::endl;
|
||||||
|
|
||||||
|
if(sizeof(DataType) != f->header.dtype.itemsize){
|
||||||
|
std::stringstream s;
|
||||||
|
s << "Data type size mismatch: " << sizeof(DataType) << " != " << f->header.dtype.itemsize;
|
||||||
|
throw std::runtime_error(s.str());
|
||||||
|
}
|
||||||
|
return file;
|
||||||
};
|
};
|
||||||
|
template class NumpyFileFactory<DetectorType::Jungfrau, uint16_t>;
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class File:
|
|||||||
raise FileNotFoundError(f"File not found: {path}")
|
raise FileNotFoundError(f"File not found: {path}")
|
||||||
ext = os.path.splitext(path)[1]
|
ext = os.path.splitext(path)[1]
|
||||||
|
|
||||||
if ext not in (".raw", ".json"):
|
if ext not in (".raw", ".json", ".npy"):
|
||||||
raise ValueError(f"Invalid file extension: {ext}")
|
raise ValueError(f"Invalid file extension: {ext}")
|
||||||
|
|
||||||
if ext == ".json":
|
if ext == ".json":
|
||||||
@ -33,6 +33,17 @@ class File:
|
|||||||
bitdepth = 16
|
bitdepth = 16
|
||||||
else:
|
else:
|
||||||
bitdepth = master_data["Dynamic Range"]
|
bitdepth = master_data["Dynamic Range"]
|
||||||
|
elif ext == ".npy":
|
||||||
|
# TODO: find solution for this. maybe add a None detector type
|
||||||
|
detector = "Jungfrau"
|
||||||
|
with open(path, "rb") as fobj:
|
||||||
|
import numpy as np
|
||||||
|
version = np.lib.format.read_magic(fobj)
|
||||||
|
# find what function to call based on the version
|
||||||
|
func_name = 'read_array_header_' + '_'.join(str(v) for v in version)
|
||||||
|
func = getattr(np.lib.format, func_name)
|
||||||
|
header = func(fobj)
|
||||||
|
bitdepth = header[2].itemsize * 8
|
||||||
else:
|
else:
|
||||||
NotImplementedError("Raw file not implemented yet")
|
NotImplementedError("Raw file not implemented yet")
|
||||||
|
|
||||||
|
@ -1,7 +1,32 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from aare import File, Frame
|
from aare import File, Frame
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
file = File("/home/bb/github/aare/data/jungfrau_single_master_0.json")
|
|
||||||
|
|
||||||
|
#get env variable
|
||||||
|
root_dir = Path(os.environ.get("PROJECT_ROOT_DIR"))
|
||||||
|
|
||||||
|
# read JSON master file
|
||||||
|
data_path = str(root_dir / "data"/"jungfrau_single_master_0.json")
|
||||||
|
|
||||||
|
file = File(data_path)
|
||||||
frame = file.get_frame(0)
|
frame = file.get_frame(0)
|
||||||
print(frame.rows, frame.cols)
|
print(frame.rows, frame.cols)
|
||||||
print(frame.get(0,0))
|
print(frame.get(0,0))
|
||||||
|
|
||||||
|
# read Numpy file
|
||||||
|
|
||||||
|
data_path = str(root_dir / "data"/"test_numpy_file.npy")
|
||||||
|
file = File(data_path)
|
||||||
|
frame = file.get_frame(0)
|
||||||
|
print(frame.rows, frame.cols)
|
||||||
|
print(frame.get(0,0))
|
||||||
|
|
||||||
|
arr = np.array(frame.get_array())
|
||||||
|
print(arr)
|
||||||
|
print(arr.shape)
|
||||||
|
|
||||||
|
print(np.array_equal(arr, np.load(data_path)[0]))
|
@ -1,6 +1,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
|
#include <pybind11/stl.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "aare/defs.hpp"
|
#include "aare/defs.hpp"
|
||||||
@ -27,6 +28,7 @@ PYBIND11_MODULE(_aare, m) {
|
|||||||
py::class_<Frame<uint16_t>>(m, "_Frame16")
|
py::class_<Frame<uint16_t>>(m, "_Frame16")
|
||||||
.def(py::init<std::byte*, ssize_t, ssize_t>())
|
.def(py::init<std::byte*, ssize_t, ssize_t>())
|
||||||
.def("get", &Frame<uint16_t>::get)
|
.def("get", &Frame<uint16_t>::get)
|
||||||
|
.def("get_array", &Frame<uint16_t>::get_array)
|
||||||
.def_property_readonly("rows", &Frame<uint16_t>::rows)
|
.def_property_readonly("rows", &Frame<uint16_t>::rows)
|
||||||
.def_property_readonly("cols", &Frame<uint16_t>::cols)
|
.def_property_readonly("cols", &Frame<uint16_t>::cols)
|
||||||
.def_property_readonly("bitdepth", &Frame<uint16_t>::bitdepth);
|
.def_property_readonly("bitdepth", &Frame<uint16_t>::bitdepth);
|
||||||
@ -36,6 +38,8 @@ PYBIND11_MODULE(_aare, m) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user