How to Save UGRID Data#

This guide covers exporting xugrid data to various formats while preserving UGRID conventions.

Saving to NetCDF#

NetCDF is the standard format for UGRID data:

import xugrid as xu

uda = xu.data.elevation_nl()

# Save UgridDataArray
uda.ugrid.to_netcdf("elevation.nc")

# Save UgridDataset
uds = xu.open_dataset("model.nc")
uds.ugrid.to_netcdf("output.nc")

The output file will include all UGRID topology variables and CF-compliant metadata.

Saving to Zarr#

Zarr is preferred for large datasets and cloud storage:

# Save to local Zarr store
uda.ugrid.to_zarr("elevation.zarr")

# Save to cloud storage (requires fsspec/s3fs)
uda.ugrid.to_zarr("s3://bucket/elevation.zarr")

# Append to existing store (e.g., for time series)
uda.ugrid.to_zarr("timeseries.zarr", mode="a", append_dim="time")

Zarr supports chunked, compressed storage suitable for parallel access.

Converting to Xarray Dataset#

To get a standard xarray Dataset (for custom I/O or further processing):

# Convert UgridDataArray to Dataset
ds = uda.ugrid.to_dataset()

# Convert UgridDataset to Dataset
ds = uds.ugrid.to_dataset()

# Now you can use any xarray export method
ds.to_netcdf("custom.nc", encoding={...})

Exporting to GeoDataFrame#

For GIS workflows, export to geopandas:

import geopandas as gpd

# Export faces as polygons
gdf = uda.ugrid.to_geodataframe()

# Export to various GIS formats
gdf.to_file("output.gpkg", driver="GPKG")
gdf.to_file("output.shp")
gdf.to_parquet("output.parquet")

You can also export specific grid elements:

# Access the grid
grid = uda.ugrid.grid

# Export nodes as points
gdf_nodes = gpd.GeoDataFrame(
    geometry=gpd.points_from_xy(grid.node_x, grid.node_y)
)

# Export edges as lines
gdf_edges = grid.to_geodataframe(dim=grid.edge_dimension)

Saving Regridder Weights#

Regridder weights can be saved for reuse:

# Create and use a regridder
regridder = xu.OverlapRegridder(source=uda, target=target_grid)
result = regridder.regrid(uda)

# Save weights to Dataset
weights_ds = regridder.to_dataset()
weights_ds.to_netcdf("regridder_weights.nc")

# Later, reload the regridder
weights_ds = xr.open_dataset("regridder_weights.nc")
regridder = xu.OverlapRegridder.from_dataset(weights_ds)

Controlling Output Encoding#

For fine-grained control over the output format:

# Get xarray Dataset first
ds = uda.ugrid.to_dataset()

# Define encoding (compression, chunking, etc.)
encoding = {
    "elevation": {
        "dtype": "float32",
        "zlib": True,
        "complevel": 4,
    }
}

# Save with custom encoding
ds.to_netcdf("compressed.nc", encoding=encoding)

For Zarr with specific chunks:

ds = uds.ugrid.to_dataset()

encoding = {
    "temperature": {"chunks": {"time": 10, "mesh2d_nFaces": 10000}},
}

ds.to_zarr("chunked.zarr", encoding=encoding)

Best Practices#

  1. Use Zarr for large datasets - Better parallel read/write performance

  2. Preserve CRS information - Set CRS before saving: uda.ugrid.set_crs("EPSG:28992")

  3. Use compression for NetCDF - Reduces file size significantly

  4. Choose appropriate chunks for Zarr - Balance between chunk size and access patterns

  5. Include metadata - Add attributes to document your data:

uda.attrs["source"] = "Model simulation v2.0"
uda.attrs["units"] = "meters"
uda.ugrid.to_netcdf("documented.nc")