climate-ref 0.5.4__py3-none-any.whl → 0.6.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/__init__.py +3 -3
- climate_ref/cli/__init__.py +20 -6
- climate_ref/cli/datasets.py +30 -7
- climate_ref/cli/solve.py +38 -3
- climate_ref/config.py +10 -1
- climate_ref/dataset_registry/obs4ref_reference.txt +44 -13
- climate_ref/dataset_registry/sample_data.txt +8 -6
- climate_ref/datasets/base.py +62 -4
- climate_ref/datasets/cmip6.py +14 -40
- climate_ref/datasets/obs4mips.py +11 -54
- climate_ref/executor/local.py +17 -3
- climate_ref/executor/result_handling.py +0 -1
- climate_ref/solver.py +67 -6
- climate_ref/testing.py +8 -5
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/METADATA +4 -4
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/RECORD +20 -20
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/WHEEL +0 -0
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/entry_points.txt +0 -0
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/licenses/LICENCE +0 -0
- {climate_ref-0.5.4.dist-info → climate_ref-0.6.0.dist-info}/licenses/NOTICE +0 -0
climate_ref/__init__.py
CHANGED
|
@@ -8,19 +8,19 @@ __version__ = importlib.metadata.version("climate-ref")
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
from climate_ref.testing import SAMPLE_DATA_VERSION
|
|
11
|
-
from climate_ref_core.dataset_registry import dataset_registry_manager
|
|
11
|
+
from climate_ref_core.dataset_registry import DATASET_URL, dataset_registry_manager
|
|
12
12
|
|
|
13
13
|
# Register the obs4REF data registry
|
|
14
14
|
dataset_registry_manager.register(
|
|
15
15
|
"obs4ref",
|
|
16
|
-
|
|
16
|
+
base_url=DATASET_URL,
|
|
17
17
|
package="climate_ref.dataset_registry",
|
|
18
18
|
resource="obs4ref_reference.txt",
|
|
19
19
|
)
|
|
20
20
|
# Register the sample data registry -- used for testing
|
|
21
21
|
dataset_registry_manager.register(
|
|
22
22
|
"sample-data",
|
|
23
|
-
"https://raw.githubusercontent.com/Climate-REF/ref-sample-data/refs/tags/{version}/data/",
|
|
23
|
+
base_url="https://raw.githubusercontent.com/Climate-REF/ref-sample-data/refs/tags/{version}/data/",
|
|
24
24
|
package="climate_ref.dataset_registry",
|
|
25
25
|
resource="sample_data.txt",
|
|
26
26
|
version=SAMPLE_DATA_VERSION,
|
climate_ref/cli/__init__.py
CHANGED
|
@@ -15,7 +15,7 @@ from climate_ref.config import Config
|
|
|
15
15
|
from climate_ref.constants import CONFIG_FILENAME
|
|
16
16
|
from climate_ref.database import Database
|
|
17
17
|
from climate_ref_core import __version__ as __core_version__
|
|
18
|
-
from climate_ref_core.logging import
|
|
18
|
+
from climate_ref_core.logging import initialise_logging
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class LogLevel(str, Enum):
|
|
@@ -112,11 +112,21 @@ app = build_app()
|
|
|
112
112
|
@app.callback()
|
|
113
113
|
def main( # noqa: PLR0913
|
|
114
114
|
ctx: typer.Context,
|
|
115
|
-
configuration_directory: Annotated[
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
configuration_directory: Annotated[
|
|
116
|
+
Path | None,
|
|
117
|
+
typer.Option(help="Configuration directory"),
|
|
118
|
+
] = None,
|
|
119
|
+
verbose: Annotated[
|
|
120
|
+
bool,
|
|
121
|
+
typer.Option("--verbose", "-v", help="Set the log level to DEBUG"),
|
|
122
|
+
] = False,
|
|
123
|
+
quiet: Annotated[
|
|
124
|
+
bool,
|
|
125
|
+
typer.Option("--quiet", "-q", help="Set the log level to WARNING"),
|
|
126
|
+
] = False,
|
|
118
127
|
log_level: Annotated[
|
|
119
|
-
LogLevel,
|
|
128
|
+
LogLevel,
|
|
129
|
+
typer.Option(case_sensitive=False, help="Set the level of logging information to display"),
|
|
120
130
|
] = LogLevel.Info,
|
|
121
131
|
version: Annotated[
|
|
122
132
|
Optional[bool],
|
|
@@ -136,11 +146,15 @@ def main( # noqa: PLR0913
|
|
|
136
146
|
log_level = LogLevel.Debug
|
|
137
147
|
|
|
138
148
|
logger.remove()
|
|
139
|
-
add_log_handler(level=log_level.value)
|
|
140
149
|
|
|
141
150
|
config = _load_config(configuration_directory)
|
|
142
151
|
config.log_level = log_level.value
|
|
143
152
|
|
|
153
|
+
log_format = config.log_format
|
|
154
|
+
initialise_logging(level=config.log_level, format=log_format, log_directory=config.paths.log)
|
|
155
|
+
|
|
156
|
+
logger.debug(f"Configuration loaded from: {config._config_file!s}")
|
|
157
|
+
|
|
144
158
|
ctx.obj = CLIContext(config=config, database=Database.from_config(config))
|
|
145
159
|
|
|
146
160
|
|
climate_ref/cli/datasets.py
CHANGED
|
@@ -34,7 +34,12 @@ def list_(
|
|
|
34
34
|
] = SourceDatasetType.CMIP6.value, # type: ignore
|
|
35
35
|
column: Annotated[list[str] | None, typer.Option()] = None,
|
|
36
36
|
include_files: bool = typer.Option(False, help="Include files in the output"),
|
|
37
|
-
limit: int = typer.Option(
|
|
37
|
+
limit: int = typer.Option(
|
|
38
|
+
100,
|
|
39
|
+
help=(
|
|
40
|
+
"Limit the number of datasets (or files when using --include-files) to display to this number."
|
|
41
|
+
),
|
|
42
|
+
),
|
|
38
43
|
) -> None:
|
|
39
44
|
"""
|
|
40
45
|
List the datasets that have been ingested
|
|
@@ -172,16 +177,28 @@ def _fetch_sample_data(
|
|
|
172
177
|
|
|
173
178
|
|
|
174
179
|
@app.command(name="fetch-data")
|
|
175
|
-
def fetch_data(
|
|
180
|
+
def fetch_data( # noqa: PLR0913
|
|
176
181
|
ctx: typer.Context,
|
|
177
|
-
registry: Annotated[
|
|
182
|
+
registry: Annotated[
|
|
183
|
+
str,
|
|
184
|
+
typer.Option(help="Name of the data registry to use"),
|
|
185
|
+
],
|
|
178
186
|
output_directory: Annotated[
|
|
179
|
-
Path | None,
|
|
187
|
+
Path | None,
|
|
188
|
+
typer.Option(help="Output directory where files will be saved"),
|
|
180
189
|
] = None,
|
|
181
|
-
force_cleanup: Annotated[
|
|
190
|
+
force_cleanup: Annotated[
|
|
191
|
+
bool,
|
|
192
|
+
typer.Option(help="If True, remove any existing files"),
|
|
193
|
+
] = False,
|
|
182
194
|
symlink: Annotated[
|
|
183
|
-
bool,
|
|
195
|
+
bool,
|
|
196
|
+
typer.Option(help="If True, symlink files into the output directory, otherwise perform a copy"),
|
|
184
197
|
] = False,
|
|
198
|
+
verify: Annotated[
|
|
199
|
+
bool,
|
|
200
|
+
typer.Option(help="Verify the checksums of the fetched files"),
|
|
201
|
+
] = True,
|
|
185
202
|
) -> None:
|
|
186
203
|
"""
|
|
187
204
|
Fetch REF-specific datasets
|
|
@@ -206,4 +223,10 @@ def fetch_data(
|
|
|
206
223
|
logger.error(f"Available registries: {', '.join(dataset_registry_manager.keys())}")
|
|
207
224
|
raise typer.Exit(code=1)
|
|
208
225
|
|
|
209
|
-
fetch_all_files(
|
|
226
|
+
fetch_all_files(
|
|
227
|
+
_registry,
|
|
228
|
+
registry,
|
|
229
|
+
output_directory,
|
|
230
|
+
symlink=symlink,
|
|
231
|
+
verify=verify,
|
|
232
|
+
)
|
climate_ref/cli/solve.py
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
1
3
|
import typer
|
|
2
4
|
|
|
3
|
-
from climate_ref.solver import solve_required_executions
|
|
5
|
+
from climate_ref.solver import SolveFilterOptions, solve_required_executions
|
|
4
6
|
|
|
5
7
|
app = typer.Typer()
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
@app.command()
|
|
9
|
-
def solve(
|
|
11
|
+
def solve( # noqa: PLR0913
|
|
10
12
|
ctx: typer.Context,
|
|
11
|
-
dry_run:
|
|
13
|
+
dry_run: Annotated[
|
|
14
|
+
bool,
|
|
15
|
+
typer.Option(help="Do not execute any diagnostics"),
|
|
16
|
+
] = False,
|
|
17
|
+
execute: Annotated[
|
|
18
|
+
bool,
|
|
19
|
+
typer.Option(help="Solve the newly identified executions"),
|
|
20
|
+
] = True,
|
|
12
21
|
timeout: int = typer.Option(60, help="Timeout in seconds for the solve operation"),
|
|
13
22
|
one_per_provider: bool = typer.Option(
|
|
14
23
|
False, help="Limit to one execution per provider. This is useful for testing"
|
|
@@ -16,6 +25,24 @@ def solve(
|
|
|
16
25
|
one_per_diagnostic: bool = typer.Option(
|
|
17
26
|
False, help="Limit to one execution per diagnostic. This is useful for testing"
|
|
18
27
|
),
|
|
28
|
+
diagnostic: Annotated[
|
|
29
|
+
list[str] | None,
|
|
30
|
+
typer.Option(
|
|
31
|
+
help="Filters executions by the diagnostic slug. "
|
|
32
|
+
"Diagnostics will be included if any of the filters match a case-insensitive subset "
|
|
33
|
+
"of the diagnostic slug. "
|
|
34
|
+
"Multiple values can be provided"
|
|
35
|
+
),
|
|
36
|
+
] = None,
|
|
37
|
+
provider: Annotated[
|
|
38
|
+
list[str] | None,
|
|
39
|
+
typer.Option(
|
|
40
|
+
help="Filters executions by provider slug. "
|
|
41
|
+
"Providers will be included if any of the filters match a case-insensitive subset "
|
|
42
|
+
"of the provider slug. "
|
|
43
|
+
"Multiple values can be provided"
|
|
44
|
+
),
|
|
45
|
+
] = None,
|
|
19
46
|
) -> None:
|
|
20
47
|
"""
|
|
21
48
|
Solve for executions that require recalculation
|
|
@@ -25,11 +52,19 @@ def solve(
|
|
|
25
52
|
"""
|
|
26
53
|
config = ctx.obj.config
|
|
27
54
|
db = ctx.obj.database
|
|
55
|
+
|
|
56
|
+
filters = SolveFilterOptions(
|
|
57
|
+
diagnostic=diagnostic,
|
|
58
|
+
provider=provider,
|
|
59
|
+
)
|
|
60
|
+
|
|
28
61
|
solve_required_executions(
|
|
29
62
|
config=config,
|
|
30
63
|
db=db,
|
|
31
64
|
dry_run=dry_run,
|
|
65
|
+
execute=execute,
|
|
32
66
|
timeout=timeout,
|
|
33
67
|
one_per_provider=one_per_provider,
|
|
34
68
|
one_per_diagnostic=one_per_diagnostic,
|
|
69
|
+
filters=filters,
|
|
35
70
|
)
|
climate_ref/config.py
CHANGED
|
@@ -38,6 +38,7 @@ from climate_ref.constants import CONFIG_FILENAME
|
|
|
38
38
|
from climate_ref_core.env import env
|
|
39
39
|
from climate_ref_core.exceptions import InvalidExecutorException
|
|
40
40
|
from climate_ref_core.executor import Executor, import_executor_cls
|
|
41
|
+
from climate_ref_core.logging import DEFAULT_LOG_FORMAT
|
|
41
42
|
|
|
42
43
|
if TYPE_CHECKING:
|
|
43
44
|
from climate_ref.database import Database
|
|
@@ -337,10 +338,18 @@ class Config:
|
|
|
337
338
|
|
|
338
339
|
log_level: str = field(default="INFO")
|
|
339
340
|
"""
|
|
340
|
-
Log level of messages that are displayed by the REF
|
|
341
|
+
Log level of messages that are displayed by the REF via the CLI
|
|
341
342
|
|
|
342
343
|
This value is overridden if a value is specified via the CLI.
|
|
343
344
|
"""
|
|
345
|
+
log_format: str = env_field("LOG_FORMAT", default=DEFAULT_LOG_FORMAT)
|
|
346
|
+
"""
|
|
347
|
+
Format of the log messages that are displayed by the REF via the CLI
|
|
348
|
+
|
|
349
|
+
Examples of the formatting options are available in the
|
|
350
|
+
[loguru documentation](https://loguru.readthedocs.io/en/stable/api/logger.html#module-loguru._logger).
|
|
351
|
+
"""
|
|
352
|
+
|
|
344
353
|
paths: PathConfig = Factory(PathConfig) # noqa
|
|
345
354
|
db: DbConfig = Factory(DbConfig) # noqa
|
|
346
355
|
executor: ExecutorConfig = Factory(ExecutorConfig) # noqa
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
+
obs4REF/ARCCSS/LORA-1-1/mon/mrro/gn/20250516/mrro_mon_LORA-1-1_REF_gn_198001-201212.nc md5:4cfbbfa3be9632b14de99b18066fbffe
|
|
2
|
+
obs4REF/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc md5:91252303cb65548fee5ff42dd3024825
|
|
3
|
+
obs4REF/ColumbiaU/WECANN-1-0/mon/gpp/gn/20250516/gpp_mon_WECANN-1-0_REF_gn_200701-201512.nc md5:c8757a92f915e7e270d94bfbf25accf7
|
|
4
|
+
obs4REF/ColumbiaU/WECANN-1-0/mon/hfls/gn/20250516/hfls_mon_WECANN-1-0_REF_gn_200701-201512.nc md5:d99c5879948f10c7fcb2f8e95922898d
|
|
5
|
+
obs4REF/ColumbiaU/WECANN-1-0/mon/hfss/gn/20250516/hfss_mon_WECANN-1-0_REF_gn_200701-201512.nc md5:b7a911e0fc164d07d3ab42a86d09b18b
|
|
1
6
|
obs4REF/ECMWF/ERA-20C/mon/psl/gn/v20210727/psl_mon_ERA-20C_PCMDI_gn_190001-201012.nc md5:c100cf25d5681c375cd6c1ee60b678ba
|
|
2
7
|
obs4REF/ECMWF/ERA-20C/mon/ts/gn/v20210727/ts_mon_ERA-20C_PCMDI_gn_190001-201012.nc md5:9ed8dfbb805ed4caa282ed70f873a3a0
|
|
3
|
-
obs4REF/
|
|
4
|
-
obs4REF/
|
|
5
|
-
obs4REF/
|
|
6
|
-
obs4REF/
|
|
7
|
-
obs4REF/
|
|
8
|
-
obs4REF/
|
|
9
|
-
obs4REF/
|
|
10
|
-
obs4REF/
|
|
11
|
-
obs4REF/
|
|
12
|
-
obs4REF/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:8abc7a724a7a297826e2f783a4ea14f9
|
|
13
|
-
obs4REF/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:8697d3d7862f6e3b72bb5a161aa75ee8
|
|
8
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_200701-200712.nc md5:695633a2b401cfb66c8addbf58073dbc
|
|
9
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_200801-200812.nc md5:404f1e1f111859be06c00bcb8d740ff2
|
|
10
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_200901-200912.nc md5:a1bb8584d60cdd71154c01a692fa1fb4
|
|
11
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201001-201012.nc md5:b78016a3c61d99dc0fd29563aa344ca1
|
|
12
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201101-201112.nc md5:d64c231a7f798a255997ffe196613ea1
|
|
13
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201201-201212.nc md5:7d90ce60b872dc4f044b9b0101114983
|
|
14
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201301-201312.nc md5:2fc032707cb8a31ac60fa4abe9efe183
|
|
15
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201401-201412.nc md5:6022d17e11df7818f5b0429d6e401d17
|
|
16
|
+
obs4REF/ECMWF/ERA-5/mon/ta/gn/v20250220/ta_mon_ERA-5_PCMDI_gn_201501-201512.nc md5:c68fdabf6eeb4813befceace089c9494
|
|
14
17
|
obs4REF/ECMWF/ERA-INT/mon/hfls/gn/v20210727/hfls_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:1ae4587143f05ee81432b3d9960aab63
|
|
15
18
|
obs4REF/ECMWF/ERA-INT/mon/hfss/gn/v20210727/hfss_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:261f02b8cbce18486548882a11f9aa34
|
|
16
19
|
obs4REF/ECMWF/ERA-INT/mon/hur/gn/v20210727/hur_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:56fcd2df8ed2879f18b5e8c78134a148
|
|
@@ -31,6 +34,34 @@ obs4REF/ECMWF/ERA-INT/mon/uas/gn/v20210727/uas_mon_ERA-INT_PCMDI_gn_197901-20190
|
|
|
31
34
|
obs4REF/ECMWF/ERA-INT/mon/va/gn/v20210727/va_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:f67ca168d6cd87bfdd4a911eb72dd022
|
|
32
35
|
obs4REF/ECMWF/ERA-INT/mon/vas/gn/v20210727/vas_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:ac19b48b897cfe839585df4ff0fc4a7b
|
|
33
36
|
obs4REF/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:d8fb93f31ff4a6370ccee93db82af86c
|
|
34
|
-
obs4REF/
|
|
37
|
+
obs4REF/ESSO/TropFlux-1-0/mon/hfls/gn/v20210727/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:2f05191d6727068e1500d8d4ed90098a
|
|
38
|
+
obs4REF/ESSO/TropFlux-1-0/mon/hfls/gn/v20250415/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:e607167a08a2521b65e55eb186182003
|
|
39
|
+
obs4REF/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:7a9019e51a41d9e4ab1fcfb072d8ca8d
|
|
40
|
+
obs4REF/ESSO/TropFlux-1-0/mon/hfss/gn/v20210727/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:1da9d8fe862c61bc49c36c18b6527213
|
|
41
|
+
obs4REF/ESSO/TropFlux-1-0/mon/hfss/gn/v20250415/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:6f766ca0332a8e566c408d237571a924
|
|
42
|
+
obs4REF/ESSO/TropFlux-1-0/mon/tas/gn/v20210727/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:a6057931b5f6bc000a44514a1a8c891f
|
|
43
|
+
obs4REF/ESSO/TropFlux-1-0/mon/tas/gn/v20250415/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:527ab1b9becf2a793df558532eccfe69
|
|
44
|
+
obs4REF/ESSO/TropFlux-1-0/mon/tauu/gn/v20210727/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:7c73a3deed3403fa9d21caef3a4d988d
|
|
45
|
+
obs4REF/ESSO/TropFlux-1-0/mon/tauu/gn/v20250415/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:0822e2002e61472277116d38e5e19498
|
|
46
|
+
obs4REF/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:8abc7a724a7a297826e2f783a4ea14f9
|
|
47
|
+
obs4REF/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:8697d3d7862f6e3b72bb5a161aa75ee8
|
|
48
|
+
obs4REF/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc md5:99c8691e0f615dc4d79b4fb5e926cc76
|
|
49
|
+
obs4REF/MOHC/HadISST-1-1/mon/ts/gn/v20250415/ts_mon_HadISST-1-1_PCMDI_gn_187001-202501.nc md5:66fb8cdf53ec0e073c565adfa57862b3
|
|
35
50
|
obs4REF/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc md5:b80c9989d358656c781be5ea5a44c64c
|
|
36
|
-
obs4REF/
|
|
51
|
+
obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rlds/gn/v20230209/rlds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc md5:897451ed566251135483d1413cd6bee3
|
|
52
|
+
obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rlus/gn/v20230209/rlus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc md5:750650025845fc89d9e56a3690deea21
|
|
53
|
+
obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rsds/gn/v20230209/rsds_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc md5:5c33068dd11e6eb8d0bf6e2aa0335ef2
|
|
54
|
+
obs4REF/NASA-LaRC/CERES-EBAF-4-2/mon/rsus/gn/v20230209/rsus_mon_CERES-EBAF-4-2_RSS_gn_200003-202309.nc md5:4f67c58186905e995a8b9497a49ecbf0
|
|
55
|
+
obs4REF/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc md5:570ce90b3afd1d0b31690ae5dbe32d31
|
|
56
|
+
obs4REF/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc md5:e4890cc19ccc5bac29c6b70f28265ff1
|
|
57
|
+
obs4REF/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc md5:9d943d2dd0645850b616820f246aedf3
|
|
58
|
+
obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc md5:0877f014868b83547448f96c3e7c83e9
|
|
59
|
+
obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20231205/pr_mon_GPCP-Monthly-3-2_RSS_gn_198301-202303.nc md5:6970c22443e2097c45de5db8947318eb
|
|
60
|
+
obs4REF/NOAA-NCEI/WOA2023/mon/no3/gn/20250516/no3_mon_WOA2023_REF_gn_201501-202212.nc md5:ffd2b0c1b1f35f5176ba26c43478c9d2
|
|
61
|
+
obs4REF/NOAA-NCEI/WOA2023/mon/o2/gn/20250516/o2_mon_WOA2023_REF_gn_201501-202212.nc md5:1a41d343329730d357a6a21b59f201c7
|
|
62
|
+
obs4REF/NOAA-NCEI/WOA2023/mon/po4/gn/20250516/po4_mon_WOA2023_REF_gn_201501-202212.nc md5:ff65f5c81f3775af49be3e22305d4979
|
|
63
|
+
obs4REF/NOAA-NCEI/WOA2023/mon/so/gn/20250516/so_mon_WOA2023_REF_gn_201501-202212.nc md5:0da9596667c3b6bbc5388e420cd24a3b
|
|
64
|
+
obs4REF/NOAA-NCEI/WOA2023/mon/thetao/gn/20250516/thetao_mon_WOA2023_REF_gn_201501-202212.nc md5:e3bb4f9b387191571459dc49520632ee
|
|
65
|
+
obs4REF/NOC/RAPID/mon/msftmz/NA/20250516/msftmz_mon_RAPID_REF_NA_200404-202302.nc md5:e9ee555d923d39112dcbf591440000b3
|
|
66
|
+
obs4REF/UCI-ORNL/Hoffman/yr/fgco2/gm/20250516/fgco2_yr_Hoffman_REF_gm_185007-201007.nc md5:93419dd752e0ae20e69b7db3f8ea9f5b
|
|
67
|
+
obs4REF/UCI-ORNL/Hoffman/yr/nbp/gm/20250516/nbp_yr_Hoffman_REF_gm_185007-201007.nc md5:1c0b93c81e2608c668ec39c45ca828de
|
|
@@ -23,22 +23,20 @@ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rsdt/gn/v20191115/rsdt_A
|
|
|
23
23
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rsut/gn/v20191115/rsut_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc b3148af8bee4c3562607aeaec9d81d94abad366c85421dd55ef222516fd3f7e0
|
|
24
24
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rsutcs/gn/v20191115/rsutcs_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200501-201412.nc 9f336ed549c02bf31f73f4679b850463ca8edc4db7afb04b31acd643bc3b51c8
|
|
25
25
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/tas/gn/v20191115/tas_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc 4c74c74031fbc88cb0df70826e0aea63a582af5f5a714603a0ae70b3ff834097
|
|
26
|
+
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/tauu/gn/v20191115/tauu_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc 2a1eb8768134189addd7541975ce39d75406d530ba68b2c1286f9f1d8fd14f17
|
|
26
27
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/ts/gn/v20191115/ts_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc b3b8e7675287471fd27f3de1f3ecada278eb7ea384da24031d0f3a949e04f757
|
|
27
28
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Emon/cSoil/gn/v20191115/cSoil_Emon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc d78d9bc532d79a50a0e40645f91572d61a92881aea43552061baea0e77353777
|
|
28
29
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/gpp/gn/v20191115/gpp_Lmon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 41a43edaa1ff7385232f8fbf67fcc551eb77e51ba6cd75b95b5f0ee71af19544
|
|
29
30
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/lai/gn/v20191115/lai_Lmon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 4e6e1530da9030cfb7c207543369c636f339ee3c59c4621e22405494dc436755
|
|
30
31
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/mrro/gn/v20191115/mrro_Lmon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 3b9c010af44ca894bb23a55903fdc57dcd5af8a4e22ea1e98b41b18274720fd9
|
|
31
32
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/mrsos/gn/v20191115/mrsos_Lmon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc ca21d4f5341114cbc217d7c30f89c4375b02ea0a2b723d9cb069db6a9c08b08f
|
|
32
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/nbp/gn/v20191115/nbp_Lmon_ACCESS-ESM1-
|
|
33
|
+
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Lmon/nbp/gn/v20191115/nbp_Lmon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc a400042a848e855335de99e3ae8f5f2a900476db953ad70e6562fc4b8beb0ffc
|
|
33
34
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Ofx/areacello/gn/v20191115/areacello_Ofx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc fe5adde7cfe6d80462ad649fe68c2aa983ba700d96cff5ac830b1d7e7b09ca6f
|
|
34
35
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Ofx/sftof/gn/v20191115/sftof_Ofx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc 89106ad204fb1ac9f3b25f4b93d6fcf9e95db5f1f4466b9baafcb426bad24e4f
|
|
35
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/msftmz/gn/v20191115/msftmz_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_197901-197912.nc 9016163abd89155710291dc541a4146778f18a320435a2ee618f0da1424b0338
|
|
36
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/msftmz/gn/v20191115/msftmz_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_198001-198912.nc 97094c32cb3e8f019ad87145d348307c2a57ba9b0acf0cc5c59978213060e8d4
|
|
37
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/msftmz/gn/v20191115/msftmz_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_199001-199912.nc be682038248b0d79ea9e0402a2a173bd5c054dfdd8cc0932f6cb85d925670889
|
|
38
36
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/msftmz/gn/v20191115/msftmz_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-200912.nc 266c386ddfbe9556404afadef1e778a64b5f4c5dd746c54a1beee3e5fbc9954b
|
|
39
37
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/msftmz/gn/v20191115/msftmz_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_201001-201412.nc 21fa3a223baced12da8a62ad406ba8126851c3e36589184fba2bb1c8b269c6e3
|
|
40
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/sos/gn/v20191115/sos_Omon_ACCESS-ESM1-
|
|
41
|
-
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/tos/gn/v20191115/tos_Omon_ACCESS-ESM1-
|
|
38
|
+
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/sos/gn/v20191115/sos_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc da3a4b261779bd8477a6e067c7e7b611d9438e74d76cff225a44a8dacedc3fd4
|
|
39
|
+
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/tos/gn/v20191115/tos_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc b10be33023c7fdc77c7550ea1bfc6976e354841e6ba6aeaece6eec4b3308d99e
|
|
42
40
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/SImon/siconc/gn/v20200817/siconc_SImon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_197901-201412.nc 384b45a0f88678ffaf0c9701a0fc0175fb0c319d7d94d0b3c4334939d653e51d
|
|
43
41
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/fx/areacella/gn/v20191115/areacella_fx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc 6750d4a2432842cb9342ef99b8ecb3569e8ff3dcbbf020f7f9f43a6f7af42f06
|
|
44
42
|
CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/fx/sftlf/gn/v20191115/sftlf_fx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc 08d84ba3cf02a2481b76611dfa1abe25cbf76326003eebc4eb00c99b32fea19a
|
|
@@ -55,6 +53,10 @@ CMIP6/CMIP/MPI-M/MPI-ESM1-2-LR/esm-piControl/r1i1p1f1/Amon/tas/gn/v20190815/tas_
|
|
|
55
53
|
CMIP6/CMIP/MPI-M/MPI-ESM1-2-LR/esm-piControl/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_189001-190912.nc ae9193e06aec8a7f63f2f7ec63fec9d25b2c1dc5de2bbe7065428c722090f45c
|
|
56
54
|
CMIP6/CMIP/MPI-M/MPI-ESM1-2-LR/esm-piControl/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn_191001-191512.nc 2113b7d4a781c7c28de55b0ffe99c42b49692d113f5109e7a4d0214211a9eb1c
|
|
57
55
|
CMIP6/CMIP/MPI-M/MPI-ESM1-2-LR/esm-piControl/r1i1p1f1/fx/areacella/gn/v20190815/areacella_fx_MPI-ESM1-2-LR_esm-piControl_r1i1p1f1_gn.nc 2f5595635a566d5b4a889468f687aabf99ca5cdadb11f6a770d05d09775bfabb
|
|
56
|
+
CMIP6/CMIP/NCAR/CESM2/historical/r1i1p1f1/ImonAnt/snc/gn/v20190308/snc_ImonAnt_CESM2_historical_r1i1p1f1_gn_200001-201412.nc 5a88cd5ed6ed33f9b24fd4bf942b5e427cb3512584a38030b07feb158c7a78c2
|
|
57
|
+
CMIP6/CMIP/NCAR/CESM2/historical/r1i1p1f1/ImonGre/snc/gn/v20190308/snc_ImonGre_CESM2_historical_r1i1p1f1_gn_200001-201412.nc 5f6b6ccb2450eeeebc3b24d3d76cf306894094efa2f6ee53403be89595f4455c
|
|
58
|
+
CMIP6/CMIP/NCAR/CESM2/historical/r1i1p1f1/LImon/snc/gn/v20190308/snc_LImon_CESM2_historical_r1i1p1f1_gn_200001-201412.nc 27005c5952a981c27c17ad8d169d01c852e2daee3236adf1e170b6b96aafcfff
|
|
59
|
+
CMIP6/CMIP/NCAR/CESM2/historical/r1i1p1f1/Lmon/burntFractionAll/gn/v20190308/burntFractionAll_Lmon_CESM2_historical_r1i1p1f1_gn_200001-201412.nc 61fbd29b05a5bdfa11001265c3960b5147e641148eff2a55cc027aa56db7263c
|
|
58
60
|
CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r1i1p1f1/Amon/psl/gn/v20200615/psl_Amon_ACCESS-ESM1-5_hist-GHG_r1i1p1f1_gn_200001-202012.nc 5fed6b48717fcf508e8b5936be304db0346362c2182c5d13a141afe7c982021a
|
|
59
61
|
CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r1i1p1f1/Amon/ts/gn/v20200615/ts_Amon_ACCESS-ESM1-5_hist-GHG_r1i1p1f1_gn_200001-202012.nc aa98fa93ef29ea266a94d87876b4ae08917caf77e38c5df1eae1ec98a5f559cb
|
|
60
62
|
CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r1i1p1f1/fx/areacella/gn/v20200615/areacella_fx_ACCESS-ESM1-5_hist-GHG_r1i1p1f1_gn.nc 7179f75ff1754e9666b10f8c5508040bbe9fdac0c8117a9231ba5977d4889f27
|
climate_ref/datasets/base.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Protocol
|
|
2
|
+
from typing import Protocol, cast
|
|
3
3
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
from loguru import logger
|
|
@@ -44,14 +44,49 @@ class DatasetAdapter(Protocol):
|
|
|
44
44
|
|
|
45
45
|
dataset_cls: type[Dataset]
|
|
46
46
|
slug_column: str
|
|
47
|
+
"""
|
|
48
|
+
The column in the data catalog that contains the dataset slug.
|
|
49
|
+
The dataset slug is a unique identifier for the dataset that includes the version of the dataset.
|
|
50
|
+
This can be used to group files together that belong to the same dataset.
|
|
51
|
+
"""
|
|
47
52
|
dataset_specific_metadata: tuple[str, ...]
|
|
48
53
|
file_specific_metadata: tuple[str, ...] = ()
|
|
49
54
|
|
|
55
|
+
version_metadata: str = "version"
|
|
56
|
+
"""
|
|
57
|
+
The column in the data catalog that contains the version of the dataset.
|
|
58
|
+
"""
|
|
59
|
+
dataset_id_metadata: tuple[str, ...] = ()
|
|
60
|
+
"""
|
|
61
|
+
The group of metadata columns that are specific to the dataset excluding the version information.
|
|
62
|
+
|
|
63
|
+
Each unique dataset should have the same values for these columns.
|
|
64
|
+
|
|
65
|
+
This is generally the columns that describe the `slug` of a dataset,
|
|
66
|
+
excluding the version information.
|
|
67
|
+
"""
|
|
68
|
+
|
|
50
69
|
def pretty_subset(self, data_catalog: pd.DataFrame) -> pd.DataFrame:
|
|
51
70
|
"""
|
|
52
71
|
Get a subset of the data_catalog to pretty print
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
data_catalog
|
|
76
|
+
Data catalog to subset
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
:
|
|
81
|
+
Subset of the data catalog to pretty print
|
|
82
|
+
|
|
53
83
|
"""
|
|
54
|
-
|
|
84
|
+
return data_catalog[
|
|
85
|
+
[
|
|
86
|
+
*self.dataset_id_metadata,
|
|
87
|
+
self.version_metadata,
|
|
88
|
+
]
|
|
89
|
+
]
|
|
55
90
|
|
|
56
91
|
def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame:
|
|
57
92
|
"""
|
|
@@ -202,6 +237,8 @@ class DatasetAdapter(Protocol):
|
|
|
202
237
|
Iterating over different datasets within the data catalog can be done using a `groupby`
|
|
203
238
|
operation for the `instance_id` column.
|
|
204
239
|
|
|
240
|
+
Only the latest version of each dataset is returned.
|
|
241
|
+
|
|
205
242
|
The index of the data catalog is the primary key of the dataset.
|
|
206
243
|
This should be maintained during any processing.
|
|
207
244
|
|
|
@@ -213,6 +250,27 @@ class DatasetAdapter(Protocol):
|
|
|
213
250
|
with db.session.begin():
|
|
214
251
|
# TODO: Paginate this query to avoid loading all the data at once
|
|
215
252
|
if include_files:
|
|
216
|
-
|
|
253
|
+
catalog = self._get_dataset_files(db, limit)
|
|
217
254
|
else:
|
|
218
|
-
|
|
255
|
+
catalog = self._get_datasets(db, limit)
|
|
256
|
+
|
|
257
|
+
def _get_latest_version(dataset_catalog: pd.DataFrame) -> pd.DataFrame:
|
|
258
|
+
"""
|
|
259
|
+
Get the latest version of each dataset based on the version metadata.
|
|
260
|
+
|
|
261
|
+
This assumes that the version can be sorted lexicographically.
|
|
262
|
+
"""
|
|
263
|
+
latest_version = dataset_catalog[self.version_metadata].max()
|
|
264
|
+
|
|
265
|
+
return cast(
|
|
266
|
+
pd.DataFrame, dataset_catalog[dataset_catalog[self.version_metadata] == latest_version]
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# If there are no datasets, return an empty DataFrame
|
|
270
|
+
if catalog.empty:
|
|
271
|
+
return pd.DataFrame(columns=self.dataset_specific_metadata + self.file_specific_metadata)
|
|
272
|
+
|
|
273
|
+
# Group by the dataset ID and get the latest version for each dataset
|
|
274
|
+
return catalog.groupby(
|
|
275
|
+
list(self.dataset_id_metadata), group_keys=False, as_index=False, sort=False
|
|
276
|
+
).apply(_get_latest_version)
|
climate_ref/datasets/cmip6.py
CHANGED
|
@@ -196,40 +196,21 @@ class CMIP6DatasetAdapter(DatasetAdapter):
|
|
|
196
196
|
|
|
197
197
|
file_specific_metadata = ("start_time", "end_time", "path")
|
|
198
198
|
|
|
199
|
+
version_metadata = "version"
|
|
200
|
+
dataset_id_metadata = (
|
|
201
|
+
"activity_id",
|
|
202
|
+
"institution_id",
|
|
203
|
+
"source_id",
|
|
204
|
+
"experiment_id",
|
|
205
|
+
"member_id",
|
|
206
|
+
"table_id",
|
|
207
|
+
"variable_id",
|
|
208
|
+
"grid_label",
|
|
209
|
+
)
|
|
210
|
+
|
|
199
211
|
def __init__(self, n_jobs: int = 1):
|
|
200
212
|
self.n_jobs = n_jobs
|
|
201
213
|
|
|
202
|
-
def pretty_subset(self, data_catalog: pd.DataFrame) -> pd.DataFrame:
|
|
203
|
-
"""
|
|
204
|
-
Get a subset of the data_catalog to pretty print
|
|
205
|
-
|
|
206
|
-
This is particularly useful for CMIP6 datasets, which have a lot of metadata columns.
|
|
207
|
-
|
|
208
|
-
Parameters
|
|
209
|
-
----------
|
|
210
|
-
data_catalog
|
|
211
|
-
Data catalog to subset
|
|
212
|
-
|
|
213
|
-
Returns
|
|
214
|
-
-------
|
|
215
|
-
:
|
|
216
|
-
Subset of the data catalog to pretty print
|
|
217
|
-
|
|
218
|
-
"""
|
|
219
|
-
return data_catalog[
|
|
220
|
-
[
|
|
221
|
-
"activity_id",
|
|
222
|
-
"institution_id",
|
|
223
|
-
"source_id",
|
|
224
|
-
"experiment_id",
|
|
225
|
-
"member_id",
|
|
226
|
-
"table_id",
|
|
227
|
-
"variable_id",
|
|
228
|
-
"grid_label",
|
|
229
|
-
"version",
|
|
230
|
-
]
|
|
231
|
-
]
|
|
232
|
-
|
|
233
214
|
def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame:
|
|
234
215
|
"""
|
|
235
216
|
Generate a data catalog from the specified file or directory
|
|
@@ -266,15 +247,8 @@ class CMIP6DatasetAdapter(DatasetAdapter):
|
|
|
266
247
|
datasets["end_time"] = _parse_datetime(datasets["end_time"])
|
|
267
248
|
|
|
268
249
|
drs_items = [
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
"source_id",
|
|
272
|
-
"experiment_id",
|
|
273
|
-
"member_id",
|
|
274
|
-
"table_id",
|
|
275
|
-
"variable_id",
|
|
276
|
-
"grid_label",
|
|
277
|
-
"version",
|
|
250
|
+
*self.dataset_id_metadata,
|
|
251
|
+
self.version_metadata,
|
|
278
252
|
]
|
|
279
253
|
datasets["instance_id"] = datasets.apply(
|
|
280
254
|
lambda row: "CMIP6." + ".".join([row[item] for item in drs_items]), axis=1
|
climate_ref/datasets/obs4mips.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
3
|
import traceback
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
from typing import Any
|
|
@@ -8,6 +7,7 @@ from typing import Any
|
|
|
8
7
|
import pandas as pd
|
|
9
8
|
import xarray as xr
|
|
10
9
|
from ecgtools import Builder
|
|
10
|
+
from ecgtools.parsers.utilities import extract_attr_with_regex # type: ignore
|
|
11
11
|
from loguru import logger
|
|
12
12
|
|
|
13
13
|
from climate_ref.datasets.base import DatasetAdapter
|
|
@@ -15,25 +15,6 @@ from climate_ref.datasets.cmip6 import _parse_datetime
|
|
|
15
15
|
from climate_ref.models.dataset import Dataset, Obs4MIPsDataset
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def extract_attr_with_regex(
|
|
19
|
-
input_str: str, regex: str, strip_chars: str | None, ignore_case: bool
|
|
20
|
-
) -> list[Any] | None:
|
|
21
|
-
"""
|
|
22
|
-
Extract version information from attribute with regular expressions.
|
|
23
|
-
"""
|
|
24
|
-
if ignore_case:
|
|
25
|
-
pattern = re.compile(regex, re.IGNORECASE)
|
|
26
|
-
else:
|
|
27
|
-
pattern = re.compile(regex)
|
|
28
|
-
match = re.findall(pattern, input_str)
|
|
29
|
-
if match:
|
|
30
|
-
matchstr = max(match, key=len)
|
|
31
|
-
match = matchstr.strip(strip_chars) if strip_chars else matchstr.strip()
|
|
32
|
-
return match
|
|
33
|
-
else:
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
|
|
37
18
|
def parse_obs4mips(file: str) -> dict[str, Any | None]:
|
|
38
19
|
"""Parser for obs4mips"""
|
|
39
20
|
keys = sorted(
|
|
@@ -144,38 +125,18 @@ class Obs4MIPsDatasetAdapter(DatasetAdapter):
|
|
|
144
125
|
)
|
|
145
126
|
|
|
146
127
|
file_specific_metadata = ("start_time", "end_time", "path")
|
|
128
|
+
version_metadata = "source_version_number"
|
|
129
|
+
dataset_id_metadata = (
|
|
130
|
+
"activity_id",
|
|
131
|
+
"institution_id",
|
|
132
|
+
"source_id",
|
|
133
|
+
"variable_id",
|
|
134
|
+
"grid_label",
|
|
135
|
+
)
|
|
147
136
|
|
|
148
137
|
def __init__(self, n_jobs: int = 1):
|
|
149
138
|
self.n_jobs = n_jobs
|
|
150
139
|
|
|
151
|
-
def pretty_subset(self, data_catalog: pd.DataFrame) -> pd.DataFrame:
|
|
152
|
-
"""
|
|
153
|
-
Get a subset of the data_catalog to pretty print
|
|
154
|
-
|
|
155
|
-
This is particularly useful for obs4MIPs datasets, which have a lot of metadata columns.
|
|
156
|
-
|
|
157
|
-
Parameters
|
|
158
|
-
----------
|
|
159
|
-
data_catalog
|
|
160
|
-
Data catalog to subset
|
|
161
|
-
|
|
162
|
-
Returns
|
|
163
|
-
-------
|
|
164
|
-
:
|
|
165
|
-
Subset of the data catalog to pretty print
|
|
166
|
-
|
|
167
|
-
"""
|
|
168
|
-
return data_catalog[
|
|
169
|
-
[
|
|
170
|
-
"activity_id",
|
|
171
|
-
"institution_id",
|
|
172
|
-
"source_id",
|
|
173
|
-
"variable_id",
|
|
174
|
-
"grid_label",
|
|
175
|
-
"source_version_number",
|
|
176
|
-
]
|
|
177
|
-
]
|
|
178
|
-
|
|
179
140
|
def find_local_datasets(self, file_or_directory: Path) -> pd.DataFrame:
|
|
180
141
|
"""
|
|
181
142
|
Generate a data catalog from the specified file or directory
|
|
@@ -211,12 +172,8 @@ class Obs4MIPsDatasetAdapter(DatasetAdapter):
|
|
|
211
172
|
datasets["end_time"] = _parse_datetime(datasets["end_time"])
|
|
212
173
|
|
|
213
174
|
drs_items = [
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"source_id",
|
|
217
|
-
"variable_id",
|
|
218
|
-
"grid_label",
|
|
219
|
-
"source_version_number",
|
|
175
|
+
*self.dataset_id_metadata,
|
|
176
|
+
self.version_metadata,
|
|
220
177
|
]
|
|
221
178
|
datasets["instance_id"] = datasets.apply(
|
|
222
179
|
lambda row: "obs4MIPs." + ".".join([row[item] for item in drs_items]), axis=1
|
climate_ref/executor/local.py
CHANGED
|
@@ -13,7 +13,7 @@ from climate_ref.models import Execution
|
|
|
13
13
|
from climate_ref_core.diagnostics import ExecutionDefinition, ExecutionResult
|
|
14
14
|
from climate_ref_core.exceptions import ExecutionError
|
|
15
15
|
from climate_ref_core.executor import execute_locally
|
|
16
|
-
from climate_ref_core.logging import
|
|
16
|
+
from climate_ref_core.logging import initialise_logging
|
|
17
17
|
|
|
18
18
|
from .result_handling import handle_execution_result
|
|
19
19
|
|
|
@@ -63,11 +63,17 @@ class ExecutionFuture:
|
|
|
63
63
|
execution_id: int | None = None
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def _process_initialiser() -> None:
|
|
66
|
+
def _process_initialiser() -> None: # pragma: no cover
|
|
67
67
|
# Setup the logging for the process
|
|
68
68
|
# This replaces the loguru default handler
|
|
69
69
|
try:
|
|
70
|
-
|
|
70
|
+
logger.remove()
|
|
71
|
+
config = Config.default()
|
|
72
|
+
initialise_logging(
|
|
73
|
+
level=config.log_level,
|
|
74
|
+
format=config.log_format,
|
|
75
|
+
log_directory=config.paths.log,
|
|
76
|
+
)
|
|
71
77
|
except Exception as e:
|
|
72
78
|
# Don't raise an exception here as that would kill the process pool
|
|
73
79
|
# We want to log the error and continue
|
|
@@ -214,9 +220,17 @@ class LocalExecutor:
|
|
|
214
220
|
elapsed_time = time.time() - start_time
|
|
215
221
|
|
|
216
222
|
if elapsed_time > timeout:
|
|
223
|
+
for result in results:
|
|
224
|
+
logger.warning(
|
|
225
|
+
f"Execution {result.definition.execution_slug()} "
|
|
226
|
+
f"did not complete within the timeout"
|
|
227
|
+
)
|
|
228
|
+
self.pool.shutdown(wait=False, cancel_futures=True)
|
|
217
229
|
raise TimeoutError("Not all tasks completed within the specified timeout")
|
|
218
230
|
|
|
219
231
|
# Wait for a short time before checking for completed executions
|
|
220
232
|
time.sleep(refresh_time)
|
|
221
233
|
finally:
|
|
222
234
|
t.close()
|
|
235
|
+
|
|
236
|
+
logger.info("All executions completed successfully")
|
|
@@ -129,7 +129,6 @@ def handle_execution_result(
|
|
|
129
129
|
cv.validate_metrics(cmec_metric_bundle)
|
|
130
130
|
except (ResultValidationError, AssertionError):
|
|
131
131
|
logger.exception("Diagnostic values do not conform with the controlled vocabulary")
|
|
132
|
-
# TODO: Mark the diagnostic execution result as failed once the CV has stabilised
|
|
133
132
|
# execution.mark_failed()
|
|
134
133
|
|
|
135
134
|
# Perform a bulk insert of scalar values
|
climate_ref/solver.py
CHANGED
|
@@ -245,6 +245,57 @@ def _solve_from_data_requirements(
|
|
|
245
245
|
)
|
|
246
246
|
|
|
247
247
|
|
|
248
|
+
@define
|
|
249
|
+
class SolveFilterOptions:
|
|
250
|
+
"""
|
|
251
|
+
Options to filter the diagnostics that are solved
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
diagnostic: list[str] | None = None
|
|
255
|
+
"""
|
|
256
|
+
Check if the diagnostic slug contains any of the provided values
|
|
257
|
+
"""
|
|
258
|
+
provider: list[str] | None = None
|
|
259
|
+
"""
|
|
260
|
+
Check if the provider slug contains any of the provided values
|
|
261
|
+
"""
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def matches_filter(diagnostic: Diagnostic, filters: SolveFilterOptions | None) -> bool:
|
|
265
|
+
"""
|
|
266
|
+
Check if a diagnostic matches the provided filters
|
|
267
|
+
|
|
268
|
+
Each filter is optional and a diagnostic will match if it satisfies all the provided filters.
|
|
269
|
+
i.e. the filters are ANDed together.
|
|
270
|
+
|
|
271
|
+
Parameters
|
|
272
|
+
----------
|
|
273
|
+
diagnostic
|
|
274
|
+
Diagnostic to check against the filters
|
|
275
|
+
filters
|
|
276
|
+
Collection of filters to apply to the diagnostic
|
|
277
|
+
|
|
278
|
+
If no filters are provided, the diagnostic is considered to match
|
|
279
|
+
|
|
280
|
+
Returns
|
|
281
|
+
-------
|
|
282
|
+
True if the diagnostic matches the filters, False otherwise
|
|
283
|
+
"""
|
|
284
|
+
if filters is None:
|
|
285
|
+
return True
|
|
286
|
+
|
|
287
|
+
diagnostic_slug = diagnostic.slug
|
|
288
|
+
provider_slug = diagnostic.provider.slug
|
|
289
|
+
|
|
290
|
+
if filters.provider and not any([f.lower() in provider_slug for f in filters.provider]):
|
|
291
|
+
return False
|
|
292
|
+
|
|
293
|
+
if filters.diagnostic and not any([f.lower() in diagnostic_slug for f in filters.diagnostic]):
|
|
294
|
+
return False
|
|
295
|
+
|
|
296
|
+
return True
|
|
297
|
+
|
|
298
|
+
|
|
248
299
|
@define
|
|
249
300
|
class ExecutionSolver:
|
|
250
301
|
"""
|
|
@@ -278,7 +329,9 @@ class ExecutionSolver:
|
|
|
278
329
|
},
|
|
279
330
|
)
|
|
280
331
|
|
|
281
|
-
def solve(
|
|
332
|
+
def solve(
|
|
333
|
+
self, filters: SolveFilterOptions | None = None
|
|
334
|
+
) -> typing.Generator[DiagnosticExecution, None, None]:
|
|
282
335
|
"""
|
|
283
336
|
Solve which executions need to be calculated for a dataset
|
|
284
337
|
|
|
@@ -293,17 +346,23 @@ class ExecutionSolver:
|
|
|
293
346
|
"""
|
|
294
347
|
for provider in self.provider_registry.providers:
|
|
295
348
|
for diagnostic in provider.diagnostics():
|
|
349
|
+
# Filter the diagnostic based on the provided filters
|
|
350
|
+
if not matches_filter(diagnostic, filters):
|
|
351
|
+
logger.debug(f"Skipping {diagnostic.full_slug()} due to filter")
|
|
352
|
+
continue
|
|
296
353
|
yield from solve_executions(self.data_catalog, diagnostic, provider)
|
|
297
354
|
|
|
298
355
|
|
|
299
356
|
def solve_required_executions( # noqa: PLR0913
|
|
300
357
|
db: Database,
|
|
301
358
|
dry_run: bool = False,
|
|
359
|
+
execute: bool = True,
|
|
302
360
|
solver: ExecutionSolver | None = None,
|
|
303
361
|
config: Config | None = None,
|
|
304
362
|
timeout: int = 60,
|
|
305
363
|
one_per_provider: bool = False,
|
|
306
364
|
one_per_diagnostic: bool = False,
|
|
365
|
+
filters: SolveFilterOptions | None = None,
|
|
307
366
|
) -> None:
|
|
308
367
|
"""
|
|
309
368
|
Solve for executions that require recalculation
|
|
@@ -328,7 +387,7 @@ def solve_required_executions( # noqa: PLR0913
|
|
|
328
387
|
diagnostic_count = {}
|
|
329
388
|
provider_count = {}
|
|
330
389
|
|
|
331
|
-
for potential_execution in solver.solve():
|
|
390
|
+
for potential_execution in solver.solve(filters):
|
|
332
391
|
# The diagnostic output is first written to the scratch directory
|
|
333
392
|
definition = potential_execution.build_execution_definition(output_root=config.paths.scratch)
|
|
334
393
|
|
|
@@ -371,6 +430,7 @@ def solve_required_executions( # noqa: PLR0913
|
|
|
371
430
|
logger.info(f"Created new execution group: {potential_execution.execution_slug()!r}")
|
|
372
431
|
db.session.flush()
|
|
373
432
|
|
|
433
|
+
# TODO: Move this logic to the solver
|
|
374
434
|
# Check if we should run given the one_per_provider or one_per_diagnostic flags
|
|
375
435
|
one_of_check_failed = (
|
|
376
436
|
one_per_provider and provider_count.get(diagnostic.provider.slug, 0) > 0
|
|
@@ -403,10 +463,11 @@ def solve_required_executions( # noqa: PLR0913
|
|
|
403
463
|
# Add links to the datasets used in the execution
|
|
404
464
|
execution.register_datasets(db, definition.datasets)
|
|
405
465
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
466
|
+
if execute:
|
|
467
|
+
executor.run(
|
|
468
|
+
definition=definition,
|
|
469
|
+
execution=execution,
|
|
470
|
+
)
|
|
410
471
|
|
|
411
472
|
provider_count[diagnostic.provider.slug] += 1
|
|
412
473
|
diagnostic_count[diagnostic.full_slug()] += 1
|
climate_ref/testing.py
CHANGED
|
@@ -13,20 +13,21 @@ from climate_ref.executor import handle_execution_result
|
|
|
13
13
|
from climate_ref.models import Execution, ExecutionGroup
|
|
14
14
|
from climate_ref_core.dataset_registry import dataset_registry_manager, fetch_all_files
|
|
15
15
|
from climate_ref_core.diagnostics import Diagnostic, ExecutionResult
|
|
16
|
+
from climate_ref_core.env import env
|
|
16
17
|
from climate_ref_core.pycmec.metric import CMECMetric
|
|
17
18
|
from climate_ref_core.pycmec.output import CMECOutput
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def _determine_test_directory() -> Path | None:
|
|
21
|
-
|
|
22
|
+
path = env.path("REF_TEST_DATA_DIR", default=Path(__file__).parents[4] / "tests" / "test-data")
|
|
22
23
|
|
|
23
|
-
if not
|
|
24
|
+
if not path.exists(): # pragma: no cover
|
|
24
25
|
return None
|
|
25
|
-
return
|
|
26
|
+
return path
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
TEST_DATA_DIR = _determine_test_directory()
|
|
29
|
-
SAMPLE_DATA_VERSION = "v0.6.
|
|
30
|
+
SAMPLE_DATA_VERSION = "v0.6.3"
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
def fetch_sample_data(force_cleanup: bool = False, symlink: bool = False) -> None:
|
|
@@ -102,7 +103,9 @@ def validate_result(diagnostic: Diagnostic, config: Config, result: ExecutionRes
|
|
|
102
103
|
|
|
103
104
|
# Validate bundles
|
|
104
105
|
metric_bundle = CMECMetric.load_from_json(result.to_output_path(result.metric_bundle_filename))
|
|
105
|
-
|
|
106
|
+
CMECMetric.model_validate(metric_bundle)
|
|
107
|
+
bundle_dimensions = tuple(metric_bundle.DIMENSIONS.root["json_structure"])
|
|
108
|
+
assert diagnostic.facets == bundle_dimensions
|
|
106
109
|
CMECOutput.load_from_json(result.to_output_path(result.output_bundle_filename))
|
|
107
110
|
|
|
108
111
|
# Create a fake log file if one doesn't exist
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: climate-ref
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Application which runs the CMIP Rapid Evaluation Framework
|
|
5
5
|
Author-email: Jared Lewis <jared.lewis@climate-resource.com>, Mika Pflueger <mika.pflueger@climate-resource.com>, Bouwe Andela <b.andela@esciencecenter.nl>, Jiwoo Lee <lee1043@llnl.gov>, Min Xu <xum1@ornl.gov>, Nathan Collier <collierno@ornl.gov>, Dora Hegedus <dora.hegedus@stfc.ac.uk>
|
|
6
|
-
License: Apache-2.0
|
|
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
|
+
Classifier: Intended Audience :: Developers
|
|
10
11
|
Classifier: Intended Audience :: Science/Research
|
|
11
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
13
|
Classifier: Operating System :: OS Independent
|
|
@@ -25,7 +26,6 @@ Requires-Dist: ecgtools>=2024.7.31
|
|
|
25
26
|
Requires-Dist: environs>=11.0.0
|
|
26
27
|
Requires-Dist: loguru>=0.7.2
|
|
27
28
|
Requires-Dist: platformdirs>=4.3.6
|
|
28
|
-
Requires-Dist: setuptools>=75.8.0
|
|
29
29
|
Requires-Dist: sqlalchemy>=2.0.36
|
|
30
30
|
Requires-Dist: tomlkit>=0.13.2
|
|
31
31
|
Requires-Dist: tqdm>=4.67.1
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
climate_ref/__init__.py,sha256=
|
|
1
|
+
climate_ref/__init__.py,sha256=M45QGfl0KCPK48A8MjI08weNvZHMYH__GblraQMxsoM,808
|
|
2
2
|
climate_ref/_config_helpers.py,sha256=-atI5FX7SukhLE_jz_rL-EHQ7s0YYqKu3dSFYWxSyMU,6632
|
|
3
3
|
climate_ref/alembic.ini,sha256=WRvbwSIFuZ7hWNMnR2-yHPJAwYUnwhvRYBzkJhtpGdg,3535
|
|
4
|
-
climate_ref/config.py,sha256=
|
|
4
|
+
climate_ref/config.py,sha256=SHxqdpzq-TIfAdhwk1Yt-ob96T2a3pqYcq-Wed4Ljgg,16882
|
|
5
5
|
climate_ref/constants.py,sha256=9RaNLgUSuQva7ki4eRW3TjOKeVP6T81QNiu0veB1zVk,111
|
|
6
6
|
climate_ref/database.py,sha256=b_6XHdr78Mo7KeLqQJ5DjLsySHPdQE83P8dRpdMfzfM,8661
|
|
7
7
|
climate_ref/provider_registry.py,sha256=dyfj4vU6unKHNXtT03HafQtAi3LilL37uvu3paCnmNY,4159
|
|
8
8
|
climate_ref/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
climate_ref/solver.py,sha256=
|
|
10
|
-
climate_ref/testing.py,sha256=
|
|
11
|
-
climate_ref/cli/__init__.py,sha256=
|
|
9
|
+
climate_ref/solver.py,sha256=T5sQjweSvpUMG4q8MfbGjljxa5kBgKxNotT78PwyxqU,16804
|
|
10
|
+
climate_ref/testing.py,sha256=1b9lVCJlKxjJ7JGq6zDD2gK3BEM9ZVv1dbA-j6yb4Yk,4256
|
|
11
|
+
climate_ref/cli/__init__.py,sha256=q-JAiRmwTXqapJGwtfuZ2P-L1a4XAmWj3CoZKLWlP3A,4357
|
|
12
12
|
climate_ref/cli/_utils.py,sha256=6bIb8zEVvzXyKpv8MG58T-T2L2jH-G8WNrOOGpz3uCw,1918
|
|
13
13
|
climate_ref/cli/config.py,sha256=8I6CLdqKgTu6yaASy-qG0T839Fc0lDZtLSZ6YCc4wOY,520
|
|
14
|
-
climate_ref/cli/datasets.py,sha256=
|
|
14
|
+
climate_ref/cli/datasets.py,sha256=5fEh4VnQUcQKxSsFc8u6lWkOlpv7-ix-1eccK2TET9c,7890
|
|
15
15
|
climate_ref/cli/executions.py,sha256=sZXyVFYWML5mD7dE8xlsqyunsrwOIweTBDEUKCjXEpo,6798
|
|
16
16
|
climate_ref/cli/providers.py,sha256=eS9IaQxW8zGxidr8TWt7thdMU5JH53u4T3xbcIe2C_E,2455
|
|
17
|
-
climate_ref/cli/solve.py,sha256=
|
|
18
|
-
climate_ref/dataset_registry/obs4ref_reference.txt,sha256=
|
|
19
|
-
climate_ref/dataset_registry/sample_data.txt,sha256=
|
|
17
|
+
climate_ref/cli/solve.py,sha256=qc7yalXxqdcSZsoCh2ZSV7Mt6mxTKc4lg7zKpMA55Y8,2112
|
|
18
|
+
climate_ref/dataset_registry/obs4ref_reference.txt,sha256=2zJMbsAsQ49KaWziX3CqrlILq9yN7S2ygmfV3V5rsnw,8395
|
|
19
|
+
climate_ref/dataset_registry/sample_data.txt,sha256=3JAHy14pRbLlo9-oNxUXLgZ_QOFJXUieEftBbapSY8E,20124
|
|
20
20
|
climate_ref/datasets/__init__.py,sha256=PV3u5ZmhyfcHbKqySgwVA8m4-naZgxzydLXSBqdTGLM,1171
|
|
21
|
-
climate_ref/datasets/base.py,sha256=
|
|
22
|
-
climate_ref/datasets/cmip6.py,sha256=
|
|
23
|
-
climate_ref/datasets/obs4mips.py,sha256=
|
|
21
|
+
climate_ref/datasets/base.py,sha256=yoip8UCcTCUPn2xVlsJ1If9zXw_476dDYViH5iMgcIE,10352
|
|
22
|
+
climate_ref/datasets/cmip6.py,sha256=3MVJ1kPdw6f6V3G4gdHIiqDGUyMqPs-_wttkw2YKAH0,8425
|
|
23
|
+
climate_ref/datasets/obs4mips.py,sha256=CmMm4kopfb0yFsMSgUlHUm8clGJImBaodSkh6lAv_Ug,5926
|
|
24
24
|
climate_ref/datasets/pmp_climatology.py,sha256=goHDc_3B2Wdiy_hmpERNvWDdDYZACPOyFDt3Du6nGc0,534
|
|
25
25
|
climate_ref/datasets/utils.py,sha256=iLJO7h4G3DWsRe9hIC4qkIyi5_zIW1ZMw-FDASLujtM,359
|
|
26
26
|
climate_ref/executor/__init__.py,sha256=DooN4jQudmLHyw24IfqNfWynfa1vEolLs-mZ7uY8O0k,604
|
|
27
|
-
climate_ref/executor/local.py,sha256=
|
|
28
|
-
climate_ref/executor/result_handling.py,sha256=
|
|
27
|
+
climate_ref/executor/local.py,sha256=P_nGD4blrLavk-ISj73cakAQCeELM_hNIhs8yVWWSAQ,8353
|
|
28
|
+
climate_ref/executor/result_handling.py,sha256=i7ZMX5vvyPY5gW-WWd-JHLi1BLviB9FXhn4FE8C9d4w,7787
|
|
29
29
|
climate_ref/executor/synchronous.py,sha256=o4TndsoKMu9AzJYLkusU9lRkgHCy6HcCP46tEs6o86U,1895
|
|
30
30
|
climate_ref/migrations/README,sha256=xM5osYbyEbEFA2eh5kwary_oh-5VFWtDubA-vgWwvlE,935
|
|
31
31
|
climate_ref/migrations/env.py,sha256=8GvBLhGTuQy6MKYMj7QszJEQ2LNewf1Z9kB9dBHQs9I,4375
|
|
@@ -39,9 +39,9 @@ climate_ref/models/diagnostic.py,sha256=YB6xzbEXdpz2j-Ddf19RV8mAiWBrkmtRmiAEUV3t
|
|
|
39
39
|
climate_ref/models/execution.py,sha256=lRCpaKLSR7rZbuoL94GW76tm9wLMsSDoIOA7bIa6xgY,9848
|
|
40
40
|
climate_ref/models/metric_value.py,sha256=44OLcZz-qLx-p_9w7YWDKpD5S7Y9HyTKKsvSb77RBro,10190
|
|
41
41
|
climate_ref/models/provider.py,sha256=RAE2qAAxwObu-72CdK4kt5ACMmKYEn07WJm7DU9hF28,990
|
|
42
|
-
climate_ref-0.
|
|
43
|
-
climate_ref-0.
|
|
44
|
-
climate_ref-0.
|
|
45
|
-
climate_ref-0.
|
|
46
|
-
climate_ref-0.
|
|
47
|
-
climate_ref-0.
|
|
42
|
+
climate_ref-0.6.0.dist-info/METADATA,sha256=Ov6ZLG2A0D78je48OtG4TOhaCczrwoknsHSSt0rwutE,4399
|
|
43
|
+
climate_ref-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
44
|
+
climate_ref-0.6.0.dist-info/entry_points.txt,sha256=IaggEJlDIhoYWXdXJafacWbWtCcoEqUKceP1qD7_7vU,44
|
|
45
|
+
climate_ref-0.6.0.dist-info/licenses/LICENCE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
46
|
+
climate_ref-0.6.0.dist-info/licenses/NOTICE,sha256=4qTlax9aX2-mswYJuVrLqJ9jK1IkN5kSBqfVvYLF3Ws,128
|
|
47
|
+
climate_ref-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|