Grid evaluation¤
Utilities for evaluating a per-point function over a cartesian product of grid points.
Conventions¤
-
The function being evaluated must have the signature:
fn(x1, x2, ..., aux) -> scalar, where coordinatesx1, x2, ...are scalar entries andauxis a tuple of auxiliary components (PDE parameters, discretized source functions, initial conditions, etc). Components ofauxmay be scalars or arrays of any (possibly different) shapes. -
The function is evaluated over a cartesian product of the 1D coordinate arrays and the leading axis of each
auxelement. The trailing axes of eachauxelement are treated as the per-call input for that component:# scalar input a = jnp.linspace(0,1,10) # function input x = jnp.linspace(0,10,20) # sensor coordinate b = jnp.linspace(0,100,15) # function parameter func = lambda x, b: b * x**2 f = jax.vmap(func, in_axes = (None, 0))(x, b) # shape = (15, 20) #the aux tuple aux = (a, f) # per-call shape: a = (1,), f = (20,) -
An element of
auxcan be a tuple of arrays that share their leading axis length. This is useful when the function requires a parameter that a functional auxiliary input was calculated from. In the above example, this would be thebarray of parameter values that were used to calculatef:aux = (a, (f, b)) # per-call shape: a = (1,), f = (20,), b = (1,) residual_fn(model): r(x, aux): a, (f, b) = aux # du/dx = b*u res = model.D(0)(x, (a, f)) - b * model(x, (a, f)) # b isn't a model input, but it is required to calculate the PDE return res return rTuple elements of
auxare zipped across their shared axis to preserve their correlated structure. -
Each function returns the same output layout
(*reversed(aux axis lengths), *reversed(coord lengths)). For the example above,aux = (a, (f, b))and a single collocation coordinatex = jnp.linspace(0,10,100), the output has a shape(15, 10, 100).
Memory dials¤
By default, the cartesian product evaluation is performed by nested jax.vmap calls, which
materializes the full grid of evaluation points in memory at once.
Each utility has the ability to trade jax.vmap for jax.lax.map on a single axis in order
to execute the computation in batches to be more memory efficient:
-
outer_batch_sizeineval_grid: batches the outermost grid axis only -- axis 0 ofaux[-1]whenauxis non-empty, otherwise the last coordinate axis (so models with no auxiliary inputs can batch over a coordinate). -
eval_grid_flat_aux: enumerate theauxcombinations and stack them into an array with shape(N_combinations, N_aux_elements), then batch over the first axis of this array.
popinn.eval_grid(fn, coords_1d, aux=(), outer_batch_size=None)
¤
Evaluate fn on the cartesian product of coordinate and auxiliary axes.
Parameters:
Returns:
| Type | Description |
|---|---|
jax.Array
|
Array of shape |
Source code in src/popinn/eval.py
popinn.eval_grid_flat_aux(fn, coords_1d, aux=(), batch_size=None)
¤
Like eval_grid, but enumerates the aux combinations by integer index and stacks them into an array with
shape (N_combinations, N_aux_elements). The computation is then performed on batch_size chunks of the combinations.
If you don't intend to utilize the batching scheme, use eval_grid instead.
Use this when even one full outermost-axis batch in eval_grid is too big, or when
the aux axes are very uneven (e.g. Na=2, Nb=10_000).
Args:
fn (Callable): Per-point function with signature fn(*coords, aux) -> scalar, where aux is a
tuple of auxiliary inputs.
coords_1d (tuple[Array, ...]): Tuple of 1-D coordinate arrays.
aux (tuple): Tuple of auxiliary components. Each TOP-LEVEL
element is one grid axis (its leading axis); trailing dims are the
per-call input for that component. Independent top-level elements are
crossed:
```python
aux = (a, b) # a.shape=(Na,), b.shape=(Nb,) -> Na x Nb grid
```
A top-level element that is itself a tuple is zipped, not
crossed: all its leaves share their leading axis. Use this for
correlated quantities, e.g. a DeepONet whose initial conditions
were generated from PDE parameters (IC[k] from param[k]):
```python
# IC.shape = (N_IC, N_IC_PTS), param.shape = (N_IC,)
aux = ((IC, param),) # ONE axis of length N_IC, zipped
```
so per call the function receives the pair `(IC[k], param[k])`.
batch_size (int | None): The batch size for `jax.lax.map`.
Returns:
(Array): Array of shape (*reversed(aux lens), *reversed(coord lens)).
Source code in src/popinn/eval.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | |