Skip to content

Commit 07e4186

Browse files
committed
Manual Merge with Both Options
2 parents 393442a + c362f49 commit 07e4186

19 files changed

+1363
-129
lines changed

ProConPy/config_var.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ def update_options_validities(self):
334334

335335
return validities_changed
336336

337+
@property
338+
def valid_options(self):
339+
"""Returns the list of valid options for this variable."""
340+
return [opt for opt in self._options if self._options_validities.get(opt, False)]
341+
337342
def _refresh_widget_options(self):
338343
"""Refresh the widget options list based on information in the current self._options_validities."""
339344

ProConPy/stage.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def _proceed(self):
352352
return
353353

354354
# Display the child stage and its siblings by appending them to the current stage's widget
355-
if self.has_children():
355+
if self.has_children() and next_stage.is_descendant_of(self):
356356
self._widget.add_child_stages(first_child=next_stage)
357357

358358
# Proceed the csp solver before enabling the next stage
@@ -378,20 +378,24 @@ def get_next(self, full_dfs=False):
378378
The next stage to visit, if found. Otherwise, None.
379379
"""
380380

381-
if self.has_children():
382-
return self._get_child_to_enable(full_dfs)
383-
elif self._right is not None:
381+
# First try to get a child stage to enable
382+
if (child_to_enable := self._get_child_to_enable(full_dfs)) is not None:
383+
return child_to_enable
384+
385+
# No child stage to enable. Try to get the right sibling.
386+
if self._right is not None:
384387
return self._right
385-
else: # Backtrack
386-
ancestor = self._parent
387-
while ancestor is not None:
388-
if ancestor._right is not None and (
389-
full_dfs or not ancestor.has_condition()
390-
):
391-
return ancestor._right
392-
else:
393-
ancestor = ancestor._parent
394-
return None
388+
389+
# No child or right sibling. Backtrack to find the next stage.
390+
ancestor = self._parent
391+
while ancestor is not None:
392+
if ancestor._right is not None and (
393+
full_dfs or not ancestor.has_condition()
394+
):
395+
return ancestor._right
396+
else:
397+
ancestor = ancestor._parent
398+
return None
395399

396400
def _get_child_to_enable(self, full_dfs):
397401
"""Determine the child stage to activate.
@@ -401,6 +405,9 @@ def _get_child_to_enable(self, full_dfs):
401405
full_dfs : bool
402406
If True, visit all the stages in the stage tree. Otherwise, skip stages whose guards
403407
are not satisfied."""
408+
409+
if self.has_children() is False:
410+
return None
404411

405412
child_to_activate = None
406413

@@ -412,18 +419,19 @@ def _get_child_to_enable(self, full_dfs):
412419
child_to_activate is None
413420
), "Only one child stage can be activated at a time."
414421
child_to_activate = child
422+
423+
if child_to_activate is None:
424+
# No child guard's condition is satisfied.
425+
# Let the caller handle this case (by backtracking).
426+
return None
415427
else:
416428
# If children are not guards, the first child is activated.
417429
# Note the remaining children will be activated in sequence by their siblings.
418430
child_to_activate = self._children[0]
419431

420432
# If the child to activate is a Guard, return it's first child
421433
if child_to_activate.has_condition():
422-
return child_to_activate._children[0]
423-
424-
assert (
425-
child_to_activate is not None
426-
), "At least one child stage must be activated."
434+
child_to_activate = child_to_activate._children[0]
427435

428436
return child_to_activate
429437

environment.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ channels:
66

77
dependencies:
88
- python>=3.11.10,<3.12
9-
#- xesmf
9+
- libxml2>=2.13,<2.14
10+
- xesmf>=0.8.10,<0.9
1011
- pip
1112
- pip:
1213
- -e ./external/mom6_bathy/

external/mom6_bathy

Submodule mom6_bathy updated 135 files
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env python3
2+
3+
import pytest
4+
import shutil
5+
import os
6+
from pathlib import Path
7+
import tempfile
8+
import time
9+
10+
from ProConPy.config_var import ConfigVar, cvars
11+
from ProConPy.stage import Stage
12+
from ProConPy.csp_solver import csp
13+
from visualCaseGen.cime_interface import CIME_interface
14+
from visualCaseGen.initialize_configvars import initialize_configvars
15+
from visualCaseGen.initialize_widgets import initialize_widgets
16+
from visualCaseGen.initialize_stages import initialize_stages
17+
from visualCaseGen.specs.options import set_options
18+
from visualCaseGen.specs.relational_constraints import get_relational_constraints
19+
from visualCaseGen.custom_widget_types.mom6_bathy_launcher import MOM6BathyLauncher
20+
from visualCaseGen.custom_widget_types.case_creator_widget import CaseCreatorWidget
21+
from tests.utils import safe_create_case
22+
23+
24+
# do not show logger output
25+
import logging
26+
27+
logger = logging.getLogger()
28+
logger.setLevel(logging.CRITICAL)
29+
30+
base_temp_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "temp"))
31+
32+
33+
def test_custom_compset_std_grid():
34+
"""Configure a custom compset with a standard grid: 2000_DATM%JRA_SLND_CICE%PRES_MOM6_SROF_SGLC_WW3. Progress through the stages
35+
until the launch stage is reached."""
36+
37+
ConfigVar.reboot()
38+
Stage.reboot()
39+
cime = CIME_interface()
40+
initialize_configvars(cime)
41+
initialize_widgets(cime)
42+
initialize_stages(cime)
43+
set_options(cime)
44+
csp.initialize(cvars, get_relational_constraints(cvars), Stage.first())
45+
46+
# At initialization, the first stage should be enabled
47+
assert Stage.first().enabled
48+
cvars['COMPSET_MODE'].value = 'Custom'
49+
50+
# CCOMPSET_MODE is the only variable in the first stage, so assigning a value to it should disable the first stage
51+
assert not Stage.first().enabled
52+
53+
# The next stge is Custom Component Set, whose first child is Model Time Period
54+
assert Stage.active().title.startswith('Time Period')
55+
cvars['INITTIME'].value = '1850'
56+
57+
cvars['COMP_OCN'].value = "mom"
58+
cvars['COMP_ICE'].value = "sice"
59+
cvars['COMP_ATM'].value = "cam"
60+
cvars['COMP_ROF'].value = "mosart"
61+
cvars['COMP_LND'].value = "clm"
62+
cvars['COMP_WAV'].value = "swav"
63+
cvars['COMP_GLC'].value = "sglc"
64+
65+
66+
assert Stage.active().title.startswith('Component Physics')
67+
68+
cvars['COMP_ATM_PHYS'].value = "CAM60"
69+
cvars['COMP_LND_PHYS'].value = "CLM60"
70+
71+
assert Stage.active().title.startswith('Component Options')
72+
73+
cvars['COMP_ATM_OPTION'].value = "1PCT"
74+
cvars['COMP_LND_OPTION'].value = "BGC"
75+
cvars['COMP_OCN_OPTION'].value = "(none)"
76+
cvars['COMP_ICE_OPTION'].value = "(none)"
77+
cvars['COMP_ROF_OPTION'].value = "(none)"
78+
79+
assert Stage.active().title.startswith('2. Grid')
80+
81+
cvars['GRID_MODE'].value = 'Standard'
82+
cvars['GRID'].value = 'f09_t232'
83+
84+
assert Stage.active().title.startswith('3. Launch')
85+
launch_stage = Stage.active()
86+
87+
with tempfile.TemporaryDirectory(dir=base_temp_dir) as temp_case_path:
88+
pass # immediately remove the random temporary directory,
89+
# which will become the caseroot directory below
90+
91+
cvars["CASEROOT"].value = temp_case_path
92+
93+
case_creator = launch_stage._widget._main_body.children[-1]
94+
assert isinstance(case_creator, CaseCreatorWidget)
95+
96+
cvars["PROJECT"].value = "12345"
97+
98+
# *Click* the create_case button
99+
safe_create_case(cime.srcroot, case_creator)
100+
101+
# sleep for a bit to allow the case to be created
102+
time.sleep(5)
103+
104+
# remove the caseroot directory
105+
shutil.rmtree(temp_case_path)
106+
107+

tests/3_system/test_custom_mom6_grid.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ def test_custom_mom6_grid():
141141
assert Stage.active().title.startswith("Simple Initial Conditions")
142142
cvars["T_REF"].value = 10.0
143143

144-
# Since land grid gets set automatically, we should be in the Launch stage:
144+
# Since land grid and runoff grid get set automatically, we should be in the runoff to ocn mapping:
145+
assert Stage.active().title.startswith("Runoff to Ocean Mapping")
146+
cvars["ROF_OCN_MAPPING_STATUS"].value = "skip"
147+
145148
assert Stage.active().title.startswith("3. Launch")
146149
launch_stage = Stage.active()
147150

tests/3_system/test_f2000_custom_grid.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ def construct_custom_res_from_std_grids(cime):
159159
assert Stage.active().title.startswith("Land Grid")
160160
cvars["CUSTOM_LND_GRID"].value = "0.9x1.25"
161161

162+
assert Stage.active().title.startswith("Runoff Grid")
163+
cvars["CUSTOM_ROF_GRID"].value = "r05"
164+
162165
assert Stage.active().title.startswith("3. Launch")
163166
launch_stage = Stage.active()
164167

@@ -248,6 +251,9 @@ def construct_custom_res_from_modified_clm_grid(cime):
248251
# click the "Run Surface Data Modifier" button
249252
fsurdat_modifier_launcher._on_launch_clicked(b=None)
250253

254+
assert Stage.active().title.startswith("Runoff Grid")
255+
cvars["CUSTOM_ROF_GRID"].value = "r05"
256+
251257
assert Stage.active().title.startswith("3. Launch")
252258
launch_stage = Stage.active()
253259

@@ -364,6 +370,9 @@ def construct_custom_res_from_new_mom6_grid_modified_clm_grid(cime):
364370
# click the "Run Surface Data Modifier" button
365371
fsurdat_modifier_launcher._on_launch_clicked(b=None)
366372

373+
assert Stage.active().title.startswith("Runoff Grid")
374+
cvars["CUSTOM_ROF_GRID"].value = "r05"
375+
367376
assert Stage.active().title.startswith("3. Launch")
368377
launch_stage = Stage.active()
369378

tests/3_system/test_fhist_custom_grid.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ def construct_custom_res_from_std_grids(cime):
129129
assert Stage.active().title.startswith("Land Grid")
130130
cvars["CUSTOM_LND_GRID"].value = "0.9x1.25"
131131

132+
assert Stage.active().title.startswith("Runoff Grid")
133+
cvars["CUSTOM_ROF_GRID"].value = "r05"
134+
132135
assert Stage.active().title.startswith("3. Launch")
133136
launch_stage = Stage.active()
134137

@@ -218,6 +221,9 @@ def construct_custom_res_from_modified_clm_grid(cime):
218221
# click the "Run Surface Data Modifier" button
219222
fsurdat_modifier_launcher._on_launch_clicked(b=None)
220223

224+
assert Stage.active().title.startswith("Runoff Grid")
225+
cvars["CUSTOM_ROF_GRID"].value = "r05"
226+
221227
assert Stage.active().title.startswith("3. Launch")
222228
launch_stage = Stage.active()
223229

0 commit comments

Comments
 (0)