Skip to content

Output and visualization API ​

Output defines snapshot capture and persistence, and observation sampling ([output.observations]: point events and station series sampled at met-window ends). Visualization provides topology-aware field views and optional Makie rendering for those snapshots.

Output ​

AtmosTransport.Output Module
julia
Output

Topology-aware diagnostic output for AtmosTransport runtime products.

This module owns the public NetCDF output contract. Runtime code should capture model state with capture_snapshot and write files with write_snapshot_netcdf instead of defining ad-hoc NetCDF layouts in runner code.

The writer is intentionally topology-dispatched:

  • LatLonMesh writes regular CF lon/lat coordinates.

  • ReducedGaussianMesh writes native cell-indexed diagnostics plus a legacy lon/lat raster view for current debug plots.

  • CubedSphereMesh writes panel-native diagnostics with GEOS-style lons, lats, corner_lons, corner_lats, cell_area, and cubed_sphere metadata so Panoply and downstream tools have enough geometry context to render C-grid snapshots.

New topologies should add methods for the small internal schema/diagnostic functions in this folder; they should not special-case the runner.

Output also owns observation sampling (observations/): the [output.observations] contract, source readers, containing-cell locators, the device column gather, and the append-only _soundings / _sites NetCDF files written by build_observation_sampler's sampler.

source
AtmosTransport.Output.VERTICAL_PLACEMENT_CODES Constant

Integer vertical_placement codes of the observation files, the method that placed each request (see vertical_placement_codes_description):

CodeNameLayer chosen by
0record_heightthe record's height above ground (intake_height, or altitude − elevation)
1altitude_minus_demaltitude − DEM ground elevation at the point
2pressurethe record's pressure against the interface pressures of the pressure_basis (total by default)
3absolute_altitudealtitude against model surface height + layer heights (absolute_altitude_above_agl_m)
4lowest_layerno vertical coordinate, for sources whose records are column or surface products
source
AtmosTransport.Output.AboveGroundPlacement Type

Every record at its height above the ground, measured up from the model surface (default).

source
AtmosTransport.Output.AbsoluteAltitudeAbove Type
julia
AbsoluteAltitudeAbove(min_height_agl_m)

absolute_altitude_above_agl_m = h: records at least h m above the ground (free-tropospheric aircraft and AirCore samples) are placed by their pressure when the record has one, else by their altitude above sea level against the model's geopotential heights (model surface height plus layer heights). The altitude is the record's altitude, else its ground elevation (the record's, else the DEM's) plus its intake_height; a record with neither keeps its height above the ground. Records below h keep AboveGroundPlacement. Needs a model surface height (surface_height_file).

source
AtmosTransport.Output.AbstractAltitudePlacement Type

How records that carry an altitude are placed once their height above the ground is known.

source
AtmosTransport.Output.AbstractAveragingKernelOutput Type
julia
AbstractAveragingKernelOutput

Whether an OCO-2 source's soundings also get the averaging-kernel column of the sampled model profile: NoAveragingKernels (the default) or AveragingKernelColumns.

source
AtmosTransport.Output.AbstractMissingHeightRule Type
julia
AbstractMissingHeightRule

What a source's records mean when they give no vertical coordinate at all (no intake_height, altitude or pressure), chosen by the source type (missing_height_rule): LowestLayerWithoutHeight or UnplacedWithoutHeight.

source
AtmosTransport.Output.AbstractModelSurfaceHeight Type
julia
AbstractModelSurfaceHeight

Surface height of the model grid (m above sea level): the ground the model's layer heights are measured from. NoModelSurfaceHeight (default) or ModelSurfaceHeight, read from a per-grid dataset by GriddedIO.read_model_surface_height. Query it with model_surface_height.

source
AtmosTransport.Output.AbstractObservationMode Type

How a source's records are sampled.

source
AtmosTransport.Output.AbstractObservationOutput Type

Parsed [output.observations]: either NoObservationOutput or a spec.

source
AtmosTransport.Output.AbstractObservationSource Type
julia
AbstractObservationSource

Where sampling requests come from. Concrete sources carry a path template ({YYYYMMDD} or {date}, {YYMMDD}, {YYYY}, {MM}, {DD} substituted per run day; * and ? wildcards in the file name) and declare whether they yield point events (SoundingMode) or station series (SiteMode).

source
AtmosTransport.Output.AbstractObservationTimeInterpolation Type

How point events are placed in time between met-window ends.

source
AtmosTransport.Output.AbstractPointElevation Type
julia
AbstractPointElevation

Ground elevation (m above sea level) at a point, from a high-resolution digital elevation model: NoPointElevation (default) or GriddedIO.LatLonPointElevation (GriddedIO.read_point_elevation). Query it with point_elevation.

source
AtmosTransport.Output.AbstractPressureBasis Type
julia
AbstractPressureBasis

The vertical basis of a column's placement (pressure_basis), one choice for the interface pressures a pressure-placed record (or an averaging-kernel column) is compared with and for the hypsometric layer heights a record placed by height is compared with: TotalFromHumidity (default) or DryInterfaces. A record's pressure is the total (ambient) pressure, dry air plus water vapour. The air mass of a dry-basis run gives dry interface pressures, pk+1/2=pk−1/2+gmk/A (the weight of the dry air above), which are lower than the total pressure at the same interface by the weight of the water vapour above it: about 0.5 % of the surface pressure for 50 kg m⁻² of precipitable water. The hydrostatic layer thickness is (RdTv/g)ln⁡(pk+1/2/pk−1/2) with total pressures and the virtual temperature Tv=T(1+0.61q); dry pressures and T put heights in a humid boundary layer about 2 % low.

source
AtmosTransport.Output.AbstractQualityFilter Type

Which satellite records become requests.

source
AtmosTransport.Output.AbstractRetrievalMapping Type
julia
AbstractRetrievalMapping

How the profile values of a retrieval relate to its pressures, and so how the model column is mapped onto them (the projection matrix P of retrieval_column_weights!): LayerRebin (values are layer means between interfaces) or HatLevelProjection (values on levels, the profile linear in pressure between them). A RetrievalColumn carries one; the operator dispatches on it.

source
AtmosTransport.Output.AbstractSiteGrouping Type

How ObsPack records are grouped into sites.

source
AtmosTransport.Output.AbstractSiteSchedule Type
julia
AbstractSiteSchedule

When a station is sampled. Chosen per site from the site table:

Table keysTypeOutput
noneEveryWindowevery met-window end, _sites file
start_time, end_timeTimeRangeevery met-window end inside the range, _sites file (NaN outside)
timesTimeListone point event per listed UTC time, _soundings file
source
AtmosTransport.Output.AbstractTableFormat Type

Encoding of a generic point table.

source
AtmosTransport.Output.AbstractUnplacedPolicy Type

What the sampler does with requests it cannot place in the column.

source
AtmosTransport.Output.AbstractVerticalCoordinate Type
julia
AbstractVerticalCoordinate

A vertical coordinate that can place a record in the model column: HeightAboveGroundCoordinate or PressureCoordinate. VerticalPlacementSpec lists the coordinates a run uses in preference order (vertical_coordinates); resolve_placement places each record by the first one it can.

source
AtmosTransport.Output.AutoTableFormat Type

Derive the format from the file extension (.csv, .toml, .nc/.nc4).

source
AtmosTransport.Output.AveragingKernelColumns Type
julia
AveragingKernelColumns(tracers, mapping = HatLevelProjection())

averaging_kernel_tracers = [...] on an oco2_lite source: the reader also reads each sounding's retrieval (levels, pressure weights, averaging kernel, prior, prior column; read_oco2_retrieval_columns), and the sampler writes, for each tracer of tracers, the averaging-kernel column X=Xa+∑ihiai((Px)i−xa,i) of the sampled profile as <tracer>_ak_column, with the operator of the 4D-Var (retrieval_column_weights!). mapping (averaging_kernel_mapping) is HatLevelProjection ("hat", the levels as given) or LayerRebin ("tm5", TM5-4DVar's 19 layers, tm5_layer_column). The prior term belongs to the retrieved gas, so name the tracer that carries it (total CO2), not components of it.

source
AtmosTransport.Output.CSVTableFormat Type

Comma-separated with a header line; # comments; no quoting. List-valued times use ;.

source
AtmosTransport.Output.DryInterfaces Type

pressure_basis = "dry": compare a record's pressure with the dry interface pressures pk+1/2=pk−1/2+gmk/A of a dry-basis run, and its height with the hypsometric heights on them with the layer temperature T, zk−1/2=zk+1/2+(RdTk/g)ln⁡(pk+1/2/pk−1/2), for runs whose binaries carry no humidity (the sampler's only rule before issue #20). Both are approximations. The dry interfaces lie at lower pressure than the total ones, so a record can be placed one or more layers lower in the column than its total pressure says, most likely near the surface where the vapour weight above an interface is largest and the layers are thinnest. The heights are low by the dry pressure ratio (−q plus the vapour weight above over the pressure) and by T against Tv (−0.61q): about 2 % in a humid tropical boundary layer (q = 16 g/kg), 6 m at a 300 m intake. Not available on a moist-basis run.

source
AtmosTransport.Output.ErrorOnUnplaced Type

unplaced_records = "error" (default): building the sampler fails, naming the requests.

source
AtmosTransport.Output.EveryWindow Type

Sample the site at every met-window end of the run.

source
AtmosTransport.Output.HatLevelProjection Type
julia
HatLevelProjection()

Retrieval values sit on N levels and the profile is linear in pressure between them: the OCO-2 and OCO-3 retrievals (20 levels, "defined on layer boundaries", the first at σ=10−4), whose pressure weights are the integrals of the levels' hat functions (the trapezoid rule with half-thickness end levels, with a dry-air correction). The model column, stretched onto the retrieval levels (top level to bottom level), is projected onto the retrieval's basis, the hat functions φj of the levels (φj(pj)=1, linear to 0 at the neighbouring levels): the level values c are the L2 (Galerkin) projection in dry air,

∑iMjici=bj,Mji=∫φjφidpdry,bj=∫φjxdpdry=∑kBjkxk,Bjk=mkΔsk∫sk−1/2sk+1/2φj(p)dp,

so P=M−1B, with each stretched model layer k (air mass mk, the run's dry air mass by default) spread evenly over its pressure thickness Δsk; M is tridiagonal. The hats sum to 1 over the stretched column, so the rows of P sum to 1 and, with the hat integrals hj=∑kBjk/∑kmk as weights, ∑jhjcj is the model's air-mass-weighted column mean: the projection conserves the column. It reproduces every profile the retrieval can represent (piecewise linear on the levels), to the discretization of the model's layer means. P, the inverse of the consistent mass matrix times B, has negative entries in general (about −0.2 in every row on a GEOS L72 column); the weights H=(h∘a)TP of OCO-2 retrievals stayed positive in the cases measured. Stored as retrieval_mapping = "hat_levels".

source
AtmosTransport.Output.HeightAboveGroundCoordinate Type

"height_above_ground": the record's height h above the true ground, the intake_height, else altitude − elevation, else altitude minus the DEM ground elevation at the point, measured up from the model surface with the model's hypsometric layer heights (vertical_placement codes record_height and altitude_minus_dem).

source
AtmosTransport.Output.LayerRebin Type
julia
LayerRebin()

Retrieval values are means over N layers between N + 1 interfaces (a TCCON or GOSAT layer grid, TM5-4DVar's 19-layer form of OCO-2, tm5_layer_column). The model column, stretched onto the retrieval column, is rebinned by pressure overlap: P=R, TM5-4DVar's mass-conserving inv_rebin (retrieval_rebin_matrix). Stored as retrieval_mapping = "layer_rebin".

source
AtmosTransport.Output.LinearWindowInterpolation Type

Blend the two met-window-end samples bracketing each sounding time (default).

source
AtmosTransport.Output.LocationGrouping Type

One site per distinct (lat, lon, intake height) rounded to 0.01° and 0.1 m, with ids <site_code>_<lat>N_<lon>E_<h>magl in signed decimal degrees.

source
AtmosTransport.Output.LowestLayerWithoutHeight Type

The record is a column or surface product: it is sampled in the lowest layer (vertical_placement = lowest_layer). OCO-2 soundings (their value is the column; the intake value is the surface layer) and table rows without height columns (surface points).

source
AtmosTransport.Output.ModelSurfaceHeight Type
julia
ModelSurfaceHeight(field, path)

Per-cell surface height of the model grid (m above sea level), in the mesh's native layout: an (Nx, Ny) matrix on a lat-lon mesh, a vector over the cells on a reduced Gaussian mesh, a 6-tuple of (Nc, Nc) panels on the cubed sphere. path is the per-grid dataset it came from (written to the observation files as provenance).

source
AtmosTransport.Output.NearestWindowSampling Type

Use the single met-window-end sample nearest to each sounding time.

source
AtmosTransport.Output.NetCDFTableFormat Type

One-dimensional NetCDF variables along the record dimension; CF time units.

source
AtmosTransport.Output.NoAveragingKernels Type

No averaging-kernel columns (the default): the reader reads no retrieval fields.

source
AtmosTransport.Output.NoModelSurfaceHeight Type

No model surface height configured; model_surface_height returns NaN.

source
AtmosTransport.Output.NoObservationOutput Type

Default when [output.observations] is absent or enabled = false.

source
AtmosTransport.Output.NoObservationSampler Type

No-op sampler installed when observation output is absent or disabled.

source
AtmosTransport.Output.NoPointElevation Type

No DEM configured; point_elevation returns NaN.

source
AtmosTransport.Output.NoQualityFilter Type

quality_filter = "none": keep every record (the OCO-2 v11 MIP co-samples all 10-s averages).

source
AtmosTransport.Output.OCO2LiteSource Type
julia
OCO2LiteSource(path_template, quality_filter[, averaging_kernel = NoAveragingKernels()])

NASA OCO-2/OCO-3 Lite XCO2 files, or the OCO-2 v11 MIP 10-second average files (same sounding_id, time, latitude, longitude layout). Records passing quality_filter become point events. With averaging_kernel = AveragingKernelColumns(tracers) (opt-in) the reader also reads each record's retrieval and the sampler writes averaging-kernel columns of the named tracers (AveragingKernelColumns).

source
AtmosTransport.Output.ObsPackSource Type
julia
ObsPackSource(path_template, mode, site_grouping)

NOAA ObsPack NetCDF dataset files. SiteMode() groups records into fixed stations by site_grouping; SoundingMode() samples every record at its own time.

source
AtmosTransport.Output.ObservationOutputSpec Type
julia
ObservationOutputSpec

Parsed [output.observations] table. path is a template: _soundings or _sites is inserted before the extension and, with daily partitions, {date} / {YYYYMMDD} / {day} are substituted per input binary exactly as for snapshot output. tracers === nothing means every model tracer. start_time is only consulted when [input].start_date is absent. placement is the VerticalPlacementSpec.

source
AtmosTransport.Output.ObservationSet Type
julia
ObservationSet(origin, soundings, sites[, dropped_outside_window, skipped_invalid])

Every sampling request of a run. build_observation_set sorts soundings by time_seconds (stable) and merges sites so they are unique by id; the constructor itself neither sorts nor deduplicates, and only rejects site series with a TimeList schedule. dropped_outside_window counts the point events outside the transported span; skipped_invalid counts source rows skipped for fill values, invalid coordinates, or the quality filter.

source
AtmosTransport.Output.ObservationTerrain Type
julia
ObservationTerrain(; model_surface = NoModelSurfaceHeight(), dem = NoPointElevation())

The static ground fields observation placement may use: the model-grid surface height (AbstractModelSurfaceHeight) and a point DEM (AbstractPointElevation). The runner builds it from [output.observations] through GriddedIO and passes it to build_observation_sampler.

source
AtmosTransport.Output.PlacementColumn Type
julia
PlacementColumn(nlevel)

Scratch for column_layer! and sample_column_layer! on a column of nlevel layers: p_half receives the interface pressures of the pressure basis (those a pressure placement is compared with, and the total pressures of the heights), and humidity holds the column's specific humidity (k = 1 at the top), which the caller fills when the pressure basis needs it (needs_column_humidity).

source
AtmosTransport.Output.PressureCoordinate Type

"pressure": the record's pressure (ObsPack pressure, a total pressure) against the column's interface pressures, built as the AbstractPressureBasis says (vertical_placement code pressure).

source
AtmosTransport.Output.QualityFlagFilter Type
julia
QualityFlagFilter(variable, max)

quality_filter = "flag_max": keep records whose integer flag variable is <= max (Lite files: xco2_quality_flag, 0 = good).

source
AtmosTransport.Output.RetrievalColumn Type
julia
RetrievalColumn(pressure_pa, pressure_weight, averaging_kernel, prior_profile,
                profile_sigma, surface_pressure_pa[, mapping = LayerRebin()[, prior_column = NaN]])
RetrievalColumn(; pressure_pa, pressure_weight, averaging_kernel, prior_profile,
                  profile_sigma = Float64[], surface_pressure_pa = first(pressure_pa),
                  mapping = LayerRebin(), prior_column = NaN)

The vertical description of one retrieved column average (a satellite or TCCON sounding) with N retrieval values, ordered from the surface up. The mapping (AbstractRetrievalMapping) says what the values are:

  • LayerRebin: means over N layers; pressure_pa holds the N + 1 layer interfaces;

  • HatLevelProjection: values on N ≥ 2 levels, the profile linear in pressure between them (OCO-2/OCO-3); pressure_pa holds the N level pressures.

Fields:

  • pressure_pa: the interfaces or levels (Pa, total pressure), surface first, strictly decreasing; the last is the retrieval top (≥ 0);

  • pressure_weight: the pressure weights hi (N, ≥ 0, summing to 1 within RETRIEVAL_WEIGHT_SUM_TOLERANCE);

  • averaging_kernel: the column averaging kernel ai (N, normalized, dimensionless: ∂X/∂xi=hiai);

  • prior_profile: the retrieval prior xa,i (N, dry mole fraction, mol mol⁻¹, in [0, 1]);

  • profile_sigma: optional 1-σ uncertainty σi of the model profile on the retrieval layers or levels (N, mol mol⁻¹, in [0, 1]; empty when absent), the input of the model-error term retrieval_model_error_variance. It is not the retrieval's a-priori uncertainty: the smoothing error is already represented by the averaging kernel;

  • surface_pressure_pa: the retrieval surface pressure (Pa), equal to the first pressure (relative tolerance 1e-6);

  • mapping: the AbstractRetrievalMapping;

  • prior_column: optional, the retrieval's prior column Xa (mol mol⁻¹, in [0, 1]; NaN when absent), e.g. the OCO-2 xco2_apriori. When given, the column is X=Xa+∑ihiai((Px)i−xa,i) (the MIP protocol's eq. 2); without it Xa=∑ihixa,i. The two differ when the weights and the prior were averaged separately (OCO-2 10-s averages: a few thousandths of a ppm).

Every value but an absent prior_column must be finite. See retrieval_column_weights! for the operator.

source
AtmosTransport.Output.RuntimeOutputMetadata Type

Metadata resolved from the typed physics objects of one runtime invocation.

source
AtmosTransport.Output.SelectedSnapshotFrame Type
julia
SelectedSnapshotFrame

CPU-resident output containing only requested levels and column reductions. nlevel preserves the original vertical coordinate. levels maps stored layers back to model levels; column sums are computed before selecting layers. Tracer storage is VMR × air mass, with no molecular-weight conversion.

source
AtmosTransport.Output.SiteCodeGrouping Type

One site per dataset file and distinct intake height. The id is the dataset name (ObsPack files already encode site, platform, and lab), suffixed with _<h>magl only when a file holds several intake heights.

source
AtmosTransport.Output.SiteMode Type

Fixed stations; written at every met-window end.

source
AtmosTransport.Output.SiteRequest Type
julia
SiteRequest(id, lon, lat, elevation_m, intake_height_m, source[, schedule[, altitude_m]])

A fixed station. The vertical fields have the meaning of those of SoundingRequest (NaN when unknown; a station has no pressure); the sampler turns them into a VerticalPlacement when it is built. schedule defaults to EveryWindow.

source
AtmosTransport.Output.SkipUnplaced Type

unplaced_records = "skip": such requests are dropped and counted (n_unplaced_* attributes).

source
AtmosTransport.Output.SnapshotFrame Type
julia
SnapshotFrame

CPU-resident snapshot of one model state at one output time.

air_mass and each entry in tracers keep the topology-native storage shape:

  • LL: (lon, lat, lev)

  • RG: (cell, lev)

  • CS: NTuple{6, Array{T, 3}} with panel interiors (Xdim, Ydim, lev)

Tracer arrays store the model's conservative χ × carrier-air-mass quantity, not mixing ratio or physical kg species. Derived VMR and column diagnostics are computed by write_snapshot_netcdf. tracer_total_mass stores a compensated Float64 sum of that conservative quantity for every tracer. It is kept separately so Float32 visualization payloads cannot degrade global signed mass diagnostics through cancellation or output conversion.

Snapshot storage must be CPU-resident. Use capture_snapshot for model state on any backend; it strips cubed-sphere halos and copies device arrays to the host before constructing the frame.

source
AtmosTransport.Output.SnapshotWriteOptions Type
julia
SnapshotWriteOptions(; float_type=Float32, deflate_level=0, shuffle=true)

Options controlling NetCDF snapshot output.

  • float_type is the on-disk type for heavy diagnostic variables.

  • deflate_level is the NetCDF compression level for heavy payload variables: 0 disables compression, 1 is fast/light, and 9 is maximum compression.

  • shuffle enables the NetCDF shuffle filter when compression is active.

source
AtmosTransport.Output.SoundingMode Type

Time-stamped point events; each record is sampled at its own time.

source
AtmosTransport.Output.SoundingRequest Type
julia
SoundingRequest(id, time_seconds, lon, lat, source[, elevation_m, intake_height_m[, altitude_m, pressure_pa[,
                retrieval]]])

One point event, sampled at time_seconds after the run origin (Float64 UTC seconds). source indexes the spec's sources. The vertical fields are what the record says about its height, NaN when it says nothing: intake_height_m (m above the ground: the record's intake height, or its altitude minus its elevation), altitude_m (m above sea level), elevation_m (ground, m above sea level) and pressure_pa (Pa). The sampler turns them into a VerticalPlacement once, when it is built (resolve_placement). retrieval is the sounding's RetrievalColumn when its source asks for averaging-kernel columns (AveragingKernelColumns), else nothing.

source
AtmosTransport.Output.TOMLTableFormat Type

[[soundings]] or [[sites]] arrays of tables; times may be a TOML array.

source
AtmosTransport.Output.TableSource Type
julia
TableSource(path_template, mode, format)

Generic point list as CSV, TOML, or NetCDF. Point events need id, time (ISO-8601 UTC), lat, lon; sites need id, lat, lon. Both accept elevation (m asl) and intake_height (m above ground) or altitude (m asl, converted with elevation, else placed by resolve_placement). Sites may add start_time/end_time (TimeRange) or times (TimeList).

source
AtmosTransport.Output.TimeList Type
julia
TimeList(times_seconds)

Sample the site once at each listed time (seconds after the run origin), like a sounding: blended between the bracketing met-window ends and written to the _soundings file with the intake-layer value.

source
AtmosTransport.Output.TimeRange Type
julia
TimeRange(start_seconds, stop_seconds)

Sample the site at every met-window end with start <= t <= stop (seconds after the run origin); records outside the range are written as NaN.

source
AtmosTransport.Output.TotalFromHumidity Type

pressure_basis = "total" (default): compare a record's pressure with the column's total interface pressures, and a record's height with the hypsometric heights of moist air on them. Specific humidity qk (kg of water vapour per kg of moist air) makes the moist air mass of layer k mk/(1−qk) for a dry air mass mk (kg), so on a dry-basis run the hydrostatic total pressures and the interface heights above the model surface are

p1/2=ptop,pk+1/2=pk−1/2+gmkA(1−qk),zk−1/2=zk+1/2+RdTk(1+cqk)gln⁡pk+1/2pk−1/2,

with zN+1/2=0, Tk the layer temperature, c=Rv/Rd−1 (VIRTUAL_TEMPERATURE_FACTOR, 0.61) and Tk(1+cqk) the virtual temperature (exact for layers of uniform T and q), A the cell area and ptop the pure-pressure model-top interface A_ifc[1], a total pressure in the met model's hybrid coordinate (level 1 is the top). This inverts the preprocessing's dry conversion Δpdry=(1−q)Δp. On merged or remapped levels the binary carries a dry-mass-weighted q, so the inverse is not exact there; on the golden pre_ll72 binary (ERA5 L137 merged to 34 levels) the rebuilt total surface pressure differs from the stored one by −0.012 Pa on average and 0.125 Pa at most, where the dry interfaces are 169 Pa low on average and 700 Pa at worst. The humidity is the binary's layer-mean specific humidity at the sampled boundary: qv_start / qv_end of lat-lon binaries preprocessed with output.include_qv = true; on cubed-sphere binaries with the GCHP VDIFF payload the window-start VDIFF qv of the next window (the run's last window end takes the ended window's, one window old). Reduced-Gaussian binaries, and cubed-sphere binaries without the VDIFF payload, carry no humidity. On a moist-basis run the air mass already includes the vapour and its interfaces are total pressures without humidity; the heights there use T (no humidity is gathered, so the virtual-temperature term, about 1 % of the heights in a humid boundary layer, is neglected). A dry-basis run whose binaries do not all carry humidity cannot build them: building a sampler with any request, whatever its vertical coordinate (every row reports its layer's heights), then fails unless pressure_basis = "dry".

source
AtmosTransport.Output.UnplacedWithoutHeight Type

The record should state a height and does not: it cannot be placed (unplaced_records). ObsPack records, where every platform carries a height.

source
AtmosTransport.Output.VerticalPlacement Type
julia
VerticalPlacement(method, height_agl_m, pressure_pa, model_surface_m)

How one request is placed in the column, resolved once by resolve_placement: method is a VERTICAL_PLACEMENT_CODES code; height_agl_m the height above the model surface that selects the layer (NaN for pressure and lowest-layer placement); pressure_pa the pressure that selects it (pressure placement only); model_surface_m the model surface height of the cell (NaN without a surface-height dataset).

source
AtmosTransport.Output.VerticalPlacementSpec Type
julia
VerticalPlacementSpec(; surface_height_file = nothing, dem_file = nothing, dem_variable = "z",
                        unplaced = ErrorOnUnplaced(), altitude_placement = AboveGroundPlacement(),
                        coordinates = DEFAULT_VERTICAL_COORDINATES,
                        pressure_basis = TotalFromHumidity())

The vertical-placement settings of [output.observations]: the per-grid model surface height dataset, an optional point DEM (file and variable), the AbstractUnplacedPolicy, the AbstractAltitudePlacement, the AbstractVerticalCoordinates in preference order (a non-empty tuple without repeats; by default height above ground, then pressure), and the AbstractPressureBasis of pressure placement.

source
AtmosTransport.Output.begin_observation_day! Method
julia
begin_observation_day!(sampler, date_label, day_index)

Called by the runner before the first window boundary of each input binary. Single-file runs open their files on the first call; daily runs close the previous day's files and open the next pair. Rows are written to the files open at emission time. A binary's last window ends at the next day's 00:00, which is still observed before the next binary opens: with linear interpolation a sounding lands in the file of its own day, and each day's sites file ends with the 00:00 sample of the next day (the first file also holds the initial state at t = 0). With nearest_window, soundings in the first half window after 00:00 are emitted at that boundary and land in the previous day's file.

source
AtmosTransport.Output.build_observation_sampler Method
julia
build_observation_sampler(spec, state, grid; origin, window_seconds, halo_width,
                          terrain = ObservationTerrain(), has_humidity = false)

Read every source for the days covering window_seconds (seconds after origin, half-open), locate the requests on grid.horizontal, place each in the column (resolve_placement with the static ground fields of terrain, see ObservationTerrain), and prepare the device gather buffers. Requests that cannot be placed fail the build or are skipped and counted, as spec.placement.unplaced says. has_humidity says whether the run's binaries carry specific humidity: on a dry-basis run every request needs it for the total interface pressures and the virtual-temperature layer heights of TotalFromHumidity (the default spec.placement.pressure_basis; check_pressure_basis), and the build fails without it unless the basis is DryInterfaces; every window end must then pass humidity to observe_window_boundary!. Output files are opened by begin_observation_day!. NoObservationOutput yields NoObservationSampler().

source
AtmosTransport.Output.build_observation_set Method
julia
build_observation_set(sources, origin, window_seconds) -> ObservationSet
build_observation_set(sources, origin, dates)

Read every source for the days covering the window, merge sites by id, expand site time lists into point events, keep the point events with window_seconds[1] <= t <= window_seconds[2] (seconds after origin; the dates form uses whole days), and sort them by time (stable). A site id that repeats (across rows, daily files, or sources) must keep its location; time lists of a repeated id are merged, and other schedules must be equal. Per-source counts are logged.

source
AtmosTransport.Output.capture_snapshot Method
julia
capture_snapshot(model; time_hours=0, halo_width=0, fields=nothing)

Capture air-mass and conservative tracer-storage fields from a TransportModel. Without fields, return a full SnapshotFrame. Passing an OutputFieldSpec returns a SelectedSnapshotFrame containing only requested layers and column diagnostics, plus compensated Float64 totals for the selected tracers.

The result is CPU-resident and topology-native. For cubed-sphere states, halo_width strips panel halos before writing. GPU-backed arrays are copied to host memory by Array(...).

source
AtmosTransport.Output.column_layer! Method
julia
column_layer!(column::PlacementColumn, placement, z_half, air_column, area, g, p_top, basis, mass_basis) -> Int

Model layer (k = 1 top) of a VerticalPlacement in one column, the rule shared by the forward sampler and any other caller: by height above the model surface on the hypsometric interface heights z_half, or the lowest layer (as placement_layer); a pressure placement against the interface pressures of the AbstractPressureBasis basis, built into column.p_half from air_column (kg per cell, of mass_basis), the cell area (m²), gravity g, the model-top pressure p_top and, for TotalFromHumidity on a dry basis, column.humidity.

source
AtmosTransport.Output.column_mass_per_area Method
julia
column_mass_per_area(field, mesh)

Vertically integrate per-cell mass and divide by horizontal cell area.

source
AtmosTransport.Output.column_mean_mixing_ratio Method
julia
column_mean_mixing_ratio(air_mass, tracer_storage)

Compute the air-mass-weighted vertical mean mixing ratio for one snapshot field.

The returned shape is topology-native horizontal storage:

  • LL: (lon, lat)

  • RG: (cell,)

  • CS: NTuple{6, Matrix{Float64}}

source
AtmosTransport.Output.define_cs_horizontal_geometry! Method
julia
define_cs_horizontal_geometry!(ds, mesh::CubedSphereMesh) -> nothing

Define the horizontal geometry of a panel-native cubed-sphere NetCDF file in the open dataset ds: the GEOS-style layout shared by runtime snapshots and cs_native input files. Vertical and time axes are not defined here; each writer owns those.

Dimensions Xdim, Ydim (Nc), Xcorner, Ycorner (Nc + 1) and nf (6). Variables (coordinates and geometry in Float64 whatever the mesh precision):

  • Xdim, Ydim: panel indices 1:Nc, tagged degrees_east/degrees_north ("Fake Longitude/Latitude for GrADS Compatibility", the GEOS-Chem convention) so Panoply and GrADS render a per-panel map; nf (Int32): panel 1:6.

  • lons, lats (Xdim, Ydim, nf): cell-centre longitude and latitude [degrees], from panel_cell_center_lonlat in the mesh's panel convention.

  • corner_lons, corner_lats (Xcorner, Ycorner, nf): cell corners [degrees], from panel_cell_corner_lonlat.

  • cell_area (Xdim, Ydim, nf) [m²]: the mesh's own cell areas (the areas the runtime multiplies fluxes by), with coordinates = "lons lats".

  • cubed_sphere (scalar Int32): grid mapping with grid_mapping_name, cs_definition, cs_coordinate_law, cs_center_law, panel_convention, longitude_of_central_meridian, semi_major_axis = mesh.radius [m] and inverse_flattening = 0. Panel data variables point at it with grid_mapping = "cubed_sphere" and coordinates = "lons lats".

The same definition tags are also written as global attributes (Nc, cs_definition, cs_coordinate_law, cs_center_law, panel_convention, grid_mapping_name, longitude_of_central_meridian); readers rebuild the mesh from them.

source
AtmosTransport.Output.define_provenance_attributes! Method
julia
define_provenance_attributes!(ds) -> (; creation_date, git_commit, git_dirty)

Write the automated provenance block shared by every NetCDF file AtmosTransport writes (snapshots, observation files, and generated input files) as global attributes of the open dataset ds:

AttributeValue
creation_datewrite time, ISO 8601 UTC with a Z suffix
framework"AtmosTransport.jl"
framework_commitcommit of the source tree (AtmosTransport.source_revision())
framework_dirty"clean", "dirty" or "unknown"
runtimeJulia version, machine triple and operating system
hostname, userhost name and USER (or USERNAME)

Every value is best-effort and falls back to "unknown" instead of throwing, so a tree without git still produces a complete block. Returns the creation date and the source-tree state so the caller can compose its history line.

source
AtmosTransport.Output.finish_observations! Method
julia
finish_observations!(sampler)

Emit events exactly at the final window end, drop events that never received their second sample, write the summary attributes, and warn about anything that was not sampled. Idempotent.

source
AtmosTransport.Output.layer_mass_per_area Method
julia
layer_mass_per_area(field, mesh)

Convert per-cell layer mass [kg cell⁻¹] to mass per horizontal area [kg m⁻²] without changing topology-native storage.

source
AtmosTransport.Output.missing_height_rule Method
julia
missing_height_rule(source) -> AbstractMissingHeightRule

How records of source without any vertical coordinate are placed: LowestLayerWithoutHeight for OCO2LiteSource and TableSource, UnplacedWithoutHeight for ObsPackSource.

source
AtmosTransport.Output.model_surface_height Method
julia
model_surface_height(surface, cell::CellLocation) -> Float64

Model surface height (m above sea level) of the cell containing an observation; NaN for NoModelSurfaceHeight.

source
AtmosTransport.Output.needs_column_humidity Method
julia
needs_column_humidity(basis, mass_basis) -> Bool

Whether a column's layer heights and interface pressures on the AbstractPressureBasis basis need its specific humidity: on a dry-basis run TotalFromHumidity builds the total pressures and the virtual temperature from it, for every placement (the heights of sample_column_layer!) and for averaging-kernel columns. DryInterfaces, and a moist-basis run, need none.

source
AtmosTransport.Output.observation_needs_humidity Method
julia
observation_needs_humidity(sampler) -> Bool

Whether observe_window_boundary! needs the specific humidity: the sampler builds its columns' heights and pressures on total pressures (TotalFromHumidity) on a dry-basis run.

source
AtmosTransport.Output.observation_output_spec Method
julia
observation_output_spec(output_cfg; partition = nothing)

Parse [output.observations] from the [output] table. Returns NoObservationOutput() when the subtable is absent or enabled = false, otherwise an ObservationOutputSpec. Unknown keys, a missing path or sources, and invalid choices raise ArgumentError. The file partition (one file vs. one per daily binary) follows [output].split unless partition is given; split is only read when observations are enabled.

source
AtmosTransport.Output.observe_window_boundary! Method
julia
observe_window_boundary!(sampler, state, time_seconds; next_window_seconds, temperature = nothing,
                         humidity = nothing)

Sample state at a met-window end time_seconds after the run origin. next_window_seconds is the length of the window that starts now (it sets which soundings receive their first sample). temperature, when given, is a per-layer temperature field (K, k = 1 at the top) used for site layer heights, either with the air-mass layout or, on the cubed sphere, as interior-only panels; otherwise the configured constant applies. humidity is the specific humidity (kg kg⁻¹ of moist air, k = 1 at the top) at this window end, in the same layouts; a sampler that builds its columns on total pressures on a dry-basis run (TotalFromHumidity: the layer heights of every row, pressure placement, averaging-kernel columns) requires it and otherwise ignores it. Call once at t = 0 on the initial state and after every window.

source
AtmosTransport.Output.placement_layer Method
julia
placement_layer(placement, z_half, p_half) -> Int

Model layer (k = 1 top) of a VerticalPlacement in one sampled column: by height above the model surface (intake_layer_index on the hypsometric interface heights z_half), by pressure (pressure_layer_index on the interface pressures p_half), or the lowest layer.

source
AtmosTransport.Output.point_elevation Method
julia
point_elevation(dem, lon, lat) -> Float64

Ground elevation (m above sea level) of dem at the point, NaN where the DEM has no value (outside its coverage, fill, or NoPointElevation).

source
AtmosTransport.Output.read_observation_requests Method
julia
read_observation_requests(source, source_index, origin, dates) -> (soundings, sites)

Expand the source's path template for the run days and read every file into SoundingRequests and SiteRequests (one of the two is empty, depending on the source mode). Times are Float64 seconds since origin. Rows with fill values or impossible coordinates are skipped; a source that resolves to no file at all logs a warning.

source
AtmosTransport.Output.read_oco2_retrieval_columns Method
julia
read_oco2_retrieval_columns(ds, rows; label = "OCO-2 file") -> Vector{RetrievalColumn{HatLevelProjection}}

The retrieval of records rows (1-based indices along sounding_id) of an open OCO-2 or OCO-3 Lite file or OCO-2 v11 MIP 10-second file, as level columns (RetrievalColumn with HatLevelProjection): the profile values of these retrievals sit on 20 levels with the profile linear in pressure between them. Read per record:

  • the level pressures: pressure_levels (levels, sounding) (Lite files) or sigma_levels (levels) times psurf (sounding) (MIP files), converted to Pa with their units (hPa);

  • pressure_weight, xco2_averaging_kernel (normalized, used as it is, not multiplied by the weights) and co2_profile_apriori (converted to mol/mol with its units, ppm);

  • xco2_apriori, the prior column, when the file has it (converted to mol/mol): the column is then Xa+∑jhjaj(cj−xa,j). For the 10-s averages it differs from ∑jhjxa,j (the weights and the prior were averaged separately) by up to about 0.01 ppm.

The files store the levels from space to the surface; each record is turned surface first (by its pressures, so either order is read correctly). The surface pressure is the bottom level. Every field must be finite and pass the RetrievalColumn checks (weights summing to 1); an invalid record is an error naming its sounding_id.

source
AtmosTransport.Output.resolve_placement Method
julia
resolve_placement(spec::VerticalPlacementSpec, missing_height, request, cell, terrain)
    -> Union{VerticalPlacement, Nothing}

Place a SoundingRequest or SiteRequest in the column of its containing cell by the first of spec.coordinates (AbstractVerticalCoordinate, in preference order) that places it:

  • HeightAboveGroundCoordinate: the record's height above ground h (intake_height, or altitude − elevation with the record's or station's elevation; record_height), else h = altitude minus the DEM ground elevation at the point (altitude_minus_dem). The record is placed h above the model surface.

  • PressureCoordinate: the record's pressure (pressure), when it is valid_pressure (finite and positive).

A record that none of the coordinates place is unplaced (nothing) when it states any vertical coordinate (an intake_height, an altitude, a valid pressure), e.g. an altitude without a ground elevation (no record elevation, no DEM value), or a coordinate the run does not use. One without any vertical coordinate goes to the lowest layer (lowest_layer) under LowestLayerWithoutHeight and is unplaced under UnplacedWithoutHeight (missing_height, from missing_height_rule of the record's source). The model surface height is never used as the true ground.

spec.altitude_placement = AbsoluteAltitudeAbove(h₀) then re-places records placed by a height h≥h0 by their pressure (when pressure is one of the coordinates), else by absolute altitude: the stated altitude, else the ground elevation (the record's, else the DEM value at the point) plus intake_height; a record with neither keeps its height above the ground.

source
AtmosTransport.Output.retrieval_column_value Method
julia
retrieval_column_value(p_half, air, column::RetrievalColumn, x) -> Float64
retrieval_column_value(p_half, column::RetrievalColumn{LayerRebin}, x) -> Float64

The simulated column X=∑kHkxk+c of the model profile x (dry mole fraction, top first) on the model interface pressures p_half (Pa, top first, total pressures) and air masses air (read by the hat projection only): retrieval_column_weights! and retrieval_prior_offset in one call.

source
AtmosTransport.Output.retrieval_column_weights! Method
julia
retrieval_column_weights!(H, s, p_half, air, column::RetrievalColumn) -> H
retrieval_column_weights!(H, s, p_half, column::RetrievalColumn{LayerRebin}) -> H
retrieval_column_weights!(H, s, p_half, r, h, a) -> H

Weights of the averaging-kernel column on the model layers: with the model profile xk (dry mole fraction, k = 1 at the top),

X=∑kHkxk+c,Hk=∑ihiaiPik,c=Xa−∑ihiaixa,i

(retrieval_prior_offset) with the column's prior column Xa (prior_column) when it gives one, Xa=∑ihixa,i (so c=∑ihi(1−ai)xa,i) when not. P maps the model column, stretched onto the retrieval column (stretch_model_interfaces!), onto the retrieval's values as its mapping says: the rebin R of LayerRebin (retrieval_rebin_matrix; the column of TM5-4DVar's OCO-2 operator, averaging_kernels.F90, lines 228-235 and 245), or the hat projection of HatLevelProjection, which weights each model layer by its air mass air (kg per cell, top first; the run's dry air mass on a dry basis). Every row of P sums to 1 (retrieval_projection_matrix). p_half are the model interface pressures (Pa, top first; total pressures, so that they compare with the retrieval's), s a scratch vector of the same length that receives the stretched interfaces. A layer column ignores air; the form without it takes layer columns only. The last form takes the retrieval interfaces r (surface first), pressure weights h and kernel a of a layer column as they are, without the checks of RetrievalColumn (weights that do not sum to 1, as TM5's hi=Δpi/ps with a retrieval top above 0 Pa).

source
AtmosTransport.Output.retrieval_layer_count Method
julia
retrieval_layer_count(column::RetrievalColumn) -> Int

Number of retrieval values of a RetrievalColumn: its layers (LayerRebin) or levels (HatLevelProjection).

source
AtmosTransport.Output.retrieval_model_error_variance Method
julia
retrieval_model_error_variance(column::RetrievalColumn) -> Float64

The model-error variance of the averaging-kernel column from the uncertainty σi of the model profile on the retrieval layers (profile_sigma), the layers taken independent: σmod2=∑i(hiaiσi)2, the operator's weights on the retrieval layers, squared, times the profile variance. Zero when the column gives no profile_sigma. It depends on the record only, so it is fixed for an inversion and the cost stays quadratic.

This is analogous to, not the same as, TM5-4DVar's model error: its CH4 TROPOMI routine (averaging_kernels.F90, line 669, and Satellite.py of the CH4 project) evaluates ∑kHk2σk2 with the weights H=(ha)R on the model layers and the spread of the modelled profiles σk from its track file, and its OCO-2 routine adds a column model error instead. profile_sigma is not the retrieval's a-priori uncertainty, whose effect (the smoothing error) the averaging kernel already represents.

source
AtmosTransport.Output.retrieval_prior_offset Method
julia
retrieval_prior_offset(column::RetrievalColumn) -> Float64
retrieval_prior_offset(h, a, prior) -> Float64

The prior term of the averaging-kernel column, which does not depend on the model: c=Xa−∑ihiaixa,i with the column's prior_column Xa when it gives one (X=Xa+∑ihiai((Px)i−xa,i), the MIP protocol's form), else c=∑i(hi−hiai)xa,i (TM5: dot_product(pres_weights - W, prior_profile); the raw form always).

source
AtmosTransport.Output.retrieval_profile! Method
julia
retrieval_profile!(xr, s, p_half, air, column::RetrievalColumn, x) -> xr
retrieval_profile!(xr, s, p_half, column::RetrievalColumn{LayerRebin}, x) -> xr

The model profile x (top first) on the retrieval layers or levels (surface first), (Px)i: for a layer column the pressure-weighted mean over each retrieval layer, for a level column the hat projection, of the model column stretched onto the retrieval column (air as in retrieval_column_weights!). s is scratch for the stretched interfaces. A diagnostic: the column itself is ∑ihiai(Px)i+c.

source
AtmosTransport.Output.retrieval_projection_matrix Method
julia
retrieval_projection_matrix(p_half, air, column::RetrievalColumn) -> Matrix{Float64}

The projection matrix P (N × Nz, retrieval values surface first, model layers top first) of the column's mapping on the model column (interface pressures p_half, Pa, top first; air masses air, kg per cell, read by the hat projection only) stretched onto the retrieval column: the rebin R for LayerRebin, the dry-air L2 projection onto the levels' hats for HatLevelProjection. (Px)i is the model profile at retrieval value i and every row sums to 1.

source
AtmosTransport.Output.retrieval_rebin_matrix Method
julia
retrieval_rebin_matrix(p_half, column::RetrievalColumn{LayerRebin}) -> Matrix{Float64}
retrieval_rebin_matrix(p_half, r) -> Matrix{Float64}

The redistribution matrix R (N × Nz, retrieval layers surface first, model layers top first) of TM5-4DVar's inv_rebin (averaging_kernels.F90, lines 60-146) on the model column stretched onto the retrieval column: Rik is the pressure overlap of stretched model layer k with retrieval layer i divided by the thickness of layer i, so (Rx)i is the pressure-weighted mean of x over retrieval layer i. The outermost retrieval interfaces are those of the stretched model column (TM5's choice; they equal the retrieval surface and top to rounding). Every row sums to 1 and every column k distributes all of the stretched layer: ∑iRikΔpir=Δsk (the rebin conserves the column integral of x). The projection matrix of LayerRebin.

source
AtmosTransport.Output.runtime_output_spec Method
julia
runtime_output_spec(output_cfg, FT; default_path="", default_cap_hours=8760, fallback_hours=[])

Parse the run-time output contract from TOML-compatible [output] settings.

Preferred keys are path, cadence_hours or hours, and split = "single" | "daily". Legacy snapshot_file, snapshot_hours, and snapshot_interval_hours remain accepted.

source
AtmosTransport.Output.sample_column_layer! Method
julia
sample_column_layer!(column::PlacementColumn, p_half, z_half, placement, air_column, area, g, p_top,
                     temperature, basis, mass_basis) -> Int

The layer (k = 1 top) of a VerticalPlacement in one sampled column, from the column alone: the interface pressures of the air mass (interface_pressures! into p_half, pk+1/2=pk−1/2+gmk/A from p_top; dry pressures on a dry-basis run), the hypsometric interface heights above the model surface on the vertical basis of basis (placement_heights! into z_half, with the AbstractLayerTemperature temperature: total pressures and virtual temperature for TotalFromHumidity on a dry basis), then column_layer!. column.humidity must hold the column's specific humidity whenever the basis needs it (needs_column_humidity), for every placement, since the heights use it. The forward observation sampler and the inversion's placed point observations both choose their layers with this function.

source
AtmosTransport.Output.samples_observations Method

Whether the runner must visit every met-window end for this sampler.

source
AtmosTransport.Output.stretch_model_interfaces! Method
julia
stretch_model_interfaces!(s, p_half, surface_pa, top_pa) -> s

TM5-4DVar's stretch of the model column onto a retrieval column (averaging_kernels.F90, lines 213-219): the model interface pressures p_half (Pa, top first, p_half[end] the model surface pressure ps, p_half[1] the model top pt) mapped linearly so that the model surface falls on the retrieval surface psr (surface_pa) and the model top on the retrieval top ptr (top_pa),

sk=μpk+c,μ=psr−ptrps−pt,c=12[(psr−μps)+(ptr−μpt)].

Each model layer keeps its share Δpk/(ps−pt) of the column, so the pressure-weighted mean of any profile over the stretched layers is its mean over the model layers: the stretch moves the model column onto the retrieval's pressure range without adding or removing air.

source
AtmosTransport.Output.tm5_layer_column Method
julia
tm5_layer_column(column::RetrievalColumn{HatLevelProjection}) -> RetrievalColumn{LayerRebin}

TM5-4DVar's layer form of a level retrieval (OCO-2/OCO-3 10-s files in proj/tracer/CO2/py/Observations.py, lines 7016-7052, used by Satellite.py, lines 707-717): the N levels become the interfaces of N − 1 layers, the averaging kernel and the prior are interpolated linearly in pressure to the layer midpoints (the mean of the two levels), and the pressure weights are the layer thicknesses Δpi, normalized to the column between the bottom and top levels. TM5 divides by the surface pressure instead, so its weights sum to 1−σtop (0.9999 for OCO-2) and its column is that fraction of this one. A profile_sigma is averaged like the kernel. The prior column is TM5's, ∑ihixa,i on its layers (a prior_column of the record is not carried). For comparisons with TM5-4DVAR; the hat projection (HatLevelProjection) is the consistent mapping of level retrievals.

source
AtmosTransport.Output.with_netcdf_lock Method
julia
with_netcdf_lock(f)

Run f() holding the process-wide NetCDF lock. Every runtime NetCDF write (snapshot files, the snapshot stream, observation streams) goes through it, because netcdf-c is not thread-safe and daily snapshot files are written on a background task.

source
AtmosTransport.Output.write_snapshot_binary Method
julia
write_snapshot_binary(path, frames, grid; mass_basis=:dry, options=SnapshotWriteOptions(),
                      physics_attributes=Dict())

Write CS snapshots to a self-describing binary file. Skips NetCDF library overhead entirely; pair with scripts/postprocess/binary_to_netcdf.jl for the offline conversion. Throws if grid.horizontal is not a CubedSphereMesh.

source
AtmosTransport.Output.write_snapshot_netcdf Method
julia
write_snapshot_netcdf(path, frames, grid; mass_basis=:dry, options=SnapshotWriteOptions(),
                      fields=output_field_spec(), physics_attributes=Dict())

Write topology-aware runtime snapshots to NetCDF.

The output contains full per-level VMR fields, stored air mass, layer mass-per-area diagnostics, column air mass per area, and tracer column means. Reduced-Gaussian files also carry a legacy lon/lat raster view for quick plots. Cubed-sphere files carry panel lon/lat coordinates and a cubed_sphere grid-mapping variable modeled after GEOS-Chem diagnostics.

source

Visualization ​

Field selection uses typed values. Pass ColumnMean(), ColumnSum(), LevelSlice(), or SurfaceSlice() as the transform keyword to fieldview; LevelSlice() also requires level. Pass NativeUnit() or PPMUnit() as unit, and pass AllFrames() to frame_indices to select every frame. These selectors are exported by AtmosTransport.Visualization, not by the top-level module. For example:

julia
using AtmosTransport.Visualization
snapshot = open_snapshot("output.nc")
surface = fieldview(snapshot, :co2; transform=SurfaceSlice(), time=1,
                    unit=PPMUnit())
levels = fieldview(snapshot, :co2; transform=LevelSlice(), level=10, time=1)
AtmosTransport.Visualization Module
julia
Visualization

Topology-aware snapshot visualization support.

This module owns the lightweight data layer only: snapshot discovery, field views, unit scaling, and topology-aware rasterization for quick maps. Makie plotting lives in AtmosTransportMakieExt so the model/runtime does not pay a plotting load cost unless a Makie backend is explicitly loaded.

source
AtmosTransport.Visualization.AllFrames Type

Select every available snapshot frame.

source
AtmosTransport.Visualization.CubedSphereSnapshotTopology Type
julia
CubedSphereSnapshotTopology(Nc, nlevel, panel_convention[, definition])

Cubed-sphere snapshot geometry. Values are stored as (Xdim, Ydim, nf) for a single horizontal field, with nf == 6. definition is the mesh the snapshot was written on (coordinate and center laws, panel convention, longitude offset); it defaults to the panel convention's standard definition.

source
AtmosTransport.Visualization.HorizontalField Type
julia
HorizontalField

A topology-native horizontal field view from one snapshot time.

For LL/RG snapshots values is a (lon, lat) matrix. For CS snapshots it is a (Xdim, Ydim, nf) array until rasterized or plotted natively.

source
AtmosTransport.Visualization.LatLonSnapshotTopology Type
julia
LatLonSnapshotTopology(lons, lats; grid_type=:latlon)

Regular lon-lat snapshot geometry. Values are stored as (lon, lat).

source
AtmosTransport.Visualization.PlotSpec Type
julia
PlotSpec(variable; transform=ColumnMean(), level=nothing, title=nothing, unit=NativeUnit())

One panel specification for multi-panel plots and movies.

source
AtmosTransport.Visualization.RasterField Type
julia
RasterField

Regular lon-lat representation used by fast debug maps and movies.

source
AtmosTransport.Visualization.ReducedGaussianSnapshotTopology Type
julia
ReducedGaussianSnapshotTopology(lons, lats, nrings, regridding)

Reduced-Gaussian snapshot geometry after the current writer's ring-aware nearest-neighbor projection onto a regular lon-lat diagnostic grid.

source
AtmosTransport.Visualization.SnapshotDataset Type
julia
SnapshotDataset

Metadata for an AtmosTransport NetCDF snapshot file.

The object intentionally does not hold an open NetCDF handle. Field reads open the file briefly and close it immediately, which is robust for scripts, animations, and long debugging sessions.

source
AtmosTransport.Visualization.SnapshotRegridCache Type
julia
SnapshotRegridCache()

Cache expensive topology-to-raster geometry, especially CS→LL conservative regridders, across frames in snapshot grids and movies.

source
AtmosTransport.Visualization.as_raster Method
julia
as_raster(field; resolution=(360, 181), cache=SnapshotRegridCache())

Return a regular lon-lat RasterField for fast plotting.

LL and current RG diagnostic snapshots are already raster-like. CS fields are conservatively regridded to lon-lat and reuse cache across frames.

source
AtmosTransport.Visualization.catrine_map_curtains Method
julia
catrine_map_curtains(at_path, gc_dir; kwargs...) -> NamedTuple

Create the CATRINE AtmosTransport/GEOS-Chem column-map and pressure-curtain comparison product. Output is controlled by the out_dir keyword. This specialized visualization requires a Makie backend.

source
AtmosTransport.Visualization.catrine_map_curtains_3way Method
julia
catrine_map_curtains_3way(at_geos_path, at_era5_path, gc_dir; kwargs...) -> NamedTuple

Compare GEOS-Chem with AtmosTransport runs driven by GEOS-IT and ERA5 in one CATRINE column-map and pressure-curtain product. Output is controlled by the out_dir keyword. This specialized visualization requires a Makie backend.

source
AtmosTransport.Visualization.fieldview Method
julia
fieldview(snapshot, variable; transform=ColumnMean(), time=1, level=nothing, unit=NativeUnit())

Load one topology-native horizontal field from a snapshot file.

time may be a one-based frame index or a snapshot hour. For CS snapshots, transform may be ColumnMean(), ColumnSum(), LevelSlice(), or SurfaceSlice(). Stored CS column means support column-only output; level selection uses original model indices and rejects levels that were not written. LL/RG snapshots currently support ColumnMean() only.

source
AtmosTransport.Visualization.mapplot! Method
julia
mapplot!(axis, field; kwargs...)

Render a topology-aware field into an existing Makie axis and return the plot object. A Makie backend must be loaded.

source
AtmosTransport.Visualization.mapplot Method
julia
mapplot(field; kwargs...) -> Figure

Render one topology-aware HorizontalField as a lon-lat map. Load a Makie backend such as CairoMakie before calling this function. Cubed-sphere fields are conservatively rasterized and may reuse a SnapshotRegridCache.

source
AtmosTransport.Visualization.movie Method
julia
movie(snapshot, variable, output_path; kwargs...) -> String

Render one snapshot variable to an animation and return output_path. A Makie backend must be loaded.

source
AtmosTransport.Visualization.movie_grid Method
julia
movie_grid(snapshot, specs, output_path; kwargs...) -> String

Render several PlotSpec panels to one animation and return output_path. A Makie backend must be loaded.

source
AtmosTransport.Visualization.open_snapshot Method
julia
open_snapshot(path) -> SnapshotDataset

Read snapshot metadata and infer its topology.

Supported formats are the current AtmosTransport LL/RG column-mean snapshots and CS panel snapshots written by run_driven_simulation.

source
AtmosTransport.Visualization.robust_colorrange Method
julia
robust_colorrange(fields; trim=(0.01, 0.99))

Compute a robust color range from one or more fields by ignoring non-finite values and clipping to quantiles.

source
AtmosTransport.Visualization.snapshot_grid Method
julia
snapshot_grid(snapshot, variable; kwargs...) -> Figure

Render one snapshot variable at several output times in a shared figure. A Makie backend must be loaded.

source