rep mage select fixed

adists_new
Youcef AOUAD 2024-07-22 15:22:55 +02:00
parent 3c82148f44
commit 75149000db
5 changed files with 601 additions and 11 deletions

View File

@ -112,7 +112,7 @@ class AdisTS(CommandLineSolver):
for line in lines: for line in lines:
rep_file.write(line.line) rep_file.write(line.line)
def _export_REP(self, study, repertory, files, qlog, name="0"): def _export_REP(self, study, repertory, mage_rep, files, qlog, name="0"):
if qlog is not None: if qlog is not None:
qlog.put("Export REP file") qlog.put("Export REP file")
@ -124,8 +124,8 @@ class AdisTS(CommandLineSolver):
), "w+" ), "w+"
) as f: ) as f:
f.write(f"NET ../default-mage/{name}.NET\n") f.write(f"NET ../{mage_rep}/{name}.NET\n")
f.write(f"REP ../default-mage/{name}.REP\n") f.write(f"REP ../{mage_rep}/{name}.REP\n")
for file in files: for file in files:
EXT = file.split('.')[1] EXT = file.split('.')[1]
@ -133,7 +133,7 @@ class AdisTS(CommandLineSolver):
self._export_REP_additional_lines(study, f) self._export_REP_additional_lines(study, f)
path_mage_net = os.path.join(os.path.abspath(os.path.join(repertory, os.pardir)), f"default-mage/net") path_mage_net = os.path.join(os.path.abspath(os.path.join(repertory, os.pardir)), f"{mage_rep}/net")
path_adists_net = os.path.join(repertory, "net") path_adists_net = os.path.join(repertory, "net")
if os.path.exists(path_mage_net): if os.path.exists(path_mage_net):
@ -466,7 +466,7 @@ class AdisTSlc(AdisTS):
] ]
@timer @timer
def export(self, study, repertory, qlog=None, name="0"): def export(self, study, repertory, mage_rep, qlog=None, name="0"):
print("cmd solver adistslc : ", self._cmd_solver) print("cmd solver adistslc : ", self._cmd_solver)
self._study = study self._study = study
name = study.name.replace(" ", "_") name = study.name.replace(" ", "_")
@ -479,7 +479,7 @@ class AdisTSlc(AdisTS):
files = files + func(study, repertory, qlog, name=name) files = files + func(study, repertory, qlog, name=name)
self.export_additional_files(study, repertory, qlog, name=name) self.export_additional_files(study, repertory, qlog, name=name)
self._export_REP(study, repertory, files, qlog, name=name) self._export_REP(study, repertory, mage_rep, files, qlog, name=name)
return True return True
except Exception as e: except Exception as e:

View File

@ -0,0 +1,200 @@
# WindowAdisTS.py -- Pamhyr
# Copyright (C) 2023-2024 INRAE
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# -*- coding: utf-8 -*-
from tools import trace, timer
from View.Tools.PamhyrWindow import PamhyrWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, QRect, QThread,
pyqtSlot, pyqtSignal,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
QProgressBar, QLabel,
)
from View.CheckList.Table import TableModel
from View.CheckList.Worker import Worker
from View.CheckList.Translate import CheckListTranslate
_translate = QCoreApplication.translate
class CheckListWindowAdisTS(PamhyrWindow):
_pamhyr_ui = "CheckList"
_pamhyr_name = "Check list"
signalStatus = pyqtSignal(str)
def __init__(self, autorun: bool = True,
study=None, config=None,
solver=None, parent=None, mage_rep=None):
trad = CheckListTranslate()
self._autorun = autorun
self._solver = solver
self._mage_rep = mage_rep
name = trad[self._pamhyr_name] + " - " + study.name
super(CheckListWindowAdisTS, self).__init__(
title=name,
study=study,
config=config,
trad=trad,
options=[],
parent=parent
)
# Add solver to hash computation data
self._hash_data.append(self._solver)
self._checker_list = (
self._study.checkers() +
self._solver.checkers()
)
self.setup_table()
self.setup_progress_bar()
self.setup_connections()
self.setup_thread()
self.setup_statusbar()
def setup_table(self):
table = self.find(QTableView, f"tableView")
self._table = TableModel(
table_view=table,
table_headers=self._trad.get_dict("table_headers"),
data=self._checker_list,
)
def setup_progress_bar(self):
self._progress = self.find(QProgressBar, f"progressBar")
self._p = 0 # Progress current step
self._progress.setRange(0, len(self._checker_list))
self._progress.setValue(self._p)
def setup_connections(self):
self.find(QPushButton, "pushButton_ok").clicked.connect(self.accept)
self.find(QPushButton, "pushButton_retry").clicked.connect(self.retry)
self.find(QPushButton, "pushButton_cancel")\
.clicked.connect(self.reject)
def setup_thread(self):
self._worker = Worker(self._study, self._checker_list)
self._worker_thread = QThread()
self._worker.moveToThread(self._worker_thread)
# Connect any worker signals
self._worker.signalStatus.connect(self.update)
self._worker_thread.started.connect(self._worker.process)
self._worker_thread.start()
def retry(self):
self._worker_thread.terminate()
self._worker_thread.wait()
self.find(QPushButton, "pushButton_retry").setEnabled(False)
self.find(QPushButton, "pushButton_ok").setEnabled(False)
self.setup_thread()
def _compute_status(self):
ok = len(list(filter(lambda c: c.is_ok(), self._checker_list)))
warning = len(
list(filter(lambda c: c.is_warning(), self._checker_list)))
error = len(list(filter(lambda c: c.is_error(), self._checker_list)))
return ok, warning, error
def _compute_status_label(self):
ok, warning, error = self._compute_status()
return (f"<font color=\"Green\">Ok: {ok} </font> |" +
f"<font color=\"Orange\">Warning: {warning} </font> |" +
f"<font color=\"Red\">Error: {error}</font>")
def setup_statusbar(self):
txt = self._compute_status_label()
self._status_label = QLabel(txt)
self.statusbar.addPermanentWidget(self._status_label)
def update_statusbar(self):
txt = self._compute_status_label()
self._status_label.setText(txt)
def progress(self):
self._p += 1
self._progress.setValue(self._p)
self._table.update()
def start_compute(self):
self._p = 0
self._progress.setValue(self._p)
def info_compute(self, str):
self.statusbar.showMessage(str, 3000)
def end_compute(self):
self._table.layoutChanged.emit()
self.find(QPushButton, "pushButton_retry").setEnabled(True)
errors = any(filter(lambda c: c.is_error(), self._checker_list))
if not errors:
self.find(QPushButton, "pushButton_ok").setEnabled(True)
if self._autorun:
self._parent.solver_log_adists(self._solver, self._mage_rep)
self.end()
self.update_statusbar()
def update(self, key: str):
if key == "start":
self.start_compute()
self.info_compute("Starting ...")
elif key == "end":
self.info_compute("Finish")
self.end_compute()
elif key == "progress":
self.progress()
else:
self.info_compute(key)
self.update_statusbar()
def end(self):
# self._worker.join()b
self.close()
def reject(self):
self.end()
def accept(self):
self._parent.solver_log_adists(self._solver, self._mage_rep)
# self.end()

View File

@ -71,8 +71,9 @@ from View.AdditionalFiles.Window import AddFileListWindow
from View.REPLines.Window import REPLineListWindow from View.REPLines.Window import REPLineListWindow
from View.SolverParameters.Window import SolverParametersWindow from View.SolverParameters.Window import SolverParametersWindow
from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow from View.RunSolver.Window import SelectSolverWindow, SolverLogWindow
from View.RunSolver.WindowAdisTS import SelectSolverWindowAdisTS from View.RunSolver.WindowAdisTS import SelectSolverWindowAdisTS, SolverLogWindowAdisTS
from View.CheckList.Window import CheckListWindow from View.CheckList.Window import CheckListWindow
from View.CheckList.WindowAdisTS import CheckListWindowAdisTS
from View.Results.Window import ResultsWindow from View.Results.Window import ResultsWindow
from View.Results.ReadingResultsDialog import ReadingResultsDialog from View.Results.ReadingResultsDialog import ReadingResultsDialog
from View.Debug.Window import ReplWindow from View.Debug.Window import ReplWindow
@ -242,7 +243,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_menu_dif": self.open_dif, "action_menu_dif": self.open_dif,
"action_menu_d90": self.open_d90, "action_menu_d90": self.open_d90,
"action_menu_pollutants": self.open_pollutants, "action_menu_pollutants": self.open_pollutants,
"action_menu_run_adists":self.run_solver_adists, "action_menu_run_adists":self.select_run_solver_adists,
"action_menu_output_kp": self.open_output_kp_adists, "action_menu_output_kp": self.open_output_kp_adists,
"action_menu_config": self.open_configure, "action_menu_config": self.open_configure,
"action_menu_new": self.open_new_study, "action_menu_new": self.open_new_study,
@ -1258,7 +1259,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
if run.exec(): if run.exec():
self.run_solver(run.solver) self.run_solver(run.solver)
def run_solver_adists(self): def select_run_solver_adists(self):
if self._study is None: if self._study is None:
return return
@ -1273,7 +1274,31 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
parent=self parent=self
) )
if run.exec(): if run.exec():
self.run_solver(run.solver) self.run_solver_adists(run.solver, run.mage_rep)
def run_solver_adists(self, solver, mage_rep):
if self._study is None:
return
if self.sub_window_exists(
CheckListWindowAdisTS,
data=[
self._study,
self.conf,
solver,
mage_rep
]
):
return
check = CheckListWindowAdisTS(
study=self._study,
config=self.conf,
solver=solver,
parent=self,
mage_rep=mage_rep,
)
check.show()
def run_solver(self, solver): def run_solver(self, solver):
if self._study is None: if self._study is None:
@ -1297,6 +1322,16 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
) )
check.show() check.show()
def solver_log_adists(self, solver, mage_rep):
sol = SolverLogWindowAdisTS(
study=self._study,
config=self.conf,
solver=solver,
parent=self,
mage_rep=mage_rep,
)
sol.show()
def solver_log(self, solver): def solver_log(self, solver):
sol = SolverLogWindow( sol = SolverLogWindow(
study=self._study, study=self._study,

View File

@ -58,7 +58,7 @@ logger = logging.getLogger()
class SelectSolverWindowAdisTS(PamhyrDialog): class SelectSolverWindowAdisTS(PamhyrDialog):
_pamhyr_ui = "SelectSolver" _pamhyr_ui = "SelectSolverAdisTS"
_pamhyr_name = "Select solver" _pamhyr_name = "Select solver"
def __init__(self, study=None, config=None, def __init__(self, study=None, config=None,
@ -89,7 +89,21 @@ class SelectSolverWindowAdisTS(PamhyrDialog):
) )
) )
solvers_mage = list(filter(lambda x: "mage" in x._type, self._config.solvers))
solvers_mage_names = list(map(lambda x: x._name, solvers_mage))
solvers_dir = os.path.join(
os.path.dirname(self._study.filename),
"_PAMHYR_",
self._study.name.replace(" ", "_"),
)
dir_solvers_List = os.listdir(solvers_dir)
display_mage_names = list(filter(lambda x: x in solvers_mage_names, dir_solvers_List))
self.combobox_add_items("comboBox", solvers_name) self.combobox_add_items("comboBox", solvers_name)
self.combobox_add_items("comboBoxRepMage", display_mage_names)
def setup_connections(self): def setup_connections(self):
self.find(QPushButton, "pushButton_run").clicked.connect(self.accept) self.find(QPushButton, "pushButton_run").clicked.connect(self.accept)
@ -120,10 +134,16 @@ class SelectSolverWindowAdisTS(PamhyrDialog):
def solver(self): def solver(self):
return self._solver return self._solver
@property
def mage_rep(self):
return self._mage_result_rep
def accept(self): def accept(self):
solver_name = self.get_combobox_text("comboBox") solver_name = self.get_combobox_text("comboBox")
solver_name = solver_name.rsplit(" - ", 1)[0] solver_name = solver_name.rsplit(" - ", 1)[0]
self._mage_result_rep = self.get_combobox_text("comboBoxRepMage")
self._config.update_last_solver_used(solver_name) self._config.update_last_solver_used(solver_name)
self._solver = next( self._solver = next(
@ -135,3 +155,273 @@ class SelectSolverWindowAdisTS(PamhyrDialog):
super(SelectSolverWindowAdisTS, self).accept() super(SelectSolverWindowAdisTS, self).accept()
class SolverLogWindowAdisTS(PamhyrWindow):
_pamhyr_ui = "SolverLog"
_pamhyr_name = "Solver Log"
def __init__(self, study=None, config=None,
solver=None, parent=None, mage_rep=None):
self._solver = solver
self._results = None
self._mage_rep = mage_rep
name = _translate("Solver", "Select log")
super(SolverLogWindowAdisTS, self).__init__(
title=name,
study=study,
config=config,
options=[],
parent=parent
)
self.setup_action()
self.setup_alarm()
self.setup_connections()
self.setup_workdir()
self.setup_process()
ok = self.export()
if ok:
self.run()
else:
self._log(
f" *** Failed to export study to {self._solver._type}",
color="red"
)
def setup_action(self):
self.find(QAction, "action_start").setEnabled(False)
if _signal:
self.find(QAction, "action_pause").setEnabled(True)
else:
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_log_file").setEnabled(False)
self.find(QAction, "action_results").setEnabled(False)
def setup_alarm(self):
self._alarm = QTimer()
def setup_connections(self):
self.find(QAction, "action_start").triggered.connect(self.start)
self.find(QAction, "action_pause").triggered.connect(self.pause)
self.find(QAction, "action_stop").triggered.connect(self.stop)
self.find(QAction, "action_log_file").triggered.connect(self.log_file)
self.find(QAction, "action_results").triggered.connect(self.results)
self._alarm.timeout.connect(self.update)
def setup_workdir(self):
self._workdir = ""
if self._study.filename == "":
self._workdir = tempfile.TemporaryDirectory()
else:
self._workdir = os.path.join(
os.path.dirname(self._study.filename),
"_PAMHYR_",
self._study.name.replace(" ", "_"),
self._solver.name.replace(" ", "_"),
)
os.makedirs(self._workdir, exist_ok=True)
def setup_process(self):
self._alarm.start(100)
self._output = Queue()
self._process = self.new_process(self._parent)
def new_process(self, parent):
new = QProcess(parent)
new.setWorkingDirectory(self._workdir)
new.setProcessChannelMode(QProcess.MergedChannels)
return new
def export(self):
self._log(f" *** Export study {self._solver.name}", color="blue")
ok = self._solver.export(self._study, self._workdir, self._mage_rep, qlog=self._output)
self.update()
return ok
def closeEvent(self, event):
self._alarm.stop()
super(SolverLogWindowAdisTS, self).closeEvent(event)
def _copy(self):
self.find(QTextEdit, "textEdit").copy()
#######
# LOG #
#######
def _log(self, msg, color=None):
if type(msg) is str:
self._log_str(msg, color)
elif type(msg) is int:
self._log_int(msg, color)
def _log_str(self, msg, color=None):
if msg == "":
return
logger.info(f"solver: {msg}")
msg = msg.rsplit('\n', 1)[0]
if color is not None:
msg = f"<font color=\"{color}\">" + msg + "</font>"
self.find(QTextEdit, "textEdit").append(msg)
def _log_int(self, int_code, color=None):
logger.info(f"solver: Returns {int_code}")
color = "blue" if int_code == 0 else "red"
self.find(QTextEdit, "textEdit")\
.append(
f"<font color=\"{color}\">" +
f" *** Finished with code {int_code}" +
"</font>"
)
self.statusbar.showMessage(
"Done" if int_code == 0 else "Failed",
3000
)
##########
# UPDATE #
##########
def update(self):
if self._solver.is_stoped():
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
self._update_logs_all()
# self._update_get_results()
self._update_logs_all()
def _update_get_results(self):
if self._results is None:
def reading_fn():
try:
self._results = self._solver.results(
self._study, self._workdir, qlog=self._output
)
self._parent.set_results(self._solver, self._results)
except Exception as e:
logger.error(f"Failed to open results")
logger_exception(e)
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
dlg.exec_()
def _update_logs_all(self):
while self._output.qsize() != 0:
s = self._output.get()
try:
if type(s) is str and "[ERROR]" in s:
self._log(s.encode("utf-8"), color="red")
else:
self._log(s)
except Exception as e:
logger_exception(e)
####################
# Process controle #
####################
def run(self):
self._log(f" *** Run solver {self._solver.name}", color="blue")
self._solver.run(
self._study,
process=self._process,
output_queue=self._output
)
def start(self):
if self._solver.is_stoped():
self._log(f" *** Export study {self._solver.name}", color="blue")
ok = self._solver.export(
self._study, self._workdir, self._mage_rep, qlog=self._output
)
if not ok:
self._log(f" *** Failed to export", color="red")
self.update()
return
else:
self.update()
self._process = self.new_process(self._parent)
self._log(" *** Start", color="blue")
self._results = None
self._solver.start(self._study, process=self._process)
self.find(QAction, "action_start").setEnabled(False)
if _signal:
self.find(QAction, "action_pause").setEnabled(True)
else:
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_log_file").setEnabled(False)
self.find(QAction, "action_results").setEnabled(False)
def pause(self):
self._log(" *** Pause", color="blue")
self._solver.pause()
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(True)
self.find(QAction, "action_results").setEnabled(False)
def stop(self):
self._log(" *** Stop", color="blue")
self._solver.kill()
self.find(QAction, "action_start").setEnabled(True)
self.find(QAction, "action_pause").setEnabled(False)
self.find(QAction, "action_stop").setEnabled(False)
self.find(QAction, "action_results").setEnabled(True)
if self._solver.log_file() != "":
self.find(QAction, "action_log_file").setEnabled(True)
###########
# Results #
###########
def results(self):
if self._results is None:
def reading_fn():
self._results = self._solver.results(
self._study, self._workdir, qlog=self._output
)
dlg = ReadingResultsDialog(reading_fn=reading_fn, parent=self)
dlg.exec_()
self._parent.set_results(self._solver, self._results)
self._parent.open_solver_results(self._solver, self._results)
self._solver.has_results_loaded()
def log_file(self):
file_name = os.path.join(self._workdir, self._solver.log_file())
log = SolverLogFileWindow(
file_name=file_name,
study=self._study,
config=self._config,
solver=self._solver,
parent=self,
)
log.show()

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>384</width>
<height>107</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QComboBox" name="comboBox"/>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_run">
<property name="text">
<string>Run</string>
</property>
<property name="icon">
<iconset>
<normaloff>ressources/run.png</normaloff>ressources/run.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_cancel">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="comboBoxRepMage"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>