mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2025-03-23 22:17:54 +05:00
409 lines
15 KiB
Python
409 lines
15 KiB
Python
# -*- coding: iso-8859-1 -*-
|
|
# Copyright (C) 2011-2013 EDF R&D
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
|
#
|
|
# Author : Guillaume Boulant (EDF)
|
|
#
|
|
|
|
from PyQt4.QtGui import QDialog, QIcon
|
|
from PyQt4.QtCore import QObject, SIGNAL, SLOT, Qt
|
|
|
|
from plugindialog_ui import Ui_PluginDialog
|
|
from inputdialog import InputDialog
|
|
from inputdata import InputData
|
|
# __GBO__: uncomment this line and comment the previous one to use the
|
|
# demo input dialog instead of the real one.
|
|
#from demoinputdialog import InputDialog
|
|
|
|
import os
|
|
import salome
|
|
from salome.kernel import studyedit
|
|
from salome.kernel.uiexception import AdminException
|
|
|
|
from omniORB import CORBA
|
|
import SMESH
|
|
from salome.smesh import smeshBuilder
|
|
smesh = smeshBuilder.New(salome.myStudy)
|
|
import MESHJOB
|
|
|
|
gui_states = ["CAN_SELECT", "CAN_COMPUTE", "CAN_REFRESH", "CAN_PUBLISH"]
|
|
|
|
run_states = ["CREATED", "IN_PROCESS", "QUEUED", "RUNNING", "PAUSED"];
|
|
end_states = ["FINISHED", "ERROR"]
|
|
all_states = run_states+end_states;
|
|
|
|
# The SALOME launcher resource is specified by its name as defined in
|
|
# the file CatalogResources.xml (see root directory of the
|
|
# application). We could have a check box in the dialog to specify
|
|
# wether we want a local execution or a remote one.
|
|
resource_name = "localhost"
|
|
from salome.smesh.spadder.configreader import ConfigReader
|
|
|
|
|
|
class PluginDialog(QDialog):
|
|
|
|
def __init__(self,parent = None,name = None,modal = 0,fl = 0):
|
|
QDialog.__init__(self,parent)
|
|
# Set up the user interface from Designer.
|
|
self.__ui = Ui_PluginDialog()
|
|
self.__ui.setupUi(self)
|
|
|
|
# The default display strategy is to use a separate dialog box
|
|
# to select the input data.
|
|
self.viewInputFrame(False)
|
|
|
|
# The icon are supposed to be located in the plugin folder,
|
|
# i.e. in the same folder than this python module file
|
|
iconfolder=os.path.dirname(os.path.abspath(__file__))
|
|
icon = QIcon()
|
|
icon.addFile(os.path.join(iconfolder,"input.png"))
|
|
self.__ui.btnInput.setIcon(icon)
|
|
icon = QIcon()
|
|
icon.addFile(os.path.join(iconfolder,"compute.png"))
|
|
self.__ui.btnCompute.setIcon(icon)
|
|
icon = QIcon()
|
|
icon.addFile(os.path.join(iconfolder,"refresh.png"))
|
|
self.__ui.btnRefresh.setIcon(icon)
|
|
icon = QIcon()
|
|
icon.addFile(os.path.join(iconfolder,"publish.png"))
|
|
self.__ui.btnPublish.setIcon(icon)
|
|
icon = QIcon()
|
|
icon.addFile(os.path.join(iconfolder,"clear.png"))
|
|
self.__ui.btnClear.setIcon(icon)
|
|
|
|
# Then, we can connect the slot to there associated button event
|
|
self.connect(self.__ui.btnInput, SIGNAL('clicked()'), self.onInput )
|
|
self.connect(self.__ui.btnCompute, SIGNAL('clicked()'), self.onCompute )
|
|
self.connect(self.__ui.btnRefresh, SIGNAL('clicked()'), self.onRefresh )
|
|
self.connect(self.__ui.btnPublish, SIGNAL('clicked()'), self.onPublish )
|
|
self.connect(self.__ui.btnClear, SIGNAL('clicked()'), self.onClear )
|
|
|
|
self.clear()
|
|
|
|
self.setupJobManager()
|
|
|
|
|
|
def setupJobManager(self):
|
|
'''
|
|
This function configures the jobmanager by transmiting the
|
|
parameters required for a local execution and a remote
|
|
execution. The choice between "local" and "remote" is done at
|
|
the initialize step, by specifing the name of the resource to
|
|
be used.
|
|
'''
|
|
# We first
|
|
|
|
configReader = ConfigReader()
|
|
config = configReader.getLocalConfig()
|
|
configId = config.resname
|
|
self.__getJobManager().configure(configId, config)
|
|
# Note that the resname parameter is used as the key identifier of
|
|
# the configuration in the job manager. As is, there can be then
|
|
# only one configuration for each machine defined in the resources
|
|
# catalog (no need to have further, I thing)
|
|
config = configReader.getRemoteConfig()
|
|
configId = config.resname
|
|
self.__getJobManager().configure(configId, config)
|
|
|
|
# We specify the default configuration identifier as the
|
|
# resource name of the default configuration
|
|
self.__configId = configReader.getDefaultConfig().resname
|
|
|
|
|
|
def viewInputFrame(self, view=True):
|
|
# By default, the top input frame is visible and the input
|
|
# button is not visible.
|
|
if view is False:
|
|
self.__ui.frameInput.setVisible(False)
|
|
self.__ui.btnInput.setVisible(True)
|
|
# We create the input dialog that will be displayed when
|
|
# button input is pressed:
|
|
self.__inputDialog = InputDialog(self)
|
|
# The window is kept on the top to ease the selection of
|
|
# items in the object browser:
|
|
self.__inputDialog.setWindowFlags(
|
|
self.__inputDialog.windowFlags() | Qt.WindowStaysOnTopHint)
|
|
# The signal inputValidated emited from inputDialog is
|
|
# connected to the slot function onProcessInput:
|
|
self.connect(self.__inputDialog, SIGNAL('inputValidated()'), self.onProcessInput)
|
|
|
|
else:
|
|
self.__ui.frameInput.setVisible(True)
|
|
self.__ui.btnInput.setVisible(False)
|
|
# This case is NOT IMPLEMENTED YET (not really). It could
|
|
# be used to draw the input frame directly in the frame
|
|
# frameInput of this dialog box.
|
|
|
|
def getInputFrame(self):
|
|
return self.__ui.frameInput
|
|
|
|
def __setGuiState(self,states=["CAN_SELECT"]):
|
|
if "CAN_SELECT" in states:
|
|
self.__ui.btnInput.setEnabled(True)
|
|
else:
|
|
self.__ui.btnInput.setEnabled(False)
|
|
|
|
if "CAN_COMPUTE" in states:
|
|
self.__ui.btnCompute.setEnabled(True)
|
|
else:
|
|
self.__ui.btnCompute.setEnabled(False)
|
|
|
|
if "CAN_REFRESH" in states:
|
|
self.__ui.btnRefresh.setEnabled(True)
|
|
else:
|
|
self.__ui.btnRefresh.setEnabled(False)
|
|
|
|
if "CAN_PUBLISH" in states:
|
|
self.__ui.btnPublish.setEnabled(True)
|
|
else:
|
|
self.__ui.btnPublish.setEnabled(False)
|
|
|
|
def __getJobManager(self):
|
|
"""
|
|
This function requests a pointer to the MeshJobManager
|
|
servant. Note that the component is loaded on first demand,
|
|
and then the reference is recycled.
|
|
"""
|
|
if self.__dict__.has_key("__jobManager") and self.__jobManager is not None:
|
|
return self.__jobManager
|
|
|
|
# WARN: we first have to update the SALOME components catalog
|
|
# with the SPADDER components (because they are not defined in
|
|
# the SMESH catalog, and then they are not in the default
|
|
# catalog)
|
|
from salome.smesh import spadder
|
|
spadder.loadSpadderCatalog()
|
|
# Then we can load the MeshJobManager component
|
|
component=salome.lcc.FindOrLoadComponent("FactoryServer","MeshJobManager")
|
|
if component is None:
|
|
msg="ERR: the SALOME component MeshJobManager can't be reached"
|
|
self.__log(msg)
|
|
raise AdminException(msg)
|
|
|
|
self.__jobManager = component
|
|
return self.__jobManager
|
|
|
|
def __log(self, message):
|
|
"""
|
|
This function prints the specified message in the log area
|
|
"""
|
|
self.__ui.txtLog.append(message)
|
|
|
|
def __exportMesh(self, meshName, meshObject):
|
|
'''
|
|
This function exports the specified mesh object to a med
|
|
file whose name (basepath) is built from the specified mesh
|
|
name. This returns the filename.
|
|
'''
|
|
filename=str("/tmp/padder_inputfile_"+meshName+".med")
|
|
meshObject.ExportToMEDX( filename, 0, SMESH.MED_V2_2, 1, 1 )
|
|
return filename
|
|
|
|
def clear(self):
|
|
"""
|
|
This function clears the log area and the states of the buttons
|
|
"""
|
|
self.__listInputData = []
|
|
self.__ui.txtLog.clear()
|
|
self.__setGuiState(["CAN_SELECT"])
|
|
self.__isRunning = False
|
|
self.__ui.lblStatusBar.setText("Ready")
|
|
|
|
def update(self):
|
|
'''
|
|
This function can be used to programmatically force the
|
|
refresh of the dialog box, the job state in particular.
|
|
'''
|
|
if self.__isRunning:
|
|
self.onRefresh()
|
|
|
|
def onInput(self):
|
|
'''
|
|
This function is the slot connected to the Input button
|
|
(signal clicked()). It opens the dialog window to input
|
|
data. The dialog is opened in a window modal mode so that the
|
|
SALOME study objects can be selected. In conterpart, this
|
|
class must listen to signals emitted by the child dialog
|
|
windows to process the validation event (see the slot
|
|
onProcessInput which is connected to this event).
|
|
'''
|
|
self.__inputDialog.setData(self.__listInputData)
|
|
self.__inputDialog.open()
|
|
|
|
def onProcessInput(self):
|
|
"""
|
|
This function is the slot connected to the signal
|
|
inputValidated(), emit by the input dialog window when it's
|
|
validated, i.e. OK is pressed and data are valid.
|
|
"""
|
|
# The processing simply consists in requesting the input data
|
|
# from the dialog window.
|
|
self.__listInputData = self.__inputDialog.getData()
|
|
self.__ui.lblStatusBar.setText("Input data OK")
|
|
self.__log("INF: Press \"Compute\" to start the job")
|
|
self.__setGuiState(["CAN_SELECT", "CAN_COMPUTE"])
|
|
|
|
def onCompute(self):
|
|
'''
|
|
This function is the slot connected to the Compute button. It
|
|
initializes a mesh computation job and start it using the
|
|
SALOME launcher.
|
|
'''
|
|
# We first have to create the list of parameters for the
|
|
# initialize function. For that, we have to create the files
|
|
# from the mesh objects:
|
|
meshJobParameterList=[]
|
|
concreteIndex=0
|
|
for inputData in self.__listInputData:
|
|
# For each input data, we have to create a
|
|
# MeshJobParameter and add it to the list.
|
|
filename = self.__exportMesh(inputData.meshName, inputData.meshObject)
|
|
if inputData.meshType == InputData.MESHTYPES.CONCRETE:
|
|
filetype = MESHJOB.MED_CONCRETE
|
|
else:
|
|
filetype = MESHJOB.MED_STEELBAR
|
|
|
|
parameter = MESHJOB.MeshJobParameter(
|
|
file_name = filename,
|
|
file_type = filetype,
|
|
group_name = inputData.groupName)
|
|
meshJobParameterList.append(parameter)
|
|
|
|
jobManager = self.__getJobManager()
|
|
self.__jobid = jobManager.initialize(meshJobParameterList, self.__configId)
|
|
if self.__jobid < 0:
|
|
self.__log("ERR: the job can't be initialized")
|
|
self.__log("ERR: %s"%jobManager.getLastErrorMessage())
|
|
return
|
|
self.__log("INF: the job has been initialized with jobid = "+str(self.__jobid))
|
|
|
|
startOk = jobManager.start(self.__jobid)
|
|
if not startOk:
|
|
self.__log("ERR: the job with jobid = "+str(self.__jobid)+" can't be started")
|
|
self.__log("ERR: %s"%jobManager.getLastErrorMessage())
|
|
return
|
|
self.__log("INF: the job "+str(self.__jobid)+" has been started")
|
|
self.__ui.lblStatusBar.setText("Submission OK")
|
|
self.__setGuiState(["CAN_REFRESH"])
|
|
self.__isRunning = True
|
|
|
|
def onRefresh(self):
|
|
"""
|
|
This function is the slot connected on the Refresh button. It
|
|
requests the mesh job manager to get the state of the job and
|
|
display it in the log area.
|
|
"""
|
|
jobManager = self.__getJobManager()
|
|
state = jobManager.getState(self.__jobid)
|
|
self.__log("INF: job state = "+str(state))
|
|
self.__ui.lblStatusBar.setText("")
|
|
if state in run_states:
|
|
return
|
|
|
|
self.__isRunning = False
|
|
if state == "FINISHED":
|
|
self.__setGuiState(["CAN_PUBLISH"])
|
|
else:
|
|
self.__setGuiState(["CAN_SELECT"])
|
|
|
|
|
|
def onPublish(self):
|
|
"""
|
|
This function is the slot connected on the Publish button. It
|
|
requests the mesh job manager to download the results data
|
|
from the computation resource host and load the med file in
|
|
the SALOME study.
|
|
"""
|
|
jobManager = self.__getJobManager()
|
|
state = jobManager.getState(self.__jobid)
|
|
if state in run_states:
|
|
self.__log("WRN: jobid = "+str(self.__jobid)+" is not finished (state="+str(state)+")")
|
|
return
|
|
|
|
if state not in end_states:
|
|
self.__log("ERR: jobid = "+str(self.__jobid)+" ended abnormally with state="+str(state))
|
|
self.__log("ERR: %s"%jobManager.getLastErrorMessage())
|
|
return
|
|
|
|
meshJobResults = jobManager.finalize(self.__jobid)
|
|
logsdirname = os.path.join(meshJobResults.results_dirname, "logs")
|
|
if state == "ERROR" or meshJobResults.status is not True:
|
|
msgtemp = "ERR: jobid = %s ended with error: %s"
|
|
self.__log(msgtemp%(str(self.__jobid),jobManager.getLastErrorMessage()))
|
|
self.__log("ERR: see log files in %s"%logsdirname)
|
|
return
|
|
|
|
self.__log("INF: jobid=%s ended normally (see log files in %s)"%(str(self.__jobid),logsdirname))
|
|
|
|
medfilename = os.path.join(meshJobResults.results_dirname,
|
|
meshJobResults.outputmesh_filename)
|
|
|
|
smesh.SetCurrentStudy(studyedit.getActiveStudy())
|
|
([outputMesh], status) = smesh.CreateMeshesFromMED(medfilename)
|
|
|
|
# By convention, the name of the output mesh in the study is
|
|
# build from a constant string 'padder' and the session jobid
|
|
meshname = 'padder_'+str(self.__jobid)
|
|
smesh.SetName(outputMesh.GetMesh(), meshname)
|
|
if salome.sg.hasDesktop():
|
|
salome.sg.updateObjBrowser(0)
|
|
|
|
self.__ui.lblStatusBar.setText("Publication OK")
|
|
self.__setGuiState(["CAN_SELECT"])
|
|
|
|
def onClear(self):
|
|
"""
|
|
This function is the slot connected on the Clear button. It
|
|
erases data in the dialog box and cancel the current job if
|
|
one is running.
|
|
"""
|
|
self.clear()
|
|
|
|
|
|
|
|
__dialog=None
|
|
def getDialog():
|
|
"""
|
|
This function returns a singleton instance of the plugin dialog.
|
|
"""
|
|
global __dialog
|
|
if __dialog is None:
|
|
__dialog = PluginDialog()
|
|
return __dialog
|
|
|
|
#
|
|
# ==============================================================================
|
|
# Basic use cases and unit test functions
|
|
# ==============================================================================
|
|
#
|
|
def TEST_PluginDialog():
|
|
import sys
|
|
from PyQt4.QtGui import QApplication
|
|
from PyQt4.QtCore import QObject, SIGNAL, SLOT
|
|
app = QApplication(sys.argv)
|
|
QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
|
|
|
|
dlg=PluginDialog()
|
|
dlg.exec_()
|
|
|
|
if __name__ == "__main__":
|
|
TEST_PluginDialog()
|
|
|
|
|
|
|