Inspiration
In Imperial Beach, Nestor and San Ysidro, sewage in the Tijuana River gives off hydrogen sulfide (H₂S). On calm nights the gas pools in the river valley and drifts into homes and schools. Residents can check the air district's monitors, but those only show what already happened, at three points. Nobody could answer the question families actually ask: "Will it be bad tonight, on my street?" We wanted to forecast sewer gas the way you'd forecast rain.
What it does
Smellcast is a 24-hour H₂S forecast for the South Bay at street level, updated every hour.
- Forecast map: shows predicted gas levels on a 50 m grid, as green, yellow and orange zones, hour by hour. It can play through the night like a weather radar loop.
- Tonight: ranks schools and neighborhoods by their expected peak. Each one gets a median forecast and a high estimate, so people see the uncertainty, not just one number.
- Alerts: at 5:15 PM, residents who sign up get an English or Spanish email when their place is likely or possibly going to reach orange (30 ppb). That leaves time to close windows or make plans.
- Replay: reruns any past night as it would have been forecast at 5 PM, next to what the monitors actually recorded. It also shows the alert email that would have gone out.
- Accuracy: a page that scores the model against simple baselines on nights it never saw while being fitted.
How we built it
- Data:
- Hourly H₂S readings from the San Diego County Air Pollution Control District (APCD) monitors, via UCSD Resilient Shield, back to 2023.
- River flow from the U.S. International Boundary and Water Commission (USIBWC) gauge at the border.
- National Weather Service forecasts, plus observed weather from the Imperial Beach airfield.
- Odor complaints and sewage spill reports.
- Gemini reads USIBWC press releases about pump shutdowns, repairs and storms, and turns them into structured flow events. Each event must be backed by a verbatim quote, and we keep only numbers that describe the river itself.
- Bright Data collects news reports about odor for each night. Its Scraping Browser and Web Unlocker are also wired in as fallback scrapers for the APCD dashboard history and USIBWC pages.
- Tiger Data (TimescaleDB): one database holds everything. Readings, weather and forecasts are hypertables, and nightly peaks are continuous aggregates.
- The model: a Gaussian puff dispersion model releases gas from three points along the river.
- Emissions scale with river flow and temperature, and are diluted during storm flows.
- Wind meander and atmospheric stability set how the gas spreads.
- A Kalman filter tunes the emission rate to the monitors every hour.
- A correction step uses each monitor's recent nights.
- An ensemble of runs gives the median (P50) and high (P90) estimates.
- Stack: FastAPI with a scheduler for collection, hourly forecasts, the 5 PM alerts and nightly validation. The front end is React with MapLibre and Recharts. Everything runs in Docker Compose.
Challenges we ran into
- Honest validation: a forecast can easily cheat with future data. Every replay uses only what was available at 5 PM that day. The model is fitted only on nights before 2026, and 2026 is held out. Replays made with an older calibration are excluded from the scores, not quietly mixed in.
- Messy locations: about 91% of odor complaints share one placeholder coordinate for a whole city. Our first "complaints match the forecast" result looked great until we found that out. Now we use only complaints with a street-level location.
- LLMs and numbers: Gemini sometimes reported a treatment plant's capacity as river flow. We added checks: every number must appear in the quoted text and must describe the river, or it gets dropped.
- Getting the data: some government sites block automated access, gauge exports come in different units, and an AI model version was retired in the middle of the hackathon.
Accomplishments that we're proud of
On 901 held-out monitor-nights in 2026:
- Half the false alarms: 20% of Smellcast's alerts were false, against 39.5% for "tonight will be like last night".
- Better ranking: when allowed the same number of alerts as that baseline, it caught 69% of orange nights instead of 61%.
- Honest uncertainty: the night's peak stayed under our high estimate on 90.8% of monitor-nights, against a target of 90%.
- Surprise spikes: it caught 83% of spikes that followed a quiet night with its "possible" alert, a case a readings-based alert can never catch.
It does all this at street level, in English and Spanish, with every number traceable to its source. It does all this at street level, in English and Spanish, with every number traceable to its source.
What we learned
A forecast is only useful if people can trust it. That meant showing uncertainty, comparing against simple baselines, and being upfront about limits. One example is that our replays use the weather that actually happened, which flatters the scores. We also learned to use AI for what it's good at, reading messy announcements, and to keep the gas predictions in physics.
What's next for Smellcast
- Score the model against archived weather forecasts instead of observed weather, to measure true live accuracy.
- Add low-cost sensors and street-level complaint reports to fill the gaps between the three monitors.
- Add SMS alerts, and partner with the APCD and local schools.
- Add flow and plant data from the Mexican side of the border.
- Build a "far reach" replay that shows nights when gas travelled more than 3 km inland to Imperial Beach.