Per-column two-band shortwave redistribution. Explicit-shape
dummies so NVHPC stdpar compiles device kernels against static
bounds. Difference form (I(d_top) - I(d_bot)) — no division
by h, so a vanishing layer (h → 0 ⇒ d_top == d_bot) absorbs
zero automatically with no guard. The transmission T(d) is
the shared sw_transmission (same-module ⇒ inlined by NVHPC),
so the deposition and the boundary-layer coupling cannot diverge.
inv_scale = dt/(rho0·cp); R/zeta1/zeta2 are the two-band
parameters; sw_pen_frac scales sw_src to the penetrating
irradiance I0. sw_src is the caller-selected source
(Q_heat for the legacy net-heat path, q_sw for the PR-12
component path); the additive-correction conservation identity
-I0 + Σ_k I0·(T_top - T_bot) = 0 holds for ANY sw_src, so the
source swap cannot break conservation. At k = nz the legacy
I0 lump is subtracted before adding the surface band, keeping
the net column change against the all-at-nz baseline at zero.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(inout) | :: | hTr(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | budget(nx,ny,nz) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| integer, | intent(in) | :: | k_bot(nx,ny) |
|
||
| real(kind=wp), | intent(in) | :: | wet_mask(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | sw_src(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | inv_scale | |||
| real(kind=wp), | intent(in) | :: | sw_pen_frac | |||
| real(kind=wp), | intent(in) | :: | R | |||
| real(kind=wp), | intent(in) | :: | zeta1 | |||
| real(kind=wp), | intent(in) | :: | zeta2 | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | absorbed | ||||
| real(kind=wp), | private | :: | add | ||||
| real(kind=wp), | private | :: | d_bot | ||||
| real(kind=wp), | private | :: | d_top | ||||
| integer, | private | :: | i | ||||
| real(kind=wp), | private | :: | i0col | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | k | ||||
| real(kind=wp), | private | :: | trans_bot | ||||
| real(kind=wp), | private | :: | trans_top |
pure subroutine apply_sw_penetration_impl(hTr, budget, h_layer, k_bot, wet_mask, & sw_src, inv_scale, sw_pen_frac, R, & zeta1, zeta2, nz, nx, ny) !! Per-column two-band shortwave redistribution. Explicit-shape !! dummies so NVHPC stdpar compiles device kernels against static !! bounds. Difference form (`I(d_top) - I(d_bot)`) — no division !! by `h`, so a vanishing layer (`h → 0 ⇒ d_top == d_bot`) absorbs !! zero automatically with no guard. The transmission `T(d)` is !! the shared `sw_transmission` (same-module ⇒ inlined by NVHPC), !! so the deposition and the boundary-layer coupling cannot diverge. !! !! `inv_scale` = dt/(rho0·cp); `R`/`zeta1`/`zeta2` are the two-band !! parameters; `sw_pen_frac` scales `sw_src` to the penetrating !! irradiance `I0`. `sw_src` is the caller-selected source !! (`Q_heat` for the legacy net-heat path, `q_sw` for the PR-12 !! component path); the additive-correction conservation identity !! `-I0 + Σ_k I0·(T_top - T_bot) = 0` holds for ANY `sw_src`, so the !! source swap cannot break conservation. At `k = nz` the legacy !! `I0` lump is subtracted before adding the surface band, keeping !! the net column change against the all-at-`nz` baseline at zero. integer, intent(in) :: nz, nx, ny real(wp), intent(inout) :: hTr(nx, ny, nz) real(wp), intent(inout) :: budget(nx, ny, nz) real(wp), intent(in) :: h_layer(nx, ny, nz) integer, intent(in) :: k_bot(nx, ny) !! `ms%k_bot` — the first LIVE layer counting up from the bed. The !! opaque-bed residual lands HERE, not on `k = 1`: under `z_fixed` !! the layers below are inert fillers (`1` elsewhere ⇒ unchanged). real(wp), intent(in) :: wet_mask(nx, ny) real(wp), intent(in) :: sw_src(nx, ny) real(wp), intent(in) :: inv_scale, sw_pen_frac, R, zeta1, zeta2 integer :: i, j, k real(wp) :: i0col, d_top, d_bot, trans_top, trans_bot, absorbed, add do concurrent(j=1:ny, i=1:nx) local(i0col, d_top, d_bot, trans_top, & trans_bot, absorbed, add, k) i0col = sw_pen_frac*sw_src(i, j)*wet_mask(i, j) d_top = 0.0_wp do k = nz, k_bot(i, j), -1 d_bot = d_top + h_layer(i, j, k) trans_top = sw_transmission(d_top, R, zeta1, zeta2) if (k > k_bot(i, j)) then trans_bot = sw_transmission(d_bot, R, zeta1, zeta2) else trans_bot = 0.0_wp ! bed opaque: column absorbs all of I0 end if absorbed = i0col*(trans_top - trans_bot) add = inv_scale*absorbed if (k == nz) add = add - inv_scale*i0col ! remove the surface lump hTr(i, j, k) = hTr(i, j, k) + add budget(i, j, k) = budget(i, j, k) + add d_top = d_bot end do end do end subroutine apply_sw_penetration_impl