Version: dev

Arrays

index, makearray, reshape, transpose, concat, broadcast.

Array shape comes from a variable’s shape — an ordered list of index-set names. Array-level expressions align their operands by index-set name and replicate along axes an operand does not declare; an operand carrying a set the result is not shaped over is rejected with array_shape_mismatch.

index

Element or sub-array access. args[0] is the array; args[1..] are the index expressions.

Text

C[i, j]

JSON

{ "op": "index", "args": ["C", "i", "j"] }

Indices are expressions, so arithmetic on them is ordinary:

Text

C[i - 1]

JSON

{ "op": "index", "args": ["C", { "op": "-", "args": ["i", 1] }] }

which is the C[i-1] of a stencil. Indices are 1-based.

Fewer indices than axes selects a sub-array rather than an element — which is how one cell’s vertex ring is handed to a geometry kernel from an array shaped [cells, verts, coord].

The array operand may itself be an expression, commonly a const table:

{
  "op": "index",
  "args": [
    { "op": "const", "value": [1.0, 0.03, 0.0001], "args": [] },
    { "op": "enum", "args": ["land_use_class", "water"] }
  ]
}

makearray

Assembles an array from a sequence of sub-region assignments — “default fill, then override”.

FieldMeaning
regionsArray of regions. Each region is a list of [start, stop] integer pairs, one per output dimension, both endpoints inclusive.
valuesArray of expressions, same length as regions. Each fills the corresponding region.
argsConventionally [] — the operands live inside values.

A scalar values entry is broadcast across its region; an array-valued entry must match the region’s shape.

Later regions overwrite earlier ones. That is what makes the interior/boundary idiom work — fill the interior with a stencil, then overwrite the faces with the boundary condition. There is no boundary-condition block anywhere in the format; this is where a BC lives:

Text

makearray([2:9] = k * C[i], [1:1] = 0, [10:10] = 0)

JSON

{
  "op": "makearray",
  "regions": [[[2, 9]], [[1, 1]], [[10, 10]]],
  "values": [
    { "op": "*", "args": ["k", { "op": "index", "args": ["C", "i"] }] },
    0,
    0
  ],
  "args": []
}

Region bounds may be metaparameter expressions, folded to integers at load — which is what lets one document serve many resolutions.

Empty and inverted bounds. [start, stop] with stop == start - 1 is the canonical empty region: it covers nothing, contributes nothing, and its values entry is never consulted. This is legal and load-clean — it is exactly what a metaparameter-folded interior region produces at the minimum admissible extent ([2, N-1] at N = 2 folds to [2, 1], leaving the faces to cover the axis). A pair with stop < start - 1 is inverted and is rejected at load with makearray_region_inverted, because it almost always means an interior stencil was instantiated below its scheme’s minimum extent.

reshape

Reshapes args[0] to the target shape field. Entries are integers or symbolic dimension names.

Text

reshape(v, [lon, lat])

JSON

{ "op": "reshape", "args": ["v"], "shape": ["lon", "lat"] }

transpose

Axis permutation of args[0]. With no perm, axes are reversed:

Text

transpose(A)

JSON

{ "op": "transpose", "args": ["A"] }

perm is a list of 0-based axis indices giving the new order:

Text

transpose(A, [1, 0])

JSON

{ "op": "transpose", "args": ["A"], "perm": [1, 0] }

concat

Concatenates its operand arrays along axis, which is 0-based. All operands must have identical shape on every other axis.

Text

concat(A, B, axis=1)

JSON

{ "op": "concat", "args": ["A", "B"], "axis": 1 }

broadcast

Applies the scalar operator named in fn elementwise to its operands. It means exactly what {"op": fn, "args": …} means, applied per element — including at arity one, where a one-operand broadcast applies fn unarily and must not be treated as the identity on its operand.

{ "op": "broadcast", "args": ["A", "B"], "fn": "*" }

fn must name a scalar operator — the pointwise ones: arithmetic (including neg ), the elementary functions, comparisons, the logical connectives, and ifelse. It may not name a non-pointwise op, and args must satisfy that operator’s arity. There is no default: an absent or invalid fn is rejected with invalid_broadcast_fn.

broadcast has no text form of its own — it prints as the operator it applies.

Most of the time you do not need it: ordinary elementwise operators already broadcast over array operands by index-set alignment. Reach for it when the operator is chosen by a template parameter, or to make the elementwise intent explicit.