zoomy_core.model.models.closures#
Composable stress closures: each Closure is one constitutive relation for a stress
component (bulk, bed trace, surface trace, horizontal) over a ClosureState.
Models list them in closures=[...] and perform the substitution when the Model is derived,
before the lift to a SystemModel.
Module Contents#
Classes#
Base class of a one-component stress closure; subclasses set the immutable |
|
Incompressible Newtonian fluid, |
|
Bulk stress |
|
Bulk stress for the positivity-preserving q-r k-epsilon model, with |
|
Regularized Bingham bulk stress |
|
Algebraic Elder eddy viscosity |
|
Linear Navier slip at the bed, |
|
Turbulent rough-wall bed drag |
|
k-epsilon rough-wall-function bed stress |
|
Manning bed friction as a bottom closure for depth-averaged SWE; |
|
Horizontal eddy viscosity closure for the depth-averaged mixing |
|
Stress-free free surface, |
|
The interface value an |
|
Base of the multilayer interface schemes; |
|
Central interface velocity |
|
Donor interface velocity chosen by the sign of the interface flux, |
Functions#
The bulk closures that supply the full stress tensor when the model keeps it ( |
|
In-plane stress relative to the vertical normal stress, |
|
Inject the bulk, bed and surface stress closures into the projected momentum equations of
SME/VAM, frame-aware and dimension-agnostic. With the full tensor ( |
|
With |
|
Per-layer variant of |
|
Return the |
|
Shared, single-valued part of the traction at an internal layer interface |
|
Build a |
API#
- zoomy_core.model.models.closures.full_tensor_closures(closures, stress)#
The bulk closures that supply the full stress tensor when the model keeps it (
stressisStress.full; a model’s choice ism.stress, set bymoment_scaling), else[].Raises
ValueError:Stress.fullwith no bulk closure, or with one that closes only the vertical shear (onlyNewtonianprovides the tensor).
- zoomy_core.model.models.closures.inplane_stress(full, s, nh)#
In-plane stress relative to the vertical normal stress,
tau_de - delta_de tau_zz, summed over the full-tensor closures at the trace ofs(nh x nhnested list).
- zoomy_core.model.models.closures.apply_stress_closures(closures, m, axes, state, horiz)#
Inject the bulk, bed and surface stress closures into the projected momentum equations of SME/VAM, frame-aware and dimension-agnostic. With the full tensor (
Stress.full) the bed and surface tractions carry the in-plane stress too (_inplane_traction) and the bulk shear itsrho nu d_d wpart.Args
closures: list ofClosureobjects.m: derivation model.axes: one{"mx": eq, "tau": FieldHandle, "velname": "u"|"v"}per horizontal momentum component.state: callablestate(at, *, alias=None, btag=None) -> ClosureState.horiz: horizontal coordinates.
Returns
True iff a bulk closure was applied.
- zoomy_core.model.models.closures.apply_full_tensor(closures, m, momentum)#
With
Stress.full, substitute the full-tensor closure’s stress (physical, fixed-z coordinates, before the sigma map) into the blueprintmomentum:tau_deandtau_zzin the horizontal rows,tau_ezandtau_zzin the vertical row (its divergence evaluated). The horizontal sheartau_dzstays a closure variable, closed after the projection (apply_stress_closures: bed / surface traction, bulk). In the vertical row therho nu d_e d_e wterm is dropped (Marche 2007, (3.2) -> (3.5)).Returns
The tensor
{key: tau}, orNonewithStress.shallow(no-op).
- class zoomy_core.model.models.closures.Closure(name=None)#
Bases:
zoomy_core.model.operations.OperationBase class of a one-component stress closure; subclasses set the immutable
closes/requiresand implementexpression.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
None
- requires#
()
- register(model)#
Register-or-query the model parameters this closure needs (override).
- check(model)#
Assert every field in
requiresis present in the model.
- abstract expression(s)#
Return the symbolic relation for this stress component over the
ClosureStates(override).
- friction_velocity(s)#
Bed friction velocity
u_starthis closure defines, orNone; bed drag laws override it so an eddy viscosity can consume it.
- traction(s)#
Boundary traction in the local frame
{n, t_a}; the default wraps the scalarexpressionas one tangential component.Returns
{"normal": n.sigma.n or None, "tangent": [t_a.sigma.n, ...]}, one tangent entry per horizontal direction.
- class zoomy_core.model.models.closures.Newtonian(name=None)#
Bases:
zoomy_core.model.models.closures.ClosureIncompressible Newtonian fluid,
tau = rho nu (grad u + grad u^T).expressionis the vertical shearrho nu d_z u(allStress.shallowkeeps); withStress.fullthe model takes the whole tensor (tensorbefore the sigma map,stress/normal_stress/shearat the traces), so the depth-averaged in-plane term isdiv(h (tau - tau_zz I)), i.e.div(nu h (grad u + grad u^T)) + 2 nu grad(h div u)at level 0.References
Marche 2007, eqs. (3.2), (3.5), (5.19), https://doi.org/10.1016/j.euromechflu.2006.04.007
Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘bulk’
- requires#
(‘u’,)
- register(m)#
Register the kinematic viscosity
nu.
- expression(s)#
Return
rho nu d_z u.
- tensor(m, uvel, w, horiz)#
The tensor in physical (fixed-z) coordinates, before the sigma map,
{key: tau}for the blueprint keys ("xx","xy","yy","xz","yz","zz"):tau_de = rho nu (d_d u_e + d_e u_d),tau_dz = rho nu (d_z u_d + d_d w),tau_zz = 2 rho nu d_z w = -2 rho nu div_h u(incompressible).
- stress(s)#
In-plane tensor
tau_de = rho nu (d_d u_e + d_e u_d)at the trace ofs, with the physical (fixed-z) derivatives of the sigma map; it enters the boundary traction (apply_stress_closures).
- normal_stress(s)#
Viscous normal stress
tau_zz = 2 rho nu d_z w = -2 rho nu div_h uat the trace ofs(physical derivatives).
- shear(s)#
The
rho nu d_d wpart of the sheartau_dzat the trace ofs(physical derivative), per axis;expressionis the other part.
- class zoomy_core.model.models.closures.KEpsilonViscosity(name=None, wall_floor=True)#
Bases:
zoomy_core.model.models.closures.ClosureBulk stress
tau = rho nu_t d_z uwith the k-epsilon eddy viscositynu_t = C_mu k^2/epsilon; needskandvarepsilonfields andquadrature_order > 0.Args
wall_floor: add the near-wall mixing-length viscosityC_mu^(1/4) sqrt(k) kappa z_pso the stress still damps the velocity moments at the wall.
References
Launder, Spalding 1974, https://doi.org/10.1016/0045-7825(74)90029-2
Initialization
Store the
wall_floorswitch.- closes#
‘bulk’
- requires#
(‘u’, ‘k’, ‘varepsilon’)
- register(m)#
Register
C_mu,nuand, withwall_floor,kappaandz_p.
- expression(s)#
Return
rho (nu + nu_t) d_z uwithnu_t = C_mu k^2/epsilonplus the optional wall floor.
- class zoomy_core.model.models.closures.QRViscosity(name=None, wall_floor=True)#
Bases:
zoomy_core.model.models.closures.ClosureBulk stress for the positivity-preserving q-r k-epsilon model, with
nu_t = C_mu sk^4/se^2for the transportedsk = sqrt(k),se = sqrt(epsilon); needsquadrature_order > 0.Args
wall_floor: add the near-wall mixing-length viscosity, as inKEpsilonViscosity.
References
Fe et al. 2009, https://doi.org/10.1002/fld.1880
Initialization
Store the
wall_floorswitch.- closes#
‘bulk’
- requires#
(‘u’, ‘sk’, ‘se’)
- register(m)#
Register
C_mu,nu, the flooreps_minand, withwall_floor,kappaandz_p.
- expression(s)#
Return
rho (nu + nu_t) d_z uwithnu_t = C_mu sk^4/(se^2 + eps_min)plus the optional wall floor.
- class zoomy_core.model.models.closures.Bingham(name=None)#
Bases:
zoomy_core.model.models.closures.ClosureRegularized Bingham bulk stress
tau = (rho nu + tau_y/sqrt((d_z u)^2 + eps^2)) d_z u, rigid below the yield stresstau_yaseps -> 0. Not analytically integrable, so build the model withquadrature_order > 0.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘bulk’
- requires#
(‘u’,)
- register(m)#
Register
nu, the yield stresstau_yand the regularization scaleeps_reg.
- expression(s)#
Return the regularized Bingham stress.
- class zoomy_core.model.models.closures.ElderViscosity(name=None, friction=None)#
Bases:
zoomy_core.model.models.closures.ClosureAlgebraic Elder eddy viscosity
nu_t = kappa u_star h zeta (1 - zeta), polynomial in zeta so the Galerkin projection closes analytically.Args
friction: optional bed closure whose livefriction_velocityreplaces theu_starparameter.
References
Elder 1959, https://doi.org/10.1017/s0022112059000374
Initialization
Store the optional bed closure supplying
u_star.- closes#
‘bulk’
- requires#
(‘u’,)
- register(m)#
Register
kappa,u_star,nuand the parameters of the bed closure, if any.
- expression(s)#
Return
rho (nu + nu_t) d_z uwith the Eldernu_t.
Bases:
zoomy_core.model.models.closures.ClosureLinear Navier slip at the bed,
tau_b = lambda_s u_b.Initialization
Name the closure after its class and describe it by the component it closes.
‘bottom’
(‘u’,)
Register the slip coefficient
lambda_s.
Return
lambda_s u.
Tangential traction
lambda_s u_tper axis (reduces tolambda_s u_iunder small-slope scaling).
- class zoomy_core.model.models.closures.RoughWall(name=None)#
Bases:
zoomy_core.model.models.closures.ClosureTurbulent rough-wall bed drag
tau_b = rho C_f u_b |u_b|withC_f = (kappa/ln(z_p/z_0))^2andz_0 = k_s/30. Needsk_s(Nikuradse roughness),z_pandkappa.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘bottom’
- requires#
(‘u’,)
- register(m)#
Register
kappa,k_sandz_p.
- expression(s)#
Return
rho C_f u |u|.
- friction_velocity(s)#
Recovered bed friction velocity
sqrt(C_f) |u_b|of the horizontal bed trace, consumed byElderViscosity.
- traction(s)#
Quadratic bed drag as a vector traction
rho C_f |U_t| u_topposing the slip velocity, coupling the x/y components through|U_t|.
- class zoomy_core.model.models.closures.WallFunctionBed(name=None)#
Bases:
zoomy_core.model.models.closures.Closurek-epsilon rough-wall-function bed stress
tau_b = rho C_f |U_p| U_pwith the log-lawC_fofRoughWallbut the velocityU_pread at the near-wall heightzeta_p = z_p/hrather than at the bed trace. Needsk_s,z_pandkappa.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘bottom’
- requires#
(‘u’,)
- register(m)#
Register
kappa,k_sandz_p.
- expression(s)#
Scalar 1-D drag
rho C_f U_p |U_p|from the near-wall velocity.
- traction(s)#
Vector bed traction
rho C_f |U_p| U_pfrom the tangential velocity atzeta_p = z_p/h.
- class zoomy_core.model.models.closures.ManningFriction(name=None, h_floor=0.0)#
Bases:
zoomy_core.model.models.closures.ClosureManning bed friction as a bottom closure for depth-averaged SWE;
expressionis the rate-g n^2 |u| / max(h, h_floor)^(1/3)multiplying each velocity component.Args
h_floor: depth floor that keeps friction finite at the wet/dry interface.
Initialization
Store the depth floor
h_floor.- closes#
‘bottom’
- requires#
(‘u’, ‘h’)
- register(m)#
Register
gand the Manning coefficientn.
- expression(s)#
Return the friction rate (per unit velocity) for the depth-averaged SWE.
- traction(s)#
Bed shear stress vector
rho g n^2 |U_t| u_t / h^(1/3)for the moment hierarchy, the Manning analogue ofRoughWall.traction.
- class zoomy_core.model.models.closures.EddyViscosity(name=None)#
Bases:
zoomy_core.model.models.closures.ClosureHorizontal eddy viscosity closure for the depth-averaged mixing
div(nu h grad u);expressionreturns the isotropicnuand the SWE model builds the diffusion tensor from it.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘horizontal’
- requires#
(‘u’,)
- register(m)#
Register the kinematic viscosity
nu.
- expression(s)#
Return
nu.
- class zoomy_core.model.models.closures.StressFree(name=None)#
Bases:
zoomy_core.model.models.closures.ClosureStress-free free surface,
tau(1) = 0.Initialization
Name the closure after its class and describe it by the component it closes.
- closes#
‘surface’
- requires#
()
- expression(s)#
Return zero.
- traction(s)#
Zero tangential traction on every axis; the free-surface pressure is left to the hydrostatic step.
- class zoomy_core.model.models.closures.InterfaceQuantity#
Bases:
zoomy_core.misc.options.OptionThe interface value an
InterfaceFluxscheme supplies.Initialization
Initialize self. See help(type(self)) for accurate signature.
- velocity#
‘velocity’
- stress#
‘stress’
- class zoomy_core.model.models.closures.InterfaceFlux(name=None, quantity=None)#
Bases:
zoomy_core.model.models.closures.ClosureBase of the multilayer interface schemes;
expression(below, above, G)takes the two one-sided interface traces and the interface mass fluxG.Args
quantity: theInterfaceQuantityit supplies.
Initialization
Store the
quantitythis scheme supplies (default: the transfer velocity).- closes#
‘interface’
- requires#
()
- abstract expression(below, above, G)#
Return the shared interface velocity
u*(override).
- class zoomy_core.model.models.closures.MeanInterface(name=None, quantity=None)#
Bases:
zoomy_core.model.models.closures.InterfaceFluxCentral interface velocity
u* = (u_below + u_above)/2.Initialization
Store the
quantitythis scheme supplies (default: the transfer velocity).- expression(below, above, G)#
Return the arithmetic mean of the two traces.
- class zoomy_core.model.models.closures.UpwindInterface(name=None, quantity=None)#
Bases:
zoomy_core.model.models.closures.InterfaceFluxDonor interface velocity chosen by the sign of the interface flux,
u* = u_belowifG >= 0elseu_above.References
Audusse et al. 2011, https://doi.org/10.1051/m2an/2010036
Initialization
Store the
quantitythis scheme supplies (default: the transfer velocity).- expression(below, above, G)#
Return the upwind trace selected by the sign of
G.
- zoomy_core.model.models.closures.apply_layer_stress_closures(closures, m, axes, state, *, is_top, is_bottom)#
Per-layer variant of
apply_stress_closuresfor the multilayer models: the surface closure acts only on the top layer and the bed closure only on the bottom layer.With the full tensor (
Stress.full) every trace carries the layer’s own in-plane traction (_inplane_traction), so the layer’s in-plane term isd_e(h_l <tau_de - delta_de tau_zz>), and the bulk shear itsrho nu d_d wpart; at an internal interface the trace is that own part only, and the model adds the shared, single-valued rest of the traction (interface_traction).Args
is_top: this layer carries the free surface.is_bottom: this layer sits on the bed.
Returns
True iff a bulk closure was applied.
- zoomy_core.model.models.closures.interface_closure(closures, quantity=InterfaceQuantity.velocity)#
Return the
InterfaceFluxclosure forquantityinclosures, orNone.
- zoomy_core.model.models.closures.interface_traction(closures, stress, below, above, G)#
Shared, single-valued part of the traction at an internal layer interface
z_l, per axis,sum_e sigma*_de d_e z_l - tau*_dz, orNonewithout the full tensor (stress).sigma*(oftau_de - delta_de tau_zz) andtau*(of the sheartau_dz) are the interface values of the two one-sided traces (below: top trace of the lower layer,above: bottom trace of the upper layer, bothClosureState) by theInterfaceFluxclosure withquantity=InterfaceQuantity.stress, by default their mean. Each layer’s trace carries only its own in-plane part (apply_layer_stress_closures); the model adds this shared part like the transfer term (+at the top of the layer below,-at the bottom of the layer above), so the interface tractiontau*_dz - sigma*_de d_e z_lis single-valued and the layer terms telescope.
- zoomy_core.model.models.closures.swe_closure_state(model)#
Build a
ClosureStateover a depth-averaged SWE model, exposings.u,s.w,s.h,s.speed(floored horizontal magnitude) ands.par, with velocity desingularised through thehinvaux.