climate-ref-pmp 0.5.4__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.
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/PKG-INFO +5 -4
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/pyproject.toml +9 -10
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/__init__.py +12 -4
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/diagnostics/__init__.py +2 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/diagnostics/annual_cycle.py +51 -42
- climate_ref_pmp-0.6.0/src/climate_ref_pmp/diagnostics/enso.py +245 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/diagnostics/variability_modes.py +6 -7
- climate_ref_pmp-0.6.0/src/climate_ref_pmp/drivers/enso_driver.py +458 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/requirements/conda-lock.yml +1809 -2362
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/requirements/environment.yml +1 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/integration/test_diagnostics.py +4 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/unit/conftest.py +1 -1
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/unit/test_annual_cycle.py +143 -21
- climate_ref_pmp-0.6.0/tests/unit/test_enso.py +33 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/unit/test_variability_modes.py +1 -12
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/.gitignore +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/LICENCE +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/NOTICE +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/README.md +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/conftest.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/dataset_registry/pmp_climatology.txt +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/params/pmp_param_MoV-psl.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/params/pmp_param_MoV-ts.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/params/pmp_param_annualcycle_1-clims.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/params/pmp_param_annualcycle_2-metrics.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/pmp_driver.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/py.typed +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/unit/test_pmp_driver.py +0 -0
- {climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/tests/unit/test_provider.py +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: climate-ref-pmp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: PMP diagnostic provider for the Rapid Evaluation Framework
|
|
5
|
-
Author-email: Jiwoo Lee <jwlee@llnl.gov>
|
|
6
|
-
License: Apache-2.0
|
|
5
|
+
Author-email: Jiwoo Lee <jwlee@llnl.gov>, Jared Lewis <jared.lewis@climate-resource.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
7
|
License-File: LICENCE
|
|
8
8
|
License-File: NOTICE
|
|
9
|
-
Classifier: Development Status ::
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
10
|
Classifier: Intended Audience :: Developers
|
|
11
11
|
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
13
|
Classifier: Operating System :: OS Independent
|
|
13
14
|
Classifier: Programming Language :: Python
|
|
14
15
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "climate-ref-pmp"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
4
4
|
description = "PMP diagnostic provider for the Rapid Evaluation Framework"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
7
|
-
{ name = "Jiwoo Lee", email = "jwlee@llnl.gov" }
|
|
7
|
+
{ name = "Jiwoo Lee", email = "jwlee@llnl.gov" },
|
|
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
|
-
"Development Status ::
|
|
12
|
-
"Intended Audience :: Developers",
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
13
14
|
"Operating System :: OS Independent",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
14
16
|
"Intended Audience :: Science/Research",
|
|
15
17
|
"Programming Language :: Python",
|
|
16
18
|
"Programming Language :: Python :: 3",
|
|
@@ -18,17 +20,14 @@ classifiers = [
|
|
|
18
20
|
"Programming Language :: Python :: 3.12",
|
|
19
21
|
"Programming Language :: Python :: 3.13",
|
|
20
22
|
"Topic :: Scientific/Engineering",
|
|
23
|
+
"License :: OSI Approved :: Apache Software License",
|
|
21
24
|
]
|
|
22
25
|
dependencies = [
|
|
23
26
|
"climate-ref-core",
|
|
24
27
|
]
|
|
25
28
|
|
|
26
|
-
[
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
[tool.uv]
|
|
30
|
-
dev-dependencies = [
|
|
31
|
-
]
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = []
|
|
32
31
|
|
|
33
32
|
[build-system]
|
|
34
33
|
requires = ["hatchling"]
|
|
@@ -4,9 +4,9 @@ Rapid evaluating CMIP data
|
|
|
4
4
|
|
|
5
5
|
import importlib.metadata
|
|
6
6
|
|
|
7
|
-
from climate_ref_core.dataset_registry import dataset_registry_manager
|
|
7
|
+
from climate_ref_core.dataset_registry import DATASET_URL, dataset_registry_manager
|
|
8
8
|
from climate_ref_core.providers import CondaDiagnosticProvider
|
|
9
|
-
from climate_ref_pmp.diagnostics import AnnualCycle, ExtratropicalModesOfVariability
|
|
9
|
+
from climate_ref_pmp.diagnostics import ENSO, AnnualCycle, ExtratropicalModesOfVariability
|
|
10
10
|
|
|
11
11
|
__version__ = importlib.metadata.version("climate-ref-pmp")
|
|
12
12
|
|
|
@@ -14,6 +14,15 @@ __version__ = importlib.metadata.version("climate-ref-pmp")
|
|
|
14
14
|
# PMP uses a conda environment to run the diagnostics
|
|
15
15
|
provider = CondaDiagnosticProvider("PMP", __version__)
|
|
16
16
|
|
|
17
|
+
# Annual cycle diagnostics and metrics
|
|
18
|
+
provider.register(AnnualCycle())
|
|
19
|
+
|
|
20
|
+
# ENSO diagnostics and metrics
|
|
21
|
+
# provider.register(ENSO("ENSO_perf")) # Assigned to ESMValTool
|
|
22
|
+
provider.register(ENSO("ENSO_tel"))
|
|
23
|
+
provider.register(ENSO("ENSO_proc"))
|
|
24
|
+
|
|
25
|
+
# Extratropical modes of variability diagnostics and metrics
|
|
17
26
|
provider.register(ExtratropicalModesOfVariability("PDO"))
|
|
18
27
|
provider.register(ExtratropicalModesOfVariability("NPGO"))
|
|
19
28
|
provider.register(ExtratropicalModesOfVariability("NAO"))
|
|
@@ -21,12 +30,11 @@ provider.register(ExtratropicalModesOfVariability("NAM"))
|
|
|
21
30
|
provider.register(ExtratropicalModesOfVariability("PNA"))
|
|
22
31
|
provider.register(ExtratropicalModesOfVariability("NPO"))
|
|
23
32
|
provider.register(ExtratropicalModesOfVariability("SAM"))
|
|
24
|
-
provider.register(AnnualCycle())
|
|
25
33
|
|
|
26
34
|
|
|
27
35
|
dataset_registry_manager.register(
|
|
28
36
|
"pmp-climatology",
|
|
29
|
-
|
|
37
|
+
base_url=DATASET_URL,
|
|
30
38
|
package="climate_ref_pmp.dataset_registry",
|
|
31
39
|
resource="pmp_climatology.txt",
|
|
32
40
|
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"""PMP diagnostics."""
|
|
2
2
|
|
|
3
3
|
from climate_ref_pmp.diagnostics.annual_cycle import AnnualCycle
|
|
4
|
+
from climate_ref_pmp.diagnostics.enso import ENSO
|
|
4
5
|
from climate_ref_pmp.diagnostics.variability_modes import ExtratropicalModesOfVariability
|
|
5
6
|
|
|
6
7
|
__all__ = [
|
|
8
|
+
"ENSO",
|
|
7
9
|
"AnnualCycle",
|
|
8
10
|
"ExtratropicalModesOfVariability",
|
|
9
11
|
]
|
{climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/diagnostics/annual_cycle.py
RENAMED
|
@@ -15,6 +15,44 @@ from climate_ref_core.pycmec.metric import remove_dimensions
|
|
|
15
15
|
from climate_ref_pmp.pmp_driver import build_glob_pattern, build_pmp_command, process_json_result
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def make_data_requirement(variable_id: str, obs_source: str) -> tuple[DataRequirement, DataRequirement]:
|
|
19
|
+
"""
|
|
20
|
+
Create a data requirement for the annual cycle diagnostic.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
variable_id : str
|
|
25
|
+
The variable ID to filter the data requirement.
|
|
26
|
+
obs_source : str
|
|
27
|
+
The observation source ID to filter the data requirement.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
DataRequirement
|
|
32
|
+
A DataRequirement object containing the necessary filters and groupings.
|
|
33
|
+
"""
|
|
34
|
+
return (
|
|
35
|
+
DataRequirement(
|
|
36
|
+
source_type=SourceDatasetType.PMPClimatology,
|
|
37
|
+
filters=(FacetFilter(facets={"source_id": (obs_source,), "variable_id": (variable_id,)}),),
|
|
38
|
+
group_by=("variable_id", "source_id"),
|
|
39
|
+
),
|
|
40
|
+
DataRequirement(
|
|
41
|
+
source_type=SourceDatasetType.CMIP6,
|
|
42
|
+
filters=(
|
|
43
|
+
FacetFilter(
|
|
44
|
+
facets={
|
|
45
|
+
"frequency": "mon",
|
|
46
|
+
"experiment_id": ("amip", "historical", "hist-GHG", "piControl"),
|
|
47
|
+
"variable_id": (variable_id,),
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
group_by=("variable_id", "source_id", "experiment_id", "member_id", "grid_label"),
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
18
56
|
class AnnualCycle(CommandLineDiagnostic):
|
|
19
57
|
"""
|
|
20
58
|
Calculate the annual cycle for a dataset
|
|
@@ -32,49 +70,20 @@ class AnnualCycle(CommandLineDiagnostic):
|
|
|
32
70
|
"statistic",
|
|
33
71
|
"season",
|
|
34
72
|
)
|
|
73
|
+
|
|
35
74
|
data_requirements = (
|
|
36
|
-
|
|
37
|
-
(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"frequency": "mon",
|
|
49
|
-
"experiment_id": ("amip", "historical", "hist-GHG", "piControl"),
|
|
50
|
-
"variable_id": ("ts",),
|
|
51
|
-
}
|
|
52
|
-
),
|
|
53
|
-
),
|
|
54
|
-
group_by=("variable_id", "source_id", "experiment_id", "member_id"),
|
|
55
|
-
),
|
|
56
|
-
),
|
|
57
|
-
# Precipitation
|
|
58
|
-
(
|
|
59
|
-
DataRequirement(
|
|
60
|
-
source_type=SourceDatasetType.PMPClimatology,
|
|
61
|
-
filters=(FacetFilter(facets={"source_id": ("GPCP-Monthly-3-2",), "variable_id": ("pr",)}),),
|
|
62
|
-
group_by=("variable_id", "source_id"),
|
|
63
|
-
),
|
|
64
|
-
DataRequirement(
|
|
65
|
-
source_type=SourceDatasetType.CMIP6,
|
|
66
|
-
filters=(
|
|
67
|
-
FacetFilter(
|
|
68
|
-
facets={
|
|
69
|
-
"frequency": "mon",
|
|
70
|
-
"experiment_id": ("amip", "historical", "hist-GHG", "piControl"),
|
|
71
|
-
"variable_id": ("pr",),
|
|
72
|
-
}
|
|
73
|
-
),
|
|
74
|
-
),
|
|
75
|
-
group_by=("variable_id", "source_id", "experiment_id", "member_id"),
|
|
76
|
-
),
|
|
77
|
-
),
|
|
75
|
+
make_data_requirement("ts", "ERA-5"),
|
|
76
|
+
make_data_requirement("uas", "ERA-5"),
|
|
77
|
+
make_data_requirement("vas", "ERA-5"),
|
|
78
|
+
make_data_requirement("psl", "ERA-5"),
|
|
79
|
+
make_data_requirement("pr", "GPCP-Monthly-3-2"),
|
|
80
|
+
make_data_requirement("rlds", "CERES-EBAF-4-2"),
|
|
81
|
+
make_data_requirement("rlus", "CERES-EBAF-4-2"),
|
|
82
|
+
make_data_requirement("rlut", "CERES-EBAF-4-2"),
|
|
83
|
+
make_data_requirement("rsds", "CERES-EBAF-4-2"),
|
|
84
|
+
make_data_requirement("rsdt", "CERES-EBAF-4-2"),
|
|
85
|
+
make_data_requirement("rsus", "CERES-EBAF-4-2"),
|
|
86
|
+
make_data_requirement("rsut", "CERES-EBAF-4-2"),
|
|
78
87
|
)
|
|
79
88
|
|
|
80
89
|
def __init__(self) -> None:
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from collections.abc import Collection, Iterable
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from loguru import logger
|
|
7
|
+
|
|
8
|
+
from climate_ref_core.constraints import AddSupplementaryDataset
|
|
9
|
+
from climate_ref_core.datasets import DatasetCollection, FacetFilter, SourceDatasetType
|
|
10
|
+
from climate_ref_core.diagnostics import (
|
|
11
|
+
CommandLineDiagnostic,
|
|
12
|
+
DataRequirement,
|
|
13
|
+
ExecutionDefinition,
|
|
14
|
+
ExecutionResult,
|
|
15
|
+
)
|
|
16
|
+
from climate_ref_pmp.pmp_driver import _get_resource, process_json_result
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ENSO(CommandLineDiagnostic):
|
|
20
|
+
"""
|
|
21
|
+
Calculate the ENSO performance metrics for a dataset
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
facets = ("source_id", "member_id", "grid_label", "experiment_id", "metric", "reference_datasets")
|
|
25
|
+
|
|
26
|
+
def __init__(self, metrics_collection: str, experiments: Collection[str] = ("historical",)) -> None:
|
|
27
|
+
self.name = metrics_collection
|
|
28
|
+
self.slug = metrics_collection.lower()
|
|
29
|
+
self.metrics_collection = metrics_collection
|
|
30
|
+
self.parameter_file = "pmp_param_enso.py"
|
|
31
|
+
self.obs_sources: tuple[str, ...]
|
|
32
|
+
self.model_variables: tuple[str, ...]
|
|
33
|
+
|
|
34
|
+
if metrics_collection == "ENSO_perf": # pragma: no cover
|
|
35
|
+
self.model_variables = ("pr", "ts", "tauu")
|
|
36
|
+
self.obs_sources = ("GPCP-Monthly-3-2", "TropFlux-1-0", "HadISST-1-1")
|
|
37
|
+
elif metrics_collection == "ENSO_tel":
|
|
38
|
+
self.model_variables = ("pr", "ts")
|
|
39
|
+
self.obs_sources = ("GPCP-Monthly-3-2", "TropFlux-1-0", "HadISST-1-1")
|
|
40
|
+
elif metrics_collection == "ENSO_proc":
|
|
41
|
+
self.model_variables = ("ts", "tauu", "hfls", "hfss", "rlds", "rlus", "rsds", "rsus")
|
|
42
|
+
self.obs_sources = (
|
|
43
|
+
"GPCP-Monthly-3-2",
|
|
44
|
+
"TropFlux-1-0",
|
|
45
|
+
"HadISST-1-1",
|
|
46
|
+
"CERES-EBAF-4-2",
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
raise ValueError(
|
|
50
|
+
f"Unknown metrics collection: {metrics_collection}. "
|
|
51
|
+
"Valid options are: ENSO_perf, ENSO_tel, ENSO_proc"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self.data_requirements = self._get_data_requirements(experiments)
|
|
55
|
+
|
|
56
|
+
def _get_data_requirements(
|
|
57
|
+
self,
|
|
58
|
+
experiments: Collection[str] = ("historical",),
|
|
59
|
+
) -> tuple[DataRequirement, DataRequirement]:
|
|
60
|
+
filters = [
|
|
61
|
+
FacetFilter(
|
|
62
|
+
facets={
|
|
63
|
+
"frequency": "mon",
|
|
64
|
+
"experiment_id": tuple(experiments),
|
|
65
|
+
"variable_id": self.model_variables,
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
DataRequirement(
|
|
72
|
+
source_type=SourceDatasetType.obs4MIPs,
|
|
73
|
+
filters=(
|
|
74
|
+
FacetFilter(facets={"source_id": self.obs_sources, "variable_id": self.model_variables}),
|
|
75
|
+
),
|
|
76
|
+
group_by=("activity_id",),
|
|
77
|
+
),
|
|
78
|
+
DataRequirement(
|
|
79
|
+
source_type=SourceDatasetType.CMIP6,
|
|
80
|
+
filters=tuple(filters),
|
|
81
|
+
group_by=("source_id", "experiment_id", "member_id", "grid_label"),
|
|
82
|
+
constraints=(
|
|
83
|
+
AddSupplementaryDataset.from_defaults("areacella", SourceDatasetType.CMIP6),
|
|
84
|
+
AddSupplementaryDataset.from_defaults("sftlf", SourceDatasetType.CMIP6),
|
|
85
|
+
),
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def build_cmd(self, definition: ExecutionDefinition) -> Iterable[str]:
|
|
90
|
+
"""
|
|
91
|
+
Run the diagnostic on the given configuration.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
definition : ExecutionDefinition
|
|
96
|
+
The configuration to run the diagnostic on.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
:
|
|
101
|
+
The result of running the diagnostic.
|
|
102
|
+
"""
|
|
103
|
+
mc_name = self.metrics_collection
|
|
104
|
+
|
|
105
|
+
# ------------------------------------------------
|
|
106
|
+
# Get the input datasets information for the model
|
|
107
|
+
# ------------------------------------------------
|
|
108
|
+
input_datasets = definition.datasets[SourceDatasetType.CMIP6]
|
|
109
|
+
input_selectors = input_datasets.selector_dict()
|
|
110
|
+
source_id = input_selectors["source_id"]
|
|
111
|
+
member_id = input_selectors["member_id"]
|
|
112
|
+
experiment_id = input_selectors["experiment_id"]
|
|
113
|
+
variable_ids = set(input_datasets["variable_id"].unique()) - {"areacella", "sftlf"}
|
|
114
|
+
mod_run = f"{source_id}_{member_id}"
|
|
115
|
+
|
|
116
|
+
# We only need one entry for the model run
|
|
117
|
+
dict_mod: dict[str, dict[str, Any]] = {mod_run: {}}
|
|
118
|
+
|
|
119
|
+
def extract_variable(dc: DatasetCollection, variable: str) -> list[str]:
|
|
120
|
+
return dc.datasets[input_datasets["variable_id"] == variable]["path"].to_list() # type: ignore
|
|
121
|
+
|
|
122
|
+
# TO DO: Get the path to the files per variable
|
|
123
|
+
for variable in variable_ids:
|
|
124
|
+
list_files = extract_variable(input_datasets, variable)
|
|
125
|
+
list_areacella = extract_variable(input_datasets, "areacella")
|
|
126
|
+
list_sftlf = extract_variable(input_datasets, "sftlf")
|
|
127
|
+
|
|
128
|
+
if len(list_files) > 0:
|
|
129
|
+
dict_mod[mod_run][variable] = {
|
|
130
|
+
"path + filename": list_files,
|
|
131
|
+
"varname": variable,
|
|
132
|
+
"path + filename_area": list_areacella,
|
|
133
|
+
"areaname": "areacella",
|
|
134
|
+
"path + filename_landmask": list_sftlf,
|
|
135
|
+
"landmaskname": "sftlf",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# -------------------------------------------------------
|
|
139
|
+
# Get the input datasets information for the observations
|
|
140
|
+
# -------------------------------------------------------
|
|
141
|
+
reference_dataset = definition.datasets[SourceDatasetType.obs4MIPs]
|
|
142
|
+
reference_dataset_names = reference_dataset["source_id"].unique()
|
|
143
|
+
|
|
144
|
+
dict_obs: dict[str, dict[str, Any]] = {}
|
|
145
|
+
|
|
146
|
+
# TO DO: Get the path to the files per variable and per source
|
|
147
|
+
for obs_name in reference_dataset_names:
|
|
148
|
+
dict_obs[obs_name] = {}
|
|
149
|
+
for variable in variable_ids:
|
|
150
|
+
# Get the list of files for the current variable and observation source
|
|
151
|
+
list_files = reference_dataset.datasets[
|
|
152
|
+
(reference_dataset["variable_id"] == variable)
|
|
153
|
+
& (reference_dataset["source_id"] == obs_name)
|
|
154
|
+
]["path"].to_list()
|
|
155
|
+
# If the list is not empty, add it to the dictionary
|
|
156
|
+
if len(list_files) > 0:
|
|
157
|
+
dict_obs[obs_name][variable] = {
|
|
158
|
+
"path + filename": list_files,
|
|
159
|
+
"varname": variable,
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Create input directory
|
|
163
|
+
dict_datasets = {
|
|
164
|
+
"model": dict_mod,
|
|
165
|
+
"observations": dict_obs,
|
|
166
|
+
"metricsCollection": mc_name,
|
|
167
|
+
"experiment_id": experiment_id,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
# Create JSON file for dictDatasets
|
|
171
|
+
json_file = os.path.join(
|
|
172
|
+
definition.output_directory, f"input_{mc_name}_{source_id}_{experiment_id}_{member_id}.json"
|
|
173
|
+
)
|
|
174
|
+
with open(json_file, "w") as f:
|
|
175
|
+
json.dump(dict_datasets, f, indent=4)
|
|
176
|
+
logger.debug(f"JSON file created: {json_file}")
|
|
177
|
+
|
|
178
|
+
driver_file = _get_resource("climate_ref_pmp.drivers", "enso_driver.py", use_resources=True)
|
|
179
|
+
return [
|
|
180
|
+
"python",
|
|
181
|
+
driver_file,
|
|
182
|
+
"--metrics_collection",
|
|
183
|
+
mc_name,
|
|
184
|
+
"--experiment_id",
|
|
185
|
+
experiment_id,
|
|
186
|
+
"--input_json_path",
|
|
187
|
+
json_file,
|
|
188
|
+
"--output_directory",
|
|
189
|
+
str(definition.output_directory),
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
def build_execution_result(self, definition: ExecutionDefinition) -> ExecutionResult:
|
|
193
|
+
"""
|
|
194
|
+
Build a diagnostic result from the output of the PMP driver
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
definition
|
|
199
|
+
Definition of the diagnostic execution
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
Result of the diagnostic execution
|
|
204
|
+
"""
|
|
205
|
+
input_datasets = definition.datasets[SourceDatasetType.CMIP6]
|
|
206
|
+
source_id = input_datasets["source_id"].unique()[0]
|
|
207
|
+
experiment_id = input_datasets["experiment_id"].unique()[0]
|
|
208
|
+
member_id = input_datasets["member_id"].unique()[0]
|
|
209
|
+
mc_name = self.metrics_collection
|
|
210
|
+
pattern = f"{mc_name}_{source_id}_{experiment_id}_{member_id}"
|
|
211
|
+
|
|
212
|
+
# Find the results files
|
|
213
|
+
results_files = list(definition.output_directory.glob(f"{pattern}_cmec.json"))
|
|
214
|
+
logger.debug(f"Results files: {results_files}")
|
|
215
|
+
|
|
216
|
+
if len(results_files) != 1: # pragma: no cover
|
|
217
|
+
logger.warning(f"A single cmec output file not found: {results_files}")
|
|
218
|
+
return ExecutionResult.build_from_failure(definition)
|
|
219
|
+
|
|
220
|
+
# Find the other outputs
|
|
221
|
+
png_files = [definition.as_relative_path(f) for f in definition.output_directory.glob("*.png")]
|
|
222
|
+
data_files = [definition.as_relative_path(f) for f in definition.output_directory.glob("*.nc")]
|
|
223
|
+
|
|
224
|
+
cmec_output, cmec_metric = process_json_result(results_files[0], png_files, data_files)
|
|
225
|
+
|
|
226
|
+
input_selectors = definition.datasets[SourceDatasetType.CMIP6].selector_dict()
|
|
227
|
+
cmec_metric_bundle = cmec_metric.remove_dimensions(
|
|
228
|
+
[
|
|
229
|
+
"model",
|
|
230
|
+
"realization",
|
|
231
|
+
],
|
|
232
|
+
).prepend_dimensions(
|
|
233
|
+
{
|
|
234
|
+
"source_id": input_selectors["source_id"],
|
|
235
|
+
"member_id": input_selectors["member_id"],
|
|
236
|
+
"grid_label": input_selectors["grid_label"],
|
|
237
|
+
"experiment_id": input_selectors["experiment_id"],
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return ExecutionResult.build_from_output_bundle(
|
|
242
|
+
definition,
|
|
243
|
+
cmec_output_bundle=cmec_output,
|
|
244
|
+
cmec_metric_bundle=cmec_metric_bundle,
|
|
245
|
+
)
|
{climate_ref_pmp-0.5.4 → climate_ref_pmp-0.6.0}/src/climate_ref_pmp/diagnostics/variability_modes.py
RENAMED
|
@@ -37,10 +37,10 @@ class ExtratropicalModesOfVariability(CommandLineDiagnostic):
|
|
|
37
37
|
self.name = f"Extratropical modes of variability: {mode_id}"
|
|
38
38
|
self.slug = f"extratropical-modes-of-variability-{mode_id.lower()}"
|
|
39
39
|
|
|
40
|
-
def
|
|
40
|
+
def _get_data_requirements(
|
|
41
41
|
obs_source: str,
|
|
42
42
|
obs_variable: str,
|
|
43
|
-
|
|
43
|
+
model_variable: str,
|
|
44
44
|
extra_experiments: str | tuple[str, ...] | list[str] = (),
|
|
45
45
|
) -> tuple[DataRequirement, DataRequirement]:
|
|
46
46
|
filters = [
|
|
@@ -48,7 +48,7 @@ class ExtratropicalModesOfVariability(CommandLineDiagnostic):
|
|
|
48
48
|
facets={
|
|
49
49
|
"frequency": "mon",
|
|
50
50
|
"experiment_id": ("historical", "hist-GHG", "piControl", *extra_experiments),
|
|
51
|
-
"variable_id":
|
|
51
|
+
"variable_id": model_variable,
|
|
52
52
|
}
|
|
53
53
|
)
|
|
54
54
|
]
|
|
@@ -64,17 +64,16 @@ class ExtratropicalModesOfVariability(CommandLineDiagnostic):
|
|
|
64
64
|
DataRequirement(
|
|
65
65
|
source_type=SourceDatasetType.CMIP6,
|
|
66
66
|
filters=tuple(filters),
|
|
67
|
-
|
|
68
|
-
group_by=("source_id", "experiment_id", "variant_label", "member_id"),
|
|
67
|
+
group_by=("source_id", "experiment_id", "member_id", "grid_label"),
|
|
69
68
|
),
|
|
70
69
|
)
|
|
71
70
|
|
|
72
71
|
if self.mode_id in self.ts_modes:
|
|
73
72
|
self.parameter_file = "pmp_param_MoV-ts.py"
|
|
74
|
-
self.data_requirements =
|
|
73
|
+
self.data_requirements = _get_data_requirements("HadISST-1-1", "ts", "ts")
|
|
75
74
|
elif self.mode_id in self.psl_modes:
|
|
76
75
|
self.parameter_file = "pmp_param_MoV-psl.py"
|
|
77
|
-
self.data_requirements =
|
|
76
|
+
self.data_requirements = _get_data_requirements("20CR", "psl", "psl", extra_experiments=("amip",))
|
|
78
77
|
else:
|
|
79
78
|
raise ValueError(
|
|
80
79
|
f"Unknown mode_id '{self.mode_id}'. Must be one of {self.ts_modes + self.psl_modes}"
|