Gotchas¤
Things that commonly trip up new users, collected from the code.
Imports and setup¤
- Import
torchbeforePISOtorch. The extension links against PyTorch's libraries. Importing it first fails with errors likeImportError: libc10.so: cannot open shared object file. - Run scripts from the repository root.
PISOtorch_simulation,PISOtorch_diffandlibare not installed, only the compiledPISOtorchmodule is. run_tests.pyselects GPU 0. The script setsCUDA_VISIBLE_DEVICES="0". Edit it if that GPU is busy.
Tensors¤
- Batch size 1. Every field tensor must have
N = 1. zyxvs.xyz. Spatial dimensions are orderedzyx(a 2D velocity has shape[1, 2, y, x]), but vector components and coordinates are orderedxyz(channel 0 is u).- Devices. Fields, boundary values and vertex coordinates must be contiguous CUDA tensors. The domain viscosity and the time step are CPU tensors of shape
[1]. - At least 3 cells along every axis of every block.
passiveScalarChannelsdefaults to 1. Pass0if you do not need scalars, otherwise an extra solve runs every step.
Domain life cycle¤
PrepareSolve()is mandatory after creating a domain and afterCopy(),Clone()orload_domain().Simulationrefuses domains that are not initialized.UpdateDomainData()after replacing tensors. Methods likesetVelocity,setVelocitySourceandsetPassiveScalarstore a new tensor reference, and the packed GPU structure only sees it afterUpdateDomainData(). Callbacks that set tensors should end with it.Copy()shares tensors. A non-differentiable simulation on a copy modifies the original domain's fields in place. UseClone()for an independent copy.Detach()after every optimization step. Otherwise reference cycles between the domain and the autograd graph keep GPU memory alive until training crashes.
Boundaries¤
- New blocks are periodic on all faces.
- Closing a face also closes its partner. For a periodic face this is the opposite face of the same block, which becomes a no-slip wall. For a connected face it is the face of the other block.
- Connecting a face that was periodic turns the opposite face of that block into a no-slip wall. Set up connections first and boundary values afterwards, as the samples do.
- Unbalanced fluxes stop the simulation. If the net boundary flux exceeds the pressure tolerance,
run()logs a warning and returnsFalsewithout simulating. Usebalance_boundary_fluxes. - Outflow boundaries must be varying.
update_advective_boundariesraises an error for static boundary velocities; callmakeVelocityVarying()first. A passive-scalar outflow must be a varying Dirichlet scalar. - Mixed block orientation. Blocks with different handedness trigger a warning and can cause problems; check
domain.GetCoordinateOrientation().
Simulation parameters¤
substeps=nvs."ADAPTIVE". With an integer, one iteration advancesn × time_step. With"ADAPTIVE", it advances exactlytime_step.- No
log_dir? Setlog_images=False. Image output is on by default andrun()writes the initial state right away, so aSimulationwithoutlog_dirstops withRuntimeError: no log_dir set. non_orthogonal=Trueis the default. On orthogonal meshes the non-orthogonal terms vanish andFalsegives the same result. The differentiable workflows of the repository useFalse.time_stepin callbacks is a CPU tensor. Usetime_step.cuda()when combining it with GPU tensors.
Physics and gradients¤
- A block viscosity replaces the global viscosity on that block, it is not added to it.
- The Smagorinsky coefficient is not squared.
SGSviscosityIncompressibleSmagorinsky(domain, C)computes \(C\,\Delta^2|\bar S|\), so pass \(C_s^2\). - Only the
"FD"velocity corrector is differentiable. - No mesh gradients. Coordinates and transformation metrics are constants for autograd.