diff --git a/changelog/208.feature.md b/changelog/208.feature.md new file mode 100644 index 000000000..b89816cd6 --- /dev/null +++ b/changelog/208.feature.md @@ -0,0 +1 @@ +Added Transient Climate Response to Cumulative CO2 Emissions (TCRE) metric to the ESMValTool metrics package. diff --git a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/__init__.py b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/__init__.py index 21ada8194..0542baad4 100644 --- a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/__init__.py +++ b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/__init__.py @@ -3,9 +3,11 @@ from cmip_ref_metrics_esmvaltool.metrics.ecs import EquilibriumClimateSensitivity from cmip_ref_metrics_esmvaltool.metrics.example import GlobalMeanTimeseries from cmip_ref_metrics_esmvaltool.metrics.tcr import TransientClimateResponse +from cmip_ref_metrics_esmvaltool.metrics.tcre import TransientClimateResponseEmissions __all__ = [ "EquilibriumClimateSensitivity", "GlobalMeanTimeseries", "TransientClimateResponse", + "TransientClimateResponseEmissions", ] diff --git a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/tcre.py b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/tcre.py new file mode 100644 index 000000000..d5e1aa5c9 --- /dev/null +++ b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/metrics/tcre.py @@ -0,0 +1,125 @@ +from pathlib import Path + +import pandas +import xarray + +from cmip_ref_core.constraints import ( + AddSupplementaryDataset, + RequireContiguousTimerange, + RequireFacets, + RequireOverlappingTimerange, +) +from cmip_ref_core.datasets import FacetFilter, SourceDatasetType +from cmip_ref_core.metrics import DataRequirement +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 TransientClimateResponseEmissions(ESMValToolMetric): + """ + Calculate the global mean Transient Climate Response to Cumulative CO2 Emissions. + """ + + name = "Transient Climate Response to Cumulative CO2 Emissions" + slug = "esmvaltool-transient-climate-response-emissions" + base_recipe = "recipe_tcre.yml" + + experiments = ( + "esm-1pctCO2", + "esm-piControl", + ) + variables = ( + "tas", + "fco2antt", + ) + data_requirements = ( + DataRequirement( + source_type=SourceDatasetType.CMIP6, + filters=( + FacetFilter( + facets={ + "variable_id": variables, + "frequency": "mon", + "experiment_id": experiments, + }, + ), + FacetFilter( + facets={ + "variable_id": "fco2antt", + "experiment_id": "esm-piControl", + }, + keep=False, + ), + ), + group_by=("source_id", "member_id", "grid_label"), + constraints=( + RequireFacets("experiment_id", experiments), + RequireFacets("variable_id", variables), + RequireContiguousTimerange(group_by=("instance_id",)), + RequireOverlappingTimerange(group_by=("instance_id",)), + AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6), + ), + ), + ) + + @staticmethod + def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None: + """Update the recipe.""" + # Prepare updated datasets section in recipe. It contains three + # datasets, "tas" and "fco2antt" for the "esm-1pctCO2" and just "tas" + # for the "esm-piControl" experiment. + recipe_variables = dataframe_to_recipe(input_files) + tas_esm_1pctCO2 = next( + ds for ds in recipe_variables["tas"]["additional_datasets"] if ds["exp"] == "esm-1pctCO2" + ) + fco2antt_esm_1pctCO2 = next( + ds for ds in recipe_variables["fco2antt"]["additional_datasets"] if ds["exp"] == "esm-1pctCO2" + ) + tas_esm_piControl = next( + ds for ds in recipe_variables["tas"]["additional_datasets"] if ds["exp"] == "esm-piControl" + ) + tas_esm_piControl["timerange"] = tas_esm_1pctCO2["timerange"] + + recipe["diagnostics"]["tcre"]["variables"] = { + "tas_esm-1pctCO2": { + "short_name": "tas", + "preprocessor": "global_annual_mean_anomaly", + "additional_datasets": [tas_esm_1pctCO2], + }, + "tas_esm-piControl": { + "short_name": "tas", + "preprocessor": "global_annual_mean_anomaly", + "additional_datasets": [tas_esm_piControl], + }, + "fco2antt": { + "preprocessor": "global_cumulative_sum", + "additional_datasets": [fco2antt_esm_1pctCO2], + }, + } + recipe["diagnostics"].pop("barplot") + + @staticmethod + def format_result(result_dir: Path) -> OutputBundle: + """Format the result.""" + tcre_file = result_dir / "work/tcre/calculate_tcre/tcre.nc" + tcre = xarray.open_dataset(tcre_file) + + source_id = tcre.dataset.values[0].decode("utf-8") + cmec_output = { + "DIMENSIONS": { + "model": {source_id: {}}, + "region": {"global": {}}, + "metric": {"tcre": {}}, + "json_structure": [ + "model", + "region", + "metric", + ], + }, + "RESULTS": { + source_id: {"global": {"tcre": float(tcre.tcre.values[0])}}, + }, + } + + return cmec_output diff --git a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipe.py b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipe.py index f53b8fdd8..3d0ba1624 100644 --- a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipe.py +++ b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipe.py @@ -113,12 +113,15 @@ def dataframe_to_recipe(files: pd.DataFrame) -> dict[str, Any]: return variables -_ESMVALTOOL_VERSION = "2.11.0" +_ESMVALTOOL_VERSION = "2.13.0.dev10+g7883d411e" +_ESMVALTOOL_COMMIT = _ESMVALTOOL_VERSION.split("+")[1][1:] _RECIPES = pooch.create( path=pooch.os_cache("cmip_ref_metrics_esmvaltool"), - base_url="https://raw.githubusercontent.com/ESMValGroup/ESMValTool/refs/tags/v{version}/esmvaltool/recipes/", - version=_ESMVALTOOL_VERSION, + # TODO: use a released version + # base_url="https://raw.githubusercontent.com/ESMValGroup/ESMValTool/refs/tags/v{version}/esmvaltool/recipes/", + # version=_ESMVALTOOL_VERSION, + base_url=f"https://raw.githubusercontent.com/ESMValGroup/ESMValTool/{_ESMVALTOOL_COMMIT}/esmvaltool/recipes/", env="REF_METRICS_ESMVALTOOL_DATA_DIR", ) _RECIPES.load_registry(importlib.resources.open_binary("cmip_ref_metrics_esmvaltool", "recipes.txt")) diff --git a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipes.txt b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipes.txt index fc91638a5..0b2a76575 100644 --- a/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipes.txt +++ b/packages/ref-metrics-esmvaltool/src/cmip_ref_metrics_esmvaltool/recipes.txt @@ -1,3 +1,4 @@ examples/recipe_python.yml ab3f06d269bb2c1368f4dc39da9bcb232fb2adb1fa556ba769e6c16294ffb4a3 recipe_ecs.yml 0cc57034fcb64e32015b4ff949ece5df8cdb8c6f493618b50ceded119fb37918 recipe_tcr.yml 35f9ef035a4e71aff5cac5dd26c49da2162fc00291bf3b0bd16b661b7b2f606b +recipe_tcre.yml 4668e357e00c515a8264ac75cb319ce558289689e10189e6f9e982886c414c94 diff --git a/packages/ref-metrics-esmvaltool/tests/unit/metrics/input_files_tcre.json b/packages/ref-metrics-esmvaltool/tests/unit/metrics/input_files_tcre.json new file mode 100644 index 000000000..21ed719e9 --- /dev/null +++ b/packages/ref-metrics-esmvaltool/tests/unit/metrics/input_files_tcre.json @@ -0,0 +1,496 @@ +[ + { + "start_time":"1850-01-16T12:00:00.000", + "end_time":"1869-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/MPI-M\/MPI-ESM1-2-LR\/esm-piControl\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_185001-186912.nc", + "activity_id":"CMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":146097.0, + "experiment":"pre-industrial control simulation with CO2 concentration calculated", + "experiment_id":"esm-piControl", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl-spinup", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1870-01-16T12:00:00.000", + "end_time":"1889-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/MPI-M\/MPI-ESM1-2-LR\/esm-piControl\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_187001-188912.nc", + "activity_id":"CMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":146097.0, + "experiment":"pre-industrial control simulation with CO2 concentration calculated", + "experiment_id":"esm-piControl", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl-spinup", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1890-01-16T12:00:00.000", + "end_time":"1909-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/MPI-M\/MPI-ESM1-2-LR\/esm-piControl\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_189001-190912.nc", + "activity_id":"CMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":146097.0, + "experiment":"pre-industrial control simulation with CO2 concentration calculated", + "experiment_id":"esm-piControl", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl-spinup", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1910-01-16T12:00:00.000", + "end_time":"1929-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/MPI-M\/MPI-ESM1-2-LR\/esm-piControl\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_191001-192912.nc", + "activity_id":"CMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":146097.0, + "experiment":"pre-industrial control simulation with CO2 concentration calculated", + "experiment_id":"esm-piControl", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl-spinup", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1850-01-16T12:00:00.000", + "end_time":"1869-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/fco2antt\/gn\/v20190815\/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_185001-186912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"fco2antt", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"tendency_of_atmosphere_mass_content_of_carbon_dioxide_expressed_as_carbon_due_to_anthropogenic_emission", + "long_name":"Carbon Mass Flux into Atmosphere Due to All Anthropogenic Emissions of CO2", + "units":"kg m-2 s-1", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815" + }, + { + "start_time":"1870-01-16T12:00:00.000", + "end_time":"1889-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/fco2antt\/gn\/v20190815\/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_187001-188912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"fco2antt", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"tendency_of_atmosphere_mass_content_of_carbon_dioxide_expressed_as_carbon_due_to_anthropogenic_emission", + "long_name":"Carbon Mass Flux into Atmosphere Due to All Anthropogenic Emissions of CO2", + "units":"kg m-2 s-1", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815" + }, + { + "start_time":"1890-01-16T12:00:00.000", + "end_time":"1909-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/fco2antt\/gn\/v20190815\/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_189001-190912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"fco2antt", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"tendency_of_atmosphere_mass_content_of_carbon_dioxide_expressed_as_carbon_due_to_anthropogenic_emission", + "long_name":"Carbon Mass Flux into Atmosphere Due to All Anthropogenic Emissions of CO2", + "units":"kg m-2 s-1", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815" + }, + { + "start_time":"1910-01-16T12:00:00.000", + "end_time":"1914-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/fco2antt\/gn\/v20190815\/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_191001-191412.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"fco2antt", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"tendency_of_atmosphere_mass_content_of_carbon_dioxide_expressed_as_carbon_due_to_anthropogenic_emission", + "long_name":"Carbon Mass Flux into Atmosphere Due to All Anthropogenic Emissions of CO2", + "units":"kg m-2 s-1", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.fco2antt.gn.v20190815" + }, + { + "start_time":"1850-01-16T12:00:00.000", + "end_time":"1869-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_185001-186912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1870-01-16T12:00:00.000", + "end_time":"1889-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_187001-188912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1890-01-16T12:00:00.000", + "end_time":"1909-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_189001-190912.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":"1910-01-16T12:00:00.000", + "end_time":"1914-12-16T12:00:00.000", + "path":"\/home\/bandela\/climate_data\/CMIP6\/C4MIP\/MPI-M\/MPI-ESM1-2-LR\/esm-1pctCO2\/r1i1p1f1\/Amon\/tas\/gn\/v20190815\/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_191001-191412.nc", + "activity_id":"C4MIP CDRMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":0.0, + "experiment":"emissions driven 1% run", + "experiment_id":"esm-1pctCO2", + "frequency":"mon", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"Amon", + "variable_id":"tas", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"air_temperature", + "long_name":"Near-Surface Air Temperature", + "units":"K", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.C4MIP CDRMIP.MPI-M.MPI-ESM1-2-LR.esm-1pctCO2.r1i1p1f1.Amon.tas.gn.v20190815" + }, + { + "start_time":null, + "end_time":null, + "path":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/MPI-M\/MPI-ESM1-2-LR\/esm-piControl\/r1i1p1f1\/fx\/areacella\/gn\/v20190815\/areacella_fx_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn.nc", + "activity_id":"CMIP", + "branch_method":"standard", + "branch_time_in_child":0.0, + "branch_time_in_parent":146097.0, + "experiment":"pre-industrial control simulation with CO2 concentration calculated", + "experiment_id":"esm-piControl", + "frequency":"fx", + "grid":"gn", + "grid_label":"gn", + "institution_id":"MPI-M", + "nominal_resolution":"250 km", + "parent_activity_id":"CMIP", + "parent_experiment_id":"esm-piControl-spinup", + "parent_source_id":"MPI-ESM1-2-LR", + "parent_time_units":"days since 1850-1-1 00:00:00", + "parent_variant_label":"r1i1p1f1", + "product":"model-output", + "realm":"atmos", + "source_id":"MPI-ESM1-2-LR", + "source_type":"AOGCM BGC", + "sub_experiment":"none", + "sub_experiment_id":"none", + "table_id":"fx", + "variable_id":"areacella", + "variant_label":"r1i1p1f1", + "member_id":"r1i1p1f1", + "standard_name":"cell_area", + "long_name":"Grid-Cell Area for Atmospheric Grid Variables", + "units":"m2", + "vertical_levels":1, + "init_year":null, + "version":"v20190815", + "instance_id":"CMIP6.CMIP.MPI-M.MPI-ESM1-2-LR.esm-piControl.r1i1p1f1.fx.areacella.gn.v20190815" + } +] diff --git a/packages/ref-metrics-esmvaltool/tests/unit/metrics/test_tcre.py b/packages/ref-metrics-esmvaltool/tests/unit/metrics/test_tcre.py new file mode 100644 index 000000000..6d7bb36d6 --- /dev/null +++ b/packages/ref-metrics-esmvaltool/tests/unit/metrics/test_tcre.py @@ -0,0 +1,88 @@ +from pathlib import Path + +import numpy as np +import pandas +import xarray as xr +from cmip_ref_metrics_esmvaltool.metrics import TransientClimateResponseEmissions +from cmip_ref_metrics_esmvaltool.recipe import load_recipe + + +def test_update_recipe(): + # Insert the following code in ZeroEmissionCommitment.update_recipe to + # save an example input dataframe: + # input_files.to_json(Path("input_files_tcre.json"), orient='records', indent=4, date_format="iso") + input_files = pandas.read_json(Path(__file__).parent / "input_files_tcre.json") + recipe = load_recipe("recipe_tcre.yml") + TransientClimateResponseEmissions().update_recipe(recipe, input_files) + assert recipe["diagnostics"]["tcre"]["variables"] == { + "tas_esm-1pctCO2": { + "short_name": "tas", + "preprocessor": "global_annual_mean_anomaly", + "additional_datasets": [ + { + "project": "CMIP6", + "activity": "C4MIP CDRMIP", + "dataset": "MPI-ESM1-2-LR", + "ensemble": "r1i1p1f1", + "institute": "MPI-M", + "exp": "esm-1pctCO2", + "grid": "gn", + "mip": "Amon", + "timerange": "18500116T120000/19141216T120000", + } + ], + }, + "tas_esm-piControl": { + "short_name": "tas", + "preprocessor": "global_annual_mean_anomaly", + "additional_datasets": [ + { + "project": "CMIP6", + "activity": "CMIP", + "dataset": "MPI-ESM1-2-LR", + "ensemble": "r1i1p1f1", + "institute": "MPI-M", + "exp": "esm-piControl", + "grid": "gn", + "mip": "Amon", + "timerange": "18500116T120000/19141216T120000", + } + ], + }, + "fco2antt": { + "preprocessor": "global_cumulative_sum", + "additional_datasets": [ + { + "project": "CMIP6", + "activity": "C4MIP CDRMIP", + "dataset": "MPI-ESM1-2-LR", + "ensemble": "r1i1p1f1", + "institute": "MPI-M", + "exp": "esm-1pctCO2", + "grid": "gn", + "mip": "Amon", + "timerange": "18500116T120000/19141216T120000", + } + ], + }, + } + + +def test_format_output(tmp_path): + tcr = xr.Dataset( + data_vars={ + "tcre": (["dim0"], np.array([1.0], dtype=np.float32)), + }, + coords={ + "dataset": ("dim0", np.array([b"abc"])), + }, + ) + result_dir = tmp_path + subdir = result_dir / "work" / "tcre" / "calculate_tcre" + subdir.mkdir(parents=True) + tcr.to_netcdf(subdir / "tcre.nc") + + output_bundle = TransientClimateResponseEmissions().format_result(result_dir) + + assert isinstance(output_bundle, dict) + assert output_bundle["RESULTS"]["abc"]["global"]["tcre"] == 1.0