Staggered grids are a key component of the marker-and-cell (MAC) method [Harlow and Welch 1965]. They sample the velocity components not at the cell centers but in staggered form at the corresponding face centers. Their main advantage is that the divergence of a cell can be computed exactly.

Φ_{Flow} only stores valid velocity values in memory.
This may require non-uniform tensors for the values since the numbers of horizontal and vertical faces are generally not equal.
Depending on the boundary conditions, the outer-most values may also be redundant and, thus, not stored.

Φ_{Flow} represents staggered grids as instances of `StaggeredGrid`

.
They have the same properties as `CenteredGrid`

but the `values`

field may reference a
non-uniform tensor
to reflect the varying number of x, y and z sample points.

In [1]:

```
# !pip install --quiet phiflow
from phi.flow import *
grid = StaggeredGrid(0, extrapolation.BOUNDARY, x=10, y=10)
grid.values
```

Out[1]:

(xˢ=(11, 10), yˢ=(10, 11), vectorᶜ=2) float32 0.0 < ... < 0.0

Here, each component of the values tensor has one more sample point in the direction it is facing.
If the extrapolation was `extrapolation.ZERO`

, it would be one less (see above image).

The `StaggeredGrid`

constructor supports two modes:

**Direct construction**`StaggeredGrid(values: Tensor, extrapolation, bounds)`

. All required fields are passed as arguments and stored as-is. The`values`

tensor must have the correct shape considering the extrapolation.**Construction by resampling**`StaggeredGrid(values: Any, extrapolation, bounds, resolution, **resolution)`

. When specifying the resolution as a`Shape`

or via keyword arguments, non-Tensor values can be passed for`values`

, such as geometries, other fields, constants or functions (see the documentation).

Examples:

In [2]:

```
domain = dict(x=10, y=10, bounds=Box[0:1, 0:1], extrapolation=extrapolation.ZERO)
grid = StaggeredGrid((1, -1), **domain) # from constant vector
grid = StaggeredGrid(Noise(), **domain) # sample analytic field
grid = StaggeredGrid(grid, **domain) # resample existing field
grid = StaggeredGrid(lambda x: math.exp(-x), **domain) # function value(location)
grid = StaggeredGrid(Sphere([0, 0], radius=1), **domain) # no anti-aliasing
grid = StaggeredGrid(SoftGeometryMask(Sphere([0, 0], radius=1)), **domain) # with anti-aliasing
```

Staggered grids can also be created from other fields using `field.at()`

or `@`

by passing an existing `StaggeredGrid`

.

Some field functions also return `StaggeredGrids`

:

`spatial_gradient()`

with`type=StaggeredGrid`

`stagger()`

For non-periodic staggered grids, the `values`

tensor is non-uniform
to reflect the different number of sample points for each component.

Functions to get a uniform tensor:

`at_centers()`

interpolates the staggered values to the cell centers and returns a`CenteredGrid`

`staggered_tensor()`

pads the internal tensor to an invariant shape with n+1 entries along all dimensions.

Like tensors, grids can be sliced using the standard syntax.
When selecting a vector component, such as `x`

or `y`

, the result is represented as a `CenteredGrid`

with shifted locations.

In [3]:

```
grid.vector['x'] # select component
```

Out[3]:

CenteredGrid[(xˢ=9, yˢ=10), size=(0.9, 1.0), extrapolation=0]

Slicing spatial dimensions on grids is different from slicing the `values`

tensor directly.
Here, a sub-grid is selected.
The number of sample points depends on the grid type and extrapolation.

In [4]:

```
grid.x[3:4] # spatial slice
```

Out[4]:

StaggeredGrid[(xˢ=3, yˢ=10, vectorᶜ=2), size=(0.099999964, 1.0), extrapolation=0]

In [5]:

```
grid.x[0] # spatial slice
```

Out[5]:

StaggeredGrid[(xˢ=3, yˢ=10, vectorᶜ=2), size=(0.099999964, 1.0), extrapolation=0]

Slicing along batch dimensions has no special effect, this just slices the `values`

.

In [6]:

```
grid.batch[0] # batch slice
```

Out[6]:

StaggeredGrid[(xˢ=10, yˢ=10, vectorᶜ=2), size=(1, 1), extrapolation=0]

Fields can also be sliced using `unstack()`

.
This returns a `tuple`

of all slices along a dimension.