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 PyQt5.QtWidgets import QMessageBox, QApplication, QDialog
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.interpolz_gui import InterpolzDlg
37 from salome.hydro.gui_utils import HSGUIException, wait_cursor, get_and_check_selected_file_path
38 import salome.hydro.study as hydro_study
39 from salome.hydro.mascaret.eficas.appli import EficasForMascaretAppli
40 from salome.hydro.telemac2d.eficas.appli import EficasForTelemac2DAppli
41 from salome.hydro.coupling1d2d.eficas.appli import EficasForCoupling1D2DAppli
42 from salome.hydro.pytel.gui import create_case_pytel, run_selected_case_pytel, edit_selected_case_pytel, generate_job_for_selected_case_pytel
43 #from salome.hydro.boundary_conditions.eficas.appli import EficasForBoundaryConditionsAppli
44 from eficasSalome import runEficas
46 import BndConditionsDialog
48 ################################################
50 # Used to store actions, menus, toolbars, etc...
51 ################################################
54 # menus/toolbars/actions IDs
56 CREATE_MASCARET_CASE_ID = 941
58 EDIT_MASCARET_CASE_ID = 943
60 CREATE_TELEMAC2D_CASE_ID = 945
61 RUN_TELEMAC2D_ID = 946
62 EDIT_TELEMAC2D_CASE_ID = 947
63 CREATE_COUPLING1D2D_CASE_ID = 948
64 EDIT_COUPLING1D2D_CASE_ID = 949
65 OPEN_SCHEMA_IN_YACS_ID = 950
66 CREATE_PYTEL_CASE_ID = 951
68 EDIT_PYTEL_CASE_ID = 953
70 #DEFINE_BOUNDARY_CONDITIONS_ID = 955
72 EDIT_BOUNDARY_CONDITIONS_FILE_ID = 956
73 GENERATE_INTERPOLZ_PY_ID = 957
74 GEN_TELEMAC2D_PYTHON_ID = 958
77 # create top-level menu
78 mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
80 tid = sgPyQt.createTool( "Hydro" )
81 # create actions and fill menu and toolbar with actions
82 a = sgPyQt.createAction( GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
83 "Edit boundary conditions file", "Edit boundary conditions file",
84 "Create/edit the boundary conditions file for Telemac",
85 "edit_boundary_conditions_file.png" )
86 sgPyQt.createMenu( a, mid )
87 sgPyQt.createTool( a, tid )
90 a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
91 "Create Mascaret case", "Create Mascaret case",
92 "Create a new Mascaret case", "create_case1d.png" )
93 sgPyQt.createMenu( a, mid )
94 sgPyQt.createTool( a, tid )
96 a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
97 "Create Telemac2D case", "Create Telemac2D case",
98 "Create a new Telemac2D case", "create_case2d.png" )
99 sgPyQt.createMenu( a, mid )
100 sgPyQt.createTool( a, tid )
102 a = sgPyQt.createAction( GUIcontext.CREATE_COUPLING1D2D_CASE_ID,
103 "Create 1D / 2D coupling", "Create 1D / 2D coupling",
104 "Create a new 1D / 2D coupling", "create_case_couplage.png" )
105 sgPyQt.createMenu( a, mid )
106 sgPyQt.createTool( a, tid )
108 a = sgPyQt.createSeparator()
110 a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
111 "Create case for Pytel execution", "Create case for Pytel execution",
112 "Create a new case for Pytel execution", "create_case_pytel.png" )
114 sgPyQt.createMenu( a, mid )
115 sgPyQt.createTool( a, tid )
117 a = sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID,
118 "Edit case for Pytel execution", "Edit case for Pytel execution",
119 "Edit a new case for Pytel execution", "edit_case_pytel.png" )
121 sgPyQt.createMenu( a, mid )
122 sgPyQt.createTool( a, tid )
124 a = sgPyQt.createSeparator()
126 a = sgPyQt.createAction( GUIcontext.GENERATE_INTERPOLZ_PY_ID,
127 "Generate interpolz.py", "Generate interpolz.py",
128 "Generate interpolation script from the template", "generate_interpolz_py.png" )
130 sgPyQt.createMenu( a, mid )
131 sgPyQt.createTool( a, tid )
133 a = sgPyQt.createSeparator()
134 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE,
135 "Edit cas file", "Edit cas file",
136 "Create/edit a .cas file for Telemac",
137 "define_cas_file.png" )
138 sgPyQt.createMenu( a, mid )
139 sgPyQt.createTool( a, tid )
142 # the following action are used in context popup
143 sgPyQt.createAction( GUIcontext.RUN_MASCARET_ID, "Compute case", "Compute case",
144 "Run Mascaret solver to compute the case" )
145 sgPyQt.createAction( GUIcontext.EDIT_MASCARET_CASE_ID, "Edit case", "Edit case",
146 "Edit the selected Mascaret case" )
147 sgPyQt.createAction( GUIcontext.SHOW_LOG_ID, "Show log", "Show log",
148 "Show the log for the selected variable" )
150 sgPyQt.createAction( GUIcontext.GEN_TELEMAC2D_PYTHON_ID, "Generate Python script",
151 "Generate Python script",
152 "Run Telemac2D solver to compute the case" )
153 sgPyQt.createAction( GUIcontext.RUN_TELEMAC2D_ID, "Compute case", "Compute case",
154 "Run Telemac2D solver to compute the case" )
155 sgPyQt.createAction( GUIcontext.EDIT_TELEMAC2D_CASE_ID, "Edit case", "Edit case",
156 "Edit the selected Telemac2D case" )
158 sgPyQt.createAction( GUIcontext.EDIT_COUPLING1D2D_CASE_ID, "Edit coupling", "Edit coupling",
159 "Edit the selected 1D / 2D coupling" )
160 sgPyQt.createAction( GUIcontext.OPEN_SCHEMA_IN_YACS_ID, "Open schema in YACS", "Open schema in YACS",
161 "Open the selected 1D / 2D coupling schema in YACS" )
163 sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
164 "Run Pytel launcher to compute the case" )
165 sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
166 "Edit the selected Pytel case" )
167 sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
168 "Generate a batch job to run the selected case")
170 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE, "Edit .cas file", "Edit .cas file",
174 ################################################
176 ################################################
178 # study-to-context map
179 __study2context__ = {}
181 __current_context__ = None
185 ################################################
187 ################################################
190 # get active study ID
193 return sgPyQt.getStudyId()
199 studyId = _getStudyId()
200 study = getStudyManager().GetStudyByID( studyId )
204 # returns True if object has children
206 def _hasChildren( sobj ):
209 iter = study.NewChildIterator( sobj )
211 name = iter.Value().GetName()
220 # get current GUI context
223 global __current_context__
224 return __current_context__
227 # set and return current GUI context
228 # study ID is passed as parameter
230 def _setContext( studyID ):
231 global __study2context__, __current_context__
232 if not __study2context__.has_key(studyID):
233 __study2context__[studyID] = GUIcontext()
235 __current_context__ = __study2context__[studyID]
236 return __current_context__
239 # increment object counter in the map
241 def _incObjToMap( m, id ):
242 if id not in m: m[id] = 0
246 ################################################
248 ################################################
250 # called when module is activated
251 # returns True if activating is successfull and False otherwise
253 ctx = _setContext( _getStudyId() )
256 # called when module is deactivated
260 # called when active study is changed
261 # active study ID is passed as parameter
262 def activeStudyChanged( studyID ):
263 ctx = _setContext( _getStudyId() )
266 # called when popup menu is invoked
267 # popup menu and menu context are passed as parameters
268 def createPopupMenu(popup, context):
269 ed = getStudyEditor()
270 _setContext(ed.studyId)
271 if salome.sg.SelectedCount() == 1:
272 # one object is selected
273 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
274 selectedType = ed.getTypeId(sobj)
275 if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
276 popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
277 popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
278 elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
279 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
280 popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
281 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_PYTHON_ID))
282 elif selectedType == hydro_study.COUPLING1D2D_CASE_TYPE_ID:
283 popup.addAction(sgPyQt.action(GUIcontext.EDIT_COUPLING1D2D_CASE_ID))
284 popup.addAction(sgPyQt.action(GUIcontext.OPEN_SCHEMA_IN_YACS_ID))
285 elif selectedType == hydro_study.LOG_TYPE_ID:
286 popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
287 elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
288 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
289 popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
290 popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
292 # called when GUI action is activated
293 # action ID is passed as parameter
294 def OnGUIEvent( commandID ):
296 dict_command[commandID]()
297 except HSGUIException, exc:
298 QMessageBox.critical(sgPyQt.getDesktop(),
299 QApplication.translate("OnGUIEvent", "Error"),
302 logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
303 msg = QApplication.translate("OnGUIEvent",
304 "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
305 '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
306 'category "HYDROSOLVER", describing how you got there and including the following traceback:')
307 msgBox = QMessageBox(QMessageBox.Critical,
308 QApplication.translate("OnGUIEvent", "Error"),
310 parent = sgPyQt.getDesktop())
311 msgBox.setDetailedText(traceback.format_exc())
314 ################################################
315 # GUI actions implementation
316 ################################################
318 # --------------------------------------------------------------------------------------- #
319 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
320 # --------------------------------------------------------------------------------------- #
322 from TextDisplayDialog import Ui_TextDisplayDialog
324 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
326 def __init__(self, parent = None, modal = 0):
327 QDialog.__init__(self, parent)
328 Ui_TextDisplayDialog.__init__(self)
330 (self.closeButton.clicked.connect(self.close)
332 def set_log(self, log):
333 self.contentTextEdit.setPlainText(log)
334 self.setWindowTitle("Coupling log")
338 # Open Eficas for Mascaret to create a new case
340 def create_mascaret_case():
341 EficasForMascaretAppli()
344 # Open Eficas for Mascaret to edit the selected case
346 def edit_mascaret_case():
347 EficasForMascaretAppli(get_and_check_selected_file_path())
349 # Run Mascaret on selected case
353 ed = hydro_study.HydroStudyEditor()
354 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
355 (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
356 var_names = [var["NOM"].strip() for var in output_vars]
357 mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
358 engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
359 logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
360 (file_list, lig_file, mascaret_vars))
361 output_values = engine.Compute(file_list, lig_file, mascaret_vars)
362 ed.add_results_to_mascaret_case(sobj, var_names, output_values)
363 salome.sg.updateObjBrowser( 0 )
364 except SALOME.SALOME_Exception, exc:
365 salome.sg.updateObjBrowser( 0 )
366 msg = unicode(QApplication.translate("run_mascaret",
367 "An error happened while trying to run Mascaret:"))
368 msg += "\n" + exc.details.text
369 raise HSGUIException(msg)
371 # Display selected log (deprecated, it was only used in the calcium coupling test)
373 ed = hydro_study.HydroStudyEditor()
374 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
376 (found, attr) = getStudyEditor().builder.FindAttribute(
377 sobj, "AttributeParameter")
378 log = attr.GetString("log")
379 dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
384 # Open Eficas for Telemac2D to create a new case
386 def create_telemac2d_case():
387 EficasForTelemac2DAppli()
390 # Open Eficas for Telemac2D to edit the selected case
392 def edit_telemac2d_case():
393 EficasForTelemac2DAppli(get_and_check_selected_file_path())
395 # Run Telemac2D on selected case
400 ed = hydro_study.HydroStudyEditor()
401 entry = salome.sg.getSelected(0)
402 engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
403 engine.Compute(ed.editor.studyId, entry)
404 # Stop container after execution so that we can use another fortran user file in the next run
405 engine.GetContainerRef().Shutdown()
406 except SALOME.SALOME_Exception, exc:
407 if engine is not None:
408 engine.GetContainerRef().Shutdown()
409 msg = unicode(QApplication.translate("run_telemac2d",
410 "An error happened while trying to run Telemac2D:"))
411 msg += "\n" + exc.details.text
412 raise HSGUIException(msg)
413 except Exception, exc:
414 logger.exception("An error happened in the computation (Telemac2D probably crashed).")
416 engine.GetContainerRef().Shutdown()
419 msg = unicode(QApplication.translate("run_telemac2d",
420 "An error happened in the computation (Telemac2D probably crashed, "
421 "see logs and listing files for more details):"))
422 msg += "\n" + unicode(exc)
423 raise HSGUIException(msg)
426 # Generate a python script from the eficas file
428 def generate_telemac2d_python():
431 ed = hydro_study.HydroStudyEditor()
432 sobj = get_and_check_selected_file_path()
434 ed.find_or_create_telemac2d_case(sobj)
435 except SALOME.SALOME_Exception, exc:
436 salome.sg.updateObjBrowser( 0 )
437 msg = unicode(QApplication.translate("generate_telemac2d_python",
438 "An error happened while trying to generate telemac2d Python script:"))
439 msg += "\n" + exc.details.text
440 raise HSGUIException(msg)
444 # Open Eficas for 1D / 2D Coupling to create a new coupling case
446 def create_coupling1d2d_case():
447 EficasForCoupling1D2DAppli()
450 # Open Eficas for 1D / 2D Coupling to edit the selected coupling case
452 def edit_coupling1d2d_case():
453 EficasForCoupling1D2DAppli(get_and_check_selected_file_path())
455 def open_schema_in_yacs():
456 ed = getStudyEditor()
457 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
458 filename = sobj.GetComment()
459 if filename.endswith(".comm"):
460 filename = filename[:-5] + ".xml"
461 if not os.path.isfile(filename):
462 raise HSGUIException(QApplication.translate("open_schema_in_yacs",
463 "Schema file %1 does not exist").arg(filename))
464 yg = salome.ImportComponentGUI("YACS")
465 yg.loadSchema(filename)
468 # Open Eficas for boundary conditions definition
470 #def define_boundary_conditions():
471 # EficasForBoundaryConditionsAppli()
474 # Open dialog for boundary conditions edition
476 def edit_boundary_conditions_file():
477 desktop = sgPyQt.getDesktop()
478 dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
482 # Open dialog for interpolz.py script generation
484 def generate_interpolz_py():
485 desktop = sgPyQt.getDesktop()
486 dlg = InterpolzDlg(desktop)
490 # Open dialog for boundary conditions edition
492 def eficas_for_cas_Telemac2D():
493 runEficas(code='TELEMAC')
495 # Commands dictionary
498 GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
499 GUIcontext.RUN_MASCARET_ID: run_mascaret,
500 GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
501 GUIcontext.SHOW_LOG_ID: show_log,
502 GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
503 GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
504 GUIcontext.GEN_TELEMAC2D_PYTHON_ID: generate_telemac2d_python,
505 GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
506 GUIcontext.CREATE_COUPLING1D2D_CASE_ID: create_coupling1d2d_case,
507 GUIcontext.EDIT_COUPLING1D2D_CASE_ID: edit_coupling1d2d_case,
508 GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
509 GUIcontext.CREATE_PYTEL_CASE_ID: create_case_pytel,
510 GUIcontext.RUN_PYTEL_ID: run_selected_case_pytel,
511 GUIcontext.EDIT_PYTEL_CASE_ID: edit_selected_case_pytel,
512 GUIcontext.GENERATE_JOB: generate_job_for_selected_case_pytel,
513 #GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,
514 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
515 GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
516 GUIcontext.DEFINE_CAS_FILE: eficas_for_cas_Telemac2D,