Salome HOME
Removing stand alone mascaret now within telemac
[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.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
44
45 import BndConditionsDialog
46
47 ################################################
48 # GUI context class
49 # Used to store actions, menus, toolbars, etc...
50 ################################################
51
52 class GUIcontext:
53     # menus/toolbars/actions IDs
54     HYDRO_MENU_ID = 90
55     CREATE_MASCARET_CASE_ID = 941
56     RUN_MASCARET_ID = 942
57     EDIT_MASCARET_CASE_ID = 943
58     SHOW_LOG_ID = 944
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
64     RUN_PYTEL_ID = 952
65     EDIT_PYTEL_CASE_ID = 953
66     GENERATE_JOB = 954
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
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.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 )
87
88
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 )
94
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 )
100
101         a = sgPyQt.createSeparator()
102
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" )
106
107         sgPyQt.createMenu( a, mid )
108         sgPyQt.createTool( a, tid )
109
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" )
113
114         sgPyQt.createMenu( a, mid )
115         sgPyQt.createTool( a, tid )
116
117         a = sgPyQt.createSeparator()
118
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" )
122
123         sgPyQt.createMenu( a, mid )
124         sgPyQt.createTool( a, tid )
125
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)",
130                                  "english.png" )
131         sgPyQt.createMenu( a, mid )
132         sgPyQt.createTool( a, tid )
133
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)",
138                                  "francais.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.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" )
161
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")
168
169         sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_EN, "Edit .cas file", "Edit .cas file",
170                              "Edit .cas file")
171         sgPyQt.createAction( GUIcontext.DEFINE_CAS_FILE_FR, "Edit .cas file (French)", "Edit .cas file (French)",
172                              "Edit .cas file (French)")
173
174
175 ################################################
176 # Global variables
177 ################################################
178
179 # study-to-context map
180 __study2context__   = {}
181 # current context
182 __current_context__ = None
183 # object counter
184 __objectid__ = 0
185
186 ################################################
187 # Internal methods
188 ################################################
189
190 ###
191 # get active study ID
192 ###
193 def _getStudyId():
194     return sgPyQt.getStudyId()
195
196 ###
197 # get active study
198 ###
199 def _getStudy():
200     studyId = _getStudyId()
201     study = getStudyManager().GetStudyByID( studyId )
202     return study
203
204 ###
205 # returns True if object has children
206 ###
207 def _hasChildren( sobj ):
208     if sobj:
209         study = _getStudy()
210         iter  = study.NewChildIterator( sobj )
211         while iter.More():
212             name = iter.Value().GetName()
213             if name:
214                 return True
215             iter.Next()
216             pass
217         pass
218     return False
219
220 ###
221 # get current GUI context
222 ###
223 def _getContext():
224     global __current_context__
225     return __current_context__
226
227 ###
228 # set and return current GUI context
229 # study ID is passed as parameter
230 ###
231 def _setContext( studyID ):
232     global __study2context__, __current_context__
233     if not __study2context__.has_key(studyID):
234         __study2context__[studyID] = GUIcontext()
235         pass
236     __current_context__ = __study2context__[studyID]
237     return __current_context__
238
239 ###
240 # increment object counter in the map
241 ###
242 def _incObjToMap( m, id ):
243     if id not in m: m[id] = 0
244     m[id] += 1
245     pass
246
247 ################################################
248 # Callback functions
249 ################################################
250
251 # called when module is activated
252 # returns True if activating is successfull and False otherwise
253 def activate():
254     ctx = _setContext( _getStudyId() )
255     return True
256
257 # called when module is deactivated
258 def deactivate():
259     pass
260
261 # called when active study is changed
262 # active study ID is passed as parameter
263 def activeStudyChanged( studyID ):
264     ctx = _setContext( _getStudyId() )
265     pass
266
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))
290
291 # called when GUI action is activated
292 # action ID is passed as parameter
293 def OnGUIEvent( commandID ):
294     try:
295         dict_command[commandID]()
296     except HSGUIException, exc:
297         QMessageBox.critical(sgPyQt.getDesktop(),
298                                    QApplication.translate("OnGUIEvent", "Error"),
299                                    unicode(exc))
300     except:
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"),
308                                    msg,
309                                    parent = sgPyQt.getDesktop())
310         msgBox.setDetailedText(traceback.format_exc())
311         msgBox.exec_()
312
313 ################################################
314 # GUI actions implementation
315 ################################################
316
317 # --------------------------------------------------------------------------------------- #
318 # Dialog box for text display (deprecated, it was only used in the calcium coupling test) #
319 # --------------------------------------------------------------------------------------- #
320 """
321 from TextDisplayDialog import Ui_TextDisplayDialog
322
323 class MyTextDisplayDialog(Ui_TextDisplayDialog, QDialog):
324
325     def __init__(self, parent = None, modal = 0):
326         QDialog.__init__(self, parent)
327         Ui_TextDisplayDialog.__init__(self)
328         self.setupUi(self)
329         (self.closeButton.clicked.connect(self.close)
330
331     def set_log(self, log):
332         self.contentTextEdit.setPlainText(log)
333         self.setWindowTitle("Coupling log")
334 """
335
336 ###
337 # Open Eficas for Mascaret to create a new case
338 ###
339 def create_mascaret_case():
340     EficasForMascaretAppli()
341
342 ###
343 # Open Eficas for Mascaret to edit the selected case
344 ###
345 def edit_mascaret_case():
346     EficasForMascaretAppli(get_and_check_selected_file_path())
347
348 # Run Mascaret on selected case
349 def run_mascaret():
350     try:
351         with wait_cursor:
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)
369
370 # Display selected log (deprecated, it was only used in the calcium coupling test)
371 def show_log():
372     ed = hydro_study.HydroStudyEditor()
373     sobj = ed.editor.study.FindObjectID(salome.sg.getSelected(0))
374     if sobj is not None:
375         (found, attr) = getStudyEditor().builder.FindAttribute(
376                                                 sobj, "AttributeParameter")
377         log = attr.GetString("log")
378         dialog = MyTextDisplayDialog(sgPyQt.getDesktop())
379         dialog.set_log(log)
380         dialog.show()
381
382 ###
383 # Open Eficas for Telemac2D to create a new case
384 ###
385 def create_telemac2d_case():
386     EficasForTelemac2DAppli()
387
388 ###
389 # Open Eficas for Telemac2D to edit the selected case
390 ###
391 def edit_telemac2d_case():
392     EficasForTelemac2DAppli(get_and_check_selected_file_path())
393
394 # Run Telemac2D on selected case
395 def run_telemac2d():
396     engine = None
397     try:
398         with wait_cursor:
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).")
414         try:
415             engine.GetContainerRef().Shutdown()
416         except:
417             pass
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)
423
424 ###
425 # Generate a python script from the eficas file
426 ###
427 def generate_telemac2d_python():
428     try:
429         with wait_cursor:
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)
439
440 ###
441 # Generate a python script from the eficas file
442 ###
443 def generate_telemac2d_yacs():
444     try:
445         with wait_cursor:
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)
455
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)
467
468 ###
469 # Open Eficas for boundary conditions definition
470 ###
471 #def define_boundary_conditions():
472 #    EficasForBoundaryConditionsAppli()
473
474 ###
475 # Open dialog for boundary conditions edition
476 ###
477 def edit_boundary_conditions_file():
478     desktop = sgPyQt.getDesktop()
479     dlg = BndConditionsDialog.BoundaryConditionsDialog(desktop)
480     dlg.exec_()
481
482 ###
483 # Open dialog for interpolz.py script generation
484 ###
485 def generate_interpolz_py():
486     desktop = sgPyQt.getDesktop()
487     dlg = InterpolzDlg(desktop)
488     dlg.show()
489
490 ###
491 # Open dialog for boundary conditions edition
492 ###
493 def eficas_for_cas_Telemac2D_fr():
494    EficasForTelemac2DAppli(code='TELEMAC', lang = 'fr')
495
496 def eficas_for_cas_Telemac2D_en():
497    EficasForTelemac2DAppli(code='TELEMAC', lang = 'en')
498
499 ###
500 # Commands dictionary
501 ###
502 dict_command = {
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,
522     }