from veros import VerosSetup, veros_routine
from veros.variables import allocate, Variable
from veros.core.operators import numpy as npx, update, at
[docs]
class FjordSetup(VerosSetup):
"""A model using spherical coordinates with a closed domain representing the idealized fjord.
The bathymetry of the model is idealized to a flat-bottom (with depth of 40 m) over the mouth of the fjord.
The bathymetry of fjord's inner part has a constant depth slope changing from 40 to 20 m from the mouth
of the fjord to the end of its inner part (northern boundary of the domain), respectively.
The horizontal grid has resolution of :math:`0.0005 \\times 0.005` degrees, and the vertical one has 10 levels.
Wind forcing over the fjord, buoyancy relaxation and sponge layer (salinity) forcing
drive water masses circulation.
This setup demonstrates:
- setting up an idealized fjord geometry
- modifing surface forcings over selected regions of the domain
- setting up sponge layer forcing
- basic usage of diagnostics
"""
@veros_routine
def set_parameter(self, state):
settings = state.settings
settings.identifier = "fjord"
settings.description = "Idealized fjord model"
settings.nx, settings.ny, settings.nz = 32, 96, 10
settings.dt_mom = 4.0
settings.dt_tracer = 4.0
settings.runlen = 86400.0 * 30
settings.x_origin = 11.0
settings.y_origin = 58.0
settings.coord_degree = True
settings.enable_cyclic_x = False
settings.enable_neutral_diffusion = True
settings.K_iso_0 = 1.0
settings.K_iso_steep = 1.0
settings.iso_dslope = 1e-3
settings.iso_slopec = 4e-3
settings.enable_skew_diffusion = True
settings.enable_hor_friction = True
settings.A_h = 10.0
settings.enable_hor_friction_cos_scaling = True
settings.hor_friction_cosPower = 1
settings.enable_tempsalt_sources = True
settings.enable_bottom_friction = True
settings.r_bot = 1e-5
settings.enable_implicit_vert_friction = True
settings.enable_tke = True
settings.c_k = 0.1
settings.c_eps = 0.7
settings.alpha_tke = 30.0
settings.mxl_min = 1e-8
settings.tke_mxl_choice = 2
settings.kappaM_min = 2e-4
settings.kappaH_min = 2e-5
settings.enable_Prandtl_tke = False
settings.enable_kappaH_profile = True
settings.K_gm_0 = 1.0
settings.enable_eke = False
settings.eke_k_max = 1e4
settings.eke_c_k = 0.4
settings.eke_c_eps = 0.5
settings.eke_cross = 2.0
settings.eke_crhin = 1.0
settings.eke_lmin = 100.0
settings.enable_eke_superbee_advection = False
settings.enable_eke_isopycnal_diffusion = False
settings.enable_idemix = False
settings.enable_idemix_hor_diffusion = False
settings.enable_eke_diss_surfbot = False
settings.eke_diss_surfbot_frac = 0.2
settings.enable_idemix_superbee_advection = False
settings.eq_of_state_type = 3
var_meta = state.var_meta
var_meta.update(
sst_star=Variable("sst_star", ("yt",), "deg C", "Reference surface temperature"),
sst_rest=Variable(
"sst_rest",
(
"xt",
"yt",
),
"m/s",
"Surface temperature restoring time scale",
),
sss_star=Variable("sss_star", ("yt",), "g/kg", "Reference surface salinity"),
sss_rest=Variable(
"sss_rest",
(
"xt",
"yt",
),
"m/s",
"Surface salinity restoring time scale",
),
s_star=Variable(
"s_star",
(
"xt",
"yt",
"zt",
),
"g/kg",
"Salinity sponge layer forcing",
),
rest_tscl=Variable(
"rest_tscl",
(
"xt",
"yt",
"zt",
),
"1/s",
"Forcing restoration time scale",
),
)
@veros_routine
def set_grid(self, state):
vs = state.variables
settings = state.settings
# keep total domain size constant when nx or ny changes
vs.dxt = update(vs.dxt, at[...], 0.0005 * 32 / settings.nx)
vs.dyt = update(vs.dyt, at[...], 0.005 * 96 / settings.ny)
vs.dzt = update(vs.dzt, at[...], 4.0 * 10.0 / settings.nz)
@veros_routine
def set_coriolis(self, state):
vs = state.variables
settings = state.settings
vs.coriolis_t = update(
vs.coriolis_t, at[:, :], 2 * settings.omega * npx.sin(vs.yt[None, :] / 180.0 * settings.pi)
)
@veros_routine
def set_topography(self, state):
vs = state.variables
x, y = npx.meshgrid(vs.xt, vs.yt, indexing="ij")
kzt = (20 * (y[y >= 58.2] - 58.2) + 1).astype("int")
landmass = npx.logical_or((x > 11.0055) & (x < 11.0105), y < 58.2).astype("int")
landmass_eq_0 = landmass == 0
vs.kbot = npx.ones(x.shape)
bathymetry = y >= 58.2
vs.kbot = update(vs.kbot, at[bathymetry], kzt)
vs.kbot = update(vs.kbot, at[landmass_eq_0], 0.0)
@veros_routine(
dist_safe=False,
local_variables=[
"sst_star",
"s_star",
"sss_star",
"sst_rest",
"rest_tscl",
"sss_rest",
"temp",
"salt",
"maskT",
"maskU",
"maskV",
"maskW",
"xt",
"yt",
"yu",
"zt",
"zw",
"dzt",
"forc_tke_surface",
"surface_taux",
"surface_tauy",
"forc_iw_bottom",
"forc_iw_surface",
],
)
def set_initial_conditions(self, state):
vs = state.variables
settings = state.settings
# initial conditions
vs.temp = update(vs.temp, at[...], (5.0 + (1 - vs.zt[None, None, :] / vs.zw[0]) * 11 * vs.maskT)[..., None])
vs.salt = update(vs.salt, at[...], (npx.linspace(34, 26, settings.nz)[None, None, :] * vs.maskT)[..., None])
# wind stress forcing
vs.surface_taux = 5e-2 * vs.maskU[:, :, -1]
vs.surface_tauy = 2e-2 * vs.maskV[:, :, -1]
# surface heatflux forcing
vs.sst_star = allocate(state.dimensions, ("yt",), fill=16.0)
# surface salinity forcing
vs.sss_star = allocate(state.dimensions, ("yt",), fill=26.0)
vs.sst_rest = vs.dzt[-1] / (10.0 * 86400.0) * vs.maskT[:, :, -1]
vs.sss_rest = vs.dzt[-1] / (30.0 * 86400.0) * vs.maskT[:, :, -1]
# salinity sponge layer forcing
_, _yt, _ = npx.meshgrid(vs.xt, vs.yt, vs.zt, indexing="ij")
sponge_region = _yt <= vs.yt[4]
vs.s_star = allocate(
state.dimensions,
(
"xt",
"yt",
"zt",
),
)
vs.s_star = update(
vs.s_star, at[sponge_region], (npx.linspace(34, 26, settings.nz)[None, None, :] * vs.maskT)[sponge_region]
)
vs.rest_tscl = allocate(
state.dimensions,
(
"xt",
"yt",
"zt",
),
)
vs.rest_tscl = update(vs.s_star, at[sponge_region], 1.0 / (30.0 * 86400.0))
if settings.enable_tke:
vs.forc_tke_surface = update(
vs.forc_tke_surface,
at[2:-2, 2:-2],
npx.sqrt(
(0.5 * (vs.surface_taux[2:-2, 2:-2] + vs.surface_taux[1:-3, 2:-2]) / settings.rho_0) ** 2
+ (0.5 * (vs.surface_tauy[2:-2, 2:-2] + vs.surface_tauy[2:-2, 1:-3]) / settings.rho_0) ** 2
)
** (1.5),
)
if settings.enable_idemix:
vs.forc_iw_bottom = 1e-6 * vs.maskW[:, :, -1]
vs.forc_iw_surface = 1e-7 * vs.maskW[:, :, -1]
@veros_routine
def set_forcing(self, state):
vs = state.variables
settings = state.settings
vs.forc_temp_surface = vs.sst_rest * (vs.sst_star - vs.temp[:, :, -1, vs.tau])
vs.forc_salt_surface = vs.sss_rest * (vs.sss_star - vs.salt[:, :, -1, vs.tau])
if settings.enable_tempsalt_sources:
vs.salt_source = update(
vs.salt_source, at[...], vs.maskT * vs.rest_tscl * (vs.s_star[:, :, :] - vs.salt[:, :, :, vs.tau])
)
@veros_routine
def set_diagnostics(self, state):
settings = state.settings
state.diagnostics["snapshot"].output_frequency = 86400.0
state.diagnostics["averages"].output_variables = (
"salt",
"temp",
"u",
"v",
"w",
"psi",
"rho",
"surface_taux",
"surface_tauy",
)
state.diagnostics["averages"].output_frequency = 86400 / 4.0
state.diagnostics["averages"].sampling_frequency = settings.dt_tracer * 10
state.diagnostics["tracer_monitor"].output_frequency = 86400.0 / 4.0
state.diagnostics["energy"].output_frequency = 86400.0 / 48
state.diagnostics["energy"].sampling_frequency = settings.dt_tracer * 10
@veros_routine
def after_timestep(self, state):
pass