WetBulbTracker — Scientific Methodology

A complete specification of every heat-stress metric, algorithm, physical constant, and adjustment used by WetBulbTracker.com.

Last updated: July 2026 · Engine version: Liljegren WBGT (physics epoch 2026-07-alb020)

This document is intended for scientists, clinicians, safety officers, and engineers who need to audit or reproduce the numbers shown in the app. Every formula below is implemented verbatim in the open metrics engine; source-file references are given for each section so the code and this document can be cross-checked line by line.


1. Scope and conventions

  • Internal units. Every quantity is computed and stored in SI / metric units: temperature in degrees Celsius (°C), wind in meters per second (m/s), pressure in hectopascals (hPa), shortwave irradiance in watts per square metre (W/m²). Imperial conversion happens only at the display layer, so the calculation engine has a single source of truth.
  • Display conversion. °F = °C · 9/5 + 32; mph = (m/s) · 2.236936; km/h = (m/s) · 3.6. The default display unit is chosen from the location's country (°F for the United States, °C elsewhere) and can be overridden.
  • Determinism. The metrics engine is a set of pure functions: given the same raw inputs it always returns the same outputs. It performs no I/O and has no dependency on the UI framework.
  • Reference temperature for thermodynamics. Energy-balance solvers work in Kelvin (K = °C + 273.15) and pascals (Pa = hPa · 100) internally, converting back to °C for the public result.

Source: src/lib/units.ts, src/lib/metrics/index.ts.


2. Data sources and pipeline

PurposeProviderEndpoint / dataset
Current & forecast weatherOpen-Meteoapi.open-meteo.com/v1/forecast
Historical reanalysisOpen-Meteo (ERA5)archive-api.open-meteo.com/v1/archive
Air quality (US AQI)Open-Meteoair-quality-api.open-meteo.com/v1/air-quality
Geocoding (search)Open-Meteogeocoding-api.open-meteo.com/v1/search
Reverse geocoding (map clicks)BigDataCloudreverse-geocode-client

Raw weather fields requested (current conditions): temperature_2m, relative_humidity_2m, apparent_temperature, is_day, wind_speed_10m, surface_pressure, shortwave_radiation, dew_point_2m, uv_index, cloud_cover, precipitation. Wind is requested in m/s. Open-Meteo's underlying model is primarily ECMWF/national NWP blends at roughly 1–11 km resolution.

Freshness. Current conditions are cached for 15 minutes server-side; the forecast and historical archive for 1 hour and 24 hours respectively. A failed upstream request is retried once without cache before erroring.

Solar instant. For "current conditions" the solar geometry (§4) is evaluated at the present UTC instant; the sun moves slowly enough that the ≤15-minute data lag is immaterial. For the forecast strip and map time scrubber, each hour is evaluated at its own true UTC instant.

Source: src/lib/openmeteo.ts, src/app/api/conditions/route.ts.

2.1 Input variables

SymbolMeaningFieldUnit
TaAir (dry-bulb) temperature at 2 mtemperature_2m°C
RHRelative humidity at 2 mrelative_humidity_2m%
vWind speed at 10 mwind_speed_10mm/s
SGlobal horizontal shortwave irradianceshortwave_radiationW/m²
PsSurface pressuresurface_pressurehPa
TdDew point (native, when present)dew_point_2m°C
AT*Apparent temperature (native, when present)apparent_temperature°C

3. Metric overview

MetricApp labelMethodCaptures
Wet Bulb Globe TemperatureHeat StressLiljegren et al. (2008)T, RH, wind, sun / shade (§5.8)
Heat IndexHeat IndexNWS Rothfusz regressionT, RH (shade)
Apparent TemperatureReal FeelBoM / SteadmanT, RH, wind
Wet-bulb temperatureWet BulbStull (2011)T, RH (thermodynamic)
Dew pointDew PtMagnus-TetensT, RH (absolute moisture)
Air temperature (dry-bulb)Air TempDirect readingT only (cool→warm reference)

WBGT is the primary metric because it is the only one that incorporates solar radiation and is the recognized standard for occupational, athletic, and military heat-stress management.


4. Solar geometry

The Liljegren WBGT model needs two solar quantities: the cosine of the solar zenith angle and the fraction of incoming shortwave that arrives as a direct beam. Source: src/lib/solar.ts.

4.1 Cosine of the solar zenith angle (NOAA equations)

Let doy be the day of year (Jan 1 = 1) and h the UTC time in fractional hours. Define the fractional-year angle γ (radians):

γ = (2π / 365) · (doy − 1 + (h − 12) / 24)

Equation of time (minutes):

EqTime = 229.18 · ( 0.000075
                   + 0.001868·cos γ  − 0.032077·sin γ
                   − 0.014615·cos 2γ − 0.040849·sin 2γ )

Solar declination δ (radians):

δ = 0.006918 − 0.399912·cos γ  + 0.070257·sin γ
              − 0.006758·cos 2γ + 0.000907·sin 2γ
              − 0.002697·cos 3γ + 0.001480·sin 3γ

True solar time and hour angle (lng east-positive degrees):

TST       = h·60 + EqTime + 4·lng           (minutes)
HourAngle = (TST / 4 − 180) · π/180         (radians)

Cosine of the zenith angle (φ = latitude):

cos Z = sin φ · sin δ + cos φ · cos δ · cos(HourAngle)      (clamped to [−1, 1])

cos Z > 0 means the sun is above the horizon.

4.2 Direct-beam fraction (Liljegren clearness index)

Top-of-atmosphere irradiance on a horizontal surface, including the Earth-Sun distance correction (S₀ = 1367 W/m²):

TOA = S₀ · (1 + 0.033·cos(2π(doy − 1)/365)) · cos Z

Clearness index and direct fraction:

Kt   = min(1, S / TOA)
fdir = exp(3 − 1.34·Kt − 1.65/Kt)        clamped to [0, 0.9]

fdir = 0 whenever the sun is below the horizon (cos Z ≤ 0) or S ≤ 0.


5. Primary metric — WBGT (Liljegren et al., 2008)

WBGT combines three temperatures:

WBGT (outdoor, in sun) = 0.7·Tnwb + 0.2·Tg + 0.1·Ta
WBGT (shade / indoor)  = 0.7·Tnwb + 0.3·Ta

where Tnwb is the natural wet-bulb temperature, Tg the black-globe temperature, and Ta the dry-bulb (air) temperature. The app uses the outdoor (in sun) form, solving Tnwb and Tg from two coupled radiative-convective energy balances by iteration.

This is a faithful port of the PyWBGT Cython implementation (github.com/QINQINKONG/PyWBGT), itself a port of Liljegren's original C code. Constants and equations are unchanged; the only deviation is the root-finder (robust bisection here versus Brent's method in the reference — both converge to the same root). Source: src/lib/metrics/liljegren.ts.

5.1 Physical constants

ConstantSymbolValueUnits
Molecular weight of dry airMAIR28.97g/mol
Molecular weight of water vaporMH2O18.015g/mol
Universal gas constantRGAS8314.34J/(kmol·K)
Specific heat of airCP1003.5J/(kg·K)
Stefan–Boltzmann constantσ5.6696×10⁻⁸W/(m²·K⁴)
Globe diameterDglobe0.0508m
Globe emissivityεg0.95
Globe albedoαg0.05
Wick emissivityεwick0.95
Wick albedoαwick0.4
Wick diameterDwick0.007m
Wick lengthLwick0.0254m
Surface albedoαsfc0.20

Derived: RATIO = CP·MAIR/MH2O, RAIR = RGAS/MAIR, Pr = CP / (CP + 1.25·RAIR) (Prandtl number).

5.2 Thermophysical helper functions

Air dynamic viscosity μ(T) [kg/(m·s)], with Ω = 1.2945 − T/1141.17647:

μ(T) = 2.6693×10⁻⁶ · √(28.97·T) / (13.082689 · Ω)

Thermal conductivity: k(T) = (CP + 1.25·RAIR) · μ(T).

Saturation vapor pressure (Pa), Buck-type with a pressure-enhancement factor; separate branches over water (T > 273.15 K) and ice:

water:  es = 611.21 · exp(17.502·(T−273.15)/(T−32.18)) · (1.0007 + 3.46×10⁻⁶·Ps_hPa)
ice:    es = 611.15 · exp(22.452·(T−273.15)/(T− 0.60)) · (1.0003 + 4.18×10⁻⁶·Ps_hPa)

Atmospheric emissivity, with vapor pressure e in hPa:

e      = RH·0.01 · (es·0.01)
εatm   = 0.575 · e^0.143

Water-vapor diffusivity in air:

D(T, Ps) = 2.471773765×10⁻⁵ · (T·0.00342105637)^2.334 / (Ps/101325)

Latent heat of vaporisation: λ(T) = 1665134.5 + 2370·T.

Convective heat-transfer coefficients (ρ = Ps/(RAIR·T)):

Sphere   (globe):  Re = v·ρ·Dglobe/μ;  Nu = 2 + 0.6·Re^0.5·Pr^0.3333;  h = Nu·k/Dglobe
Cylinder (wick):   Re = v·ρ·Dwick /μ;  Nu = 0.281·Re^0.6·Pr^0.44;       h = Nu·k/Dwick

5.3 Black-globe energy balance

Direct-beam geometry term (0 when fdir = 0 or cos Z ≤ 0):

directTerm = (0.5/cos Z − 1) · fdir

Radiative constant:

C0 = 0.5·(1 + εatm)·Ta⁴
   + (1 / (2·εg·σ)) · S·(1 − αg)·(1 + directTerm + αsfc)

Globe temperature Tg (K) is the root of, with h the sphere coefficient evaluated at the film temperature ½(Ta + Tg):

C0 − (1/(εg·σ))·h·(Tg − Ta) − Tg⁴ = 0          bracket [Ta−50, Ta+90]

5.4 Natural wet-bulb energy balance

eair       = RH·0.01 · es(Ta)
directTerm = ( tan(arccos(min(1, cos Z)))/π + Dwick/(4·Lwick) ) · fdir
D4         = εwick·0.5·σ·Ta⁴·(εatm + 1)
           + (1 − αwick)·S·( (1 + Dwick/(4·Lwick))·(1 − fdir) + directTerm + αsfc )

Natural wet-bulb temperature Tnwb (K) is the root of, with Tref = ½(Ta+Tw), Sc = μ(Tref)/(ρ·D(Tref)) the Schmidt number, h the cylinder coefficient at Tref, and Fatm = D4 − εwick·σ·Tw⁴:

Ta − (λ(Tref)/RATIO)·((es(Tw) − eair)/(Ps − es(Tw)))·(Pr/Sc)^0.56 + Fatm/h − Tw = 0

bracket [Ta − (100 − RH)/5 − 50, min(Ta + 70, 340)].

5.5 Adjustments and solver details

  • Wind height correction & low-wind floor. Inputs are 10 m winds; the model expects ~2 m. Converted with the power law v₂ = v₁₀·(2/10)^0.2, then floored at 1.5 m/s. The Liljegren reference floors at 0.13 m/s, but near-calm air makes the globe and wet-wick energy balances hypersensitive and over-reads heat stress: validated against the NWS published WBGT across CONUS, below ~1 m/s we ran +5–8 °C high (a false "Extreme" on mild, sunny, dead-calm days) while NWS stayed put, with excellent agreement at a real breeze. The 1.5 m/s floor — a defensible minimum realistic ventilation at 2 m — removes those calm-air spikes while still never reading below NWS. The smaller residual high bias at moderate wind is handled by the conditions-based bias correction, not this floor.
  • Humidity clamp. RH is clamped to [1, 100] %.
  • Irradiance / geometry guards. S is floored at 0; fdir is forced to 0 when the sun is below the horizon.
  • Root finder. Bisection over the brackets above, tolerance 1×10⁻⁴ K, up to 80 iterations. If either balance fails to bracket a root (no sign change), the engine falls back to the simplified estimate (§5.7) rather than returning a bad number.

5.6 Validation status

The Liljegren method is the validated reference model and is reported to be more accurate than handheld WBGT meters (Duke Nicholas Institute, 2024).

Cross-validation against the National Weather Service. An automated suite (npm run validate:wbgt) compares this implementation against the NWS's published WBGT (api.weather.gov gridpoint forecasts) at eight CONUS cities for the next forecast hour. Representative run (June 9 2026, 23:00 UTC — a hot late-afternoon across the US):

StationNWS (°C)Ours (°C)Δ (°C)
Phoenix, AZ27.226.5−0.77
Dallas, TX27.830.6+2.84
Miami, FL26.727.7+1.07
Atlanta, GA24.427.1+2.64
St. Louis, MO30.030.8+0.75
Washington, DC23.923.3−0.57
New Orleans, LA27.828.3+0.50
Kansas City, MO28.929.8+0.91

In this June 2026 eight-station snapshot, mean |Δ| = 1.26 °C — within the ±1.5 °C target, with six of eight stations within ±1.1 °C. Treat this as a dated snapshot, not a standing guarantee: the figure moves day to day with conditions and station mix, and on some days it exceeds ±1.5 °C. A live version of this comparison runs continuously at [/validation](/validation) (and the public /api/validation endpoint) — that live value, not the number above, is the current source of truth. Note the comparison conflates method and input differences: NWS drives its WBGT from the National Blend of Models while this app uses Open-Meteo's model blend, so part of each Δ (especially at hours with uncertain afternoon convection, e.g. the Dallas/Atlanta rows) is the two systems disagreeing about clouds and irradiance, not about the WBGT physics. The suite asserts a mean |Δ| ≤ 1.5 °C and per-station |Δ| ≤ 3.5 °C and can be re-run at any time.

Retained accuracy corpus. Beyond the live snapshot, a scheduled collector records each comparison — the full input feature vector, our WBGT (sun and shade), and the NWS reference — into a growing, retained dataset. Because the inputs are stored (not just the final number), this corpus lets us measure systematic bias over time, correct it, and refine the methods, and it remains useful even as the models evolve. An aggregate, no-personal-data readout (total records and rolling mean bias / mean absolute error) is surfaced on the validation dashboard once enough has accrued.

Physical sanity checks also pass: dry desert heat (e.g. Phoenix) reads moderate WBGT, humid tropical nights (e.g. Miami) read elevated WBGT, and in direct sun Tnwb < WBGT < Tg, with Tg rising sharply under high irradiance and low wind.

5.7 Simplified fallback (only when geometry/pressure are unavailable)

When cos Z, fdir, or surface pressure are missing, WBGT uses a closed-form estimate: a Stull wet bulb (§7) for Tnwb and a parameterised globe term:

Tg ≈ Ta + min(25, 0.024·S / √max(0.5, v))
WBGT = 0.7·Tnwb_Stull + 0.2·Tg + 0.1·Ta

This is directionally correct but not validated to the ±1.5 °C target; in normal operation (with full solar geometry) the Liljegren path is always used.

5.8 Sun vs shade (microclimate)

WBGT is acutely sensitive to direct solar load — the same air can be safe under a tree and dangerous on open pavement. To make that difference explicit, the conditions API returns a second WBGT computed in full shade alongside the in-sun value, and the app lets you toggle between them.

The shade value is the identical Liljegren energy balance (§5.3–5.4) re-run with the shortwave terms removed:

S = 0,  fdir = 0   →   directTerm = 0  in both the globe and wick balances

With no beam or diffuse irradiance the black globe relaxes toward air temperature and the natural wet-bulb term loses its radiative gain, so the result is the WBGT a shaded thermometer would read under the same air temperature, humidity, wind, and pressure. When pressure is unavailable the shade value falls back to the closed form WBGT = 0.7·Tnwb_Stull + 0.3·Ta (no globe term), consistent with the standard indoor/shade WBGT definition.

The sun-minus-shade gap is surfaced directly on the card (e.g. "Direct sun adds 4.9 °C of heat stress versus full shade"). It is largest under high irradiance and light wind, and collapses to zero at night — a physically expected result, since with S = 0 the in-sun and shade balances become the same equation. The shade value is then re-classified against the same WBGT scale (§11.1), so the displayed tier, color, and advice follow the shade reading.

This is a microclimate estimate, not a substitute for measuring your specific spot: real shade also depends on ground albedo, sky-view fraction, nearby hot surfaces, and ventilation, which a point model cannot see.

5.9 Bias correction (data flywheel)

The retained corpus (§5.6) lets us not only measure systematic bias but correct it — and the corpus showed the bias is conditions-dependent, not constant. Across ~1,000 compared samples the global mean residual is ~0 °C, but that average hides real structure: our in-sun WBGT runs roughly +1.4 °C warm in strong sun and −1.4 °C cool at night, with the warm bias worst in calm air (up to ~+3–4 °C in calm, intense sun — the regime that produced the occasional false "Extreme"). A single global offset is therefore useless (it is ~0); the correction has to be keyed on conditions.

So the displayed WBGT is corrected by a small, learned correction surface over (solar irradiance × wind speed) — the two variables that drive the residual. Both exist in the input for every point on Earth, so a surface learned at the U.S. reference stations generalizes anywhere with the same conditions. The correction is computed per point and bilinearly interpolated between anchor cells so it stays continuous (no banding on the map). Strict guardrails keep it honest:

  • Direction. Mean residual is ours − reference; a positive bias (we run warm) yields a negative correction, and vice-versa. In strong sun the surface subtracts ~1–2 °C; at night it adds ~1.3 °C.
  • Shrinkage and clamping. Each (solar, wind) cell is shrunk toward its solar-trend by how much data supports it — a thin, noisy cell borrows from the well-supported trend instead of swinging readings — and its magnitude is clamped to ±3 °C.
  • Minimum data. No correction is applied until enough compared samples have accrued; below that threshold the correction is exactly zero.
  • Proven to generalize (self-gating). The surface is applied only if it lowers error under day-blocked cross-validation — trained on all other calendar days and tested on a held-out day, by a margin of at least 5 %. We block by day rather than by station because reference stations share synoptic weather days, so a leave-one-station-out test leaves the held-out day's pattern in the training set through the other stations and reports an optimistic gain; blocking by day removes that temporal leakage and yields the honest, more-conservative number. The live held-out figures are shown on the /validation page; if the correction ever stops clearing the margin, it switches itself off.
  • Trained per physics epoch. The correction trains only on residuals gathered under the current raw-physics version. When the engine's physics changes (e.g. the §5.1 surface-albedo correction), residuals measured under the old physics are excluded, so a fixed bias can't be "corrected" twice — the correction simply falls back to the improved raw model until it re-accumulates.
  • Applied consistently. The same per-point correction is applied across all user-facing in-sun WBGT — the current reading, the forecast, the map, the city pages, and heat alerts — so the corrected value (the product's core output) is the same everywhere. The shade figure is served uncorrected: the correction surface has no daytime-shade reference (its solar=0 column is night-dominated), so applying it to daytime shade would add an unfounded offset.
  • No tail-chasing. It is applied only to that user-facing output. The collector and the validation suite always use the raw, uncorrected engine, so the flywheel keeps measuring the model's true bias rather than the bias of an already-corrected number.

The conditions breakdown is public at /api/bias/segments, and the correction surface with its cross-validation at /api/bias/validate; when a correction is in effect it is also surfaced per reading in the conditions API (biasCorrection, °C). A fully learned model — a regression on the complete feature vector (adding humidity, cloud, time of day, season) — is the natural next refinement (§7).


6. Heat Index (NWS Rothfusz regression)

The familiar US "feels like in the shade" number. Defined in °F; the engine converts in and out so the rest of the pipeline stays in °C. Source: src/lib/metrics/heatindex.ts.

A Steadman blend is always computed first (T in °F, R = RH %):

HI = 0.5·(T + 61 + (T − 68)·1.2 + R·0.094)

If the average (HI + T)/2 ≥ 80 °F, the full Rothfusz regression replaces it:

HI = −42.379
   + 2.04901523·T   + 10.14333127·R
   − 0.22475541·T·R − 0.00683783·T²
   − 0.05481717·R²  + 0.00122874·T²·R
   + 0.00085282·T·R² − 0.00000199·T²·R²

with the two standard corrections:

if R < 13 and 80 ≤ T ≤ 112:   HI −= ((13 − R)/4)·√((17 − |T − 95|)/17)
if R > 85 and 80 ≤ T ≤  87:   HI += ((R − 85)/10)·((87 − T)/5)

The result is converted back to °C.


7. Wet-bulb temperature (Stull, 2011)

A fast psychrometric (thermodynamic) wet-bulb approximation, valid near sea-level pressure for roughly T ∈ [−20, 50] °C and RH ∈ [5, 99] %, accurate to about ±0.3 °C. RH is clamped to [1, 100] %. Source: src/lib/metrics/wetbulb.ts.

Tw = T·arctan(0.151977·√(RH + 8.313659))
   + arctan(T + RH) − arctan(RH − 1.676331)
   + 0.00391838·RH^1.5·arctan(0.023101·RH)
   − 4.686035

Note: this thermodynamic wet bulb does not include radiation or wind, so in direct sun it slightly underestimates the natural wet bulb. The app surfaces it as its own "Wet Bulb" metric and uses it as the Tnwb term only in the simplified WBGT fallback (§5.7); the primary WBGT uses the full Liljegren natural wet-bulb solver.


8. Apparent Temperature / "Real Feel" (BoM, Steadman)

The Australian Bureau of Meteorology apparent-temperature formulation. Unlike Heat Index it includes the cooling effect of wind, making it the better everyday "real feel". Water-vapor pressure e in hPa, wind v in m/s. Source: src/lib/metrics/apparent.ts.

e   = (RH/100) · 6.105 · exp(17.27·Ta / (237.7 + Ta))
AT  = Ta + 0.33·e − 0.70·v − 4.00

When Open-Meteo supplies a native apparent_temperature, that value is used in preference to this formula; otherwise the formula above is computed.


9. Dew point (Magnus-Tetens)

Coefficients from Alduchov & Eskridge (1996); accurate to about ±0.4 °C for 0 < T < 60 °C. RH clamped to [1, 100] %. a = 17.625, b = 243.04. Source: src/lib/metrics/dewpoint.ts.

γ  = ln(RH/100) + (a·Ta)/(b + Ta)
Td = (b·γ) / (a − γ)

The provider's native dew_point_2m is preferred when present.


10. Supporting context fields

These are displayed for context and are not inputs to the heat-stress calculations:

  • UV Index (uv_index) — bucketed Low / Moderate / High / Very High / Extreme at 3 / 6 / 8 / 11.
  • Air Quality (us_aqi) — US AQI, bucketed Good / Moderate / Sensitive / Unhealthy / Very Bad / Hazardous at 50 / 100 / 150 / 200 / 300.
  • Cloud cover (cloud_cover, %), surface pressure (surface_pressure, hPa), precipitation (precipitation, mm; shown in inches when imperial).

11. Classification scales

All thresholds are stored in °C (engine units); °F equivalents are given here for convenience. Bands share a common green → yellow → orange → red → purple → black severity gradient so that color means the same thing across metrics. Source: src/lib/metrics/scales.ts.

11.1 WBGT — "Heat Stress" (primary)

TierFrom (°C)From (°F)
Safe< 18< 64.4
Caution1864.4
Moderate2373.4
High2882.4
Extreme3289.6
Lethal3595.0

11.2 Wet-bulb temperature

TierFrom (°C)From (°F)
Safe< 25< 77.0
Uncomfortable2577.0
Stressful2882.4
Dangerous3187.8
Severe3391.4
Unsurvivable3595.0

The ~35 °C wet-bulb survivability limit is the temperature above which a healthy person can no longer shed metabolic heat by sweating, even at rest in shade.

11.3 Heat Index

TierFrom (°C)From (°F)
Comfortable< 27< 80.6
Caution2780.6
Extreme Caution3289.6
Danger39102.2
Extreme Danger51123.8

11.4 Real Feel (apparent temperature)

TierFrom (°C)From (°F)
Cold< 10< 50.0
Cool1050.0
Warm2068.0
Hot2780.6
Very Hot3289.6
Dangerous39102.2

11.5 Dew point (comfort)

TierFrom (°C)From (°F)
Dry< 10< 50.0
Comfortable1050.0
Slightly Humid1355.4
Humid1660.8
Very Humid1864.4
Oppressive2169.8
Miserable2475.2

11.6 Unified advisory

The card shows one persistent heat-danger advisory: the most severe guidance across the three monotonic heat-stress metrics (WBGT, Heat Index, Wet Bulb), independent of which metric the user is viewing. Severity is ranked by band index and mapped to the WBGT advisory ladder:

LevelAdvice
CautionLight precautions for intense activity. Keep water handy.
ModerateReduce exertion and hydrate frequently. Take regular shade breaks.
HighLimit outdoor exertion. Drink water every 15 minutes and rest in shade.
ExtremeDangerous. Outdoor work and sport are not recommended.
LethalSurvival limit. The body cannot cool itself — stay indoors and cool.

Dew point (a comfort scale) and Real Feel (which has cold bands) are excluded from the unified advisory.


12. "This day in history"

Places today's heat in climatological context using ERA5 reanalysis. Source: src/app/api/history/route.ts, src/lib/openmeteo.ts.

  • Variable. Daily maximum apparent temperature (apparent_temperature_max), a humidity-aware, precomputed daily aggregate — chosen so decades of context come from a single cheap request rather than recomputing hourly WBGT.
  • Window. A ±3-day window around today's calendar day, across the most recent 35 complete years.
  • Per-year peak. For each year, the maximum daily feels-like high within the window. Window days are grouped by climatological season-year so a window that straddles 1 January stays in one group (correct for Southern-Hemisphere summers).
  • Outputs. Percentile rank of today's forecast feels-like high among the per-year peaks; the climatological normal (mean of the peaks); the all-time record (value and year); and the full per-year series for the sparkline.
  • Today's value. Today's forecast apparent_temperature_max.

If fewer than five valid years are available, the panel hides itself.


13. Map visualization (interpolation)

The heat map is a continuous field built from point samples. For a viewport the app samples a grid of points (current conditions, or a forecast hour from the time scrubber); at low zoom it uses an always-on 10°-aligned global grid (37 × 17 = 629 points). Sample nodes snap to a fixed absolute lat/lng lattice with a discrete halving step ladder (10° → 5° → … → ~0.01°), so node positions are stable across pans and zooming refines onto an aligned subgrid. All layers sample at a shared 15-minute time bucket: solar geometry is evaluated at the same instant for every zoom level, so the field is consistent across views and rolls over together. Each sampled point is run through the same metrics engine, then the grid is bilinearly interpolated per pixel and colored along the metric's continuous gradient; ocean / missing nodes fade to transparent so the field flows seamlessly. This is a visualization step only and does not alter the per-point metric values. Source: src/components/HeatMap.tsx, src/app/api/grid/route.ts, src/app/api/global/route.ts.


14. Limitations and assumptions

  • Inputs are NWP model output, not in-situ observations; local microclimate (pavement, shade, buildings) is not captured.
  • The Liljegren surface albedo (0.20, representative of vegetated/urban CONUS) and the assumption of a standing person in the open are fixed; true WBGT varies with ground cover and posture.
  • Shortwave radiation is global horizontal; the direct/diffuse split is inferred from a clearness-index parameterisation, not measured.
  • Stull wet bulb assumes near-sea-level pressure.
  • Historical context uses daily apparent-temperature maxima (not WBGT) for tractability, and ERA5 has a coarser grid than the live forecast.
  • The simplified WBGT fallback (§5.7) is not validated and is used only when solar geometry or pressure are unavailable.

15. Personalization ("safe for me")

The objective WBGT is universal and is never altered by personalization. To make it actionable for an individual, the app computes a separate personal-risk readout shown alongside the objective number. Source: src/lib/personalize.ts.

The person optionally provides a few heat-risk factors. Each maps to a small °C-equivalent "personal heat load" added to the objective WBGT to form an effective value, which is then classified on the same WBGT scale (§11.1) — so the "Your risk" tier and color mean the same thing as everywhere else.

FactorSetting → load (°C-equivalent)
Age bandchild +1.0 · adult +0 · 65+ +1.5
Heat acclimatizationyes +0 · unsure +0.5 · no +1.5
Activity / exertionresting +0 · light +1.5 · heavy +3.0
Health sensitivities+1.5 for one, +0.5 each additional, capped at +2.5

The total load is clamped to +6 °C.

On the scientific basis (and its honest limits). There is no single published table that converts "age" or "a heart condition" into a WBGT offset. What the literature does establish is the underlying physiology and the practice of adjusting heat-stress limits for these factors. We translate that established guidance into one intuitive °C-equivalent readout, calibrated conservatively:

  • Exertion. Heat-stress standards do not use a single WBGT threshold — they lower the safe limit (or shorten the work/rest ratio) as metabolic heat production rises. ISO 7243 sets WBGT limits by metabolic rate, and the U.S. ACGIH/NIOSH action limits drop by roughly 4–6 °C WBGT from rest to heavy work [10][11][12]. Our resting → light → heavy loads (0 / +1.5 / +3.0) sit well inside that established range.
  • Heat acclimatization. Acclimatized individuals tolerate substantially higher heat strain; NIOSH and ACGIH publish separate, lower limits for the unacclimatized, and acclimatization is among the strongest modifiable protective adaptations [11][12][13]. Hence the +1.5 °C for "not acclimatized."
  • Age. Older adults have blunted thermoregulation (reduced skin blood flow and sweating) [14]; children have a higher surface-area-to-mass ratio and lower sweat capacity [15]. Both are recognized heat-vulnerable groups [11].
  • Health sensitivities. Cardiovascular and respiratory disease, pregnancy, and many common medications (e.g. diuretics, anticholinergics, some psychiatric drugs) impair heat dissipation or fluid balance and raise heat-illness risk [11][16][17]. We apply a conservative, capped load and never infer or display any specific condition.

This "objective hazard × personal vulnerability" framing mirrors public-health tools such as the U.S. CDC/NWS HeatRisk index [18]. Our specific weights are deliberately conservative starting points, not clinical thresholds, and are a prime target for data-driven refinement as the accuracy flywheel (§5.6) and the literature inform them.

This is guidance, not medical advice or a diagnosis. Inputs are optional and self-reported, stored on the device and synced to the account only when signed in, and can be cleared at any time.


16. Where this is headed (roadmap)

Accuracy here is a continuous commitment, not a fixed claim. Three directions, all powered by the retained corpus (§5.6):

  1. A fully learned bias-correction model. The conditions-based correction is already live (§5.9): a (solar × wind) surface, cross-validated to cut held-out error ~31 %. The staged rollout was global offset → segmented surface → a learned model, and that last step is the open one — a regression (gradient-boosted trees or a small network) on the complete feature vector stored with each sample (adding humidity, cloud cover, time of day, and season) to squeeze the residual further. Every candidate stays guarded by shrinkage, magnitude clamps, and held-out cross-validation, so a richer model ships only if it provably generalizes to stations it never trained on.
  1. Multi-source ground truth. The NWS reference is itself a model, so agreement measures method+input agreement, not absolute truth. The corpus schema carries a ref_source field so additional references slot in and are weighted by reliability: physical sensors (mesonets, handheld WBGT meters, a small owned network) > ERA5 reanalysis (global coverage, extends the comparison outside the US) > forecast models. Because raw inputs are retained, history can be re-graded as better truth arrives.
  1. Microclimate refinement. Sun vs. shade (§5.8) is the first of several layers that move from the model's open-surface, ~km-scale grid toward the meter-scale reality: surface type and albedo (e.g. hot asphalt vs. grass, which feed the globe energy balance directly), the urban heat island, sky-view factor in urban canyons, tree canopy, and wind sheltering — each derivable from land-cover and terrain data and, ultimately, calibrated against the corpus.

Full detail and guardrails are in the project roadmap (docs/roadmap.md).


17. References

  1. Liljegren, J. C., Carhart, R. A., Lawday, P., Tschopp, S., & Sharp, R. (2008). Modeling the Wet Bulb Globe Temperature Using Standard Meteorological Measurements. Journal of Occupational and Environmental Hygiene, 5(10), 645–655.
  2. Stull, R. (2011). Wet-Bulb Temperature from Relative Humidity and Air Temperature. Journal of Applied Meteorology and Climatology, 50(11), 2267–2269.
  3. Rothfusz, L. P. (1990). The Heat Index Equation. NWS Southern Region Technical Attachment SR/SSD 90-23.
  4. Steadman, R. G. (1984). A Universal Scale of Apparent Temperature. Journal of Climate and Applied Meteorology, 23(12), 1674–1687. (BoM apparent temperature.)
  5. Alduchov, O. A., & Eskridge, R. E. (1996). Improved Magnus Form Approximation of Saturation Vapor Pressure. Journal of Applied Meteorology, 35(4), 601–609.
  6. NOAA Global Monitoring Laboratory. Solar Position Calculator equations (general solar geometry).
  7. Kong, Q., & Huber, M. PyWBGT — reference implementation of the Liljegren WBGT model. github.com/QINQINKONG/PyWBGT
  8. Hersbach, H., et al. (2020). The ERA5 global reanalysis. Quarterly Journal of the Royal Meteorological Society, 146(730), 1999–2049.
  9. Open-Meteo. Open-Meteo Weather, Air-Quality, and Historical Reanalysis APIs. open-meteo.com
  10. International Organization for Standardization (2017). ISO 7243:2017 — Ergonomics of the thermal environment: Assessment of heat stress using the WBGT (wet bulb globe temperature) index.
  11. National Institute for Occupational Safety and Health (2016). Criteria for a Recommended Standard: Occupational Exposure to Heat and Hot Environments. DHHS (NIOSH) Publication No. 2016-106.
  12. American Conference of Governmental Industrial Hygienists (ACGIH). Heat Stress and Strain: TLV® Physical Agents documentation (WBGT screening limits by workload and acclimatization state).
  13. Périard, J. D., Racinais, S., & Sawka, M. N. (2015). Adaptations and mechanisms of human heat acclimation. Scandinavian Journal of Medicine & Science in Sports, 25(S1), 20–38.
  14. Kenney, W. L., & Munce, T. A. (2003). Invited Review: Aging and human temperature regulation. Journal of Applied Physiology, 95(6), 2598–2603.
  15. Falk, B., & Dotan, R. (2008). Children's thermoregulation during exercise in the heat: a revisit. Applied Physiology, Nutrition, and Metabolism, 33(2), 420–427.
  16. Westaway, K., Frank, O., Husband, A., et al. (2015). Medicines can affect thermoregulation and accentuate the risk of dehydration and heat-related illness during hot weather. Journal of Clinical Pharmacy and Therapeutics, 40(4), 363–367.
  17. Ravanelli, N., Casasola, W., English, T., Edwards, K. M., & Jay, O. (2019). Heat stress and fetal risk: environmental limits for exercise and passive heat stress during pregnancy — a systematic review. British Journal of Sports Medicine, 53(13), 799–805.
  18. U.S. Centers for Disease Control and Prevention & National Weather Service. HeatRisk — an index combining heat intensity with population vulnerability. cdc.gov / weather.gov.

Generated for WetBulbTracker.com. The metrics engine is a pure, framework-free module; every formula above is implemented in `src/lib/metrics/` and `src/lib/solar.ts` and can be audited directly.

Tip: use your browser’s Print → Save as PDF to export this report.