Partial-step z-level FACE CLOSURE mask for VCOORD_Z_FIXED
(&vcoord_nml zfixed_closed_faces; Adcroft, Hill & Marshall
1997; Losch 2008 §2.1 for the ice-shelf cavity).
Under z_fixed a layer whose nominal geopotential range lies
inside the bed — or inside the ice draft — is an inert FILLER of
thickness zstar_h_min (<= h_vanished). A velocity face at
which layer k is a filler on EITHER side is not a thin
passage: geometrically there is no water there on one side, so
it is a WALL for that layer — no normal velocity, no mass or
tracer flux, free-slip on the tangential component. This marks
those faces.
open_u(I,j,k) = 1 iff target_h(I-1,j,k) > h_vanished
.and. target_h(I ,j,k) > h_vanished
and the v-face mirror. The mask is STATIC: the bed and the
draft are static, and under z_fixed η is absorbed by the
first LIVE layer (the partial cell) — a filler’s target is
zstar_h_min whatever η does — so the live/filler pattern
does not move. Build it once, from
ocean_vcoord_z_fixed_target at η = 0, so there is exactly
ONE definition of “live” shared with the ALE regrid and the IC
seed.
The mask is a THIRD, independent factor on the face width, not a replacement for either of the other two:
dy_eff(I,j,k) = dy_cu(I,j) · por_face_area_u(I,j,k) · open_u(I,j,k)
land (2-D) porous (subgrid) z-level (per layer)
I = 1 and I = nx+1 are left fully OPEN (1), exactly as the
porous kernel leaves them: their dy_cu is already zero and the
continuity wall zeroing owns them. The PHYSICAL seam of a
periodic axis is an interior index (nghost+1), so it is
covered by the 2:nx sweep — provided the caller built
target_h from GHOST-FILLED inputs (bt_H_ref and z_top are
periodic-wrapped + halo-exchanged before this runs).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(out) | :: | open_u(nx+1,ny,nz) |
u-face 0/1 open mask. |
||
| real(kind=wp), | intent(out) | :: | open_v(nx,ny+1,nz) |
v-face 0/1 open mask. |
||
| real(kind=wp), | intent(in) | :: | target_h(nx,ny,nz) |
The |
||
| integer, | intent(in) | :: | nx |
i-extent of the CENTRE arrays (total, incl. halos). |
||
| integer, | intent(in) | :: | ny |
j-extent of the CENTRE arrays (total, incl. halos). |
||
| integer, | intent(in) | :: | nz |
Number of layers; |
||
| real(kind=wp), | intent(in) | :: | h_vanished |
Inert-filler marker ( |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | i | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | k |
pure subroutine ocean_vcoord_closed_face_masks(open_u, open_v, target_h, & nx, ny, nz, h_vanished) !! Partial-step z-level FACE CLOSURE mask for `VCOORD_Z_FIXED` !! (`&vcoord_nml zfixed_closed_faces`; Adcroft, Hill & Marshall !! 1997; Losch 2008 §2.1 for the ice-shelf cavity). !! !! Under `z_fixed` a layer whose nominal geopotential range lies !! inside the bed — or inside the ice draft — is an inert FILLER of !! thickness `zstar_h_min` (`<= h_vanished`). A velocity face at !! which layer `k` is a filler on EITHER side is not a thin !! passage: geometrically there is no water there on one side, so !! it is a **WALL for that layer** — no normal velocity, no mass or !! tracer flux, free-slip on the tangential component. This marks !! those faces. !! !! ### The rule, in one line !! !! ``` !! open_u(I,j,k) = 1 iff target_h(I-1,j,k) > h_vanished !! .and. target_h(I ,j,k) > h_vanished !! ``` !! and the v-face mirror. The mask is **STATIC**: the bed and the !! draft are static, and under `z_fixed` `η` is absorbed by the !! first LIVE layer (the partial cell) — a filler's target is !! `zstar_h_min` whatever `η` does — so the live/filler pattern !! does not move. Build it once, from !! `ocean_vcoord_z_fixed_target` at `η = 0`, so there is exactly !! ONE definition of "live" shared with the ALE regrid and the IC !! seed. !! !! ### Composition !! !! The mask is a THIRD, independent factor on the face width, not a !! replacement for either of the other two: !! ``` !! dy_eff(I,j,k) = dy_cu(I,j) · por_face_area_u(I,j,k) · open_u(I,j,k) !! land (2-D) porous (subgrid) z-level (per layer) !! ``` !! !! ### Array-edge faces !! !! `I = 1` and `I = nx+1` are left fully OPEN (1), exactly as the !! porous kernel leaves them: their `dy_cu` is already zero and the !! continuity wall zeroing owns them. The PHYSICAL seam of a !! periodic axis is an interior index (`nghost+1`), so it is !! covered by the `2:nx` sweep — provided the caller built !! `target_h` from GHOST-FILLED inputs (`bt_H_ref` and `z_top` are !! periodic-wrapped + halo-exchanged before this runs). integer, intent(in) :: nx !! i-extent of the CENTRE arrays (total, incl. halos). integer, intent(in) :: ny !! j-extent of the CENTRE arrays (total, incl. halos). integer, intent(in) :: nz !! Number of layers; `k = 1` is the bed, `k = nz` the top. real(wp), intent(out) :: open_u(nx + 1, ny, nz) !! u-face 0/1 open mask. real(wp), intent(out) :: open_v(nx, ny + 1, nz) !! v-face 0/1 open mask. real(wp), intent(in) :: target_h(nx, ny, nz) !! The `z_fixed` target thickness at `η = 0`. real(wp), intent(in) :: h_vanished !! Inert-filler marker (`H_VANISHED`). A layer is LIVE iff its !! target thickness is strictly greater than this. integer :: i, j, k do concurrent(k=1:nz, j=1:ny, i=1:nx + 1) open_u(i, j, k) = 1.0_wp end do do concurrent(k=1:nz, j=1:ny + 1, i=1:nx) open_v(i, j, k) = 1.0_wp end do do concurrent(k=1:nz, j=1:ny, i=2:nx) if (target_h(i - 1, j, k) > h_vanished .and. & target_h(i, j, k) > h_vanished) then open_u(i, j, k) = 1.0_wp else open_u(i, j, k) = 0.0_wp end if end do do concurrent(k=1:nz, j=2:ny, i=1:nx) if (target_h(i, j - 1, k) > h_vanished .and. & target_h(i, j, k) > h_vanished) then open_v(i, j, k) = 1.0_wp else open_v(i, j, k) = 0.0_wp end if end do end subroutine ocean_vcoord_closed_face_masks