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.
- climate_ref_esmvaltool/dataset_registry/data.txt +4 -0
- climate_ref_esmvaltool/diagnostics/__init__.py +22 -0
- climate_ref_esmvaltool/diagnostics/base.py +112 -14
- climate_ref_esmvaltool/diagnostics/climate_at_global_warming_levels.py +41 -15
- climate_ref_esmvaltool/diagnostics/climate_drivers_for_fire.py +90 -0
- climate_ref_esmvaltool/diagnostics/cloud_radiative_effects.py +26 -20
- climate_ref_esmvaltool/diagnostics/cloud_scatterplots.py +200 -0
- climate_ref_esmvaltool/diagnostics/ecs.py +32 -20
- climate_ref_esmvaltool/diagnostics/enso.py +88 -12
- climate_ref_esmvaltool/diagnostics/example.py +17 -3
- climate_ref_esmvaltool/diagnostics/regional_historical_changes.py +435 -0
- climate_ref_esmvaltool/diagnostics/sea_ice_area_basic.py +63 -5
- climate_ref_esmvaltool/diagnostics/sea_ice_sensitivity.py +31 -14
- climate_ref_esmvaltool/diagnostics/tcr.py +23 -19
- climate_ref_esmvaltool/diagnostics/tcre.py +13 -12
- climate_ref_esmvaltool/diagnostics/zec.py +20 -3
- climate_ref_esmvaltool/recipe.py +55 -10
- climate_ref_esmvaltool/recipes.txt +16 -11
- climate_ref_esmvaltool/requirements/conda-lock.yml +4081 -3770
- climate_ref_esmvaltool/requirements/environment.yml +1 -0
- {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/METADATA +1 -1
- climate_ref_esmvaltool-0.7.0.dist-info/RECORD +30 -0
- climate_ref_esmvaltool-0.6.5.dist-info/RECORD +0 -27
- {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/WHEEL +0 -0
- {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/entry_points.txt +0 -0
- {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/licenses/LICENCE +0 -0
- {climate_ref_esmvaltool-0.6.5.dist-info → climate_ref_esmvaltool-0.7.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
|
|
3
|
+
import pandas
|
|
4
|
+
|
|
5
|
+
from climate_ref_core.constraints import (
|
|
6
|
+
AddSupplementaryDataset,
|
|
7
|
+
PartialDateTime,
|
|
8
|
+
RequireFacets,
|
|
9
|
+
RequireTimerange,
|
|
10
|
+
)
|
|
11
|
+
from climate_ref_core.datasets import FacetFilter, SourceDatasetType
|
|
12
|
+
from climate_ref_core.diagnostics import DataRequirement
|
|
13
|
+
from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
|
|
14
|
+
from climate_ref_esmvaltool.recipe import dataframe_to_recipe
|
|
15
|
+
from climate_ref_esmvaltool.types import Recipe
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_cmip6_data_requirements(variables: tuple[str, ...]) -> tuple[DataRequirement, ...]:
|
|
19
|
+
"""Create a data requirement for CMIP6 data."""
|
|
20
|
+
return (
|
|
21
|
+
DataRequirement(
|
|
22
|
+
source_type=SourceDatasetType.CMIP6,
|
|
23
|
+
filters=(
|
|
24
|
+
FacetFilter(
|
|
25
|
+
facets={
|
|
26
|
+
"variable_id": variables,
|
|
27
|
+
"experiment_id": "historical",
|
|
28
|
+
"table_id": "Amon",
|
|
29
|
+
},
|
|
30
|
+
),
|
|
31
|
+
),
|
|
32
|
+
group_by=("source_id", "experiment_id", "member_id", "frequency", "grid_label"),
|
|
33
|
+
constraints=(
|
|
34
|
+
RequireTimerange(
|
|
35
|
+
group_by=("instance_id",),
|
|
36
|
+
start=PartialDateTime(1996, 1),
|
|
37
|
+
end=PartialDateTime(2014, 12),
|
|
38
|
+
),
|
|
39
|
+
RequireFacets("variable_id", variables),
|
|
40
|
+
AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def update_recipe(
|
|
47
|
+
recipe: Recipe,
|
|
48
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
49
|
+
var_x: str,
|
|
50
|
+
var_y: str,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Update the recipe."""
|
|
53
|
+
recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
|
|
54
|
+
diagnostics = recipe["diagnostics"]
|
|
55
|
+
diagnostic_name = f"plot_joint_{var_x}_{var_y}_model"
|
|
56
|
+
diagnostic = diagnostics.pop(diagnostic_name)
|
|
57
|
+
diagnostics.clear()
|
|
58
|
+
diagnostics[diagnostic_name] = diagnostic
|
|
59
|
+
recipe_variables = {k: v for k, v in recipe_variables.items() if k != "areacella"}
|
|
60
|
+
datasets = next(iter(recipe_variables.values()))["additional_datasets"]
|
|
61
|
+
for dataset in datasets:
|
|
62
|
+
dataset["timerange"] = "1996/2014"
|
|
63
|
+
diagnostic["additional_datasets"] = datasets
|
|
64
|
+
suptitle = "CMIP6 {dataset} {ensemble} {grid} {timerange}".format(**datasets[0])
|
|
65
|
+
diagnostic["scripts"]["plot"]["suptitle"] = suptitle
|
|
66
|
+
diagnostic["scripts"]["plot"]["plot_filename"] = (
|
|
67
|
+
f"jointplot_{var_x}_{var_y}_{suptitle.replace(' ', '_').replace('/', '-')}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CloudScatterplotCltSwcre(ESMValToolDiagnostic):
|
|
72
|
+
"""
|
|
73
|
+
Scatterplot of clt vs swcre.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
name = "Scatterplots of two cloud-relevant variables (clt vs swcre)"
|
|
77
|
+
slug = "cloud-scatterplots-clt-swcre"
|
|
78
|
+
base_recipe = "ref/recipe_ref_scatterplot.yml"
|
|
79
|
+
facets = ()
|
|
80
|
+
data_requirements = get_cmip6_data_requirements(("clt", "rsut", "rsutcs"))
|
|
81
|
+
update_recipe = partial(update_recipe, var_x="clt", var_y="swcre")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class CloudScatterplotClwviPr(ESMValToolDiagnostic):
|
|
85
|
+
"""
|
|
86
|
+
Scatterplot of clwvi vs pr.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
name = "Scatterplots of two cloud-relevant variables (clwvi vs pr)"
|
|
90
|
+
slug = "cloud-scatterplots-clwvi-pr"
|
|
91
|
+
base_recipe = "ref/recipe_ref_scatterplot.yml"
|
|
92
|
+
facets = ()
|
|
93
|
+
data_requirements = get_cmip6_data_requirements(("clwvi", "pr"))
|
|
94
|
+
update_recipe = partial(update_recipe, var_x="clwvi", var_y="pr")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class CloudScatterplotCliviLwcre(ESMValToolDiagnostic):
|
|
98
|
+
"""
|
|
99
|
+
Scatterplot of clivi vs lwcre.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
name = "Scatterplots of two cloud-relevant variables (clivi vs lwcre)"
|
|
103
|
+
slug = "cloud-scatterplots-clivi-lwcre"
|
|
104
|
+
base_recipe = "ref/recipe_ref_scatterplot.yml"
|
|
105
|
+
facets = ()
|
|
106
|
+
data_requirements = get_cmip6_data_requirements(("clivi", "rlut", "rlutcs"))
|
|
107
|
+
update_recipe = partial(update_recipe, var_x="clivi", var_y="lwcre")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class CloudScatterplotCliTa(ESMValToolDiagnostic):
|
|
111
|
+
"""
|
|
112
|
+
Scatterplot of cli vs ta.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
name = "Scatterplots of two cloud-relevant variables (cli vs ta)"
|
|
116
|
+
slug = "cloud-scatterplots-cli-ta"
|
|
117
|
+
base_recipe = "ref/recipe_ref_scatterplot.yml"
|
|
118
|
+
facets = ()
|
|
119
|
+
data_requirements = get_cmip6_data_requirements(("cli", "ta"))
|
|
120
|
+
update_recipe = partial(update_recipe, var_x="cli", var_y="ta")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class CloudScatterplotsReference(ESMValToolDiagnostic):
|
|
124
|
+
"""
|
|
125
|
+
Reference scatterplots of two cloud-relevant variables.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
name = "Reference scatterplots of two cloud-relevant variables"
|
|
129
|
+
slug = "cloud-scatterplots-reference"
|
|
130
|
+
base_recipe = "ref/recipe_ref_scatterplot.yml"
|
|
131
|
+
facets = ()
|
|
132
|
+
data_requirements = (
|
|
133
|
+
DataRequirement(
|
|
134
|
+
source_type=SourceDatasetType.obs4MIPs,
|
|
135
|
+
filters=(
|
|
136
|
+
FacetFilter(
|
|
137
|
+
facets={
|
|
138
|
+
"source_id": ("ERA-5",),
|
|
139
|
+
"variable_id": ("ta",),
|
|
140
|
+
},
|
|
141
|
+
),
|
|
142
|
+
),
|
|
143
|
+
group_by=("instance_id",),
|
|
144
|
+
constraints=(
|
|
145
|
+
RequireTimerange(
|
|
146
|
+
group_by=("instance_id",),
|
|
147
|
+
start=PartialDateTime(2007, 1),
|
|
148
|
+
end=PartialDateTime(2014, 12),
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
# TODO: Add obs4MIPs datasets once available and working:
|
|
152
|
+
#
|
|
153
|
+
# obs4MIPs datasets with issues:
|
|
154
|
+
# - GPCP-V2.3: pr
|
|
155
|
+
# - CERES-EBAF-4-2: rlut, rlutcs, rsut, rsutcs
|
|
156
|
+
#
|
|
157
|
+
# Unsure if available on obs4MIPs:
|
|
158
|
+
# - AVHRR-AMPM-fv3.0: clivi, clwvi
|
|
159
|
+
# - ESACCI-CLOUD: clt
|
|
160
|
+
# - CALIPSO-ICECLOUD: cli
|
|
161
|
+
#
|
|
162
|
+
# Related issues:
|
|
163
|
+
# - https://github.com/Climate-REF/climate-ref/issues/260
|
|
164
|
+
# - https://github.com/esMValGroup/esMValCore/issues/2712
|
|
165
|
+
# - https://github.com/esMValGroup/esMValCore/issues/2711
|
|
166
|
+
# - https://github.com/sciTools/iris/issues/6411
|
|
167
|
+
),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
@staticmethod
|
|
171
|
+
def update_recipe(
|
|
172
|
+
recipe: Recipe,
|
|
173
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
174
|
+
) -> None:
|
|
175
|
+
"""Update the recipe."""
|
|
176
|
+
recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.obs4MIPs])
|
|
177
|
+
recipe["diagnostics"] = {k: v for k, v in recipe["diagnostics"].items() if k.endswith("_ref")}
|
|
178
|
+
|
|
179
|
+
era5_dataset = recipe_variables["ta"]["additional_datasets"][0]
|
|
180
|
+
era5_dataset["timerange"] = "2007/2015" # Use the same timerange as for the other variable.
|
|
181
|
+
era5_dataset["alias"] = era5_dataset["dataset"]
|
|
182
|
+
diagnostic = recipe["diagnostics"]["plot_joint_cli_ta_ref"]
|
|
183
|
+
diagnostic["variables"]["ta"]["additional_datasets"] = [era5_dataset]
|
|
184
|
+
suptitle = "CALIPSO-ICECLOUD / {dataset} {timerange}".format(**era5_dataset)
|
|
185
|
+
diagnostic["scripts"]["plot"]["suptitle"] = suptitle
|
|
186
|
+
diagnostic["scripts"]["plot"]["plot_filename"] = (
|
|
187
|
+
f"jointplot_cli_ta_{suptitle.replace(' ', '_').replace('/', '-')}"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Use the correct obs4MIPs dataset name for dataset that cannot be ingested
|
|
191
|
+
# https://github.com/Climate-REF/climate-ref/issues/260.
|
|
192
|
+
diagnostic = recipe["diagnostics"]["plot_joint_clwvi_pr_ref"]
|
|
193
|
+
diagnostic["variables"]["pr"]["additional_datasets"] = [
|
|
194
|
+
{
|
|
195
|
+
"dataset": "GPCP-V2.3",
|
|
196
|
+
"project": "obs4MIPs",
|
|
197
|
+
"alias": "GPCP-SG",
|
|
198
|
+
"timerange": "1992/2016",
|
|
199
|
+
}
|
|
200
|
+
]
|
|
@@ -11,6 +11,7 @@ from climate_ref_core.constraints import (
|
|
|
11
11
|
)
|
|
12
12
|
from climate_ref_core.datasets import ExecutionDatasetCollection, FacetFilter, SourceDatasetType
|
|
13
13
|
from climate_ref_core.diagnostics import DataRequirement
|
|
14
|
+
from climate_ref_core.metric_values.typing import SeriesDefinition
|
|
14
15
|
from climate_ref_core.pycmec.metric import CMECMetric, MetricCV
|
|
15
16
|
from climate_ref_core.pycmec.output import CMECOutput
|
|
16
17
|
from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
|
|
@@ -45,23 +46,46 @@ class EquilibriumClimateSensitivity(ESMValToolDiagnostic):
|
|
|
45
46
|
facets={
|
|
46
47
|
"variable_id": variables,
|
|
47
48
|
"experiment_id": experiments,
|
|
49
|
+
"table_id": "Amon",
|
|
48
50
|
},
|
|
49
51
|
),
|
|
50
52
|
),
|
|
51
53
|
group_by=("source_id", "member_id", "grid_label"),
|
|
52
54
|
constraints=(
|
|
53
|
-
RequireFacets("variable_id", variables),
|
|
54
|
-
RequireFacets("experiment_id", experiments),
|
|
55
55
|
RequireContiguousTimerange(group_by=("instance_id",)),
|
|
56
56
|
RequireOverlappingTimerange(group_by=("instance_id",)),
|
|
57
|
+
RequireFacets(
|
|
58
|
+
"variable_id",
|
|
59
|
+
required_facets=variables,
|
|
60
|
+
group_by=("source_id", "member_id", "grid_label", "experiment_id"),
|
|
61
|
+
),
|
|
62
|
+
RequireFacets(
|
|
63
|
+
"experiment_id",
|
|
64
|
+
required_facets=experiments,
|
|
65
|
+
group_by=("source_id", "member_id", "grid_label", "variable_id"),
|
|
66
|
+
),
|
|
57
67
|
AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
|
|
58
68
|
),
|
|
59
69
|
),
|
|
60
70
|
)
|
|
61
71
|
facets = ("grid_label", "member_id", "source_id", "region", "metric")
|
|
72
|
+
series = (
|
|
73
|
+
SeriesDefinition(
|
|
74
|
+
file_pattern="ecs/calculate/ecs_regression_*.nc",
|
|
75
|
+
dimensions={
|
|
76
|
+
"statistic": ("global annual mean anomaly of rtnt vs tas"),
|
|
77
|
+
},
|
|
78
|
+
values_name="rtnt_anomaly",
|
|
79
|
+
index_name="tas_anomaly",
|
|
80
|
+
attributes=[],
|
|
81
|
+
),
|
|
82
|
+
)
|
|
62
83
|
|
|
63
84
|
@staticmethod
|
|
64
|
-
def update_recipe(
|
|
85
|
+
def update_recipe(
|
|
86
|
+
recipe: Recipe,
|
|
87
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
88
|
+
) -> None:
|
|
65
89
|
"""Update the recipe."""
|
|
66
90
|
# Only run the diagnostic that computes ECS for a single model.
|
|
67
91
|
recipe["diagnostics"] = {
|
|
@@ -88,21 +112,11 @@ class EquilibriumClimateSensitivity(ESMValToolDiagnostic):
|
|
|
88
112
|
# Prepare updated datasets section in recipe. It contains two
|
|
89
113
|
# datasets, one for the "abrupt-4xCO2" and one for the "piControl"
|
|
90
114
|
# experiment.
|
|
91
|
-
recipe_variables = dataframe_to_recipe(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
for variable in recipe_variables.values():
|
|
97
|
-
for dataset in variable["additional_datasets"]:
|
|
98
|
-
start, end = dataset["timerange"].split("/")
|
|
99
|
-
start_times.append(start)
|
|
100
|
-
end_times.append(end)
|
|
101
|
-
timerange = f"{max(start_times)}/{min(end_times)}"
|
|
102
|
-
|
|
103
|
-
datasets = recipe_variables["tas"]["additional_datasets"]
|
|
104
|
-
for dataset in datasets:
|
|
105
|
-
dataset["timerange"] = timerange
|
|
115
|
+
recipe_variables = dataframe_to_recipe(
|
|
116
|
+
input_files[SourceDatasetType.CMIP6],
|
|
117
|
+
equalize_timerange=True,
|
|
118
|
+
)
|
|
119
|
+
recipe["datasets"] = recipe_variables["tas"]["additional_datasets"]
|
|
106
120
|
|
|
107
121
|
# Remove keys from the recipe that are only used for YAML anchors
|
|
108
122
|
keys_to_remove = [
|
|
@@ -116,8 +130,6 @@ class EquilibriumClimateSensitivity(ESMValToolDiagnostic):
|
|
|
116
130
|
for key in keys_to_remove:
|
|
117
131
|
recipe.pop(key, None)
|
|
118
132
|
|
|
119
|
-
recipe["datasets"] = datasets
|
|
120
|
-
|
|
121
133
|
@staticmethod
|
|
122
134
|
def format_result(
|
|
123
135
|
result_dir: Path,
|
|
@@ -11,6 +11,7 @@ from climate_ref_core.constraints import (
|
|
|
11
11
|
)
|
|
12
12
|
from climate_ref_core.datasets import ExecutionDatasetCollection, FacetFilter, SourceDatasetType
|
|
13
13
|
from climate_ref_core.diagnostics import DataRequirement
|
|
14
|
+
from climate_ref_core.metric_values.typing import SeriesDefinition
|
|
14
15
|
from climate_ref_core.pycmec.metric import CMECMetric, MetricCV
|
|
15
16
|
from climate_ref_core.pycmec.output import CMECOutput
|
|
16
17
|
from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
|
|
@@ -27,36 +28,104 @@ class ENSOBasicClimatology(ESMValToolDiagnostic):
|
|
|
27
28
|
slug = "enso-basic-climatology"
|
|
28
29
|
base_recipe = "ref/recipe_enso_basicclimatology.yml"
|
|
29
30
|
|
|
30
|
-
variables = (
|
|
31
|
-
"pr",
|
|
32
|
-
"tos",
|
|
33
|
-
"tauu",
|
|
34
|
-
)
|
|
35
31
|
data_requirements = (
|
|
36
32
|
DataRequirement(
|
|
37
33
|
source_type=SourceDatasetType.CMIP6,
|
|
38
34
|
filters=(
|
|
39
35
|
FacetFilter(
|
|
40
36
|
facets={
|
|
41
|
-
"variable_id":
|
|
37
|
+
"variable_id": ("pr", "tauu"),
|
|
38
|
+
"experiment_id": "historical",
|
|
39
|
+
"table_id": "Amon",
|
|
40
|
+
},
|
|
41
|
+
),
|
|
42
|
+
FacetFilter(
|
|
43
|
+
facets={
|
|
44
|
+
"variable_id": "tos",
|
|
42
45
|
"experiment_id": "historical",
|
|
46
|
+
"table_id": "Omon",
|
|
43
47
|
},
|
|
44
48
|
),
|
|
45
49
|
),
|
|
46
50
|
group_by=("source_id", "member_id", "grid_label"),
|
|
47
51
|
constraints=(
|
|
48
|
-
RequireFacets("variable_id", variables),
|
|
49
52
|
RequireContiguousTimerange(group_by=("instance_id",)),
|
|
50
53
|
RequireOverlappingTimerange(group_by=("instance_id",)),
|
|
54
|
+
RequireFacets(
|
|
55
|
+
"variable_id",
|
|
56
|
+
(
|
|
57
|
+
"pr",
|
|
58
|
+
"tauu",
|
|
59
|
+
"tos",
|
|
60
|
+
),
|
|
61
|
+
),
|
|
51
62
|
),
|
|
52
63
|
),
|
|
53
64
|
)
|
|
54
65
|
facets = ()
|
|
55
66
|
|
|
67
|
+
series = (
|
|
68
|
+
tuple(
|
|
69
|
+
SeriesDefinition(
|
|
70
|
+
file_pattern=f"diagnostic_metrics/plot_script/{{source_id}}_eq_{var_name}_bias.nc",
|
|
71
|
+
dimensions={
|
|
72
|
+
"statistic": (
|
|
73
|
+
f"zonal bias in the time-mean {var_name} structure across the equatorial Pacific"
|
|
74
|
+
),
|
|
75
|
+
},
|
|
76
|
+
values_name="tos" if var_name == "sst" else var_name,
|
|
77
|
+
index_name="lon",
|
|
78
|
+
attributes=[],
|
|
79
|
+
)
|
|
80
|
+
for var_name in ["pr", "sst", "tauu"]
|
|
81
|
+
)
|
|
82
|
+
+ tuple(
|
|
83
|
+
SeriesDefinition(
|
|
84
|
+
file_pattern=f"diagnostic_metrics/plot_script/{{source_id}}_eq_{var_name}_seacycle.nc",
|
|
85
|
+
dimensions={
|
|
86
|
+
"statistic": (
|
|
87
|
+
"zonal bias in the amplitude of the mean seasonal cycle of "
|
|
88
|
+
f"{var_name} in the equatorial Pacific"
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
values_name="tos" if var_name == "sst" else var_name,
|
|
92
|
+
index_name="lon",
|
|
93
|
+
attributes=[],
|
|
94
|
+
)
|
|
95
|
+
for var_name in ["pr", "sst", "tauu"]
|
|
96
|
+
)
|
|
97
|
+
+ (
|
|
98
|
+
SeriesDefinition(
|
|
99
|
+
file_pattern="diagnostic_metrics/plot_script/{source_id}_pr_double.nc",
|
|
100
|
+
dimensions={
|
|
101
|
+
"statistic": ("meridional bias in the time-mean pr structure across the eastern Pacific"),
|
|
102
|
+
},
|
|
103
|
+
values_name="pr",
|
|
104
|
+
index_name="lat",
|
|
105
|
+
attributes=[],
|
|
106
|
+
),
|
|
107
|
+
SeriesDefinition(
|
|
108
|
+
file_pattern="diagnostic_metrics/plot_script/*_pr_double_seacycle.nc",
|
|
109
|
+
dimensions={
|
|
110
|
+
"statistic": (
|
|
111
|
+
"meridional bias in the amplitude of the mean seasonal "
|
|
112
|
+
"pr cycle in the eastern Pacific"
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
values_name="pr",
|
|
116
|
+
index_name="lat",
|
|
117
|
+
attributes=[],
|
|
118
|
+
),
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
|
|
56
122
|
@staticmethod
|
|
57
|
-
def update_recipe(
|
|
123
|
+
def update_recipe(
|
|
124
|
+
recipe: Recipe,
|
|
125
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
126
|
+
) -> None:
|
|
58
127
|
"""Update the recipe."""
|
|
59
|
-
recipe_variables = dataframe_to_recipe(input_files)
|
|
128
|
+
recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
|
|
60
129
|
recipe.pop("datasets")
|
|
61
130
|
for diagnostic in recipe["diagnostics"].values():
|
|
62
131
|
for variable in diagnostic["variables"].values():
|
|
@@ -82,24 +151,31 @@ class ENSOCharacteristics(ESMValToolDiagnostic):
|
|
|
82
151
|
facets={
|
|
83
152
|
"variable_id": "tos",
|
|
84
153
|
"experiment_id": "historical",
|
|
154
|
+
"table_id": "Omon",
|
|
85
155
|
},
|
|
86
156
|
),
|
|
87
157
|
),
|
|
88
158
|
group_by=("source_id", "member_id", "grid_label"),
|
|
89
159
|
constraints=(
|
|
90
|
-
RequireFacets("variable_id", ("tos",)),
|
|
91
160
|
RequireContiguousTimerange(group_by=("instance_id",)),
|
|
92
161
|
RequireOverlappingTimerange(group_by=("instance_id",)),
|
|
93
162
|
AddSupplementaryDataset.from_defaults("areacello", SourceDatasetType.CMIP6),
|
|
163
|
+
RequireFacets("variable_id", ("tos", "areacello")),
|
|
94
164
|
),
|
|
95
165
|
),
|
|
96
166
|
)
|
|
97
167
|
facets = ("grid_label", "member_id", "source_id", "region", "metric")
|
|
168
|
+
# ENSO pattern and lifecycle are series, but the ESMValTool diagnostic
|
|
169
|
+
# script does not save the values used in the figure.
|
|
170
|
+
series = tuple()
|
|
98
171
|
|
|
99
172
|
@staticmethod
|
|
100
|
-
def update_recipe(
|
|
173
|
+
def update_recipe(
|
|
174
|
+
recipe: Recipe,
|
|
175
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
176
|
+
) -> None:
|
|
101
177
|
"""Update the recipe."""
|
|
102
|
-
recipe_variables = dataframe_to_recipe(input_files)
|
|
178
|
+
recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
|
|
103
179
|
recipe["datasets"] = recipe_variables["tos"]["additional_datasets"]
|
|
104
180
|
# TODO: update the observational data requirement once available on ESGF.
|
|
105
181
|
# Observations - use only one per run
|
|
@@ -3,6 +3,7 @@ import pandas
|
|
|
3
3
|
from climate_ref_core.constraints import AddSupplementaryDataset, RequireContiguousTimerange
|
|
4
4
|
from climate_ref_core.datasets import FacetFilter, SourceDatasetType
|
|
5
5
|
from climate_ref_core.diagnostics import DataRequirement
|
|
6
|
+
from climate_ref_core.metric_values.typing import SeriesDefinition
|
|
6
7
|
from climate_ref_esmvaltool.diagnostics.base import ESMValToolDiagnostic
|
|
7
8
|
from climate_ref_esmvaltool.recipe import dataframe_to_recipe
|
|
8
9
|
from climate_ref_esmvaltool.types import Recipe
|
|
@@ -21,17 +22,30 @@ class GlobalMeanTimeseries(ESMValToolDiagnostic):
|
|
|
21
22
|
DataRequirement(
|
|
22
23
|
source_type=SourceDatasetType.CMIP6,
|
|
23
24
|
filters=(FacetFilter(facets={"variable_id": ("tas",)}),),
|
|
24
|
-
group_by=("
|
|
25
|
+
group_by=("source_id", "experiment_id", "member_id", "table_id", "variable_id", "grid_label"),
|
|
25
26
|
constraints=(
|
|
26
27
|
RequireContiguousTimerange(group_by=("instance_id",)),
|
|
27
28
|
AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
|
|
28
29
|
),
|
|
29
30
|
),
|
|
30
31
|
)
|
|
32
|
+
|
|
31
33
|
facets = ()
|
|
34
|
+
series = (
|
|
35
|
+
SeriesDefinition(
|
|
36
|
+
file_pattern="timeseries/script1/*.nc",
|
|
37
|
+
dimensions={"statistic": "tas annual global mean"},
|
|
38
|
+
values_name="tas",
|
|
39
|
+
index_name="time",
|
|
40
|
+
attributes=[],
|
|
41
|
+
),
|
|
42
|
+
)
|
|
32
43
|
|
|
33
44
|
@staticmethod
|
|
34
|
-
def update_recipe(
|
|
45
|
+
def update_recipe(
|
|
46
|
+
recipe: Recipe,
|
|
47
|
+
input_files: dict[SourceDatasetType, pandas.DataFrame],
|
|
48
|
+
) -> None:
|
|
35
49
|
"""Update the recipe."""
|
|
36
50
|
# Clear unwanted elements from the recipe.
|
|
37
51
|
recipe["datasets"].clear()
|
|
@@ -40,7 +54,7 @@ class GlobalMeanTimeseries(ESMValToolDiagnostic):
|
|
|
40
54
|
variables.clear()
|
|
41
55
|
|
|
42
56
|
# Prepare updated variables section in recipe.
|
|
43
|
-
recipe_variables = dataframe_to_recipe(input_files)
|
|
57
|
+
recipe_variables = dataframe_to_recipe(input_files[SourceDatasetType.CMIP6])
|
|
44
58
|
recipe_variables = {k: v for k, v in recipe_variables.items() if k != "areacella"}
|
|
45
59
|
for variable in recipe_variables.values():
|
|
46
60
|
variable["preprocessor"] = "annual_mean_global"
|