Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

Notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Next

- **Dimensions are types.** Declare a dimension as a class — `class IDim(gtx.DimensionIndex): ...` — instead of `IDim = gtx.Dimension("IDim")`. `gtx.Field[gtx.Dims[IDim], gtx.float64]` is now a valid annotation for any type checker, including pyright, with no gt4py mypy plugin. See ADR 0028.
- **Breaking:** `gtx.Dimension` is now annotation-only (a PEP 695 alias for `type[gtx.DimensionIndex]`), so `gtx.Dimension("IDim")` raises `TypeError`. Use the class statement above, or `gtx.dimension("IDim")` where a dimension has to be built programmatically from a tag.
- **Breaking:** the dimension's name moved from `dim.value` to `dim.tag`; `common.NamedIndex` is removed — an index along `IDim` is now `IDim(0)`, with the same `.dim` / `.value` accessors.
- `repr()` of a dimension is now `IDim[horizontal]`, matching what `str()` already produced. Error messages are unchanged.
- The dimension hooks are removed from `gt4py.next.type_system.mypy_plugin`; only scalar-precision blurring remains. Downstream projects that migrate to class-style dimensions no longer need the plugin for dimensions.

Comment on lines +5 to +14

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## [Unreleased]
### Next
- **Dimensions are types.** Declare a dimension as a class — `class IDim(gtx.DimensionIndex): ...` — instead of `IDim = gtx.Dimension("IDim")`. `gtx.Field[gtx.Dims[IDim], gtx.float64]` is now a valid annotation for any type checker, including pyright, with no gt4py mypy plugin. See ADR 0028.
- **Breaking:** `gtx.Dimension` is now annotation-only (a PEP 695 alias for `type[gtx.DimensionIndex]`), so `gtx.Dimension("IDim")` raises `TypeError`. Use the class statement above, or `gtx.dimension("IDim")` where a dimension has to be built programmatically from a tag.
- **Breaking:** the dimension's name moved from `dim.value` to `dim.tag`; `common.NamedIndex` is removed — an index along `IDim` is now `IDim(0)`, with the same `.dim` / `.value` accessors.
- `repr()` of a dimension is now `IDim[horizontal]`, matching what `str()` already produced. Error messages are unchanged.
- The dimension hooks are removed from `gt4py.next.type_system.mypy_plugin`; only scalar-precision blurring remains. Downstream projects that migrate to class-style dimensions no longer need the plugin for dimensions.

undo, we don't do it like this currently.

## [1.2.2] - 2026-08-31

### General
Expand Down
320 changes: 320 additions & 0 deletions docs/development/ADRs/next/0028-Dimensions_As_Types.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/development/ADRs/next/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Writing a new ADR is simple:
- [0020 - Runtime domains](0020-Runtime-domains.md)
- [0021 - Argument Descriptors](0021-Argument-Descriptors.md)
- [0023 - Fingerprinting](0023-Fingerprinting.md)
- [0028 - Dimensions as Types](0028-Dimensions_As_Types.md)
- [0026 - Staggered Dimensions](0026-Staggered_Dimensions.md)

### Frontend and Parsing #frontend
Expand Down
24 changes: 14 additions & 10 deletions docs/user/next/QuickstartGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ from gt4py.next import float64, neighbor_sum, where, Dims
Fields store data as a multi-dimensional array, and are defined over a set of named dimensions. The code snippet below defines two named dimensions, _Cell_ and _K_, and creates the fields `a` and `b` over their cartesian product using the `gtx.as_field` helper function. The fields contain the values 2 for `a` and 3 for `b` for all entries.

```{code-cell} ipython3
CellDim = gtx.Dimension("Cell")
KDim = gtx.Dimension("K")

class CellDim(gtx.DimensionIndex):
tag = "Cell"
class KDim(gtx.DimensionIndex):
tag = "K"
num_cells = 5
num_layers = 6
grid_shape = (num_cells, num_layers)
Expand All @@ -70,9 +71,8 @@ b = gtx.as_field([CellDim, KDim], np.full(shape=grid_shape, fill_value=b_value,
Additional numpy-equivalent constructors are available, namely `ones`, `zeros`, `empty`, `full`. These require domain, dtype, and allocator (e.g. a backend) specifications.

```{code-cell} ipython3
I = gtx.Dimension("I")
J = gtx.Dimension("J")

class I(gtx.DimensionIndex): ...
class J(gtx.DimensionIndex): ...
array_of_ones_numpy = np.ones((grid_shape[0], grid_shape[1]))
field_of_ones = gtx.ones(
domain={I: range(grid_shape[0]), J: range(grid_shape[0])},
Expand Down Expand Up @@ -168,8 +168,10 @@ The examples related to unstructured meshes use the mesh below. The edges (in bl
The fields in the subsequent code snippets are 1-dimensional, either over the cells or over the edges. The corresponding named dimensions are thus the following:

```{code-cell} ipython3
CellDim = gtx.Dimension("Cell")
EdgeDim = gtx.Dimension("Edge")
class CellDim(gtx.DimensionIndex):
tag = "Cell"
class EdgeDim(gtx.DimensionIndex):
tag = "Edge"
```

You can express connectivity between elements (i.e. cells or edges) of the mesh using connectivity (a.k.a. adjacency or neighborhood) tables. The table below, `edge_to_cell_table`, has one row for every edge where it lists the indices of cells adjacent to that edge. For example, this table says that edge #6 connects to cells #0 and #5. Similarly, `cell_to_edge_table` lists the edges that are neighbors to a particular cell.
Expand Down Expand Up @@ -228,7 +230,8 @@ Another way to look at it is that transform uses the edge-to-cell connectivity t
You can use the field offset `E2C` below to transform a field over cells to a field over edges using the edge-to-cell connectivities:

```{code-cell} ipython3
E2CDim = gtx.Dimension("E2C", kind=gtx.DimensionKind.LOCAL)
class E2CDim(gtx.DimensionIndex, kind=gtx.DimensionKind.LOCAL):
tag = "E2C"
E2C = gtx.FieldOffset("E2C", source=CellDim, target=(EdgeDim,E2CDim))
```

Expand Down Expand Up @@ -380,7 +383,8 @@ print("where nested tuple return: {}".format(((result_1.asnumpy(), result_2.asnu
As explained in the section outline, the pseudo-laplacian needs the cell-to-edge connectivities as well in addition to the edge-to-cell connectivities. Though the connectivity table has been filled in above, you still need to define the local dimension, the field offset, and the offset provider that describe how to use the connectivity table. The procedure is identical to the edge-to-cell connectivity from before:

```{code-cell} ipython3
C2EDim = gtx.Dimension("C2E", kind=gtx.DimensionKind.LOCAL)
class C2EDim(gtx.DimensionIndex, kind=gtx.DimensionKind.LOCAL):
tag = "C2E"
C2E = gtx.FieldOffset("C2E", source=EdgeDim, target=(CellDim, C2EDim))

C2E_offset_provider = gtx.as_connectivity([CellDim, C2EDim], codomain=EdgeDim, data=cell_to_edge_table, skip_value=-1)
Expand Down
8 changes: 6 additions & 2 deletions docs/user/next/workshop/exercises/1_simple_addition.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@
"metadata": {},
"outputs": [],
"source": [
"I = gtx.Dimension(\"I\")\n",
"J = gtx.Dimension(\"J\")\n",
"class I(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class J(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"size = 10"
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@
"metadata": {},
"outputs": [],
"source": [
"I = gtx.Dimension(\"I\")\n",
"J = gtx.Dimension(\"J\")\n",
"class I(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class J(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"size = 10"
]
},
Expand Down
50 changes: 40 additions & 10 deletions docs/user/next/workshop/exercises/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import gt4py.next as gtx
from gt4py.next.iterator.embedded import MutableLocatedField
from gt4py.next import neighbor_sum, where, Dims
from gt4py.next import Dimension, DimensionKind, FieldOffset
from gt4py.next import DimensionIndex, DimensionKind, FieldOffset
from gt4py.next.program_processors.runners import roundtrip
from gt4py.next.program_processors.runners.gtfn import (
run_gtfn as gtfn_cpu,
Expand Down Expand Up @@ -377,18 +377,48 @@ def ripple_field(domain: gtx.Domain, *, allocator=None) -> MutableLocatedField:
)


C = Dimension("C")
V = Dimension("V")
E = Dimension("E")
K = Dimension("K", kind=gtx.DimensionKind.VERTICAL)
class C(DimensionIndex): ...


class V(DimensionIndex): ...


class E(DimensionIndex): ...


class K(DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ...


class C2EDim(DimensionIndex, kind=DimensionKind.LOCAL):
tag = "C2E"


C2EDim = Dimension("C2E", kind=DimensionKind.LOCAL)
C2E = FieldOffset("C2E", source=E, target=(C, C2EDim))
V2EDim = Dimension("V2E", kind=DimensionKind.LOCAL)


class V2EDim(DimensionIndex, kind=DimensionKind.LOCAL):
tag = "V2E"


V2E = FieldOffset("V2E", source=E, target=(V, V2EDim))
E2VDim = Dimension("E2V", kind=DimensionKind.LOCAL)


class E2VDim(DimensionIndex, kind=DimensionKind.LOCAL):
tag = "E2V"


E2V = FieldOffset("E2V", source=V, target=(E, E2VDim))
E2CDim = Dimension("E2C", kind=DimensionKind.LOCAL)


class E2CDim(DimensionIndex, kind=DimensionKind.LOCAL):
tag = "E2C"


E2C = FieldOffset("E2C", source=C, target=(E, E2CDim))
E2C2VDim = Dimension("E2C2V", kind=DimensionKind.LOCAL)


class E2C2VDim(DimensionIndex, kind=DimensionKind.LOCAL):
tag = "E2C2V"


E2C2V = FieldOffset("E2C2V", source=V, target=(E, E2C2VDim))
7 changes: 5 additions & 2 deletions docs/user/next/workshop/slides/slides_1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,11 @@
}
],
"source": [
"Cell = gtx.Dimension(\"Cell\")\n",
"K = gtx.Dimension(\"K\", kind=gtx.DimensionKind.VERTICAL)\n",
"class Cell(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class K(gtx.DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ...\n",
"\n",
"\n",
"domain = gtx.domain({Cell: 5, K: 6})\n",
"\n",
Expand Down
17 changes: 12 additions & 5 deletions docs/user/next/workshop/slides/slides_2.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
"metadata": {},
"outputs": [],
"source": [
"Cell = gtx.Dimension(\"Cell\")\n",
"K = gtx.Dimension(\"K\", kind=gtx.DimensionKind.VERTICAL)"
"class Cell(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class K(gtx.DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ..."
]
},
{
Expand Down Expand Up @@ -152,8 +154,10 @@
"metadata": {},
"outputs": [],
"source": [
"Cell = gtx.Dimension(\"Cell\")\n",
"Edge = gtx.Dimension(\"Edge\")"
"class Cell(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class Edge(gtx.DimensionIndex): ..."
]
},
{
Expand Down Expand Up @@ -272,7 +276,10 @@
"metadata": {},
"outputs": [],
"source": [
"E2CDim = gtx.Dimension(\"E2C\", kind=gtx.DimensionKind.LOCAL)\n",
"class E2CDim(gtx.DimensionIndex, kind=gtx.DimensionKind.LOCAL):\n",
" tag = \"E2C\"\n",
"\n",
"\n",
"E2C = gtx.FieldOffset(\"E2C\", source=Cell, target=(Edge, E2CDim))"
]
},
Expand Down
6 changes: 4 additions & 2 deletions docs/user/next/workshop/slides/slides_3.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
"metadata": {},
"outputs": [],
"source": [
"Cell = gtx.Dimension(\"Cell\")\n",
"K = gtx.Dimension(\"K\", kind=gtx.DimensionKind.VERTICAL)"
"class Cell(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class K(gtx.DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ..."
]
},
{
Expand Down
2 changes: 1 addition & 1 deletion docs/user/next/workshop/slides/slides_4.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"metadata": {},
"outputs": [],
"source": [
"K = gtx.Dimension(\"K\", kind=gtx.DimensionKind.VERTICAL)"
"class K(gtx.DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ..."
]
},
{
Expand Down
12 changes: 9 additions & 3 deletions examples/lap_cartesian_vs_next.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,16 @@
"# allocator = gtx.gtfn_cpu\n",
"# allocator = gtx.gtfn_gpu\n",
"\n",
"\n",
"# Note: for gt4py.next, names don't matter, for gt4py.cartesian they have to be \"I\", \"J\", \"K\"\n",
"I = gtx.Dimension(\"I\")\n",
"J = gtx.Dimension(\"J\")\n",
"K = gtx.Dimension(\"K\", kind=gtx.DimensionKind.VERTICAL)\n",
"class I(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class J(gtx.DimensionIndex): ...\n",
"\n",
"\n",
"class K(gtx.DimensionIndex, kind=gtx.DimensionKind.VERTICAL): ...\n",
"\n",
"\n",
"domain = gtx.domain({I: nx, J: ny, K: nz})\n",
"\n",
Expand Down
4 changes: 4 additions & 0 deletions src/gt4py/next/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
CartesianConnectivity,
Connectivity,
Dimension,
DimensionIndex,
DimensionKind,
Dims,
Domain,
Field,
GridType,
UnitRange,
as_non_staggered,
dimension,
domain,
flip_staggered,
is_staggered,
Expand Down Expand Up @@ -115,6 +117,8 @@
"is_scalar_type",
# from common

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

regarding the isinstance(..., DimensionMeta) vs is_dimension. Here we should export one or the other.

"Dimension",
"DimensionIndex",
"dimension",
"DimensionKind",
"Dims",
"Field",
Expand Down
Loading