Skip to main content

Module wyoming

Module wyoming 

Source
Expand description

Weather-balloon soundings from the University of Wyoming’s radiosonde archive, turned into a SoundingProfile.

A radiosonde is an instrument package carried up by a weather balloon, usually at 00 and 12 UTC, from hundreds of stations worldwide. It measures pressure, temperature and humidity, and its drift gives the wind. The University of Wyoming serves the archive of these soundings. It is a measurement, not a forecast, but only at the station and the time of the flight, which can be a hundred kilometers and some hours from a launch.

A WyomingRequest names a station (its WMO number, such as 72364 for Santa Teresa, New Mexico) and the sounding’s nominal hour, and asks for the comma-separated text, one row per level, with these columns (among others) in these units:

columnunitread as
timeYYYY-MM-DD HH:MM:SS UTCthe release time, from the first row
latitude, longitudedegreesthe release point, from the first row
pressure_hPahPapressure
geopotential height_mgeopotential mheight above sea level
temperature_C°Ctemperature
relative humidity_%%over liquid water (the file has humidity wrt ice_% too)
wind direction_degree, wind speed_m/s°, m/sthe wind, the direction it blows from

A column in any other unit is refused, not converted. Two versions of most soundings are served (WyomingVersion): the coded message stations send (WMO FM 35, “TEMP”), with the standard pressure levels and the significant levels between them, about 200 rows; and the BUFR file (WMO’s binary format, as the archive decodes it), a row a second, about 6,000.

WyomingSounding::parse first finds the rows that fit. A row with a pressure, height and temperature fits the row before it when its height above that row is the layer’s thickness by the hypsometric equation (from the two pressures and virtual temperatures, WMO-No. 8 eqs. 12.17 and 12.18), within 5% (THICKNESS_SHARE) plus what rounding the pressures can move it plus 30 m (THICKNESS_SLACK_M). Rows are kept from the longest chain from the ground in which each row fits the one before it, skipping at most MAX_MISFITS rows at a time (rows with no temperature, or one out of bounds, can’t be checked, and aren’t counted); of equally long chains, the one whose layers miss by the smallest total share of their allowances. A row missing only its wind or humidity can be in the chain, so a gap in the wind doesn’t widen the layers checked. A row not in the chain is left out (DropReason::Thickness); in the recordings every row fits the row before it, to within 1 m beyond rounding. Then it keeps:

  • The ground, the first row: the pressure, temperature, humidity and wind at the station when the balloon was released. Nothing before it checks it, so a chain without it that beats every chain with it, starting among the rows it could reach, refuses the answer (WyomingError::GroundMisfit). Bad rows right after a good ground that fit the rows above them can beat it the same way, and refuse the answer: two BUFR rows 31 m high do it.
  • One row of each run of rows in the chain with the same pressure, the middle one. BUFR’s pressures are rounded to 0.1 hPa, and high up the balloon climbs tens of meters while the pressure falls that much, so runs of rows share a pressure; the rounded value is the pressure at about the middle of its run.
  • Each such row that lies above the last row kept, higher and at a lower pressure.

A row missing a value (the last row often has no wind) is dropped, and so is one with a value no air on Earth has (DropReason::OutOfRange lists the bounds). WyomingSounding::dropped lists each row left out, with its reason.

So a row with a bad pressure or height, a pressure missing a digit, say, is left out, not kept to hide the good rows after it; rows that fall or stay at one height, a balloon coming down, fit and are left out however many. More than MAX_MISFITS rows after the chain’s end refuse the answer (WyomingError::Misfit): the end, or all of them, are wrong (a block of heights 1 km off), or a long run of rows with no temperature leaves a layer too thick for its two ends’ temperatures to give. Not caught: a wrong wind, humidity or temperature (the check doesn’t use the wind, humidity moves it by a few percent, and on layers under about 100 m any temperature within the bounds fits), a height error within the allowance, a row whose pressure and height are both wrong yet fit each other, and a bad ground that fits the row after it or has only one row after it. A block of bad rows that fit their neighbours can be kept, and good rows beside them left out instead, no more than the block holds. A row, or a short block, kept a little too high leaves out the good rows just above it, which now lie below it: in the tests, at most 2 other levels of a coded message and 10 other rows of a BUFR file (8 for one row).

Heights are geopotential meters (the column says so), converted to geometric heights at the first row’s latitude with WMO-No. 8 (2023) eqs. 12.15 and 12.16 (hpr_atmos::profile::geometric_from_wmo_geopotential_m); the atmosphere page explains why. That is the latitude the profile uses for its hydrostatics. The balloon drifts; converting at the latitude it reached instead would move a height by about 0.8 m per degree of drift at 10 km, 2.5 m at 30 km. A relative humidity above 100%, which radiosondes report in cloud, is kept as recorded and taken as 100% in WyomingSounding::sounding, as the atmosphere’s decision record asks.

fetch asks a Client for the URL, so the answer comes from the cache when it can, and offline from the cache only; an answer that doesn’t parse is never cached. Show ATTRIBUTION (it is on every Fetched) wherever the sounding is shown.

How far to trust it: the profile gives back every row it keeps as recorded (the tests). A radiosonde’s own errors are small next to how far the air can change between the station and the launch, and nothing here measures that. The guide page says more.

use hpr_atmos::WindInterpolation;
use hpr_net::wyoming::WyomingSounding;

// Santa Teresa, New Mexico, 21 June 2025, 12 UTC: the coded message's 228 rows.
let body = include_bytes!("../tests/fixtures/replay/wyoming-72364-fm35.csv");
let sounding = WyomingSounding::parse(body)?;
assert_eq!(sounding.levels.len(), 227); // the last row has no wind
let air = sounding.sounding(WindInterpolation::SpeedDirection)?;
let at_5_km = air.sample(5_000.0)?.air;
// Between the rows at 570 hPa (4,852 m) and 557 hPa (5,035 m) of geopotential height.
assert!((at_5_km.pressure_pa - 55_950.0).abs() < 100.0);

Structs§

DroppedLevel
A row left out of the profile, and why.
WyomingLevel
One level of a sounding, as recorded, in SI units.
WyomingRequest
What to ask the archive for: a station, the sounding’s nominal hour and its version.
WyomingSounding
A sounding read from the archive’s answer: the ground and the levels above it.

Enums§

DropReason
Why a row was left out of the profile.
WyomingError
Why a Wyoming request or answer was refused.
WyomingVersion
Which version of a sounding to ask for.

Constants§

ATTRIBUTION
The credit shown wherever a sounding is shown. The archive states no license; the soundings are the stations’ observations, which weather services exchange freely (WMO Resolution 40).
ENDPOINT
The archive’s address.
MAX_MISFITS
The most rows with a pressure, height and temperature within the bounds the chain of rows that fit may skip at a time, and the most that may follow its end. More after its end means the end, or all of them, are wrong (a block of heights 1 km off), and the answer is refused. In a BUFR file 10 rows are about 10 s of the balloon’s climb, some 50 m; in a coded message they can span kilometers.
MAX_ROWS
The most rows an answer may have. The archive’s BUFR files have about 6,000.
SETTLED_TTL_S
How long an answer fetched after its sounding settled stays fresh, s: 30 days.
SETTLE_S
How long after its nominal hour a sounding may still be filling in, s: a day. The archive’s copy can grow for some hours after the flight, as a station’s later messages arrive.
THICKNESS_SHARE
The share of a layer’s hypsometric thickness a row’s height may miss it by, beyond rounding and THICKNESS_SLACK_M: 5%, for a layer whose inner rows have no temperature, which the mean of its two ends’ temperatures gives less well. A judgment, not a measurement: no row in the recordings needs any share.
THICKNESS_SLACK_M
The meters a row’s height may miss its layer’s thickness by, beyond the share and the pressures’ rounding: 30 m. A coded message’s heights from 500 hPa up are rounded to 10 m; a height 30 m off misplaces its level by as much as a pressure error of 0.33% to 0.55% (the air’s scale height, the climb over which pressure falls by a factor of e, is 5.5 to 9 km), so the check is for gross errors, not for these.
YOUNG_TTL_S
How long an answer stays fresh while its sounding may still be filling in, s: an hour.

Functions§

fetch
Fetches request through client and reads it.