Skip to content

Document antimeridian limitations of the ensemble scores#41

Merged
vadmbertr merged 1 commit into
mainfrom
feature/score-antimeridian-docs
Jul 9, 2026
Merged

Document antimeridian limitations of the ensemble scores#41
vadmbertr merged 1 commit into
mainfrom
feature/score-antimeridian-docs

Conversation

@vadmbertr

@vadmbertr vadmbertr commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Motivation

The scoring rules in score.py operate on the raw [lon, lat] components and are not aware of the ±180° antimeridian:

  • squared_error / energy_score use the default Euclidean l2_distance kernel;
  • dawid_sebastiani takes a sample covariance and Mahalanobis term in raw [lon, lat];
  • variogram_score takes cross-component |X_i − X_j| differences on absolute longitude.

So a pair straddling the dateline (e.g. 179° and −179°) reads as ~358° apart rather than ~2°, and a forecast and observation supplied in different longitude conventions (one wrapped to [-180, 180), the other carrying the solver's unbounded longitude) are compared inconsistently. This is a realistic failure mode now that the integrator leaves longitude unbounded.

By contrast, everything in metric.py (separation_distance, normalized_separation_distance, liu_index) is already seam-safe — it routes through haversine, which is periodic in longitude.

Change

Documentation only — no behaviour change:

  • A module-level .. warning:: in score.py explaining the antimeridian/convention pitfall and the mitigations.
  • A per-function .. note:: on each of the four scores:
    • squared_error / energy_score: pass a great-circle kernel (kernel=pastax.haversine or pastax.metric.separation_distance) and keep inputs in one convention. For energy_score, also note the propriety trade-off (Euclidean is strictly proper; geodesic is not guaranteed to be — a chordal distance is both seam-safe and strictly proper).
    • dawid_sebastiani / variogram_score: no kernel hook, so they rely on keeping every input (ensemble members and observation) in one consistent longitude convention, away from the seam — e.g. normalized the same way with wrap_longitude.

Tests

None added (docstring-only). ruff check src tests passes; pytest tests/test_score.py → 53 passed; the package imports cleanly.

The scores in score.py operate on raw [lon, lat] components: squared_error and
energy_score via the default Euclidean l2_distance kernel, and dawid_sebastiani
/ variogram_score directly (sample covariance and cross-component differences).
None is aware of the ±180° seam, so a pair straddling the dateline reads as
~358° apart, and a forecast and observation given in different longitude
conventions are compared inconsistently — a real risk now that the solver
leaves integrated longitude unbounded.

Add an antimeridian warning to the module docstring and a per-function note to
each score, pointing at the mitigations: a great-circle kernel
(kernel=haversine or metric.separation_distance) for the kernel-based scores,
and a single consistent longitude convention (e.g. via wrap_longitude) for all
four. Documentation only — no behaviour change. The metrics in metric.py are
already seam-safe (they route through haversine).
@vadmbertr
vadmbertr marked this pull request as ready for review July 9, 2026 11:17
@vadmbertr
vadmbertr merged commit ee77220 into main Jul 9, 2026
1 check passed
@vadmbertr
vadmbertr deleted the feature/score-antimeridian-docs branch July 9, 2026 11:17
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