committed 05:58AM - 31 Aug 26 UTC
Adds `dwd/phenology`, the DWD phenological observation network: the day of the
y…ear on which a plant reached a developmental phase, at `annual` resolution,
reaching back to 1925.
Phenology carries one dimension the model has no slot for -- the plant -- so it
is mapped onto the file layout, which already separates by plant: a dataset is
one plant as published by one reporter group (110 of them,
`annual_common_hazel`, `immediate_winter_wheat`, ...) and a parameter is one
phenological phase (50 new canonical `phenology_*` names). A value is DWD's
`Jultag`, dated to the 1st of January of the reference year, so the entry date
is that date plus the value; `quality` carries `Qualitaetsniveau`. A parameter's
`name_original` is the numeric `Phase_id`, the only name the data files use.
Both reporter groups are covered with their own station catalogues: the
~6600-station Jahresmelder and the ~1200-station Sofortmelder.
Three things about the source shape the implementation:
- DWD leaves earlier historical releases of a series in place beside the current
one, distinguished only by the end year in the file name, and the earlier ones
are truncated -- the 2018 release of the mugwort series is 150 kB against
6.5 MB for the 2024 one. The file index takes the latest end year, anchored on
the suffix so that `..._Obst_Apfel` does not match
`..._Obst_Apfel_spaete_Reife_...`.
- The files are per plant rather than per station, and the larger crop and tree
series run to 50-160 MB. Each is parsed once per (dataset, period) and cut to
the stations of the request, so a many-station request costs no more than a
one-station request.
- Headers are inconsistent: the two beet files open with a blank line, upper
case their headers, and one writes `REFERENZ_JAHR` where every other file
writes `REFERENZJAHR`. Everything is latin-1 and blank-padded to a fixed
width, so it is read as string and cast afterwards.
Which phases each plant is observed for is the union of DWD's
`PH_Beschreibung_Phasendefinition_*.txt` files and a scan of the data itself:
the definition files describe the current programme and miss a few historical
combinations (hazel phase 41, immediate-reporter oak phase 4) that a
definition-only table would have dropped without a trace. Remote tests check the
phase and plant tables against the descriptions DWD publishes, and check that
every plant and period declared is published and that nothing published is left
unreachable.
`_periods_for` reads a dataset published in one period only whatever period the
request's dates imply: the two datasets with no historical release carry their
whole record in the recent file, back to 2018 and 2021, which a plain
intersection left unreachable by any date range.
The 50 new canonical parameters are labelled in all eleven app glossary locales;
the 110 plant dataset names are not translated yet and fall back to the
prettified id.