1 # Copyright (C) 2009-2024 EDF
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
26 from PyQt5 import QtCore, QtGui, QtWidgets
27 from salome.kernel import termcolor
28 from salome.kernel.logger import Logger
29 from salome.kernel.parametric import study_exchange_vars
30 from salome.kernel.studyedit import getStudyEditor
38 # Get SALOME PyQt interface
39 sgPyQt = SalomePyQt.SalomePyQt()
41 logger = Logger("GENERICSOLVERGUI", color=termcolor.RED_FG)
45 VARS_ICON = "icon_variables.png"
46 SOLVER_ENGINE_NAME = "DEVIATION"
48 ################################################
50 # Used to store actions, menus, toolbars, etc...
51 ################################################
56 MODULE_NAME = "GENERICSOLVER"
58 MODULE_PIXMAP = "GENERICSOLVER_small.png"
63 # menus/toolbars/actions IDs
64 GENERICSOLVER_MENU_ID = 90
74 DEFAULT_CASE_NAME = "Case"
78 # create top-level menu
79 mid = sgPyQt.createMenu("Genericsolver", -1, GUIcontext.GENERICSOLVER_MENU_ID,
80 sgPyQt.defaultMenuGroup())
82 tid = sgPyQt.createTool("Genericsolver")
83 # create actions and fill menu and toolbar with actions
84 a = sgPyQt.createAction(GUIcontext.CREATE_CASE_ID, "Create case", "Create case",
85 "Create a new case", "CaseGENERICSOLVER.png")
86 sgPyQt.createMenu(a, mid)
87 sgPyQt.createTool(a, tid)
88 a = sgPyQt.createSeparator()
89 sgPyQt.createMenu(a, mid)
90 ag = sgPyQt.createActionGroup(GUIcontext.OPTIONS_ID)
91 ag.setText("Creation mode")
92 ag.setUsesDropDown(True)
93 a = sgPyQt.createAction(GUIcontext.OPTION_1_ID, "Default name", "Default name",
94 "Use default name for the objects")
97 a = sgPyQt.createAction(GUIcontext.OPTION_2_ID, "Generate name", "Generate name",
98 "Generate name for the objects")
101 a = sgPyQt.createAction(GUIcontext.OPTION_3_ID, "Ask name", "Ask name",
102 "Request object name from the user") # , "", 0, True)
105 sgPyQt.createMenu(ag, mid)
106 sgPyQt.createTool(ag, tid)
107 default_mode = sgPyQt.integerSetting("GENERICSOLVER", "creation_mode", 0)
108 sgPyQt.action(GUIcontext.OPTION_1_ID + default_mode).setChecked(True)
109 # the following action are used in context popup
110 a = sgPyQt.createAction(GUIcontext.DELETE_ALL_ID, "Delete all", "Delete all",
111 "Delete all objects")
112 a = sgPyQt.createAction(GUIcontext.SET_VALUE_ID, "Set value", "Set Value",
113 "Set a new value to variable")
114 a = sgPyQt.createAction(GUIcontext.SOLVER_ID, "Run Solver", "Run Solver",
115 "Run Solver on selected case", "ExecGENERICSOLVER.png")
117 ################################################
119 ################################################
121 # study-to-context map
122 __study2context__ = {}
124 __current_context__ = None
128 ################################################
130 ################################################
134 # get active study ID
137 return sgPyQt.getStudyId()
144 studyId = getStudyId()
145 study = salome.myStudyManager.GetStudyByID(studyId)
150 # returns True if object has children
152 def hasChildren(sobj):
155 iterator = study.NewChildIterator(sobj)
156 while iterator.More():
157 name = iterator.Value().GetName()
167 # get current GUI context
170 global __current_context__
171 return __current_context__
175 # set and return current GUI context
176 # study ID is passed as parameter
178 def setContext(studyID):
179 global __study2context__, __current_context__
180 if studyID not in __study2context__:
181 __study2context__[studyID] = GUIcontext()
183 __current_context__ = __study2context__[studyID]
184 return __current_context__
186 ################################################
188 ################################################
191 # called when module is initialized
192 # perform initialization actions
194 logger.debug("GENERICSOLVERGUI.initialize() : study : %d" % getStudyId())
195 # set default preferences values
196 if not sgPyQt.hasSetting("GENERICSOLVER", "def_case_name"):
197 sgPyQt.addSetting("GENERICSOLVER", "def_case_name", GUIcontext.DEFAULT_CASE_NAME)
198 if not sgPyQt.hasSetting("GENERICSOLVER", "creation_mode"):
199 sgPyQt.addSetting("GENERICSOLVER", "creation_mode", 0)
203 # called when module is initialized
204 # return map of popup windows to be used by the module
206 logger.debug("GENERICSOLVERGUI.windows() : study : %d" % getStudyId())
208 wm[SalomePyQt.WT_ObjectBrowser] = QtCore.Qt.LeftDockWidgetArea
209 wm[SalomePyQt.WT_PyConsole] = QtCore.Qt.BottomDockWidgetArea
213 # called when module is initialized
214 # return list of 2d/3d views to be used ny the module
216 logger.debug("GENERICSOLVERGUI.views() : study : %d" % getStudyId())
220 # called when module is initialized
221 # export module's preferences
222 def createPreferences():
223 logger.debug("GENERICSOLVERGUI.createPreferences() : study : %d" % getStudyId())
224 gid = sgPyQt.addPreference("General")
225 gid = sgPyQt.addPreference("Object creation", gid)
226 sgPyQt.addPreference("Default case name", gid, SalomePyQt.PT_String,
227 "GENERICSOLVER", "def_case_name")
228 pid = sgPyQt.addPreference("Default creation mode", gid, SalomePyQt.PT_Selector,
229 "GENERICSOLVER", "creation_mode")
230 strings = ["Default name", "Generate name", "Ask name"]
232 sgPyQt.setPreferenceProperty(pid, "strings", strings)
233 sgPyQt.setPreferenceProperty(pid, "indexes", indexes)
237 # called when module is activated
238 # returns True if activating is successfull and False otherwise
240 logger.debug("GENERICSOLVERGUI.activate() : study : %d" % getStudyId())
241 setContext(getStudyId())
245 # called when module is deactivated
247 logger.debug("GENERICSOLVERGUI.deactivate() : study : %d" % getStudyId())
251 # called when active study is changed
252 # active study ID is passed as parameter
253 def activeStudyChanged(studyID):
254 logger.debug("GENERICSOLVERGUI.activeStudyChanged(): study : %d" % studyID)
255 setContext(getStudyId())
259 # called when popup menu is invoked
260 # popup menu and menu context are passed as parameters
261 def createPopupMenu(popup, context):
262 logger.debug("GENERICSOLVERGUI.createPopupMenu(): context = %s" % context)
263 ed = getStudyEditor()
264 setContext(ed.studyId)
265 if salome.sg.SelectedCount() == 1: # one object is selected
266 typeId = ed.getTypeId(ed.study.FindObjectID(salome.sg.getSelected(0)))
267 if typeId == GUIcontext.MODULE_ID:
269 popup.addAction(sgPyQt.action(GUIcontext.DELETE_ALL_ID))
270 elif typeId == GUIcontext.CASE_ID:
272 popup.addAction(sgPyQt.action(GUIcontext.SOLVER_ID))
273 elif typeId == GUIcontext.VARIABLE_ID:
275 popup.addAction(sgPyQt.action(GUIcontext.SET_VALUE_ID))
278 # called when GUI action is activated
279 # action ID is passed as parameter
280 def OnGUIEvent(commandID):
281 logger.debug("GENERICSOLVERGUI.OnGUIEvent(): command = %d" % commandID)
282 if commandID in dict_command:
284 dict_command[commandID]()
286 traceback.print_exc()
287 elif commandID in (GUIcontext.OPTION_1_ID, GUIcontext.OPTION_2_ID, GUIcontext.OPTION_3_ID):
288 pass # Option selection does not trigger a method
290 logger.error("The command is not implemented: %d" % commandID)
294 # called when module's preferences are changed
295 # preference's resources section and setting name are passed as parameters
296 def preferenceChanged(section, setting):
297 logger.debug("GENERICSOLVERGUI.preferenceChanged(): %s / %s" % (section, setting))
301 # called when active view is changed
302 # view ID is passed as parameter
303 def activeViewChanged(viewID):
304 logger.debug("GENERICSOLVERGUI.activeViewChanged(): %d" % viewID)
308 # called when active view is cloned
309 # cloned view ID is passed as parameter
310 def viewCloned(viewID):
311 logger.debug("GENERICSOLVERGUI.viewCloned(): %d" % viewID)
315 # called when active view is viewClosed
316 # view ID is passed as parameter
317 def viewClosed(viewID):
318 logger.debug("GENERICSOLVERGUI.viewClosed(): %d" % viewID)
321 ################################################
322 # GUI actions implementation
323 ################################################
327 # Create a deterministic case
330 logger.debug("GENERICSOLVERGUI.CreateCase : enter")
331 default_case_name = sgPyQt.stringSetting("GENERICSOLVER", "def_case_name",
332 GUIcontext.DEFAULT_CASE_NAME).strip()
335 if sgPyQt.action(GUIcontext.OPTION_3_ID).isChecked():
336 # request object name from the user
337 name, ok = QtWidgets.QInputDialog.getText(sgPyQt.getDesktop(),
340 QtWidgets.QLineEdit.Normal,
345 elif sgPyQt.action(GUIcontext.OPTION_2_ID).isChecked():
346 # generate object name
348 name = "%s %d" % (default_case_name, __id__)
350 name = default_case_name
353 except Exception as e:
355 # generate object name
357 name = "%s %d" % (default_case_name, __id__)
361 ed = getStudyEditor()
362 father = ed.findOrCreateComponent(GUIcontext.MODULE_NAME,
363 icon=GUIcontext.MODULE_PIXMAP)
364 ed.setTypeId(father, GUIcontext.MODULE_ID)
365 case = ed.findItem(father, name)
367 case = ed.createItem(father, name, typeId=GUIcontext.CASE_ID)
368 varE = ed.createItem(case, "E", typeId=GUIcontext.VARIABLE_ID)
369 ed.setAttributeValue(varE, "AttributeReal", 210.e9)
370 varF = ed.createItem(case, "F", typeId=GUIcontext.VARIABLE_ID)
371 ed.setAttributeValue(varF, "AttributeReal", 1000.)
372 varL = ed.createItem(case, "L", typeId=GUIcontext.VARIABLE_ID)
373 ed.setAttributeValue(varL, "AttributeReal", 1.5)
374 varI = ed.createItem(case, "I", typeId=GUIcontext.VARIABLE_ID)
375 ed.setAttributeValue(varI, "AttributeReal", 2.e-6)
377 inputVarList = [study_exchange_vars.Variable("E"),
378 study_exchange_vars.Variable("F"),
379 study_exchange_vars.Variable("L"),
380 study_exchange_vars.Variable("I")]
381 outputVarList = [study_exchange_vars.Variable("dev")]
382 exchVars = study_exchange_vars.ExchangeVariables(inputVarList, outputVarList)
383 study_exchange_vars.createSObjectForExchangeVariables(case, exchVars, icon=VARS_ICON)
385 salome.sg.updateObjBrowser(True)
386 logger.debug("GENERICSOLVERGUI.CreateCase : exit")
393 ed = getStudyEditor()
395 entry = salome.sg.getSelected(0)
396 assert entry is not None
397 sobj = ed.study.FindObjectID(entry)
399 assert ed.getTypeId(sobj) == GUIcontext.CASE_ID
400 assert hasChildren(sobj)
402 # Initialize and run the solver
403 solver_engine = salome.lcc.FindOrLoadComponent("FactoryServer", SOLVER_ENGINE_NAME)
405 solver_engine.Init(getStudyId(), entry)
407 param_input = SALOME_TYPES.ParametricInput(inputVarList=[],
408 outputVarList=["dev"],
410 specificParameters=[])
414 param_output = solver_engine.Exec(param_input)
415 except SALOME.SALOME_Exception as exc:
416 error = exc.details.text
418 solver_engine.Finalize()
420 if error is not None:
421 QtWidgets.critical(sgPyQt.getDesktop(), "Error", error)
422 elif param_output.returnCode != 0:
423 QtWidgets.critical(sgPyQt.getDesktop(), "Error", param_output.errorMessage)
425 # Add result to deterministic case in object browser
426 var = ed.findOrCreateItem(sobj, "Deviation")
427 ed.setAttributeValue(var, "AttributeReal", param_output.outputValues[0][0][0][0])
428 salome.sg.updateObjBrowser(False)
436 father = study.FindComponent(GUIcontext.MODULE_NAME)
438 iterator = study.NewChildIterator(father)
439 builder = study.NewBuilder()
440 while iterator.More():
441 sobj = iterator.Value()
443 builder.RemoveObjectWithChildren(sobj)
445 salome.sg.updateObjBrowser(True)
451 # Set value to variable
454 ed = getStudyEditor()
455 entry = salome.sg.getSelected(0)
456 assert entry is not None
457 sobj = ed.study.FindObjectID(entry)
459 oldvalue = ed.getAttributeValue(sobj, "AttributeReal", 0.0)
460 name, ok = QtWidgets.QInputDialog.getText(sgPyQt.getDesktop(),
463 QtWidgets.QLineEdit.Normal,
466 value = float(name.strip())
469 if not ok or value is None:
471 ed.setAttributeValue(sobj, "AttributeReal", value)
472 salome.sg.updateObjBrowser(False)
475 # Commands dictionary
478 GUIcontext.SOLVER_ID: RunSOLVER,
479 GUIcontext.CREATE_CASE_ID: CreateCase,
480 GUIcontext.DELETE_ALL_ID: DeleteAll,
481 GUIcontext.SET_VALUE_ID: SetValue,