Salome HOME
appel d eficas for telemac2d
[modules/hydrosolver.git] / src / HYDROGUI / HYDROSOLVERGUI.py
1 #  Copyright (C) 2012-2013 EDF
2 #
3 #  This file is part of SALOME HYDRO module.
4 #
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.
9 #
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.
14 #
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/>.
17
18 import sys
19 import os
20 import traceback
21 import logging
22
23 from PyQt5.QtWidgets import QMessageBox, QApplication, QDialog
24
25 import salome
26 import SALOME
27 import SalomePyQt
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)
34
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
45
46 import BndConditionsDialog
47
48 ################################################
49 # GUI context class
50 # Used to store actions, menus, toolbars, etc...
51 ################################################
52
53 class GUIcontext:
54     # menus/toolbars/actions IDs
55     HYDRO_MENU_ID = 90
56     CREATE_MASCARET_CASE_ID = 941
57     RUN_MASCARET_ID = 942
58     EDIT_MASCARET_CASE_ID = 943
59     SHOW_LOG_ID = 944
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
67     RUN_PYTEL_ID = 952
68     EDIT_PYTEL_CASE_ID = 953
69     GENERATE_JOB = 954
70     #DEFINE_BOUNDARY_CONDITIONS_ID = 955
71     DEFINE_CAS_FILE = 955
72     EDIT_BOUNDARY_CONDITIONS_FILE_ID = 956
73     GENERATE_INTERPOLZ_PY_ID = 957
74
75     def __init__( self ):
76         # create top-level menu
77         mid = sgPyQt.createMenu( "Hydro", -1, GUIcontext.HYDRO_MENU_ID, sgPyQt.defaultMenuGroup() )
78         # create toolbar
79         tid = sgPyQt.createTool( "Hydro" )
80         # create actions and fill menu and toolbar with actions
81         #a = sgPyQt.createAction( GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID,
82         #                         "Define boundary conditions", "Define boundary conditions",
83         #                         "Define the boundary conditions for Telemac",
84         #                         "define_boundary_conditions.png" )
85         sgPyQt.createMenu( a, mid )
86         sgPyQt.createTool( a, tid )
87
88         a = sgPyQt.createAction( GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
89                                  "Edit boundary conditions file", "Edit boundary conditions file",
90                                  "Create/edit the boundary conditions file for Telemac",
91                                  "edit_boundary_conditions_file.png" )
92         sgPyQt.createMenu( a, mid )
93         sgPyQt.createTool( a, tid )
94
95
96         a = sgPyQt.createAction( GUIcontext.CREATE_MASCARET_CASE_ID,
97                                  "Create Mascaret case", "Create Mascaret case",
98                                  "Create a new Mascaret case", "create_case1d.png" )
99         sgPyQt.createMenu( a, mid )
100         sgPyQt.createTool( a, tid )
101
102         a = sgPyQt.createAction( GUIcontext.CREATE_TELEMAC2D_CASE_ID,
103                                  "Create Telemac2D case", "Create Telemac2D case",
104                                  "Create a new Telemac2D case", "create_case2d.png" )
105         sgPyQt.createMenu( a, mid )
106         sgPyQt.createTool( a, tid )
107
108         a = sgPyQt.createAction( GUIcontext.CREATE_COUPLING1D2D_CASE_ID,
109                                  "Create 1D / 2D coupling", "Create 1D / 2D coupling",
110                                  "Create a new 1D / 2D coupling", "create_case_couplage.png" )
111         sgPyQt.createMenu( a, mid )
112         sgPyQt.createTool( a, tid )
113
114         a = sgPyQt.createSeparator()
115
116         a = sgPyQt.createAction( GUIcontext.CREATE_PYTEL_CASE_ID,
117                                 "Create case for Pytel execution", "Create case for Pytel execution",
118                                 "Create a new case for Pytel execution", "create_case_pytel.png" )
119
120         sgPyQt.createMenu( a, mid )
121         sgPyQt.createTool( a, tid )
122
123         a = sgPyQt.createSeparator()
124         sgPyQt.createMenu( a, mid )
125         sgPyQt.createTool( a, tid )
126
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" )
130
131         sgPyQt.createMenu( a, mid )
132         sgPyQt.createTool( a, tid )
133
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 )
141
142
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" )
150
151         sgPyQt.createAction( GUIcontext.RUN_TELEMAC2D_ID, "Compute case", "Compute case",
152                              "Run Telemac2D solver to compute the case" )
153         sgPyQt.createAction( GUIcontext.EDIT_TELEMAC2D_CASE_ID, "Edit case", "Edit case",
154                              "Edit the selected Telemac2D case" )
155
156         sgPyQt.createAction( GUIcontext.EDIT_COUPLING1D2D_CASE_ID, "Edit coupling", "Edit coupling",
157                              "Edit the selected 1D / 2D coupling" )
158         sgPyQt.createAction( GUIcontext.OPEN_SCHEMA_IN_YACS_ID, "Open schema in YACS", "Open schema in YACS",
159                              "Open the selected 1D / 2D coupling schema in YACS" )
160
161         sgPyQt.createAction( GUIcontext.RUN_PYTEL_ID, "Compute case", "Compute case",
162                             "Run Pytel launcher to compute the case" )
163         sgPyQt.createAction( GUIcontext.EDIT_PYTEL_CASE_ID, "Edit case", "Edit case",
164                             "Edit the selected Pytel case" )
165         sgPyQt.createAction( GUIcontext.GENERATE_JOB, "Generate batch job", "Generate batch job",
166                              "Generate a batch job to run the selected case")
167
168         sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE, "Edit .cas file", "Edit .cas file",
169                              "Edit .cas file")
170
171
172 ################################################
173 # Global variables
174 ################################################
175
176 # study-to-context map
177 __study2context__   = {}
178 # current context
179 __current_context__ = None
180 # object counter
181 __objectid__ = 0
182
183 ################################################
184 # Internal methods
185 ################################################
186
187 ###
188 # get active study ID
189 ###
190 def _getStudyId():
191     return sgPyQt.getStudyId()
192
193 ###
194 # get active study
195 ###
196 def _getStudy():
197     studyId = _getStudyId()
198     study = getStudyManager().GetStudyByID( studyId )
199     return study
200
201 ###
202 # returns True if object has children
203 ###
204 def _hasChildren( sobj ):
205     if sobj:
206         study = _getStudy()
207         iter  = study.NewChildIterator( sobj )
208         while iter.More():
209             name = iter.Value().GetName()
210             if name:
211                 return True
212             iter.Next()
213             pass
214         pass
215     return False
216
217 ###
218 # get current GUI context
219 ###
220 def _getContext():
221     global __current_context__
222     return __current_context__
223
224 ###
225 # set and return current GUI context
226 # study ID is passed as parameter
227 ###
228 def _setContext( studyID ):
229     global __study2context__, __current_context__
230     if not __study2context__.has_key(studyID):
231         __study2context__[studyID] = GUIcontext()
232         pass
233     __current_context__ = __study2context__[studyID]
234     return __current_context__
235
236 ###
237 # increment object counter in the map
238 ###
239 def _incObjToMap( m, id ):
240     if id not in m: m[id] = 0
241     m[id] += 1
242     pass
243
244 ################################################
245 # Callback functions
246 ################################################
247
248 # called when module is activated
249 # returns True if activating is successfull and False otherwise
250 def activate():
251     ctx = _setContext( _getStudyId() )
252     return True
253
254 # called when module is deactivated
255 def deactivate():
256     pass
257
258 # called when active study is changed
259 # active study ID is passed as parameter
260 def activeStudyChanged( studyID ):
261     ctx = _setContext( _getStudyId() )
262     pass
263
264 # called when popup menu is invoked
265 # popup menu and menu context are passed as parameters
266 def createPopupMenu(popup, context):
267     ed = getStudyEditor()
268     _setContext(ed.studyId)
269     if salome.sg.SelectedCount() == 1:
270         # one object is selected
271         sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
272         selectedType = ed.getTypeId(sobj)
273         if selectedType == hydro_study.MASCARET_CASE_TYPE_ID:
274             popup.addAction(sgPyQt.action(GUIcontext.EDIT_MASCARET_CASE_ID))
275             popup.addAction(sgPyQt.action(GUIcontext.RUN_MASCARET_ID))
276         elif selectedType == hydro_study.TELEMAC2D_CASE_TYPE_ID:
277             popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELEMAC2D_CASE_ID))
278             popup.addAction(sgPyQt.action(GUIcontext.RUN_TELEMAC2D_ID))
279         elif selectedType == hydro_study.COUPLING1D2D_CASE_TYPE_ID:
280             popup.addAction(sgPyQt.action(GUIcontext.EDIT_COUPLING1D2D_CASE_ID))
281             popup.addAction(sgPyQt.action(GUIcontext.OPEN_SCHEMA_IN_YACS_ID))
282         elif selectedType == hydro_study.LOG_TYPE_ID:
283             popup.addAction(sgPyQt.action(GUIcontext.SHOW_LOG_ID))
284         elif selectedType == hydro_study.PYTEL_CASE_TYPE_ID:
285            popup.addAction(sgPyQt.action(GUIcontext.EDIT_PYTEL_CASE_ID))
286            popup.addAction(sgPyQt.action(GUIcontext.RUN_PYTEL_ID))
287            popup.addAction(sgPyQt.action(GUIcontext.GENERATE_JOB))
288
289 # called when GUI action is activated
290 # action ID is passed as parameter
291 def OnGUIEvent( commandID ):
292     try:
293         dict_command[commandID]()
294     except HSGUIException, exc:
295         QMessageBox.critical(sgPyQt.getDesktop(),
296                                    QApplication.translate("OnGUIEvent", "Error"),
297                                    unicode(exc))
298     except:
299         logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
300         msg = QApplication.translate("OnGUIEvent",
301             "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
302             '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
303             'category "HYDROSOLVER", describing how you got there and including the following traceback:')
304         msgBox = QMessageBox(QMessageBox.Critical,
305                                    QApplication.translate("OnGUIEvent", "Error"),
306                                    msg,
307                                    parent = sgPyQt.getDesktop())
308         msgBox.setDetailedText(traceback.format_exc())
309         msgBox.exec_()
310
311 ################################################
312 # GUI actions implementation
313 ################################################
314
315 # --------------------------------------------------------------------------------------- #
316 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
317 # --------------------------------------------------------------------------------------- #
318 """
319 from TextDisplayDialog import Ui_TextDisplayDialog
320
321 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
322
323     def __init__(self, parent = None, modal = 0):
324         QDialog.__init__(self, parent)
325         Ui_TextDisplayDialog.__init__(self)
326         self.setupUi(self)
327         (self.closeButton.clicked.connect(self.close)
328
329     def set_log(self, log):
330         self.contentTextEdit.setPlainText(log)
331         self.setWindowTitle("Coupling log")
332 """
333
334 ###
335 # Open Eficas for Mascaret to create a new case
336 ###
337 def create_mascaret_case():
338     EficasForMascaretAppli()
339
340 ###
341 # Open Eficas for Mascaret to edit the selected case
342 ###
343 def edit_mascaret_case():
344     EficasForMascaretAppli(get_and_check_selected_file_path())
345
346 # Run Mascaret on selected case
347 def run_mascaret():
348     try:
349         with wait_cursor:
350             ed = hydro_study.HydroStudyEditor()
351             sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
352             (file_list, lig_file, input_vars, output_vars) = ed.get_mascaret_params_from_case(sobj)
353             var_names = [var["NOM"].strip() for var in output_vars]
354             mascaret_vars = [var["VARIABLE_MASCARET"].strip() for var in output_vars]
355             engine = salome.lcc.FindOrLoadComponent("FactoryServer", "MASCARET")
356             logger.debug("Calling MASCARET.Compute(%s, %s, %s)" %
357                          (file_list, lig_file, mascaret_vars))
358             output_values = engine.Compute(file_list, lig_file, mascaret_vars)
359             ed.add_results_to_mascaret_case(sobj, var_names, output_values)
360             salome.sg.updateObjBrowser( 0 )
361     except SALOME.SALOME_Exception, exc:
362         salome.sg.updateObjBrowser( 0 )
363         msg = unicode(QApplication.translate("run_mascaret",
364                       "An error happened while trying to run Mascaret:"))
365         msg += "\n" + exc.details.text
366         raise HSGUIException(msg)
367
368 # Display selected log (deprecated, it was only used in the calcium coupling test)
369 def show_log():
370     ed = hydro_study.HydroStudyEditor()
371     sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
372     if sobj is not None:
373         (found, attr) = getStudyEditor().builder.FindAttribute(
374                                                 sobj, "AttributeParameter")
375         log = attr.GetString("log")
376         dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
377         dialog.set_log(log)
378         dialog.show()
379
380 ###
381 # Open Eficas for Telemac2D to create a new case
382 ###
383 def create_telemac2d_case():
384     EficasForTelemac2DAppli()
385
386 ###
387 # Open Eficas for Telemac2D to edit the selected case
388 ###
389 def edit_telemac2d_case():
390     EficasForTelemac2DAppli(get_and_check_selected_file_path())
391
392 # Run Telemac2D on selected case
393 def run_telemac2d():
394     engine = None
395     try:
396         with wait_cursor:
397             ed = hydro_study.HydroStudyEditor()
398             entry = salome.sg.getSelected(0)
399             engine = salome.lcc.FindOrLoadComponent("Telemac2DContainer", "TELEMAC2D")
400             engine.Compute(ed.editor.studyId, entry)
401             # Stop container after execution so that we can use another fortran user file in the next run
402             engine.GetContainerRef().Shutdown()
403     except SALOME.SALOME_Exception, exc:
404         if engine is not None:
405             engine.GetContainerRef().Shutdown()
406         msg = unicode(QApplication.translate("run_telemac2d",
407                       "An error happened while trying to run Telemac2D:"))
408         msg += "\n" + exc.details.text
409         raise HSGUIException(msg)
410     except Exception, exc:
411         logger.exception("An error happened in the computation (Telemac2D probably crashed).")
412         try:
413             engine.GetContainerRef().Shutdown()
414         except:
415             pass
416         msg = unicode(QApplication.translate("run_telemac2d",
417                       "An error happened in the computation (Telemac2D probably crashed, "
418                       "see logs and listing files for more details):"))
419         msg += "\n" + unicode(exc)
420         raise HSGUIException(msg)
421
422 ###
423 # Open Eficas for 1D / 2D Coupling to create a new coupling case
424 ###
425 def create_coupling1d2d_case():
426     EficasForCoupling1D2DAppli()
427
428 ###
429 # Open Eficas for 1D / 2D Coupling to edit the selected coupling case
430 ###
431 def edit_coupling1d2d_case():
432     EficasForCoupling1D2DAppli(get_and_check_selected_file_path())
433
434 def open_schema_in_yacs():
435     ed = getStudyEditor()
436     sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
437     filename = sobj.GetComment()
438     if filename.endswith(".comm"):
439         filename = filename[:-5] + ".xml"
440     if not os.path.isfile(filename):
441         raise HSGUIException(QApplication.translate("open_schema_in_yacs",
442                                   "Schema file %1 does not exist").arg(filename))
443     yg = salome.ImportComponentGUI("YACS")
444     yg.loadSchema(filename)
445
446 ###
447 # Open Eficas for boundary conditions definition
448 ###
449 #def define_boundary_conditions():
450 #    EficasForBoundaryConditionsAppli()
451
452 ###
453 # Open dialog for boundary conditions edition
454 ###
455 def edit_boundary_conditions_file():
456     desktop = sgPyQt.getDesktop()
457     dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
458     dlg.exec_()
459
460 ###
461 # Open dialog for interpolz.py script generation
462 ###
463 def generate_interpolz_py():
464     desktop = sgPyQt.getDesktop()
465     dlg = InterpolzDlg(desktop)
466     dlg.show()
467
468 ###
469 # Open dialog for boundary conditions edition
470 ###
471 def eficas_for_cas_Telemac2D()
472    runEficas(code='TELEMAC')
473 ###
474 # Commands dictionary
475 ###
476 dict_command = {
477     GUIcontext.CREATE_MASCARET_CASE_ID: create_mascaret_case,
478     GUIcontext.RUN_MASCARET_ID: run_mascaret,
479     GUIcontext.EDIT_MASCARET_CASE_ID: edit_mascaret_case,
480     GUIcontext.SHOW_LOG_ID: show_log,
481     GUIcontext.CREATE_TELEMAC2D_CASE_ID: create_telemac2d_case,
482     GUIcontext.RUN_TELEMAC2D_ID: run_telemac2d,
483     GUIcontext.EDIT_TELEMAC2D_CASE_ID: edit_telemac2d_case,
484     GUIcontext.CREATE_COUPLING1D2D_CASE_ID: create_coupling1d2d_case,
485     GUIcontext.EDIT_COUPLING1D2D_CASE_ID: edit_coupling1d2d_case,
486     GUIcontext.OPEN_SCHEMA_IN_YACS_ID: open_schema_in_yacs,
487     GUIcontext.CREATE_PYTEL_CASE_ID: create_case_pytel,
488     GUIcontext.RUN_PYTEL_ID: run_selected_case_pytel,
489     GUIcontext.EDIT_PYTEL_CASE_ID: edit_selected_case_pytel,
490     GUIcontext.GENERATE_JOB: generate_job_for_selected_case_pytel,
491     #GUIcontext.DEFINE_BOUNDARY_CONDITIONS_ID: define_boundary_conditions,
492     GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
493     GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
494     GUIcontext.GUIcontext.DEFINE_CAS_FILE: eficas_for_cas_Telemac2D,
495     }