Copy the &ocean_ddiff_nml knobs onto ocean_state%vmix – every
field, no dead-config gaps. Like convection, double diffusion adds
no new slot (it rides the unconditionally-allocated vmix and the
already-mirrored vmix%eos); vmix%ddiff_enable IS the latch.
Folded into vmix_split_kd_heat_salt, so it needs the interior
closure pipeline (use_closure) and thermodynamics (it reads T/S
and the EOS alpha/beta). enable=.false. => bit-identical.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(in) | :: | cfg | |||
| type(ocean_state_t), | intent(inout) | :: | ocean_state | |||
| integer, | intent(in) | :: | compute_rank | |||
| integer, | intent(out), | optional | :: | ierr |
Non-zero on a double-diffusion configuration conflict when
present; absent behaves as today ( |
subroutine configure_ocean_ddiff(cfg, ocean_state, compute_rank, ierr) !! Copy the `&ocean_ddiff_nml` knobs onto `ocean_state%vmix` -- every !! field, no dead-config gaps. Like convection, double diffusion adds !! no new slot (it rides the unconditionally-allocated `vmix` and the !! already-mirrored `vmix%eos`); `vmix%ddiff_enable` IS the latch. !! Folded into `vmix_split_kd_heat_salt`, so it needs the interior !! closure pipeline (`use_closure`) and thermodynamics (it reads T/S !! and the EOS alpha/beta). `enable=.false.` => bit-identical. type(config_t), intent(in) :: cfg type(ocean_state_t), intent(inout) :: ocean_state integer, intent(in) :: compute_rank integer, intent(out), optional :: ierr !! Non-zero on a double-diffusion configuration conflict when !! present; absent behaves as today (`error stop`). associate (vmix => ocean_state%vmix, dcfg => cfg%ocean%ddiff) ! `ddiff_enable` is flipped LAST, only once every validation ! below has passed (P0.1 review F9 — `configure_ocean_porous` is ! the pattern): setting it up front left a half-configured slot ! flagged enabled on any of this routine's failure returns. if (.not. dcfg%enable) then vmix%ddiff_enable = .false. if (present(ierr)) ierr = OCEAN_STATUS_OK return end if vmix%ddiff_strat_param_max = dcfg%strat_param_max vmix%ddiff_kappa_s = dcfg%kappa_ddiff_s vmix%ddiff_exp1 = dcfg%ddiff_exp1 vmix%ddiff_exp2 = dcfg%ddiff_exp2 vmix%ddiff_param1 = dcfg%param1 vmix%ddiff_param2 = dcfg%param2 vmix%ddiff_param3 = dcfg%param3 vmix%ddiff_mol_diff = dcfg%mol_diff vmix%ddiff_use_k90 = dcfg%use_k90 ! Validation. if (.not. cfg%ocean%vmix%use_closure) then call fail("ocean_ddiff_nml: enable=.true. requires "// & "ocean_vmix_nml use_closure=.true. (double diffusion "// & "folds into the interior closure's heat/salt split)", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (.not. cfg%ocean%thermo%enable_thermodynamics) then call fail("ocean_ddiff_nml: enable=.true. requires "// & "active thermodynamics (double diffusion reads T/S "// & "and the EOS alpha/beta)", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (dcfg%strat_param_max <= 1.0_wp) then call fail("ocean_ddiff_nml: strat_param_max must be > 1 "// & "(the fingering form divides by strat_param_max - 1)", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (dcfg%kappa_ddiff_s < 0.0_wp .or. dcfg%mol_diff < 0.0_wp) then call fail("ocean_ddiff_nml: kappa_ddiff_s and mol_diff must be >= 0", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (compute_rank == 0) then call logger%info("Double diffusion: enabled (Rrho_max="// & to_string(dcfg%strat_param_max)//" K_f="// & to_string(dcfg%kappa_ddiff_s)//" m^2/s "// & "conv="//trim(merge("K90 ", "MC76", dcfg%use_k90))//")") end if vmix%ddiff_enable = .true. end associate if (present(ierr)) ierr = OCEAN_STATUS_OK end subroutine configure_ocean_ddiff