A lightweight Python module for reading, analysing, and presenting sea-ice observational products (and closely related ocean/reanalysis fields) in a format suitable for monthly technical meetings and discussion among sea-ice scientists.
This repository is being built by consolidating an existing, working collection of analysis scripts (see [https://github.com/willrhobbs/Obs-seaice-analysis]) into a maintainable Python package. The initial backbone is the IceReader class, which standardises file discovery and loading across multiple products and sources.
- Meeting-ready by default: quick loading of common products and rapid generation of monthly figures/tables.
- Reproducible and modular: scripts become importable functions/classes with stable APIs.
- Pragmatic HPC-first : designed to work on NCI/Gadi-style filesystems (large NetCDF collections, Dask chunking, conservative parallel I/O).
Implemented (and used in notebooks):
IceReader.read_model(...)for model/reanalysis-style NetCDF collections (e.g., ORAS5; optional ACCESS-OM2 via intake).IceReader.read_awi(...)for AWI ESA CCI sea-ice thickness products:- L3CP (default) and scaffolding for L2P
- platform-aware and platform-agnostic access (
platform="all"/platforms=[...])
In progress:
- Porting the legacy scripts/notebooks into cohesive submodules (readers, diagnostics, plotting, workflow scripts).
obs_seaice_analysis/
├── __init__.py # exports IceReader
├── src/
│ ├── __init__.py
│ └── IceReader.py # core reader class (model + satellite products)
├── notebooks/ # working notebooks / examples (WIP)
└── scripts/
└── downloading/
├── download_AWI_SIT.py # resumable FTP mirror for AWI ESA-CCI products
└── download_AWI_SIT.pbs # example PBS job for Gadi (copyq)
From a terminal:
git clone https://github.com/dpath2o/obs_seaice_analysis.git
cd obs_seaice_analysisIf you are working in the same remote repository:
git checkout -b feature/<short-description>git clone <your-fork-url>
cd obs_seaice_analysis
git remote add upstream https://github.com/dpath2o/obs_seaice_analysis.git
git fetch upstream
git checkout -b feature/<short-description>This repository is currently used as an importable source tree (no packaging metadata required).
In your notebook (or any Python session), add the directory containing obs_seaice_analysis/ to sys.path
import sys
from pathlib import Path
# Example: if you cloned into /home/581/<user>/AFIM/src/obs_seaice_analysis
repo_parent = Path("/home/581/da1339/AFIM/src") # adjust for your location
sys.path.insert(0, str(repo_parent))
from obs_seaice_analysis import IceReader
print(obs_seaice_analysis.__file__)r = IceReader(base_dir="/g/data/gv90/wrh581")
vosaline = r.read_model(src = "ORAS5",
var = "vosaline",
start_year = 2006,
end_year = 2007,
latmin = -80,
latmax = -45,
zmin = 0,
zmax = 1000,
chunks = "auto",
parallel = False) # recommended on shared filesystemsNotes:
- ORAS5 uses 2D nav_lat/nav_lon. The reader uses an index-based y slice to avoid boolean indexing with Dask.
- If you encounter NetCDF: HDF error, try parallel=False, chunks=None, or (in code) switching the xarray engine to h5netcdf.
sit = r.read_awi(var = "sea_ice_thickness",
start_year = 2010,
end_year = 2012,
hemisphere = "sh",
platform = "cryosat2",
chunks = "auto")sit = r.read_awi(var = "sea_ice_thickness",
start_year = 2010,
end_year = 2012,
hemisphere = "sh",
platform = "all",
chunks = "auto")sit = r.read_awi(var = "sea_ice_thickness",
start_year = 2010,
end_year = 2012,
hemisphere = "sh",
platforms = ["cryosat2", "envisat", "sentinel3a", "sentinel3b"],
collapse_platforms = True, # fill missing values by priority order
chunks = "auto")sit = r.read_awi(var = ["sea_ice_thickness", "status_flag", "quality_flag"],
start_year = 2010,
end_year = 2012,
hemisphere = "sh",
platform = "all",
chunks = "auto")AWI L3CP SIT is provided on a projected grid with coordinates xc/yc (km). A reliable PyGMT approach is to plot in Cartesian space using -JX:
import numpy as np
from pathlib import Path
import pygmt
def plot_sit_monthly(sit, D_out,
platform_name = None,
region = None,
fig_size = "20c"
vmin = 0.0,
vmax = 5.0,
cmap = "cmocean/matter"):
'''
sit must be a 3D array (i.e. time, x, y) and be stripped of the platform dimension before providing to this function
'''
D_out = Path(D_out); D_out.mkdir(parents=True, exist_ok=True)
sit = sit.sortby("yc") # GMT expects ascending y
region = region if region is not None else [float(sit.xc.min()), float(sit.xc.max()), float(sit.yc.min()), float(sit.yc.max())]
for t in sit.time.values:
tstr = np.datetime_as_string(t, unit="M")
grid = sit.sel(time=t).load() # compute one month at a time
fig = pygmt.Figure()
pygmt.makecpt(cmap = cmap, series=[vmin, vmax])
fig.basemap(region = region,
projection = f"X{fig_size}/0",
frame = [f'+tAWI SIT {platform_name} {tstr}', "xaf", "yaf"])
fig.grdimage(grid = grid, cmap = True, nan_transparent = True)
fig.colorbar(frame = ['x+lSea-ice thickness (m)'])
fig.savefig(D_out / f"awi_sit_{platform_name}_{tstr}.png", dpi=300)Two helper scripts are included under scripts/downloading/ to mirror the AWI ESA-CCI (CRDP v4p0)
tree from ftp.awi.de to local disk:
download_AWI_SIT.py: plain FTP mirror (anonymous), verbose logging, resumable downloads (.part), retry logic, year range filters, include/exclude globs, and passive/active mode fallback.download_AWI_SIT.pbs: example PBS job script for Gadi copyq to run the mirror unattended.
cd /path/to/obs_seaice_analysis/scripts/downloading
python download_AWI_SIT.py --year-min 2010 --year-max 2025Common environment variables (all optional):
REMOTE_BASE/REMOTE_ROOT(default:/sea_ice/projects/cci/crdp/v4p0)LOCAL_ROOT(default:~/seaice/AWI)INCLUDE_GLOBS(default:*.nc)EXCLUDE_GLOBS(default: empty)PASSIVE_MODE(1default; set to0if LIST timeouts occur)FTP_USER/FTP_PASS(default anonymous; AWI FTP typically acceptsanonymouswith an email-like password)
qsub scripts/downloading/download_AWI_SIT.pbsBefore submitting, confirm the PBS directives and LOCAL_ROOT are appropriate for the expected data volume
(e.g., consider pointing LOCAL_ROOT to a project or scratch location rather than $HOME).
The OBS-SEAICE-SCRIPTS.zip archive is treated as the authoritative reference for the workflows that will be migrated into this module. Contents currently include:
- NCL plotting/analysis scripts (*.ncl)
- Python readers/workflows (read_functions.py, read_ocean_data.py, SIT_obs_analysis.py)
- Jupyter notebooks (*.ipynb)
- ARGO_ocean_lontime_hovmuller.ncl
- ERA5_sfcflux_map.ncl
- ncl_funcs.ncl
- NSIDC_ice_area_write.ncl
- NSIDC_ice_atmo_streamline_summary_map.ncl
- NSIDC_ice_atmo_summary_map.ncl
- NSIDC_ice_sst_summary_map.ncl
- NSIDC_SIA_cycle_tplot.ncl
- NSIDC_SIA_sector_tplot.ncl
- NSIDC_sic_clim_map.ncl
- NSIDC_sic_map_generic.ncl
- NSIDC_totalSIA_anoms_byyear.ncl
- NSIDC_totalSIA_SH-NH_compare.ncl
- NSIDC_totalSIA_tplot.ncl
- NSIDC_totalSIA_write.ncl
- OBS_ocean_depthtime_hovmuller.ncl
- plot_funcs.ncl
- Reanalysis_sfcflux_map.ncl
- SIA_anoms_tplot_bymonth.ncl
- SST_arealave_tplot.ncl
- SST_ice_timeseries.ncl
- read_functions.py
- read_ocean_data.py
- SIT_obs_analysis.py
- merid-wind-and-SIE_monthly.ipynb
- merid-wind-and-SIE.ipynb
- NSIDC_SIE_max_vs_maxdate.ipynb
- Obs_depth_lat_trend.ipynb
- OBS_ocean_depthtime_hovmuller.ipynb
- OISST_global_anoms.ipynb
- OSISAF_totalSIA_plot.ipynb
Open an issue describing the dataset/workflow you want to add (inputs, outputs, expected figures).
Implement as an importable function/class under obs_seaice_analysis/.
Add a small notebook in notebooks/ demonstrating usage with a minimal working example.
This repository is an evolving research toolset. Interfaces may change while the legacy scripts are being migrated into stable APIs.