23#ifndef PECLET_CORE_PYTHON_NDARRAY_INTEROP_HPP
24#define PECLET_CORE_PYTHON_NDARRAY_INTEROP_HPP
26#include <nanobind/nanobind.h>
27#include <nanobind/ndarray.h>
31#include <Kokkos_Core.hpp>
46template <
class MemorySpace>
48 Kokkos::SpaceAccessibility<Kokkos::HostSpace, MemorySpace>::accessible;
52template <
class MemorySpace>
55 return {nb::device::cpu::value, 0};
57#if defined(KOKKOS_ENABLE_HIP)
58 return {nb::device::rocm::value, Kokkos::device_id()};
60 return {nb::device::cuda::value, Kokkos::device_id()};
68 if (a.dtype() != nb::dtype<T>())
69 throw std::runtime_error(std::string(
who) +
": array dtype does not match the expected scalar");
88template <
class V, std::
size_t N>
90 const std::array<std::int64_t, N>&
strides) {
91 using T = std::remove_const_t<typename V::value_type>;
92 using Mem =
typename V::memory_space;
95 nb::capsule owner(
held, [](
void* p)
noexcept {
delete static_cast<ViewCapsule<V>*
>(p); });
97 auto* data =
const_cast<T*
>(view.data());
99 return nb::ndarray<nb::numpy, T>(data,
N, shape.data(), owner,
strides.data(), nb::dtype<T>(),
100 nb::device::cpu::value, 0);
103 return nb::ndarray<T>(data,
N, shape.data(), owner,
strides.data(), nb::dtype<T>(),
dev,
id);
113 constexpr std::size_t
N = V::rank;
114 std::array<std::size_t, N> shape;
115 std::array<std::int64_t, N>
strides;
116 for (std::size_t
i = 0;
i <
N; ++
i) {
117 shape[
i] = view.extent(
i);
118 strides[
i] =
static_cast<std::int64_t
>(view.stride(
i));
129 std::initializer_list<std::size_t> shape,
130 std::initializer_list<std::int64_t>
strides) {
131 auto*
held =
new std::vector<T>(std::move(v));
132 nb::capsule owner(
held, [](
void* p)
noexcept {
delete static_cast<std::vector<T>*
>(p); });
133 return nb::ndarray<nb::numpy, T>(
held->data(), shape, owner,
strides, nb::dtype<T>(),
134 nb::device::cpu::value, 0);
147 const std::size_t n = a.size();
149 const int dev = a.device_type();
150 if (
dev == nb::device::cpu::value) {
151 Kokkos::View<const T*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
hv(
152 static_cast<const T*
>(a.data()), n);
153 Kokkos::deep_copy(
d,
hv);
156 throw std::runtime_error(
157 "ndarray_to_view: array is on an incompatible device for this build");
158 Kokkos::View<const T*, peclet::core::MemSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
dv(
159 static_cast<const T*
>(a.data()), n);
160 Kokkos::deep_copy(
d,
dv);
162 throw std::runtime_error(
"ndarray_to_view: array is on an incompatible device for this build");
174 const std::size_t n = a.size();
175 std::vector<T>
out(n);
176 const int dev = a.device_type();
177 if (
dev == nb::device::cpu::value) {
179 std::memcpy(
out.data(), a.data(), n *
sizeof(
T));
182 throw std::runtime_error(
183 "ndarray_to_vector: array is on an incompatible device for this build");
184 Kokkos::View<const T*, peclet::core::MemSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
dv(
185 static_cast<const T*
>(a.data()), n);
186 Kokkos::View<T*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
hv(
out.data(), n);
187 Kokkos::deep_copy(
hv,
dv);
189 throw std::runtime_error(
190 "ndarray_to_vector: array is on an incompatible device for this build");
Base of everything on the binding side that owns Kokkos Views on Python's behalf.
nb::ndarray< nb::numpy, T > vector_to_ndarray(std::vector< T > &&v, std::initializer_list< std::size_t > shape, std::initializer_list< std::int64_t > strides)
Export a host std::vector<T> as a NumPy array of the given logical shape and element-unit strides,...
peclet::core::View< T > ndarray_to_view(const nb::ndarray<> &a, const std::string &label)
Import a (contiguous) Python array into a freshly-allocated flat device peclet::core::View<T>.
std::vector< T > ndarray_to_vector(const nb::ndarray<> &a)
Import a (contiguous) Python array into a host std::vector<T>.
void require_dtype(const nb::ndarray<> &a, const char *who)
Throw if a's element type is not T.
auto view_to_ndarray(const V &view, const std::array< std::size_t, N > &shape, const std::array< std::int64_t, N > &strides)
Export a Kokkos View to a Python array without copying, with an explicit logical shape and element-un...
constexpr bool is_host_space_v
True when MemorySpace is reachable from the host (NumPy export path); false for a device-resident spa...
std::pair< int, int > dlpack_device()
Map a Kokkos memory space to a DLPack {device_type, device_id} pair.
Kokkos::View< T *, MemSpace > View
1D device array.
The payload of a zero-copy capsule: a reference to the exported View, registered as a Releasable so t...
void release() noexcept override