SolverParameters: Add solver parameter window base.

mesh
Pierre-Antoine Rouby 2023-06-12 15:33:25 +02:00
parent eb6d218b8e
commit 9cd8fadcd1
13 changed files with 616 additions and 45 deletions

View File

@ -12,6 +12,7 @@ from Model.LateralContribution.LateralContributionList import LateralContributio
from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict from Model.InitialConditions.InitialConditionsDict import InitialConditionsDict
from Model.Stricklers.StricklersList import StricklersList from Model.Stricklers.StricklersList import StricklersList
from Model.Section.SectionList import SectionList from Model.Section.SectionList import SectionList
from Model.SolverParameters.SolverParametersList import SolverParametersList
class RiverNode(Node): class RiverNode(Node):
def __init__(self, id:str, name:str, def __init__(self, id:str, name:str,
@ -69,6 +70,7 @@ class River(Graph):
self._lateral_contribution = LateralContributionList(status=self._status) self._lateral_contribution = LateralContributionList(status=self._status)
self._initial_conditions = InitialConditionsDict(status=self._status) self._initial_conditions = InitialConditionsDict(status=self._status)
self._stricklers = StricklersList(status=self._status) self._stricklers = StricklersList(status=self._status)
self._parameters = {}
@property @property
def boundary_condition(self): def boundary_condition(self):
@ -99,6 +101,20 @@ class River(Graph):
return ret[0] return ret[0]
@property
def parameters(self):
return self._parameters
def get_params(self, solver):
if solver in self._parameters:
return self._parameters[solver]
new = SolverParametersList(status = self._status)
self._parameters[solver] = new
self._status.modified()
return self._parameters[solver]
def has_current_reach(self): def has_current_reach(self):
return self._current_reach is not None return self._current_reach is not None

View File

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
from copy import copy
from tools import trace, timer
class Parameter(object):
def __init__(self, status = None):
self._status = status
self._name = ""
self._value = ""
@property
def name(self):
return self._name
@property
def value(self):
return self._value
def __getitem__(self, key):
if key == "name":
return self._name
elif key == "value":
return self._value
return None
def __setitem__(self, key, value):
if key == "name":
self._name = str(value)
elif key == "value":
self._value = str(value)
self._status.modified()
class SolverParametersList(object):
def __init__(self, status = None):
super(SolverParametersList, self).__init__()
self._status = status
self._parameters = []
def __len__(self):
return len(self._parameters)
@property
def parameters(self):
return self._parameters.copy()
def get(self, index):
return self._parameters[index]
def set(self, index, new):
self._parameters[index] = new
self._status.modified()
def new(self, index):
n = Parameter(status = self._status)
self._parameters.insert(index, n)
self._status.modified()
return n
def insert(self, index, new):
self._parameters.insert(index, new)
self._status.modified()
def delete(self, parameters):
for parameter in parameters:
self._parameters.remove(parameter)
self._status.modified()
def delete_i(self, indexes):
parameters = list(
map(
lambda x: x[1],
filter(
lambda x: x[0] in indexes,
enumerate(self._parameters)
)
)
)
self.delete(parameters)
def sort(self, reverse=False, key=None):
self._parameters.sort(reverse=reverse, key=key)
self._status.modified()
def move_up(self, index):
if index < len(self._parameters):
next = index - 1
l = self._parameters
l[index], l[next] = l[next], l[index]
self._status.modified()
def move_down(self, index):
if index >= 0:
prev = index + 1
l = self._parameters
l[index], l[prev] = l[prev], l[index]
self._status.modified()

View File

@ -29,7 +29,11 @@ class Study(Serializable):
self.last_save_date = datetime.now() self.last_save_date = datetime.now()
# Study data # Study data
self.river = River(status=self.status) self._river = River(status = self.status)
@property
def river(self):
return self._river
@property @property
def is_saved(self): def is_saved(self):

View File

@ -14,81 +14,84 @@ class AbstractSolver(object):
def __init__(self, name): def __init__(self, name):
super(AbstractSolver, self).__init__() super(AbstractSolver, self).__init__()
self.current_process = None self._current_process = None
self.status = STATUS.STOPED self._status = STATUS.STOPED
# Informations # Informations
self._type = "" self._type = ""
self.name = name self._name = name
self.description = "" self._description = ""
self.path_input = "" self._path_input = ""
self.path_solver = "" self._path_solver = ""
self.path_output = "" self._path_output = ""
self.cmd_input = "" self._cmd_input = ""
self.cmd_solver = "" self._cmd_solver = ""
self.cmd_output = "" self._cmd_output = ""
def __str__(self): def __str__(self):
return f"{self.name} : {self._type} : {self.description}" return f"{self._name} : {self._type} : {self._description}"
# Getter @classmethod
def get_status(self): def default_parameters(cls):
return self.status return []
def get_type(self): @property
def name(self):
return self.name
@property
def description(self):
return self.description
@property
def status(self):
return self._status
@property
def type(self):
return self._type return self._type
def __getitem__(self, name): @status.setter
ret = None def status(self, status):
self._status = status
if name == "name": @name.setter
ret = self.name def name(self, name):
elif name == "description": self._name = name
ret = self.description
elif name == "type":
ret = self._type
return ret @description.setter
def description(self, description):
# Setter self._description = description
def set_status(self, status):
self.status = status
def set_name(self, name):
self.name = name
def set_description(self, description):
self.description = description
def set_input(self, path, cmd): def set_input(self, path, cmd):
self.path_input = path self._path_input = path
self.cmd_input = cmd self._cmd_input = cmd
def set_solver(self, path, cmd): def set_solver(self, path, cmd):
self.path_solver = path self._path_solver = path
self.cmd_solver = cmd self._cmd_solver = cmd
def set_output(self, path, cmd): def set_output(self, path, cmd):
self.path_output = path self._path_output = path
self.cmd_output = cmd self._cmd_output = cmd
# Run # Run
def run_input_data_fomater(self): def run_input_data_fomater(self):
if self.cmd_input == "": if self._cmd_input == "":
return True return True
return False return False
def run_solver(self): def run_solver(self):
if self.cmd_solver == "": if self._cmd_solver == "":
return True return True
return False return False
def run_output_data_fomater(self, ): def run_output_data_fomater(self, ):
if self.cmd_output == "": if self._cmd_output == "":
return True return True
return False return False

View File

@ -9,3 +9,9 @@ class GenericSolver(AbstractSolver):
super(GenericSolver, self).__init__(name) super(GenericSolver, self).__init__(name)
self._type = "generic" self._type = "generic"
@classmethod
def default_parameters(cls):
lst = super(Mage, cls).default_parameters()
return lst

48
src/Solver/Mage.py Normal file
View File

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from Solver.GenericSolver import GenericSolver
class Mage(GenericSolver):
def __init__(self, name):
super(Mage, self).__init__(name)
self._type = "mage"
self._cmd_input = ""
self._cmd_solver = "@path @input -o @output"
self._cmd_output = ""
@classmethod
def default_parameters(cls):
lst = super(Mage, cls).default_parameters()
lst += [
("time_step", "300"),
]
return lst
class Mage7(Mage):
def __init__(self, name):
super(Mage7, self).__init__(name)
self._type = "mage7"
@classmethod
def default_parameters(cls):
lst = super(Mage7, cls).default_parameters()
return lst
class Mage8(Mage):
def __init__(self, name):
super(Mage8, self).__init__(name)
self._type = "mage8"
@classmethod
def default_parameters(cls):
lst = super(Mage8, cls).default_parameters()
return lst

View File

@ -27,6 +27,7 @@ from View.LateralContribution.Window import LateralContributionWindow
from View.InitialConditions.Window import InitialConditionsWindow from View.InitialConditions.Window import InitialConditionsWindow
from View.Stricklers.Window import StricklersWindow from View.Stricklers.Window import StricklersWindow
from View.Sections.Window import SectionsWindow from View.Sections.Window import SectionsWindow
from View.SolverParameters.Window import SolverParametersWindow
from Model.Study import Study from Model.Study import Study
@ -125,7 +126,7 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
"action_toolBar_network": self.open_network, "action_toolBar_network": self.open_network,
"action_toolBar_geometry": self.open_geometry, "action_toolBar_geometry": self.open_geometry,
"action_toolBar_mesh": lambda: self.open_dummy("Mesh"), "action_toolBar_mesh": lambda: self.open_dummy("Mesh"),
"action_toolBar_run_meshing_tool": lambda: self.open_dummy("Lancement mailleur externe"), "action_toolBar_run_meshing_tool": self.open_solver_parameters,
"action_toolBar_boundary_cond": self.open_boundary_cond, "action_toolBar_boundary_cond": self.open_boundary_cond,
"action_toolBar_lateral_contrib": self.open_lateral_contrib, "action_toolBar_lateral_contrib": self.open_lateral_contrib,
"action_toolBar_spills": lambda: self.open_dummy("Deversement"), "action_toolBar_spills": lambda: self.open_dummy("Deversement"),
@ -361,6 +362,14 @@ class ApplicationWindow(QMainWindow, ListedSubWindow, WindowToolKit):
) )
self.initial.show() self.initial.show()
def open_solver_parameters(self):
self.params = SolverParametersWindow(
study = self.model,
parent = self
)
self.params.show()
# TODO: Delete me ! # TODO: Delete me !
############### ###############
# DUMMY STUFF # # DUMMY STUFF #

View File

@ -0,0 +1,157 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox,
)
from View.SolverParameters.UndoCommand import *
from View.SolverParameters.translate import *
_translate = QCoreApplication.translate
class TableModel(QAbstractTableModel):
def __init__(self, data=None, undo=None, tab=""):
super(QAbstractTableModel, self).__init__()
self._headers = list(table_headers.keys())
self._data = data
self._undo = undo
self._tab = tab
self._params = self._data.get_params(self._tab)
def flags(self, index):
options = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if self._headers[self._column] == "value":
options |= Qt.ItemIsEditable
return options
def rowCount(self, parent):
return len(self._params)
def columnCount(self, parent):
return len(self._headers)
def data(self, index, role):
if role != Qt.ItemDataRole.DisplayRole:
return QVariant()
row = index.row()
column = index.column()
if 0 <= column < len(self._headers):
return self._params.get(row)[self._headers[column]]
return QVariant()
def headerData(self, section, orientation, role):
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
return table_headers[self._headers[section]]
return QVariant()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid() or role != Qt.EditRole:
return False
row = index.row()
column = index.column()
if self._headers[column] == "value":
self._undo.push(
SetCommand(
self._params, row, "value", value
)
)
self.dataChanged.emit(index, index)
return True
# def add(self, row, parent=QModelIndex()):
# self.beginInsertRows(parent, row, row - 1)
# self._undo.push(
# AddCommand(
# self._params, row
# )
# )
# self.endInsertRows()
# self.layoutChanged.emit()
# def delete(self, rows, parent=QModelIndex()):
# self.beginRemoveRows(parent, rows[0], rows[-1])
# self._undo.push(
# DelCommand(
# self._params, rows
# )
# )
# self.endRemoveRows()
# self.layoutChanged.emit()
# def sort(self, _reverse, parent=QModelIndex()):
# self.layoutAboutToBeChanged.emit()
# self._undo.push(
# SortCommand(
# self._params, False
# )
# )
# self.layoutAboutToBeChanged.emit()
# self.layoutChanged.emit()
# def move_up(self, row, parent=QModelIndex()):
# if row <= 0:
# return
# target = row + 2
# self.beginMoveRows(parent, row - 1, row - 1, parent, target)
# self._undo_stack.push(
# MoveCommand(
# self._params, "up", row
# )
# )
# self.endMoveRows()
# self.layoutChanged.emit()
# def move_down(self, index, parent=QModelIndex()):
# if row > len(self._params):
# return
# target = row
# self.beginMoveRows(parent, row + 1, row + 1, parent, target)
# self._undo_stack.push(
# MoveCommand(
# self._params, "down", row
# )
# )
# self.endMoveRows()
# self.layoutChanged.emit()
def undo(self):
self._undo.undo()
self.layoutChanged.emit()
def redo(self):
self._undo.redo()
self.layoutChanged.emit()

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from copy import deepcopy
from tools import trace, timer
from PyQt5.QtWidgets import (
QMessageBox, QUndoCommand, QUndoStack,
)
from Model.SolverParameters.SolverParametersList import SolverParametersList
class SetCommand(QUndoCommand):
def __init__(self, data, index, column, new_value):
QUndoCommand.__init__(self)
self._data = data
self._index = index
self._column = column
self._old = self._data.get(self._index)[column]
self._new = new_value
def undo(self):
self._data.get(self._index)[column] = self._old
def redo(self):
self._data.get(self._index)[column] = self._new

View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
from tools import trace, timer
from View.ASubWindow import ASubMainWindow
from View.ListedSubWindow import ListedSubWindow
from PyQt5.QtGui import (
QKeySequence,
)
from PyQt5.QtCore import (
Qt, QVariant, QAbstractTableModel,
QCoreApplication, QModelIndex, pyqtSlot,
QRect,
)
from PyQt5.QtWidgets import (
QDialogButtonBox, QPushButton, QLineEdit,
QFileDialog, QTableView, QAbstractItemView,
QUndoStack, QShortcut, QAction, QItemDelegate,
QComboBox, QVBoxLayout, QHeaderView, QTabWidget,
)
from View.SolverParameters.UndoCommand import *
from View.SolverParameters.Table import TableModel
from View.SolverParameters.translate import *
_translate = QCoreApplication.translate
class SolverParametersWindow(ASubMainWindow, ListedSubWindow):
def __init__(self, title="Solver parameters", study=None, parent=None):
title = title + " - " + study.name
super(SolverParametersWindow, self).__init__(
name=title, ui="SolverParameters", parent=parent
)
self._study = study
self._params = self._study.river.parameters
self.setup_sc()
self.setup_table()
self.setup_connections()
self.ui.setWindowTitle(title)
def setup_sc(self):
self._undo_stack = QUndoStack()
self.undo_sc = QShortcut(QKeySequence.Undo, self)
self.redo_sc = QShortcut(QKeySequence.Redo, self)
self.copy_sc = QShortcut(QKeySequence.Copy, self)
self.paste_sc = QShortcut(QKeySequence.Paste, self)
def setup_table(self):
self._table = {}
for t in ["mage"]:
table = self.find(QTableView, f"tableView_{t}")
self._table[t] = TableModel(
data = self._study.river,
undo = self._undo_stack,
tab = t,
)
table.setModel(self._table[t])
table.setSelectionBehavior(QAbstractItemView.SelectRows)
table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
table.setAlternatingRowColors(True)
def setup_connections(self):
self.undo_sc.activated.connect(self.undo)
self.redo_sc.activated.connect(self.redo)
self.copy_sc.activated.connect(self.copy)
self.paste_sc.activated.connect(self.paste)
def current_tab(self):
return self.find(QTabWidget, "tabWidget")\
.currentWidget()\
.objectName()\
.replace("tab_", "")
def undo(self):
tab = self.current_tab()
self._table[tab].undo()
self._set_current_reach()
def redo(self):
tab = self.current_tab()
self._table[tab].redo()
self._set_current_reach()
def copy(self):
print("TODO")
def paste(self):
print("TODO")

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from PyQt5.QtCore import QCoreApplication
_translate = QCoreApplication.translate
table_headers = {
"name": _translate("LateralContribution", "Name"),
"value": _translate("LateralContribution", "Value")
}
# Used to translate user parameter with value yes or no
yes_no = {
"yes": _translate("SolverParameters", "Yes"),
"no": _translate("SolverParameters", "No"),
"y": _translate("SolverParameters", "Y"),
"n": _translate("SolverParameters", "N"),
# Reverse
_translate("SolverParameters", "Yes"): "Yes",
_translate("SolverParameters", "No"): "No",
_translate("SolverParameters", "Y"): "y",
_translate("SolverParameters", "N"): "n",
}
names = {
"mage_time_step": _translate("SolverParameters", "Time step in second")
}

View File

@ -113,6 +113,9 @@
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<property name="text"> <property name="text">
<string>Input formater</string> <string>Input formater</string>
</property> </property>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>480</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="locale">
<locale language="English" country="Europe"/>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_mage">
<attribute name="title">
<string>Mage</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTableView" name="tableView_mage"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_rubarbe">
<attribute name="title">
<string>Rubarbe</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Not implemented yet !</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>900</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>