1 # Copyright (C) 2012-2013 EDF
3 # This file is part of SALOME HYDRO module.
5 # SALOME HYDRO module is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # SALOME HYDRO module is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with SALOME HYDRO module. If not, see <http://www.gnu.org/licenses/>.
21 from PyQt5.QtCore import *
22 from PyQt5.QtGui import *
23 from PyQt5.QtWidgets import *
26 from MEDLoader import MEDFileMesh
28 # TODO: get rid of sys.path.append() ?
29 hydro_solver_root = os.path.join(os.environ['HYDROSOLVER_ROOT_DIR'], 'lib', 'python2.7', 'site-packages', 'salome')
30 sys.path.append(os.path.join(hydro_solver_root, 'salome', 'hydrotools'))
32 import boundaryConditions
34 ROW_PROPERTY_NAME = "row"
36 """Get names of groups on edges from the given MED file"""
37 def get_med_groups_on_edges(file_path):
39 med_file_mesh = MEDFileMesh.New(file_path)
40 groups = list(med_file_mesh.getGroupsOnSpecifiedLev(-1))
41 except Exception as e:
47 """Get preset name corresponding to the given values of LIHBOR, LIUBOR, LIVBOR and LITBOR"""
48 def get_preset_name(presets, lihbor, liubor, livbor, litbor):
51 for preset_name in presets:
52 values = presets[preset_name]
59 if not p_lihbor or p_lihbor == lihbor:
60 if not p_liubor or p_liubor == liubor:
61 if not p_livbor or p_livbor == livbor:
62 if not p_litbor or p_litbor == litbor:
67 """Convert string to integer, return None if conversion is not possible"""
76 """Item delegate for LIHBOR, LIUBOR, LIVBOR and LITBOR columns"""
77 class ValueDelegate(QStyledItemDelegate):
79 def __init__(self, parent = None):
80 QStyledItemDelegate.__init__(self, parent)
82 def createEditor(self, parent, option, index):
83 line_edit = QLineEdit(parent)
85 validator = QIntValidator(parent)
86 validator.setRange(0, 6)
88 line_edit.setValidator(validator)
92 def setEditorData(self, editor, index):
93 value = index.model().data(index, Qt.EditRole)
99 def setModelData(self, editor, model, index):
100 model.setData(index, editor.text(), Qt.EditRole)
102 def updateEditorGeometry(self, editor, option, index):
103 editor.setGeometry(option.rect)
105 """Boundary conditions definition dialog"""
106 class BoundaryConditionsDialog(QDialog):
108 def __init__(self, parent = None, modal = 0):
109 QDialog.__init__(self, parent)
110 uic.loadUi(os.path.join(hydro_solver_root, 'BndConditionsDialog.ui'), self )
113 self.medFileButton.clicked.connect(self.on_med_file_browse)
114 self.bndConditionsFileButton.clicked.connect(self.on_bnd_file_browse)
115 self.resultBndConditionsFileButton.clicked.connect(self.on_result_file_browse)
117 self.sameAsInputCB.toggled.connect(self.resultBndConditionsFileEdit.setDisabled)
118 self.sameAsInputCB.toggled.connect(self.resultBndConditionsFileButton.setDisabled)
120 self.boundaryConditionsTable.cellChanged.connect(self.on_cell_changed)
122 self.applyAndCloseButton.clicked.connect(self.on_apply_and_close)
123 self.applyButton.clicked.connect(self.on_apply)
124 self.closeButton.clicked.connect(self.reject)
125 self.helpButton.clicked.connect(self.on_help)
127 # Set widgets properties
131 self.input_conditions = {}
137 """Initialize presets"""
138 def init_presets(self):
139 # TODO: determine another presets path
140 presets_data_root = os.path.join(os.environ['HYDROSOLVER_ROOT_DIR'], 'lib', 'python2.7', 'site-packages', 'salome', 'tests', 'data')
141 file_path = os.path.join(presets_data_root, 'bnd_conditions_presets.txt')
142 reader = boundaryConditions.PresetReader(file_path)
143 self.presets = reader.read()
145 """Initialize widget properties"""
146 def init_widgets(self):
147 self.medFileEdit.setReadOnly(True)
148 self.bndConditionsFileEdit.setReadOnly(True)
149 self.resultBndConditionsFileEdit.setReadOnly(True)
151 delegate = ValueDelegate(self.boundaryConditionsTable)
152 self.boundaryConditionsTable.setItemDelegateForColumn(1, delegate)
153 self.boundaryConditionsTable.setItemDelegateForColumn(2, delegate)
154 self.boundaryConditionsTable.setItemDelegateForColumn(3, delegate)
155 self.boundaryConditionsTable.setItemDelegateForColumn(4, delegate)
157 """Process cell data changes"""
158 def on_cell_changed(self, row, column):
159 lihbor = liubor = livbor = litbor = None
161 item = self.boundaryConditionsTable.item(row, 1)
163 lihbor = get_int(str(item.text()))
165 item = self.boundaryConditionsTable.item(row, 2)
167 liubor = get_int(str(item.text()))
169 item = self.boundaryConditionsTable.item(row, 3)
171 livbor = get_int(str(item.text()))
173 item = self.boundaryConditionsTable.item(row, 4)
175 litbor = get_int(str(item.text()))
177 preset_name = get_preset_name(self.presets, lihbor, liubor, livbor, litbor)
179 combo = self.boundaryConditionsTable.cellWidget(row, 0)
180 if isinstance(combo, QComboBox):
181 ind = combo.findText(preset_name)
183 combo.setCurrentIndex(ind)
185 """Save the user data to boundary conditions file"""
187 # Save boundary conditions file
188 if not self.is_valid():
191 file_path = self.resultBndConditionsFileEdit.text()
192 writer = boundaryConditions.BoundaryConditionWriter(file_path)
195 for row_nb in xrange(0, self.boundaryConditionsTable.rowCount()):
196 lihbor = str(self.boundaryConditionsTable.item(row_nb, 1).text())
197 liubor = str(self.boundaryConditionsTable.item(row_nb, 2).text())
198 livbor = str(self.boundaryConditionsTable.item(row_nb, 3).text())
199 litbor = str(self.boundaryConditionsTable.item(row_nb, 4).text())
200 group_name = str(self.boundaryConditionsTable.item(row_nb, 5).text())
201 conditions.append(boundaryConditions.BoundaryCondition(lihbor, liubor, livbor, litbor, group_name))
203 writer.write(conditions)
207 """Save the user data to boundary conditions file and close the dialog"""
208 def on_apply_and_close(self):
212 """Select MED file"""
213 def on_med_file_browse(self):
215 file_path, filt = QFileDialog.getOpenFileName(self, self.tr("Open MED file"), "", self.tr("MED files (*.med)"))
219 # Get names of groups on edges
220 groups = get_med_groups_on_edges(str(file_path))
224 self.medFileEdit.setText(file_path)
227 self.set_groups(groups)
229 QMessageBox.warning(self, self.tr("Warning"), self.tr("Can't get group names from the selected MED file."))
231 """Select boundary conditions file"""
232 def on_bnd_file_browse(self):
233 file_path, filt = QFileDialog.getOpenFileName(self, self.tr("Open boundary conditions file"))
236 self.bndConditionsFileEdit.setText(file_path)
237 reader = boundaryConditions.BoundaryConditionReader(file_path)
238 conditions = reader.read()
240 self.input_conditions.clear()
241 for cnd in conditions:
242 self.input_conditions[cnd.group] = (cnd.lihbor, cnd.liubor, cnd.livbor, cnd.litbor)
245 read_errors = reader.errors
246 if len( read_errors ) > 0:
247 msg = "\n".join(read_errors)
248 QMessageBox.warning(self, self.tr("Warning"), msg)
250 if len(self.input_conditions) > 0:
253 QMessageBox.warning(self, self.tr("Warning"), self.tr("No conditions have been read from the file."))
255 """Called on preset selection in the first column of the table"""
256 def on_preset_changed(self):
257 combo = self.sender()
259 preset = str(combo.currentText())
261 if preset and self.presets.has_key(preset):
262 values = self.presets[preset]
263 row_nb = combo.property(ROW_PROPERTY_NAME)
265 if row_nb >= 0 and row_nb < self.boundaryConditionsTable.rowCount():
272 self.boundaryConditionsTable.item(row_nb, 1).setText(str(lihbor))
275 self.boundaryConditionsTable.item(row_nb, 2).setText(str(liubor))
278 self.boundaryConditionsTable.item(row_nb, 3).setText(str(livbor))
281 self.boundaryConditionsTable.item(row_nb, 4).setText(str(litbor))
283 """Define result file path"""
284 def on_result_file_browse(self):
285 file_path, filt = QFileDialog.getSaveFileName(self, self.tr("Select output file path"))
288 self.resultBndConditionsFileEdit.setText(file_path)
290 """Set groups list"""
291 def set_groups(self, groups):
292 self.boundaryConditionsTable.setRowCount(0)
295 row_nb = self.boundaryConditionsTable.rowCount()
296 self.boundaryConditionsTable.insertRow(row_nb)
299 combo = QComboBox(self)
301 if len(self.presets) > 0:
302 combo.addItems(self.presets.keys())
304 combo.setProperty(ROW_PROPERTY_NAME, row_nb)
306 combo.currentIndexChanged.connect(self.on_preset_changed)
308 self.boundaryConditionsTable.setCellWidget(row_nb, 0, combo)
311 self.boundaryConditionsTable.setItem(row_nb, 1, QTableWidgetItem(''))
314 self.boundaryConditionsTable.setItem(row_nb, 2, QTableWidgetItem(''))
317 self.boundaryConditionsTable.setItem(row_nb, 3, QTableWidgetItem(''))
320 self.boundaryConditionsTable.setItem(row_nb, 4, QTableWidgetItem(''))
323 item = QTableWidgetItem(group)
327 item.setFlags(Qt.ItemIsEnabled)
328 self.boundaryConditionsTable.setItem(row_nb, 5, item)
332 """Update conditions data in the table from the conditions input file"""
333 def update_table(self):
336 nb_rows = self.boundaryConditionsTable.rowCount()
337 for row_nb in xrange(0, nb_rows):
338 group_name = str(self.boundaryConditionsTable.item(row_nb, 5).text())
339 if self.input_conditions.has_key(group_name):
340 values = self.input_conditions[group_name]
342 lihbor = str(values[0])
343 liubor = str(values[1])
344 livbor = str(values[2])
345 litbor = str(values[3])
347 self.boundaryConditionsTable.item(row_nb, 1).setText(lihbor)
348 self.boundaryConditionsTable.item(row_nb, 2).setText(liubor)
349 self.boundaryConditionsTable.item(row_nb, 3).setText(livbor)
350 self.boundaryConditionsTable.item(row_nb, 4).setText(litbor)
354 if not is_updated and nb_rows > 0 and len(self.input_conditions) > 0:
355 QMessageBox.information(self, self.tr("Information"), self.tr("No one group name from the MED file is presented in the input list of conditions."))
357 """Get output file path"""
358 def get_output_path(self):
359 path = self.bndConditionsFileEdit.text()
361 if not self.sameAsInputCB.isChecked():
362 path = self.resultBndConditionsFileEdit.text()
366 """Check if the input data is valid"""
370 if self.boundaryConditionsTable.rowCount() < 1:
371 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Boundary conditions list is empty."))
372 elif len(self.get_output_path())==0:
373 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Output file path is empty."))
375 has_empty_cells = False
376 for row_nb in xrange(0, self.boundaryConditionsTable.rowCount()):
377 lihbor = str(self.boundaryConditionsTable.item(row_nb, 1).text())
378 liubor = str(self.boundaryConditionsTable.item(row_nb, 2).text())
379 livbor = str(self.boundaryConditionsTable.item(row_nb, 3).text())
380 litbor = str(self.boundaryConditionsTable.item(row_nb, 4).text())
382 if (not lihbor) or (not liubor) or (not livbor) or (not litbor):
383 has_empty_cells = True
387 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Table has empty cell(s)."))
393 """Shows help page"""
396 <h2>Boundary conditions dialog</h2>
398 This dialog is used to read and write boundary conditions files.
399 Below is the description of the dialog controls.
402 This field allows selection of a med file (via the standard file open dialog).
403 The file must contain groups of edges, if this is not the case a warning message appears.
404 The filling of this field is mandatory.
406 <h3>Boundary conditions file</h3>
407 This field allows selecting the file of boundary conditions (via the standard file open dialog).
408 The data from this file is displayed in the table "Boundary conditions".
409 This field is optional; if it is not selected the table will not be prefilled.
411 <h3>Result boundary conditions file</h3>
412 This field allows selecting the file in which to save the data (via the standard file save dialog).
413 This field is mandatory if the "Same as the input" check box is unchecked.
415 <h3>Boundary conditions table</h3>
416 Contains data representing the list of boundary conditions.
417 The first column contains a list of presets.
418 The last columns is read-only, it contains names of group of edges from the selected MED file.
419 Other columns is for LIHBOR, LIUBOR, LIVBOR and LITBOR parameters, which can take a value ranging between 0 and 6.
422 When the table is filled and the output file is defined, the user clicks on "Apply" or "Apply and Close" button
423 to perform the data export to the file.
424 Click on "Close" button does not lead to saving the data and just closes the dialog.
426 QMessageBox.about(self, self.tr("About boundary conditions dialog"), msg);