PISOtorch (core module)¤
The compiled core of PICT. It contains the data structures, the PISO operators with their backward kernels, the sparse linear solvers, and grid, resampling and per-cell linear-algebra utilities.
Domain¤
PISOtorch.Domain(spatialDims, viscosity, name, dtype, device, passiveScalarChannels=1, scalarViscosity=None)
| Argument | Description |
|---|---|
spatialDims |
1, 2 or 3 |
viscosity |
global (kinematic) viscosity, CPU tensor of shape [1] |
name |
name used in logs and output |
dtype |
torch.float32 or torch.float64 |
device |
the CUDA device |
passiveScalarChannels |
number of passive scalar fields; defaults to 1, use 0 for none |
scalarViscosity |
optional scalar diffusivity: a 1D CUDA tensor with 1 value or one value per channel |
Blocks
| Method | Description |
|---|---|
CreateBlock(velocity=None, pressure=None, passiveScalar=None, vertexCoordinates=None, name="Block") |
create and add a block; at least one tensor must be given, the others are zero-initialized; vertex coordinates generate the transformation metrics |
CreateBlockWithSize(size, name="Block") |
create and add a zero-initialized block with unit cells; size is a PISOtorch.Int4 |
AddBlock(block), getBlock(index), getBlocks(), getNumBlocks() |
manage and access blocks |
Setup and copies
| Method | Description |
|---|---|
PrepareSolve() |
validate the setup and create the secondary tensors (matrices, RHS, results, gradients); required before simulating |
UpdateDomainData() |
refresh the packed GPU structure after tensors were replaced |
IsInitialized() |
whether PrepareSolve() was called |
Copy(newName=None) |
copy the structure, share the primary tensors (velocity, pressure, ...) |
Clone(newName=None) |
copy the structure and clone the primary tensors |
Detach(), DetachFwd(), DetachGrad() |
detach all (forward / gradient) tensors from the autograd graph |
Queries
| Method | Description |
|---|---|
getSpatialDims(), getTotalSize(), getDevice(), getDtype() |
basic information; getTotalSize() is the total number of cells of all blocks |
hasPassiveScalar(), getPassiveScalarChannels() |
passive scalar setup |
getMaxVelocity(withBounds=True, computational=False) |
maximum absolute velocity component, optionally including boundaries and in computational (cell) units |
getMaxVelocityMagnitude(withBounds=True, computational=False) |
maximum velocity magnitude |
hasVertexCoordinates(), getVertexCoordinates() |
vertex coordinate tensors of all blocks |
GetCoordinateOrientation() |
the sign of the cell determinants if all blocks share the same orientation, 0 otherwise |
GetBoundaryFluxBalance(), CheckBoundaryFluxBalance(eps=1e-5) |
net flux through all boundaries (must be ~0 for incompressible flow) |
hasPrescribedBoundary(), isAllFixedBoundariesPassiveScalarTypeStatic() |
boundary queries |
Viscosity
| Member | Description |
|---|---|
viscosity, setViscosity(v) |
global viscosity |
hasBlockViscosity() |
whether any block has its own viscosity |
passiveScalarViscosity, setScalarViscosity(v), clearScalarViscosity(), hasPassiveScalarViscosity(), isPassiveScalarViscosityStatic() |
scalar diffusivity |
Solver data. These are read-only attributes. The vectors have set* / Create* methods (e.g. setVelocityRHS, CreateVelocityRHS), A has setA / CreateA, and the matrices C and P are CSRmatrix objects whose values are set with setValue / CreateValue:
| Attribute | Content |
|---|---|
C |
advection–diffusion matrix (CSRmatrix) |
A |
diagonal of C |
P |
pressure matrix (CSRmatrix) |
velocityRHS, velocityResult |
right-hand side and result of the velocity solve (all blocks, flattened) |
scalarRHS, scalarResult |
the same for passive scalars |
pressureRHS, pressureRHSdiv, pressureResult |
\(\mathbf{h}\), \(\nabla\cdot\mathbf{h}\) and the pressure solution |
CreateVelocityOnBlocks(), CreatePressureOnBlocks() and CreatePassiveScalarOnBlocks() (re)create zero fields on all blocks. (grad) Every solver tensor has a gradient counterpart (CGrad, AGrad, PGrad, velocityResultGrad, ...), together with CreateVelocityGradOnBlocks() and similar.
Block¤
Blocks are created with Domain.CreateBlock or Domain.CreateBlockWithSize.
Fields
| Member | Description |
|---|---|
name |
block name |
velocity, setVelocity(t), getVelocity(computational), CreateVelocity() |
velocity [1, dims, (z,) y, x]; getVelocity(True) returns it transformed to computational space with the inverse metrics |
pressure, setPressure(t), CreatePressure() |
pressure [1, 1, (z,) y, x] |
passiveScalar, setPassiveScalar(t), CreatePassiveScalar(), hasPassiveScalar(), getPassiveScalarChannels() |
passive scalars [1, S, (z,) y, x] |
velocitySource, setVelocitySource(t), clearVelocitySource(), hasVelocitySource(), isVelocitySourceStatic, CreateVelocitySource(createStatic) |
momentum source, [1, dims] or per cell |
viscosity, setViscosity(t), clearViscosity(), hasViscosity(), isViscosityStatic() |
block viscosity [1, 1] or per cell; replaces the global viscosity for the velocity (not for passive scalars) |
Geometry
| Member | Description |
|---|---|
vertexCoordinates, setVertexCoordinates(t), hasVertexCoordinates() |
cell corner coordinates; setting them recomputes all metrics |
getCellCoordinates() |
cell centers |
getCellSizes() |
cell volumes [1, 1, (z,) y, x] |
transform, setTransform(transform, faceTransform=None), hasTransform() |
per-cell metrics (matrix, inverse, determinant; channels last) |
faceTransform, hasFaceTransform() |
per-face metrics |
clearCoordsTransforms() |
back to unit cells |
GetCoordinateOrientation() |
orientation of the block's cells |
Boundaries
| Method | Description |
|---|---|
getBoundary(face), getBoundaries(), getFixedBoundaries() |
access boundaries; getFixedBoundaries() returns (index, boundary) pairs |
CloseBoundary(face, velocity=None, passiveScalar=None) |
make face a FixedBoundary (Dirichlet); closes periodic/connected partners too |
CloseAllBoundaries() |
no-slip walls on all faces |
ConnectBlock(faceString, otherBlock, otherFaceString, axis1String="", axis2String="") |
connect two blocks (see Grids); an overload takes face indices |
MakePeriodic(axis), MakeAllPeriodic() |
periodic boundaries |
hasPrescribedBoundary(), isAllFixedBoundariesPassiveScalarTypeStatic() |
boundary queries |
Other members
| Member | Description |
|---|---|
getSizes(), getStrides(), getDim(), getSpatialDims(), getDevice() |
shape information (Int4 in xyzw order) |
getMaxVelocity(withBounds=True, computational=False), getMaxVelocityMagnitude(...) |
velocity maxima |
getParentDomain() |
the owning domain |
globalOffset, csrOffset, ComputeCSRSize() |
position of the block in the global vectors and matrices |
Detach(), DetachFwd(), DetachGrad() |
detach tensors |
(grad) velocityGrad, pressureGrad, passiveScalarGrad, velocitySourceGrad, viscosityGrad (+ set*/Create*) |
gradient tensors |
Boundaries¤
FixedBoundary prescribes values on a face. It is created by CloseBoundary / CloseAllBoundaries.
| Member | Description |
|---|---|
velocity, setVelocity(t), CreateVelocity(createStatic) |
boundary velocity, static [1, dims] or varying [1, dims, ...] with size 1 normal to the face |
velocityType, setVelocityType(t), isVelocityStatic |
velocity condition type (only DIRICHLET is supported) and whether the velocity is static |
getVelocity(computational) |
velocity broadcast to the face shape, optionally in computational components |
getVelocityVarying(size=None), makeVelocityVarying(size=None) |
broadcast a static velocity (and set it) |
GetFluxes() |
boundary-normal fluxes per boundary cell |
passiveScalar, setPassiveScalar(t), CreatePassiveScalar(createStatic), hasPassiveScalar(), getPassiveScalarChannels(), isPassiveScalarStatic() |
scalar boundary values |
passiveScalarTypes, setPassiveScalarType(type_or_list), isPassiveScalarBoundaryTypeStatic() |
Dirichlet/Neumann per channel |
transform, hasTransform(), setTransform(t), clearTransform() |
face metrics |
getSizes(), hasSize(), getStrides(), getSpatialDims(), getDevice() |
shape information |
(grad) velocityGrad, passiveScalarGrad (+ set*/Create*) |
gradients of the boundary values |
PeriodicBoundary has no parameters. ConnectedBoundary provides getConnectedBlock() and axes, the connected face and the axis mapping. The base class Boundary provides type and getParentDomain(). StaticDirichletBoundary and VaryingDirichletBoundary are deprecated legacy boundary types; use FixedBoundary.
Enums and small types¤
| Type | Values / members |
|---|---|
Int4(x=0, y=0, z=0, w=0) |
integer 4-vector; .x .y .z .w, indexable |
BoundaryType |
DIRICHLET, DIRICHLET_VARYING, NEUMANN, FIXED, CONNECTED, PERIODIC |
BoundaryConditionType |
DIRICHLET, NEUMANN |
ConvergenceCriterion |
NORM2, NORM2_NORMALIZED, ABS_SUM, ABS_MEAN, ABS_MAX |
BoundarySampling |
CONSTANT, CLAMP (for resampling) |
CSRmatrix(value, index, row) |
sparse matrix: value, index, row, setValue, CreateValue, getRows(), getSize(), copy(), clone(), detach(), WithZeroValue(), toType(dtype) |
LinearSolverResultInfo |
finalResidual, usedIterations, converged, isFiniteResidual |
PISO operators¤
These are the building blocks of a PISO step, normally orchestrated by Simulation. timeStep is a CPU tensor of shape [1].
| Function | Description |
|---|---|
SetupAdvectionMatrix(domain, timeStep, nonOrthoFlags, forPassiveScalar=False, passiveScalarChannel=0) |
assemble the implicit advection–diffusion matrix C (and A); used for velocity and passive scalars |
SetupAdvectionScalar(domain, timeStep, nonOrthoFlags) |
right-hand side for passive scalar advection |
SetupAdvectionVelocity(domain, timeStep, nonOrthoFlags, applyPressureGradient=False) |
right-hand side for velocity advection |
SetupPressureCorrection(domain, timeStep, nonOrthoMode=0, useFaceTransform=False, timeStepNorm=False) |
pressure matrix, RHS and divergence of RHS |
SetupPressureMatrix(...), SetupPressureRHS(...), SetupPressureRHSdiv(...) |
the individual parts (for non-orthogonal iterations) |
CorrectVelocity(domain, timeStep, version=0, timeStepNorm=False) |
velocity correction with the pressure gradient; Simulation uses version 1 ("FD"), 5 ("FVM_CENTER") or 6 ("FVM_FACE") |
Copy{Velocity,Pressure,Scalar}Result{To,From}Blocks(domain) |
copy between the global result vectors and the block fields |
ComputeVelocityDivergence(domain) |
per-cell velocity divergence as a flat global vector (shaped like domain.pressureResult) |
ComputePressureGradient(domain, useFVM, gradientInterpolation) |
pressure gradient as a flat global vector (shaped like domain.velocityResult); useFVM=False uses the gradient of the "FD" corrector (gradientInterpolation is then ignored), useFVM=True the finite-volume gradient with gradientInterpolation=0 (interpolated metrics, as "FVM_CENTER") or 3 (face metrics, as "FVM_FACE"); channel_flow_learning.py calls it with False, 0. Copy to the blocks with domain.setVelocityResult(...), UpdateDomainData(), CopyVelocityResultToBlocks(domain) |
ComputeSpatialVelocityGradients(domain) |
\(\partial u_i/\partial x_j\) per block: nested list [blocks][components] of NCDHW tensors |
SGSviscosityIncompressibleSmagorinsky(domain, coefficient) |
Smagorinsky eddy viscosity per block (forward only) |
(grad) SetupAdvectionMatrixGrad, SetupAdvectionScalarGrad, SetupAdvectionVelocityGrad, SetupPressureCorrectionGrad, SetupPressureMatrixGrad, SetupPressureRHSGrad, SetupPressureRHSdivGrad, CorrectVelocityGrad, Copy*ResultGrad* |
backward kernels |
Non-orthogonal flags (nonOrthoFlags, a bit field; the values are defined as constants of PISOtorch_simulation.Simulation):
| Flag | Value | Meaning |
|---|---|---|
NON_ORTHO_DIRECT_MATRIX |
1 | implicit non-orthogonal terms of the direct neighbors |
NON_ORTHO_DIRECT_RHS |
2 | explicit (deferred) direct terms; less stable than the matrix variant |
NON_ORTHO_DIAGONAL_MATRIX |
4 | not implemented |
NON_ORTHO_DIAGONAL_RHS |
8 | explicit diagonal-neighbor terms |
NON_ORTHO_CENTER_MATRIX |
16 | implicit center contribution |
Simulation(non_orthogonal=True) uses 16 | 1 | 8; 0 means orthogonal.
Linear solver¤
infos = PISOtorch.SolveLinear(A, RHS, x, maxIterations, tolerance,
convergenceCriterion=PISOtorch.ConvergenceCriterion.NORM2_NORMALIZED,
useBiCG=False, matrixRankDeficient=False, residualResetSteps=0,
transposeA=False, printResidual=False, returnBestResult=False,
BiCGwithPreconditioner=True)
Solves A x = RHS in place on the GPU, using CG, or BiCGStab with useBiCG=True, ILU(0)-preconditioned if BiCGwithPreconditioner=True (the default of the binding; Simulation passes its own preconditionBiCG setting). maxIterations (torch.IntTensor([n])) and tolerance (a 1-element tensor of the RHS dtype) are CPU tensors and must be passed explicitly: the binding declares scalar defaults (1000, 1e-8), but calling SolveLinear(A, RHS, x) without them fails with a TypeError because the arguments are tensors. A RHS that is a multiple of the matrix size is solved as a batch, and one LinearSolverResultInfo is returned per RHS. transposeA=True solves with \(A^\mathsf{T}\), which the backward pass uses.
SparseOuterProduct(a, b, out_pattern) computes \(\mathbf{a}\mathbf{b}^\mathsf{T}\) only on the sparsity pattern of out_pattern; this gives the matrix gradient of a linear solve. TransformVectors(vectors, transforms, inverse) applies per-cell transformations.
Grids and metrics¤
| Function | Description |
|---|---|
CoordsToTransforms(vertexCoordinates) |
per-cell metrics from vertex coordinates |
CoordsToFaceTransforms(vertexCoordinates) |
per-face metrics |
MakeGrid2DNonUniformScale, MakeGridNDNonUniformScaleNormalized, MakeGridNDExpScaleNormalized, MakeCoordsNDNonUniformScaleNormalized |
GPU generators for refined grids and their transformations |
Per-cell linear algebra¤
These functions operate on small vectors or matrices stored in the channel dimension of NCDHW tensors, with matrices flattened in row-major order:
| Function | Description |
|---|---|
matmul(A, B, transposeA=False, invertA=False, transposeB=False, invertB=False, transposeOutput=False, invertOutput=False) |
matrix/vector products per cell; (grad) matmulGrad |
InvertMatrix(matrices, inPlace=False), VectorToDiagMatrix(vectors) |
inversion, diagonal matrices |
EigenDecomposition(matrices, outputEigenvalues=True, outputEigenvectors=True, normalizeEigenvectors=False) |
closed-form eigen decomposition of symmetric 2×2/3×3 matrices |
MakeBasisUnique(basisMatrices, sortingVectors, inPlace=False) |
make orthogonal bases unique (ordering, signs, handedness) |
Resampling¤
| Function | Description |
|---|---|
SampleTransformedGridGlobalToLocal(globalData, globalTransform, localCoords, boundarySamplingMode, constantValue) |
gather from a uniform (globally transformed) grid onto curvilinear cells |
SampleTransformedGridLocalToGlobal(localData, localCoords, globalTransform, globalShape, fillMaxSteps=0) |
scatter curvilinear cells onto a uniform grid; returns data and weights |
SampleTransformedGridLocalToGlobalMulti(...) |
the same for a list of blocks |
The Python wrappers in lib.data.resample are easier to use.