diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index ca2b1d5b..cdadcaf4 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -70,12 +70,20 @@ from View.SedimentLayers.Reach.Window import ReachSedimentLayersWindow from View.AdditionalFiles.Window import AddFileListWindow from View.REPLines.Window import REPLineListWindow from View.SolverParameters.Window import SolverParametersWindow -from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow +from View.RunSolver.Window import ( + SelectSolverWindow, + SolverLogWindow, + CompareSolversWindow + ) from View.CheckList.Window import CheckListWindow -from View.Results.Window import ResultsWindow +from View.Results.Window import ResultsWindow, CompareResultsWindow from View.Results.ReadingResultsDialog import ReadingResultsDialog from View.Debug.Window import ReplWindow +from Solver.Solvers import GenericSolver + +from Model.Results.Results import Results + # Optional internal display of documentation for make the application # package lighter... try: @@ -117,7 +125,7 @@ define_model_action = [ "action_menu_edit_reach_sediment_layers", "action_menu_edit_reservoirs", "action_menu_edit_hydraulic_structures", "action_menu_additional_file", "action_menu_results_last", "action_open_results_from_file", - "action_menu_boundary_conditions_sediment", + "action_compare_results", "action_menu_boundary_conditions_sediment", "action_menu_rep_additional_lines", ] @@ -255,6 +263,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): "action_menu_close": self.close_model, "action_menu_results_last": self.open_last_results, "action_open_results_from_file": self.open_results_from_file, + "action_compare_results": self.compare_results, # Help "action_menu_pamhyr_users_wiki": self.open_doc_user, "action_menu_pamhyr_developers_pdf": @@ -1344,6 +1353,103 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): results=file_name[0] ) + def compare_results(self): + if self._study is None: + return + + run = CompareSolversWindow( + study=self._study, + config=self.conf, + parent=self + ) + if run.exec(): + results = self.diff_results(run.solver1, + run.solver2) + + # At least one result not available + if results is None: + return + + # Windows already opened + if self.sub_window_exists( + ResultsWindow, + data=[ + self._study, + None, # No config + results._solver, + results + ] + ): + return + + res = CompareResultsWindow( + study=self._study, + solver=results._solver, + results=results, + parent=self + ) + res.show() + + + def diff_results(self, solver1, solver2): + if solver1 is None: + # TODO message + return None + if solver2 is None: + # TODO message + return None + + solver3 = GenericSolver(solver1.name+" - "+solver2.name) + + result1 = solver1.results( + self._study, + self._solver_workdir(solver1), + ) + + if result1 is None: + # TODO message + return None + + result2 = solver2.results( + self._study, + self._solver_workdir(solver2), + ) + + if result2 is None: + # TODO message + return None + + if result2.get("nb_reach") != result1.get("nb_reach"): + # TODO message + return None + + if result2.get("nb_profile") != result1.get("nb_profile"): + # TODO message + return None + + result3 = Results(self._study, solver3) + result3.set("nb_reach", result1.get("nb_reach")) + result3.set("nb_profile", result1.get("nb_profile")) + ts = list(result1.get("timestamps").intersection(result2.get("timestamps"))) + result3.set("timestamps", ts) + + for i in range(int(result1.get("nb_reach"))): + # Add reach to results reach list + r = result3.river.add(i) + + for timestamp in result3.get("timestamps"): + for r in range(int(result1.get("nb_reach"))): + reach1 = result1.river.reach(r) + reach2 = result2.river.reach(r) + reach3 = result3.river.reach(r) + for p, (profile1, profile2) in enumerate(zip(reach1.profiles, reach2.profiles)): + for key in ["Z", "Q"]: + d1 = profile1.get_ts_key(timestamp, key) + d2 = profile2.get_ts_key(timestamp, key) + reach3.set(p, timestamp, key, d1-d2) + + return result3 + ################# # DOCUMENTATION # ################# diff --git a/src/View/Results/Table.py b/src/View/Results/Table.py index 7a4c3b1d..b0d7e23f 100644 --- a/src/View/Results/Table.py +++ b/src/View/Results/Table.py @@ -123,7 +123,10 @@ class TableModel(PamhyrTableModel): v = self._lst[row].geometry.speed(q, z) a = self._lst[row].geometry.wet_area(z) b = self._lst[row].geometry.wet_width(z) - froude = v / sqrt(9.81 * (a / b)) + if b == 0.0 or a == 0.0: + froude = 0.0 + else: + froude = v / sqrt(9.81 * (a / b)) return f"{froude:.4f}" else: v = 0.0 diff --git a/src/View/Results/Window.py b/src/View/Results/Window.py index c87c998e..62ce832f 100644 --- a/src/View/Results/Window.py +++ b/src/View/Results/Window.py @@ -61,7 +61,10 @@ from View.Results.CustomPlot.CustomPlotValuesSelectionDialog import ( ) from View.Results.Table import TableModel -from View.Results.translate import ResultsTranslate +from View.Results.translate import ( + ResultsTranslate, + CompareResultsTranslate +) from View.Stricklers.Window import StricklersWindow _translate = QCoreApplication.translate @@ -83,11 +86,12 @@ class ResultsWindow(PamhyrWindow): def __init__(self, study=None, config=None, solver=None, results=None, - parent=None): + parent=None, trad=None): self._solver = solver self._results = results - trad = ResultsTranslate() + if trad is None: + trad = ResultsTranslate() name = ( trad[self._pamhyr_name] + " - " + study.name + " - " @@ -855,3 +859,38 @@ class ResultsWindow(PamhyrWindow): ) return my_dict + + +class CompareResultsWindow(ResultsWindow): + _pamhyr_ui = "Results" + _pamhyr_name = "Results" + + def _path_file(self, filename): + return os.path.abspath( + os.path.join( + os.path.dirname(__file__), + "..", "ui", "ressources", filename + ) + ) + + def __init__(self, study=None, config=None, + solver=None, results=None, + parent=None): + self._solver = solver + self._results = results + + trad = CompareResultsTranslate() + name = ( + trad[self._pamhyr_name] + " - " + + study.name + " - " + + self._solver.name + ) + + super(CompareResultsWindow, self).__init__( + study=study, + config=config, + solver=solver, + results=results, + parent=parent, + trad=trad + ) diff --git a/src/View/Results/translate.py b/src/View/Results/translate.py index cb6ae63e..2c028494 100644 --- a/src/View/Results/translate.py +++ b/src/View/Results/translate.py @@ -95,3 +95,35 @@ class ResultsTranslate(MainTranslate): "min_depth": self._dict["unit_min_depth"], "max_depth": self._dict["unit_max_depth"], } + +class CompareResultsTranslate(ResultsTranslate): + def __init__(self): + super(CompareResultsTranslate, self).__init__() + + self._dict['label_water'] = u"Δ "+_translate("Results", "Water elevation") + self._dict['unit_elevation'] = u"Δ "+self._dict["unit_elevation"] + + self._sub_dict["table_headers_raw_data"] = { + "name": _translate("Results", "Profile"), + "water_elevation": u"Δ "+self._dict["unit_water_elevation"], + "discharge": u"Δ "+self._dict["unit_discharge"], + "velocity": u"Δ "+self._dict["unit_velocity"], + "width": u"Δ "+self._dict["unit_width"], + "depth": u"Δ "+self._dict["unit_depth"], + "mean_depth": u"Δ "+self._dict["unit_mean_depth"], + "wet_area": u"Δ "+self._dict["unit_wet_area"], + "wet_perimeter": u"Δ "+self._dict["unit_wet_perimeter"], + "hydraulic_radius": u"Δ "+self._dict["unit_hydraulic_radius"], + "froude": u"Δ "+self._dict["unit_froude"], + } + + self._sub_dict["values_y"] = { + "bed_elevation": u"Δ "+self._dict["unit_bed_elevation"], + "water_elevation": u"Δ "+self._dict["unit_water_elevation"], + "discharge": u"Δ "+self._dict["unit_discharge"], + "velocity": u"Δ "+self._dict["unit_velocity"], + "depth": u"Δ "+self._dict["unit_depth"], + "mean_depth": u"Δ "+self._dict["unit_mean_depth"], + "froude": u"Δ "+self._dict["unit_froude"], + "wet_area": u"Δ "+self._dict["unit_wet_area"], + } diff --git a/src/View/RunSolver/Window.py b/src/View/RunSolver/Window.py index 6f9bf5e6..37c7a8b6 100644 --- a/src/View/RunSolver/Window.py +++ b/src/View/RunSolver/Window.py @@ -134,6 +134,107 @@ class SelectSolverWindow(PamhyrDialog): super(SelectSolverWindow, self).accept() +class CompareSolversWindow(PamhyrDialog): + _pamhyr_ui = "CompareSolvers" + _pamhyr_name = "Compare solvers" + + def __init__(self, study=None, config=None, + parent=None): + self._solver1 = None + self._solver2 = None + + name = _translate("Solver", "Compare solvers") + super(CompareSolversWindow, self).__init__( + title=name, + study=study, + config=config, + options=[], + parent=parent + ) + + self.setup_combobox1() + self.setup_combobox2() + self.setup_connections() + self.select_last_solver() + + def setup_combobox1(self): + solvers = self._config.solvers + solvers_name = list( + map( + self._format_solver_name, + solvers + ) + ) + + self.combobox_add_items("comboBox1", solvers_name) + + def setup_combobox2(self): + solvers = self._config.solvers + solvers_name = list( + map( + self._format_solver_name, + solvers + ) + ) + + self.combobox_add_items("comboBox2", solvers_name) + + def setup_connections(self): + self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept) + self.find(QPushButton, "pushButton_cancel")\ + .clicked.connect(self.reject) + + def select_last_solver(self): + solvers = self._config.solvers + last = self._config.last_solver_name + + solver = list( + filter( + lambda s: s.name == last, + solvers + ) + ) + + if len(solver) != 0: + self.set_combobox_text( + "comboBox1", + self._format_solver_name(solver[0]) + ) + + def _format_solver_name(self, solver): + return f"{solver.name} - ({solver._type})" + + @property + def solver1(self): + return self._solver1 + + @property + def solver2(self): + return self._solver2 + + def accept(self): + solver_name1 = self.get_combobox_text("comboBox1") + solver_name1 = solver_name1.rsplit(" - ", 1)[0] + + self._solver1 = next( + filter( + lambda s: s.name == solver_name1, + self._config.solvers + ) + ) + solver_name2 = self.get_combobox_text("comboBox2") + solver_name2 = solver_name2.rsplit(" - ", 1)[0] + + self._solver2 = next( + filter( + lambda s: s.name == solver_name2, + self._config.solvers + ) + ) + + super(CompareSolversWindow, self).accept() + + class SolverLogWindow(PamhyrWindow): _pamhyr_ui = "SolverLog" _pamhyr_name = "Solver Log" diff --git a/src/View/ui/CompareSolvers.ui b/src/View/ui/CompareSolvers.ui new file mode 100644 index 00000000..ac427713 --- /dev/null +++ b/src/View/ui/CompareSolvers.ui @@ -0,0 +1,61 @@ + + + Dialog + + + + 0 + 0 + 320 + 80 + + + + Dialog + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + OK + + + + + + + + + + + + + diff --git a/src/View/ui/MainWindow.ui b/src/View/ui/MainWindow.ui index 1156fca9..5f6ed597 100644 --- a/src/View/ui/MainWindow.ui +++ b/src/View/ui/MainWindow.ui @@ -158,6 +158,7 @@ + @@ -730,6 +731,14 @@ REP additional lines + + + false + + + Compare results + + diff --git a/tests_cases/Ardeche/Ardeche.pamhyr b/tests_cases/Ardeche/Ardeche.pamhyr index 1dc13ad2..cf33bf7f 100644 Binary files a/tests_cases/Ardeche/Ardeche.pamhyr and b/tests_cases/Ardeche/Ardeche.pamhyr differ diff --git a/tests_cases/Saar/Saar.pamhyr b/tests_cases/Saar/Saar.pamhyr index 5aba7521..e14c634a 100644 Binary files a/tests_cases/Saar/Saar.pamhyr and b/tests_cases/Saar/Saar.pamhyr differ