Configure porous barriers (&ocean_porous_nml, Adcroft 2013).
Grows the ocean_metrics_t porous arrays to full face size and
fills the STATIC along-face d_min/d_max/d_avg statistics;
the layer-averaged open fractions themselves are recomputed on
the device every RK2 stage (they depend on the interface
heights).
MUST run AFTER bathymetry is set (ocean_state%barotropic%b)
and land masking, and BEFORE ocean_state_enter_data — the
realloc has to happen before the device map, and the host fill
is what the copyin captures. Leaves the placeholder-sized
arrays untouched when the knob is off (bit-identical).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(in) | :: | cfg | |||
| type(ocean_state_t), | intent(inout) | :: | ocean_state | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in) | :: | compute_rank | |||
| integer, | intent(out), | optional | :: | ierr |
Non-zero on a porous-barrier configuration conflict when
present; absent behaves as today ( |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | interp | ||||
| integer, | private | :: | nx | ||||
| integer, | private | :: | ny | ||||
| integer, | private | :: | nz | ||||
| integer, | private | :: | src |
subroutine configure_ocean_porous(cfg, ocean_state, grid, compute_rank, ierr) !! Configure porous barriers (`&ocean_porous_nml`, Adcroft 2013). !! Grows the `ocean_metrics_t` porous arrays to full face size and !! fills the STATIC along-face `d_min`/`d_max`/`d_avg` statistics; !! the layer-averaged open fractions themselves are recomputed on !! the device every RK2 stage (they depend on the interface !! heights). !! !! MUST run AFTER bathymetry is set (`ocean_state%barotropic%b`) !! and land masking, and BEFORE `ocean_state_enter_data` — the !! realloc has to happen before the device map, and the host fill !! is what the `copyin` captures. Leaves the placeholder-sized !! arrays untouched when the knob is off (bit-identical). type(config_t), intent(in) :: cfg type(ocean_state_t), intent(inout) :: ocean_state type(hgrid_t), intent(in) :: grid integer, intent(in) :: compute_rank integer, intent(out), optional :: ierr !! Non-zero on a porous-barrier configuration conflict when !! present; absent behaves as today (`error stop`). integer :: src, interp, nx, ny, nz if (.not. cfg%ocean%porous%enable) then if (present(ierr)) ierr = OCEAN_STATUS_OK return end if if (.not. ocean_state%multilayer%is_init) then call fail("&ocean_porous_nml enable requires the ocean multilayer "// & "path (the open fractions are per-layer)", ierr, OCEAN_STATUS_ERR_SETUP) return end if src = parse_porous_source(cfg%ocean%porous%source) select case (src) case (POROUS_SOURCE_RESOLVED) continue case (POROUS_SOURCE_FILE) call fail("&ocean_porous_nml source='file' (an offline "// & "subgrid-bathymetry file, MOM6 topog_edge.nc) is not "// & "implemented — it needs the file-forcing backend that "// & "&ocean_bt_nml wave_drag_form='file' also waits on. "// & "Use source='resolved' (a documented proxy).", ierr, OCEAN_STATUS_ERR_SETUP) return case default call fail("&ocean_porous_nml source='"// & trim(cfg%ocean%porous%source)//"' is not recognised", ierr, OCEAN_STATUS_ERR_SETUP) return end select interp = parse_porous_eta_interp(cfg%ocean%porous%eta_interp) if (interp < 0) then call fail("&ocean_porous_nml eta_interp='"// & trim(cfg%ocean%porous%eta_interp)//"' is not recognised", ierr, OCEAN_STATUS_ERR_SETUP) return end if nx = grid%nx_total ny = grid%ny_total nz = ocean_state%multilayer%nz_ml call metrics_porous_alloc(ocean_state%metrics, grid, nz) ocean_state%metrics%porous_eta_interp = interp ! The namelist knob is a DEPTH (positive below the surface); the ! kernel gate compares HEIGHTS, so flip the sign once here. ocean_state%metrics%porous_mask_depth = -cfg%ocean%porous%masking_depth ! SIGN CONVENTION. The Adcroft fit works in topographic HEIGHTS ! (positive up, negative below the sea surface) so that they compare ! directly against interface heights. On the ocean path ! `barotropic%b` holds the reference column DEPTH, positive down ! (`SSH = sum(h_layer) - b`), so it is negated once, here, and every ! porous array downstream is a height. Bathymetry is static, so a ! snapshot on the metrics slot is exact and lets the per-step ! recompute stay a metrics-only kernel. ocean_state%metrics%por_bed = -ocean_state%barotropic%b call porous_fill_stats_resolved(nx, ny, ocean_state%metrics%por_bed, & ocean_state%metrics%wet_T, & ocean_state%metrics%por_dmin_u, & ocean_state%metrics%por_dmax_u, & ocean_state%metrics%por_davg_u, & ocean_state%metrics%por_dmin_v, & ocean_state%metrics%por_dmax_v, & ocean_state%metrics%por_davg_v) ! READER-BOUNDARY ASSERTION. `m = (d_avg-d_min)/(d_max-d_min)` is ! only a valid Adcroft parameter when `d_min <= d_avg <= d_max`. ! The resolved fill cannot break that (d_avg is a convex combination ! of the samples d_min/d_max bracket), but a FILE-backed source ! could, so the check sits here — at the boundary every source ! passes through — rather than inside one filler. if (.not. porous_stats_are_ordered(nx + 1, ny, & ocean_state%metrics%por_dmin_u, & ocean_state%metrics%por_dmax_u, & ocean_state%metrics%por_davg_u)) then call fail("&ocean_porous_nml: u-face subgrid statistics violate "// & "d_min <= d_avg <= d_max", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (.not. porous_stats_are_ordered(nx, ny + 1, & ocean_state%metrics%por_dmin_v, & ocean_state%metrics%por_dmax_v, & ocean_state%metrics%por_davg_v)) then call fail("&ocean_porous_nml: v-face subgrid statistics violate "// & "d_min <= d_avg <= d_max", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! Flip the master switch LAST: every kernel branches on it, and the ! stats must be in place before any of them can read a narrowed width. ocean_state%metrics%use_porous = .true. if (compute_rank == 0) then call logger%info("Porous barriers: ON (Adcroft 2013), source='"// & trim(cfg%ocean%porous%source)//"' eta_interp='"// & trim(cfg%ocean%porous%eta_interp)//"' masking_depth="// & to_string(cfg%ocean%porous%masking_depth)//" m") call logger%info(" source='resolved' is an along-face "// & "statistic of the RESOLVED bathymetry, a documented "// & "proxy for true subgrid data") end if if (present(ierr)) ierr = OCEAN_STATUS_OK end subroutine configure_ocean_porous