| 36 | |
| 37 | template <class TDataType> |
| 38 | pybind11::array_t<TDataType> AllocateNumpyArray( |
| 39 | const std::size_t NumberOfEntities, |
| 40 | const std::vector<std::size_t>& rShape) |
| 41 | { |
| 42 | const std::size_t size = std::accumulate(rShape.begin(), |
| 43 | rShape.end(), |
| 44 | 1UL, |
| 45 | [](std::size_t left, std::size_t right) {return left * right;}); |
| 46 | |
| 47 | TDataType* array = new TDataType[size * NumberOfEntities]; |
| 48 | pybind11::capsule release(array, [](void* a) { |
| 49 | delete[] reinterpret_cast<TDataType*>(a); |
| 50 | }); |
| 51 | |
| 52 | // we allocate one additional dimension for the shape to hold the |
| 53 | // number of entities. So if the shape within kratos is [2, 3] with 70 entities, |
| 54 | // then the final shape of the numpy array will be [70,2,3] so it can keep the |
| 55 | // existing shape preserved for each entitiy. |
| 56 | std::vector<std::size_t> c_shape(rShape.size() + 1); |
| 57 | c_shape[0] = NumberOfEntities; |
| 58 | std::copy(rShape.begin(), rShape.end(), c_shape.begin() + 1); |
| 59 | |
| 60 | // we have to allocate number of bytes to be skipped to reach next element |
| 61 | // in each dimension. So this is calculated backwards. |
| 62 | std::vector<std::size_t> strides(c_shape.size()); |
| 63 | std::size_t stride_items = 1; |
| 64 | for (int i = c_shape.size() - 1; i >= 0; --i) { |
| 65 | strides[i] = sizeof(TDataType) * stride_items; |
| 66 | stride_items *= c_shape[i]; |
| 67 | } |
| 68 | |
| 69 | return ContiguousNumpyArray<TDataType>( |
| 70 | c_shape, |
| 71 | strides, |
| 72 | array, |
| 73 | release |
| 74 | ); |
| 75 | } |
| 76 | |
| 77 | template <class TDataType> |
| 78 | pybind11::array_t<TDataType> MakeNumpyArray( |