Seine nowcast, 2026 season — what the record says
Paris (four sites on the Seine and the Villette basin) and the Marne (three sites, Syndicat Marne Vive). Written 2026-09-24 by OpenCurrent, after the Paris bathing season closed. Frozen: every number below is computed from the published decision record, the 2026-09-08 full-history replay, the Pumphaus installation register, the units' own diagnostics and Open-Meteo archive rainfall. Nothing is estimated.
What the nowcast is, for readers new to it
Every hour, for every site in the fleet, the nowcast publishes an estimate of the E. coli concentration in the water and a probability that it is above that site's action limit (900 CFU/100 mL on the Seine and Marne, the EU bathing-water threshold). If that probability is 0.35 or higher the site shows an alert. Several versions of the model, called arms, run side by side:
- calibration
- a prior for the site (from satellite and landscape data, pooled with the region) plus a slowly updated site offset learned from that site's own lab results. It has no sensor input, so it barely moves between lab samples.
- stack
- calibration plus a machine-learned correction from the Lume sensor (tryptophan-like fluorescence, turbidity, temperature) and recent rain, trained on the whole fleet's paired samples.
- regression
- a small per-site linear model on the sensor features, using only that site's own samples.
Two words are kept apart throughout. A sample is the bottle of water taken at the site on a given morning. Its result is the lab's E. coli count for that bottle, which comes back one to two days later. The arms are judged the honest way: when a result comes back, it is scored against what each arm had already published at the hour the sample was taken. A missed exceedance costs 3 points, a false alarm 1. Per site, the arm with the lowest cost is the one whose estimate the dashboard shows (the served arm). Arms never see the result they are being judged on.
"Never alarm" is the reference in every table: a model that stays silent pays 3 per exceedance and nothing else. At an 11% exceedance rate, an alarm only pays for itself when more than a quarter of the alarms it raises turn out to be right.
1The deployment and the lab record
Each panel is one site: lab results on a log scale (red triangles are exceedances, green dots are under the limit), the dashed line is the 900 limit, the thin line is the estimate the nowcast was serving each hour (from the full-history replay, through 2026-09-08, and cut at the unit's removal), the shaded band is the window in which the Pumphaus register says the unit was in the water, and the grey stripe marks each site's first days, when samples were being taken but no result from that site had come back yet (see stage 2). Hover any point for the numbers.
Sites, units and sampling
| site | unit | in water | lab samples | exceedances | notes |
|---|
Paris sampling stopped on 2026-08-27, the day the register records the Bercy, Bras Marie and Grenelle units being removed. Villette stays in with a weekly sample. The Marne programme continues. Bercy and Bras Marie were cleaned on 2026-08-18, which stepped their fluorescence up 2 to 4 fold.
2The scoreboard
Decision cost (3 per missed exceedance + 1 per false alarm) on the published record, by arm, against the never-alarm reference. Lower is better. Hover a bar for the miss and false-alarm split.
Scoreboard as a table
| pool | samples | exceedances | never alarm | calibration | stack | regression |
|---|
Where the cost comes from
- A cold start that was scored. samples were taken in each site's first days, before the result of any earlier sample from that site had come back from the lab. The model had nothing from the site to calibrate on, so at those hours every arm was running on the region-pooled prior, about 2.9 log10 (the Marne's level) at Paris sites whose true level was about 1.8, so every arm alarmed on nearly all of them, and none was an exceedance. The dashboard held those alarms back (a site shows "held" until its first result), but the scoring did not, so a third of the Seine's cost is charged to a period when nothing was being served.
- Weak ranking at a low base rate. The arms' probabilities separate exceedances from clean samples only modestly on the Seine (area under the ROC curve 0.56 to 0.65). At the 0.35 alarm threshold they raise 40 to 46 false alarms to catch 4 to 10 of the 19 exceedances. Sweeping the threshold (below) helps, but on the warm record the best any arm reaches is a few points under never-alarm.
- The uncertainty is fleet-wide and honest. Each arm's spread is its own prediction error pooled across all 27 sites, about 0.65 to 0.75 log10. The Seine's lab results themselves scatter by 0.62, and the arms' estimates correlate with them at only 0.2 to 0.4. The level model has almost nothing to say about which morning will exceed.
Cost against alarm threshold, warm record only
Alarm if the arm's published probability is at or above the threshold. The production threshold is 0.35. The horizontal rule is never-alarm.
Reading the numbers
Five Paris exceedances and fourteen on the Marne, nine of them at Neuilly. Five of the Neuilly nine came in one storm week (08-28 to 09-01).
3What the sensors saw
How well does one measurement, on its own, rank the exceedances above the clean samples? The score is the area under the ROC curve: 0.5 is a coin toss, 1.0 is perfect. "Raw" uses the value as measured. "Within site" first removes each site's own average, so a feature only scores if it moves within a site when that site exceeds, rather than merely being higher at the site that exceeds most. Both are shown because the Marne site with the most exceedances is also the most turbid and the most fluorescent, which flatters the raw column.
- The fluorescence level carries real signal on the Seine, and it survives the within-site test (0.69). It is already a feature of the stack, alongside the anomaly. What the stack learned about it came from a fleet dominated by Boulder Creek, a clear snowmelt stream, and does not transfer well: its probability ranks Seine exceedances at 0.59 on the same samples.
- The anomaly (level against a 14-day trailing baseline) is close to noise at Paris (correlation with the lab value of about −0.14), and the two cleanings on 08-18 are part of why: a cleaning steps fluorescence up 2 to 4 fold, which looks like an event to a trailing baseline and then poisons the baseline for two weeks. On the Marne, where nothing was cleaned, the anomaly is the best single feature at Neuilly (0.73).
- Turbidity is a between-site effect, not a within-site one: raw 0.71, within site 0.55, and its within-site correlation with the lab value is negative.
- Rain matters with a lag the features do not cover (stage 4).
4Rain, and the lag
Daily rainfall from the Open-Meteo archive at Paris and three points up the Marne and Seine, with the exceedance days marked. The nowcast's rain features are 24, 48 and 72 hour totals at the site itself, taken at the hour of the sample.
- 08-19: 7.7 mm at Paris, 13 mm at Chateau-Thierry on the upper Marne. Exceedances followed on 08-21 at Bercy, Bras Marie and Neuilly on the Marne, and again at Bercy and Bras Marie on 08-23 (5,794 CFU). At the 08-21 morning sample the 48-hour rain total was 2 to 3 mm: the rain had already left the window. A 72-hour total would have held it, but a single lag of 2 to 4 days is not something one event can teach a model.
- 08-27: 34 mm at Paris, 9 to 23 mm upstream. Neuilly read 11,199 and 15,531 CFU on 08-28 and 08-29 and stayed above the limit to 09-01. The stack caught this one (probability 0.47 to 0.59), and that single week is most of its Marne advantage.
- Dry-weather exceedances: Bercy on 08-10 (1,935 CFU) and St-Maur on 09-03, 09-07 and 09-10 (2,045, 8,972, 6,014 CFU) came with no rain anywhere in the basin for five days. The sensors did register them, but in two different ways that the level model does not separate. At Bercy and Bras Marie on 08-21 and 08-23, and at Neuilly on 07-31 to 08-03, fluorescence ran 2 to 3.6 times the site's median while turbidity was normal or near zero: a dissolved, organic-rich input, which is what a sewer or treatment-works discharge looks like (with the caveat that the 08-18 cleanings also raised Paris fluorescence). At St-Maur on 09-03, 09-07 and 09-10, fluorescence sat below the site's median while the 24-hour turbidity peak ran 4 to 9 times it: a particle pulse without dissolved organics, which is what resuspended sediment or a mineral-laden inflow looks like. Neither is a rain or river-flow signature, and neither is something the current models are built to see: the stack learned the fleet's joint storm pattern of fluorescence and turbidity rising together, and the per-site regression uses each channel only as a plain additive term with no excursion or interaction terms, so a large rise in one channel while the other sits at zero registers as half a signal or none. A Seine-only model with per-channel excursion terms and a joint term would represent both routes; that is a model specification question, not a limit of regression. Independently, they need an explanation from the operators (dry-weather sewer discharges, treatment-works bypasses, lock or dredging operations, boat traffic) before any model can be expected to catch them.
5River flow: a dry season, and a feature for next year
Flow at the Paris-Austerlitz gauge on the Seine and the Gournay gauge on the Marne (Vigicrues, daily means), against the day-of-year climatology of the same reach from a 39-year GloFAS record (median and the 10th to 90th percentile band). Red rules mark days with an exceedance on that river; the shaded span is the Paris sampling window.
- It was a low-flow season. From August through late September the Seine ran at 0.4 to 0.6 of its climatological median for the date, below the 10th percentile, and the Marne the same. While Paris was sampling, flow sat between 64 and 78 m3/s with no pulse at all. The one pulse of the season, on 08-27, arrived the day Paris sampling stopped, and it coincides with the Neuilly exceedance cluster on the Marne. A model cannot learn a flow response from a season without a flow event.
- Flow carries signal once it is standardized. Raw flow pooled across the two rivers ranks exceedances at 0.42 (a Marne flow is a fraction of a Seine flow). Expressed as an anomaly against each reach's climatology, the same flows rank them at 0.74 to 0.76 across both rivers with one feature. In the pooled nowcast model, tested walk-forward with the same standardized feature at every site (USGS gauges in the US), it improves Boulder (decision cost 39 to 33) and the fleet (106 to 101) and leaves the Seine unchanged this season. It is a cheap, promising feature for 2027.
- Gauges, not modelled discharge. GloFAS tracks the Seine and Marne at a correlation of 0.7 to 0.8 (running about 1.3x the Seine gauge and exaggerating the 08-27 pulse), but on the small or managed streams the US fleet sits on it does not: Boulder Creek 0.04, Old Woman Creek near zero, and the DC cell is the Potomac rather than the Anacostia. The feature has to come from a gauge at every site, with GloFAS used only to supply the Seine's long-term climatology until a gauge record is obtained.
6Units on a shelf
The three Paris units kept transmitting after they were removed on 08-27, and the nowcast kept treating them as in the water: its registry knows when a unit was installed but not when it was removed, and its health check only asks whether readings are fresh. The units' own temperature record settles it. Every unit in a river swings several degrees over a few days; the three Paris units read a constant 23.3 °C, identical to each other, for as long as we looked.
Hourly mean board temperature from unit diagnostics, 2026-09-18 to 09-24. The Bercy, Bras Marie and Grenelle traces lie on top of one another at 23.3 °C. Villette (Paris, still in the basin) and Neuilly (Marne) for comparison.
So from 08-27 until the ingest cut them off on 09-23, the dashboard published "sensor+rain, health ok" estimates for Bercy, Bras Marie and Grenelle that were computed from a room. The Grenelle alert that stood on the dashboard in the last week of September was the regression arm reacting to a shelf. None of this touched the scoreboard above: every Paris lab sample predates the removal.
7Notes
- The first days at each site are no longer scored (changed 2026-09-24). When a site was new, the model had no lab result from it, its guess was a regional average, and those first samples were scored against that guess and charged to every version of the model, although the dashboard showed "held" and nobody saw an alarm. A third of the Seine's cost came from this. Such samples now stay in the record but are left out of the comparison between arms. On the Seine that takes the stack's cost from 73 to 48 on the remaining 144 samples, still not better than never alarming (57).
- Three Paris units kept reporting from a shelf after 08-27. The nowcast did not know they had been removed, so from 08-27 to 09-22 it published sensor-based estimates for Bercy, Bras Marie and Grenelle that were computed from a room, and those rows have since been dropped from the database. Worse, the database then stopped accepting any row for those sites, so their tiles kept showing the last row from before, a two-day-old alert at Grenelle, with nothing to say it was old. Fixed 2026-09-24/25: the feed reads the installation register, a removed unit gets the site's calibration estimate and the label "unit not deployed", the database accepts that row, and each tile now shows a "not deployed" chip or a "stale, N h behind" chip when its row lags the feed. Any look at those three sites between 08-27 and 09-22 should use the engine's replay, not the published series.
8What we changed after the season, and what it measured
Six changes were tried in the engine on 2026-09-24 and 25; five were kept. Each was measured the same way the arms are judged: refit as each lab result became known and scored on the samples that came after, over the whole fleet's record. "Cost" is the decision cost from stage 2.
| change | what it does | measured effect |
|---|---|---|
| Cold start | a site's first samples, before any of its results are known, are not scored against the arms | Seine stack cost 73 to 48 on the warm record; 53 samples fleet-wide set aside |
| Units out of the water | the installation register decides; a removed unit serves calibration, labelled "unit not deployed"; a rejected site fails the run | ends four weeks of bench readings served as river readings at three Paris sites |
| Fast site state | the most recent lab result at a site pulls the estimate toward itself, shrunk by 0.3 and fading with a 3-day half-life | fleet error 0.609 to 0.600 log10, cost 179 to 174; Seine error 0.595 to 0.576, cost unchanged; Boulder 90 to 83; DC 25 to 18 |
| Longer rain windows | 96- and 120-hour rain totals were tried alongside the 24/48/72-hour ones, so a storm two to four days back would still count | on their own they rank Seine exceedances better (0.69 to 0.71, Marne 0.68 to 0.76), but inside the model they changed nothing on the Seine and cost 6 points fleet-wide; not adopted, kept for a Seine-only model |
| Gauge discharge | river flow from the nearest gauge, expressed against that gauge's own day-of-year climatology (stage 5); GloFAS not used as a feature | Boulder cost 39 to 33, fleet 106 to 101, Seine 35 to 36 (no flow event during Paris sampling) |
| Basin-areal rain | rain averaged over 3 to 8 upstream points per river basin (the Paris sewershed and the Seine and Yonne up to Troyes; the Marne up to Saint-Dizier), summed over 48 and 96 hours, alongside the site's own point rain | on its own ranks Seine exceedances at 0.72 vs 0.70 for point rain, Paris 0.73 vs 0.69, Marne 0.76 vs 0.73; in the model, replayed: fleet cost unchanged (157), Seine stack 38 to 36, fleet error 0.523 to 0.519; kept |
All five together, replayed over the whole fleet's record from April to September (427 samples after the cold-start rule, 120 exceedances): decision cost for the calibration arm 167 to 156, for the per-site regression 179 to 161, for the stack 156 to 157, which is within noise at this sample size. On the Seine the stack's cost rose from 33 to 38 and calibration's fell from 34 to 31, so the replayed record would now serve calibration at the Paris sites and keep the stack at Neuilly. None of these changes the Paris verdict on this season's record. They make the fleet's model better, and they put the Seine in a position to be judged properly when sampling resumes.
9What it would take to serve decision makers on the Seine
The Paris decision is binary and daily: is the bathing site open this morning, at 900 CFU/100 mL, with lab results that arrive a day or two late. The city already closes on rain. A nowcast earns a place in that decision only if it calls the morning better than "closed if it rained, otherwise yesterday's result", and can show it on a season of paired data. In order:
- Registry, ingest and dashboard agree on what is in the water. Done 2026-09-25: the feed applies the installation windows, the database accepts the feed's "unit not deployed" rows, and the dashboard marks a removed or stale site. A bench detector (temperature range over 24 h) would be a backstop.
- Score only what was served. Done 2026-09-24: a site's first samples, taken before any of its results were known, are no longer scored against the arms.
- A Seine regime of its own. A pooled Seine model on raw fluorescence, turbidity and lagged rain, trained on Seine samples only, run as a shadow arm through the Marne autumn and the 2027 Paris season. Do not expect the Boulder-trained stack to transfer. In progress 2026-09-25: built and running as the shadow arm
seine_pooled, alongside two other Seine candidates (a multi-route "pathway" model and an XGB exceedance classifier), with a season-tuned model evaluated for 2027; results so far in the table below. - Basin signals, not point rain. Tested 2026-09-25, marginal: rain averaged over the Paris sewershed and the upper Marne and Seine (4 to 5 reanalysis points per basin) ranks Seine exceedances at 0.72 against 0.70 for rain at the site itself, at 72- to 96-hour windows; Paris 0.73 against 0.69 at 120 hours, Marne 0.76 against 0.73 at 96 hours. Real, small, and inside the noise of 19 events; the rain that matters fell over the whole basin this season, so a basin average adds little beyond a longer window. Worth revisiting with radar rainfall rather than reanalysis points. Gauge discharge at every gauged site is in (stage 8). Still open: a one-time Banque Hydro export for the Seine's climatology, and the combined-sewer-overflow and dry-weather discharge logs the city's own bathing programme runs on, if the operators will share them.
- Use the city's daily lab results as a feature. Done 2026-09-24 as the fast site state (stage 8). What remains is the day-of-week and time-of-day pattern once a season of daily Paris results exists.
- A Seine operating point. The 3:1 cost and the 0.35 threshold were set for Boulder's limit and base rate. Paris needs its own price for a wrongly open beach against a wrongly closed one, agreed with the city, and the threshold set on the Seine record alone. Interim, live 2026-09-25: on the Seine and Marne a missed exceedance is priced at five false alarms, every arm raises the alarm at the matching probability, 1/(1+5) ≈ 0.17, and the arms are compared at that price; the rest of the fleet is unchanged. Choosing the threshold on the season's record instead did not carry over from week to week (the best threshold swung between 0.20 and 0.45). The price still wants the city's agreement.
- Explain the dry-weather exceedances on the Marne and at Bercy with the customer before promising to catch them.
- Deploy before the season. Units in the water from April and samples from May, so 2027 opens with a warm record instead of a cold start.
A Seine model: what the 2026 record says so far
A brief for operators and partners (everything tried, the nowcast against the operators' rules, and why the Lume saw nothing at the Seine exceedances) is at seine-2026-brief.html.
In progress, not a conclusion. Every model below starts from the site calibration (the site's own level from its lab results, including the latest one) and asks whether the sensors and rain add to it. Unless marked, each is scored on the Seine samples taken after the site's first result was known, on the live record to 09-23 (144 samples, 19 exceedances; 5 in Paris, 14 on the Marne; a few fewer where a model needs some exceedances before it can be fitted), and compared with calibration on exactly the same samples, shown in brackets. "AUC" is how well a model ranks exceedances above clean samples (0.5 is chance, 1.0 perfect); the last column is what each would have done at the Seine operating point (alarm at P ≥ 0.17); on all 144 samples calibration catches 12 with 36 false alarms.
| model | how it was scored | AUC (calibration) | 95% interval of the difference | at P ≥ 0.17 |
|---|---|---|---|---|
| Pathway model | fluorescence alone, turbidity alone and both, each against the site's own two-week baseline, plus rain and flow; refit as results arrived | 0.61 (0.65)* | log loss 0.318 vs 0.315; the sensor routes learned almost no weight | 6 of 11 caught, 53 false* |
| XGB classifier | predicts the exceedance itself from sensor, rain, flow and the last result; whole fleet; refit as results arrived | 0.73 (0.72) | −0.07 to +0.07 | 11 caught, 30 false |
| 181 site baselines | every combination of baseline window (3 days to since the last cleaning), gap, centre and form for fluorescence and turbidity, Seine-only; baseline chosen on earlier data only | 0.50 (0.65)† | −0.36 to +0.02; the best of the 181 in hindsight (+0.06) is what shuffled sensor data also gives (p = 0.45) | — |
| Pooled Seine regression | item 3 above: one Seine-only regression on the residual from calibration, raw fluorescence, turbidity, rain; refit as results arrived | 0.76 (0.71) | −0.11 to +0.15; Paris 0.67 vs 0.55, Marne 0.72 vs 0.55 | replay: 8 of 11 caught, 33 false (calibration 6, 33)* |
| Season-tuned, forecast for 2027 | 54 candidates (regression or classifier, linear or trees, Seine-only or whole fleet, three input sets, three settings each) chosen and tuned on six weeks, predicting the seventh, for every week in turn | 0.72 (0.72) | −0.08 to +0.08; the model chosen changed from week to week | 13 caught, 35 false |
| Season-tuned in hindsight | the single best of the 54 on the whole season, then refit as results arrived: the ceiling, since the choice saw every week it is scored on | 0.76 (0.68) | −0.01 to +0.16 | 9 caught, 28 false (calibration 9, 34) |
* scored on the 2026-09-08 replay (122 samples, 11 exceedances). † 114 samples (14 exceedances): the Seine-only models need five known exceedances before they exist; the reference is a Seine-only fit to calibration's estimate. Intervals: resampling site-weeks, 2,000 draws.
What it says so far. On this season, a model tuned on everything the season taught us would be expected to do about as well as site calibration next year, not clearly better: one more exceedance caught at a similar number of false alarms (13 and 35 against 12 and 36), inside the noise of 19 events. The ceiling, tuning with hindsight, reaches 0.76 against 0.68, and the gap between the two is the price of choosing on the answer. Comparing each fluorescence and turbidity reading to the site's own baseline, whichever of 181 ways it is done, adds nothing that survives chance on this record: this season's Seine exceedances did not follow a sensor excursion the models could see.
Regression or XGB? Neither. Holding the inputs fixed and varying one thing at a time over all 54 candidates, predicting the concentration versus the exceedance changed the median log loss by 0.004, and linear versus trees by 0.002; the best of each tied (0.344). The one choice that mattered consistently was training on the whole fleet rather than the Seine alone: better in 17 of 20 otherwise identical pairs (median log loss 0.022 lower), because 19 exceedances are too few to set a model's probabilities by themselves and the rest of the fleet's roughly 140 lend them a scale. Rain and flow helped a little; the site-baseline excursions made models worse. The pooled Seine regression's lead in the table is the same size as the XGB classifier's gap to calibration, and both are noise at this sample size.
Added 2026-09-25: the fleet-trained version of item 3 (the configuration that tied for best above: the same regression
with river flow added, trained on every region) runs as a fourth shadow arm, pooled_fleet, beside the
Seine-only one. Still open: which of the two to carry into 2027; what the Marne
autumn adds (every Seine candidate is logging from 2026-09-25); and the signals the models do not have, above all the
combined-sewer-overflow and discharge logs behind the dry-weather exceedances (item 7).
With steps 1 and 2 in place, the Seine's live record can be read as a measurement of the model from here on. What it cannot yet answer is Paris, until Paris is sampled again.
Sources and reproduction
- Decision record:
GET /api/nowcast/decisions?site=<site>for the seven Seine sites, 170 rows as of 2026-09-24. Cold-start flag: no earlier sample from the site whose result was known (known_at) by this sample's hour. - Sensor features at each sample:
lume-nowcast/state/grab_features.parquetjoined to the 2026-09-08 full-history replay (out/replay_full/decisions.parquet, 132 Seine rows, 126 with features). Served-estimate lines:out/replay_full/series.parquet. - Installation windows: inventory worker
/api/validation/install-windows. Unit diagnostics:/api/pumphaus/proxy, endpointdiagnostics. - Discharge: Vigicrues observations service (stations F700000103 Paris-Austerlitz, F664000104 Gournay-sur-Marne, 5-minute Q, last two months); USGS daily values 1990 to date (06730200, 05536290, 04199155, 01649500, 06711565, 06710247); GloFAS v4 intermediate 2026 and consolidated 1985-2023 from the Copernicus Early Warning Data Store via discharge_etl. Climatology: 31-day day-of-year window on the 39-year GloFAS record at the Paris cells.
- Rain: Open-Meteo archive, daily precipitation sum at 48.85/2.35 (Paris), 48.96/2.88 (Meaux), 49.04/3.40 (Chateau-Thierry), 48.54/2.66 (Melun).
- Walk-forward Seine model: logistic regression on log fluorescence, log 24-hour turbidity max, log 48-hour rain and temperature, refit on all Seine samples known at each sample hour (minimum 20 with 2 exceedances), class-balanced, C = 0.5.
- Seine model evaluations (2026-09-25), each with its protocol written before it ran: pathway model
engine/PATHWAY_ARM.md(engine.pathway_eval); XGB and operational baselinesengine/SEINE_BENCHMARK.md(engine.benchmark); 181 site baselinesengine/SEINE_SEARCH.md(engine.seine_search); season-tuned models and the regression-versus-XGB comparisonengine/SEINE_TUNED.md(engine.seine_tuned). Seine units re-pulled from 2026-08-25 to 09-25 for the September samples; identical to the archive where they overlap. - The full engineering postmortem is
lume-nowcast/engine/SEINE_POSTMORTEM.md.