1 # -*- coding: iso-8859-1 -*-
2 """Ce module sert pour lire un schema de calcul Salome décrit en XML.
3 et le convertir en schema de calcul YACS
5 Cette lecture est réalisée au moyen de la classe SalomeLoader
11 import cElementTree as ElementTree
16 class UnknownKind(Exception):pass
26 #Les fonctions suivantes : invert, reachable,InducedSubgraph,write_dot,display
27 #permettent de realiser des operations sur un graphe.
28 #Est considere comme un graphe un objet G qui supporte les
29 #operations suivantes : l'iteration sur les noeuds (for n in G parcourt
30 #tous les noeuds du graphe) et l'iteration sur les suivants
31 # (for v in G[n] parcourt tous les suivants du noeud n)
33 """Construit le graphe inverse de G en inversant les liens de voisinage"""
38 I.setdefault(v,Set()).add(n)
42 """Construit le set de noeuds atteignables depuis le noeud n
44 Le noeud n n'est pas dans le set retourné sauf en cas de boucles
45 Ce cas n'est pas traité ici (limitation)
52 def InducedSubgraph(V,G,adjacency_list_type=Set):
53 """ Construit un sous graphe de G avec les noeuds contenus dans V """
58 return dict([(x,adjacency_list_type(neighbors(x))) for x in G if x in V])
60 def write_dot(stream,G):
61 """Ecrit la representation (au format dot) du graphe G dans le fichier stream"""
63 stream.write('digraph %s {\nnode [ style="filled" ]\n' % name)
66 label = "%s:%s"% (node.name,node.__class__.__name__)
70 stream.write(' %s [fillcolor="%s" label=< %s >];\n' % ( id(node), color, label))
73 stream.write(' %s -> %s;\n' % (id(src), id(dst)))
76 def display(G,suivi="sync"):
77 """Affiche le graphe G avec l'outil dot"""
78 f=file("graph.dot", 'w')
81 cmd="dot -Tpng graph.dot |display" + (suivi == "async" and "&" or "")
98 print reachable(G,2) & reachable(I,6)
100 #Fin des fonctions graphe
105 """Loader de schéma Salome natif et convertisseur en schéma 'nouvelle formule'.
106 La méthode loadxml parse le fichier xml et retourne un objet SalomeProc
108 La méthode load parse le fichier xml et retourne un objet représentant
109 un schéma Salome converti (objet Proc de YACS)
112 def loadxml(self,filename):
114 Lit un fichier XML du SUPERV de Salome et retourne la liste des
115 procedures (instances de SalomeProc)
117 tree = ElementTree.ElementTree(file=filename)
118 root = tree.getroot()
119 if debug:print "root.tag:",root.tag,root
122 if root.tag == "dataflow":
125 if debug:print dataflow
126 proc=SalomeProc(dataflow)
129 #un ou plusieurs dataflow. Le schema contient des macros.
130 # Toutes les macros sont
131 #décrites au meme niveau dans le fichier XML.
132 for dataflow in root.findall("dataflow"):
133 if debug:print dataflow
134 proc=SalomeProc(dataflow)
135 if debug:print "nom du dataflow:",proc.name
139 def load(self,filename):
140 """Lit un fichier XML et convertit les procedures lues en procedures
144 procs=self.loadxml(filename)
145 #on récupère le schema de tete d'un coté et les éventuelles
146 #macros de l'autre: procs[0]
150 #Enregistrement des éventuelles macros dans macro_dict
153 if debug:print "proc_name:",p.name,"coupled_node:",p.coupled_node
156 if debug:print filename
157 yacsproc=ProcNode(proc,macro_dict)
158 return yacsproc.createNode()
161 """Classe pour porter les caractéristiques d'un service"""
163 """Classe pour porter les caractéristiques d'un parametre"""
165 """Classe pour porter les caractéristiques d'un link"""
167 """Classe pour porter les caractéristiques d'un data"""
170 """Node de calcul simple : classe de base à spécialiser """
173 self.links=[] # liste pour stocker les entrees sous forme de link
174 # le link doit avoir deux attributs : from_node qui donne le node origine
175 # et to_node qui donne le node cible
177 self.inStreamLinks=[] #liste des liens dataStream associés à ce node (in)
178 self.outStreamLinks=[] #liste des liens dataStream associés à ce node (out)
179 def createNode(self):
180 raise NotImplementedError
181 def getInputPort(self,p):
182 return self.node.getInputPort(".".join(p.split("__")))
183 def getOutputPort(self,p):
184 return self.node.getOutputPort(".".join(p.split("__")))
185 def getInputDataStreamPort(self,p):
186 return self.node.getInputDataStreamPort(p)
187 def getOutputDataStreamPort(self,p):
188 return self.node.getOutputDataStreamPort(p)
190 class InlineNode(Node):
191 """Node de calcul inline salome : fonction dans self.codes[0]"""
195 def createNode(self):
196 r = pilot.getRuntime()
197 if self.fnames[0] == "?":
198 n=r.createScriptNode("",self.name)
200 n=r.createFuncNode("",self.name)
201 n.setFname(self.fnames[0])
202 n.setScript(self.codes[0])
204 for para in self.service.inParameters:
205 if not typeMap.has_key(para.type):
206 #create the missing type and add it in type map
207 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
208 currentProc.typeMap[para.type]=typeMap[para.type]
209 n.edAddInputPort(para.name,typeMap[para.type])
210 for para in self.service.outParameters:
211 if not typeMap.has_key(para.type):
212 #create the missing type and add it in type map
213 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
214 currentProc.typeMap[para.type]=typeMap[para.type]
215 n.edAddOutputPort(para.name,typeMap[para.type])
219 class ComputeNode(Node):
220 """Node de calcul pour exécuter un service Salome"""
221 def createNode(self):
222 r = pilot.getRuntime()
223 n=r.createCompoNode("",self.name)
224 n.setRef(self.sComponent)
225 n.setMethod(self.service.name)
228 #ajout des ports in et out du service
229 for para in self.service.inParameters:
230 if not typeMap.has_key(para.type):
231 #on cree le type manquant et on l'ajoute dans la table des types
232 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
233 currentProc.typeMap[para.type]=typeMap[para.type]
234 n.edAddInputPort(para.name,typeMap[para.type])
235 for para in self.service.outParameters:
236 if not typeMap.has_key(para.type):
237 #on cree le type manquant et on l'ajoute dans la table des types
238 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
239 currentProc.typeMap[para.type]=typeMap[para.type]
240 pout=n.edAddOutputPort(para.name,typeMap[para.type])
242 #ajout des ports datastream in et out
243 for para in self.inStreams:
244 if debug:print para.name,para.type,para.dependency,para.schema, para.interpolation,
245 if debug:print para.extrapolation
246 pin=n.edAddInputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
247 for para in self.outStreams:
248 if debug:print para.name,para.type,para.dependency,para.values
249 pout=n.edAddOutputDataStreamPort(para.name,typeMap[streamTypes[para.type]])
253 class ComposedNode(Node):
254 """Node de calcul composite Salome (classe de base)"""
256 def reduceLoop(self):
257 """Transforme un graphe de type Salome avec les boucles
258 a plat en un graphe hierarchique
259 Le graphe de depart (Salome) est dans self.G.
260 On le transforme en place
264 #calcul du graphe inverse
268 #on recherche toutes les boucles et leurs noeuds internes
273 loops[n]=reachable(G,n)&reachable(I,n.endloop)
274 n.inner_nodes=loops[n]
275 n.G=InducedSubgraph(loops[n],G)
277 if debug:print "toutes les boucles du graphe"
280 #on recherche les boucles les plus externes
281 outer_loops=loops.keys()
283 for ll in outer_loops:
284 if loops[l] < loops[ll]:
286 outer_loops.remove(l)
290 #a la fin, les boucles restantes dans outer_loops sont les plus externes
291 if debug:print outer_loops
293 #on supprime les noeuds internes des boucles les plus externes
294 for l in outer_loops:
295 #on enleve les noeuds internes
298 #on enleve le noeud endloop
301 #on remplace les noeuds suivants de loop par ceux de endloop
304 #on tente de transformer les liens entrants et sortants sur le noeud endloop
305 #en noeuds directs. On ne traite probablement pas tous les cas.
307 for link in l.endloop.links:
308 if debug:print link.from_node,link.to_node,link.from_param,link.to_param
309 inputs[link.to_param]=link.from_node,link.from_param
313 if link.from_node == l.endloop:
314 link.from_node,link.from_param=inputs[link.from_param]
315 if debug:print link.from_node,link.to_node,link.from_param,link.to_param
319 #on applique le traitement de reduction aux boucles les plus externes (recursif)
320 for l in outer_loops:
323 def connect_macros(self,macro_dict):
324 """Cette methode rattache les macros salome contenues dans macro_dict
325 a la procedure YACS proc
326 On est ici dans le noeud auquel on veut rattacher une des macros
327 macro_dict est un dictionnaire dont la cle est le nom de la macro
328 et la valeur est un graphe Salome (objet SalomeProc)
329 Les noeuds concernes sont les MacroNode et les SalomeProc
331 if debug:print "connect_macros",self.node,macro_dict
333 if isinstance(node,MacroNode):
334 #c'est une macro, il faut rattacher sa description
335 #p est le sous graphe Salome (objet SalomeProc)
336 #node est le MacroNode Salome qui utilise le sous graphe p
337 #node.node est le bloc YACS equivalent
338 p=macro_dict[node.coupled_node]
340 if debug:print "macronode:",node.name,node.coupled_node,p
341 #a partir de la procédure salome a plat on cree un
342 #graphe d'exécution hiérarchique nouvelle formule
346 #chaque noeud du graphe G cree un noeud YACS equivalent
350 #on demande le rattachement des macros aux nodes du macroNode node
351 node.connect_macros(macro_dict)
353 #on ajoute les liens de controle
356 bloc.edAddCFLink(n.node,v.node)
357 #on ajoute les liens de donnees et les initialisations
361 bloc.edAddLink(l.from_node.getOutputPort(l.from_param),
362 l.to_node.getInputPort(l.to_param))
364 for l in n.outStreamLinks:
365 pout=l.from_node.getOutputDataStreamPort(l.from_param)
366 pin=l.to_node.getInputDataStreamPort(l.to_param)
367 bloc.edAddLink(pout,pin)
372 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
375 n.getInputPort(l.tonodeparam).edInitInt(l.value)
377 class LoopNode(ComposedNode):
378 """Objet qui simule le comportement d'une boucle Salome."""
380 ComposedNode.__init__(self)
382 #inner_nodes contient les noeuds internes au sens Salome (a plat
383 #avec les noeuds endloop)
386 def set_node(self,node):
389 def set_inner(self,loop):
390 for i in self.inner_loops:
391 if loop.inner_nodes < i.inner_nodes:
392 #la boucle est contenue dans i
395 self.inner_loops.append(loop)
397 def createNode(self):
398 """Cree l'objet boucle equivalent
400 Un objet boucle Salome a n ports d'entrée et les memes ports en sortie.
401 La tete de boucle a 3 fonctions : init, next, more qui ont des signatures
402 tres voisines. init et next ont la meme signature : en entree les parametres
403 d'entree de la boucle et en sortie les parametres de sortie de la boucle c'est
404 à dire les memes qu'en entrée. more a les memes parametres d'entree et a un
405 parametre de sortie supplementaire qui vient en premiere position. Ce
406 parametre indique si la boucle doit etre poursuivie ou stoppée.
407 La fin de boucle a une fonction qui a la meme signature que next.
409 Pour transformer ce type de boucle, on crée un ensemble de noeuds de calcul
410 regroupés dans un bloc. Dans ce bloc, on crée un noeud externe pour init suivi
412 Ensuite on crée un bloc qui contiendra 2 noeuds (next et more) plus tous
413 les noeuds internes de la boucle.
416 r = pilot.getRuntime()
417 bloop=r.createBloc(self.name)
420 init=r.createFuncNode("","init")
422 init.setScript(self.codes[0])
423 init.setFname(self.fnames[0])
424 for para in self.service.inParameters:
425 if not typeMap.has_key(para.type):
426 #create the missing type and add it in type map
427 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
428 currentProc.typeMap[para.type]=typeMap[para.type]
429 init.edAddInputPort(para.name,typeMap[para.type])
430 for para in self.service.outParameters:
431 if not typeMap.has_key(para.type):
432 #create the missing type and add it in type map
433 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
434 currentProc.typeMap[para.type]=typeMap[para.type]
435 init.edAddOutputPort(para.name,typeMap[para.type])
436 bloop.edAddChild(init)
439 wh=r.createWhileLoop(self.name)
441 blnode=r.createBloc(self.name)
443 cport=wh.edGetConditionPort()
444 cport.edInitBool(True)
447 next=r.createFuncNode("","next")
449 next.setScript(self.codes[2])
450 next.setFname(self.fnames[2])
451 for para in self.service.inParameters:
452 if not typeMap.has_key(para.type):
453 #create the missing type and add it in type map
454 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
455 currentProc.typeMap[para.type]=typeMap[para.type]
456 next.edAddInputPort(para.name,typeMap[para.type])
457 for para in self.service.outParameters:
458 if not typeMap.has_key(para.type):
459 #create the missing type and add it in type map
460 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
461 currentProc.typeMap[para.type]=typeMap[para.type]
462 next.edAddOutputPort(para.name,typeMap[para.type])
463 blnode.edAddChild(next)
467 more=r.createFuncNode("","more")
469 more.setScript(self.codes[1])
470 more.setFname(self.fnames[1])
471 for para in self.service.inParameters:
472 if not typeMap.has_key(para.type):
473 #create the missing type and add it in type map
474 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
475 currentProc.typeMap[para.type]=typeMap[para.type]
476 more.edAddInputPort(para.name,typeMap[para.type])
477 more.edAddOutputPort("DoLoop",typeMap["int"])
478 for para in self.service.outParameters:
479 if not typeMap.has_key(para.type):
480 #create the missing type and add it in type map
481 typeMap[para.type]= currentProc.createInterfaceTc("",para.type,[])
482 currentProc.typeMap[para.type]=typeMap[para.type]
483 more.edAddOutputPort(para.name,typeMap[para.type])
484 blnode.edAddChild(more)
487 for para in self.service.outParameters:
488 bloop.edAddDFLink(init.getOutputPort(para.name),next.getInputPort(para.name))
490 for para in self.service.outParameters:
491 blnode.edAddDFLink(next.getOutputPort(para.name),more.getInputPort(para.name))
493 wh.edAddLink(more.getOutputPort("DoLoop"),wh.getInputPort("condition"))
495 for para in self.service.outParameters:
496 wh.edAddLink(more.getOutputPort(para.name),next.getInputPort(para.name))
502 blnode.edAddChild(node)
506 blnode.edAddCFLink(n.node,v.node)
510 print l.from_node.name,l.to_node.name
511 print l.from_param,l.to_param
512 blnode.edAddDFLink(l.from_node.getOutputPort(l.from_param),
513 l.to_node.getInputPort(l.to_param))
517 def getInputPort(self,p):
518 return self.init.getInputPort(p)
520 def getOutputPort(self,p):
521 return self.more.getOutputPort(p)
523 class Bloc(ComposedNode):
524 """ Objet composé d'un ensemble de nodes enchaines et qui se
525 comporte comme un node simple.
532 def addLink(self,node1,node2):
533 if node1 not in self.nodes:self.nodes.append(node1)
534 if node2 not in self.nodes:self.nodes.append(node2)
536 class MacroNode(Bloc):
537 """Objet qui représente une Macro Salome c'est a dire un node
538 composite avec une interface : ports in et out.
540 def createNode(self):
541 """Cree l'objet correspondant a une Macro Salome : un Bloc"""
542 r = pilot.getRuntime()
543 macro=r.createBloc(self.name)
548 """Indique si n est un node de début de boucle"""
549 return isinstance(n,LoopNode)
551 class ProcNode(ComposedNode):
552 """Procedure YACS equivalente a une procedure Salome accompagnee
555 def __init__(self,proc,macro_dict):
556 ComposedNode.__init__(self)
558 self.macro_dict=macro_dict
560 def createNode(self):
561 """Cree l'objet YACS equivalent"""
563 r = pilot.getRuntime()
565 #create_graph retourne un graphe representatif de la
566 #procedure Salome transformee en un graphe hierarchique
567 G=self.proc.create_graph()
570 #on utilise le graphe G pour construire la
571 #procedure YACS equivalente p
575 typeMap["double"]=p.typeMap["double"]
576 typeMap["int"]=p.typeMap["int"]
577 typeMap["long"]=p.typeMap["int"]
578 typeMap["string"]=p.typeMap["string"]
579 typeMap["bool"]=p.typeMap["bool"]
580 typeMap["Unknown"]=p.createInterfaceTc("","Unknown",[])
581 typeMap["GEOM_Object"]=p.createInterfaceTc("","GEOM_Object",[])
582 typeMap["GEOM_Shape"]=typeMap["GEOM_Object"]
583 typeMap["CALCIUM_int"]=p.createInterfaceTc("","CALCIUM_int",[])
584 typeMap["CALCIUM_real"]=p.createInterfaceTc("","CALCIUM_real",[])
585 currentProc.typeMap["Unknown"]=typeMap["Unknown"]
586 currentProc.typeMap["GEOM_Object"]=typeMap["GEOM_Object"]
587 currentProc.typeMap["GEOM_Shape"]=typeMap["GEOM_Shape"]
588 currentProc.typeMap["CALCIUM_int"]=typeMap["CALCIUM_int"]
589 currentProc.typeMap["CALCIUM_real"]=typeMap["CALCIUM_real"]
592 #chaque noeud du graphe G cree un noeud YACS equivalent
596 #on demande le rattachement des macros aux nodes de la procédure p
597 self.connect_macros(self.macro_dict)
599 #on ajoute les liens de controle
602 p.edAddCFLink(n.node,v.node)
604 #on ajoute les liens de donnees et les initialisations
608 print l.from_node.name,l.to_node.name
609 print l.from_param,l.to_param
610 p.edAddLink(l.from_node.getOutputPort(l.from_param),
611 l.to_node.getInputPort(l.to_param))
614 for l in n.outStreamLinks:
615 pout=l.from_node.getOutputDataStreamPort(l.from_param)
616 pin=l.to_node.getInputDataStreamPort(l.to_param)
617 p.edAddLink(pout,pin)
622 n.getInputPort(l.tonodeparam).edInitDbl(l.value)
625 n.getInputPort(l.tonodeparam).edInitInt(l.value)
630 class SalomeProc(ComposedNode):
631 """Objet pour décrire un schéma Salome natif avec ses liens
632 dataflow, datastream et gate
633 L'objet est construit en parsant un fichier XML
635 def __init__(self,dataflow):
638 #self.links : liste des liens dataflow du graphe (objets Link)
639 #self.nodes : liste des noeuds du graphe
640 #self.node_dict : le dictionnaire des noeuds (nom,node)
641 #self.datas : liste des datas du graphe
642 #chaque noeud a 2 listes de liens datastream (inStreams, outStreams)
644 def parse(self,dataflow):
645 if debug:print "Tous les noeuds XML"
646 for node in dataflow:
647 if debug:print node.tag,node
649 #Récupération des informations du dataflow
650 self.dataflow_info=self.parseService(dataflow.find("info-list/node/service"))
651 if debug:print self.dataflow_info
652 if debug:print self.dataflow_info.inParameters
653 if debug:print self.dataflow_info.outParameters
655 for para in self.dataflow_info.inParameters:
656 print "inParam:",para.name,para.name.split("__",1)
658 self.name=dataflow.findtext("info-list/node/node-name")
659 self.coupled_node=dataflow.findtext("info-list/node/coupled-node")
661 if debug:print "Tous les noeuds XML dataflow/node-list"
664 #on parcourt tous les noeuds
665 for n in dataflow.findall('node-list/node'):
666 #n est un node de node-list
667 kind=n.findtext("kind")
668 comp=n.find("component-name").text
669 name=n.find("node-name").text
670 coupled_node=n.find("coupled-node").text
671 interface=n.find("interface-name").text
672 container=n.find("container").text
676 #kind=9 : schema avec datastream ?
679 #Il s'agit d'un service
682 node.sComponent = comp
683 node.interface=interface
685 #il s'agit d'une fonction
690 for pyfunc in n.findall("PyFunction-list/PyFunction"):
691 fnames.append(pyfunc.findtext("FuncName"))
692 codes.append(self.parsePyFunction(pyfunc))
696 #si kind vaut 4 on a une boucle : on crée un LoopNode
697 #les fonctions python (next, more, init) sont stockées dans codes
702 for pyfunc in n.findall("PyFunction-list/PyFunction"):
703 fnames.append(pyfunc.findtext("FuncName"))
704 codes.append(self.parsePyFunction(pyfunc))
708 #noeud de fin de boucle : on crée un InlineNode
713 for pyfunc in n.findall("PyFunction-list/PyFunction"):
714 fnames.append(pyfunc.findtext("FuncName"))
715 codes.append(self.parsePyFunction(pyfunc))
719 #si kind vaut 10 on a un noeud Macro : on cree un MacroNode
723 raise UnknownKind,kind
726 node.container=container
728 node.coupled_node=coupled_node
729 #on stocke les noeuds dans un dictionnaire pour faciliter les recherches
730 node_dict[node.name]=node
731 if debug:print "\tnode-name",node.name
732 if debug:print "\tkind",node.kind,node.__class__.__name__
733 if debug:print "\tcontainer",node.container
737 node.service=self.parseService(s)
740 #on parcourt les ports datastream
741 if debug:print "DataStream"
743 for indata in n.findall("DataStream-list/inParameter"):
744 inStreams.append(self.parseInData(indata))
745 node.inStreams=inStreams
748 for outdata in n.findall("DataStream-list/outParameter"):
749 p=self.parseOutData(outdata)
751 outStreams_dict[p.name]=p
752 node.outStreams=outStreams
753 node.outStreams_dict=outStreams_dict
754 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
758 self.node_dict=node_dict
759 #Le parcours des noeuds est fini.
760 #On parcourt les connexions dataflow et datastream
763 <fromnode-name>Node_A_1</fromnode-name>
764 <fromserviceparameter-name>a_1</fromserviceparameter-name>
765 <tonode-name>Node_B_1</tonode-name>
766 <toserviceparameter-name>b_1</toserviceparameter-name>
770 if debug:print "Tous les noeuds XML dataflow/link-list"
772 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
773 for link in dataflow.findall('link-list/link'):
775 l.from_name=link.findtext("fromnode-name")
776 l.to_name=link.findtext("tonode-name")
777 l.from_param=link.findtext("fromserviceparameter-name")
778 l.to_param=link.findtext("toserviceparameter-name")
780 if debug:print "\tfromnode-name",l.from_name
781 if debug:print "\tfromserviceparameter-name",l.from_param
782 if debug:print "\ttonode-name",l.to_name
783 if debug:print "\ttoserviceparameter-name",l.to_param
784 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
787 if debug:print "Tous les noeuds XML dataflow/data-list"
789 for data in dataflow.findall('data-list/data'):
790 d=self.parseData(data)
792 if debug:print "\ttonode-name",d.tonode
793 if debug:print "\ttoserviceparameter-name",d.tonodeparam
794 if debug:print "\tparameter-value",d.value
795 if debug:print "\tparameter-type",d.type
796 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
800 def parseService(self,s):
802 service.name=s.findtext("service-name")
803 if debug:print "\tservice-name",service.name
806 for inParam in s.findall("inParameter-list/inParameter"):
808 p.name=inParam.findtext("inParameter-name")
809 p.type=inParam.findtext("inParameter-type")
810 if debug:print "\tinParameter-name",p.name
811 if debug:print "\tinParameter-type",p.type
812 inParameters.append(p)
813 service.inParameters=inParameters
814 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
817 for outParam in s.findall("outParameter-list/outParameter"):
819 p.name=outParam.findtext("outParameter-name")
820 p.type=outParam.findtext("outParameter-type")
821 if debug:print "\toutParameter-name",p.name
822 if debug:print "\toutParameter-type",p.type
823 outParameters.append(p)
824 service.outParameters=outParameters
825 if debug:print "\t++++++++++++++++++++++++++++++++++++++++++++"
828 def parseData(self,d):
830 da.tonode=d.findtext("tonode-name")
831 da.tonodeparam=d.findtext("toserviceparameter-name")
832 da.value=d.findtext("data-value/value")
833 da.type=eval(d.findtext("data-value/value-type"))
835 da.value=eval(da.value)
838 def parsePyFunction(self,pyfunc):
839 if debug:print pyfunc.tag,":",pyfunc
840 if debug:print "\tFuncName",pyfunc.findtext("FuncName")
842 for cdata in pyfunc.findall("PyFunc"):
843 if text:text=text+'\n'
844 text=text+ cdata.text
847 """<inParameter-type>1</inParameter-type>
848 <inParameter-name>istream</inParameter-name>
849 <inParameter-dependency>2</inParameter-dependency>
850 <inParameter-schema>0</inParameter-schema>
851 <inParameter-interpolation>0</inParameter-interpolation>
852 <inParameter-extrapolation>0</inParameter-extrapolation>
855 <outParameter-type>1</outParameter-type>
856 <outParameter-name>ostream</outParameter-name>
857 <outParameter-dependency>2</outParameter-dependency>
858 <outParameter-values>0</outParameter-values>
862 def parseInData(self,d):
863 if debug:print d.tag,":",d
865 p.name=d.findtext("inParameter-name")
866 p.type=d.findtext("inParameter-type")
867 p.dependency=d.findtext("inParameter-dependency")
868 p.schema=d.findtext("inParameter-schema")
869 p.interpolation=d.findtext("inParameter-interpolation")
870 p.extrapolation=d.findtext("inParameter-extrapolation")
871 if debug:print "\tinParameter-name",p.name
874 def parseOutData(self,d):
875 if debug:print d.tag,":",d
877 p.name=d.findtext("outParameter-name")
878 p.type=d.findtext("outParameter-type")
879 p.dependency=d.findtext("outParameter-dependency")
880 p.values=d.findtext("outParameter-values")
881 if debug:print "\toutParameter-name",p.name
884 def create_graph(self):
885 #un graphe est un dictionnaire dont la clé est un noeud et la valeur
886 #est la liste (en fait un set sans doublon) des noeuds voisins suivants
887 #for v in graphe (python >= 2.3): parcourt les noeuds du graphe
888 #for v in graphe[noeud] parcourt les voisins (suivants) de noeud
890 #on cree tous les noeuds avec un voisinage (suivants) vide
894 #on construit le voisinage en fonction des divers liens
895 for link in self.links:
896 from_node=self.node_dict[link.from_name]
897 if link.from_param == "Gate" or link.to_param == "Gate":
898 #control link salome : on ajoute le noeud to_name dans les voisins
899 if debug:print "ajout control link",link.from_name,link.to_name
900 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
902 elif from_node.outStreams_dict.has_key(link.from_param):
903 #lien datastream salome :
904 # 1- on ajoute le lien dans les listes de liens des noeuds
905 # 2- on ajoute dans le lien des pointeurs sur les noeuds (from_node et to_node)
906 if debug:print "ajout stream link",link.from_name,link.to_name
907 self.node_dict[link.to_name].inStreamLinks.append(link)
908 self.node_dict[link.from_name].outStreamLinks.append(link)
909 link.from_node=self.node_dict[link.from_name]
910 link.to_node=self.node_dict[link.to_name]
914 #si c'est un lien entre Loop node et EndOfLoop node, on l'ignore
915 #tous les autres sont conservés
916 from_node=self.node_dict[link.from_name]
917 to_node=self.node_dict[link.to_name]
918 if isinstance(to_node,LoopNode):
919 #Est-ce le lien entre EndOfLoop et Loop ? Si oui, on ne le garde pas
920 if to_node.coupled_node == from_node.name:
921 if debug:print "lien arriere loop:",from_node,to_node
924 if debug:print "ajout dataflow link",link.from_name,link.to_name
925 G[self.node_dict[link.from_name]].add(self.node_dict[link.to_name])
927 if link.from_param != "DoLoop" and link.to_param != "DoLoop":
928 #Les liens sur parametre DoLoop servent au superviseur Salome, on les ignore
929 #on ajoute dans le lien des pointeurs sur les noeuds (from_node et to_node)
930 #on ajoute ce lien à la liste des liens du noeud cible (to)
931 self.node_dict[link.to_name].links.append(link)
932 link.from_node=self.node_dict[link.from_name]
933 link.to_node=self.node_dict[link.to_name]
935 #Dans un graphe salome avec boucles, les noeuds de tete et de fin
936 #de boucle sont reliés par 2 liens de sens opposés
937 #on stocke le noeud de fin dans l'attribut endloop du noeud de tete.
938 if link.from_param == "DoLoop" and link.to_param == "DoLoop" \
939 and is_loop(self.node_dict[link.from_name]) \
940 and isinstance(self.node_dict[link.to_name],InlineNode):
941 #on repère le node inline de fin de boucle en le stockant
942 #dans l'attribut endloop du node loop
943 #self.node_dict[link.to_name] est le node de fin de boucle
944 #de self.node_dict[link.from_name]
945 if debug:print "ajout loop",link.from_name,link.to_name
946 self.node_dict[link.from_name].endloop=self.node_dict[link.to_name]
947 self.node_dict[link.to_name].loop=self.node_dict[link.from_name]
949 for data in self.datas:
950 self.node_dict[data.tonode].datas.append(data)
954 #on modifie le graphe en place :
955 # transformation des boucles a plat en graphe hierarchique
958 #on peut maintenant créer le schéma de calcul YACS
961 def display(self,suivi="sync"):
962 """Visualise la procedure Salome avec dot"""
963 #pour visualiser : dot -Tpng salome.dot |display
964 f=file("salome.dot", 'w')
967 cmd="dot -Tpng salome.dot |display" + (suivi == "async" and "&" or "")
970 def write_dot(self,stream):
971 """Dumpe la procedure Salome dans stream au format dot"""
972 stream.write('digraph %s {\nnode [ style="filled" ]\n' % self.name)
973 for node in self.nodes:
974 label = "%s:%s"% (node.name,node.__class__.__name__)
976 stream.write(' %s [fillcolor="%s" label=< %s >];\n' % (
977 id(node), color, label
979 for link in self.links:
980 from_node=self.node_dict[link.from_name]
981 to_node=self.node_dict[link.to_name]
982 stream.write(' %s -> %s;\n' % (id(from_node), id(to_node)))
985 if __name__ == "__main__":
988 usage ="""Usage: %s salomeFile convertedFile
989 where salomeFile is the name of the input schema file (old Salome syntax)
990 and convertedFile is the name of the output schema file (new YACS syntax)
993 salomeFile=sys.argv[1]
994 convertedFile=sys.argv[2]
996 print usage%(sys.argv[0])
999 SALOMERuntime.RuntimeSALOME_setRuntime()
1000 loader=SalomeLoader()
1003 p= loader.load(salomeFile)
1004 s= pilot.SchemaSave(p)
1005 s.save(convertedFile)
1007 traceback.print_exc()
1008 f=open(convertedFile,'w')
1009 f.write("<proc></proc>\n")