Skip to content

GEOS native cubed-sphere ​

The GEOS path takes GEOS-IT C180 native NetCDF — the FV3 dynamical core's own cubed-sphere output — and writes a transport binary on the same cubed-sphere grid (no horizontal regrid). GEOS-FP native C720 hourly CTM files use the same source contract, with tavg and inst files per UTC hour. It preserves native FV3 horizontal mass fluxes, balances them against raw next-hour dry-air endpoints, and diagnoses the vertical mass flux required by that discrete continuity target.

GEOS-FP C720 support covers the native hourly CTM layout (GEOS.fp.asm.tavg_1hr_ctm_c0720_v72.YYYYMMDD_HH30.V01.nc4, with legacy HH00 also supported, plus GEOS.fp.asm.inst_1hr_ctm_c0720_v72.YYYYMMDD_HH00.V01.nc4). Both collections are required: tavg has no QV and its mean PS cannot supply endpoint pressure. Surface/convection physics from the 0.25° GEOS-FP products can be attached by setting [source] physics_dir, include_surface = true, and include_convection = true; the day handle validates and embeds those payloads into the same transport binary.

GEOS-FP physics order and interpolation (OF-119) ​

The latlon_025 fallback uses the GEOS-Chem-processed GEOSFP.YYYYMMDD.{A1,A3mstE,A3dyn,I3}.025x03125.nc archive (0.25° latitude by 0.3125° longitude). Its physics level order is validated independently of native CTM order. Dimensionless lev = 1:N does not identify physical order: when physical level metadata is absent, provide the matching GEOSFP.YYYYMMDD.I3.025x03125.nc file. The reader compares global mean QV at the two I3 endpoints and requires a greater than 100-fold contrast; the moist end is the surface. Coordinates are resolved from each field's actual vertical dimension: CMFMC may use ilev while DTRAIN and QV use lev, even when both axes exist in the same file. I3 and A3dyn level coordinates must agree and CMFMC must have one extra edge in the same archive index convention.

Files with physical lev coordinates can instead specify positive = "up" or "down" (pressure units imply "down"). Both A3 collections must agree; I3 evidence, when present, must also agree. The cubed_sphere fallback uses the same validation, with GEOSFP.YYYYMMDD.I3.C<Nc>.nc or physical level metadata. Missing, ambiguous, or conflicting evidence errors at day opening. The CTM level_orientation setting applies only to native CTM fields. The geosfp_025 physics download defaults include A1, A3mstE, A3dyn, and I3 so standard dimensionless archives can be opened directly.

GEOS-Chem physics is normally surface-first while native FP CTM is top-down. Before interpolation or drying, surface-first CMFMC reverses its 73 edges (k → 74-k) and DTRAIN its 72 layers (k → 73-k). The normalized physics then uses the corresponding top-down native humidity: endpoint mean QV for DTRAIN, adjacent-layer and endpoint mean QV for CMFMC, with the single adjacent layer at the top and surface. Windows 1–3 use A3 record 1, windows 4–6 record 2, and so on.

Horizontal interpolation brackets actual sorted coordinates. Latitude clamps to the endpoint rows, retaining the 0.1875° polar intervals; longitude wraps periodically through the last/first coordinate pair. Coordinate and field permutations match for descending latitude and alternate longitude origins. Stencils are cached once per day and reused for all surface fields and levels.

Regenerate affected binaries from source. Before OF-119, fallback convection inherited CTM order, putting lower-atmosphere fluxes into thin top layers, and latitude interpolation used the first polar spacing everywhere, displacing all fallback physics fields. Both config/preprocessing/geosfp_c720_native_to_cs720.toml and config/preprocessing/geosfp_c720_native_to_cs180.toml with latlon_025 and enabled surface/convection are affected. C180 coarsening inherits both defects. This includes CMFMC, DTRAIN, PBLH, USTAR, HFLUX, and T2M. Reversing a dry binary cannot fix the original humidity pairing or the geographic displacement.

How the native fluxes are balanced ​

The native MFXC and MFYC fields provide the starting horizontal mass-flux amounts. After conversion to the transport grid, mass basis and time schedule, they must close against the selected next-hour dry-air endpoint.

The current path uses balance_cs_column_mass_fluxes!: it integrates each column vertically, applies a global cubed-sphere Poisson correction to those column totals, and distributes the face corrections back over levels using local air-mass weights in hybrid layers (hybrid_mass, the default; a layer is hybrid when ΔB_k ≥ 10⁻⁶, so the 150–177 hPa layer 41 of GEOS L72, ΔB = 8.2 × 10⁻⁹, counts as pure pressure). Pure-pressure layers therefore receive no correction. The pressure_fixer and pfix_corrected closures keep the native fluxes; the weights do not apply to them. This avoids an independent correction at every level while retaining the column budget needed for closed top and bottom boundaries.

The preprocessor then diagnoses vertical mass flux with diagnose_cs_cm! from the corrected horizontal divergence and explicit layer mass tendency. The implementation and its correction policy live in src/Preprocessing/cs_poisson_balance.jl and the native-source driver src/Preprocessing/transport_binary/cubed_sphere_geos.jl (the per-window closures in geos_cs_window.jl and geos_cs_omega.jl beside it).

The endpoint convention is the raw dry endpoint rather than the endpoint implied by an FV3-style pressure fixer. The pressure-fixer endpoint can go slightly negative in thin upper layers; the raw endpoint is robust and the header records "geos_mass_endpoint" => "raw_dry_endpoint" for traceability.

Required input per day ​

CollectionCadenceVariables
CTM_A1hourly (window-averaged)MFXC, MFYC, DELP
CTM_I1hourly (instantaneous)PS, QV
A1hourlyPBLH, USTAR, HFLUX, T2M (GEOS-IT native or GEOS-FP physics fallback, only if surface is enabled)
A3mstE3-hourly (window-averaged)CMFMC (only if convection is enabled)
A3dyn3-hourly (window-averaged)DTRAIN (only if convection is enabled)
I33-hourly (instantaneous)QV (GEOS-FP convection order validation when A3 coordinates lack physical metadata)

GEOS-IT file-naming convention: GEOSIT.YYYYMMDD.<COLLECTION>.C180.nc. GEOS-FP maps CTM_A1 to tavg_1hr_ctm_c0720_v72 at HH30 and CTM_I1 to inst_1hr_ctm_c0720_v72 at HH00. Window n starts at hour n-1 and ends at hour n, so window 24 requires the next day's 00Z inst file. Files can be in the flat root or YYYYMMDD/ directories. Missing inst files error; there is no tavg PS or zero-QV fallback. As for GEOS-IT, endpoint dry layer pressure is (1-QV_inst) * (ΔA + ΔB*PS_inst) and dry surface pressure is the column sum. Tavg DELP supplies the level-order heuristic, while dry MFXC/MFYC supply the horizontal transport with unchanged 450 s dynamics-step scaling.

GEOS preprocessing TOML ​

A working GEOS-IT C180 → CS C180 preprocessing config has two TOML files: a small preprocessing TOML (per-run knobs) and a separate source descriptor TOML (shared with the runtime, declares the source's invariants):

toml
# config/preprocessing/geosit_c180_to_cs180.toml
[source]
toml               = "config/met_sources/geosit.toml"   # source descriptor (below)
root_dir           = "~/data/AtmosTransport/met/geosit_c180/raw_catrine"
include_surface    = true     # PBL surface payload (pblh, ustar, hflux, t2m)
include_convection = true     # CMFMC + DTRAIN payload
include_vdiff_fields = true   # GCHP VDIFF payload (u, v, T, qv at substep cadence)

[output]
directory  = "~/data/AtmosTransport/met/geosit/C180/preprocessed/merge025hpa_adaptive_f32"
mass_basis = "dry"                             # binary header

[grid]
type                = "cubed_sphere"
Nc                  = 180
panel_convention    = "geos_native"
regridder_cache_dir = "~/.cache/AtmosTransport/cr_regridding"

[vertical]
transform    = "merge_above_pressure"
threshold_pa = 25.0                              # merge above 0.25 hPa → 64-level product
coefficients = "config/geos_L72_coefficients.toml"
# The default "identity" transform keeps all 72 levels; production
# C180 uses "merge_above_pressure" with threshold_pa = 25.0 (0.25 hPa)
# to fold the very thin upper-mesosphere layers into one, which makes
# the palindrome positivity budget feasible.

[numerics]
float_type            = "Float32"
dt_met_seconds        = 3600.0           # CTM cadence (hourly for GEOS-IT)
substep_schedule      = "adaptive_cfl"   # per-window adaptive substep count
substep_cfl_target    = 0.95
min_steps_per_window  = 2
max_steps_per_window  = 16

The source descriptor (referenced via [source] toml = …) declares collection mappings and FV3-specific invariants. The actual descriptor TOML is in config/met_sources/geosit.toml; the keys the preprocessor reads sit under [preprocessing]:

toml
# config/met_sources/geosit.toml (extract — full file is longer)
[preprocessing]
mass_flux_dt_seconds  = 450.0     # FV3 dynamics step — see Conventions
level_orientation     = "auto"    # bottom_up | top_down | auto
collections_required  = ["CTM_A1", "CTM_I1"]
collections_optional  = ["A3mstE", "A3dyn"]   # used when convection is on

The preprocessing TOML's [source] block can override include_surface, include_convection, include_vdiff_fields, and, for GEOS-FP, physics_dir / physics_layout. GEOS-IT reads native A1/A3 files next to CTM_A1/CTM_I1. GEOS-FP reads native C720 CTM files from root_dir and physics fallback files from physics_dir.

Adaptive substep schedule ​

The CS GEOS-native path supports per-window adaptive substep counts. When [numerics].substep_schedule = "adaptive_cfl":

  1. _geos_select_steps_for_window! runs up to 8 refinement iterations per window, evaluating the palindrome positivity budget 2·(out_x + out_y + out_z) / m_start against substep_cfl_target.

  2. The final per-window substep count is collected into a steps_per_window_by_window :: Vector{Int} of length 24.

  3. driver_before_close_writer! patches the schedule into the streaming binary header via set_streaming_steps_per_window_schedule!.

  4. The header carries runtime_substep_contract = "binary_schedule", which tells the runtime to advance using the per-window schedule rather than a single scalar.

C180 production binaries use this. The scalar steps_per_window in the header equals maximum(schedule); the runtime reads steps_per_window_by_window instead and gets per-window granularity.

GCHP VDIFF preprocessing payload ​

When [source].include_vdiff_fields = true, the preprocessor writes four extra payload sections:

SectionContents
:vdiff_u, :vdiff_vSubstep-cadence horizontal wind components
:vdiff_t, :vdiff_qvSubstep-cadence temperature and specific humidity

These feed the LocalHoltslagBovilleKzField local Kz at runtime. The binary's capability surface advertises gchp_vdiff = true once all four are present. The runtime's [diffusion].kind = "geoschem_holtslag_boville_vdiff" requires this capability.

Per-window pipeline ​

For each of the 24 hourly windows:

  1. Read (src/Preprocessing/sources/geos_read_window.jl::read_window!):
  • Open CTM_A1 for hourly MFXC, MFYC, DELP (window-constant).

  • Open CTM_I1 for instantaneous PS, QV at hour n and n+1.

  • Expose MFXC / MFYC as a rate-like diagnostic by dividing by mass_flux_dt = 450 s. CTM_A1 stores a dry pressure-area transport amount for one 450 s dynamics step, so the GEOS-CS writer stores each Strang half-sweep face flux as MFXC / (2g) and reuses that amount for the 8 substeps in the hourly window. The logged flux_scaleis450 / (2g) = 22.94361479.

  • Auto-detect level orientation (detect_level_orientation): GEOS-IT files are bottom-up (k=1 surface), the runtime expects top-down (k=1 TOA). The reader flips once at read time so all downstream code sees the runtime convention.

  1. Endpoint dry-mass reconstruction (endpoint_dry_mass!):
  • From PS_total + QV + the hybrid-σ-pressure coefficients, reconstruct DELP_dry, PS_dry, ensuring Σ DELP_dry = PS_dry to machine precision.
  1. Native MFXC/MFYC → v4 face flux layout (geos_native_to_face_flux!):
  • GEOS-IT MFXC/MFYC are already on a dry basis (per the GMAO product manual). No (1 − qv) correction is applied.

  • Re-stagger from the FV3 layout (cell-centered values that represent the east / north face) into the v4 layout (am[i+1, j, k] = MFXC[i, j, k]).

  • Sync west / south halos via _propagate_cs_outflow_to_halo!.

  1. Raw dry endpoint target + column balance (balance_cs_column_mass_fluxes!):
  • The next-hour raw GEOS DELP_dry endpoint is transformed with the same vertical plan as m_cur.

  • Native horizontal fluxes are column-balanced to that endpoint for the selected per-window substep count.

  1. Diagnosed vertical mass flux (diagnose_cs_cm!):
  • The binary stores dm = (m_next_raw - m_cur) / (2 * n_sub[win]).

  • cm is diagnosed from the balanced horizontal fluxes and this dm, so runtime replay closes against the same raw endpoint used by the positivity gate.

  • With chain_mass = true, the raw endpoint is chained into the next window/day. With chain_mass = false, every window seeds m_cur from the raw GEOS start endpoint.

  1. Write-time replay gate — same contract as the spectral path (verify_write_replay_cs!); failures abort.

  2. Cross-day chain — when chain_mass = true, the day's final_m is threaded as seed_m for the next day's process_day invocation. When chain_mass = false, no cross-day seed is returned; each day/window is re-seeded from raw GEOS mass.

GCHP-style convection wiring ​

When [source] include_convection = true:

  1. The reader opens A3mstE and A3dyn (3-hourly NetCDF). If either collection is missing, the open fails loudly — there is no silent fallback. GEOS-FP also requires matching I3 QV when the A3 fields lack physical orientation metadata, as described above.

  2. 3-hourly hold-constant binding — every hourly window w reads from A3 record index (w − 1) ÷ 3 + 1. Windows 1, 2, 3 see the same A3 record; windows 22, 23, 24 see the 8th. The dry-basis correction is still per-window (see step 3).

  3. Dry-basis correction (_moist_to_dry_dtrain!, _moist_to_dry_cmfmc!):

  • GMAO ships CMFMC and DTRAIN as moist-air mass fluxes, kg / m² / s. The runtime needs them on the same dry basis as state.air_mass, so the reader multiplies by (1 − qv_face) using the window-mean QV (average of t_n and t_{n+1} humidity).

  • CMFMC lives at NZ+1 interfaces; the dry factor at face k is the four-corner mean of QV at the two adjacent centers averaged over the two endpoints. DTRAIN is at centers; the dry factor is the simple two-endpoint mean.

  1. Binary write — the :cmfmc and :dtrain payload sections land in the binary; inspect_binary advertises cmfmc_convection = true once they're present. The runtime's CMFMCConvection operator picks them up via the ConvectionForcing carrier.

If include_convection = false, the orchestrator's per-window NamedTuple omits the :cmfmc / :dtrain keys and the writer no-ops them (the binary's payload_sections does not list them and runtime convection is automatically gated off).

Performance notes ​

  • A 1-day GEOS-IT C180 → CS C180 F32 preprocess is ~1 minute on a recent workstation; with include_convection = true, add ~10 s per day for the A3 reads. include_vdiff_fields = true adds another ~10 s per day for the substep-cadence VDIFF fields.

  • The column-balance + diagnose_cs_cm! path has zero global Poisson iteration — every step is a per-column scan, embarrassingly parallel. There's no diminishing return from adding cores.

  • Real GEOS-IT data closes write-time replay at machine precision for each written window. Worst replay relative errors on real C180 days land around 5e-08 in F32.

What's next ​

  • Regridding — how the conservative weights are built and cached (relevant for cross-topology paths).

  • Conventions cheat sheet — mass_flux_dt = 450 s, panel conventions, units cheat sheet.