From 765bbdc295f08bcc6a34d9361eef3b6bbe867def Mon Sep 17 00:00:00 2001 From: Bechir Date: Fri, 8 Mar 2024 18:26:02 +0100 Subject: [PATCH 1/5] read numpy file: works --- .vscode/c_cpp_properties.json | 5 +- CMakeLists.txt | 2 +- core/include/aare/Frame.hpp | 1 + core/src/Frame.cpp | 9 ++- data/test_numpy_file.npy | Bin 0 -> 125128 bytes examples/main.cpp | 29 +++++---- file_io/include/aare/File.hpp | 2 + file_io/include/aare/JsonFileFactory.hpp | 3 +- file_io/include/aare/NumpyFile.hpp | 51 ++++++++++++++-- file_io/include/aare/NumpyFileFactory.hpp | 20 +++---- file_io/src/FileFactory.cpp | 3 +- file_io/src/JsonFile.cpp | 3 + file_io/src/NumpyFile.cpp | 24 ++++++++ file_io/src/NumpyFileFactory.cpp | 69 ++++++++++++---------- 14 files changed, 154 insertions(+), 67 deletions(-) create mode 100644 data/test_numpy_file.npy diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 930311e..67bb44b 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,10 @@ { "name": "Linux", "includePath": [ - "${workspaceFolder}/**", + "${workspaceFolder}/file_io/**", + "${workspaceFolder}/core/**", + "${workspaceFolder}/tests/**", + "${workspaceFolder}/tests/**", "/usr/include" ], "defines": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index b6fbd68..76ccfa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ include(GNUInstallDirs) include(FetchContent) -option(AARE_USE_WARNINGS "Eable warnings" ON) +option(AARE_USE_WARNINGS "Eable warnings" OFF) option(AARE_PYTHON_BINDINGS "Build python bindings" ON) option(AARE_TESTS "Build tests" ON) option(AARE_EXAMPLES "Build examples" ON) diff --git a/core/include/aare/Frame.hpp b/core/include/aare/Frame.hpp index 78918a6..b19689a 100644 --- a/core/include/aare/Frame.hpp +++ b/core/include/aare/Frame.hpp @@ -22,6 +22,7 @@ template class Frame{ ssize_t cols; DataType* data; ssize_t bitdepth = sizeof(DataType)*8; + Frame(ssize_t rows, ssize_t cols); Frame(std::byte* fp, ssize_t rows, ssize_t cols); DataType get(int row, int col); diff --git a/core/src/Frame.cpp b/core/src/Frame.cpp index f035fc4..8bed03d 100644 --- a/core/src/Frame.cpp +++ b/core/src/Frame.cpp @@ -8,13 +8,18 @@ Frame::Frame(std::byte* bytes, ssize_t rows, ssize_t cols): std::memcpy(data, bytes, rows*cols*sizeof(DataType)); } +template +Frame::Frame(ssize_t rows, ssize_t cols): + rows(rows), cols(cols) { + data = new DataType[rows*cols]; + } + template DataType Frame::get(int row, int col) { if (row < 0 || row >= rows || col < 0 || col >= cols) { - std::cerr << "Invalid row or column index" << std::endl; - return 0; + throw std::runtime_error("Invalid row or column index"); } return data[row*cols + col]; } diff --git a/data/test_numpy_file.npy b/data/test_numpy_file.npy new file mode 100644 index 0000000000000000000000000000000000000000..ca1bc7ee80fdc3cb0294da19690cac93046f8dcf GIT binary patch literal 125128 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 HriT9m4%pI{ literal 0 HcmV?d00001 diff --git a/examples/main.cpp b/examples/main.cpp index f4d45cb..66d8af5 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -1,25 +1,30 @@ // Your First C++ Program -#include #include "aare/FileHandler.hpp" +#include -using JFileHandler = FileHandler; -using JFile = File; +using JFileHandler = FileHandler; +using JFile = File; using JFrame = Frame; - -void test(JFileHandler* f,int frame_number){ +void test(JFileHandler *f, int frame_number) { std::cout << "frame number: " << frame_number << std::endl; - JFrame* frame = f->get_frame(frame_number); - std::cout << frame->get(0,0) << ' '; - std::cout << frame->get(0,1) << ' '; - std::cout << frame->get(1,0) << ' '; - std::cout << frame->get(511,1023) << std::endl; + JFrame *frame = f->get_frame(frame_number); + std::cout << frame->get(0, 0) << std::endl; + std::cout << frame->get(0, 1) << std::endl; + std::cout << frame->get(1, 0) << std::endl; + std::cout << frame->get(49, 49) << std::endl; delete frame; } int main() { - std::filesystem::path fpath("/home/bb/github/aare/data/jungfrau_single_master_0.json"); - auto fileHandler = new JFileHandler (fpath); + // std::filesystem::path fpath("/home/bb/github/aare/data/jungfrau_single_master_0.json"); + std::filesystem::path fpath("/home/bb/github/aare/data/test_numpy_file.npy"); + + auto fileHandler = new JFileHandler(fpath); + test(fileHandler, 0); + test(fileHandler, 24); + delete fileHandler; + } diff --git a/file_io/include/aare/File.hpp b/file_io/include/aare/File.hpp index 0a4f628..75c4d28 100644 --- a/file_io/include/aare/File.hpp +++ b/file_io/include/aare/File.hpp @@ -15,6 +15,8 @@ class File { virtual Frame* get_frame(int frame_number) = 0; private: + //comment + public: std::filesystem::path fname; diff --git a/file_io/include/aare/JsonFileFactory.hpp b/file_io/include/aare/JsonFileFactory.hpp index a65453c..4c0ffac 100644 --- a/file_io/include/aare/JsonFileFactory.hpp +++ b/file_io/include/aare/JsonFileFactory.hpp @@ -5,11 +5,10 @@ class JsonFileFactory: public FileFactory private: /* data */ public: + JsonFileFactory(std::filesystem::path fpath); File* load_file() override; void parse_metadata(File*) override; void parse_fname(File*) override; - - JsonFileFactory(std::filesystem::path fpath); void open_subfiles(File*); sls_detector_header read_header(const std::filesystem::path &fname); void find_geometry(File*); diff --git a/file_io/include/aare/NumpyFile.hpp b/file_io/include/aare/NumpyFile.hpp index 1230af9..33ab769 100644 --- a/file_io/include/aare/NumpyFile.hpp +++ b/file_io/include/aare/NumpyFile.hpp @@ -1,9 +1,52 @@ +#pragma once #include "aare/File.hpp" #include "aare/defs.hpp" +#include +#include -template -class NumpyFile : public File -{ +using shape_t = std::vector; + +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 class NumpyFile : public File { + FILE *fp = nullptr; - + public: + NumpyFile(std::filesystem::path fname); + Frame *get_frame(int frame_number) override; + header_t header{}; + static constexpr std::array 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()); + }; + inline ssize_t bytes_per_frame() { return header.dtype.itemsize * pixels_per_frame(); }; }; \ No newline at end of file diff --git a/file_io/include/aare/NumpyFileFactory.hpp b/file_io/include/aare/NumpyFileFactory.hpp index 3ba3903..f75fcf6 100644 --- a/file_io/include/aare/NumpyFileFactory.hpp +++ b/file_io/include/aare/NumpyFileFactory.hpp @@ -1,6 +1,7 @@ -#include "aare/defs.hpp" +#pragma once #include "aare/FileFactory.hpp" #include "aare/NumpyFile.hpp" +#include "aare/defs.hpp" #include #include #include @@ -8,22 +9,17 @@ #include #include #include +#include template class NumpyFileFactory : public FileFactory { + private: + std::ifstream f; + void read_data(File *_file); + public: NumpyFileFactory(std::filesystem::path fpath); void parse_metadata(File *_file) override; - void open_subfiles(File *_file) override; File *load_file() override; + void parse_fname(File *){}; - uint8_t major_ver() const noexcept { return major_ver_; } - uint8_t minor_ver() const noexcept { return minor_ver_; } - - private: - static constexpr std::array 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}; }; \ No newline at end of file diff --git a/file_io/src/FileFactory.cpp b/file_io/src/FileFactory.cpp index 9e7ed47..37eaf0c 100644 --- a/file_io/src/FileFactory.cpp +++ b/file_io/src/FileFactory.cpp @@ -1,6 +1,7 @@ #include "aare/FileFactory.hpp" #include "aare/File.hpp" #include "aare/JsonFileFactory.hpp" +#include "aare/NumpyFileFactory.hpp" #include template @@ -20,7 +21,7 @@ FileFactory *FileFactory::get_factory(st // check if extension is numpy else if (fpath.extension() == ".npy") { std::cout << "Loading numpy file" << std::endl; - throw std::runtime_error("Numpy file not implemented"); + return new NumpyFileFactory(fpath); } throw std::runtime_error("Unsupported file type"); diff --git a/file_io/src/JsonFile.cpp b/file_io/src/JsonFile.cpp index c900e74..503b6fa 100644 --- a/file_io/src/JsonFile.cpp +++ b/file_io/src/JsonFile.cpp @@ -2,6 +2,9 @@ template Frame *JsonFile::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; std::byte *buffer; size_t frame_size = this->subfiles[subfile_id]->bytes_per_frame(); diff --git a/file_io/src/NumpyFile.cpp b/file_io/src/NumpyFile.cpp index e69de29..78de3d8 100644 --- a/file_io/src/NumpyFile.cpp +++ b/file_io/src/NumpyFile.cpp @@ -0,0 +1,24 @@ + +#include "aare/NumpyFile.hpp" + +template +NumpyFile::NumpyFile(std::filesystem::path fname){ + this->fname = fname; + fp = fopen(fname.c_str(), "rb"); +} + +template +Frame *NumpyFile::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 *frame = new Frame(header.shape[1], header.shape[2]); + fseek(fp, header_size + frame_number * bytes_per_frame(), SEEK_SET); + fread(frame->data, sizeof(DataType), pixels_per_frame(), fp); + return frame; +} + +template class NumpyFile; \ No newline at end of file diff --git a/file_io/src/NumpyFileFactory.cpp b/file_io/src/NumpyFileFactory.cpp index fc5d470..fd15970 100644 --- a/file_io/src/NumpyFileFactory.cpp +++ b/file_io/src/NumpyFileFactory.cpp @@ -13,8 +13,8 @@ inline std::string parse_str(const std::string &in) { /** Removes leading and trailing whitespaces */ -inline std::string trim(const std::string& str) { - const std::string whitespace = " \t"; +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) @@ -52,7 +52,6 @@ inline bool parse_bool(const std::string &in) { 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) @@ -63,7 +62,6 @@ inline std::string get_value_from_map(const std::string &mapstr) { } std::unordered_map parse_dict(std::string in, const std::vector &keys) { std::unordered_map map; - if (keys.size() == 0) return map; @@ -113,19 +111,6 @@ std::unordered_map parse_dict(std::string in, const st return map; } - -using shape_t = std::vector; - -struct dtype_t { - char byteorder; - char kind; - unsigned int itemsize; -}; -struct header_t { - dtype_t dtype; - bool fortran_order; - shape_t shape; -}; template inline bool in_array(T val, const std::array &arr) { return std::find(std::begin(arr), std::end(arr), val) != std::end(arr); } @@ -160,14 +145,15 @@ template void NumpyFileFactory::parse_metadata(File *_file) { auto file = dynamic_cast *>(_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()) { throw std::runtime_error(fmt::format("Could not open: {} for reading", file->fname.c_str())); } // read magic number std::array tmp{}; f.read(tmp.data(), tmp.size()); - if (tmp != NumpyFileFactory::magic_str) { + if (tmp != NumpyFile::magic_str) { for (auto item : tmp) fmt::print("{}, ", int(item)); fmt::print("\n"); @@ -175,29 +161,31 @@ void NumpyFileFactory::parse_metadata(File(&major_ver_), 1); - f.read(reinterpret_cast(&minor_ver_), 1); + f.read(reinterpret_cast(&file->major_ver_), 1); + f.read(reinterpret_cast(&file->minor_ver_), 1); - if (major_ver_ == 1) { - header_len_size = 2; - } else if (major_ver_ == 2) { - header_len_size = 4; + if (file->major_ver_ == 1) { + file->header_len_size = 2; + } else if (file->major_ver_ == 2) { + file->header_len_size = 4; } else { throw std::runtime_error("Unsupported numpy version"); } // read header length - f.read(reinterpret_cast(&header_len), header_len_size); - if ((magic_string_length + 2 + header_len_size + header_len) % 16 != 0) { + f.read(reinterpret_cast(&file->header_len), file->header_len_size); + 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"); } // read header - auto buf_v = std::vector(header_len); - f.read(buf_v.data(), header_len); - std::string header(buf_v.data(), header_len); + auto buf_v = std::vector(file->header_len); + f.read(buf_v.data(), file->header_len); + std::string header(buf_v.data(), file->header_len); // parse header std::vector keys{"descr", "fortran_order", "shape"}; + std::cout << "original header: " << '"' << header << '"' << std::endl; auto dict_map = parse_dict(header, keys); if (dict_map.size() == 0) @@ -220,6 +208,23 @@ void NumpyFileFactory::parse_metadata(File(std::stoul(item)); shape.push_back(dim); } + file->header = {dtype, fortran_order, shape}; +} + +template + File* NumpyFileFactory::load_file() { + NumpyFile *file = new NumpyFile(this->fpath); + parse_metadata(file); + NumpyFile *f = dynamic_cast *>(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; + - // {dtype, fortran_order, shape}; -}; \ No newline at end of file From 5173f26bf8e9a66d924bd4c1dd4801446238a74b Mon Sep 17 00:00:00 2001 From: Bechir Date: Fri, 8 Mar 2024 18:42:24 +0100 Subject: [PATCH 2/5] fix merge errors --- core/include/aare/Frame.hpp | 10 ++++------ core/src/Frame.cpp | 4 ++-- file_io/src/NumpyFile.cpp | 2 +- file_io/src/NumpyFileFactory.cpp | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/core/include/aare/Frame.hpp b/core/include/aare/Frame.hpp index 78f5d47..e33563f 100644 --- a/core/include/aare/Frame.hpp +++ b/core/include/aare/Frame.hpp @@ -18,13 +18,8 @@ template class Frame { DataType *m_data; ssize_t m_bitdepth = sizeof(DataType) * 8; - public: - ssize_t rows; - ssize_t cols; - DataType* data; - ssize_t bitdepth = sizeof(DataType)*8; + public: Frame(ssize_t rows, ssize_t cols); - Frame(std::byte *fp, ssize_t rows, ssize_t cols); DataType get(int row, int col); ssize_t rows() const{ @@ -36,6 +31,9 @@ template class Frame { ssize_t bitdepth() const{ return m_bitdepth; } + DataType* _get_data(){ + return m_data; + } ~Frame() { delete[] m_data; } }; diff --git a/core/src/Frame.cpp b/core/src/Frame.cpp index 575e25d..28d72b7 100644 --- a/core/src/Frame.cpp +++ b/core/src/Frame.cpp @@ -10,8 +10,8 @@ Frame::Frame(std::byte* bytes, ssize_t rows, ssize_t cols): template Frame::Frame(ssize_t rows, ssize_t cols): - rows(rows), cols(cols) { - data = new DataType[rows*cols]; + m_rows(rows), m_cols(cols) { + m_data = new DataType[m_rows*m_cols]; } diff --git a/file_io/src/NumpyFile.cpp b/file_io/src/NumpyFile.cpp index 78de3d8..245942e 100644 --- a/file_io/src/NumpyFile.cpp +++ b/file_io/src/NumpyFile.cpp @@ -17,7 +17,7 @@ Frame *NumpyFile::get_frame(int frame_number) { } Frame *frame = new Frame(header.shape[1], header.shape[2]); fseek(fp, header_size + frame_number * bytes_per_frame(), SEEK_SET); - fread(frame->data, sizeof(DataType), pixels_per_frame(), fp); + fread(frame->_get_data(), sizeof(DataType), pixels_per_frame(), fp); return frame; } diff --git a/file_io/src/NumpyFileFactory.cpp b/file_io/src/NumpyFileFactory.cpp index fd15970..0f90a7d 100644 --- a/file_io/src/NumpyFileFactory.cpp +++ b/file_io/src/NumpyFileFactory.cpp @@ -2,7 +2,7 @@ template NumpyFileFactory::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() == '\'')) @@ -213,7 +213,7 @@ void NumpyFileFactory::parse_metadata(File File* NumpyFileFactory::load_file() { - NumpyFile *file = new NumpyFile(this->fpath); + NumpyFile *file = new NumpyFile(this->m_fpath); parse_metadata(file); NumpyFile *f = dynamic_cast *>(file); std::cout << "parsed header: " << f->header.to_string() << std::endl; From 25d282717c24c9e3555483517a9467387281e29c Mon Sep 17 00:00:00 2001 From: Bechir Braham Date: Mon, 11 Mar 2024 14:58:44 +0100 Subject: [PATCH 3/5] move static numpy functions to another header - use env variables - change warnings back to ON --- .env.dev | 1 + CMakeLists.txt | 6 +- examples/main.cpp | 7 +- file_io/include/aare/NumpyFileFactory.hpp | 9 +- file_io/include/aare/NumpyHelpers.hpp | 146 ++++++++++++++++++++++ file_io/src/NumpyFileFactory.cpp | 139 +------------------- python/example/read_frame.py | 8 +- 7 files changed, 167 insertions(+), 149 deletions(-) create mode 100644 .env.dev create mode 100644 file_io/include/aare/NumpyHelpers.hpp diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..eb19e75 --- /dev/null +++ b/.env.dev @@ -0,0 +1 @@ +export PROJECT_ROOT_DIR=/home/l_bechir/github/aare diff --git a/CMakeLists.txt b/CMakeLists.txt index e17c311..59a3c34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ include(FetchContent) include(cmake/helpers.cmake) default_build_type("Release") -option(AARE_USE_WARNINGS "Eable warnings" OFF) +option(AARE_USE_WARNINGS "Eable warnings" ON) option(AARE_PYTHON_BINDINGS "Build python bindings" ON) option(AARE_TESTS "Build tests" ON) option(AARE_EXAMPLES "Build examples" ON) @@ -86,4 +86,6 @@ target_link_libraries(example PUBLIC aare) if(AARE_PYTHON_BINDINGS) add_subdirectory(python) -endif() \ No newline at end of file +endif() + +set(ENV{PROJECT_ROOT_DIR} ${PROJECT_SOURCE_DIR}) diff --git a/examples/main.cpp b/examples/main.cpp index 66d8af5..a1464e0 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -2,6 +2,8 @@ #include "aare/FileHandler.hpp" #include +#define AARE_ROOT_DIR_VAR "PROJECT_ROOT_DIR" + using JFileHandler = FileHandler; using JFile = File; using JFrame = Frame; @@ -18,8 +20,11 @@ void test(JFileHandler *f, int frame_number) { } int main() { + 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("/home/bb/github/aare/data/test_numpy_file.npy"); + std::filesystem::path fpath(PROJECT_ROOT_DIR / "data" / "test_numpy_file.npy"); + std::cout< -#include -#include #include -#include -#include -#include -#include + + template class NumpyFileFactory : public FileFactory { private: diff --git a/file_io/include/aare/NumpyHelpers.hpp b/file_io/include/aare/NumpyHelpers.hpp new file mode 100644 index 0000000..21b08d4 --- /dev/null +++ b/file_io/include/aare/NumpyHelpers.hpp @@ -0,0 +1,146 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +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 parse_tuple(std::string in) { + std::vector 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 parse_dict(std::string in, const std::vector &keys) { + std::unordered_map 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> 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 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 inline bool in_array(T val, const std::array &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}; +} diff --git a/file_io/src/NumpyFileFactory.cpp b/file_io/src/NumpyFileFactory.cpp index 0f90a7d..42e2056 100644 --- a/file_io/src/NumpyFileFactory.cpp +++ b/file_io/src/NumpyFileFactory.cpp @@ -1,146 +1,9 @@ #include "aare/NumpyFileFactory.hpp" - +#include "aare/NumpyHelpers.hpp" template NumpyFileFactory::NumpyFileFactory(std::filesystem::path 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\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 parse_tuple(std::string in) { - std::vector 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 parse_dict(std::string in, const std::vector &keys) { - std::unordered_map 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> 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 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 inline bool in_array(T val, const std::array &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 void NumpyFileFactory::parse_metadata(File *_file) { auto file = dynamic_cast *>(_file); diff --git a/python/example/read_frame.py b/python/example/read_frame.py index 457a4ef..293ac45 100644 --- a/python/example/read_frame.py +++ b/python/example/read_frame.py @@ -1,7 +1,13 @@ +import os +from pathlib import Path from aare import File, Frame 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")) + data_path = str(root_dir / "data"/"jungfrau_single_master_0.json") + + file = File(data_path) frame = file.get_frame(0) print(frame.rows, frame.cols) print(frame.get(0,0)) \ No newline at end of file From c4c88c50d129315990cc188bc181b32ae56a5471 Mon Sep 17 00:00:00 2001 From: Bechir Braham Date: Mon, 11 Mar 2024 16:05:54 +0100 Subject: [PATCH 4/5] add python bindings for numpy --- core/include/aare/Frame.hpp | 1 + core/src/Frame.cpp | 12 ++++++++++++ python/aare/File.py | 13 ++++++++++++- python/example/read_frame.py | 21 ++++++++++++++++++++- python/src/bindings.cpp | 4 ++++ 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/core/include/aare/Frame.hpp b/core/include/aare/Frame.hpp index e33563f..41c9b68 100644 --- a/core/include/aare/Frame.hpp +++ b/core/include/aare/Frame.hpp @@ -22,6 +22,7 @@ template class Frame { Frame(ssize_t rows, ssize_t cols); Frame(std::byte *fp, ssize_t rows, ssize_t cols); DataType get(int row, int col); + std::vector> get_array(); ssize_t rows() const{ return m_rows; } diff --git a/core/src/Frame.cpp b/core/src/Frame.cpp index 28d72b7..3d4e940 100644 --- a/core/src/Frame.cpp +++ b/core/src/Frame.cpp @@ -25,5 +25,17 @@ DataType Frame::get(int row, int col) { return m_data[row*m_cols + col]; } +template +std::vector> Frame::get_array() { + std::vector> array; + for (int i = 0; i < m_rows; i++) { + std::vector row; + row.assign(m_data + i*m_cols, m_data + (i+1)*m_cols); + array.push_back(row); + } + + return array; +} + template class Frame; diff --git a/python/aare/File.py b/python/aare/File.py index da454e9..fe8a026 100644 --- a/python/aare/File.py +++ b/python/aare/File.py @@ -21,7 +21,7 @@ class File: raise FileNotFoundError(f"File not found: {path}") 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}") if ext == ".json": @@ -33,6 +33,17 @@ class File: bitdepth = 16 else: 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: NotImplementedError("Raw file not implemented yet") diff --git a/python/example/read_frame.py b/python/example/read_frame.py index 293ac45..2191305 100644 --- a/python/example/read_frame.py +++ b/python/example/read_frame.py @@ -1,13 +1,32 @@ import os from pathlib import Path from aare import File, Frame +import numpy as np if __name__ == "__main__": + + #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) print(frame.rows, frame.cols) - print(frame.get(0,0)) \ No newline at end of file + 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])) \ No newline at end of file diff --git a/python/src/bindings.cpp b/python/src/bindings.cpp index 91c880b..d14b0ee 100644 --- a/python/src/bindings.cpp +++ b/python/src/bindings.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include "aare/defs.hpp" @@ -27,10 +28,13 @@ PYBIND11_MODULE(_aare, m) { py::class_>(m, "_Frame16") .def(py::init()) .def("get", &Frame::get) + .def("get_array", &Frame::get_array) .def_property_readonly("rows", &Frame::rows) .def_property_readonly("cols", &Frame::cols) .def_property_readonly("bitdepth", &Frame::bitdepth); + + From fd0bbf817064cf834c0237f814a2f612c0a5a9ae Mon Sep 17 00:00:00 2001 From: Bechir Braham Date: Mon, 11 Mar 2024 17:47:52 +0100 Subject: [PATCH 5/5] Update CMakeLists.txt --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 59a3c34..e000e6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,5 +87,3 @@ target_link_libraries(example PUBLIC aare) if(AARE_PYTHON_BINDINGS) add_subdirectory(python) endif() - -set(ENV{PROJECT_ROOT_DIR} ${PROJECT_SOURCE_DIR})