pure subroutine ocean_channel_drag_compute_tendencies(grid, metrics, this, ms)
!! Per-layer lateral side-wall (channel) Rayleigh RATE
!! (`lambda_side_u/v`, 1/s) for every velocity face whose
!! cross-stream perimeter is partially blocked by land or a vanished
!! (sloping-bathymetry) neighbour layer — fires at EVERY layer k that
!! intersects the obstruction, not just the bed.
!! `f_blocked` = perimeter fraction blocked, summed over the two
!! flanking `wet_q` corners (each weighted 0.5), with a corner
!! also counted blocked when its two cross-stream cells' min
!! `h_layer < SIDE_H_VANISH`.
!! `lambda = cdrag_side·|U_face|·f_blocked/max(W, eps)`, W the
!! cross-stream face length (`dyCu` u-face, `dxCv` v-face).
!! All-wet / flat-bottom ⇒ `f_blocked ≡ 0` ⇒ `lambda ≡ 0` (no-op);
!! `channel_drag=.false.` or `cdrag_side=0` short-circuits to zero.
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_bottom_drag_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
integer :: nx, ny, nz
nx = grid%nx_total
ny = grid%ny_total
nz = ms%nz_ml
call compute_channel_drag_rates(this%lambda_side_u%data, this%lambda_side_v%data, &
ms%u_face_x_layer, ms%v_face_y_layer, &
ms%h_layer, metrics%wet_q, &
metrics%dyCu, metrics%dxCv, &
this%channel_drag, this%cdrag_side, &
size(ms%u_face_x_layer, 1), size(ms%u_face_x_layer, 2), &
size(ms%v_face_y_layer, 1), size(ms%v_face_y_layer, 2), &
nx, ny, nz)
end subroutine ocean_channel_drag_compute_tendencies