Salome HOME
dialog initial field
[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
37 from salome.hydro.interpolz_gui import InterpolzDlg
38 from salome.hydro.assignStrickler_gui import assignStricklerDlg
39 from salome.hydro.changeCoordsDialog import changeCoordsDialog 
40 from salome.hydro.gui_utils import HSGUIException, wait_cursor, \
41                                    get_and_check_selected_file_path
42 import salome.hydro.study as hydro_study
43 from salome.hydro.run_study.eficas.appli import EficasForRunStudyAppli
44 from salome.hydro.param_study.eficas.appli import EficasForParamStudyAppli
45 from salome.hydro.telma.eficas.appli import EficasForTelmaAppli
46 from salome.hydro.run_study.gui import create_case_study, \
47                                    run_selected_case_study, \
48                                    edit_selected_case_study, \
49                                    generate_job_for_selected_case_study
50 from eficasSalome import runEficas
51
52 from BndConditionsDialog import BoundaryConditionsDialog
53 from LiquidBoundariesDialog import LiquidBoundariesDialog
54 from BreachesDialog import BreachesDialog
55 from salome.hydro.initialFieldDialog import initialFieldDialog
56
57 ################################################
58 # GUI context class
59 # Used to store actions, menus, toolbars, etc...
60 ################################################
61
62 class GUIcontext:
63   
64     # --- menus/toolbars/actions IDss
65     
66     HYDRO_MENU_ID = 90
67     CREATE_STUDY_ID = 951
68     EDIT_STUDY_ID = 952
69     RUN_STUDY_ID = 953
70     GEN_STUDY_BATCH_ID = 954
71
72     CREATE_TELMA_CAS_ID = 955
73     EDIT_TELMA_CAS_ID = 956
74
75     GENERATE_INTERPOLZ_PY_ID = 957
76     GENERATE_ASSIGNSTRICKLER_PY_ID = 958
77
78     # TODO Add create and edit ?
79     EDIT_BOUNDARY_CONDITIONS_FILE_ID = 959
80     EDIT_LIQUID_BOUNDARY_FILE_ID = 960
81     EDIT_BREACHES_FILE_ID = 961
82     EDIT_INITIAL_FIELD_FILE_ID = 962
83
84     CREATE_PARAM_STUDY_ID = 963
85     EDIT_PARAM_STUDY_ID = 964
86     GEN_PARAM_STUDY_PYTHON_ID = 965
87     GEN_PARAM_STUDY_YACS_ID = 966
88     
89     CHANGECOORDS_PY_ID = 967
90
91     def __init__(self):
92         # create top-level menu
93         mid = sgPyQt.createMenu("Hydro", -1, GUIcontext.HYDRO_MENU_ID,
94                                 sgPyQt.defaultMenuGroup())
95         # create toolbar
96         tid = sgPyQt.createTool("Hydro")
97         # create actions and fill menu and toolbar with actions
98         act = sgPyQt.createAction(\
99                 GUIcontext.CHANGECOORDS_PY_ID,
100                 "Change coordinates",
101                 "Change coordinates",
102                 "Change mesh coordinates",
103                 "generate_interpolz_py.png")
104         sgPyQt.createMenu(act, mid)
105         sgPyQt.createTool(act, tid)
106
107         act = sgPyQt.createAction(\
108                 GUIcontext.GENERATE_INTERPOLZ_PY_ID,
109                 "Generate interpolz.py",
110                 "Generate interpolz.py",
111                 "Generate interpolation script for altitudes",
112                 "generate_interpolz_py.png")
113         sgPyQt.createMenu(act, mid)
114         sgPyQt.createTool(act, tid)
115
116         act = sgPyQt.createAction(\
117                 GUIcontext.GENERATE_ASSIGNSTRICKLER_PY_ID,
118                 "Generate assignStrickler.py",
119                 "Generate assignStrickler.py",
120                 "Generate assignation script for bottom friction coefficients",
121                  "generate_interpolz_py.png" )
122         sgPyQt.createMenu( act, mid )
123         sgPyQt.createTool( act, tid )
124         
125         act = sgPyQt.createSeparator()
126
127         act = sgPyQt.createAction(\
128                 GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID,
129                 "Edit boundary conditions file",
130                 "Edit boundary conditions file",
131                 "Create/edit the boundary conditions file for Telemac",
132                 "edit_boundary_conditions_file.png")
133         sgPyQt.createMenu(act, mid)
134         sgPyQt.createTool(act, tid)
135
136         act = sgPyQt.createAction(\
137                 GUIcontext.EDIT_LIQUID_BOUNDARY_FILE_ID,
138                 "Edit liquid boundary conditions file",
139                 "Edit liquid boundary conditions file",
140                 "Create/edit the liquid boundary conditions file for Telemac",
141                 "edit_liquid_boundary_conditions_file.png")
142         sgPyQt.createMenu(act, mid)
143         sgPyQt.createTool(act, tid)
144
145         act = sgPyQt.createAction(\
146                 GUIcontext.EDIT_BREACHES_FILE_ID,
147                 "Edit breaches file",
148                 "Edit breaches file",
149                 "Create/edit the breaches file for Telemac",
150                 "edit_breaches_file.png")
151         sgPyQt.createMenu(act, mid)
152         sgPyQt.createTool(act, tid)
153         
154         act = sgPyQt.createAction(\
155                 GUIcontext.EDIT_INITIAL_FIELD_FILE_ID,
156                 "Edit initial field file",
157                 "Edit initial field file",
158                 "Create/edit the initial field file for Telemac",
159                 "edit_boundary_conditions_file.png" )
160         sgPyQt.createMenu( act, mid )
161         sgPyQt.createTool( act, tid )
162
163         act = sgPyQt.createAction(\
164                 GUIcontext.CREATE_TELMA_CAS_ID,
165                 "Edit cas file (English)",
166                 "Edit cas file (English)",
167                 "Create/edit act .cas file for Telemac (English)",
168                 "create_telma_cas.png")
169         sgPyQt.createMenu(act, mid)
170         sgPyQt.createTool(act, tid)
171
172         act = sgPyQt.createAction(\
173                 GUIcontext.CREATE_STUDY_ID,
174                 "Execute a steering file",
175                 "Execute a steering file",
176                 "Fill formular for a normal execution",
177                 "create_study.png")
178
179         sgPyQt.createMenu(act, mid)
180         sgPyQt.createTool(act, tid)
181
182         act = sgPyQt.createAction(\
183                 GUIcontext.CREATE_PARAM_STUDY_ID,
184                 "Create Parameter Study",
185                 "Create Parameter Study",
186                 "Create act new Parameter Study",
187                 "create_param_study.png")
188         sgPyQt.createMenu(act, mid)
189         sgPyQt.createTool(act, tid)
190
191         act = sgPyQt.createSeparator()
192
193         # the following action are used in context popup
194
195         sgPyQt.createAction(\
196                 GUIcontext.EDIT_PARAM_STUDY_ID,
197                 "Edit param study",
198                 "Edit param study",
199                 "Edit study using python launcher")
200         sgPyQt.createAction(\
201                 GUIcontext.GEN_PARAM_STUDY_PYTHON_ID,
202                 "Generate Python script",
203                 "Generate Python script",
204                 "Generate act Python script from the eficas date")
205         sgPyQt.createAction(\
206                 GUIcontext.GEN_PARAM_STUDY_YACS_ID,
207                 "Generate YACS script",
208                 "Generate YACS script",
209                 "Generate act YACS script from the eficas date")
210
211         sgPyQt.createAction(\
212                 GUIcontext.RUN_STUDY_ID,
213                 "Compute study",
214                 "Compute study",
215                 "Compute study using python launcher")
216         sgPyQt.createAction(\
217                 GUIcontext.EDIT_STUDY_ID,
218                 "Edit study",
219                 "Edit study",
220                 "Edit the selected study")
221         sgPyQt.createAction(\
222                 GUIcontext.GEN_STUDY_BATCH_ID,
223                 "Generate batch job",
224                 "Generate batch job",
225                 "Generate a batch job to run the selected study")
226
227         sgPyQt.createAction(\
228                 GUIcontext.EDIT_TELMA_CAS_ID,
229                 "Edit Steering file",
230                 "Edit Steering file",
231                 "Edit a Telemac-Mascaret steering file")
232
233
234 ################################################
235 # Global variables
236 ################################################
237
238 # study-to-context map
239 __study2context__ = {}
240 # current context
241 __current_context__ = None
242 # object counter
243 __objectid__ = 0
244
245 ################################################
246 # Internal methods
247 ################################################
248
249 ###
250 # get active study ID
251 ###
252 #def _getStudyId():
253     #return sgPyQt.getStudyId()
254
255 ###
256 # get active study
257 ###
258 #def _getStudy():
259     #studyId = _getStudyId()
260     #study = getStudyManager().GetStudyByID(studyId)
261     #return study
262
263 ###
264 # returns True if object has children
265 ###
266 def _hasChildren(sobj):
267     if sobj:
268         study = salome.myStudy
269         iter  = study.NewChildIterator(sobj)
270         while iter.More():
271             name = iter.Value().GetName()
272             if name:
273                 return True
274             iter.Next()
275             pass
276         pass
277     return False
278
279 ###
280 # get current GUI context
281 ###
282 def _getContext():
283     global __current_context__
284     return __current_context__
285
286 ###
287 # set and return current GUI context
288 # study ID is passed as parameter
289 ###
290 def _setContext():
291     global __study2context__, __current_context__
292     #if studyID not in __study2context__:
293         #__study2context__[studyID] = GUIcontext()
294         #pass
295     #__current_context__ = __study2context__[studyID]
296     __current_context__ = GUIcontext()
297     return __current_context__
298
299 ###
300 # increment object counter in the map
301 ###
302 def _incObjToMap(m, id):
303     if id not in m: m[id] = 0
304     m[id] += 1
305     pass
306
307 ################################################
308 # Callback functions
309 ################################################
310
311 # called when module is activated
312 # returns True if activating is successfull and False otherwise
313 def activate():
314     ctx = _setContext()
315     return True
316
317 # called when module is deactivated
318 def deactivate():
319     pass
320
321 # called when active study is changed
322 # active study ID is passed as parameter
323 def activeStudyChanged():
324     ctx = _setContext()
325     pass
326
327 # called when popup menu is invoked
328 # popup menu and menu context are passed as parameters
329 def createPopupMenu(popup, context):
330     ed = getStudyEditor()
331     _setContext()
332     if salome.sg.SelectedCount() == 1:
333         # one object is selected
334         sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
335         print("sobj: %s"%sobj) # strange bug with sobj is None when right clic on 3Dview in HYDROSOLVER used after HYDRO (generate AssignStrickler)
336         if sobj:
337             selectedType = ed.getTypeId(sobj)
338             if selectedType == hydro_study.TELMA_TYPE_ID:
339                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_TELMA_CAS_ID))
340             elif selectedType == hydro_study.PARAM_STUDY_TYPE_ID:
341                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_PARAM_STUDY_ID))
342                 popup.addAction(sgPyQt.action(GUIcontext.GEN_PARAM_STUDY_PYTHON_ID))
343                 popup.addAction(sgPyQt.action(GUIcontext.GEN_PARAM_STUDY_YACS_ID))
344             elif selectedType == hydro_study.STUDY_TYPE_ID:
345                 popup.addAction(sgPyQt.action(GUIcontext.EDIT_STUDY_ID))
346                 popup.addAction(sgPyQt.action(GUIcontext.RUN_STUDY_ID))
347                 popup.addAction(sgPyQt.action(GUIcontext.GEN_STUDY_BATCH_ID))
348
349 # called when GUI action is activated
350 # action ID is passed as parameter
351 def OnGUIEvent(commandID):
352     try:
353         dict_command[commandID]()
354     except HSGUIException as exc:
355         QMessageBox.critical(sgPyQt.getDesktop(),
356                                    QApplication.translate("OnGUIEvent", "Error"),
357                                    str(exc))
358     except:
359         logger.exception("Unhandled exception caught in HYDROSOLVER GUI")
360         msg = QApplication.translate("OnGUIEvent",
361             "Unhandled error happened in HYDROSOLVER module. Please report a bug on "
362             '<a href="https://forge-pleiade.der.edf.fr/projects/salome-rex/issues">SALOME bugtracker</a>, '
363             'category "HYDROSOLVER", describing how you got there and including the following traceback:')
364         msgBox = QMessageBox(QMessageBox.Critical,
365                                    QApplication.translate("OnGUIEvent", "Error"),
366                                    msg,
367                                    parent=sgPyQt.getDesktop())
368         msgBox.setDetailedText(traceback.format_exc())
369         msgBox.exec_()
370
371 ################################################
372 # GUI actions implementation
373 ################################################
374
375 ###
376 # Open Eficas for a new parametric study
377 ###
378 def create_param_study():
379     EficasForParamStudyAppli()
380 ###
381 # Open Eficas to edit a new parametric study
382 ###
383 def edit_param_study():
384     EficasForParamStudyAppli(get_and_check_selected_file_path())
385
386 ###
387 # Generate a python script from the eficas file
388 ###
389 def generate_param_study_python():
390     try:
391         with wait_cursor:
392             ed = hydro_study.HydroStudyEditor()
393             sobj = get_and_check_selected_file_path()
394             ed.generate_study_script(sobj)
395     except SALOME.SALOME_Exception as exc:
396         salome.sg.updateObjBrowser()
397         msg = str(QApplication.translate("generate_telemac2d_python",
398                       "An error happened while trying to generate telemac2d Python script:"))
399         msg += "\n" + exc.details.text
400         raise HSGUIException(msg)
401
402 ###
403 # Generate a python script from the eficas file
404 ###
405 def generate_param_study_yacs():
406     try:
407         with wait_cursor:
408             ed = hydro_study.HydroStudyEditor()
409             sobj = get_and_check_selected_file_path()
410             ed.generate_study_yacs(sobj)
411     except SALOME.SALOME_Exception as exc:
412         salome.sg.updateObjBrowser()
413         msg = str(QApplication.translate("generate_telemac2d_yacs",
414                       "An error happened while trying to generate telemac2d Python script:"))
415         msg += "\n" + exc.details.text
416         raise HSGUIException(msg)
417
418 def open_schema_in_yacs():
419     ed = getStudyEditor()
420     sobj = ed.study.FindObjectID(salome.sg.getSelected(0))
421     filename = sobj.GetComment()
422     if filename.endswith(".comm"):
423         filename = filename[:-5] + ".xml"
424     if not os.path.isfile(filename):
425         raise HSGUIException(QApplication.translate("open_schema_in_yacs",
426                                   "Schema file %1 does not exist").arg(filename))
427     yg = salome.ImportComponentGUI("YACS")
428     yg.loadSchema(filename)
429
430 ###
431 # Open dialog for boundary conditions edition
432 ###
433 def edit_boundary_conditions_file():
434     desktop = sgPyQt.getDesktop()
435     dlg = BoundaryConditionsDialog(desktop)
436     dlg.exec_()
437
438 ###
439 # Open dialog for liquid boundaries edition
440 ###
441 def edit_liquid_boundaries_file():
442     desktop = sgPyQt.getDesktop()
443     dlg = LiquidBoundariesDialog(desktop)
444     dlg.exec_()
445
446 ###
447 # Open dialog for breaches edition
448 ###
449 def edit_breaches_file():
450     desktop = sgPyQt.getDesktop()
451     dlg = BreachesDialog(desktop)
452     dlg.exec_()
453
454 ###
455 # Open dialog for initial conditions edition
456 ###
457 def edit_initial_field_file():
458     desktop = sgPyQt.getDesktop()
459     dlg = initialFieldDialog(desktop)
460     dlg.exec_()
461
462 ###
463 # Open dialog for liquid boundary conditions edition
464 ###
465 def edit_liquid_boundary_file():
466     # TODO: Implement gui
467     QMessageBox.warning(sgPyQt.getDesktop(),
468                         "",
469                         "Liquid boundary file handling not implemented yet")
470     return
471
472 ###
473 # Open dialog for breaches file edition
474 ###
475 def edit_breaches_file():
476     # TODO: Implement gui
477     QMessageBox.warning(sgPyQt.getDesktop(),
478                         "",
479                         "Breaches file handling not implemented yet")
480     return
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 assignStrickler.py script generation
492 ###
493 def generate_assignStrickler_py():
494     desktop = sgPyQt.getDesktop()
495     dlg = assignStricklerDlg(desktop)
496     dlg.show()
497
498 def changeCoords_py():
499     desktop = sgPyQt.getDesktop()
500     dlg = changeCoordsDialog(desktop)
501     dlg.show()
502     
503 ###
504 # Open dialog for boundary conditions edition
505 ###
506 def generate_interpolks_py():
507     QMessageBox.warning(sgPyQt.getDesktop(),
508                         "",
509                         "Generation of interpolks.py not implemented yet")
510     return
511
512 ###
513 # Open dialog for creation of steering file
514 ###
515 def create_telma_cas():
516     EficasForTelmaAppli(code='TELEMAC', lang='en')
517
518 ###
519 # Open dialog for edition of steering file
520 ###
521 def edit_telma_cas():
522     # TODO: See how to detect module
523     EficasForTelmaAppli(fichier=get_and_check_selected_file_path(),
524                         code='TELEMAC', lang='en')
525
526 ###
527 # Commands dictionary
528 ###
529 dict_command = {
530     GUIcontext.CREATE_STUDY_ID: create_case_study,
531     GUIcontext.EDIT_STUDY_ID: edit_selected_case_study,
532     GUIcontext.RUN_STUDY_ID: run_selected_case_study,
533     GUIcontext.GEN_STUDY_BATCH_ID: generate_job_for_selected_case_study,
534     GUIcontext.CREATE_TELMA_CAS_ID: create_telma_cas,
535     GUIcontext.EDIT_TELMA_CAS_ID: edit_telma_cas,
536     GUIcontext.GENERATE_INTERPOLZ_PY_ID: generate_interpolz_py,
537     GUIcontext.GENERATE_ASSIGNSTRICKLER_PY_ID: generate_assignStrickler_py,
538     GUIcontext.CHANGECOORDS_PY_ID: changeCoords_py, 
539     GUIcontext.EDIT_LIQUID_BOUNDARY_FILE_ID: edit_liquid_boundary_file,
540     GUIcontext.EDIT_BOUNDARY_CONDITIONS_FILE_ID: edit_boundary_conditions_file,
541     GUIcontext.EDIT_BREACHES_FILE_ID: edit_breaches_file,
542     GUIcontext.EDIT_INITIAL_FIELD_FILE_ID: edit_initial_field_file,
543     GUIcontext.CREATE_PARAM_STUDY_ID: create_param_study,
544     GUIcontext.EDIT_PARAM_STUDY_ID: edit_param_study,
545     GUIcontext.GEN_PARAM_STUDY_PYTHON_ID: generate_param_study_python,
546     GUIcontext.GEN_PARAM_STUDY_YACS_ID: generate_param_study_yacs,
547     }