]> SALOME platform Git repositories - modules/yacs.git/blob - src/salomeloader/salomeloader.py
Salome HOME
merge from branch DEV tag mergeto_trunk_04apr08
[modules/yacs.git] / src / salomeloader / salomeloader.py
1 # -*- coding: iso-8859-1 -*-
2 """This module is used to parse a supervision graph Salome (XML) and convert it into
3    YACS calculation schema
4
5    This parsing is done with SalomeLoader class and its method load.
6 """
7
8 import sys,os
9 try:
10   import cElementTree as ElementTree
11 except ImportError:
12   import ElementTree
13
14 from sets import Set
15 import graph
16 import pilot
17 import SALOMERuntime
18
19 class UnknownKind(Exception):pass
20
21 debug=0
22 typeMap={}
23 objref=None
24
25 def typeName(name):
26   """Replace :: in type name by /"""
27   return "/".join(name.split("::"))
28
29 streamTypes={
30              '0':"Unknown",
31              '1':"CALCIUM_integer",
32              '3':"CALCIUM_real",
33             }
34
35 currentProc=None
36
37 class SalomeLoader:
38   """This class parses a Salome graph (version 3.2.x) and converts it into YACS schema.
39
40      The loadxml method parses xml file and returns a SalomeProc object
41
42      The load method calls the loadxml method and creates a YACS object of class Proc
43   """
44
45   def loadxml(self,filename):
46     """
47        Parse a XML file from Salome SUPERV and return a list of SalomeProc objects.
48     """
49     tree = ElementTree.ElementTree(file=filename)
50     root = tree.getroot()
51     if debug:print "root.tag:",root.tag,root
52
53     procs=[]
54     if root.tag == "dataflow":
55       #only one dataflow
56       dataflow=root
57       if debug:print dataflow
58       proc=SalomeProc(dataflow)
59       procs.append(proc)
60     else:
61       #one or more dataflows. The graph contains macros.
62       #All macros are defined at the same level in the XML file.
63       for dataflow in root.findall("dataflow"):
64         if debug:print dataflow
65         proc=SalomeProc(dataflow)
66         if debug:print "dataflow name:",proc.name
67         procs.append(proc)
68     return procs
69
70   def load(self,filename):
71     """Parse a SUPERV XML file (method loadxml) and return a YACS Proc object.
72     """
73     global currentProc
74     procs=self.loadxml(filename)
75     #Split the master proc from the possible macros.
76     proc=procs.pop(0)
77     #proc.display()
78
79     #Put macros in macro_dict
80     macro_dict={}
81     for p in procs:
82       if debug:print "proc_name:",p.name,"coupled_node:",p.coupled_node
83       macro_dict[p.name]=p
84
85     if debug:print filename
86     yacsproc=ProcNode(proc,macro_dict,filename)
87     return yacsproc.createNode()
88
89 class Container:
90   """Class that defines a Salome Container"""
91   def __init__(self,mach,name):
92     self.mach=mach
93     self.name=name
94     self.components={}
95   def getName(self):
96     return self.mach+"/"+self.name
97
98 _containers={}
99 def getContainer(name):
100   if not name:
101     name="localhost/FactoryServer"
102   elif "/" not in name:
103     #no machine name: use localhost
104     name="localhost/"+name
105   return _containers.get(name)
106
107 def addContainer(name):
108   if not name:
109     mach="localhost"
110     name="FactoryServer"
111   elif "/" not in name:
112     #no machine name: use localhost for mach
113     mach="localhost"
114   else:
115     mach,name=name.split("/")
116   c=Container(mach,name)
117   _containers[mach+"/"+name]=c
118   return c
119
120 class Service:
121     """Class for Service properties"""
122 class Parameter:
123     """Class for Parameter properties"""
124 class Link:
125     """Class for Link properties"""
126 class Data:
127     """Class for Data properties"""
128
129 class Node:
130     """Base class for all nodes """
131     label="Node: "
132     def __init__(self):
133       self.links=[]    # list to store inputs as links
134       # a link has two attributes : from_node, the starting node
135       # to_node, the end node
136       self.datas=[]
137       self.inStreamLinks=[] #list of dataStream links connected to this node (in)
138       self.outStreamLinks=[] #list of dataStream links connected to this node (out)
139       self.node=None
140     def createNode(self):
141       raise NotImplementedError
142     def getInputPort(self,p):
143       return self.node.getInputPort(".".join(p.split("__")))
144     def getOutputPort(self,p):
145       if not self.node:
146         self.createNode()
147       return self.node.getOutputPort(".".join(p.split("__")))
148     def getInputDataStreamPort(self,p):
149       return self.node.getInputDataStreamPort(p)
150     def getOutputDataStreamPort(self,p):
151       return self.node.getOutputDataStreamPort(p)
152
153     def initPort(self,l):
154       if l.type == 7:
155         #double (CORBA::tk_double)
156         try:
157           self.getInputPort(l.tonodeparam).edInitDbl(l.value)
158         except:
159           reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
160           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
161       elif l.type == 3:
162         #int (CORBA::tk_long)
163         try:
164           self.getInputPort(l.tonodeparam).edInitInt(l.value)
165         except:
166           reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
167           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
168       elif l.type == 14:
169         #objref (CORBA::tk_objref)
170         try:
171           self.getInputPort(l.tonodeparam).edInitString(l.value)
172         except:
173           reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
174           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
175       elif l.type == 18:
176         #string (CORBA::tk_string)
177         try:
178           self.getInputPort(l.tonodeparam).edInitString(l.value)
179         except:
180           reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
181           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
182       else:
183         reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
184         currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
185
186 class InlineNode(Node):
187     """Inline Node salome : python function in self.codes[0]"""
188     def __init__(self):
189       Node.__init__(self)
190       self.codes=[]
191     def createNode(self):
192       r = pilot.getRuntime()
193       if self.fnames[0] == "?":
194         n=r.createScriptNode("",self.name)
195       else:
196         n=r.createFuncNode("",self.name)
197         n.setFname(self.fnames[0])
198         n.setScript(self.codes[0])
199       self.node=n
200       for para in self.service.inParameters:
201         if not typeMap.has_key(para.type):
202           #create the missing type and add it in type map
203           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
204         if not currentProc.typeMap.has_key(para.type):
205           currentProc.typeMap[para.type]=typeMap[para.type]
206         n.edAddInputPort(para.name,typeMap[para.type])
207       for para in self.service.outParameters:
208         if not typeMap.has_key(para.type):
209           #create the missing type and add it in type map
210           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
211         if not currentProc.typeMap.has_key(para.type):
212           currentProc.typeMap[para.type]=typeMap[para.type]
213         n.edAddOutputPort(para.name,typeMap[para.type])
214
215       for d in self.datas:
216         self.initPort(d)
217
218       return n
219
220 class ComputeNode(Node):
221     """Compute Node Salome execute a component service"""
222     def createNode(self):
223       if self.node:
224         return self.node
225
226       r = pilot.getRuntime()
227       if self.container.components.has_key(self.sComponent):
228         #a node for this component already exists
229         compo_node=self.container.components[self.sComponent]
230         #It's a node associated with another node of the same component instance
231         #It is not sure that the yacs node has been created ????
232         master_node=compo_node.createNode()
233         n=master_node.createNode(self.name)
234       else:
235         #there is no node for this component. This node is first
236         self.container.components[self.sComponent]=self
237         #There is no component instance for this node
238         n=r.createCompoNode("",self.name)
239         n.setRef(self.sComponent)
240
241       n.setMethod(self.service.name)
242       self.node=n
243       #set the container for the node
244       if self.container:
245         n.getComponent().setContainer(currentProc.containerMap[self.container.getName()])
246
247       #add  dataflow ports in out 
248       for para in self.service.inParameters:
249         if not typeMap.has_key(para.type):
250           #Create the missing type and adds it into types table
251           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
252         if not currentProc.typeMap.has_key(para.type):
253           currentProc.typeMap[para.type]=typeMap[para.type]
254         n.edAddInputPort(para.name,typeMap[para.type])
255       for para in self.service.outParameters:
256         if not typeMap.has_key(para.type):
257           #Create the missing type and adds it into types table
258           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
259         if not currentProc.typeMap.has_key(para.type):
260           currentProc.typeMap[para.type]=typeMap[para.type]
261         pout=n.edAddOutputPort(para.name,typeMap[para.type])
262
263       #add datastream ports in and out
264       for para in self.inStreams:
265         if debug:print para.name,para.type,para.dependency,para.schema, para.interpolation,
266         if debug:print para.extrapolation
267         pin=n.edAddInputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
268       for para in self.outStreams:
269         if debug:print para.name,para.type,para.dependency,para.values
270         pout=n.edAddOutputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
271
272       for d in self.datas:
273         self.initPort(d)
274
275       return n
276
277 class ComposedNode(Node):
278   """Composed Node Salome (base class)"""
279
280   def reduceLoop(self):
281     """Transform a Salome graph with loops on one level
282        in a hierarchical graph.
283
284        The initial graph is in self.G. It is transformed in place.
285     """
286     G=self.G
287     if debug:graph.display(G)
288     #invert the graph
289     I=graph.invert(G)
290     #graph.display(I)
291
292     #Get all loops and their internal nodes
293     loops={}
294     for n in G:
295       if n.kind == 4:
296         #Beginning of loop
297         loops[n]=graph.reachable(G,n)&graph.reachable(I,n.endloop)
298         n.inner_nodes=loops[n]
299         n.G=graph.InducedSubgraph(loops[n],G)
300
301     if debug:print "all loops"
302     if debug:print loops
303
304     #Get most external loops 
305     outer_loops=loops.keys()
306     for l in loops:
307       for ll in outer_loops:
308         if loops[l] < loops[ll]:
309           #internal loop
310           outer_loops.remove(l)
311           ll.set_inner(l)
312           break
313
314     #In the end all remaining loops in outer_loops are the most external
315     if debug:print outer_loops
316
317     #We remove all internal nodes of most external loops 
318     for l in outer_loops:
319       #Remove internal nodes
320       for n in loops[l]:
321         del G[n]
322       #Remove endloop node
323       suiv=G[l.endloop]
324       del G[l.endloop]
325       #Replace neighbours of loop by those of endloop
326       G[l]= suiv
327
328       #Try to transform incoming and outcoming links of endloop in incoming and 
329       #outcoming links of internal nodes. Probably not complete.
330       inputs={}
331       for link in l.endloop.links:
332         if debug:print link.from_node,link.to_node,link.from_param,link.to_param
333         inputs[link.to_param]=link.from_node,link.from_param
334
335       for s in suiv:
336         for link in s.links:
337           if link.from_node == l.endloop:
338             link.from_node,link.from_param=inputs[link.from_param]
339           if debug:print link.from_node,link.to_node,link.from_param,link.to_param
340
341       if debug:graph.display(G)
342
343       #Apply the reduction treatment to most external loops (recurse)
344       for l in outer_loops:
345         l.reduceLoop()
346
347   def connect_macros(self,macro_dict):
348     """This method connects the salome macros in macro_dict to the master YACS Proc.
349        
350     """
351     if debug:print "connect_macros",self.node,macro_dict
352     for node in self.G:
353       if isinstance(node,MacroNode):
354         #node is a macro, connect its definition to self.
355         #p is the Salome macro (class SalomeProc)
356         #node is the Salome MacroNode that has the subgraph p
357         #node.node is the YACS Bloc equivalent to node
358         p=macro_dict[node.coupled_node]
359         bloc=node.node
360         if debug:print "macronode:",node.name,node.coupled_node,p
361         #Create a hierarchical graph from the salome graph
362         G=p.create_graph()
363         node.G=G
364         for n in G:
365           #create an equivalent YACS node from each salome node
366           nod=n.createNode()
367           bloc.edAddChild(nod)
368
369         #Connect macros to node
370         node.connect_macros(macro_dict)
371
372         #add control links
373         for n in G:
374           for v in G[n]:
375             bloc.edAddCFLink(n.node,v.node)
376         #add dataflow links and initializations
377         for n in G:
378           #dataflow links
379           for l in n.links:
380             bloc.edAddLink(l.from_node.getOutputPort(l.from_param),
381                         l.to_node.getInputPort(l.to_param))
382           #datastream links
383           for l in n.outStreamLinks:
384             pout=l.from_node.getOutputDataStreamPort(l.from_param)
385             pin=l.to_node.getInputDataStreamPort(l.to_param)
386             bloc.edAddLink(pout,pin)
387           #initializations
388           for l in n.datas:
389             if l.type == 7:
390               #double (CORBA::tk_double)
391               try:
392                 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
393               except:
394                 reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
395                 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
396             elif l.type == 3:
397               #int (CORBA::tk_long)
398               try:
399                 n.getInputPort(l.tonodeparam).edInitInt(l.value)
400               except:
401                 reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
402                 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
403             elif l.type == 14:
404               #objref (CORBA::tk_objref)
405               try:
406                 n.getInputPort(l.tonodeparam).edInitString(l.value)
407               except:
408                 reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
409                 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
410             elif l.type == 18:
411               #string (CORBA::tk_string)
412               try:
413                 n.getInputPort(l.tonodeparam).edInitString(l.value)
414               except:
415                 reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
416                 currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
417             else:
418               reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
419               currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
420
421 class LoopNode(ComposedNode):
422     """Objet qui simule le comportement d'une boucle Salome."""
423     def __init__(self):
424       ComposedNode.__init__(self)
425       self.inner_loops=[]
426       #inner_nodes contains internal nodes as in Salome (on one level with endloop nodes)
427       self.inner_nodes=[]
428
429     def set_node(self,node):
430       self.node=node
431
432     def set_inner(self,loop):
433       for i in self.inner_loops:
434         if loop.inner_nodes < i.inner_nodes:
435           #the loop is contained in i
436           i.set_inner(loop)
437           break
438       self.inner_loops.append(loop)
439
440     def createNode(self):
441       """Create the equivalent YACS loop and store it in attribute node
442
443          A Salome loop has n input ports and output ports with exactly same names.
444          The head of loop has 3 functions : init, next, more which have almost same 
445          interface. init and next have same interface : on input, input loop parameters
446          on output, output loop parameters (same as input). more has one more output parameter
447          in first place. This parameter says if the loop must go on or not.
448          The endloop has a function with the same interface as next.
449
450          To transform this node, create a YACS Bloc. In this bloc put a node for the init function
451          and a While node. In the while put all internal nodes plus 2 nodes for the next and more 
452          functions.
453       """
454
455       r = pilot.getRuntime()
456       bloop=r.createBloc(self.name)
457
458       #init node
459       init=r.createFuncNode("","init")
460       #print self.codes[0]
461       init.setScript(self.codes[0])
462       init.setFname(self.fnames[0])
463       for para in self.service.inParameters:
464         if not typeMap.has_key(para.type):
465           #create the missing type and add it in type map
466           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
467         if not currentProc.typeMap.has_key(para.type):
468           currentProc.typeMap[para.type]=typeMap[para.type]
469         init.edAddInputPort(para.name,typeMap[para.type])
470       for para in self.service.outParameters:
471         if not typeMap.has_key(para.type):
472           #create the missing type and add it in type map
473           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
474         if not currentProc.typeMap.has_key(para.type):
475           currentProc.typeMap[para.type]=typeMap[para.type]
476         init.edAddOutputPort(para.name,typeMap[para.type])
477       bloop.edAddChild(init)
478       self.init=init
479
480       wh=r.createWhileLoop(self.name)
481       bloop.edAddChild(wh)
482       blnode=r.createBloc(self.name)
483       wh.edSetNode(blnode)
484       cport=wh.edGetConditionPort()
485       cport.edInitBool(True)
486
487       #next node
488       next=r.createFuncNode("","next")
489       #print self.codes[2]
490       next.setScript(self.codes[2])
491       next.setFname(self.fnames[2])
492       for para in self.service.inParameters:
493         if not typeMap.has_key(para.type):
494           #create the missing type and add it in type map
495           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
496         if not currentProc.typeMap.has_key(para.type):
497           currentProc.typeMap[para.type]=typeMap[para.type]
498         next.edAddInputPort(para.name,typeMap[para.type])
499       for para in self.service.outParameters:
500         if not typeMap.has_key(para.type):
501           #create the missing type and add it in type map
502           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
503         if not currentProc.typeMap.has_key(para.type):
504           currentProc.typeMap[para.type]=typeMap[para.type]
505         next.edAddOutputPort(para.name,typeMap[para.type])
506       blnode.edAddChild(next)
507       self.next=next
508
509       #more node
510       more=r.createFuncNode("","more")
511       #print self.codes[1]
512       more.setScript(self.codes[1])
513       more.setFname(self.fnames[1])
514       for para in self.service.inParameters:
515         if not typeMap.has_key(para.type):
516           #create the missing type and add it in type map
517           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
518         if not currentProc.typeMap.has_key(para.type):
519           currentProc.typeMap[para.type]=typeMap[para.type]
520         more.edAddInputPort(para.name,typeMap[para.type])
521       more.edAddOutputPort("DoLoop",typeMap["int"])
522       for para in self.service.outParameters:
523         if not typeMap.has_key(para.type):
524           #create the missing type and add it in type map
525           typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[objref])
526         if not currentProc.typeMap.has_key(para.type):
527           currentProc.typeMap[para.type]=typeMap[para.type]
528         more.edAddOutputPort(para.name,typeMap[para.type])
529       blnode.edAddChild(more)
530       self.more=more
531
532       for para in self.service.outParameters:
533         bloop.edAddDFLink(init.getOutputPort(para.name),next.getInputPort(para.name))
534
535       for para in self.service.outParameters:
536         blnode.edAddDFLink(next.getOutputPort(para.name),more.getInputPort(para.name))
537
538       wh.edAddLink(more.getOutputPort("DoLoop"),wh.getInputPort("condition"))
539
540       for para in self.service.outParameters:
541         wh.edAddLink(more.getOutputPort(para.name),next.getInputPort(para.name))
542
543       self.node=bloop
544
545       for n in self.G:
546         node=n.createNode()
547         blnode.edAddChild(node)
548
549       for n in self.G:
550         for v in self.G[n]:
551           blnode.edAddCFLink(n.node,v.node)
552
553       for n in self.G:
554         for l in n.links:
555           try:
556             blnode.edAddDFLink(l.from_node.getOutputPort(l.from_param),
557                              l.to_node.getInputPort(l.to_param))
558           except:
559             reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
560             reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
561             currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
562
563       return bloop
564
565     def getInputPort(self,p):
566       return self.init.getInputPort(p)
567
568     def getOutputPort(self,p):
569       return self.more.getOutputPort(p)
570
571 class Bloc(ComposedNode):
572     """ Composed node containing a set of connected nodes
573     """
574     label="Bloc: "
575     def __init__(self):
576       Node.__init__(self)
577       self.nodes=[]
578
579     def addLink(self,node1,node2):
580       if node1 not in self.nodes:self.nodes.append(node1)
581       if node2 not in self.nodes:self.nodes.append(node2)
582
583 class MacroNode(Bloc):
584   """Objet that represents a Salome Macro
585   """
586   def createNode(self):
587     """Create a YACS node (Bloc) equivalent to a Salome Macro """
588     r = pilot.getRuntime()
589     macro=r.createBloc(self.name)
590     self.node=macro
591     return macro
592
593 def is_loop(n):
594   """Return true if n is a head loop node"""
595   return isinstance(n,LoopNode)
596
597 class ProcNode(ComposedNode):
598   """Salome proc with its macros
599
600      The Salome proc is stored in attribute proc
601      The Salome macros are stored in attribute macro_dict ({})
602   """
603   def __init__(self,proc,macro_dict,filename):
604     ComposedNode.__init__(self)
605     self.proc=proc
606     self.macro_dict=macro_dict
607     self.filename=filename
608
609   def createNode(self):
610     """Create the YACS node (Proc) equivalent a Salome proc"""
611     global currentProc,objref
612     r = pilot.getRuntime()
613
614     #create_graph gives a hierarchical graph equivalent to the Salome proc
615     G=self.proc.create_graph()
616     self.G=G
617
618     #Create the YACS proc with its elements (types, nodes, containers)
619     p=r.createProc("pr")
620     self.node=p
621     currentProc=p
622     p.filename=self.filename
623     typeMap["double"]=p.typeMap["double"]
624     typeMap["float"]=p.typeMap["double"]
625     typeMap["int"]=p.typeMap["int"]
626     typeMap["short"]=p.typeMap["int"]
627     typeMap["long"]=p.typeMap["int"]
628     typeMap["string"]=p.typeMap["string"]
629     typeMap["char"]=p.typeMap["string"]
630     typeMap["boolean"]=p.typeMap["bool"]
631     typeMap["bool"]=p.typeMap["bool"]
632
633     objref=p.createInterfaceTc("IDL:omg.org/CORBA/Object:1.0","Object",[])
634     typeMap["objref"]=objref
635     typeMap["Unknown"]=p.createInterfaceTc("","Unknown",[])
636     typeMap["GEOM_Object"]=p.createInterfaceTc("IDL:GEOM/GEOM_Object:1.0","GEOM_Object",[objref])
637     typeMap["GEOM_Shape"]=typeMap["GEOM_Object"]
638
639     typeMap["CALCIUM_integer"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Integer_Port:1.0","CALCIUM_integer",[])
640     typeMap["CALCIUM_real"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Real_Port:1.0","CALCIUM_real",[])
641     typeMap["CALCIUM_double"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Double_Port:1.0","CALCIUM_double",[])
642     typeMap["CALCIUM_string"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_String_Port:1.0","CALCIUM_string",[])
643     typeMap["CALCIUM_boolean"]=p.createInterfaceTc("IDL:Ports/Calcium_Ports/Calcium_Logical_Port:1.0","CALCIUM_boolean",[])
644
645     typeMap["SuperVisionTest::Adder"]=p.createInterfaceTc("","SuperVisionTest/Adder",[objref])
646     typeMap["Adder"]=typeMap["SuperVisionTest::Adder"]
647
648     currentProc.typeMap["Object"]=typeMap["objref"]
649     currentProc.typeMap["Unknown"]=typeMap["Unknown"]
650     currentProc.typeMap["GEOM_Object"]=typeMap["GEOM_Object"]
651     currentProc.typeMap["GEOM_Shape"]=typeMap["GEOM_Shape"]
652     currentProc.typeMap["CALCIUM_integer"]=typeMap["CALCIUM_integer"]
653     currentProc.typeMap["CALCIUM_real"]=typeMap["CALCIUM_real"]
654
655     #create all containers
656     for name,container in _containers.items():
657       cont=r.createContainer()
658       cont.setName(name)
659       cont.setProperty("hostname",container.mach)
660       cont.setProperty("container_name",container.name)
661       currentProc.containerMap[name]=cont
662
663     for n in G:
664       #each node in G creates an equivalent YACS node.
665       node=n.createNode()
666       p.edAddChild(node)
667
668     #Connect Salome macros to nodes of proc p.
669     self.connect_macros(self.macro_dict)
670
671     #add control links
672     for n in G:
673       for v in G[n]:
674         p.edAddCFLink(n.node,v.node)
675
676     #add dataflow links and initializations
677     for n in G:
678       #dataflow links
679       for l in n.links:
680         try:
681           p.edAddLink(l.from_node.getOutputPort(l.from_param),
682                     l.to_node.getInputPort(l.to_param))
683         except:
684           reason="Error while connecting output port: "+l.from_param+" from node: "+l.from_node.name
685           reason=reason+" to input port: "+l.to_param+" from node: "+l.to_node.name
686           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
687
688       #datastream links
689       for l in n.outStreamLinks:
690         pout=l.from_node.getOutputDataStreamPort(l.from_param)
691         pin=l.to_node.getInputDataStreamPort(l.to_param)
692         p.edAddLink(pout,pin)
693       #initializations
694       for l in n.datas:
695         if l.type == 7:
696           #double (CORBA::tk_double)
697           try:
698             n.getInputPort(l.tonodeparam).edInitDbl(l.value)
699           except:
700             reason="Problem in initialization, not expected type (double): %s %s" % (l.tonodeparam,l.value)
701             currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
702         elif l.type == 3:
703           #int (CORBA::tk_long)
704           port=n.getInputPort(l.tonodeparam)
705           try:
706             port.edInitInt(l.value)
707           except:
708             reason="Problem in initialization, not expected type (int): %s %s" % (l.tonodeparam,l.value)
709             currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
710         elif l.type == 14:
711           #objref (CORBA::tk_objref)
712           try:
713             n.getInputPort(l.tonodeparam).edInitString(l.value)
714           except:
715             reason="Problem in initialization, not expected type (objref): %s %s" % (l.tonodeparam,l.value)
716             currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
717         elif l.type == 18:
718           #string (CORBA::tk_string)
719           try:
720             n.getInputPort(l.tonodeparam).edInitString(l.value)
721           except:
722             reason="Problem in initialization, not expected type (string): %s %s" % (l.tonodeparam,l.value)
723             currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
724         else:
725           reason="Problem in initialization, not expected type (%s): %s %s" % (l.type,l.tonodeparam,l.value)
726           currentProc.getLogger("parser").error(reason,currentProc.filename,-1)
727
728     return p
729
730
731 class SalomeProc(ComposedNode):
732     """Salome proc with all its dataflow, datastream and control links
733        The object is built by parsing an XML file.
734     """
735     def __init__(self,dataflow):
736         self.name="name"
737         self.parse(dataflow)
738         #self.links : list of dataflow links (Link objects)
739         #self.nodes : list of graph nodes
740         #self.node_dict : nodes dict ({name:node})
741         #self.datas : list of graph datas 
742         #each node has 2 lists of datastream links (inStreams, outStreams)
743
744     def parse(self,dataflow):
745         if debug:print "All XML nodes"
746         for node in dataflow:
747             if debug:print node.tag,node
748
749         #Parse dataflow info-list
750         self.dataflow_info=self.parseService(dataflow.find("info-list/node/service"))
751         if debug:print self.dataflow_info
752         if debug:print self.dataflow_info.inParameters
753         if debug:print self.dataflow_info.outParameters
754         if debug:
755             for para in self.dataflow_info.inParameters:
756                 print "inParam:",para.name,para.name.split("__",1)
757
758         self.name=dataflow.findtext("info-list/node/node-name")
759         self.coupled_node=dataflow.findtext("info-list/node/coupled-node")
760
761         if debug:print "All XML nodes dataflow/node-list"
762         nodes=[]
763         node_dict={}
764         #Parse all nodes
765         for n in dataflow.findall('node-list/node'):
766             #n is a node-list node
767             kind=n.findtext("kind")
768             comp=n.findtext("component-name")
769             name=n.findtext("node-name")
770             coupled_node=n.findtext("coupled-node")
771             interface=n.findtext("interface-name")
772             container=n.findtext("container")
773
774             #kind=1 : dataflow ?
775             #kind=2 : ?
776             #kind=9 : datastream graph ?
777             #kind=6 : ??
778             #kind=8 : ??
779
780             if kind == "0":
781               #It's a service
782               node=ComputeNode()
783               node.kind=0
784               node.sComponent = comp
785               node.interface=interface
786               node.container= getContainer(container)
787               if not node.container:
788                 node.container=addContainer(container)
789               if debug:print "\tcontainer",node.container
790
791             elif kind == "3":
792               #It's a python function
793               node=InlineNode()
794               node.kind=3
795               codes=[]
796               fnames=[]
797               for pyfunc in n.findall("PyFunction-list/PyFunction"):
798                 fnames.append(pyfunc.findtext("FuncName"))
799                 codes.append(self.parsePyFunction(pyfunc))
800               node.fnames=fnames
801               node.codes=codes
802
803             elif kind == "4":
804               #It's a loop : make a LoopNode
805               #python functions (next, more, init) are found in codes
806               node=LoopNode()
807               node.kind=4
808               codes=[]
809               fnames=[]
810               for pyfunc in n.findall("PyFunction-list/PyFunction"):
811                 fnames.append(pyfunc.findtext("FuncName"))
812                 codes.append(self.parsePyFunction(pyfunc))
813               node.fnames=fnames
814               node.codes=codes
815
816             elif kind == "5":
817               #End of loop : make an InlineNode
818               node=InlineNode()
819               node.kind=5
820               codes=[]
821               fnames=[]
822               for pyfunc in n.findall("PyFunction-list/PyFunction"):
823                 fnames.append(pyfunc.findtext("FuncName"))
824                 codes.append(self.parsePyFunction(pyfunc))
825               node.fnames=fnames
826               node.codes=codes
827
828             elif kind == "10":
829               # It's a Macro node : make a MacroNode
830               node=MacroNode()
831               node.kind=10
832             else:
833               raise UnknownKind,kind
834
835             node.name=name
836             node.service=None
837             node.coupled_node=coupled_node
838             #Put nodes in a dict to ease search
839             node_dict[node.name]=node
840             if debug:print "\tnode-name",node.name
841             if debug:print "\tkind",node.kind,node.__class__.__name__
842
843             s=n.find("service")
844             if s:
845                 node.service=self.parseService(s)
846
847
848             #Parse datastream ports
849             if debug:print "DataStream ports"
850             inStreams=[]
851             for indata in n.findall("DataStream-list/inParameter"):
852                 inStreams.append(self.parseInData(indata))
853             node.inStreams=inStreams
854             outStreams=[]
855             outStreams_dict={}
856             for outdata in n.findall("DataStream-list/outParameter"):
857                 p=self.parseOutData(outdata)
858                 outStreams.append(p)
859                 outStreams_dict[p.name]=p
860             node.outStreams=outStreams
861             node.outStreams_dict=outStreams_dict
862             if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
863             nodes.append(node)
864
865         self.nodes=nodes
866         self.node_dict=node_dict
867         #Nodes parsing is finished.
868         #Parse dataflow and datastream links.
869         """
870         <link>
871         <fromnode-name>Node_A_1</fromnode-name>
872         <fromserviceparameter-name>a_1</fromserviceparameter-name>
873         <tonode-name>Node_B_1</tonode-name>
874         <toserviceparameter-name>b_1</toserviceparameter-name>
875         <coord-list/>
876         </link>
877         """
878         if debug:print "All XML nodes dataflow/link-list"
879         links=[]
880         if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
881         for link in dataflow.findall('link-list/link'):
882             l=Link()
883             l.from_name=link.findtext("fromnode-name")
884             l.to_name=link.findtext("tonode-name")
885             l.from_param=link.findtext("fromserviceparameter-name")
886             l.to_param=link.findtext("toserviceparameter-name")
887             links.append(l)
888             if debug:print "\tfromnode-name",l.from_name
889             if debug:print "\tfromserviceparameter-name",l.from_param
890             if debug:print "\ttonode-name",l.to_name
891             if debug:print "\ttoserviceparameter-name",l.to_param
892             if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
893
894         self.links=links
895         if debug:print "All XML nodes dataflow/data-list"
896         datas=[]
897         for data in dataflow.findall('data-list/data'):
898             d=self.parseData(data)
899             datas.append(d)
900             if debug:print "\ttonode-name",d.tonode
901             if debug:print "\ttoserviceparameter-name",d.tonodeparam
902             if debug:print "\tparameter-value",d.value
903             if debug:print "\tparameter-type",d.type
904             if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
905
906         self.datas=datas
907
908     def parseService(self,s):
909         service=Service()
910         service.name=s.findtext("service-name")
911         if debug:print "\tservice-name",service.name
912
913         inParameters=[]
914         for inParam in s.findall("inParameter-list/inParameter"):
915             p=Parameter()
916             p.name=inParam.findtext("inParameter-name")
917             p.type=typeName(inParam.findtext("inParameter-type"))
918             if debug:print "\tinParameter-name",p.name
919             if debug:print "\tinParameter-type",p.type
920             inParameters.append(p)
921         service.inParameters=inParameters
922         if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
923
924         outParameters=[]
925         for outParam in s.findall("outParameter-list/outParameter"):
926             p=Parameter()
927             p.name=outParam.findtext("outParameter-name")
928             p.type=typeName(outParam.findtext("outParameter-type"))
929             if debug:print "\toutParameter-name",p.name
930             if debug:print "\toutParameter-type",p.type
931             outParameters.append(p)
932         service.outParameters=outParameters
933         if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
934         return service
935
936     def parseData(self,d):
937         da=Data()
938         da.tonode=d.findtext("tonode-name")
939         da.tonodeparam=d.findtext("toserviceparameter-name")
940         da.value=d.findtext("data-value/value")
941         da.type=eval(d.findtext("data-value/value-type"))
942         if da.type < 9:
943             da.value=eval(da.value)
944         return da
945
946     def parsePyFunction(self,pyfunc):
947         if debug:print pyfunc.tag,":",pyfunc
948         if debug:print "\tFuncName",pyfunc.findtext("FuncName")
949         text=""
950         for cdata in pyfunc.findall("PyFunc"):
951             if text:text=text+'\n'
952             if cdata.text != '?':
953               text=text+ cdata.text
954         return text
955
956     """<inParameter-type>1</inParameter-type>
957     <inParameter-name>istream</inParameter-name>
958     <inParameter-dependency>2</inParameter-dependency>
959     <inParameter-schema>0</inParameter-schema>
960     <inParameter-interpolation>0</inParameter-interpolation>
961     <inParameter-extrapolation>0</inParameter-extrapolation>
962     </inParameter>
963     <outParameter>
964     <outParameter-type>1</outParameter-type>
965     <outParameter-name>ostream</outParameter-name>
966     <outParameter-dependency>2</outParameter-dependency>
967     <outParameter-values>0</outParameter-values>
968     </outParameter>
969     """
970
971     def parseInData(self,d):
972         if debug:print d.tag,":",d
973         p=Parameter()
974         p.name=d.findtext("inParameter-name")
975         p.type=typeName(d.findtext("inParameter-type"))
976         p.dependency=d.findtext("inParameter-dependency")
977         p.schema=d.findtext("inParameter-schema")
978         p.interpolation=d.findtext("inParameter-interpolation")
979         p.extrapolation=d.findtext("inParameter-extrapolation")
980         if debug:print "\tinParameter-name",p.name
981         return p
982
983     def parseOutData(self,d):
984         if debug:print d.tag,":",d
985         p=Parameter()
986         p.name=d.findtext("outParameter-name")
987         p.type=typeName(d.findtext("outParameter-type"))
988         p.dependency=d.findtext("outParameter-dependency")
989         p.values=d.findtext("outParameter-values")
990         if debug:print "\toutParameter-name",p.name
991         return p
992
993     def create_graph(self):
994       #a graph is a dict {node:neighbours}
995       #neighbours is a Set of neighbour nodes (of course)
996       #for v in graph (python >= 2.3): iterate through graph nodes 
997       #for v in graph[node] iterate through node neighbours 
998       G={}
999       #create all nodes without neighbours
1000       for n in self.nodes:
1001         G[n]=Set()
1002
1003       #calculate neighbours with links
1004       for link in self.links:
1005         from_node=self.node_dict[link.from_name]
1006         if link.from_param == "Gate" or link.to_param == "Gate":
1007           #control link salome : add to_name node to neighbours
1008           if debug:print "add control link",link.from_name,link.to_name
1009           G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1010
1011         elif from_node.outStreams_dict.has_key(link.from_param):
1012           # datastream link : 
1013           # 1- add link in link list
1014           # 2- add in link references on from_node and to_node
1015           if debug:print "add stream link",link.from_name,link.to_name
1016           self.node_dict[link.to_name].inStreamLinks.append(link)
1017           self.node_dict[link.from_name].outStreamLinks.append(link)
1018           link.from_node=self.node_dict[link.from_name]
1019           link.to_node=self.node_dict[link.to_name]
1020
1021         else:
1022           # other salome link
1023           # if link from Loop node to EndOfLoop node, we ignore it
1024           # all others are kept
1025           from_node=self.node_dict[link.from_name]
1026           to_node=self.node_dict[link.to_name]
1027           if isinstance(to_node,LoopNode):
1028             # If it's the link from EndOfLoop to Loop , we ignore it
1029             if to_node.coupled_node == from_node.name:
1030               if debug:print "backlink loop:",from_node,to_node
1031               #ignored
1032               continue
1033           if debug:print "add dataflow link",link.from_name,link.to_name
1034           G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
1035
1036           if link.from_param != "DoLoop" and link.to_param != "DoLoop":
1037             #Links on DoLoop are used by Salome supervisor. We ignore them.
1038             #Add in the link references on nodes (from_node and to_node)
1039             #Add this link into the list of links of to_node node.
1040             self.node_dict[link.to_name].links.append(link)
1041             link.from_node=self.node_dict[link.from_name]
1042             link.to_node=self.node_dict[link.to_name]
1043
1044           #In a Salome graph with loops, head node and end node are connected 
1045           #with 2 opposite links 
1046           #Store the endloop in attribute endloop of head node.
1047           if link.from_param == "DoLoop" and link.to_param == "DoLoop" \
1048              and is_loop(self.node_dict[link.from_name]) \
1049              and isinstance(self.node_dict[link.to_name],InlineNode):
1050             #Store the end loop inline node in attribute endloop
1051             #self.node_dict[link.to_name] is the end node of the head loop node self.node_dict[link.from_name]
1052             if debug:print "add loop",link.from_name,link.to_name
1053             self.node_dict[link.from_name].endloop=self.node_dict[link.to_name]
1054             self.node_dict[link.to_name].loop=self.node_dict[link.from_name]
1055
1056       for data in self.datas:
1057         if debug:print "datas",data
1058         self.node_dict[data.tonode].datas.append(data)
1059
1060       self.G=G
1061
1062       #Transform the graph in place
1063       # Transform one level loops in hierarchical graph
1064       self.reduceLoop()
1065
1066       #Return the hierarchical graph that can be transform into YACS objects.
1067       return G
1068
1069     def display(self,suivi="sync"):
1070         """Display Salome proc with graphviz (dot file)"""
1071         #to display : dot -Tpng salome.dot |display
1072         f=file("salome.dot", 'w')
1073         self.write_dot(f)
1074         f.close()
1075         cmd="dot -Tpng salome.dot |display" + (suivi == "async" and "&" or "")
1076         os.system(cmd)
1077
1078     def write_dot(self,stream):
1079         """Dump Salome proc into stream with dot format"""
1080         stream.write('digraph %s {\nnode [ style="filled" ]\n' % self.name)
1081         for node in self.nodes:
1082             label = "%s:%s"% (node.name,node.__class__.__name__)
1083             color='green'
1084             stream.write('   %s [fillcolor="%s" label=< %s >];\n' % (
1085                     id(node), color, label
1086                 ))
1087         for link in self.links:
1088             from_node=self.node_dict[link.from_name]
1089             to_node=self.node_dict[link.to_name]
1090             stream.write('   %s -> %s;\n' % (id(from_node), id(to_node)))
1091         stream.write("}\n")
1092
1093
1094 def main():
1095   import traceback
1096   usage ="""Usage: %s salomeFile convertedFile
1097     where salomeFile is the name of the input schema file (old Salome syntax)
1098     and convertedFile is the name of the output schema file (new YACS syntax)
1099     """
1100   try:
1101     salomeFile=sys.argv[1]
1102     convertedFile=sys.argv[2]
1103   except :
1104     print usage%(sys.argv[0])
1105     sys.exit(3)
1106
1107   SALOMERuntime.RuntimeSALOME_setRuntime()
1108   loader=SalomeLoader()
1109
1110   try:
1111     p= loader.load(salomeFile)
1112     s= pilot.SchemaSave(p)
1113     s.save(convertedFile)
1114   except:
1115     traceback.print_exc(file=sys.stdout)
1116     f=open(convertedFile,'w')
1117     f.write("<proc></proc>\n")
1118     sys.exit(2)
1119
1120   logger=p.getLogger("parser")
1121   if not logger.isEmpty():
1122     print logger.getStr()
1123     sys.exit(1)
1124
1125 if __name__ == "__main__":
1126   main()