seed_ts_from_zfile Subroutine

public subroutine seed_ts_from_zfile(ms, grid, cfg, ierr, z_draft)

Read T/S from the configured z-level NetCDF and overwrite the tracer slots with the depth-interpolated profiles. Wet columns interpolate; dry columns get the namelist land-fill constants. Must be called AFTER bathymetry, the uniform h_layer seed, and wet_mask are in place. Takes the multilayer slot directly (not the full ocean state) to avoid a circular dependency.

Arguments

Type IntentOptional Attributes Name
type(multilayer_state_t), intent(inout) :: ms
type(hgrid_t), intent(in) :: grid
type(ocean_zinit_config_t), intent(in) :: cfg
integer, intent(out), optional :: ierr

Non-zero on a malformed/mismatched z-level IC file when present; absent behaves as today (error stop).

real(kind=wp), intent(in), optional :: z_draft(:,:)

Ice-base depth (m, positive-down, >= 0), FULL ghosted (nx_total, ny_total) shape — metrics%z_draft. The geopotential depth of every layer centre is measured from z = 0, so the column top sits at z_draft under a shelf. Absent ⇒ z_top = 0 (open ocean), bit-identical to the pre-cavity behaviour.


Calls

proc~~seed_ts_from_zfile~~CallsGraph proc~seed_ts_from_zfile seed_ts_from_zfile info info proc~seed_ts_from_zfile->info proc~build_z_ctr build_z_ctr proc~seed_ts_from_zfile->proc~build_z_ctr proc~draft_shape_ok draft_shape_ok proc~seed_ts_from_zfile->proc~draft_shape_ok proc~fail fail proc~seed_ts_from_zfile->proc~fail proc~find_var find_var proc~seed_ts_from_zfile->proc~find_var proc~interp_column_linear_z interp_column_linear_z proc~seed_ts_from_zfile->proc~interp_column_linear_z proc~nc_close nc_close proc~seed_ts_from_zfile->proc~nc_close proc~nc_get_var_1d nc_get_var_1d proc~seed_ts_from_zfile->proc~nc_get_var_1d proc~nc_open_read nc_open_read proc~seed_ts_from_zfile->proc~nc_open_read proc~read_dims read_dims proc~seed_ts_from_zfile->proc~read_dims proc~read_field_xyz read_field_xyz proc~seed_ts_from_zfile->proc~read_field_xyz proc~zinit_io_ok zinit_io_ok proc~seed_ts_from_zfile->proc~zinit_io_ok to_string to_string proc~seed_ts_from_zfile->to_string error error proc~fail->error proc~error_ring_push error_ring_push proc~fail->proc~error_ring_push proc~find_var->proc~fail proc~find_var->proc~nc_close nf90_inq_varid nf90_inq_varid proc~find_var->nf90_inq_varid nf90_close nf90_close proc~nc_close->nf90_close proc~nc_check nc_check proc~nc_close->proc~nc_check nf90_get_var nf90_get_var proc~nc_get_var_1d->nf90_get_var proc~nc_get_var_1d->proc~nc_check nf90_open nf90_open proc~nc_open_read->nf90_open proc~nc_open_read->proc~nc_check proc~read_dims->proc~fail proc~read_dims->proc~nc_close proc~read_dims->proc~zinit_io_ok proc~read_dims->to_string nf90_inquire_dimension nf90_inquire_dimension proc~read_dims->nf90_inquire_dimension nf90_inquire_variable nf90_inquire_variable proc~read_dims->nf90_inquire_variable proc~read_dims->proc~nc_check proc~nc_get_var_slab_3d nc_get_var_slab_3d proc~read_field_xyz->proc~nc_get_var_slab_3d proc~zinit_io_ok->proc~nc_close proc~nc_check->proc~fail nf90_strerror nf90_strerror proc~nc_check->nf90_strerror proc~nc_get_var_slab_3d->nf90_get_var proc~nc_get_var_slab_3d->proc~nc_check

Called by

proc~~seed_ts_from_zfile~~CalledByGraph proc~seed_ts_from_zfile seed_ts_from_zfile proc~seed_zinit_overlay seed_zinit_overlay proc~seed_zinit_overlay->proc~seed_ts_from_zfile proc~ocean_state_seed_from_cfg ocean_state_seed_from_cfg proc~ocean_state_seed_from_cfg->proc~seed_zinit_overlay proc~engine_setup engine_setup proc~engine_setup->proc~ocean_state_seed_from_cfg 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
logical, private :: have_draft
integer, private :: i
integer, private :: idx_S
integer, private :: idx_T
integer, private :: j
integer, private :: k
integer, private :: local_ierr
integer, private :: ncid
logical, private :: needs_transpose
integer, private :: ng
integer, private :: nx
integer, private :: ny
integer, private :: nz_ml
integer, private :: nz_src
real(kind=wp), private :: s_col(ms%nz_ml)
real(kind=wp), private, allocatable :: s_src(:,:,:)
integer, private :: s_varid
real(kind=wp), private :: t_col(ms%nz_ml)
real(kind=wp), private, allocatable :: t_src(:,:,:)
integer, private :: t_varid
real(kind=wp), private :: z_ctr(ms%nz_ml)
real(kind=wp), private, allocatable :: z_src(:)
real(kind=wp), private :: z_top
integer, private :: z_varid

Source Code

   subroutine seed_ts_from_zfile(ms, grid, cfg, ierr, z_draft)
      !! Read T/S from the configured z-level NetCDF and overwrite the
      !! tracer slots with the depth-interpolated profiles.  Wet columns
      !! interpolate; dry columns get the namelist land-fill constants.
      !! Must be called AFTER bathymetry, the uniform `h_layer` seed, and
      !! `wet_mask` are in place.  Takes the multilayer slot directly (not
      !! the full ocean state) to avoid a circular dependency.
      type(multilayer_state_t), intent(inout) :: ms
      type(hgrid_t), intent(in) :: grid
      type(ocean_zinit_config_t), intent(in) :: cfg
      integer, intent(out), optional :: ierr
         !! Non-zero on a malformed/mismatched z-level IC file when
         !! present; absent behaves as today (`error stop`).
      real(wp), intent(in), optional :: z_draft(:, :)
         !! Ice-base depth (m, positive-down, `>= 0`), FULL ghosted
         !! `(nx_total, ny_total)` shape — `metrics%z_draft`.  The
         !! geopotential depth of every layer centre is measured from
         !! `z = 0`, so the column top sits at `z_draft` under a shelf.
         !! Absent ⇒ `z_top = 0` (open ocean), bit-identical to the
         !! pre-cavity behaviour.

      integer :: ncid, ng, nx, ny, nz_ml, nz_src, local_ierr
      integer :: idx_S, idx_T, i, j, k
      integer :: t_varid, s_varid, z_varid
      real(wp), allocatable :: t_src(:, :, :), s_src(:, :, :), z_src(:)
      real(wp) :: z_ctr(ms%nz_ml)
      real(wp) :: t_col(ms%nz_ml), s_col(ms%nz_ml)
      real(wp) :: z_top
      logical :: needs_transpose, have_draft

      have_draft = present(z_draft)
      if (have_draft) then
         if (.not. draft_shape_ok(z_draft, ms)) then
            call fail("ocean_zinit: z_draft must be the FULL ghosted "// &
                      "(nx_total, ny_total) array, matching h_layer", &
                      ierr, OCEAN_STATUS_ERR_IO)
            return
         end if
      end if
      ng = grid%nghost
      nx = grid%nx_phys
      ny = grid%ny_phys
      nz_ml = ms%nz_ml
      idx_S = ms%idx_salinity
      idx_T = ms%idx_temperature

      call logger%info("Loading z-level T/S IC from: "//trim(cfg%file))

      call nc_open_read(trim(cfg%file), ncid, ierr=local_ierr)
      if (.not. zinit_io_ok(local_ierr, ierr)) return

      ! Locate the three variables: namelist override then name-fallbacks.
      ! ierr threaded down ONLY when THIS routine's own ierr is present:
      ! otherwise find_var/read_dims must keep reaching their own
      ! `error stop` (specific text) rather than the generic wrapper
      ! message below (P0.1 review F2).
      if (present(ierr)) then
         call find_var(ncid, cfg%t_var, &
                       [character(len=16) :: "temp", "T", "temperature"], "temperature", t_varid, &
                       ierr=local_ierr)
         if (local_ierr /= 0) then
            ierr = local_ierr
            return
         end if
      else
         call find_var(ncid, cfg%t_var, &
                       [character(len=16) :: "temp", "T", "temperature"], "temperature", t_varid)
      end if
      if (present(ierr)) then
         call find_var(ncid, cfg%s_var, &
                       [character(len=16) :: "salt", "S", "salinity"], "salinity", s_varid, &
                       ierr=local_ierr)
         if (local_ierr /= 0) then
            ierr = local_ierr
            return
         end if
      else
         call find_var(ncid, cfg%s_var, &
                       [character(len=16) :: "salt", "S", "salinity"], "salinity", s_varid)
      end if
      if (present(ierr)) then
         call find_var(ncid, cfg%z_var, &
                       [character(len=16) :: "z_src", "z", "depth", "lev"], "source axis", z_varid, &
                       ierr=local_ierr)
         if (local_ierr /= 0) then
            ierr = local_ierr
            return
         end if
      else
         call find_var(ncid, cfg%z_var, &
                       [character(len=16) :: "z_src", "z", "depth", "lev"], "source axis", z_varid)
      end if

      ! Validate dims + determine the storage-order permutation against
      ! the model grid; error-stops on mismatch.
      if (present(ierr)) then
         call read_dims(ncid, t_varid, grid, nz_src, needs_transpose, ierr=local_ierr)
         if (local_ierr /= 0) then
            ierr = local_ierr
            return
         end if
      else
         call read_dims(ncid, t_varid, grid, nz_src, needs_transpose)
      end if

      ! Read the source axis + assert monotonic increase (positive-down).
      allocate (z_src(nz_src))
      call nc_get_var_1d(ncid, z_varid, z_src, ierr=local_ierr)
      if (.not. zinit_io_ok(local_ierr, ierr, ncid)) return
      do k = 2, nz_src
         if (z_src(k) <= z_src(k - 1)) then
            call nc_close(ncid)
            call fail("ocean_zinit: z_src not monotonically increasing at level "// &
                      to_string(k)//" ("//to_string(z_src(k))//" <= "// &
                      to_string(z_src(k - 1))//")", ierr, OCEAN_STATUS_ERR_IO)
            return
         end if
      end do

      ! Read T/S into model-grid (x, y, z) interior arrays, undoing the
      ! C/Fortran dimension reversal when the file is C-ordered (z, y, x).
      allocate (t_src(nx, ny, nz_src), s_src(nx, ny, nz_src))
      call read_field_xyz(ncid, t_varid, t_src, nx, ny, nz_src, needs_transpose, &
                          grid%i_offset_global, grid%j_offset_global, ierr=local_ierr)
      if (.not. zinit_io_ok(local_ierr, ierr, ncid)) return
      call read_field_xyz(ncid, s_varid, s_src, nx, ny, nz_src, needs_transpose, &
                          grid%i_offset_global, grid%j_offset_global, ierr=local_ierr)
      if (.not. zinit_io_ok(local_ierr, ierr, ncid)) return
      call nc_close(ncid)

      ! Host-side per-column interpolation.  Plain do loops: this runs
      ! before enter_data, so the arrays are host-resident.
      do j = 1, ny
         do i = 1, nx
            ! Layer-centre GEOPOTENTIAL depths (positive-down from z = 0)
            ! from h_layer, offset by the depth of the column top.
            ! Bottom-up: k=1 bed (deepest), k=nz_ml surface (shallowest).
            z_top = 0.0_wp
            if (have_draft) z_top = z_draft(ng + i, ng + j)
            call build_z_ctr(ms%h_layer(ng + i, ng + j, :), nz_ml, z_top, z_ctr)

            if (ms%wet_mask(ng + i, ng + j) <= 0.0_wp) then
               ! Dry column — fill with the namelist land-fill constants.
               t_col = cfg%land_fill_t
               s_col = cfg%land_fill_s
            else
               ! Interp in DEPTH SPACE so the source's ascending
               ! positive-down order and the model's bottom-up order
               ! never need reconciling.
               call interp_column_linear_z(z_src, t_src(i, j, :), nz_src, z_ctr, nz_ml, t_col)
               call interp_column_linear_z(z_src, s_src(i, j, :), nz_src, z_ctr, nz_ml, s_col)
            end if

            ! Roundabout tracer convention: hTr = value * h_layer.
            if (idx_T > 0) then
               do k = 1, nz_ml
                  ms%tracers(idx_T)%hTr(ng + i, ng + j, k) = &
                     t_col(k)*ms%h_layer(ng + i, ng + j, k)
               end do
            end if
            if (idx_S > 0) then
               do k = 1, nz_ml
                  ms%tracers(idx_S)%hTr(ng + i, ng + j, k) = &
                     s_col(k)*ms%h_layer(ng + i, ng + j, k)
               end do
            end if
         end do
      end do

      deallocate (t_src, s_src, z_src)

      call logger%info("ocean_zinit: seeded T/S from "//to_string(nz_src)// &
                       " source z-levels onto "//to_string(nz_ml)//" model layers.")
      if (present(ierr)) ierr = OCEAN_STATUS_OK
   end subroutine seed_ts_from_zfile