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
75 GEN_TELEMAC2D_YACS_ID = 959
78 # create top-level menu
79 mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
81 tid = sgPyQt.createTool( "Hydro" )
82 # create actions and fill menu and toolbar with actions
83 a = sgPyQt.createAction( GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
84 "Edit boundary conditions file", "Edit boundary conditions file",
85 "Create/edit the boundary conditions file for Telemac",
86 "edit_boundary_conditions_file.png" )
87 sgPyQt.createMenu( a, mid )
88 sgPyQt.createTool( a, tid )
91 a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
92 "Create Mascaret case", "Create Mascaret case",
93 "Create a new Mascaret case", "create_case1d.png" )
94 sgPyQt.createMenu( a, mid )
95 sgPyQt.createTool( a, tid )
97 a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
98 "Create Telemac2D case", "Create Telemac2D case",
99 "Create a new Telemac2D case", "create_case2d.png" )
100 sgPyQt.createMenu( a, mid )
101 sgPyQt.createTool( a, tid )
103 a = sgPyQt.createAction( GUIcontext.CREATE_COUPLING1D2D_CASE_ID,
104 "Create 1D / 2D coupling", "Create 1D / 2D coupling",
105 "Create a new 1D / 2D coupling", "create_case_couplage.png" )
106 sgPyQt.createMenu( a, mid )
107 sgPyQt.createTool( a, tid )
109 a = sgPyQt.createSeparator()
111 a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
112 "Create case for Pytel execution", "Create case for Pytel execution",
113 "Create a new case for Pytel execution", "create_case_pytel.png" )
115 sgPyQt.createMenu( a, mid )
116 sgPyQt.createTool( a, tid )
118 a = sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID,
119 "Edit case for Pytel execution", "Edit case for Pytel execution",
120 "Edit a new case for Pytel execution", "edit_case_pytel.png" )
122 sgPyQt.createMenu( a, mid )
123 sgPyQt.createTool( a, tid )
125 a = sgPyQt.createSeparator()
127 a = sgPyQt.createAction( GUIcontext.GENERATE_INTERPOLZ_PY_ID,
128 "Generate interpolz.py", "Generate interpolz.py",
129 "Generate interpolation script from the template", "generate_interpolz_py.png" )
131 sgPyQt.createMenu( a, mid )
132 sgPyQt.createTool( a, tid )
134 a = sgPyQt.createSeparator()
135 a = sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE,
136 "Edit cas file", "Edit cas file",
137 "Create/edit a .cas file for Telemac",
138 "define_cas_file.png" )
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.EDIT_COUPLING1D2D_CASE_ID, "Edit coupling", "Edit coupling",
163 "Edit the selected 1D / 2D coupling" )
164 sgPyQt.createAction( GUIcontext.OPEN_SCHEMA_IN_YACS_ID, "Open schema in YACS", "Open schema in YACS",
165 "Open the selected 1D / 2D coupling schema in YACS" )
167 sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
168 "Run Pytel launcher to compute the case" )
169 sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
170 "Edit the selected Pytel case" )
171 sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
172 "Generate a batch job to run the selected case")
174 sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE, "Edit .cas file", "Edit .cas file",
178 ################################################
180 ################################################
182 # study-to-context map
183 __study2context__ = {}
185 __current_context__ = None
189 ################################################
191 ################################################
194 # get active study ID
197 return sgPyQt.getStudyId()
203 studyId = _getStudyId()
204 study = getStudyManager().GetStudyByID( studyId )
208 # returns True if object has children
210 def _hasChildren( sobj ):
213 iter = study.NewChildIterator( sobj )
215 name = iter.Value().GetName()
224 # get current GUI context
227 global __current_context__
228 return __current_context__
231 # set and return current GUI context
232 # study ID is passed as parameter
234 def _setContext( studyID ):
235 global __study2context__, __current_context__
236 if not __study2context__.has_key(studyID):
237 __study2context__[studyID] = GUIcontext()
239 __current_context__ = __study2context__[studyID]
240 return __current_context__
243 # increment object counter in the map
245 def _incObjToMap( m, id ):
246 if id not in m: m[id] = 0
250 ################################################
252 ################################################
254 # called when module is activated
255 # returns True if activating is successfull and False otherwise
257 ctx = _setContext( _getStudyId() )
260 # called when module is deactivated
264 # called when active study is changed
265 # active study ID is passed as parameter
266 def activeStudyChanged( studyID ):
267 ctx = _setContext( _getStudyId() )
270 # called when popup menu is invoked
271 # popup menu and menu context are passed as parameters
272 def createPopupMenu(popup, context):
273 ed = getStudyEditor()
274 _setContext(ed.studyId)
275 if salome.sg.SelectedCount() == 1:
276 # one object is selected
277 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
278 selectedType = ed.getTypeId(sobj)
279 if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
280 popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
281 popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
282 elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
283 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
284 popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
285 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_PYTHON_ID))
286 popup.addAction(sgPyQt.action(GUIcontext.GEN_TELEMAC2D_YACS_ID))
287 elif selectedType == hydro_study.COUPLING1D2D_CASE_TYPE_ID:
288 popup.addAction(sgPyQt.action(GUIcontext.EDIT_COUPLING1D2D_CASE_ID))
289 popup.addAction(sgPyQt.action(GUIcontext.OPEN_SCHEMA_IN_YACS_ID))
290 elif selectedType == hydro_study.LOG_TYPE_ID:
291 popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
292 elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
293 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
294 popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
295 popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
297 # called when GUI action is activated
298 # action ID is passed as parameter
299 def OnGUIEvent( commandID ):
301 dict_command[commandID]()
302 except HSGUIException, exc:
303 QMessageBox.critical(sgPyQt.getDesktop(),
304 QApplication.translate("OnGUIEvent", "Error"),
307 logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
308 msg = QApplication.translate("OnGUIEvent",
309 "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
310 '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
311 'category "HYDROSOLVER", describing how you got there and including the following traceback:')
312 msgBox = QMessageBox(QMessageBox.Critical,
313 QApplication.translate("OnGUIEvent", "Error"),
315 parent = sgPyQt.getDesktop())
316 msgBox.setDetailedText(traceback.format_exc())
319 ################################################
320 # GUI actions implementation
321 ################################################
323 # --------------------------------------------------------------------------------------- #
324 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
325 # --------------------------------------------------------------------------------------- #
327 from TextDisplayDialog import Ui_TextDisplayDialog
329 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
331 def __init__(self, parent = None, modal = 0):
332 QDialog.__init__(self, parent)
333 Ui_TextDisplayDialog.__init__(self)
335 (self.closeButton.clicked.connect(self.close)
337 def set_log(self, log):
338 self.contentTextEdit.setPlainText(log)
339 self.setWindowTitle("Coupling log")
343 # Open Eficas for Mascaret to create a new case
345 def create_mascaret_case():
346 EficasForMascaretAppli()
349 # Open Eficas for Mascaret to edit the selected case
351 def edit_mascaret_case():
352 EficasForMascaretAppli(get_and_check_selected_file_path())
354 # Run Mascaret on selected case
358 ed = hydro_study.HydroStudyEditor()
359 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
360 (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
361 var_names = [var["NOM"].strip() for var in output_vars]
362 mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
363 engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
364 logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
365 (file_list, lig_file, mascaret_vars))
366 output_values = engine.Compute(file_list, lig_file, mascaret_vars)
367 ed.add_results_to_mascaret_case(sobj, var_names, output_values)
368 salome.sg.updateObjBrowser( 0 )
369 except SALOME.SALOME_Exception, exc:
370 salome.sg.updateObjBrowser( 0 )
371 msg = unicode(QApplication.translate("run_mascaret",
372 "An error happened while trying to run Mascaret:"))
373 msg += "\n" + exc.details.text
374 raise HSGUIException(msg)
376 # Display selected log (deprecated, it was only used in the calcium coupling test)
378 ed = hydro_study.HydroStudyEditor()
379 sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
381 (found, attr) = getStudyEditor().builder.FindAttribute(
382 sobj, "AttributeParameter")
383 log = attr.GetString("log")
384 dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
389 # Open Eficas for Telemac2D to create a new case
391 def create_telemac2d_case():
392 EficasForTelemac2DAppli()
395 # Open Eficas for Telemac2D to edit the selected case
397 def edit_telemac2d_case():
398 EficasForTelemac2DAppli(get_and_check_selected_file_path())
400 # Run Telemac2D on selected case
405 ed = hydro_study.HydroStudyEditor()
406 entry = salome.sg.getSelected(0)
407 engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
408 engine.Compute(ed.editor.studyId, entry)
409 # Stop container after execution so that we can use another fortran user file in the next run
410 engine.GetContainerRef().Shutdown()
411 except SALOME.SALOME_Exception, exc:
412 if engine is not None:
413 engine.GetContainerRef().Shutdown()
414 msg = unicode(QApplication.translate("run_telemac2d",
415 "An error happened while trying to run Telemac2D:"))
416 msg += "\n" + exc.details.text
417 raise HSGUIException(msg)
418 except Exception, exc:
419 logger.exception("An error happened in the computation (Telemac2D probably crashed).")
421 engine.GetContainerRef().Shutdown()
424 msg = unicode(QApplication.translate("run_telemac2d",
425 "An error happened in the computation (Telemac2D probably crashed, "
426 "see logs and listing files for more details):"))
427 msg += "\n" + unicode(exc)
428 raise HSGUIException(msg)
431 # Generate a python script from the eficas file
433 def generate_telemac2d_python():
436 ed = hydro_study.HydroStudyEditor()
437 sobj = get_and_check_selected_file_path()
438 ed.generate_study_script(sobj)
439 except SALOME.SALOME_Exception, exc:
440 salome.sg.updateObjBrowser( 0 )
441 msg = unicode(QApplication.translate("generate_telemac2d_python",
442 "An error happened while trying to generate telemac2d Python script:"))
443 msg += "\n" + exc.details.text
444 raise HSGUIException(msg)
447 # Generate a python script from the eficas file
449 def generate_telemac2d_yacs():
452 ed = hydro_study.HydroStudyEditor()
453 sobj = get_and_check_selected_file_path()
454 ed.generate_study_yacs(sobj)
455 except SALOME.SALOME_Exception, exc:
456 salome.sg.updateObjBrowser( 0 )
457 msg = unicode(QApplication.translate("generate_telemac2d_yacs",
458 "An error happened while trying to generate telemac2d Python script:"))
459 msg += "\n" + exc.details.text
460 raise HSGUIException(msg)
463 # Open Eficas for 1D / 2D Coupling to create a new coupling case
465 def create_coupling1d2d_case():
466 EficasForCoupling1D2DAppli()
469 # Open Eficas for 1D / 2D Coupling to edit the selected coupling case
471 def edit_coupling1d2d_case():
472 EficasForCoupling1D2DAppli(get_and_check_selected_file_path())
474 def open_schema_in_yacs():
475 ed = getStudyEditor()
476 sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
477 filename = sobj.GetComment()
478 if filename.endswith(".comm"):
479 filename = filename[:-5] + ".xml"
480 if not os.path.isfile(filename):
481 raise HSGUIException(QApplication.translate("open_schema_in_yacs",
482 "Schema file %1 does not exist").arg(filename))
483 yg = salome.ImportComponentGUI("YACS")
484 yg.loadSchema(filename)
487 # Open Eficas for boundary conditions definition
489 #def define_boundary_conditions():
490 # EficasForBoundaryConditionsAppli()
493 # Open dialog for boundary conditions edition
495 def edit_boundary_conditions_file():
496 desktop = sgPyQt.getDesktop()
497 dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
501 # Open dialog for interpolz.py script generation
503 def generate_interpolz_py():
504 desktop = sgPyQt.getDesktop()
505 dlg = InterpolzDlg(desktop)
509 # Open dialog for boundary conditions edition
511 def eficas_for_cas_Telemac2D():
512 runEficas(code='TELEMAC')
514 # Commands dictionary
517 GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
518 GUIcontext.RUN_MASCARET_ID: run_mascaret,
519 GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
520 GUIcontext.SHOW_LOG_ID: show_log,
521 GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
522 GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
523 GUIcontext.GEN_TELEMAC2D_PYTHON_ID: generate_telemac2d_python,
524 GUIcontext.GEN_TELEMAC2D_YACS_ID: generate_telemac2d_yacs,
525 GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
526 GUIcontext.CREATE_COUPLING1D2D_CASE_ID: create_coupling1d2d_case,
527 GUIcontext.EDIT_COUPLING1D2D_CASE_ID: edit_coupling1d2d_case,
528 GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
529 GUIcontext.CREATE_PYTEL_CASE_ID: create_case_pytel,
530 GUIcontext.RUN_PYTEL_ID: run_selected_case_pytel,
531 GUIcontext.EDIT_PYTEL_CASE_ID: edit_selected_case_pytel,
532 GUIcontext.GENERATE_JOB: generate_job_for_selected_case_pytel,
533 #GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,
534 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
535 GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
536 GUIcontext.DEFINE_CAS_FILE: eficas_for_cas_Telemac2D,