ice_itd_category_bounds Subroutine

public pure subroutine ice_itd_category_bounds(ncat, h_lim, mh_lim, hlim_vals)

SIS2 initialize_ice_categories (SIS_state_initialization.F90:45-78): absent hlim_vals fills the first min(ncat+1, 8) entries from the default lower-thickness-limit table HLIM_DFLT_TABLE; a supplied hlim_vals fills the first min(ncat+1, size(hlim_vals)) entries from IT instead (PR-58 — the SIS2 hLim_vals optional dummy Roundabout’s port originally declined to carry). Either way, the remainder extrapolates by constant width, h_lim(k) = 2*h_lim(k-1) - h_lim(k-2), resuming at ONE PAST however many entries were actually supplied — not at a fixed index 9. mh_lim = ICE_RHO_ICE*h_lim (SIS2 mH_cat_bound, SIS_state_initialization.F90:75-77). h_lim(c)/mh_lim(c) is the LOWER bound of category c (1-based); index ncat+1 is the lower bound that WOULD start category ncat+1 — stored (SIS2 keeps it) but never used as an upper cap on category ncat (ice_adjust_categories’s upward pass stops at c = ncat-1). No fixed-size local arrays — ncat is unbounded here (unlike the per-column ICE_NK_MAX-capped layer arrays).

Thickness-distribution discretization: Thorndike, Rothrock, Maykut & Colony (1975), JGR 80, 4501-4513; Bitz, Holland, Weaver & Eby (2001), JGR 106, 2441-2463.

Documented divergences from SIS2’s initialize_ice_categories (PR-58 plan §4): D1 — SIS2 silently falls back to the default table for a 1-element hlim_vals (size(hLim_vals) > 1 gate, :60). Roundabout’s caller (rdb_config%validate_config) FAILS LOUD instead via ice_hlim_spec_is_valid (house rule: a wordless no-op is worse than an error). This routine itself has no opinion — the size floor is enforced by the caller, not here. D2 — SIS2’s namelist CALLER truncates to CatIce entries (ice_model.F90:2110), so its top edge can never be stated via the namelist. This routine (and Roundabout’s &ocean_ice_nml hlim) accept the procedure’s own native range, 2..ncat+1.

Arguments

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

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

real(kind=wp), intent(out) :: h_lim(ncat+1)

Category lower thickness limits (m), h_lim(1:ncat+1).

real(kind=wp), intent(out) :: mh_lim(ncat+1)

Category lower mass limits (kg/m²), = ICE_RHO_ICE*h_lim.

real(kind=wp), intent(in), optional :: hlim_vals(:)

entries, strictly increasing, hlim_vals(1) > 0 — SIS2 initialize_ice_categories’s hLim_vals (SIS_state_initialization.F90:50). Assumed-shape is correct here: this is a host-side, once-per-run init routine with no do concurrent, not a per-step kernel. Absent => the pre-PR-58 behaviour, bit-for-bit (the default-table branch below is unmodified). Validated by the caller (ice_hlim_spec_is_valid) before it ever reaches here — this routine trusts its shape.


Called by

proc~~ice_itd_category_bounds~~CalledByGraph proc~ice_itd_category_bounds ice_itd_category_bounds proc~ocean_sea_ice_init ocean_sea_ice_t%ocean_sea_ice_init proc~ocean_sea_ice_init->proc~ice_itd_category_bounds

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private, parameter :: HLIM_DFLT_TABLE(N_HLIM_DFLT) = [1.0e-10_wp, 0.1_wp, 0.3_wp, 0.7_wp, 1.1_wp, 1.5_wp, 2.0_wp, 2.5_wp]
integer, private, parameter :: N_HLIM_DFLT = 8

Number of entries in the SIS2 default table (declared before the array that uses it — decl-order).

integer, private :: k

n_given: how many entries were actually filled from the source (table OR hlim_vals) before extrapolation takes over. Renamed from the pre-PR-58 n_dflt (PR-58 plan §11.1) because after this change it no longer means “how many came from the table” — it means “how many came from wherever we got them”, and the extrapolation loop below is only correct if it resumes at n_given + 1 regardless of source.

integer, private :: n_given

n_given: how many entries were actually filled from the source (table OR hlim_vals) before extrapolation takes over. Renamed from the pre-PR-58 n_dflt (PR-58 plan §11.1) because after this change it no longer means “how many came from the table” — it means “how many came from wherever we got them”, and the extrapolation loop below is only correct if it resumes at n_given + 1 regardless of source.


Source Code

   pure subroutine ice_itd_category_bounds(ncat, h_lim, mh_lim, hlim_vals)
      !! SIS2 `initialize_ice_categories`
      !! (`SIS_state_initialization.F90:45-78`): absent `hlim_vals` fills
      !! the first `min(ncat+1, 8)` entries from the default
      !! lower-thickness-limit table `HLIM_DFLT_TABLE`; a supplied
      !! `hlim_vals` fills the first `min(ncat+1, size(hlim_vals))`
      !! entries from IT instead (PR-58 — the SIS2 `hLim_vals` optional
      !! dummy Roundabout's port originally declined to carry). Either way,
      !! the remainder extrapolates by constant width,
      !! `h_lim(k) = 2*h_lim(k-1) - h_lim(k-2)`, resuming at ONE PAST
      !! however many entries were actually supplied — not at a fixed
      !! index 9. `mh_lim = ICE_RHO_ICE*h_lim` (SIS2 `mH_cat_bound`,
      !! `SIS_state_initialization.F90:75-77`). `h_lim(c)`/`mh_lim(c)` is
      !! the LOWER bound of category `c` (1-based); index `ncat+1` is the
      !! lower bound that WOULD start category `ncat+1` — stored (SIS2
      !! keeps it) but never used as an upper cap on category `ncat`
      !! (`ice_adjust_categories`'s upward pass stops at `c = ncat-1`).
      !! No fixed-size local arrays — `ncat` is unbounded here (unlike
      !! the per-column `ICE_NK_MAX`-capped layer arrays).
      !!
      !! Thickness-distribution discretization: Thorndike, Rothrock,
      !! Maykut & Colony (1975), JGR 80, 4501-4513; Bitz, Holland, Weaver
      !! & Eby (2001), JGR 106, 2441-2463.
      !!
      !! Documented divergences from SIS2's `initialize_ice_categories`
      !! (PR-58 plan §4):
      !!   D1 — SIS2 silently falls back to the default table for a
      !!        1-element `hlim_vals` (`size(hLim_vals) > 1` gate,
      !!        `:60`). Roundabout's caller (`rdb_config%validate_config`)
      !!        FAILS LOUD instead via `ice_hlim_spec_is_valid` (house
      !!        rule: a wordless no-op is worse than an error). This
      !!        routine itself has no opinion — the size floor is
      !!        enforced by the caller, not here.
      !!   D2 — SIS2's namelist CALLER truncates to `CatIce` entries
      !!        (`ice_model.F90:2110`), so its top edge can never be
      !!        stated via the namelist. This routine (and Roundabout's
      !!        `&ocean_ice_nml hlim`) accept the procedure's own native
      !!        range, `2..ncat+1`.
      integer, intent(in) :: ncat
         !! Number of ice thickness categories (declared first —
         !! decl-order).
      real(wp), intent(out) :: h_lim(ncat + 1)
         !! Category lower thickness limits (m), `h_lim(1:ncat+1)`.
      real(wp), intent(out) :: mh_lim(ncat + 1)
         !! Category lower mass limits (kg/m²), `= ICE_RHO_ICE*h_lim`.
      real(wp), intent(in), optional :: hlim_vals(:)
         !! PR-58: optional user-supplied lower edges (m), `2..ncat+1`
         !! entries, strictly increasing, `hlim_vals(1) > 0` — SIS2
         !! `initialize_ice_categories`'s `hLim_vals`
         !! (`SIS_state_initialization.F90:50`). Assumed-shape is correct
         !! here: this is a host-side, once-per-run `init` routine with
         !! no `do concurrent`, not a per-step kernel. Absent => the
         !! pre-PR-58 behaviour, bit-for-bit (the default-table branch
         !! below is unmodified). Validated by the caller
         !! (`ice_hlim_spec_is_valid`) before it ever reaches here — this
         !! routine trusts its shape.

      integer, parameter :: N_HLIM_DFLT = 8
         !! Number of entries in the SIS2 default table (declared before
         !! the array that uses it — decl-order).
      real(wp), parameter :: HLIM_DFLT_TABLE(N_HLIM_DFLT) = &
                             [1.0e-10_wp, 0.1_wp, 0.3_wp, 0.7_wp, 1.1_wp, 1.5_wp, 2.0_wp, 2.5_wp]
      integer :: n_given, k
         !! `n_given`: how many entries were actually filled from the
         !! source (table OR `hlim_vals`) before extrapolation takes
         !! over. Renamed from the pre-PR-58 `n_dflt` (PR-58 plan §11.1)
         !! because after this change it no longer means "how many came
         !! from the table" — it means "how many came from wherever we
         !! got them", and the extrapolation loop below is only correct
         !! if it resumes at `n_given + 1` regardless of source.

      if (present(hlim_vals)) then
         n_given = min(ncat + 1, size(hlim_vals))
         do k = 1, n_given
            h_lim(k) = hlim_vals(k)
         end do
      else
         n_given = min(ncat + 1, N_HLIM_DFLT)
         do k = 1, n_given
            h_lim(k) = HLIM_DFLT_TABLE(k)
         end do
      end if
      do k = n_given + 1, ncat + 1
         h_lim(k) = 2.0_wp*h_lim(k - 1) - h_lim(k - 2)
      end do
      do k = 1, ncat + 1
         mh_lim(k) = ICE_RHO_ICE*h_lim(k)
      end do
   end subroutine ice_itd_category_bounds