-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ESMValTool Transient Climate Response recipe (#62)
- Loading branch information
1 parent
6dd6995
commit a291dd6
Showing
8 changed files
with
317 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added Transient Climate Response (TCS) to the ESMValTool metrics package. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/tcr.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
from pathlib import Path | ||
|
||
import pandas | ||
import xarray | ||
|
||
from cmip_ref_core.datasets import FacetFilter, SourceDatasetType | ||
from cmip_ref_core.metrics import DataRequirement | ||
from cmip_ref_metrics_esmvaltool._version import __version__ | ||
from cmip_ref_metrics_esmvaltool.metrics.base import ESMValToolMetric | ||
from cmip_ref_metrics_esmvaltool.recipe import dataframe_to_recipe | ||
from cmip_ref_metrics_esmvaltool.types import OutputBundle, Recipe | ||
|
||
|
||
class TransientClimateResponse(ESMValToolMetric): | ||
""" | ||
Calculate the global mean transient climate response for a dataset. | ||
""" | ||
|
||
name = "Transient Climate Response" | ||
slug = "esmvaltool-transient-climate-response" | ||
base_recipe = "recipe_tcr.yml" | ||
|
||
data_requirements = ( | ||
DataRequirement( | ||
source_type=SourceDatasetType.CMIP6, | ||
filters=( | ||
FacetFilter( | ||
facets={ | ||
"variable_id": ("tas",), | ||
"experiment_id": ( | ||
"1pctCO2", | ||
"piControl", | ||
), | ||
}, | ||
), | ||
), | ||
# TODO: Select only datasets that have both experiments | ||
# TODO: Select only datasets that have a contiguous, shared timerange | ||
# TODO: Add cell areas to the groups | ||
# constraints=(AddCellAreas(),), | ||
group_by=("source_id", "variant_label"), | ||
), | ||
) | ||
|
||
@staticmethod | ||
def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None: | ||
"""Update the recipe.""" | ||
# Only run the diagnostic that computes TCR for a single model. | ||
recipe["diagnostics"] = { | ||
"cmip6": { | ||
"description": "Calculate TCR.", | ||
"variables": { | ||
"tas": { | ||
"preprocessor": "spatial_mean", | ||
}, | ||
}, | ||
"scripts": { | ||
"tcr": { | ||
"script": "climate_metrics/tcr.py", | ||
"calculate_mmm": False, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
# Prepare updated datasets section in recipe. It contains two | ||
# datasets, one for the "1pctCO2" and one for the "piControl" | ||
# experiment. | ||
recipe_variables = dataframe_to_recipe(input_files) | ||
|
||
# Select a timerange covered by all datasets. | ||
start_times, end_times = [], [] | ||
for variable in recipe_variables.values(): | ||
for dataset in variable["additional_datasets"]: | ||
start, end = dataset["timerange"].split("/") | ||
start_times.append(start) | ||
end_times.append(end) | ||
timerange = f"{max(start_times)}/{min(end_times)}" | ||
|
||
datasets = recipe_variables["tas"]["additional_datasets"] | ||
for dataset in datasets: | ||
dataset["timerange"] = timerange | ||
|
||
recipe["datasets"] = datasets | ||
|
||
@staticmethod | ||
def format_result(result_dir: Path) -> OutputBundle: | ||
"""Format the result.""" | ||
tcr_file = result_dir / "work/cmip6/tcr/tcr.nc" | ||
tcr = xarray.open_dataset(tcr_file) | ||
|
||
source_id = tcr.dataset.values[0].decode("utf-8") | ||
cmec_output = { | ||
"DIMENSIONS": { | ||
"dimensions": { | ||
"source_id": {source_id: {}}, | ||
"region": {"global": {}}, | ||
"variable": {"tcr": {}}, | ||
}, | ||
"json_structure": [ | ||
"model", | ||
"region", | ||
"statistic", | ||
], | ||
}, | ||
# Is the schema tracked? | ||
"SCHEMA": { | ||
"name": "CMEC-REF", | ||
"package": "cmip_ref_metrics_esmvaltool", | ||
"version": __version__, | ||
}, | ||
"RESULTS": { | ||
source_id: {"global": {"tcr": float(tcr.tcr.values[0])}}, | ||
}, | ||
} | ||
|
||
return cmec_output |
1 change: 1 addition & 0 deletions
1
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipes.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
examples/recipe_python.yml ab3f06d269bb2c1368f4dc39da9bcb232fb2adb1fa556ba769e6c16294ffb4a3 | ||
recipe_ecs.yml 0cc57034fcb64e32015b4ff949ece5df8cdb8c6f493618b50ceded119fb37918 | ||
recipe_tcr.yml 35f9ef035a4e71aff5cac5dd26c49da2162fc00291bf3b0bd16b661b7b2f606b |
146 changes: 146 additions & 0 deletions
146
packages/ref-metrics-esmvaltool/tests/unit/metrics/input_files_tcr.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
{ | ||
"start_time": { | ||
"94": "0101-01-16T12:00:00.000", | ||
"92": "0101-01-16T12:00:00.000" | ||
}, | ||
"end_time": { | ||
"94": "0250-12-16T12:00:00.000", | ||
"92": "0600-12-16T12:00:00.000" | ||
}, | ||
"path": { | ||
"94": "/home/bandela/climate_data/CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/1pctCO2/r1i1p1f1/Amon/tas/gn/v20191115/tas_Amon_ACCESS-ESM1-5_1pctCO2_r1i1p1f1_gn_010101-025012.nc", | ||
"92": "/home/bandela/climate_data/CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/Amon/tas/gn/v20210316/tas_Amon_ACCESS-ESM1-5_piControl_r1i1p1f1_gn_010101-060012.nc" | ||
}, | ||
"activity_id": { | ||
"94": "CMIP", | ||
"92": "CMIP" | ||
}, | ||
"branch_method": { | ||
"94": "standard", | ||
"92": "standard" | ||
}, | ||
"branch_time_in_child": { | ||
"94": 0.0, | ||
"92": 0.0 | ||
}, | ||
"branch_time_in_parent": { | ||
"94": 0.0, | ||
"92": 36524.0 | ||
}, | ||
"experiment": { | ||
"94": "1 percent per year increase in CO2", | ||
"92": "pre-industrial control" | ||
}, | ||
"experiment_id": { | ||
"94": "1pctCO2", | ||
"92": "piControl" | ||
}, | ||
"frequency": { | ||
"94": "mon", | ||
"92": "mon" | ||
}, | ||
"grid": { | ||
"94": "native atmosphere N96 grid (145x192 latxlon)", | ||
"92": "native atmosphere N96 grid (145x192 latxlon)" | ||
}, | ||
"grid_label": { | ||
"94": "gn", | ||
"92": "gn" | ||
}, | ||
"institution_id": { | ||
"94": "CSIRO", | ||
"92": "CSIRO" | ||
}, | ||
"nominal_resolution": { | ||
"94": "250 km", | ||
"92": "250 km" | ||
}, | ||
"parent_activity_id": { | ||
"94": "CMIP", | ||
"92": "CMIP" | ||
}, | ||
"parent_experiment_id": { | ||
"94": "piControl", | ||
"92": "piControl-spinup" | ||
}, | ||
"parent_source_id": { | ||
"94": "ACCESS-ESM1-5", | ||
"92": "ACCESS-ESM1-5" | ||
}, | ||
"parent_time_units": { | ||
"94": "days since 0101-01-01", | ||
"92": "days since 0001-01-01" | ||
}, | ||
"parent_variant_label": { | ||
"94": "r1i1p1f1", | ||
"92": "r1i1p1f1" | ||
}, | ||
"product": { | ||
"94": "model-output", | ||
"92": "model-output" | ||
}, | ||
"realm": { | ||
"94": "atmos", | ||
"92": "atmos" | ||
}, | ||
"source_id": { | ||
"94": "ACCESS-ESM1-5", | ||
"92": "ACCESS-ESM1-5" | ||
}, | ||
"source_type": { | ||
"94": "AOGCM", | ||
"92": "AOGCM" | ||
}, | ||
"sub_experiment": { | ||
"94": "none", | ||
"92": "none" | ||
}, | ||
"sub_experiment_id": { | ||
"94": "none", | ||
"92": "none" | ||
}, | ||
"table_id": { | ||
"94": "Amon", | ||
"92": "Amon" | ||
}, | ||
"variable_id": { | ||
"94": "tas", | ||
"92": "tas" | ||
}, | ||
"variant_label": { | ||
"94": "r1i1p1f1", | ||
"92": "r1i1p1f1" | ||
}, | ||
"member_id": { | ||
"94": "r1i1p1f1", | ||
"92": "r1i1p1f1" | ||
}, | ||
"standard_name": { | ||
"94": "air_temperature", | ||
"92": "air_temperature" | ||
}, | ||
"long_name": { | ||
"94": "Near-Surface Air Temperature", | ||
"92": "Near-Surface Air Temperature" | ||
}, | ||
"units": { | ||
"94": "K", | ||
"92": "K" | ||
}, | ||
"vertical_levels": { | ||
"94": 1, | ||
"92": 1 | ||
}, | ||
"init_year": { | ||
"94": null, | ||
"92": null | ||
}, | ||
"version": { | ||
"94": "v20191115", | ||
"92": "v20210316" | ||
}, | ||
"instance_id": { | ||
"94": "CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.1pctCO2.r1i1p1f1.Amon.tas.gn.v20191115", | ||
"92": "CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.piControl.r1i1p1f1.Amon.tas.gn.v20210316" | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
packages/ref-metrics-esmvaltool/tests/unit/metrics/test_tcr.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from pathlib import Path | ||
|
||
import numpy as np | ||
import pandas | ||
import xarray as xr | ||
from cmip_ref_metrics_esmvaltool.metrics import TransientClimateResponse | ||
from cmip_ref_metrics_esmvaltool.recipe import load_recipe | ||
|
||
|
||
def test_update_recipe(): | ||
input_files = pandas.read_json(Path(__file__).parent / "input_files_tcr.json") | ||
recipe = load_recipe("recipe_tcr.yml") | ||
TransientClimateResponse().update_recipe(recipe, input_files) | ||
assert len(recipe["datasets"]) == 2 | ||
assert len(recipe["diagnostics"]) == 1 | ||
assert set(recipe["diagnostics"]["cmip6"]["variables"]) == {"tas"} | ||
|
||
|
||
def test_format_output(tmp_path): | ||
tcr = xr.Dataset( | ||
data_vars={ | ||
"tcr": (["dim0"], np.array([1.0], dtype=np.float32)), | ||
}, | ||
coords={ | ||
"dataset": ("dim0", np.array([b"abc"])), | ||
}, | ||
) | ||
result_dir = tmp_path | ||
subdir = result_dir / "work" / "cmip6" / "tcr" | ||
subdir.mkdir(parents=True) | ||
tcr.to_netcdf(subdir / "tcr.nc") | ||
|
||
output_bundle = TransientClimateResponse().format_result(result_dir) | ||
|
||
assert isinstance(output_bundle, dict) | ||
assert output_bundle["RESULTS"]["abc"]["global"]["tcr"] == 1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters