| 177 | |
| 178 | template<class TDataType> |
| 179 | pybind11::array_t<TDataType, pybind11::array::c_style> GetPybindArray(NDData<TDataType>& rDDArray) |
| 180 | { |
| 181 | const auto& r_shape = rDDArray.Shape(); |
| 182 | |
| 183 | std::vector<std::size_t> c_shape(r_shape.size()); |
| 184 | std::copy(r_shape.begin(), r_shape.end(), c_shape.begin()); |
| 185 | std::vector<std::size_t> strides(c_shape.size()); |
| 186 | |
| 187 | std::size_t stride_items = 1; |
| 188 | for (int i = c_shape.size() - 1; i >= 0; --i) { |
| 189 | strides[i] = sizeof(TDataType) * stride_items; |
| 190 | stride_items *= c_shape[i]; |
| 191 | } |
| 192 | |
| 193 | // here we create a raw pointer to the underlying PointerWrapper used in the |
| 194 | // @p rDDArray. This is done to create an on the fly intrusive_ptr from the |
| 195 | // raw pointer when creating the capsule, so the PointerWrapper will be kept alive |
| 196 | // until the capsule releases the memory. This guarantees that, even if the @p rDDArray |
| 197 | // is killed, the numpy array will be able to function without a problem. |
| 198 | auto p_raw_data = &*rDDArray.pData(); |
| 199 | |
| 200 | pybind11::capsule release(new Kratos::intrusive_ptr<typename NDData<TDataType>::PointerWrapper>(p_raw_data), [](void* a){ |
| 201 | delete static_cast<Kratos::intrusive_ptr<typename NDData<TDataType>::PointerWrapper>*>(a); |
| 202 | }); |
| 203 | |
| 204 | return pybind11::array_t<TDataType, pybind11::array::c_style>(pybind11::buffer_info( |
| 205 | p_raw_data->Data(), // Pointer to data |
| 206 | sizeof(TDataType), // Size of one item |
| 207 | pybind11::format_descriptor<TDataType>::format(), // Python format descriptor |
| 208 | c_shape.size(), // Number of dimensions |
| 209 | c_shape, // Shape of the array |
| 210 | strides // Strides |
| 211 | ), release); |
| 212 | } |
| 213 | |
| 214 | } // namespace Kratos::Python |