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