ice_frazil_uptake_column Subroutine

private pure subroutine ice_frazil_uptake_column(nk, frazil, tfw, sst, s_surf, m_snow, m_ice_tot, enth_ice_bu, sal_ice_bu, m_frozen, salt_to_ice)

Per-(cell,category-1) column worker: gather + flip (bottom-up -> top-down, TRAP #2 discipline), spend the whole frazil bank evenly over the nk layers (SIS2:1402), rebalance, scatter + flip back. Port of add_frazil_SIS2 (SIS2_ice_thm.F90:1342-1444), bulk-salinity mode (salin_freeze = ICE_BULK_SALINITY, SIS_slow_thermo.F90: 1207-1209) — the ice_rel_salin mode is NOT ported.

Snow slot (m_snow, index 0 in the local top-down column) is carried through untouched — the frazil spend loop only ever touches k = 1..nk (ice layers); enthalpy(0)/salin(0) are placeholder zeros that ice_rebalance_layers neither reads nor writes.

Empty-column degeneracy: m_lay(k) = 0 on entry makes the mass-weighted mix reduce exactly to enthalpy(k) = enth_frazil, salin(k) = ICE_BULK_SALINITY — SIS2’s post-rebalance mH_ice == 0 => enthalpy_liquid_freeze reset (SIS2_ice_thm.F90:1420-1424) is unreachable here (a spend only runs when frazil > 0, which always deposits mass) and is deliberately NOT ported.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nk

Number of ice layers (declared first — decl-order).

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

Whole per-cell frazil bank to spend this call (J/m² of cell).

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

Seawater freezing temperature at the surface (degC).

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

Sea-surface temperature (degC) — feeds the TRAP-#1 liquid ocean enthalpy.

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

Sea-surface salinity (PSU) — feeds the TRAP-#1 liquid ocean enthalpy (unused by the linear formula, kept for call-site parity with ice_enthalpy_liquid).

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

Snow mass per unit CELL area (kg/m²) — untouched, carried through only to seed the local column’s slot 0.

real(kind=wp), intent(inout) :: m_ice_tot

Total category-1 ice mass per unit CELL area (kg/m²); in = prior step, out = post-freeze.

real(kind=wp), intent(inout) :: enth_ice_bu(nk)

BOTTOM-UP ice specific enthalpies (J/kg) — state order, enth_ice_bu(1) = ice bottom.

real(kind=wp), intent(inout) :: sal_ice_bu(nk)

BOTTOM-UP ice bulk salinities (PSU) — state order.

real(kind=wp), intent(out) :: m_frozen

Total new-ice mass formed this call (kg/m² of cell).

real(kind=wp), intent(out) :: salt_to_ice

Salt content retained by the new ice (kg/m² of cell) — m_frozen * ICE_BULK_SALINITY.


Calls

proc~~ice_frazil_uptake_column~~CallsGraph proc~ice_frazil_uptake_column ice_frazil_uptake_column proc~ice_enth_from_ts ice_enth_from_ts proc~ice_frazil_uptake_column->proc~ice_enth_from_ts proc~ice_enthalpy_liquid ice_enthalpy_liquid proc~ice_frazil_uptake_column->proc~ice_enthalpy_liquid proc~ice_rebalance_layers ice_rebalance_layers proc~ice_frazil_uptake_column->proc~ice_rebalance_layers proc~ice_t_freeze ice_t_freeze proc~ice_frazil_uptake_column->proc~ice_t_freeze

Called by

proc~~ice_frazil_uptake_column~~CalledByGraph proc~ice_frazil_uptake_column ice_frazil_uptake_column proc~ice_frazil_uptake_impl ice_frazil_uptake_impl proc~ice_frazil_uptake_impl->proc~ice_frazil_uptake_column proc~ice_frazil_uptake_multicat_impl ice_frazil_uptake_multicat_impl proc~ice_frazil_uptake_multicat_impl->proc~ice_frazil_uptake_column proc~ice_frazil_uptake ice_frazil_uptake proc~ice_frazil_uptake->proc~ice_frazil_uptake_impl proc~ice_frazil_uptake->proc~ice_frazil_uptake_multicat_impl proc~engine_step_ice engine_step_ice proc~engine_step_ice->proc~ice_frazil_uptake 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 :: enth_frazil
real(kind=wp), private :: enth_ocean
real(kind=wp), private :: enthalpy(0:ICE_NK_MAX)
real(kind=wp), private :: frazil_per_layer
integer, private :: k
real(kind=wp), private :: m_frazil
real(kind=wp), private :: m_lay(0:ICE_NK_MAX)
real(kind=wp), private :: min_denth
real(kind=wp), private :: mtot_ice
real(kind=wp), private :: salin(0:ICE_NK_MAX)
real(kind=wp), private :: t_frazil

Source Code

   pure subroutine ice_frazil_uptake_column(nk, frazil, tfw, sst, s_surf, m_snow, &
                                            m_ice_tot, enth_ice_bu, sal_ice_bu, &
                                            m_frozen, salt_to_ice)
      !! Per-(cell,category-1) column worker: gather + flip
      !! (bottom-up -> top-down, TRAP #2 discipline), spend the whole
      !! `frazil` bank evenly over the `nk` layers (SIS2:1402), rebalance,
      !! scatter + flip back. Port of `add_frazil_SIS2`
      !! (SIS2_ice_thm.F90:1342-1444), bulk-salinity mode
      !! (`salin_freeze = ICE_BULK_SALINITY`, SIS_slow_thermo.F90:
      !! 1207-1209) — the `ice_rel_salin` mode is NOT ported.
      !!
      !! Snow slot (`m_snow`, index 0 in the local top-down column) is
      !! carried through untouched — the frazil spend loop only ever
      !! touches `k = 1..nk` (ice layers); `enthalpy(0)`/`salin(0)` are
      !! placeholder zeros that `ice_rebalance_layers` neither reads nor
      !! writes.
      !!
      !! Empty-column degeneracy: `m_lay(k) = 0` on entry makes the
      !! mass-weighted mix reduce exactly to
      !! `enthalpy(k) = enth_frazil`, `salin(k) = ICE_BULK_SALINITY` —
      !! SIS2's post-rebalance `mH_ice == 0 => enthalpy_liquid_freeze`
      !! reset (SIS2_ice_thm.F90:1420-1424) is unreachable here (a spend
      !! only runs when `frazil > 0`, which always deposits mass) and is
      !! deliberately NOT ported.
      !$acc routine seq
      integer, intent(in) :: nk
         !! Number of ice layers (declared first — decl-order).
      real(wp), intent(in) :: frazil
         !! Whole per-cell frazil bank to spend this call (J/m² of cell).
      real(wp), intent(in) :: tfw
         !! Seawater freezing temperature at the surface (degC).
      real(wp), intent(in) :: sst
         !! Sea-surface temperature (degC) — feeds the TRAP-#1 liquid
         !! ocean enthalpy.
      real(wp), intent(in) :: s_surf
         !! Sea-surface salinity (PSU) — feeds the TRAP-#1 liquid ocean
         !! enthalpy (unused by the linear formula, kept for call-site
         !! parity with `ice_enthalpy_liquid`).
      real(wp), intent(in) :: m_snow
         !! Snow mass per unit CELL area (kg/m²) — untouched, carried
         !! through only to seed the local column's slot 0.
      real(wp), intent(inout) :: m_ice_tot
         !! Total category-1 ice mass per unit CELL area (kg/m²); in =
         !! prior step, out = post-freeze.
      real(wp), intent(inout) :: enth_ice_bu(nk)
         !! BOTTOM-UP ice specific enthalpies (J/kg) — state order,
         !! `enth_ice_bu(1)` = ice bottom.
      real(wp), intent(inout) :: sal_ice_bu(nk)
         !! BOTTOM-UP ice bulk salinities (PSU) — state order.
      real(wp), intent(out) :: m_frozen
         !! Total new-ice mass formed this call (kg/m² of cell).
      real(wp), intent(out) :: salt_to_ice
         !! Salt content retained by the new ice (kg/m² of cell) —
         !! `m_frozen * ICE_BULK_SALINITY`.

      real(wp) :: m_lay(0:ICE_NK_MAX), enthalpy(0:ICE_NK_MAX), salin(0:ICE_NK_MAX)
      real(wp) :: frazil_per_layer, enth_ocean, min_denth, t_frazil, enth_frazil, m_frazil
      real(wp) :: mtot_ice
      integer :: k

      ! ---- Gather + flip (TRAP #2): bottom-up state -> top-down local ----
      do k = 1, nk
         enthalpy(k) = enth_ice_bu(nk + 1 - k)
         salin(k) = sal_ice_bu(nk + 1 - k)
      end do
      m_lay(0) = m_snow
      enthalpy(0) = 0.0_wp
      salin(0) = 0.0_wp
      do k = 1, nk
         m_lay(k) = m_ice_tot/real(nk, wp)
      end do

      ! ---- Spend the whole bank, evenly split, top-down (SIS2:1402) ----
      frazil_per_layer = frazil/real(nk, wp)
      enth_ocean = ice_enthalpy_liquid(sst, s_surf)   ! TRAP #1
      min_denth = ICE_LAT_FUS*(1.0_wp - ICE_LIQ_LIM)
      m_frozen = 0.0_wp
      salt_to_ice = 0.0_wp
      do k = 1, nk
         t_frazil = min(tfw, ice_t_freeze(salin(k)) - ICE_FRAZIL_T_OFFSET)
         enth_frazil = min(ice_enth_from_ts(t_frazil, salin(k)), enth_ocean - min_denth)
         m_frazil = frazil_per_layer/(enth_ocean - enth_frazil)
         enthalpy(k) = (m_lay(k)*enthalpy(k) + m_frazil*enth_frazil)/(m_lay(k) + m_frazil)
         salin(k) = (m_lay(k)*salin(k) + m_frazil*ICE_BULK_SALINITY)/(m_lay(k) + m_frazil)
         m_lay(k) = m_lay(k) + m_frazil
         m_frozen = m_frozen + m_frazil
         salt_to_ice = salt_to_ice + m_frazil*ICE_BULK_SALINITY
      end do

      call ice_rebalance_layers(nk, m_lay(0:nk), enthalpy(0:nk), salin(0:nk), mtot_ice)

      ! ---- Scatter + flip back: top-down local -> bottom-up state ----
      m_ice_tot = mtot_ice
      do k = 1, nk
         enth_ice_bu(nk + 1 - k) = enthalpy(k)
         sal_ice_bu(nk + 1 - k) = salin(k)
      end do
   end subroutine ice_frazil_uptake_column