# cloud_cover Downloads total cloud cover (CLCT) predictions from the [DWD open-data server](https://opendata.dwd.de/weather/nwp/icon-d2/grib/) and renders one PNG map per forecast hour, centred on the Brandenburg / Berlin area. This is a Rust port of `../cloud_cover_prediction.py`. The output format differs: instead of using PyNGL's contour renderer the Rust version does a direct point-by-point orthographic projection of the ICON-D2 grid onto a bitmap, which avoids every system-library dependency (no CDO, no PyNIO, no PyNGL, no libssl, no libbz2 — the binary is fully self-contained). ## Usage ``` cloud_cover ``` | Argument | Description | |---|---| | `ISO_TIMESTAMP` | Model run time in ISO 8601, e.g. `2026-03-03T18:00:00Z` | | `HOURS` | Number of forecast steps to render (0–48) | The timestamp must correspond to an ICON-D2 model run, which is issued every 3 hours starting at 00 UTC (00, 03, 06, 09, 12, 15, 18, 21). ### Example ```sh cargo run --release -- "2026-03-03T18:00:00Z" 12 ``` Output PNGs are written to `cache/_UTC/clct_000001.png` … `clct_NNNNNN.png`. Downloaded GRIB2 files are cached in the same directory so that re-running the same timestamp skips the network requests. ## How it works 1. **Download** — `reqwest` fetches the bzip2-compressed GRIB2 files from the DWD server. Two coordinate files (`clat`, `clon`) give the latitude and longitude of every point on the ICON-D2 icosahedral grid (~542 000 points for Germany). One `clct` file per forecast step contains the total cloud cover percentage at each point. 2. **Decompress** — `bzip2` decompresses the files in-memory. 3. **Parse** — A minimal built-in GRIB2 decoder extracts the data values. Only simple packing (data representation template 0) is supported, which is what DWD uses. Grid points that are flagged as absent by the section-6 bitmap are set to `NaN` and skipped during rendering. 4. **Project & render** — Each grid point is projected onto the image plane using an orthographic projection centred on Falkensee (52.56 °N, 13.08 °E). Points are painted as 2 × 2 pixel squares, colour-coded by cloud cover percentage. City markers and labels are drawn on top, and a colour-scale legend is shown on the right. `plotters` writes the final PNG. ## Cloud cover colour scale | Cloud cover | Colour | |---|---| | < 1 % | Land background (clear) | | 1–2 % | Very light blue | | 2–5 % | Light blue | | 5–10 % | Medium blue | | 10–20 % | Blue | | 20–50 % | Dark blue | | 50–100 % | Very dark blue | ## Marked locations Falkensee · Pausin · Nauen · Hennigsdorf · Ketzin/Brückenkopf · Potsdam · Berlin (Mitte) ## Dependencies All dependencies are pure Rust or vendored C code compiled into the binary. No system shared libraries are required at runtime beyond libc. | Crate | Role | |---|---| | `reqwest` (rustls-tls) | HTTP client with pure-Rust TLS | | `bzip2` | bzip2 decompression (vendors libbzip2) | | `plotters` + `plotters-bitmap` | PNG rendering with built-in bitmap font | | `clap` | CLI argument parsing | | `chrono` | Date/time handling | | `anyhow` | Error propagation | ## Building ```sh cd cloud_cover_rs cargo build --release ``` The compiled binary ends up at `target/release/cloud_cover`.