ice_snow_ice_flood Subroutine

public pure subroutine ice_snow_ice_flood(nk, m_lay, enthalpy, salin, rho_ratio, snow_to_ice)

Archimedes freeboard snow-ice flooding — the FINAL substantive block of ice_resize_SIS2 (SIS2_ice_thm.F90:1303-1320; PR 27). Standard closure: Leppäranta (1983), A growth model for black ice, snow ice and snow thickness in subarctic basins, Nordic Hydrology 14, 59-70; Fichefet & Morales Maqueda (1997), JGR 102, 12609-12646 §2.3.

The column floats, displacing its own mass of seawater. If the ice alone cannot support the snow load (m_submerged = (m_i+m_s)*rho_ratio > m_i, rho_ratio = ICE_RHO_ICE/ ICE_RHO_OCEAN), the snow-ice interface is below the waterline (“flooded”): convert snow_to_ice = min(m_submerged - m_i, m_lay(0)) kg/m^2 of snow into the TOP ice layer (local index 1 — TOP-DOWN column, TRAP #2 in rdb_ice_column’s module docstring; the caller flips this to the state’s bottom-up enth_ice(...,nk) at the scatter boundary). One non-iterative step suffices: the conversion is 1:1 in mass, so m_i+m_lay(0) is invariant and m_submerged does not move, so the interface lands EXACTLY on the waterline (see PLAN_PR27_snow_ice_ flooding.md §3 for the algebraic proof + a worked golden).

Roundabout has no ponds (m_pond is a hardwired dead local in rdb_ice_column), so the min(...) clamp is PROVABLY DEAD CODE here: it binds iff m_lay(0) < -m_i, impossible for non-negative masses (see the plan §9.2 sweep test). Kept for SIS2 parity — ponds would resurrect it.

Mass-, enthalpy- and salt-conserving WITHIN THE COLUMN, exactly ((m_0-s)*E_0 + (m_1+s)*[(m_1*E_1+s*E_0)/(m_1+s)] = m_0*E_0 + m_1*E_1, identity; the salinity dilution S_1*m_1/(m_1+s) IS the mass-weighted mix since S_snow == 0, salin(0)). enthalpy(1) and salin(1) both DECREASE — snow’s cold, fresh mass lands in the ice.

Known physical incompleteness, inherited from SIS2 (not fixed here — true seawater flooding is a materially larger, separate closure, see the plan’s §12/§14 Q1). Real flooding draws SEAWATER into the pore space, which then refreezes, releasing latent heat and rejecting brine. SIS2 instead moves snow mass with the SNOW’s enthalpy and ZERO salinity — snow enthalpy (<= -L_f ~ -3.34e5 J/kg) is far more negative than near-freezing seawater, so the new ice is too COLD; S_snow == 0 means it is too FRESH. snow_to_ice is diagnostic-only (SIS2’s SN2IC): flooding exchanges NOTHING with the ocean (SIS2_ice_thm.F90:1273, “There are no further heat or mass losses or gains by the ice+snow”).

Arguments

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

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

real(kind=wp), intent(inout) :: m_lay(0:nk)

Layer masses (kg/m²), 0 = snow, 1..nk = ice.

real(kind=wp), intent(inout) :: enthalpy(0:nk)

Layer specific enthalpies (J/kg).

real(kind=wp), intent(inout) :: salin(0:nk)

Layer bulk salinities (PSU).

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

ICE_RHO_ICE/ICE_RHO_OCEAN (nondim, < 1) — computed by the caller (rdb_ice_column), which already has both density parameters in scope; keeps this module free of a circular use rdb_ice_column (that module uses this one).

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

Mass converted from snow to the top ice layer this call (kg/m²), >= 0 — SIS2 SN2IC.


Called by

proc~~ice_snow_ice_flood~~CalledByGraph proc~ice_snow_ice_flood ice_snow_ice_flood proc~ice_column_step ice_column_step proc~ice_column_step->proc~ice_snow_ice_flood proc~ice_thermo_columns ice_thermo_columns proc~ice_thermo_columns->proc~ice_column_step proc~ice_thermo_driver_step ice_thermo_driver_step proc~ice_thermo_driver_step->proc~ice_thermo_columns proc~engine_step_ice engine_step_ice proc~engine_step_ice->proc~ice_thermo_driver_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

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: m_i
real(kind=wp), private :: m_submerged

Source Code

   pure subroutine ice_snow_ice_flood(nk, m_lay, enthalpy, salin, rho_ratio, snow_to_ice)
      !! Archimedes freeboard snow-ice flooding — the FINAL substantive
      !! block of `ice_resize_SIS2` (SIS2_ice_thm.F90:1303-1320; PR 27).
      !! Standard closure: Leppäranta (1983), *A growth model for black
      !! ice, snow ice and snow thickness in subarctic basins*, Nordic
      !! Hydrology 14, 59-70; Fichefet & Morales Maqueda (1997), JGR 102,
      !! 12609-12646 §2.3.
      !!
      !! The column floats, displacing its own mass of seawater. If the
      !! ice alone cannot support the snow load (`m_submerged =
      !! (m_i+m_s)*rho_ratio > m_i`, `rho_ratio = ICE_RHO_ICE/
      !! ICE_RHO_OCEAN`), the snow-ice interface is below the waterline
      !! ("flooded"): convert `snow_to_ice = min(m_submerged - m_i,
      !! m_lay(0))` kg/m^2 of snow into the TOP ice layer (local index 1
      !! — TOP-DOWN column, TRAP #2 in `rdb_ice_column`'s module
      !! docstring; the caller flips this to the state's bottom-up
      !! `enth_ice(...,nk)` at the scatter boundary). One non-iterative
      !! step suffices: the conversion is 1:1 in mass, so `m_i+m_lay(0)`
      !! is invariant and `m_submerged` does not move, so the interface
      !! lands EXACTLY on the waterline (see PLAN_PR27_snow_ice_
      !! flooding.md §3 for the algebraic proof + a worked golden).
      !!
      !! Roundabout has no ponds (`m_pond` is a hardwired dead local in
      !! `rdb_ice_column`), so the `min(...)` clamp is PROVABLY DEAD
      !! CODE here: it binds iff `m_lay(0) < -m_i`, impossible for
      !! non-negative masses (see the plan §9.2 sweep test). Kept for
      !! SIS2 parity — ponds would resurrect it.
      !!
      !! Mass-, enthalpy- and salt-conserving WITHIN THE COLUMN, exactly
      !! (`(m_0-s)*E_0 + (m_1+s)*[(m_1*E_1+s*E_0)/(m_1+s)] = m_0*E_0 +
      !! m_1*E_1`, identity; the salinity dilution `S_1*m_1/(m_1+s)` IS
      !! the mass-weighted mix since `S_snow == 0`, `salin(0)`).
      !! `enthalpy(1)` and `salin(1)` both DECREASE — snow's cold, fresh
      !! mass lands in the ice.
      !!
      !! **Known physical incompleteness, inherited from SIS2 (not fixed
      !! here — true seawater flooding is a materially larger, separate
      !! closure, see the plan's §12/§14 Q1).** Real flooding draws
      !! SEAWATER into the pore space, which then refreezes, releasing
      !! latent heat and rejecting brine. SIS2 instead moves snow mass
      !! with the SNOW's enthalpy and ZERO salinity — snow enthalpy
      !! (<= -L_f ~ -3.34e5 J/kg) is far more negative than near-freezing
      !! seawater, so the new ice is too COLD; `S_snow == 0` means it is
      !! too FRESH. `snow_to_ice` is diagnostic-only (SIS2's SN2IC):
      !! flooding exchanges NOTHING with the ocean (SIS2_ice_thm.F90:1273,
      !! "There are no further heat or mass losses or gains by the
      !! ice+snow").
      !$acc routine seq
      integer, intent(in) :: nk
         !! Number of ice layers (declared first — decl-order).
      real(wp), intent(inout) :: m_lay(0:nk)
         !! Layer masses (kg/m²), 0 = snow, 1..nk = ice.
      real(wp), intent(inout) :: enthalpy(0:nk)
         !! Layer specific enthalpies (J/kg).
      real(wp), intent(inout) :: salin(0:nk)
         !! Layer bulk salinities (PSU).
      real(wp), intent(in) :: rho_ratio
         !! `ICE_RHO_ICE/ICE_RHO_OCEAN` (nondim, < 1) — computed by the
         !! caller (`rdb_ice_column`), which already has both density
         !! parameters in scope; keeps this module free of a circular
         !! `use rdb_ice_column` (that module `use`s this one).
      real(wp), intent(out) :: snow_to_ice
         !! Mass converted from snow to the top ice layer this call
         !! (kg/m²), >= 0 — SIS2 `SN2IC`.

      real(wp) :: m_i, m_submerged

      m_i = sum(m_lay(1:nk))
      m_submerged = (m_i + m_lay(0))*rho_ratio

      snow_to_ice = 0.0_wp
      if (m_submerged > m_i) then
         snow_to_ice = min(m_submerged - m_i, m_lay(0))
      end if

      ! Denominator `m_lay(1) + snow_to_ice` is provably > 0 whenever
      ! this branch is taken: entering it forces `m_lay(0) > 0` (since
      ! rho_ratio < 1, m_submerged > m_i needs m_lay(0) > 0), hence
      ! snow_to_ice = min(m_lay(0), ...) > 0 — even if m_lay(1) == 0
      ! (top layer melted out this step). The inner guard below is free
      ! and makes the no-snow no-op provable by inspection; it is NOT
      ! `H_DIV_EPS` armour (CLAUDE.md taxonomy — the branch guard above
      ! already rules out the zero case).
      if (snow_to_ice > 0.0_wp) then
         m_lay(0) = m_lay(0) - snow_to_ice
         enthalpy(1) = (m_lay(1)*enthalpy(1) + snow_to_ice*enthalpy(0))/ &
                       (m_lay(1) + snow_to_ice)
         salin(1) = salin(1)*m_lay(1)/(m_lay(1) + snow_to_ice)
         m_lay(1) = m_lay(1) + snow_to_ice
      end if
   end subroutine ice_snow_ice_flood