ice_transport_step Subroutine

public subroutine ice_transport_step(grid, metrics, ms, ice, dt, adv_substeps, roll_factor, ok, bc)

Entry point (host orchestration; kernels inside). Outer-shim + flat-impl: every phase below dispatches to a pure _impl kernel; this routine only sequences them and owns the host-visible ok fail-loud signal.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(multilayer_state_t), intent(in) :: ms

face velocities the v1 sampler reads.

type(ocean_sea_ice_t), intent(inout) :: ice
real(kind=wp), intent(in) :: dt

The thermo-step dt (cadence = the ice slow step).

integer, intent(in) :: adv_substeps

SIS2 NSTEPS_ADV (&ocean_ice_nml adv_substeps), >= 1.

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

SIS2 SEA_ICE_ROLL_FACTOR (&ocean_ice_nml roll_factor). 0 disables rolling.

logical, intent(out) :: ok

.false. => the caller (driver) must abort fail-loud (conservation/positivity violation, or a compress-time consistency failure SIS2 would FATAL on). Rank-uniform.

type(ocean_bc_state_t), intent(in), optional :: bc

Edge policy (periodic_x/_y, has_*). Present (the engine always passes it): X4 per substep and walls only on a physical, non-periodic edge. Absent (the single-tile unit-test seam): no exchange and every tile edge is a wall, as before.


Calls

proc~~ice_transport_step~~CallsGraph proc~ice_transport_step ice_transport_step proc~halo_allreduce_max halo_allreduce_max proc~ice_transport_step->proc~halo_allreduce_max proc~ice_adjust_categories ice_adjust_categories proc~ice_transport_step->proc~ice_adjust_categories proc~ice_cas_to_ist_impl ice_cas_to_ist_impl proc~ice_transport_step->proc~ice_cas_to_ist_impl proc~ice_compress_impl ice_compress_impl proc~ice_transport_step->proc~ice_compress_impl proc~ice_ist_to_cas_impl ice_ist_to_cas_impl proc~ice_transport_step->proc~ice_ist_to_cas_impl proc~ice_max_speed_impl ice_max_speed_impl proc~ice_transport_step->proc~ice_max_speed_impl proc~ice_pass_x ice_pass_x proc~ice_transport_step->proc~ice_pass_x proc~ice_pass_y ice_pass_y proc~ice_transport_step->proc~ice_pass_y proc~ice_sample_velocity_impl ice_sample_velocity_impl proc~ice_transport_step->proc~ice_sample_velocity_impl proc~ocean_halo_exchange_ice_transport ocean_halo_exchange_ice_transport proc~ice_transport_step->proc~ocean_halo_exchange_ice_transport proc~ocean_halo_is_decomposed ocean_halo_is_decomposed proc~ice_transport_step->proc~ocean_halo_is_decomposed proc~ocean_halo_is_init ocean_halo_is_init proc~ice_transport_step->proc~ocean_halo_is_init proc~ok_all_ranks ok_all_ranks proc~ice_transport_step->proc~ok_all_ranks allreduce allreduce proc~halo_allreduce_max->allreduce proc~comm_env_compute_comm comm_env_compute_comm proc~halo_allreduce_max->proc~comm_env_compute_comm proc~ice_adjust_categories_impl ice_adjust_categories_impl proc~ice_adjust_categories->proc~ice_adjust_categories_impl local local proc~ice_cas_to_ist_impl->local proc~ice_compress_impl->local proc~ice_compress_cell_inline ice_compress_cell_inline proc~ice_compress_impl->proc~ice_compress_cell_inline reduce reduce proc~ice_compress_impl->reduce proc~ice_max_speed_impl->reduce proc~ice_cat_flux_x_impl ice_cat_flux_x_impl proc~ice_pass_x->proc~ice_cat_flux_x_impl proc~ice_gather_flux_x_impl ice_gather_flux_x_impl proc~ice_pass_x->proc~ice_gather_flux_x_impl proc~ice_gather_flux_x_layer_impl ice_gather_flux_x_layer_impl proc~ice_pass_x->proc~ice_gather_flux_x_layer_impl proc~ice_mask_snow_by_ice_impl ice_mask_snow_by_ice_impl proc~ice_pass_x->proc~ice_mask_snow_by_ice_impl proc~ice_mass_update_x_impl ice_mass_update_x_impl proc~ice_pass_x->proc~ice_mass_update_x_impl proc~ice_ride_update_x_impl ice_ride_update_x_impl proc~ice_pass_x->proc~ice_ride_update_x_impl proc~ice_ride_update_x_layer_impl ice_ride_update_x_layer_impl proc~ice_pass_x->proc~ice_ride_update_x_layer_impl proc~ice_validity_reduce_impl ice_validity_reduce_impl proc~ice_pass_x->proc~ice_validity_reduce_impl proc~ice_cat_flux_y_impl ice_cat_flux_y_impl proc~ice_pass_y->proc~ice_cat_flux_y_impl proc~ice_gather_flux_y_impl ice_gather_flux_y_impl proc~ice_pass_y->proc~ice_gather_flux_y_impl proc~ice_gather_flux_y_layer_impl ice_gather_flux_y_layer_impl proc~ice_pass_y->proc~ice_gather_flux_y_layer_impl proc~ice_pass_y->proc~ice_mask_snow_by_ice_impl proc~ice_mass_update_y_impl ice_mass_update_y_impl proc~ice_pass_y->proc~ice_mass_update_y_impl proc~ice_ride_update_y_impl ice_ride_update_y_impl proc~ice_pass_y->proc~ice_ride_update_y_impl proc~ice_ride_update_y_layer_impl ice_ride_update_y_layer_impl proc~ice_pass_y->proc~ice_ride_update_y_layer_impl proc~ice_pass_y->proc~ice_validity_reduce_impl proc~ice_halo_centre_flat ice_halo_centre_flat proc~ocean_halo_exchange_ice_transport->proc~ice_halo_centre_flat proc~ocean_fold_wrap_centre_flat ocean_fold_wrap_centre_flat proc~ocean_halo_exchange_ice_transport->proc~ocean_fold_wrap_centre_flat proc~oh_count_suppress_off oh_count_suppress_off proc~ocean_halo_exchange_ice_transport->proc~oh_count_suppress_off proc~oh_count_suppress_on oh_count_suppress_on proc~ocean_halo_exchange_ice_transport->proc~oh_count_suppress_on proc~profiler_start profiler_start proc~ocean_halo_exchange_ice_transport->proc~profiler_start proc~profiler_stop profiler_stop proc~ocean_halo_exchange_ice_transport->proc~profiler_stop proc~ok_all_ranks->proc~ocean_halo_is_decomposed proc~halo_allreduce_min halo_allreduce_min proc~ok_all_ranks->proc~halo_allreduce_min comm_world comm_world proc~comm_env_compute_comm->comm_world proc~halo_allreduce_min->allreduce proc~halo_allreduce_min->proc~comm_env_compute_comm proc~ice_adjust_categories_impl->local proc~ice_cat_flux_x_impl->local proc~ppm_cell_limiter ppm_cell_limiter proc~ice_cat_flux_x_impl->proc~ppm_cell_limiter proc~ppm_limit_pos ppm_limit_pos proc~ice_cat_flux_x_impl->proc~ppm_limit_pos proc~ppm_limited_slope ppm_limited_slope proc~ice_cat_flux_x_impl->proc~ppm_limited_slope proc~ppm_mirror_h ppm_mirror_h proc~ice_cat_flux_x_impl->proc~ppm_mirror_h proc~volcfl_face volcfl_face proc~ice_cat_flux_x_impl->proc~volcfl_face proc~ice_cat_flux_y_impl->local proc~ice_cat_flux_y_impl->proc~ppm_cell_limiter proc~ice_cat_flux_y_impl->proc~ppm_limit_pos proc~ice_cat_flux_y_impl->proc~ppm_limited_slope proc~ice_cat_flux_y_impl->proc~ppm_mirror_h proc~ice_cat_flux_y_impl->proc~volcfl_face interface~ocean_halo_centre ocean_halo_centre proc~ice_halo_centre_flat->interface~ocean_halo_centre proc~ice_ride_update_x_impl->local proc~ice_ride_update_x_layer_impl->local proc~ice_ride_update_y_impl->local proc~ice_ride_update_y_layer_impl->local proc~ice_validity_reduce_impl->reduce interface~fold_north_centre fold_north_centre proc~ocean_fold_wrap_centre_flat->interface~fold_north_centre interface~ocean_fold_pack ocean_fold_pack proc~ocean_fold_wrap_centre_flat->interface~ocean_fold_pack interface~ocean_fold_unpack ocean_fold_unpack proc~ocean_fold_wrap_centre_flat->interface~ocean_fold_unpack proc~ocean_fold_begin ocean_fold_begin proc~ocean_fold_wrap_centre_flat->proc~ocean_fold_begin proc~ocean_fold_end ocean_fold_end proc~ocean_fold_wrap_centre_flat->proc~ocean_fold_end proc~ocean_fold_exchange ocean_fold_exchange proc~ocean_fold_wrap_centre_flat->proc~ocean_fold_exchange proc~ocean_fold_is_distributed ocean_fold_is_distributed proc~ocean_fold_wrap_centre_flat->proc~ocean_fold_is_distributed proc~find_or_create_region find_or_create_region proc~profiler_start->proc~find_or_create_region proc~get_wall_time get_wall_time proc~profiler_start->proc~get_wall_time proc~nvtx_range_push nvtx_range_push proc~profiler_start->proc~nvtx_range_push proc~profiler_stop->proc~get_wall_time proc~nvtx_range_pop nvtx_range_pop proc~profiler_stop->proc~nvtx_range_pop proc~fold_north_centre_2d fold_north_centre_2d interface~fold_north_centre->proc~fold_north_centre_2d proc~fold_north_centre_3d fold_north_centre_3d interface~fold_north_centre->proc~fold_north_centre_3d proc~ocean_fold_pack_2d ocean_fold_pack_2d interface~ocean_fold_pack->proc~ocean_fold_pack_2d proc~ocean_fold_pack_3d ocean_fold_pack_3d interface~ocean_fold_pack->proc~ocean_fold_pack_3d proc~ocean_fold_unpack_2d ocean_fold_unpack_2d interface~ocean_fold_unpack->proc~ocean_fold_unpack_2d proc~ocean_fold_unpack_3d ocean_fold_unpack_3d interface~ocean_fold_unpack->proc~ocean_fold_unpack_3d proc~ocean_halo_centre_2d ocean_halo_centre_2d interface~ocean_halo_centre->proc~ocean_halo_centre_2d proc~ocean_halo_centre_3d ocean_halo_centre_3d interface~ocean_halo_centre->proc~ocean_halo_centre_3d proc~grow_buffers grow_buffers proc~ocean_fold_begin->proc~grow_buffers to_string to_string proc~ocean_fold_begin->to_string warning warning proc~ocean_fold_begin->warning proc~ocean_fold_exchange->proc~comm_env_compute_comm comm_irecv_real_sp_array_n comm_irecv_real_sp_array_n proc~ocean_fold_exchange->comm_irecv_real_sp_array_n comm_isend_real_sp_array_n comm_isend_real_sp_array_n proc~ocean_fold_exchange->comm_isend_real_sp_array_n waitall waitall proc~ocean_fold_exchange->waitall proc~ocean_fold_pack_2d->proc~ocean_fold_pack_3d proc~fold_stagger_family fold_stagger_family proc~ocean_fold_pack_3d->proc~fold_stagger_family proc~fold_stagger_nrows fold_stagger_nrows proc~ocean_fold_pack_3d->proc~fold_stagger_nrows proc~ocean_fold_unpack_2d->proc~ocean_fold_unpack_3d proc~ocean_fold_unpack_3d->proc~fold_stagger_family proc~ocean_fold_unpack_3d->proc~fold_stagger_nrows proc~ocean_halo_centre_2d_impl ocean_halo_centre_2d_impl proc~ocean_halo_centre_2d->proc~ocean_halo_centre_2d_impl proc~oh_count_centre_2d oh_count_centre_2d proc~ocean_halo_centre_2d->proc~oh_count_centre_2d proc~ocean_halo_centre_3d->proc~comm_env_compute_comm proc~ocean_halo_centre_3d->comm_irecv_real_sp_array_n proc~ocean_halo_centre_3d->comm_isend_real_sp_array_n proc~ocean_halo_centre_3d->waitall proc~ew_rank_east ew_rank_east proc~ocean_halo_centre_3d->proc~ew_rank_east proc~ew_rank_west ew_rank_west proc~ocean_halo_centre_3d->proc~ew_rank_west proc~needs_flags needs_flags proc~ocean_halo_centre_3d->proc~needs_flags proc~ns_rank_north ns_rank_north proc~ocean_halo_centre_3d->proc~ns_rank_north proc~ns_rank_south ns_rank_south proc~ocean_halo_centre_3d->proc~ns_rank_south proc~ocean_halo_buffers_ensure_nz ocean_halo_buffers_ensure_nz proc~ocean_halo_centre_3d->proc~ocean_halo_buffers_ensure_nz proc~ocean_periodic_wrap_centre_3d ocean_periodic_wrap_centre_3d proc~ocean_halo_centre_3d->proc~ocean_periodic_wrap_centre_3d proc~oh_count_centre_3d oh_count_centre_3d proc~ocean_halo_centre_3d->proc~oh_count_centre_3d proc~oh_count_msgs oh_count_msgs proc~ocean_halo_centre_3d->proc~oh_count_msgs

Called by

proc~~ice_transport_step~~CalledByGraph proc~ice_transport_step ice_transport_step proc~engine_step_ice engine_step_ice proc~engine_step_ice->proc~ice_transport_step proc~driver_run_ocean driver_run_ocean proc~driver_run_ocean->proc~engine_step_ice proc~rdb_ocean_step rdb_ocean_step proc~rdb_ocean_step->proc~engine_step_ice proc~driver_run driver_run proc~driver_run->proc~driver_run_ocean

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: dt_adv
integer, private :: n
integer, private :: nghost
integer, private :: nx
integer, private :: ny
integer, private :: nz
real(kind=wp), private :: vglob
real(kind=wp), private :: vmax
logical, private :: wall_e
logical, private :: wall_n
logical, private :: wall_s
logical, private :: wall_w
logical, private :: x4

Source Code

   subroutine ice_transport_step(grid, metrics, ms, ice, dt, adv_substeps, roll_factor, ok, bc)
      !! Entry point (host orchestration; kernels inside).  Outer-shim +
      !! flat-impl: every phase below dispatches to a `pure` `_impl`
      !! kernel; this routine only sequences them and owns the
      !! host-visible `ok` fail-loud signal.
      type(hgrid_t), intent(in) :: grid
      type(ocean_metrics_t), intent(in) :: metrics
      type(multilayer_state_t), intent(in) :: ms
         !! READ-ONLY: `wet_mask` (physical-cell gate) + the surface-layer
         !! face velocities the v1 sampler reads.
      type(ocean_sea_ice_t), intent(inout) :: ice
      real(wp), intent(in) :: dt
         !! The thermo-step dt (cadence = the ice slow step).
      integer, intent(in) :: adv_substeps
         !! SIS2 `NSTEPS_ADV` (`&ocean_ice_nml adv_substeps`), >= 1.
      real(wp), intent(in) :: roll_factor
         !! SIS2 `SEA_ICE_ROLL_FACTOR` (`&ocean_ice_nml roll_factor`).
         !! 0 disables rolling.
      logical, intent(out) :: ok
         !! `.false.` => the caller (driver) must abort fail-loud
         !! (conservation/positivity violation, or a compress-time
         !! consistency failure SIS2 would FATAL on).  Rank-uniform.
      type(ocean_bc_state_t), intent(in), optional :: bc
         !! Edge policy (`periodic_x/_y`, `has_*`).  Present (the engine
         !! always passes it): X4 per substep and walls only on a physical,
         !! non-periodic edge.  Absent (the single-tile unit-test seam):
         !! no exchange and every tile edge is a wall, as before.

      integer :: nx, ny, nz, nghost, n
      real(wp) :: dt_adv, vmax, vglob
      logical :: wall_w, wall_e, wall_s, wall_n, x4

      ok = .true.
      if (.not. ice%is_init) return
      if (ice%ncat == 1) return

      nx = grid%nx_total
      ny = grid%ny_total
      nz = ms%nz_ml
      nghost = grid%nghost
      wall_w = .true.
      wall_e = .true.
      wall_s = .true.
      wall_n = .true.
      x4 = .false.
      if (present(bc)) then
         wall_w = bc%has_west .and. .not. bc%periodic_x
         wall_e = bc%has_east .and. .not. bc%periodic_x
         wall_s = bc%has_south .and. .not. bc%periodic_y
         ! A tripolar north edge is topologically connected (folded), not
         ! a solid boundary -- `bc%north_fold` is the fold-seam twin of
         ! `periodic_y` here, and must be excluded from the wall test the
         ! same way.  Missing this made `vhtot_work` at the exact
         ! fold-line face (`nghost+ny_phys+1`) get force-zeroed every
         ! substep regardless of the (now fold-exchanged) ghost data, so
         ! category transport could never cross the seam at all: any
         ! poleward convergence simply piled up against this phantom wall
         ! with no outlet, which is the dominant mechanism behind the
         ! fold-row ice growing without bound (CLAUDE.md fold-seam fix).
         wall_n = bc%has_north .and. .not. bc%periodic_y .and. .not. bc%north_fold
         x4 = ocean_halo_is_init()
      end if

      ! ---- Phase 0: sample the ocean surface-layer velocity onto the
      ! ice C-grid faces (v1 interim filler).  PR 5: skipped when EVP
      ! dynamics is on — ice_evp_step (driver, runs BEFORE this call)
      ! already wrote u_ice/v_ice directly; the sampler would clobber
      ! them with the ocean surface velocity. ----
      if (.not. ice%dynamics) then
         call ice_sample_velocity_impl(ms%u_face_x_layer(:, :, nz), ms%v_face_y_layer(:, :, nz), &
                                       metrics%wet_u, metrics%wet_v, ice%u_ice, ice%v_ice, nx, ny)
      end if

      ! ---- Zero-velocity exact no-op (D6): the CAS<->IST round trip
      ! re-derives part_size by division and would otherwise perturb
      ! last bits even under zero flow. ----
      call ice_max_speed_impl(ice%u_ice, ice%v_ice, nghost, grid%nx_phys, grid%ny_phys, &
                              nx, ny, vmax)
      ! Rank-uniform: a rank that skips the round trip while another
      ! enters the substep exchanges deadlocks.  A max is exact.
      if (ocean_halo_is_decomposed()) then
         call halo_allreduce_max(vmax, vglob)
         vmax = vglob
      end if
      if (vmax == 0.0_wp) return

      ! ---- Phase 1: IST -> CAS ----
      call ice_ist_to_cas_impl(ms%wet_mask, ice%part_size, ice%m_ice, ice%m_snow, &
                               ice%mca_ice, ice%mca_snow, nghost, ice%ncat, nx, ny)

      ! ---- Phase 2: adv_substeps advective iterations, x-pass then y-pass ----
      dt_adv = dt/real(max(adv_substeps, 1), wp)
      do n = 1, adv_substeps
         ! X4: seam ghosts of the CAS masses + riding tracers (and, on one
         ! periodic rank, the wrap) before this substep's stencils read them.
         if (x4) call ocean_halo_exchange_ice_transport(ice, grid, bc)
         call ice_pass_x(grid, metrics, ice, dt_adv, wall_w, wall_e, ok)
         call ok_all_ranks(ok)
         if (.not. ok) return
         call ice_pass_y(grid, metrics, ice, dt_adv, wall_s, wall_n, ok)
         call ok_all_ranks(ok)
         if (.not. ok) return
      end do

      ! ---- Phase 3: CAS -> IST ----
      call ice_cas_to_ist_impl(ms%wet_mask, metrics%areaT, ice%mca_ice, ice%mca_snow, &
                               ice%part_size, ice%m_ice, ice%m_snow, ice%mh_lim, roll_factor, &
                               nghost, ice%ncat, nx, ny)

      ! ---- Phase 4: compress_ice ----
      call ice_compress_impl(ms%wet_mask, ice%part_size, ice%m_ice, ice%m_snow, &
                             ice%enth_ice, ice%enth_snow, ice%sal_ice, ice%mh_lim, &
                             nghost, ice%ncat, ice%nk_ice, nx, ny, ok)
      call ok_all_ranks(ok)
      if (.not. ok) return

      ! ---- Phase 5: recategorize (PR 4a, unchanged) ----
      call ice_adjust_categories(grid, ms, ice)
   end subroutine ice_transport_step