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.