diff --git a/src/Types/Array.h b/src/Types/Array.h index 8da11cccd08f9475470b7889e21a8a3a11118332..5e0a377906fb61888ca1217051107082f69ab6ce 100644 --- a/src/Types/Array.h +++ b/src/Types/Array.h @@ -333,6 +333,8 @@ struct Array { } #endif HOST DEVICE size_t size() const { return num; } + + HOST T* get_pointer() const { return values; } private: HOST void host_allocate() { diff --git a/src/pybindings/pytypes.cpp b/src/pybindings/pytypes.cpp index 01ddd8995fa5bf5ba52643c0e125ebbaca026dc8..924826a552fe4819b366af5ac610e541fe1ac937 100644 --- a/src/pybindings/pytypes.cpp +++ b/src/pybindings/pytypes.cpp @@ -3,6 +3,8 @@ #include <pybind11/numpy.h> #include <pybind11/operators.h> +#include <iostream> + namespace py = pybind11; /// Convert a NumPy array to a Vector3_t object. @@ -27,13 +29,14 @@ Vector3_t<T> array_to_vector(py::array_t<T> a) { return Vector3_t<T>(ptr[0],ptr[1],ptr[2],ptr[3]); } -/// Convert a NumPy array to a Vector3_t object. + +/// Convert a NumPy array to an Array<Vector3_t> object. /// -/// This function converts a 1D NumPy array of size 3 or 4 into a Vector3_t object. +/// This function converts a 2D NumPy array of shape [N,M] with M in (3,4) into an Array<Vector3_t<T> object. /// /// \tparam T - The data type of the elements in the NumPy array. /// \param a - The NumPy array to convert. -/// \return A Array<Vector3_t<T>> object created from the array. +/// \return An Array<Vector3_t<T>> object created from the array. template<typename T> Array<Vector3_t<T>> array_to_vector_arr(py::array_t<T> a) { py::buffer_info info = a.request(); @@ -45,11 +48,13 @@ Array<Vector3_t<T>> array_to_vector_arr(py::array_t<T> a) { T *ptr = static_cast<T *>(info.ptr); Array<Vector3_t<T>> arr(static_cast<size_t>(info.shape[0])); - assert( info.strides[0] == info.shape[1] ); + // std::cerr << "Shape : " << info.shape[0] << " " << info.shape[1] << std::endl; + // std::cerr << "Stride : " << info.strides[0] << " " << info.strides[1] << std::endl; if (info.shape[1] == 3) { for (size_t i = 0; i < info.shape[0]; ++i) { - size_t j = i*info.strides[0]; + size_t j = i*info.shape[1]; arr[i] = (Vector3_t<T>( ptr[j], ptr[j+1], ptr[j+2] )); + // std::cerr << arr[i].to_string() << std::endl; } } else { for (size_t i = 0; i < info.shape[0]; ++i) { @@ -57,9 +62,81 @@ Array<Vector3_t<T>> array_to_vector_arr(py::array_t<T> a) { arr[i] = (Vector3_t<T>( ptr[j], ptr[j+1], ptr[j+2], ptr[j+3] )); } } + + // std::cerr << "Created Array<Vector3_t<T>> @" << &arr << + // " with data @" << arr.get_pointer() << std::endl; return arr; } +/// Convert am Array<Vector3_t> object to a NumPy array. +/// +/// This function converts an Array<Vector3_t<T> object into a 2D NumPy array of shape [N,M] with M in (3,4). +/// +/// \tparam T - The data type of the elements in the arrays. +/// \param a - The Array<Vector3_t<T>> object to convert. +/// \return A NumPy object created from the array. +template<typename T> +auto vector_arr_to_numpy_array(Array<Vector3_t<T>>& inp) { + // NOTE: this may not work on all architectures; reinterpret_cast is dangerous! + + // Create a Python object that will free the allocated + // memory when destroyed: + + T* ptr = reinterpret_cast<T*>(inp.get_pointer()); + + // unsigned char* cptr = reinterpret_cast<unsigned char*>(inp.get_pointer()); + // Vector3_t<T> tmp(1); + // assert( reinterpret_cast<unsigned char*>(&(tmp.x)) - reinterpret_cast<unsigned char*>(&(tmp)) == 0 ); + // cptr += reinterpret_cast<unsigned char*>(&(tmp.x)) - reinterpret_cast<unsigned char*>(&(tmp)); + // T* ptr = reinterpret_cast<T*>(cptr); + + // assert(&(inp[0]) != inp.get_pointer()); + // std::cerr << "addr: " << inp.get_pointer() << " (" << + // ptr << ")" << std::endl; + + py::capsule free_when_done(ptr, [](void *f) { + /* Don't do anything + T *ptr = reinterpret_cast<T *>(f); + std::cerr << "Element [0] = " << ptr[0] << "\n"; + std::cerr << "not freeing memory @ " << f << "\n"; + delete[] ptr; + */ + }); + + + // std::cerr << "Printing array" << std::endl; + // for (size_t i = 0; i < inp.size(); ++i) { + // std::cerr << inp[i].to_string() << std::endl; + // } + // std::cerr << " done printing" << std::endl; + + // std::cerr << "Printing raw data" << std::endl; + // for (size_t i = 0; i < inp.size(); ++i) { + // for (size_t j = i*4; j < 4*i+4; ++j) { + // std::cerr << ptr[j] << " "; + // } + // std::cerr << std::endl; + // } + // std::cerr << " done printing" << std::endl; + + // std::vector<size_t> shape; + // shape.push_back(inp.size()); + // shape.push_back(4); + py::array::ShapeContainer shape = {inp.size(), std::size_t{4}}; + py::array::StridesContainer strides = {sizeof(Vector3_t<T>), sizeof(T)}; + + // std::cerr << "sizeof(T) " << sizeof(T) << std::endl; + + assert( sizeof(Vector3_t<T>) == 4 * sizeof(T) ); + auto a = py::template array_t<T>( + shape, //shape + strides, // strides + ptr, // data pointer + free_when_done); // numpy array references this parent + return a; + +} + /// Declare Python bindings for Vector3_t<some_type> /// @@ -120,6 +197,7 @@ void declare_vector_array(py::module &m, const std::string &typestr) { // .def(-py::self) // Conversions + .def("as_array", [](Array<Vector3_t<T>>& a) { return vector_arr_to_numpy_array<T>(a); }) // .def("__repr__", &Class::to_string) ; }