Oceanography: units, equations and validation#

Conventions and model limits#

Depth is positive downward, but the density gradient for N squared is defined upward. Hydrostatic pressure is gauge pressure and omits atmospheric pressure. The linear density law is a local reference-state approximation, not TEOS-10. Choose anomalies and coefficients that keep density positive and the linearization small.

Geostrophic and Ekman helpers return signed scalar cross-gradient/cross-wind components; constructing a vector requires a consistent orientation. Coriolis parameter is signed, and zero is rejected. Volume transport is m^3/s; divide by 1e6 or convert to Sv for Sverdrups.

Surface-wave formulas assume small amplitude, no current and no capillarity. Finite-depth dispersion approaches shallow-water speed sqrt(g h) and deep-water speed sqrt(g/k). Deep-water group speed is half phase speed. The Rossby radius uses the first-mode constant-N estimate N H/(pi abs(f)), which differs from a reduced-gravity estimate. A harmonic tide with user parameters is not a local operational prediction.

Gerstner orbits use the rest depth of the orbit centre, positive downward, and require amplitude * wavenumber <= 1. The Ekman spiral returns the downwind and crosswind components on the last axis, with crosswind positive to the right of the wind; its depth integral equals ekman_transport with the same sign convention. The Stommel streamfunction uses x east from the western wall and y north from the southern wall, with zonal stress -wind_stress * cos(pi y / basin_length); positive stress gives a clockwise gyre and northward transport dpsi/dx. Sverdrup transport is per unit zonal width (m^2/s). In the two-box thermohaline model, positive overturning means polar sinking and the salt forcing is a virtual salt flux in g/kg m^3/s. The abyssal profile measures height upward from the bottom of the column. The simplified seawater density is the Roquet et al. (2015) S-EOS with NEMO’s default coefficients; it reproduces TEOS-10 gradients, including cabbeling and thermobaricity, but not TEOS-10 absolute density.

Input contracts#

Algebraic models accept finite real scalars or nonempty arrays. Booleans, complex inputs, nonnumeric values and NaN/Inf are rejected. Physical bounds apply element by element; NumPy broadcasting applies between arguments. No unit metadata are carried in raw numbers. Bounds protect mathematical domains and obvious physical contradictions, but do not establish model applicability.

Equation and output map#

hydrostatic_pressure#

earthsciencekit.oceanography.hydrostatic_pressure()

Output: Pa. Gauge pressure with constant density; atmospheric pressure is excluded.

density * gravity * depth

linear_density#

earthsciencekit.oceanography.linear_density()

Output: kg/m^3. Local linearization around a supplied reference; not TEOS-10 and no pressure dependence.

reference_density * (1 - thermal_expansion * temperature_anomaly + haline_contraction * salinity_anomaly)

buoyancy_frequency_squared#

earthsciencekit.oceanography.buoyancy_frequency_squared()

Output: 1/s^2. Coordinate increases upward; negative output denotes unstable stratification.

-gravity * upward_density_gradient / density

geostrophic_current#

earthsciencekit.oceanography.geostrophic_current()

Output: m/s. Signed cross-slope component away from the equator; no ageostrophic velocity.

gravity * surface_slope / coriolis

ekman_transport#

earthsciencekit.oceanography.ekman_transport()

Output: m^2/s. Signed cross-wind component per unit width; direction requires a consistent vector convention.

wind_stress / (density * coriolis)

inertial_period#

earthsciencekit.oceanography.inertial_period()

Output: s. No pressure gradient or friction; invalid at zero Coriolis parameter.

2 * np.pi / np.abs(coriolis)

shallow_wave_speed#

earthsciencekit.oceanography.shallow_wave_speed()

Output: m/s. Wavelength much greater than depth, small amplitude, no dispersion.

np.sqrt(gravity * depth)

deep_wave_speed#

earthsciencekit.oceanography.deep_wave_speed()

Output: m/s. Deep-water small-amplitude gravity waves without capillarity.

np.sqrt(gravity * wavelength / (2 * np.pi))

wave_angular_frequency#

earthsciencekit.oceanography.wave_angular_frequency()

Output: rad/s. Linear inviscid surface gravity wave, no current or surface tension.

np.sqrt(gravity * wavenumber * np.tanh(wavenumber * depth))

deep_group_speed#

earthsciencekit.oceanography.deep_group_speed()

Output: m/s. Deep-water gravity waves; group speed is half phase speed.

0.5 * np.sqrt(gravity * wavelength / (2 * np.pi))

rossby_radius#

earthsciencekit.oceanography.rossby_radius()

Output: m. First-mode constant-N rigid-boundary estimate N H over pi f; not a general layered solution.

buoyancy_frequency * depth / (np.pi * np.abs(coriolis))

reduced_gravity#

earthsciencekit.oceanography.reduced_gravity()

Output: m/s^2. Boussinesq small density contrast; output is acceleration.

gravity * density_difference / reference_density

internal_wave_speed#

earthsciencekit.oceanography.internal_wave_speed()

Output: m/s. Hydrostatic two-layer fluid under a rigid lid.

np.sqrt(reduced_gravity * upper_depth * lower_depth / (upper_depth + lower_depth))

volume_transport#

earthsciencekit.oceanography.volume_transport()

Output: m^3/s. Uniform signed velocity and rectangular section; output m cubed per second, not Sverdrups.

speed * width * depth

tidal_elevation#

earthsciencekit.oceanography.tidal_elevation()

Output: m. One supplied constituent; not a site-specific tide prediction or navigational product.

amplitude * np.cos(2 * np.pi * time / period + phase)

gerstner_orbit_radius#

earthsciencekit.oceanography.gerstner_orbit_radius()

Output: m. Exact deep-water trochoidal wave; requires amplitude * wavenumber <= 1.

amplitude * np.exp(-wavenumber * rest_depth)

ekman_spiral_velocity#

earthsciencekit.oceanography.ekman_spiral_velocity()

Output: m/s, shape (…, 2). Steady, infinitely deep, constant eddy viscosity; crosswind positive to the right of the wind.

d = np.sqrt(2 * eddy_viscosity / abs(coriolis))
v0 = wind_stress / (density * np.sqrt(eddy_viscosity * abs(coriolis)))
s = depth / d
v0 * np.exp(-s) * [np.sin(np.pi / 4 - s), np.sign(coriolis) * np.cos(np.pi / 4 - s)]

sverdrup_transport#

earthsciencekit.oceanography.sverdrup_transport()

Output: m^2/s. Steady linear interior balance away from boundaries and the equator.

wind_stress_curl / (density * beta)

stommel_streamfunction#

earthsciencekit.oceanography.stommel_streamfunction()

Output: m^3/s. Steady linear barotropic gyre with bottom friction in a rectangular basin.

k = np.pi / basin_length
m1, m2 = (-beta + np.sqrt(beta**2 + 4 * friction**2 * k**2)) / (2 * friction), (-beta - ...) / (2 * friction)
L = basin_width
X = 1 + ((np.exp(m2 * L) - 1) * np.exp(m1 * (x - L)) + (np.exp(-m1 * L) - 1) * np.exp(m2 * x)) / (1 - np.exp((m2 - m1) * L))
wind_stress * basin_length / (np.pi * density * friction) * np.sin(np.pi * y / basin_length) * X

thermohaline_forcing#

earthsciencekit.oceanography.thermohaline_forcing()

Output: g/kg m^3/s. Stommel two-box steady state with fixed temperatures; folds at flow = thermal_flow / 2.

np.abs(flow) * (thermal_flow - flow) / haline_coefficient

abyssal_temperature#

earthsciencekit.oceanography.abyssal_temperature()

Output: K. Steady one-dimensional upwelling-diffusion balance with fixed end temperatures.

h = diffusivity / upwelling
bottom_temperature + (top_temperature - bottom_temperature) * (np.exp((height - column_height) / h) - np.exp(-column_height / h)) / (1 - np.exp(-column_height / h))

simplified_seawater_density#

earthsciencekit.oceanography.simplified_seawater_density()

Output: kg/m^3. Roquet et al. (2015) fit to TEOS-10 gradients; not TEOS-10 absolute density.

t, s = conservative_temperature - 283.15, absolute_salinity - 35
1026 - a0 * (1 + lambda1 * t / 2 + mu1 * depth) * t + b0 * (1 - lambda2 * s / 2 - mu2 * depth) * s - nu * t * s

Thermohaline boxes#

earthsciencekit.oceanography.simulate_thermohaline_boxes() integrates volume * dS/dt = salt_forcing - abs(q) * dS with q = thermal_flow - haline_coefficient * dS and returns the salinity difference and the overturning. Its steady states satisfy thermohaline_forcing; below the fold the initial salinity difference selects the thermal or the haline state.

Independent validation#

Every algebraic API has a fixed-value check, broadcasting check and invalid-input contracts. The shared suite adds cross-model identities, energy/conservation checks and independent analytic solutions for dynamics. See Validation policy for the exact evidence and Numerical methods and sampled results for numerical conventions.