z_fixed_nominal_dz Subroutine

public pure subroutine z_fixed_nominal_dz(profile, nz, h_ref, dz_list, dz_top, center, width, dz, ierr)

Nominal layer thicknesses of a VCOORD_Z_FIXED column, SURFACE FIRST (dz(1) is the top layer) — the order MOM6 writes ALE_COORDINATE_CONFIG = "PARAM:..." lists and vgrid files in. The caller flips to the bottom-up state convention.

  • ZFIXED_PROFILE_UNIFORM — dz = h_ref/nz.
  • ZFIXED_PROFILE_LIST — the leading positive entries of dz_list, which must number exactly nz (entries past them must be unset, i.e. <= 0). The total depth is whatever they sum to; a column deeper than that puts the excess in the bed layer, exactly as the uniform profile does below h_ref.
  • ZFIXED_PROFILE_TANH — a hyperbolic-tangent ramp in the layer INDEX n = 1..nz (surface first), from exactly dz_top at the surface to an emergent bottom thickness, scaled so the column sums to h_ref:

    s(n) = [tanh((n-c)/w) - tanh((1-c)/w)] / [tanh((nz-c)/w) - tanh((1-c)/w)] dz(n) = dz_top + A s(n), A = (h_ref - nz dz_top) / sum_n s(n)

with c = 1 + center (nz-1) and w = width (nz-1). s(1) = 0, s(nz) = 1 and s is increasing, so the profile is monotone and dz(1) = dz_top exactly. The same shape as MOM6’s OM4 z* grids (thin near the surface, a tanh transition, thick abyssal layers); h_ref = 6500, nz = 50, dz_top = 2, center = 0.5, width = 0.25 gives 2 m at the top and ~250 m at depth.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: profile

ZFIXED_PROFILE_* code.

integer, intent(in) :: nz

Number of layers.

real(kind=wp), intent(in) :: h_ref

Reference column depth (m) — &ocean_topo_nml max_depth.

real(kind=wp), intent(in) :: dz_list(:)

&vcoord_nml z_fixed_dz (m), surface first; <= 0 = unset.

real(kind=wp), intent(in) :: dz_top

tanh: surface-layer thickness (m).

real(kind=wp), intent(in) :: center

tanh: transition centre as a fraction of the index span [0, 1].

real(kind=wp), intent(in) :: width

tanh: transition width as a fraction of the index span (> 0).

real(kind=wp), intent(out) :: dz(nz)

Nominal thicknesses (m), surface first.

integer, intent(out) :: ierr

ZFIXED_DZ_* status.


Called by

proc~~z_fixed_nominal_dz~~CalledByGraph proc~z_fixed_nominal_dz z_fixed_nominal_dz proc~configure_ocean_z_fixed_profile configure_ocean_z_fixed_profile proc~configure_ocean_z_fixed_profile->proc~z_fixed_nominal_dz proc~validate_config validate_config proc~validate_config->proc~z_fixed_nominal_dz proc~build_pending_handle build_pending_handle proc~build_pending_handle->proc~validate_config proc~configure_ocean_lateral configure_ocean_lateral proc~configure_ocean_lateral->proc~configure_ocean_z_fixed_profile proc~engine_setup engine_setup proc~engine_setup->proc~configure_ocean_z_fixed_profile proc~engine_setup->proc~configure_ocean_lateral proc~complete_ocean_create complete_ocean_create proc~complete_ocean_create->proc~engine_setup proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_setup proc~driver_validate driver_validate proc~driver_validate->proc~engine_setup proc~rdb_ocean_create_from_string rdb_ocean_create_from_string proc~rdb_ocean_create_from_string->proc~build_pending_handle proc~rdb_ocean_create_from_string->proc~complete_ocean_create proc~rdb_ocean_create_pending rdb_ocean_create_pending proc~rdb_ocean_create_pending->proc~build_pending_handle proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean proc~rdb_ocean_create_finalize rdb_ocean_create_finalize proc~rdb_ocean_create_finalize->proc~complete_ocean_create

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: a
real(kind=wp), private :: c
integer, private :: n
integer, private :: n_set
real(kind=wp), private :: s(nz)
real(kind=wp), private :: s_sum
real(kind=wp), private :: t1
real(kind=wp), private :: tn
real(kind=wp), private :: w

Source Code

   pure subroutine z_fixed_nominal_dz(profile, nz, h_ref, dz_list, dz_top, center, width, &
                                      dz, ierr)
      !! Nominal layer thicknesses of a `VCOORD_Z_FIXED` column, SURFACE
      !! FIRST (`dz(1)` is the top layer) — the order MOM6 writes
      !! `ALE_COORDINATE_CONFIG = "PARAM:..."` lists and `vgrid` files in.
      !! The caller flips to the bottom-up state convention.
      !!
      !! * `ZFIXED_PROFILE_UNIFORM` — `dz = h_ref/nz`.
      !! * `ZFIXED_PROFILE_LIST` — the leading positive entries of
      !!   `dz_list`, which must number exactly `nz` (entries past them
      !!   must be unset, i.e. `<= 0`).  The total depth is whatever they
      !!   sum to; a column deeper than that puts the excess in the bed
      !!   layer, exactly as the uniform profile does below `h_ref`.
      !! * `ZFIXED_PROFILE_TANH` — a hyperbolic-tangent ramp in the layer
      !!   INDEX `n = 1..nz` (surface first), from exactly `dz_top` at the
      !!   surface to an emergent bottom thickness, scaled so the column
      !!   sums to `h_ref`:
      !!
      !!       s(n)  = [tanh((n-c)/w) - tanh((1-c)/w)] / [tanh((nz-c)/w) - tanh((1-c)/w)]
      !!       dz(n) = dz_top + A s(n),   A = (h_ref - nz dz_top) / sum_n s(n)
      !!
      !!   with `c = 1 + center (nz-1)` and `w = width (nz-1)`.  `s(1) = 0`,
      !!   `s(nz) = 1` and `s` is increasing, so the profile is monotone and
      !!   `dz(1) = dz_top` exactly.  The same shape as MOM6's OM4 z*
      !!   grids (thin near the surface, a tanh transition, thick abyssal
      !!   layers); `h_ref = 6500`, `nz = 50`, `dz_top = 2`, `center = 0.5`,
      !!   `width = 0.25` gives 2 m at the top and ~250 m at depth.
      integer, intent(in) :: profile
         !! `ZFIXED_PROFILE_*` code.
      integer, intent(in) :: nz
         !! Number of layers.
      real(wp), intent(in) :: h_ref
         !! Reference column depth (m) — `&ocean_topo_nml max_depth`.
      real(wp), intent(in) :: dz_list(:)
         !! `&vcoord_nml z_fixed_dz` (m), surface first; `<= 0` = unset.
      real(wp), intent(in) :: dz_top
         !! tanh: surface-layer thickness (m).
      real(wp), intent(in) :: center
         !! tanh: transition centre as a fraction of the index span `[0, 1]`.
      real(wp), intent(in) :: width
         !! tanh: transition width as a fraction of the index span (`> 0`).
      real(wp), intent(out) :: dz(nz)
         !! Nominal thicknesses (m), surface first.
      integer, intent(out) :: ierr
         !! `ZFIXED_DZ_*` status.
      integer :: n, n_set
      real(wp) :: c, w, t1, tn, s_sum, a
      real(wp) :: s(nz)

      dz = 0.0_wp
      ierr = ZFIXED_DZ_OK
      select case (profile)
      case (ZFIXED_PROFILE_UNIFORM)
         if (h_ref <= 0.0_wp) then
            ierr = ZFIXED_DZ_ERR_VALUE
            return
         end if
         dz = h_ref/real(nz, wp)
      case (ZFIXED_PROFILE_LIST)
         n_set = 0
         do n = 1, size(dz_list)
            if (dz_list(n) > 0.0_wp) then
               if (n_set /= n - 1) then
                  ierr = ZFIXED_DZ_ERR_COUNT
                  return
               end if
               n_set = n
            end if
         end do
         if (n_set /= nz) then
            ierr = ZFIXED_DZ_ERR_COUNT
            return
         end if
         dz = dz_list(1:nz)
      case (ZFIXED_PROFILE_TANH)
         if (h_ref <= 0.0_wp .or. dz_top <= 0.0_wp .or. width <= 0.0_wp .or. &
             center < 0.0_wp .or. center > 1.0_wp) then
            ierr = ZFIXED_DZ_ERR_VALUE
            return
         end if
         if (real(nz, wp)*dz_top >= h_ref) then
            ierr = ZFIXED_DZ_ERR_TOO_DEEP
            return
         end if
         if (nz == 1) then
            dz(1) = h_ref
            return
         end if
         c = 1.0_wp + center*real(nz - 1, wp)
         w = width*real(nz - 1, wp)
         t1 = tanh((1.0_wp - c)/w)
         tn = tanh((real(nz, wp) - c)/w)
         do n = 1, nz
            s(n) = (tanh((real(n, wp) - c)/w) - t1)/(tn - t1)
         end do
         s(1) = 0.0_wp
         s_sum = sum(s)
         a = (h_ref - real(nz, wp)*dz_top)/s_sum
         do n = 1, nz
            dz(n) = dz_top + a*s(n)
         end do
      case default
         ierr = ZFIXED_DZ_ERR_PROFILE
      end select
   end subroutine z_fixed_nominal_dz