Public only for the unit-test suite (no production module imports it); ignore when developing production code in other modules.
Fill b(:,:) with the Neverworld2 idealized-basin bathymetry
(Marques et al. 2022, GMD; MOM6-inspired). A single Pangaea-style
basin spanning a 60°×140° spherical sector with a re-entrant
(periodic-x) southern channel — the Drake-Passage analog. Depth is
built in normalized coordinates
x = (i_phys − 0.5)/nx_phys ∈ [0,1], y = (j_phys − 0.5)/ny_phys ∈ [0,1]
which equal MOM6’s (lon − west)/len_lon and (lat − south)/len_lat
on a uniform grid, so no metrics access is needed. The fractional
depth is
D_frac(x,y) = 1
− 1.1·spike(y−1, 0.12) ! great northern wall
− 1.1·spike(y, 0.12) ! Antarctica (south wall)
− A_c·[ continents + ridges ] ! A_c = nl_continent_amp
− A_r·cos(14πx)·sin(14πy) ! A_r = nl_roughness_amp
− A_r·cos(20πx)·cos(20πy)
clamped D_frac = max(D_frac, 0), then D = D_frac·max_depth. The
continent/ridge block carves two meridional barriers (S-America at the
x-edges, Africa mid-basin) that wall the northern gyres, plus the
Drake/Scotia ridge system that sets the channel sill; A_c=0 gives an
aquaplanet with the southern channel only (useful for bring-up).
Sign convention: b is bottom depth positive-down (matching the spoon
+ flat branches). Land emerges where D_frac→0 (the wet/dry mask is
seeded downstream from b ≥ LAND_DEPTH_THRESHOLD).
GHOST-ROW FOOTGUN (load-bearing): the loop runs over the FULL array
incl. ghost rows. Leaving ghosts at the alloc-time zero gives
h_layer = 0 there, sending the EOS into its vanishing-layer fallback
(rho_layer = rho_0) → a spurious density jump at wall-adjacent faces
→ ~12-h e-fold blowup (the same trap the spoon/seamount setters guard).
Host only — call enter_data afterwards.
MPI: the normalised coordinates divide by the GLOBAL extents
grid%nx_global / grid%ny_global, and local cell indices are
mapped to global physical indices with grid%i_offset_global /
grid%j_offset_global, so x/y sweep [0,1] across the WHOLE
basin. Normalised by the LOCAL extents instead, every rank would
rebuild the entire Pangaea basin — walls, continents and all —
inside its own tile. On a single rank the offsets are 0 and
global == local, so the fill is byte-identical.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | b(:,:) | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| real(kind=wp), | intent(in) | :: | max_depth | |||
| real(kind=wp), | intent(in) | :: | nl_continent_amp | |||
| real(kind=wp), | intent(in) | :: | nl_roughness_amp | |||
| real(kind=wp), | intent(in) | :: | min_depth |
Floor on the resulting depth (m). The fractional-depth formula
produces b in [0, ~1.1*max_depth]; the |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private, | parameter | :: | PI | = | 4.0_wp*atan(1.0_wp) | |
| real(kind=wp), | private | :: | d_frac | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | i_phys | ||||
| integer, | private | :: | ioff | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | j_phys | ||||
| integer, | private | :: | joff | ||||
| integer, | private | :: | ng | ||||
| real(kind=wp), | private | :: | nxp | ||||
| real(kind=wp), | private | :: | nyp | ||||
| real(kind=wp), | private | :: | x | ||||
| real(kind=wp), | private | :: | y |
subroutine set_bathymetry_neverworld2(b, grid, max_depth, nl_continent_amp, nl_roughness_amp, min_depth) !! Public only for the unit-test suite (no production module imports it); !! ignore when developing production code in other modules. !! !! Fill `b(:,:)` with the **Neverworld2** idealized-basin bathymetry !! (Marques et al. 2022, GMD; MOM6-inspired). A single Pangaea-style !! basin spanning a 60°×140° spherical sector with a re-entrant !! (periodic-x) southern channel — the Drake-Passage analog. Depth is !! built in **normalized coordinates** !! !! x = (i_phys − 0.5)/nx_phys ∈ [0,1], y = (j_phys − 0.5)/ny_phys ∈ [0,1] !! !! which equal MOM6's `(lon − west)/len_lon` and `(lat − south)/len_lat` !! on a uniform grid, so no metrics access is needed. The fractional !! depth is !! !! D_frac(x,y) = 1 !! − 1.1·spike(y−1, 0.12) ! great northern wall !! − 1.1·spike(y, 0.12) ! Antarctica (south wall) !! − A_c·[ continents + ridges ] ! A_c = nl_continent_amp !! − A_r·cos(14πx)·sin(14πy) ! A_r = nl_roughness_amp !! − A_r·cos(20πx)·cos(20πy) !! !! clamped `D_frac = max(D_frac, 0)`, then `D = D_frac·max_depth`. The !! continent/ridge block carves two meridional barriers (S-America at the !! x-edges, Africa mid-basin) that wall the northern gyres, plus the !! Drake/Scotia ridge system that sets the channel sill; `A_c=0` gives an !! aquaplanet with the southern channel only (useful for bring-up). !! !! Sign convention: `b` is bottom depth positive-down (matching the spoon !! + flat branches). Land emerges where D_frac→0 (the wet/dry mask is !! seeded downstream from `b ≥ LAND_DEPTH_THRESHOLD`). !! !! GHOST-ROW FOOTGUN (load-bearing): the loop runs over the FULL array !! incl. ghost rows. Leaving ghosts at the alloc-time zero gives !! `h_layer = 0` there, sending the EOS into its vanishing-layer fallback !! (`rho_layer = rho_0`) → a spurious density jump at wall-adjacent faces !! → ~12-h e-fold blowup (the same trap the spoon/seamount setters guard). !! Host only — call `enter_data` afterwards. !! !! MPI: the normalised coordinates divide by the GLOBAL extents !! `grid%nx_global` / `grid%ny_global`, and local cell indices are !! mapped to global physical indices with `grid%i_offset_global` / !! `grid%j_offset_global`, so `x`/`y` sweep [0,1] across the WHOLE !! basin. Normalised by the LOCAL extents instead, every rank would !! rebuild the entire Pangaea basin — walls, continents and all — !! inside its own tile. On a single rank the offsets are 0 and !! global == local, so the fill is byte-identical. real(wp), intent(inout) :: b(:, :) type(hgrid_t), intent(in) :: grid real(wp), intent(in) :: max_depth, nl_continent_amp, nl_roughness_amp real(wp), intent(in) :: min_depth !! Floor on the resulting depth (m). The fractional-depth formula !! produces b in [0, ~1.1*max_depth]; the `1.1*spike` walls and the !! continent terms drive b to 0 (land) at the basin edges. The ocean !! C-grid dyn-core does not yet carry a robust wet/dry path, and true !! zero-depth land + the resulting sub-metre surface layers blow up !! within ~12 h. Flooring every cell to `min_depth` (MOM6's !! MINIMUM_DEPTH approach) turns the continents into shallow shelves !! that steer — rather than hard-block — the flow, keeping the basin !! all-wet and stable. Lower values give stronger topographic !! steering at the cost of thinner layers (min_depth/nz); true land !! barriers wait on the wet/dry-plumbing follow-up. real(wp), parameter :: PI = 4.0_wp*atan(1.0_wp) real(wp) :: x, y, d_frac, nxp, nyp integer :: i, j, i_phys, j_phys, ng, ioff, joff ng = grid%nghost ioff = grid%i_offset_global joff = grid%j_offset_global nxp = real(grid%nx_global, wp) nyp = real(grid%ny_global, wp) do j = 1, size(b, 2) ! GLOBAL physical indices of this local cell. j_phys = j - ng + joff y = (real(j_phys, wp) - 0.5_wp)/nyp do i = 1, size(b, 1) i_phys = i - ng + ioff x = (real(i_phys, wp) - 0.5_wp)/nxp d_frac = 1.0_wp & - 1.1_wp*nw2_spike(y - 1.0_wp, 0.12_wp) & ! great northern wall - 1.1_wp*nw2_spike(y, 0.12_wp) & ! Antarctica (south wall) - nl_continent_amp*( & (1.2_wp*nw2_spike(x, 0.2_wp) + 1.2_wp*nw2_spike(x - 1.0_wp, 0.2_wp)) & *nw2_spike(min(0.0_wp, y - 0.3_wp), 0.2_wp) & ! South America + 1.2_wp*nw2_spike(x - 0.5_wp, 0.2_wp) & *nw2_spike(min(0.0_wp, y - 0.55_wp), 0.2_wp) & ! Africa + 1.2_wp*(nw2_spike(x, 0.12_wp) + nw2_spike(x - 1.0_wp, 0.12_wp)) & *nw2_spike(max(0.0_wp, y - 0.06_wp), 0.12_wp) & ! Antarctic Peninsula + 0.1_wp*(nw2_cosbell(x, 0.1_wp) + nw2_cosbell(x - 1.0_wp, 0.1_wp)) & ! Drake Passage ridge + 0.5_wp*nw2_cosbell(x - 0.16_wp, 0.05_wp)*(nw2_cosbell(y - 0.18_wp, 0.13_wp)**0.4_wp) & ! Scotia Arc E + 0.4_wp*(nw2_cosbell(x - 0.09_wp, 0.08_wp)**0.4_wp)*nw2_cosbell(y - 0.26_wp, 0.05_wp) & ! Scotia Arc N + 0.4_wp*(nw2_cosbell(x - 0.08_wp, 0.08_wp)**0.4_wp)*nw2_cosbell(y - 0.1_wp, 0.05_wp)) & ! Scotia Arc S - nl_roughness_amp*cos(14.0_wp*PI*x)*sin(14.0_wp*PI*y) & ! roughness - nl_roughness_amp*cos(20.0_wp*PI*x)*cos(20.0_wp*PI*y) if (d_frac < 0.0_wp) d_frac = 0.0_wp b(i, j) = max(d_frac*max_depth, min_depth) end do end do end subroutine set_bathymetry_neverworld2