Repository navigation
fix(radar): decode FMI precipitation as a rate, not metres of water - #1008
Merged
Merged
Conversation
FMI encodes `Precipitation1h` as GRIB2 parameter 0-1-7 — precipitation rate in kg m⁻² s⁻¹ (mm/s) — but the decoder treated it as metres of water and multiplied by 1000 instead of 3600. Every value came out 3.6× low and was then rounded to 0.1 mm, which zeroed anything under 0.18 mm/h and left the forecast half of the timeline all but blank: only cells above ~0.36 mm/h rendered at all, and everything up to 3.6 mm/h drew in the palest blue. Confirmed against FMI's own point forecast — the Tampere cell decodes to 2.7778e-5 and opendata.fmi.fi/timeseries reports 0.1 mm for that hour (× 3600 = 0.1, × 1000 = 0.028). Every decoded value is an exact multiple of 0.1/3600, so the source is 0.1 mm/h-quantised and rounding the converted result stays lossless. Alongside the fix: - Request a 4.4° × 2.4° box instead of 9.0° × 3.4°. The old one produced 401 native cells, tripping MAX_GRID_SIDE and halving the grid to 201×76 — of which only ~22% of the width was ever on screen at the default zoom. It now ships at native ~2.5 km resolution, 196×107. - Retune PRECIP_STOPS to span 0.1–30 mm/h. Finnish rain is mostly 0.1–5 mm/h, which the old 0.1–40 ramp spent entirely on blues. - Resample the forecast overlay's rows into Mercator. imageOverlay stretches linearly in the projection but the grid is regular in latitude, so rows landed ~2.6 km too far north mid-box. - Switch the observed frames to Radar:suomi_rr_eureffin (rain rate, band = mm/h × 100) and restyle them with halo's own ramp via SLD_BODY, so one legend describes the whole timeline instead of the palette jumping at "now". The dBZ composite could only ever be labelled qualitatively — FMI's own style names its bins kohtalainen/sakea/hyvin sakea. Both halves now share one opacity and the same per-pixel alpha. - Fall back to FMI's built-in style when a tile carrying SLD_BODY comes back as a ServiceException, so the radar degrades to their palette rather than a blank map. - Mark the saved location with an accent ring and dot so the centre point stays findable under the overlay.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The rain tab's forecast frames rendered essentially blank while FMI's own app
showed a clear precipitation field for the same hour.
Root cause
Precipitation1his GRIB2 parameter 0-1-7 — precipitation rate inkg m⁻² s⁻¹ (mm/s), not metres of water. The decoder multiplied by 1000 instead
of 3600, so every value came out 3.6× low, was rounded to 0.1 mm, and then had
anything below the ramp's 0.1 threshold dropped. Net effect: only cells above
~0.36 mm/h drew at all, and everything up to 3.6 mm/h drew in the palest blue.
It also explains why the "ei sadetta ennusteessa" hint never appeared on those
frames —
frame.maxwas non-zero (0.72 for the reference hour), so the framewasn't classified as dry even though it painted almost nothing.
Verification
Checked against FMI's own point-forecast API rather than only unit tests:
2.7778e-5;opendata.fmi.fi/timeseriesreports0.1 mmfor that hour.× 3600 = 0.1✔,× 1000 = 0.028✘. Every decodedvalue is an exact multiple of
0.1/3600.Precipitation1hexactly; the two outliers differ by 0.1 mm, which is nearest-cell pick vs FMI's
bilinear interpolation.
where a flipped-rows bug would be invisible — these confirm orientation too.
0.1–1 mm/h precipitation, peaking at 1.4 mm/h.
For the observed/forecast ramp unification, tested through halo's own proxy: the
styled tile returns 9/9 halo ramp colours with zero foreign colours; the unstyled
tile returns FMI's palette instead (proving the SLD is what's doing the work);
and a deliberately broken SLD falls back to a tile byte-identical to the
unstyled one.
cargo test24 + 18 green (4 new radar tests),yarn validateclean.Also in here
MAX_GRID_SIDEand halving the grid to 201×76 — of which only ~22% of thewidth was ever on screen at the default zoom. Now 4.4° × 2.4°, shipping at
native ~2.5 km resolution (196×107, stride 1).
old 0.1–40 ramp spent entirely on blues.
imageOverlaystretches linearly in theprojection, but the grid is regular in latitude, so rows landed ~2.6 km too far
north mid-box. Measured placement error drops 2.57 km → 1.26 km, the residual
being half-cell quantisation.
Radar:suomi_dbz_eureffintoRadar:suomi_rr_eureffin(rain rate, band =mm/h × 100) and are restyled with halo's own ramp via
SLD_BODY, generatedfrom
PRECIP_STOPS. Previously the palette jumped as you scrubbed past "now"and the legend described only half the timeline — dBZ can only be labelled
qualitatively, and FMI's own style names its bins
kohtalainen/sakea/hyvin sakea. Retuning
PRECIP_STOPSlater now updates bothhalves automatically.
SLD_BODYcomes back as a WMSServiceException(XML, sometimes with a 200), the proxy retries once withoutit, so the radar degrades to FMI's palette rather than an empty map.
markerPaneso frames never paint over it and non-interactive so it doesn'teat the long-press scrub gesture.
Worth knowing
That view is a radar extrapolation nowcast; this is the HARMONIE model, and
HARMONIE genuinely forecast only 0.1–0.4 mm over Tampere for the hour in
question — FMI's human-edited
pal_skandinaviaagrees. FMI's open WMSpublishes no nowcast layer (all 116
Radar:*layers are observed products), sothere is nothing to switch to. That gap is meteorology, not code.
rrshows slightly less fine texture than dBZ. Reflectivity picks up faintechoes the rain-rate product doesn't, and halo's ramp starts at 0.1 mm/h where
FMI's
rrstyle starts at 0.07 — so the very lightest returns now read as dry.That's the cost of both halves being the same quantity.
RADAR_OPACITY(0.75) and
FORECAST_OPACITY(0.6) collapsed into oneOVERLAY_OPACITY;differing alphas would have re-introduced a jump at "now".
them turning it off — if the observed frames ever show FMI's louder cyan/green
palette, that's it firing (
retrying with FMI's own stylein the log).