Kamino#

SolverKamino simulates constrained rigid multi-body systems in maximal coordinates. It is designed for mechanical assemblies with kinematic loops, under- or overactuation, joint limits, hard frictional contacts, and restitutive impacts.

Unlike the other maximal-coordinate solvers, Kamino focuses on constrained rigid mechanical assemblies rather than particle or deformable simulation. Kamino is currently in BETA 1, and Newton users are discouraged from depending on it. Evaluate it only when kinematic loops and hard contact constraints are primary requirements and an experimental solver is acceptable.

Experimental

SolverKamino is experimental. Its public API, behavior, feature support, performance, and implementation may change without prior notice.

See the SolverKamino API reference for construction and configuration details. Runnable workflows are available in the Kamino examples.

Choosing a dynamics solver#

Kamino provides two forward-dynamics backends:

  • "padmm" (default): proximal ADMM, dense Jacobians/dynamics, and the Euler integrator. It is the slower, more robust option because it solves equality and inequality constraints together.

  • "dvi" (opt-in): projected dual iterations, sparse Jacobians, dense dynamics with the RCM-reordered blocked LLT solver, and the Euler integrator. It is generally faster, but approximates the coupled problem by alternating between a direct solve for equality constraints and projected iterations for inequality constraints. As a rule of thumb, DVI solves inequality constraints less accurately than PADMM, particularly as the number of active inequalities grows. Dual preconditioning is not supported.

Select the backend when constructing the configuration so dependent defaults initialize consistently:

config = newton.solvers.SolverKamino.Config(dynamics_solver="dvi")
solver = newton.solvers.SolverKamino(model, config=config)

DVI is best suited to performance-sensitive rigid mechanisms with relatively few active contacts; PADMM remains the safer and more broadly validated choice. Set sparse_jacobian=False for fully dense DVI, or set sparse_dynamics=True to use sparse dynamics with the Conjugate Residual solver.

For large bilateral systems, opt into RCM-reordered factorization explicitly:

config.dvi.bilateral_solver_type = "LLTBRCM"
config.dvi.bilateral_solver_kwargs = {
    "block_size": 32,
    "reuse_permutation": True,
    "parallel_factorization": True,
}

The cached permutation remains mathematically valid when matrix values or sparsity change and is recomputed automatically if the active dimension changes. Keep the default "LLTB" solver for small systems.

Inspecting terminal status#

After each step, status provides one device-resident terminal status record per world. PADMM and DVI both provide converged, iterations, r_p, r_d, and r_c fields. Their residual definitions are backend-specific:

  • PADMM: Let x and y be the current preconditioned impulse iterates, x_prev and y_prev their previous values, P the diagonal dual preconditioner, and eta and rho the proximal and penalty parameters. r_p = ||P (x - y)||_inf is the primal consensus residual [N·s or N·m·s]. r_d = ||P^-1 (eta (x - x_prev) + rho (y - y_prev))||_inf is the ADMM dual residual [m/s or rad/s]. r_c is the maximum absolute impulse-velocity inner product over inequality blocks [J]. The P factors convert the first two residuals from solver scaling to physical constraint units.

  • DVI: With physical impulse lambda and augmented constraint velocity v, r_p is the maximum infinity-norm projection distance of unilateral impulses from the nonnegative limit cone or Coulomb contact cone [N·s or N·m·s]. r_d is the maximum of the corresponding velocity distance from the dual cone and the bilateral velocity violation [m/s or rad/s]. r_c = max |lambda_k dot v_k| is the maximum inequality complementarity violation [J].

These are absolute maxima: neither backend divides them by a reference norm, constraint count, or tolerance. Additional fields are not portable between backends.

status = solver.status
assert status.device == model.device
assert status.shape == (model.world_count,)

# Host inspection is explicit and synchronizes the device-to-host copy.
status_host = status.numpy()
unconverged_worlds = (~status_host["converged"].astype(bool)).nonzero()[0]

Terminal status is always maintained. collect_solver_info=True enables additional solver diagnostics and adds runtime and memory overhead; it is not required to access status.

Actuation and forward kinematics#

Kamino dynamics routes actuation independently for each joint DoF. A DoF can use explicit effort, unbounded implicit PD, or effort-limited implicit PD; passive armature, damping, and Coulomb friction are likewise configured per DoF. Implicit-PD target modes require a non-zero applicable gain: velocity mode requires derivative gain, while position-based modes require proportional or derivative gain. Coulomb friction supports all non-free joint types, while joint dynamics and implicit PD currently support revolute, prismatic, and gimbal joint types only.

The forward-kinematics solver still partitions each joint as entirely passive or entirely actuated. Different non-passive target modes are allowed within a joint, but mixing passive and actuated DoFs within one joint is not yet supported. The fk_actuation_flag model attribute provides an explicit joint-level override for this FK partition.