diff --git a/cnorxz/core/include/array_wrapper.h b/cnorxz/core/include/array_wrapper.h index fb553fc..a13ee9f 100644 --- a/cnorxz/core/include/array_wrapper.h +++ b/cnorxz/core/include/array_wrapper.h @@ -4,6 +4,8 @@ #include #include "cnorxz.h" +#include "cereal/cnorxz_cereal.h" +#include "numpy/ndarraytypes.h" namespace CNORXZ { @@ -18,9 +20,42 @@ namespace CNORXZ virtual SizeT size() const = 0; // virtual PyObject* get() const = 0; // operator[]!! #ifdef HAVE_CEREAL - virtual void writeFile(Format f, const String& fname); - virtual void readFile(Format f, const String& fname); + virtual void writeFile(cer::Format f, const String& fname) const = 0; + virtual void readFile(cer::Format f, const String& fname) const = 0; #endif + virtual int typenum() const = 0; + virtual const void* data() const = 0; + virtual SizeT datasize() const = 0; + }; + + template + struct Typenum + { + static const int value = NPY_NOTYPE; + }; + + template <> + struct Typenum + { + static const int value = NPY_DOUBLE; + }; + + template <> + struct Typenum + { + static const int value = NPY_INT32; + }; + + template <> + struct Typenum + { + static const int value = NPY_INT64; + }; + + template <> + struct Typenum + { + static const int value = NPY_UINT64; }; template @@ -31,11 +66,29 @@ namespace CNORXZ public: CArrayWrapper() : mArr( std::make_shared>() ) {} - //DEFAULT_MEMBERS(CArrayWrapper); CArrayWrapper(const RangePtr& r) : mArr( std::make_shared>(r) ) {} virtual RangePtr range() const override final { return mArr->range(); } virtual SizeT size() const override final { return mArr->size(); } +#ifdef HAVE_CEREAL + virtual void writeFile(cer::Format f, const String& fname) const override final + { + if(f == cer::Format::XML) { cer::writeXMLFile(fname, *mArr); } + else if(f == cer::Format::JSON) { cer::writeJSONFile(fname, *mArr); } + else { cer::writeBINARYFile(fname, *mArr); } + } + + virtual void readFile(cer::Format f, const String& fname) const override final + { + if(f == cer::Format::XML) { cer::readXMLFile(fname, *mArr); } + else if(f == cer::Format::JSON) { cer::readJSONFile(fname, *mArr); } + else { cer::readBINARYFile(fname, *mArr); } + } +#endif + virtual int typenum() const override final { return Typenum::value; } + virtual const void* data() const override final + { return reinterpret_cast( mArr->data() ); } + virtual SizeT datasize() const override final { return size() * sizeof(T); } }; } diff --git a/cnorxz/core/lib/array_wrapper.cpp b/cnorxz/core/lib/array_wrapper.cpp index c7ba2b1..5957a44 100644 --- a/cnorxz/core/lib/array_wrapper.cpp +++ b/cnorxz/core/lib/array_wrapper.cpp @@ -1,13 +1,15 @@ #include "array_wrapper.h" +#include "numpy/arrayobject.h" using namespace CNORXZ; +using namespace CNORXZ::cer; int PyCArrayB_init(PyCArrayB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "type", "extension" , NULL }; SizeT ext = 0; - const char* type; + char* type = NULL; if(not PyArg_ParseTupleAndKeywords(args, kwds, "s|k", kwlist, &type, &ext)){ return -1; @@ -37,12 +39,103 @@ PyObject* PyCArrayB_size(PyCArrayB* self) return NULL; } const SizeT retval = self->ptrObj->size(); - return Py_BuildValue("k",retval); + return Py_BuildValue("k", retval); +} + +PyObject* PyCArrayB_range(PyCArrayB* self) +{ + if(not self->ptrObj->range()){ + PyErr_SetString(PyExc_RuntimeError, "array not initialized"); + return NULL; + } + const RangePtr retval = self->ptrObj->range(); + return Py_BuildValue("k", retval); +} + +Format formatFromString(const char* fstr) +{ + Format f = Format::BINARY; + if(fstr != NULL){ + if(strcmp(fstr,"binary") == 0){ + f = Format::BINARY; + } + else if(strcmp(fstr,"json") == 0){ + f = Format::JSON; + } + else if(strcmp(fstr,"xml") == 0){ + f = Format::XML; + } + else { + PyErr_SetString(PyExc_RuntimeError, "unknown format"); + } + } + return f; +} + +void PyCArrayB_writeFile(PyCArrayB* self, PyObject* args, PyObject* kwds) +{ + if(not self->ptrObj->range()){ + PyErr_SetString(PyExc_RuntimeError, "array not initialized"); + } + static char* kwlist[] = { "format", "filename" , NULL }; + char* fname = NULL; + char* format = NULL; + + if(not PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &fname, &format)){ + return; + } + const String fn(fname); + const Format f = formatFromString(format); + self->ptrObj->writeFile(f, fn); +} + +void PyCArrayB_readFile(PyCArrayB* self, PyObject* args, PyObject* kwds) +{ + static char* kwlist[] = { "format", "filename" , NULL }; + char* fname = NULL; + char* format = NULL; + + if(not PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &fname, &format)){ + return; + } + const String fn(fname); + const Format f = formatFromString(format); + self->ptrObj->readFile(f, fn); +} + +PyObject* PyCArrayB_npa(PyCArrayB* self) +{ + // return viewing (!) numpy array + if(not self->ptrObj->range()){ + PyErr_SetString(PyExc_RuntimeError, "array not initialized"); + return NULL; + } + const SizeT d = self->ptrObj->range()->dim(); + std::vector dims(d); + /* + Py_INCREF(self); // keep data alive + PyObject* o = PyArray_SimpleNewFromData + ( static_cast( d ) , dims.data(), self->ptrObj->typenum(), self->ptrObj->data() ); + PyArray_BASE(o) = (PyObject*) self; + */ + PyObject* o = PyArray_SimpleNew + ( static_cast( d ) , dims.data(), self->ptrObj->typenum() ); + void* data = PyArray_DATA(o); + const npy_intp s = PyArray_NBYTES(o); + if(s != self->ptrObj->datasize()) { + PyErr_SetString(PyExc_RuntimeError, "lib error"); + } + memcpy( data, self->ptrObj->data(), self->ptrObj->datasize() ); + return o; } PyMethodDef PyCArrayB_methods[] = { - { "size", (PyCFunction) PyCArrayB_size, METH_VARARGS, "return size of the array" }, - { NULL } + { "size", (PyCFunction) PyCArrayB_size, METH_VARARGS| METH_KEYWORDS, "return size of the array" }, + { "range", (PyCFunction) PyCArrayB_range, METH_VARARGS| METH_KEYWORDS, "return array range" }, + { "writeFile", (PyCFunction) PyCArrayB_writeFile, METH_VARARGS| METH_KEYWORDS, "write array to file" }, + { "readFile", (PyCFunction) PyCArrayB_readFile, METH_VARARGS| METH_KEYWORDS, "read array from file" }, + { "npa", (PyCFunction) PyCArrayB_npa, METH_VARARGS| METH_KEYWORDS, "return numpy array (view)" }, + { NULL, NULL, 0, NULL } }; PyTypeObject PyCArrayBType = { PyVarObject_HEAD_INIT(NULL,0) "cnorxz.CArray" }; diff --git a/cnorxz/core/lib/range_wrapper.cpp b/cnorxz/core/lib/range_wrapper.cpp index 184a886..38626a0 100644 --- a/cnorxz/core/lib/range_wrapper.cpp +++ b/cnorxz/core/lib/range_wrapper.cpp @@ -59,6 +59,8 @@ PyTypeObject* PyCRangeType_init() PyCRangeType.tp_methods = PyCRange_methods; PyCRangeType.tp_init = (initproc) PyCRange_init; + import_array(); + if(PyType_Ready(&PyCRangeType) < 0){ return NULL; } diff --git a/setup.py b/setup.py index 726b3ab..48b3b9f 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -import Cython.Build -#import setuptools +#import numpy +import setuptools from distutils.core import setup, Extension import sysconfig import subprocess @@ -27,6 +27,8 @@ inc_dirs = list() if path_to_cnorxz != "": inc_dirs.append( path_to_cnorxz + "/include/cnorxz" ) inc_dirs.append( "cnorxz/core/include" ) +#inc_dirs.append( numpy.get_include() ) +inc_dirs.append( "/home/chizeta/my_env/lib/python3.11/site-packages/numpy/core/include" ) lib_dirs = list() lib_dirs.append( "/usr/lib" ) @@ -37,6 +39,7 @@ lib_dirs.append( "/home/chizeta/repos/cnorxz/install/lib" ) extra_compile_args = sysconfig.get_config_var('CFLAGS').split() cnorxz_flags = subprocess.run([path_to_cnorxz+"/bin/cnorxz-config",'--flags'],stdout=subprocess.PIPE).stdout.decode('ascii').split() +cnorxz_flags.remove("-Werror") extra_compile_args += cnorxz_flags default_extension_args = dict(