climate-ref-esmvaltool 0.6.5__py3-none-any.whl → 0.7.0__py3-none-any.whl

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 (27) hide show
  1. climate_ref_esmvaltool/dataset_registry/data.txt +4 -0
  2. climate_ref_esmvaltool/diagnostics/__init__.py +22 -0
  3. climate_ref_esmvaltool/diagnostics/base.py +112 -14
  4. climate_ref_esmvaltool/diagnostics/climate_at_global_warming_levels.py +41 -15
  5. climate_ref_esmvaltool/diagnostics/climate_drivers_for_fire.py +90 -0
  6. climate_ref_esmvaltool/diagnostics/cloud_radiative_effects.py +26 -20
  7. climate_ref_esmvaltool/diagnostics/cloud_scatterplots.py +200 -0
  8. climate_ref_esmvaltool/diagnostics/ecs.py +32 -20
  9. climate_ref_esmvaltool/diagnostics/enso.py +88 -12
  10. climate_ref_esmvaltool/diagnostics/example.py +17 -3
  11. climate_ref_esmvaltool/diagnostics/regional_historical_changes.py +435 -0
  12. climate_ref_esmvaltool/diagnostics/sea_ice_area_basic.py +63 -5
  13. climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py +31 -14
  14. climate_ref_esmvaltool/diagnostics/tcr.py +23 -19
  15. climate_ref_esmvaltool/diagnostics/tcre.py +13 -12
  16. climate_ref_esmvaltool/diagnostics/zec.py +20 -3
  17. climate_ref_esmvaltool/recipe.py +55 -10
  18. climate_ref_esmvaltool/recipes.txt +16 -11
  19. climate_ref_esmvaltool/requirements/conda-lock.yml +4081 -3770
  20. climate_ref_esmvaltool/requirements/environment.yml +1 -0
  21. {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/METADATA +1 -1
  22. climate_ref_esmvaltool-0.7.0.dist-info/RECORD +30 -0
  23. climate_ref_esmvaltool-0.6.5.dist-info/RECORD +0 -27
  24. {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/WHEEL +0 -0
  25. {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/entry_points.txt +0 -0
  26. {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/licenses/LICENCE +0 -0
  27. {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/licenses/NOTICE +0 -0
@@ -73,6 +73,9 @@ ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlut_200003-202311
73
73
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rlutcs_200003-202311.nc e70e3273092edf01527970693271641fc6474d1974887d7d272e7d656bab83c2
74
74
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rsut_200003-202311.nc e31e648886c4fa9c09686672a06ab18fbba687ff0d6de2891616d4c8b74e215d
75
75
  ESMValTool/OBS/Tier2/CERES-EBAF/OBS_CERES-EBAF_sat_Ed4.2_Amon_rsutcs_200003-202311.nc eb96edd9274670aa705eab2a6d1ee0cca11e01ac17096706463e032b58e6be47
76
+ ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_clivi_198201-201612.nc 13bc6e3a46397386a14a36776fdd6bdbf5c45147c8dc695d4a7387883d449775
77
+ ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_clt_198201-201612.nc 4a430d77dbe9164dba2d1fdef4bb89ea9358b6d10023f3fbee50917422446ed0
78
+ ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_clwvi_198201-201612.nc e0ffa31369d9552be16b920110b24013d31e116b180ee3f70b3d0aaa5281eff0
76
79
  ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rlut_198201-201612.nc 075144d673a9f2ff49fbe59e701535bf80c04908797a9dca83781000a9b1b7f2
77
80
  ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rlutcs_198201-201612.nc 21f096ecafff659e5c7e3338060425f7194e5d1b39c9510865496e04ecac3d75
78
81
  ESMValTool/OBS/Tier2/ESACCI-CLOUD/OBS_ESACCI-CLOUD_sat_AVHRR-AMPM-fv3.0_Amon_rsut_198201-201612.nc f2c3f3afcdc2e730df7985c210a3de89b0d4f83b150e0c3846f7ac3c5fa9c54a
@@ -156,5 +159,6 @@ ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201101-20111
156
159
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201201-201212.nc 86187c3d1174053f2cba6dad010af49ceab77d368aa9314bf53c330b5f2217b9
157
160
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201301-201312.nc 8820353570884b2ef182caaffb5986ed6268bbe199fd867f61b56e798ca01f1a
158
161
  ESMValTool/OBS/Tier2/OSI-450-sh/OBS_OSI-450-sh_reanaly_v3_OImon_sic_201401-201412.nc 7102d0db3dc02c5b0eb0cfe3535ee50171007ef5b43eb9aae1220ac21b0b98e9
162
+ ESMValTool/OBS/Tier3/CALIPSO-ICECLOUD/OBS_CALIPSO-ICECLOUD_sat_1-00_Amon_cli_200701-201512.nc 977824810e8f9dbe7df278c59397ffc3f78491a9eb5a0b70e6b28ac66db8e12d
159
163
  ESMValTool/OBS/Tier2/TROPFLUX/OBS6_TROPFLUX_reanaly_v1_Amon_tauu_197901-201812.nc bf313e661b42341d5090038b501ed1ff09e58201009c3fccfe45b78e116fdd78
160
164
  ESMValTool/OBS/Tier2/TROPFLUX/OBS6_TROPFLUX_reanaly_v1_Omon_tos_197901-201812.nc 5f10a5a2aa47f5d21378ad3178bf8e4b577b0ed72ef8402dc04f5ff6fc99ec07
@@ -1,10 +1,23 @@
1
1
  """ESMValTool diagnostics."""
2
2
 
3
3
  from climate_ref_esmvaltool.diagnostics.climate_at_global_warming_levels import ClimateAtGlobalWarmingLevels
4
+ from climate_ref_esmvaltool.diagnostics.climate_drivers_for_fire import ClimateDriversForFire
4
5
  from climate_ref_esmvaltool.diagnostics.cloud_radiative_effects import CloudRadiativeEffects
6
+ from climate_ref_esmvaltool.diagnostics.cloud_scatterplots import (
7
+ CloudScatterplotCliTa,
8
+ CloudScatterplotCliviLwcre,
9
+ CloudScatterplotCltSwcre,
10
+ CloudScatterplotClwviPr,
11
+ CloudScatterplotsReference,
12
+ )
5
13
  from climate_ref_esmvaltool.diagnostics.ecs import EquilibriumClimateSensitivity
6
14
  from climate_ref_esmvaltool.diagnostics.enso import ENSOBasicClimatology, ENSOCharacteristics
7
15
  from climate_ref_esmvaltool.diagnostics.example import GlobalMeanTimeseries
16
+ from climate_ref_esmvaltool.diagnostics.regional_historical_changes import (
17
+ RegionalHistoricalAnnualCycle,
18
+ RegionalHistoricalTimeSeries,
19
+ RegionalHistoricalTrend,
20
+ )
8
21
  from climate_ref_esmvaltool.diagnostics.sea_ice_area_basic import SeaIceAreaBasic
9
22
  from climate_ref_esmvaltool.diagnostics.sea_ice_sensitivity import SeaIceSensitivity
10
23
  from climate_ref_esmvaltool.diagnostics.tcr import TransientClimateResponse
@@ -13,11 +26,20 @@ from climate_ref_esmvaltool.diagnostics.zec import ZeroEmissionCommitment
13
26
 
14
27
  __all__ = [
15
28
  "ClimateAtGlobalWarmingLevels",
29
+ "ClimateDriversForFire",
16
30
  "CloudRadiativeEffects",
31
+ "CloudScatterplotCliTa",
32
+ "CloudScatterplotCliviLwcre",
33
+ "CloudScatterplotCltSwcre",
34
+ "CloudScatterplotClwviPr",
35
+ "CloudScatterplotsReference",
17
36
  "ENSOBasicClimatology",
18
37
  "ENSOCharacteristics",
19
38
  "EquilibriumClimateSensitivity",
20
39
  "GlobalMeanTimeseries",
40
+ "RegionalHistoricalAnnualCycle",
41
+ "RegionalHistoricalTimeSeries",
42
+ "RegionalHistoricalTrend",
21
43
  "SeaIceAreaBasic",
22
44
  "SeaIceSensitivity",
23
45
  "TransientClimateResponse",
@@ -1,9 +1,11 @@
1
+ import fnmatch
1
2
  from abc import abstractmethod
2
3
  from collections.abc import Iterable
3
4
  from pathlib import Path
4
5
  from typing import ClassVar
5
6
 
6
7
  import pandas
8
+ import xarray as xr
7
9
  import yaml
8
10
  from loguru import logger
9
11
 
@@ -14,6 +16,7 @@ from climate_ref_core.diagnostics import (
14
16
  ExecutionDefinition,
15
17
  ExecutionResult,
16
18
  )
19
+ from climate_ref_core.metric_values.typing import SeriesMetricValue
17
20
  from climate_ref_core.pycmec.metric import CMECMetric, MetricCV
18
21
  from climate_ref_core.pycmec.output import CMECOutput, OutputCV
19
22
  from climate_ref_esmvaltool.recipe import load_recipe, prepare_climate_data
@@ -27,7 +30,10 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
27
30
 
28
31
  @staticmethod
29
32
  @abstractmethod
30
- def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
33
+ def update_recipe(
34
+ recipe: Recipe,
35
+ input_files: dict[SourceDatasetType, pandas.DataFrame],
36
+ ) -> None:
31
37
  """
32
38
  Update the base recipe for the run.
33
39
 
@@ -67,9 +73,9 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
67
73
  """
68
74
  return CMECMetric.model_validate(metric_args), CMECOutput.model_validate(output_args)
69
75
 
70
- def build_cmd(self, definition: ExecutionDefinition) -> Iterable[str]:
76
+ def write_recipe(self, definition: ExecutionDefinition) -> Path:
71
77
  """
72
- Build the command to run an ESMValTool recipe.
78
+ Update the ESMValTool recipe for the diagnostic and write it to file.
73
79
 
74
80
  Parameters
75
81
  ----------
@@ -79,22 +85,43 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
79
85
  Returns
80
86
  -------
81
87
  :
82
- The result of running the diagnostic.
88
+ The path to the written recipe.
83
89
  """
84
- input_files = definition.datasets[SourceDatasetType.CMIP6].datasets
90
+ input_files = {
91
+ project: dataset_collection.datasets
92
+ for project, dataset_collection in definition.datasets.items()
93
+ }
85
94
  recipe = load_recipe(self.base_recipe)
86
95
  self.update_recipe(recipe, input_files)
87
-
96
+ recipe_txt = yaml.safe_dump(recipe, sort_keys=False)
97
+ logger.info(f"Using ESMValTool recipe:\n{recipe_txt}")
88
98
  recipe_path = definition.to_output_path("recipe.yml")
89
99
  with recipe_path.open("w", encoding="utf-8") as file:
90
- yaml.dump(recipe, file)
100
+ file.write(recipe_txt)
101
+ return recipe_path
102
+
103
+ def build_cmd(self, definition: ExecutionDefinition) -> Iterable[str]:
104
+ """
105
+ Build the command to run an ESMValTool recipe.
91
106
 
107
+ Parameters
108
+ ----------
109
+ definition
110
+ A description of the information needed for this execution of the diagnostic
111
+
112
+ Returns
113
+ -------
114
+ :
115
+ The result of running the diagnostic.
116
+ """
117
+ recipe_path = self.write_recipe(definition)
92
118
  climate_data = definition.to_output_path("climate_data")
93
119
 
94
- prepare_climate_data(
95
- definition.datasets[SourceDatasetType.CMIP6].datasets,
96
- climate_data_dir=climate_data,
97
- )
120
+ for metric_dataset in definition.datasets.values():
121
+ prepare_climate_data(
122
+ metric_dataset.datasets,
123
+ climate_data_dir=climate_data,
124
+ )
98
125
 
99
126
  config = {
100
127
  "drs": {
@@ -130,7 +157,7 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
130
157
  {
131
158
  "OBS": str(data_dir / "OBS"),
132
159
  "OBS6": str(data_dir / "OBS"),
133
- "native6": str(data_dir / "RAWOBS"),
160
+ "native6": str(data_dir / "native6"),
134
161
  }
135
162
  )
136
163
  config["rootpath"]["obs4MIPs"] = [ # type: ignore[index]
@@ -140,8 +167,10 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
140
167
 
141
168
  config_dir = definition.to_output_path("config")
142
169
  config_dir.mkdir()
170
+ config_txt = yaml.safe_dump(config)
171
+ logger.info(f"Using ESMValTool configuration:\n{config_txt}")
143
172
  with (config_dir / "config.yml").open("w", encoding="utf-8") as file:
144
- yaml.dump(config, file)
173
+ file.write(config_txt)
145
174
 
146
175
  return [
147
176
  "esmvaltool",
@@ -172,7 +201,17 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
172
201
  metric_args = CMECMetric.create_template()
173
202
  output_args = CMECOutput.create_template()
174
203
 
204
+ # Input selectors for the datasets used in the diagnostic.
205
+ # TODO: Better handling of multiple source types
206
+ if SourceDatasetType.CMIP6 in definition.datasets:
207
+ input_selectors = definition.datasets[SourceDatasetType.CMIP6].selector_dict()
208
+ elif SourceDatasetType.obs4MIPs in definition.datasets:
209
+ input_selectors = definition.datasets[SourceDatasetType.obs4MIPs].selector_dict()
210
+ else:
211
+ input_selectors = {}
212
+
175
213
  # Add the plots and data files
214
+ series = []
176
215
  plot_suffixes = {".png", ".jpg", ".pdf", ".ps"}
177
216
  for metadata_file in result_dir.glob("run/*/*/diagnostic_provenance.yml"):
178
217
  metadata = yaml.safe_load(metadata_file.read_text(encoding="utf-8"))
@@ -188,6 +227,11 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
188
227
  OutputCV.LONG_NAME.value: caption,
189
228
  OutputCV.DESCRIPTION.value: "",
190
229
  }
230
+ series.extend(
231
+ self._extract_series_from_file(
232
+ definition, filename, relative_path, caption=caption, input_selectors=input_selectors
233
+ )
234
+ )
191
235
 
192
236
  # Add the index.html file
193
237
  index_html = f"{result_dir}/index.html"
@@ -211,11 +255,65 @@ class ESMValToolDiagnostic(CommandLineDiagnostic):
211
255
 
212
256
  # Add the extra information from the groupby operations
213
257
  if len(metric_bundle.DIMENSIONS[MetricCV.JSON_STRUCTURE.value]):
214
- input_selectors = definition.datasets[SourceDatasetType.CMIP6].selector_dict()
215
258
  metric_bundle = metric_bundle.prepend_dimensions(input_selectors)
216
259
 
217
260
  return ExecutionResult.build_from_output_bundle(
218
261
  definition,
219
262
  cmec_output_bundle=output_bundle,
220
263
  cmec_metric_bundle=metric_bundle,
264
+ series=series,
221
265
  )
266
+
267
+ def _extract_series_from_file(
268
+ self,
269
+ definition: ExecutionDefinition,
270
+ filename: Path,
271
+ relative_path: Path,
272
+ caption: str,
273
+ input_selectors: dict[str, str],
274
+ ) -> list[SeriesMetricValue]:
275
+ """
276
+ Extract series data from a file if it matches any of the series definitions.
277
+ """
278
+ variable_attributes = (
279
+ "long_name",
280
+ "standard_name",
281
+ "units",
282
+ )
283
+
284
+ series = []
285
+ for series_def in definition.diagnostic.series:
286
+ if fnmatch.fnmatch(
287
+ str(relative_path),
288
+ f"executions/*/{series_def.file_pattern.format(**input_selectors)}",
289
+ ):
290
+ dataset = xr.open_dataset(filename, decode_times=xr.coders.CFDatetimeCoder(use_cftime=True))
291
+ dataset = dataset.sel(series_def.sel)
292
+ attributes = {
293
+ attr: dataset.attrs[attr] for attr in series_def.attributes if attr in dataset.attrs
294
+ }
295
+ attributes["caption"] = caption
296
+ attributes["values_name"] = series_def.values_name
297
+ attributes["index_name"] = series_def.index_name
298
+ for attr in variable_attributes:
299
+ if attr in dataset[series_def.values_name].attrs:
300
+ attributes[f"value_{attr}"] = dataset[series_def.values_name].attrs[attr]
301
+ if attr in dataset[series_def.index_name].attrs:
302
+ attributes[f"index_{attr}"] = dataset[series_def.index_name].attrs[attr]
303
+ index = dataset[series_def.index_name].values.tolist()
304
+ if hasattr(index[0], "calendar"):
305
+ attributes["calendar"] = index[0].calendar
306
+ if hasattr(index[0], "isoformat"):
307
+ # Convert time objects to strings.
308
+ index = [v.isoformat() for v in index]
309
+
310
+ series.append(
311
+ SeriesMetricValue(
312
+ dimensions={**input_selectors, **series_def.dimensions},
313
+ values=dataset[series_def.values_name].values.tolist(),
314
+ index=index,
315
+ index_name=series_def.index_name,
316
+ attributes=attributes,
317
+ )
318
+ )
319
+ return series
@@ -2,8 +2,9 @@ import pandas
2
2
 
3
3
  from climate_ref_core.constraints import (
4
4
  AddSupplementaryDataset,
5
- RequireContiguousTimerange,
5
+ PartialDateTime,
6
6
  RequireFacets,
7
+ RequireTimerange,
7
8
  )
8
9
  from climate_ref_core.datasets import FacetFilter, SourceDatasetType
9
10
  from climate_ref_core.diagnostics import DataRequirement
@@ -26,6 +27,14 @@ class ClimateAtGlobalWarmingLevels(ESMValToolDiagnostic):
26
27
  "tas",
27
28
  )
28
29
 
30
+ matching_facets = (
31
+ "source_id",
32
+ "member_id",
33
+ "grid_label",
34
+ "table_id",
35
+ "variable_id",
36
+ )
37
+
29
38
  data_requirements = (
30
39
  DataRequirement(
31
40
  source_type=SourceDatasetType.CMIP6,
@@ -39,25 +48,32 @@ class ClimateAtGlobalWarmingLevels(ESMValToolDiagnostic):
39
48
  "ssp370",
40
49
  "ssp585",
41
50
  ),
51
+ "table_id": "Amon",
42
52
  },
43
53
  ),
44
54
  ),
45
55
  group_by=("experiment_id",),
46
56
  constraints=(
47
- RequireFacets("variable_id", variables),
48
57
  AddSupplementaryDataset(
49
58
  supplementary_facets={"experiment_id": "historical"},
50
- matching_facets=(
51
- "source_id",
52
- "member_id",
53
- "grid_label",
54
- "table_id",
55
- "variable_id",
56
- ),
59
+ matching_facets=matching_facets,
57
60
  optional_matching_facets=tuple(),
58
61
  ),
59
- RequireFacets("experiment_id", ("historical",)),
60
- RequireContiguousTimerange(group_by=("instance_id",)),
62
+ RequireTimerange(
63
+ group_by=matching_facets,
64
+ start=PartialDateTime(year=1850, month=1),
65
+ end=PartialDateTime(year=2100, month=12),
66
+ ),
67
+ RequireFacets(
68
+ "experiment_id",
69
+ required_facets=("historical",),
70
+ group_by=matching_facets,
71
+ ),
72
+ RequireFacets(
73
+ "variable_id",
74
+ required_facets=variables,
75
+ group_by=("experiment_id", "source_id", "member_id", "grid_label", "table_id"),
76
+ ),
61
77
  AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
62
78
  ),
63
79
  ),
@@ -65,19 +81,29 @@ class ClimateAtGlobalWarmingLevels(ESMValToolDiagnostic):
65
81
  facets = ()
66
82
 
67
83
  @staticmethod
68
- def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
84
+ def update_recipe(
85
+ recipe: Recipe,
86
+ input_files: dict[SourceDatasetType, pandas.DataFrame],
87
+ ) -> None:
69
88
  """Update the recipe."""
70
89
  # Set up the datasets
71
90
  diagnostics = recipe["diagnostics"]
72
91
  for diagnostic in diagnostics.values():
73
92
  diagnostic.pop("additional_datasets")
74
- recipe_variables = dataframe_to_recipe(input_files)
93
+ recipe_variables = dataframe_to_recipe(
94
+ input_files[SourceDatasetType.CMIP6],
95
+ group_by=(
96
+ "source_id",
97
+ "member_id",
98
+ "grid_label",
99
+ "table_id",
100
+ "variable_id",
101
+ ),
102
+ )
75
103
  datasets = recipe_variables["tas"]["additional_datasets"]
76
104
  datasets = [ds for ds in datasets if ds["exp"] != "historical"]
77
105
  for dataset in datasets:
78
106
  dataset.pop("timerange")
79
- dataset["activity"] = ["CMIP", dataset["activity"]]
80
- dataset["exp"] = ["historical", dataset["exp"]]
81
107
  recipe["datasets"] = datasets
82
108
 
83
109
  # Specify the timeranges
@@ -0,0 +1,90 @@
1
+ import pandas
2
+
3
+ from climate_ref_core.constraints import (
4
+ AddSupplementaryDataset,
5
+ PartialDateTime,
6
+ RequireFacets,
7
+ RequireTimerange,
8
+ )
9
+ from climate_ref_core.datasets import FacetFilter, SourceDatasetType
10
+ from climate_ref_core.diagnostics import DataRequirement
11
+ from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
12
+ from climate_ref_esmvaltool.recipe import dataframe_to_recipe
13
+ from climate_ref_esmvaltool.types import Recipe
14
+
15
+
16
+ class ClimateDriversForFire(ESMValToolDiagnostic):
17
+ """
18
+ Calculate diagnostics regarding climate drivers for fire.
19
+ """
20
+
21
+ name = "Climate drivers for fire"
22
+ slug = "climate-drivers-for-fire"
23
+ base_recipe = "ref/recipe_ref_fire.yml"
24
+
25
+ data_requirements = (
26
+ DataRequirement(
27
+ source_type=SourceDatasetType.CMIP6,
28
+ filters=(
29
+ FacetFilter(
30
+ {
31
+ "variable_id": ("hurs", "pr", "tas", "tasmax"),
32
+ "experiment_id": "historical",
33
+ "table_id": "Amon",
34
+ }
35
+ ),
36
+ FacetFilter(
37
+ {
38
+ "variable_id": ("cVeg", "treeFrac"),
39
+ "experiment_id": "historical",
40
+ "table_id": "Lmon",
41
+ }
42
+ ),
43
+ FacetFilter(
44
+ {
45
+ "variable_id": "vegFrac",
46
+ "experiment_id": "historical",
47
+ "table_id": "Emon",
48
+ }
49
+ ),
50
+ ),
51
+ group_by=("source_id", "member_id", "grid_label"),
52
+ constraints=(
53
+ RequireTimerange(
54
+ group_by=("instance_id",),
55
+ start=PartialDateTime(2013, 1),
56
+ end=PartialDateTime(2014, 12),
57
+ ),
58
+ AddSupplementaryDataset.from_defaults("sftlf", SourceDatasetType.CMIP6),
59
+ RequireFacets(
60
+ "variable_id",
61
+ (
62
+ "cVeg",
63
+ "hurs",
64
+ "pr",
65
+ "tas",
66
+ "tasmax",
67
+ "sftlf",
68
+ "treeFrac",
69
+ "vegFrac",
70
+ ),
71
+ ),
72
+ ),
73
+ ),
74
+ )
75
+ facets = ()
76
+
77
+ @staticmethod
78
+ def update_recipe(
79
+ recipe: Recipe,
80
+ input_files: dict[SourceDatasetType, pandas.DataFrame],
81
+ ) -> None:
82
+ """Update the recipe."""
83
+ recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
84
+ dataset = recipe_variables["cVeg"]["additional_datasets"][0]
85
+ dataset.pop("mip")
86
+ dataset.pop("timerange")
87
+ dataset["start_year"] = 2013
88
+ dataset["end_year"] = 2014
89
+ recipe["datasets"] = [dataset]
90
+ recipe["diagnostics"]["fire_evaluation"]["scripts"]["fire_evaluation"]["remove_confire_files"] = True
@@ -2,12 +2,14 @@ import pandas
2
2
 
3
3
  from climate_ref_core.constraints import (
4
4
  AddSupplementaryDataset,
5
- RequireContiguousTimerange,
5
+ PartialDateTime,
6
6
  RequireFacets,
7
7
  RequireOverlappingTimerange,
8
+ RequireTimerange,
8
9
  )
9
10
  from climate_ref_core.datasets import FacetFilter, SourceDatasetType
10
11
  from climate_ref_core.diagnostics import DataRequirement
12
+ from climate_ref_core.metric_values.typing import SeriesDefinition
11
13
  from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
12
14
  from climate_ref_esmvaltool.recipe import dataframe_to_recipe
13
15
  from climate_ref_esmvaltool.types import Recipe
@@ -22,8 +24,6 @@ class CloudRadiativeEffects(ESMValToolDiagnostic):
22
24
  slug = "cloud-radiative-effects"
23
25
  base_recipe = "ref/recipe_ref_cre.yml"
24
26
 
25
- facets = ()
26
-
27
27
  variables = (
28
28
  "rlut",
29
29
  "rlutcs",
@@ -37,40 +37,46 @@ class CloudRadiativeEffects(ESMValToolDiagnostic):
37
37
  FacetFilter(
38
38
  facets={
39
39
  "variable_id": variables,
40
- "experiment_id": ("historical",),
40
+ "experiment_id": "historical",
41
+ "table_id": "Amon",
41
42
  }
42
43
  ),
43
44
  ),
44
45
  group_by=("source_id", "member_id", "grid_label"),
45
46
  constraints=(
46
- RequireFacets("variable_id", variables),
47
- RequireContiguousTimerange(group_by=("instance_id",)),
47
+ RequireTimerange(
48
+ group_by=("instance_id",),
49
+ start=PartialDateTime(1996, 1),
50
+ end=PartialDateTime(2014, 12),
51
+ ),
48
52
  RequireOverlappingTimerange(group_by=("instance_id",)),
53
+ RequireFacets("variable_id", variables),
49
54
  AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
50
55
  ),
51
56
  ),
52
57
  # TODO: Use CERES-EBAF, ESACCI-CLOUD, and ISCCP-FH from obs4MIPs once available.
53
58
  )
54
59
 
60
+ facets = ()
61
+ series = tuple(
62
+ SeriesDefinition(
63
+ file_pattern=f"plot_profiles/plot/variable_vs_lat_{var_name}_*.nc",
64
+ sel={"dim0": 0}, # Select the model and not the observations.
65
+ dimensions={"statistic": f"{var_name} zonal mean"},
66
+ values_name=var_name,
67
+ index_name="lat",
68
+ attributes=[],
69
+ )
70
+ for var_name in ["lwcre", "swcre"]
71
+ )
72
+
55
73
  @staticmethod
56
- def update_recipe(recipe: Recipe, input_files: pandas.DataFrame) -> None:
74
+ def update_recipe(recipe: Recipe, input_files: dict[SourceDatasetType, pandas.DataFrame]) -> None:
57
75
  """Update the recipe."""
58
- recipe_variables = dataframe_to_recipe(input_files)
76
+ recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
59
77
  recipe_variables = {k: v for k, v in recipe_variables.items() if k != "areacella"}
60
78
 
61
- # Select a timerange covered by all datasets.
62
- start_times, end_times = [], []
63
- for variable in recipe_variables.values():
64
- for dataset in variable["additional_datasets"]:
65
- start, end = dataset["timerange"].split("/")
66
- start_times.append(start)
67
- end_times.append(end)
68
- start_time = max(start_times)
69
- start_time = max(start_time, "20010101T000000") # Earliest observational dataset availability
70
- timerange = f"{start_time}/{min(end_times)}"
71
-
72
79
  datasets = recipe_variables["rsut"]["additional_datasets"]
73
80
  for dataset in datasets:
74
81
  dataset.pop("timerange")
75
82
  recipe["datasets"] = datasets
76
- recipe["timerange_for_models"] = timerange