Skip to content

Commit 24d23cc

Browse files
authored
tests: align CMIP7 full integration params with baseline config (#492)
1 parent fec46b4 commit 24d23cc

1 file changed

Lines changed: 129 additions & 23 deletions

File tree

tests/integration/test_full_cmorisation.py

Lines changed: 129 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
from tempfile import gettempdir
2121

2222
import pytest
23+
import yaml
2324

2425
from access_moppy import ACCESS_ESM_CMORiser
26+
from access_moppy.utilities import _get_cmip7_to_cmip6_mapping
2527

2628
# Import the utility function from conftest
2729
from ..conftest import load_filtered_variables
@@ -51,6 +53,20 @@
5153
"CMIP7": "access_moppy.vocabularies.cmip7-cmor-tables.tables",
5254
}
5355

56+
CMIP7_REALM_TO_TABLE_FILE = {
57+
"atmos": "CMIP7_atmos.json",
58+
"ocean": "CMIP7_ocean.json",
59+
"seaIce": "CMIP7_seaIce.json",
60+
"aerosol": "CMIP7_aerosol.json",
61+
"land": "CMIP7_land.json",
62+
"landIce": "CMIP7_landIce.json",
63+
}
64+
65+
CMIP7_BASELINE_CONFIG_PATH = (
66+
Path(__file__).resolve().parents[2]
67+
/ "src/access_moppy/examples/batch_config_esm1-6_cmip7_baseline.yml"
68+
)
69+
5470

5571
def _get_cmor_table_path(cmip_version: str, cmor_table_file: str):
5672
"""Resolve a bundled CMOR table path for the requested CMIP family."""
@@ -166,12 +182,50 @@ def _generate_variable_test_params(
166182
return params
167183

168184

185+
@lru_cache(maxsize=1)
186+
def _load_cmip7_baseline_variables() -> tuple[str, ...]:
187+
"""Load the CMIP7 baseline variable list from the example batch config."""
188+
with CMIP7_BASELINE_CONFIG_PATH.open("r", encoding="utf-8") as config_file:
189+
payload = yaml.safe_load(config_file) or {}
190+
191+
variables = payload.get("variables", [])
192+
if not isinstance(variables, list):
193+
return tuple()
194+
195+
return tuple(
196+
str(variable).strip() for variable in variables if str(variable).strip()
197+
)
198+
199+
200+
def _generate_cmip7_baseline_test_params() -> list[tuple[str, str, str, str, str]]:
201+
"""Generate CMIP7 params directly from the baseline example config."""
202+
params: list[tuple[str, str, str, str, str]] = []
203+
204+
for cmip7_compound_name in _load_cmip7_baseline_variables():
205+
realm = cmip7_compound_name.split(".", 1)[0]
206+
cmor_table_file = CMIP7_REALM_TO_TABLE_FILE.get(realm)
207+
if cmor_table_file is None:
208+
continue
209+
210+
params.append(
211+
(
212+
realm,
213+
"ACCESS-ESM1-6",
214+
cmor_table_file,
215+
"CMIP7",
216+
cmip7_compound_name,
217+
)
218+
)
219+
220+
return params
221+
222+
169223
# Generate variable-level test parameters for granular control
170224
VARIABLE_TEST_PARAMS_CMIP6 = _generate_variable_test_params(tuple(CMOR_TABLES_CMIP6))
171225
VARIABLE_TEST_PARAMS_CMIP6PLUS = _generate_variable_test_params(
172226
tuple(CMOR_TABLES_CMIP6PLUS)
173227
)
174-
VARIABLE_TEST_PARAMS_CMIP7 = _generate_variable_test_params(tuple(CMOR_TABLES_CMIP7))
228+
VARIABLE_TEST_PARAMS_CMIP7 = _generate_cmip7_baseline_test_params()
175229

176230

177231
def _parametrize_test_ids(param_set: tuple) -> str:
@@ -187,6 +241,9 @@ def _parametrize_test_ids(param_set: tuple) -> str:
187241
return str(param_set)
188242

189243
table, model_id, cmor_table, cmip_version, variable = param_set
244+
if cmip_version == "CMIP7" and variable.count(".") >= 3:
245+
return variable
246+
190247
suffix = ""
191248
if cmip_version == "CMIP7":
192249
suffix = "-cmip7"
@@ -257,21 +314,41 @@ def _get_input_files_for_compound(
257314
# exposed through the Omon table in CMIP7 mappings.
258315
return None
259316

260-
if table_name == "Omon":
317+
if table_name in {"Omon", "Oday"}:
261318
# For ocean variables, use only configured external ocean files.
262319
data_root = self._configured_data_root()
263320
if data_root is None:
264321
return []
265322

266323
try:
267-
ocean_files = get_monthly_ocean_files(
268-
compound_name,
269-
model_id=model_id,
270-
root_folder=str(data_root),
271-
target_folders=OCEAN_TARGET_FOLDERS,
272-
)
273-
if ocean_files:
274-
return [Path(f) for f in ocean_files]
324+
if table_name == "Omon":
325+
ocean_files = get_monthly_ocean_files(
326+
compound_name,
327+
model_id=model_id,
328+
root_folder=str(data_root),
329+
target_folders=OCEAN_TARGET_FOLDERS,
330+
)
331+
if ocean_files:
332+
return [Path(f) for f in ocean_files]
333+
else:
334+
from access_moppy.utilities import load_model_mappings
335+
336+
_, variable_name = compound_name.split(".", 1)
337+
mapping = load_model_mappings(compound_name, model_id=model_id)
338+
model_variables = mapping.get(variable_name, {}).get(
339+
"model_variables", []
340+
)
341+
342+
daily_ocean_files: set[Path] = set()
343+
for model_variable in model_variables:
344+
daily_ocean_files.update(
345+
data_root.glob(
346+
f"output*/ocean/*-{model_variable}-1daily-mean*.nc"
347+
)
348+
)
349+
350+
if daily_ocean_files:
351+
return sorted(daily_ocean_files)
275352
except Exception:
276353
pass
277354
return []
@@ -282,6 +359,19 @@ def _get_input_files_for_compound(
282359
)
283360
return external_files
284361

362+
if table_name == "SIday":
363+
external_files = self._discover_external_files(
364+
"ice/iceh-1daily-mean_*.nc", max_files=2
365+
)
366+
return external_files
367+
368+
if "1hr" in table_name.lower():
369+
# Use hourly files for 1hr tables
370+
external_files = self._discover_external_files(
371+
"atmosphere/netCDF/*_1hr.nc", max_files=2
372+
)
373+
return external_files
374+
285375
if "3hr" in table_name.lower():
286376
# Use 3-hourly files for 3hr tables
287377
external_files = self._discover_external_files(
@@ -415,23 +505,38 @@ def _run_cmorisation_variable(
415505
"""
416506
# Map CMIP7 table names to CMIP6 equivalents if needed
417507
compound_table = table_name
508+
cmor_name = variable_name
509+
compound_name = f"{compound_table}.{variable_name}"
510+
input_lookup_compound = compound_name
511+
418512
if cmip_version == "CMIP7":
419-
cmip7_to_cmip6_table = {
420-
"atmos": "Amon",
421-
"ocean": "Omon",
422-
"seaIce": "SImon",
423-
"aerosol": "AERmon",
424-
"land": "Lmon",
425-
}
426-
compound_table = cmip7_to_cmip6_table.get(table_name, table_name)
513+
if variable_name.count(".") >= 3:
514+
compound_name = variable_name
515+
cmip6_equivalent = _get_cmip7_to_cmip6_mapping(compound_name)
516+
if cmip6_equivalent is None:
517+
pytest.skip(f"No CMIP7->CMIP6 mapping found for {compound_name}")
518+
519+
input_lookup_compound = cmip6_equivalent
520+
compound_table, cmor_name = cmip6_equivalent.split(".", 1)
521+
else:
522+
cmip7_to_cmip6_table = {
523+
"atmos": "Amon",
524+
"ocean": "Omon",
525+
"seaIce": "SImon",
526+
"aerosol": "AERmon",
527+
"land": "Lmon",
528+
}
529+
compound_table = cmip7_to_cmip6_table.get(table_name, table_name)
530+
compound_name = f"{compound_table}.{variable_name}"
531+
input_lookup_compound = compound_name
532+
cmor_name = variable_name
427533

428534
# Skip ocean tests if ocean data is not available
429-
if compound_table == "Omon" and not self._ocean_data_available():
535+
if compound_table in {"Omon", "Oday"} and not self._ocean_data_available():
430536
pytest.skip(f"Ocean data directory not available; set {DATA_ROOT_ENV_VAR}")
431537

432-
compound_name = f"{compound_table}.{variable_name}"
433538
input_files = self._get_input_files_for_compound(
434-
compound_name, model_id=model_id
539+
input_lookup_compound, model_id=model_id
435540
)
436541

437542
# Skip if required files don't exist.
@@ -452,8 +557,9 @@ def _run_cmorisation_variable(
452557
"parent_source_id": model_id,
453558
"parent_mip_era": cmip_version,
454559
}
560+
safe_var_name = compound_name.replace(".", "_").replace("-", "_")
455561
output_dir = (
456-
Path(gettempdir()) / f"cmor_output_{compound_table}_{variable_name}"
562+
Path(gettempdir()) / f"cmor_output_{compound_table}_{safe_var_name}"
457563
)
458564
drs_enabled = compliance_validation_tool == "wcrp"
459565

@@ -491,7 +597,7 @@ def _run_cmorisation_variable(
491597

492598
self._validate_output_compliance(
493599
output_files[0],
494-
variable_name,
600+
cmor_name,
495601
table_path,
496602
cmip_version,
497603
compliance_validation_tool,

0 commit comments

Comments
 (0)