Salome HOME
897e07a3e94886640fb1bd7f4b9c5c35e1f10764
[samples/atomgen.git] / src / ATOMGEN / ATOMGEN.py
1 # Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
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
20 import ATOMGEN_ORB
21 import ATOMGEN_ORB__POA
22 import SALOME_ComponentPy
23 import SALOME_DriverPy
24 import SALOMEDS
25
26 #--- init ORB ---
27 from omniORB import CORBA
28 myORB = CORBA.ORB_init([''], CORBA.ORB_ID)
29
30 def ObjectToString(object):
31     return myORB.object_to_string(object)
32
33 def StringToObject(string):
34     return myORB.string_to_object(string)
35
36 #--- init POA ---
37 from omniORB import PortableServer
38 myPOA = myORB.resolve_initial_references("RootPOA");
39
40 def ObjectToServant(object):
41     return myPOA.reference_to_servant(object)
42
43 __entry2IOR__ = {}
44
45 __pyEngineName__ = "atomgen"
46
47 #--- Engine implementation ---
48 class ATOMGEN( ATOMGEN_ORB__POA.ATOMGEN_Gen,
49                SALOME_ComponentPy.SALOME_ComponentPy_i,
50                SALOME_DriverPy.SALOME_DriverPy_i ):
51     """
52     ATOMGEN component engine
53     """
54     def __init__ ( self, orb, poa, contID, containerName, instanceName,
55                    interfaceName ):
56         """
57         Constructor
58         """
59         SALOME_ComponentPy.SALOME_ComponentPy_i.__init__( self, orb, poa,
60                                                           contID, containerName,
61                                                           instanceName, interfaceName, 0 )
62         SALOME_DriverPy.SALOME_DriverPy_i.__init__( self, interfaceName )
63         
64         self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
65         self.study = None
66         self.studyData = {}
67         self.entry2PyName = {}
68         pass
69
70     def getData( self, studyID ):
71         """
72         Gets study data
73         """
74         if self.studyData.has_key( studyID ):
75             l = []
76             for m in self.studyData[ studyID ]:
77                 l.append( m._this() )
78             return l
79         print "ATOMGEN: getData() failed because studyID ", str( studyID ), " was not found"
80         return []
81
82     def Save( self, component, URL, isMultiFile ):
83         """
84         Saves data.
85         Nothing to do here because in our case all data
86         are stored in the SALOMEDS attributes.
87         """
88         return ""
89
90     def Load( self, component, stream, URL, isMultiFile ):
91         """
92         Loads data
93         """
94         global __entry2IOR__
95         __entry2IOR__.clear()
96         import StringIO, pickle
97         study = component.GetStudy()
98         self.setCurrentStudy( study )
99         iter = study.NewChildIterator(component)
100         data = []
101         while iter.More():
102             sobject = iter.Value()
103             iter.Next()
104             found, attr = sobject.FindAttribute("AttributeName")
105             if not found: continue
106             from ATOMGEN_Data import Molecule, Atom
107             mol = Molecule(attr.Value())
108             __entry2IOR__[sobject.GetID()] = ObjectToString(mol._this())
109             iter1 = study.NewChildIterator(sobject)
110             while iter1.More():
111                 sobject1 = iter1.Value()
112                 iter1.Next()
113                 found, attr = sobject1.FindAttribute("AttributeName")
114                 if not found: continue
115                 name = attr.Value()
116                 x = y = z = None
117                 iter2 = study.NewChildIterator(sobject1)
118                 while iter2.More():
119                     sobject2 = iter2.Value()
120                     iter2.Next()
121                     found, attr1 = sobject2.FindAttribute("AttributeName")
122                     if not found: continue
123                     found, attr2 = sobject2.FindAttribute("AttributeReal")
124                     if not found: continue
125                     if attr1.Value() == "x": x = attr2.Value()
126                     if attr1.Value() == "y": y = attr2.Value()
127                     if attr1.Value() == "z": z = attr2.Value()
128                 if None not in [x, y, z]:
129                     atom = Atom(name, x, y, z)
130                     mol.addAtom(atom)
131                     __entry2IOR__[sobject1.GetID()] = ObjectToString(atom._this())
132                 pass
133             data.append(mol)
134         self.appendData( data, False )
135         return 1
136
137     def IORToLocalPersistentID(self, sobject, IOR, isMultiFile, isASCII):
138         """
139         Gets persistent ID for the CORBA object.
140         It's enough to use study entry.
141         """
142         return sobject.GetID()
143
144     def LocalPersistentIDToIOR(self, sobject, persistentID, isMultiFile, isASCII):
145         "Converts persistent ID of the object to its IOR."
146         global __entry2IOR__
147         if __entry2IOR__.has_key(persistentID):
148             return __entry2IOR__[persistentID]
149         return ""
150
151     def Close( self, component ):
152         """
153         Called when study is closed
154         """
155         study = component.GetStudy()
156         if study and self.studyData.has_key( study._get_StudyId() ):
157             del self.studyData[ study._get_StudyId() ]
158         if study == self.study:
159             self.study = None
160         pass
161
162     def CanPublishInStudy( self, IOR ):
163         """
164         Returns True if the object can be published.
165         Nothing to do here. Usually this method should perform
166         check for the object type.
167         """
168         return True
169
170     def PublishInStudy( self, study, sobject, object, name ):
171         """
172         Publishes the object in the study.
173         """
174         if study and object and object._narrow(ATOMGEN_ORB.Molecule):
175             builder = study.NewBuilder()
176             builder.NewCommand()
177             # get or create component object
178             father = study.FindComponent(self._ComponentDataType)
179             if father is None:
180                 builder
181                 father = builder.NewComponent(self._ComponentDataType)
182                 attr = builder.FindOrCreateAttribute(father, "AttributeName")
183                 attr.SetValue(self._ComponentDataType)
184                 builder.DefineComponentInstance(father, self._this())
185                 pass
186             # publish molecule
187             sobject = builder.NewObject(father)
188             attr = builder.FindOrCreateAttribute(sobject, "AttributeName")
189             if not name:
190                 name = object.getName()
191             attr.SetValue(name)
192             attr = builder.FindOrCreateAttribute(sobject, "AttributeIOR")
193             attr.SetValue(ObjectToString(object))
194             # publish atoms
195             for i in range(object.getNbAtoms()):
196                 atom = object.getAtom( i )
197                 sobject1 = builder.NewObject(sobject)
198                 attr = builder.FindOrCreateAttribute(sobject1, "AttributeName")
199                 attr.SetValue(atom.getName())
200                 attr = builder.FindOrCreateAttribute(sobject1, "AttributeIOR")
201                 attr.SetValue(ObjectToString(atom))
202                 sobject2 = builder.NewObject(sobject1)
203                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeName")
204                 attr.SetValue("x")
205                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeReal")
206                 attr.SetValue(atom.getX())
207                 sobject2 = builder.NewObject(sobject1)
208                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeName")
209                 attr.SetValue("y")
210                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeReal")
211                 attr.SetValue(atom.getY())
212                 sobject2 = builder.NewObject(sobject1)
213                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeName")
214                 attr.SetValue("z")
215                 attr = builder.FindOrCreateAttribute(sobject2, "AttributeReal")
216                 attr.SetValue(atom.getZ())
217             builder.CommitCommand()
218             return sobject
219         return None
220
221     def setCurrentStudy( self, study ):
222         """
223         Sets the active study
224         """
225         self.study = study
226         if self.study and not self.getData( self.study._get_StudyId() ):
227             studyID = self.study._get_StudyId()
228             self.studyData[ studyID ] = []
229             self.entry2PyName[ studyID ] = {}
230             print "ATOMGEN: init new arrays for studyID ", str( studyID ) 
231         pass
232
233     def importXmlFile( self, fileName ):
234         """
235         Imports atomic data from external XML file
236         and publishes the data in the active study
237         """
238         if self.study:
239             # import file
240             from ATOMGEN_XmlParser import readXmlFile
241             new_data = readXmlFile( fileName )
242             entries = self.appendData( new_data )
243             if len(entries)  > 0 :
244                 cmd = "[" + ", ".join(entries) + "] = "+__pyEngineName__
245                 cmd += ".importXmlFile('" + fileName + "')"
246                 attr = self._getTableAttribute()                
247                 if attr is not None:
248                     attr.PutValue(cmd,attr.GetNbRows()+1,1)
249             res = []
250             for m in new_data:                
251                 res.append(m._this())
252             return res
253         return []
254
255     def exportXmlFile( self, fileName ):
256         """
257         Exports atomic data from the active study to
258         the external XML file
259         """
260         if self.study:
261             from ATOMGEN_XmlParser import writeXmlFile
262             studyID = self.study._get_StudyId()
263             writeXmlFile( fileName, self.studyData[ studyID ] )
264             cmd = __pyEngineName__+ ".exportXmlFile('" + fileName + "')"
265             attr = self._getTableAttribute()
266             if attr is not None:
267                 attr.PutValue(cmd,attr.GetNbRows()+1,1)
268             return True
269         return False
270
271     def processData( self, data ):
272         """
273         Perform some specific action on the atomic data
274         """
275         if not self.study: return []
276         nb_steps = 5
277         new_data = []
278         dx = 10.0
279         dy = 5.0
280         dz = 3.0
281         for i in range( nb_steps ):
282             for mol in data:
283                 new_mol = self._translateMolecule( mol, i, dx * (i+1), dy * (i+1), dz * (i+1) )                
284                 new_data.append( new_mol )
285         entries = self.appendData( new_data )
286         if len(entries) > 0 :
287             lst = []
288             for m in data:
289                 ior = ObjectToString(m)
290                 so = self.study.FindObjectIOR(ior)
291                 lst.append(so.GetID())
292                 
293             cmd =  "[" + ", ".join(entries) + "] = "+__pyEngineName__
294             cmd += ".processData([" + ", ".join(lst) + "])"
295             attr = self._getTableAttribute()
296             if attr is not None:
297                 attr.PutValue(cmd, attr.GetNbRows()+1,1)
298         res = []
299         for m in new_data:
300             res.append(m._this())
301         return res
302
303     def appendData( self, new_data, publish = True ):
304         """
305         Add new molecules to data published under current study
306         """
307         entries = []
308         # activate servants
309         if not self.study:
310             return entries
311         for mol in new_data:
312             for i in range(mol.getNbAtoms()):
313                 mol.atoms[ i ]._this()
314             mol_servant = mol._this()
315             if publish :
316                 so = self.PublishInStudy(self.study, None, mol_servant, mol_servant.getName())
317                 if so is not None:
318                     entries.append(so.GetID())
319         # store data
320         studyID = self.study._get_StudyId()
321         if self.studyData.has_key( studyID ):
322             data = self.studyData[ studyID ]
323             data += new_data
324             self.studyData[ studyID ] = data
325             return entries
326         print "ATOMGEN: could not append new data because studyID ", str( studyID ), " was not found"
327         return entries
328
329     def _translateMolecule( self, mol, i, dx, dy, dz ):
330         """
331         Translates atomic molecule along x, y, z axis
332         by given distances dx, dy, dz
333         Returns translated molecule
334         """
335         mol = ObjectToServant( mol )
336         from ATOMGEN_Data import Molecule, Atom
337         new_mol = Molecule( mol.name + "_translated_" + str( i ) )
338         for atom in mol.atoms:
339             new_mol.addAtom( Atom( atom.name, atom.x + dx, atom.y + dy, atom.z + dz ) )
340         return new_mol
341
342
343     def DumpPython(self, theStudy, isPublished, isMultiFile):
344         script = []
345         prefix = ""
346         if isMultiFile :
347             script.append("import salome")
348             script.append("\n")
349             prefix = "\t"
350         script.append("import ATOMGEN\n")
351         script.append(__pyEngineName__ + " = salome.lcc.FindOrLoadComponent(\"FactoryServerPy\", \"ATOMGEN\")")
352         
353         if isMultiFile :
354             script.append("def RebuildData(theStudy):\n")
355             script.append(prefix+__pyEngineName__ + ".setCurrentStudy(theStudy)\n")
356         else:
357             script.append(__pyEngineName__ + ".setCurrentStudy(theStudy)\n")
358         
359         attr = self._getTableAttribute()
360         if attr is not None:
361             for idx in range(attr.GetNbRows()):
362                 s = prefix + attr.GetValue(idx+1,1)
363                 script.append(s)
364         
365         if isMultiFile :
366             script.append(prefix+"pass")
367         else:
368             script.append("\n")
369         script.append("\0")
370         
371         all = "\n".join(script)
372         self._getPyNames()        
373         studyID = self.study._get_StudyId()
374         
375         for k in self.entry2PyName[studyID].keys() :
376             all = all.replace(k,self.entry2PyName[studyID][k])
377         
378         return (all,1)
379     
380     def _getTableAttribute(self):
381         """
382         Create and return AttributeTableOfString attribute
383         on the root module object. This attribute used to store
384         python script.
385         """
386         if self.study is not None:            
387             father = self.study.FindComponent(self._ComponentDataType)
388             if father is not None :
389                 attribute = None
390                 hasAttribute, attribute = father.FindAttribute("AttributeTableOfString")
391                 if not hasAttribute:
392                     builder = self.study.NewBuilder()
393                     attribute = builder.FindOrCreateAttribute(father,"AttributeTableOfString")
394                     attribute.SetNbColumns(1)
395                     return attribute
396                 return attribute
397         return None
398
399     def _getPyNames(self):
400         """
401         Generate python name for the each object published in the study.
402         """
403         if self.study is None:
404             return
405         
406         studyID = self.study._get_StudyId()
407         self.entry2PyName[studyID] = {}
408         iter = self.study.NewChildIterator(self.study.FindComponent(self._ComponentDataType))
409         while iter.More():
410             sobject = iter.Value()
411             iter.Next()            
412             found, attr = sobject.FindAttribute("AttributeName")
413             if not found: continue
414             self.entry2PyName[studyID][sobject.GetID()] = self._fixPythonName(attr.Value())            
415             
416     def _fixPythonName(self, in_str):
417         """
418         Make a string be a valid python name
419         """
420         import string
421         allowed = string.ascii_lowercase+string.ascii_uppercase + string.digits + "_"
422         newstring = ""
423         for i in range(len(in_str)):
424             ch = in_str[i]
425             if ch in allowed:
426                 newstring += ch
427                 
428         if len(newstring) == 0 :
429             newstring = "mol_1"
430
431         if newstring[0] in string.digits:
432             newstring = "a"+newstring
433             
434         studyID = self.study._get_StudyId()
435         
436         if newstring in self.entry2PyName[studyID].values():
437            newstring = self._fixPythonName( newstring + "_1")
438         return newstring