Per-variable diagnostic record. Owned by ocean_diag_t.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | accumulator(:,:,:) | |||
| real(kind=wp), | public | :: | dt_accum | = | 0.0_wp |
Wall time accumulated into this var’s window (s). |
|
| real(kind=wp), | public | :: | dt_out | = | 3600.0_wp |
Output cadence (s). Manager keeps a per-var counter and fires when the accumulated dt passes the threshold. |
|
| logical, | public | :: | enabled | = | .true. |
When |
|
| procedure(diag_fill_proc), | public, | pointer, nopass | :: | fill | => | null() | |
| integer, | public | :: | fire_count | = | 0 |
Number of times this var’s |
|
| logical, | public | :: | has_missing | = | .false. |
When |
|
| logical, | public | :: | is_extensive | = | .false. |
Phase B v1 status: the existing |
|
| real(kind=wp), | public, | allocatable | :: | layer_buffer(:,:,:) | |||
| character(len=128), | public | :: | long_name | = | "" |
CF-compliant long_name attribute. |
|
| type(diag_mask_t), | public, | allocatable | :: | mask |
Optional region mask. When allocated, |
||
| integer, | public | :: | n_accum | = | 0 |
Number of contributions in the current accumulator window. |
|
| character(len=64), | public | :: | name | = | "" |
Short netcdf variable name. |
|
| integer, | public | :: | nc_time_dimid | = | -1 | ||
| integer, | public | :: | nc_time_index | = | 0 |
Number of slices already written for this var (1-indexed position of the NEXT write). |
|
| integer, | public | :: | nc_time_varid | = | -1 | ||
| integer, | public | :: | nc_varid | = | -1 | ||
| integer, | public | :: | nc_z_dimid | = | -1 |
-1 for 2D vars; set for 3D vars when the stream is opened. |
|
| real(kind=wp), | public, | allocatable | :: | output_buffer(:,:,:) | |||
| integer, | public | :: | output_vgrid | = | DIAG_VGRID_LAYER | ||
| procedure(diag_remap_proc), | public, | pointer, nopass | :: | remap | => | null() |
Optional vertical-remap routine. Set at register time
when |
| integer, | public | :: | source_loc | = | DIAG_LOC_CENTER | ||
| integer, | public | :: | source_vgrid | = | DIAG_VGRID_LAYER | ||
| character(len=64), | public | :: | standard_name | = | "" | ||
| integer, | public | :: | stream_id | = | 0 |
ID of the output stream this var ships to (Phase 6 wires the I/O server stream table). |
|
| integer, | public | :: | time_op | = | DIAG_OP_MEAN | ||
| character(len=32), | public | :: | units | = | "" |
Counted allocatable footprint of ONE registered diagnostic (0 for every buffer that is unallocated).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(diag_var_t), | intent(in) | :: | this |
type :: diag_var_t !! Per-variable diagnostic record. Owned by ocean_diag_t. character(len=64) :: name = "" !! Short netcdf variable name. character(len=128) :: long_name = "" !! CF-compliant long_name attribute. character(len=32) :: units = "" character(len=64) :: standard_name = "" ! ---- Source binding ---- ! Procedure pointer to the per-var fill routine. Set at ! `register` time by the slot that owns the source data; the ! manager invokes it on cadence-fire to populate the buffer. ! `nopass` because the registry holds the bind, not the var. procedure(diag_fill_proc), pointer, nopass :: fill => null() procedure(diag_remap_proc), pointer, nopass :: remap => null() !! Optional vertical-remap routine. Set at register time !! when `output_vgrid /= DIAG_VGRID_LAYER`; null otherwise. integer :: source_loc = DIAG_LOC_CENTER integer :: source_vgrid = DIAG_VGRID_LAYER ! ---- Output binding ---- integer :: output_vgrid = DIAG_VGRID_LAYER integer :: time_op = DIAG_OP_MEAN real(wp) :: dt_out = 3600.0_wp !! Output cadence (s). Manager keeps a per-var counter and !! fires when the accumulated dt passes the threshold. ! ---- Buffers ---- ! `output_buffer` is the post-remap buffer that gets shipped ! to the I/O server. `layer_buffer` is the manager-owned ! native-grid scratch the `fill` routine writes into when a ! remap step is required; for `output_vgrid == LAYER` the ! fill writes directly to `output_buffer` and `layer_buffer` ! stays unallocated. `accumulator` is the running-sum buffer ! used when `time_op /= DIAG_OP_INSTANT`. real(wp), allocatable :: output_buffer(:, :, :) real(wp), allocatable :: layer_buffer(:, :, :) real(wp), allocatable :: accumulator(:, :, :) integer :: n_accum = 0 !! Number of contributions in the current accumulator window. real(wp) :: dt_accum = 0.0_wp !! Wall time accumulated into this var's window (s). ! ---- Region restriction ---- type(diag_mask_t), allocatable :: mask !! Optional region mask. When allocated, `fold_sample` !! multiplies each sample by `mask%weight(i, j)` before !! folding into the accumulator — cells outside the region !! contribute zero. Output buffer shape is unchanged (full !! domain with zeros outside the mask); scalar-aggregating !! reductions land with the Phase D budget plumbing or as !! a Phase C v2 follow-on. ! ---- Vertical quantity kind ---- logical :: is_extensive = .false. !! `.false.` (default): field is INTENSIVE — per-unit-thickness !! quantity like temperature, salinity, velocity, density. !! When remapped to a non-LAYER vgrid, the column value is !! weight-averaged across overlapping source layers. !! !! `.true.`: field is EXTENSIVE — already thickness-integrated, !! e.g. `hTr` (tracer · m), KE per layer (h · 0.5 · |u|²), !! transport per layer (h · u). When remapped, the column !! values must be conservatively REDISTRIBUTED across the !! target layers (sum preserved), not averaged. !! !! Phase B v1 status: the existing `remap_layer_to_z` is !! intensive-only. Extensive remap (and the corresponding !! split inside `diag_remap_proc`) lands with isopycnal / !! density-bin remap in Phase E. Flag is here now so calling !! code can declare intent and the upgrade is non-breaking. ! ---- Enable gate ---- logical :: enabled = .true. !! When `.false.` the dispatcher skips this var entirely — no !! `fill_*` kernel, no accumulator fold, no emit — so an !! unrequested diagnostic costs zero GPU work. Lets a run turn !! off individual default diagnostics it does not want. Default !! `.true.` ⇒ every registered var runs (bit-identical). ! ---- Vanished-target masking ---- logical :: has_missing = .false. !! When `.true.` the remap fills target cells that overlap no water !! (below-bottom / pinched-out in a shallow column) with !! `DIAG_MISSING_VALUE` instead of 0, and the NetCDF writer tags the !! variable with a `_FillValue` / `missing_value` attribute. Set at !! register time for non-LAYER diagnostics when masking is enabled !! (`&ocean_diag_nml mask_vanished_layers`). Default `.false.` => !! below-bottom cells read 0 (bit-identical to the legacy writer). ! ---- I/O server binding ---- integer :: stream_id = 0 !! ID of the output stream this var ships to (Phase 6 wires !! the I/O server stream table). ! ---- Per-var NetCDF state ---- ! Populated by `rdb_ocean_diag_netcdf` when the stream is ! opened; consumed by the NetCDF emit hook on each fire. integer :: nc_varid = -1 integer :: nc_time_dimid = -1 integer :: nc_time_varid = -1 integer :: nc_z_dimid = -1 !! -1 for 2D vars; set for 3D vars when the stream is opened. integer :: nc_time_index = 0 !! Number of slices already written for this var (1-indexed !! position of the NEXT write). ! ---- In-memory access generation (P7) ---- integer :: fire_count = 0 !! Number of times this var's `output_buffer` has been !! refreshed (filled/folded/finalised + pulled host-ward) since !! registration. Incremented unconditionally in `ocean_diag_step` !! at the SAME point as the per-fire `update self` — independent !! of whether a NetCDF stream is open (`nc_time_index` stays 0 !! with diagnostics disabled or output suppressed, so it cannot !! serve this role). This is the `generation` the C ABI's !! `rdb_ocean_get_diagnostic_ptr` returns: a Python `Field` !! re-checks it on access and knows `output_buffer` is already !! host-current the instant it changes (no separate refresh call !! needed — the pull above already happened synchronously). contains procedure, non_overridable :: bytes => diag_var_bytes end type diag_var_t