Tips & Tricks¤
Setting up simulations¤
- Start from a sample.
minimal_lid_sample.pyis a complete setup in under 100 lines. Copy it and change the mesh and boundaries step by step. - Look at your mesh first.
lib.util.output.plot_grids(domain.getVertexCoordinates(), color=[...], path=out_dir)plots all blocks, one color per block. It shows wrong connections, flipped blocks and bad cells before you spend GPU time on them. - Make the initial state consistent. Call
sim.make_divergence_free()beforerun()whenever the initial velocity was set by hand or the boundaries changed. - Balance open boundaries. With inflow and outflow, call
PISOtorch_simulation.balance_boundary_fluxes(domain, out_bounds)once during setup, and useupdate_advective_boundariesin aPREcallback. - Disable what you don't need. Pass
passiveScalarChannels=0if you do not need scalars, which saves a linear solve in every step. On orthogonal meshes,non_orthogonal=Falseskips the non-orthogonal terms, which vanish there anyway.
Robustness¤
- Adaptive time stepping (
substeps="ADAPTIVE") keeps the CFL number belowadaptive_CFL. Turbulent flows need small values, e.g. 0.1 for the channel flow. - Difficult pressure solves:
pressure_return_best_result=Truecontinues with the best iterate instead of aborting. Check the log for warnings about solves that did not converge. -
Difficult advection solves: keep
BiCG_precondition_fallback=True, which retries with an ILU(0) preconditioner. The obstacle samples use this combination: -
Double precision (
dtype=torch.float64) tightens the default solver tolerance from 1e-5 to 1e-8. This is useful for validation runs and gradient checks. - Fine grids need tighter tolerances. The tolerances are absolute (RMS of the residual), so on fine grids a solve can count as converged after very few iterations. See the note on the Validation page.
- Watch the log. Every
log_interval, the simulation logs the maximum velocity, pressure statistics and the velocity divergence. A growing divergence or velocity usually points to boundary or mesh problems.
Output and analysis¤
- Physical-space images. Pass
output_resampling_shape=[...]to get images resampled onto a uniform grid, in addition to the per-block images in computational space. - ParaView.
log_vtk=Truewrites VTK multi-block files (requirespyvista). - Custom diagnostics. A
log_fngets the domain after every iteration, e.g. to compute vorticity withPISOtorch.ComputeSpatialVelocityGradients(domain)or to accumulate statistics withlib.data.online_statistics. - Checkpoints.
save_domain_name="domain"saves the final state.lib.util.domain_io.load_domainrestores it, and you callPrepareSolve()afterwards. The channel-flow scripts build their warm-up and data pipeline on this (load_run_id).
Learning and optimization¤
- Fresh copy per step, detach after. For every optimization step, create the working domain with
domain.Copy(), callPrepareSolve(), simulate differentiably, callbackward(), and finish withdomain.Detach(). - Warm up without gradients. Run the first steps with
differentiable=Falseand only the last steps differentiably. This saves memory and time, and randomizing the number of warm-up steps diversifies the training states. - Approximate gradients first.
exclude_advection_solve_gradientsandexclude_pressure_solve_gradientsremove the backward linear solves. This is often enough early in training. Re-enable them for fine-tuning. - Curricula over the unroll length. Increase the number of differentiable steps during training (e.g. 4 → 8 → 16) for long-term stability.
- Convolutions across blocks. Use
MultiblockConvinstead of per-block convolutions so that the receptive field crosses block interfaces seamlessly. - Verify gradients. For custom operators or new setups, compare against finite differences in double precision, as
tests/gradcheck.pydoes.