Skip to content

Solver Internal Data Pipeline

Convention for all solvers under novaphy/include/dynamics/. Rationale in spec 2026-05-21.

Rules

  1. Container. Any per-element scratch consumed by a numerical loop is a DeviceArray<T> member, not std::vector<T>.
  2. Layout. Strict struct-of-arrays. No AoS DeviceArray<MyStruct> for solver scratch — one DeviceArray<scalar/Vec3f/Quatf/...> per field.
  3. Device. scratch.device() == model.device() always — even when the math is currently CPU-only. This lets a later PR swap in a CUDA kernel without touching declarations.
  4. Allocation. Newton-aligned: at the top of step() (or in a prepare_* / ensure_* helper called from step()), via DeviceArray<T>::zeros(N, model.device()) or DeviceArray<T>::empty_like(model.x). The constructor allocates only Settings and trivially-copyable scalar/counter members.
  5. Variable-size scratch. Capacity comes from Contacts::rigid_contact_max or a Model::*_count. Active count is contacts->rigid_count(). Solvers must assert(active_count <= capacity).
  6. Exceptions (must stay std::vector). Build-time CPU-only assets (Mesh::vertices_, Mesh::indices_), tree-shaped ownership (std::unique_ptr<MultiBody>), and short-lived function-local temporaries. POD scalars and counters stay plain members (e.g. int active_contact_count_, float last_dt_).
  7. Private helper signatures. When a private helper takes per-element data, the parameter type is DeviceArray<T>& (or const DeviceArray<T>&). std::span is reserved for stack-local arrays and Mesh build-time data. Uniform from step() entry through leaf math, ready for a future GPU kernel swap.

Performance note (interim)

Until docs/handoffs/devicearray-pool.md lands, ensure_*_scratch_ helpers may early-return when sizes match, to avoid cudaMalloc overhead per step. Semantically equivalent to Newton's per-step wp.zeros once a pool exists.

Migration log

Solver Status PR
SolverXPBD done (this PR)
SolverSemiImplicit pending future
SolverFeatherstone pending future
VbdSolver pending future
SolverIPC pending future
PBFSolver pending future