You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds an optional power-spectra diagnostic to the experiment pipeline, so we can compare the effective resolution of model outputs against the truth and spot over-smoothing or spurious small-scale noise that point metrics like RMSE do not reveal.
The diagnostic computes 2D variance spectra (DCT by default, FFT optional) per participant and lead time, averages over initialisation times, and overlays each model against the truth with grid-resolution, effective-resolution and Nyquist reference lines.
What changed
New src/spectra package: numpy-only spectral core (DCT/FFT with variance-conserving normalisation and radial averaging), ICON native-to-regular regridding with runtime grid detection, plus field extraction and IO helpers.
Snakemake wiring (rules/spectra.smk): per-participant compute, aggregate over inits, overlay plot, gated behind an experiment target.
Config: new experiment.spectra section (enable flag, method, lead times, variables, optional init-hour subset) with validation and regenerated JSON schema.
Unit tests for the spectral core, regridding and IO.
Notes
Disabled by default; opt in with experiment.spectra.enabled: true.
ICON native grids are regridded to a regular grid before the transform; the eckit grid file is fetched automatically.
resolve conflicts in config, snakefile and schema (additive: scoremaps +
spectra side by side). drop the eckit_grids input from the spectra rules,
mirroring 3e7660b which deleted data_download_eckit_geo_grids.
The reason will be displayed to describe this comment to others. Learn more.
@frazane Thanks for pushing this. I have a few comments in particular around organization and generalization that should be easy to address. Good to go after that.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Baseline spectra can use the wrong ensemble member, configuration changes can reuse stale outputs, and frequency binning can discard valid spectral power.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The spectra diagnostic fails for empty reference-time selections and INCA baselines, while missing memory-proportional core reservations risk overcommitting Balfrin nodes.
No open issues 🎉
3 previously missed issues
In code that hasn't changed since last review
Support or reject INCA regular-grid spectra participants
src/spectra/compute.py:30
All participants are forced through the native-ICON path here, but load_forecast_data returns INCA fields on a regular (y, x) grid. Those fields fail native_field's 1-D guard, so enabling spectra for an experiment containing an INCA baseline cannot complete. Add a regular-grid path with the appropriate spacing, or reject unsupported participant types during configuration validation.
Reject empty reference-time selections before scheduling
workflow/rules/spectra.smk:19
With midnight-only experiment dates and init_hours: [12] (or an empty list), this returns no reference times. The aggregation rules are still scheduled, but spectra_aggregate.py requires at least one positional input, so the diagnostic fails with an argparse error. Reject an empty selection with an actionable configuration error before scheduling the enabled diagnostic.
Reserve memory-proportional cores for Balfrin jobs
workflow/rules/spectra.smk:52
These executor jobs bypass the memory-proportional core reservation documented in workflow/rules/common.smk:579–592, allowing concurrent jobs to overcommit Balfrin nodes where per-job memory limits are not enforced. Follow workflow/rules/verification.smk:105: use balfrin_cpus(50_000, actual_cpus=8) here and at lines 86 and 119, reserving 25 cores for each compute job. The plot rule at line 204 likewise needs balfrin_cpus(20_000, actual_cpus=2) to reserve ten cores.
The reason will be displayed to describe this comment to others. Learn more.
I tested the PR locally, and works well. Thanks!
A few minor points to address (suggested by Claude):
Wrong reference line in every plot. plot.py:18 labels a line "CERRA (~9 km)" but draws it at 0.10° × 111.2 ≈ 11 km. CERRA's grid is 5.5 km. Every figure shows a misleading reference.
Unsupported grids are only caught at runtime. validate_spectra_sources rejects INCA and station truth only. A forecaster whose GRIB isn't on the CH1 or CH2 native grid (a global model, or stretched output holding global and LAM points together) passes validation. It then fails in regrid.weights_path_for_npoints after the jobs are submitted. This could be relevant in case evalml will transition into the "bring your own gribs" concept.
Good to merge once these minor comments are addressed
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
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.
Adds an optional power-spectra diagnostic to the experiment pipeline, so we can compare the effective resolution of model outputs against the truth and spot over-smoothing or spurious small-scale noise that point metrics like RMSE do not reveal.
The diagnostic computes 2D variance spectra (DCT by default, FFT optional) per participant and lead time, averages over initialisation times, and overlays each model against the truth with grid-resolution, effective-resolution and Nyquist reference lines.
What changed
Notes
Example output, T_2M at +24h: