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.pytel.gui import create_case_pytel, run_selected_case_pytel, edit_selected_case_pytel, generate_job_for_selected_case_pytel
42 #from salome.hydro.boundary_conditions.eficas.appli import EficasForBoundaryConditionsAppli
43 from eficasSalome import runEficas
45 import BndConditionsDialog
47 ################################################
49 # Used to store actions, menus, toolbars, etc...
50 ################################################
53 # menus/toolbars/actions IDs
55 CREATE_MASCARET_CASE_ID = 941
57 EDIT_MASCARET_CASE_ID = 943
59 CREATE_TELEMAC2D_CASE_ID = 945
60 RUN_TELEMAC2D_ID = 946
61 EDIT_TELEMAC2D_CASE_ID = 947
62 OPEN_SCHEMA_IN_YACS_ID = 950
63 CREATE_PYTEL_CASE_ID = 951
65 EDIT_PYTEL_CASE_ID = 953
67 #DEFINE_BOUNDARY_CONDITIONS_ID = 955
68 DEFINE_CAS_FILE_EN = 955
69 EDIT_BOUNDARY_CONDITIONS_FILE_ID = 956
70 GENERATE_INTERPOLZ_PY_ID = 957
71 GEN_TELEMAC2D_PYTHON_ID = 958
72 GEN_TELEMAC2D_YACS_ID = 959
73 DEFINE_CAS_FILE_FR = 960
76 # create top-level menu
77 mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
79 tid = sgPyQt.createTool( "Hydro" )
80 # create actions and fill menu and toolbar with actions
81 a = sgPyQt.createAction( GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
82 "Edit boundary conditions file", "Edit boundary conditions file",
83 "Create/edit the boundary conditions file for Telemac",
84 "edit_boundary_conditions_file.png" )
85 sgPyQt.createMenu( a, mid )
86 sgPyQt.createTool( a, tid )
89 a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
90 "Create Mascaret case", "Create Mascaret case",
91 "Create a new Mascaret case", "create_case1d.png" )
92 sgPyQt.createMenu( a, mid )
93 sgPyQt.createTool( a, tid )
95 a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
96 "Create Telemac2D case", "Create Telemac2D case",
97 "Create a new Telemac2D case", "create_case2d.png" )
98 sgPyQt.createMenu( a, mid )
99 sgPyQt.createTool( a, tid )
101 a = sgPyQt.createSeparator()
103 a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
104 "Create case for Pytel execution", "Create case for Pytel execution",
105 "Create a new case for Pytel execution", "create_case_pytel.png" )
107 sgPyQt.createMenu( a, mid )
108 sgPyQt.createTool( a, tid )
110 a = sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID,
111 "Edit case for Pytel execution", "Edit case for Pytel execution",
112 "Edit a new case for Pytel execution", "case_pytel.png" )
114 sgPyQt.createMenu( a, mid )
115 sgPyQt.createTool( a, tid )
117 a = sgPyQt.createSeparator()
119 a = sgPyQt.createAction( GUIcontext.GENERATE_INTERPOLZ_PY_ID,
120 "Generate interpolz.py", "Generate interpolz.py",
121 "Generate interpolation script from the template", "generate_interpolz_py.png" )
123 sgPyQt.createMenu( a, mid )
124 sgPyQt.createTool( a, tid )
126 a = sgPyQt.createSeparator()
127 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_EN,
128 "Edit cas file (English)", "Edit cas file (English)",
129 "Create/edit a .cas file for Telemac (English)",
131 sgPyQt.createMenu( a, mid )
132 sgPyQt.createTool( a, tid )
134 a = sgPyQt.createSeparator()
135 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_FR,
136 "Edit cas file (French)", "Edit cas file (French)",
137 "Create/edit a .cas file for Telemac (French)",
139 sgPyQt.createMenu( a, mid )
140 sgPyQt.createTool( a, tid )
143 # the following action are used in context popup
144 sgPyQt.createAction( GUIcontext.RUN_MASCARET_ID, "Compute case", "Compute case",
145 "Run Mascaret solver to compute the case" )
146 sgPyQt.createAction( GUIcontext.EDIT_MASCARET_CASE_ID, "Edit case", "Edit case",
147 "Edit the selected Mascaret case" )
148 sgPyQt.createAction( GUIcontext.SHOW_LOG_ID, "Show log", "Show log",
149 "Show the log for the selected variable" )
151 sgPyQt.createAction( GUIcontext.GEN_TELEMAC2D_PYTHON_ID, "Generate Python script",
152 "Generate Python script",
153 "Generate a Python script from the eficas date" )
154 sgPyQt.createAction( GUIcontext.GEN_TELEMAC2D_YACS_ID, "Generate YACS script",
155 "Generate YACS script",
156 "Generate a YACS script from the eficas date" )
157 sgPyQt.createAction( GUIcontext.RUN_TELEMAC2D_ID, "Compute case", "Compute case",
158 "Run Telemac2D solver to compute the case" )
159 sgPyQt.createAction( GUIcontext.EDIT_TELEMAC2D_CASE_ID, "Edit case", "Edit case",
160 "Edit the selected Telemac2D case" )
162 sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
163 "Run Pytel launcher to compute the case" )
164 sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
165 "Edit the selected Pytel case" )
166 sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
167 "Generate a batch job to run the selected case")
169 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_EN, "Edit .cas file", "Edit .cas file",
171 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_FR, "Edit .cas file (French)", "Edit .cas file (French)",
172 "Edit .cas file (French)")
175 ################################################
177 ################################################
179 # study-to-context map
180 __study2context__ = {}
182 __current_context__ = None
186 ################################################
188 ################################################
191 # get active study ID
194 return sgPyQt.getStudyId()
200 studyId = _getStudyId()
201 study = getStudyManager().GetStudyByID( studyId )
205 # returns True if object has children
207 def _hasChildren( sobj ):
210 iter = study.NewChildIterator( sobj )
212 name = iter.Value().GetName()
221 # get current GUI context
224 global __current_context__
225 return __current_context__
228 # set and return current GUI context
229 # study ID is passed as parameter
231 def _setContext( studyID ):
232 global __study2context__, __current_context__
233 if not __study2context__.has_key(studyID):
234 __study2context__[studyID] = GUIcontext()
236 __current_context__ = __study2context__[studyID]
237 return __current_context__
240 # increment object counter in the map
242 def _incObjToMap( m, id ):
243 if id not in m: m[id] = 0
247 ################################################
249 ################################################
251 # called when module is activated
252 # returns True if activating is successfull and False otherwise
254 ctx = _setContext( _getStudyId() )
257 # called when module is deactivated
261 # called when active study is changed
262 # active study ID is passed as parameter
263 def activeStudyChanged( studyID ):
264 ctx = _setContext( _getStudyId() )
267 # called when popup menu is invoked
268 # popup menu and menu context are passed as parameters
269 def createPopupMenu(popup, context):
270 ed = getStudyEditor()
271 _setContext(ed.studyId)
272 if salome.sg.SelectedCount() == 1:
273 # one object is selected
274 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
275 selectedType = ed.getTypeId(sobj)
276 if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
277 popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
278 popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
279 elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
280 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
281 popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
282 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_PYTHON_ID))
283 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_YACS_ID))
284 elif selectedType == hydro_study.LOG_TYPE_ID:
285 popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
286 elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
287 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
288 popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
289 popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
291 # called when GUI action is activated
292 # action ID is passed as parameter
293 def OnGUIEvent( commandID ):
295 dict_command[commandID]()
296 except HSGUIException, exc:
297 QMessageBox.critical(sgPyQt.getDesktop(),
298 QApplication.translate("OnGUIEvent", "Error"),
301 logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
302 msg = QApplication.translate("OnGUIEvent",
303 "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
304 '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
305 'category "HYDROSOLVER", describing how you got there and including the following traceback:')
306 msgBox = QMessageBox(QMessageBox.Critical,
307 QApplication.translate("OnGUIEvent", "Error"),
309 parent = sgPyQt.getDesktop())
310 msgBox.setDetailedText(traceback.format_exc())
313 ################################################
314 # GUI actions implementation
315 ################################################
317 # --------------------------------------------------------------------------------------- #
318 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
319 # --------------------------------------------------------------------------------------- #
321 from TextDisplayDialog import Ui_TextDisplayDialog
323 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
325 def __init__(self, parent = None, modal = 0):
326 QDialog.__init__(self, parent)
327 Ui_TextDisplayDialog.__init__(self)
329 (self.closeButton.clicked.connect(self.close)
331 def set_log(self, log):
332 self.contentTextEdit.setPlainText(log)
333 self.setWindowTitle("Coupling log")
337 # Open Eficas for Mascaret to create a new case
339 def create_mascaret_case():
340 EficasForMascaretAppli()
343 # Open Eficas for Mascaret to edit the selected case
345 def edit_mascaret_case():
346 EficasForMascaretAppli(get_and_check_selected_file_path())
348 # Run Mascaret on selected case
352 ed = hydro_study.HydroStudyEditor()
353 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
354 (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
355 var_names = [var["NOM"].strip() for var in output_vars]
356 mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
357 engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
358 logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
359 (file_list, lig_file, mascaret_vars))
360 output_values = engine.Compute(file_list, lig_file, mascaret_vars)
361 ed.add_results_to_mascaret_case(sobj, var_names, output_values)
362 salome.sg.updateObjBrowser( 0 )
363 except SALOME.SALOME_Exception, exc:
364 salome.sg.updateObjBrowser( 0 )
365 msg = unicode(QApplication.translate("run_mascaret",
366 "An error happened while trying to run Mascaret:"))
367 msg += "\n" + exc.details.text
368 raise HSGUIException(msg)
370 # Display selected log (deprecated, it was only used in the calcium coupling test)
372 ed = hydro_study.HydroStudyEditor()
373 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
375 (found, attr) = getStudyEditor().builder.FindAttribute(
376 sobj, "AttributeParameter")
377 log = attr.GetString("log")
378 dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
383 # Open Eficas for Telemac2D to create a new case
385 def create_telemac2d_case():
386 EficasForTelemac2DAppli()
389 # Open Eficas for Telemac2D to edit the selected case
391 def edit_telemac2d_case():
392 EficasForTelemac2DAppli(get_and_check_selected_file_path())
394 # Run Telemac2D on selected case
399 ed = hydro_study.HydroStudyEditor()
400 entry = salome.sg.getSelected(0)
401 engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
402 engine.Compute(ed.editor.studyId, entry)
403 # Stop container after execution so that we can use another fortran user file in the next run
404 engine.GetContainerRef().Shutdown()
405 except SALOME.SALOME_Exception, exc:
406 if engine is not None:
407 engine.GetContainerRef().Shutdown()
408 msg = unicode(QApplication.translate("run_telemac2d",
409 "An error happened while trying to run Telemac2D:"))
410 msg += "\n" + exc.details.text
411 raise HSGUIException(msg)
412 except Exception, exc:
413 logger.exception("An error happened in the computation (Telemac2D probably crashed).")
415 engine.GetContainerRef().Shutdown()
418 msg = unicode(QApplication.translate("run_telemac2d",
419 "An error happened in the computation (Telemac2D probably crashed, "
420 "see logs and listing files for more details):"))
421 msg += "\n" + unicode(exc)
422 raise HSGUIException(msg)
425 # Generate a python script from the eficas file
427 def generate_telemac2d_python():
430 ed = hydro_study.HydroStudyEditor()
431 sobj = get_and_check_selected_file_path()
432 ed.generate_study_script(sobj)
433 except SALOME.SALOME_Exception, exc:
434 salome.sg.updateObjBrowser( 0 )
435 msg = unicode(QApplication.translate("generate_telemac2d_python",
436 "An error happened while trying to generate telemac2d Python script:"))
437 msg += "\n" + exc.details.text
438 raise HSGUIException(msg)
441 # Generate a python script from the eficas file
443 def generate_telemac2d_yacs():
446 ed = hydro_study.HydroStudyEditor()
447 sobj = get_and_check_selected_file_path()
448 ed.generate_study_yacs(sobj)
449 except SALOME.SALOME_Exception, exc:
450 salome.sg.updateObjBrowser( 0 )
451 msg = unicode(QApplication.translate("generate_telemac2d_yacs",
452 "An error happened while trying to generate telemac2d Python script:"))
453 msg += "\n" + exc.details.text
454 raise HSGUIException(msg)
456 def open_schema_in_yacs():
457 ed = getStudyEditor()
458 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
459 filename = sobj.GetComment()
460 if filename.endswith(".comm"):
461 filename = filename[:-5] + ".xml"
462 if not os.path.isfile(filename):
463 raise HSGUIException(QApplication.translate("open_schema_in_yacs",
464 "Schema file %1 does not exist").arg(filename))
465 yg = salome.ImportComponentGUI("YACS")
466 yg.loadSchema(filename)
469 # Open Eficas for boundary conditions definition
471 #def define_boundary_conditions():
472 # EficasForBoundaryConditionsAppli()
475 # Open dialog for boundary conditions edition
477 def edit_boundary_conditions_file():
478 desktop = sgPyQt.getDesktop()
479 dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
483 # Open dialog for interpolz.py script generation
485 def generate_interpolz_py():
486 desktop = sgPyQt.getDesktop()
487 dlg = InterpolzDlg(desktop)
491 # Open dialog for boundary conditions edition
493 def eficas_for_cas_Telemac2D_fr():
494 EficasForTelemac2DAppli(code='TELEMAC', lang = 'fr')
496 def eficas_for_cas_Telemac2D_en():
497 EficasForTelemac2DAppli(code='TELEMAC', lang = 'en')
500 # Commands dictionary
503 GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
504 GUIcontext.RUN_MASCARET_ID: run_mascaret,
505 GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
506 GUIcontext.SHOW_LOG_ID: show_log,
507 GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
508 GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
509 GUIcontext.GEN_TELEMAC2D_PYTHON_ID: generate_telemac2d_python,
510 GUIcontext.GEN_TELEMAC2D_YACS_ID: generate_telemac2d_yacs,
511 GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
512 GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
513 GUIcontext.CREATE_PYTEL_CASE_ID: create_case_pytel,
514 GUIcontext.RUN_PYTEL_ID: run_selected_case_pytel,
515 GUIcontext.EDIT_PYTEL_CASE_ID: edit_selected_case_pytel,
516 GUIcontext.GENERATE_JOB: generate_job_for_selected_case_pytel,
517 #GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,
518 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
519 GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
520 GUIcontext.DEFINE_CAS_FILE_EN: eficas_for_cas_Telemac2D_en,
521 GUIcontext.DEFINE_CAS_FILE_FR: eficas_for_cas_Telemac2D_fr,