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 @@
+
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