Skip to content

Commit acca33b

Browse files
authored
Merge pull request #401 from xylar/detect-ocean-model
By default, detect ocean model based on files in path
2 parents 37d8818 + ccf9879 commit acca33b

File tree

4 files changed

+96
-23
lines changed

4 files changed

+96
-23
lines changed

docs/developers_guide/quick_start.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ make <mpas_make_target>
478478

479479
The same applies to MPAS-Seaice except with `mpas-seaice` in the path above.
480480

481+
To set up tasks and suites to use MPAS-Ocean, it should be sufficient to point
482+
to an MPAS-Ocean build with the `-p` flag to `polaris setup` or
483+
`polaris suite`. MPAS-Ocean should automatically be detected. You can use
484+
the flag `--model mpas-ocean` to be explicit, though.
485+
481486
(dev-omega-build)=
482487

483488
### Omega
@@ -526,9 +531,10 @@ location you like. If you build in a location other than
526531
relative or absolute path using the `-p` flag when you call `polaris setup` or
527532
`polaris suite`.
528533

529-
To set up tasks and suites to use Omega, you need to supply `--model=omega`
530-
to `polaris setup` or `polaris suite`. Otherwise, it will default to
531-
MPAS-Ocean.
534+
As with MPAS-Ocean, to set up tasks and suites to use Omega, it should be
535+
sufficient to point to an Omega build with the `-p` flag to `polaris setup` or
536+
`polaris suite`, which should allow Omega to be detected automatically.
537+
But you can use the flag `--model omega` to indicate this explicitly.
532538

533539
(dev-working-with-polaris)=
534540

polaris/ocean/ocean.cfg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
# Options related the ocean component
55
[ocean]
6-
# Which model, MPAS-Ocean or Omega, is used
7-
model = mpas-ocean
6+
# Which model, MPAS-Ocean or Omega, is used, or "detect" to auto-detect
7+
model = detect
88

99
# the number of cells per core to aim for
1010
goal_cells_per_core = 200

polaris/setup.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,15 @@ def setup_tasks(
112112
component = tasks[first_path].component
113113

114114
basic_config = _get_basic_config(
115-
config_file, machine, component_path, component, model
115+
config_file=config_file,
116+
machine=machine,
117+
component_path=component_path,
118+
component=component,
119+
model=model,
116120
)
117121

122+
component.configure(basic_config)
123+
118124
provenance.write(work_dir, tasks, config=basic_config)
119125

120126
if clean:
@@ -124,14 +130,11 @@ def setup_tasks(
124130
print('')
125131

126132
_setup_configs(
127-
component,
128-
tasks,
129-
work_dir,
130-
config_file,
131-
machine,
132-
component_path,
133-
copy_executable,
134-
model,
133+
basic_config=basic_config,
134+
component=component,
135+
tasks=tasks,
136+
work_dir=work_dir,
137+
copy_executable=copy_executable,
135138
)
136139

137140
# do this after _setup_configs() in case tasks mark additional steps
@@ -432,20 +435,15 @@ def _expand_and_mark_cached_steps(tasks, cached_steps):
432435

433436

434437
def _setup_configs(
438+
basic_config,
435439
component,
436440
tasks,
437441
work_dir,
438-
config_file,
439-
machine,
440-
component_path,
441442
copy_executable,
442-
model,
443443
):
444444
"""Set up config parsers for this component"""
445445

446-
common_config = _get_basic_config(
447-
config_file, machine, component_path, component, model
448-
)
446+
common_config = basic_config.copy()
449447
if copy_executable:
450448
common_config.set('setup', 'copy_executable', 'True')
451449

@@ -718,8 +716,6 @@ def _get_basic_config(config_file, machine, component_path, component, model):
718716
exception=False,
719717
)
720718

721-
component.configure(config)
722-
723719
# set the component_path path from the command line if provided
724720
if component_path is not None:
725721
component_path = os.path.abspath(component_path)

polaris/tasks/ocean/__init__.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import importlib.resources as imp_res
2+
import os
23
from typing import Dict, Union
34

45
import xarray as xr
@@ -44,6 +45,10 @@ def configure(self, config):
4445
"""
4546
section = config['ocean']
4647
model = section.get('model')
48+
if model == 'detect':
49+
model = self._detect_model(config)
50+
print('Detected ocean model:', model)
51+
config.set('ocean', 'model', model)
4752
configs = {'mpas-ocean': 'mpas_ocean.cfg', 'omega': 'omega.cfg'}
4853
if model not in configs:
4954
raise ValueError(f'Unknown ocean model {model} in config options')
@@ -228,6 +233,72 @@ def _read_var_map(self):
228233
self.mpaso_to_omega_dim_map = nested_dict['dimensions']
229234
self.mpaso_to_omega_var_map = nested_dict['variables']
230235

236+
def _detect_model(self, config) -> str:
237+
"""
238+
Detect which ocean model to use
239+
"""
240+
# build config options for each model, so the default component_path
241+
# can be read if it hasn't been overridden
242+
omega_config = config.copy()
243+
omega_config.add_from_package('polaris.ocean', 'omega.cfg')
244+
omega_path = omega_config.get('paths', 'component_path')
245+
246+
mpas_ocean_config = config.copy()
247+
mpas_ocean_config.add_from_package('polaris.ocean', 'mpas_ocean.cfg')
248+
mpas_ocean_path = mpas_ocean_config.get('paths', 'component_path')
249+
250+
if self._detect_omega_build(omega_path):
251+
return 'omega'
252+
elif self._detect_mpas_ocean_build(mpas_ocean_path):
253+
return 'mpas-ocean'
254+
else:
255+
raise ValueError(
256+
f'Could not detect ocean model; neither MPAS-Ocean '
257+
f'nor Omega appear to be available; '
258+
f'searched {omega_path} and {mpas_ocean_path}.'
259+
)
260+
261+
def _detect_omega_build(self, path) -> bool:
262+
"""
263+
Detect if Omega is available
264+
"""
265+
required_files = [
266+
'configs/Default.yml',
267+
'src/omega.exe',
268+
]
269+
path = os.path.abspath(path)
270+
271+
all_found = True
272+
for required_file in required_files:
273+
if not os.path.exists(os.path.join(path, required_file)):
274+
all_found = False
275+
break
276+
return all_found
277+
278+
def _detect_mpas_ocean_build(self, path) -> bool:
279+
"""
280+
Detect if MPAS-Ocean is available
281+
282+
Returns
283+
-------
284+
is_mpas_ocean : bool
285+
True if MPAS-Ocean appears to be available, False otherwise
286+
"""
287+
required_files = [
288+
'default_inputs/namelist.ocean.forward',
289+
'default_inputs/streams.ocean.forward',
290+
'src/Registry_processed.xml',
291+
'ocean_model',
292+
]
293+
path = os.path.abspath(path)
294+
295+
all_found = True
296+
for required_file in required_files:
297+
if not os.path.exists(os.path.join(path, required_file)):
298+
all_found = False
299+
break
300+
return all_found
301+
231302

232303
# create a single module-level instance available to other components
233304
ocean = Ocean()

0 commit comments

Comments
 (0)