8#define PY_ARRAY_UNIQUE_SYMBOL _cpp2py_ARRAY_API
10#include <numpy/arrayobject.h>
11#include <c2py/c2py.hpp>
43 const auto h5_py_type_table = std::vector<h5_py_type_t>{
66 auto pos = std::ranges::find_if(h5_py_type_table, [t](
auto const &x) {
return hdf5_type_equal(x.hdf5_type, t); });
67 if (pos == h5_py_type_table.end())
throw std::runtime_error(
"HDF5/Python Error: HDF5 type not supported");
68 return static_cast<long>(pos->size);
72 int h5_to_npy(
datatype t,
bool is_complex) {
73 auto pos = std::ranges::find_if(h5_py_type_table, [t](
auto const &x) {
return hdf5_type_equal(x.hdf5_type, t); });
74 if (pos == h5_py_type_table.end())
throw std::runtime_error(
"HDF5/Python Error: HDF5 type not supported");
75 int res = pos->numpy_type;
77 if (res == NPY_DOUBLE) res = NPY_CDOUBLE;
78 if (res == NPY_FLOAT) res = NPY_CFLOAT;
79 if (res == NPY_LONGDOUBLE) res = NPY_CLONGDOUBLE;
86 auto pos = std::ranges::find_if(h5_py_type_table, [t](
auto const &x) {
return x.numpy_type == t; });
87 if (pos == h5_py_type_table.end())
throw std::runtime_error(
"HDF5/Python Error: Numpy type not supported");
88 return pos->hdf5_type;
94 int numpy_type = PyArray_DESCR(arr_obj)->type_num;
95 int rank = PyArray_NDIM(arr_obj);
99 const bool is_complex = (numpy_type == NPY_CDOUBLE) or (numpy_type == NPY_CLONGDOUBLE) or (numpy_type == NPY_CFLOAT);
103 std::vector<long> c_strides(rank + is_complex, 0), c_shape(rank + is_complex, 2);
104 for (
int i = 0; i < rank; ++i) {
105 c_shape[i] = PyArray_DIMS(arr_obj)[i];
106 res.slab.count[i] =
static_cast<size_t>(c_shape[i]);
107 c_strides[i] = PyArray_STRIDES(arr_obj)[i] /
static_cast<long>(h5_c_size(dt));
112 for (
int i = 0; i < rank; ++i) {
113 res.parent_shape[i] = Ltot[i];
114 res.slab.stride[i] = stri[i];
121 PyObject *h5_read_any_int(
group g, std::string
const &name,
datatype ty) {
122 if (H5Tequal(ty, H5T_NATIVE_SHORT)) {
124 }
else if (H5Tequal(ty, H5T_NATIVE_INT)) {
126 }
else if (H5Tequal(ty, H5T_NATIVE_LONG)) {
128 }
else if (H5Tequal(ty, H5T_NATIVE_LLONG)) {
130 }
else if (H5Tequal(ty, H5T_NATIVE_USHORT)) {
132 }
else if (H5Tequal(ty, H5T_NATIVE_UINT)) {
134 }
else if (H5Tequal(ty, H5T_NATIVE_ULONG)) {
136 }
else if (H5Tequal(ty, H5T_NATIVE_ULLONG)) {
139 PyErr_SetString(PyExc_RuntimeError,
"h5::h5_read_bare: Integer type can not be read from HDF5");
147 if (PyArray_Check(ob)) {
148 auto *arr_obj = (PyArrayObject *)ob;
150 }
else if (PyArray_CheckScalar(ob)) {
152 c2py::pyref obsc = PyArray_FromScalar(ob,
nullptr);
154 }
else if (PyFloat_Check(ob)) {
155 h5_write(g, name, PyFloat_AsDouble(ob));
156 }
else if (PyBool_Check(ob)) {
157 h5_write(g, name,
static_cast<bool>(PyLong_AsLong(ob)));
158 }
else if (PyLong_Check(ob)) {
159 h5_write(g, name,
static_cast<long>(PyLong_AsLong(ob)));
160 }
else if (PyUnicode_Check(ob)) {
161 h5_write(g, name,
static_cast<const char *
>(PyUnicode_AsUTF8(ob)));
162 }
else if (PyComplex_Check(ob)) {
163 h5_write(g, name, std::complex<double>{PyComplex_RealAsDouble(ob), PyComplex_ImagAsDouble(ob)});
165 PyErr_SetString(PyExc_RuntimeError,
"h5::h5_write_bare: Python object can not be written to HDF5");
174 if (ds_info.rank() == 0) {
176 if (H5Tget_class(ds_info.ty) == H5T_FLOAT) {
179 return PyFloat_FromDouble(x);
183 if (H5Tget_class(ds_info.ty) == H5T_INTEGER) {
return h5_read_any_int(g, name, ds_info.ty); }
189 return PyBool_FromLong(
long(x));
193 if (H5Tget_class(ds_info.ty) == H5T_STRING) {
196 return PyUnicode_FromString(x.c_str());
203 return PyComplex_FromDoubles(x.
r, x.
i);
207 PyErr_SetString(PyExc_RuntimeError,
"h5::h5_read_bare: Scalar type can not be read from HDF5");
212 if ((ds_info.rank() == 1) and ds_info.has_complex_attribute) {
213 std::complex<double> z{};
215 return PyComplex_FromDoubles(z.real(), z.imag());
219 if (H5Tget_class(ds_info.ty) == H5T_STRING) {
220 if (ds_info.rank() == 1) {
222 return c2py::cxx2py(x);
225 if (ds_info.rank() == 2) {
227 return c2py::cxx2py(x);
230 PyErr_SetString(PyExc_RuntimeError,
"h5::h5_read_bare: String dataset with rank > 2 is not allowed");
235 auto shape = std::vector<npy_intp>(ds_info.lengths.begin(), ds_info.lengths.end());
236 auto numpy_type = h5_to_npy(ds_info.ty, ds_info.has_complex_attribute);
239 if (ds_info.has_complex_attribute) shape.pop_back();
242 PyObject *ob = PyArray_SimpleNewFromDescr(
int(shape.size()), &shape[0], PyArray_DescrFromType(numpy_type));
243 if (PyErr_Occurred())
return nullptr;
A handle to an HDF5 group.
Provides a generic interface for reading/writing data from/to various HDF5 objects.
object datatype
Type alias for an HDF5 datatype.
bool hdf5_type_equal(datatype dt1, datatype dt2)
Check if two HDF5 datatypes are equal.
datatype hdf5_type()
Map a given C++ type to an HDF5 datatype.
c2py::pyref h5_read_bare(group g, std::string const &name)
Read a dataset from an HDF5 group and return it as a Python object.
void h5_write_bare(group g, std::string const &name, PyObject *ob)
Write a Python object to an HDF5 group.
void read(group g, std::string const &name, array_view v, hyperslab sl)
Read a given hyperslab from an HDF5 dataset into an array view.
dataset_info get_dataset_info(dataset ds)
Retrieve the shape and the h5::datatype from a dataset.
void write(group g, std::string const &name, array_view const &v, bool compress)
Write an array view to an HDF5 dataset.
std::pair< v_t, v_t > get_parent_shape_and_h5_strides(long const *np_strides, int rank, long const *view_shape)
Given a view on an n-dimensional array (dataspace) by specifying its numpy/nda-style strides and its ...
T h5_read(group g, std::string const &key)
Generic implementation for reading from an HDF5 dataset/subgroup.
void h5_write(group g, std::string const &name, T const &x)
Write a scalar to an HDF5 dataset.
Provides helper functions to read/write Python objects to/from HDF5 files.
Provides a generic handle for HDF5 objects.
Provides a generic interface to read/write scalars from/to HDF5.
Provides functions to read/write std::string, char* and h5::char_buf objects from/to HDF5.
Struct representing a view on an n-dimensional array/dataspace.
A complex compound type consisting of two doubles to represent a complex number.
Provides functions to read/write std::vector objects from/to HDF5.