Analogue of MOM6’s heat/salt diffusivity split. Derives the
per-tracer diffusivities from the assembled interior/boundary-
layer diffusivity:
Kd_heat = Kd_int + Kd_extra_T -> kt
Kd_salt = Kd_int + Kd_extra_S -> ks
kt holds Kd_int on entry (every contributor writes it). No
double-diffusion contributor exists yet, so Kd_extra_{T,S} = 0
and the split reduces to ks := kt => bit-identical. PR-33
extends this to
ks = kt + kd_extra_s ; kt = kt + kd_extra_t
BOTH computed from the SAME pre-split kt – read kt into a
local before writing it, or the kt update poisons the ks
update.
vmix_split_kd_heat_salt is not a contributor – it is the
last statement before vmix_assemble, always. Any PR adding
a kv/kt contributor inserts it ABOVE this split.
Runs over the full k = 1..nz+1 range (not 2..nz): kt’s
boundary interfaces are zeroed every stage by
vmix_compute_pp81, so an all-k copy reproduces ks’s
init-time boundary zeros exactly and keeps the closed-BC
invariant true by construction.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_vmix_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | nx | ||||
| integer, | private | :: | ny | ||||
| integer, | private | :: | nz |
pure subroutine vmix_split_kd_heat_salt(grid, this, ms) !! Analogue of MOM6's heat/salt diffusivity split. Derives the !! per-tracer diffusivities from the assembled interior/boundary- !! layer diffusivity: !! Kd_heat = Kd_int + Kd_extra_T -> kt !! Kd_salt = Kd_int + Kd_extra_S -> ks !! `kt` holds Kd_int on entry (every contributor writes it). No !! double-diffusion contributor exists yet, so Kd_extra_{T,S} = 0 !! and the split reduces to `ks := kt` => bit-identical. PR-33 !! extends this to !! ks = kt + kd_extra_s ; kt = kt + kd_extra_t !! BOTH computed from the SAME pre-split kt -- read kt into a !! local before writing it, or the kt update poisons the ks !! update. !! !! `vmix_split_kd_heat_salt` is not a contributor -- it is the !! last statement before `vmix_assemble`, always. Any PR adding !! a kv/kt contributor inserts it ABOVE this split. !! !! Runs over the full k = 1..nz+1 range (not 2..nz): `kt`'s !! boundary interfaces are zeroed every stage by !! `vmix_compute_pp81`, so an all-k copy reproduces `ks`'s !! init-time boundary zeros exactly and keeps the closed-BC !! invariant true by construction. type(hgrid_t), intent(in) :: grid type(ocean_vmix_t), intent(inout) :: this type(multilayer_state_t), intent(in) :: ms integer :: nx, ny, nz nx = grid%nx_total ny = grid%ny_total nz = ms%nz_ml if (this%ddiff_enable .and. this%buoyancy_coeffs == BUOY_COEFFS_EOS) then ! E4: same closure, but α/β come from the ACTIVE EOS at each ! interface's own (T, S, p) instead of the scalar pair. A ! SEPARATE impl, deliberately, not a branch inside the collapsed ! one: the in-situ pressure has to be accumulated DOWN a column, ! which forces `do concurrent(j, i)` + a serial k sweep, and the ! default path must keep its fully-collapsed (i, j, k) launch — ! both for its GPU parallelism and so its byte-identity is ! structural rather than argued. call vmix_split_ddiff_eos_impl(nx, ny, nz + 1, this%kt, this%ks, & ms%tracers(ms%idx_temperature)%hTr, & ms%tracers(ms%idx_salinity)%hTr, ms%h_layer, & ms%p_top, this%eos, this%rho0, & this%p_top_in_eos, & this%ddiff_strat_param_max, this%ddiff_kappa_s, & this%ddiff_exp1, this%ddiff_exp2, & this%ddiff_param1, this%ddiff_param2, & this%ddiff_param3, this%ddiff_mol_diff, & this%ddiff_use_k90) else if (this%ddiff_enable) then ! Outer shim: dereference the registry tracers (idx 1/2) on the ! host and hand the flat top-level arrays to the do-concurrent ! impl (array-of-derived-type device indirection rule). call vmix_split_ddiff_impl(nx, ny, nz + 1, this%kt, this%ks, & ms%tracers(ms%idx_temperature)%hTr, & ms%tracers(ms%idx_salinity)%hTr, ms%h_layer, & this%eos%alpha_T, this%eos%beta_S, & this%ddiff_strat_param_max, this%ddiff_kappa_s, & this%ddiff_exp1, this%ddiff_exp2, & this%ddiff_param1, this%ddiff_param2, & this%ddiff_param3, this%ddiff_mol_diff, & this%ddiff_use_k90) else call vmix_split_kd_heat_salt_impl(nx, ny, nz + 1, this%kt, this%ks) end if end subroutine vmix_split_kd_heat_salt