CMIP6 core recipe example¶
Shows the recipe API with the bundled cmip6.core_units recipe.
Flow: load recipe -> check -> dry-run -> apply -> re-check.
In [1]:
Copied!
import numpy as np
import woodpecker
from woodpecker.testing import make_cmip6
import numpy as np
import woodpecker
from woodpecker.testing import make_cmip6
Create a CMIP6-like dataset where tas is stored in Celsius instead of Kelvin.
In [2]:
Copied!
dataset = make_cmip6(overrides={"units": "degC"}, seed=7)
original_values = dataset["tas"].values.copy()
dataset
dataset = make_cmip6(overrides={"units": "degC"}, seed=7)
original_values = dataset["tas"].values.copy()
dataset
Out[2]:
<xarray.Dataset> Size: 32kB
Dimensions: (time: 12, lat: 18, lon: 36)
Coordinates:
* time (time) datetime64[s] 96B 2000-01-01 2000-02-01 ... 2000-12-01
* lat (lat) float64 144B -85.0 -75.0 -65.0 -55.0 ... 55.0 65.0 75.0 85.0
* lon (lon) float64 288B 0.0 10.0 20.0 30.0 ... 320.0 330.0 340.0 350.0
Data variables:
tas (time, lat, lon) float32 31kB 251.3 251.4 251.5 ... 249.7 249.8
Attributes: (12/15)
project_id: CMIP6
dataset_id: CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3....
source_file: CMIP6.CMIP.MOHC.HadGEM3-GC31-LL.historical.r1i1p1f3....
source_id: HadGEM3-GC31-LL
source_name: HadGEM3-GC31-LL
mip_era: CMIP6
... ...
variable_id: tas
table_id: Amon
units: degC
frequency: mon
grid_label: gn
nominal_resolution: 250 kmLoad the recipe and inspect the selected core units fix.
In [3]:
Copied!
recipe = woodpecker.recipe.get("cmip6.core_units")
recipe.model_dump()
recipe = woodpecker.recipe.get("cmip6.core_units")
recipe.model_dump()
Out[3]:
{'id': 'cmip6.core_units',
'aliases': [],
'description': '',
'match': {'attrs': {'project_id': 'CMIP6', 'activity_id': 'CMIP'},
'dataset_id_patterns': ['CMIP6.CMIP.*.Amon.tas.*'],
'path_patterns': []},
'steps': [{'id': 'woodpecker.normalize_tas_units_to_kelvin',
'phase': 'apply',
'options': {},
'links': []}],
'links': [{'rel': 'self',
'href': 'https://github.com/roocs/woodpecker/blob/main/woodpecker/recipes/recipes/cmip6_core_recipe.yaml',
'title': 'Source recipe document'}]}
In [4]:
Copied!
findings = woodpecker.recipe.check(dataset, recipe)
findings.fix_ids
findings = woodpecker.recipe.check(dataset, recipe)
findings.fix_ids
Out[4]:
('woodpecker.normalize_tas_units_to_kelvin',)
Dry-run previews the repair without changing the dataset.
In [5]:
Copied!
result = woodpecker.recipe.apply(dataset, recipe, dry_run=True)
(
result.stats,
result.preview,
dataset["tas"].attrs["units"],
np.allclose(dataset["tas"].values, original_values),
)
result = woodpecker.recipe.apply(dataset, recipe, dry_run=True)
(
result.stats,
result.preview,
dataset["tas"].attrs["units"],
np.allclose(dataset["tas"].values, original_values),
)
Out[5]:
({'attempted': 1,
'changed': 1,
'persist_attempted': 0,
'persisted': 0,
'persist_failed': 0,
'preview': [{'path': 'HadGEM3-GC31-LL',
'fix_id': 'woodpecker.normalize_tas_units_to_kelvin',
'name': 'Normalize tas-like units to Kelvin',
'labels': ['risk.value_transformation'],
'label_titles': ['careful: value transformation'],
'label_metadata': [{'id': 'risk.value_transformation',
'title': 'careful: value transformation',
'description': 'Transforms data or coordinate values.',
'category': 'risk-medium'}],
'changed': True}]},
({'path': 'HadGEM3-GC31-LL',
'fix_id': 'woodpecker.normalize_tas_units_to_kelvin',
'name': 'Normalize tas-like units to Kelvin',
'labels': ['risk.value_transformation'],
'label_titles': ['careful: value transformation'],
'label_metadata': [{'id': 'risk.value_transformation',
'title': 'careful: value transformation',
'description': 'Transforms data or coordinate values.',
'category': 'risk-medium'}],
'changed': True},),
'degC',
True)
Apply the recipe in memory and re-check.
In [6]:
Copied!
write = woodpecker.recipe.apply(dataset, recipe, dry_run=False)
(
write.stats,
dataset["tas"].attrs["units"],
np.allclose(dataset["tas"].values, original_values + 273.15),
)
write = woodpecker.recipe.apply(dataset, recipe, dry_run=False)
(
write.stats,
dataset["tas"].attrs["units"],
np.allclose(dataset["tas"].values, original_values + 273.15),
)
Out[6]:
({'attempted': 1,
'changed': 1,
'persist_attempted': 1,
'persisted': 1,
'persist_failed': 0,
'preview': [{'path': 'HadGEM3-GC31-LL',
'fix_id': 'woodpecker.normalize_tas_units_to_kelvin',
'name': 'Normalize tas-like units to Kelvin',
'labels': ['risk.value_transformation'],
'label_titles': ['careful: value transformation'],
'label_metadata': [{'id': 'risk.value_transformation',
'title': 'careful: value transformation',
'description': 'Transforms data or coordinate values.',
'category': 'risk-medium'}],
'changed': True}]},
'K',
True)
In [7]:
Copied!
recheck = woodpecker.recipe.check(dataset, recipe)
bool(recheck)
recheck = woodpecker.recipe.check(dataset, recipe)
bool(recheck)
Out[7]:
False