3.1. Code organization
This page describes how the mediator code is laid out and introduces the internal state — the data structure at the heart of the mediator. It builds on the high-level grouping in Coupling architecture at a glance; read that first if you have not. As noted in the Developer Guide introduction, this page assumes familiarity with ESMF and the NUOPC Layer.
3.1.1. The mediator/ directory
All of the shared mediator code lives in mediator/. It falls into three
groups (described in the architecture overview):
Generic infrastructure — the reusable machinery:
the mediator component (
med.F90)the internal state (
med_internalstate_mod.F90)mapping (
med_map_mod.F90)merging (
med_merge_mod.F90)fractions (
med_fraction_mod.F90)I/O (
med_io_mod.F90)history output (
med_phases_history_mod.F90)restarts (
med_phases_restart_mod.F90)time management (
med_time_mod.F90)methods and helpers (
med_methods_mod.F90)shared utilities (
med_utils_mod.F90)constants (
med_constants_mod.F90)kind definitions (
med_kind_mod.F90)
Application-specific exchange code — decides which fields are exchanged and how they are mapped and merged:
the per-host exchange modules (
esmFldsExchange_<host>_mod.F90)shared exchange definitions (
esmFlds.F90)the per-host field dictionaries (
fd_<host>.yaml)
Phase code — the per-component and cross-cutting work run each coupling step:
per-component prep phases (
med_phases_prep_<comp>_mod.F90)per-component post phases (
med_phases_post_<comp>_mod.F90)the atmosphere/ocean flux interface (
med_phases_aofluxes_mod.F90)the ocean albedo phase (
med_phases_ocnalb_mod.F90)the diagnostics phase (
med_diag_mod.F90)the timing/profiling phase (
med_phases_profile_mod.F90)
The host-specific driver (under cesm/) and the UFS-specific flux code (under
ufs/) live outside mediator/ and are not part of the shared mediator; see
Core concepts for the driver/mediator distinction.
3.1.2. The mediator component
med.F90 is the mediator’s NUOPC component — a NUOPC_Mediator (its
SetServices specializes the generic NUOPC_Mediator). It registers the
initialization and run phases with NUOPC (the phases the run sequence names),
and it owns the mediator’s internal state. The registration and the
initialization sequence are covered on the phase-lifecycle page (next); this
page focuses on the data the phases operate on.
3.1.3. The internal state
The mediator’s working data is held in a single internal state derived type
(defined in med_internalstate_mod.F90 and carried on the component as
is_local%wrap). Understanding its field bundles is the key to reading almost
any phase.
For a run with ncomps components, the central members are:
- Per-component states
NStateImp(n)— the ESMF import state from componentn.NStateExp(n)— the ESMF export state to componentn.
- The import/export field bundles
FBImp(n,k)— a matrix of field bundles: the fields imported from componentn, interpolated to the grid of componentk. The diagonalFBImp(n,n)points into componentn’s fields on its own grid (the fields inNStateImp(n)); the off-diagonalFBImp(n,k)holds those fields after mapping onto gridk. This matrix is what lets aprepphase pull any source component’s fields already on the destination grid.FBExp(n)— the field bundle of fields to be exported to componentn, on componentn’s grid; its fields point intoNStateExp(n), the export state the connector sends to componentn.
- Mediator-computed field bundles
FBMed_aoflux_a/FBMed_aoflux_o— the atmosphere/ocean flux outputs on the atmosphere and ocean grids.FBMed_ocnalb_a/FBMed_ocnalb_o— the ocean albedos on the atmosphere and ocean grids.
- Fractions and areas
FBfrac(n)— the surface fractions for componentnon its grid.FBArea(n)— component areas (used by the mediator history writes).
- Mapping
RH(:,:,:)— the routehandles for each pair of components and each mapping type (conservative, bilinear, and so on). These are created once during initialization and reused every coupling step.
- Accumulators
FBExpAccumOcn/FBExpAccumWav(with their countersExpAccumOcnCnt/ExpAccumWavCnt) — accumulators used to average an export over several fast coupling intervals before it is sent to a component coupled less frequently (the accumulate-then-average pattern seen in the run sequence for the ocean).
3.1.3.1. The coupling matrix
Which components exchange fields — and therefore which off-diagonal
FBImp(n,k) entries are populated and which prep / post work runs — is
captured by a coupling matrix that the mediator prints at start-up. Rows are
the source (from) component and columns are the destination (to)
component; a T marks an active coupling from the row component to the column
component.
CMEPS prints two versions, which mirror the advertise/realize superset-vs-intersection idea.
The allowed coupling matrix is every coupling CMEPS supports (the superset):
from to -> med atm lnd ocn ice rof wav glc1 glc2
med - - - - - - - - -
atm - - T T T - T - -
lnd - T - - - T - T T
ocn - T - - T - T T T
ice - T - T - - T - -
rof - - T T T - - - -
wav - T - T T - - - -
glc1 - - T - T T - - -
glc2 - - T - T T - - -
The active coupling matrix is the subset actually turned on for a given configuration — mirroring how NUOPC realizes only the connected fields. Two examples follow.
A fully coupled system without an active wave component (its row and column drop out):
from to -> med atm lnd ocn ice rof wav glc1 glc2
med - - - - - - - - -
atm - - T T T - - - -
lnd - T - - - T - T T
ocn - T - - T - - T T
ice - T - T - - - - -
rof - - T T T - - - -
wav - - - - - - - - -
glc1 - - T - T T - - -
glc2 - - T - T T - - -
A configuration with active CAM, CLM and CICE (atm, lnd, ice) and data ocean (DOCN) and land-ice (DGLC):
from to -> med atm lnd ocn ice rof wav glc1 glc2
med - - - - - - - - -
atm - - T - T - - - -
lnd - T - - - T - T T
ocn - T - - T - - - -
ice - T - - - - - - -
rof - - T - T - - - -
wav - - - - - - - - -
glc1 - - T - T T - - -
glc2 - - T - T T - - -
Notice how the data components change the picture. Nothing needs to force
the data ocean, so atm -> ocn, ice -> ocn and rof -> ocn all go
inactive — but DOCN still provides its prescribed state to the atmosphere and
ice (ocn -> atm, ocn -> ice stay active). A data component is coupled
where it is a source, and decoupled where it would be a destination of
fields it does not consume.
Reading the matrix ties directly back to the internal state. Each active
coupling is stored as one off-diagonal FBImp entry:
an active coupling atm -> ocn (a "T" in the matrix above)
is stored as FBImp(atm, ocn) = atm fields on the ocn grid
and it ties back to the phases. For each active coupling X -> Y:
post_XmapsX’s fields ontoY’s grid (fillingFBImp(X,Y)), andprep_Ymerges those mapped fields — with the other active sources intoY— intoFBExp(Y).
So a row shows everything a component feeds (its post targets), and a
column shows everything that feeds a component (its prep sources).