29#include <pybind11/cast.h>
30#include <pybind11/complex.h>
43 [](
u32 n,
const T *rhs, T *lhs) {
56 [](
u32 n,
const T *rhs, T *lhs) {
61 lhs[n] = std::numeric_limits<f64>::quiet_NaN();
70 auto &m = root_module;
72 py::enum_<shammodels::NeighCacheStrategy>(
76 Strategy used to build the neighbours cache out of the tree traversal.
80 >>> from shamrock import NeighCacheStrategy
81 >>> cfg.set_neigh_cache_strategy(NeighCacheStrategy.SingleStage)
87 Single tree traversal per particle.
89 Each particle walks the tree itself and writes its neighbours straight to the
90 cache. Prefer this one when the tree ends up with giant leaves, as on a chaotic
91 disc: there the leaf bounding boxes grow so large that the two stage search makes
92 each particle scan far more candidates than it keeps.
98 Two stage neighbours search (see the shamrock paper). This is the default.
100 A first pass walks the tree once per leaf to build a leaf to leaf neighbour map,
101 then each particle only scans the particles held by its own leaf's neighbour
102 leaves. This is usually the faster of the two, since the tree traversal is paid
103 once per leaf instead of once per particle.
108 [](std::vector<f64> bin_edges,
111 bool do_average) -> std::vector<f64> {
112 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
114 u32 nx = bin_edges.size() - 1;
115 std::vector<f64> bin_edge_inf(nx);
116 std::vector<f64> bin_edge_sup(nx);
118 for (
size_t i = 0; i < nx; i++) {
119 bin_edge_inf[i] = bin_edges[i];
120 bin_edge_sup[i] = bin_edges[i + 1];
128 bin_inf.copy_from_stdvec(bin_edge_inf);
129 bin_sup.copy_from_stdvec(bin_edge_sup);
133 obj_cnts.
for_each([&](
u64 id_patch,
const unsigned int &obj_cnt) {
134 ret += shamalgs::primitives::compute_histogram<f64>(
139 [](
const f64 &bin_edge_inf,
140 const f64 &bin_edge_sup,
144 has_value = x_val >= bin_edge_inf && x_val < bin_edge_sup;
145 return has_value ? y_val : 0;
147 x_field.get_buf(id_patch),
148 y_field.get_buf(id_patch));
151 shamalgs::collective::reduce_buffer_in_place_sum(ret, MPI_COMM_WORLD);
158 obj_cnts.
for_each([&](
u64 id_patch,
const unsigned int &obj_cnt) {
162 norm += shamalgs::primitives::compute_histogram<f64>(
167 [](
const f64 &bin_edge_inf,
168 const f64 &bin_edge_sup,
172 has_value = x_val >= bin_edge_inf && x_val < bin_edge_sup;
173 return has_value ? y_val : 0;
175 x_field.get_buf(id_patch),
179 shamalgs::collective::reduce_buffer_in_place_sum(norm, MPI_COMM_WORLD);
184 return ret.copy_to_stdvec();
187 py::arg(
"bin_edges"),
190 py::arg(
"do_average") =
false);
193 "compute_histogram_convolve_x",
194 [](std::vector<f64> bin_edges,
198 bool do_average) -> std::vector<f64> {
199 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
201 u32 nx = bin_edges.size() - 1;
202 std::vector<f64> bin_edge_inf(nx);
203 std::vector<f64> bin_edge_sup(nx);
205 for (
size_t i = 0; i < nx; i++) {
206 bin_edge_inf[i] = bin_edges[i];
207 bin_edge_sup[i] = bin_edges[i + 1];
215 bin_inf.copy_from_stdvec(bin_edge_inf);
216 bin_sup.copy_from_stdvec(bin_edge_sup);
220 obj_cnts.
for_each([&](
u64 id_patch,
const unsigned int &obj_cnt) {
221 ret += shamalgs::primitives::compute_histogram<f64>(
226 [](
const f64 &bin_edge_inf,
227 const f64 &bin_edge_sup,
233 = x_val >= bin_edge_inf - size_val && x_val < bin_edge_sup + size_val;
234 return has_value ? y_val : 0;
236 x_field.get_buf(id_patch),
237 y_field.get_buf(id_patch),
238 size_field.get_buf(id_patch));
241 shamalgs::collective::reduce_buffer_in_place_sum(ret, MPI_COMM_WORLD);
248 obj_cnts.
for_each([&](
u64 id_patch,
const unsigned int &obj_cnt) {
252 norm += shamalgs::primitives::compute_histogram<f64>(
257 [](
const f64 &bin_edge_inf,
258 const f64 &bin_edge_sup,
263 has_value = x_val >= bin_edge_inf - size_val
264 && x_val < bin_edge_sup + size_val;
265 return has_value ? y_val : 0;
267 x_field.get_buf(id_patch),
269 size_field.get_buf(id_patch));
272 shamalgs::collective::reduce_buffer_in_place_sum(norm, MPI_COMM_WORLD);
277 return ret.copy_to_stdvec();
280 py::arg(
"bin_edges"),
283 py::arg(
"size_field"),
284 py::arg(
"do_average") =
false);
287 "compute_histogram_2d",
288 [](std::vector<f64> bin_edges_x,
289 std::vector<f64> bin_edges_y,
292 auto dev_sched = shamsys::instance::get_compute_scheduler_ptr();
294 u32 nx = bin_edges_x.size() - 1;
295 u32 ny = bin_edges_y.size() - 1;
304 binsx.copy_from_stdvec(bin_edges_x);
305 binsy.copy_from_stdvec(bin_edges_y);
307 obj_cnts.
for_each([&](
u64 id_patch,
const unsigned int &obj_cnt) {
309 dev_sched->get_queue(),
311 binsx, binsy, x_field.get_buf(id_patch), y_field.get_buf(id_patch)},
316 const f64 *__restrict x_bins,
317 const f64 *__restrict y_bins,
318 const f64 *__restrict x_field,
319 const f64 *__restrict y_field,
320 u64 *__restrict pic) {
321 auto get_pic_coord = [&](u32 ix, u32 iy) {
325 f64 x_val = x_field[
id];
326 f64 y_val = y_field[
id];
328 bool is_in_x_range = x_bins[0] <= x_val && x_val <= x_bins[nx];
329 bool is_in_y_range = y_bins[0] <= y_val && y_val <= y_bins[ny];
331 if (!(is_in_x_range && is_in_y_range)) {
336 x_bins, 0, nx + 1, x_val);
338 y_bins, 0, ny + 1, y_val);
340 if (ix >= nx || iy >= ny) {
344 using atomic_ref_T = sycl::atomic_ref<
346 sycl::memory_order_relaxed,
347 sycl::memory_scope_device,
348 sycl::access::address_space::global_space>;
350 atomic_ref_T pic_ref(pic[get_pic_coord(ix, iy)]);
355 shamalgs::collective::reduce_buffer_in_place_sum(ret, MPI_COMM_WORLD);
357 return ret.copy_to_stdvec();
360 py::arg(
"bin_edges_x"),
361 py::arg(
"bin_edges_y"),
Header file describing a Node Instance.
double f64
Alias for double.
std::uint32_t u32
32 bit unsigned integer
std::uint64_t u64
64 bit unsigned integer
A buffer allocated in USM (Unified Shared Memory).
Represents a collection of objects distributed across patches identified by a u64 id.
void for_each(std::function< void(u64, T &)> &&f)
Applies a function to each object in the collection.
Neighbour cache build strategy enum + json serialization/deserialization.
namespace for backends this one is named only sham since shambackends is too long to write
void kernel_call(sham::DeviceQueue &q, RefIn in, RefOut in_out, u32 n, Functor &&func, SourceLocation &&callsite=SourceLocation{})
Submit a kernel to a SYCL queue.
constexpr u32 binary_search_upper_bound(const Tkey *__restrict__ key, u32 first, u32 last, const Tkey &value)
GPU compatible implementation of std::upper_bound.
@ SingleStage
Single tree traversal per particle.
@ TwoStage
Two stage neighbours search (see shamrock paper).
Pybind11 include and definitions.
#define ON_PYTHON_INIT
Register a Python module init function using static initialization.
A class that references multiple buffers or similar objects.
GPU compatible implementation of std::upper_bound.