Skip to content

Add ECMWF SEAS5 seasonal forecasts as a weather source - #40

Open
mrke wants to merge 4 commits into
Docsfrom
seas5
Open

mrke wants to merge 4 commits into
Docsfrom
seas5

Conversation

@mrke

@mrke mrke commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Adds ECMWF's SEAS5 seasonal forecasts as a weather_source, so a microclimate can be run forward from a forecast:

model = MicroMapModel(; weather_source = seas5_forecast(Date(2026, 9, 1); member = 0), init_source = ERA5ECMWFLand, ...)
problem = MicroVectorProblem(; model, points, dates = Date(2026, 9, 1):Day(1):Date(2026, 11, 30), soil_profile)

This is based on Docs (#39), not main, so the diff shows only SEAS5. GitHub will retarget it to main if Docs is merged and its branch is deleted. It depends on two RasterDataSources PRs, so Project.toml pins RasterDataSources to the fork branch franken-seas5 (= franken-branch + SEAS5) until those land:

Design

  • One forecast and one ensemble member per run. seas5_forecast(start; member) returns SEAS5Forecast{Init,Member}, with start snapped to the 1st of the month. Member 0 is the control forecast. For the spread, run members 0–50 separately.
  • Daily min/max source, like GRIDMET, not sub-daily. CDS only serves SEAS5 radiation and rainfall as 24-hourly accumulations, and a source has one native timestep. Daily radiation is also what the min/max path's clear-sky spreading is built for. The six daily fields are:
    • Tmax and Tmin, from SEAS5's own 24-hour max and min variables.
    • Dewpoint, the daily mean of the 6-hourly values.
    • Wind speed, the mean of the 6-hourly speeds rather than the speed of the mean wind vector, which shrinks when direction changes.
    • Shortwave radiation and rainfall, converted from SEAS5's running totals to daily totals.
      Days are UTC days.
  • New loader SingleForecast. It makes one CDS request per SEAS5 variable (7 in total, at most 4 at a time) through getraster(SEAS5, …), over the whole-degree box around the area. It returns daily layers on the full-years calendar the other loaders use, with NaN outside the forecast's 215 days.
  • New hook _check_weather_dates(source, dates). It does nothing by default and is called where both inits normalise dates. SEAS5 uses it to reject runs outside the forecast window up front, instead of solving on NaN forcing.
  • Buffers: points_load_buffer is 0.5° (SEAS5's grid points sit at cell centres) and weather_area_buffer is 2° (two 1° cells each side for the cubic-spline regridding, as NCEP gets).
  • Initial soil state: none from SEAS5. Its soil moisture is daily only, and I couldn't check its layer structure without a key. The example seeds from init_source = ERA5ECMWFLand; passing init also works.

Also adds examples/microclimate/seas5_point.jl and SEAS5 entries in the forcing-data and data-source docs.

Testing

  • test/seas5.jl (31 tests, no network). It covers the type and traits, the request extent, the date-window check, the daily reductions, and reading files in the exact layout CDS returned for a live SEAS5 request. It also runs the loader end to end, from files planted in getraster's cache through member selection, daily reduction and calendar placement.
  • Full solve locally with synthetic SEAS5 files (Melbourne, 30 days, real SRTM). It produced 720 hourly steps. Air temperature at 1.2 m stayed within the planted Tmin/Tmax. Humidity of 43–86% matches the planted dewpoint. Solar radiation peaked at 757 W/m². An out-of-window run was rejected.
  • Not yet tested: a real CDS run through MicroclimateMapper. The underlying getraster/getpoint path was checked against a live SEAS5 download.
  • This solve needed output_layers without ground_surface_water. On Docs, the default output layers ask Microclimate for that field, and the installed canopy Microclimate doesn't have it. That's unrelated to this PR.

🤖 Generated with Claude Code

`seas5_forecast(start; member)` picks one forecast and ensemble member as
`weather_source`. Loaded as a daily min/max source via
RasterDataSources' CDS-queued `SEAS5`: CDS only serves radiation and
rainfall as 24-hourly accumulations, so 6-hourly dewpoint and wind are
averaged to days and accumulations de-accumulated. Adds a
`_check_weather_dates` hook so runs outside the 215-day forecast window
fail clearly instead of solving on NaN forcing.

Pins RasterDataSources to the fork's `franken-seas5` (franken-branch +
SEAS5) until EcoJulia/RasterDataSources.jl#113 is merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mrke and others added 3 commits October 24, 2026 23:24
… wind

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rafaqz
rafaqz added this pull request to stack #44 October 30, 2026 00:32

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant