phi.field module contains various data structures - such as grids or point clouds -
and provides a common interface to access them.
This allows the physics to be independent of the underlying data structure to some degree.
Field class is the base class that all fields extend.
It represents a physical quantity
F(x) that defines a value at every point
x in n-dimensional space.
The values of
F(x) may have any number of dimensions, described by the channel dimensions of the Field.
Scalar fields have no channel dimensions, vector fields have one, etc.
.shape: Shapecontains batch and spatial dimensions from
.spatial_rank: int = len(shape.spatial)is the dimensionality of physical space
sample_at(Tensor) -> Tensorcomputes the field values at the given points
sample_in(Geometry) -> Tensorcomputes the field values in the given volumes
at(SampledField) -> SampledFieldreturns a field with the same sample points as the specified representation.
unstack(dim) -> tuple[Field]slices the field along a dimension
Fields implement many mathematical operators, e.g.
+, -, * , /, **.
The shift operator
@ calls the
at() method on the left field.
.values: Tensordata that is used in sampling
.elements: Geometrysample points as finite volumes
.points: Tensorcenter points of
.extrapolation: Extrapolationdetermines how values outside the region covered by
Non-sampled fields inherit from
F(x) as a function instead of from data.
CenteredGrid stores values in a regular grid structure.
The grid values are stored in a
Tensor whose spatial dimensions match the resolution of the grid.
bounds property stores the physical size of the grid from which the cell size is derived.
CenteredGrid.elements is a
GridCell matching the grid resolution.
stores vector fields in staggered form.
The velocity components are not sampled at the cell centers but at the cell faces.
This results in the
values having different shapes for the different vector components.
More on staggered grids.
is a set of points or finite elements, each associated with a value.
samples random fluctuations of certain sizes.
Currently, it only supports resampling to grids.
models a vortex-like velocity field around one or multiple points.
This is useful for sampling the velocity of rotating objects.
val: Field and
representation: SampledField with different values structures or different sampling points,
they can be made compatible using
val.at(representation, keep_extrapolation=False) # resamples val at the elements of representation val @ representation # same as above
These functions return a
Field of the same type as
If they are already sampled at the same elements, the above operations simply return
ΦFlow may choose optimized code paths for specific combinations, such as two grids with equal sample point spacing
When resampling staggered grids with
keep_extrapolation=True, the sample points of the resampled field may be different from
This is because the sample points and value tensor shape of staggered grids depends on the extrapolation type.
Additionally, there are two functions for sampling field values at given locations.
samplesamples the field values at the location of a single geometry or geometry batch.
samplein that the geometry here describes staggered locations at which the individual channel components of the field are stored. For centered grids,
Sampled fields, such as
PointCloud all have an
extrapolation member variable of type
The extrapolation determines the values outside the region in which the field is sampled.
It takes the place of the boundary condition (e.g. Neumann / Dirichlet) which would be used in a mathematical formulation.
While both extrapolation and traditional boundary conditions fill the same role, there are a couple of differences between the two. Boundary conditions determine the field values (or a spatial derivative thereof) at the boundary of a volume, i.e. they cover an n-1 dimensional region. Extrapolations, on the other hand, cover everything outside the sampled volume, i.e. an n-dimensional region.
Numerical methods working directly with traditional boundary conditions have to treat the boundaries separately (e.g. different stencils). With extrapolations, the same computations can typically be achieved by first padding the field and then applying a single operation everywhere. This makes low-order methods more efficient, especially on GPUs or TPUs where fewer kernels need to be launched, reducing the overhead. Also, user code typically is more concise and expressive with extrapolations.
Standard extrapolation types are listed here.
PERIODICcopies the values from the opposite side.
BOUNDARYcopies the closest value from the grid. For the boundary condition ∂u/∂x = 0, this is accurate to second order.
ConstantExtrapolation, such as
ONEfill the outside with a constant value. For a boundary condition u=c, the first padded value is exact and values padded further out are accurate to first order.
Custom extrapolations can be implemented by extending the
Extrapolations also support a limited set of arithmetic operations, e.g.
PERIODIC * ZERO = ZERO.
Different extrapolation types can be chosen for each side of a domain, e.g. a closed box with an open top.
This can be achieved using
which allows the extrapolations to be specified by dimension.
The following example uses 0 for the upper face along
y and 1 everywhere else.
zero_top = extrapolation.combine_sides(x=extrapolation.ONE, y=(extrapolation.ONE, extrapolation.ZERO))
For a full example, see the pipe demo.