Running xhycom at scale#
Regridding or averaging full HYCOM archives is compute-intensive: a single year of daily fields on the TP2 grid to GLORYS is ~1.6 TB, and streaming through all daily files to build monthly means takes the same wall time regardless of how many output steps you want. For multi-year or multi-variable runs, a Slurm batch job is more practical than an interactive notebook kernel.
This page covers the most common pre-compute pattern — monthly means on a fixed grid — and points to real-world Slurm script examples.
Setup#
The cells below pick up where Regridding left off — the same HYCOM dataset, GLORYS mask, and cached regrid weights.
import numpy as np
import xarray as xr
import xhycom
import dask
from dask.diagnostics import ProgressBar
import os
os.environ["XHYCOM_CACHE_DIR"] = f"/cluster/projects/nn2993k/{os.environ['USER']}/.xhycom-cache-dir"
grid = "/cluster/home/nlo043/NERSC-HYCOM-CICE/TP2a0.10/topo/regional.grid"
DATA_PATH = "/nird/datalake/NS9481K/shuang/TP2_output/expt_02.8/"
ds = xhycom.open_mfdataset(DATA_PATH + "archm.2020*", grid=grid, chunks={"time": 1}, postprocess=True)
GRIDS = "/nird/datapeak/NS9481K/MERCATOR_DATA/REGULAR_GRID_COORD"
glorys = xr.open_dataset(f"{GRIDS}/GLO-MFC_001_030_mask_bathy.nc")
Computing monthly means#
The full daily regrid is large (~1.6 TB for four variables) and rarely what you
want — the usual target is monthly means on the GLORYS grid. For two variables
(temp and salin) that is ~26 GB for one year and takes around 10 minutes to
write on Olivia.
How you build the monthly mean is a methodology question in its own right — average on the native layers (thickness-weighted, the way HYCOM averages online) or at fixed depth — and the choice matters near fronts and the seasonal pycnocline. That’s covered in Time-averaging on a moving vertical grid; here we use the recommended thickness-weighted route and write it to disk.
Even the monthly-mean route streams through all the daily fields to build the average, so runtime scales with the full time range, not just the 12 output steps. A single year interactively in a notebook is fine; a multi-decade run belongs in a Slurm script — see below.
# Recommended monthly mean: thickness-weighted on the native layers (the HYCOM
# monthly mean — see time-averaging.ipynb), then a single regrid. Cheap: ~12 remaps.
h = ds["thknss"]
hbar = h.resample(time="1MS").mean()
monthly = (ds[["temp", "salin"]] * h).resample(time="1MS").mean() / hbar.where(hbar > 0)
monthly["thknss"] = hbar
g_month = xhycom.regrid(monthly, target=glorys, grid=grid, weights=True)
g_month # 12 monthly means on the GLORYS grid
<xarray.Dataset> Size: 26GB
Dimensions: (time: 12, lat: 624, lon: 4320, depth: 50)
Coordinates:
* time (time) object 96B 2020-01-01 00:00:00 ... 2020-12-01 00:00:00
* lat (lat) float32 2kB 38.08 38.17 38.25 38.33 ... 89.83 89.92 90.0
* lon (lon) float32 17kB -180.0 -179.9 -179.8 ... 179.8 179.8 179.9
* depth (depth) float64 400B 0.494 1.541 2.646 ... 5.275e+03 5.728e+03
Data variables:
temp (time, lat, lon, depth) float64 13GB dask.array<chunksize=(1, 624, 4320, 50), meta=np.ndarray>
salin (time, lat, lon, depth) float64 13GB dask.array<chunksize=(1, 624, 4320, 50), meta=np.ndarray>
Attributes:
iversn: 23
iexpt: 28
yrflag: 3
archive_type: mean
long_name: layer thickness
units: m
comment: converted from Pa (factor 0.000101978)
regrid_method: conservative# Cap workers to keep memory bounded — the ~GB regridded chunks can outrun the
# single-locked netCDF writer at high parallelism.
with dask.config.set(num_workers=4), ProgressBar():
g_month.to_netcdf("/cluster/work/projects/nn2993k/nlo043/hycom_on_glorys_2020_monthly.nc")
[########################################] | 100% Completed | 599.47 s
Slurm script examples#
The OHC-GLORYS-HYCOM repository contains worked examples of running xhycom regridding in Slurm batch jobs on Sigma2 Olivia. Start there when setting up a multi-year regrid pipeline.