diff --git a/src/itzi/providers/grass_interface.py b/src/itzi/providers/grass_interface.py index d145db62..eef5466d 100644 --- a/src/itzi/providers/grass_interface.py +++ b/src/itzi/providers/grass_interface.py @@ -369,6 +369,14 @@ def get_sim_extend_in_stds_unit(self, strds) -> tuple[int | datetime, int | date # get start time and end time in seconds rel_end_time = (self.end_time - self.start_time).total_seconds() rel_unit = strds.get_relative_time_unit() + if rel_unit not in self.t_unit_conv: + supported_units = ", ".join(sorted(self.t_unit_conv)) + if rel_unit is None: + msgr.fatal(f"STRDS <{strds.get_id()}> has no relative time unit") + msgr.fatal( + f"STRDS <{strds.get_id()}> uses unsupported relative time unit " + f"<{rel_unit}>; supported units are {supported_units}" + ) start_time_in_stds_unit = 0 end_time_in_stds_unit = self.from_s(rel_unit, rel_end_time) elif strds.get_temporal_type() == TemporalType.ABSOLUTE: @@ -387,6 +395,12 @@ def stds_temporal_sanity(self, stds_id: str) -> bool: """ out = True stds = tgis.open_stds.open_old_stds(stds_id, "strds") + stds_start, stds_end = stds.get_temporal_extent_as_tuple() + if stds_start is None or stds_end is None: + msgr.fatal( + f"STRDS <{stds_id}> has no temporal extent; " + "make sure it contains registered raster maps" + ) # valid topology if not stds.check_temporal_topology(): out = False @@ -397,7 +411,6 @@ def stds_temporal_sanity(self, stds_id: str) -> bool: msgr.warning("{}: gaps found".format(stds_id)) # cover all simulation time sim_start, sim_end = self.get_sim_extend_in_stds_unit(stds) - stds_start, stds_end = stds.get_temporal_extent_as_tuple() if stds_start > sim_start: out = False msgr.warning("{}: starts after simulation".format(stds_id)) diff --git a/tests/grass/test_itzi.py b/tests/grass/test_itzi.py index d10b3159..bcdec638 100644 --- a/tests/grass/test_itzi.py +++ b/tests/grass/test_itzi.py @@ -195,6 +195,87 @@ def test_fails_when_region_has_no_dem_data(test_data_temp_path): SimulationRunner(conf_data.get_sim_params(), conf_data.get_grass_params()) +@pytest.mark.forked +@pytest.mark.usefixtures("grass_5by5") +@pytest.mark.parametrize("temporal_type", ["relative", "absolute"]) +def test_empty_strds_fails_with_clear_error(test_data_temp_path, temporal_type: str): + current_mapset = gscript.read_command("g.mapset", flags="p").rstrip() + strds_name = f"empty_{temporal_type}_rain_{uuid4().hex[:8]}" + gscript.run_command( + "t.create", + output=strds_name, + type="strds", + temporaltype=temporal_type, + semantictype="mean", + title=strds_name, + description=strds_name, + ) + + input_names = { + "rain": f"{strds_name}@{current_mapset}", + "water_depth": f"start_h@{current_mapset}", + } + with pytest.raises( + RuntimeError, + match=rf"STRDS <{strds_name}@{current_mapset}> has no temporal extent", + ): + _build_timed_rain_runner( + test_data_temp_path, + input_names=input_names, + duration="00:00:20", + record_step="00:00:20", + prefix=f"out_empty_{temporal_type}_{uuid4().hex[:8]}", + ) + + +@pytest.mark.forked +@pytest.mark.usefixtures("grass_5by5") +def test_relative_strds_with_unsupported_unit_fails_with_clear_error(test_data_temp_path): + current_mapset = gscript.read_command("g.mapset", flags="p").rstrip() + suffix = uuid4().hex[:8] + strds_name = f"monthly_rain_{suffix}" + rain_map_name = f"monthly_rain_map_{suffix}" + gscript.mapcalc(f"{rain_map_name}=10") + gscript.run_command( + "t.create", + output=strds_name, + type="strds", + temporaltype="relative", + semantictype="mean", + title=strds_name, + description=strds_name, + ) + gscript.run_command( + "t.register", + flags="i", + input=strds_name, + type="raster", + maps=rain_map_name, + start="0", + increment="1", + unit="months", + ) + + input_names = { + "rain": f"{strds_name}@{current_mapset}", + "water_depth": f"start_h@{current_mapset}", + } + with pytest.raises( + RuntimeError, + match=( + rf"STRDS <{strds_name}@{current_mapset}> uses unsupported relative time unit " + r"" + ), + ): + _build_timed_rain_runner( + test_data_temp_path, + input_names=input_names, + duration="00:00:20", + record_step="00:00:20", + prefix=f"out_monthly_relative_{uuid4().hex[:8]}", + ) + + @pytest.mark.forked @pytest.mark.usefixtures("grass_5by5") @pytest.mark.parametrize(