SFSolver#

The SFSolver is the Stable Fluid solver: a grid-based (Eulerian) solver for gaseous phenomena such as smoke. It advects a velocity field and one or more scalar density fields on a fixed 3D grid, then makes the velocity field divergence-free with a Jacobi pressure projection.

Unlike the particle- and mesh-based solvers, the Stable Fluid solver does not track Lagrangian entities. It solves everything on a uniform grid whose resolution you set through SFOptions.res, and gas is injected by velocity jets that you register on the solver. It simulates the SF.Smoke material; see gs.materials.SF.Smoke.

Usage#

The smoke example drives the solver with a set of velocity jets, then reads the density grid back for rendering. Jets are registered directly on the solver with set_jets.

import genesis as gs

gs.init()
scene = gs.Scene(
    sim_options=gs.options.SimOptions(dt=1e-2),
    sf_options=gs.options.SFOptions(
        res=384,          # grid cells per axis (res x res x res)
        solver_iters=200,  # Jacobi iterations for pressure projection
        decay=0.025,       # per-step density decay
    ),
)

# `jets` is a list of jet objects, each exposing get_tan_dir / get_factor.
# See examples/smoke.py for a complete jet implementation.
scene.sim.sf_solver.set_jets(jets)

scene.build()

for _ in range(200):
    density = scene.sim.sf_solver.grid.q.to_numpy()  # shape (res, res, res, n_jets)
    scene.step()

See examples/smoke.py for the full runnable example, including the jet class and the code that writes the density field to images.

Configure the grid resolution and projection through SFOptions; see gs.options.SFOptions for the full option set.

Behavior and guarantees#

  • The solver is active only once at least one jet is registered with set_jets. With no jets, it allocates no fields and does nothing.

  • Each substep advects the velocity and scalar fields (RK3 backtracing with trilinear interpolation), injects momentum at the jets, computes divergence, runs solver_iters Jacobi pressure iterations, and subtracts the pressure gradient to keep the velocity field divergence-free.

  • State lives on a fixed grid; there are no per-entity get/set state methods, and the solver does not currently participate in checkpointing.

See also#