Skip to content

PISOtorch_simulation¤

import PISOtorch_simulation

The simulation driver. It composes the PISOtorch operators into PISO time steps. See Running Simulations for a guided introduction.

Simulation¤

PISOtorch_simulation.Simulation(domain=None, *, time_step=1.0, substeps=1, corrector_steps=2, adaptive_CFL=0.8,
    prep_fn=None, advection_use_BiCG=True, pressure_use_BiCG=False,
    scipy_solve_advection=False, scipy_solve_pressure=False,
    preconditionBiCG=False, BiCG_precondition_fallback=True,
    advection_tol=None, pressure_tol=None, convergence_tol=None, solver_double_fallback=False,
    advect_non_ortho_steps=1, pressure_non_ortho_steps=1,
    advect_reuse_result=False, pressure_reuse_result=False,
    normalize_pressure_result=True, pressure_return_best_result=False,
    advect_passive_scalar=True, pressure_time_step_normalized=False,
    velocity_corrector="FD", non_orthogonal=True,
    differentiable=False, exclude_advection_solve_gradients=False, exclude_pressure_solve_gradients=False,
    log_dir=None, log_interval=0, log_images=True, log_vtk=False, norm_vel=False, block_layout=None,
    output_mode3D="slice", log_fn=None,
    output_resampling_coords=None, output_resampling_shape=None, output_resampling_fill_max_steps=0,
    save_domain_name=None, stop_fn=lambda: False)

All arguments after domain are keyword-only. They can also be changed later as attributes of the simulation, most of them through properties with type checks.

Note

log_images=True is the default, and run() writes the images of the initial state right away. Without a log_dir, it stops with RuntimeError: no log_dir set., so pass log_images=False for runs without output.

Time stepping

Parameter Default Description
domain None a PISOtorch.Domain on which PrepareSolve() was called
time_step 1.0 time step size; with "ADAPTIVE", the time per iteration
substeps 1 fixed number of steps per iteration (each of size time_step), or "ADAPTIVE"
adaptive_CFL 0.8 target CFL number for adaptive sub-stepping
corrector_steps 2 PISO pressure correctors per step
convergence_tol None stop once the maximum velocity change per step falls below this value

Linear solvers

Parameter Default Description
advection_use_BiCG / pressure_use_BiCG True / False BiCGStab instead of CG
preconditionBiCG False ILU(0)-preconditioned BiCGStab
BiCG_precondition_fallback True retry a failed unpreconditioned BiCGStab solve with the preconditioner
advection_tol / pressure_tol None residual tolerances; None selects 1e-5 (float32) or 1e-8 (float64)
pressure_return_best_result False continue with the best CG iterate if the pressure solve does not converge
solver_double_fallback False retry a failed single-precision solve in double precision
scipy_solve_advection / scipy_solve_pressure False solve on the CPU with SciPy (debugging)
advect_reuse_result / pressure_reuse_result False previous result as the initial guess (ignored when differentiable)
normalize_pressure_result True subtract the mean pressure
pressure_time_step_normalized False divide the right-hand side of the pressure system by the time step (timeStepNorm of the pressure operators)

The attribute linear_solve_max_iterations (default 5000) limits the iterations of each solve.

Discretization

Parameter Default Description
non_orthogonal True non-orthogonal correction for skewed grids
advect_non_ortho_steps / pressure_non_ortho_steps 1 / 1 non-orthogonal corrector iterations
velocity_corrector "FD" "FD", "FVM_CENTER" or "FVM_FACE"; only "FD" is differentiable
advect_passive_scalar True advect the passive scalars

Differentiability

Parameter Default Description
differentiable False route all operators through PISOtorch_diff
exclude_advection_solve_gradients False run the advection solves under torch.no_grad() (drops \(J^{\text{Adv}}\))
exclude_pressure_solve_gradients False run the pressure solves under torch.no_grad() (drops \(J^{P}\))

Callbacks, output and control

Parameter Default Description
prep_fn None dict of callbacks
log_fn None log_fn(domain=, out_dir=, it=, out_it=, total_step=), called after every iteration
log_dir, log_interval None, 0 output directory and interval (iterations)
log_images, log_vtk True, False image and VTK output
norm_vel, block_layout, output_mode3D False, None, "slice" image appearance
output_resampling_coords, output_resampling_shape, output_resampling_fill_max_steps None, None, 0 resample all blocks onto one uniform image
save_domain_name None save the final state into log_dir
stop_fn lambda: False checked regularly; return True to stop

Methods

Method Description
run(iterations, static=False, log_domain=True) run iterations output steps; static=True only advects passive scalars. Returns False if the boundary fluxes are unbalanced or the velocity becomes NaN. A failed linear solve is logged and stops the run.
make_divergence_free(iterations=1, max_iter=1000) pressure projection of the current velocity field
advect_static(iterations, time_step=None) passive-scalar-only advection
save_domain(name="domain"), save_domain_images(...), save_domain_vtk(...) manual output
reset_step_counters() reset total_step, total_time and the output counters
linear_solve(csrMat, rhs, x=None, use_BiCG=False, tol=None, max_iter=None, ...) solve with the simulation's settings and backend

total_step and total_time count the performed PISO steps and the simulated time.

Boundary helpers¤

Function Description
balance_boundary_fluxes(domain, free_bounds, tol=None) rescale the velocity of the boundaries in free_bounds so that the net boundary flux is zero
update_advective_boundaries(domain, bounds, velms, dt, tol=None) advective outflow update for bounds; velms is a global [1, dims] velocity or one tensor per boundary; then re-balances the fluxes
get_max_time_step(domain, time_step_target, CFL_cond=0.8, with_transformations=True) time step and number of sub-steps for a CFL condition

Callback helpers¤

Function Description
append_prep_fn(prep_fn, name, fn) add fn at the end of hook name
prepend_prep_fn(prep_fn, name, fn) add fn at the start of hook name

StopHandler¤

stop_handler = PISOtorch_simulation.StopHandler(log=None)
stop_handler.register_signal()     # SIGINT (Ctrl-C) sets the stop flag
...
Simulation(..., stop_fn=stop_handler)
stop_handler.unregister_signal()

stop_handler() returns whether a stop was requested. stop() requests one manually, and reset() clears the flag.