Overview: x4c as a CESM Diagnostic System#
x4c provides a high-level diagnositc system for CESM output analysis and visualization. In this tutorial, we show some simple examples to give a quick glance of the major features, including:
The
Timeseriescase systemThe
spellmagicsAdding new diagnostic variables
More detailed explainations of each feature can be found in later sections.
Example Datasets: Zhu, F. & Zhu, J. Long simulations of the Miocene Climatic Optimum, DOI: 10.5065/3QFN-GN70 (2025). https://rda.ucar.edu/datasets/d010026/.
[1]:
%load_ext autoreload
%autoreload 2
import os
import x4c
import datetime
os.chdir('/glade/u/home/fengzhu/Github/x4c/docsrc/notebooks')
print(x4c.__version__)
print(f'Last Update: {datetime.date.today()}')
2026.3.9
Last Update: 2026-03-09
[ ]:
dirpath = './b.e13.B1850C5.ne16_g16.icesm131_d18O_fixer.Miocene.3xCO2.005'
case = x4c.Timeseries(dirpath, grid_dict={'atm': 'ne16np4'}, cesm_ver=1)
>>> case.root_dir: /glade/u/home/fengzhu/Github/x4c/docsrc/notebooks/b.e13.B1850C5.ne16_g16.icesm131_d18O_fixer.Miocene.3xCO2.005
>>> case.path_pattern: comp/proc/tseries/*/casename.hstr.vn.timespan.nc
>>> case.grid_dict: {'atm': 'ne16np4', 'ocn': 'g16', 'lnd': 'ne16np4', 'rof': 'ne16np4', 'ice': 'g16'}
>>> case.casename: b.e13.B1850C5.ne16_g16.icesm131_d18O_fixer.Miocene.3xCO2.005
>>> case.paths["atm"]["cam.h0"] created
>>> case.paths["ocn"]["pop.h"] created
>>> case.paths["lnd"]["clm2.h0"] created
>>> case.paths["rof"]["rtm.h0"] created
>>> case.paths["ice"]["cice.h"] created
>>> case.vns["atm"]["cam.h0"] created
>>> case.vns["ocn"]["pop.h"] created
>>> case.vns["lnd"]["clm2.h0"] created
>>> case.vns["rof"]["rtm.h0"] created
>>> case.vns["ice"]["cice.h"] created
Now let’s load the surface temperature (TS).
[3]:
case.load('TS')
case.ds['TS']
>>> case.ds["TS"] created
[3]:
<xarray.Dataset> Size: 34MB
Dimensions: (lev: 30, ilev: 31, ncol: 13826, time: 600, nbnd: 2)
Coordinates:
* lev (lev) float64 240B 3.643 7.595 14.36 ... 957.5 976.3 992.6
* ilev (ilev) float64 248B 2.255 5.032 10.16 ... 967.5 985.1 1e+03
* time (time) object 5kB 8951-02-01 00:00:00 ... 9001-01-01 00:00:00
Dimensions without coordinates: ncol, nbnd
Data variables: (12/31)
hyam (lev) float64 240B ...
hybm (lev) float64 240B ...
P0 float64 8B ...
hyai (ilev) float64 248B ...
hybi (ilev) float64 248B ...
lat (ncol) float64 111kB ...
... ...
n2ovmr (time) float64 5kB ...
f11vmr (time) float64 5kB ...
f12vmr (time) float64 5kB ...
sol_tsi (time) float64 5kB ...
nsteph (time) int32 2kB ...
TS (time, ncol) float32 33MB ...
Attributes: (12/20)
np: 4
ne: 16
Conventions: CF-1.0
source: CAM
case: b.e13.B1850C5.ne16_g16.icesm131_d18O_fixer.Miocene.3xCO...
title: UNSET
... ...
comp: atm
hstr: cam.h0
grid: ne16np4
gw: <xarray.DataArray 'area' (ncol: 13826)> Size: 111kB\n[1...
lat: <xarray.DataArray 'lat' (ncol: 13826)> Size: 111kB\n[13...
lon: <xarray.DataArray 'lon' (ncol: 13826)> Size: 111kB\n[13...Note that the same variable name could exist for multiple history strings (h-strings). In which case we should specify the component and h-string:
[4]:
case.load('TS', comp='atm', hstr='cam.h0a')
case.ds['TS']
>>> case.ds["TS"] already loaded; to reload, run case.load("TS", ..., reload=True).
[4]:
<xarray.Dataset> Size: 34MB
Dimensions: (lev: 30, ilev: 31, ncol: 13826, time: 600, nbnd: 2)
Coordinates:
* lev (lev) float64 240B 3.643 7.595 14.36 ... 957.5 976.3 992.6
* ilev (ilev) float64 248B 2.255 5.032 10.16 ... 967.5 985.1 1e+03
* time (time) object 5kB 8951-02-01 00:00:00 ... 9001-01-01 00:00:00
Dimensions without coordinates: ncol, nbnd
Data variables: (12/31)
hyam (lev) float64 240B ...
hybm (lev) float64 240B ...
P0 float64 8B ...
hyai (ilev) float64 248B ...
hybi (ilev) float64 248B ...
lat (ncol) float64 111kB ...
... ...
n2ovmr (time) float64 5kB ...
f11vmr (time) float64 5kB ...
f12vmr (time) float64 5kB ...
sol_tsi (time) float64 5kB ...
nsteph (time) int32 2kB ...
TS (time, ncol) float32 33MB ...
Attributes: (12/20)
np: 4
ne: 16
Conventions: CF-1.0
source: CAM
case: b.e13.B1850C5.ne16_g16.icesm131_d18O_fixer.Miocene.3xCO...
title: UNSET
... ...
comp: atm
hstr: cam.h0
grid: ne16np4
gw: <xarray.DataArray 'area' (ncol: 13826)> Size: 111kB\n[1...
lat: <xarray.DataArray 'lat' (ncol: 13826)> Size: 111kB\n[13...
lon: <xarray.DataArray 'lon' (ncol: 13826)> Size: 111kB\n[13...All derived variables should follow the same idea of specifying component and h-strings if the underlying variables exist for multiple h-strings:
[5]:
case.load('LST', comp='atm', hstr='cam.h0a')
case.ds['LST']
>>> LST is a supported derived variable.
>>> case.ds["TS"] already loaded; to reload, run case.load("TS", ..., reload=True).
>>> case.ds["LANDFRAC"] created
>>> case.ds["LST"] created
[5]:
<xarray.DataArray 'LST' (time: 600, ncol: 13826)> Size: 33MB
array([[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
...,
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan]],
shape=(600, 13826), dtype=float32)
Coordinates:
* time (time) object 5kB 8951-02-01 00:00:00 ... 9001-01-01 00:00:00
lat (ncol) float64 111kB -35.26 -35.98 -37.07 ... 37.91 37.91 36.74
lon (ncol) float64 111kB 315.0 316.6 319.1 320.6 ... 132.5 137.5 135.0
Dimensions without coordinates: ncol
Attributes:
units: K
long_name: Land Surface Temperature
cell_methods: time: mean
path: /glade/u/home/fengzhu/Github/x4c/docsrc/notebooks/b.e13.B1...
gw: <xarray.DataArray 'area' (ncol: 13826)> Size: 111kB\narray...
lat: <xarray.DataArray 'lat' (ncol: 13826)> Size: 111kB\n[13826...
lon: <xarray.DataArray 'lon' (ncol: 13826)> Size: 111kB\n[13826...
comp: atm
grid: ne16np4
vn: LST[ ]: