-
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.
Merge pull request #66 from nocollier/ilamb3
ilamb3 integration
- Loading branch information
Showing
10 changed files
with
333 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
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 a sample metric to the ilamb 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# ref-metrics-ilamb | ||
|
||
Use [ILAMB](https://github.com/rubisco-sfa/ilamb3) as a REF metrics provider. See [ilamb.org](https://www.ilamb.org/) for more information on project goals and resources. | ||
|
||
See [running-metrics-locally](https://cmip-ref.readthedocs.io/en/latest/how-to-guides/running-metrics-locally/) for usage instructions. |
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,40 @@ | ||
[project] | ||
name = "cmip_ref_metrics_ilamb" | ||
version = "0.1.5" | ||
description = "ILAMB metrics provider for the CMIP Rapid Evaluation Framework" | ||
readme = "README.md" | ||
authors = [ | ||
{ name = "Nathan Collier", email = "nathaniel.collier@gmail.com" } | ||
] | ||
requires-python = ">=3.10" | ||
classifiers = [ | ||
"Development Status :: 4 - Beta", | ||
"Intended Audience :: Developers", | ||
"Operating System :: OS Independent", | ||
"Intended Audience :: Science/Research", | ||
"Programming Language :: Python", | ||
"Programming Language :: Python :: 3", | ||
"Programming Language :: Python :: 3.10", | ||
"Programming Language :: Python :: 3.11", | ||
"Programming Language :: Python :: 3.12", | ||
"Programming Language :: Python :: 3.13", | ||
"Topic :: Scientific/Engineering", | ||
] | ||
dependencies = [ | ||
"cmip_ref_core", | ||
"ilamb3" | ||
] | ||
|
||
[tool.uv.sources] | ||
ilamb3 = { git = "https://github.com/rubisco-sfa/ilamb3" } | ||
|
||
[project.license] | ||
text = "Apache-2.0" | ||
|
||
[tool.uv] | ||
dev-dependencies = [ | ||
] | ||
|
||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" |
14 changes: 14 additions & 0 deletions
14
packages/ref-metrics-ilamb/src/cmip_ref_metrics_ilamb/__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,14 @@ | ||
""" | ||
Rapid evaluating CMIP data | ||
""" | ||
|
||
import importlib.metadata | ||
|
||
from cmip_ref_core.providers import MetricsProvider | ||
from cmip_ref_metrics_ilamb.example import GlobalMeanTimeseries | ||
|
||
__version__ = importlib.metadata.version("cmip_ref_metrics_ilamb") | ||
|
||
# Initialise the metrics manager and register the example metric | ||
provider = MetricsProvider("ILAMB", __version__) | ||
provider.register(GlobalMeanTimeseries()) |
107 changes: 107 additions & 0 deletions
107
packages/ref-metrics-ilamb/src/cmip_ref_metrics_ilamb/example.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,107 @@ | ||
from pathlib import Path | ||
from typing import Any | ||
|
||
import xarray as xr | ||
from ilamb3.dataset import integrate_space # type: ignore | ||
|
||
from cmip_ref_core.datasets import FacetFilter, SourceDatasetType | ||
from cmip_ref_core.metrics import DataRequirement, Metric, MetricExecutionDefinition, MetricResult | ||
|
||
|
||
def calculate_global_mean_timeseries(input_files: list[Path]) -> xr.Dataset: | ||
""" | ||
Calculate the global mean timeseries for a dataset. | ||
Parameters | ||
---------- | ||
input_files | ||
List of input files to calculate the annual mean timeseries. | ||
Returns | ||
------- | ||
: | ||
The annual mean timeseries of the dataset | ||
""" | ||
ds = xr.open_mfdataset(input_files, combine="by_coords", chunks=None, use_cftime=True) | ||
mean: xr.Dataset = integrate_space(ds, "tas", mean=True).to_dataset() | ||
return mean | ||
|
||
|
||
def format_cmec_output_bundle(dataset: xr.Dataset) -> dict[str, Any]: | ||
""" | ||
Create a simple CMEC output bundle for the dataset. | ||
Parameters | ||
---------- | ||
dataset | ||
Processed dataset | ||
Returns | ||
------- | ||
A CMEC output bundle ready to be written to disk | ||
""" | ||
cmec_output = { | ||
"DIMENSIONS": { | ||
"dimensions": { | ||
"source_id": {dataset.attrs["source_id"]: {}}, | ||
"region": {"global": {}}, | ||
"variable": {"tas": {}}, | ||
}, | ||
"json_structure": [ | ||
"model", | ||
"region", | ||
"statistic", | ||
], | ||
}, | ||
"SCHEMA": { | ||
"name": "CMEC-REF", | ||
"package": "example", | ||
"version": "v1", | ||
}, | ||
"RESULTS": { | ||
dataset.attrs["source_id"]: {"global": {"tas": 0}}, | ||
}, | ||
} | ||
|
||
return cmec_output | ||
|
||
|
||
class GlobalMeanTimeseries(Metric): | ||
""" | ||
Calculate the global mean timeseries for a dataset | ||
""" | ||
|
||
name = "Global Mean Timeseries" | ||
slug = "global-mean-timeseries" | ||
|
||
data_requirements = ( | ||
DataRequirement( | ||
source_type=SourceDatasetType.CMIP6, | ||
filters=( | ||
FacetFilter(facets={"variable_id": ("tas", "rsut")}), | ||
FacetFilter(facets={"experiment_id": ("1pctCO2-*", "hist-*")}, keep=False), | ||
), | ||
group_by=("source_id", "variable_id", "experiment_id", "variant_label"), | ||
), | ||
) | ||
|
||
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_datasets = definition.metric_dataset[SourceDatasetType.CMIP6] | ||
global_mean_timeseries = calculate_global_mean_timeseries(input_files=input_datasets.path.to_list()) | ||
|
||
return MetricResult.build_from_output_bundle( | ||
definition, format_cmec_output_bundle(global_mean_timeseries) | ||
) |
Empty file.
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,60 @@ | ||
import pathlib | ||
|
||
import pytest | ||
from cmip_ref_metrics_ilamb.example import GlobalMeanTimeseries, calculate_global_mean_timeseries | ||
|
||
from cmip_ref_core.datasets import DatasetCollection, MetricDataset, SourceDatasetType | ||
from cmip_ref_core.metrics import MetricExecutionDefinition | ||
|
||
|
||
@pytest.fixture | ||
def metric_dataset(cmip6_data_catalog) -> MetricDataset: | ||
selected_dataset = cmip6_data_catalog[ | ||
cmip6_data_catalog["instance_id"] | ||
== "CMIP6.ScenarioMIP.CSIRO.ACCESS-ESM1-5.ssp126.r1i1p1f1.Amon.tas.gn.v20210318" | ||
] | ||
return MetricDataset( | ||
{ | ||
SourceDatasetType.CMIP6: DatasetCollection( | ||
selected_dataset, | ||
"instance_id", | ||
) | ||
} | ||
) | ||
|
||
|
||
def test_annual_mean(metric_dataset): | ||
annual_mean = calculate_global_mean_timeseries(metric_dataset["cmip6"].path.to_list()) | ||
assert annual_mean.time.size == 572 | ||
|
||
|
||
def test_example_metric(tmp_path, cmip6_data_catalog, mocker): | ||
metric = GlobalMeanTimeseries() | ||
ds = cmip6_data_catalog.groupby("instance_id").first() | ||
output_directory = tmp_path / "output" | ||
|
||
mock_calc = mocker.patch("cmip_ref_metrics_ilamb.example.calculate_global_mean_timeseries") | ||
mock_calc.return_value.attrs.__getitem__.return_value = "ABC" | ||
|
||
definition = MetricExecutionDefinition( | ||
output_directory=output_directory, | ||
output_fragment=pathlib.Path(metric.slug), | ||
key="global_mean_timeseries", | ||
metric_dataset=MetricDataset( | ||
{ | ||
SourceDatasetType.CMIP6: DatasetCollection(ds, "instance_id"), | ||
} | ||
), | ||
) | ||
|
||
result = metric.run(definition) | ||
|
||
assert mock_calc.call_count == 1 | ||
|
||
assert str(result.bundle_filename) == "output.json" | ||
|
||
output_bundle_path = definition.output_directory / definition.output_fragment / result.bundle_filename | ||
|
||
assert result.successful | ||
assert output_bundle_path.exists() | ||
assert output_bundle_path.is_file() |
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 @@ | ||
from cmip_ref_metrics_ilamb import __version__, provider | ||
|
||
|
||
def test_provider(): | ||
assert provider.name == "ILAMB" | ||
assert provider.slug == "ilamb" | ||
assert provider.version == __version__ | ||
|
||
assert len(provider) == 1 |
Oops, something went wrong.