Reference: variables, levels & output#
Lookup tables for what a store contains and how to change it: the extracted variables, the coordinates and attributes that come with them, how to override the selection, the on-disk format and chunking, and the full raw UM inventory.
See also: concepts.md for what the data types, Mk blocks, regions and grid modes are — read that first if you are deciding what to extract. This page is for looking things up once you are.
1. What a store contains#
Variables#
UM_Global extraction keeps 12 variables, all from the I variable set.
Units are whatever the archive carries, passed through by iris unchanged.
Variable |
Units |
On model levels? |
How it is produced |
|---|---|---|---|
|
Pa |
yes |
instantaneous, mass grid |
|
Pa |
no |
instantaneous, mass grid |
|
K |
yes |
instantaneous, mass grid |
|
— |
no |
instantaneous, mass grid |
|
kg kg-1 |
yes |
instantaneous, mass grid |
|
Pa |
no |
instantaneous, mass grid |
|
m s-1 |
yes |
instantaneous, mass grid |
|
m s-1 |
yes |
staggered → interpolated onto the mass grid |
|
m s-1 |
yes |
staggered → interpolated onto the mass grid |
|
W m-2 |
no |
3-hour mean, re-stamped to interval end |
|
Pa |
no |
3-hour mean, re-stamped to interval end |
|
Pa |
no |
3-hour mean, re-stamped to interval end |
The three production kinds correspond one-to-one to the config keys you override
in §2: mass_vars, wind_vars, and
averaged_mass_vars / averaged_staggered_vars. Selection is by name + level
presence.
Dimensions and coordinates#
Dims are time × levels × lat × lon. CF attributes are set by
metadata.apply_cf_metadata:
Coord |
A dimension? |
Meaning |
|---|---|---|
|
yes |
validity time; |
|
yes |
UM model level number, subsampled (see below); |
|
yes |
|
|
yes |
|
|
no — indexed by |
model run (analysis) reference time |
|
no — indexed by |
time since the forecast reference time |
The two forecast coords are retained as time-indexed provenance, not as dimensions: they record which model run each timestep came from.
Model levels are subsampled — level 1 plus every 3rd level up to L59, i.e.
[1, 3, 6, 9, …, 57] (level_stride, default 3).
Global attributes#
CF attributes, written from the config metadata: block — empty config fields
are omitted rather than written blank:
Conventions · title · institution · source · references · history ·
comment · author · grid_mode · mk_version · data_type ·
delta_lat / delta_lon (mean grid spacing)
Provenance and completeness attributes, written by zarr_io.finalize_attrs
after each year:
created_by · created_at · time_start · time_end ·
n_time / n_lat / n_lon / n_levels · zarr_chunks · months_present ·
n_months_present · missing_months · year_complete
year_complete and missing_months are the quickest check that a year finished:
import xarray as xr
ds = xr.open_zarr(".../SOUTHAMERICA/SOUTHAMERICA_Met_2016.zarr")
ds.attrs["year_complete"], ds.attrs["missing_months"]
2. Choosing your own variables and levels#
The lists above are defaults, not fixed: both are overridable per data type under
config.yaml → data_types:, no code change needed.
data_types:
UM_Global:
archive_directory: "/gws/ssde/j25a/name/met_archive/Global/"
# Just temperature, humidity and winds — no averaged fields.
mass_vars:
- [air_temperature, true]
- [specific_humidity, true]
- [surface_air_pressure, false]
wind_vars:
- [x_wind, true]
- [y_wind, true]
averaged_mass_vars: []
averaged_staggered_vars: []
model_levels: [1, 10, 20, 30, 40, 50, 59] # or "all" for every level
Key |
Form |
Notes |
|---|---|---|
|
|
|
|
bare cube names |
3-hour means, re-stamped to interval end |
|
int |
level 1 plus every Nth level (default 3) |
|
list of ints, 1-based |
exact levels; overrides |
|
|
every level the source has (L59 global, L70 NZCSM) |
Cube names must match the archive’s iris names exactly — pick them from the
inventory in §3. Any variable group may be set to
[] to drop it entirely.
Two things to watch. Editing these changes every run using that config, so
keep a job-specific config (or a --suffix) for variant extractions rather than
editing in place. And because stores are appended to per month, changing the
variable or level selection part-way through a year will not line up with the
months already written — rebuild that year with --overwrite.
3. Raw UM variable inventory#
Everything a UM_Global .pp file carries, by variable set. ✓ marks the 12
fields extraction keeps (all from the I set) — see §1.
The rest are read past, not dropped for any quality reason; add one by editing
the *_vars tuples on the MetSource in sources.py.
The I set — instantaneous fields, plus the surface fluxes/stresses:
# |
Name |
Kept |
Notes |
|---|---|---|---|
0 |
|
unnamed STASH code |
|
1 |
|
has a “pseudo level” coord |
|
2 |
canopy water on tiles / (kg/m^2) |
||
3 |
|
unnamed STASH code |
|
4 |
|
✓ |
3-hour mean |
5 |
|
✓ |
3-hour mean |
6 |
|
✓ |
model levels |
7 |
|
✓ |
|
8 |
|
the 1.5 m field — deliberately excluded |
|
9 |
|
✓ |
model levels |
10 |
|
✓ |
|
11 |
|
has a depth coord |
|
12 |
|
✓ |
model levels |
13 |
|
✓ |
|
14 |
|
✓ |
3-hour mean |
15 |
|
✓ |
model levels |
16 |
|
✓ |
model levels, staggered |
17 |
|
✓ |
model levels, staggered |
Entries 8 and 9 are both air_temperature — 8 is the 1.5 m diagnostic, 9 is
the model-level field. This is why selection is by name plus level presence
rather than by name alone, and why _pick raises on an archive change instead of
silently taking the wrong one.
The M set — cloud and precipitation fields. None are currently extracted:
# |
Name |
Notes |
|---|---|---|
0 |
|
unnamed STASH code |
1 |
|
unnamed STASH code |
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
has a height coord |
8 |
|
has a height coord |
9 |
|
|
10 |
|
|
11 |
|
The set is the {set} token in the filename (see
concepts.md) — a domain-month has an I file and
an M file per timestep. Extraction reads only I today; pulling M fields
would mean loading the second file too.
4. Output format and chunking#
One yearly Zarr store per domain/year:
{zarr_save_directory}/{DOMAIN_NAME}/{DOMAIN_NAME}_Met_{YYYY}.zarr
e.g. …/satellite_met_zarr/SOUTHAMERICA/SOUTHAMERICA_Met_2016.zarr
Float32 with zstd Blosc compression, CF time encoding, NaN fill. Single-day
smoke tests write a separate …_Met_{YYYYMMDD}.zarr debug store, and
--suffix TAG writes …_{TAG}_Met_{YYYY}.zarr beside the main store.
zarr_format (config, or --zarr-format) picks the on-disk version: 2 is
readable by both zarr 2.18.7 and 3.x, 3 by 3.x only. Per-region scratch
intermediates are written in the same format, so scratch and output never
straddle two versions.
Choosing the output chunks#
The default chunk shape is {time: 1, levels: 3, lat: -1, lon: -1}, tuned for
the dominant access pattern: time: 1 because scattered single-timestep reads
are the common case, levels in groups of 3, lat/lon whole. A domain can override
it in config:
domains:
SA:
domain_name: "SOUTHAMERICA"
output_chunks:
time: 24 # only the dims you name change; the rest keep the default
Keys are time, levels, lat, lon; -1 means one chunk spanning the whole
dim. An unrecognised key (latitude:) raises at config load rather than silently
leaving the default in place, and run prints the resolved chunks before it
starts. The shape actually used is recorded on the store as zarr_chunks.
Which way to go depends on how you read the store: keep time: 1 for reading
whole fields at scattered timesteps, and raise it when you mostly pull long time
series at a few points, which the default makes expensive (one chunk touched per
timestep).
Applies at store creation only. The chunk layout is fixed when a store is first written; later months inherit it. Changing
output_chunksfor a year that already exists has no effect until you rebuild it with--overwrite.
5. Scratch intermediates and peak memory#
Extraction stages each region into a transient zarr store under
{scratch}/files/, joins them, and appends the result to the yearly store.
Extraction holds one period of one region in memory at a time, so how much
time one intermediate covers is what sets the pipeline’s peak memory. A domain
chooses it with intermediate_period:
domains:
SA:
domain_name: "SOUTHAMERICA"
intermediate_period: week # month (default) | week | day
Period |
One intermediate covers |
Peak memory |
Scratch stores per region-month |
|---|---|---|---|
|
the whole month |
baseline |
1 |
|
a 7-day block |
roughly a quarter of monthly |
5 |
|
one day |
roughly a thirtieth |
28–31 |
Weeks are 7-day blocks within the month — 1–7, 8–14, 15–21, 22–28, 29–end, so the last block is short. Periods never cross a month boundary, which keeps one Mk version per period and leaves the yearly store keyed exactly as before.
The output is identical either way. This knob only changes how the work is broken up on the way there. The cost of a shorter period is more (smaller) scratch stores and more appends to the yearly store.
Reach for it when a large domain runs out of memory — big domains, many model levels and fine target grids all push in the same direction. Note that Mk10 onward is ~2.8× the points of Mk8/9, so a domain that fits monthly in 2016 may not in 2018.
How periods are named#
A period covering a whole month is tagged YYYYMM, the name monthly
intermediates have always had, so existing scratch stores stay reusable. Any
shorter period is tagged with its first day, YYYYMMDD:
{scratch}/files/SOUTHAMERICA_Met_201601_6.zarr # month period
{scratch}/files/SOUTHAMERICA_Met_20160108_6.zarr # week period starting the 8th
Resume is driven by the days actually present in the yearly store, not by the
period setting, so changing intermediate_period part-way through a year is safe
— already-written days are skipped either way.