-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ESMValTool Equilibrium Climate Sensitivity recipe (#51)
Co-authored-by: Jared Lewis <jared@jared.kiwi.nz>
- Loading branch information
1 parent
b0d2c90
commit 6dd6995
Showing
15 changed files
with
719 additions
and
133 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 Equilibrium Climate Sensitivity (ECS) 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
3 changes: 3 additions & 0 deletions
3
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/_version.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,3 @@ | ||
import importlib | ||
|
||
__version__ = importlib.metadata.version("cmip_ref_metrics_esmvaltool") |
110 changes: 0 additions & 110 deletions
110
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/example.py
This file was deleted.
Oops, something went wrong.
9 changes: 9 additions & 0 deletions
9
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/__init__.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,9 @@ | ||
"""ESMValTool metrics.""" | ||
|
||
from cmip_ref_metrics_esmvaltool.metrics.ecs import EquilibriumClimateSensitivity | ||
from cmip_ref_metrics_esmvaltool.metrics.example import GlobalMeanTimeseries | ||
|
||
__all__ = [ | ||
"EquilibriumClimateSensitivity", | ||
"GlobalMeanTimeseries", | ||
] |
68 changes: 68 additions & 0 deletions
68
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/base.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,68 @@ | ||
from abc import abstractmethod | ||
from pathlib import Path | ||
from typing import ClassVar | ||
|
||
import pandas | ||
|
||
from cmip_ref_core.datasets import SourceDatasetType | ||
from cmip_ref_core.metrics import Metric, MetricExecutionDefinition, MetricResult | ||
from cmip_ref_metrics_esmvaltool.recipe import load_recipe, run_recipe | ||
from cmip_ref_metrics_esmvaltool.types import OutputBundle, Recipe | ||
|
||
|
||
class ESMValToolMetric(Metric): | ||
"""ESMValTool Metric base class.""" | ||
|
||
base_recipe: ClassVar | ||
|
||
@staticmethod | ||
@abstractmethod | ||
def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None: | ||
""" | ||
Update the base recipe for the run. | ||
Parameters | ||
---------- | ||
recipe: | ||
The base recipe to update. | ||
input_files: | ||
The dataframe describing the input files. | ||
""" | ||
|
||
@staticmethod | ||
@abstractmethod | ||
def format_result(result_dir: Path) -> OutputBundle: | ||
""" | ||
Create a CMEC output bundle for the results. | ||
Parameters | ||
---------- | ||
result_dir | ||
Directory containing results from an ESMValTool run. | ||
Returns | ||
------- | ||
A CMEC output bundle. | ||
""" | ||
|
||
def run(self, definition: MetricExecutionDefinition) -> MetricResult: | ||
""" | ||
Run a metric | ||
Parameters | ||
---------- | ||
definition | ||
A description of the information needed for this execution of the metric | ||
Returns | ||
------- | ||
: | ||
The result of running the metric. | ||
""" | ||
input_files = definition.metric_dataset[SourceDatasetType.CMIP6].datasets | ||
recipe = load_recipe(self.base_recipe) | ||
self.update_recipe(recipe, input_files) | ||
result_dir = run_recipe(recipe, definition) | ||
output_bundle = self.format_result(result_dir) | ||
return MetricResult.build_from_output_bundle(definition, output_bundle) |
126 changes: 126 additions & 0 deletions
126
packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/ecs.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,126 @@ | ||
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 EquilibriumClimateSensitivity(ESMValToolMetric): | ||
""" | ||
Calculate the global mean equilibrium climate sensitivity for a dataset. | ||
""" | ||
|
||
name = "Equilibrium Climate Sensitivity" | ||
slug = "esmvaltool-equilibrium-climate-sensitivity" | ||
base_recipe = "recipe_ecs.yml" | ||
|
||
data_requirements = ( | ||
DataRequirement( | ||
source_type=SourceDatasetType.CMIP6, | ||
filters=( | ||
FacetFilter( | ||
facets={ | ||
"variable_id": ( | ||
"rlut", | ||
"rsdt", | ||
"rsut", | ||
"tas", | ||
), | ||
"experiment_id": ( | ||
"abrupt-4xCO2", | ||
"piControl", | ||
), | ||
}, | ||
), | ||
), | ||
# TODO: Select only datasets that have both experiments and all four variables | ||
# 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 ECS for a single model. | ||
recipe["diagnostics"] = { | ||
"cmip6": { | ||
"description": "Calculate ECS.", | ||
"variables": { | ||
"tas": { | ||
"preprocessor": "spatial_mean", | ||
}, | ||
"rtnt": { | ||
"preprocessor": "spatial_mean", | ||
"derive": True, | ||
}, | ||
}, | ||
"scripts": { | ||
"ecs": { | ||
"script": "climate_metrics/ecs.py", | ||
"calculate_mmm": False, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
# Prepare updated datasets section in recipe. It contains two | ||
# datasets, one for the "abrupt-4xCO2" 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.""" | ||
ecs_file = result_dir / "work/cmip6/ecs/ecs.nc" | ||
ecs = xarray.open_dataset(ecs_file) | ||
|
||
source_id = ecs.dataset.values[0].decode("utf-8") | ||
cmec_output = { | ||
"DIMENSIONS": { | ||
"dimensions": { | ||
"source_id": {source_id: {}}, | ||
"region": {"global": {}}, | ||
"variable": {"ecs": {}}, | ||
}, | ||
"json_structure": [ | ||
"model", | ||
"region", | ||
"statistic", | ||
], | ||
}, | ||
# Is the schema tracked? | ||
"SCHEMA": { | ||
"name": "CMEC-REF", | ||
"package": "cmip_ref_metrics_esmvaltool", | ||
"version": __version__, | ||
}, | ||
"RESULTS": { | ||
source_id: {"global": {"ecs": ecs.ecs.values[0]}}, | ||
}, | ||
} | ||
|
||
return cmec_output |
Oops, something went wrong.