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