Populate target_h(i,j,k) from the column-total depth (H,
constant per column for the ocean path; coastal would pass
the bathymetry) and the free-surface anomaly η.
Cases:
VCOORD_EULERIAN_Z — target_h(:,:,k) = H(:,:) · dsig(k).
The reference grid that rdb_ocean_vertical_advection
pins h_layer to via its cancellation trick. No η
dependence — that’s the whole point of the mode.
VCOORD_SIGMA — target_h(:,:,k) = (H + η) · dsig(k).
Pure terrain-following.
VCOORD_ZSTAR — MOM6 z* (ocean_vcoord_zstar_target): the
z_fixed nominal profile dilated per column by the free-surface
stretching, over a partial bed cell and inert bed fillers.
VCOORD_ZSIGMA / VCOORD_ZSTAR_SIGMA — smoothstep blends, see module head comment.
VCOORD_ZSTAR_FULL — walks the per-column z_ref(:, :, 0:nz)
table populated by build_zref_full. Surface layer absorbs
η; subsurface layers keep their reference thicknesses
when the column is at or above reference depth. When the
column is shallower than reference (η < 0), bed-side
layers vanish to zstar_h_min and the surface trim makes
sum(target_h) = H exactly. Mirrors coastal
vcoord_target_dz_column_zstar_full.
All cases preserve sum_k target_h(i,j,k) = H + η (or = H
for EULERIAN_Z). The remap kernel will rely on this.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_vcoord_t), | intent(inout) | :: | this | |||
| real(kind=wp), | intent(in) | :: | total_h(:,:) |
Column-total depth H(i, j) (m). |
||
| real(kind=wp), | intent(in) | :: | eta(:,:) |
Free-surface anomaly η(i, j) (m). |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | h_nominal |
pure subroutine ocean_vcoord_compute_target_h_impl(this, total_h, eta) !! Populate `target_h(i,j,k)` from the column-total depth (`H`, !! constant per column for the ocean path; coastal would pass !! the bathymetry) and the free-surface anomaly `η`. !! !! Cases: !! !! VCOORD_EULERIAN_Z — `target_h(:,:,k) = H(:,:) · dsig(k)`. !! The reference grid that `rdb_ocean_vertical_advection` !! pins `h_layer` to via its cancellation trick. No η !! dependence — that's the whole point of the mode. !! !! VCOORD_SIGMA — `target_h(:,:,k) = (H + η) · dsig(k)`. !! Pure terrain-following. !! !! VCOORD_ZSTAR — MOM6 z* (`ocean_vcoord_zstar_target`): the !! `z_fixed` nominal profile dilated per column by the free-surface !! stretching, over a partial bed cell and inert bed fillers. !! !! VCOORD_ZSIGMA / VCOORD_ZSTAR_SIGMA — smoothstep blends, see !! module head comment. !! !! VCOORD_ZSTAR_FULL — walks the per-column `z_ref(:, :, 0:nz)` !! table populated by `build_zref_full`. Surface layer absorbs !! η; subsurface layers keep their reference thicknesses !! when the column is at or above reference depth. When the !! column is shallower than reference (η < 0), bed-side !! layers vanish to `zstar_h_min` and the surface trim makes !! sum(target_h) = H exactly. Mirrors coastal !! `vcoord_target_dz_column_zstar_full`. !! !! All cases preserve `sum_k target_h(i,j,k) = H + η` (or `= H` !! for EULERIAN_Z). The remap kernel will rely on this. type(ocean_vcoord_t), intent(inout) :: this ! assumed-shape-ok: cadence-bounded (once per outer ALE step); flat impl ! behind the thin ocean_vcoord_compute_target_h class wrapper below. real(wp), intent(in) :: total_h(:, :) !! Column-total depth H(i, j) (m). real(wp), intent(in) :: eta(:, :) ! assumed-shape-ok: same reason as total_h above !! Free-surface anomaly η(i, j) (m). real(wp) :: h_nominal if (.not. this%is_init) return ! Lagrangian / isopycnal: the target IS the current h_layer — ! nothing to compute, the ALE remap step is a no-op (see ! `ocean_apply_ale_remap_step`). Return before touching ! `target_h` so the caller keeps the live `h_layer`. if (this%coord_type == VCOORD_LAGRANGIAN) return ! VCOORD_LAGRANGIAN: target is whatever `h_layer` already is. The ! ALE remap is a no-op for this case (see `ocean_apply_ale_remap_step`), ! so `target_h` is never read; we can skip the compute entirely to ! avoid burning a kernel launch. if (this%coord_type == VCOORD_LAGRANGIAN) return ! Every loop runs in a flat kernel on explicit-shape / scalar dummies: ! no `this%` component and no `associate`-name reaches a ! `do concurrent` (ifx's do-concurrent -> OpenMP-target lowering ICEs ! on the former; the latter is the shape CLAUDE.md forbids — ifx ! evaluates such names as zero, and nvfortran -stdpar=gpu hands a ! by-reference one to a device callee as a HOST address, see ! `ocean_vcoord_rho_target`). if (this%coord_type == VCOORD_Z_FIXED) then ! Fixed-z (quasi-geopotential) interfaces with vanishing ! layers at BOTH ends: `h_min` fillers below the bed and — ! under a rigid top (`z_top > 0`, an ice-shelf cavity) — ! `h_min` fillers inside the ice, with a partial cell at each ! live end. See `ocean_vcoord_z_fixed_target`, which owns the ! algorithm and is shared with the initial-thickness seed. ! ! When `z_fixed_h_ref = 0` (knob unset) fall back to uniform ! `(H + η) · dsig(k)` so tests that omit the knob still get ! something sensible: the SIGMA branch of the geometric kernel ! evaluates exactly that expression. ! ! A stretched nominal profile (`z_fixed_use_profile`) replaces ! `h_nominal` with the per-layer `z_fixed_zi` / `z_fixed_dz` ! tables; the uniform path below is untouched. h_nominal = 0.0_wp if (this%z_fixed_h_ref > 0.0_wp) then h_nominal = this%z_fixed_h_ref/real(this%nz_ml, wp) end if if (this%z_fixed_use_profile .or. h_nominal > 0.0_wp) then call ocean_vcoord_z_fixed_target(this%target_h, total_h, eta, this%z_top, & this%nx_total, this%ny_total, this%nz_ml, & h_nominal, this%z_fixed_use_profile, & this%z_fixed_zi, this%z_fixed_dz, & this%zstar_h_min) return end if call ocean_vcoord_geometric_target(VCOORD_SIGMA, this%nx_total, this%ny_total, & this%nz_ml, this%target_h, total_h, eta, & this%dsig, this%z_ref_global, this%z_ref, & this%zsigma_depth_transition, & this%zsigma_blend_width, this%zstar_h_min) return end if if (this%coord_type == VCOORD_ZSTAR) then ! MOM6 z*: the `z_fixed` nominal profile (uniform `z_fixed_h_ref/nz` ! or the stretched `z_fixed_zi` table) dilated by the column's ! free-surface stretching. Same `z_fixed_h_ref = 0` fallback as ! `z_fixed` (uniform sigma) for a slot no profile was resolved on. h_nominal = 0.0_wp if (this%z_fixed_h_ref > 0.0_wp) then h_nominal = this%z_fixed_h_ref/real(this%nz_ml, wp) end if if (this%z_fixed_use_profile .or. h_nominal > 0.0_wp) then call ocean_vcoord_zstar_target(this%target_h, total_h, eta, & this%nx_total, this%ny_total, this%nz_ml, & h_nominal, this%z_fixed_use_profile, & this%z_fixed_zi, this%zstar_h_min) return end if call ocean_vcoord_geometric_target(VCOORD_SIGMA, this%nx_total, this%ny_total, & this%nz_ml, this%target_h, total_h, eta, & this%dsig, this%z_ref_global, this%z_ref, & this%zsigma_depth_transition, & this%zsigma_blend_width, this%zstar_h_min) return end if call ocean_vcoord_geometric_target(this%coord_type, this%nx_total, this%ny_total, & this%nz_ml, this%target_h, total_h, eta, & this%dsig, this%z_ref_global, this%z_ref, & this%zsigma_depth_transition, & this%zsigma_blend_width, this%zstar_h_min) end subroutine ocean_vcoord_compute_target_h_impl