Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog/241.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Added an ESMValTool metric to compute climatologies and zonal mean profiles of
cloud radiative effects.
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlut_200003-202311.nc ede887cf2d83c848a0d71316799232e4d717662bd2f78d5aa1fc166b41d9953b
ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlutcs_200003-202311.nc e70e3273092edf01527970693271641fc6474d1974887d7d272e7d656bab83c2
ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rsut_200003-202311.nc e31e648886c4fa9c09686672a06ab18fbba687ff0d6de2891616d4c8b74e215d
ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rsutcs_200003-202311.nc eb96edd9274670aa705eab2a6d1ee0cca11e01ac17096706463e032b58e6be47
ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rlut_198201-201612.nc 075144d673a9f2ff49fbe59e701535bf80c04908797a9dca83781000a9b1b7f2
ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rlutcs_198201-201612.nc 21f096ecafff659e5c7e3338060425f7194e5d1b39c9510865496e04ecac3d75
ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rsut_198201-201612.nc f2c3f3afcdc2e730df7985c210a3de89b0d4f83b150e0c3846f7ac3c5fa9c54a
ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rsutcs_198201-201612.nc d180d3140d4c1f6b9bb1960e07b45f192643f047e7c272c8c8c7070296ca3ab7
ESMValTool/OBS/Tier2/ISCCP-FH/OBS_ISCCP-FH_sat_v0_Amon_rlut_198401-201612.nc 650b347df432f6e5f3f693310aad695a7502f2905ac545753c7d4ccb0592adbe
ESMValTool/OBS/Tier2/ISCCP-FH/OBS_ISCCP-FH_sat_v0_Amon_rlutcs_198401-201612.nc a90d9e035447f8778a2f64362411c079536d9dea559f6d53d032710b2c9b00e3
ESMValTool/OBS/Tier2/ISCCP-FH/OBS_ISCCP-FH_sat_v0_Amon_rsut_198401-201612.nc 8afa3afd416500b17bceda5689c43d64277a4c32f99521f79a3603d0e3fe0570
ESMValTool/OBS/Tier2/ISCCP-FH/OBS_ISCCP-FH_sat_v0_Amon_rsutcs_198401-201612.nc 922aebf600f56a69c7b0b9d4b72eca0edb3dd495bd7a05209a07d4e50bd69b57
ESMValTool/OBS/Tier2/OSI-450-nh/OBS_OSI-450-nh_reanaly_v3_fx_areacello.nc aead9fc03e6773f66c3fa522ddd9cc36ff6a5b47cfab02d3cb9481b52cc2f7cb
ESMValTool/OBS/Tier2/OSI-450-nh/OBS_OSI-450-nh_reanaly_v3_OImon_sic_197901-197912.nc b5fe29fd2864248580043af4bca27a4771cf216ef7db74d645590ba10809dbe8
ESMValTool/OBS/Tier2/OSI-450-nh/OBS_OSI-450-nh_reanaly_v3_OImon_sic_198001-198012.nc ce988e813cae4c59bbb622420e7e339b9e435117486af8aa81afaa54e19d7d68
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""ESMValTool diagnostics."""

from climate_ref_esmvaltool.diagnostics.climate_at_global_warming_levels import ClimateAtGlobalWarmingLevels
from climate_ref_esmvaltool.diagnostics.cloud_radiative_effects import CloudRadiativeEffects
from climate_ref_esmvaltool.diagnostics.ecs import EquilibriumClimateSensitivity
from climate_ref_esmvaltool.diagnostics.example import GlobalMeanTimeseries
from climate_ref_esmvaltool.diagnostics.sea_ice_area_seasonal_cycle import SeaIceAreaSeasonalCycle
Expand All @@ -10,6 +11,7 @@

__all__ = [
"ClimateAtGlobalWarmingLevels",
"CloudRadiativeEffects",
"EquilibriumClimateSensitivity",
"GlobalMeanTimeseries",
"SeaIceAreaSeasonalCycle",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pandas

from climate_ref_core.constraints import (
AddSupplementaryDataset,
RequireContiguousTimerange,
RequireFacets,
RequireOverlappingTimerange,
)
from climate_ref_core.datasets import FacetFilter, SourceDatasetType
from climate_ref_core.diagnostics import DataRequirement
from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
from climate_ref_esmvaltool.recipe import dataframe_to_recipe
from climate_ref_esmvaltool.types import Recipe


class CloudRadiativeEffects(ESMValToolDiagnostic):
"""
Plot climatologies and zonal mean profiles of cloud radiative effects (sw + lw) for a dataset.
"""

name = "Climatologies and zonal mean profiles of cloud radiative effects"
slug = "cloud-radiative-effects"
base_recipe = "ref/recipe_ref_cre.yml"

# TODO: These facets are needed to pass metric bundle validation,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #280

# in the integration test, but this diagnostic does not produce a metric.
# Should they be removed?
facets = ("model", "metric")

variables = (
"rlut",
"rlutcs",
"rsut",
"rsutcs",
)
data_requirements = (
DataRequirement(
source_type=SourceDatasetType.CMIP6,
filters=(
FacetFilter(
facets={
"variable_id": variables,
"experiment_id": ("historical",),
}
),
),
group_by=("source_id", "member_id", "grid_label"),
constraints=(
RequireFacets("variable_id", variables),
RequireContiguousTimerange(group_by=("instance_id",)),
RequireOverlappingTimerange(group_by=("instance_id",)),
AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
),
),
# TODO: Use CERES-EBAF, ESACCI-CLOUD, and ISCCP-FH from obs4MIPs once available.
)

@staticmethod
def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
"""Update the recipe."""
recipe_variables = dataframe_to_recipe(input_files)
recipe_variables = {k: v for k, v in recipe_variables.items() if k != "areacella"}

# 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)
start_time = max(start_times)
start_time = max(start_time, "20010101T000000") # Earliest observational dataset availability
timerange = f"{start_time}/{min(end_times)}"

datasets = recipe_variables["rsut"]["additional_datasets"]
for dataset in datasets:
dataset.pop("timerange")
recipe["datasets"] = datasets
recipe["timerange_for_models"] = timerange
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ def dataframe_to_recipe(files: pd.DataFrame) -> dict[str, Any]:
base_url=f"https://raw.githubusercontent.com/ESMValGroup/ESMValTool/{_ESMVALTOOL_COMMIT}/esmvaltool/recipes/",
env="REF_METRICS_ESMVALTOOL_DATA_DIR",
)
_RECIPES.load_registry(str(importlib.resources.files("climate_ref_esmvaltool").joinpath("recipes.txt")))
with importlib.resources.files("climate_ref_esmvaltool").joinpath("recipes.txt").open("rb") as _buffer:
_RECIPES.load_registry(_buffer)


def load_recipe(recipe: str) -> Recipe:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ recipe_ecs.yml 0cc57034fcb64e32015b4ff949ece5df8cdb8c6f493618b50cede
recipe_tcr.yml 35f9ef035a4e71aff5cac5dd26c49da2162fc00291bf3b0bd16b661b7b2f606b
recipe_tcre.yml 4668e357e00c515a8264ac75cb319ce558289689e10189e6f9e982886c414c94
recipe_zec.yml b0af7f789b7610ab3f29a6617124aa40c40866ead958204fc199eaf82863de51
ref/recipe_ref_cre.yml 4f35d9639f1008be3b5382a5bd8933a855cb5368ccf5d04a1c70227172e2e82c
ref/recipe_ref_sea_ice_area_basic.yml 552e282a16ec355778b06f33897e1b8ba8388e5f8a5f814c4c42d91f63007457
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
{
"start_time":{
"4":"1850-01-16T12:00:00.000",
"3":"1850-01-16T12:00:00.000",
"2":"1850-01-16T12:00:00.000",
"1":"1850-01-16T12:00:00.000"
},
"end_time":{
"4":"2014-12-16T12:00:00.000",
"3":"2014-12-16T12:00:00.000",
"2":"2014-12-16T12:00:00.000",
"1":"2014-12-16T12:00:00.000"
},
"path":{
"4":"\/work\/bd0854\/DATA\/ESMValTool2\/CMIP6_DKRZ\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/rsut\/gn\/v20191115\/rsut_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
"3":"\/work\/bd0854\/DATA\/ESMValTool2\/CMIP6_DKRZ\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/rsutcs\/gn\/v20191115\/rsutcs_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
"2":"\/work\/bd0854\/DATA\/ESMValTool2\/CMIP6_DKRZ\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/rlutcs\/gn\/v20191115\/rlutcs_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
"1":"\/work\/bd0854\/DATA\/ESMValTool2\/CMIP6_DKRZ\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/rlut\/gn\/v20191115\/rlut_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc"
},
"activity_id":{
"4":"CMIP",
"3":"CMIP",
"2":"CMIP",
"1":"CMIP"
},
"branch_method":{
"4":"standard",
"3":"standard",
"2":"standard",
"1":"standard"
},
"branch_time_in_child":{
"4":0.0,
"3":0.0,
"2":0.0,
"1":0.0
},
"branch_time_in_parent":{
"4":21915.0,
"3":21915.0,
"2":21915.0,
"1":21915.0
},
"experiment":{
"4":"all-forcing simulation of the recent past",
"3":"all-forcing simulation of the recent past",
"2":"all-forcing simulation of the recent past",
"1":"all-forcing simulation of the recent past"
},
"experiment_id":{
"4":"historical",
"3":"historical",
"2":"historical",
"1":"historical"
},
"frequency":{
"4":"mon",
"3":"mon",
"2":"mon",
"1":"mon"
},
"grid":{
"4":"native atmosphere N96 grid (145x192 latxlon)",
"3":"native atmosphere N96 grid (145x192 latxlon)",
"2":"native atmosphere N96 grid (145x192 latxlon)",
"1":"native atmosphere N96 grid (145x192 latxlon)"
},
"grid_label":{
"4":"gn",
"3":"gn",
"2":"gn",
"1":"gn"
},
"institution_id":{
"4":"CSIRO",
"3":"CSIRO",
"2":"CSIRO",
"1":"CSIRO"
},
"nominal_resolution":{
"4":"250 km",
"3":"250 km",
"2":"250 km",
"1":"250 km"
},
"parent_activity_id":{
"4":"CMIP",
"3":"CMIP",
"2":"CMIP",
"1":"CMIP"
},
"parent_experiment_id":{
"4":"piControl",
"3":"piControl",
"2":"piControl",
"1":"piControl"
},
"parent_source_id":{
"4":"ACCESS-ESM1-5",
"3":"ACCESS-ESM1-5",
"2":"ACCESS-ESM1-5",
"1":"ACCESS-ESM1-5"
},
"parent_time_units":{
"4":"days since 0101-1-1",
"3":"days since 0101-1-1",
"2":"days since 0101-1-1",
"1":"days since 0101-1-1"
},
"parent_variant_label":{
"4":"r1i1p1f1",
"3":"r1i1p1f1",
"2":"r1i1p1f1",
"1":"r1i1p1f1"
},
"product":{
"4":"model-output",
"3":"model-output",
"2":"model-output",
"1":"model-output"
},
"realm":{
"4":"atmos",
"3":"atmos",
"2":"atmos",
"1":"atmos"
},
"source_id":{
"4":"ACCESS-ESM1-5",
"3":"ACCESS-ESM1-5",
"2":"ACCESS-ESM1-5",
"1":"ACCESS-ESM1-5"
},
"source_type":{
"4":"AOGCM",
"3":"AOGCM",
"2":"AOGCM",
"1":"AOGCM"
},
"sub_experiment":{
"4":"none",
"3":"none",
"2":"none",
"1":"none"
},
"sub_experiment_id":{
"4":"none",
"3":"none",
"2":"none",
"1":"none"
},
"table_id":{
"4":"Amon",
"3":"Amon",
"2":"Amon",
"1":"Amon"
},
"variable_id":{
"4":"rsut",
"3":"rsutcs",
"2":"rlutcs",
"1":"rlut"
},
"variant_label":{
"4":"r1i1p1f1",
"3":"r1i1p1f1",
"2":"r1i1p1f1",
"1":"r1i1p1f1"
},
"member_id":{
"4":"r1i1p1f1",
"3":"r1i1p1f1",
"2":"r1i1p1f1",
"1":"r1i1p1f1"
},
"standard_name":{
"4":"toa_outgoing_shortwave_flux",
"3":"toa_outgoing_shortwave_flux_assuming_clear_sky",
"2":"toa_outgoing_longwave_flux_assuming_clear_sky",
"1":"toa_outgoing_longwave_flux"
},
"long_name":{
"4":"TOA Outgoing Shortwave Radiation",
"3":"TOA Outgoing Clear-Sky Shortwave Radiation",
"2":"TOA Outgoing Clear-Sky Longwave Radiation",
"1":"TOA Outgoing Longwave Radiation"
},
"units":{
"4":"W m-2",
"3":"W m-2",
"2":"W m-2",
"1":"W m-2"
},
"vertical_levels":{
"4":1,
"3":1,
"2":1,
"1":1
},
"init_year":{
"4":null,
"3":null,
"2":null,
"1":null
},
"version":{
"4":"v20191115",
"3":"v20191115",
"2":"v20191115",
"1":"v20191115"
},
"instance_id":{
"4":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.rsut.gn.v20191115",
"3":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.rsutcs.gn.v20191115",
"2":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.rlutcs.gn.v20191115",
"1":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.rlut.gn.v20191115"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from pathlib import Path

import pandas
from climate_ref_esmvaltool.diagnostics import CloudRadiativeEffects
from climate_ref_esmvaltool.recipe import load_recipe


def test_update_recipe():
# Insert the following code in CloudRadiativeEffects.update_recipe to
# save an example input dataframe:
# input_files.to_json(Path("input_files_cloud_radiative_effects.json"), indent=4, date_format="iso")
input_files = pandas.read_json(Path(__file__).parent / "input_files_cloud_radiative_effects.json")
recipe = load_recipe("ref/recipe_ref_cre.yml")
CloudRadiativeEffects().update_recipe(recipe, input_files)
assert recipe["datasets"] == [
{
"activity": "CMIP",
"dataset": "ACCESS-ESM1-5",
"ensemble": "r1i1p1f1",
"exp": "historical",
"grid": "gn",
"institute": "CSIRO",
"mip": "Amon",
"project": "CMIP6",
},
]
assert recipe["timerange_for_models"] == "20010101T000000/20141216T120000"
4 changes: 1 addition & 3 deletions packages/climate-ref/src/climate_ref/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ def validate_result(diagnostic: Diagnostic, config: Config, result: ExecutionRes

# Validate bundles
metric_bundle = CMECMetric.load_from_json(result.to_output_path(result.metric_bundle_filename))
assert diagnostic.facets == tuple(metric_bundle.DIMENSIONS.root["json_structure"]), (
metric_bundle.DIMENSIONS.root["json_structure"]
)
assert diagnostic.facets == tuple(metric_bundle.DIMENSIONS.root["json_structure"])
CMECOutput.load_from_json(result.to_output_path(result.output_bundle_filename))

# Create a fake log file if one doesn't exist
Expand Down
Loading