Barotropic-Baroclinic Mode Splitting
A critical feature of NeuralPOM is the separation of the ocean circulation into fast barotropic (external) modes and slow baroclinic (internal) modes. This mode splitting allows the model to efficiently handle both the rapidly propagating surface gravity waves and the slower three-dimensional density-driven currents.
Motivation
The primitive equations support two distinct classes of motion:
| Mode | Character | Speed | Time Step Required |
|---|---|---|---|
| Barotropic (external) | Depth-independent, surface gravity waves | Small ( | |
| Baroclinic (internal) | Depth-dependent, density-driven | Larger ( |
Without splitting, the entire 3D model would be constrained by the CFL condition of the fastest surface waves. Mode splitting solves the depth-integrated barotropic equations at a much smaller time step than the three-dimensional baroclinic equations, dramatically improving computational efficiency.
Depth-Integrated (Barotropic) Equations
The barotropic equations are obtained by vertically integrating the primitive equations from the bottom
Continuity (Free Surface Evolution)
where
The depth-integrated volume transports are:
Momentum (Depth-Integrated)
The
Baroclinic (Internal) Equations
The baroclinic equations describe the vertical structure of the flow. They are obtained by subtracting the depth-averaged (barotropic) flow from the full 3D flow:
The vertical shear evolves according to the 3D momentum equations:
where baropg().
The Free Surface as Coupling Variable
The free surface elevation
graph TD
A["3D Baroclinic Fields<br/>(u, v, T, S, ρ)"] -->|"Vertical integration<br/>of baroclinic PGF"| B["Barotropic RHS<br/>(F_U, F_V)"]
B --> C["Barotropic Solver<br/>(solve for η, U, V)"]
C -->|"Surface slope<br/>∂η/∂x, ∂η/∂y"| D["3D Momentum<br/>(pressure gradient term)"]
D -->|"Updated velocities"| A2
3
4
5
- Baroclinic to Barotropic: The vertically integrated baroclinic pressure gradient, advection, and diffusion terms are computed from 3D fields and passed to the barotropic solver as forcing terms.
- Barotropic to Baroclinic: The updated surface elevation
provides the surface slope component of the 3D pressure gradient for the next baroclinic time step.
In the code, the surface pressure gradient in advu is computed as:
# Gradient of Elevation (Future + Back)
grad_eg = (egf[s_i, s_j] - egf[s_im1, s_j]) + (egb[s_i, s_j] - egb[s_im1, s_j])
# Gradient of Atmos Pressure
grad_pa = 2.0 * (e_atmos[s_i, s_j] - e_atmos[s_im1, s_j])
press_grad = grav * 0.125 * _b(dt_sum * (grad_eg + grad_pa) * dy_sum)2
3
4
5
6
7
Here, egf and egb represent the forward and backward time levels of
Implicit Barotropic Formulation
NeuralPOM's implicit core (implicit_barotropic.py) solves the barotropic equations semi-implicitly, which relaxes the CFL constraint on surface gravity waves.
The Elliptic Equation for
The semi-implicit discretization leads to a Helmholtz-type elliptic equation for the free surface:
In operator form:
where
The elliptic operator is implemented in apply_elliptic_operator:
def apply_elliptic_operator(self, eta, d_2d):
# H at U/V faces (Arakawa C)
H_u_east = 0.5 * (d_2d[s_i_p1, s_j] + d_2d[s_i, s_j])
H_u_west = 0.5 * (d_2d[s_i, s_j] + d_2d[s_i_m1, s_j])
H_v_north = 0.5 * (d_2d[s_i, s_j_p1] + d_2d[s_i, s_j])
H_v_south = 0.5 * (d_2d[s_i, s_j] + d_2d[s_i, s_j_m1])
# Fluxes with land mask (dum @ U-faces, dvm @ V-faces)
flux_x_east = H_u_east * (eta[s_i_p1, s_j] - eta[s_i, s_j]) / dx_east * dy_east * dum
flux_x_west = H_u_west * (eta[s_i, s_j] - eta[s_i_m1, s_j]) / dx_west * dy_west * dum
flux_y_north = H_v_north * (eta[s_i, s_j_p1] - eta[s_i, s_j]) / dy_north * dx_north * dvm
flux_y_south = H_v_south * (eta[s_i, s_j] - eta[s_i, s_j_m1]) / dy_south * dx_south * dvm
div_flux = (flux_x_east - flux_x_west + flux_y_north - flux_y_south) / art
coeff = 4.0 * (self.dti ** 2) * self.grav * self.alpha
out[s_i, s_j] = eta[s_i, s_j] - coeff * div_flux
return out2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Conjugate Gradient Solver
The elliptic system
x = (2.0 * self.el - self.elb).clone() # warm start: linear extrapolation
r = rhs - self.apply_elliptic_operator(x, d_2d)
p = r.clone()
rs_old = (r * r).sum()
for it in range(max_iter):
Ap = self.apply_elliptic_operator(p, d_2d)
alpha = rs_old / (p * Ap).sum()
x += alpha * p
r -= alpha * Ap
rs_new = (r * r).sum()
if rs_new <= tol * tol:
break
beta = rs_new / rs_old
p = r + beta * p
rs_old = rs_new2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
A warm start using linear extrapolation in time (
Boundary Conditions for
The CG solver supports two types of boundary conditions:
| Problem Type | BC for | Description |
|---|---|---|
iproblem == 4, 5 (Double Gyre) | Dirichlet: | Rigid wall (closed basin) |
| Others | Neumann: | Ghost cell equals inner cell |
def _enforce_eta_neumann_bc(self, eta):
if self.iproblem == 4 or self.iproblem == 5:
# Dirichlet: rigid wall
eta[0, :] = 0.0
eta[-1, :] = 0.0
eta[:, 0] = 0.0
eta[:, -1] = 0.0
else:
# Neumann: ghost = inner
eta[0, :] = eta[1, :]
eta[-1, :] = eta[-2, :]
eta[:, 0] = eta[:, 1]
eta[:, -1] = eta[:, -2]2
3
4
5
6
7
8
9
10
11
12
13
Time Step Ratio
The barotropic time step is typically much smaller than the baroclinic time step:
Typical values:
| Configuration | Ratio | ||
|---|---|---|---|
| Coastal (1 km, 40 layers) | 30--60 s | 1--3 s | 1:20--1:30 |
| Basin-scale (10 km, 20 layers) | 300--600 s | 10--20 s | 1:30 |
| Deep ocean (25 km, 30 layers) | 900--1800 s | 30--60 s | 1:30 |
The barotropic solver is called multiple times per baroclinic step (typically 20--30 sub-steps), with the 3D baroclinic forcing terms held constant or linearly extrapolated over the barotropic sub-cycles. In the explicit core, the splitting may use a simpler forward-backward scheme for the barotropic mode.
Implementation Architecture
The two cores in NeuralPOM handle the mode splitting differently:
Explicit Core
- Uses a forward-backward time stepping for the barotropic mode
advave()computes the 2D external mode advection and diffusion at each barotropic sub-step- The barotropic mode is integrated in
time_loop.pywith a fixed number of sub-steps per baroclinic step
Implicit Core
- Uses the CG solver for the implicit free surface equation
solve_implicit_eta_cg()inimplicit_barotropic.pyhandles the elliptic solve- The
solution feeds back into the 3D pressure gradient throughegf/egbarrays
The key advantage of the implicit formulation is that the barotropic time step is no longer limited by the CFL condition for surface gravity waves, allowing larger
