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/>.
23 from PyQt4 import QtCore, QtGui
28 sgPyQt = SalomePyQt.SalomePyQt()
29 from salome.kernel.studyedit import getStudyEditor
30 from salome.kernel.logger import Logger
31 from salome.kernel import termcolor
32 logger = Logger("HYDROGUI", color = termcolor.BLUE)
33 #logger.setLevel(logging.ERROR)
35 import HYDROSOLVER_ORB
36 from salome.hydro.gui_utils import HSGUIException, wait_cursor, get_and_check_selected_file_path
37 import salome.hydro.study as hydro_study
38 from salome.hydro.mascaret.eficas.appli import EficasForMascaretAppli
39 from salome.hydro.telemac2d.eficas.appli import EficasForTelemac2DAppli
40 from salome.hydro.coupling1d2d.eficas.appli import EficasForCoupling1D2DAppli
41 import salome.hydro.pytel.gui as pytel_gui
42 from salome.hydro.boundary_conditions.eficas.appli import EficasForBoundaryConditionsAppli
44 ################################################
46 # Used to store actions, menus, toolbars, etc...
47 ################################################
50 # menus/toolbars/actions IDs
52 CREATE_MASCARET_CASE_ID = 941
54 EDIT_MASCARET_CASE_ID = 943
56 CREATE_TELEMAC2D_CASE_ID = 945
57 RUN_TELEMAC2D_ID = 946
58 EDIT_TELEMAC2D_CASE_ID = 947
59 CREATE_COUPLING1D2D_CASE_ID = 948
60 EDIT_COUPLING1D2D_CASE_ID = 949
61 OPEN_SCHEMA_IN_YACS_ID = 950
62 CREATE_PYTEL_CASE_ID = 951
64 EDIT_PYTEL_CASE_ID = 953
66 DEFINE_BOUNDARY_CONDITIONS_ID = 955
69 # create top-level menu
70 mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
72 tid = sgPyQt.createTool( "Hydro" )
73 # create actions and fill menu and toolbar with actions
74 a = sgPyQt.createAction( GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID,
75 "Define boundary conditions", "Define boundary conditions",
76 "Define the boundary conditions for Telemac",
77 "define_boundary_conditions.png" )
78 sgPyQt.createMenu( a, mid )
79 sgPyQt.createTool( a, tid )
81 a = sgPyQt.createSeparator()
82 sgPyQt.createMenu( a, mid )
83 sgPyQt.createTool( a, tid )
85 a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
86 "Create Mascaret case", "Create Mascaret case",
87 "Create a new Mascaret case", "create_case1d.png" )
88 sgPyQt.createMenu( a, mid )
89 sgPyQt.createTool( a, tid )
91 a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
92 "Create Telemac2D case", "Create Telemac2D case",
93 "Create a new Telemac2D case", "create_case2d.png" )
94 sgPyQt.createMenu( a, mid )
95 sgPyQt.createTool( a, tid )
97 a = sgPyQt.createAction( GUIcontext.CREATE_COUPLING1D2D_CASE_ID,
98 "Create 1D / 2D coupling", "Create 1D / 2D coupling",
99 "Create a new 1D / 2D coupling", "create_case_couplage.png" )
100 sgPyQt.createMenu( a, mid )
101 sgPyQt.createTool( a, tid )
103 a = sgPyQt.createSeparator()
104 sgPyQt.createMenu( a, mid )
105 sgPyQt.createTool( a, tid )
107 a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
108 "Create case for Pytel execution", "Create case for Pytel execution",
109 "Create a new case for Pytel execution", "create_case_pytel.png" )
110 sgPyQt.createMenu( a, mid )
111 sgPyQt.createTool( a, tid )
113 # the following action are used in context popup
114 sgPyQt.createAction( GUIcontext.RUN_MASCARET_ID, "Compute case", "Compute case",
115 "Run Mascaret solver to compute the case" )
116 sgPyQt.createAction( GUIcontext.EDIT_MASCARET_CASE_ID, "Edit case", "Edit case",
117 "Edit the selected Mascaret case" )
118 sgPyQt.createAction( GUIcontext.SHOW_LOG_ID, "Show log", "Show log",
119 "Show the log for the selected variable" )
121 sgPyQt.createAction( GUIcontext.RUN_TELEMAC2D_ID, "Compute case", "Compute case",
122 "Run Telemac2D solver to compute the case" )
123 sgPyQt.createAction( GUIcontext.EDIT_TELEMAC2D_CASE_ID, "Edit case", "Edit case",
124 "Edit the selected Telemac2D case" )
126 sgPyQt.createAction( GUIcontext.EDIT_COUPLING1D2D_CASE_ID, "Edit coupling", "Edit coupling",
127 "Edit the selected 1D / 2D coupling" )
128 sgPyQt.createAction( GUIcontext.OPEN_SCHEMA_IN_YACS_ID, "Open schema in YACS", "Open schema in YACS",
129 "Open the selected 1D / 2D coupling schema in YACS" )
131 sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
132 "Run Pytel launcher to compute the case" )
133 sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
134 "Edit the selected Pytel case" )
135 sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
136 "Generate a batch job to run the selected case")
138 ################################################
140 ################################################
142 # study-to-context map
143 __study2context__ = {}
145 __current_context__ = None
149 ################################################
151 ################################################
154 # get active study ID
157 return sgPyQt.getStudyId()
163 studyId = _getStudyId()
164 study = getStudyManager().GetStudyByID( studyId )
168 # returns True if object has children
170 def _hasChildren( sobj ):
173 iter = study.NewChildIterator( sobj )
175 name = iter.Value().GetName()
184 # get current GUI context
187 global __current_context__
188 return __current_context__
191 # set and return current GUI context
192 # study ID is passed as parameter
194 def _setContext( studyID ):
195 global __study2context__, __current_context__
196 if not __study2context__.has_key(studyID):
197 __study2context__[studyID] = GUIcontext()
199 __current_context__ = __study2context__[studyID]
200 return __current_context__
203 # increment object counter in the map
205 def _incObjToMap( m, id ):
206 if id not in m: m[id] = 0
210 ################################################
212 ################################################
214 # called when module is activated
215 # returns True if activating is successfull and False otherwise
217 ctx = _setContext( _getStudyId() )
220 # called when module is deactivated
224 # called when active study is changed
225 # active study ID is passed as parameter
226 def activeStudyChanged( studyID ):
227 ctx = _setContext( _getStudyId() )
230 # called when popup menu is invoked
231 # popup menu and menu context are passed as parameters
232 def createPopupMenu(popup, context):
233 ed = getStudyEditor()
234 _setContext(ed.studyId)
235 if salome.sg.SelectedCount() == 1:
236 # one object is selected
237 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
238 selectedType = ed.getTypeId(sobj)
239 if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
240 popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
241 popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
242 elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
243 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
244 popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
245 elif selectedType == hydro_study.COUPLING1D2D_CASE_TYPE_ID:
246 popup.addAction(sgPyQt.action(GUIcontext.EDIT_COUPLING1D2D_CASE_ID))
247 popup.addAction(sgPyQt.action(GUIcontext.OPEN_SCHEMA_IN_YACS_ID))
248 elif selectedType == hydro_study.LOG_TYPE_ID:
249 popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
250 elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
251 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
252 popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
253 popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
255 # called when GUI action is activated
256 # action ID is passed as parameter
257 def OnGUIEvent( commandID ):
259 dict_command[commandID]()
260 except HSGUIException, exc:
261 QtGui.QMessageBox.critical(sgPyQt.getDesktop(),
262 QtGui.QApplication.translate("OnGUIEvent", "Error"),
265 logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
266 msg = QtGui.QApplication.translate("OnGUIEvent",
267 "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
268 '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
269 'category "HYDROSOLVER", describing how you got there and including the following traceback:')
270 msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Critical,
271 QtGui.QApplication.translate("OnGUIEvent", "Error"),
273 parent = sgPyQt.getDesktop())
274 msgBox.setDetailedText(traceback.format_exc())
277 ################################################
278 # GUI actions implementation
279 ################################################
281 # --------------------------------------------------------------------------------------- #
282 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
283 # --------------------------------------------------------------------------------------- #
285 from TextDisplayDialog import Ui_TextDisplayDialog
287 class MyTextDisplayDialog(Ui_TextDisplayDialog, QtGui.QDialog):
289 def __init__(self, parent = None, modal = 0):
290 QtGui.QDialog.__init__(self, parent)
291 Ui_TextDisplayDialog.__init__(self)
293 self.connect(self.closeButton, QtCore.SIGNAL("clicked()"), self.close)
295 def set_log(self, log):
296 self.contentTextEdit.setPlainText(log)
297 self.setWindowTitle("Coupling log")
301 # Open Eficas for Mascaret to create a new case
303 def create_mascaret_case():
304 EficasForMascaretAppli()
307 # Open Eficas for Mascaret to edit the selected case
309 def edit_mascaret_case():
310 EficasForMascaretAppli(get_and_check_selected_file_path())
312 # Run Mascaret on selected case
316 ed = hydro_study.HydroStudyEditor()
317 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
318 (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
319 var_names = [var["NOM"].strip() for var in output_vars]
320 mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
321 engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
322 logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
323 (file_list, lig_file, mascaret_vars))
324 output_values = engine.Compute(file_list, lig_file, mascaret_vars)
325 ed.add_results_to_mascaret_case(sobj, var_names, output_values)
326 salome.sg.updateObjBrowser( 0 )
327 except SALOME.SALOME_Exception, exc:
328 salome.sg.updateObjBrowser( 0 )
329 msg = unicode(QtGui.QApplication.translate("run_mascaret",
330 "An error happened while trying to run Mascaret:"))
331 msg += "\n" + exc.details.text
332 raise HSGUIException(msg)
334 # Display selected log (deprecated, it was only used in the calcium coupling test)
336 ed = hydro_study.HydroStudyEditor()
337 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
339 (found, attr) = getStudyEditor().builder.FindAttribute(
340 sobj, "AttributeParameter")
341 log = attr.GetString("log")
342 dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
347 # Open Eficas for Telemac2D to create a new case
349 def create_telemac2d_case():
350 EficasForTelemac2DAppli()
353 # Open Eficas for Telemac2D to edit the selected case
355 def edit_telemac2d_case():
356 EficasForTelemac2DAppli(get_and_check_selected_file_path())
358 # Run Telemac2D on selected case
363 ed = hydro_study.HydroStudyEditor()
364 entry = salome.sg.getSelected(0)
365 engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
366 engine.Compute(ed.editor.studyId, entry)
367 # Stop container after execution so that we can use another fortran user file in the next run
368 engine.GetContainerRef().Shutdown()
369 except SALOME.SALOME_Exception, exc:
370 if engine is not None:
371 engine.GetContainerRef().Shutdown()
372 msg = unicode(QtGui.QApplication.translate("run_telemac2d",
373 "An error happened while trying to run Telemac2D:"))
374 msg += "\n" + exc.details.text
375 raise HSGUIException(msg)
376 except Exception, exc:
377 logger.exception("An error happened in the computation (Telemac2D probably crashed).")
379 engine.GetContainerRef().Shutdown()
382 msg = unicode(QtGui.QApplication.translate("run_telemac2d",
383 "An error happened in the computation (Telemac2D probably crashed, "
384 "see logs and listing files for more details):"))
385 msg += "\n" + unicode(exc)
386 raise HSGUIException(msg)
389 # Open Eficas for 1D / 2D Coupling to create a new coupling case
391 def create_coupling1d2d_case():
392 EficasForCoupling1D2DAppli()
395 # Open Eficas for 1D / 2D Coupling to edit the selected coupling case
397 def edit_coupling1d2d_case():
398 EficasForCoupling1D2DAppli(get_and_check_selected_file_path())
400 def open_schema_in_yacs():
401 ed = getStudyEditor()
402 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
403 filename = sobj.GetComment()
404 if filename.endswith(".comm"):
405 filename = filename[:-5] + ".xml"
406 if not os.path.isfile(filename):
407 raise HSGUIException(QtGui.QApplication.translate("open_schema_in_yacs",
408 "Schema file %1 does not exist").arg(filename))
409 yg = salome.ImportComponentGUI("YACS")
410 yg.loadSchema(filename)
413 # Open Eficas for boundary conditions definition
415 def define_boundary_conditions():
416 EficasForBoundaryConditionsAppli()
419 # Commands dictionary
422 GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
423 GUIcontext.RUN_MASCARET_ID: run_mascaret,
424 GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
425 GUIcontext.SHOW_LOG_ID: show_log,
426 GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
427 GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
428 GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
429 GUIcontext.CREATE_COUPLING1D2D_CASE_ID: create_coupling1d2d_case,
430 GUIcontext.EDIT_COUPLING1D2D_CASE_ID: edit_coupling1d2d_case,
431 GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
432 GUIcontext.CREATE_PYTEL_CASE_ID: pytel_gui.create_case,
433 GUIcontext.RUN_PYTEL_ID: pytel_gui.run_selected_case,
434 GUIcontext.EDIT_PYTEL_CASE_ID: pytel_gui.edit_selected_case,
435 GUIcontext.GENERATE_JOB: pytel_gui.generate_job_for_selected_case,
436 GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,