Files
GeoLibre/scripts
Qiusheng Wu 63d4a583c3 feat(dynamical): draw the virtual and time-series datasets (#3050)
* feat(dynamical): draw the virtual and time-series datasets

The Dynamical panel greyed out 21 of dynamical.org's 26 datasets. Both
blockers are lifted:

- Virtual repositories point each chunk at one message in NOAA's or
  ECMWF's GRIB2 files and name the `gribberish` codec, which has no
  JavaScript build. Add a GRIB2 decoder (grid templates 3.0 and 3.30;
  packing 5.0, 5.2/5.3 and 5.42 CCSDS with a port of libaec's decoder)
  and register it as a zarrita codec, which zarr-layer reads through
  too. It matches ecCodes value for value on real GFS, GEFS, HRRR and
  AIFS messages.
- Analyses and ensembles pack hundreds to thousands of steps into each
  chunk. They now draw a region at a time: a minimum zoom is worked out
  from the chunk size and the map size so a view decodes at most
  256 MB, the map zooms in to it on add, and the layer's zoom range
  keeps a zoomed-out view (or a re-slice while zoomed out) from
  fetching anything.

Part of #3048.

* Address Claude review feedback

- grib2: a zero subdivision count falls back to microdegrees instead of
  dividing by zero, and a missing (all-ones) longitude increment leaves
  the step unset so the longitude roll is skipped.
- grib2: a truncated data section now throws instead of decoding the
  missing tail as zeros, and the encoded-value and group counts are
  checked against the grid before they size any allocation.
- grib2: orientGrib2Field defaults northUp to off, matching the codec.
- grib2-codec: document the zarrita contract the registry cast relies
  on, and test a read through zarrita end to end.
- Dynamical panel: branch on the dataset bbox explicitly and treat a
  bbox crossing 180 degrees correctly (bboxContains, bboxCenter).
- Dynamical panel: recompute regional layers' minimum zoom when the map
  resizes, since a larger map at the same zoom holds more chunks.

* Address review feedback

- grib2: validate template 5.3's differencing header (order 1 or 2, at
  least one extra octet, a data section long enough for it) instead of
  decoding NaN initial values (Claude).
- grib2: throw when the group lengths cover fewer values than the
  message declares, rather than scaling the untouched zeros (CodeRabbit).
- grib2: cap decoded grids at 16 million points, eight times the
  largest virtual grid (HRRR), so a corrupt message cannot make a
  decode allocate gigabytes (CodeRabbit).
- Dynamical panel: put the camera back if a regional add fails after
  the map jumped in to its minimum zoom (Claude).
- Dynamical panel: track regional layers even when their first minimum
  zoom is 0, so a later resize can raise it; clamp the zoom range at 0
  (CodeRabbit).
- Add an upstream contract test for zarr-layer's private minZoom and a
  docs/maintenance.md section on it (Claude).
- Drop chunkBytes' unused dataset parameter (Claude).

* test(grib2): drop the fixture files

Build the simple-packed messages inside the test with a small GRIB2
writer (grids, orientation, bitmap, truncation and count checks), and
keep the complex (5.3) and CCSDS (5.42) decoders covered by two tiny
ecCodes-encoded messages inlined as base64, checked against ecCodes'
sum, missing points and sampled values. This removes
tests/fixtures/grib2/ (13 files, including the generator).

* Address review feedback

- grib2-codec: clear the cached codec registration when the zarrita
  import fails, so a transient chunk-load error does not stick until
  reload.
- grib2: refuse a section whose length runs past the buffer with the
  descriptive "Corrupt GRIB section" error instead of truncating it or
  hitting a raw DataView RangeError; the truncation test now expects it.
- grib2: refuse a group whose length would push the decoded index past
  the declared count, rather than truncating it and accepting the layout.
- dynamical: move a regional layer's view into the dataset bbox when the
  map is already at the minimum zoom but centred outside it, keeping the
  current zoom.
- zarr: add a minZoom option that sets the renderer's own zoom gate in
  the synchronous layeradd handler, before its metadata (and first
  fetch) loads; the dynamical panel passes its regional threshold, so a
  zoom-out during the pending add cannot start a whole-globe read.
2026-10-08 12:46:36 -04:00
..