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
71 DEFINE_CAS_FILE_EN = 955
72 EDIT_BOUNDARY_CONDITIONS_FILE_ID = 956
73 GENERATE_INTERPOLZ_PY_ID = 957
74 GEN_TELEMAC2D_PYTHON_ID = 958
75 GEN_TELEMAC2D_YACS_ID = 959
76 DEFINE_CAS_FILE_FR = 960
79 # create top-level menu
80 mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
82 tid = sgPyQt.createTool( "Hydro" )
83 # create actions and fill menu and toolbar with actions
84 a = sgPyQt.createAction( GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
85 "Edit boundary conditions file", "Edit boundary conditions file",
86 "Create/edit the boundary conditions file for Telemac",
87 "edit_boundary_conditions_file.png" )
88 sgPyQt.createMenu( a, mid )
89 sgPyQt.createTool( a, tid )
92 a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
93 "Create Mascaret case", "Create Mascaret case",
94 "Create a new Mascaret case", "create_case1d.png" )
95 sgPyQt.createMenu( a, mid )
96 sgPyQt.createTool( a, tid )
98 a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
99 "Create Telemac2D case", "Create Telemac2D case",
100 "Create a new Telemac2D case", "create_case2d.png" )
101 sgPyQt.createMenu( a, mid )
102 sgPyQt.createTool( a, tid )
104 a = sgPyQt.createAction( GUIcontext.CREATE_COUPLING1D2D_CASE_ID,
105 "Create 1D / 2D coupling", "Create 1D / 2D coupling",
106 "Create a new 1D / 2D coupling", "create_case_couplage.png" )
107 sgPyQt.createMenu( a, mid )
108 sgPyQt.createTool( a, tid )
110 a = sgPyQt.createSeparator()
112 a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
113 "Create case for Pytel execution", "Create case for Pytel execution",
114 "Create a new case for Pytel execution", "create_case_pytel.png" )
116 sgPyQt.createMenu( a, mid )
117 sgPyQt.createTool( a, tid )
119 a = sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID,
120 "Edit case for Pytel execution", "Edit case for Pytel execution",
121 "Edit a new case for Pytel execution", "edit_case_pytel.png" )
123 sgPyQt.createMenu( a, mid )
124 sgPyQt.createTool( a, tid )
126 a = sgPyQt.createSeparator()
128 a = sgPyQt.createAction( GUIcontext.GENERATE_INTERPOLZ_PY_ID,
129 "Generate interpolz.py", "Generate interpolz.py",
130 "Generate interpolation script from the template", "generate_interpolz_py.png" )
132 sgPyQt.createMenu( a, mid )
133 sgPyQt.createTool( a, tid )
135 a = sgPyQt.createSeparator()
136 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_EN,
137 "Edit cas file (English)", "Edit cas file (English)",
138 "Create/edit a .cas file for Telemac (English)",
139 "define_cas_file.png" )
140 sgPyQt.createMenu( a, mid )
141 sgPyQt.createTool( a, tid )
143 a = sgPyQt.createSeparator()
144 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_FR,
145 "Edit cas file (French)", "Edit cas file (French)",
146 "Create/edit a .cas file for Telemac (French)",
147 "define_cas_file.png" )
148 sgPyQt.createMenu( a, mid )
149 sgPyQt.createTool( a, tid )
152 # the following action are used in context popup
153 sgPyQt.createAction( GUIcontext.RUN_MASCARET_ID, "Compute case", "Compute case",
154 "Run Mascaret solver to compute the case" )
155 sgPyQt.createAction( GUIcontext.EDIT_MASCARET_CASE_ID, "Edit case", "Edit case",
156 "Edit the selected Mascaret case" )
157 sgPyQt.createAction( GUIcontext.SHOW_LOG_ID, "Show log", "Show log",
158 "Show the log for the selected variable" )
160 sgPyQt.createAction( GUIcontext.GEN_TELEMAC2D_PYTHON_ID, "Generate Python script",
161 "Generate Python script",
162 "Generate a Python script from the eficas date" )
163 sgPyQt.createAction( GUIcontext.GEN_TELEMAC2D_YACS_ID, "Generate YACS script",
164 "Generate YACS script",
165 "Generate a YACS script from the eficas date" )
166 sgPyQt.createAction( GUIcontext.RUN_TELEMAC2D_ID, "Compute case", "Compute case",
167 "Run Telemac2D solver to compute the case" )
168 sgPyQt.createAction( GUIcontext.EDIT_TELEMAC2D_CASE_ID, "Edit case", "Edit case",
169 "Edit the selected Telemac2D case" )
171 sgPyQt.createAction( GUIcontext.EDIT_COUPLING1D2D_CASE_ID, "Edit coupling", "Edit coupling",
172 "Edit the selected 1D / 2D coupling" )
173 sgPyQt.createAction( GUIcontext.OPEN_SCHEMA_IN_YACS_ID, "Open schema in YACS", "Open schema in YACS",
174 "Open the selected 1D / 2D coupling schema in YACS" )
176 sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
177 "Run Pytel launcher to compute the case" )
178 sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
179 "Edit the selected Pytel case" )
180 sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
181 "Generate a batch job to run the selected case")
183 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_EN, "Edit .cas file", "Edit .cas file",
185 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_FR, "Edit .cas file (French)", "Edit .cas file (French)",
186 "Edit .cas file (French)")
189 ################################################
191 ################################################
193 # study-to-context map
194 __study2context__ = {}
196 __current_context__ = None
200 ################################################
202 ################################################
205 # get active study ID
208 return sgPyQt.getStudyId()
214 studyId = _getStudyId()
215 study = getStudyManager().GetStudyByID( studyId )
219 # returns True if object has children
221 def _hasChildren( sobj ):
224 iter = study.NewChildIterator( sobj )
226 name = iter.Value().GetName()
235 # get current GUI context
238 global __current_context__
239 return __current_context__
242 # set and return current GUI context
243 # study ID is passed as parameter
245 def _setContext( studyID ):
246 global __study2context__, __current_context__
247 if not __study2context__.has_key(studyID):
248 __study2context__[studyID] = GUIcontext()
250 __current_context__ = __study2context__[studyID]
251 return __current_context__
254 # increment object counter in the map
256 def _incObjToMap( m, id ):
257 if id not in m: m[id] = 0
261 ################################################
263 ################################################
265 # called when module is activated
266 # returns True if activating is successfull and False otherwise
268 ctx = _setContext( _getStudyId() )
271 # called when module is deactivated
275 # called when active study is changed
276 # active study ID is passed as parameter
277 def activeStudyChanged( studyID ):
278 ctx = _setContext( _getStudyId() )
281 # called when popup menu is invoked
282 # popup menu and menu context are passed as parameters
283 def createPopupMenu(popup, context):
284 ed = getStudyEditor()
285 _setContext(ed.studyId)
286 if salome.sg.SelectedCount() == 1:
287 # one object is selected
288 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
289 selectedType = ed.getTypeId(sobj)
290 if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
291 popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
292 popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
293 elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
294 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
295 popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
296 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_PYTHON_ID))
297 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_YACS_ID))
298 elif selectedType == hydro_study.COUPLING1D2D_CASE_TYPE_ID:
299 popup.addAction(sgPyQt.action(GUIcontext.EDIT_COUPLING1D2D_CASE_ID))
300 popup.addAction(sgPyQt.action(GUIcontext.OPEN_SCHEMA_IN_YACS_ID))
301 elif selectedType == hydro_study.LOG_TYPE_ID:
302 popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
303 elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
304 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
305 popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
306 popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
308 # called when GUI action is activated
309 # action ID is passed as parameter
310 def OnGUIEvent( commandID ):
312 dict_command[commandID]()
313 except HSGUIException, exc:
314 QMessageBox.critical(sgPyQt.getDesktop(),
315 QApplication.translate("OnGUIEvent", "Error"),
318 logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
319 msg = QApplication.translate("OnGUIEvent",
320 "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
321 '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
322 'category "HYDROSOLVER", describing how you got there and including the following traceback:')
323 msgBox = QMessageBox(QMessageBox.Critical,
324 QApplication.translate("OnGUIEvent", "Error"),
326 parent = sgPyQt.getDesktop())
327 msgBox.setDetailedText(traceback.format_exc())
330 ################################################
331 # GUI actions implementation
332 ################################################
334 # --------------------------------------------------------------------------------------- #
335 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
336 # --------------------------------------------------------------------------------------- #
338 from TextDisplayDialog import Ui_TextDisplayDialog
340 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
342 def __init__(self, parent = None, modal = 0):
343 QDialog.__init__(self, parent)
344 Ui_TextDisplayDialog.__init__(self)
346 (self.closeButton.clicked.connect(self.close)
348 def set_log(self, log):
349 self.contentTextEdit.setPlainText(log)
350 self.setWindowTitle("Coupling log")
354 # Open Eficas for Mascaret to create a new case
356 def create_mascaret_case():
357 EficasForMascaretAppli()
360 # Open Eficas for Mascaret to edit the selected case
362 def edit_mascaret_case():
363 EficasForMascaretAppli(get_and_check_selected_file_path())
365 # Run Mascaret on selected case
369 ed = hydro_study.HydroStudyEditor()
370 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
371 (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
372 var_names = [var["NOM"].strip() for var in output_vars]
373 mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
374 engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
375 logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
376 (file_list, lig_file, mascaret_vars))
377 output_values = engine.Compute(file_list, lig_file, mascaret_vars)
378 ed.add_results_to_mascaret_case(sobj, var_names, output_values)
379 salome.sg.updateObjBrowser( 0 )
380 except SALOME.SALOME_Exception, exc:
381 salome.sg.updateObjBrowser( 0 )
382 msg = unicode(QApplication.translate("run_mascaret",
383 "An error happened while trying to run Mascaret:"))
384 msg += "\n" + exc.details.text
385 raise HSGUIException(msg)
387 # Display selected log (deprecated, it was only used in the calcium coupling test)
389 ed = hydro_study.HydroStudyEditor()
390 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
392 (found, attr) = getStudyEditor().builder.FindAttribute(
393 sobj, "AttributeParameter")
394 log = attr.GetString("log")
395 dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
400 # Open Eficas for Telemac2D to create a new case
402 def create_telemac2d_case():
403 EficasForTelemac2DAppli()
406 # Open Eficas for Telemac2D to edit the selected case
408 def edit_telemac2d_case():
409 EficasForTelemac2DAppli(get_and_check_selected_file_path())
411 # Run Telemac2D on selected case
416 ed = hydro_study.HydroStudyEditor()
417 entry = salome.sg.getSelected(0)
418 engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
419 engine.Compute(ed.editor.studyId, entry)
420 # Stop container after execution so that we can use another fortran user file in the next run
421 engine.GetContainerRef().Shutdown()
422 except SALOME.SALOME_Exception, exc:
423 if engine is not None:
424 engine.GetContainerRef().Shutdown()
425 msg = unicode(QApplication.translate("run_telemac2d",
426 "An error happened while trying to run Telemac2D:"))
427 msg += "\n" + exc.details.text
428 raise HSGUIException(msg)
429 except Exception, exc:
430 logger.exception("An error happened in the computation (Telemac2D probably crashed).")
432 engine.GetContainerRef().Shutdown()
435 msg = unicode(QApplication.translate("run_telemac2d",
436 "An error happened in the computation (Telemac2D probably crashed, "
437 "see logs and listing files for more details):"))
438 msg += "\n" + unicode(exc)
439 raise HSGUIException(msg)
442 # Generate a python script from the eficas file
444 def generate_telemac2d_python():
447 ed = hydro_study.HydroStudyEditor()
448 sobj = get_and_check_selected_file_path()
449 ed.generate_study_script(sobj)
450 except SALOME.SALOME_Exception, exc:
451 salome.sg.updateObjBrowser( 0 )
452 msg = unicode(QApplication.translate("generate_telemac2d_python",
453 "An error happened while trying to generate telemac2d Python script:"))
454 msg += "\n" + exc.details.text
455 raise HSGUIException(msg)
458 # Generate a python script from the eficas file
460 def generate_telemac2d_yacs():
463 ed = hydro_study.HydroStudyEditor()
464 sobj = get_and_check_selected_file_path()
465 ed.generate_study_yacs(sobj)
466 except SALOME.SALOME_Exception, exc:
467 salome.sg.updateObjBrowser( 0 )
468 msg = unicode(QApplication.translate("generate_telemac2d_yacs",
469 "An error happened while trying to generate telemac2d Python script:"))
470 msg += "\n" + exc.details.text
471 raise HSGUIException(msg)
474 # Open Eficas for 1D / 2D Coupling to create a new coupling case
476 def create_coupling1d2d_case():
477 EficasForCoupling1D2DAppli()
480 # Open Eficas for 1D / 2D Coupling to edit the selected coupling case
482 def edit_coupling1d2d_case():
483 EficasForCoupling1D2DAppli(get_and_check_selected_file_path())
485 def open_schema_in_yacs():
486 ed = getStudyEditor()
487 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
488 filename = sobj.GetComment()
489 if filename.endswith(".comm"):
490 filename = filename[:-5] + ".xml"
491 if not os.path.isfile(filename):
492 raise HSGUIException(QApplication.translate("open_schema_in_yacs",
493 "Schema file %1 does not exist").arg(filename))
494 yg = salome.ImportComponentGUI("YACS")
495 yg.loadSchema(filename)
498 # Open Eficas for boundary conditions definition
500 #def define_boundary_conditions():
501 # EficasForBoundaryConditionsAppli()
504 # Open dialog for boundary conditions edition
506 def edit_boundary_conditions_file():
507 desktop = sgPyQt.getDesktop()
508 dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
512 # Open dialog for interpolz.py script generation
514 def generate_interpolz_py():
515 desktop = sgPyQt.getDesktop()
516 dlg = InterpolzDlg(desktop)
520 # Open dialog for boundary conditions edition
522 def eficas_for_cas_Telemac2D_fr():
523 EficasForTelemac2DAppli(code='TELEMAC', lang = 'fr')
525 def eficas_for_cas_Telemac2D_en():
526 EficasForTelemac2DAppli(code='TELEMAC', lang = 'en')
529 # Commands dictionary
532 GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
533 GUIcontext.RUN_MASCARET_ID: run_mascaret,
534 GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
535 GUIcontext.SHOW_LOG_ID: show_log,
536 GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
537 GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
538 GUIcontext.GEN_TELEMAC2D_PYTHON_ID: generate_telemac2d_python,
539 GUIcontext.GEN_TELEMAC2D_YACS_ID: generate_telemac2d_yacs,
540 GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
541 GUIcontext.CREATE_COUPLING1D2D_CASE_ID: create_coupling1d2d_case,
542 GUIcontext.EDIT_COUPLING1D2D_CASE_ID: edit_coupling1d2d_case,
543 GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
544 GUIcontext.CREATE_PYTEL_CASE_ID: create_case_pytel,
545 GUIcontext.RUN_PYTEL_ID: run_selected_case_pytel,
546 GUIcontext.EDIT_PYTEL_CASE_ID: edit_selected_case_pytel,
547 GUIcontext.GENERATE_JOB: generate_job_for_selected_case_pytel,
548 #GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,
549 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
550 GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
551 GUIcontext.DEFINE_CAS_FILE_EN: eficas_for_cas_Telemac2D_en,
552 GUIcontext.DEFINE_CAS_FILE_FR: eficas_for_cas_Telemac2D_fr,