SAP coupler#
The Semi-Analytic Primal (SAP) coupler resolves contact between rigid bodies and FEM soft bodies with a convex, semi-analytic solver derived from the model Drake uses (paper). Reach for it when a rigid robot manipulates a moderately deformable volumetric object (grasping, pressing, lifting) and you need contact forces that stay stable and accurate under sustained load.
SAP handles two solvers: Rigid and FEM. For cloth and highly deformable bodies, use the IPC coupler instead; for multi-solver scenes (MPM, SPH, PBD) or differentiable simulation, use the default coupler described in Solvers and coupling.
Requirements#
SAP coupling imposes three hard requirements. Each is checked at build time and raises if unmet:
64-bit precision: initialize with
precision="64". The solver is ill-conditioned in 32-bit and refuses to run.Implicit FEM solver: any FEM entity must be simulated with
FEMOptions(use_implicit_solver=True).Rigid or FEM only: SAP couples the rigid and FEM solvers. Other solvers (MPM, SPH, PBD) are not supported.
SAP does not support differentiable simulation. Calls into the gradient path raise and direct you to the default coupler.
Minimal example#
The complete script is examples/sap_coupling/fem_sphere_and_cube.py, which drops an FEM cube onto an FEM sphere. The setup that turns on SAP coupling is these three choices:
import genesis as gs
gs.init(backend=gs.gpu, precision="64") # SAP requires 64-bit
scene = gs.Scene(
sim_options=gs.options.SimOptions(dt=1 / 60, substeps=2),
fem_options=gs.options.FEMOptions(use_implicit_solver=True), # SAP requires implicit FEM
coupler_options=gs.options.SAPCouplerOptions(),
)
Selecting the coupler is a single line: pass SAPCouplerOptions() as coupler_options. Everything else is a normal Genesis scene. Add FEM entities with an elastic material and step as usual:
sphere = scene.add_entity(
morph=gs.morphs.Sphere(pos=(0.0, 0.0, 0.1), radius=0.1),
material=gs.materials.FEM.Elastic(model="linear_corotated", E=1e5, nu=0.4),
)
Solver parameters#
SAP runs an outer convex solver whose Newton steps are solved by a preconditioned conjugate gradient (PCG) inner loop and refined by a line search. The defaults below are tuned for typical manipulation scenes; tighten the tolerances when contact forces look noisy or a grasp drifts.
Parameter |
Default |
Meaning |
|---|---|---|
|
|
Outer SAP (Newton) iterations per step |
|
|
Maximum PCG iterations per Newton step |
|
|
Maximum line-search iterations per Newton step |
|
|
Absolute tolerance for SAP convergence |
|
|
Relative tolerance for SAP convergence |
|
|
Convergence threshold for the PCG inner solve |
|
|
Sufficient-decrease tolerance for exact line search |
|
|
Maximum line-search step size |
|
|
Contact dissipation time scale |
|
|
Normal-force regularization |
|
|
Friction regularization |
Contact model parameters#
SAP models contact with a compliant, hydroelastic pressure field. The stiffness parameters set how firmly surfaces resist interpenetration; the contact-type parameters choose how each contact pair is discretized.
Parameter |
Default |
Meaning |
|---|---|---|
|
|
Stiffness of the hydroelastic (pressure-field) contact |
|
|
Stiffness of point contact |
|
|
Couple the rigid and FEM solvers |
|
|
Detect FEM self-contact using tetrahedra |
Three parameters select the contact discretization per pair. Each accepts one of:
"tet": tetrahedralization-based contact. The default and the most accurate choice for most meshes."vert": vertex-based contact, preferable for very coarse meshes such as a single cube or tetrahedron."none": disable contact for that pair.
Parameter |
Default |
Accepted values |
|---|---|---|
|
|
|
|
|
|
|
|
|
Note
rigid_rigid_contact_type is declared to accept "vert", but the solver only implements "tet" and "none"; passing "vert" raises. Use "tet" or "none" for rigid-rigid contact.
Grasping a deformable object#
examples/sap_coupling/franka_grasp_fem_sphere.py has a Franka arm grasp and lift an FEM sphere, the workload SAP is built for. A rigid-cube variant lives in franka_grasp_rigid_cube.py.
A steady grasp demands tighter convergence than the defaults, because a loose solve lets the object creep out of the fingers over many steps. The example tightens both the PCG threshold and the SAP tolerances, and disables self-collision on the arm so the fingers can close fully:
scene = gs.Scene(
sim_options=gs.options.SimOptions(dt=1 / 60, substeps=2),
rigid_options=gs.options.RigidOptions(enable_self_collision=False),
fem_options=gs.options.FEMOptions(use_implicit_solver=True, pcg_threshold=1e-10),
coupler_options=gs.options.SAPCouplerOptions(
pcg_threshold=1e-10,
sap_convergence_atol=1e-10,
sap_convergence_rtol=1e-10,
linesearch_ftol=1e-10,
),
)
To hold a target vertex of an FEM body in place (a fixed constraint rather than a grasp), see fem_fixed_constraint.py, which sets FEMOptions(enable_vertex_constraints=True) and drives a vertex with set_vertex_constraints.
When to use SAP#
Use SAP for rigid-FEM manipulation of moderately deformable volumetric bodies, where you need stable, accurate contact under sustained load and can afford 64-bit precision.
Use the IPC coupler for cloth and highly deformable soft bodies.
Use the default coupler (Solvers and coupling) for scenes with MPM, SPH, or PBD, for rigid-only simulation, or when you need gradients for differentiable simulation.
See also#
IPC coupler: barrier-based contact for cloth and highly deformable bodies.
Solvers and coupling: how solvers and couplers fit together.
FEM options and FEM elastic material: configuring the deformable bodies SAP couples.