Generating Limited-Area ICON Grids
Use LimitedAreaGridSpec to generate an open spherical grid for a regional ICON
domain. A specification combines:
- the global
R<n>B<k>grid that determines the target resolution and refinement topology; - optional generation settings that orient that global grid;
- a geographic or rotated-pole region;
- optional rules for selecting cells and treating the open boundary; and
- an optional grid name.
For an operational-resolution grid, prefer generate_grid_to_netcdf(). It can
build a large global construction parent through resumable, disk-backed stages
and materializes only the selected regional mesh. Use generate_grid() when
you need the resulting IconGrid in memory for inspection or further Python
processing.
Quick start
This example creates a modest regional grid in memory and writes the complete ICON-style NetCDF schema:
from grid_generator import LimitedAreaGridSpec, Region, generate_grid
spec = LimitedAreaGridSpec(
parent="R2B4",
region=Region.lonlat_box(
lon_min=3.0,
lon_max=17.0,
lat_min=43.0,
lat_max=50.0,
),
name="central_europe_R02B04",
)
grid = generate_grid(spec)
print(grid.name, grid.dims)
grid.to_netcdf("central_europe_R02B04.nc", fields="full")
parent="R2B4" describes the requested final resolution. With the default
construction mode, the generator builds R2B3, selects and compacts the
region, and performs the final bisection locally. You do not need to specify
the construction parent yourself.
For a larger grid that is needed only as a file, install the acceleration and NetCDF extras and use the file-oriented API:
python -m pip install "icon-grid-generator[accelerate,netcdf]"
from grid_generator import LimitedAreaGridSpec, Region, generate_grid_to_netcdf
spec = LimitedAreaGridSpec(
parent="R2B10",
region=Region.lonlat_box(
lon_min=3.0,
lon_max=17.0,
lat_min=43.0,
lat_max=50.0,
),
name="central_europe_R02B10",
)
generate_grid_to_netcdf(
spec,
"central_europe_R02B10.nc",
max_cells=None,
accelerator="numba",
work_dir="central_europe_R02B10-work",
fields="full",
)
Put both the output and work_dir on disk-backed storage. When staged global
construction is needed, the work directory contains resumable checkpoints and
can be removed after a successful export.
Describing an operational domain
Operational centers describe their regional domains in different coordinate systems. The API supports ordinary longitude/latitude extents, rotated-pole boxes, circles, oriented rectangles, and polygons. Coordinates are in degrees.
The examples in this section demonstrate the corresponding construction patterns. They do not reproduce or certify a currently operational grid. To replace an existing MeteoSwiss, DWD, or other institutional grid, use that system's authoritative parent resolution, orientation, region definition, and boundary configuration.
Rotated-pole domains
Use Region.rotated_lonlat_box() when a domain is defined in a rotated-pole
coordinate system, as in a MeteoSwiss ICON-CH-style setup:
from grid_generator import LimitedAreaGridSpec, Region
ch_region = Region.rotated_lonlat_box(
pole_lon=-170.0,
pole_lat=43.0,
center_lon=-1.01,
center_lat=-0.53,
half_width_lon=5.93,
half_width_lat=4.01,
)
ch_spec = LimitedAreaGridSpec(
parent="R2B8",
region=ch_region,
name="ch_domain_R02B08",
)
center_lon, center_lat, half_width_lon, and half_width_lat are expressed
in the rotated coordinate system. pole_lon and pole_lat define that system
in geographic coordinates. These values are independent of
north_pole_lon, north_pole_lat, and rotation_angle_degrees, which orient
the icosahedral global parent.
Geographic and polygon domains
Use Region.lonlat_box() when a domain is given as a geographic extent, for
example in a DWD-style regional workflow. Replace the illustrative bounds with
the authoritative domain definition:
from grid_generator import LimitedAreaGridSpec, Region
dwd_region = Region.lonlat_box(
lon_min=-10.0,
lon_max=30.0,
lat_min=40.0,
lat_max=60.0,
)
dwd_spec = LimitedAreaGridSpec(
parent="R2B8",
region=dwd_region,
name="de_domain_R02B08",
)
For an irregular footprint, pass its geographic vertices to
Region.polygon():
region = Region.polygon(
(
(-10.0, 42.0),
(22.0, 42.0),
(30.0, 55.0),
(5.0, 61.0),
(-10.0, 52.0),
)
)
The available region constructors are:
| Region | Use when the domain is defined by |
|---|---|
Region.lonlat_box(...) |
geographic longitude/latitude bounds |
Region.rotated_lonlat_box(...) |
bounds in a rotated-pole coordinate system |
Region.circle(...) |
a center and angular radius |
Region.rectangle(...) |
a locally oriented geographic rectangle |
Region.polygon(...) |
an irregular geographic footprint |
For Region.lonlat_box(), lon_min > lon_max intentionally selects a box that
crosses the antimeridian.
Choosing the grid settings
The defaults are intended to produce an ICON-ordered regional grid with a
clean, covered boundary. Most users need to choose only parent, region, and
name.
Parent grid and construction mode
parent is a global grid name such as "R2B8" or a GlobalGridSpec. It
controls the final regional resolution and refinement topology. Pass
north_pole_lon, north_pole_lat, and rotation_angle_degrees to the
generation call when the global parent needs a non-default orientation.
The default construction="refine_last" is recommended for a new regional
grid. It selects cells at bisection level B-1, compacts the result, and
refines it once locally. This preserves immediate-parent refinement information
without constructing the four-times-larger final global grid.
Use construction="cut_final" only when the regional grid must be an exact
cell subset of the final-resolution global parent:
spec = LimitedAreaGridSpec(
parent="R2B8",
region=region,
construction="cut_final",
name="exact_R02B08_cut",
)
cut_final needs the final-resolution global construction parent and therefore
uses substantially more time, memory, and checkpoint storage. At bisection
level zero it is selected automatically because no preceding level exists.
Cell selection and buffer rings
The default selection policy is equivalent to:
from grid_generator import RegionSelectionOptions
selection = RegionSelectionOptions(
inclusion="circumradius",
cleanup="remove_ears",
buffer_rings=0,
)
Choose an inclusion rule according to the domain contract:
inclusion |
Result |
|---|---|
"circumradius" |
Includes cells whose circumdisks intersect supported boxes or circles; recommended for boundary coverage. |
"overlap" |
Includes cells whose center or at least one vertex is inside the region. |
"center" |
Includes only cells whose centers are inside the region; produces the narrowest selection. |
Polygons always use center-or-vertex overlap because they have no corresponding
circumdisk predicate. cleanup="remove_ears" removes one-cell protrusions from
the selected mask. Use cleanup="none" only when the raw predicate result is
part of the required domain definition.
buffer_rings adds complete cell-neighbor rings after selection and cleanup.
This is useful when the supplied region describes the interior area of interest
and the grid must also include a halo for relaxation, interpolation, or boundary
forcing:
spec = LimitedAreaGridSpec(
parent="R2B8",
region=region,
selection=RegionSelectionOptions(buffer_rings=2),
)
Do not confuse selection buffer rings with ICON boundary indexing depth. The
older boundary_depth argument is retained only as an alias for
selection.buffer_rings; new code should use buffer_rings.
Open-boundary policy
The default boundary policy is:
from grid_generator import OpenBoundaryOptions
boundary = OpenBoundaryOptions(
metric_closure="clipped",
indexing_depth=14,
ordering="icon",
)
Keep ordering="icon" for NetCDF export. It groups boundary-control levels and
creates matching ICON start/end tables. ordering="source" preserves the
parent entity order for in-memory analysis, but the strict regional writer
rejects it.
indexing_depth=14 supports the usual ICON boundary and nudging-zone layout.
Change it only when the consuming model configuration requires a different
depth. It does not add cells to the selected domain.
metric_closure="clipped" terminates each dual edge at the physical boundary
and is the normal finite-volume choice. "mirrored" reflects the interior half
of the dual across the boundary for consumers that explicitly require a
ghost-cell convention.
Local optimization
With construction="refine_last", the compact child grid is spring-relaxed
with boundary vertices fixed. The default cap is 2,000 iterations. Set
local_optimization_iterations=0 when unrelaxed local refinement geometry is
required, or set a smaller positive cap for exploratory and lower-cost runs.
This setting is separate from spring_iterations, which controls optimization
of the generated global construction parent.
Producing and checking the result
Use fields="full" for general exchange unless the downstream reader's exact
field requirements are known. The "icon", "icon4py", and "reduced"
profiles produce smaller files for their documented consumer scopes; see
NetCDF field profiles.
The writer checks that the result has an open boundary, ICON-contiguous
boundary prefixes, finite physical metrics, and correctly shaped hierarchy
fields before publishing the file. A spherical regional file uses
grid_geometry = 1 and carries the independent open_boundary = 1 attribute.
Missing neighbors are encoded as -1 in exported connectivity.
For an in-memory result, basic inspection can include:
import numpy as np
grid = generate_grid(spec)
boundary_edges = np.any(grid.edge_cells < 0, axis=1)
print(grid.dims)
print("boundary edges:", np.count_nonzero(boundary_edges))
print("grid UUID:", grid.metadata["uuidOfHGrid"])
print("construction parent:", grid.metadata["construction_parent_grid_name"])
Generation creates a new horizontal-grid UUID. It does not recreate a historical operational file bit for bit or reuse that file's UUID. Before a new grid can drive an operational ICON run, generate matching EXTPAR, vertical-grid, initial-condition, and lateral-boundary products and validate the complete model configuration.
Large-grid workflow
Operational resolutions can have very large global construction parents even when the selected regional result is much smaller. For these cases:
- use
generate_grid_to_netcdf()rather than creating an in-memoryIconGrid; - install the
accelerateextra and selectaccelerator="numba"; - set
max_cells=Noneonly after confirming the intended resolution; - place the output and
work_diron disk-backed storage with enough space for checkpoints and atomic replacement files; and - leave
resume=Trueto reuse completed construction stages after an interruption.
chunk_size bounds regional predicate evaluation and NetCDF-only work arrays.
It does not partition the compact core topology or the final selected regional
mesh. Use distinct output and work-directory paths for concurrent jobs.
See Resource Expectations for global parent sizes and Performance and Scaling for measured requirements.
Implementation details
The preceding sections are sufficient for normal grid generation. The details below explain the boundary and provenance fields that advanced users may need when integrating a generated grid with ICON tooling.
Refine-last pipeline and provenance
For a requested R<n>B<k> grid with k > 0, the default pipeline:
- generates the global
R<n>B<k-1>construction parent; - evaluates the region, cleans the mask, and adds requested buffer rings;
- compacts the selected parent cells into an open mesh;
- bisects that compact parent once;
- locally optimizes the child while holding boundary vertices fixed;
- creates boundary-control fields and applies stable ICON permutations; and
- recomputes connectivity, coordinates, metrics, index tables, metadata, and grid identity.
The locally refined result records four one-based parent_cell_index entries
per compact coarse parent, ICON child-cell type codes, one-based parent-edge
indices and child types, and parent-vertex provenance. In
parent_vertex_index, a positive value refers to a parent vertex and a
negative value refers to a parent edge whose midpoint created the child vertex;
the negative values are provenance, not missing indices.
uuidOfParHGrid identifies the compact immediate parent against which these
structural indices are defined. construction_parent_uuid retains the UUID of
the full global source grid.
Boundary indexing
The boundary indexer starts with vertices on edges that have one real adjacent
cell, then propagates levels inward through incident cells up to
indexing_depth. Cell and edge controls are derived from those vertex levels.
Stable permutations move the active control levels to entity prefixes, and
fixed-width start_idx_* and end_idx_* tables describe those prefixes and
the unordered interior.
Internal connectivity is zero-based and uses -1 for a missing neighbor.
Regional NetCDF connectivity uses one-based real indices and retains -1 for
missing neighbors, adjacent cells, and vertex incidence.
Boundary metrics
With metric_closure="clipped", the real side of a boundary edge stores its
cell-center-to-edge-center distance, the missing side stores zero, and the dual
edge ends at the physical boundary. edgequad_area and dual-area contributions
use that clipped dual.
With metric_closure="mirrored", the generator reflects the real half of the
dual across the boundary. The boundary dual length is doubled and the exterior
side distance equals the real-side distance. Geometry transforms rebuild open
metrics using the policy recorded on the grid.
Metadata and NetCDF contract
Regional metadata records the requested grid_root and grid_level, the
construction-parent name and UUID, the boundary indexing depth, resolved
selection and boundary policies, center/subcenter fields, and
number_of_grid_used.
Spherical limited-area and spherical cut files remain ICON geometry type 1.
Geometry type 3 denotes a planar channel, not a generic limited-area grid.
The separate open_boundary = 1 attribute activates regional validation and
missing-neighbor encoding without disabling spherical behavior.
The implementation maintains reciprocal manifold topology, requires exactly one real cell on each open boundary edge, recomputes metrics after final geometry changes, and discards a local-optimization update if it is non-finite or inverts a cell. Tests cover region-selection policies, refinement provenance, boundary controls and permutations, clipped and mirrored metrics, open NetCDF connectivity, and unchanged global and periodic contracts.