From a3a5ec52a9add7fcebe6a0f35fff30f647071943 Mon Sep 17 00:00:00 2001 From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de> Date: Thu, 21 Sep 2023 17:07:40 +0200 Subject: [PATCH] + Datafield::npErrors --- Device/Data/Datafield.cpp | 105 +++++++++++++++----------- Device/Data/Datafield.h | 1 + auto/Wrap/libBornAgainDevice.py | 4 + auto/Wrap/libBornAgainDevice_wrap.cpp | 34 +++++++++ 4 files changed, 101 insertions(+), 43 deletions(-) diff --git a/Device/Data/Datafield.cpp b/Device/Data/Datafield.cpp index da0c4953557..13842cb118b 100644 --- a/Device/Data/Datafield.cpp +++ b/Device/Data/Datafield.cpp @@ -19,6 +19,63 @@ #include "Base/Util/Assert.h" #include <algorithm> +#ifdef BORNAGAIN_PYTHON + +#include "PyCore/Embed/PyInterpreter.h" // Numpy::arrayND, Numpy::getDataPtr + +namespace { + +PyObject* npExport(const Frame& frame, const std::vector<double>& flatData) +{ + if (flatData.empty()) + return nullptr; + + // TODO: Thoroughly check this function regarding index manipulations + + PyInterpreter::Numpy::initialize(); + + ASSERT(frame.rank() <= 2); + + std::vector<size_t> dimensions; + for (size_t i = 0; i < frame.rank(); i++) + dimensions.push_back(frame.axis(i).size()); + // for rot90 of 2-dim arrays to conform with numpy + if (dimensions.size() == 2) + std::swap(dimensions[0], dimensions[1]); + + // creating ndarray objects describing size of dimensions + PyObjectPtr pyarray{PyInterpreter::Numpy::arrayND(dimensions)}; + ASSERT(pyarray.valid()); + + // get the pointer to the data buffer of the array (assumed to be C-contiguous) + double* data{PyInterpreter::Numpy::getDataPtr(pyarray.get())}; + ASSERT(data); + + double* array_buffer = data; + + // filling numpy array with output_data + if (frame.rank() == 2) { + for (size_t i = 0; i < frame.size(); ++i) { + std::vector<int> axes_indices = frame.allIndices(i); + size_t offset = axes_indices[0] + + frame.axis(0).size() * (frame.axis(1).size() - 1 - axes_indices[1]); + array_buffer[offset] = flatData[i]; + } + } else if (frame.rank() == 1) { + for (size_t i = 0; i < frame.size(); ++i) + *array_buffer++ = flatData[i]; + } else + ASSERT_NEVER; + + // returns a _new_ reference; ie. caller is responsible for the ref-count + return pyarray.release(); +} + +} // namespace + +#endif // BORNAGAIN_PYTHON + + Datafield::Datafield(std::string title, const Frame* frame, std::vector<double> values, std::vector<double> errSigmas) : m_title(std::move(title)) @@ -224,52 +281,14 @@ Datafield* Datafield::crop(double xmin, double xmax) const #ifdef BORNAGAIN_PYTHON -#include "PyCore/Embed/PyInterpreter.h" // Numpy::arrayND, Numpy::getDataPtr - PyObject* Datafield::npArray() const { - // TODO: Thoroughly check this function regarding index manipulations - - PyInterpreter::Numpy::initialize(); - - ASSERT(rank() <= 2); - - std::vector<size_t> dimensions; - for (size_t i = 0; i < rank(); i++) - dimensions.push_back(axis(i).size()); - - // for rot90 of 2-dim arrays to conform with numpy - if (dimensions.size() == 2) - std::swap(dimensions[0], dimensions[1]); - - // creating ndarray objects describing size of dimensions - PyObjectPtr pyarray{PyInterpreter::Numpy::arrayND(dimensions)}; - if (!pyarray.valid()) - return nullptr; - - // get the pointer to the data buffer of the array (assumed to be C-contiguous) - double* data{PyInterpreter::Numpy::getDataPtr(pyarray.get())}; - - if (!data) - return nullptr; - - double* array_buffer = data; - - // filling numpy array with output_data - if (rank() == 2) { - for (size_t i = 0; i < size(); ++i) { - std::vector<int> axes_indices = frame().allIndices(i); - size_t offset = - axes_indices[0] + axis(0).size() * (axis(1).size() - 1 - axes_indices[1]); - array_buffer[offset] = (*this)[i]; - } - } else if (rank() == 1) { - for (size_t i = 0; i < size(); ++i) - *array_buffer++ = (*this)[i]; - } + return ::npExport(frame(), flatVector()); +} - // returns a _new_ reference; ie. caller is responsible for the ref-count - return pyarray.release(); +PyObject* Datafield::npErrors() const +{ + return ::npExport(frame(), errorSigmas()); } #endif // BORNAGAIN_PYTHON diff --git a/Device/Data/Datafield.h b/Device/Data/Datafield.h index b835382576d..739d2a2b892 100644 --- a/Device/Data/Datafield.h +++ b/Device/Data/Datafield.h @@ -65,6 +65,7 @@ public: #ifdef BORNAGAIN_PYTHON //! Returns data as Python numpy array. PyObject* npArray() const; + PyObject* npErrors() const; #endif //... retrieve basic info diff --git a/auto/Wrap/libBornAgainDevice.py b/auto/Wrap/libBornAgainDevice.py index 81641c33be0..fcd2b4c12bd 100644 --- a/auto/Wrap/libBornAgainDevice.py +++ b/auto/Wrap/libBornAgainDevice.py @@ -2093,6 +2093,10 @@ class Datafield(object): r"""npArray(Datafield self) -> PyObject *""" return _libBornAgainDevice.Datafield_npArray(self) + def npErrors(self): + r"""npErrors(Datafield self) -> PyObject *""" + return _libBornAgainDevice.Datafield_npErrors(self) + def frame(self): r"""frame(Datafield self) -> Frame""" return _libBornAgainDevice.Datafield_frame(self) diff --git a/auto/Wrap/libBornAgainDevice_wrap.cpp b/auto/Wrap/libBornAgainDevice_wrap.cpp index a2b67fac7c3..e8cd0ec2047 100644 --- a/auto/Wrap/libBornAgainDevice_wrap.cpp +++ b/auto/Wrap/libBornAgainDevice_wrap.cpp @@ -29712,6 +29712,39 @@ fail: } +SWIGINTERN PyObject *_wrap_Datafield_npErrors(PyObject *self, PyObject *args) { + PyObject *resultobj = 0; + Datafield *arg1 = (Datafield *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject *swig_obj[1] ; + PyObject *result = 0 ; + + if (!args) SWIG_fail; + swig_obj[0] = args; + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Datafield, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Datafield_npErrors" "', argument " "1"" of type '" "Datafield const *""'"); + } + arg1 = reinterpret_cast< Datafield * >(argp1); + { + try { + result = (PyObject *)((Datafield const *)arg1)->npErrors(); + } catch (const std::exception& ex) { + // message shown in the Python interpreter + const std::string msg { + "BornAgain C++ Exception: " + std::string(ex.what()) + }; + SWIG_exception(SWIG_RuntimeError, msg.c_str()); + } + } + resultobj = result; + return resultobj; +fail: + return NULL; +} + + SWIGINTERN PyObject *_wrap_Datafield_frame(PyObject *self, PyObject *args) { PyObject *resultobj = 0; Datafield *arg1 = (Datafield *) 0 ; @@ -40895,6 +40928,7 @@ static PyMethodDef SwigMethods[] = { { "Datafield_setAt", _wrap_Datafield_setAt, METH_VARARGS, "Datafield_setAt(Datafield self, size_t i, double val)"}, { "Datafield_valAt", _wrap_Datafield_valAt, METH_VARARGS, "Datafield_valAt(Datafield self, size_t i) -> double"}, { "Datafield_npArray", _wrap_Datafield_npArray, METH_O, "Datafield_npArray(Datafield self) -> PyObject *"}, + { "Datafield_npErrors", _wrap_Datafield_npErrors, METH_O, "Datafield_npErrors(Datafield self) -> PyObject *"}, { "Datafield_frame", _wrap_Datafield_frame, METH_O, "Datafield_frame(Datafield self) -> Frame"}, { "Datafield_rank", _wrap_Datafield_rank, METH_O, "Datafield_rank(Datafield self) -> size_t"}, { "Datafield_axis", _wrap_Datafield_axis, METH_VARARGS, "Datafield_axis(Datafield self, size_t k) -> Scale"}, -- GitLab