4 Définition d'un schéma de calcul avec l'interface de programmation Python
5 ============================================================================
6 Un schéma de calcul YACS peut être défini à partir d'un programme écrit en langage Python (http://www.python.org/).
7 Pour une initiation au langage, on consultera le `tutorial Python <http://docs.python.org/tut/tut.html>`_.
9 L'interface de programmation (API) est portée par trois modules Python : pilot, SALOMERuntime et loader.
11 Le module SALOMERuntime sert pour initialiser YACS pour SALOME.
13 Le module loader sert pour créer des schémas de calcul en chargeant des fichiers au format XML.
15 Le module pilot est celui qui sert à créer des schémas de calcul.
17 Ces modules doivent être importés au début du programme Python et YACS doit être initialisé::
23 SALOMERuntime.RuntimeSALOME_setRuntime()
25 Pour pouvoir importer les modules YACS, l'environnement doit être correctement configuré ce qui est le
26 cas si on utilise l'application SALOME. Sinon, il faut positionner la variable d'environnement PYTHONPATH
27 à <YACS_ROOT_DIR>/lib/lib/pythonX.Y/site-packages/salome.
31 Créer un schéma de calcul par chargement d'un fichier XML
32 --------------------------------------------------------------
33 C'est la façon la plus simple de créer un schéma de calcul. Si on a un fichier conforme à la syntaxe YACS
34 (voir :ref:`schemaxml`), il suffit de créer un chargeur de fichier XML puis d'utiliser sa méthode load
35 pour obtenir un objet schéma de calcul en Python.
37 Voici le code Python suffisant pour charger un fichier XML::
39 xmlLoader = loader.YACSLoader()
41 p = xmlLoader.load("simple1.xml")
43 print "IO exception:",ex
46 Ensuite, si on met dans un fichier de nom testLoader.py le code de l'initialisation et le code
47 du chargement, il suffit de faire::
51 pour exécuter le programme. L'exception IOError peut être levée par l'opération de chargement
52 principalement si le fichier n'existe pas ou ne peut pas être lu.
53 Dans le cas où aucune exception n'a été levé, il faut vérifier que l'analyse du fichier s'est
54 bien passée. Ceci est fait en utilisant l'objet Logger associé au schéma de calcul::
56 logger=p.getLogger("parser")
57 if not logger.isEmpty():
58 print "The imported file has errors :"
62 Enfin, si l'analyse du fichier s'est bien passée, il faut vérifier la validité du schéma (complétude
63 des connexions, pas de port d'entrée non connecté, ...). On utilise pour celà la méthode isValid de
64 l'objet schéma de calcul puis la méthode p.checkConsistency de ce même objet comme ci-dessous::
67 print "The schema is not valid and can not be executed"
68 print p.getErrorReport()
71 info=pilot.LinkInfo(pilot.LinkInfo.ALL_DONT_STOP)
72 p.checkConsistency(info)
73 if info.areWarningsOrErrors():
74 print "The schema is not consistent and can not be executed"
75 print info.getGlobalRepr()
79 Si tous ces tests se sont bien passés, le schéma est prêt à être exécuté (voir :ref:`execpy`).
81 Créer un schéma de calcul de zéro
82 -----------------------------------
83 On suivra ici la même progression que dans :ref:`schemaxml`.
85 La première chose à faire avant de créer les objets constitutifs du schéma est d'obtenir
86 l'objet runtime qui va servir pour leur création::
88 r = pilot.getRuntime()
90 Création d'un schéma vide
91 ''''''''''''''''''''''''''''
92 On l'obtient par en utilisant la méthode createProc de l'objet runtime avec le nom
93 du schéma en argument::
97 L'objet schéma de nom "pr" a été créé. Il est représenté par l'objet Python p.
99 Définition des types de données
100 '''''''''''''''''''''''''''''''''
103 On ne peut définir de type de base. Ils sont définis par YACS. Il faut cependant pouvoir
104 récupérer un objet Python équivalent à un type de base pour pouvoir créer par la suite des
107 On récupère un type de données de base en utilisant la méthode getTypeCode du schéma de calcul
108 avec le nom du type en argument. Par exemple::
110 td=p.getTypeCode("double")
112 permet d'obtenir le type double (objet Python td).
113 Les autres types de base s'obtiennent par::
115 ti=p.getTypeCode("int")
116 ts=p.getTypeCode("string")
117 tb=p.getTypeCode("bool")
118 tf=p.getTypeCode("file")
122 +++++++++++++++++++++
123 Pour définir un type référence d'objet, on utilise la méthode createInterfaceTc du schéma de calcul. Cette méthode
124 prend trois arguments : le repository id de l'objet SALOME correspondant, le nom du type, une liste de types
125 qui seront des types de base de ce type. Si le repository id vaut "", la valeur par défaut sera utilisée.
127 Voici un exemple minimal de définition de référence d'objet de nom Obj (repository id par défaut, pas de type de base)::
129 tc1=p.createInterfaceTc("","Obj",[])
131 On peut définir le même type Obj, en donnant le repository id::
133 tc1=p.createInterfaceTc("IDL:GEOM/GEOM_Object","Obj",[])
135 Pour définir un type référence d'objet dérivé d'un autre type, on fournit en plus une liste de types de base.
137 Voici la définition du type MyObj dérivé du type Obj::
139 tc2=p.createInterfaceTc("","MyObj",[tc1])
143 Pour définir un type séquence, on utilise la méthode createSequenceTc du schéma de calcul. Cette méthode
144 prend trois arguments : le repository id, le nom du type, le type des éléments de la séquence. Il n'est
145 généralement pas utile de spécifier le repository id. On donnera la valeur "".
147 Voici un exemple de définition du type séquence de double seqdbl::
149 tc3=p.createSequenceTc("","seqdbl",td)
151 td est le type double que l'on obtiendra comme ci-dessus : `Types de base`_.
153 Pour définir un type séquence de séquence, on écrit::
155 tc4=p.createSequenceTc("","seqseqdbl",tc3)
157 Pour définir un type séquence de référence, on écrit::
159 tc5=p.createSequenceTc("","seqobj",tc1)
164 Pour définir un type structure, on utilise la méthode createStructTc du schéma de calcul. Cette méthode
165 prend deux arguments : le repository id, le nom du type. Pour une utilisation standard, le repository
166 id prendra la valeur "". Le type structure est le seul qui se définit en deux étapes. Il est créé
167 vide suite à l'appel de la méthode createStructTc. Pour définir ses membres, il faut ensuite
169 Voici un exemple de définition du type structure s1 avec 2 membres (m1 et m2) de types double et séquence de doubles::
171 ts1=p.createStructTc("","s1")
172 ts1.addMember("m1",td);
173 ts1.addMember("m2",tc3);
175 Récupérer les types prédéfinis
176 +++++++++++++++++++++++++++++++++
177 Par défaut, YACS définit seulement les types de base. Pour obtenir plus de types prédéfinis, il faut
178 les demander à SALOME. Ces autres types prédéfinis sont contenus dans les catalogues des modules
181 La séquence de code qui permet d'obtenir une image des catalogues SALOME dans YACS est la suivante::
184 cata=r.loadCatalog("session","corbaname::localhost:2810/NameService#Kernel.dir/ModulCatalog.object")
185 except CORBA.TRANSIENT,ex:
186 print "Unable to contact server:",ex
187 except CORBA.SystemException,ex:
188 print ex,CORBA.id(ex)
190 Il faut que l'application SALOME ait été lancée pour que le catalogue soit accessible.
191 Ensuite, les types prédéfinis sont accessibles dans le dictionnaire cata._typeMap.
192 Si on connait le nom du type voulu ('GEOM_Shape', par exemple), on l'obtient par::
194 tgeom=cata._typeMap['GEOM_Shape']
198 Ajouter un type dans le dictionnaire des types du schéma
199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
200 Certaines opérations nécessitent d'avoir les types définis dans le dictionnaire du schéma.
201 Pour mettre un type dans le dictionnaire, on fait, par exemple pour le type seqobj défini ci-dessus::
203 p.typeMap["seqobj"]=tc5
205 avec le nom du type comme clé du dictionnaire et le type comme valeur.
207 Définition des noeuds de calcul élémentaires
208 ''''''''''''''''''''''''''''''''''''''''''''''
210 +++++++++++++++++++++
211 Pour définir un noeud script dans un contexte donné (le schéma de calcul, par exemple), on
212 procède en plusieurs étapes.
213 La première étape consiste à créer l'objet noeud par appel à la méthode createScriptNode du runtime.
214 Cette méthode a 2 arguments dont le premier doit valoir "" en utilisation standard et le deuxième
215 est le nom du noeud. Voici un exemple de création du noeud node1::
217 n=r.createScriptNode("","node1")
219 La deuxième étape consiste à rattacher le noeud à son contexte de définition par appel à la méthode
220 edAddChild de l'objet contexte. Cette méthode a un argument : le noeud à rattacher. Voici un exemple
221 de rattachement du noeud node1 au schéma de calcul::
225 Attention, le nom de la méthode à utiliser dépend du type de noeud contexte. On verra plus tard pour d'autres
226 types de noeud quelle méthode utiliser.
228 La troisième étape consiste à définir le script Python associé au noeud. On utilise pour celà la méthode setScript
229 du noeud avec un argument chaine de caractères qui contient le code Python. Voici un exemple de définition
232 n.setScript("p1=p1+2.5")
234 La quatrième étape consiste à définir les ports de données d'entrée et de sortie. Un port d'entrée est créé par appel
235 à la méthode edAddInputPort du noeud. Un port de sortie est créé par appel à la méthode edAddOutputPort du noeud.
236 Ces deux méthodes ont deux arguments : le nom du port et le type de données du port. Voici un exemple de création
237 d'un port d'entrée p1 de type double et d'un port de sortie p1 de type double::
239 n.edAddInputPort("p1",td)
240 n.edAddOutputPort("p1",td)
242 Maintenant notre noeud est complètement défini avec son nom, son script, ses ports et son contexte. Il récupère
243 un double dans le port d'entrée p1, lui ajoute 2.5 et met le résultat dans le port de sortie p1.
245 Noeud fonction Python
246 ++++++++++++++++++++++
247 Pour définir un noeud fonction, on procède de la même manière. Les seules différences concernent la création :
248 utiliser la méthode createFuncNode et la définition de la fonction : il faut en plus appeler la méthode setFname
249 pour donner le nom de la fonction à exécuter. Voici un exemple complet de définition d'un noeud fonction
250 qui est fonctionnellement identique au noeud script précédent::
252 n2=r.createFuncNode("","node2")
260 n2.edAddInputPort("p1",td)
261 n2.edAddOutputPort("p1",td)
264 Noeud de service SALOME
265 ++++++++++++++++++++++++++
266 On a deux formes de définition d'un noeud de service SALOME.
268 La première forme dans laquelle on donne le nom du composant utilise la méthode createCompoNode
269 pour la création du noeud. Le nom du composant est donné en argument de la méthode setRef du noeud.
270 Le nom du service est donné en argument de la méthode setMethod du noeud. Le reste de la définition est
271 identique à celui des noeuds Python précédents.
273 Voici un exemple de noeud qui appelle le service makeBanner d'un composant PYHELLO::
275 n3=r.createCompoNode("","node3")
278 n3.setMethod("makeBanner")
279 n3.edAddInputPort("p1",ts)
280 n3.edAddOutputPort("p1",ts)
282 La deuxième forme qui permet de définir un noeud qui utilise le même composant qu'un autre noeud
283 utilise la méthode createNode de ce dernier noeud. Cette méthode n'a qu'un argument, le nom du noeud.
284 Le reste de la définition est identique à celui de la précédente forme.
286 Voici un exemple de noeud de service qui appelle une deuxième fois le service makeBanner de la même
287 instance de composant que le noeud précédent::
289 n4=n3.createNode("node4")
291 n4.setMethod("makeBanner")
292 n4.edAddInputPort("p1",ts)
293 n4.edAddOutputPort("p1",ts)
295 Définition des connexions
296 ''''''''''''''''''''''''''''
297 Obtenir un port d'un noeud
298 ++++++++++++++++++++++++++++
299 Pour pouvoir définir des liens, il faut presque toujours disposer des objets Python représentant
300 le port de sortie à connecter au port d'entrée.
301 Il y a deux façons de disposer de cet objet.
303 La première façon est de récupérer le port lors de sa création avec les méthodes edAddInputPort et
304 edAddOutputPort. On écrira alors, par exemple::
306 pin=n4.edAddInputPort("p1",ts)
307 pout=n4.edAddOutputPort("p1",ts)
309 pin et pout sont alors les objets nécessaires pour définir des liens.
311 La deuxième façon est d'interroger le noeud et de lui demander un de ses ports par son nom. On utilise pour
312 celà les méthodes getInputPort et getOutputPort.
314 On pourra alors obtenir pin et pout comme suit::
316 pin=n4.getInputPort("p1")
317 pout=n4.getOutputPort("p1")
321 Pour définir un lien de contrôle entre deux noeuds, on utilise la méthode edAddCFLink du contexte en lui passant
322 en arguments les deux noeuds à connecter.
323 Par exemple, un lien de contrôle entre les noeuds n3 et n4 s'écrira::
327 Le noeud n3 sera exécuté avant le noeud n4.
331 Pour définir un lien dataflow, il faut tout d'abord obtenir les objets ports par une des méthodes vues
332 ci-dessus. Ensuite on utilise la méthode edAddDFLink du noeud contexte en lui passant les deux ports à connecter.
334 Voici un exemple de lien dataflow entre le port de sortie p1 du noeud n3 et le port d'entrée du noeud n4::
336 pout=n3.getOutputPort("p1")
337 pin=n4.getInputPort("p1")
338 p.edAddDFLink(pout,pin)
342 Un lien data se définit comme un lien dataflow en utilisant la méthode edAddLink au lieu de edAddDFLink.
343 Le même exemple que ci-dessus avec un lien data::
345 pout=n3.getOutputPort("p1")
346 pin=n4.getInputPort("p1")
347 p.edAddLink(pout,pin)
349 Initialisation d'un port de données d'entrée
350 '''''''''''''''''''''''''''''''''''''''''''''''
351 Pour initialiser un port de données d'entrée, il faut tout d'abord obtenir l'objet port correspondant. Ensuite, il existe
352 deux méthodes pour l'initialiser.
354 La première initialise le port avec une valeur encodée en XML-RPC. On utilise alors la méthode edInitXML du
355 port. Voici un exemple qui initialise un port avec la valeur entière 5::
357 pin.edInitXML("<value><int>5</int></value>")
359 La deuxième méthode initialise le port avec une valeur Python. On utilise alors la méthode edInitPy. Voici
360 un exemple qui initialise ce même port avec la même valeur::
364 On peut également utiliser des méthodes spécifiques pour les types de base :
366 - ``edInitInt`` pour le type int
367 - ``edInitDbl`` pour le type double
368 - ``edInitBool`` pour le type bool
369 - ``edInitString`` pour le type string
371 Premier exemple à partir des éléments précédents
372 '''''''''''''''''''''''''''''''''''''''''''''''''''
373 En rassemblant tous les éléments de définition précédents, un schéma de calcul complet identique à celui
374 du chapitre :ref:`schemaxml` se présentera comme suit::
380 SALOMERuntime.RuntimeSALOME_setRuntime()
381 r = pilot.getRuntime()
383 ti=p.getTypeCode("int")
385 n1=r.createScriptNode("","node1")
387 n1.setScript("p1=p1+10")
388 n1.edAddInputPort("p1",ti)
389 n1.edAddOutputPort("p1",ti)
391 n2=r.createScriptNode("","node2")
393 n2.setScript("p1=2*p1")
394 n2.edAddInputPort("p1",ti)
395 n2.edAddOutputPort("p1",ti)
397 n4=r.createCompoNode("","node4")
400 n4.setMethod("echoDouble")
401 n4.edAddInputPort("p1",td)
402 n4.edAddOutputPort("p1",td)
407 pout=n3.getOutputPort("p1")
408 pin=n4.getInputPort("p1")
410 p.edAddDFLink(n1.getOutputPort("p1"),n2.getInputPort("p1"))
411 p.edAddDFLink(n1.getOutputPort("p1"),n4.getInputPort("p1"))
412 #initialisation ports
413 n1.getInputPort("p1").edInitPy(5)
416 Définition de noeuds composés
417 '''''''''''''''''''''''''''''''''
420 Pour définir un Bloc, on utilise la méthode createBloc du runtime en lui passant le nom du Bloc en argument. Ensuite,
421 on rattache le noeud à son contexte de définition comme un noeud élémentaire. Voici un exemple de définition de Bloc
422 dans un schéma de calcul::
427 Une fois le Bloc créé, il est possible d'ajouter tous les noeuds et liens possibles dans son contexte. En reprenant une partie
428 de l'exemple ci-dessus, on aura::
430 n1=r.createScriptNode("","node1")
432 n1.setScript("p1=p1+10")
433 n1.edAddInputPort("p1",ti)
434 n1.edAddOutputPort("p1",ti)
435 n2=r.createScriptNode("","node2")
437 n2.setScript("p1=2*p1")
438 n2.edAddInputPort("p1",ti)
439 n2.edAddOutputPort("p1",ti)
441 b.edAddDFLink(n1.getOutputPort("p1"),n2.getInputPort("p1"))
445 Pour définir une ForLoop, on utilise la méthode createForLoop du runtime en lui passant le nom du noeud en argument.
446 Ensuite on rattache le noeud à son contexte de définition. Voici un exemple de définition de ForLoop
447 dans un schéma de calcul::
449 l=r.createForLoop("l1")
452 Pour initialiser le nombre de tours de boucle à exécuter, on utilise le port "nsteps" que l'on initialise
453 avec un entier. Par exemple::
455 ip=l.getInputPort("nsteps")
458 Il existe une méthode spéciale pour obtenir le port "nsteps" de la boucle : edGetNbOfTimesInputPort. On pourrait donc
459 l'écrire également ainsi::
461 ip=l.edGetNbOfTimesInputPort()
464 Enfin, pour ajouter un noeud (et un seul) dans le contexte d'une boucle, on n'utilisera pas la méthode edAddChild
465 mais une méthode différente de nom edSetNode. Voici un petit exemple de définition d'un noeud interne de boucle::
467 n1=r.createScriptNode("","node1")
469 n1.setScript("p1=p1+10")
470 n1.edAddInputPort("p1",ti)
471 n1.edAddOutputPort("p1",ti)
475 Un noeud WhileLoop se définit presque comme un noeud ForLoop. Les seules différences concernent la création et
476 l'affectation de la condition de fin de boucle. Pour la création on utilise la méthode createWhileLoop. Pour la
477 condition, on utilise le port "condition". Si on fait un rebouclage sur un noeud, il ne faut pas oublier d'utiliser
478 un lien data et non un lien dataflow.
479 Voici un exemple de définition de noeud WhileLoop avec un noeud interne script Python. La condition est initialisée
480 à True puis passée à False par le noeud interne. On a donc un rebouclage::
482 wh=r.createWhileLoop("w1")
484 n=r.createScriptNode("","node3")
486 n.edAddOutputPort("p1",ti)
488 cport=wh.getInputPort("condition")
489 cport.edInitBool(True)
490 p.edAddLink(n.getOutputPort("p1"),cport)
492 Il existe une méthode spéciale pour obtenir le port "condition" de la boucle : edGetConditionPort.
496 Un noeud ForEach se définit à la base comme un autre noeud boucle. Il y a plusieurs différences. Le noeud
497 est créé avec la méthode createForEachLoop qui prend un argument de plus : le type de données géré par le ForEach.
498 Le nombre de branches du ForEach est spécifié avec le port "nbBranches". La gestion de la collection sur
499 laquelle itère le ForEach est faite par connexion des ports "SmplPrt" et "SmplsCollection".
501 Voici un exemple de définition de noeud ForEach avec un noeud interne script Python qui incrémente l'élément
502 de la collection de 3.::
504 fe=r.createForEachLoop("fe1",td)
506 n=r.createScriptNode("","node3")
507 n.setScript("p1=p1+3.")
508 n.edAddInputPort("p1",td)
509 n.edAddOutputPort("p1",td)
511 p.edAddLink(fe.getOutputPort("SmplPrt"),n.getInputPort("p1"))
512 fe.getInputPort("nbBranches").edInitPy(3)
513 fe.getInputPort("SmplsCollection").edInitPy([2.,3.,4.])
515 Pour obtenir les ports spéciaux du ForEach, on peut utiliser les méthodes suivantes à la place de getInputPort et
518 - edGetNbOfBranchesPort pour le port "nbBranches"
519 - edGetSamplePort pour le port "SmplPrt"
520 - edGetSeqOfSamplesPort pour le port "SmplsCollection"
524 La définition d'un noeud Switch se fait en plusieurs étapes. Les deux premières sont la création et le rattachment
525 au noeud de contexte. Le noeud est créé par appel de la méthode createSwitch du runtime avec le nom du noeud
526 en argument. Le noeud est rattaché au noeud contexte par appel de la méthode edAddChild pour un schéma ou un bloc
527 ou edSetNode pour un noeud boucle.
529 Voici un exemple de création suivi du rattachement::
531 sw=r.createSwitch("sw1")
534 Ensuite on crée un noeud interne élémentaire ou composé par cas. Le noeud pour le cas par défaut est
535 rattaché au switch avec la méthode edSetDefaultNode. Les noeuds pour les autres cas sont rattachés au switch
536 avec la méthode edSetNode qui prend en premier argument la valeur du cas (entier) et en deuxième argument
539 Voici un exemple de switch avec un noeud script pour le cas "1" et un autre noeud script
540 pour le cas "default" et un noeud script pour initialiser une variable échangée::
543 n=r.createScriptNode("","node3")
544 n.setScript("p1=3.5")
545 n.edAddOutputPort("p1",td)
548 sw=r.createSwitch("sw1")
550 nk1=r.createScriptNode("","ncas1")
551 nk1.setScript("p1=p1+3.")
552 nk1.edAddInputPort("p1",td)
553 nk1.edAddOutputPort("p1",td)
555 ndef=r.createScriptNode("","ndefault")
556 ndef.setScript("p1=p1+5.")
557 ndef.edAddInputPort("p1",td)
558 ndef.edAddOutputPort("p1",td)
559 sw.edSetDefaultNode(ndef)
560 #initialisation port select
561 sw.getInputPort("select").edInitPy(1)
562 #connexion des noeuds internes
563 p.edAddDFLink(n.getOutputPort("p1"),nk1.getInputPort("p1"))
564 p.edAddDFLink(n.getOutputPort("p1"),ndef.getInputPort("p1"))
566 Pour obtenir le port spécial "select" du Switch, on peut utiliser la méthode edGetConditionPort à la place de getInputPort.
568 Définition de containers
569 ''''''''''''''''''''''''''''
570 Pour définir un container, on utilise la méthode createContainer du runtime puis on lui donne un nom avec sa méthode
571 setName. Enfin on lui affecte des contraintes en lui ajoutant des propriétés.
572 Voici un exemple de création d'un container de nom "A"::
574 c1=r.createContainer()
577 On ajoute une propriété à un container en utilisant sa méthode setProperty qui prend 2 arguments (chaines de caractères).
578 Le premier est le nom de la propriété. Le deuxième est sa valeur.
579 Voici un exemple du même container "A" avec des contraintes::
581 c1=r.createContainer()
583 c1.setProperty("container_name","FactoryServer")
584 c1.setProperty("hostname","localhost")
585 c1.setProperty("mem_mb","1000")
587 Une fois que les containers sont définis, on peut placer des composants SALOME sur ce container.
588 Pour placer le composant d'un noeud de service SALOME, il faut tout d'abord obtenir l'instance de
589 composant de ce noeud de service en utilisant la méthode getComponent de ce noeud. Puis on affecte le container
590 précédemment défini à cette instance de composant en utilisant la méthode setContainer de l'instance
593 Si on veut placer le service SALOME défini plus haut (noeud "node3") sur le container "A", on écrira::
595 n3.getComponent().setContainer(c1)
598 Les propriétés de noeuds
599 '''''''''''''''''''''''''''
600 On ajoute (ou modifie) une propriété à un noeud élémentaire ou composé en utilisant sa méthode
601 setProperty qui prend 2 arguments (chaines de caractères).
602 Le premier est le nom de la propriété. Le deuxième est sa valeur.
604 Voici un exemple pour le noeud "node3" précédent::
606 n3.setProperty("VERBOSE","2")
608 Les connexions datastream
609 ''''''''''''''''''''''''''''
610 Les connexions datastream ne sont possibles que pour des noeuds de service SALOME comme on l'a vu dans Principes.
611 Il faut tout d'abord définir les ports datastream dans le noeud de service. Un port datastream d'entrée se définit
612 en utilisant la méthode edAddInputDataStreamPort. Un port datastream de sortie se définit
613 en utilisant la méthode edAddOutputDataStreamPort.
614 Ces méthodes prennent en arguments le nom du port et le type du datastream.
616 Certains ports datastream (par exemple les ports CALCIUM) doivent être configurés avec des propriétés.
617 On utilise la méthode setProperty du port pour les configurer.
619 Voici un exemple de définition de noeud de service SALOME avec des ports datastream.
620 Il s'agit du composant DSCCODC que l'on peut trouver dans le module DSCCODES de la base EXAMPLES.
621 Les ports datastream sont de type "CALCIUM_integer" avec dépendance temporelle::
623 calcium_int=cata._typeMap['CALCIUM_integer']
624 n5=r.createCompoNode("","node5")
628 pin=n5.edAddInputDataStreamPort("ETP_EN",calcium_int)
629 pin.setProperty("DependencyType","TIME_DEPENDENCY")
630 pout=n5.edAddOutputDataStreamPort("STP_EN",calcium_int)
631 pout.setProperty("DependencyType","TIME_DEPENDENCY")
633 Une fois les noeuds de service dotés de ports datastream, il ne reste plus qu'à les connecter.
634 Cette connexion est réalisée en utilisant la méthode edAddLink du noeud contexte comme pour
635 les liens data. Seul le type des ports passés en arguments est différent.
637 Pour compléter notre exemple on définit un deuxième noeud de service et on connecte les
638 ports datastream de ces services::
640 n6=r.createCompoNode("","node6")
644 pin=n6.edAddInputDataStreamPort("ETP_EN",calcium_int)
645 pin.setProperty("DependencyType","TIME_DEPENDENCY")
646 pout=n6.edAddOutputDataStreamPort("STP_EN",calcium_int)
647 pout.setProperty("DependencyType","TIME_DEPENDENCY")
648 p.edAddLink(n5.getOutputDataStreamPort("STP_EN"),n6.getInputDataStreamPort("ETP_EN"))
649 p.edAddLink(n6.getOutputDataStreamPort("STP_EN"),n5.getInputDataStreamPort("ETP_EN"))
651 D'autres noeuds élémentaires
652 '''''''''''''''''''''''''''''''
655 La définition d'un noeud SalomePython est quasiment identique à celle d'un `Noeud fonction Python`_. On utilise
656 la méthode createSInlineNode du runtime à la place de createFuncNode et on ajoute une information de
657 placement sur un container comme pour un noeud de service SALOME (méthode setContainer).
659 Voici un exemple semblable à celui de :ref:`schemaxml`::
661 n2=r.createSInlineNode("","node2")
668 print __container__from__YACS__
669 machine,container=__container__from__YACS__.split('/')
670 param={'hostname':machine,'container_name':container}
671 compo=salome.lcc.LoadComponent(param, "PYHELLO")
672 print compo.makeBanner(p1)
676 n2.edAddInputPort("p1",ts)
677 n2.getComponent().setContainer(c1)
681 Pour définir un noeud DataIn, on utilise la méthode createInDataNode du runtime. Elle prend deux arguments
682 dont le premier doit être "" et le deuxième le nom du noeud.
683 Pour définir les données du noeud, on lui ajoute des ports de données de sortie avec la méthode edAddOutputPort
684 en lui passant le nom de la donnée et son type en arguments.
685 Pour initialiser la valeur de la donnée, on utilise la méthode setData du port ainsi créé en lui passant
686 la valeur encodée en XML-RPC (voir :ref:`initialisation`).
688 Voici un exemple de noeud DataIn qui définit 2 données de type double (b et c) et une donnée de type fichier (f)::
690 n=r.createInDataNode("","data1")
692 pout=n.edAddOutputPort('a',td)
693 pout.setData("<value><double>-1.</double></value>")
694 pout=n.edAddOutputPort('b',td)
695 pout.setData("<value><double>5.</double></value>")
696 pout=n.edAddOutputPort('f',tf)
697 pout.setData("<value><objref>f.data</objref></value>")
699 Il est possible d'affecter une valeur à une donnée directement avec un objet Python en utilisant
700 la méthode setDataPy. Exemple pour une séquence::
702 pout.setDataPy([1.,5.])
706 Pour définir un noeud DataOut, on utilise la méthode createOutDataNode du runtime. Elle prend deux arguments
707 dont le premier doit être "" et le deuxième le nom du noeud.
708 Pour définir les résultats du noeud, on lui ajoute des ports de données d'entrée en utilisant la
709 méthode edAddInputPort avec le nom du résultat et son type en arguments.
710 Pour sauvegarder les résultats dans un fichier on utilise la méthode setRef du noeud avec le nom
711 du fichier en argument.
712 Pour recopier un résultat fichier dans un fichier local, on utilise la méthode setData du port correspondant
713 au résultat avec le nom du fichier en argument.
715 Voici un exemple de noeud DataOut qui définit des résultats (a, b, c, d, f) de différents
716 types (double, int, string, vecteur de doubles, fichier) et écrit les valeurs correspondantes
717 dans le fichier g.data. Le fichier résultat sera copié dans le fichier local monfich::
719 n=r.createOutDataNode("","data2")
722 n.edAddInputPort('a',td)
723 n.edAddInputPort('b',ti)
724 n.edAddInputPort('c',ts)
725 n.edAddInputPort('d',tc3)
726 pin=n.edAddInputPort('f',tf)
727 pin.setData("monfich")
731 Pour définir un noeud StudyIn, on utilise la méthode createInDataNode du runtime. Elle prend deux arguments
732 dont le premier doit être "study" et le deuxième le nom du noeud.
733 Pour spécifier l'étude associée, on ajoute la propriété "StudyID" au noeud en utilisant sa méthode setProperty.
734 Pour définir les données du noeud, on lui ajoute des ports de données de sortie avec la méthode edAddOutputPort
735 en lui passant le nom de la donnée et son type en arguments.
736 Pour initialiser la donnée avec la référence dans l'étude, on utilise la méthode setData du port ainsi créé
737 en lui passant une chaine de caractères qui contient soit l'Entry SALOME soit le chemin dans l'arbre d'étude.
739 Voici un exemple de noeud StudyIn qui définit 2 données de type GEOM_Object (a et b).
740 L'étude est supposée chargée en mémoire par SALOME sous le StudyID 1.
741 La donnée a est référencée par une Entry SALOME. La donnée b est référencée par un chemin dans l'arbre d'étude::
743 n=r.createInDataNode("study","study1")
745 n.setProperty("StudyID","1")
746 pout=n.edAddOutputPort('a',tgeom)
747 pout.setData("0:1:1:1")
748 pout=n.edAddOutputPort('b',tgeom)
749 pout.setData("/Geometry/Sphere_1")
754 Pour définir un noeud StudyOut, on utilise la méthode createOutDataNode du runtime. Elle prend deux arguments
755 dont le premier doit être "study" et le deuxième le nom du noeud.
756 Pour spécifier l'étude associée, on ajoute la propriété "StudyID" au noeud en utilisant sa méthode setProperty.
757 Pour spécifier un nom de fichier dans lequel sera sauvegardée l'étude, on utilise la méthode setRef du noeud
758 avec le nom du fichier en argument.
759 Pour définir les résultats du noeud, on lui ajoute des ports de données d'entrée avec la méthode edAddInputPort
760 en lui passant le nom de la donnée et son type en arguments.
761 Pour associer l'entrée dans l'étude au résultat, on utilise la méthode setData du port
762 en lui passant une chaine de caractères qui contient soit l'Entry SALOME soit le chemin dans l'arbre d'étude.
764 Voici un exemple de noeud StudyOut qui définit 2 résultats (a et b) de type GEOM_Object.
765 L'étude utilisée a le studyId 1. Le résultat a est référencé par une Entry SALOME.
766 Le résultat b est référencé par un chemin.
767 L'étude complète est sauvegardée en fin de calcul dans le fichier study1.hdf::
769 n=r.createOutDataNode("study","study2")
770 n.setRef("study1.hdf")
772 n.setProperty("StudyID","1")
773 pout=n.edAddInputPort('a',tgeom)
774 pout.setData("0:1:2:1")
775 pout=n.edAddInputPort('b',tgeom)
776 pout.setData("/Save/Sphere_2")
779 Sauvegarder un schéma de calcul dans un fichier XML
780 ------------------------------------------------------
781 Pour sauvegarder un schéma de calcul dans un fichier au format XML, il faut utiliser la méthode saveSchema
782 du schéma de calcul en lui passant le nom du fichier en argument.
783 Pour qu'un schéma de calcul, construit en Python, puisse être sauvegardé sous une forme cohérente
784 dans un fichier XML, il ne faut pas oublier d'ajouter dans le dictionnaire des types du schéma
785 tous les types qui ont été définis en Python (voir :ref:`typedict`). La sauvegarde ne le fait pas automatiquement.
787 Pour sauver le schéma p construit ci-dessus, dans le fichier monschema.xml, il faut écrire::
789 p.saveSchema("monschema.xml")
791 Le fichier ainsi obtenu pourra ensuite être chargé comme dans :ref:`loadxml`.
794 Quelques opérations utiles
795 ------------------------------
796 Retrouver un noeud par son nom
797 '''''''''''''''''''''''''''''''''''
798 Pour retrouver un noeud (objet Python) quand on n'a que l'objet schéma de calcul et le nom absolu du noeud, il
799 suffit d'appeler la méthode getChildByName du schéma en lui passant le nom absolu.
801 Pour retrouver le noeud script Python défini en `Noeud script Python`_::
803 n=p.getChildByName("node1")
805 Pour retrouver le noeud "node1" dans le bloc "b1"::
807 n=p.getChildByName("b1.node1")
809 Cette opération est également utilisable à partir d'un noeud composé à condition d'utiliser le nom
811 On peut réécrire l'exemple précédent::
813 n=b.getChildByName("node1")
815 Retrouver un port par son nom
816 ''''''''''''''''''''''''''''''''
817 Pour retrouver un port d'un noeud par son nom, il faut d'abord récupérer le noeud par son nom. Puis
818 on retrouve un port de données d'entrée avec la méthode getInputPort et un port de données de sortie
819 avec la méthode getOutputPort.
821 Voici un exemple à partir du noeud n précédent::
823 pin=n.getOutputPort("p1")
824 pout=n.getInputPort("p2")
826 Obtenir la valeur d'un port
827 ''''''''''''''''''''''''''''''''
828 Pour obtenir la valeur d'un port on utilise sa méthode getPyObj.
832 print pout.getPyObj()
834 Obtenir l'état d'un noeud
835 ''''''''''''''''''''''''''''
836 Pour obtenir l'état d'un noeud on utilise sa méthode getEffectiveState (voir les valeurs
837 posssibles dans :ref:`etats`)
839 Retirer un noeud de son contexte
840 ''''''''''''''''''''''''''''''''''
841 Il est possible de retirer un noeud de son noeud contexte en utilisant une méthode du contexte.
842 Le nom de la méthode diffère selon le type de contexte.
844 - Pour un Bloc ou un schéma de calcul on utilisera la méthode edRemoveChild avec le noeud à retirer en argument::
848 - Pour une boucle (ForLoop, WhileLoop ou ForEachLoop) on utilisera la méthode edRemoveNode sans argument::
852 - Pour un Switch, on utilisera la méthode edRemoveChild avec le noeud interne concerné en argument::
854 sw.edRemoveChild(nk1)