climate-ref-esmvaltool 0.5.5__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/PKG-INFO +3 -3
  2. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/pyproject.toml +4 -5
  3. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/dataset_registry/data.txt +3 -0
  4. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/__init__.py +5 -2
  5. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/base.py +9 -3
  6. climate_ref_esmvaltool-0.6.0/src/climate_ref_esmvaltool/diagnostics/enso.py +155 -0
  7. climate_ref_esmvaltool-0.5.5/src/climate_ref_esmvaltool/diagnostics/sea_ice_area_seasonal_cycle.py → climate_ref_esmvaltool-0.6.0/src/climate_ref_esmvaltool/diagnostics/sea_ice_area_basic.py +13 -8
  8. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/tcre.py +11 -0
  9. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/recipe.py +2 -2
  10. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/recipes.txt +4 -2
  11. climate_ref_esmvaltool-0.6.0/tests/unit/diagnostics/input_files_enso_characteristics.json +142 -0
  12. climate_ref_esmvaltool-0.6.0/tests/unit/diagnostics/input_files_enso_climatology.json +177 -0
  13. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_base.py +1 -1
  14. climate_ref_esmvaltool-0.6.0/tests/unit/diagnostics/test_enso.py +47 -0
  15. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_sea_ice_area.py +3 -3
  16. climate_ref_esmvaltool-0.6.0/tests/unit/test_provider.py +18 -0
  17. climate_ref_esmvaltool-0.5.5/tests/unit/test_provider.py +0 -17
  18. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/.gitignore +0 -0
  19. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/LICENCE +0 -0
  20. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/NOTICE +0 -0
  21. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/README.md +0 -0
  22. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/__init__.py +0 -0
  23. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/_version.py +0 -0
  24. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/climate_at_global_warming_levels.py +0 -0
  25. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/cloud_radiative_effects.py +0 -0
  26. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/ecs.py +0 -0
  27. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/example.py +0 -0
  28. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/tcr.py +0 -0
  29. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/diagnostics/zec.py +0 -0
  30. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/py.typed +0 -0
  31. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/requirements/conda-lock.yml +0 -0
  32. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/requirements/environment.yml +0 -0
  33. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/src/climate_ref_esmvaltool/types.py +0 -0
  34. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/integration/test_diagnostics.py +0 -0
  35. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_climate_at_global_warming_levels.json +0 -0
  36. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_cloud_radiative_effects.json +0 -0
  37. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_ecs.json +0 -0
  38. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_sea_ice_area.json +0 -0
  39. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_tcr.json +0 -0
  40. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_tcre.json +0 -0
  41. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/input_files_zec.json +0 -0
  42. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_climate_at_global_warming_levels.py +0 -0
  43. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_cloud_radiative_effects.py +0 -0
  44. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_ecs.py +0 -0
  45. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_tcr.py +0 -0
  46. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_tcre.py +0 -0
  47. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/diagnostics/test_zec.py +0 -0
  48. {climate_ref_esmvaltool-0.5.5 → climate_ref_esmvaltool-0.6.0}/tests/unit/test_metrics.py +0 -0
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: climate-ref-esmvaltool
3
- Version: 0.5.5
3
+ Version: 0.6.0
4
4
  Summary: ESMValTool diagnostic provider for the Rapid Evaluation Framework
5
- Author-email: ESMValTool development team <esmvaltool-dev@listserv.dfn.de>
6
- License: Apache-2.0
5
+ Author-email: ESMValTool development team <esmvaltool-dev@listserv.dfn.de>, Jared Lewis <jared.lewis@climate-resource.com>
6
+ License-Expression: Apache-2.0
7
7
  License-File: LICENCE
8
8
  License-File: NOTICE
9
9
  Classifier: Development Status :: 3 - Alpha
@@ -1,11 +1,13 @@
1
1
  [project]
2
2
  name = "climate-ref-esmvaltool"
3
- version = "0.5.5"
3
+ version = "0.6.0"
4
4
  description = "ESMValTool diagnostic provider for the Rapid Evaluation Framework"
5
5
  readme = "README.md"
6
6
  authors = [
7
- { name = "ESMValTool development team", email = "esmvaltool-dev@listserv.dfn.de " }
7
+ { name = "ESMValTool development team", email = "esmvaltool-dev@listserv.dfn.de" },
8
+ { name = "Jared Lewis", email = "jared.lewis@climate-resource.com" },
8
9
  ]
10
+ license = "Apache-2.0"
9
11
  requires-python = ">=3.11"
10
12
  classifiers = [
11
13
  "Development Status :: 3 - Alpha",
@@ -27,9 +29,6 @@ dependencies = [
27
29
  "xarray >= 2023.3.0",
28
30
  ]
29
31
 
30
- [project.license]
31
- text = "Apache-2.0"
32
-
33
32
  [build-system]
34
33
  requires = ["hatchling"]
35
34
  build-backend = "hatchling.build"
@@ -1,3 +1,4 @@
1
+ ESMValTool/obs4MIPs/GPCP-V2.3/v20180519/pr_GPCP-SG_L3_v2.3_197901-201710.nc 4dd4678b79ef139446c8406da5aae4fed210abb2f2160ef95f6988bf83e4525b
1
2
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlut_200003-202311.nc ede887cf2d83c848a0d71316799232e4d717662bd2f78d5aa1fc166b41d9953b
2
3
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlutcs_200003-202311.nc e70e3273092edf01527970693271641fc6474d1974887d7d272e7d656bab83c2
3
4
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rsut_200003-202311.nc e31e648886c4fa9c09686672a06ab18fbba687ff0d6de2891616d4c8b74e215d
@@ -84,3 +85,5 @@ ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201101-20111
84
85
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201201-201212.nc 86187c3d1174053f2cba6dad010af49ceab77d368aa9314bf53c330b5f2217b9
85
86
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201301-201312.nc 8820353570884b2ef182caaffb5986ed6268bbe199fd867f61b56e798ca01f1a
86
87
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201401-201412.nc 7102d0db3dc02c5b0eb0cfe3535ee50171007ef5b43eb9aae1220ac21b0b98e9
88
+ ESMValTool/OBS/Tier2/TROPFLUX/OBS6_TROPFLUX_reanaly_v1_Amon_tauu_197901-201812.nc bf313e661b42341d5090038b501ed1ff09e58201009c3fccfe45b78e116fdd78
89
+ ESMValTool/OBS/Tier2/TROPFLUX/OBS6_TROPFLUX_reanaly_v1_Omon_tos_197901-201812.nc 5f10a5a2aa47f5d21378ad3178bf8e4b577b0ed72ef8402dc04f5ff6fc99ec07
@@ -3,8 +3,9 @@
3
3
  from climate_ref_esmvaltool.diagnostics.climate_at_global_warming_levels import ClimateAtGlobalWarmingLevels
4
4
  from climate_ref_esmvaltool.diagnostics.cloud_radiative_effects import CloudRadiativeEffects
5
5
  from climate_ref_esmvaltool.diagnostics.ecs import EquilibriumClimateSensitivity
6
+ from climate_ref_esmvaltool.diagnostics.enso import ENSOBasicClimatology, ENSOCharacteristics
6
7
  from climate_ref_esmvaltool.diagnostics.example import GlobalMeanTimeseries
7
- from climate_ref_esmvaltool.diagnostics.sea_ice_area_seasonal_cycle import SeaIceAreaSeasonalCycle
8
+ from climate_ref_esmvaltool.diagnostics.sea_ice_area_basic import SeaIceAreaBasic
8
9
  from climate_ref_esmvaltool.diagnostics.tcr import TransientClimateResponse
9
10
  from climate_ref_esmvaltool.diagnostics.tcre import TransientClimateResponseEmissions
10
11
  from climate_ref_esmvaltool.diagnostics.zec import ZeroEmissionCommitment
@@ -12,9 +13,11 @@ from climate_ref_esmvaltool.diagnostics.zec import ZeroEmissionCommitment
12
13
  __all__ = [
13
14
  "ClimateAtGlobalWarmingLevels",
14
15
  "CloudRadiativeEffects",
16
+ "ENSOBasicClimatology",
17
+ "ENSOCharacteristics",
15
18
  "EquilibriumClimateSensitivity",
16
19
  "GlobalMeanTimeseries",
17
- "SeaIceAreaSeasonalCycle",
20
+ "SeaIceAreaBasic",
18
21
  "TransientClimateResponse",
19
22
  "TransientClimateResponseEmissions",
20
23
  "ZeroEmissionCommitment",
@@ -101,15 +101,17 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
101
101
  config = {
102
102
  "drs": {
103
103
  "CMIP6": "ESGF",
104
+ "obs4MIPs": "ESGF",
104
105
  },
105
106
  "output_dir": str(definition.to_output_path("executions")),
106
107
  "rootpath": {
107
- "default": str(climate_data),
108
+ "CMIP6": str(climate_data),
109
+ "obs4MIPs": str(climate_data),
108
110
  },
109
111
  "search_esgf": "never",
110
112
  }
111
113
 
112
- # Configure the paths to OBS/OBS6/native6 data
114
+ # Configure the paths to OBS/OBS6/native6 and non-compliant obs4MIPs data
113
115
  registry = dataset_registry_manager["esmvaltool"]
114
116
  data_dir = registry.abspath / "ESMValTool" # type: ignore[attr-defined]
115
117
  if not data_dir.exists():
@@ -129,10 +131,14 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
129
131
  config["rootpath"].update( # type: ignore[attr-defined]
130
132
  {
131
133
  "OBS": str(data_dir / "OBS"),
132
- "OBS6": str(data_dir / "OBS6"),
134
+ "OBS6": str(data_dir / "OBS"),
133
135
  "native6": str(data_dir / "RAWOBS"),
134
136
  }
135
137
  )
138
+ config["rootpath"]["obs4MIPs"] = [ # type: ignore[index]
139
+ config["rootpath"]["obs4MIPs"], # type: ignore[index]
140
+ str(data_dir),
141
+ ]
136
142
 
137
143
  config_dir = definition.to_output_path("config")
138
144
  config_dir.mkdir()
@@ -0,0 +1,155 @@
1
+ from pathlib import Path
2
+
3
+ import pandas
4
+ import pandas as pd
5
+
6
+ from climate_ref_core.constraints import (
7
+ AddSupplementaryDataset,
8
+ RequireContiguousTimerange,
9
+ RequireFacets,
10
+ RequireOverlappingTimerange,
11
+ )
12
+ from climate_ref_core.datasets import ExecutionDatasetCollection, FacetFilter, SourceDatasetType
13
+ from climate_ref_core.diagnostics import DataRequirement
14
+ from climate_ref_core.pycmec.metric import CMECMetric, MetricCV
15
+ from climate_ref_core.pycmec.output import CMECOutput
16
+ from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
17
+ from climate_ref_esmvaltool.recipe import dataframe_to_recipe
18
+ from climate_ref_esmvaltool.types import MetricBundleArgs, OutputBundleArgs, Recipe
19
+
20
+
21
+ class ENSOBasicClimatology(ESMValToolDiagnostic):
22
+ """
23
+ Calculate the ENSO CLIVAR metrics - background climatology.
24
+ """
25
+
26
+ name = "ENSO Basic Climatology"
27
+ slug = "enso-basic-climatology"
28
+ base_recipe = "ref/recipe_enso_basicclimatology.yml"
29
+
30
+ variables = (
31
+ "pr",
32
+ "tos",
33
+ "tauu",
34
+ )
35
+ data_requirements = (
36
+ DataRequirement(
37
+ source_type=SourceDatasetType.CMIP6,
38
+ filters=(
39
+ FacetFilter(
40
+ facets={
41
+ "variable_id": variables,
42
+ "experiment_id": "historical",
43
+ },
44
+ ),
45
+ ),
46
+ group_by=("source_id", "member_id", "grid_label"),
47
+ constraints=(
48
+ RequireFacets("variable_id", variables),
49
+ RequireContiguousTimerange(group_by=("instance_id",)),
50
+ RequireOverlappingTimerange(group_by=("instance_id",)),
51
+ ),
52
+ ),
53
+ )
54
+ facets = ()
55
+
56
+ @staticmethod
57
+ def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
58
+ """Update the recipe."""
59
+ recipe_variables = dataframe_to_recipe(input_files)
60
+ recipe.pop("datasets")
61
+ for diagnostic in recipe["diagnostics"].values():
62
+ for variable in diagnostic["variables"].values():
63
+ variable["additional_datasets"].extend(
64
+ recipe_variables[variable["short_name"]]["additional_datasets"]
65
+ )
66
+
67
+
68
+ class ENSOCharacteristics(ESMValToolDiagnostic):
69
+ """
70
+ Calculate the ENSO CLIVAR metrics - basic ENSO characteristics.
71
+ """
72
+
73
+ name = "ENSO Characteristics"
74
+ slug = "enso-characteristics"
75
+ base_recipe = "ref/recipe_enso_characteristics.yml"
76
+
77
+ data_requirements = (
78
+ DataRequirement(
79
+ source_type=SourceDatasetType.CMIP6,
80
+ filters=(
81
+ FacetFilter(
82
+ facets={
83
+ "variable_id": "tos",
84
+ "experiment_id": "historical",
85
+ },
86
+ ),
87
+ ),
88
+ group_by=("source_id", "member_id", "grid_label"),
89
+ constraints=(
90
+ RequireFacets("variable_id", ("tos",)),
91
+ RequireContiguousTimerange(group_by=("instance_id",)),
92
+ RequireOverlappingTimerange(group_by=("instance_id",)),
93
+ AddSupplementaryDataset.from_defaults("areacello", SourceDatasetType.CMIP6),
94
+ ),
95
+ ),
96
+ )
97
+ facets = ("grid_label", "member_id", "source_id", "region", "metric")
98
+
99
+ @staticmethod
100
+ def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
101
+ """Update the recipe."""
102
+ recipe_variables = dataframe_to_recipe(input_files)
103
+ recipe["datasets"] = recipe_variables["tos"]["additional_datasets"]
104
+ # TODO: update the observational data requirement once available on ESGF.
105
+ # Observations - use only one per run
106
+ recipe["datasets"].append(
107
+ # {
108
+ # "dataset": "NOAA-ERSSTv5",
109
+ # "version": "v5",
110
+ # "project": "OBS6",
111
+ # "type": "reanaly",
112
+ # "tier": 2,
113
+ # }
114
+ {
115
+ "dataset": "TROPFLUX",
116
+ "version": "v1",
117
+ "project": "OBS6",
118
+ "type": "reanaly",
119
+ "tier": 2,
120
+ }
121
+ )
122
+
123
+ @staticmethod
124
+ def format_result(
125
+ result_dir: Path,
126
+ execution_dataset: ExecutionDatasetCollection,
127
+ metric_args: MetricBundleArgs,
128
+ output_args: OutputBundleArgs,
129
+ ) -> tuple[CMECMetric, CMECOutput]:
130
+ """Format the result."""
131
+ metrics = pd.read_csv(
132
+ result_dir / "work" / "diagnostic_metrics" / "plot_script" / "matrix.csv",
133
+ names=["dataset", "metric_name", "metric_value"],
134
+ )
135
+
136
+ # Update the diagnostic bundle arguments with the computed diagnostics.
137
+ metric_args[MetricCV.DIMENSIONS.value] = {
138
+ "json_structure": [
139
+ "region",
140
+ "metric",
141
+ ],
142
+ "region": {"global": {}},
143
+ "metric": {metric: {} for metric in metrics.metric_name},
144
+ }
145
+ metric_args[MetricCV.RESULTS.value] = {
146
+ "global": {
147
+ metric_name: metric_value
148
+ for metric_name, metric_value in zip(
149
+ metrics.metric_name,
150
+ metrics.metric_value,
151
+ )
152
+ },
153
+ }
154
+
155
+ return CMECMetric.model_validate(metric_args), CMECOutput.model_validate(output_args)
@@ -11,13 +11,13 @@ from climate_ref_esmvaltool.recipe import dataframe_to_recipe
11
11
  from climate_ref_esmvaltool.types import Recipe
12
12
 
13
13
 
14
- class SeaIceAreaSeasonalCycle(ESMValToolDiagnostic):
14
+ class SeaIceAreaBasic(ESMValToolDiagnostic):
15
15
  """
16
16
  Calculate seasonal cycle and time series of NH and SH sea ice area.
17
17
  """
18
18
 
19
- name = "Sea ice area seasonal cycle"
20
- slug = "sea-ice-area-seasonal-cycle"
19
+ name = "Sea ice area basic"
20
+ slug = "sea-ice-area-basic"
21
21
  base_recipe = "ref/recipe_ref_sea_ice_area_basic.yml"
22
22
 
23
23
  data_requirements = (
@@ -44,14 +44,13 @@ class SeaIceAreaSeasonalCycle(ESMValToolDiagnostic):
44
44
  @staticmethod
45
45
  def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
46
46
  """Update the recipe."""
47
- # Overlap between observations and historical experiment.
48
- timerange = "1995/2014"
49
-
50
47
  # Update datasets
51
48
  recipe_variables = dataframe_to_recipe(input_files)
52
49
  recipe["datasets"] = recipe_variables["siconc"]["additional_datasets"]
50
+
51
+ # Use the timerange from the recipe, as defined in the variable.
53
52
  for dataset in recipe["datasets"]:
54
- dataset["timerange"] = timerange
53
+ dataset.pop("timerange")
55
54
 
56
55
  # Update observational datasets
57
56
  nh_obs = {
@@ -65,7 +64,6 @@ class SeaIceAreaSeasonalCycle(ESMValToolDiagnostic):
65
64
  },
66
65
  ],
67
66
  "tier": 2,
68
- "timerange": timerange,
69
67
  "type": "reanaly",
70
68
  "version": "v3",
71
69
  }
@@ -76,3 +74,10 @@ class SeaIceAreaSeasonalCycle(ESMValToolDiagnostic):
76
74
  diagnostics["siarea_min"]["variables"]["sea_ice_area_sh_feb"]["additional_datasets"] = [sh_obs]
77
75
  diagnostics["siarea_seas"]["variables"]["sea_ice_area_nh"]["additional_datasets"] = [nh_obs]
78
76
  diagnostics["siarea_seas"]["variables"]["sea_ice_area_sh"]["additional_datasets"] = [sh_obs]
77
+
78
+ # Update the captions.
79
+ dataset = "{dataset}.{ensemble}.{grid}".format(**recipe["datasets"][0])
80
+ for diagnostic in diagnostics.values():
81
+ for script_settings in diagnostic["scripts"].values():
82
+ for plot_settings in script_settings["plots"].values():
83
+ plot_settings["caption"] = plot_settings["caption"].replace("[dataset]", dataset)
@@ -102,6 +102,17 @@ class TransientClimateResponseEmissions(ESMValToolDiagnostic):
102
102
  }
103
103
  recipe["diagnostics"].pop("barplot")
104
104
 
105
+ # Update descriptions.
106
+ dataset = tas_esm_1pctCO2["dataset"]
107
+ ensemble = tas_esm_1pctCO2["ensemble"]
108
+ settings = recipe["diagnostics"]["tcre"]["scripts"]["calculate_tcre"]
109
+ settings["caption"] = (
110
+ settings["caption"].replace("MPI-ESM1-2-LR", dataset).replace("r1i1p1f1", ensemble)
111
+ )
112
+ settings["pyplot_kwargs"]["title"] = (
113
+ settings["pyplot_kwargs"]["title"].replace("MPI-ESM1-2-LR", dataset).replace("r1i1p1f1", ensemble)
114
+ )
115
+
105
116
  @staticmethod
106
117
  def format_result(
107
118
  result_dir: Path,
@@ -115,8 +115,8 @@ def dataframe_to_recipe(files: pd.DataFrame) -> dict[str, Any]:
115
115
  return variables
116
116
 
117
117
 
118
- _ESMVALTOOL_COMMIT = "a759ce46d5185e3784997ce38a3956e39322cdac"
119
- _ESMVALTOOL_VERSION = f"2.13.0.dev27+g{_ESMVALTOOL_COMMIT[:9]}"
118
+ _ESMVALTOOL_COMMIT = "58fd0b8ece981bc97c4fbd213b11f2228d90db28"
119
+ _ESMVALTOOL_VERSION = f"2.13.0.dev65+g{_ESMVALTOOL_COMMIT[:9]}"
120
120
 
121
121
  _RECIPES = pooch.create(
122
122
  path=pooch.os_cache("climate_ref_esmvaltool"),
@@ -2,7 +2,9 @@ examples/recipe_python.yml ab3f06d269bb2c1368f4dc39da9bcb232fb2adb1fa556ba769e6c
2
2
  recipe_calculate_gwl_exceedance_stats.yml 5aa266abc9a8029649b689a2b369a47623b0935d609354332ff4148994642d6b
3
3
  recipe_ecs.yml 0cc57034fcb64e32015b4ff949ece5df8cdb8c6f493618b50ceded119fb37918
4
4
  recipe_tcr.yml 35f9ef035a4e71aff5cac5dd26c49da2162fc00291bf3b0bd16b661b7b2f606b
5
- recipe_tcre.yml 4668e357e00c515a8264ac75cb319ce558289689e10189e6f9e982886c414c94
5
+ recipe_tcre.yml 48fc9e3baf541bbcef7491853ea3a774053771dca33352b41466425faeaa38af
6
6
  recipe_zec.yml b0af7f789b7610ab3f29a6617124aa40c40866ead958204fc199eaf82863de51
7
+ ref/recipe_enso_basicclimatology.yml 9ea7deb7ee668e39ac44618b96496d898bd82285c22dcee4fce4695e0c9fa82b
8
+ ref/recipe_enso_characteristics.yml 34c2518b138068ac96d212910b979d54a8fcedee2c0089b5acd56a42c41dc3e4
7
9
  ref/recipe_ref_cre.yml 4f35d9639f1008be3b5382a5bd8933a855cb5368ccf5d04a1c70227172e2e82c
8
- ref/recipe_ref_sea_ice_area_basic.yml 552e282a16ec355778b06f33897e1b8ba8388e5f8a5f814c4c42d91f63007457
10
+ ref/recipe_ref_sea_ice_area_basic.yml 7d01a8527880663ca28284772f83a8356d9972fb4f022a4000e50a56ce044b09
@@ -0,0 +1,142 @@
1
+ {
2
+ "start_time":{
3
+ "1":"1850-01-16T12:00:00.000",
4
+ "109":null
5
+ },
6
+ "end_time":{
7
+ "1":"2014-12-16T12:00:00.000",
8
+ "109":null
9
+ },
10
+ "path":{
11
+ "1":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Omon\/tos\/gn\/v20191115\/tos_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
12
+ "109":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Ofx\/areacello\/gn\/v20191115\/areacello_Ofx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc"
13
+ },
14
+ "activity_id":{
15
+ "1":"CMIP",
16
+ "109":"CMIP"
17
+ },
18
+ "branch_method":{
19
+ "1":"standard",
20
+ "109":"standard"
21
+ },
22
+ "branch_time_in_child":{
23
+ "1":0.0,
24
+ "109":0.0
25
+ },
26
+ "branch_time_in_parent":{
27
+ "1":21915.0,
28
+ "109":21915.0
29
+ },
30
+ "experiment":{
31
+ "1":"all-forcing simulation of the recent past",
32
+ "109":"all-forcing simulation of the recent past"
33
+ },
34
+ "experiment_id":{
35
+ "1":"historical",
36
+ "109":"historical"
37
+ },
38
+ "frequency":{
39
+ "1":"mon",
40
+ "109":"fx"
41
+ },
42
+ "grid":{
43
+ "1":"native atmosphere N96 grid (145x192 latxlon)",
44
+ "109":"native atmosphere N96 grid (145x192 latxlon)"
45
+ },
46
+ "grid_label":{
47
+ "1":"gn",
48
+ "109":"gn"
49
+ },
50
+ "institution_id":{
51
+ "1":"CSIRO",
52
+ "109":"CSIRO"
53
+ },
54
+ "nominal_resolution":{
55
+ "1":"250 km",
56
+ "109":"250 km"
57
+ },
58
+ "parent_activity_id":{
59
+ "1":"CMIP",
60
+ "109":"CMIP"
61
+ },
62
+ "parent_experiment_id":{
63
+ "1":"piControl",
64
+ "109":"piControl"
65
+ },
66
+ "parent_source_id":{
67
+ "1":"ACCESS-ESM1-5",
68
+ "109":"ACCESS-ESM1-5"
69
+ },
70
+ "parent_time_units":{
71
+ "1":"days since 0101-1-1",
72
+ "109":"days since 0101-1-1"
73
+ },
74
+ "parent_variant_label":{
75
+ "1":"r1i1p1f1",
76
+ "109":"r1i1p1f1"
77
+ },
78
+ "product":{
79
+ "1":"model-output",
80
+ "109":"model-output"
81
+ },
82
+ "realm":{
83
+ "1":"ocean",
84
+ "109":"ocean"
85
+ },
86
+ "source_id":{
87
+ "1":"ACCESS-ESM1-5",
88
+ "109":"ACCESS-ESM1-5"
89
+ },
90
+ "source_type":{
91
+ "1":"AOGCM",
92
+ "109":"AOGCM"
93
+ },
94
+ "sub_experiment":{
95
+ "1":"none",
96
+ "109":"none"
97
+ },
98
+ "sub_experiment_id":{
99
+ "1":"none",
100
+ "109":"none"
101
+ },
102
+ "table_id":{
103
+ "1":"Omon",
104
+ "109":"Ofx"
105
+ },
106
+ "variable_id":{
107
+ "1":"tos",
108
+ "109":"areacello"
109
+ },
110
+ "variant_label":{
111
+ "1":"r1i1p1f1",
112
+ "109":"r1i1p1f1"
113
+ },
114
+ "member_id":{
115
+ "1":"r1i1p1f1",
116
+ "109":"r1i1p1f1"
117
+ },
118
+ "vertical_levels":{
119
+ "1":1,
120
+ "109":1
121
+ },
122
+ "version":{
123
+ "1":"v20191115",
124
+ "109":"v20191115"
125
+ },
126
+ "standard_name":{
127
+ "1":"sea_surface_temperature",
128
+ "109":"cell_area"
129
+ },
130
+ "long_name":{
131
+ "1":"Sea Surface Temperature",
132
+ "109":"Grid-Cell Area for Ocean Variables"
133
+ },
134
+ "units":{
135
+ "1":"degC",
136
+ "109":"m2"
137
+ },
138
+ "instance_id":{
139
+ "1":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115",
140
+ "109":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Ofx.areacello.gn.v20191115"
141
+ }
142
+ }
@@ -0,0 +1,177 @@
1
+ {
2
+ "start_time":{
3
+ "31":"1850-01-16T12:00:00.000",
4
+ "39":"1850-01-16T12:00:00.000",
5
+ "1":"1850-01-16T12:00:00.000"
6
+ },
7
+ "end_time":{
8
+ "31":"2014-12-16T12:00:00.000",
9
+ "39":"2014-12-16T12:00:00.000",
10
+ "1":"2014-12-16T12:00:00.000"
11
+ },
12
+ "path":{
13
+ "31":"\/home\/bandela\/.esgf\/CMIP6\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/pr\/gn\/v20191115\/pr_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
14
+ "39":"\/home\/bandela\/.esgf\/CMIP6\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Amon\/tauu\/gn\/v20191115\/tauu_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc",
15
+ "1":"\/home\/bandela\/climate_data\/CMIP6\/CMIP\/CSIRO\/ACCESS-ESM1-5\/historical\/r1i1p1f1\/Omon\/tos\/gn\/v20191115\/tos_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc"
16
+ },
17
+ "activity_id":{
18
+ "31":"CMIP",
19
+ "39":"CMIP",
20
+ "1":"CMIP"
21
+ },
22
+ "branch_method":{
23
+ "31":"standard",
24
+ "39":"standard",
25
+ "1":"standard"
26
+ },
27
+ "branch_time_in_child":{
28
+ "31":0.0,
29
+ "39":0.0,
30
+ "1":0.0
31
+ },
32
+ "branch_time_in_parent":{
33
+ "31":21915.0,
34
+ "39":21915.0,
35
+ "1":21915.0
36
+ },
37
+ "experiment":{
38
+ "31":"all-forcing simulation of the recent past",
39
+ "39":"all-forcing simulation of the recent past",
40
+ "1":"all-forcing simulation of the recent past"
41
+ },
42
+ "experiment_id":{
43
+ "31":"historical",
44
+ "39":"historical",
45
+ "1":"historical"
46
+ },
47
+ "frequency":{
48
+ "31":"mon",
49
+ "39":"mon",
50
+ "1":"mon"
51
+ },
52
+ "grid":{
53
+ "31":"native atmosphere N96 grid (145x192 latxlon)",
54
+ "39":"native atmosphere N96 grid (145x192 latxlon)",
55
+ "1":"native atmosphere N96 grid (145x192 latxlon)"
56
+ },
57
+ "grid_label":{
58
+ "31":"gn",
59
+ "39":"gn",
60
+ "1":"gn"
61
+ },
62
+ "institution_id":{
63
+ "31":"CSIRO",
64
+ "39":"CSIRO",
65
+ "1":"CSIRO"
66
+ },
67
+ "nominal_resolution":{
68
+ "31":"250 km",
69
+ "39":"250 km",
70
+ "1":"250 km"
71
+ },
72
+ "parent_activity_id":{
73
+ "31":"CMIP",
74
+ "39":"CMIP",
75
+ "1":"CMIP"
76
+ },
77
+ "parent_experiment_id":{
78
+ "31":"piControl",
79
+ "39":"piControl",
80
+ "1":"piControl"
81
+ },
82
+ "parent_source_id":{
83
+ "31":"ACCESS-ESM1-5",
84
+ "39":"ACCESS-ESM1-5",
85
+ "1":"ACCESS-ESM1-5"
86
+ },
87
+ "parent_time_units":{
88
+ "31":"days since 0101-1-1",
89
+ "39":"days since 0101-1-1",
90
+ "1":"days since 0101-1-1"
91
+ },
92
+ "parent_variant_label":{
93
+ "31":"r1i1p1f1",
94
+ "39":"r1i1p1f1",
95
+ "1":"r1i1p1f1"
96
+ },
97
+ "product":{
98
+ "31":"model-output",
99
+ "39":"model-output",
100
+ "1":"model-output"
101
+ },
102
+ "realm":{
103
+ "31":"atmos",
104
+ "39":"atmos",
105
+ "1":"ocean"
106
+ },
107
+ "source_id":{
108
+ "31":"ACCESS-ESM1-5",
109
+ "39":"ACCESS-ESM1-5",
110
+ "1":"ACCESS-ESM1-5"
111
+ },
112
+ "source_type":{
113
+ "31":"AOGCM",
114
+ "39":"AOGCM",
115
+ "1":"AOGCM"
116
+ },
117
+ "sub_experiment":{
118
+ "31":"none",
119
+ "39":"none",
120
+ "1":"none"
121
+ },
122
+ "sub_experiment_id":{
123
+ "31":"none",
124
+ "39":"none",
125
+ "1":"none"
126
+ },
127
+ "table_id":{
128
+ "31":"Amon",
129
+ "39":"Amon",
130
+ "1":"Omon"
131
+ },
132
+ "variable_id":{
133
+ "31":"pr",
134
+ "39":"tauu",
135
+ "1":"tos"
136
+ },
137
+ "variant_label":{
138
+ "31":"r1i1p1f1",
139
+ "39":"r1i1p1f1",
140
+ "1":"r1i1p1f1"
141
+ },
142
+ "member_id":{
143
+ "31":"r1i1p1f1",
144
+ "39":"r1i1p1f1",
145
+ "1":"r1i1p1f1"
146
+ },
147
+ "vertical_levels":{
148
+ "31":1,
149
+ "39":1,
150
+ "1":1
151
+ },
152
+ "version":{
153
+ "31":"v20191115",
154
+ "39":"v20191115",
155
+ "1":"v20191115"
156
+ },
157
+ "standard_name":{
158
+ "31":"precipitation_flux",
159
+ "39":"surface_downward_eastward_stress",
160
+ "1":"sea_surface_temperature"
161
+ },
162
+ "long_name":{
163
+ "31":"Precipitation",
164
+ "39":"Surface Downward Eastward Wind Stress",
165
+ "1":"Sea Surface Temperature"
166
+ },
167
+ "units":{
168
+ "31":"kg m-2 s-1",
169
+ "39":"Pa",
170
+ "1":"degC"
171
+ },
172
+ "instance_id":{
173
+ "31":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.pr.gn.v20191115",
174
+ "39":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Amon.tauu.gn.v20191115",
175
+ "1":"CMIP6.CMIP.CSIRO.ACCESS-ESM1-5.historical.r1i1p1f1.Omon.tos.gn.v20191115"
176
+ }
177
+ }
@@ -41,7 +41,7 @@ def test_build_cmd(mocker, tmp_path, metric_definition, mock_diagnostic, data_di
41
41
  assert cmd == ["esmvaltool", "run", f"--config-dir={config_dir}", f"{recipe}"]
42
42
  assert (output_dir / "climate_data").is_dir()
43
43
  config = yaml.load((config_dir / "config.yml").read_text(encoding="utf-8"))
44
- assert len(config["rootpath"]) == 4 if data_dir_exists else 1
44
+ assert len(config["rootpath"]) == 5 if data_dir_exists else 1
45
45
 
46
46
 
47
47
  def test_build_metric_result(metric_definition, mock_diagnostic):
@@ -0,0 +1,47 @@
1
+ from pathlib import Path
2
+
3
+ import pandas
4
+ from climate_ref_esmvaltool.diagnostics import ENSOBasicClimatology, ENSOCharacteristics
5
+ from climate_ref_esmvaltool.recipe import load_recipe
6
+
7
+
8
+ def test_enso_basicclimatology_update_recipe():
9
+ # Insert the following code in CloudRadiativeEffects.update_recipe to
10
+ # save an example input dataframe:
11
+ # input_files.to_json(Path("input_files_enso_climatology.json"), indent=4, date_format="iso")
12
+ input_files = pandas.read_json(Path(__file__).parent / "input_files_enso_climatology.json")
13
+ recipe = load_recipe("ref/recipe_enso_basicclimatology.yml")
14
+ ENSOBasicClimatology().update_recipe(recipe, input_files)
15
+ assert "datasets" not in recipe
16
+ for diagnostic in recipe["diagnostics"].values():
17
+ for variable in diagnostic["variables"].values():
18
+ assert variable["additional_datasets"][-1]["dataset"] == "ACCESS-ESM1-5"
19
+
20
+
21
+ def test_enso_characteristics_update_recipe():
22
+ # Insert the following code in CloudRadiativeEffects.update_recipe to
23
+ # save an example input dataframe:
24
+ # input_files.to_json(Path("input_files_enso_characteristics.json"), indent=4, date_format="iso")
25
+ input_files = pandas.read_json(Path(__file__).parent / "input_files_enso_characteristics.json")
26
+ recipe = load_recipe("ref/recipe_enso_characteristics.yml")
27
+ ENSOCharacteristics().update_recipe(recipe, input_files)
28
+ assert recipe["datasets"] == [
29
+ {
30
+ "activity": "CMIP",
31
+ "dataset": "ACCESS-ESM1-5",
32
+ "ensemble": "r1i1p1f1",
33
+ "exp": "historical",
34
+ "grid": "gn",
35
+ "institute": "CSIRO",
36
+ "mip": "Omon",
37
+ "project": "CMIP6",
38
+ "timerange": "18500116T120000/20141216T120000",
39
+ },
40
+ {
41
+ "dataset": "TROPFLUX",
42
+ "project": "OBS6",
43
+ "tier": 2,
44
+ "type": "reanaly",
45
+ "version": "v1",
46
+ },
47
+ ]
@@ -1,16 +1,16 @@
1
1
  from pathlib import Path
2
2
 
3
3
  import pandas
4
- from climate_ref_esmvaltool.diagnostics import SeaIceAreaSeasonalCycle
4
+ from climate_ref_esmvaltool.diagnostics import SeaIceAreaBasic
5
5
  from climate_ref_esmvaltool.recipe import load_recipe
6
6
 
7
7
 
8
8
  def test_update_recipe():
9
9
  input_files = pandas.read_json(Path(__file__).parent / "input_files_sea_ice_area.json")
10
10
  recipe = load_recipe("ref/recipe_ref_sea_ice_area_basic.yml")
11
- SeaIceAreaSeasonalCycle().update_recipe(recipe, input_files)
11
+ SeaIceAreaBasic().update_recipe(recipe, input_files)
12
12
  assert len(recipe["datasets"]) == 1
13
13
  dataset = recipe["datasets"][0]
14
14
  assert dataset["dataset"] == input_files.iloc[0].source_id
15
- assert dataset["timerange"] == "1995/2014"
15
+ assert "timerange" not in dataset
16
16
  assert len(recipe["diagnostics"]) == 2
@@ -0,0 +1,18 @@
1
+ import importlib.metadata
2
+
3
+ from climate_ref_esmvaltool import __version__, provider
4
+
5
+
6
+ def test_provider():
7
+ assert provider.name == "ESMValTool"
8
+ assert provider.slug == "esmvaltool"
9
+ assert provider.version == __version__
10
+
11
+ diagnostic_modules = importlib.resources.files("climate_ref_esmvaltool").glob("diagnostics/*.py")
12
+ diagnostics_per_module = {
13
+ "__init__.py": 0,
14
+ "base.py": 0,
15
+ "enso.py": 2,
16
+ }
17
+ n_diagnostics = sum(diagnostics_per_module.get(f.name, 1) for f in diagnostic_modules)
18
+ assert len(provider) == n_diagnostics
@@ -1,17 +0,0 @@
1
- import importlib.metadata
2
-
3
- from climate_ref_esmvaltool import __version__, provider
4
-
5
-
6
- def test_provider():
7
- assert provider.name == "ESMValTool"
8
- assert provider.slug == "esmvaltool"
9
- assert provider.version == __version__
10
-
11
- metric_modules = importlib.resources.files("climate_ref_esmvaltool").glob("diagnostics/*.py")
12
- ignore = {
13
- "__init__.py",
14
- "base.py",
15
- }
16
- n_metric_modules = len([f for f in metric_modules if f.name not in ignore])
17
- assert len(provider) == n_metric_modules