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 from salome.hydro 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):
50 res = (lihbor, liubor, livbor, litbor)
51 for key, val in presets.iteritems():
57 """Convert string to integer, return None if conversion is not possible"""
66 """Item delegate for LIHBOR, LIUBOR, LIVBOR and LITBOR columns"""
67 class ValueDelegate(QStyledItemDelegate):
69 def __init__(self, parent = None):
70 QStyledItemDelegate.__init__(self, parent)
72 def createEditor(self, parent, option, index):
73 line_edit = QLineEdit(parent)
75 validator = QIntValidator(parent)
76 validator.setRange(0, 6)
78 line_edit.setValidator(validator)
82 def setEditorData(self, editor, index):
83 value = index.model().data(index, Qt.EditRole)
89 def setModelData(self, editor, model, index):
90 model.setData(index, editor.text(), Qt.EditRole)
92 def updateEditorGeometry(self, editor, option, index):
93 editor.setGeometry(option.rect)
95 """Boundary conditions definition dialog"""
96 class BoundaryConditionsDialog(QDialog):
98 def __init__(self, parent = None, modal = 0):
99 QDialog.__init__(self, parent)
100 uic.loadUi(os.path.join(hydro_solver_root, 'BndConditionsDialog.ui'), self )
103 self.medFileButton.clicked.connect(self.on_med_file_browse)
104 self.bndConditionsFileButton.clicked.connect(self.on_bnd_file_browse)
105 self.resultBndConditionsFileButton.clicked.connect(self.on_result_file_browse)
107 self.sameAsInputCB.toggled.connect(self.resultBndConditionsFileEdit.setDisabled)
108 self.sameAsInputCB.toggled.connect(self.resultBndConditionsFileButton.setDisabled)
110 self.boundaryConditionsTable.cellChanged.connect(self.on_cell_changed)
112 self.applyAndCloseButton.clicked.connect(self.on_apply_and_close)
113 self.applyButton.clicked.connect(self.on_apply)
114 self.closeButton.clicked.connect(self.reject)
115 self.helpButton.clicked.connect(self.on_help)
117 # Set widgets properties
121 self.input_conditions = {}
127 """Initialize presets"""
128 def init_presets(self):
129 # TODO: determine another presets path
130 presets_data_root = os.path.join(os.environ['HYDROSOLVER_ROOT_DIR'], 'lib', 'python2.7', 'site-packages', 'salome', 'tests', 'data')
131 file_path = os.path.join(presets_data_root, 'bnd_conditions_presets.txt')
132 reader = boundaryConditions.PresetReader(file_path)
133 self.presets = reader.read()
135 """Initialize widget properties"""
136 def init_widgets(self):
137 self.medFileEdit.setReadOnly(True)
138 self.bndConditionsFileEdit.setReadOnly(True)
139 self.resultBndConditionsFileEdit.setReadOnly(True)
141 delegate = ValueDelegate(self.boundaryConditionsTable)
142 self.boundaryConditionsTable.setItemDelegateForColumn(1, delegate)
143 self.boundaryConditionsTable.setItemDelegateForColumn(2, delegate)
144 self.boundaryConditionsTable.setItemDelegateForColumn(3, delegate)
145 self.boundaryConditionsTable.setItemDelegateForColumn(4, delegate)
147 """Process cell data changes"""
148 def on_cell_changed(self, row, column):
149 #print "on_cell_changed"
150 lihbor = liubor = livbor = litbor = None
152 item = self.boundaryConditionsTable.item(row, 1)
154 lihbor = get_int(str(item.text()))
156 item = self.boundaryConditionsTable.item(row, 2)
158 liubor = get_int(str(item.text()))
160 item = self.boundaryConditionsTable.item(row, 3)
162 livbor = get_int(str(item.text()))
164 item = self.boundaryConditionsTable.item(row, 4)
166 litbor = get_int(str(item.text()))
168 preset_name = get_preset_name(self.presets, lihbor, liubor, livbor, litbor)
169 #print "on_cell_changed ", preset_name, lihbor, liubor, livbor, litbor
171 combo = self.boundaryConditionsTable.cellWidget(row, 0)
172 if isinstance(combo, QComboBox):
173 ind = combo.findText(preset_name)
175 combo.currentIndexChanged.disconnect(self.on_preset_changed)
176 combo.setCurrentIndex(ind)
177 combo.currentIndexChanged.connect(self.on_preset_changed)
179 """Save the user data to boundary conditions file"""
181 # Save boundary conditions file
182 if not self.is_valid():
186 if self.sameAsInputCB.isChecked():
187 file_path = self.bndConditionsFileEdit.text()
189 file_path = self.resultBndConditionsFileEdit.text()
190 print 'File path:', file_path
191 writer = boundaryConditions.BoundaryConditionWriter(file_path)
194 for row_nb in xrange(0, self.boundaryConditionsTable.rowCount()):
195 lihbor = str(self.boundaryConditionsTable.item(row_nb, 1).text())
196 liubor = str(self.boundaryConditionsTable.item(row_nb, 2).text())
197 livbor = str(self.boundaryConditionsTable.item(row_nb, 3).text())
198 litbor = str(self.boundaryConditionsTable.item(row_nb, 4).text())
199 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."))
230 self.boundaryConditionsTable.resizeColumnsToContents()
232 """Select boundary conditions file"""
233 def on_bnd_file_browse(self):
234 file_path, filt = QFileDialog.getOpenFileName(self, self.tr("Open boundary conditions file"))
237 self.bndConditionsFileEdit.setText(file_path)
238 reader = boundaryConditions.BoundaryConditionReader(file_path)
239 conditions = reader.read()
241 self.input_conditions.clear()
242 for cnd in conditions:
243 self.input_conditions[cnd.group] = (cnd.lihbor, cnd.liubor, cnd.livbor, cnd.litbor)
246 read_errors = reader.errors
247 if len( read_errors ) > 0:
248 msg = "\n".join(read_errors)
249 QMessageBox.warning(self, self.tr("Warning"), msg)
251 if len(self.input_conditions) > 0:
254 QMessageBox.warning(self, self.tr("Warning"), self.tr("No conditions have been read from the file."))
256 """Called on preset selection in the first column of the table"""
257 def on_preset_changed(self):
258 #print"on_preset_changed"
259 combo = self.sender()
261 preset = str(combo.currentText())
263 if preset and self.presets.has_key(preset):
264 values = self.presets[preset]
265 row_nb = combo.property(ROW_PROPERTY_NAME)
267 if row_nb >= 0 and row_nb < self.boundaryConditionsTable.rowCount():
272 #print "on_preset_changed ", preset, lihbor, liubor, livbor, litbor
274 #if lihbor is not None:
275 self.boundaryConditionsTable.item(row_nb, 1).setText(str(lihbor))
277 #if liubor is not None:
278 self.boundaryConditionsTable.item(row_nb, 2).setText(str(liubor))
280 #if livbor is not None:
281 self.boundaryConditionsTable.item(row_nb, 3).setText(str(livbor))
283 #if litbor is not None:
284 self.boundaryConditionsTable.item(row_nb, 4).setText(str(litbor))
286 if isinstance(combo, QComboBox):
287 ind = combo.findText(preset)
289 combo.setCurrentIndex(ind)
291 """Define result file path"""
292 def on_result_file_browse(self):
293 file_path, filt = QFileDialog.getSaveFileName(self, self.tr("Select output file path"))
296 self.resultBndConditionsFileEdit.setText(file_path)
298 """Set groups list"""
299 def set_groups(self, groups):
301 self.boundaryConditionsTable.setRowCount(0)
304 row_nb = self.boundaryConditionsTable.rowCount()
305 self.boundaryConditionsTable.insertRow(row_nb)
308 combo = QComboBox(self)
310 if len(self.presets) > 0:
311 items = self.presets.keys()
313 combo.addItems(items)
315 combo.setProperty(ROW_PROPERTY_NAME, row_nb)
316 combo.currentIndexChanged.connect(self.on_preset_changed)
318 self.boundaryConditionsTable.setCellWidget(row_nb, 0, combo)
321 self.boundaryConditionsTable.setItem(row_nb, 1, QTableWidgetItem(''))
324 self.boundaryConditionsTable.setItem(row_nb, 2, QTableWidgetItem(''))
327 self.boundaryConditionsTable.setItem(row_nb, 3, QTableWidgetItem(''))
330 self.boundaryConditionsTable.setItem(row_nb, 4, QTableWidgetItem(''))
333 item = QTableWidgetItem(group)
337 item.setFlags(Qt.ItemIsEnabled)
338 self.boundaryConditionsTable.setItem(row_nb, 5, item)
342 """Update conditions data in the table from the conditions input file"""
343 def update_table(self):
344 #print "update_table"
347 nb_rows = self.boundaryConditionsTable.rowCount()
348 for row_nb in xrange(0, nb_rows):
349 group_name = str(self.boundaryConditionsTable.item(row_nb, 5).text())
350 if self.input_conditions.has_key(group_name):
352 values = self.input_conditions[group_name]
355 lihbor = str(values[0])
356 liubor = str(values[1])
357 livbor = str(values[2])
358 litbor = str(values[3])
359 #print lihbor, liubor, livbor, litbor
361 self.boundaryConditionsTable.item(row_nb, 1).setText(lihbor)
362 self.boundaryConditionsTable.item(row_nb, 2).setText(liubor)
363 self.boundaryConditionsTable.item(row_nb, 3).setText(livbor)
364 self.boundaryConditionsTable.item(row_nb, 4).setText(litbor)
366 # combo = self.boundaryConditionsTable.cellWidget(row_nb, 0)
367 # if isinstance(combo, QComboBox):
368 # preset_name = get_preset_name(self.presets, lihbor, liubor, livbor, litbor)
369 # ind = combo.findText(preset_name)
371 # combo.setCurrentIndex(ind)
375 if not is_updated and nb_rows > 0 and len(self.input_conditions) > 0:
376 QMessageBox.information(self, self.tr("Information"), self.tr("No one group name from the MED file is presented in the input list of conditions."))
378 """Get output file path"""
379 def get_output_path(self):
380 path = self.bndConditionsFileEdit.text()
382 if not self.sameAsInputCB.isChecked():
383 path = self.resultBndConditionsFileEdit.text()
387 """Check if the input data is valid"""
391 if self.boundaryConditionsTable.rowCount() < 1:
392 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Boundary conditions list is empty."))
393 elif len(self.get_output_path())==0:
394 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Output file path is empty."))
396 for row_nb in xrange(0, self.boundaryConditionsTable.rowCount()):
397 has_empty_cells = True
398 lihbor = str(self.boundaryConditionsTable.item(row_nb, 1).text())
399 liubor = str(self.boundaryConditionsTable.item(row_nb, 2).text())
400 livbor = str(self.boundaryConditionsTable.item(row_nb, 3).text())
401 litbor = str(self.boundaryConditionsTable.item(row_nb, 4).text())
402 #print "test valid: ", lihbor, liubor, livbor, litbor
403 if (lihbor != '') and (liubor != '') and (livbor != '') and (litbor != '') :
404 has_empty_cells = False # Full lines are OK
405 #print "valid: full line"
406 if (lihbor == '') and (liubor == '') and (livbor == '') and (litbor == ''):
407 has_empty_cells = False # Empty lines are OK
408 #print "valid: empty line"
412 QMessageBox.critical(self, self.tr("Insufficient input data"), self.tr("Table has empty cell(s)."))
418 """Shows help page"""
421 <h2>Boundary conditions dialog</h2>
423 This dialog is used to read and write boundary conditions files.
424 Below is the description of the dialog controls.
427 This field allows selection of a med file (via the standard file open dialog).
428 The file must contain groups of edges, if this is not the case a warning message appears.
429 The filling of this field is mandatory.
431 <h3>Boundary conditions file</h3>
432 This field allows selecting the file of boundary conditions (via the standard file open dialog).
433 The data from this file is displayed in the table "Boundary conditions".
434 This field is optional; if it is not selected the table will not be prefilled.
436 <h3>Result boundary conditions file</h3>
437 This field allows selecting the file in which to save the data (via the standard file save dialog).
438 This field is mandatory if the "Same as the input" check box is unchecked.
440 <h3>Boundary conditions table</h3>
441 Contains data representing the list of boundary conditions.
442 The first column contains a list of presets.
443 The last columns is read-only, it contains names of group of edges from the selected MED file.
444 Other columns is for LIHBOR, LIUBOR, LIVBOR and LITBOR parameters, which can take a value ranging between 0 and 6.
447 When the table is filled and the output file is defined, the user clicks on "Apply" or "Apply and Close" button
448 to perform the data export to the file.
449 Click on "Close" button does not lead to saving the data and just closes the dialog.
451 QMessageBox.about(self, self.tr("About boundary conditions dialog"), msg);