Why xhycom?#
xhycom reads HYCOM .ab output directly into a labelled xarray Dataset — names, coordinates, units, a decoded time axis, and lazy out-of-memory access — with no intermediate files.
Reading HYCOM output#
There are three common workflows.
1. abfile + NumPy — the standard low-level reader; returns one masked array per field:
import abfile.abfile as abf
ab = abf.ABFileArchv("archv.2020_001_00", "r")
temp_sfc = ab.read_field("temp", 1) # (jdm, idm) masked array, layer 1
2. m2nc → xarray — a Fortran tool (hycom/MSCPROGS/src/ExtractNC2D) that converts .ab to NetCDF, which you then open with xarray:
m2nc archv.2020_001_00.a ... # writes tmp1.nc
3. xhycom — straight to a labelled, lazy Dataset:
import xhycom
ds = xhycom.open_dataset("archv.2020_001_00", grid="regional.grid")
ds["temp"].isel(time=0, k=0).plot() # lon/lat/time already attached
|
|
xhycom |
|
|---|---|---|---|
Output |
one masked array per field |
NetCDF file |
labelled |
|
carried separately |
in file |
attached automatically |
Time axis |
not decoded |
one record per file |
calendar-aware datetime |
Layer / density |
manual |
in file |
|
Lazy / out-of-memory |
no — eager into RAM |
no — must convert first |
yes — Dask via |
Extra step |
— |
compile Fortran, convert |
none |
Best when |
low-level field access |
NetCDF needed (NCO/CDO/…) |
interactive / larger-than-RAM |
Out-of-memory analysis with chunks#
The key difference: xhycom can open decades of output without loading any field data into memory. With chunks={"time": 1} the Dataset is Dask-backed and each step is read only when computed:
# ~1 TB on disk; returns in seconds, ~100 MB RAM.
ds = xhycom.open_mfdataset("data/archm.199*-202*", grid="regional.grid",
chunks={"time": 1})
ds["temp"].isel(k=0).mean("time").compute().plot(x="lon", y="lat")
abfile always loads eagerly; m2nc must process every file before analysis can begin. Directory globs are discovered and concatenated along time automatically.
Conservative regridding to a regular grid#
HYCOM’s curvilinear, hybrid-coordinate output usually has to be mapped onto a regular lon/lat/depth grid before it can be compared with reanalyses such as GLORYS. The established tool is hyc2proj (Fortran, hycom/MSCPROGS/src/Hyc2proj): you edit proj.in, depthlevels.in and extract.archv, run the compiled binary, and get a NetCDF file. Its horizontal step is bilinear and its vertical step is spline / linear / staircase — none of them conservative.
xhycom.regrid does it in one in-process call and conservatively by default — area-conservative horizontally, depth-integral-conserving (thickness-weighted) vertically — onto any regular grid, including a GLORYS grid opened straight from its NetCDF file:
glorys = xr.open_dataset("GLO-MFC_001_030_mask_bathy.nc") # regular lon/lat/depth + mask
ds_glorys = xhycom.regrid(ds, target=glorys, grid="regional.grid")
|
||
|---|---|---|
Horizontal |
bilinear |
conservative (default), bilinear, patch |
Vertical |
spline / linear / staircase |
conservative (default, thickness-weighted) or linear |
Conservative? |
no |
yes |
Target grid |
native / polar-stereographic / mercator |
any regular grid, incl. a GLORYS Dataset via |
Interface |
edit text input files, run a Fortran binary |
one Python call, returns an |
Output |
static NetCDF file |
lazy / Dask Dataset (write NetCDF if you want) |
Velocities |
rotated to east/north |
de-staggered to T-points and rotated to east/north |
Regridding many time steps of large output is still expensive — as with the Fortran tools, xhycom doesn’t change that, and a batch job (e.g. a Slurm script) is often the right way to run it. For a handful of time steps or a short time horizon, it works fine interactively.
See the regridding tutorial for worked examples.
Exporting to NetCDF#
If you do need NetCDF for downstream tools, there is no separate conversion step:
xhycom.open_dataset("archv.2020_001_00", grid="regional.grid").to_netcdf("out.nc")