From e04767d32a6529ad026946a5e759770df827c8a1 Mon Sep 17 00:00:00 2001 From: Giovanni Cozzolongo Date: Tue, 18 Aug 2026 09:28:43 +0200 Subject: [PATCH] Preserve mapped forecast dates --- AUTHORS.md | 1 + CHANGELOG.md | 1 + climada/hazard/forecast.py | 6 ++++-- climada/hazard/test/test_forecast.py | 30 ++++++++++++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 20abd4b0ec..5df024637d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -37,3 +37,4 @@ * Samuel Juhel * Valentin Gebhart * Dahyann Araya +* Giovanni Cozzolongo diff --git a/CHANGELOG.md b/CHANGELOG.md index fe3eb4e99e..47c78a8272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Code freeze date: YYYY-MM-DD ### Fixed +- Preserve explicitly mapped dates in `HazardForecast.from_xarray_raster` [#1305](https://github.com/CLIMADA-project/climada_python/issues/1305). - Fixed asset count in impact logging message [#1195](https://github.com/CLIMADA-project/climada_python/pull/1195). - `Hazard.from_raster_xarray` now returns a sparse matrix instead of a sparse array [#1261](https://github.com/CLIMADA-project/climada_python/pull/1261). - Fix TCTracks.from_FAST duplicate loading from year loop [#1269](github.com/CLIMADA-project/climada_python/pull/1269) diff --git a/climada/hazard/forecast.py b/climada/hazard/forecast.py index 884e544e51..6e8d4e51da 100644 --- a/climada/hazard/forecast.py +++ b/climada/hazard/forecast.py @@ -443,7 +443,8 @@ def from_xarray_raster( data_vars : dict(str, str), optional Mapping from default variable names to variable names used in the data to read. See :py:meth:`~climada.hazard.io.HazardIO.from_xarray_raster` for - details. + details. To load forecast dates, map ``date`` to the corresponding + variable. Dates default to 0 when no date mapping is provided. crs : str, optional Coordinate reference system identifier. Defaults to "EPSG:4326". rechunk : bool, optional @@ -537,7 +538,8 @@ def from_xarray_raster( f"lt_{lt / np.timedelta64(1, 'h'):.0f}h_m_{m}" for lt, m in zip(kwargs["lead_time"], kwargs["member"]) ] - kwargs["date"] = np.zeros_like(kwargs["date"], dtype=int) + if not (data_vars or {}).get("date"): + kwargs["date"] = np.zeros_like(kwargs["date"], dtype=int) # Convert to HazardForecast with forecast attributes return cls(**Hazard._check_and_cast_attrs(kwargs)) diff --git a/climada/hazard/test/test_forecast.py b/climada/hazard/test/test_forecast.py index fcc683cb19..cdb8952fd5 100644 --- a/climada/hazard/test/test_forecast.py +++ b/climada/hazard/test/test_forecast.py @@ -187,6 +187,7 @@ def forecast_netcdf_file(self, tmp_path_factory): "n_lat": n_lat, "n_lon": n_lon, "eps": eps, + "ref_time": ref_time[0], "lead_time": lead_time_vals, "lon": lon, "lat": lat, @@ -263,9 +264,10 @@ def test_from_xarray_raster_event_names(self, forecast_netcdf_file): ] npt.assert_array_equal(haz_fc.event_name, event_names_expected) + @pytest.mark.parametrize("data_vars", [None, {"date": ""}]) @xarray_leadtime - def test_from_xarray_raster_dates(self, forecast_netcdf_file): - """Test that dates are set to 0 for forecast events""" + def test_from_xarray_raster_dates(self, forecast_netcdf_file, data_vars): + """Test that dates default to 0 when no date coordinate is mapped""" haz_fc = HazardForecast.from_xarray_raster( forecast_netcdf_file["path"], hazard_type="PR", @@ -276,6 +278,7 @@ def test_from_xarray_raster_dates(self, forecast_netcdf_file): "lead_time": "lead_time", "member": "eps", }, + data_vars=data_vars, crs=forecast_netcdf_file["crs"], ) @@ -285,6 +288,29 @@ def test_from_xarray_raster_dates(self, forecast_netcdf_file): ) npt.assert_array_equal(haz_fc.date, np.zeros(expected_n_events, dtype=int)) + @xarray_leadtime + def test_from_xarray_raster_dates_from_data(self, forecast_netcdf_file): + """Test that an explicitly mapped date coordinate is preserved""" + haz_fc = HazardForecast.from_xarray_raster( + forecast_netcdf_file["path"], + hazard_type="PR", + intensity_unit="mm/h", + coordinate_vars={ + "longitude": "lon", + "latitude": "lat", + "lead_time": "lead_time", + "member": "eps", + }, + data_vars={"date": "valid_time"}, + crs=forecast_netcdf_file["crs"], + ) + + expected_dates = [ + pd.Timestamp(forecast_netcdf_file["ref_time"] + lead_time).toordinal() + for lead_time in haz_fc.lead_time + ] + npt.assert_array_equal(haz_fc.date, expected_dates) + class TestSelect: @pytest.mark.parametrize(