configure_ocean_k_bot Subroutine

public subroutine configure_ocean_k_bot(ocean_state, grid, compute_rank)

Fill ms%k_bot / k_bot_u / k_bot_v — the shared index of the first LIVE layer counting UP from the bed, and the field every bed-side consumer reads instead of spelling 1. The bed-side mirror of configure_ocean_k_top.

Under vcoord_type = "z_fixed" (with a resolved z_fixed_h_ref) every column shallower than the nominal stack carries inert FILLERS at zstar_h_min below its partial bed cell, so k = 1 is not the bed-adjacent layer: a bottom drag, an implicit-drag diagonal, a geothermal deposit or a tidal-mixing bed anchor put on k = 1 lands on a layer the vdiff solve has cut out of the column. Unlike k_top this is NOT gated on a cavity — bed fillers exist on every z_fixed run with topography.

Static. Read ONCE from ocean_vcoord_z_fixed_target at eta = 0 — the same kernel, bt_H_ref, z_top and profile the closed-face mask and k_top are built from (one definition of “live”). The bed is static and eta is absorbed by the first live layer at the TOP, so the bed-side pattern never moves. It is derived from bathymetry + the vcoord config, so it is rebuilt on every start (cold or warm) and is not restart state.

Every other coordinate is a literal no-op: the arrays were allocated at source = 1 in multilayer_state_init, which IS the answer wherever nothing vanishes against the bed.

Seams. The centre index is built from the ghost-filled bt_H_ref, so it is seam-correct by construction; the OUTERMOST face of each face twin cannot be evaluated locally (it needs a cell beyond the array) and takes its one column. A plain face halo exchange (integer → real → integer: the halo layer moves real(wp), and an integer < 2**53 round-trips exactly) makes that ghost face carry its owner’s value on a tile seam or a periodic wrap. Single-rank non-periodic: a no-op.

Ordering. Same as configure_ocean_k_top: after the cavity draft, after configure_ocean_bt_split (bt_H_ref), after the periodic-wrap / halo pass, BEFORE ocean_state_enter_data (the host fill is what the copyin captures).

Arguments

Type IntentOptional Attributes Name
type(ocean_state_t), intent(inout) :: ocean_state
type(hgrid_t), intent(in) :: grid
integer, intent(in) :: compute_rank

Calls

proc~~configure_ocean_k_bot~~CallsGraph proc~configure_ocean_k_bot configure_ocean_k_bot info info proc~configure_ocean_k_bot->info interface~ocean_halo_face_x ocean_halo_face_x proc~configure_ocean_k_bot->interface~ocean_halo_face_x interface~ocean_halo_face_y ocean_halo_face_y proc~configure_ocean_k_bot->interface~ocean_halo_face_y proc~ocean_halo_is_init ocean_halo_is_init proc~configure_ocean_k_bot->proc~ocean_halo_is_init proc~ocean_vcoord_k_bot_from_target ocean_vcoord_k_bot_from_target proc~configure_ocean_k_bot->proc~ocean_vcoord_k_bot_from_target proc~ocean_vcoord_z_fixed_target ocean_vcoord_z_fixed_target proc~configure_ocean_k_bot->proc~ocean_vcoord_z_fixed_target to_string to_string proc~configure_ocean_k_bot->to_string proc~ocean_halo_face_x_2d ocean_halo_face_x_2d interface~ocean_halo_face_x->proc~ocean_halo_face_x_2d proc~ocean_halo_face_x_3d ocean_halo_face_x_3d interface~ocean_halo_face_x->proc~ocean_halo_face_x_3d proc~ocean_halo_face_y_2d ocean_halo_face_y_2d interface~ocean_halo_face_y->proc~ocean_halo_face_y_2d proc~ocean_halo_face_y_3d ocean_halo_face_y_3d interface~ocean_halo_face_y->proc~ocean_halo_face_y_3d local local proc~ocean_vcoord_k_bot_from_target->local proc~ocean_vcoord_z_fixed_target->local proc~ocean_halo_face_x_2d_impl ocean_halo_face_x_2d_impl proc~ocean_halo_face_x_2d->proc~ocean_halo_face_x_2d_impl proc~oh_count_face_x_2d oh_count_face_x_2d proc~ocean_halo_face_x_2d->proc~oh_count_face_x_2d comm_irecv_real_sp_array_n comm_irecv_real_sp_array_n proc~ocean_halo_face_x_3d->comm_irecv_real_sp_array_n comm_isend_real_sp_array_n comm_isend_real_sp_array_n proc~ocean_halo_face_x_3d->comm_isend_real_sp_array_n proc~comm_env_compute_comm comm_env_compute_comm proc~ocean_halo_face_x_3d->proc~comm_env_compute_comm proc~ew_rank_east ew_rank_east proc~ocean_halo_face_x_3d->proc~ew_rank_east proc~ew_rank_west ew_rank_west proc~ocean_halo_face_x_3d->proc~ew_rank_west proc~needs_flags needs_flags proc~ocean_halo_face_x_3d->proc~needs_flags proc~ns_rank_north ns_rank_north proc~ocean_halo_face_x_3d->proc~ns_rank_north proc~ns_rank_south ns_rank_south proc~ocean_halo_face_x_3d->proc~ns_rank_south proc~ocean_halo_buffers_ensure_nz ocean_halo_buffers_ensure_nz proc~ocean_halo_face_x_3d->proc~ocean_halo_buffers_ensure_nz proc~ocean_periodic_wrap_face_x_3d ocean_periodic_wrap_face_x_3d proc~ocean_halo_face_x_3d->proc~ocean_periodic_wrap_face_x_3d proc~oh_count_face_x_3d oh_count_face_x_3d proc~ocean_halo_face_x_3d->proc~oh_count_face_x_3d proc~oh_count_msgs oh_count_msgs proc~ocean_halo_face_x_3d->proc~oh_count_msgs waitall waitall proc~ocean_halo_face_x_3d->waitall proc~ocean_halo_face_y_2d_impl ocean_halo_face_y_2d_impl proc~ocean_halo_face_y_2d->proc~ocean_halo_face_y_2d_impl proc~oh_count_face_y_2d oh_count_face_y_2d proc~ocean_halo_face_y_2d->proc~oh_count_face_y_2d proc~ocean_halo_face_y_3d->comm_irecv_real_sp_array_n proc~ocean_halo_face_y_3d->comm_isend_real_sp_array_n proc~ocean_halo_face_y_3d->proc~comm_env_compute_comm proc~ocean_halo_face_y_3d->proc~ew_rank_east proc~ocean_halo_face_y_3d->proc~ew_rank_west proc~ocean_halo_face_y_3d->proc~needs_flags proc~ocean_halo_face_y_3d->proc~ns_rank_north proc~ocean_halo_face_y_3d->proc~ns_rank_south proc~ocean_halo_face_y_3d->proc~ocean_halo_buffers_ensure_nz proc~ocean_periodic_wrap_face_y_3d ocean_periodic_wrap_face_y_3d proc~ocean_halo_face_y_3d->proc~ocean_periodic_wrap_face_y_3d proc~oh_count_face_y_3d oh_count_face_y_3d proc~ocean_halo_face_y_3d->proc~oh_count_face_y_3d proc~ocean_halo_face_y_3d->proc~oh_count_msgs proc~ocean_halo_face_y_3d->waitall comm_world comm_world proc~comm_env_compute_comm->comm_world proc~decomp_rank_from_coords decomp_rank_from_coords proc~ew_rank_east->proc~decomp_rank_from_coords proc~ew_rank_west->proc~decomp_rank_from_coords proc~ns_rank_north->proc~decomp_rank_from_coords proc~ns_rank_south->proc~decomp_rank_from_coords proc~ocean_halo_buffers_ensure_nz->to_string warning warning proc~ocean_halo_buffers_ensure_nz->warning proc~ocean_halo_face_x_2d_impl->comm_irecv_real_sp_array_n proc~ocean_halo_face_x_2d_impl->comm_isend_real_sp_array_n proc~ocean_halo_face_x_2d_impl->proc~comm_env_compute_comm proc~ocean_halo_face_x_2d_impl->proc~ew_rank_east proc~ocean_halo_face_x_2d_impl->proc~ew_rank_west proc~ocean_halo_face_x_2d_impl->proc~needs_flags proc~ocean_halo_face_x_2d_impl->proc~ns_rank_north proc~ocean_halo_face_x_2d_impl->proc~ns_rank_south proc~ocean_halo_face_x_2d_impl->proc~oh_count_msgs proc~ocean_halo_face_x_2d_impl->waitall proc~ocean_periodic_wrap_face_x_2d ocean_periodic_wrap_face_x_2d proc~ocean_halo_face_x_2d_impl->proc~ocean_periodic_wrap_face_x_2d proc~ocean_halo_face_y_2d_impl->comm_irecv_real_sp_array_n proc~ocean_halo_face_y_2d_impl->comm_isend_real_sp_array_n proc~ocean_halo_face_y_2d_impl->proc~comm_env_compute_comm proc~ocean_halo_face_y_2d_impl->proc~ew_rank_east proc~ocean_halo_face_y_2d_impl->proc~ew_rank_west proc~ocean_halo_face_y_2d_impl->proc~needs_flags proc~ocean_halo_face_y_2d_impl->proc~ns_rank_north proc~ocean_halo_face_y_2d_impl->proc~ns_rank_south proc~ocean_halo_face_y_2d_impl->proc~oh_count_msgs proc~ocean_halo_face_y_2d_impl->waitall proc~ocean_periodic_wrap_face_y_2d ocean_periodic_wrap_face_y_2d proc~ocean_halo_face_y_2d_impl->proc~ocean_periodic_wrap_face_y_2d

Called by

proc~~configure_ocean_k_bot~~CalledByGraph proc~configure_ocean_k_bot configure_ocean_k_bot proc~engine_setup engine_setup proc~engine_setup->proc~configure_ocean_k_bot 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~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 proc~rdb_ocean_create_from_string rdb_ocean_create_from_string proc~rdb_ocean_create_from_string->proc~complete_ocean_create

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private, allocatable :: eta0(:,:)
real(kind=wp), private, allocatable :: fx(:,:)
real(kind=wp), private, allocatable :: fy(:,:)
real(kind=wp), private :: h_min
real(kind=wp), private :: h_nominal
integer, private :: n_filler
integer, private :: nx
integer, private :: ny
integer, private :: nz
real(kind=wp), private, allocatable :: tgt(:,:,:)

Source Code

   subroutine configure_ocean_k_bot(ocean_state, grid, compute_rank)
      !! Fill `ms%k_bot` / `k_bot_u` / `k_bot_v` — the shared index of the
      !! first LIVE layer counting UP from the bed, and the field every
      !! bed-side consumer reads instead of spelling `1`.  The bed-side
      !! mirror of `configure_ocean_k_top`.
      !!
      !! Under `vcoord_type = "z_fixed"` (with a resolved `z_fixed_h_ref`)
      !! every column shallower than the nominal stack carries inert
      !! FILLERS at `zstar_h_min` below its partial bed cell, so `k = 1`
      !! is not the bed-adjacent layer: a bottom drag, an implicit-drag
      !! diagonal, a geothermal deposit or a tidal-mixing bed anchor put
      !! on `k = 1` lands on a layer the vdiff solve has cut out of the
      !! column.  Unlike `k_top` this is NOT gated on a cavity — bed
      !! fillers exist on every `z_fixed` run with topography.
      !!
      !! **Static.** Read ONCE from `ocean_vcoord_z_fixed_target` at
      !! `eta = 0` — the same kernel, `bt_H_ref`, `z_top` and profile the
      !! closed-face mask and `k_top` are built from (one definition of
      !! "live").  The bed is static and `eta` is absorbed by the first
      !! live layer at the TOP, so the bed-side pattern never moves.  It
      !! is derived from bathymetry + the vcoord config, so it is rebuilt
      !! on every start (cold or warm) and is not restart state.
      !!
      !! **Every other coordinate is a literal no-op**: the arrays were
      !! allocated at `source = 1` in `multilayer_state_init`, which IS
      !! the answer wherever nothing vanishes against the bed.
      !!
      !! **Seams.** The centre index is built from the ghost-filled
      !! `bt_H_ref`, so it is seam-correct by construction; the OUTERMOST
      !! face of each face twin cannot be evaluated locally (it needs a
      !! cell beyond the array) and takes its one column.  A plain face
      !! halo exchange (integer → real → integer: the halo layer moves
      !! `real(wp)`, and an integer < 2**53 round-trips exactly) makes
      !! that ghost face carry its owner's value on a tile seam or a
      !! periodic wrap.  Single-rank non-periodic: a no-op.
      !!
      !! **Ordering.** Same as `configure_ocean_k_top`: after the cavity
      !! draft, after `configure_ocean_bt_split` (`bt_H_ref`), after the
      !! periodic-wrap / halo pass, BEFORE `ocean_state_enter_data` (the
      !! host fill is what the `copyin` captures).
      type(ocean_state_t), intent(inout) :: ocean_state
      type(hgrid_t), intent(in) :: grid
      integer, intent(in) :: compute_rank

      integer :: nx, ny, nz, n_filler
      real(wp) :: h_nominal, h_min
      real(wp), allocatable :: tgt(:, :, :), eta0(:, :), fx(:, :), fy(:, :)

      if (.not. ocean_state%multilayer%is_init) return
      if (ocean_state%vcoord%coord_type /= VCOORD_Z_FIXED) return
      if (ocean_state%vcoord%z_fixed_h_ref <= 0.0_wp) return
      if (.not. ocean_state%dyn%bt_work%is_init) return
      if (maxval(ocean_state%dyn%bt_work%bt_H_ref) <= 0.0_wp) return

      nx = grid%nx_total
      ny = grid%ny_total
      nz = ocean_state%multilayer%nz_ml
      h_nominal = ocean_state%vcoord%z_fixed_h_ref/real(nz, wp)
      h_min = ocean_state%vcoord%zstar_h_min

      allocate (tgt(nx, ny, nz), source=0.0_wp)
      allocate (eta0(nx, ny), source=0.0_wp)
      call ocean_vcoord_z_fixed_target(tgt, ocean_state%dyn%bt_work%bt_H_ref, &
                                       eta0, ocean_state%vcoord%z_top, &
                                       nx, ny, nz, h_nominal, &
                                       ocean_state%vcoord%z_fixed_use_profile, &
                                       ocean_state%vcoord%z_fixed_zi, &
                                       ocean_state%vcoord%z_fixed_dz, h_min)
      call ocean_vcoord_k_bot_from_target(ocean_state%multilayer%k_bot, &
                                          ocean_state%multilayer%k_bot_u, &
                                          ocean_state%multilayer%k_bot_v, &
                                          tgt, nx, ny, nz, H_VANISHED)
      deallocate (tgt, eta0)

      if (ocean_halo_is_init()) then
         allocate (fx(nx + 1, ny), fy(nx, ny + 1))
         fx = real(ocean_state%multilayer%k_bot_u, wp)
         fy = real(ocean_state%multilayer%k_bot_v, wp)
         call ocean_halo_face_x(fx, device_resident=.false.)
         call ocean_halo_face_y(fy, device_resident=.false.)
         ocean_state%multilayer%k_bot_u = nint(fx)
         ocean_state%multilayer%k_bot_v = nint(fy)
         deallocate (fx, fy)
      end if

      n_filler = count(ocean_state%multilayer%k_bot > 1)
      if (compute_rank == 0) then
         call logger%info("z_fixed k_bot: "//to_string(n_filler)//"/"// &
                          to_string(nx*ny)//" columns carry bed-side "// &
                          "fillers (k_bot > 1); max k_bot = "// &
                          to_string(maxval(ocean_state%multilayer%k_bot))// &
                          ", nz = "//to_string(nz))
      end if
   end subroutine configure_ocean_k_bot