Skip to content

Commit fcd4d6c

Browse files
committed
Simplify: from_numpy in C++
No need to wrap extra.
1 parent bc8924f commit fcd4d6c

2 files changed

Lines changed: 39 additions & 62 deletions

File tree

src/Base/PODVector.cpp

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -117,33 +117,30 @@ namespace
117117
podvector[index] = value;
118118
}
119119

120-
/** Bulk-copy a host (NumPy) array into an existing PODVector.
120+
/** Create a new PODVector with a copy of a host (NumPy) array.
121121
*
122-
* The source array is normalized on the host by pybind11
123-
* (``c_style | forcecast``): a non-contiguous or differently-typed
124-
* input is staged into a contiguous, ``T``-typed temporary before the
125-
* copy. The destination is filled with a single contiguous transfer:
126-
* a host copy for host-accessible allocators, or
122+
* Always copies: a ``PODVector`` owns its memory through its allocator,
123+
* so a zero-copy view is not possible. The source array is normalized on
124+
* the host by pybind11 (``c_style | forcecast``): a non-contiguous or
125+
* differently-typed input is staged into a contiguous, ``T``-typed
126+
* temporary before the copy. The destination is filled with a single
127+
* contiguous transfer: a host copy for host-accessible allocators, or
127128
* ``Gpu::copyAsync(hostToDevice, ...)`` for device memory. This keeps
128129
* the host-to-device path free of any CuPy dependency.
129130
*/
130131
template <class T, class Allocator>
131-
void
132-
copy_from_host(
133-
PODVector<T, Allocator> & podvector,
134-
py::array_t<T, py::array::c_style | py::array::forcecast> const & arr
135-
)
132+
PODVector<T, Allocator>
133+
from_numpy(py::array_t<T, py::array::c_style | py::array::forcecast> const & arr)
136134
{
137135
auto const buf = arr.request();
138136
if (buf.ndim != 1) {
139-
throw py::value_error("copy_from_host: expected a 1-D array");
140-
}
141-
if (static_cast<std::size_t>(buf.shape[0]) != podvector.size()) {
142-
throw py::value_error(
143-
"copy_from_host: array size does not match PODVector size");
137+
throw py::value_error("from_numpy: expected a 1-D array");
144138
}
145-
if (podvector.empty()) {
146-
return;
139+
auto const n = static_cast<std::size_t>(buf.shape[0]);
140+
141+
PODVector<T, Allocator> podvector(n);
142+
if (n == 0) {
143+
return podvector;
147144
}
148145

149146
auto const * src = static_cast<T const *>(buf.ptr);
@@ -152,14 +149,15 @@ namespace
152149
Gpu::copyAsync(
153150
Gpu::hostToDevice,
154151
src,
155-
src + podvector.size(),
152+
src + n,
156153
podvector.begin()
157154
);
158155
Gpu::streamSynchronize();
159-
return;
156+
return podvector;
160157
}
161158
#endif
162-
std::copy(src, src + podvector.size(), podvector.begin());
159+
std::copy(src, src + n, podvector.begin());
160+
return podvector;
163161
}
164162
}
165163

@@ -271,13 +269,26 @@ void make_PODVector(py::module &m, std::string typestr, std::string allocstr)
271269
.def("__setitem__", &set_item<T, Allocator>)
272270
.def("__getitem__", &get_item<T, Allocator>)
273271

274-
// bulk copy from a host (NumPy) array into this vector
275-
.def("copy_from_host", &copy_from_host<T, Allocator>,
272+
// create a new vector with a copy of a host (NumPy) array
273+
.def_static("from_numpy", &from_numpy<T, Allocator>,
276274
py::arg("arr"),
277-
"Copy a 1-D host (NumPy) array into this vector.\n\n"
278-
"The input is cast to the vector's element type and made "
279-
"contiguous as needed. Device memory is filled via an AMReX "
280-
"host-to-device copy.")
275+
py::return_value_policy::move,
276+
R"(Create a new PODVector from a NumPy array (or array-like).
277+
278+
Always copies the data into a newly allocated PODVector. The input is cast to
279+
the vector's element type and made contiguous as needed. The copy into
280+
device-only memory uses an AMReX host-to-device copy and does not require CuPy.
281+
282+
Parameters
283+
----------
284+
arr : array_like
285+
Input data, convertible to a NumPy array.
286+
287+
Returns
288+
-------
289+
PODVector
290+
A new PODVector with a copy of the data.
291+
)")
281292
;
282293
}
283294

src/amrex/extensions/PODVector.py

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -126,40 +126,6 @@ def _is_host_accessible(cls):
126126
return arenas[suffix]().is_host_accessible
127127

128128

129-
def podvector_from_numpy(cls, arr):
130-
"""
131-
Create a new PODVector from a NumPy array (or array-like).
132-
133-
Always copies the data into a newly allocated PODVector. The input is
134-
cast to the vector's element type and made contiguous as needed. The
135-
copy into device-only memory uses an AMReX host-to-device copy and does
136-
not require CuPy.
137-
138-
Parameters
139-
----------
140-
cls : type
141-
The PODVector type to construct.
142-
arr : array_like
143-
Input data, convertible to a NumPy array.
144-
145-
Returns
146-
-------
147-
PODVector
148-
A new PODVector with a copy of the data.
149-
150-
"""
151-
import numpy as np
152-
153-
arr_np = np.asarray(arr)
154-
n = len(arr_np)
155-
if n == 0:
156-
return cls()
157-
158-
pv = cls(n)
159-
pv.copy_from_host(arr_np)
160-
return pv
161-
162-
163129
def podvector_from_cupy(cls, arr):
164130
"""
165131
Create a new PODVector from a CuPy array (or array-like).
@@ -246,6 +212,6 @@ def register_PODVector_extension(amr):
246212
POD_type.to_xp = podvector_to_xp
247213

248214
# class methods: array -> PODVector
249-
POD_type.from_numpy = classmethod(podvector_from_numpy)
215+
# (from_numpy is provided in C++ as a static method)
250216
POD_type.from_cupy = classmethod(podvector_from_cupy)
251217
POD_type.from_xp = classmethod(podvector_from_xp)

0 commit comments

Comments
 (0)