peclet-dem
Performance-portable XPBD Discrete Element Method (Kokkos + ArborX)
Loading...
Searching...
No Matches
dem_bindings.cpp
Go to the documentation of this file.
1
10#include <nanobind/nanobind.h>
11#include <nanobind/ndarray.h>
12#include <nanobind/stl/optional.h>
13#include <nanobind/stl/string.h>
14#include <nanobind/stl/tuple.h>
15#include <nanobind/stl/vector.h>
16
17#include <cstdint>
18#include <Kokkos_Core.hpp>
19#include <optional>
20#include <tuple>
21#include <vector>
22
23#ifdef PECLET_DEM_MPI
24#include <mpi.h>
25#endif
26
27#include "peclet/core/python/ndarray_interop.hpp"
28#include "sim.hpp"
29
30namespace nb = nanobind;
32
33// A contiguous numpy array -> flat C-order host vector (the bridge handles host copy / device
34// wrap).
35static std::vector<float> to_vec(nb::ndarray<float, nb::c_contig> a) {
36 return peclet::core::python::ndarray_to_vector<float>(nb::ndarray<>(a));
37}
38
39// A flat C-order vector -> (N,cols) numpy array, moved into the array's backing store (no extra
40// copy).
41static nb::ndarray<nb::numpy, float> rows(std::vector<float>&& v, int cols) {
42 const std::size_t n = v.size() / static_cast<std::size_t>(cols);
43 return peclet::core::python::vector_to_ndarray(std::move(v), {n, (std::size_t)cols},
44 {(std::int64_t)cols, 1});
45}
46static nb::ndarray<nb::numpy, float> flat(std::vector<float>&& v) {
47 const std::size_t n = v.size();
48 return peclet::core::python::vector_to_ndarray(std::move(v), {n}, {1});
49}
50
51NB_MODULE(_dem, m) {
52 m.attr("__doc__") = "DEM-GPU (Kokkos + ArborX): portable XPBD granular dynamics";
53
54 if (!Kokkos::is_initialized())
55 Kokkos::initialize();
56 // Teardown order matters on CUDA: releaseAll() drops every live Simulation's Views FIRST (so none
57 // outlive finalize -> no "deallocated after Kokkos::finalize"), THEN Kokkos::finalize() runs from
58 // a Python atexit hook while the CUDA driver is still up (so no cudaErrorCudartUnloading). Doing
59 // only one of the two aborts on CUDA. Returned arrays are backed by host std::vectors (no device
60 // Views).
61 auto shutdown = []() {
63 if (Kokkos::is_initialized() && !Kokkos::is_finalized())
64 Kokkos::finalize();
65 };
66 m.def("finalize", shutdown,
67 "Release all live Simulations and finalize Kokkos (deterministic teardown; also run at "
68 "exit).");
69 nb::module_::import_("atexit").attr("register")(nb::cpp_function(shutdown));
70 m.attr("execution_space") = nb::str(Kokkos::DefaultExecutionSpace::name());
71
72 nb::class_<Simulation>(m, "Simulation")
73 .def(nb::init<int>(), nb::arg("capacity"))
74 .def("set_sphere_shape", &Simulation::setSphereShape, nb::arg("radius"),
75 "Use a uniform sphere of the given radius for all particles.")
76 .def("initialize_shape", &Simulation::initializeShape, nb::arg("shape_type"),
77 nb::arg("radius"), nb::arg("height") = 0.0f, nb::arg("thickness") = 0.0f,
78 "Select the particle shape (sphere/cylinder/ring/...) and its dimensions.")
79 // CUDA-API alias: initialize(shape_type, radius, height, thickness).
80 .def("initialize", &Simulation::initializeShape, nb::arg("shape_type"),
81 nb::arg("radius") = 0.5f, nb::arg("height") = 2.0f, nb::arg("thickness") = 0.0f,
82 "CUDA-API alias for initialize_shape.")
83 // Import a general particle as a grid SDF + surface point shell (all particles share it).
84 // grid: flat [nx*ny*nz] signed-distance samples, x-fastest (idx = x + y*nx + z*nx*ny), at
85 // nodes origin + (x,y,z)*spacing (negative inside). shell: (M,3) surface points. inv_inertia:
86 // unit-mass principal-frame diagonal inverse inertia. bounding_radius: canonical enclosing
87 // radius. See peclet.dem.particle_builder for the SDF -> (grid, shell, inertia) helper.
88 .def(
89 "set_sdf_shape",
90 [](Simulation& s, nb::ndarray<float, nb::c_contig> grid, int nx, int ny, int nz,
91 std::tuple<float, float, float> origin, std::tuple<float, float, float> spacing,
92 nb::ndarray<float, nb::c_contig> shell, std::tuple<float, float, float> inv_inertia,
93 float bounding_radius) {
95 to_vec(grid), nx, ny, nz,
96 peclet::dem::F3{std::get<0>(origin), std::get<1>(origin), std::get<2>(origin)},
97 peclet::dem::F3{std::get<0>(spacing), std::get<1>(spacing), std::get<2>(spacing)},
98 to_vec(shell),
99 peclet::dem::F3{std::get<0>(inv_inertia), std::get<1>(inv_inertia),
100 std::get<2>(inv_inertia)},
101 bounding_radius);
102 },
103 nb::arg("grid"), nb::arg("nx"), nb::arg("ny"), nb::arg("nz"), nb::arg("origin"),
104 nb::arg("spacing"), nb::arg("shell"), nb::arg("inv_inertia"), nb::arg("bounding_radius"),
105 "Import a general particle: grid SDF (flat nx*ny*nz, x-fastest), surface point shell "
106 "(M,3), unit-mass principal diagonal inverse inertia, and canonical bounding radius.")
107 .def("set_domain", &Simulation::setDomain, nb::arg("lx"), nb::arg("ly"), nb::arg("lz"),
108 nb::arg("px") = true, nb::arg("py") = true, nb::arg("pz") = false,
109 "Set the box size (lx,ly,lz) and per-axis periodicity.")
110 // CUDA-API overload: set_domain(min, max) tuples (arbitrary origin); keeps current
111 // periodicity.
112 .def(
113 "set_domain",
114 [](Simulation& s, std::tuple<float, float, float> mn,
115 std::tuple<float, float, float> mx) {
116 s.setDomainMinMax(peclet::dem::F3{std::get<0>(mn), std::get<1>(mn), std::get<2>(mn)},
117 peclet::dem::F3{std::get<0>(mx), std::get<1>(mx), std::get<2>(mx)});
118 },
119 nb::arg("min"), nb::arg("max"),
120 "Set the domain by (min, max) corner tuples (arbitrary origin); keeps current "
121 "periodicity.")
122 .def("enable_periodicity", &Simulation::enablePeriodicity, nb::arg("x"), nb::arg("y"),
123 nb::arg("z"), "Enable periodic boundaries per axis (x, y, z).")
124 .def("get_domain_min", &Simulation::getDomainMin,
125 "Return the domain minimum corner (x, y, z).")
126 .def("get_domain_max", &Simulation::getDomainMax,
127 "Return the domain maximum corner (x, y, z).")
128 .def("set_gravity", &Simulation::setGravity,
129 "Set the gravitational acceleration vector (gx, gy, gz).")
130 .def("set_thermostat", &Simulation::setThermostat, nb::arg("temperature"), nb::arg("tau"),
131 nb::arg("kB") = 1.0f,
132 "Enable a Berendsen-style velocity thermostat (target temperature, coupling time tau).")
133 .def("set_solver_iterations", &Simulation::setSolverIterations, nb::arg("pos"),
134 nb::arg("vel"), "Set the XPBD position- and velocity-solve iteration counts.")
135 .def("set_global_scale", &Simulation::setGlobalScale,
136 "Set a global length scale applied to all particles.")
137 .def("set_dt", &Simulation::setDt, "Set the time step dt.")
138 .def("set_material_params", &Simulation::setMaterialParams, nb::arg("restitution_normal"),
139 nb::arg("restitution_tangent") = 0.0f, nb::arg("friction") = 0.0f,
140 "Set normal/tangential restitution and the Coulomb friction coefficient.")
141 .def("add_plane", &Simulation::addPlane, "Add a boundary wall plane (px,py,pz, nx,ny,nz).")
142 // CUDA-API overload: add_plane(point, normal) as 3-sequences.
143 .def(
144 "add_plane",
145 [](Simulation& s, std::tuple<float, float, float> p, std::tuple<float, float, float> n) {
146 s.addPlane(std::get<0>(p), std::get<1>(p), std::get<2>(p), std::get<0>(n),
147 std::get<1>(n), std::get<2>(n));
148 },
149 nb::arg("point"), nb::arg("normal"),
150 "Add a boundary wall plane from a point and a normal (3-sequences).")
151 // Static world-space SDF wall/container (drum barrel, hopper, vibrating tray). grid: flat
152 // [nx*ny*nz] signed distance, x-fastest (idx = x + y*nx + z*nx*ny), at world nodes
153 // origin+(x,y,z)*spacing — POSITIVE in the void where grains live, NEGATIVE in the solid wall.
154 // restitution/friction are the binary particle–wall material. Returns the wall index (for
155 // set_wall_velocity). See peclet.dem.build_wall_sdf for the SDF -> (grid, origin, spacing)
156 // helper.
157 .def(
158 "add_sdf_wall",
159 [](Simulation& s, nb::ndarray<float, nb::c_contig> grid, int nx, int ny, int nz,
160 std::tuple<float, float, float> origin, std::tuple<float, float, float> spacing,
161 float restitution, float friction) {
162 return s.addSdfWall(
163 to_vec(grid), nx, ny, nz,
164 peclet::dem::F3{std::get<0>(origin), std::get<1>(origin), std::get<2>(origin)},
165 peclet::dem::F3{std::get<0>(spacing), std::get<1>(spacing), std::get<2>(spacing)},
166 restitution, friction);
167 },
168 nb::arg("grid"), nb::arg("nx"), nb::arg("ny"), nb::arg("nz"), nb::arg("origin"),
169 nb::arg("spacing"), nb::arg("restitution") = 0.0f, nb::arg("friction") = 0.0f,
170 "Add a static world-space SDF wall/container: flat grid SDF (nx*ny*nz, x-fastest, positive "
171 "in the void), world origin/spacing, and the binary particle–wall restitution & friction. "
172 "Returns the wall index.")
173 // Rigid-body surface-velocity field of a wall: v(x) = linVel + angVel × (x − center). Rotating
174 // drum: set angVel about the axis point `center`. Vibrating wall: drive linVel each step.
175 .def(
176 "set_wall_velocity",
177 [](Simulation& s, int wall_index, std::tuple<float, float, float> lin,
178 std::tuple<float, float, float> ang, std::tuple<float, float, float> center) {
180 wall_index,
181 peclet::dem::F3{std::get<0>(lin), std::get<1>(lin), std::get<2>(lin)},
182 peclet::dem::F3{std::get<0>(ang), std::get<1>(ang), std::get<2>(ang)},
183 peclet::dem::F3{std::get<0>(center), std::get<1>(center), std::get<2>(center)});
184 },
185 nb::arg("wall_index"), nb::arg("lin_vel") = std::make_tuple(0.0f, 0.0f, 0.0f),
186 nb::arg("ang_vel") = std::make_tuple(0.0f, 0.0f, 0.0f),
187 nb::arg("center") = std::make_tuple(0.0f, 0.0f, 0.0f),
188 "Set a wall's rigid-body surface velocity v(x) = lin_vel + ang_vel × (x − center) (felt by "
189 "grains in contact even though the geometry is static). Cheap; call every step for a "
190 "vibrating wall.")
191 // Accepts (N,3) or (N,4) like CUDA set_positions; column 3 (if present) is inv_mass (w==0
192 // -> 1.0).
193 .def(
194 "set_positions",
195 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) {
196 if (a.ndim() == 2 && (a.shape(1) == 3 || a.shape(1) == 4)) {
197 const int n = (int)a.shape(0), k = (int)a.shape(1);
198 const float* p = static_cast<const float*>(a.data());
199 std::vector<float> xyz((size_t)n * 3), im;
200 const bool hasMass = (k == 4);
201 if (hasMass)
202 im.resize(n);
203 for (int i = 0; i < n; ++i) {
204 xyz[3 * i] = p[k * i];
205 xyz[3 * i + 1] = p[k * i + 1];
206 xyz[3 * i + 2] = p[k * i + 2];
207 if (hasMass) {
208 float w = p[k * i + 3];
209 im[i] = (w == 0.0f) ? 1.0f : w;
210 }
211 }
212 s.setPositions(xyz);
213 if (hasMass)
214 s.setInvMass(im);
215 } else {
216 s.setPositions(to_vec(a)); // flat [n*3] fallback
217 }
218 },
219 "Set particle positions from an (N,3) array, or (N,4) where column 3 is inverse mass.")
220 .def(
221 "set_velocities",
222 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setVelocities(to_vec(a)); },
223 "Set particle velocities from an (N,3) array.")
224 .def(
225 "set_external_forces",
226 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setExternalForces(to_vec(a)); },
227 "Set the per-particle external FORCE (e.g. fluid drag) from an (N,3) array. Applied each "
228 "step as dv = F*invMass*dt; persists until re-set or cleared.")
229 .def("clear_external_forces", &Simulation::clearExternalForces,
230 "Zero all per-particle external forces.")
231 .def(
232 "set_quaternions",
233 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setQuaternions(to_vec(a)); },
234 "Set particle orientation quaternions from an (N,4) array.")
235 .def(
236 "set_angular_velocities",
237 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) {
239 },
240 "Set particle angular velocities from an (N,3) array.")
241 .def(
242 "set_inv_inertia",
243 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setInvInertia(to_vec(a)); },
244 "Set per-particle inverse inertia from an (N,3) array.")
245 .def(
246 "set_inv_mass",
247 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setInvMass(to_vec(a)); },
248 "Set per-particle inverse mass (0 => fixed/immovable).")
249 .def("get_angular_velocities",
250 [](const Simulation& s) { return rows(s.getAngularVelocities(), 3); })
251 .def("get_inv_inertia", [](const Simulation& s) { return rows(s.getInvInertia(), 3); })
252 .def("set_scales_uniform", &Simulation::setScalesUniform,
253 "Set a single uniform scale for all particles.")
254 .def(
255 "set_scales",
256 [](Simulation& s, nb::ndarray<float, nb::c_contig> a) { s.setScales(to_vec(a)); },
257 "Set per-particle scales from an array.")
258 .def("set_growth_params", &Simulation::setGrowthParams, nb::arg("rate"),
259 nb::arg("new_factor") = -1.0f, "Set the particle growth rate and target size factor.")
260 .def("get_growth_factor", &Simulation::growthFactor,
261 "Return the current particle growth factor.")
262 .def("get_growth_rate", &Simulation::getGrowthRate, "Return the particle growth rate.")
263 .def("get_masses", [](const Simulation& s) { return flat(s.getMasses()); })
264 .def(
265 "get_positions", [](const Simulation& s) { return rows(s.getPositions(), 3); },
266 "Return particle positions as an (N,3) numpy array.")
267 .def(
268 "get_velocities", [](const Simulation& s) { return rows(s.getVelocities(), 3); },
269 "Return particle velocities as an (N,3) numpy array.")
270 // Zero-copy device export (H2): the returned (N,3) array REFERENCES the device particle Views
271 // — a NumPy view on a host backend, a DLPack/__cuda_array_interface__ array (consume with
272 // cupy.from_dlpack / torch.from_dlpack) on CUDA/HIP — so a GPU-resident analysis chain never
273 // pays the device->host copy. The array keeps the (ref-counted) View alive.
274 .def(
275 "get_positions_view",
276 [](const Simulation& s) {
277 return peclet::core::python::view_to_ndarray(Kokkos::subview(
278 s.positionsView(), Kokkos::make_pair(0, s.numParticles()), Kokkos::ALL));
279 },
280 "Zero-copy (N,3) device array of positions (NumPy view on host, DLPack/CuPy on GPU).")
281 .def(
282 "get_velocities_view",
283 [](const Simulation& s) {
284 return peclet::core::python::view_to_ndarray(Kokkos::subview(
285 s.velocitiesView(), Kokkos::make_pair(0, s.numParticles()), Kokkos::ALL));
286 },
287 "Zero-copy (N,3) device array of velocities (NumPy view on host, DLPack/CuPy on GPU).")
288 .def(
289 "get_external_forces_view",
290 [](const Simulation& s) {
291 return peclet::core::python::view_to_ndarray(Kokkos::subview(
292 s.externalForcesView(), Kokkos::make_pair(0, s.numParticles()), Kokkos::ALL));
293 },
294 "Zero-copy (N,3) device array of the per-particle external force (NumPy view on host, "
295 "DLPack/CuPy on GPU) — write fluid drag here directly to avoid a host round-trip.")
296 .def(
297 "get_quaternions", [](const Simulation& s) { return rows(s.getQuaternions(), 4); },
298 "Return particle orientation quaternions as an (N,4) numpy array.")
299 .def(
300 "get_scales", [](const Simulation& s) { return flat(s.getScales()); },
301 "Return per-particle scales as a numpy array.")
302 .def("step", &Simulation::step, nb::arg("dt") = 0.0f,
303 "Advance the simulation one step (dt=0 uses the configured time step).")
304 .def(
305 "get_sdf_grid",
306 [](Simulation& s, std::tuple<int, int, int> res) {
307 auto [rx, ry, rz] = res;
308 // C-order (rx,ry,rz) float array, matching the prior py::array_t<float>({rx,ry,rz},
309 // ...).
310 return peclet::core::python::vector_to_ndarray(
311 s.getSdfGrid(rx, ry, rz), {(std::size_t)rx, (std::size_t)ry, (std::size_t)rz},
312 {(std::int64_t)ry * rz, (std::int64_t)rz, 1});
313 },
314 nb::arg("resolution"),
315 "Reconstruct a packed-bed SDF on a (rx,ry,rz) grid (the get_sdf_grid pipeline for CFD).")
316 .def("write_vtp", &Simulation::writeVtp, nb::arg("filename"),
317 "Write particle state to a VTP file (ParaView/Ovito).")
318 .def("num_particles", &Simulation::numParticles, "Return the number of particles.")
319 .def("num_contacts", &Simulation::numContacts, "Return the number of broad-phase contacts.")
320 .def("num_manifolds", &Simulation::numManifolds, "Return the number of contact manifolds.")
321 .def("max_overlap", &Simulation::maxOverlap, "Return the maximum particle-particle overlap.")
322 // CUDA-API parity: overlap measurement + LAMMPS/SDF export + profiling.
323 .def("get_num_contacts", &Simulation::numContacts) // CUDA-API alias
324 .def("get_num_manifolds", &Simulation::numManifolds) // CUDA-API alias
325 .def("get_max_overlap", &Simulation::maxOverlap) // CUDA-API alias
326 .def("compute_overlaps", &Simulation::computeOverlaps, "Recompute particle overlaps.")
327 .def("export_lammps", &Simulation::exportLammps, nb::arg("filename"), nb::arg("step"),
328 "Export particle state to a LAMMPS dump file.")
329 .def(
330 "export_sdf",
331 [](Simulation& s, const std::string& filename, std::tuple<int, int, int> res) {
332 auto [rx, ry, rz] = res;
333 s.exportSdf(filename, rx, ry, rz);
334 },
335 nb::arg("filename"), nb::arg("resolution"),
336 "Reconstruct and write the packed-bed SDF on a (rx,ry,rz) grid to a VTI file.")
337 .def(
338 "get_profiling_info",
339 [](Simulation& s) {
340 nb::dict d;
341 d["num_particles"] = s.numParticles();
342 d["num_contacts"] = s.numContacts();
343 d["num_manifolds"] = s.numManifolds();
344 d["max_overlap"] = s.maxOverlap();
345 return d;
346 },
347 "Return a dict of particle/contact/manifold counts and the max overlap.")
348#ifdef PECLET_DEM_MPI
349 // Gated MPI step (mirrors the CUDA dem MPI binding); built only with -DDEM_MPI.
350 .def(
351 "init_mpi",
352 [](Simulation& s, std::tuple<double, double, double> origin,
353 std::tuple<double, double, double> size, std::tuple<long, long, long> gsize,
354 std::tuple<bool, bool, bool> periodic) {
355 int inited = 0;
356 MPI_Initialized(&inited);
357 if (!inited) {
358 int argc = 0;
359 char** argv = nullptr;
360 MPI_Init(&argc, &argv);
361 }
362 s.initMpi(origin, size, gsize, periodic, MPI_COMM_WORLD);
363 },
364 nb::arg("origin"), nb::arg("size"), nb::arg("gsize"), nb::arg("periodic"),
365 "Set up the ORB block decomposition + transport-core particle halo for the distributed "
366 "step.")
367 .def("enable_mpi_step", &Simulation::enableMpiStep, nb::arg("rcut"),
368 nb::arg("sync_every") = 1, nb::arg("forward_rotation") = true,
369 nb::arg("rebalance_every") = 0, nb::arg("verlet_skin") = 0.0,
370 "Enable the distributed step: ghost cutoff rcut, sync cadence, rotation forwarding, the "
371 "load-rebalance interval in steps (0 = fixed decomposition), and the Verlet ghost-reuse "
372 "skin "
373 "(0 = rebuild the halo topology every substep; >0 = reuse it until a particle moves > "
374 "skin).")
375 .def("step_mpi", &Simulation::stepMpi, nb::arg("nsteps") = 1,
376 "Advance the distributed (MPI) simulation by nsteps with halo exchange.")
377 .def("rebalance", &Simulation::rebalance,
378 "Re-decompose by particle count and migrate ownership now; returns this rank's new "
379 "owned count.")
380 .def("migrate_to_weights", &Simulation::migrateToWeights, nb::arg("weights"),
381 "Co-rebalance: migrate ownership onto the weighted ORB of per-cell weights (global "
382 "x-fastest, matching the ORB grid) -- the SAME partition the coupled flow solver "
383 "redistributes onto from the same weight field. Returns this rank's new owned count.")
384 .def("rank", &Simulation::rank, "Return this rank's MPI index.")
385 .def("num_ghost", &Simulation::numGhost, "Return the number of ghost particles on this rank.")
386 .def("mpi_rebuilds", &Simulation::mpiRebuilds,
387 "Cumulative halo topology-rebuild count (Verlet-skin path); pair with mpi_gathers() for "
388 "the ghost-reuse ratio.")
389 .def("mpi_gathers", &Simulation::mpiGathers,
390 "Cumulative ghost gather() count across distributed steps.")
391#endif
392 ;
393
394 // CUDA-API parity: module-level export_lammps(filename, step, pos, vel, quats, radii, box_min,
395 // box_max, pbc).
396 m.def(
397 "export_lammps",
398 [](const std::string& filename, int step, nb::ndarray<float, nb::c_contig> pos,
399 nb::ndarray<float, nb::c_contig> vel, nb::ndarray<float, nb::c_contig> quats,
400 nb::ndarray<float, nb::c_contig> radii,
401 std::optional<std::tuple<float, float, float>> box_min,
402 std::optional<std::tuple<float, float, float>> box_max, bool pbc_enabled) {
403 float bmin[3], bmax[3];
404 const float *pmn = nullptr, *pmx = nullptr;
405 if (box_min) {
406 bmin[0] = std::get<0>(*box_min);
407 bmin[1] = std::get<1>(*box_min);
408 bmin[2] = std::get<2>(*box_min);
409 pmn = bmin;
410 }
411 if (box_max) {
412 bmax[0] = std::get<0>(*box_max);
413 bmax[1] = std::get<1>(*box_max);
414 bmax[2] = std::get<2>(*box_max);
415 pmx = bmax;
416 }
417 peclet::dem::writeLammpsDump(filename, step, to_vec(pos), to_vec(vel), to_vec(quats),
418 to_vec(radii), pmn, pmx, pbc_enabled);
419 },
420 nb::arg("filename"), nb::arg("step"), nb::arg("pos"), nb::arg("vel"), nb::arg("quats"),
421 nb::arg("radii"), nb::arg("box_min") = std::nullopt, nb::arg("box_max") = std::nullopt,
422 nb::arg("pbc_enabled") = false,
423 "Module-level LAMMPS dump writer from raw arrays (filename, step, pos, vel, quats, radii, "
424 "box, pbc).");
425}
Host-facing facade with std::vector setters/getters (binding-agnostic).
Definition sim.hpp:393
void setQuaternions(const std::vector< float > &q)
Definition sim.hpp:761
float computeOverlaps()
Definition sim.hpp:851
std::vector< float > getMasses() const
Definition sim.hpp:818
void setThermostat(float temperature, float tau, float kB)
Definition sim.hpp:596
std::tuple< float, float, float > getDomainMax() const
Definition sim.hpp:592
std::vector< float > getInvInertia() const
Definition sim.hpp:799
std::vector< float > getVelocities() const
Definition sim.hpp:831
static void releaseAll()
Definition sim.hpp:418
std::vector< float > getScales() const
Definition sim.hpp:839
void enablePeriodicity(bool x, bool y, bool z)
Definition sim.hpp:584
void setSphereShape(float radius)
Definition sim.hpp:427
std::vector< float > getQuaternions() const
Definition sim.hpp:835
void setWallVelocity(int wallIndex, F3 linVel, F3 angVel, F3 center)
Definition sim.hpp:672
void exportSdf(const std::string &filename, int rx, int ry, int rz)
Definition sim.hpp:867
void writeVtp(const std::string &filename) const
Definition sim.hpp:949
int numParticles() const
Definition sim.hpp:933
void setGlobalScale(float s)
Definition sim.hpp:605
void addPlane(float px, float py, float pz, float nx, float ny, float nz)
Definition sim.hpp:618
void setVelocities(const std::vector< float > &v)
Definition sim.hpp:737
float growthFactor() const
Definition sim.hpp:814
std::tuple< float, float, float > getDomainMin() const
Definition sim.hpp:589
int addSdfWall(const std::vector< float > &grid, int nx, int ny, int nz, F3 origin, F3 spacing, float restitution, float friction)
Definition sim.hpp:634
void setPositions(const std::vector< float > &xyz)
Definition sim.hpp:682
void setInvInertia(const std::vector< float > &ii)
Definition sim.hpp:780
void setDt(float dt)
Definition sim.hpp:609
void setAngularVelocities(const std::vector< float > &w)
Definition sim.hpp:771
const V3 & externalForcesView() const
Definition sim.hpp:758
void clearExternalForces()
Definition sim.hpp:757
std::vector< float > getAngularVelocities() const
Definition sim.hpp:795
void setScalesUniform(float s)
Definition sim.hpp:721
std::vector< float > getSdfGrid(int rx, int ry, int rz)
Definition sim.hpp:927
void step(float dt)
Definition sim.hpp:845
void setDomain(float lx, float ly, float lz, bool px, bool py, bool pz)
Definition sim.hpp:570
void setSolverIterations(int pos, int vel)
Definition sim.hpp:601
void initializeShape(int shape_type, float radius, float height, float thickness)
Definition sim.hpp:433
const V3 & velocitiesView() const
Definition sim.hpp:938
void setExternalForces(const std::vector< float > &f)
Definition sim.hpp:748
std::vector< float > getPositions() const
Definition sim.hpp:827
void setMaterialParams(float restitution_normal, float restitution_tangent, float friction)
Definition sim.hpp:613
void exportLammps(const std::string &filename, int step) const
Definition sim.hpp:855
float getGrowthRate() const
Definition sim.hpp:815
void setDomainMinMax(F3 mn, F3 mx)
Definition sim.hpp:575
const V3 & positionsView() const
Definition sim.hpp:937
void setInvMass(const std::vector< float > &im)
Definition sim.hpp:789
void setSdfShape(const std::vector< float > &grid, int nx, int ny, int nz, F3 origin, F3 spacing, const std::vector< float > &shellFlat, F3 invInertia, float boundingRadius)
Definition sim.hpp:518
void setScales(const std::vector< float > &s)
Definition sim.hpp:730
void setGrowthParams(float rate, float new_factor)
Definition sim.hpp:805
void setGravity(float gx, float gy, float gz)
Definition sim.hpp:595
static std::vector< float > to_vec(nb::ndarray< float, nb::c_contig > a)
NB_MODULE(_dem, m)
static nb::ndarray< nb::numpy, float > rows(std::vector< float > &&v, int cols)
static nb::ndarray< nb::numpy, float > flat(std::vector< float > &&v)
void writeLammpsDump(const std::string &filename, int step, const std::vector< float > &pos, const std::vector< float > &vel, const std::vector< float > &quat, const std::vector< float > &radii, const float *boxMin, const float *boxMax, bool pbcEnabled)
Definition io.hpp:23
dem — portable (Kokkos) Simulation facade: the dem flip's host-facing driver.