One cavity basal-melt update: sample the far field, solve the three-equation interface on every covered column, deliver the two owned surface-flux components, and account for the solver status.
CADENCE + PLACEMENT. Called once per outer step at THERMO
cadence from engine_step_finalize, immediately BEFORE
ocean_surface_flux_assemble — the assembler must see the
components this routine writes. The tracers then integrate the
assembled Q_heat/Q_salt on the NEXT outer step, which is the
same one-step lag the sea-ice coupler documents.
NON-pure, and it is the only non-pure procedure this module
adds: it logs (n_not_converged warnings) and it FAILS LOUD on
a non-finite column. Its three kernels are all pure.
mem:separate: every array read or written here is mapped by
its owning slot’s enter_data. ms%tracers(idx)%hTr is
dereferenced on the HOST before the kernels (the outer-shim
rule for the array-of-derived-types registry).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid |
Horizontal grid (for |
||
| type(ocean_cavity_flux_t), | intent(inout) | :: | cav |
The cavity-melt slot. |
||
| type(ocean_metrics_t), | intent(in) | :: | metrics |
Reads |
||
| type(multilayer_state_t), | intent(in) | :: | ms |
Reads |
||
| type(eos_t), | intent(in) | :: | eos |
Shared EOS handle — the liquidus. Flat POD, by value. |
||
| type(ocean_surface_flux_t), | intent(inout) | :: | sf |
Writes |
||
| logical, | intent(in), | optional | :: | active |
Thermo-cadence gate. Present-and-false ⇒ early return;
absent ⇒ run (the |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | idx_s | ||||
| integer, | private | :: | idx_t | ||||
| integer, | private | :: | nx | ||||
| integer, | private | :: | ny | ||||
| integer, | private | :: | nz |
subroutine ocean_cavity_flux_step(grid, cav, metrics, ms, eos, sf, active) !! One cavity basal-melt update: sample the far field, solve the !! three-equation interface on every covered column, deliver the !! two owned surface-flux components, and account for the solver !! status. !! !! CADENCE + PLACEMENT. Called once per outer step at THERMO !! cadence from `engine_step_finalize`, immediately BEFORE !! `ocean_surface_flux_assemble` — the assembler must see the !! components this routine writes. The tracers then integrate the !! assembled `Q_heat`/`Q_salt` on the NEXT outer step, which is the !! same one-step lag the sea-ice coupler documents. !! !! NON-`pure`, and it is the only non-pure procedure this module !! adds: it logs (`n_not_converged` warnings) and it FAILS LOUD on !! a non-finite column. Its three kernels are all `pure`. !! !! `mem:separate`: every array read or written here is mapped by !! its owning slot's `enter_data`. `ms%tracers(idx)%hTr` is !! dereferenced on the HOST before the kernels (the outer-shim !! rule for the array-of-derived-types registry). use pic_logger, only: global_logger use pic_strings, only: to_string use rdb_error_ring, only: fail use rdb_ocean_status, only: OCEAN_STATUS_ERR_SETUP type(hgrid_t), intent(in) :: grid !! Horizontal grid (for `nx_total`/`ny_total`). type(ocean_cavity_flux_t), intent(inout) :: cav !! The cavity-melt slot. type(ocean_metrics_t), intent(in) :: metrics !! Reads `cover_frac` only. type(multilayer_state_t), intent(in) :: ms !! Reads `h_layer`, the S/T tracer loads, the face velocities, !! `p_top` (THE interface pressure) and `wet_mask`. type(eos_t), intent(in) :: eos !! Shared EOS handle — the liquidus. Flat POD, by value. type(ocean_surface_flux_t), intent(inout) :: sf !! Writes `heat_cavity`/`salt_cavity` and latches !! `has_heat`/`has_salt` host-side. logical, intent(in), optional :: active !! Thermo-cadence gate. Present-and-false ⇒ early return; !! absent ⇒ run (the `ocean_surface_flux_assemble` convention). integer :: nx, ny, nz, idx_t, idx_s if (.not. cav%is_init) return if (.not. cav%enable) return if (present(active)) then if (.not. active) return end if if (.not. allocated(ms%tracers)) return idx_t = ms%idx_temperature idx_s = ms%idx_salinity if (idx_t <= 0 .or. idx_s <= 0) return nx = grid%nx_total ny = grid%ny_total nz = ms%nz_ml call cavity_far_field_impl(nx, ny, nz, cav%far_field_depth, & metrics%cover_frac, ms%wet_mask, ms%h_layer, & ms%tracers(idx_t)%hTr, ms%tracers(idx_s)%hTr, & ms%u_face_x_layer, ms%v_face_y_layer, & cav%active, cav%t_far, cav%s_far, cav%u_far, cav%v_far) call cavity_melt_columns_2d(nx, ny, cav%active, cav%t_far, cav%s_far, ms%p_top, & cav%u_far, cav%v_far, cav%s_ice, cav%f_cor, & cav%cdrag_top, cav%u_tide, cav%ustar_min, & cav%par, cav%ice, eos, cav%const, & cav%ustar, cav%t_b, cav%s_b, cav%melt, cav%q_ocean, & cav%gamma_t, cav%gamma_s, cav%status) call cavity_flux_fill_impl(nx, ny, cav%s_ice, cav%active, cav%melt, cav%q_ocean, & cav%s_far, sf%heat_cavity, sf%salt_cavity) ! The filler's own obligations (PR-12 fill contract): latch the ! has_* flags HOST-side, never from a device reduction. They stay ! latched for the rest of the run — the melt rate can legitimately ! pass through zero, and un-latching there would change the ! apply-path operand count mid-run. sf%has_heat = .true. sf%has_salt = .true. call cavity_status_counts_impl(nx, ny, cav%active, cav%status, & cav%n_nonfinite_step, cav%n_not_converged_step, & cav%n_no_root_step, cav%n_other_step) cav%n_not_converged_total = cav%n_not_converged_total & + int(cav%n_not_converged_step, int64) cav%n_no_root_total = cav%n_no_root_total + int(cav%n_no_root_step, int64) cav%n_other_total = cav%n_other_total + int(cav%n_other_step, int64) if (cavity_melt_status_is_fatal(cav%n_nonfinite_step)) then call fail("&ocean_cavity_melt_nml: "//to_string(cav%n_nonfinite_step)// & " ice-covered column(s) fed the basal-melt solver a non-finite "// & "far-field temperature, salinity, velocity or interface pressure "// & "(CAVITY_MELT_NONFINITE_*). The kernel's safe state is zero melt, "// & "which would hide an already-corrupt column behind a plausible "// & "run, so this is fatal. NOT_CONVERGED / NO_PHYSICAL_ROOT are "// & "counted and warned instead.", code=OCEAN_STATUS_ERR_SETUP) end if if (cav%n_not_converged_step > 0 .or. cav%n_no_root_step > 0 .or. & cav%n_other_step > 0) then call global_logger%warning("cavity melt: zero melt applied on "// & to_string(cav%n_not_converged_step)// & " non-converged, "//to_string(cav%n_no_root_step)// & " no-physical-root and "// & to_string(cav%n_other_step)// & " otherwise-refused column(s) this step") end if end subroutine ocean_cavity_flux_step