rdb_ice_transport Module

Port of SIS2’s DEFAULT (velocity, non-merged) ice_cat_transport (SIS_transport.F90:127) + finish_ice_transport (:255) + compress_ice (:898), grounded per SPEC_ice-pr4b-transport.md. Source citations below are SIS_transport.F90 / SIS_continuity.F90 / SIS_tracer_advect.F90 unless noted; when this module and the SIS2 source disagree, the source (re-verified against the running SIS2 tree for this port) wins.

What SIS2 actually runs (MERGED_CONTINUITY defaults .false., SIS_dyn_trans.F90:2377): per-medium continuity driven by FACE VELOCITIES (uc/vc), not the merged/proportionate-split variant. ice_continuity (SIS_continuity.F90:69) reconstructs a PPM parabola on the CATEGORY-SUMMED mass, computes ONE total-mass face transport from that parabola, then splits it into per-category flux proportionally to each category’s share of the summed mass (SIS_continuity.F90:1184-1215) — there is no separate “split” pass. Snow rides its OWN independent PPM solve on summed snow mass, then is masked to zero wherever the CO-LOCATED ice flux is exactly zero (SIS_continuity.F90:1210-1215; the frac_neglect second masking clause is dead at SIS2’s own default frac_neglect=0, so it is not ported). x_first is fixed by FIRST_DIRECTION (default 0); the second (y) pass reads the ALREADY-UPDATED post-x-pass masses (SIS_continuity.F90:170-216).

Algorithm per outer call (ice_transport_step): Phase 0 — gates (is_init, ncat==1) + velocity sampling + zero-velocity exact no-op. Phase 1 — IST -> CAS (ice_state_to_cell_ave_state, :465): mca_ice(c) = part_size(c)*m_ice(c), ditto snow. Phase 2 — adv_substeps iterations, each an x-pass then y-pass; each pass does (a) total-mass PPM + proportionate ice-flux split, (b) same for snow + the co-located mask, (c) PCM tracer riding (mass-weighted, BEFORE the mass update, with SIS2’s H_NEGLECT conditioning guard for thin remainders), (d) the mass update, then a fail-loud positivity/orphan-snow reduction. Phase 3 — CAS -> IST (cell_ave_state_to_ice_state, :540): re-derive part_size by division, with the pre-floor + optional thin-ice rolling + general floor. part_size(0) may go negative here — compress (Phase 4) is what fixes it. Phase 4 — compress_ice (:898, no-ridge default, ponds dropped): thinnest-first cascade that returns part_size(0) to >= 0 by compacting / promoting categories, tracer-merging on transfer. Phase 5 — ice_adjust_categories (PR 4a, unchanged): restore the ITD partition.

GPU race-hazard note (Phase 2c, tracer riding). A per-cell update that reads a NEIGHBOUR cell’s intensive value (the upwind donor of the west/east face) while another loop iteration may be WRITING that same neighbour is a do concurrent race — iteration order is unspecified. This module never reads a neighbour’s val directly: it first runs a FACE-indexed gather kernel (ice_gather_flux_{x,y}[_layer]_impl) that computes tr_flux(I) = uh(I)*val(donor of I) — reading val ONLY at that face’s own donor cell, writing to the SEPARATE tr_flux_x_work/tr_flux_y_work face buffer (never val itself) — then a CELL-indexed update kernel (ice_ride_update_{x,y}[_layer]_impl) that reads only the face buffer plus its OWN cell’s prior mass/value and writes val(i,j,c[,l]). This mirrors rdb_continuity’s Tr_face_left_x gather/scatter split (tracer_advect_zonal_one_impl) verbatim in spirit.

Reuse contract. The five SIS2-equivalent PPM helpers (ppm_mirror_h, volcfl_face, ppm_limited_slope, ppm_cell_limiter, ppm_limit_pos) are promoted to production public in rdb_continuity and called verbatim here — their bodies are NOT duplicated (SPEC §2).

Documented divergences from SIS2 (kept in sync with SPEC_ice-pr4b-transport.md §10): D1: continuity scheme fixed to Roundabout’s PPM (H3-style limited edges + CW84 + limit_pos) rather than SIS2’s in-code legacy default UPWIND_2D; matches SIS2’s modern PPM configs in structure. D2: no massless-category mH fill (SIS2 :509-520) — moot under PCM tracer riding (a massless category’s scalar value is never read: its face fluxes are always zero because mca=0). D3: tracer riding is PCM (piecewise-constant upwind), one of SIS2’s four schemes (SIS_TRACER_ADVECTION_SCHEME=PCM) — not the PPM:H3 modern configs use. Upgrade path open. D4: no melt ponds (Roundabout carries none). D5: fixed x-first directional split (SIS2 FIRST_DIRECTION default 0; no alternation). D6: zero-velocity early-exit and ncat==1 early-exit are Roundabout bit-identity contract additions; SIS2 has neither. D7: fail-loud negativity/orphan-snow detection via a post-pass device REDUCTION + driver abort, instead of SIS2’s in-loop FATALs (GPU portability — a do concurrent kernel cannot abort mid-loop). Also STRICTLY SAFER than SIS2 at the top-category compaction: part(ncat) <= excess (negative- or, at the exact tie, zero-denominator f) is routed into the fail-loud branch (SIS2 has that hole). D8: compress_ice tracer-merges INSIDE the thinnest-first cascade at each transfer site, whereas SIS2 defers to advect_tracers_thicker AFTER the category k-loop — equivalent to round-off (each boundary visited once in a fixed order with running masses; same argument as the PR-4a ice_adjust_categories merge).

Multi-rank / periodic (ice_transport_step with bc): the ice uses the ocean’s decomposition and nghost (>= 3 on a decomposed run, ocean_halo_init). X4 — the CAS masses and every riding tracer are halo-exchanged at the TOP of every advective substep (ocean_halo_exchange_ice_transport; on one rank with a periodic axis the same call wraps it). One exchange per substep suffices at nghost = 3: the x-pass flux, ride and mass update run over every row, ghost rows included, from corner-valid inputs, so the y-pass reads ghost rows that are already post-x-pass. The physical-edge wall faces are zeroed only on a PHYSICAL, non-periodic edge (bc%has_*) — an MPI or periodic seam is an ordinary face. The zero-velocity early exit and the validity / compress ok flags are made RANK-UNIFORM (global max / min) before anyone acts on them: a rank that skipped the CAS<->IST round trip or returned early while another entered X4 would deadlock, and a rank-local abort would strand the others in the next exchange.


Uses

  • module~~rdb_ice_transport~~UsesGraph module~rdb_ice_transport rdb_ice_transport module~rdb_constants rdb_constants module~rdb_ice_transport->module~rdb_constants module~rdb_continuity rdb_continuity module~rdb_ice_transport->module~rdb_continuity module~rdb_grid rdb_grid module~rdb_ice_transport->module~rdb_grid module~rdb_halo rdb_halo module~rdb_ice_transport->module~rdb_halo module~rdb_ice_column rdb_ice_column module~rdb_ice_transport->module~rdb_ice_column module~rdb_ice_itd rdb_ice_itd module~rdb_ice_transport->module~rdb_ice_itd module~rdb_ice_state rdb_ice_state module~rdb_ice_transport->module~rdb_ice_state module~rdb_multilayer_state rdb_multilayer_state module~rdb_ice_transport->module~rdb_multilayer_state module~rdb_ocean_boundary_types rdb_ocean_boundary_types module~rdb_ice_transport->module~rdb_ocean_boundary_types module~rdb_ocean_halo rdb_ocean_halo module~rdb_ice_transport->module~rdb_ocean_halo module~rdb_ocean_halo_state rdb_ocean_halo_state module~rdb_ice_transport->module~rdb_ocean_halo_state module~rdb_ocean_metrics rdb_ocean_metrics module~rdb_ice_transport->module~rdb_ocean_metrics pic_types pic_types module~rdb_constants->pic_types module~rdb_continuity->module~rdb_constants module~rdb_continuity->module~rdb_grid module~rdb_continuity->module~rdb_multilayer_state module~rdb_continuity->module~rdb_ocean_boundary_types module~rdb_continuity->module~rdb_ocean_halo module~rdb_continuity->module~rdb_ocean_metrics iso_fortran_env iso_fortran_env module~rdb_continuity->iso_fortran_env module~rdb_barotropic_state rdb_barotropic_state module~rdb_continuity->module~rdb_barotropic_state module~rdb_mem_report rdb_mem_report module~rdb_continuity->module~rdb_mem_report module~rdb_ocean_fold rdb_ocean_fold module~rdb_continuity->module~rdb_ocean_fold module~rdb_ocean_fold_apply rdb_ocean_fold_apply module~rdb_continuity->module~rdb_ocean_fold_apply module~rdb_ocean_fold_exchange rdb_ocean_fold_exchange module~rdb_continuity->module~rdb_ocean_fold_exchange module~rdb_ocean_gm rdb_ocean_gm module~rdb_continuity->module~rdb_ocean_gm module~rdb_ocean_mle rdb_ocean_mle module~rdb_continuity->module~rdb_ocean_mle module~rdb_ocean_periodic rdb_ocean_periodic module~rdb_continuity->module~rdb_ocean_periodic module~rdb_profiler rdb_profiler module~rdb_continuity->module~rdb_profiler module~rdb_recon_weno rdb_recon_weno module~rdb_continuity->module~rdb_recon_weno module~rdb_scratch_3d rdb_scratch_3d module~rdb_continuity->module~rdb_scratch_3d module~rdb_tracer rdb_tracer module~rdb_continuity->module~rdb_tracer module~rdb_grid->module~rdb_constants module~rdb_halo->module~rdb_constants module~rdb_halo->iso_fortran_env module~rdb_comm_env rdb_comm_env module~rdb_halo->module~rdb_comm_env module~rdb_decomp rdb_decomp module~rdb_halo->module~rdb_decomp module~rdb_efp rdb_efp module~rdb_halo->module~rdb_efp pic_logger pic_logger module~rdb_halo->pic_logger pic_mpi_lib pic_mpi_lib module~rdb_halo->pic_mpi_lib module~rdb_ice_column->module~rdb_constants module~rdb_ice_enthalpy rdb_ice_enthalpy module~rdb_ice_column->module~rdb_ice_enthalpy module~rdb_ice_mass rdb_ice_mass module~rdb_ice_column->module~rdb_ice_mass module~rdb_ice_optics rdb_ice_optics module~rdb_ice_column->module~rdb_ice_optics module~rdb_ice_itd->module~rdb_constants module~rdb_ice_itd->module~rdb_grid module~rdb_ice_itd->module~rdb_ice_state module~rdb_ice_itd->module~rdb_multilayer_state module~rdb_ice_state->module~rdb_constants module~rdb_ice_state->module~rdb_grid module~rdb_ice_state->module~rdb_ice_column module~rdb_ice_state->iso_fortran_env module~rdb_ice_state->module~rdb_ice_enthalpy module~rdb_ice_state->module~rdb_mem_report module~rdb_multilayer_state->module~rdb_constants module~rdb_multilayer_state->module~rdb_grid module~rdb_multilayer_state->iso_fortran_env module~rdb_multilayer_state->module~rdb_efp module~rdb_error_ring rdb_error_ring module~rdb_multilayer_state->module~rdb_error_ring module~rdb_multilayer_state->module~rdb_mem_report module~rdb_multilayer_state->module~rdb_tracer module~rdb_multilayer_state->pic_logger module~rdb_ocean_boundary_types->module~rdb_constants module~rdb_ocean_boundary_types->module~rdb_grid module~rdb_ocean_boundary_types->iso_fortran_env module~rdb_ocean_boundary_types->module~rdb_mem_report module~rdb_ocean_status rdb_ocean_status module~rdb_ocean_boundary_types->module~rdb_ocean_status module~rdb_ocean_tide_astro rdb_ocean_tide_astro module~rdb_ocean_boundary_types->module~rdb_ocean_tide_astro pic_ascii pic_ascii module~rdb_ocean_boundary_types->pic_ascii module~rdb_ocean_boundary_types->pic_logger module~rdb_ocean_halo->module~rdb_constants module~rdb_ocean_halo->module~rdb_comm_env module~rdb_ocean_halo->module~rdb_decomp module~rdb_ocean_halo->module~rdb_error_ring module~rdb_ocean_halo_counters rdb_ocean_halo_counters module~rdb_ocean_halo->module~rdb_ocean_halo_counters module~rdb_ocean_halo->module~rdb_ocean_periodic module~rdb_ocean_halo->module~rdb_ocean_status module~rdb_ocean_halo->pic_logger module~rdb_ocean_halo->pic_mpi_lib pic_strings pic_strings module~rdb_ocean_halo->pic_strings module~rdb_ocean_halo_state->module~rdb_constants module~rdb_ocean_halo_state->module~rdb_grid module~rdb_ocean_halo_state->module~rdb_ice_state module~rdb_ocean_halo_state->module~rdb_multilayer_state module~rdb_ocean_halo_state->module~rdb_ocean_boundary_types module~rdb_ocean_halo_state->module~rdb_ocean_halo module~rdb_ocean_halo_state->module~rdb_ocean_fold_apply module~rdb_ocean_halo_state->module~rdb_ocean_halo_counters module~rdb_ocean_halo_state->module~rdb_ocean_periodic module~rdb_ocean_surface_stress rdb_ocean_surface_stress module~rdb_ocean_halo_state->module~rdb_ocean_surface_stress module~rdb_ocean_halo_state->module~rdb_profiler module~rdb_ocean_metrics->module~rdb_constants module~rdb_ocean_metrics->module~rdb_grid module~rdb_ocean_metrics->iso_fortran_env module~rdb_ocean_metrics->module~rdb_error_ring module~rdb_io_netcdf rdb_io_netcdf module~rdb_ocean_metrics->module~rdb_io_netcdf module~rdb_ocean_metrics->module~rdb_mem_report module~rdb_ocean_bipolar rdb_ocean_bipolar module~rdb_ocean_metrics->module~rdb_ocean_bipolar module~rdb_ocean_metrics->module~rdb_ocean_fold module~rdb_ocean_metrics->module~rdb_ocean_status netcdf netcdf module~rdb_ocean_metrics->netcdf module~rdb_ocean_metrics->pic_logger module~rdb_ocean_metrics->pic_strings module~rdb_barotropic_state->module~rdb_constants module~rdb_barotropic_state->module~rdb_grid module~rdb_barotropic_state->iso_fortran_env module~rdb_barotropic_state->module~rdb_mem_report module~rdb_comm_env->module~rdb_constants module~rdb_comm_env->iso_fortran_env module~rdb_comm_env->pic_mpi_lib module~rdb_config rdb_config module~rdb_decomp->module~rdb_config module~rdb_efp->iso_fortran_env ieee_arithmetic ieee_arithmetic module~rdb_efp->ieee_arithmetic module~rdb_error_ring->pic_logger module~rdb_ice_enthalpy->module~rdb_constants module~rdb_ice_mass->module~rdb_constants module~rdb_ice_mass->module~rdb_ice_enthalpy module~rdb_ice_optics->module~rdb_constants module~rdb_ice_optics->module~rdb_ice_enthalpy module~rdb_io_netcdf->module~rdb_constants module~rdb_io_netcdf->iso_fortran_env module~rdb_io_netcdf->module~rdb_error_ring module~rdb_io_netcdf->netcdf module~rdb_io_netcdf->pic_logger module~rdb_io_netcdf->pic_strings iso_c_binding iso_c_binding module~rdb_io_netcdf->iso_c_binding module~rdb_mem_report->module~rdb_constants module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->pic_logger module~rdb_mem_report->pic_strings module~rdb_ocean_bipolar->module~rdb_constants module~rdb_ocean_fold->module~rdb_constants module~rdb_ocean_fold_apply->module~rdb_constants module~rdb_ocean_fold_apply->module~rdb_grid module~rdb_ocean_fold_apply->module~rdb_multilayer_state module~rdb_ocean_fold_apply->module~rdb_ocean_boundary_types module~rdb_ocean_fold_apply->module~rdb_ocean_fold module~rdb_ocean_fold_apply->module~rdb_ocean_fold_exchange module~rdb_ocean_fold_exchange->module~rdb_constants module~rdb_ocean_fold_exchange->module~rdb_comm_env module~rdb_ocean_fold_exchange->module~rdb_decomp module~rdb_ocean_fold_exchange->module~rdb_error_ring module~rdb_ocean_fold_exchange->module~rdb_ocean_fold module~rdb_ocean_fold_exchange->module~rdb_ocean_status module~rdb_ocean_fold_exchange->pic_logger module~rdb_ocean_fold_exchange->pic_mpi_lib module~rdb_ocean_fold_exchange->pic_strings module~rdb_ocean_fold_plan rdb_ocean_fold_plan module~rdb_ocean_fold_exchange->module~rdb_ocean_fold_plan module~rdb_ocean_gm->module~rdb_constants module~rdb_ocean_gm->module~rdb_grid module~rdb_ocean_gm->module~rdb_multilayer_state module~rdb_ocean_gm->module~rdb_ocean_metrics module~rdb_ocean_gm->iso_fortran_env module~rdb_ocean_gm->module~rdb_mem_report module~rdb_ocean_gm->ieee_arithmetic module~rdb_ocean_isopycnal_slopes rdb_ocean_isopycnal_slopes module~rdb_ocean_gm->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_halo_counters->iso_fortran_env module~rdb_ocean_halo_counters->pic_strings module~rdb_ocean_mle->module~rdb_constants module~rdb_ocean_mle->module~rdb_grid module~rdb_ocean_mle->module~rdb_multilayer_state module~rdb_ocean_mle->module~rdb_ocean_boundary_types module~rdb_ocean_mle->module~rdb_ocean_metrics module~rdb_ocean_mle->iso_fortran_env module~rdb_ocean_mle->module~rdb_mem_report module~rdb_ocean_mle->module~rdb_ocean_surface_stress module~rdb_ocean_epbl rdb_ocean_epbl module~rdb_ocean_mle->module~rdb_ocean_epbl module~rdb_ocean_periodic->module~rdb_constants module~rdb_ocean_periodic->module~rdb_grid module~rdb_ocean_periodic->module~rdb_multilayer_state module~rdb_ocean_periodic->module~rdb_ocean_boundary_types module~rdb_ocean_surface_stress->module~rdb_constants module~rdb_ocean_surface_stress->module~rdb_grid module~rdb_ocean_surface_stress->module~rdb_multilayer_state module~rdb_ocean_surface_stress->iso_fortran_env module~rdb_ocean_surface_stress->module~rdb_mem_report module~rdb_ocean_surface_stress->module~rdb_scratch_3d module~rdb_ocean_tide_astro->module~rdb_constants module~rdb_ocean_tide_astro->iso_fortran_env module~rdb_profiler->iso_fortran_env module~rdb_profiler->pic_logger module~rdb_recon_weno->module~rdb_constants module~rdb_recon_weno->module~rdb_grid module~rdb_scratch_3d->module~rdb_constants module~rdb_scratch_3d->iso_fortran_env module~rdb_scratch_3d->module~rdb_mem_report module~rdb_tracer->module~rdb_constants module~rdb_tracer->module~rdb_grid module~rdb_tracer->iso_fortran_env module~rdb_tracer->module~rdb_mem_report module~rdb_config->module~rdb_constants module~rdb_config->module~rdb_error_ring module~rdb_config->module~rdb_ice_enthalpy module~rdb_config->module~rdb_ocean_status module~rdb_config->pic_ascii module~rdb_config->pic_logger module~rdb_config->pic_strings module~rdb_ice_init rdb_ice_init module~rdb_config->module~rdb_ice_init module~rdb_nml_schema rdb_nml_schema module~rdb_config->module~rdb_nml_schema module~rdb_ocean_epbl->module~rdb_constants module~rdb_ocean_epbl->module~rdb_grid module~rdb_ocean_epbl->module~rdb_multilayer_state module~rdb_ocean_epbl->iso_fortran_env module~rdb_ocean_epbl->module~rdb_mem_report module~rdb_ocean_epbl->module~rdb_ocean_surface_stress module~rdb_ocean_epbl->module~rdb_scratch_3d module~rdb_eos rdb_eos module~rdb_ocean_epbl->module~rdb_eos module~rdb_ocean_surface_flux rdb_ocean_surface_flux module~rdb_ocean_epbl->module~rdb_ocean_surface_flux module~rdb_ocean_isopycnal_slopes->module~rdb_constants module~rdb_ocean_isopycnal_slopes->module~rdb_grid module~rdb_ocean_isopycnal_slopes->module~rdb_multilayer_state module~rdb_ocean_isopycnal_slopes->module~rdb_ocean_metrics module~rdb_ocean_isopycnal_slopes->iso_fortran_env module~rdb_ocean_isopycnal_slopes->module~rdb_mem_report module~rdb_ocean_isopycnal_slopes->module~rdb_eos module~rdb_eos->module~rdb_constants module~rdb_eos->module~rdb_grid module~rdb_ice_init->module~rdb_constants module~rdb_ice_init->module~rdb_grid module~rdb_ice_init->module~rdb_ice_column module~rdb_ice_init->module~rdb_ice_state module~rdb_ice_init->module~rdb_multilayer_state module~rdb_ice_init->module~rdb_ocean_metrics module~rdb_ice_init->module~rdb_ice_enthalpy module~rdb_nml_schema->module~rdb_constants module~rdb_nml_schema->module~rdb_error_ring module~rdb_nml_schema->pic_logger module~rdb_ocean_surface_flux->module~rdb_constants module~rdb_ocean_surface_flux->module~rdb_grid module~rdb_ocean_surface_flux->module~rdb_multilayer_state module~rdb_ocean_surface_flux->iso_fortran_env module~rdb_ocean_surface_flux->module~rdb_mem_report

Used by

  • module~~rdb_ice_transport~~UsedByGraph module~rdb_ice_transport rdb_ice_transport module~rdb_ocean_engine rdb_ocean_engine module~rdb_ocean_engine->module~rdb_ice_transport module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_handle->module~rdb_ocean_engine module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_ocean_api->module~rdb_handle

Variables

Type Visibility Attributes Name Initial
real(kind=wp), public, parameter :: H_NEGLECT_ICE_TRANSPORT = 1.0e-30_wp

SIS2 IG%H_subroundoff role (SIS_tracer_advect.F90 advect_scalar_x conditioning guard): a per-CELL mass floor (kg/m² of cell area) below which the tracer-riding division is reconditioned rather than divided directly. Deliberately distinct from rdb_constants’ H_VANISHED/H_DIV_EPS — this guard’s algebra (proportional h_add redistribution across the old mass + both face transports) is SIS2-specific and belongs with the kernel that uses it.

real(kind=wp), public, parameter :: MASS_NEGLECT_ICE_TRANSPORT = 1.0e-60_wp

SIS2 compress_ice’s mass_neglect (SIS_transport.F90:959) — the cell-average-mass gate below which a category is treated as contributing nothing to a transfer (guards the thickness-merge division, not a physical floor).


Subroutines

public pure subroutine ice_cat_flux_x_impl(wet_T, dy_cu, idxT, u_ice, mca, htot_work, hl_x_work, hr_x_work, uhtot_work, uh_out, dt_adv, nghost, nx_phys, ncat, nx, ny, wall_w, wall_e)

SIS2 zonal_mass_flux (SIS_continuity.F90:1064): PPM reconstruction of the category-SUMMED mass htot, ONE total face transport uhtot from the swept-volume parabola integral (volcfl_face, bit-for-bit the SIS2 face expression), then the PROPORTIONATE split uh(c) = uhtot*mca(donor,c)*I_htot(donor) (SIS_continuity.F90:1199-1205, Adcroft reciprocal — I_htot=0 when htot(donor)<=0). Stencil + edge STORAGE CONVENTION + swept-face orientation copied verbatim from continuity_zonal_flux (rdb_continuity.F90:871-948): hl_x_work(i) == h_face_left_x(i) is the value AT east face i from the LEFT cell i-1 (that cell’s OWN downwind edge); hr_x_work(i) == h_face_right_x(i) is from the RIGHT cell i (its OWN left edge). H3-style limited edges + CW84 + ppm_limit_pos (SIS2 runs PPM_limit_pos UNCONDITIONALLY on the PD scheme, so it is not optional here). CFL metric: SIS2’s shipped default vol_CFL=.false. uses CFL = |u|*dt*IdxT(donor) (SIS_continuity.F90:1165) — the T-cell inverse spacing, NOT the dy_cu*iareaT swept-area ratio (== SIS2’s vol_CFL=.true. variant). Identical on uniform Cartesian; correct on spherical / anisotropic.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: wet_T(nx,ny)
real(kind=wp), intent(in) :: dy_cu(nx+1,ny)
real(kind=wp), intent(in) :: idxT(nx,ny)
real(kind=wp), intent(in) :: u_ice(nx+1,ny)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: htot_work(nx,ny)
real(kind=wp), intent(inout) :: hl_x_work(nx+1,ny)
real(kind=wp), intent(inout) :: hr_x_work(nx+1,ny)
real(kind=wp), intent(inout) :: uhtot_work(nx+1,ny)
real(kind=wp), intent(out) :: uh_out(nx+1,ny,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: nghost
integer, intent(in) :: nx_phys
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny
logical, intent(in) :: wall_w

Zero face nghost+1 / nghost+nx_phys+1: only on a physical, non-periodic tile edge. At an MPI or periodic seam the face is an ordinary face whose donor ghosts X4 filled (F1).

logical, intent(in) :: wall_e

Zero face nghost+1 / nghost+nx_phys+1: only on a physical, non-periodic tile edge. At an MPI or periodic seam the face is an ordinary face whose donor ghosts X4 filled (F1).

public pure subroutine ice_cat_flux_y_impl(wet_T, dx_cv, idyT, v_ice, mca, htot_work, hl_y_work, hr_y_work, vhtot_work, vh_out, dt_adv, nghost, ny_phys, ncat, nx, ny, wall_s, wall_n)

Meridional twin of ice_cat_flux_x_impl. Same face-indexed edge STORAGE + swept orientation as continuity_meridional_flux (rdb_continuity.F90:1159-1202): hl_y_work(i,j) == north-face h_face_left_y (from the SOUTH cell j-1), hr_y_work(i,j) == h_face_right_y (from the NORTH cell j). CFL uses IdyT(donor) (SIS2 vol_CFL=.false. default).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: wet_T(nx,ny)
real(kind=wp), intent(in) :: dx_cv(nx,ny+1)
real(kind=wp), intent(in) :: idyT(nx,ny)
real(kind=wp), intent(in) :: v_ice(nx,ny+1)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: htot_work(nx,ny)
real(kind=wp), intent(inout) :: hl_y_work(nx,ny+1)
real(kind=wp), intent(inout) :: hr_y_work(nx,ny+1)
real(kind=wp), intent(inout) :: vhtot_work(nx,ny+1)
real(kind=wp), intent(out) :: vh_out(nx,ny+1,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: nghost
integer, intent(in) :: ny_phys
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny
logical, intent(in) :: wall_s

Zero face nghost+1 / nghost+ny_phys+1: only on a physical, non-periodic tile edge (F1, see the x twin).

logical, intent(in) :: wall_n

Zero face nghost+1 / nghost+ny_phys+1: only on a physical, non-periodic tile edge (F1, see the x twin).

public pure subroutine ice_transport_compress_cell(part_size, m_ice, m_snow, enth_ice, enth_snow, sal_ice, mh_lim, ncat, nk, ok)

KEEP IN SYNC with ice_compress_cell_inline (the DEVICE production twin, directly above). Same excess/ratio/compaction algorithm; this HOST twin exists only as the directly unit-testable seam (small standalone per-cell arrays, no !$acc routine seq), while the device twin takes full device-present arrays + a scalar (i,j) index. Any change to the compaction logic here MUST be mirrored there (the fused device path is what production runs).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: part_size(0:ncat)
real(kind=wp), intent(inout) :: m_ice(ncat)
real(kind=wp), intent(inout) :: m_snow(ncat)
real(kind=wp), intent(inout) :: enth_ice(ncat,nk)
real(kind=wp), intent(inout) :: enth_snow(ncat,1)
real(kind=wp), intent(inout) :: sal_ice(ncat,nk)
real(kind=wp), intent(in) :: mh_lim(ncat+1)
integer, intent(in) :: ncat
integer, intent(in) :: nk
logical, intent(out) :: ok

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.

private pure subroutine ice_cas_to_ist_impl(wet_mask, areaT, mca_ice, mca_snow, part_size, m_ice, m_snow, mh_lim, roll_factor, nghost, ncat, nx, ny)

SIS2 cell_ave_state_to_ice_state (:540). Per cell, per category: pre-floor category 1, optional thin-ice rolling (roll_factor > 0), general floor, then re-derive part_size(c) = mca_ice(c)/m_ice(c) and m_snow(c) = m_ice(c)*(mca_snow(c)/mca_ice(c)) (per-ICE-area). part_size(0) = 1 - Sum_c part_size(c) — MAY be negative here; ice_compress_impl (Phase 4) is what restores >= 0.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: areaT(nx,ny)
real(kind=wp), intent(in) :: mca_ice(nx,ny,ncat)
real(kind=wp), intent(in) :: mca_snow(nx,ny,ncat)
real(kind=wp), intent(inout) :: part_size(nx,ny,0:ncat)
real(kind=wp), intent(inout) :: m_ice(nx,ny,ncat)
real(kind=wp), intent(inout) :: m_snow(nx,ny,ncat)
real(kind=wp), intent(in) :: mh_lim(ncat+1)
real(kind=wp), intent(in) :: roll_factor
integer, intent(in) :: nghost
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_compress_cell_inline(part_size, m_ice, m_snow, enth_ice, enth_snow, sal_ice, mh_lim, i, j, ncat, nk, nx, ny, ok)

KEEP IN SYNC with ice_transport_compress_cell (the HOST tested seam twin, directly below). Same excess/ratio/compaction algorithm; this twin exists only for a different argument shape — full device-present arrays + scalar (i,j) indices for the fused device path (fixed-size device locals), vs the twin’s small standalone per-cell arrays for the unit test. Any change to the compaction logic here MUST be mirrored there (the test only drives the twin).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: part_size(nx,ny,0:ncat)
real(kind=wp), intent(inout) :: m_ice(nx,ny,ncat)
real(kind=wp), intent(inout) :: m_snow(nx,ny,ncat)
real(kind=wp), intent(inout) :: enth_ice(nx,ny,ncat,nk)
real(kind=wp), intent(inout) :: enth_snow(nx,ny,ncat,1)
real(kind=wp), intent(inout) :: sal_ice(nx,ny,ncat,nk)
real(kind=wp), intent(in) :: mh_lim(ncat+1)
integer, intent(in) :: i
integer, intent(in) :: j
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny
logical, intent(out) :: ok

private pure subroutine ice_compress_impl(wet_mask, part_size, m_ice, m_snow, enth_ice, enth_snow, sal_ice, mh_lim, nghost, ncat, nk, nx, ny, ok)

Outer per-cell dispatch: ONE do concurrent(j,i) over physical cells (ghosts excluded), wet_mask > 0.5 inner gate, serial in category within the cell (same shape as ice_adjust_categories_impl). The per-cell algebra is the SAME algorithm ice_transport_compress_cell implements (public, directly unit-testable on small standalone arrays — SPEC §7 test 3’s single-cell hand-check) — but this production kernel does NOT call it with a derived slice: part_size(i,j,:) etc. are NON-CONTIGUOUS sections (the category axis is not the fastest dimension), which a device !$acc routine seq call cannot take safely (would force a compiler temporary — the array-of- derived-type/strided-slice indirection trap, CLAUDE.md memory). Instead the algorithm is INLINED here operating on (i,j,c) triples directly, mirroring ice_adjust_categories_impl’s established pattern. ok is a per-cell-then-reduced flag (D7: SIS2 FATALs on the top-category overflow inconsistency; ported as a !$acc parallel loop reduction instead, since do concurrent cannot itself carry a boolean/min reduction in the house style — CLAUDE.md “Reductions use !$acc parallel loop reduction(...)”).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(inout) :: part_size(nx,ny,0:ncat)
real(kind=wp), intent(inout) :: m_ice(nx,ny,ncat)
real(kind=wp), intent(inout) :: m_snow(nx,ny,ncat)
real(kind=wp), intent(inout) :: enth_ice(nx,ny,ncat,nk)
real(kind=wp), intent(inout) :: enth_snow(nx,ny,ncat,1)
real(kind=wp), intent(inout) :: sal_ice(nx,ny,ncat,nk)
real(kind=wp), intent(in) :: mh_lim(ncat+1)
integer, intent(in) :: nghost
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny
logical, intent(out) :: ok

private pure subroutine ice_gather_flux_x_impl(uh, val, tr_flux_x_work, ncat, nx, ny)

Gather pass (race-free): tr_flux_x_work(I,c) = val(donor of I,c), donor by the sign of the FLUX. uh is exactly 0.0 at the array-edge faces I=1 and I=nx+1 (the flux kernel zeros them unconditionally), so the I=1 donor-by-sign branch (uh>=0) would read the out-of-bounds val(0,j,c) — guarded explicitly below (I==1/I==nx+1 fall back to the IN-BOUNDS neighbour; the value is never actually consumed by the update kernel there since uh==0 at both those faces makes them inert, but the gather must still avoid the invalid index). Reads val ONLY at a donor cell — never writes val — so this kernel has no race with any other iteration.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: uh(nx+1,ny,ncat)
real(kind=wp), intent(in) :: val(nx,ny,ncat)
real(kind=wp), intent(out) :: tr_flux_x_work(nx+1,ny,ncat)
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_gather_flux_x_layer_impl(uh, val4, layer, tr_flux_x_work, ncat, nk, nx, ny)

Layer-indexed twin of ice_gather_flux_x_impl for enth_ice/sal_ice/enth_snow (shape (nx,ny,ncat,nk)).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: uh(nx+1,ny,ncat)
real(kind=wp), intent(in) :: val4(nx,ny,ncat,nk)
integer, intent(in) :: layer
real(kind=wp), intent(out) :: tr_flux_x_work(nx+1,ny,ncat)
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_gather_flux_y_impl(vh, val, tr_flux_y_work, ncat, nx, ny)

Meridional twin of ice_gather_flux_x_impl.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: vh(nx,ny+1,ncat)
real(kind=wp), intent(in) :: val(nx,ny,ncat)
real(kind=wp), intent(out) :: tr_flux_y_work(nx,ny+1,ncat)
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_gather_flux_y_layer_impl(vh, val4, layer, tr_flux_y_work, ncat, nk, nx, ny)

Meridional twin of ice_gather_flux_x_layer_impl.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: vh(nx,ny+1,ncat)
real(kind=wp), intent(in) :: val4(nx,ny,ncat,nk)
integer, intent(in) :: layer
real(kind=wp), intent(out) :: tr_flux_y_work(nx,ny+1,ncat)
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_ist_to_cas_impl(wet_mask, part_size, m_ice, m_snow, mca_ice, mca_snow, nghost, ncat, nx, ny)

SIS2 ice_state_to_cell_ave_state (:465): mca(c) = part_size(c)*m(c) per category, physical cells only. Ghost cells are zeroed (never read as donors in the flux kernels below — wet mirroring + wall zeroing exclude them).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: wet_mask(nx,ny)
real(kind=wp), intent(in) :: part_size(nx,ny,0:ncat)
real(kind=wp), intent(in) :: m_ice(nx,ny,ncat)
real(kind=wp), intent(in) :: m_snow(nx,ny,ncat)
real(kind=wp), intent(out) :: mca_ice(nx,ny,ncat)
real(kind=wp), intent(out) :: mca_snow(nx,ny,ncat)
integer, intent(in) :: nghost
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_mask_snow_by_ice_impl(uh_ice, uh_snow, nfi, nfj, ncat)

SIS2 masking_uh=uh_ice (SIS_continuity.F90:1210-1215): uh_snow(I,c) = 0 wherever uh_ice(I,c) == 0. Face-shaped array, works identically for the x-face (nx+1,ny,ncat) and y-face (nx,ny+1,ncat) layouts (caller passes the right extents). frac_neglect (SIS2’s second masking clause) is dead at SIS2’s own default frac_neglect=0 — not ported (D-noted in the module docstring).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: uh_ice(nfi,nfj,ncat)
real(kind=wp), intent(inout) :: uh_snow(nfi,nfj,ncat)
integer, intent(in) :: nfi
integer, intent(in) :: nfj
integer, intent(in) :: ncat

private pure subroutine ice_mass_update_x_impl(iareaT, uh, mca, dt_adv, nghost, nx_phys, ncat, nx, ny)

SIS2 :183-191: mca(c) -= dt_adv*iareaT*(uh(I)-uh(I-1)), physical cells only. No race (reads faces, writes cells).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: uh(nx+1,ny,ncat)
real(kind=wp), intent(inout) :: mca(nx,ny,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: nghost
integer, intent(in) :: nx_phys
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_mass_update_y_impl(iareaT, vh, mca, dt_adv, nghost, ny_phys, ncat, nx, ny)

Meridional twin of ice_mass_update_x_impl.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: vh(nx,ny+1,ncat)
real(kind=wp), intent(inout) :: mca(nx,ny,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: nghost
integer, intent(in) :: ny_phys
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_max_speed_impl(u_ice, v_ice, nghost, nx_phys, ny_phys, nx, ny, vmax)

Max |u_ice|/|v_ice| over PHYSICAL faces only (the array-edge ghost faces carry no meaning here). !$acc parallel loop reduction (inert comment on non-OpenACC compilers) — GPU-safe max reduction for the zero-velocity exact no-op gate.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: u_ice(nx+1,ny)
real(kind=wp), intent(in) :: v_ice(nx,ny+1)
integer, intent(in) :: nghost
integer, intent(in) :: nx_phys
integer, intent(in) :: ny_phys
integer, intent(in) :: nx
integer, intent(in) :: ny
real(kind=wp), intent(out) :: vmax

private pure subroutine ice_pass_x(grid, metrics, ice, dt_adv, wall_w, wall_e, ok)

One zonal pass: total-mass PPM + proportionate ice-flux split, the snow twin + co-located mask, PCM tracer riding (gather then cell update), the mass update (AFTER every ride reads the pre-update mass), and the post-pass validity reduction.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_sea_ice_t), intent(inout) :: ice
real(kind=wp), intent(in) :: dt_adv
logical, intent(in) :: wall_w

Zero the west / east tile-edge face (a physical, non-periodic edge); a seam face is an ordinary face.

logical, intent(in) :: wall_e

Zero the west / east tile-edge face (a physical, non-periodic edge); a seam face is an ordinary face.

logical, intent(out) :: ok

private pure subroutine ice_pass_y(grid, metrics, ice, dt_adv, wall_s, wall_n, ok)

Meridional twin of ice_pass_x. Reads the POST-x-pass masses (SIS2 SIS_continuity.F90:170-216).

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_sea_ice_t), intent(inout) :: ice
real(kind=wp), intent(in) :: dt_adv
logical, intent(in) :: wall_s

Zero the south / north tile-edge face (physical, non-periodic).

logical, intent(in) :: wall_n

Zero the south / north tile-edge face (physical, non-periodic).

logical, intent(out) :: ok

private pure subroutine ice_ride_update_x_impl(iareaT, uh, tr_flux_x_work, mca, val, dt_adv, ncat, nx, ny)

Cell-update pass (race-free): reads tr_flux_x_work (the GATHERED donor VALUE at each face, from ice_gather_flux_x_impl) + its OWN cell’s mca/val (never a neighbour’s val), applies SIS2’s advect_scalar_x flux-form update + the H_NEGLECT conditioning guard (SIS_tracer_advect.F90:735-760), writes val(i,j,c). hnew is the SAME expression the mass-update kernel (d) uses, so the implied masses agree bitwise. Bitwise no-op when both faces carry zero flux (F_W==F_E==0).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: uh(nx+1,ny,ncat)
real(kind=wp), intent(in) :: tr_flux_x_work(nx+1,ny,ncat)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: val(nx,ny,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_ride_update_x_layer_impl(iareaT, uh, tr_flux_x_work, mca, val4, layer, dt_adv, ncat, nk, nx, ny)

Layer-indexed twin of ice_ride_update_x_impl for enth_ice/sal_ice/enth_snow (shape (nx,ny,ncat,nk)). Same algebra, applied to val4(:,:,:,layer).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: uh(nx+1,ny,ncat)
real(kind=wp), intent(in) :: tr_flux_x_work(nx+1,ny,ncat)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: val4(nx,ny,ncat,nk)
integer, intent(in) :: layer
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_ride_update_y_impl(iareaT, vh, tr_flux_y_work, mca, val, dt_adv, ncat, nx, ny)

Meridional twin of ice_ride_update_x_impl.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: vh(nx,ny+1,ncat)
real(kind=wp), intent(in) :: tr_flux_y_work(nx,ny+1,ncat)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: val(nx,ny,ncat)
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_ride_update_y_layer_impl(iareaT, vh, tr_flux_y_work, mca, val4, layer, dt_adv, ncat, nk, nx, ny)

Layer-indexed twin of ice_ride_update_y_impl for enth_ice/sal_ice/enth_snow (shape (nx,ny,ncat,nk)).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: iareaT(nx,ny)
real(kind=wp), intent(in) :: vh(nx,ny+1,ncat)
real(kind=wp), intent(in) :: tr_flux_y_work(nx,ny+1,ncat)
real(kind=wp), intent(in) :: mca(nx,ny,ncat)
real(kind=wp), intent(inout) :: val4(nx,ny,ncat,nk)
integer, intent(in) :: layer
real(kind=wp), intent(in) :: dt_adv
integer, intent(in) :: ncat
integer, intent(in) :: nk
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_sample_velocity_impl(u_surf, v_surf, wet_u, wet_v, u_ice, v_ice, nx, ny)

u_ice(i,j) = u_surf(i,j)*wet_u(i,j), ditto v. v1 interim filler (SPEC §5 Phase 0) — PR 5 EVP replaces this call with a dynamics solve writing the SAME u_ice/v_ice faces.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: u_surf(nx+1,ny)
real(kind=wp), intent(in) :: v_surf(nx,ny+1)
real(kind=wp), intent(in) :: wet_u(nx+1,ny)
real(kind=wp), intent(in) :: wet_v(nx,ny+1)
real(kind=wp), intent(out) :: u_ice(nx+1,ny)
real(kind=wp), intent(out) :: v_ice(nx,ny+1)
integer, intent(in) :: nx
integer, intent(in) :: ny

private pure subroutine ice_validity_reduce_impl(mca_ice, mca_snow, nghost, nx_phys, ny_phys, ncat, nx, ny, ok)

ok = .false. when min(mca_ice) < 0, min(mca_snow) < 0, or an “orphan snow” cell exists (mca_snow > 0 where mca_ice <= 0 by more than H_NEGLECT_ICE_TRANSPORT) — SIS2 FATALs on any of these; ported as a post-pass reduction (GPU-safe fail-loud, D7) rather than an in-loop abort. Physical cells only.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: mca_ice(nx,ny,ncat)
real(kind=wp), intent(in) :: mca_snow(nx,ny,ncat)
integer, intent(in) :: nghost
integer, intent(in) :: nx_phys
integer, intent(in) :: ny_phys
integer, intent(in) :: ncat
integer, intent(in) :: nx
integer, intent(in) :: ny
logical, intent(out) :: ok

private subroutine ok_all_ranks(ok)

Make a validity flag rank-uniform (global AND, as an exact min of 0/1) BEFORE anyone acts on it: a rank-local early return would strand the other ranks in the next substep’s exchange. No collective unless the run is decomposed (a serial run inside a multi-rank job — the bit-identity reference — stays local).

Arguments

Type IntentOptional Attributes Name
logical, intent(inout) :: ok