Salome HOME
4e53671377bedb3592c387df4b99a1b434de9e5d
[samples/genericsolver.git] / src / GENERICSOLVER / DEVIATION.py
1 #  Copyright (C) 2009-2015 EDF R&D
2 #
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.
7 #
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.
12 #
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
16 #
17 #  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19 #  $Id$
20 #
21
22 import inspect
23 import logging
24 import os
25 import platform
26 import threading
27 import traceback
28
29 from salome.gui.helper import sgPyQt
30 from salome.kernel import termcolor
31 from salome.kernel.logger import Logger
32 from salome.kernel.parametric.compo_utils import \
33     create_input_dict, create_normal_parametric_output, create_error_parametric_output
34 import GENERICSOLVER_ORB__POA
35 import SALOME
36 import SALOME_ComponentPy
37 import SALOME_DriverPy
38 import _thread
39 import salome
40
41
42 logger = Logger("DEVIATION", color=termcolor.RED_FG)
43 logger.setLevel(logging.INFO)
44
45
46 VARIABLE_ID = 1030
47
48 ###
49 # Retrieve data from selected case
50 ###
51 def GetDataFromCase( studyId, caseEntry ):
52     theCase = {}
53     study = salome.myStudyManager.GetStudyByID( studyId )
54     case = study.FindObjectID( caseEntry )
55     builder = study.NewBuilder()
56     # Get the values of the variables and make them a list
57     for name in ("E", "F", "L", "I"):
58         var = getSubSObjectByName( studyId, case, name )
59         if var is None:
60             raise Exception('No variable "%s" was found in case "%s" (entry %s). '
61                             'It is probably not a case for the code DEVIATION.' %
62                             (name, case.GetName(), caseEntry))
63         theCase[ name ] = getValueOfVariable( builder, var )
64     return theCase
65
66 ###
67 # Plays with study
68 ###
69
70 def getValueOfVariable( builder, varobj ):
71     attr = builder.FindOrCreateAttribute( varobj, "AttributeLocalID" )
72     objid = attr.Value()
73     if (objid == VARIABLE_ID):
74         attr = builder.FindOrCreateAttribute( varobj, "AttributeReal" )
75         return attr.Value()
76     else:
77         attr = builder.FindOrCreateAttribute( varobj, "AttributeName" )
78         QMessageBox.information( sgPyQt.getDesktop(), 'Info', "Object '%s' isn't a variable. Can't set value." % attr.Value() )
79     return 0.
80
81 def getSubSObjectByName( studyId, sobjFather, childName ):
82     logger.debug("GENERICSOLVER.getSubSObjectByName Looking for sobjet named " + childName)
83     study = salome.myStudyManager.GetStudyByID( studyId )
84     iterator = study.NewChildIterator(sobjFather)
85     #builder = study.NewBuilder()
86     while iterator.More():
87         sobj = iterator.Value()
88         logger.debug("GENERICSOLVER.getSubSObjectByName Got sobjet named " + sobj.GetName())
89         if sobj.GetName() == childName:
90             return sobj
91         iterator.Next()
92         pass
93     return None
94
95 ################################################
96
97 class DEVIATION(GENERICSOLVER_ORB__POA.DEVIATION_Gen,
98                 SALOME_ComponentPy.SALOME_ComponentPy_i,
99                 SALOME_DriverPy.SALOME_DriverPy_i):
100     
101     lock = threading.Lock()
102     
103     """
104         Pour etre un composant SALOME cette classe Python
105         doit avoir le nom du composant et heriter de la
106         classe DEVIATION_Gen issue de la compilation de l'idl
107         par omniidl et de la classe SALOME_ComponentPy_i
108         qui porte les services generaux d'un composant SALOME
109     """
110     def __init__ ( self, orb, poa, contID, containerName, instanceName, 
111                    interfaceName ):
112         logger.info("__init__: " + containerName + ' ; ' + instanceName)
113         SALOME_ComponentPy.SALOME_ComponentPy_i.__init__(self, orb, poa,
114                     contID, containerName, instanceName, interfaceName, False)
115         SALOME_DriverPy.SALOME_DriverPy_i.__init__(self, interfaceName)
116         # On stocke dans l'attribut _naming_service, une reference sur
117         # le Naming Service CORBA
118         self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
119         self.deterministicValues = {}
120
121 ######################################################################
122 # This is the Wrapper part of the GENERICSOLVER module, ie
123 # the three following methods are used by generic controlling
124 # modules like OpenTURNS in order to launch a computation.
125 # The interface is declared in GENERICSOLVER_Gen.idl. The methods
126 # are free to call the legacy interface (see below).
127 ######################################################################
128
129     def _raiseSalomeError(self):
130         message = "Error in component %s running in container %s." % (self._instanceName, self._containerName)
131         logger.exception(message)
132         message += " " + traceback.format_exc()
133         exc = SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR, message,
134                                      inspect.stack()[1][1], inspect.stack()[1][2])
135         raise SALOME.SALOME_Exception(exc)
136     
137     def _getIdMessage(self):
138         return "%s in container %s running on %s, process %d, thread %d" % \
139                (self._instanceName, self._containerName,
140                 platform.node(), os.getpid(), _thread.get_ident())
141
142     def Init(self, studyId, detCaseEntry):
143         """
144         This method is an example for the initialization of a computation component for
145         use with OpenTURNS in SALOME 5.1.5 and later (for YACS integration)
146         """
147         try:
148             logger.info("Init: " + self._getIdMessage())
149             DEVIATION.lock.acquire()
150             salome.salome_init()
151             DEVIATION.lock.release()
152
153             self.deterministicValues = GetDataFromCase(studyId, detCaseEntry)
154             logger.debug("deterministic values: %s" % self.deterministicValues)
155         except:
156             self._raiseSalomeError()
157
158     def Exec(self, paramInput):
159         """
160         This method is an example for the execution of a computation component for
161         use with OpenTURNS in SALOME 5.1.5 and later (for YACS integration)
162         """
163         try:
164             logger.info("Exec: " + self._getIdMessage())
165             logger.debug("inputVarList: %s" % paramInput.inputVarList)
166             logger.debug("outputVarList: %s" % paramInput.outputVarList)
167             logger.debug("inputValues: %s" % paramInput.inputValues)
168
169             # Get id and execution mode
170             id = ""
171             exec_mode = ""
172             for parameter in paramInput.specificParameters:
173                 if parameter.name == "id":
174                     id = parameter.value
175                 if parameter.name == "executionMode":
176                     exec_mode = parameter.value
177             logger.debug("ID: %s" % id)
178             logger.debug("Execution mode: %s" % exec_mode)
179
180             inputDict = create_input_dict(self.deterministicValues, paramInput)
181             logger.debug("inputDict = %s" % inputDict)
182             
183             # Test for an invalid parameter and return an error in this case
184             if inputDict["L"] <= 0:
185                 return create_error_parametric_output("Invalid value: L must be positive")
186
187             outputDict = {}
188             outputDict["dev"] = self.BeamModel(**inputDict)
189
190             paramOutput = create_normal_parametric_output(outputDict, paramInput)
191             logger.debug("outputValues: %s" % paramOutput.outputValues)
192             return paramOutput
193         except:
194             self._raiseSalomeError()
195
196     def Finalize(self):
197         """
198         This method is an implementation for the DEVIATION interface.
199         It cleans everything set so far.
200         """
201         try:
202             logger.info("Finalize: " + self._getIdMessage())
203         except:
204             self._raiseSalomeError()
205
206     def GetFilesToTransfer(self, studyId, detCaseEntry):
207         """
208         This method can be used to specify files to transfer to the
209         computation resource. It is not useful for DEVIATION since it only
210         uses values from Salome study.
211         """
212         try:
213             logger.info("GetFilesToTransfer: " + self._getIdMessage())
214             inputFiles = []
215             outputFiles = []
216             return (inputFiles, outputFiles)
217         except:
218             self._raiseSalomeError()
219
220 ######################################################################
221 # This is the computation part of the GENERICSOLVER module, ie
222 # the following method realizes what the solver is intended to do.
223 # The interface of this method (and maybe other ones) is absolutely
224 # free and depends on the module (legacy interface).
225 ######################################################################
226
227     def BeamModel(self, E, F, L, I):
228        """
229        This method implements a beam bending model based on the following formula:
230        deviation = ( Force * Length^3 ) / ( 3 * YoungModulus * InertiaSection )
231        """
232        d = (F * L * L * L) / (3. * E * I)
233        logger.debug("BeamModel (E=%g, F=%g, L=%g, I=%g) = %g" % (E, F, L, I, d))
234        return d