Skip to content

Commit

Permalink
UW-533 & UW-534 MPAS driver for init_atmosphere and atmosphere foreca…
Browse files Browse the repository at this point in the history
…st (ufs-community#447)

* init

* WIP

* mpas files

* Adding the initial bits of an MPAS driver.

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* Driver WIP

* WIP

* edit namelist name

* WIP

* WIP

* WIP

* WIP

* WIP

* Fixing namelist and streams creation.

* WIP

* WIP

* clean up

* renaming

* WIP

* mpas_init.yaml

* new line

* punctuation

* A tested MPAS driver.

* Adding schema with updated tests.

* WIP

* Works for running mpas.

* PR feedback

* feedback

* config optional path

* Formatting.

* WIP

* WIP

* Updating schemas for consistency.

* WIP

* Default dict for mpas boundary files algo.

* update CLI

* DRY boundary files

* doc string

* update namelist_file

* mpas updates

* added try block

* remove comment

* simplify tests

* updated runscript tests and configs

---------

Co-authored-by: Christina Holt <[email protected]>
  • Loading branch information
elcarpenterNOAA and christinaholtNOAA authored Apr 1, 2024
1 parent c75f40b commit b8eacbf
Show file tree
Hide file tree
Showing 16 changed files with 1,385 additions and 2 deletions.
62 changes: 62 additions & 0 deletions docs/shared/mpas_init.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
user:
mpas_app: /path/to/mpas_app
platform:
account: me
scheduler: slurm
mpas_init:
boundary_conditions:
interval_hours: 6
length: 6
execution:
executable: "{{ user.mpas_app }}/exec/init_atmosphere_model"
batchargs:
walltime: 01:30:00
cores: 4
mpiargs:
- "--ntasks=4"
mpicmd: srun
envcmds:
- module use {{ user.mpas_app }}/modulefiles
- module load build_jet_intel
files_to_copy:
conus.static.nc: /path/to/conus.static.nc
conus.graph.info.part.{{mpas_init.execution["batchargs"]["cores"]}}: /path/to/conus.graph.info.part.{{mpas_init.execution["batchargs"]["cores"]}}
conus.init.nc: /path/to/conus.init.nc
stream_list.atmosphere.diagnostics: "{{ user.mpas_app }}/src/MPAS-Model/stream_list.atmosphere.diagnostics"
stream_list.atmosphere.output: "{{ user.mpas_app }}/src/MPAS-Model/stream_list.atmosphere.output"
stream_list.atmosphere.surface: "{{ user.mpas_app }}/src/MPAS-Model/stream_list.atmosphere.surface"
files_to_link:
CAM_ABS_DATA.DBL: "{{ user.mpas_app }}/src/MPAS-Model/CAM_ABS_DATA.DBL"
CAM_AEROPT_DATA.DBL: "{{ user.mpas_app }}/src/MPAS-Model/CAM_AEROPT_DATA.DBL"
GENPARM.TBL: "{{ user.mpas_app }}/src/MPAS-Model/GENPARM.TBL"
LANDUSE.TBL: "{{ user.mpas_app }}/src/MPAS-Model/LANDUSE.TBL"
OZONE_DAT.TBL: "{{ user.mpas_app }}/src/MPAS-Model/OZONE_DAT.TBL"
OZONE_LAT.TBL: "{{ user.mpas_app }}/src/MPAS-Model/OZONE_LAT.TBL"
OZONE_PLEV.TBL: "{{ user.mpas_app }}/src/MPAS-Model/OZONE_PLEV.TBL"
RRTMG_LW_DATA: "{{ user.mpas_app }}/src/MPAS-Model/RRTMG_LW_DATA"
RRTMG_LW_DATA.DBL: "{{ user.mpas_app }}/src/MPAS-Model/RRTMG_LW_DATA.DBL"
RRTMG_SW_DATA: "{{ user.mpas_app }}/src/MPAS-Model/RRTMG_SW_DATA"
RRTMG_SW_DATA.DBL: "{{ user.mpas_app }}/src/MPAS-Model/RRTMG_SW_DATA.DBL"
SOILPARM.TBL: "{{ user.mpas_app }}/src/MPAS-Model/SOILPARM.TBL"
VEGPARM.TBL: "{{ user.mpas_app }}/src/MPAS-Model/VEGPARM.TBL"
namelist:
base_file: "{{ user.mpas_app }}/src/MPAS-Model/namelist.init_atmosphere"
update_values:
nhyd_model:
config_init_case: 9
data_sources:
config_met_prefix: FILE
config_fg_interval: !int "{{ mpas_init.boundary_conditions['interval_hours'] * 3600 }}"
vertical_grid:
config_blend_bdy_terrain: true
preproc_stages:
config_static_interp: false
config_native_gwd_static: false
decomposition:
config_block_decomp_file_prefix: conus.graph.info.part.
run_dir: /path/to/rundir
streams:
path: /path/to/streams.init_atmosphere.IN
values:
input_filename: conus.init.nc
output_filename: foo.nc
54 changes: 54 additions & 0 deletions src/uwtools/api/mpas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
API access to the ``uwtools`` ``mpas`` driver.
"""

import datetime as dt
from pathlib import Path
from typing import Dict, Optional

import uwtools.drivers.support as _support
from uwtools.drivers.mpas import MPAS as _MPAS


def execute(
task: str,
cycle: dt.datetime,
config: Optional[Path] = None,
batch: bool = False,
dry_run: bool = False,
graph_file: Optional[Path] = None,
) -> bool:
"""
Execute an ``mpas`` task.
If ``batch`` is specified, a runscript will be written and submitted to the batch system.
Otherwise, the executable will be run directly on the current system.
:param task: The task to execute.
:param cycle: The cycle.
:param config: Path to config file (read stdin if missing or None).
:param batch: Submit run to the batch system.
:param dry_run: Do not run the executable, just report what would have been done.
:param graph_file: Write Graphviz DOT output here.
:return: ``True`` if task completes without raising an exception.
"""
obj = _MPAS(config=config, cycle=cycle, batch=batch, dry_run=dry_run)
getattr(obj, task)()
if graph_file:
with open(graph_file, "w", encoding="utf-8") as f:
print(graph(), file=f)
return True


def graph() -> str:
"""
Returns Graphviz DOT code for the most recently executed task.
"""
return _support.graph()


def tasks() -> Dict[str, str]:
"""
Returns a mapping from task names to their one-line descriptions.
"""
return _support.tasks(_MPAS)
54 changes: 54 additions & 0 deletions src/uwtools/api/mpas_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
API access to the ``uwtools`` ``mpas-init`` driver.
"""

import datetime as dt
from pathlib import Path
from typing import Dict, Optional

import uwtools.drivers.support as _support
from uwtools.drivers.mpas_init import MPASInit as _MPASInit


def execute(
task: str,
cycle: dt.datetime,
config: Optional[Path] = None,
batch: bool = False,
dry_run: bool = False,
graph_file: Optional[Path] = None,
) -> bool:
"""
Execute an MPAS ``init-atmosphere`` task.
If ``batch`` is specified, a runscript will be written and submitted to the batch system.
Otherwise, the executable will be run directly on the current system.
:param task: The task to execute.
:param config: Path to config file (read stdin if missing or None).
:param cycle: The cycle.
:param batch: Submit run to the batch system?
:param dry_run: Do not run the executable, just report what would have been done.
:param graph_file: Write Graphviz DOT output here.
:return: ``True`` if task completes without raising an exception.
"""
obj = _MPASInit(config=config, cycle=cycle, batch=batch, dry_run=dry_run)
getattr(obj, task)()
if graph_file:
with open(graph_file, "w", encoding="utf-8") as f:
print(graph(), file=f)
return True


def graph() -> str:
"""
Returns Graphviz DOT code for the most recently executed task.
"""
return _support.graph()


def tasks() -> Dict[str, str]:
"""
Returns a mapping from task names to their one-line descriptions.
"""
return _support.tasks(_MPASInit)
114 changes: 114 additions & 0 deletions src/uwtools/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import uwtools.api.config
import uwtools.api.file
import uwtools.api.fv3
import uwtools.api.mpas
import uwtools.api.mpas_init
import uwtools.api.rocoto
import uwtools.api.sfc_climo_gen
import uwtools.api.template
Expand Down Expand Up @@ -61,6 +63,8 @@ def main() -> None:
STR.config: _dispatch_config,
STR.file: _dispatch_file,
STR.fv3: _dispatch_fv3,
STR.mpas: _dispatch_mpas,
STR.mpasinit: _dispatch_mpas_init,
STR.rocoto: _dispatch_rocoto,
STR.sfcclimogen: _dispatch_sfc_climo_gen,
STR.template: _dispatch_template,
Expand Down Expand Up @@ -425,6 +429,114 @@ def _dispatch_fv3(args: Args) -> bool:
)


# Mode mpas


def _add_subparser_mpas(subparsers: Subparsers) -> ModeChecks:
"""
Subparser for mode: mpas
:param subparsers: Parent parser's subparsers, to add this subparser to.
"""
parser = _add_subparser(subparsers, STR.mpas, "Execute MPAS tasks")
_basic_setup(parser)
subparsers = _add_subparsers(parser, STR.action, STR.task.upper())
return {
task: _add_subparser_mpas_task(subparsers, task, helpmsg)
for task, helpmsg in uwtools.api.mpas.tasks().items()
}


def _add_subparser_mpas_task(subparsers: Subparsers, task: str, helpmsg: str) -> ActionChecks:
"""
Subparser for mode: mpas <task>
:param subparsers: Parent parser's subparsers, to add this subparser to.
:param task: The task to add a subparser for.
:param helpmsg: Help message for task.
"""
parser = _add_subparser(subparsers, task, helpmsg.rstrip("."))
required = parser.add_argument_group(TITLE_REQ_ARG)
_add_arg_cycle(required)
optional = _basic_setup(parser)
_add_arg_config_file(group=optional, required=False)
_add_arg_batch(optional)
_add_arg_dry_run(optional)
_add_arg_graph_file(optional)
checks = _add_args_verbosity(optional)
return checks


def _dispatch_mpas(args: Args) -> bool:
"""
Dispatch logic for mpas mode.
:param args: Parsed command-line args.
"""
return uwtools.api.mpas.execute(
task=args[STR.action],
config=args[STR.cfgfile],
cycle=args[STR.cycle],
batch=args[STR.batch],
dry_run=args[STR.dryrun],
graph_file=args[STR.graphfile],
)


# Mode mpas_init


def _add_subparser_mpas_init(subparsers: Subparsers) -> ModeChecks:
"""
Subparser for mode: mpas_init
:param subparsers: Parent parser's subparsers, to add this subparser to.
"""
parser = _add_subparser(subparsers, STR.mpasinit, "Execute MPASInit tasks")
_basic_setup(parser)
subparsers = _add_subparsers(parser, STR.action, STR.task.upper())
return {
task: _add_subparser_mpas_init_task(subparsers, task, helpmsg)
for task, helpmsg in uwtools.api.mpas_init.tasks().items()
}


def _add_subparser_mpas_init_task(subparsers: Subparsers, task: str, helpmsg: str) -> ActionChecks:
"""
Subparser for mode: mpas_init <task>
:param subparsers: Parent parser's subparsers, to add this subparser to.
:param task: The task to add a subparser for.
:param helpmsg: Help message for task.
"""
parser = _add_subparser(subparsers, task, helpmsg.rstrip("."))
required = parser.add_argument_group(TITLE_REQ_ARG)
_add_arg_cycle(required)
optional = _basic_setup(parser)
_add_arg_config_file(group=optional, required=False)
_add_arg_batch(optional)
_add_arg_dry_run(optional)
_add_arg_graph_file(optional)
checks = _add_args_verbosity(optional)
return checks


def _dispatch_mpas_init(args: Args) -> bool:
"""
Dispatch logic for mpas_init mode.
:param args: Parsed command-line args.
"""
return uwtools.api.mpas_init.execute(
task=args[STR.action],
config=args[STR.cfgfile],
cycle=args[STR.cycle],
batch=args[STR.batch],
dry_run=args[STR.dryrun],
graph_file=args[STR.graphfile],
)


# Mode rocoto


Expand Down Expand Up @@ -1092,6 +1204,8 @@ def _parse_args(raw_args: List[str]) -> Tuple[Args, Checks]:
STR.config: _add_subparser_config(subparsers),
STR.file: _add_subparser_file(subparsers),
STR.fv3: _add_subparser_fv3(subparsers),
STR.mpas: _add_subparser_mpas(subparsers),
STR.mpasinit: _add_subparser_mpas_init(subparsers),
STR.rocoto: _add_subparser_rocoto(subparsers),
STR.sfcclimogen: _add_subparser_sfc_climo_gen(subparsers),
STR.template: _add_subparser_template(subparsers),
Expand Down
Loading

0 comments on commit b8eacbf

Please sign in to comment.