vcoord_init Subroutine

private subroutine vcoord_init(self, nz, coord_type, remap_method)

Initialise a vertical coordinate definition. Allocates + populates dsig_target for the given type. Unknown types: error stop.

Type Bound

vcoord_t

Arguments

Type IntentOptional Attributes Name
class(vcoord_t), intent(inout) :: self
integer, intent(in) :: nz

Number of vertical layers

integer, intent(in) :: coord_type

Coordinate type constant (VCOORD_SIGMA, etc.)

integer, intent(in) :: remap_method

Remapping method constant (REMAP_PLM, etc.)


Calls

proc~~vcoord_init~~CallsGraph proc~vcoord_init vcoord_t%vcoord_init error error proc~vcoord_init->error proc~nz_stack_is_sufficient nz_stack_is_sufficient proc~vcoord_init->proc~nz_stack_is_sufficient proc~nz_stack_required nz_stack_required proc~vcoord_init->proc~nz_stack_required to_string to_string proc~vcoord_init->to_string warning warning proc~vcoord_init->warning proc~nz_stack_is_sufficient->proc~nz_stack_required

Source Code

   subroutine vcoord_init(self, nz, coord_type, remap_method)
      !! Initialise a vertical coordinate definition. Allocates + populates
      !! `dsig_target` for the given type. Unknown types: error stop.
      class(vcoord_t), intent(inout) :: self
      integer, intent(in) :: nz
         !! Number of vertical layers
      integer, intent(in) :: coord_type
         !! Coordinate type constant (VCOORD_SIGMA, etc.)
      integer, intent(in) :: remap_method
         !! Remapping method constant (REMAP_PLM, etc.)

      self%nz = nz
      self%coord_type = coord_type
      self%remap_method = remap_method

      ! (Re)allocate target distribution
      if (allocated(self%dsig_target)) deallocate (self%dsig_target)
      allocate (self%dsig_target(nz))

      ! (Re)allocate z_ref if needed
      if (allocated(self%z_ref)) deallocate (self%z_ref)

      select case (coord_type)
      case (VCOORD_SIGMA)
         self%dsig_target = 1.0_wp/real(nz, wp)

      case (VCOORD_ZSIGMA)
         ! z-sigma hybrid: dsig_target is used for the sigma component,
         ! z_ref defines the reference z-level interfaces.
         self%dsig_target = 1.0_wp/real(nz, wp)
         allocate (self%z_ref(0:nz))
         ! Reference z-levels: uniform spacing over the blending depth.
         ! Columns shallower than depth_transition use pure sigma.
         ! Columns deeper blend toward these fixed horizontal levels.
         block
            real(wp) :: h_ref
            integer :: kk
            h_ref = self%depth_transition + self%blend_width
            self%z_ref(0) = 0.0_wp
            do kk = 1, nz
               self%z_ref(kk) = real(kk, wp)*h_ref/real(nz, wp)
            end do
         end block

      case (VCOORD_ZSTAR_FULL)
         ! Per-column z_ref built later by zstar_full_build_column from local
         ! bathymetry; this uniform template keeps allocated(z_ref) checks valid.
         self%dsig_target = 1.0_wp/real(nz, wp)
         allocate (self%z_ref(0:nz))
         block
            real(wp) :: h_ref
            integer :: kk
            h_ref = self%depth_transition + self%blend_width
            self%z_ref(0) = 0.0_wp
            do kk = 1, nz
               self%z_ref(kk) = real(kk, wp)*h_ref/real(nz, wp)
            end do
         end block

      case (VCOORD_ZSTAR_SIGMA)
         ! z*/sigma hybrid: same template as VCOORD_ZSTAR / VCOORD_ZSIGMA.
         ! The blend is applied per-column in `vcoord_target_dz_column`
         ! based on the local H vs depth_transition / blend_width.
         self%dsig_target = 1.0_wp/real(nz, wp)
         allocate (self%z_ref(0:nz))
         block
            real(wp) :: h_ref
            integer :: kk
            h_ref = self%depth_transition + self%blend_width
            self%z_ref(0) = 0.0_wp
            do kk = 1, nz
               self%z_ref(kk) = real(kk, wp)*h_ref/real(nz, wp)
            end do
         end block

      case (VCOORD_ZSTAR)
         ! z*-lite: uniform reference spacing over depth_transition+blend_width;
         ! stretched per column by H/z_ref(nz) in vcoord_target_dz_column.
         self%dsig_target = 1.0_wp/real(nz, wp)
         allocate (self%z_ref(0:nz))
         block
            real(wp) :: h_ref
            integer :: kk
            h_ref = self%depth_transition + self%blend_width
            self%z_ref(0) = 0.0_wp
            do kk = 1, nz
               self%z_ref(kk) = real(kk, wp)*h_ref/real(nz, wp)
            end do
         end block

      case default
         call logger%error("vcoord_init: unknown coord_type "//to_string(coord_type)// &
                           ". Valid options are 'sigma', 'zsigma', and 'zstar'.")
         error stop "vcoord_init: unknown coord_type"
      end select

      ! Defence in depth.  `validate_config` refuses this outright, so a
      ! namelist-driven run never reaches here; this catches the FFI /
      ! two-phase `rdb_create` paths that build a vcoord without going
      ! through config validation.  Threshold is `nz + 1` — see
      ! `nz_stack_required`.
      if (.not. nz_stack_is_sufficient(nz)) then
         call logger%warning("nz = "//to_string(nz)//" needs NZ_STACK_MAX >= "// &
                             to_string(nz_stack_required(nz))//" but this binary was "// &
                             "compiled with NZ_STACK_MAX = "//to_string(NZ_STACK_MAX)// &
                             ". Per-column stack kernels (BPG, remap) will overrun "// &
                             "thread-local storage and silently produce wrong answers. "// &
                             "Rebuild with -DRDB_NZ_STACK_MAX="// &
                             to_string(nz_stack_required(nz))//" (or larger).")
      end if
   end subroutine vcoord_init