climate-ref 0.5.2__tar.gz → 0.5.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {climate_ref-0.5.2 → climate_ref-0.5.4}/PKG-INFO +3 -3
  2. {climate_ref-0.5.2 → climate_ref-0.5.4}/README.md +2 -2
  3. {climate_ref-0.5.2 → climate_ref-0.5.4}/pyproject.toml +1 -1
  4. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/solve.py +14 -1
  5. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/config.py +10 -0
  6. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/database.py +46 -0
  7. climate_ref-0.5.4/src/climate_ref/dataset_registry/obs4ref_reference.txt +36 -0
  8. climate_ref-0.5.4/src/climate_ref/dataset_registry/sample_data.txt +105 -0
  9. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/cmip6.py +87 -2
  10. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/executor/result_handling.py +17 -16
  11. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/provider_registry.py +2 -1
  12. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/solver.py +39 -8
  13. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/testing.py +1 -1
  14. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_cmip6.py +14 -1
  15. climate_ref-0.5.4/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml +720 -0
  16. climate_ref-0.5.4/tests/unit/datasets/test_obs4mips/obs4mips_catalog_local.yml +756 -0
  17. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_obs4mips.py +44 -28
  18. climate_ref-0.5.4/tests/unit/datasets/test_pmp_climatology/pmp_catalog_local.yml +756 -0
  19. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_pmp_climatology.py +8 -5
  20. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/models/test_metric_value.py +3 -3
  21. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/test_config.py +5 -1
  22. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/test_database.py +107 -1
  23. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/test_solver.py +85 -12
  24. climate_ref-0.5.2/src/climate_ref/dataset_registry/obs4ref_reference.txt +0 -2
  25. climate_ref-0.5.2/src/climate_ref/dataset_registry/sample_data.txt +0 -74
  26. climate_ref-0.5.2/tests/unit/datasets/test_obs4mips/obs4mips_catalog_db.yml +0 -60
  27. climate_ref-0.5.2/tests/unit/datasets/test_obs4mips/obs4mips_catalog_local.yml +0 -21
  28. climate_ref-0.5.2/tests/unit/datasets/test_pmp_climatology/pmp_catalog_local.yml +0 -21
  29. {climate_ref-0.5.2 → climate_ref-0.5.4}/.gitignore +0 -0
  30. {climate_ref-0.5.2 → climate_ref-0.5.4}/Dockerfile +0 -0
  31. {climate_ref-0.5.2 → climate_ref-0.5.4}/LICENCE +0 -0
  32. {climate_ref-0.5.2 → climate_ref-0.5.4}/NOTICE +0 -0
  33. {climate_ref-0.5.2 → climate_ref-0.5.4}/conftest.py +0 -0
  34. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/__init__.py +0 -0
  35. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/_config_helpers.py +0 -0
  36. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/alembic.ini +0 -0
  37. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/__init__.py +0 -0
  38. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/_utils.py +0 -0
  39. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/config.py +0 -0
  40. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/datasets.py +0 -0
  41. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/executions.py +0 -0
  42. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/cli/providers.py +0 -0
  43. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/constants.py +0 -0
  44. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/__init__.py +0 -0
  45. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/base.py +0 -0
  46. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/obs4mips.py +0 -0
  47. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/pmp_climatology.py +0 -0
  48. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/datasets/utils.py +0 -0
  49. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/executor/__init__.py +0 -0
  50. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/executor/local.py +0 -0
  51. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/executor/synchronous.py +0 -0
  52. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/migrations/README +0 -0
  53. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/migrations/env.py +0 -0
  54. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/migrations/script.py.mako +0 -0
  55. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/migrations/versions/2025-05-02T1418_341a4aa2551e_regenerate.py +0 -0
  56. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/migrations/versions/2025-05-09T2032_03dbb4998e49_series_metric_value.py +0 -0
  57. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/__init__.py +0 -0
  58. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/base.py +0 -0
  59. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/dataset.py +0 -0
  60. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/diagnostic.py +0 -0
  61. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/execution.py +0 -0
  62. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/metric_value.py +0 -0
  63. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/models/provider.py +0 -0
  64. {climate_ref-0.5.2 → climate_ref-0.5.4}/src/climate_ref/py.typed +0 -0
  65. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_config.py +0 -0
  66. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_datasets.py +0 -0
  67. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_executions/test_inspect.txt +0 -0
  68. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_executions.py +0 -0
  69. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_providers.py +0 -0
  70. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_root.py +0 -0
  71. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/cli/test_solve.py +0 -0
  72. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/conftest.py +0 -0
  73. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_cmip6/cmip6_catalog_db.yml +0 -0
  74. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_cmip6/cmip6_catalog_local.yml +0 -0
  75. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_datasets.py +0 -0
  76. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/datasets/test_utils.py +0 -0
  77. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/executor/test_local_executor.py +0 -0
  78. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/executor/test_result_handling.py +0 -0
  79. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/executor/test_synchronous_executor.py +0 -0
  80. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/models/test_metric_execution.py +0 -0
  81. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/test_provider_registry.py +0 -0
  82. {climate_ref-0.5.2 → climate_ref-0.5.4}/tests/unit/test_solver/test_solve_metrics.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: climate-ref
3
- Version: 0.5.2
3
+ Version: 0.5.4
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
6
  License: Apache-2.0
@@ -75,8 +75,8 @@ pip install climate-ref[aft-providers]
75
75
 
76
76
  ```bash
77
77
  # Ingest some observation datasets
78
- ref datasets fetch-data --registry obs4ref --output-dir datasets/obs4ref
79
- ref datasets fetch-data --registry sample-data --output-dir datasets/sample-data
78
+ ref datasets fetch-data --registry obs4ref ---output-directory datasets/obs4ref
79
+ ref datasets fetch-data --registry sample-data ---output-directory datasets/sample-data
80
80
 
81
81
  # Run metrics against your climate data
82
82
  ref solve
@@ -28,8 +28,8 @@ pip install climate-ref[aft-providers]
28
28
 
29
29
  ```bash
30
30
  # Ingest some observation datasets
31
- ref datasets fetch-data --registry obs4ref --output-dir datasets/obs4ref
32
- ref datasets fetch-data --registry sample-data --output-dir datasets/sample-data
31
+ ref datasets fetch-data --registry obs4ref ---output-directory datasets/obs4ref
32
+ ref datasets fetch-data --registry sample-data ---output-directory datasets/sample-data
33
33
 
34
34
  # Run metrics against your climate data
35
35
  ref solve
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "climate-ref"
3
- version = "0.5.2"
3
+ version = "0.5.4"
4
4
  description = "Application which runs the CMIP Rapid Evaluation Framework"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -10,6 +10,12 @@ def solve(
10
10
  ctx: typer.Context,
11
11
  dry_run: bool = typer.Option(False, help="Do not execute any diagnostics"),
12
12
  timeout: int = typer.Option(60, help="Timeout in seconds for the solve operation"),
13
+ one_per_provider: bool = typer.Option(
14
+ False, help="Limit to one execution per provider. This is useful for testing"
15
+ ),
16
+ one_per_diagnostic: bool = typer.Option(
17
+ False, help="Limit to one execution per diagnostic. This is useful for testing"
18
+ ),
13
19
  ) -> None:
14
20
  """
15
21
  Solve for executions that require recalculation
@@ -19,4 +25,11 @@ def solve(
19
25
  """
20
26
  config = ctx.obj.config
21
27
  db = ctx.obj.database
22
- solve_required_executions(config=config, db=db, dry_run=dry_run, timeout=timeout)
28
+ solve_required_executions(
29
+ config=config,
30
+ db=db,
31
+ dry_run=dry_run,
32
+ timeout=timeout,
33
+ one_per_provider=one_per_provider,
34
+ one_per_diagnostic=one_per_diagnostic,
35
+ )
@@ -276,6 +276,16 @@ class DbConfig:
276
276
  """
277
277
  run_migrations: bool = field(default=True)
278
278
 
279
+ max_backups: int = env_field(name="MAX_BACKUPS", default=5)
280
+ """
281
+ Maximum number of database backups to keep.
282
+
283
+
284
+ When running migrations for on-disk SQLite databases, a backup of the database is created.
285
+ This setting controls how many of these backups are retained.
286
+ The oldest backups are automatically removed when this limit is exceeded.
287
+ """
288
+
279
289
  @database_url.default
280
290
  def _connection_url_factory(self) -> str:
281
291
  filename = env.path("REF_CONFIGURATION") / "db" / "climate_ref.db"
@@ -9,6 +9,8 @@ It provides a session object that can be used to interact with the database and
9
9
  """
10
10
 
11
11
  import importlib.resources
12
+ import shutil
13
+ from datetime import datetime
12
14
  from pathlib import Path
13
15
  from typing import TYPE_CHECKING, Any
14
16
  from urllib import parse as urlparse
@@ -53,6 +55,44 @@ def _get_database_revision(connection: sqlalchemy.engine.Connection) -> str | No
53
55
  return current_rev
54
56
 
55
57
 
58
+ def _create_backup(db_path: Path, max_backups: int) -> Path:
59
+ """
60
+ Create a backup of the database file
61
+
62
+ Parameters
63
+ ----------
64
+ db_path
65
+ Path to the database file
66
+ max_backups
67
+ Maximum number of backups to keep
68
+
69
+ Returns
70
+ -------
71
+ :
72
+ Path to the backup file
73
+ """
74
+ if not db_path.exists():
75
+ logger.warning(f"Database file {db_path} does not exist, skipping backup")
76
+ return db_path
77
+
78
+ backup_dir = db_path.parent / "backups"
79
+ backup_dir.mkdir(exist_ok=True)
80
+
81
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
82
+ backup_path = backup_dir / f"{db_path.stem}_{timestamp}{db_path.suffix}"
83
+
84
+ logger.info(f"Creating backup of database at {backup_path}")
85
+ shutil.copy2(db_path, backup_path)
86
+
87
+ # Clean up old backups
88
+ backups = sorted(backup_dir.glob(f"{db_path.stem}_*{db_path.suffix}"), reverse=True)
89
+ for old_backup in backups[max_backups:]:
90
+ logger.info(f"Removing old backup {old_backup}")
91
+ old_backup.unlink()
92
+
93
+ return backup_path
94
+
95
+
56
96
  def validate_database_url(database_url: str) -> str:
57
97
  """
58
98
  Validate a database URL
@@ -153,6 +193,12 @@ class Database:
153
193
  "Please delete your database and start again."
154
194
  )
155
195
 
196
+ # Create backup before running migrations
197
+ split_url = urlparse.urlsplit(self.url)
198
+ if split_url.scheme == "sqlite" and split_url.path != ":memory:":
199
+ db_path = Path(split_url.path[1:])
200
+ _create_backup(db_path, config.db.max_backups)
201
+
156
202
  alembic.command.upgrade(self.alembic_config(config), "heads")
157
203
 
158
204
  @staticmethod
@@ -0,0 +1,36 @@
1
+ obs4REF/ECMWF/ERA-20C/mon/psl/gn/v20210727/psl_mon_ERA-20C_PCMDI_gn_190001-201012.nc md5:c100cf25d5681c375cd6c1ee60b678ba
2
+ obs4REF/ECMWF/ERA-20C/mon/ts/gn/v20210727/ts_mon_ERA-20C_PCMDI_gn_190001-201012.nc md5:9ed8dfbb805ed4caa282ed70f873a3a0
3
+ obs4REF/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc md5:570ce90b3afd1d0b31690ae5dbe32d31
4
+ obs4REF/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc md5:e4890cc19ccc5bac29c6b70f28265ff1
5
+ obs4REF/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc md5:9d943d2dd0645850b616820f246aedf3
6
+ obs4REF/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc md5:99c8691e0f615dc4d79b4fb5e926cc76
7
+ obs4REF/ESSO/TropFlux-1-0/mon/hfls/gn/v20210727/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:2f05191d6727068e1500d8d4ed90098a
8
+ obs4REF/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:7a9019e51a41d9e4ab1fcfb072d8ca8d
9
+ obs4REF/ESSO/TropFlux-1-0/mon/hfss/gn/v20210727/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:1da9d8fe862c61bc49c36c18b6527213
10
+ obs4REF/ESSO/TropFlux-1-0/mon/tas/gn/v20210727/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:a6057931b5f6bc000a44514a1a8c891f
11
+ obs4REF/ESSO/TropFlux-1-0/mon/tauu/gn/v20210727/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc md5:7c73a3deed3403fa9d21caef3a4d988d
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
14
+ obs4REF/ECMWF/ERA-INT/mon/hfls/gn/v20210727/hfls_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:1ae4587143f05ee81432b3d9960aab63
15
+ obs4REF/ECMWF/ERA-INT/mon/hfss/gn/v20210727/hfss_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:261f02b8cbce18486548882a11f9aa34
16
+ obs4REF/ECMWF/ERA-INT/mon/hur/gn/v20210727/hur_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:56fcd2df8ed2879f18b5e8c78134a148
17
+ obs4REF/ECMWF/ERA-INT/mon/hus/gn/v20210727/hus_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:6f3344d5d936fb84084ac1caf6431016
18
+ obs4REF/ECMWF/ERA-INT/mon/pr/gn/v20210727/pr_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:92e48c992cde6850d41c52e1778057c2
19
+ obs4REF/ECMWF/ERA-INT/mon/psl/gn/v20210727/psl_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:7409d0caa4a675436e28085bed12d0c9
20
+ obs4REF/ECMWF/ERA-INT/mon/rlds/gn/v20210727/rlds_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:dfba31b6b8e6a4924b7b6cfba648715f
21
+ obs4REF/ECMWF/ERA-INT/mon/rlus/gn/v20210727/rlus_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:94acf2c3bd5f39301148f610722b4590
22
+ obs4REF/ECMWF/ERA-INT/mon/rsds/gn/v20210727/rsds_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:0a56d7cd3fdf112a37c48433b8cd1e29
23
+ obs4REF/ECMWF/ERA-INT/mon/rsus/gn/v20210727/rsus_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:ec8f6e9cb64d81a7c0b70fbd7692e133
24
+ obs4REF/ECMWF/ERA-INT/mon/sfcWind/gn/v20210727/sfcWind_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:8a54a0edef0b9c22ea0b1dd8d5f2dd57
25
+ obs4REF/ECMWF/ERA-INT/mon/ta/gn/v20210727/ta_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:458b5d536c7314c29f8867a5417a95a1
26
+ obs4REF/ECMWF/ERA-INT/mon/tauu/gn/v20210727/tauu_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:af86da822ebd76ed3ee0a7e5d5a9912f
27
+ obs4REF/ECMWF/ERA-INT/mon/tauv/gn/v20210727/tauv_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:87757bbcaff35aef1d685649563ba0a7
28
+ obs4REF/ECMWF/ERA-INT/mon/ts/gn/v20210727/ts_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:f6a6f2bd8710df95c06dcb910501a771
29
+ obs4REF/ECMWF/ERA-INT/mon/ua/gn/v20210727/ua_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:054306f777065cf8cf94d44e412510bd
30
+ obs4REF/ECMWF/ERA-INT/mon/uas/gn/v20210727/uas_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:2b3144fc737c5e3d2aa930c53751ff2b
31
+ obs4REF/ECMWF/ERA-INT/mon/va/gn/v20210727/va_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:f67ca168d6cd87bfdd4a911eb72dd022
32
+ obs4REF/ECMWF/ERA-INT/mon/vas/gn/v20210727/vas_mon_ERA-INT_PCMDI_gn_197901-201903.nc md5:ac19b48b897cfe839585df4ff0fc4a7b
33
+ obs4REF/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc md5:d8fb93f31ff4a6370ccee93db82af86c
34
+ obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc md5:0877f014868b83547448f96c3e7c83e9
35
+ obs4REF/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc md5:b80c9989d358656c781be5ea5a44c64c
36
+ obs4REF/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc md5:91252303cb65548fee5ff42dd3024825
@@ -0,0 +1,105 @@
1
+ CMIP6/C4MIP/CSIRO/ACCESS-ESM1-5/esm-1pct-brch-1000PgC/r1i1p1f1/Amon/tas/gn/v20191206/tas_Amon_ACCESS-ESM1-5_esm-1pct-brch-1000PgC_r1i1p1f1_gn_016801-026812.nc ffef38229e3b69ea703274f174152cfc4886665bb346c1cc604d88f932137828
2
+ CMIP6/C4MIP/CSIRO/ACCESS-ESM1-5/esm-1pct-brch-1000PgC/r1i1p1f1/fx/areacella/gn/v20191206/areacella_fx_ACCESS-ESM1-5_esm-1pct-brch-1000PgC_r1i1p1f1_gn.nc d3292e1af73f8ab0327a4f689f8b4fdd7d818e861d8b78351daf392de15e4409
3
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/fco2antt/gn/v20190815/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_185001-186912.nc c027154d3ef3962584d48e603638754c59f8bb106923cd8523a08db5be67f2a0
4
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/fco2antt/gn/v20190815/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_187001-188912.nc a550c2c36e620eafadba06a6e6f80ff231481b23eb225d9c25874e50122107a9
5
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/fco2antt/gn/v20190815/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_189001-190912.nc 05734f60346b084873772e9b166c136fa5daf1338e8a5a15721e2834389c0cc6
6
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/fco2antt/gn/v20190815/fco2antt_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_191001-191412.nc 82bf8fbcfde0418b4ec95b14af9b653f9b654f748ca1d1deb6450c4ea4ef277c
7
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_185001-186912.nc f0dcb10542fc6b685238028a333f6255d22b630d588555a7691c26e213267033
8
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_187001-188912.nc b9cd82588c1a5be0a6eb9b54cb3f6699c9a0f39ce0ce87f59ea8a6ac76c16561
9
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_189001-190912.nc 5000371d6f31bab096119b000edd5be66b3dbe1b53962ccb01b3105ad449579a
10
+ CMIP6/C4MIP/MPI-M/MPI-ESM1-2-LR/esm-1pctCO2/r1i1p1f1/Amon/tas/gn/v20190815/tas_Amon_MPI-ESM1-2-LR_esm-1pctCO2_r1i1p1f1_gn_191001-191412.nc 9213e72eb6e1e77e7585313838ca245c8ab8f87829ad2e55ba9769df8dde0035
11
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/1pctCO2/r1i1p1f1/Amon/tas/gn/v20191115/tas_Amon_ACCESS-ESM1-5_1pctCO2_r1i1p1f1_gn_010101-025012.nc b995e36ed0a7d1748901d83359f8995e0d7bfeb1af05ee25e6a376815417ba85
12
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/1pctCO2/r1i1p1f1/fx/areacella/gn/v20191115/areacella_fx_ACCESS-ESM1-5_1pctCO2_r1i1p1f1_gn.nc f6b1dcf34a6de5c9c0c0743d1f3344923e476e3ad33d73d29da67163b6973d01
13
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/abrupt-4xCO2/r1i1p1f1/Amon/rlut/gn/v20191115/rlut_Amon_ACCESS-ESM1-5_abrupt-4xCO2_r1i1p1f1_gn_010101-012512.nc d02d4096c7cd1892e284a97d5009e109fce474c2c9e91e43f83ecc9519ae2ce5
14
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/abrupt-4xCO2/r1i1p1f1/Amon/rsdt/gn/v20191115/rsdt_Amon_ACCESS-ESM1-5_abrupt-4xCO2_r1i1p1f1_gn_010101-012512.nc 14cd0b3ce52c8e11c92cf24ffc70bda191a1da41b0004afdcfbd43d71730d10d
15
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/abrupt-4xCO2/r1i1p1f1/Amon/rsut/gn/v20191115/rsut_Amon_ACCESS-ESM1-5_abrupt-4xCO2_r1i1p1f1_gn_010101-012512.nc 85c6e81dc193b326646781e5b46d481fa720435b30adf40370a8dc0dd1c49714
16
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/abrupt-4xCO2/r1i1p1f1/Amon/tas/gn/v20191115/tas_Amon_ACCESS-ESM1-5_abrupt-4xCO2_r1i1p1f1_gn_010101-012512.nc 9469aca1a6d082ae052e0885207acd8b16859aad37d9e0a514c71c7b45419887
17
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/abrupt-4xCO2/r1i1p1f1/fx/areacella/gn/v20191115/areacella_fx_ACCESS-ESM1-5_abrupt-4xCO2_r1i1p1f1_gn.nc 78f79e91d0fa163e2744aa70c1ac89b8c878a2753ece016110563b6e3c4afd8b
18
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/pr/gn/v20191115/pr_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_185001-201412.nc 6696166383b0427476de40658f1d31666a28d9ec2334ffb68be49339e24f49bc
19
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/psl/gn/v20191115/psl_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 42c9e8f0d432fe634abab6fe3499854e19ae5ccaf5d70dba6e930aed4c8fd635
20
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rlut/gn/v20191115/rlut_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 019b61b1a05bfc06ef35a1b97e0544d242996c3c1d177ad9da6189e549af0e19
21
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rlutcs/gn/v20191115/rlutcs_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200501-201412.nc d639634716a12c0af933aa4cbd62edef8e2f1bbab454f3935ed0b1d91d384b63
22
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Amon/rsdt/gn/v20191115/rsdt_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc dd43eb17caf7082bcc18f31ecd756566466f7fc17ae86284985177ba0ac7d386
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
+ 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
+ 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/ts/gn/v20191115/ts_Amon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc b3b8e7675287471fd27f3de1f3ecada278eb7ea384da24031d0f3a949e04f757
27
+ 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
+ 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
+ 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
+ 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
+ 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-5_historical_r1i1p1f1_gn_200001-201412.nc 476b4ebacf38ddb78d44975b01d859e9ca3ed7955b92adc4bd098591867e56b0
33
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Ofx/areacello/gn/v20191115/areacello_Ofx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc fe5adde7cfe6d80462ad649fe68c2aa983ba700d96cff5ac830b1d7e7b09ca6f
34
+ 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
+ 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
+ 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-5_historical_r1i1p1f1_gn_197901-201412.nc a757237973708d28f2333542fc34ed9543a15256c7f38d0139fcfe66bdb8d95c
41
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/Omon/tos/gn/v20191115/tos_Omon_ACCESS-ESM1-5_historical_r1i1p1f1_gn_200001-201412.nc 701fa01ac2c50b622c3454bb3d69a54fed1c92b66f9194c09148b2349aa11342
42
+ 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
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/fx/areacella/gn/v20191115/areacella_fx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc 6750d4a2432842cb9342ef99b8ecb3569e8ff3dcbbf020f7f9f43a6f7af42f06
44
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r1i1p1f1/fx/sftlf/gn/v20191115/sftlf_fx_ACCESS-ESM1-5_historical_r1i1p1f1_gn.nc 08d84ba3cf02a2481b76611dfa1abe25cbf76326003eebc4eb00c99b32fea19a
45
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r2i1p1f1/Amon/psl/gn/v20191128/psl_Amon_ACCESS-ESM1-5_historical_r2i1p1f1_gn_200001-201412.nc 0344cf5babc7e3f827d66e1c41a9aaa89b52b6345381bf478146df44c7ec813e
46
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r2i1p1f1/Amon/ts/gn/v20191128/ts_Amon_ACCESS-ESM1-5_historical_r2i1p1f1_gn_200001-201412.nc e5dde58ae1b21c765d00dea5e6362c771f6945dcb62def864313c9756ed4b8db
47
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/historical/r2i1p1f1/fx/areacella/gn/v20191128/areacella_fx_ACCESS-ESM1-5_historical_r2i1p1f1_gn.nc 9a1df5675b2168b3da8e5537f339196ebb8eb73f2dbcf1431f5c269c46191f40
48
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/Amon/rlut/gn/v20210316/rlut_Amon_ACCESS-ESM1-5_piControl_r1i1p1f1_gn_010101-012512.nc a8bf35b4415b5d24971fb94f7a04b99ea3534157ea3c1995abf379bad82bbc83
49
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/Amon/rsdt/gn/v20210316/rsdt_Amon_ACCESS-ESM1-5_piControl_r1i1p1f1_gn_010101-012512.nc 158cea3284df26fa95851e22bdee4064b909ecd87e12acd52aec242df7171e49
50
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/Amon/rsut/gn/v20210316/rsut_Amon_ACCESS-ESM1-5_piControl_r1i1p1f1_gn_010101-012512.nc 5a8f026e4be636e51625a6b59e504de6ed2dfcfae1df8be60084fdf1d602fc1c
51
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/Amon/tas/gn/v20210316/tas_Amon_ACCESS-ESM1-5_piControl_r1i1p1f1_gn_010101-018012.nc e8705dda0c26cad086526d8e77f10a91707187e371d90f5ebb7feb4187cec2b4
52
+ CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl/r1i1p1f1/fx/areacella/gn/v20210316/areacella_fx_ACCESS-ESM1-5_piControl_r1i1p1f1_gn.nc c3f274b147fbcb7e7c6116a933a40993c4f2186952b8e8fd4ad8056326688887
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_185001-186912.nc 141a24094d42fe2bc0b765774905c192d77817620da273b7e7c789510d0891c9
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_187001-188912.nc 5f0dc6bee4c4eb12a05c532fb0ca08aaacbb869b43306c8b82f4bdd6adc661a4
55
+ 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
+ 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
+ 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
58
+ 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
+ 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
+ CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r1i1p1f1/fx/areacella/gn/v20200615/areacella_fx_ACCESS-ESM1-5_hist-GHG_r1i1p1f1_gn.nc 7179f75ff1754e9666b10f8c5508040bbe9fdac0c8117a9231ba5977d4889f27
61
+ CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r2i1p1f1/Amon/psl/gn/v20200615/psl_Amon_ACCESS-ESM1-5_hist-GHG_r2i1p1f1_gn_200001-202012.nc 2073711f1517b53f2670f939b3ad8c81f24ae8d022bd193157e173733eb19636
62
+ CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r2i1p1f1/Amon/ts/gn/v20200615/ts_Amon_ACCESS-ESM1-5_hist-GHG_r2i1p1f1_gn_200001-202012.nc dd8b8043a058454c6218d3895ffd12d3d8cfc2ccef485ece30c913ecc2244d57
63
+ CMIP6/DAMIP/CSIRO/ACCESS-ESM1-5/hist-GHG/r2i1p1f1/fx/areacella/gn/v20200615/areacella_fx_ACCESS-ESM1-5_hist-GHG_r2i1p1f1_gn.nc 6a25555c13d62859cb81f739f24398ae4f1dae60d495d8ada5f799411471985b
64
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/Amon/pr/gn/v20210318/pr_Amon_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn_201501-210012.nc 3650d30ce27d44a0564ee29fd5e4741a60fe7e91ea634f4f6896f3fc494c1cd7
65
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/Amon/rsdt/gn/v20210318/rsdt_Amon_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn_201501-202512.nc 9a04641b91da68be60e307cd1b3e6af72098ae09e5d16103910368314ebf6217
66
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/Amon/rsut/gn/v20210318/rsut_Amon_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn_201501-202512.nc 61aee51691b9e5b4a9d1189bdd59a8dd206ad5e8d554c5ea5e47827e0fd9216a
67
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/Amon/tas/gn/v20210318/tas_Amon_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn_201501-210012.nc b164b974798624b284ac83425fc02f42ae88d75071d76aa3b860253f527ce27f
68
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/Omon/tos/gn/v20210318/tos_Omon_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn_201501-202512.nc 8138c9e1d5ba641799b547b0867fa0068902c17b95277cd26bec1c7e91c7eb0c
69
+ CMIP6/ScenarioMIP/CSIRO/ACCESS-ESM1-5/ssp126/r1i1p1f1/fx/areacella/gn/v20210318/areacella_fx_ACCESS-ESM1-5_ssp126_r1i1p1f1_gn.nc 0b3daf08cacf722fe51e01dd106f0df2fa86b11764befcf26a55d2e670db74df
70
+ obs4REF/obs4REF/CNES/AVISO-1-0/mon/zos/gn/v20210727/zos_mon_AVISO-1-0_PCMDI_gn_199301-201912.nc 1b0a61ea75fbc12a0c8f5ed64c62ddd52c14b30a2873b4977584899c879b66c2
71
+ obs4REF/obs4REF/ECMWF/ERA-20C/mon/psl/gn/v20210727/psl_mon_ERA-20C_PCMDI_gn_190001-201012.nc a307849fa2ef38954400ecef089438400a98e2ba38806c36529ac4b7b91c11a5
72
+ obs4REF/obs4REF/ECMWF/ERA-20C/mon/ts/gn/v20210727/ts_mon_ERA-20C_PCMDI_gn_190001-201012.nc e75d22c2cd5077cc4ced12526f280248b3ab251b0995b830f2f6d716a165af3f
73
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/hfls/gn/v20210727/hfls_mon_ERA-INT_PCMDI_gn_197901-201903.nc c51b850dccfa4a95d4cbd9555a333aef6f6299191a5a6ccf5a8dec0b3ba389a4
74
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/hfss/gn/v20210727/hfss_mon_ERA-INT_PCMDI_gn_197901-201903.nc 11f12bb01d71a8d769099fff0f2ff41a2c01a967ce6ab5eb4ef4f691f669de80
75
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/hur/gn/v20210727/hur_mon_ERA-INT_PCMDI_gn_198901-201001.nc 06b9290fef6dbd9bd776a428429309aed88c32faf2ddae2c3076c817d22ca75b
76
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/hus/gn/v20210727/hus_mon_ERA-INT_PCMDI_gn_198901-201001.nc 97af286fe733dcf33144517034df92803b80057fecbda488a576a60515763d62
77
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/pr/gn/v20210727/pr_mon_ERA-INT_PCMDI_gn_197901-201903.nc 7f663506b2984a98b952efc0cae7c2165d5b201884480462672d219e1ac03c13
78
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/psl/gn/v20210727/psl_mon_ERA-INT_PCMDI_gn_197901-201903.nc 7b9e6aeafe4926fa2435fcf0f8cb0a4afcbfc9aa8db47187e21d5f280879e0ec
79
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/rlds/gn/v20210727/rlds_mon_ERA-INT_PCMDI_gn_197901-201903.nc d20e0f45fe49252982afbd281980764cac4d3d2aec93e6c18f0f88f30382397c
80
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/rlus/gn/v20210727/rlus_mon_ERA-INT_PCMDI_gn_197901-201903.nc ba7f248c2dd60f4ce52bb34390c133f2ff73f507476899c6430ba88fa0e92baf
81
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/rsds/gn/v20210727/rsds_mon_ERA-INT_PCMDI_gn_197901-201903.nc b37c38913868538c6ef1aed10c80c0492dc83cf897073c7bcfd820f716f69db1
82
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/rsus/gn/v20210727/rsus_mon_ERA-INT_PCMDI_gn_197901-201903.nc 4840ef8fdce03ed7397756d5cbc445949bfce2e64e4f469559eefc0acb0bfd53
83
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/sfcWind/gn/v20210727/sfcWind_mon_ERA-INT_PCMDI_gn_197901-201903.nc 0e96f90f858cdcd394a6c75c37bd5cf16f8629c46a7ff7e160141c216812eb4f
84
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/ta/gn/v20210727/ta_mon_ERA-INT_PCMDI_gn_198901-201001.nc d8024c2a148d9c096bb89a6ab7cf88a4857d6368bd87b3b2e8ec2d9e6f99259c
85
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/tauu/gn/v20210727/tauu_mon_ERA-INT_PCMDI_gn_197901-201903.nc a89e8f5bc93ceca4f73eaab3320836ec29396125ae66df2ba8f55053dd7127fe
86
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/tauv/gn/v20210727/tauv_mon_ERA-INT_PCMDI_gn_197901-201903.nc 6879b06537c0bb899171f26594e80a4e83b6c5ff70e4304811bf5f334f841a91
87
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/ts/gn/v20210727/ts_mon_ERA-INT_PCMDI_gn_197901-201903.nc f37fae9b17febbe259044c8652798a94ed50549603dbd2bd0d481c8838bc8f7d
88
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/ua/gn/v20210727/ua_mon_ERA-INT_PCMDI_gn_198901-201001.nc 988cc905d04e6aa0278d915dd1873242277fca5901c82b3e674e4775bfe71da7
89
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/uas/gn/v20210727/uas_mon_ERA-INT_PCMDI_gn_197901-201903.nc c104226c7c8cb3ba1c0a75e848eb1c4ad33f4337c283b96daf9a565ead018283
90
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/va/gn/v20210727/va_mon_ERA-INT_PCMDI_gn_198901-201001.nc 1549f008a6ee6a1d2c8b76f9094328acd296a220cc36e39eb40e4ec345db7785
91
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/vas/gn/v20210727/vas_mon_ERA-INT_PCMDI_gn_197901-201903.nc 366d6726c8e8f998a4c51eaf9e3905f915cd269171b491afaedf0581d28be2a5
92
+ obs4REF/obs4REF/ECMWF/ERA-INT/mon/zg/gn/v20210727/zg_mon_ERA-INT_PCMDI_gn_198901-201001.nc 60083418a6597e41d9d9b4f80f3731db2c93d065b4ed9113383470a3090943fc
93
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfls/gn/v20210727/hfls_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc c05111c9b0680c52b0f78a0f0603c204130d941527f079ba6c431c35b81d1b09
94
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfns/gn/v20210727/hfns_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc 0f47f55514cb6ac29d8903775cd5af197ccb828d3eb9403eb94c71bdc5a08fc4
95
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/hfss/gn/v20210727/hfss_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc 1fc71a0befc05e29295025b4f2a1d3030000991ce54ffd5e4e57b513af74f9f5
96
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tas/gn/v20210727/tas_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc 8ac0c77ebc9672401bebfc599b7535696eead0c75f4f40ffa735be802b5d6a62
97
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tauu/gn/v20210727/tauu_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc b073ed8f915064cf69daeb51d5c31b1167ca8f1ac1f5d4f324ecdfd5847827c6
98
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/tauv/gn/v20210727/tauv_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc f9b27f56e08dbccec19aa33ac70f1f04bd51eac4d1fa7554c237676b7a3411e2
99
+ obs4REF/obs4REF/ESSO/TropFlux-1-0/mon/ts/gn/v20210727/ts_mon_TropFlux-1-0_PCMDI_gn_197901-201707.nc 8c8857d8dca575d7b2e9cfd7130cfe6172d96e41614ed3666cbfbdb4af9fbdda
100
+ obs4REF/obs4REF/MOHC/HadISST-1-1/mon/ts/gn/v20210727/ts_mon_HadISST-1-1_PCMDI_gn_187001-201907.nc f5cc77d002cd90dc63c63a4db62863fcbf72763d02ae7ba743ff691fe3b10fe3
101
+ obs4REF/obs4REF/NASA-GSFC/TRMM-3B43v-7/mon/pr/gn/v20210727/pr_mon_TRMM-3B43v-7_PCMDI_gn_199801-201712.nc 5df3a5cb29bb08f317dda64bd3659d81c382d69c29d1325f461cbcb0272eb5bc
102
+ obs4REF/obs4REF/NOAA-ESRL-PSD/20CR/mon/psl/gn/v20210727/psl_mon_20CR_PCMDI_gn_187101-201212.nc 47c894191e9a9f62d4c455721ff6bf1a5ab1571082b5a08a2c52ff1240b77ac3
103
+ obs4REF/obs4REF/NOAA-ESRL-PSD/20CR/mon/ts/gn/v20210727/ts_mon_20CR_PCMDI_gn_187101-201212.nc c9a4a75c3df7c24e5662756a7ca8674af8275244ea9fe213384d1a1e41e1bbad
104
+ obs4REF/obs4REF/NOAA-NCEI/CMAP-V1902/mon/pr/gn/v20210727/pr_mon_CMAP-V1902_PCMDI_gn_197901-201901.nc 0a73fa7fef1f631321f2cb70a6aea12c9cc2a2ed00e6cb5d8c03618fe6c9f2ae
105
+ obs4REF/obs4REF/NOAA-NCEI/GPCP-2-3/mon/pr/gn/v20210727/pr_mon_GPCP-2-3_PCMDI_gn_197901-201907.nc dcca502f8748a73b0be5c6e402e14086f1d45e5c85be3cbbe63ba6c07ab0eb21
@@ -1,13 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import traceback
3
4
  import warnings
4
5
  from datetime import datetime
5
6
  from pathlib import Path
6
7
  from typing import Any
7
8
 
8
- import ecgtools.parsers
9
9
  import pandas as pd
10
+ import xarray as xr
10
11
  from ecgtools import Builder
12
+ from ecgtools.parsers.utilities import extract_attr_with_regex # type: ignore
13
+ from loguru import logger
11
14
 
12
15
  from climate_ref.datasets.base import DatasetAdapter
13
16
  from climate_ref.models.dataset import CMIP6Dataset
@@ -65,6 +68,88 @@ def _clean_branch_time(branch_time: pd.Series[str]) -> pd.Series[float]:
65
68
  return pd.to_numeric(branch_time.astype(str).str.replace("D", ""), errors="coerce")
66
69
 
67
70
 
71
+ def parse_cmip6(file: str) -> dict[str, Any]:
72
+ """
73
+ Parser for CMIP6
74
+
75
+ This function parses the CMIP6 dataset and returns a dictionary with the metadata.
76
+ This was copied from the ecgtools package, but we want to log the exception when it fails.
77
+ """
78
+ keys = sorted(
79
+ {
80
+ "activity_id",
81
+ "branch_method",
82
+ "branch_time_in_child",
83
+ "branch_time_in_parent",
84
+ "experiment",
85
+ "experiment_id",
86
+ "frequency",
87
+ "grid",
88
+ "grid_label",
89
+ "institution_id",
90
+ "nominal_resolution",
91
+ "parent_activity_id",
92
+ "parent_experiment_id",
93
+ "parent_source_id",
94
+ "parent_time_units",
95
+ "parent_variant_label",
96
+ "realm",
97
+ "product",
98
+ "source_id",
99
+ "source_type",
100
+ "sub_experiment",
101
+ "sub_experiment_id",
102
+ "table_id",
103
+ "variable_id",
104
+ "variant_label",
105
+ }
106
+ )
107
+
108
+ try:
109
+ with xr.open_dataset(file, chunks={}, use_cftime=True) as ds:
110
+ info = {key: ds.attrs.get(key) for key in keys}
111
+ info["member_id"] = info["variant_label"]
112
+
113
+ variable_id = info["variable_id"]
114
+ if variable_id: # pragma: no branch
115
+ attrs = ds[variable_id].attrs
116
+ for attr in ["standard_name", "long_name", "units"]:
117
+ info[attr] = attrs.get(attr)
118
+
119
+ # Set the default of # of vertical levels to 1
120
+ vertical_levels = 1
121
+ start_time, end_time = None, None
122
+ init_year = None
123
+ try:
124
+ vertical_levels = ds[ds.cf["vertical"].name].size
125
+ except (KeyError, AttributeError, ValueError):
126
+ ...
127
+
128
+ try:
129
+ start_time, end_time = str(ds.cf["T"][0].data), str(ds.cf["T"][-1].data)
130
+ except (KeyError, AttributeError, ValueError):
131
+ ...
132
+ if info.get("sub_experiment_id"): # pragma: no branch
133
+ init_year = extract_attr_with_regex(info["sub_experiment_id"], r"\d{4}")
134
+ if init_year: # pragma: no cover
135
+ init_year = int(init_year)
136
+ info["vertical_levels"] = vertical_levels
137
+ info["init_year"] = init_year
138
+ info["start_time"] = start_time
139
+ info["end_time"] = end_time
140
+ if not (start_time and end_time):
141
+ info["time_range"] = None
142
+ else:
143
+ info["time_range"] = f"{start_time}-{end_time}"
144
+ info["path"] = str(file)
145
+ info["version"] = extract_attr_with_regex(str(file), regex=r"v\d{4}\d{2}\d{2}|v\d{1}") or "v0"
146
+ return info
147
+
148
+ except Exception:
149
+ logger.exception(f"Failed to parse {file}")
150
+ return {"INVALID_ASSET": file, "TRACEBACK": traceback.format_exc()}
151
+
152
+
68
153
  class CMIP6DatasetAdapter(DatasetAdapter):
69
154
  """
70
155
  Adapter for CMIP6 datasets
@@ -171,7 +256,7 @@ class CMIP6DatasetAdapter(DatasetAdapter):
171
256
  depth=10,
172
257
  include_patterns=["*.nc"],
173
258
  joblib_parallel_kwargs={"n_jobs": self.n_jobs},
174
- ).build(parsing_func=ecgtools.parsers.parse_cmip6)
259
+ ).build(parsing_func=parse_cmip6) # type: ignore
175
260
 
176
261
  datasets: pd.DataFrame = builder.df.drop(["init_year"], axis=1)
177
262
 
@@ -133,24 +133,25 @@ def handle_execution_result(
133
133
  # execution.mark_failed()
134
134
 
135
135
  # Perform a bulk insert of scalar values
136
- # TODO: The section below will likely fail until we have agreed on a controlled vocabulary
137
136
  # The current implementation will swallow the exception, but display a log message
138
137
  try:
139
- # Perform this in a nested transaction to (hopefully) gracefully rollback if something
140
- # goes wrong
141
- with database.session.begin_nested():
142
- database.session.execute(
143
- insert(ScalarMetricValue),
144
- [
145
- {
146
- "execution_id": execution.id,
147
- "value": result.value,
148
- "attributes": result.attributes,
149
- **result.dimensions,
150
- }
151
- for result in cmec_metric_bundle.iter_results()
152
- ],
153
- )
138
+ scalar_values = [
139
+ {
140
+ "execution_id": execution.id,
141
+ "value": result.value,
142
+ "attributes": result.attributes,
143
+ **result.dimensions,
144
+ }
145
+ for result in cmec_metric_bundle.iter_results()
146
+ ]
147
+ if scalar_values:
148
+ # Perform this in a nested transaction to rollback if something goes wrong
149
+ # We will lose the metric values for a given execution, but not the whole execution
150
+ with database.session.begin_nested():
151
+ database.session.execute(
152
+ insert(ScalarMetricValue),
153
+ scalar_values,
154
+ )
154
155
  except Exception:
155
156
  # TODO: Remove once we have settled on a controlled vocabulary
156
157
  logger.exception("Something went wrong when ingesting diagnostic values")
@@ -34,9 +34,10 @@ def _register_provider(db: Database, provider: DiagnosticProvider) -> None:
34
34
  provider_model, created = db.get_or_create(
35
35
  Provider,
36
36
  slug=provider.slug,
37
- version=provider.version,
38
37
  defaults={
39
38
  "name": provider.name,
39
+ # TODO: Handle if this changes
40
+ "version": provider.version,
40
41
  },
41
42
  )
42
43
  if created:
@@ -49,6 +49,12 @@ class DiagnosticExecution:
49
49
  diagnostic: Diagnostic
50
50
  datasets: ExecutionDatasetCollection
51
51
 
52
+ def execution_slug(self) -> str:
53
+ """
54
+ Get a slug for the execution
55
+ """
56
+ return f"{self.diagnostic.full_slug()}/{self.dataset_key}"
57
+
52
58
  @property
53
59
  def dataset_key(self) -> str:
54
60
  """
@@ -290,12 +296,14 @@ class ExecutionSolver:
290
296
  yield from solve_executions(self.data_catalog, diagnostic, provider)
291
297
 
292
298
 
293
- def solve_required_executions(
299
+ def solve_required_executions( # noqa: PLR0913
294
300
  db: Database,
295
301
  dry_run: bool = False,
296
302
  solver: ExecutionSolver | None = None,
297
303
  config: Config | None = None,
298
304
  timeout: int = 60,
305
+ one_per_provider: bool = False,
306
+ one_per_diagnostic: bool = False,
299
307
  ) -> None:
300
308
  """
301
309
  Solve for executions that require recalculation
@@ -317,6 +325,9 @@ def solve_required_executions(
317
325
 
318
326
  executor = config.executor.build(config, db)
319
327
 
328
+ diagnostic_count = {}
329
+ provider_count = {}
330
+
320
331
  for potential_execution in solver.solve():
321
332
  # The diagnostic output is first written to the scratch directory
322
333
  definition = potential_execution.build_execution_definition(output_root=config.paths.scratch)
@@ -337,7 +348,6 @@ def solve_required_executions(
337
348
  .join(DiagnosticModel.provider)
338
349
  .filter(
339
350
  ProviderModel.slug == potential_execution.provider.slug,
340
- ProviderModel.version == potential_execution.provider.version,
341
351
  DiagnosticModel.slug == potential_execution.diagnostic.slug,
342
352
  )
343
353
  .one()
@@ -352,17 +362,35 @@ def solve_required_executions(
352
362
  },
353
363
  )
354
364
 
365
+ if diagnostic.provider.slug not in provider_count:
366
+ provider_count[diagnostic.provider.slug] = 0
367
+ if diagnostic.full_slug() not in diagnostic_count:
368
+ diagnostic_count[diagnostic.full_slug()] = 0
369
+
355
370
  if created:
356
- logger.info(
357
- f"Created new execution group: "
358
- f"{definition.key!r} for {potential_execution.diagnostic.full_slug()}"
359
- )
371
+ logger.info(f"Created new execution group: {potential_execution.execution_slug()!r}")
360
372
  db.session.flush()
361
373
 
374
+ # Check if we should run given the one_per_provider or one_per_diagnostic flags
375
+ one_of_check_failed = (
376
+ one_per_provider and provider_count.get(diagnostic.provider.slug, 0) > 0
377
+ ) or (one_per_diagnostic and diagnostic_count.get(diagnostic.full_slug(), 0) > 0)
378
+
379
+ logger.debug(
380
+ f"one_per_provider={one_per_provider}, one_per_diagnostic={one_per_diagnostic}, "
381
+ f"one_of_check_failed={one_of_check_failed}, diagnostic_count={diagnostic_count}, "
382
+ f"provider_count={provider_count}"
383
+ )
384
+
362
385
  if execution_group.should_run(definition.datasets.hash):
386
+ if (one_per_provider or one_per_diagnostic) and one_of_check_failed:
387
+ logger.info(
388
+ f"Skipping execution due to one-of check: {potential_execution.execution_slug()!r}"
389
+ )
390
+ continue
391
+
363
392
  logger.info(
364
- f"Running new execution for execution group: "
365
- f"{definition.key!r} for {potential_execution.diagnostic.full_slug()}"
393
+ f"Running new execution for execution group: {potential_execution.execution_slug()!r}"
366
394
  )
367
395
  execution = Execution(
368
396
  execution_group=execution_group,
@@ -379,5 +407,8 @@ def solve_required_executions(
379
407
  definition=definition,
380
408
  execution=execution,
381
409
  )
410
+
411
+ provider_count[diagnostic.provider.slug] += 1
412
+ diagnostic_count[diagnostic.full_slug()] += 1
382
413
  if timeout > 0:
383
414
  executor.join(timeout=timeout)
@@ -26,7 +26,7 @@ def _determine_test_directory() -> Path | None:
26
26
 
27
27
 
28
28
  TEST_DATA_DIR = _determine_test_directory()
29
- SAMPLE_DATA_VERSION = "v0.5.2"
29
+ SAMPLE_DATA_VERSION = "v0.6.0"
30
30
 
31
31
 
32
32
  def fetch_sample_data(force_cleanup: bool = False, symlink: bool = False) -> None:
@@ -3,7 +3,13 @@ import datetime
3
3
  import numpy as np
4
4
  import pandas as pd
5
5
 
6
- from climate_ref.datasets.cmip6 import CMIP6DatasetAdapter, _apply_fixes, _clean_branch_time, _parse_datetime
6
+ from climate_ref.datasets.cmip6 import (
7
+ CMIP6DatasetAdapter,
8
+ _apply_fixes,
9
+ _clean_branch_time,
10
+ _parse_datetime,
11
+ parse_cmip6,
12
+ )
7
13
 
8
14
 
9
15
  def test_parse_datetime():
@@ -16,6 +22,13 @@ def test_parse_datetime():
16
22
  )
17
23
 
18
24
 
25
+ def test_parse_exception():
26
+ result = parse_cmip6("missing_file")
27
+
28
+ assert result["INVALID_ASSET"] == "missing_file"
29
+ assert "TRACEBACK" in result
30
+
31
+
19
32
  def test_clean_branch_time():
20
33
  inp = pd.Series(["0D", "12", "12.0", "12.000", "12.0000", "12.00000", None, np.nan])
21
34
  exp = pd.Series([0.0, 12.0, 12.0, 12.0, 12.0, 12.0, np.nan, np.nan])