rdb_ice_column Module

Port of ice_temp_SIS2 + laytemp_SIS2 + update_lay_enth (SIS2_ice_thm.F90:169-945, Apache-2.0) under the ICE_CP_BRINE == ICE_CP_ICE simplification (rdb_ice_enthalpy module docstring): every per-layer implicit solve and T<->E inversion is a closed-form quadratic — no Newton / false-position iteration anywhere. Ported line-by-line from the validated stdlib-only Python prototype tmp_local_artifacts/ice_pr3a_prototype/ sis2_column.py; when any formula here and SIS2 itself seem to disagree, the prototype (which reproduces SIS2’s own commented-out col_check energy-closure diagnostic to ~1e-14 fractional) is the tiebreaker.

Index convention — TRAP #2. Internal columns are TOP-DOWN, identical to SIS2 and the prototype: index 0 = snow, 1..nk = ice, top to bottom. Roundabout’s state (ocean_sea_ice_t) is BOTTOM-UP: enth_ice(..., 1) = ice bottom (ocean side), enth_ice(..., nk_ice) = ice top (atm/snow side). The flip happens ONLY at the gather/scatter boundary in ice_column_step (local(k) = state(nk+1-k), the kg = nz+1-k idiom of kappa_shear_column_driver, rdb_ocean_kappa_shear.F90:366) — nothing inside ice_temp_sis2 / laytemp_sis2 / update_lay_enth ever sees the bottom-up convention.

Ocean-freeze enthalpy — TRAP #1. The bottom-freeze ocean-side enthalpy is the LIQUID formula ice_enthalpy_liquid(sst, s_surf) (SIS_slow_thermo.F90:981), never the frozen/mushy ice_enth_from_ts(tfw, sice) — the latter is ~8-9x more negative at typical sea-ice salinities, inflating freeze mass per Joule and making Stefan growth ~3x too fast. Lands in ice_column_step step 4 (§3.4).

fb is a post-hoc residual, not a matrix BC — TRAP #3. The conduction matrix’s bottom row always couples to the freezing temperature tfw (cc(nk+1) = 2*kk*dtt); fb (ocean->ice heat flux) enters exactly once, AFTER the conservative enthalpy update, as bmelt = bmelt + (dtt*fb - tflux_bot). See ice_temp_sis2.

bb(k) two-branch live formula — TRAP #4. Not dead code: see ice_temp_sis2’s bb computation, the (Cp_brine - Cp_ice) term kept explicit even though it is 0 under the simplification (matches the prototype’s chosen style, sis2_column.py:214).

nk_ice == 2 quasi-conservative double-pass — TRAP #5. After the up/down tridiagonal estimate, every layer temperature is re-solved via laytemp_sis2 (SIS2_ice_thm.F90:372-388) — this is what pulls the Stefan-problem error under 1%; see ice_temp_sis2. ICE_CP_BRINE == ICE_CP_ICE is asserted at slot init (ocean_sea_ice_init, rdb_ice_state) so the unported Newton/false-position branches (SIS2_ice_thm.F90:625-692, 837-870, 1876-1933) are provably unreachable.

Snow lands AFTER optics + conduction — TRAP #6 (PR 26). ice_column_step’s snow argument is added in step 4 (resize, via ice_snow_accumulate), which runs strictly after step 2 (optics, ice_optics_csim4) and step 3 (conduction, ice_temp_sis2) already used the PRE-snowfall m_snow. This is SIS2’s fast/slow split (ice_resize_SIS2 runs after the conduction solve, SIS2_ice_thm.F90:1122), NOT an oversight: new snow IS meltable in the same window (ice_top_melt_peel starts at k=0), but its albedo and conduction effect are felt only on the NEXT window. Do not move the add earlier chasing “why doesn’t the albedo respond immediately”.

Flood after melt, before rebalance — TRAP #7 (PR 27). The Archimedes freeboard snow-ice flood (ice_snow_ice_flood) runs AFTER ice_bottom_melt_peel (so freshly-converted mass is not re-melted this step and m_i reflects the post-melt column) and BEFORE ice_rebalance_layers (else the new mass in layer 1 is never redistributed across the nk layers) — exactly SIS2’s order (ice_resize_SIS2 -> rebalance_ice_layers, SIS_slow_thermo.F90:998,1008). It writes local index 1 (the TOP ice layer, TRAP #2) — do not “helpfully” index nk.

Everything pure; every per-column routine !$acc routine seq; explicit-shape dummies with integer dims declared before the arrays that use them (decl-order); fixed-size locals capped by ICE_NK_MAX (kappa-shear NZ_STACK_MAX precedent) in the driver.


Uses

  • module~~rdb_ice_column~~UsesGraph module~rdb_ice_column rdb_ice_column module~rdb_constants rdb_constants 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 pic_types pic_types module~rdb_constants->pic_types 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

Used by

  • module~~rdb_ice_column~~UsedByGraph module~rdb_ice_column rdb_ice_column module~rdb_ice_basal_flux rdb_ice_basal_flux module~rdb_ice_basal_flux->module~rdb_ice_column module~rdb_ice_state rdb_ice_state module~rdb_ice_basal_flux->module~rdb_ice_state module~rdb_ice_evp rdb_ice_evp module~rdb_ice_evp->module~rdb_ice_column module~rdb_ice_evp->module~rdb_ice_state module~rdb_ocean_halo rdb_ocean_halo module~rdb_ice_evp->module~rdb_ocean_halo module~rdb_ice_frazil_uptake rdb_ice_frazil_uptake module~rdb_ice_frazil_uptake->module~rdb_ice_column module~rdb_ice_frazil_uptake->module~rdb_ice_state module~rdb_ice_init rdb_ice_init module~rdb_ice_init->module~rdb_ice_column module~rdb_ice_init->module~rdb_ice_state module~rdb_ice_state->module~rdb_ice_column module~rdb_ice_thermo_driver rdb_ice_thermo_driver module~rdb_ice_thermo_driver->module~rdb_ice_column module~rdb_ice_thermo_driver->module~rdb_ice_state module~rdb_ice_transport rdb_ice_transport module~rdb_ice_transport->module~rdb_ice_column module~rdb_ice_transport->module~rdb_ice_state module~rdb_ice_itd rdb_ice_itd module~rdb_ice_transport->module~rdb_ice_itd module~rdb_ocean_halo_state rdb_ocean_halo_state module~rdb_ice_transport->module~rdb_ocean_halo_state module~rdb_halo rdb_halo module~rdb_ice_transport->module~rdb_halo module~rdb_ice_transport->module~rdb_ocean_halo module~rdb_ocean_console_stats rdb_ocean_console_stats module~rdb_ocean_console_stats->module~rdb_ice_column module~rdb_ocean_console_stats->module~rdb_halo module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_diag_fills->module~rdb_ice_column module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_diag_fills->module~rdb_ocean_state module~rdb_config rdb_config module~rdb_config->module~rdb_ice_init module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_console_stats module~rdb_driver->module~rdb_config module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_driver->module~rdb_ocean_dyn module~rdb_ocean_engine rdb_ocean_engine module~rdb_driver->module~rdb_ocean_engine module~rdb_driver->module~rdb_ocean_state module~rdb_driver->module~rdb_halo module~rdb_ice_atm_forcing rdb_ice_atm_forcing module~rdb_ice_atm_forcing->module~rdb_ice_state module~rdb_ice_itd->module~rdb_ice_state module~rdb_ice_ocean_coupler rdb_ice_ocean_coupler module~rdb_ice_ocean_coupler->module~rdb_ice_state module~rdb_ice_ocean_coupler->module~rdb_ocean_halo_state module~rdb_ice_snow rdb_ice_snow module~rdb_ice_snow->module~rdb_ice_state module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_config module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_dyn module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_diag_derived->module~rdb_ocean_diag_fills module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_dyn->module~rdb_ocean_console_stats module~rdb_ocean_dyn->module~rdb_ocean_halo_state module~rdb_ocean_dyn->module~rdb_ocean_halo module~rdb_ocean_engine->module~rdb_ice_basal_flux module~rdb_ocean_engine->module~rdb_ice_evp module~rdb_ocean_engine->module~rdb_ice_frazil_uptake module~rdb_ocean_engine->module~rdb_ice_init module~rdb_ocean_engine->module~rdb_ice_thermo_driver module~rdb_ocean_engine->module~rdb_ice_transport module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_ocean_engine->module~rdb_config module~rdb_ocean_engine->module~rdb_ice_atm_forcing module~rdb_ocean_engine->module~rdb_ice_itd module~rdb_ocean_engine->module~rdb_ice_ocean_coupler module~rdb_ocean_engine->module~rdb_ice_snow module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_dyn module~rdb_ocean_engine->module~rdb_ocean_halo_state module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_decomp rdb_decomp module~rdb_ocean_engine->module~rdb_decomp module~rdb_ocean_data_forcing rdb_ocean_data_forcing module~rdb_ocean_engine->module~rdb_ocean_data_forcing module~rdb_ocean_data_input rdb_ocean_data_input module~rdb_ocean_engine->module~rdb_ocean_data_input module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_stability_audit rdb_ocean_stability_audit module~rdb_ocean_engine->module~rdb_ocean_stability_audit module~rdb_state rdb_state module~rdb_ocean_engine->module~rdb_state module~rdb_ocean_engine->module~rdb_halo module~rdb_ocean_fold_exchange rdb_ocean_fold_exchange module~rdb_ocean_engine->module~rdb_ocean_fold_exchange module~rdb_ocean_engine->module~rdb_ocean_halo module~rdb_ocean_halo_state->module~rdb_ice_state module~rdb_ocean_halo_state->module~rdb_ocean_halo module~rdb_ocean_state->module~rdb_ice_state module~rdb_ocean_state->module~rdb_config module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_ocean_state->module~rdb_decomp module~rdb_ocean_state->module~rdb_ocean_data_forcing module~rdb_ocean_state->module~rdb_ocean_data_input module~rdb_ocean_z_init rdb_ocean_z_init module~rdb_ocean_state->module~rdb_ocean_z_init module~rdb_ocean_restart_io rdb_ocean_restart_io module~rdb_ocean_state->module~rdb_ocean_restart_io module~rdb_config_schema rdb_config_schema module~rdb_config_schema->module~rdb_config module~rdb_decomp->module~rdb_config module~rdb_handle->module~rdb_config module~rdb_handle->module~rdb_ocean_engine module~rdb_handle->module~rdb_ocean_state module~rdb_ocean_data_forcing->module~rdb_config module~rdb_ocean_data_forcing->module~rdb_ocean_halo_state module~rdb_ocean_data_forcing->module~rdb_ocean_data_input module~rdb_ocean_data_input->module~rdb_config module~rdb_ocean_setup->module~rdb_config module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_halo_state module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_setup->module~rdb_decomp module~rdb_ocean_setup->module~rdb_halo module~rdb_ocean_setup->module~rdb_ocean_fold_exchange module~rdb_ocean_setup->module~rdb_ocean_halo module~rdb_ocean_stability_audit->module~rdb_config module~rdb_ocean_z_init->module~rdb_config module~rdb_state->module~rdb_config module~rdb_halo->module~rdb_decomp module~rdb_ocean_fold_exchange->module~rdb_decomp module~rdb_ocean_halo->module~rdb_decomp module~rdb_ocean_restart_io->module~rdb_decomp module~rdb_barotropic_substep rdb_barotropic_substep module~rdb_barotropic_substep->module~rdb_ocean_fold_exchange module~rdb_barotropic_substep->module~rdb_ocean_halo module~rdb_continuity rdb_continuity module~rdb_continuity->module~rdb_ocean_fold_exchange module~rdb_continuity->module~rdb_ocean_halo module~rdb_ocean_bt_wide rdb_ocean_bt_wide module~rdb_ocean_bt_wide->module~rdb_ocean_halo module~rdb_ocean_chksum rdb_ocean_chksum module~rdb_ocean_chksum->module~rdb_halo module~rdb_ocean_fold_apply rdb_ocean_fold_apply module~rdb_ocean_fold_apply->module~rdb_ocean_fold_exchange proc~ocean_cavity_mass_step ocean_cavity_mass_step proc~ocean_cavity_mass_step->module~rdb_halo

Variables

Type Visibility Attributes Name Initial
real(kind=wp), public, parameter :: ICE_BULK_SALINITY = 4.0_wp

ICE_BULK_SALINITY (SIS_slow_thermo.F90:1604) — new-ice salinity used by ice_bottom_freeze’s salin_freeze, AND the sal_ice state-init value (rdb_ice_state). NOT 5 — resolves to the prototype/SIS2 default 4.0 (run_validation.py:21 sice_val=4.0).

real(kind=wp), public, parameter :: ICE_H_LO_LIM = 0.0_wp

MIN_H_FOR_TEMP_CALC (m) — floor applied in the effective layer-thickness expressions of ice_temp_sis2. Kept in the algebra at 0 per the prototype (sis2_thermo.py:41).

real(kind=wp), public, parameter :: ICE_K_ICE = 2.03_wp

Bulk ice thermal conductivity (W/m/K) — SIS2 ICE_CONDUCTIVITY.

real(kind=wp), public, parameter :: ICE_K_SNOW = 0.31_wp

Bulk snow thermal conductivity (W/m/K) — SIS2 SNOW_CONDUCTIVITY.

real(kind=wp), public, parameter :: ICE_RHO_ICE = 905.0_wp

Nominal sea-ice density (kg/m³).

real(kind=wp), public, parameter :: ICE_RHO_OCEAN = 1030.0_wp

Nominal seawater reference density (kg/m³) — SIS2 RHO_OCEAN. Consumed by the PR-27 Archimedes freeboard flood (ice_column_step passes ICE_RHO_ICE/ICE_RHO_OCEAN into ice_snow_ice_flood). Deliberately independent of &ocean_ice_nml rho_ocean (the EVP ice-drag reference density, rdb_ice_evp) — do not unify them, that would silently couple the flood threshold to an EVP tuning knob.

real(kind=wp), public, parameter :: ICE_RHO_SNOW = 330.0_wp

Nominal snow density (kg/m³).

real(kind=wp), public, parameter :: ICE_TEMP_RANGE_EST = 40.0_wp

temp_range_est default (K) — feeds heat_flux_err_rat (SIS2_ice_thm.F90:397ff; prototype sis2_column.py:291).


Functions

public pure function laytemp_sis2(m, t_fr, qf, bf, tp, dtt) result(new_temp)

Per-layer implicit heat-budget solve for the new layer temperature — SIS2 laytemp_SIS2 (SIS2_ice_thm.F90:544-700), ICE_CP_BRINE == ICE_CP_ICE closed-form branches only (the Newton/false-position refinement at :625-692 is dead code under the simplification and is deliberately NOT ported). Port of prototype sis2_column.py:21-55.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: m

Layer mass (kg/m²).

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

Layer freezing temperature (degC); 0 for snow/fresh water.

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

Forcing heat flux into the layer (W/m²).

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

Implicit coupling coefficient to the neighbour temperature (W/m²/K).

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

Previous-step layer temperature (degC).

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

Timestep (s).

Return Value real(kind=wp)


Subroutines

public pure subroutine ice_column_step(nk, m_snow, m_ice_tot, enth_snow_pt, enth_ice_bu, sal_ice_bu, sf_0, dsf_dt, sw_dn, tfw, fb, sst, s_surf, dtt, do_snow_ice, snow, tsurf, h2o_ocn_to_ice, h2o_ice_to_ocn, heat_to_ocn, sw_thru, snow_to_ice)

Per-(cell,category) orchestrator: gather (bottom-up -> top-down flip, TRAP #2), optics, conduction (ice_temp_sis2), resize (snow add, bottom-freeze, top/bottom melt peel, rebalance), scatter (flip back).

Read more…

Arguments

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

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

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

Snow mass per unit area (kg/m²).

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

Total ice mass per unit area (kg/m²).

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

Snow specific enthalpy (J/kg).

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(in) :: sf_0

Linearized SEB intercept (W/m²), upward-positive.

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

Linearized SEB slope (W/m²/K), upward-positive.

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

Downwelling shortwave at the surface (W/m²).

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

Seawater freezing temperature at the ice base (degC).

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

Ocean -> ice-base heat flux (W/m²).

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 but kept for call-site parity, ice_enthalpy_liquid).

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

Timestep (s).

logical, intent(in) :: do_snow_ice

Archimedes freeboard flood gate (&ocean_ice_nml snow_ice, PR 27) — .false. (the default) is a bit-identical no-op: snow_to_ice stays 0 and ice_snow_ice_flood is never called.

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

New snow mass this window (kg/m²), fprec*dtt — PR 26 source term, ice_snow_accumulate’s snow argument. 0 (the &ocean_ice_nml snowfall=0 default) is a bit-identical no-op.

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

Surface skin temperature (degC).

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

Mass flux frozen from the ocean onto the ice base (kg/m²).

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

Meltwater mass flux to the ocean (kg/m²), top + bottom peel.

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

Leftover melt heat dumped to the ocean (J/m²), top + bottom.

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

Shortwave transmitted through the ice to the ocean (W/m²).

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

Mass converted from snow to the top ice layer this call (kg/m²), >= 0 — SIS2 SN2IC (PR 27). 0 when do_snow_ice is .false. or the column is not flooded.

public pure subroutine ice_temp_sis2(nk, m_snow, m_ice_tot, sice, enthalpy, sf_0, dsf_dt, sol, tfw, fb, dtt, tsurf, tmelt, bmelt, col_enth_in, col_enth_out, sum_sol, tflux_sfc, tflux_bot)

SEB + vertical-conduction column solve — SIS2 ice_temp_SIS2 (SIS2_ice_thm.F90:169-540). Port of prototype sis2_column.py:151-412. TOP-DOWN column (index 0 = snow, 1..nk = ice top->bottom) — see module docstring TRAP #2.

Read more…

Arguments

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

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

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

Snow mass per unit area (kg/m²).

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

Total ice mass per unit area (kg/m²).

real(kind=wp), intent(in) :: sice(nk)

TOP-DOWN ice bulk salinities (PSU).

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

TOP-DOWN specific enthalpies (J/kg): 0 = snow, 1..nk = ice.

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

Linearized SEB intercept (W/m²), upward-positive: SF(T) = sf_0 + dsf_dt*T.

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

Linearized SEB slope (W/m²/K), upward-positive.

real(kind=wp), intent(in) :: sol(0:nk)

Absorbed solar per layer (W/m²), TOP-DOWN.

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

Seawater freezing temperature at the ice base (degC).

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

Ocean -> ice-base heat flux (W/m²); post-hoc residual only — TRAP #3.

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

Timestep (s).

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

Surface skin temperature (degC).

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

Accumulated top melting energy (J/m²); caller zeroes per step.

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

Accumulated bottom melting/freezing energy (J/m²); caller zeroes per step.

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

Column enthalpy Σ m_lay*enth BEFORE anything (diag).

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

Column enthalpy Σ m_lay*enth AFTER the conservative update, BEFORE the liq-lim clamp (diag).

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

Σ sol*dtt over the column (diag, J/m²).

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

Time-integrated surface heat flux into the column (diag, J/m²).

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

Time-integrated basal heat flux into the column (diag, J/m²).

public pure subroutine ice_thermo_columns(nghost, nx, ny, ncat, nk, dtt, do_snow_ice, wet_mask, m_ice, m_snow, enth_ice, enth_snow, sal_ice, sf_0, dsf_dt, sw_dn, fprec, tfw, fb, sst, s_surf, tsurf_out, h2o_ocn_to_ice, h2o_ice_to_ocn, heat_to_ocn, sw_thru, snow_to_ice)

do concurrent cell driver: PHYSICAL cells only, inner if gate (never a masked DC header), serial do cat loop inside. Per (i,j,cat): outputs zeroed unconditionally, then gated on wet_mask > 0.5 .and. m_ice > ICE_RHO_ICE*H_VANISHED (dynamic- vanish taxonomy: skip intact, never clamp/divide a vanished column). part_size is deliberately NOT an argument — thermo is per unit ice area.

Arguments

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

Grid + category + layer extents (declared first — decl-order).

integer, intent(in) :: nx

Grid + category + layer extents (declared first — decl-order).

integer, intent(in) :: ny

Grid + category + layer extents (declared first — decl-order).

integer, intent(in) :: ncat

Grid + category + layer extents (declared first — decl-order).

integer, intent(in) :: nk

Grid + category + layer extents (declared first — decl-order).

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

Timestep (s).

logical, intent(in) :: do_snow_ice

Archimedes freeboard flood gate (&ocean_ice_nml snow_ice, PR 27), captured by value into the DC loop (same treatment as dtt). .false. (the default) is a bit-identical no-op.

real(kind=wp), intent(in) :: wet_mask(nx,ny)

Ocean wet mask (>0.5 = wet).

real(kind=wp), intent(inout) :: m_ice(nx,ny,ncat)

Total ice mass per unit area per category (kg/m²).

real(kind=wp), intent(inout) :: m_snow(nx,ny,ncat)

Snow mass per unit area per category (kg/m²).

real(kind=wp), intent(inout) :: enth_ice(nx,ny,ncat,nk)

Ice specific enthalpy (J/kg), BOTTOM-UP (k=1 = ice bottom).

real(kind=wp), intent(inout) :: enth_snow(nx,ny,ncat,1)

Snow specific enthalpy (J/kg).

real(kind=wp), intent(inout) :: sal_ice(nx,ny,ncat,nk)

Ice bulk salinity (PSU), BOTTOM-UP.

real(kind=wp), intent(in) :: sf_0(nx,ny)

Linearized SEB intercept (W/m²), upward-positive.

real(kind=wp), intent(in) :: dsf_dt(nx,ny)

Linearized SEB slope (W/m²/K), upward-positive.

real(kind=wp), intent(in) :: sw_dn(nx,ny)

Downwelling shortwave at the surface (W/m²).

real(kind=wp), intent(in) :: fprec(nx,ny)

Frozen-precipitation rate onto the ice top (kg/m²/s), >= 0 — PR 26 snowfall seam (ice%atm_fprec). Passed to ice_column_step as fprec(i,j)*dtt; 0 (the &ocean_ice_nml snowfall=0 default) is a bit-identical no-op.

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

Seawater freezing temperature at the ice base (degC).

real(kind=wp), intent(in) :: fb(nx,ny)

Ocean -> ice-base heat flux (W/m²).

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

Sea-surface temperature (degC).

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

Sea-surface salinity (PSU).

real(kind=wp), intent(inout) :: tsurf_out(nx,ny,ncat)

Surface skin temperature (degC).

real(kind=wp), intent(inout) :: h2o_ocn_to_ice(nx,ny,ncat)

Mass flux frozen from the ocean onto the ice base (kg/m²).

real(kind=wp), intent(inout) :: h2o_ice_to_ocn(nx,ny,ncat)

Meltwater mass flux to the ocean (kg/m²).

real(kind=wp), intent(inout) :: heat_to_ocn(nx,ny,ncat)

Leftover melt heat dumped to the ocean (J/m²).

real(kind=wp), intent(inout) :: sw_thru(nx,ny,ncat)

Shortwave transmitted through the ice to the ocean (W/m²).

real(kind=wp), intent(inout) :: snow_to_ice(nx,ny,ncat)

Mass converted from snow to the top ice layer this call (kg/m²), >= 0 — SIS2 SN2IC (PR 27). Zeroed unconditionally every thermo step, same lifecycle as sw_thru.

public pure subroutine update_lay_enth(m_lay, sice, enth, ftop, ht_body, fbot, dftop_dt, dfbot_dt, dtt, hf_err_rat, extra_heat, new_temp, has_temp_max, temp_max)

Conservative per-layer implicit enthalpy update — SIS2 update_lay_enth (SIS2_ice_thm.F90:704-945), closed-form branches only. Port of prototype sis2_column.py:58-135. Four solution branches (massless layer; pin-to-max with banked extra_enth; fresh sice==0 linear; salty quadratic), then the three-way explicit-vs-conservation-inverted flux bookkeeping (prototype :117-133, incl. the denom > 0 guard).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: m_lay

Layer mass (kg/m²).

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

Layer bulk salinity (PSU); 0 for snow/fresh.

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

Layer specific enthalpy (J/kg); in = prior step, out = new.

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

Heat flux at the layer’s top interface (W/m²); in = prior estimate, out = updated (explicit or conservation-inverted).

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

In-layer heating (solar absorption) (W/m²).

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

Heat flux at the layer’s bottom interface (W/m²); in/out as ftop.

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

d(ftop)/d(new_temp) (W/m²/K).

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

d(fbot)/d(new_temp) (W/m²/K).

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

Timestep (s).

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

Precomputed heat_flux_err_rat (degC*s/J) deciding explicit vs conservation-inverted flux bookkeeping.

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

Banked excess heat when pinned to temp_max (J/m²).

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

Resulting layer temperature (degC).

logical, intent(in) :: has_temp_max

True when an explicit temp_max clamp applies (snow-branch call site); false uses the freezing point as the max.

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

Explicit temperature ceiling (degC), used only when has_temp_max.