Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
46f7b43
add cartesian coordinates to serialbox
jcanton Jan 22, 2026
c021067
add cartesian coordinates to tests
jcanton Jan 22, 2026
7b46f67
pre-commit
jcanton Jan 22, 2026
2b1b0d4
update serialized data names
jcanton Jan 23, 2026
d384330
Merge branch 'main' into test_cartesian_coords
jcanton Jan 23, 2026
35f3b31
Merge branch 'main' into test_cartesian_coords
jcanton Jan 29, 2026
d890878
grid.kind -> grid.shape and no more guessing
jcanton Jan 29, 2026
ad3b34e
unify names with icon-exclaim
jcanton Jan 29, 2026
bf31078
Add reserved ranks and versioning properties to Experiment class; imp…
jcanton Jan 29, 2026
3830bc0
Fix data download paths
msimberg Jan 29, 2026
b3afef5
Fix formatting
msimberg Jan 29, 2026
26e1542
shuffle functionality
jcanton Jan 29, 2026
51dcb49
Small refactor of test data downloading
msimberg Jan 30, 2026
6eff2d2
move to normal
jcanton Jan 30, 2026
cb50ad2
formatting
jcanton Jan 30, 2026
ebaab87
Make lockfile instead of suffix explicit
msimberg Jan 30, 2026
3f242c5
Fewer assumptions
msimberg Jan 30, 2026
8e33640
Formatting
msimberg Jan 30, 2026
3303745
some update
jcanton Jan 30, 2026
8266e7e
update extra_ranks
jcanton Jan 30, 2026
f7ad71b
script text -> content
jcanton Jan 30, 2026
eab98f6
move functionality
jcanton Jan 30, 2026
0d4b0a5
undo cartesian related changes, now in #1013
jcanton Jan 30, 2026
601412d
Merge fix-data-download from msimberg/icon4py
jcanton Jan 30, 2026
a4e682e
cleanup
jcanton Jan 30, 2026
616524f
pre-commit
jcanton Jan 30, 2026
04ce1d0
put this back
jcanton Jan 30, 2026
4c508fc
cli Typer stuff
jcanton Jan 30, 2026
f583ae5
Merge branch 'main' into test_cartesian_coords
jcanton Jan 30, 2026
98f64ac
flatten directory structure
jcanton Jan 30, 2026
39827df
restrict search to nml block
jcanton Jan 30, 2026
8b995ef
comm_size and tar toplevel
jcanton Jan 30, 2026
ac28470
run only these two for now
jcanton Jan 30, 2026
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
41 changes: 38 additions & 3 deletions model/common/tests/common/grid/unit_tests/test_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,17 +321,28 @@ def test_dual_normal_vert(

@pytest.mark.datatest
def test_cartesian_centers_edge(
backend: gtx_typing.Backend, experiment: definitions.Experiment
backend: gtx_typing.Backend,
grid_savepoint: sb.IconGridSavepoint,
experiment: definitions.Experiment,
) -> None:
grid_geometry = grid_utils.get_grid_geometry(backend, experiment)
grid = grid_geometry.grid
x = grid_geometry.get(attrs.EDGE_CENTER_X)
y = grid_geometry.get(attrs.EDGE_CENTER_Y)
z = grid_geometry.get(attrs.EDGE_CENTER_Z)

ser_x = grid_savepoint.edges_center_cart_x()
ser_y = grid_savepoint.edges_center_cart_y()
ser_z = grid_savepoint.edges_center_cart_z()

assert x.ndarray.shape == (grid.num_edges,)
assert y.ndarray.shape == (grid.num_edges,)
assert z.ndarray.shape == (grid.num_edges,)

assert test_utils.dallclose(x.asnumpy(), ser_x.asnumpy(), atol=1e-15)
assert test_utils.dallclose(y.asnumpy(), ser_y.asnumpy(), atol=1e-15)
assert test_utils.dallclose(z.asnumpy(), ser_z.asnumpy(), atol=1e-15)

match grid.geometry_type:
case base.GeometryType.ICOSAHEDRON:
# those are coordinates on the unit sphere: hence norm should be 1
Expand All @@ -349,17 +360,28 @@ def test_cartesian_centers_edge(

@pytest.mark.datatest
def test_cartesian_centers_cell(
backend: gtx_typing.Backend, experiment: definitions.Experiment
backend: gtx_typing.Backend,
grid_savepoint: sb.IconGridSavepoint,
experiment: definitions.Experiment,
) -> None:
grid_geometry = grid_utils.get_grid_geometry(backend, experiment)
grid = grid_geometry.grid
x = grid_geometry.get(attrs.CELL_CENTER_X)
y = grid_geometry.get(attrs.CELL_CENTER_Y)
z = grid_geometry.get(attrs.CELL_CENTER_Z)

ser_x = grid_savepoint.cell_center_cart_x()
ser_y = grid_savepoint.cell_center_cart_y()
ser_z = grid_savepoint.cell_center_cart_z()

assert x.ndarray.shape == (grid.num_cells,)
assert y.ndarray.shape == (grid.num_cells,)
assert z.ndarray.shape == (grid.num_cells,)

assert test_utils.dallclose(x.asnumpy(), ser_x.asnumpy(), atol=1e-15)
assert test_utils.dallclose(y.asnumpy(), ser_y.asnumpy(), atol=1e-15)
assert test_utils.dallclose(z.asnumpy(), ser_z.asnumpy(), atol=1e-15)

match grid.geometry_type:
case base.GeometryType.ICOSAHEDRON:
# those are coordinates on the unit sphere: hence norm should be 1
Expand All @@ -376,16 +398,29 @@ def test_cartesian_centers_cell(


@pytest.mark.datatest
def test_vertex(backend: gtx_typing.Backend, experiment: definitions.Experiment) -> None:
def test_vertex(
backend: gtx_typing.Backend,
grid_savepoint: sb.IconGridSavepoint,
experiment: definitions.Experiment,
) -> None:
grid_geometry = grid_utils.get_grid_geometry(backend, experiment)
grid = grid_geometry.grid
x = grid_geometry.get(attrs.VERTEX_X)
y = grid_geometry.get(attrs.VERTEX_Y)
z = grid_geometry.get(attrs.VERTEX_Z)

ser_x = grid_savepoint.verts_vertex_cart_x()
ser_y = grid_savepoint.verts_vertex_cart_y()
ser_z = grid_savepoint.verts_vertex_cart_z()

assert x.ndarray.shape == (grid.num_vertices,)
assert y.ndarray.shape == (grid.num_vertices,)
assert z.ndarray.shape == (grid.num_vertices,)

assert test_utils.dallclose(x.asnumpy(), ser_x.asnumpy(), atol=1e-15)
assert test_utils.dallclose(y.asnumpy(), ser_y.asnumpy(), atol=1e-15)
assert test_utils.dallclose(z.asnumpy(), ser_z.asnumpy(), atol=1e-15)

match grid.geometry_type:
case base.GeometryType.ICOSAHEDRON:
# those are coordinates on the unit sphere: hence norm should be 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from icon4py.model.common import dimension as dims
from icon4py.model.common.grid import (
base,
grid_manager as gm,
grid_refinement as refin,
gridfile,
Expand Down Expand Up @@ -80,7 +81,7 @@ def test_grid_manager_eval_v2e(
# indexes (while REGIONAL and GLOBAL grids can have)
assert (
not has_invalid_index(v2e_table)
if experiment.grid.kind == definitions.GridKind.TORUS
if experiment.grid.shape == base.GeometryType.TORUS
else has_invalid_index(v2e_table)
)
_reset_invalid_index(seralized_v2e)
Expand Down Expand Up @@ -126,7 +127,7 @@ def test_grid_manager_eval_v2c(
# indexes (while REGIONAL and GLOBAL grids can have)
assert (
not has_invalid_index(v2c_table)
if experiment.grid.kind == definitions.GridKind.TORUS
if experiment.grid.shape == base.GeometryType.TORUS
else has_invalid_index(v2c_table)
)
_reset_invalid_index(serialized_v2c)
Expand Down
24 changes: 0 additions & 24 deletions model/testing/src/icon4py/model/testing/datatest_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,6 @@
from icon4py.model.testing import definitions, serialbox


def guess_grid_shape(experiment: definitions.Experiment) -> icon.GridShape:
"""Guess the grid type, root, and level from the experiment name.

Reads the level and root parameters from a string in the canonical ICON gridfile format
RxyBab where 'xy' and 'ab' are numbers and denote the root and level of the icosahedron grid construction.

Args: experiment: str: The experiment name.
Returns: tuple[int, int]: The grid root and level.
"""
if "torus" in experiment.name.lower():
return icon.GridShape(geometry_type=base.GeometryType.TORUS)

try:
root, level = map(int, re.search(r"[Rr](\d+)[Bb](\d+)", experiment.name).groups()) # type:ignore[union-attr]
return icon.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon.GridSubdivision(root=root, level=level),
)
except AttributeError as err:
raise ValueError(
f"Could not parse grid_root and grid_level from experiment: {experiment.name} no 'rXbY'pattern."
) from err


def get_processor_properties_for_run(
run_instance: decomposition.RunType,
) -> decomposition.ProcessProperties:
Expand Down
76 changes: 55 additions & 21 deletions model/testing/src/icon4py/model/testing/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
from __future__ import annotations

import dataclasses
import enum
import pathlib
from collections.abc import Mapping
from typing import TYPE_CHECKING, Final, Literal

from icon4py.model.common.grid import base, icon as icon_grid
from icon4py.model.testing import config


Expand Down Expand Up @@ -44,17 +44,11 @@ def grids_path() -> pathlib.Path:
return get_test_data_root_path().joinpath("grids")


class GridKind(enum.Enum):
REGIONAL = "REGIONAL"
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't use the REGIONAL property anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nah, it's a leftover from who knows what, never used anywhere...
also grid root and level -> global_num_cells -> mean_cell_area can be removed, but will do the cleanup in a separate PR as that's purely cleaning

GLOBAL = "GLOBAL"
TORUS = "TORUS"


@dataclasses.dataclass
class GridDescription:
name: str
description: str
kind: GridKind
shape: icon_grid.GridShape
sizes: Mapping[Literal["cell", "edge", "vertex"], int]
file_name: str
uri: str
Expand All @@ -65,7 +59,10 @@ class Grids:
name="r02b04_global",
description="R02B04, small global grid, default grid used in ICON testing, origin of this file is unclear (source = icon-dev)",
sizes={"cell": 20480, "vertex": 10242, "edge": 30720},
kind=GridKind.GLOBAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=2, level=4),
),
file_name="icon_grid_0013_R02B04_R.nc",
uri="https://polybox.ethz.ch/index.php/s/BRiF7XrCCpGqpEF/download",
)
Expand All @@ -74,63 +71,81 @@ class Grids:
name="r02b07_global",
description="R02B07, large global grid, generated by MPI-M GridGenerator",
sizes={"cell": 1310720, "vertex": 655362, "edge": 1966080},
kind=GridKind.GLOBAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=2, level=7),
),
file_name="icon_grid_0023_R02B07_G.nc",
uri="https://polybox.ethz.ch/index.php/s/RMqNbaeHLD5tDd6/download",
)
R02B06_GLOBAL: Final = GridDescription(
name="r02b06_global",
description="R02B06, generated by MPI-M GridGenerator",
sizes={"cell": 327680, "vertex": 163842, "edge": 491520},
kind=GridKind.GLOBAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=2, level=6),
),
file_name="icon_grid_0021_R02B06_G.nc",
uri="https://polybox.ethz.ch/index.php/s/WsHr5e2MKpHkkmp/download",
)
R19_B07_MCH_LOCAL: Final = GridDescription(
name="mch_opr_r19b07_icon_ch2",
description="Grid used in the full icon-ch2 (2km resolution) operational setup of MeteoSwiss, generated by icontools (DWD)",
sizes={"cell": 283876, "vertex": 142724, "edge": 426599},
kind=GridKind.REGIONAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=19, level=7),
),
file_name="icon_grid_0002_R19B07_mch.nc",
uri="https://polybox.ethz.ch/index.php/s/tFQian4aDzTES6c/download",
)
MCH_OPR_R04B07_DOMAIN01: Final = GridDescription(
name="mch_opr_r4b7",
description="Grid used in the icon-ch2_small experiment (generated by IconTools (DWD) (used by MeteoSwiss for verification of icon-ch2 setup) )",
sizes={"cell": 10700, "vertex": 5510, "edge": 16209},
kind=GridKind.REGIONAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=4, level=7),
),
file_name="mch_opr_r4b7_DOM01.nc",
uri="https://polybox.ethz.ch/index.php/s/ZL7LeEDijGCSJGz/download",
)
MCH_OPR_R19B08_DOMAIN01: Final = GridDescription(
name="mch_opr_r19b08",
description="Grid used in some older MCH experiment, suitable for running single GPU benchmarks",
sizes={"cell": 44528, "vertex": 22569, "edge": 67096},
kind=GridKind.REGIONAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=19, level=8),
),
file_name="domain1_DOM01.nc",
uri="https://polybox.ethz.ch/index.php/s/P6XfWcYjnrsNmeX/download",
)
MCH_CH_R04B09_DSL: Final = GridDescription(
name="mch_ch_r04b09_dsl",
description="grid used in the mch_ch_r04b09_dsl experiment used for verification of ICON-exclaim DSL port, generated by IconTools (DWD)",
sizes={"cell": 20896, "vertex": 10663, "edge": 31558},
kind=GridKind.REGIONAL,
shape=icon_grid.GridShape(
geometry_type=base.GeometryType.ICOSAHEDRON,
subdivision=icon_grid.GridSubdivision(root=4, level=9),
),
file_name="grid.nc",
uri="https://polybox.ethz.ch/index.php/s/hD232znfEPBh4Oh/download",
)
TORUS_100X116_1000M: Final = GridDescription(
name="torus_100x116_res1000",
description="Torus grid with a domain (100x116) vertices and a resolution (edge length) of 1000m, generated by MPI-M GridGenerator ",
sizes={"cell": 23200, "vertex": 11600, "edge": 34800},
kind=GridKind.TORUS,
shape=icon_grid.GridShape(geometry_type=base.GeometryType.TORUS),
file_name="Torus_Triangles_100x116_1000m.nc",
uri="https://polybox.ethz.ch/index.php/s/yqvotFss9i1OKzs/download",
)
TORUS_50000x5000: Final = GridDescription(
name="torus_50000x5000_res500",
description="Torus grid with a resolution (edge_length) of 757m, generated by MPI-M GridGenerator",
sizes={"cell": 1056, "vertex": 52, "edge": 1584},
kind=GridKind.TORUS,
shape=icon_grid.GridShape(geometry_type=base.GeometryType.TORUS),
file_name="Torus_Triangles_50000m_x_5000m_res500m.nc",
uri="https://polybox.ethz.ch/index.php/s/eclzK00TM9nnLtE/download",
)
Expand All @@ -143,6 +158,24 @@ class Experiment:
grid: GridDescription
num_levels: int
partitioned_data: Mapping[int, str]
reserved_ranks: int = 0
version: int = 0

@property
def slurm_name(self) -> str:
return f"{self.name}_sb"

@property
def script_name(self) -> str:
return f"exp.{self.slurm_name}.run"

@property
def name_with_version(self) -> str:
return f"{self.name}_v{self.version:02d}"

@property
def archive_filename(self) -> str:
return f"{self.name_with_version}.tar.gz"


class Experiments:
Expand All @@ -158,7 +191,7 @@ class Experiments:
},
)
MCH_CH_R04B09: Final = Experiment(
name="mch_ch_r04b09_dsl",
name="exclaim_ch_r04b09_dsl",
description="Regional setup used by EXCLAIM to validate the icon-exclaim.",
grid=Grids.MCH_CH_R04B09_DSL,
num_levels=65,
Expand All @@ -167,9 +200,10 @@ class Experiments:
2: "https://polybox.ethz.ch/index.php/s/ZSwAoox8WnPSmYc/download",
4: "https://polybox.ethz.ch/index.php/s/y7AnTai3g5eSnsC/download",
},
reserved_ranks=1,
)
JW: Final = Experiment(
name="jabw_R02B04",
name="exclaim_nh35_tri_jws",
description="Jablonowski Williamson atmospheric test case",
grid=Grids.R02B04_GLOBAL,
num_levels=35,
Expand All @@ -180,7 +214,7 @@ class Experiments:
},
)
GAUSS3D: Final = Experiment(
name="gauss3d_torus",
name="exclaim_gauss3d",
description="Gauss 3d test case",
grid=Grids.TORUS_50000x5000,
num_levels=35,
Expand All @@ -191,7 +225,7 @@ class Experiments:
},
)
WEISMAN_KLEMP_TORUS: Final = Experiment(
name="weisman_klemp_torus",
name="exclaim_nh_weisman_klemp",
description="Weisman-Klemp experiment on Torus Grid",
grid=Grids.TORUS_50000x5000,
num_levels=64,
Expand Down
6 changes: 2 additions & 4 deletions model/testing/src/icon4py/model/testing/fixtures/datatest.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,7 @@ def data_provider(
def grid_savepoint(
data_provider: serialbox.IconSerialDataProvider, experiment: definitions.Experiment
) -> serialbox.IconGridSavepoint:
grid_shape = dt_utils.guess_grid_shape(experiment)
return data_provider.from_savepoint_grid(experiment.name, grid_shape)
return data_provider.from_savepoint_grid(experiment.name, experiment.grid.shape)


@pytest.fixture
Expand All @@ -186,9 +185,8 @@ def icon_grid(
def decomposition_info(
data_provider: serialbox.IconSerialDataProvider, experiment: definitions.Experiment
) -> decomposition.DecompositionInfo:
grid_shape = dt_utils.guess_grid_shape(experiment)
return data_provider.from_savepoint_grid(
grid_id=experiment.name, grid_shape=grid_shape
grid_id=experiment.name, grid_shape=experiment.grid.shape
).construct_decomposition_info()


Expand Down
Loading
Loading