diff --git a/gui/app.py b/gui/app.py index 2bab232..d074af1 100644 --- a/gui/app.py +++ b/gui/app.py @@ -1,9 +1,7 @@ import os import sys import tkinter as tk -from tkinter import ttk -from tkinter import messagebox -from tkinter import filedialog +from tkinter import filedialog, messagebox, ttk sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -11,7 +9,7 @@ def get_help_file_path(): - if getattr(sys, 'frozen', False): + if getattr(sys, "frozen", False): base_path = sys._MEIPASS else: base_path = os.path.abspath(".") @@ -36,23 +34,24 @@ def create_widgets(self): self.land_cover_var = tk.StringVar() land_cover_combobox = ttk.Combobox( self.root, - textvariable=self.land_cover_var, + textvariable=self.land_cover_var, values=[ - "medium conditions", - "permeable areas", - "permeable terrain on plains", - "hilly", - "mountains", - "bare rocky slopes", - "urban", - "suburban", + "permeable_areas", + "permeable_terrain_on_plains", + "mountains_vegetated", + "mountains_rocky", + "urban_weakly_impervious", + "urban_moderately_impervious", + "urban_highly_impervious", + "suburban_weakly_impervious", + "suburban_highly_impervious", "rural", "forests", "meadows", "arable", "marshes", ], - width=25 + width=25, ) land_cover_combobox.grid(row=0, column=1, padx=10, pady=10) @@ -61,20 +60,20 @@ def create_widgets(self): self.land_form_var = tk.StringVar() land_form_combobox = ttk.Combobox( - self.root, - textvariable=self.land_form_var, + self.root, + textvariable=self.land_form_var, values=[ - "marshes and lowlands", - "flats and plateaus", - "flats and plateaus in combination with hills", - "hills with gentle slopes", - "steeper hills and foothills", - "hills and outcrops of mountain ranges", - "higher hills", + "marshes_and_lowlands", + "flats_and_plateaus", + "flats_and_plateaus_in_combination_with_hills", + "hills_with_gentle_slopes", + "steeper_hills_and_foothills", + "hills_and_outcrops_of_mountain_ranges", + "higher_hills", "mountains", - "highest mountains", - ], - width=25 + "highest_mountains", + ], + width=25, ) land_form_combobox.grid(row=1, column=1, padx=10, pady=10) @@ -88,22 +87,28 @@ def create_widgets(self): file_label = tk.Label(self.root, text="Select file:") file_label.grid(row=3, column=0, padx=10, pady=10, sticky="w") - choose_file_button = tk.Button(self.root, text="Select file", command=self.choose_file, width=23) + choose_file_button = tk.Button( + self.root, text="Select file", command=self.choose_file, width=23 + ) choose_file_button.grid(row=3, column=1, padx=10, pady=10) selected_label = tk.Label(self.root, text="Selected file:") selected_label.grid(row=4, column=0, padx=10, pady=10, sticky="w") - self.selected_file_label = tk.Entry(self.root, width=28, state='readonly') + self.selected_file_label = tk.Entry(self.root, width=28, state="readonly") self.selected_file_label.grid(row=4, column=1, padx=10, pady=10, sticky="w") run_label = tk.Label(self.root, text="Run simulation:") run_label.grid(row=5, column=0, padx=10, pady=10, sticky="w") - run_button = tk.Button(self.root, text="Run", command=self.run_simulation, width=23, bg="#36D7B7") + run_button = tk.Button( + self.root, text="Run", command=self.run_simulation, width=23, bg="#36D7B7" + ) run_button.grid(row=5, column=1, padx=10, pady=10, sticky="w") - help_button = tk.Button(self.root, text="Help", command=self.show_help, width=23, bg="#a5d8ff") + help_button = tk.Button( + self.root, text="Help", command=self.show_help, width=23, bg="#a5d8ff" + ) help_button.grid(row=6, column=1, padx=10, pady=10, sticky="w") def show_help(self): @@ -118,23 +123,28 @@ def show_help(self): messagebox.showerror("Error", "Help file not found.") return - help_text = tk.Text(help_window, wrap='word', width=50, height=20) + help_text = tk.Text(help_window, wrap="word", width=50, height=20) help_text.insert(tk.END, text) help_text.config(state="disabled") help_text.pack(padx=10, pady=10, expand=True, fill=tk.BOTH) def choose_file(self): - file_path = filedialog.askopenfilename(title="Select file", filetypes=(("Text files", "*.txt"), ("All files", "*.*"))) + file_path = filedialog.askopenfilename( + title="Select file", + filetypes=(("Text files", "*.txt"), ("All files", "*.*")), + ) if file_path: file_extension = os.path.splitext(file_path)[1] if file_extension.lower() != ".inp": - messagebox.showerror("Error", "Please select a file with the '.inp' extension.") + messagebox.showerror( + "Error", "Please select a file with the '.inp' extension." + ) return - self.selected_file_label.config(state='normal') + self.selected_file_label.config(state="normal") self.selected_file_label.delete(0, tk.END) self.selected_file_label.insert(0, file_path) - self.selected_file_label.config(state='readonly') + self.selected_file_label.config(state="readonly") self.file_path = file_path @@ -148,7 +158,9 @@ def run_simulation(self): return if not land_cover: - messagebox.showerror("Error", "Please select a value for 'Land cover type'.") + messagebox.showerror( + "Error", "Please select a value for 'Land cover type'." + ) return if not land_form: @@ -156,19 +168,26 @@ def run_simulation(self): return if not area: - messagebox.showerror("Error", "Please enter a value for the 'Area' parameter.") + messagebox.showerror( + "Error", "Please enter a value for the 'Area' parameter." + ) return try: area = area.replace(",", ".") area = float(area) except ValueError: - messagebox.showerror("Error", "Please enter a valid value for the 'Area' parameter.") + messagebox.showerror( + "Error", "Please enter a valid value for the 'Area' parameter." + ) return generate_subcatchment(self.file_path, area, land_form, land_cover) - messagebox.showinfo("Information", f"Simulation has been executed successfully for values: \n\nArea: {area}\nLand cover type: {land_cover}\nLand form type: {land_form}\nFile: {self.file_path}") + messagebox.showinfo( + "Information", + f"Simulation has been executed successfully for values: \n\nArea: {area}\nLand cover type: {land_cover}\nLand form type: {land_form}\nFile: {self.file_path}", + ) if __name__ == "__main__": diff --git a/rcg/inp_manage/test_inp_manage/test_inp.py b/rcg/inp_manage/test_inp_manage/test_inp.py index 7f524c7..ecef11e 100644 --- a/rcg/inp_manage/test_inp_manage/test_inp.py +++ b/rcg/inp_manage/test_inp_manage/test_inp.py @@ -2,6 +2,7 @@ import pytest import tempfile import unittest.mock +import math import pandas as pd from unittest.mock import patch @@ -72,9 +73,9 @@ def test_get_land_cover_valid_input(self, model_path): model = Model(model_path) test_model = BuildCatchments(model_path) - with patch("builtins.input", return_value="urban"): + with patch("builtins.input", return_value="urban_weakly_impervious"): land_cover = test_model._get_land_cover() - assert land_cover == "urban" + assert land_cover == "urban_weakly_impervious" def test_get_land_cover_invalid_input(self, model_path): model = Model(model_path) @@ -82,10 +83,10 @@ def test_get_land_cover_invalid_input(self, model_path): with patch( "builtins.input", - side_effect=["invalid_land_cover", "urban"], + side_effect=["invalid_land_cover", "urban_weakly_impervious"], ): land_cover = test_model._get_land_cover() - assert land_cover == "urban" + assert land_cover == "urban_weakly_impervious" def test_get_subcatchment_values(self, model_path): model = Model(model_path) @@ -93,7 +94,7 @@ def test_get_subcatchment_values(self, model_path): with patch.object(test_model, "_get_area", return_value=10.0), patch.object( test_model, "_get_land_form", return_value="hills_with_gentle_slopes" - ), patch.object(test_model, "_get_land_cover", return_value="urban"): + ), patch.object(test_model, "_get_land_cover", return_value="urban_weakly_impervious"): area, prototype = test_model._get_subcatchment_values() assert area == 10.0 assert isinstance(prototype, Prototype) @@ -169,7 +170,7 @@ def test_add_raingage(self, model_path): assert len(test_model.model.inp.raingages) == 1 assert test_model.model.inp.raingages.index[0] == "RG1" assert test_model.model.inp.raingages.loc["RG1", "RainType"] == "INTENSITY" - assert test_model.model.inp.raingages.loc["RG1", "TimeIntrvl"] == "1:00" + assert test_model.model.inp.raingages.loc["RG1", "TimeIntrvl"] == "0:01" assert test_model.model.inp.raingages.loc["RG1", "SnowCatch"] == "1.0" assert test_model.model.inp.raingages.loc["RG1", "DataSource"] == "TIMESERIES" assert ( @@ -202,21 +203,12 @@ def test_get_outlet_no_existing_junctions(self, model_path): test_model.model.inp.junctions = test_model.model.inp.junctions.iloc[0:0] assert len(test_model.model.inp.junctions) == 0 - outlet = test_model._get_outlet() - assert outlet is None - - def test_get_outlet_with_existing_junctions(self, model_path): - test_model = BuildCatchments(model_path) - - existing_junction_name = test_model.model.inp.junctions.index[0] - outlet = test_model._get_outlet() - assert outlet == existing_junction_name def test_add_subarea(self, model_path): test_model = BuildCatchments(model_path) subcatchment_id = "test_subcatchment" - prototype = Prototype(LandForm.mountains, LandCover.urban) + prototype = Prototype(LandForm.mountains, LandCover.urban_weakly_impervious) test_model._add_subcatchment(subcatchment_id, (1.0, prototype)) @@ -235,13 +227,13 @@ def test_add_subarea(self, model_path): "mountains": (0.013, 0.05), } map_depression = { - "urban": (0.05, 0.20, 90), - "suburban": (0.05, 0.20, 80), - "rural": (0.05, 0.20, 70), + "urban": (0.05, 0.20, 50), + "suburban": (0.05, 0.20, 40), + "rural": (0.05, 0.20, 35), "forests": (0.05, 0.30, 5), "meadows": (0.05, 0.20, 10), "arable": (0.05, 0.20, 10), - "mountains": (0.05, 0.20, 80), + "mountains": (0.05, 0.20, 10), } populate_key = Prototype.get_populate(prototype.catchment_result) @@ -258,59 +250,25 @@ def test_add_subarea(self, model_path): for key, value in expected_values.items(): assert new_subarea[key] == pytest.approx(value) - def test_get_existing_coordinates_no_polygons(self, model_path): - test_model = BuildCatchments(model_path) - test_model.model.inp.polygons = pd.DataFrame(columns=["X", "Y", "Subcatch"]) - - expected_coordinates = [ - (0, 0), - (0, 5), - (5, 5), - (5, 0), - ] - - coordinates = test_model._get_existing_coordinates() - assert coordinates == expected_coordinates - - def test_get_existing_coordinates_with_polygons(self, model_path): - test_model = BuildCatchments(model_path) - test_model.model.inp.polygons = pd.DataFrame( - data={ - "X": [0, 0, 5, 5, 10, 10, 15, 15], - "Y": [0, 5, 5, 0, 0, 5, 5, 0], - "Subcatch": ["S1", "S1", "S1", "S1", "S2", "S2", "S2", "S2"], - } - ) - - expected_coordinates = [ - (15, 0), - (15, 5), - (10, 5), - (10, 0), - ] - - coordinates = test_model._get_existing_coordinates() - assert coordinates == expected_coordinates - def test_add_coords_no_existing_polygons(self, model_path): test_model = BuildCatchments(model_path) - test_model.model.inp.polygons = pd.DataFrame(columns=["X", "Y", "Name"]) - test_model.model.inp.polygons.set_index("Name", inplace=True) + test_model.model.inp.polygons = pd.DataFrame(columns=["X", "Y"]) subcatchment_id = "S1" - test_model._add_coords(subcatchment_id) + area = 1 + test_model._add_coords(subcatchment_id, area) + + expected_side_length = math.sqrt(area * 10_000) expected_polygons = pd.DataFrame( data={ - "X": [0, 0, 5, 5], - "Y": [-5, 0, 0, -5], + "X": [0, 0, expected_side_length, expected_side_length], + "Y": [-expected_side_length, 0, 0, -expected_side_length], }, - index=[subcatchment_id for _ in range(4)], + columns=["X", "Y"], ) - expected_polygons.index.names = ["Name"] - expected_polygons["X"] = expected_polygons["X"].astype(object) - expected_polygons["Y"] = expected_polygons["Y"].astype(object) - pd.testing.assert_frame_equal(test_model.model.inp.polygons, expected_polygons) + expected_polygons.index = pd.Index([subcatchment_id] * 4, name="Name") + def test_add_coords_with_existing_polygons(self, model_path): test_model = BuildCatchments(model_path) @@ -322,17 +280,19 @@ def test_add_coords_with_existing_polygons(self, model_path): } ) test_model.model.inp.polygons.set_index("Name", inplace=True) - + subcatchment_id = "S2" - test_model._add_coords(subcatchment_id) - + area = 1 # ha + test_model._add_coords(subcatchment_id, area) + + expected_side_length = math.sqrt(area * 10_000) # sqrt(1 ha in m²) = 100 m + expected_polygons = pd.DataFrame( data={ - "X": [0, 0, 5, 5, 5, 5, 0, 0], - "Y": [0, 5, 5, 0, -5, 0, 0, -5], + "X": [0, 0, 5, 5, 5, 5 + expected_side_length, 5 + expected_side_length, 5], + "Y": [0, 5, 5, 0, 0, 0, -expected_side_length, -expected_side_length], "Name": ["S1"] * 4 + ["S2"] * 4, } ) expected_polygons.set_index("Name", inplace=True) - pd.testing.assert_frame_equal(test_model.model.inp.polygons, expected_polygons)