Coming From X-STILT#

PYSTILT has the main pieces of X-STILT’s column and satellite workflow: column and slant receptors, sounding selection, averaging kernels, and pressure weighting. In X-STILT you configure one large script. In PYSTILT these pieces are Python functions and objects that you combine in your own script. PYSTILT does not try to copy every X-STILT feature. The table shows the ones that have an equivalent.

X-STILT concept

X-STILT API / file

PYSTILT equivalent

Column receptor (minagl / maxagl, agl levels)

get.recp.sensorv2.r

stilt.ColumnReceptor from the sounding’s coordinates

Slant column (run_slant)

get.recp.sensorv2.r

stilt.observations.slant_points() + stilt.Receptor.from_points()

Sounding selection (near-field + background)

sel.obs4recpv2

stilt.observations.select_observations_spatial()

Jittered receptors in a pixel (jitterTF)

jitter.obs4recp.r

stilt.observations.jitter_points()

Overpass grouping

get_timestr / overpass search

stilt.observations.group_by_overpass(), then df.groupby("overpass")

Vertical weighting (AK × PWF)

wgt.trajec.foot*.r

averaging_kernel and pressure_weighting transforms (Particle Weighting (Transforms))

Per-sounding averaging kernels (get.wgt.funcv3)

wgt.trajec.foot*.r

averaging_kernel with table: (stilt.transforms.averaging_kernel_table())

First-order chemistry

chem_lifetime

first_order_lifetime transform

Column footprint outputs

X-STILT column products

standard PYSTILT footprints from column or slant receptors

Product readers (OCO-2/3, TROPOMI, TCCON)

column_obs/*

read_oco2(), read_tropomi_ch4(), read_tccon() (Reading Retrieval Products). For other products, write a reader that returns the same table.

Transport error on the modeled column (cal.trajfoot.stat, cal.trans.err)

error_functions/

sim.transport_error on the particles of an unperturbed variant and a wind-error variant (Transport Error). X-STILT’s separate outerr_ tree becomes one more variant.

Modeled enhancement from an inventory (ff.trajfoot)

error_functions/, run.xco2ff.sim

foot.stilt.enhancement, particles.stilt.enhancement

Wind error statistics from radiosondes and surface stations

get.uverr, get.siguverr, cal.wind.err, grab.raob

variogram() and fit_variogram() estimate all four error settings. X-STILT estimates only siguverr and fixes the others. The met is sampled at the observations with arlmet.sample_points instead of one HYSPLIT run per sonde, and sondes come from IGRA2 through siphon. See Wind Error Statistics.

Mixing-height scaling for the vertical transport error (run_ver_err, zisf)

get.zierr

ziscale, one variant per factor in the same project (see the mixed-layer height section of Transport Error). X-STILT uses one constant factor and leaves the random sigzierr unset. PYSTILT supports both.

Background from trajectory endpoints (endpts.trajfoot, CarbonTracker)

background/

sim.background with any xarray field (Background)

Emission-error propagation (cal.emiss.err, footprint × inventory spread)

error_functions/

the same product as the enhancement, foot.stilt.enhancement(sigma). With a spatial correlation, use fips’s prior_obs_error (see the emission error section of Transport Error).

Satellite-derived plume background (compute_bg, forward trajectories)

background/

stilt.observations.plume_polygon() and stilt.observations.plume_background() on forward runs (Plume Background)

Runs you already have in X-STILT’s out/by-id folder are read with stilt.migration.read_stilt_r() (Coming From STILT-R). X-STILT weights the footprint by the averaging kernel and pressure weighting, but saves the particles before it does, so the particles read are unweighted. X-STILT keeps rslurm’s params.RDS in a folder named for the job inside its own working directory, not beside out/, so give the smooth_factor of run_xstilt.r to read the footprints: read_stilt_r("out/by-id", smooth_factor=1). stilt.migration.import_stilt_r() writes them into a project’s output directory the same way, with the X-STILT commit as version (Coming From STILT-R).

Where the methods differ#

On the same particles, a few steps give different numbers in PYSTILT and in X-STILT. Each row says what each one does.

Step

X-STILT

PYSTILT

Transport error across release levels (scale.dvar)

Fits a weighted line of the perturbed variance against the unperturbed variance through the levels where the variance rose, and scales every level’s variance with that line.

Uses each level’s variance difference as it is, with its sign (Lin and Gerbig’s equation 4), so the noise in it averages out over many receptors. noise says how large it is (Transport Error).

Particles kept in each level (pct)

Drops the particles above the 99th percentile of the enhancement.

Keeps every particle, as Lin and Gerbig do. percentile=0.99 gives X-STILT’s trimming.

Vertical correlation of the level errors (Lh)

356 m, an empirical mean length scale.

356 m by default (length_scale). None treats the levels as independent.

Emission error (cal.emiss.err)

Reports the fully correlated sum, a footprint times a sigma from the spread of several inventories.

The same sum, and also the root-sum-square for independent cells, which bounds the error from below. With a spatial correlation, fips’s prior_obs_error gives the value in between.

Pressure weighting (get.wgt.*.func)

Gives each particle the layer below its release pressure, from the next particle down (or the ground, for the lowest). A particle released at the surface gets almost no weight.

Gives each particle the slab centered on its release height, with edges halfway to its neighbors and the ground closing the lowest slab, because HYSPLIT places each particle at random inside its own slab. A particle’s slab is half a slab higher than in X-STILT (Particle Weighting (Transforms)).

Moving a workflow over#

  1. Write a reader that turns your product into a DataFrame with one row per sounding (see Your own instrument in Tutorial: A Satellite Column, Start To Finish).

  2. Group the soundings by overpass and select the ones to run with the helpers above.

  3. Build one receptor per row. For slant columns, use slant_points.

  4. Build the averaging-kernel table with averaging_kernel_table and save it in the project. Then list averaging_kernel (with table:) and pressure_weighting under transforms in config.yaml.