Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
2b49526
Simplified way of implementing fields
jonasbhend Dec 19, 2025
a456b1d
Exclude spatial data from being plotted and included in dashboard
jonasbhend Dec 19, 2025
0ec286f
delete intermeidate verification files
jonasbhend Jan 7, 2026
28692d6
Fix typo
jonasbhend Jan 7, 2026
f3dcf0d
include score components for maps
jonasbhend Jan 7, 2026
99dac52
Revert "Exclude spatial data from being plotted and included in dashb…
jonasbhend Jan 7, 2026
edcca5b
remove source dimension from scores
jonasbhend Jan 7, 2026
0ec8a0f
clean up
jonasbhend Jan 8, 2026
51f22a6
New rule and plotting file for plotting maps of
Louis-Frey Jan 12, 2026
366249d
Obvious changes to the new plotting rule for maps
Louis-Frey Jan 12, 2026
f531395
Some more changes (preliminary, to be continued).
Louis-Frey Jan 12, 2026
32c7ecf
Further changes to plotting scripts.
Louis-Frey Jan 13, 2026
c2ab645
First version of colour maps finished.
Louis-Frey Jan 14, 2026
27b91e2
Better comments in the colour map code.
Louis-Frey Jan 14, 2026
1b2e670
Better Comments, some further changes to code.
Louis-Frey Jan 14, 2026
52dd1e7
Added back instances of lead time.
Louis-Frey Jan 15, 2026
ddc5883
New function for loading netCDF files added to
Louis-Frey Jan 15, 2026
35396a7
Marimo app cell for loading data from .nc
Louis-Frey Jan 15, 2026
e8a92aa
Remove .nc-loading function again, do it with
Louis-Frey Jan 19, 2026
06be6fa
All kinds of changes. Co-Development session with
Louis-Frey Jan 21, 2026
61c728e
Generalized to the other non-trivial (non-wind)
Louis-Frey Jan 22, 2026
761f8d9
Some changes to plotting script.
Louis-Frey Jan 22, 2026
1cd4dbf
Plotting region now dynamical (but not yet
Louis-Frey Jan 23, 2026
cdb2ccd
Dynamic Regions now working.
Louis-Frey Jan 23, 2026
558689c
Store results under experiment hash.
Louis-Frey Jan 23, 2026
986a7ee
Introduced new domain "switzerland_small" for more
Louis-Frey Jan 26, 2026
7f70fb4
Reverse Red-Blue colour maps for bias.
Louis-Frey Jan 27, 2026
50e899f
Preliminary changes to plotting script for getting
Louis-Frey Jan 27, 2026
a0aefc0
Temporarily changed plotting script back to original
Louis-Frey Jan 27, 2026
be6fa35
Fix to the functioning of _compute_scores and
Louis-Frey Jan 27, 2026
2fcd1f9
Working version for colour scale for bias that is
Louis-Frey Jan 29, 2026
7864b5d
New colour map defaults for T_2M
Louis-Frey Jan 29, 2026
de0f279
Hard-Code levels for colour breaks.
Louis-Frey Feb 3, 2026
69e7b36
New Rule for Map plots of Baselines.
Louis-Frey Feb 3, 2026
1353788
Different File naming (Region first -> Order)
Louis-Frey Feb 4, 2026
569759a
Temporarily remove rule for maps for baselines.
Louis-Frey Feb 5, 2026
bda0e0d
Renamed domain "switzerland_small".
Louis-Frey Feb 5, 2026
ccf6279
Generate Colour breaks more elegantly.
Louis-Frey Feb 5, 2026
258b2de
Colour breaks from function for all T2m metrics.
Louis-Frey Feb 5, 2026
5c0151b
Map plots now also for baselines.
Louis-Frey Feb 9, 2026
7b50809
Fix memory leak occurring during creation of html.
Louis-Frey Feb 9, 2026
c3d37a2
"Alias" Rule for Plotting maps of Baselines
Louis-Frey Feb 10, 2026
8323fbd
Reorganisation of Domains.
Louis-Frey Feb 11, 2026
d03781c
Introduce Seasonal Stratification.
Louis-Frey Feb 11, 2026
48e6789
Definitive Colour Levels for 2m-Temperature
Louis-Frey Feb 12, 2026
1c3e629
Colour levels for Precipitation complete.
Louis-Frey Feb 13, 2026
a4a5607
Colour Levels for Dew-Point Temperature
Louis-Frey Feb 17, 2026
f245ea3
Calculate and Evaluate Wind Speed too
Louis-Frey Feb 19, 2026
ccea8db
Fix for Wind speed calculation
Louis-Frey Feb 19, 2026
ce4242f
Name Wind Speed consistent with the previous def.
Louis-Frey Feb 23, 2026
9628fae
Verification files not temporary any more
Louis-Frey Feb 24, 2026
59d4b12
Precipitation plotting: meters to millimeters.
Louis-Frey Feb 26, 2026
28ad4c5
Map plotting not on default busy nodes.
Louis-Frey Feb 26, 2026
db60db5
Preliminary Colour Levels for Wind Bias.
Louis-Frey Feb 26, 2026
e2570fb
Merge main into feature branch
Louis-Frey Feb 26, 2026
2fcfd8a
Replace EXPERIMENT_HASH by EXPERIMENT_NAME
Louis-Frey Feb 26, 2026
c00c5a0
Colour Levels for Pressure Bias.
Louis-Frey Mar 2, 2026
23d8c9c
Colour Levels for Pressure MAE and RMSE
Louis-Frey Mar 9, 2026
84edd34
Colour Levels for 10m Wind MAE and RMSE
Louis-Frey Mar 10, 2026
a9099c1
Merge branch 'main' into MRB-650-Maps-simplified
Louis-Frey Mar 20, 2026
ab36af2
Bug fix
Louis-Frey Mar 20, 2026
7dc82dc
Another Bug Fix.
Louis-Frey Mar 20, 2026
d33f776
More Bug fixes.
Louis-Frey Mar 20, 2026
8aa43f7
Separate spatial verification files
Louis-Frey Mar 30, 2026
c291f0f
Introduce Season Handling
Louis-Frey Mar 31, 2026
8afb9ac
Additional Log Statements for Map Plotting plus
Louis-Frey Apr 1, 2026
f8a6602
Fix all-NaN spatial verification output for cumulative params (TOT_PREC)
Louis-Frey Apr 1, 2026
26f6f9d
Add opt-in spatial verification via `evalml experiment --spatial`
Louis-Frey Apr 1, 2026
df65a71
Addendum suggested by Claude.
Louis-Frey Apr 2, 2026
be1bbef
Add default experiment config
Louis-Frey Apr 2, 2026
cf4ae6d
Spatial Verification Pipeline also for Baselines.
Louis-Frey Apr 2, 2026
c6a392d
Cosmetic Change.
Louis-Frey Apr 2, 2026
8a60301
Unify run and baseline spatial verification, restrict to configured i…
Louis-Frey Apr 30, 2026
50eaeff
Todo for future improvement of GRIB loading speed (profiling pending).
Louis-Frey Apr 30, 2026
75bbf6c
Move spatial map plots under plots/maps/
Louis-Frey Apr 30, 2026
0362d61
Drop preprocess_field cell and TOT_PREC quick-fix from spatial map plot
Louis-Frey May 4, 2026
4822d3b
Rename and re-design the map-plotting section of all example configs
Louis-Frey May 4, 2026
d1ca122
Rename "spatial verification" → "metric maps" throughout
Louis-Frey May 4, 2026
ef22a3f
Remove obsolete spatial-data filtering from dashboard script
Louis-Frey May 4, 2026
2636813
Move metric maps to results/{experiment}/metric_maps/
Louis-Frey May 4, 2026
b18c3c7
Remove stray files.
Louis-Frey May 5, 2026
85b1863
Cleanup: drop dead params block
Louis-Frey May 5, 2026
4e312f3
Untrack dev-only example configs
Louis-Frey May 5, 2026
223ef7d
Cleanup
Louis-Frey May 5, 2026
4674639
Cleanup
Louis-Frey May 5, 2026
bc2571d
More Cleanup
Louis-Frey May 5, 2026
74d1548
More Cleanup
Louis-Frey May 5, 2026
6b39d80
More Cleanup ...
Louis-Frey May 5, 2026
51bf6d6
Improved Domains
Louis-Frey May 5, 2026
3151447
Tidy plot_summary_stat_maps.mo.py: drop dead code and dev comments
Louis-Frey May 5, 2026
9293f37
Black coast lines and country borders for better visibility
Louis-Frey May 5, 2026
3a2e7ad
Drop hardcoded SLURM node-exclude lines
Louis-Frey May 5, 2026
91fab2f
Merge remote-tracking branch 'origin/main' into MRB-650-Maps-simplified
Louis-Frey May 5, 2026
04022f8
Revert "Drop hardcoded SLURM node-exclude lines"
Louis-Frey May 5, 2026
4d1aa65
Apply pre-commit auto-fixes (whitespace, formatting, linting)
Louis-Frey May 5, 2026
94a7b0a
Drop hardcoded SLURM node-exclude lines
Louis-Frey May 5, 2026
413a1f6
metric_maps config section for interpolator too.
Louis-Frey May 5, 2026
ececb1e
Fix single-leadtime TOT_PREC verification in maps rules
Louis-Frey May 8, 2026
5ed413b
Rename plot_summary_stat_maps[_baseline] -> plot_metric_maps[_baseline]
Louis-Frey May 8, 2026
445020e
Merge remote-tracking branch 'origin/main' into MRB-650-Maps-simplified
Louis-Frey May 8, 2026
4326de5
Revert .gitignore changes to match main
Louis-Frey May 8, 2026
de72f2a
Revert changes to .gitignore
Louis-Frey May 8, 2026
52e60bf
...
Louis-Frey May 8, 2026
9042795
Comment out local map plotting.
Louis-Frey May 8, 2026
4961065
Drop ad-hoc SP_10M derivation from verification_metrics.py
Louis-Frey May 8, 2026
858f872
Skip unnecessary comment.
Louis-Frey May 8, 2026
1244b7c
Drop another unnecessary comment.
Louis-Frey May 8, 2026
080509e
Tidy colormap_defaults.py: drop wishful-thinking comments
Louis-Frey May 8, 2026
c6fffd1
Add init_hour stratification to metric maps
Louis-Frey May 11, 2026
90ff476
Apply ruff-format to metric_maps scripts
Louis-Frey May 11, 2026
e9fbef9
Rename "metric maps" → "score maps" for naming consistency
Louis-Frey Jun 1, 2026
77c9a64
Add `leadtimes: "all"` shortcut to score_maps config
Louis-Frey Jun 4, 2026
eb0f519
Scope baseline score-maps paths by truth_label
Louis-Frey Jun 4, 2026
7173cc2
Scope verification_score_maps_baseline log path by truth_label
Louis-Frey Jun 4, 2026
7dfd8be
Add TODO note to consolidate truth-loading with data_input refactor
Louis-Frey Jun 4, 2026
3cda778
Drop empty "GRIB step helpers" section header
Louis-Frey Jun 4, 2026
008c92e
Derive baseline zarrs by glob instead of explicit CLI list
Louis-Frey Jun 4, 2026
082ff37
Require --output for verification_score_maps, drop unsafe fallback
Louis-Frey Jun 4, 2026
24ac031
Add STDE (standard deviation of error) score map
Louis-Frey Jun 4, 2026
91983fe
Rename score-maps "metric" selector → "score" for naming consistency
Louis-Frey Jun 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions config/forecasters-co1e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/forecasters-co2-disentangled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,36 @@ profile:
runtime: "1h"
gpus: 0
jobs: 50

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/forecasters-co2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/forecasters-ich1-oper-fixed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/forecasters-ich1-oper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/forecasters-ich1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/interpolators-co2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
33 changes: 33 additions & 0 deletions config/interpolators-ich1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,36 @@ profile:
jobs: 50
batch_rules:
plot_forecast_frame: 32

score_maps:
params:
- T_2M
# - TD_2M
# - U_10M
# - V_10M
# - SP_10M
# - PS
# - PMSL
# - TOT_PREC
leadtimes: [6, 24]
# Or, to compute every available leadtime from runs+baselines:
# leadtimes: "all"
scores:
- BIAS
# - RMSE
# - MAE
regions:
- switzerland
# - centraleurope
seasons:
- all
# - DJF
# - MAM
# - JJA
# - SON
init_hours:
- all
# - "00"
# - "06"
# - "12"
# - "18"
51 changes: 44 additions & 7 deletions src/data_input/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,21 +111,46 @@ def load_fct_data_from_grib(
root: Path, reftime: datetime, steps: list[int], params: list[str]
) -> xr.Dataset:
"""Load forecast data from GRIB files for a specific valid time."""
# TODO: this function carries a large per-call setup cost that is
# independent of data volume (likely eccodes/FileDataSource init or GRIB
# index build, not decoding). It dominates runtime in any rule that calls
# it inside a per-init-time loop (e.g. verification_score_maps) and also
# adds noticeable overhead to verif_metrics and the plot rules.
files = sorted(root.glob(f"{reftime:%Y%m%d%H%M}*.grib"))
fds = data_source.FileDataSource(datafiles=files)
ds = grib_decoder.load(fds, {"param": params, "step": steps})
# For TOT_PREC (cumulative-from-start) we need step 0 to disaggregate to a
# 0->step period accumulation even when the caller asks for a single step.
# anemoi-inference may omit step 0 from the GRIB; tolerate that and
# synthesize lead_time=0, TOT_PREC=0 below (cumulative-from-start has
# nothing accumulated at the IC by definition).
needs_step_zero = "TOT_PREC" in params and 0 not in steps
fetch_steps = [0, *steps] if needs_step_zero else list(steps)
ds = grib_decoder.load(fds, {"param": params, "step": fetch_steps})
# grib_decoder.load may silently drop steps that aren't on disk
# (anemoi-inference often omits step 0 even with cumulative-from-start
# accumulation). Detect that here so the TOT_PREC block can synthesize
# lead_time=0, TOT_PREC=0 below.
zero_lt = np.timedelta64(0, "h")
loaded_lead_times = next(iter(ds.values())).lead_time.values
step_zero_synthetic = needs_step_zero and zero_lt not in loaded_lead_times
for var, da in ds.items():
if "z" in da.dims and da.sizes["z"] == 1:
ds[var] = da.squeeze("z", drop=True)
elif "z" in da.dims and da.sizes["z"] > 1:
ds[var] = da.rename({"z": da.attrs["vcoord_type"]})
ds = xr.merge([ds[p].rename(p) for p in ds], compat="no_conflicts")
lead_times = np.array(steps, dtype="timedelta64[h]")
# Restrict to the requested lead times so that the TOT_PREC disaggregation
# below operates on the correct step interval even if the GRIB contains
# extra (e.g. hourly) steps beyond those requested — e.g. when consuming
# output from an interpolator emulator or a baseline with sub-step output.
ds = ds.sel(lead_time=lead_times)
fetch_lead_times = np.array(fetch_steps, dtype="timedelta64[h]")
# Restrict to the lead times we'll work with (fetch_lead_times = requested
# steps + step 0 if needed). This drops any extra (e.g. hourly) steps the
# GRIB may contain beyond what we asked for — e.g. when consuming output
# from an interpolator emulator or a baseline with sub-step output.
if step_zero_synthetic:
# Step 0 is missing from the GRIB; reindex inserts NaN at lead 0,
# which the xr.where below replaces with 0.
ds = ds.sel(lead_time=lead_times).reindex(lead_time=fetch_lead_times)
else:
ds = ds.sel(lead_time=fetch_lead_times)
if "TOT_PREC" in ds.data_vars:
## Disaggregate TOT_PREC from cumulative-from-start (expected when the
## accumulate_from_start_of_forecast post-processor is enabled in
Expand Down Expand Up @@ -166,6 +191,8 @@ def load_fct_data_from_grib(
## small float-noise negatives to zero (anything below -0.1 mm has
## already been caught by the check above).
ds = ds.assign(TOT_PREC=diff.clip(min=0.0).reindex(lead_time=lead_times))
# Drop the auxiliary step 0 from any non-TOT_PREC variables.
ds = ds.sel(lead_time=lead_times)
# make sure time coordinate is available, and valid_time is not
if "valid_time" in ds.coords:
ds = ds.rename({"valid_time": "time"})
Expand All @@ -192,10 +219,18 @@ def load_baseline_from_zarr(
{"forecast_reference_time": "ref_time", "step": "lead_time"}
).sortby("lead_time")
lead_times = np.array(steps, dtype="timedelta64[h]")
# For TOT_PREC (cumulative-from-start) we need step 0 in the slice so that
# .diff() yields a 0->step period accumulation even when the caller
# requested a single step. The extra step is dropped at the final reindex.
zero_lt = np.timedelta64(0, "h")
if "TOT_PREC" in params and zero_lt not in lead_times:
fetch_lead_times = np.concatenate([[zero_lt], lead_times])
else:
fetch_lead_times = lead_times
# Restrict to the requested lead times up-front so that the TOT_PREC
# disaggregation below operates on the correct step interval, and so that
# all other variables avoid loading unused hourly steps from the zarr.
baseline = baseline[params].sel(ref_time=reftime, lead_time=lead_times)
baseline = baseline[params].sel(ref_time=reftime, lead_time=fetch_lead_times)
if "TOT_PREC" in baseline.data_vars:
if baseline.TOT_PREC.units == "m":
baseline = baseline.assign(TOT_PREC=lambda x: x.TOT_PREC * 1000)
Expand All @@ -222,6 +257,8 @@ def load_baseline_from_zarr(
baseline = baseline.assign(
TOT_PREC=diff.clip(min=0.0).reindex(lead_time=lead_times)
)
# Drop the auxiliary step 0 from any non-TOT_PREC variables.
baseline = baseline.sel(lead_time=lead_times)
baseline = baseline.assign_coords(time=baseline.ref_time + baseline.lead_time)
if "latitude" in baseline.coords and "longitude" in baseline:
baseline = baseline.rename({"latitude": "lat", "longitude": "lon"})
Expand Down
Loading