Skip to content

Commit b501e91

Browse files
authored
Merge pull request #231 from xylar/update-omega-iostream
Updates related to Omega IOStreams
2 parents e1ad8af + 531877f commit b501e91

File tree

10 files changed

+203
-64
lines changed

10 files changed

+203
-64
lines changed

e3sm_submodules/Omega

Submodule Omega updated 235 files

polaris/model_step.py

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import shutil
33
from collections import OrderedDict
4-
from typing import List, Union
4+
from typing import Dict, List, Union
55

66
import numpy as np
77
import xarray as xr
@@ -69,6 +69,8 @@ class ModelStep(Step):
6969
Whether to create a yaml file with model config options and streams
7070
instead of MPAS namelist and streams files
7171
72+
streams_section : str
73+
The name of the streams section in yaml files
7274
"""
7375
def __init__(self, component, name, subdir=None, indir=None, ntasks=None,
7476
min_tasks=None, openmp_threads=None, max_memory=None,
@@ -173,6 +175,7 @@ def __init__(self, component, name, subdir=None, indir=None, ntasks=None,
173175
self.graph_filename = graph_filename
174176

175177
self.make_yaml = make_yaml
178+
self.streams_section = 'streams'
176179

177180
self.add_input_file(filename='<<<model>>>')
178181

@@ -275,7 +278,7 @@ def add_yaml_file(self, package, yaml, template_replacements=None):
275278

276279
def map_yaml_options(self, options, config_model):
277280
"""
278-
A mapping between model config options between different models. This
281+
A mapping between model config options from different models. This
279282
method should be overridden for situations in which yaml config
280283
options have diverged in name or structure from their counterparts in
281284
another model (e.g. when translating from MPAS-Ocean namelist options
@@ -301,7 +304,7 @@ def map_yaml_options(self, options, config_model):
301304

302305
def map_yaml_configs(self, configs, config_model):
303306
"""
304-
A mapping between model config options between different models. This
307+
A mapping between model config options from different models. This
305308
method should be overridden for situations in which yaml config
306309
options have diverged in name or structure from their counterparts in
307310
another model (e.g. when translating from MPAS-Ocean namelist options
@@ -325,6 +328,29 @@ def map_yaml_configs(self, configs, config_model):
325328
"""
326329
return configs
327330

331+
def map_yaml_streams(self, streams, config_model):
332+
"""
333+
A mapping between model streams from different models. This method
334+
should be overridden for situations in which yaml streams have diverged
335+
in name or structure from their counterparts in another model (e.g.
336+
when translating from MPAS-Ocean streams to Omega IOStreams)
337+
338+
Parameters
339+
----------
340+
streams : dict
341+
A nested dictionary of streams data
342+
343+
config_model : str or None
344+
If streams are available for multiple models, the model that the
345+
streams are from
346+
347+
Returns
348+
-------
349+
configs : dict
350+
A revised nested dictionary of streams data
351+
"""
352+
return streams
353+
328354
def map_yaml_to_namelist(self, options):
329355
"""
330356
A mapping from yaml model config options to namelist options. This
@@ -440,7 +466,7 @@ def runtime_setup(self):
440466
self.dynamic_model_config(at_setup=False)
441467

442468
if self.make_yaml:
443-
self._process_yaml(quiet=quiet)
469+
self._process_yaml(quiet=quiet, remove_unrequested_streams=False)
444470
else:
445471
self._process_namelists(quiet=quiet)
446472
self._process_streams(quiet=quiet, remove_unrequested=False)
@@ -481,7 +507,7 @@ def process_inputs_and_outputs(self):
481507
self._create_model_config()
482508

483509
if self.make_yaml:
484-
self._process_yaml(quiet=quiet)
510+
self._process_yaml(quiet=quiet, remove_unrequested_streams=True)
485511
else:
486512
self._process_namelists(quiet=quiet)
487513
self._process_streams(quiet=quiet, remove_unrequested=True)
@@ -563,7 +589,8 @@ def _create_model_config(self):
563589
config = self.config
564590
if self.make_yaml:
565591
defaults_filename = config.get('model_config', 'defaults')
566-
self._yaml = PolarisYaml.read(defaults_filename)
592+
self._yaml = PolarisYaml.read(defaults_filename,
593+
streams_section=self.streams_section)
567594
else:
568595
defaults_filename = config.get('namelists', 'forward')
569596
self._namelist = polaris.namelist.ingest(defaults_filename)
@@ -578,7 +605,8 @@ def _read_model_config(self):
578605
"""
579606
if self.make_yaml:
580607
filename = os.path.join(self.work_dir, self.yaml)
581-
self._yaml = PolarisYaml.read(filename)
608+
self._yaml = PolarisYaml.read(filename,
609+
streams_section=self.streams_section)
582610
else:
583611
filename = os.path.join(self.work_dir, self.namelist)
584612
self._namelist = polaris.namelist.ingest(filename)
@@ -641,10 +669,10 @@ def _process_namelists(self, quiet):
641669
options = self.map_yaml_to_namelist(options)
642670
replacements.update(options)
643671
if 'yaml' in entry:
644-
yaml = PolarisYaml.read(filename=entry['yaml'],
645-
package=entry['package'],
646-
replacements=entry['replacements'],
647-
model=config_model)
672+
yaml = PolarisYaml.read(
673+
filename=entry['yaml'], package=entry['package'],
674+
replacements=entry['replacements'], model=config_model,
675+
streams_section=self.streams_section)
648676

649677
configs = self.map_yaml_configs(configs=yaml.configs,
650678
config_model=config_model)
@@ -727,8 +755,7 @@ def _process_streams(self, quiet, remove_unrequested):
727755
if not found:
728756
defaults.remove(default)
729757

730-
@staticmethod
731-
def _process_yaml_streams(yaml_filename, package, replacements,
758+
def _process_yaml_streams(self, yaml_filename, package, replacements,
732759
config_model, processed_registry_filename,
733760
tree, quiet):
734761
if not quiet:
@@ -737,14 +764,15 @@ def _process_yaml_streams(yaml_filename, package, replacements,
737764
yaml = PolarisYaml.read(filename=yaml_filename,
738765
package=package,
739766
replacements=replacements,
740-
model=config_model)
767+
model=config_model,
768+
streams_section=self.streams_section)
741769
assert processed_registry_filename is not None
742770
new_tree = yaml_to_mpas_streams(
743771
processed_registry_filename, yaml)
744772
tree = polaris.streams.update_tree(tree, new_tree)
745773
return tree
746774

747-
def _process_yaml(self, quiet):
775+
def _process_yaml(self, quiet, remove_unrequested_streams):
748776
"""
749777
Processes changes to a yaml file from the files and dictionaries
750778
in the step's ``model_config_data``.
@@ -759,6 +787,8 @@ def _process_yaml(self, quiet):
759787
if not quiet:
760788
print(f'Warning: replacing yaml options in {self.yaml}')
761789

790+
streams: Dict[str, Dict[str, Union[str, float, int, List[str]]]] = {}
791+
762792
for entry in self.model_config_data:
763793
if 'namelist' in entry:
764794
raise ValueError('Cannot generate a yaml config from an MPAS '
@@ -773,14 +803,49 @@ def _process_yaml(self, quiet):
773803
config_model=config_model)
774804
self._yaml.update(options=options, quiet=quiet)
775805
if 'yaml' in entry:
776-
yaml = PolarisYaml.read(filename=entry['yaml'],
777-
package=entry['package'],
778-
replacements=entry['replacements'],
779-
model=config_model)
806+
yaml = PolarisYaml.read(
807+
filename=entry['yaml'], package=entry['package'],
808+
replacements=entry['replacements'], model=config_model,
809+
streams_section=self.streams_section)
780810

781811
configs = self.map_yaml_configs(configs=yaml.configs,
782812
config_model=config_model)
813+
new_streams = self.map_yaml_streams(
814+
streams=yaml.streams, config_model=config_model)
815+
self._update_yaml_streams(streams, new_streams,
816+
quiet=quiet,
817+
remove_unrequested=False)
783818
self._yaml.update(configs=configs, quiet=quiet)
819+
self._update_yaml_streams(
820+
self._yaml.streams, streams, quiet=quiet,
821+
remove_unrequested=remove_unrequested_streams)
822+
823+
@staticmethod
824+
def _update_yaml_streams(streams, new_streams, quiet, remove_unrequested):
825+
"""
826+
Update yaml streams, optionally removing any streams that aren't in
827+
new_streams
828+
"""
829+
830+
for stream_name, new_stream in new_streams.items():
831+
if stream_name in streams:
832+
streams[stream_name].update(new_stream)
833+
if not quiet:
834+
print(f' updating: {stream_name}')
835+
else:
836+
if not quiet:
837+
print(f' adding: {stream_name}')
838+
streams[stream_name] = new_stream
839+
840+
if remove_unrequested:
841+
# during setup, we remove any default streams that aren't requested
842+
# but at runtime we don't want to do this because we would lose any
843+
# streams added only during setup.
844+
for stream_name in list(streams.keys()):
845+
if stream_name not in new_streams:
846+
if not quiet:
847+
print(f' dropping: {stream_name}')
848+
streams.pop(stream_name)
784849

785850

786851
def make_graph_file(mesh_filename, graph_filename='graph.info',

polaris/ocean/convergence/forward.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ def dynamic_model_config(self, at_setup):
141141
output_interval_str = get_time_interval_string(
142142
seconds=output_interval * s_per_hour)
143143

144+
# For Omega, we want the output interval as a number of seconds
145+
output_freq = int(output_interval * s_per_hour)
146+
144147
time_integrator = section.get('time_integrator')
145148
time_integrator_map = dict([('RK4', 'RungeKutta4')])
146149
model = config.get('ocean', 'model')
@@ -158,6 +161,7 @@ def dynamic_model_config(self, at_setup):
158161
btr_dt=btr_dt_str,
159162
run_duration=run_duration_str,
160163
output_interval=output_interval_str,
164+
output_freq=f'{output_freq}'
161165
)
162166

163167
self.add_yaml_file(self.package, self.yaml_filename,

polaris/ocean/model/mpaso_to_omega.yaml

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,33 @@
1+
dimensions:
2+
Time: time
3+
nCells: NCells
4+
nEdges: NEdges
5+
nVertices: NVertices
6+
maxEdges: MaxEdges
7+
maxEdges2: MaxEdges2
8+
TWO: MaxCellsOnEdge
9+
vertexDegree: VertexDegree
10+
nVertLevels: NVertLevels
11+
nVertLevelsP1: NVertLevelsP1
12+
113
variables:
2-
temperature: Temp
3-
salinity: Salt
14+
# tracers
15+
temperature: Temperature
16+
salinity: Salinity
417
tracer1: Debug1
518
tracer2: Debug2
619
tracer3: Debug3
7-
ssh: SshCell
20+
21+
# state
22+
layerThickness: LayerThickness
23+
normalVelocity: NormalVelocity
24+
25+
# auxiliary state
26+
ssh: SshCellDefault
827

928
config:
1029
- section:
11-
time_management: TimeManagement
30+
time_management: TimeIntegration
1231
options:
1332
config_start_time: StartTime
1433
config_stop_time: StopTime
@@ -47,3 +66,10 @@ config:
4766
options:
4867
config_use_mom_del4: VelHyperDiffTendencyEnable
4968
config_mom_del4: ViscDel4
69+
70+
- section:
71+
manufactured_solution: ManufacturedSolution
72+
options:
73+
config_manufactured_solution_wavelength_x: WavelengthX
74+
config_manufactured_solution_wavelength_y: WavelengthY
75+
config_manufactured_solution_amplitude: Amplitude

0 commit comments

Comments
 (0)