seamount
The seamount task group is comprised of a default task and a short task
in each of four task trees,
planar/seamount/{linear,nonlinear}/{sigma,zstar}, combining the equation of
state with the vertical coordinate used for the initial condition. This
follows the planar/overflow/{eos}/{coord} pattern.
framework
The shared config options for seamount tests are described in
seamount in the User’s Guide. coord_type, and for z-star
partial_cell_type, live in per-coordinate seamount_sigma.cfg and
seamount_zstar.cfg overrides layered on top of the shared seamount.cfg.
The equation of state is layered on the same way: seamount_linear.cfg
carries the eos_linear_* options, which mean nothing to the nonlinear
trees and so are added only for the linear ones. add_seamount_tasks()
also picks up linear.cfg or teos10.cfg from polaris.ocean.eos per
tree; the nonlinear trees need nothing beyond that.
Neither equation of state needs new plumbing. update_namelist_eos()
already maps teos-10 to jm for MPAS-Ocean and passes it through to
Omega, and the geometric-to-pseudo-height conversion described below
dispatches on eos_type through
polaris.ocean.eos.compute_specvol().
Additionally, the tests share a forward.yaml file with a few common model
config options related to time management, time integration, Laplacian
viscosity, bottom drag and vertical mixing, as well as defining mesh,
input, restart, and output streams. It is split into a shared ocean:
section and model-specific mpas-ocean: and Omega: sections.
support for both ocean models
Both coordinates are geometric, so one init step serves either model. When
model = omega, Ocean.write_vert_coord_dataset() and
Ocean.write_model_dataset() convert restingThickness and layerThickness
into RefPseudoThickness and PseudoThickness by integrating gauge pressure
down each column through the configured equation of state. No p-star-specific
initialization is involved and no reference pseudo-grid is needed, so the
seamount does not use
polaris.ocean.vertical.pstar_init.PStarInitStep.
tests/ocean/seamount/test_sigma_to_pseudo.py covers that conversion: the
geometric round trip, that sigma layers stay proportional to column depth, and
that interior interfaces sit at genuinely different pressures from column to
column, with a flat-bottom negative control for the last of these.
tests/ocean/seamount/test_tracers.py covers the initial condition: that
both equation-of-state branches reproduce the same Beckmann and Haidvogel
profile, and the negative control that in-situ density under TEOS-10 really
does depart from it with depth.
init
The class polaris.tasks.ocean.seamount.init.Init
defines a step for setting up the initial state for each test case.
First, a mesh appropriate for the resolution is generated using
mpas_tools.planar_hex.make_planar_hex_mesh(). The bottom topography
is defined along with a vertical grid with 32 layers by default. Next, the
ocean state is generated with a vertical temperature stratification,
back-computed from the target Beckmann and Haidvogel density so that the
density the model sees matches the profile the test intends.
The profile and the back-solve live in
polaris.tasks.ocean.seamount.init_utils, a leaf module free of
mpas_tools and of the step framework so the unit tests can import it.
polaris.tasks.ocean.seamount.init_utils.compute_tracers() branches
on eos_type: the linear equation of state is inverted algebraically with
the salinity term included, and TEOS-10 is inverted with
polaris.ocean.eos.ct_from_potential_density(), which reads the
profile as a potential density referenced to the surface. See
initial conditions in the User’s Guide for why the surface reference
is the only workable one and what it buys.
The step leaves its tracers in the convention implied by eos_type and does
nothing model-specific: in the nonlinear trees, the framework converts them
to potential temperature and practical salinity at the nominal lon/lat when
the model is MPAS-Ocean (see Initial state), computing
the pressure that conversion needs from the layer thicknesses since a
geometric vertical coordinate carries none.
Note that the tracers carry the Time dimension that layerThickness and
the rest of the state have. TEOS-10 requires its inputs to be aligned; the
linear equation of state did not, which is why the seamount got away without
it for a while.
forward
The class polaris.tasks.ocean.seamount.forward.Forward
defines a step for running the ocean from the initial condition produced in
the init step. Namelist and streams files are updated in
polaris.tasks.ocean.seamount.forward.Forward.dynamic_model_config()
with time steps determined algorithmically based on config options. Both
models take the same step from dt_per_km and the same integrator from
time_integrator; the only model-dependent part is translating the
integrator name to Omega’s (RK4 becomes RungeKutta4). The
number of cells is approximated from config options in
polaris.tasks.ocean.seamount.forward.Forward.compute_cell_count()
so that this can be used to constrain the number of MPI tasks that Polaris
tasks have as their target and minimum (if the resources are not explicitly
prescribed). For MPAS-Ocean, PIO namelist options are modified and a
graph partition is generated as part of runtime_setup(). Next, the ocean
model is run. The duration is set by run_duration, in hours, in the config
section corresponding to the task (seamount_default or seamount_short,
selected by the task_name passed to the step). Finally,
the variables kineticEnergyCell and normalVelocity in the
output.nc file are visualized in the viz directory.
viz
The polaris.tasks.ocean.seamount.viz.Viz plots the maximum velocity
as a function of time; a horizontal cross-section of the normal velocity;
and a vertical cross-section of the kinetic energy. The vertical cross-section
is also convenient to see the vertical coordinate (sigma versus z-star) and
the bottom topography.
The transect needs a geometric layer thickness, and layerThickness is the
right field for both models. Omega writes PseudoThickness rather than a
geometric thickness, but Ocean.open_model_dataset() converts it on read,
as RhoSw * SpecVol * PseudoThickness. That is why SpecVol has to be in
the Omega History stream alongside State.
default
The polaris.tasks.ocean.seamount.default.Default
test runs the init step, a 6 day forward step, and the viz step. It is
added once per tree, so four times. Unlike most tasks, viz runs by
default here: the forward run is long enough that it is not worth making the
user re-run the task just to get the plots.
short
The polaris.tasks.ocean.seamount.short.Short test is the same
task with a 1 hour forward step, and it too is added once per tree. It
exists as a regression test rather than a measurement: an hour is far too
short for the spurious circulation to develop. viz is opt-in here, as
usual, because re-running the task to get the plots is cheap.
The two tasks differ only in their config section, seamount_default versus
seamount_short, which is what Forward looks up from its
task_name.
Two of the four short tasks are in the mpaso_pr and omega_pr suites,
linear/zstar and nonlinear/sigma, which covers both equations of state
and both coordinates in two runs. Nothing from the seamount is in the
nightly suites yet; the default tasks are 6 day runs.