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