diff --git a/src/View/MainWindow.py b/src/View/MainWindow.py index 6306e77e..ae401e89 100644 --- a/src/View/MainWindow.py +++ b/src/View/MainWindow.py @@ -84,10 +84,12 @@ from View.SolverParameters.Window import SolverParametersWindow from View.RunSolver.Window import ( SelectSolverWindow, SolverLogWindow, - CompareSolversWindow ) from View.Results.Window import ResultsWindow +from View.Results.CompareDialog import ( + CompareSolversWindow, CompareScenariosWindow +) from View.RunSolver.WindowAdisTS import ( SelectSolverWindowAdisTS, @@ -128,8 +130,8 @@ no_model_action = [ model_action = [ "action_menu_close", "action_menu_edit", "action_menu_save", "action_menu_save_as", "action_toolBar_close", "action_toolBar_save", - "action_menu_numerical_parameter", "action_open_results_from_file", - "action_open_results_adists", + "action_menu_numerical_parameter", "action_menu_open_results_from_file", + "action_menu_open_results_adists", ] other_model_action = [ @@ -150,8 +152,9 @@ define_model_action = [ "action_menu_run_solver", "action_menu_sediment_layers", "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_compare_results", "action_menu_boundary_conditions_sediment", + "action_menu_results_last", "action_menu_open_results_from_file", + "action_menu_compare_results", "action_menu_compare_scenarios_results", + "action_menu_boundary_conditions_sediment", "action_menu_rep_additional_lines", "action_menu_output_rk", "action_menu_run_adists", "action_menu_pollutants", "action_menu_d90", "action_menu_dif", @@ -296,9 +299,10 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): "action_menu_rep_additional_lines": self.open_rep_lines, "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, - "action_open_results_adists": self.open_results_adists, + "action_menu_open_results_from_file": self.open_results_from_file, + "action_menu_compare_results": self.compare_results, + "action_menu_compare_scenarios_results": self.compare_results_scenarios, + "action_menu_open_results_adists": self.open_results_adists, # Help "action_menu_pamhyr_users_wiki": self.open_doc_user, "action_menu_pamhyr_developers_pdf": @@ -1641,13 +1645,16 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ) res.show() - def _solver_workdir(self, solver): + def _solver_workdir(self, solver, scenario=None): + if scenario is None: + scenario = self._study.status.scenario + workdir = os.path.join( os.path.dirname(self._study.filename), "_PAMHYR_", self._study.name.replace(" ", "_"), solver.name.replace(" ", "_"), - self._study.status.scenario.workdir(), + scenario.workdir(), ) return workdir @@ -1724,7 +1731,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): # Windows already opened if self.sub_window_exists( - ResultsWindow, + CompareSolversWindow, data=[self._study, None] + [r._solver for r in results] + [r._repertory for r in results] + @@ -1739,6 +1746,46 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ) res.show() + def compare_results_scenarios(self): + if self._study is None: + return + + dlg = CompareScenariosWindow( + study=self._study, + config=self.conf, + parent=self + ) + if not dlg.exec(): + return + + results = self.diff_results( + dlg.solver1, dlg.solver2, + scenario1=dlg.scenario1, + scenario2=dlg.scenario2 + ) + + # At least one result not available + if results is None: + return + + # Windows already opened + if self.sub_window_exists( + CompareScenariosWindow, + data=[self._study, None] + + [r._solver for r in results] + + [r._repertory for r in results] + + [r._name for r in results] + + [dlg.scenario1, dlg.scenario2] + ): + return + + res = ResultsWindow( + study=self._study, + results=results, + parent=self + ) + res.show() + def msg_diff_results_param(self): self.message_box( window_title=self._trad["Error"], @@ -1754,21 +1801,33 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit): ) @timer - def diff_results(self, solver1, solver2): + def diff_results(self, solver1, solver2, + scenario1=None, scenario2=None): if solver1 is None or solver2 is None: self.msg_diff_results_param() return None - solver3 = GenericSolver(solver1.name + " <> " + solver2.name) + study1 = self._study + study2 = self._study + + s3_name = solver1.name + " <> " + solver2.name + + if not (scenario2 is None or scenario2 is None): + study1 = self._study.copy_from_scenario(scenario1) + study2 = self._study.copy_from_scenario(scenario2) + + s3_name = scenario1.name + " <> " + scenario2.name + + solver3 = GenericSolver(s3_name) result1 = solver1.results( - self._study, - self._solver_workdir(solver1), + study1, + self._solver_workdir(solver1, scenario=scenario1), ) result2 = solver2.results( - self._study, - self._solver_workdir(solver2), + study2, + self._solver_workdir(solver2, scenario=scenario2), ) if result1 is None or result2 is None: diff --git a/src/View/Results/CompareDialog.py b/src/View/Results/CompareDialog.py new file mode 100644 index 00000000..d4d0f6b4 --- /dev/null +++ b/src/View/Results/CompareDialog.py @@ -0,0 +1,253 @@ +import os +import logging +import tempfile + +from queue import Queue +from tools import trace, timer, logger_exception + +from View.Tools.PamhyrWindow import PamhyrDialog, PamhyrWindow + +from PyQt5.QtGui import ( + QKeySequence, +) + +from PyQt5.QtCore import ( + Qt, QVariant, QAbstractTableModel, + QCoreApplication, QModelIndex, pyqtSlot, + QRect, QTimer, QProcess, +) + +from PyQt5.QtWidgets import ( + QDialogButtonBox, QPushButton, QLineEdit, + QFileDialog, QTableView, QAbstractItemView, + QUndoStack, QShortcut, QAction, QItemDelegate, + QComboBox, QVBoxLayout, QHeaderView, QTabWidget, + QTextEdit, +) + +from View.WaitingDialog import WaitingDialog + +_translate = QCoreApplication.translate + +logger = logging.getLogger() + + + +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_solvers() + self.setup_connections() + self.select_last_solver() + + def setup_solvers(self): + solvers = self._config.solvers + solvers_name = list( + map( + self._format_solver_name, + solvers + ) + ) + + self.combobox_add_items("comboBox1", solvers_name) + 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 CompareScenariosWindow(PamhyrDialog): + _pamhyr_ui = "CompareScenarios" + _pamhyr_name = "Compare scenarios" + + def __init__(self, study=None, config=None, + parent=None): + self._solver1 = None + self._solver2 = None + self._scenario1 = None + self._scenario2 = None + + name = _translate("Solver", "Compare solvers") + super(CompareScenariosWindow, self).__init__( + title=name, + study=study, + config=config, + options=[], + parent=parent + ) + + self.setup_solvers() + self.setup_scenarios() + self.setup_connections() + self.select_last_solver() + + def setup_solvers(self): + solvers = self._config.solvers + solvers_name = list( + map( + self._format_solver_name, solvers + ) + ) + + self.combobox_add_items("comboBoxSolver1", solvers_name) + self.combobox_add_items("comboBoxSolver2", solvers_name) + + def setup_scenarios(self): + scenarios = self._study.scenarios.lst + scenarios_name = list( + map( + lambda s : s.name, scenarios + ) + ) + + self.combobox_add_items("comboBoxScenario1", scenarios_name) + self.combobox_add_items("comboBoxScenario2", scenarios_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( + "comboBoxSolver1", + self._format_solver_name(solver[0]) + ) + self.set_combobox_text( + "comboBoxSolver2", + 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 + + @property + def scenario1(self): + return self._scenario1 + + @property + def scenario2(self): + return self._scenario2 + + def accept(self): + solver_name1 = self.get_combobox_text("comboBoxSolver1") + 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("comboBoxSolver2") + solver_name2 = solver_name2.rsplit(" - ", 1)[0] + self._solver2 = next( + filter( + lambda s: s.name == solver_name2, + self._config.solvers + ) + ) + + scenario_name1 = self.get_combobox_text("comboBoxScenario1") + self._scenario1 = next( + filter( + lambda s: s.name == scenario_name1, + self._study.scenarios + ) + ) + + scenario_name2 = self.get_combobox_text("comboBoxScenario2") + self._scenario2 = next( + filter( + lambda s: s.name == scenario_name2, + self._study.scenarios + ) + ) + + super(CompareScenariosWindow, self).accept() diff --git a/src/View/RunSolver/Window.py b/src/View/RunSolver/Window.py index 22b24bbc..64134c7d 100644 --- a/src/View/RunSolver/Window.py +++ b/src/View/RunSolver/Window.py @@ -138,107 +138,6 @@ 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/CompareScenarios.ui b/src/View/ui/CompareScenarios.ui new file mode 100644 index 00000000..8f1b18a5 --- /dev/null +++ b/src/View/ui/CompareScenarios.ui @@ -0,0 +1,79 @@ + + + Dialog + + + + 0 + 0 + 488 + 117 + + + + Dialog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + OK + + + + + + + + + + diff --git a/src/View/ui/MainWindow.ui b/src/View/ui/MainWindow.ui index 22d1c542..9f1f3b79 100644 --- a/src/View/ui/MainWindow.ui +++ b/src/View/ui/MainWindow.ui @@ -160,9 +160,10 @@ &Results - - - + + + + @@ -726,7 +727,7 @@ Edit hydraulic structures - + false @@ -787,12 +788,15 @@ DIF - + + + false + Compare results - + false @@ -800,6 +804,14 @@ Open results AdisTS + + + false + + + Compare scenarios results + +