21#ifndef PECLET_CORE_PYTHON_NDARRAY_INTEROP_HPP
22#define PECLET_CORE_PYTHON_NDARRAY_INTEROP_HPP
24#include <nanobind/nanobind.h>
25#include <nanobind/ndarray.h>
29#include <Kokkos_Core.hpp>
43template <
class MemorySpace>
45 Kokkos::SpaceAccessibility<Kokkos::HostSpace, MemorySpace>::accessible;
49template <
class MemorySpace>
52 return {nb::device::cpu::value, 0};
54#if defined(KOKKOS_ENABLE_HIP)
55 return {nb::device::rocm::value, Kokkos::device_id()};
57 return {nb::device::cuda::value, Kokkos::device_id()};
65 if (
a.dtype() != nb::dtype<T>())
66 throw std::runtime_error(std::string(
who) +
": array dtype does not match the expected scalar");
77 using T = std::remove_const_t<typename V::value_type>;
78 using Mem =
typename V::memory_space;
79 constexpr std::size_t
N = V::rank;
81 std::array<std::size_t, N> shape;
82 std::array<std::int64_t, N>
strides;
83 for (std::size_t
i = 0;
i <
N; ++
i) {
91 nb::capsule owner(
held, [](
void* p)
noexcept {
delete static_cast<V*
>(p); });
93 auto* data =
const_cast<T*
>(
view.data());
95 return nb::ndarray<nb::numpy, T>(data,
N, shape.data(), owner,
strides.data(), nb::dtype<T>(),
96 nb::device::cpu::value, 0);
99 return nb::ndarray<T>(data,
N, shape.data(), owner,
strides.data(), nb::dtype<T>(),
dev,
id);
109 std::initializer_list<std::size_t> shape,
110 std::initializer_list<std::int64_t>
strides) {
111 auto*
held =
new std::vector<T>(std::move(
v));
112 nb::capsule owner(
held, [](
void* p)
noexcept {
delete static_cast<std::vector<T>*
>(p); });
113 return nb::ndarray<nb::numpy, T>(
held->data(), shape, owner,
strides, nb::dtype<T>(),
114 nb::device::cpu::value, 0);
127 const std::size_t n =
a.size();
129 const int dev =
a.device_type();
130 if (
dev == nb::device::cpu::value) {
131 Kokkos::View<const T*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
hv(
132 static_cast<const T*
>(
a.data()), n);
133 Kokkos::deep_copy(d,
hv);
136 throw std::runtime_error(
137 "ndarray_to_view: array is on an incompatible device for this build");
138 Kokkos::View<const T*, peclet::core::MemSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
dv(
139 static_cast<const T*
>(
a.data()), n);
140 Kokkos::deep_copy(d,
dv);
142 throw std::runtime_error(
"ndarray_to_view: array is on an incompatible device for this build");
154 const std::size_t n =
a.size();
155 std::vector<T>
out(n);
156 const int dev =
a.device_type();
157 if (
dev == nb::device::cpu::value) {
159 std::memcpy(
out.data(),
a.data(), n *
sizeof(
T));
162 throw std::runtime_error(
163 "ndarray_to_vector: array is on an incompatible device for this build");
164 Kokkos::View<const T*, peclet::core::MemSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
dv(
165 static_cast<const T*
>(
a.data()), n);
166 Kokkos::View<T*, Kokkos::HostSpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>
hv(
out.data(), n);
167 Kokkos::deep_copy(
hv,
dv);
169 throw std::runtime_error(
170 "ndarray_to_vector: array is on an incompatible device for this build");
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>.
auto view_to_ndarray(const V &view)
Export a Kokkos View to a Python array without copying.
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.
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.