diff --git a/src/modelskill/matching.py b/src/modelskill/matching.py index 38e5c913a..3ac14a753 100644 --- a/src/modelskill/matching.py +++ b/src/modelskill/matching.py @@ -382,8 +382,6 @@ def _match_single_obs( def _get_global_start_end(idxs: Iterable[pd.DatetimeIndex]) -> Period: - assert all([len(x) > 0 for x in idxs]), "All datetime indices must be non-empty" - starts = [x[0] for x in idxs] ends = [x[-1] for x in idxs] @@ -408,6 +406,22 @@ def _check_timezone_compatibility( ) +def _check_model_results_not_empty( + observation: Observation, + raw_mod_data: Mapping[ + str, + PointModelResult | TrackModelResult | VerticalModelResult | NodeModelResult, + ], +) -> None: + for name, mr in raw_mod_data.items(): + if len(mr.time) == 0: + raise ValueError( + f"Model result '{name}' has no data at observation '{observation.name}'. " + "Check that the observation is inside the model domain and that the " + "model has valid values there (e.g. the location is not dry)." + ) + + def _at_observation(mr: NodeModelResult, obs: TimeSeries) -> NodeModelResult: """The extracted model result, placed where the observation sits. @@ -431,6 +445,7 @@ def _match_space_time( obs_no_overlap: Literal["ignore", "error", "warn"], ) -> xr.Dataset | None: _check_timezone_compatibility(observation, raw_mod_data) + _check_model_results_not_empty(observation, raw_mod_data) idxs = [m.time for m in raw_mod_data.values()] period = _get_global_start_end(idxs) diff --git a/tests/test_match.py b/tests/test_match.py index 0d0032269..dbf370b40 100644 --- a/tests/test_match.py +++ b/tests/test_match.py @@ -963,6 +963,23 @@ def test_match_raises_clear_error_on_tz_aware_vs_naive_mismatch(): ms.match(obs, mr) +def test_match_raises_clear_error_when_model_result_is_empty(): + """An empty extraction (e.g. point outside domain or dry) must raise a clear error, not a bare assert.""" + obs = ms.PointObservation( + data=pd.Series( + [1.0, 2.0, 3.0], index=pd.date_range("2020-01-01", periods=3, freq="h") + ), + name="Station", + ) + mr = ms.PointModelResult( + data=pd.Series([], dtype=float, index=pd.DatetimeIndex([])), + name="Model", + ) + + with pytest.raises(ValueError, match="'Model' has no data.*'Station'"): + ms.match(obs, mr) + + def test_multiple_models_same_name(tmp_path: Path) -> None: obs = ms.PointObservation( "tests/testdata/SW/HKNA_Hm0.dfs0", item=0, x=4.2420, y=52.6887, name="HKNA"