Skip to content

Commit 30c2cee

Browse files
forsyth2xylar
andauthored
Add mpas_analysis_subsection parameter to global_time_series (#788)
* Add mpas_analysis_subsection parameter to global_time_series * Allow multiple mpas_analysis subsections * Fix mpas_analysis status file names. We need to use the climatology and time series bounds from that analysis, rather than from global time series, to construct their filenames. To make this easier and better share code, the bulk of this work happens in the mpas_analysis module, not in global_time_series. * Add unit tests to ensure correct status filenames * Add comparison_type subdir * Put mpas_analysis runs in mvo or mvm subdirs This requires having a way for a user to specify whether an external reference run (not defined in a given config file as a subsection) was `mvo` or `mvm` via a new `reference_comparison_type` config option. * Update the docs with reference_comparison_type, etc. * Update auto-generated files --------- Co-authored-by: Xylar Asay-Davis <xylarstorm@gmail.com>
1 parent 016d220 commit 30c2cee

File tree

11 files changed

+466
-58
lines changed

11 files changed

+466
-58
lines changed

docs/source/parameters.rst

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ For the ``mpas_analysis`` task:
7676
* ``reference_data_path`` and ``test_data_path`` are optional and are only used for model-vs-model comparisons.
7777
If provided, ``zppy`` uses them to locate the MPAS-Analysis config files from a *previous* MPAS-Analysis run and passes those through to MPAS-Analysis as ``controlRunConfigFile`` (reference) and ``mainRunConfigFile`` (test).
7878

79+
The comparison type of the *current* MPAS-Analysis run is inferred implicitly:
80+
if ``reference_data_path`` is set, the run is treated as model-vs-model (``mvm``);
81+
otherwise it is treated as model-vs-observations (``mvo``). Users normally do
82+
not need to set a comparison type for the current run.
83+
7984
.. note::
8085
These parameter names are intentionally consistent with the terminology used by ``e3sm_diags`` for model-vs-model runs: in both cases, ``reference_data_path`` identifies the *reference simulation's zppy-generated outputs*.
8186

@@ -84,7 +89,16 @@ For the ``mpas_analysis`` task:
8489
For MPAS-Analysis, ``zppy`` resolves the config file when ``reference_data_path`` points to the prior run's zppy output directory (the one containing ``post/``).
8590

8691
``reference_data_path`` is intended to point to the prior run's zppy output directory (the one containing ``post/``). ``zppy`` will then use:
87-
``<reference_data_path>/post/analysis/mpas_analysis/cfg/mpas_analysis_<identifier>.cfg`` (or ``mpas_analysis_mvm`` if the referenced run was MVM).
92+
``<reference_data_path>/post/analysis/mpas_analysis/<comparison_type>/cfg/mpas_analysis_<identifier>.cfg``
93+
where ``<comparison_type>`` is ``mvo`` or ``mvm``.
94+
95+
For referenced prior runs, ``reference_comparison_type`` and
96+
``test_comparison_type`` can be set to ``"auto"``, ``"mvo"``, or ``"mvm"``.
97+
The default is ``"auto"``. In auto mode:
98+
99+
* if the path points to ``[[subsection]]``, zppy uses the referenced subsection's actual comparison type
100+
* if the path points to an external zppy output directory, zppy looks for the matching cfg under ``mvo`` and ``mvm``
101+
* if both exist for the same identifier, zppy raises an error and the user should set ``reference_comparison_type`` or ``test_comparison_type`` explicitly
88102

89103
When ``reference_data_path`` is set to a non-subsection path, ``reference_case`` is required so the MVM output directory can include the reference case name. If ``reference_data_path`` is set to ``[[subsection]]``, ``reference_case`` is inferred to be the same as the current ``case``.
90104

@@ -132,4 +146,4 @@ In ``e3sm_diags.py``:
132146
* ``check_mvm_only_parameters_for_bash``: similar, but these are specifically parameters used for model-vs-model runs. Uses ``check_parameter_defined`` in addition to ``check_set_specific_parameter``.
133147
* ``check_and_define_parameters``: make sure all parameters are defined, using ``utils.py get_value_from_parameter``, ``utils.py set_value_of_parameter_if_undefined``, and ``check_mvm_only_parameters_for_bash``.
134148

135-
``check_parameters_for_bash`` can be run immediately for each subtask because it has very few conditions. Other checks are included in ``check_and_define_parameters`` later on in the code.
149+
``check_parameters_for_bash`` can be run immediately for each subtask because it has very few conditions. Other checks are included in ``check_and_define_parameters`` later on in the code.

docs/source/post.mpas_analysis_model_vs_model.cfg

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ enso_years = "1850-2014",
2222

2323
# Point at a *previous zppy run output directory* for the reference simulation.
2424
# zppy will locate the matching MPAS-Analysis cfg file under:
25-
# <reference_data_path>/post/analysis/mpas_analysis/cfg/
25+
# <reference_data_path>/post/analysis/mpas_analysis/<comparison_type>/cfg/
2626
reference_data_path = <reference zppy output directory>
2727

28+
# Optional: override how zppy resolves the referenced prior run.
29+
# Usually "auto" is sufficient. Set this only if both mvo and mvm outputs exist
30+
# for the same year range under the referenced run.
31+
# reference_comparison_type = "auto"
32+
2833
# Required when reference_data_path is not a [[subsection]].
2934
# Used to build the MVM output directory name.
3035
reference_case = <reference case name>
@@ -34,6 +39,7 @@ reference_case = <reference case name>
3439
# If set to [[subsection]], zppy will use that subsection's year ranges
3540
# when ts_years/climo_years/enso_years are not provided.
3641
# test_data_path = <test zppy output directory>
42+
# test_comparison_type = "auto"
3743

3844
# Optional: override the reference year ranges (defaults to the test ranges).
3945
# If reference_data_path points to a prior [mpas_analysis] subsection using

docs/source/tutorial.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ Unlike ``e3sm_diags`` (where ``run_type = "model_vs_model"`` and ``reference_dat
7474
points directly at reference climatology output), MPAS-Analysis comparisons are driven
7575
by MPAS-Analysis config files. For model-vs-model mode, ``zppy`` locates the matching
7676
config file(s) from prior MPAS-Analysis output and passes them to MPAS-Analysis.
77+
The current run's type is inferred automatically: setting ``reference_data_path``
78+
makes it an ``mvm`` run, otherwise it is an ``mvo`` run. If a referenced prior
79+
run could resolve to either ``mvo`` or ``mvm``, use ``reference_comparison_type``
80+
or ``test_comparison_type`` to disambiguate.
7781

7882
.. literalinclude:: post.mpas_analysis_model_vs_model.cfg
7983
:language: cfg

tests/integration/generated/test_weekly_comprehensive_v3_chrysalis.cfg

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,24 +284,36 @@ tc_obs = "/lcrc/group/e3sm/diagnostics/observations/Atm/tc-analysis/"
284284
[mpas_analysis]
285285
active = True
286286
anomalyRefYear = 1985
287-
climo_years = "1985-1989", "1990-1995",
288-
enso_years = "1985-1989", "1990-1995",
289287
environment_commands = "source <INSERT PATH TO CONDA>/conda.sh; conda activate <INSERT ENV NAME>"
290288
mesh = "IcoswISC30E3r5"
291289
parallelTaskCount = 6
292290
partition = "compute"
293291
qos = "regular"
294292
shortTermArchive = True
295-
ts_years = "1985-1989", "1985-1995",
296293
walltime = "00:30:00"
297294

295+
[[ reference ]]
296+
ts_years = "1985-1989",
297+
climo_years = "1985-1989",
298+
enso_years = "1985-1989",
299+
300+
[[ test ]]
301+
ts_years = "1985-1995",
302+
climo_years = "1990-1995",
303+
enso_years = "1990-1995",
304+
305+
[[ mvm ]]
306+
reference_data_path = [[ reference ]]
307+
test_data_path = [[ test ]]
308+
298309
[global_time_series]
299310
active = True
300311
climo_years = "1985-1989", "1990-1995",
301312
environment_commands = "source <INSERT PATH TO CONDA>/conda.sh; conda activate <INSERT ENV NAME>"
302313
experiment_name = "v3.LR.historical_0051"
303314
figstr = "v3.LR.historical_0051"
304315
#moc_file=mocTimeSeries_1985-1995.nc
316+
mpas_analysis_subsections = "reference", "test",
305317
# plots_lnd = "FSH,RH2M,LAISHA,LAISUN,QINTR,QOVER,QRUNOFF,QSOIL,QVEGE,QVEGT,SOILWATER_10CM,TSA,H2OSNO,TOTLITC,CWDC,SOIL1C,SOIL2C,SOIL3C,SOIL4C,WOOD_HARVESTC,TOTVEGC,NBP,GPP,AR,HR"
306318
ts_num_years = 5
307319
ts_years = "1985-1989", "1985-1995",

tests/integration/image_checker.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,7 @@ def _check_mismatched_images(
185185
print(f"Reading expected images file {parameters.expected_images_list}")
186186
for line in f:
187187
image_name = line.strip("./").strip("\n")
188-
proceed = False
189-
if image_name.startswith(prefix):
190-
proceed = True
191-
if proceed:
188+
if image_name.startswith(f"{prefix}/"):
192189
counter += 1
193190
if counter % 250 == 0:
194191
print("On line #", counter)

tests/integration/template_weekly_comprehensive_v3.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ environment_commands = "#expand global_time_series_environment_commands#"
313313
experiment_name = "#expand case_name#"
314314
figstr = "#expand case_name#"
315315
#moc_file=mocTimeSeries_1985-1995.nc
316+
mpas_analysis_subsections = "reference", "test",
316317
# plots_lnd = "FSH,RH2M,LAISHA,LAISUN,QINTR,QOVER,QRUNOFF,QSOIL,QVEGE,QVEGT,SOILWATER_10CM,TSA,H2OSNO,TOTLITC,CWDC,SOIL1C,SOIL2C,SOIL3C,SOIL4C,WOOD_HARVESTC,TOTVEGC,NBP,GPP,AR,HR"
317318
ts_num_years = 5
318319
ts_years = "1985-1989", "1985-1995",

tests/test_zppy_global_time_series.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
import os
12
from typing import Any, Dict, List
23

34
import pytest
5+
from configobj import ConfigObj
6+
from validate import Validator
47

58
from zppy.global_time_series import determine_and_add_dependencies, determine_components
9+
from zppy.mpas_analysis import (
10+
_get_referenced_comparison_type,
11+
_resolve_mpas_analysis_config_file,
12+
get_mpas_analysis_prefixes,
13+
)
614

715

816
def test_determine_components():
@@ -123,6 +131,28 @@ def test_determine_and_add_dependencies():
123131
expected = ["script_dir/mpas_analysis_ts_1980-1989_climo_1980-1989.status"]
124132
assert dependencies == expected
125133

134+
c = {
135+
"use_atm": False,
136+
"use_lnd": False,
137+
"use_ocn": True,
138+
"mpas_analysis_subsections": ["reference", "test"],
139+
}
140+
dependencies = []
141+
determine_and_add_dependencies(
142+
c,
143+
dependencies,
144+
"script_dir",
145+
mpas_analysis_prefixes={
146+
"reference": ["mpas_analysis_reference_ts_1980-1989_climo_1980-1989"],
147+
"test": ["mpas_analysis_test_ts_1980-1999_climo_1990-1999"],
148+
},
149+
)
150+
expected = [
151+
"script_dir/mpas_analysis_reference_ts_1980-1989_climo_1980-1989.status",
152+
"script_dir/mpas_analysis_test_ts_1980-1999_climo_1990-1999.status",
153+
]
154+
assert dependencies == expected
155+
126156
c = {
127157
"use_atm": False,
128158
"use_lnd": False,
@@ -144,3 +174,157 @@ def test_determine_and_add_dependencies():
144174
dependencies = []
145175
with pytest.raises(Exception):
146176
determine_and_add_dependencies(c, dependencies, "script_dir")
177+
178+
c = {
179+
"use_atm": False,
180+
"use_lnd": False,
181+
"use_ocn": True,
182+
"mpas_analysis_subsections": ["missing"],
183+
}
184+
dependencies = []
185+
with pytest.raises(ValueError):
186+
determine_and_add_dependencies(
187+
c,
188+
dependencies,
189+
"script_dir",
190+
mpas_analysis_prefixes={
191+
"reference": ["mpas_analysis_reference_ts_1980-1989_climo_1980-1989"]
192+
},
193+
)
194+
195+
196+
def test_get_mpas_analysis_prefixes(tmp_path):
197+
config_path = tmp_path / "mpas_analysis.cfg"
198+
config_path.write_text(
199+
"""
200+
[default]
201+
case = "case_name"
202+
input = "input_dir"
203+
output = "output_dir"
204+
www = "www_dir"
205+
206+
[mpas_analysis]
207+
active = True
208+
mesh = "EC30to60E2r2"
209+
210+
[[ reference ]]
211+
ts_years = "1985-1989",
212+
climo_years = "1985-1989",
213+
enso_years = "1985-1989",
214+
215+
[[ test ]]
216+
ts_years = "1985-1995",
217+
climo_years = "1990-1995",
218+
enso_years = "1990-1995",
219+
220+
[[ mvm ]]
221+
reference_data_path = [[ reference ]]
222+
test_data_path = [[ test ]]
223+
""".strip()
224+
)
225+
226+
config = ConfigObj(
227+
str(config_path), configspec=os.path.join("zppy", "defaults", "default.ini")
228+
)
229+
validator = Validator()
230+
assert config.validate(validator)
231+
232+
prefixes = get_mpas_analysis_prefixes(config)
233+
234+
assert prefixes == {
235+
"reference": ["mpas_analysis_reference_ts_1985-1989_climo_1985-1989"],
236+
"test": ["mpas_analysis_test_ts_1985-1995_climo_1990-1995"],
237+
"mvm": [
238+
"mpas_analysis_mvm_ts_1985-1995_climo_1990-1995_vs_ref_ts_1985-1989_climo_1985-1989"
239+
],
240+
}
241+
242+
243+
def test_resolve_mpas_analysis_config_file_uses_comparison_type(tmp_path):
244+
config_file = _resolve_mpas_analysis_config_file(
245+
str(tmp_path), "ts_1985-1989_climo_1985-1989", comparison_type="mvm"
246+
)
247+
248+
assert config_file == os.path.join(
249+
str(tmp_path.resolve()),
250+
"post",
251+
"analysis",
252+
"mpas_analysis",
253+
"mvm",
254+
"cfg",
255+
"mpas_analysis_ts_1985-1989_climo_1985-1989.cfg",
256+
)
257+
258+
259+
def test_get_referenced_comparison_type_infers_from_subsection():
260+
comparison_type = _get_referenced_comparison_type(
261+
"auto",
262+
"/unused",
263+
"reference",
264+
"ts_1985-1989_climo_1985-1989",
265+
{"reference": "mvm"},
266+
"reference_data_path",
267+
)
268+
269+
assert comparison_type == "mvm"
270+
271+
272+
def test_get_referenced_comparison_type_raises_on_subsection_mismatch():
273+
with pytest.raises(ValueError, match="which is a mvo run, not mvm"):
274+
_get_referenced_comparison_type(
275+
"mvm",
276+
"/unused",
277+
"reference",
278+
"ts_1985-1989_climo_1985-1989",
279+
{"reference": "mvo"},
280+
"reference_data_path",
281+
)
282+
283+
284+
def test_get_referenced_comparison_type_auto_prefers_mvo_if_cfg_missing(tmp_path):
285+
comparison_type = _get_referenced_comparison_type(
286+
"auto",
287+
str(tmp_path),
288+
"",
289+
"ts_1985-1989_climo_1985-1989",
290+
{},
291+
"reference_data_path",
292+
)
293+
294+
assert comparison_type == "mvo"
295+
296+
297+
def test_get_referenced_comparison_type_auto_detects_mvm(tmp_path):
298+
cfg_dir = tmp_path / "post" / "analysis" / "mpas_analysis" / "mvm" / "cfg"
299+
cfg_dir.mkdir(parents=True)
300+
(cfg_dir / "mpas_analysis_ts_1985-1989_climo_1985-1989.cfg").write_text("")
301+
302+
comparison_type = _get_referenced_comparison_type(
303+
"auto",
304+
str(tmp_path),
305+
"",
306+
"ts_1985-1989_climo_1985-1989",
307+
{},
308+
"reference_data_path",
309+
)
310+
311+
assert comparison_type == "mvm"
312+
313+
314+
def test_get_referenced_comparison_type_auto_raises_if_ambiguous(tmp_path):
315+
for comparison_type in ["mvo", "mvm"]:
316+
cfg_dir = (
317+
tmp_path / "post" / "analysis" / "mpas_analysis" / comparison_type / "cfg"
318+
)
319+
cfg_dir.mkdir(parents=True, exist_ok=True)
320+
(cfg_dir / "mpas_analysis_ts_1985-1989_climo_1985-1989.cfg").write_text("")
321+
322+
with pytest.raises(ValueError, match="reference_comparison_type"):
323+
_get_referenced_comparison_type(
324+
"auto",
325+
str(tmp_path),
326+
"",
327+
"ts_1985-1989_climo_1985-1989",
328+
{},
329+
"reference_data_path",
330+
)

zppy/defaults/default.ini

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,16 @@ enso_years = string_list(default=list(""))
327327
# Set these to the output directory of a prior zppy run (the one containing post/),
328328
# or to [[ subsection ]] to refer to a previous mpas_analysis subsection in this workflow.
329329
# zppy will use:
330-
# <output>/post/analysis/mpas_analysis/cfg/mpas_analysis_<identifier>.cfg
331-
# (or <output>/post/analysis/mpas_analysis_mvm/cfg/ if the referenced run was MVM)
330+
# <output>/post/analysis/mpas_analysis/<comparison_type>/cfg/mpas_analysis_<identifier>.cfg
332331
# where <identifier> matches each MPAS-Analysis sub-run (e.g. ts_1850-2014_climo_1985-2014).
332+
# comparison_type for the current run is inferred implicitly:
333+
# if reference_data_path is set, it is an mvm run; otherwise it is an mvo run.
334+
# These options are only for resolving referenced prior runs. In auto mode, zppy
335+
# prefers mvo unless it finds only mvm; if both exist, it raises an error.
333336
reference_data_path = string(default="")
334337
test_data_path = string(default="")
338+
reference_comparison_type = option("auto", "mvo", "mvm", default="auto")
339+
test_comparison_type = option("auto", "mvo", "mvm", default="auto")
335340
# Required when reference_data_path is set to a non-subsection path.
336341
# If reference_data_path is set to [[subsection]], reference_case is inferred
337342
# to be the same as the current case.
@@ -370,6 +375,8 @@ walltime = string(default="06:00:00")
370375
enso_years = string_list(default=None)
371376
reference_data_path = string(default=None)
372377
test_data_path = string(default=None)
378+
reference_comparison_type = option("auto", "mvo", "mvm", default=None)
379+
test_comparison_type = option("auto", "mvo", "mvm", default=None)
373380
reference_case = string(default=None)
374381
ref_ts_years = string_list(default=None)
375382
ref_climo_years = string_list(default=None)
@@ -408,6 +415,9 @@ ts_years = string_list(default=list(""))
408415
# NOTE: always overrides value in [default]
409416
input_subdir = string(default="archive/ocn/hist")
410417
moc_file = string(default="")
418+
# Name of the `[mpas_analysis]` subtasks to depend on
419+
# Leave empty if no subtasks are defined for mpas_analysis
420+
mpas_analysis_subsections = string_list(default=list(""))
411421
# nrows, ncols are DEPRECATED. Specifying them will have no effect.
412422
# Number of columns per page
413423
ncols = integer(default=2)
@@ -441,6 +451,7 @@ plots_ocn = string(default="")
441451
input_subdir = string(default=None)
442452
make_viewer = boolean(default=None)
443453
moc_file = string(default=None)
454+
mpas_analysis_subsections = string_list(default=None)
444455
ncols = integer(default=None)
445456
nrows = integer(default=None)
446457
plots_original = string(default=None)

0 commit comments

Comments
 (0)