]> SALOME platform Git repositories - modules/yacs.git/blob - doc/yacsgen.rst
Salome HOME
mergefrom branch BR_V511_PR tag mergeto_trunk_03feb09
[modules/yacs.git] / doc / yacsgen.rst
1
2 :tocdepth: 3
3
4 .. raw:: latex
5
6   \makeatletter
7   \g@addto@macro\@verbatim\small
8   \makeatother
9
10
11 .. _yacsgen:
12
13 YACSGEN : Générateur automatique de module SALOME 
14 ==================================================
15
16 YACSGEN est un module python (module_generator.py) qui permet de fabriquer un module
17 SALOME automatiquement à partir d'une description synthétique des composants
18 qu'il contiendra. Cette description est faite en langage Python.
19
20 Les caractéristiques de ces composants ne sont pas générales mais devraient
21 faciliter l'intégration de nombreux composants de calcul scientifique.
22
23 Ce générateur ne prend pas en charge l'intégration d'une IHM graphique mais seulement
24 la partie calcul. L'objectif principal est l'intégration d'une bibliothèque Fortran dans laquelle 
25 on peut faire des appels aux ports datastream (Calcium, en particulier).
26
27 Obtenir module_generator.py
28 ------------------------------------------------------------
29 Voir site PAL : http://pal.der.edf.fr/pal/projets/pal/superv/modulegenerator
30
31 Versions et architectures supportées
32 -----------------------------------------------------------------
33 Module_generator.py utilise des fonctionnalités de python 2.4 mais a un mode de compatibilité avec python 2.3.
34 Il fonctionne sur architecture 32 bits et 64 bits (testé sur machine Aster).
35
36 Installation
37 ----------------------------
38 Il n'y a pas de procédure d'installation particulière. Il suffit de décompresser et détarrer l'archive 
39 obtenue à partir du site PAL (YACSGEN-x.y.tar.gz) et d'ajouter le répertoire ainsi créé au PYTHONPATH.
40
41 Description d'un module SALOME
42 --------------------------------------------------------
43 Un module SALOME est décrit au moyen d'instructions Python et en utilisant des définitions contenues
44 dans le module Python module_generator.py.
45
46 La première action à réaliser est d'importer ces définitions::
47
48      from module_generator import Generator,Module,PYComponent
49      from module_generator import CPPComponent,Service,F77Component
50
51 Pour décrire un module SALOME, on donne son nom <nommodule>, la liste de ses composants (<liste des composants>) 
52 et le nom du répertoire dans lequel il sera installé (<prefix>).
53
54 Sa description prend la forme suivante ::
55
56      m=Module(<nommodule>,components=<liste des composants>,prefix=<prefix>)
57
58 Pour un module de nom "toto" avec un composant c1 (voir ci-dessous pour la description des composants) qui sera installé dans le
59 répertoire "Install", on aura ::
60
61      m=Module("toto",components=[c1],prefix="Install")
62
63
64
65 Description des composants
66 ------------------------------------------------
67
68 Il est possible de créer plusieurs types de composants :
69
70   - le type C/C++
71   - le type Fortran 77
72   - le type Python
73   - le type Aster
74
75 Tous ces types ont une description semblable. On commencera par le type C++ puis
76 on décrira les différences principales pour les autres types.
77
78 Composant C/C++
79 ++++++++++++++++++++++++++++++++++++++++
80 Tout d'abord, un composant C++ a un nom. Ce nom sera utilisé par la suite quand on voudra créer
81 des instances de ce composant. Le module SALOME, une fois compilé et installé contiendra une
82 librairie dynamique de nom lib<compo>Engine.so, où <compo> est le nom du composant.
83 Un composant C++ est implémenté comme un objet C++ exécutable à distance.
84
85 Un composant C++ a un ou plusieurs services. Chaque service a un nom qui est le nom de
86 la méthode de l'objet C++ qui correspond au composant.
87 Chaque service a, éventuellement, des ports dataflow d'entrée et de sortie et des ports datastream
88 d'entrée et de sortie.
89
90 Un premier service avec des ports dataflow
91 """""""""""""""""""""""""""""""""""""""""""""""""""""""
92 Pour le moment, les seuls types possibles pour les ports dataflow sont :
93
94 - double : scalaire équivalent à un double C
95 - long : scalaire équivalent à un long C
96 - string : équivalent à un char* C (chaine de caractères de longueur quelconque)
97 - dblevec : vecteur de doubles
98 - stringvec : vecteur de string
99 - intvec : vecteur de longs
100 - pyobj : objet python serialisé avec pickle (ne marche qu'avec des composants implémentés en Python)
101
102 Un port est décrit par un tuple python de longueur 2 dont la première valeur est le nom du port
103 et la deuxième le nom du type. Les ports d'entrée sont décrits par une liste de ces tuples
104 ainsi que les ports de sortie.
105
106 Un petit exemple vaut mieux qu'un long discours. Un composant de nom "moncompo" avec un service
107 de nom "monservice" qui a un port dataflow d'entrée de nom "portentrant" de type double
108 et un port dataflow de sortie de nom "portsortant" de type double aura la description suivante ::
109
110       c1=CPPComponent("moncompo",
111                       services=[
112                                 Service("monservice",
113                                         inport=[("portentrant","double"),],
114                                         outport=[("portsortant","double")],
115                                        ),
116                                ]
117                      )
118
119 c1 est une variable intermédiaire Python qui sera utilisée pour décrire la liste des composants d'un module : (components=[c1])
120 pour un module avec un seul composant.
121
122
123 En fait ce composant n'a pas grand intérêt car lors de l'exécution, il va prendre un double en entrée
124 d'exécution et fournir un double en sortie d'exécution mais il ne fait rien entre temps.
125 Il faut donc lui ajouter un contenu. Ce contenu sera spécifié dans 2 attributs du service : defs et body.
126 defs contiendra du code C++ de définition (par exemple, #include <iostream>) et body contiendra le code C++
127 qui sera exécuté entre l'entrée et la sortie (par exemple, portsortant=2*portentrant;).
128 Au final notre description devient ::
129
130       c1=CPPComponent("moncompo",
131                        services=[
132                                  Service("monservice",
133                                          inport=[("portentrant","double"),],
134                                          outport=[("portsortant","double")],
135                                          defs="#include <iostream>",
136                                          body="portsortant=2*portentrant;",
137                                         ),
138                                 ]
139                      )
140
141 Ajouter des ports datastream au service
142 """"""""""""""""""""""""""""""""""""""""""""""
143 Pour ajouter des ports datastream au service "monservice", on ajoute à la description les attributs instream et outstream.
144 Ces attributs doivent être des listes de triplets dont les éléments sont :
145
146   1. le nom du port
147   2. le type du port.
148   3. le mode de dépendance temporelle ("T") ou itérative ("I") (se référer à la documentation Calcium pour plus de détails)
149
150 Les types possibles sont "CALCIUM_double", "CALCIUM_integer", "CALCIUM_real", "CALCIUM_string", "CALCIUM_logical"
151 et "CALCIUM_complex".
152
153 Avec un port datastream entrant et un port sortant en dépendance temporelle, la description devient ::
154
155       c1=CPPComponent("moncompo",
156                       services=[
157                                 Service("monservice",
158                                         inport=[("portentrant","double"),],
159                                         outport=[("portsortant","double")],
160                                         instream=[("porta","CALCIUM_double","T")],
161                                         outstream=[("portb","CALCIUM_double","T")],
162                                         defs="#include <iostream>",
163                                         body="portsortant=2*portentrant;",
164                                         ),
165                                ]
166                      )
167
168 Il faudrait bien sûr ajouter dans body des appels à la bibliothèque CALCIUM pour que le service soit vraiment fonctionnel.
169
170 Ajouter un deuxième service au composant
171 """""""""""""""""""""""""""""""""""""""""""""""""
172 Si on veut un deuxième service pour le composant il suffit d'ajouter une autre description de service ::
173
174       c1=CPPComponent("moncompo",
175                       services=[
176                                 Service("monservice",
177                                         inport=[("portentrant","double"),],
178                                         outport=[("portsortant","double")],
179                                         instream=[("porta","CALCIUM_double","T")],
180                                         outstream=[("portb","CALCIUM_double","T")],
181                                         defs="#include <iostream>",
182                                         body="portsortant=2*portentrant;",
183                                        ),
184                                 Service("serv2",
185                                         inport=[("a","double"),("b","long")],
186                                         outport=[("c","double")],
187                                         body="c=b*a",
188                                        ),
189                                ]
190                      )
191
192 Ici, on a ajouté un deuxième service de nom "serv2" avec 2 ports dataflow d'entrée (a et b) et un port dataflow de sortie (c).
193 Le service est réduit à sa plus simple expression : il retourne le produit de ses 2 entrées.
194
195 Assembler avec des bibliothèques externes
196 """"""""""""""""""""""""""""""""""""""""""""""""""""
197 On a vu que les attributs *defs* et *body* permettent de définir le corps du service mais il est souvent plus pratique d'utiliser des bibliothèques
198 externes plutôt que de tout mettre dans ces 2 attributs.
199 Ceci est possible à condition d'indiquer dans les attributs *libs* et *rlibs* du composant, tout ce qui est nécessaire pour l'étape de link
200 du composant.
201
202 On pourra avoir, par exemple::
203
204       c1=CPPComponent("moncompo",
205                       services=[
206                                 Service("monservice",
207                                         inport=[("portentrant","double"),],
208                                         outport=[("portsortant","double")],
209                                         defs="extern double myfunc(double);",
210                                         body="portsortant=myfunc(portentrant);",
211                                        ),
212                                ],
213                       libs="-L/usr/local/mysoft -lmybib",
214                       rlibs="-Wl,--rpath -Wl,/usr/local/mysoft"
215                       )
216
217 L'attribut *rlibs* n'est pas obligatoire mais peut être utilisé pour indiquer un path de recherche pour des bibliothèques 
218 dynamiques à l'exécution.
219 *libs* est utilisé pendant la phase de link. *rlibs* est utilisé uniquement à l'exécution, il évite d'avoir à positionner 
220 la variable d'environnement LD_LIBRARY_PATH pour trouver la librairie dynamique.
221
222 Ajouter des includes
223 """"""""""""""""""""""""""""""""""""""""""""""""""""
224 Les includes seront ajoutés au moyen de l'attribut *defs*. Par exemple ::
225
226    defs="#include "moninclude.h"
227
228 Le chemin des includes sera spécifié dans l'attribut *includes* du composant, sous la forme suivante ::
229
230    defs="""#include "moninclude.h"
231    extern double myfunc(double);
232    """
233    c1=CPPComponent("moncompo",
234                    services=[
235                              Service("monservice",
236                                      inport=[("portentrant","double"),],
237                                      outport=[("portsortant","double")],
238                                      defs=defs,
239                                      body="portsortant=myfunc(portentrant);",
240                                     ),
241                             ],
242                    libs="-L/usr/local/mysoft -lmybib",
243                    rlibs="-Wl,--rpath -Wl,/usr/local/mysoft",
244                    includes="-I/usr/local/mysoft/include",
245                   )
246
247
248 Composant Fortran
249 ++++++++++++++++++++++++++++++++++++++++
250 Un composant Fortran se décrit comme un composant C++ à quelques différences près. 
251 Tout d'abord, on utilise l'objet de définition F77Component au lieu de CPPComponent.
252 Ensuite, un interfaçage supplémentaire spécial au Fortran est réalisé. On suppose que les fonctionnalités Fortran
253 sont implémentées dans une librairie (dynamique ou statique) qui sera linkée avec le composant et qui dispose de
254 plusieurs points d'entrée de mêmes noms que les services du composant. L'appel à ce point d'entrée sera ajouté
255 automatiquement après le code C++ fourni par l'utilisateur dans l'attribut body.
256
257 Ceci permet de découpler presque totalement l'implémentation du composant Fortran qui sera dans la bibliothèque
258 externe, de l'implémentation du composant SALOME qui ne sert que pour l'encapsulation.
259
260 L'exemple suivant permettra de préciser ces dernières notions ::
261
262      c3=F77Component("compo3",
263                      services=[
264                                Service("s1",
265                                        inport=[("a","double"),("b","long"),("c","string")],
266                                        outport=[("d","double"),("e","long"),("f","string")],
267                                        instream=[("a","CALCIUM_double","T"),
268                                                  ("b","CALCIUM_double","I")],
269                                        outstream=[("ba","CALCIUM_double","T"),
270                                                   ("bb","CALCIUM_double","I")],
271                                        defs="#include <unistd.h>",
272                                        body="chdir(c);"
273                                       ),
274                               ],
275                      libs="-L/usr/local/fcompo -lfcompo",
276                      rlibs="-Wl,--rpath -Wl,/usr/local/fcompo"
277                     )
278
279 Le composant Fortran "compo3" a des ports dataflow et datastream comme le composant C++. La bibliothèque dynamique Fortran
280 qui contient le point d'entrée Fortran s1 sera linkée grâce aux attributs libs et rlibs de la description. Le composant
281 Fortran supporte également l'attribut *includes*.
282
283 Il est possible d'ajouter un bout de code C++ avant l'appel au point d'entrée Fortan. Ce bout de code doit être mis
284 dans l'attribut body avec des définitions éventuelles dans defs. Ici, on utilise la variable dataflow entrante "c"
285 pour faire un changement de répertoire avec l'appel à chdir.
286
287 Composant Python
288 ++++++++++++++++++++++++++++++++++++++++
289 Un composant Python se décrit également comme un composant C++. Les seules différences portent sur l'objet Python
290 à utiliser pour le définir : PYComponent au lieu de CPPComponent et sur le contenu des attributs *defs* et *body*
291 qui doivent contenir du code Python et non C++ (attention à l'indentation, elle n'est pas prise en charge automatiquement).
292
293 Exemple de composant Python ::
294
295       pyc1=PYComponent("moncompo",
296                        services=[
297                                  Service("monservice",
298                                          inport=[("portentrant","double"),],
299                                          outport=[("portsortant","double")],
300                                          defs="import sys",
301                                          body="      portsortant=2*portentrant;",
302                                         ),
303                                 ]
304                       )
305
306 L'équivalent de l'assemblage avec des bibliothèques externes est réalisé ici avec la possibilité d'importer des modules
307 Python externes. Il suffit d'ajouter l'attribut *python_path* à la description du composant pour avoir cette possibilité. La valeur
308 à donner est une liste de répertoires susceptibles de contenir des modules à importer.
309
310 Exemple::
311
312      pyc1=PYComponent("moncompo",
313                       services=[
314                                 Service("monservice",
315                                         inport=[("portentrant","double"),],
316                                         outport=[("portsortant","double")],
317                                        ),
318                                ],
319                       python_path=["/usr/local/mysoft","/home/chris/monsoft"],
320                      )
321
322 Composant Aster
323 ++++++++++++++++++++++++++++++++++++++++
324 Un composant Aster est un composant un peu particulier car les fonctionnalités du logiciel sont implémentées en Fortran mais elles
325 sont activées par un superviseur de commandes écrit en Python. Au final ce superviseur exécute un script Python mais il faut gérer le transfert
326 des données entre Python et Fortran et l'intégration du superviseur de commandes dans un composant SALOME.
327
328 Le point de départ est le suivant : on suppose que l'on dispose d'une installation d'Aster qui fournit un module python aster
329 sous la forme d'une bibliothèque dynamique importable (astermodule.so) et non comme c'est le cas dans l'installation actuelle
330 d'un interpréteur Python spécifique linké avec ce même module.
331
332 Un composant Aster se décrit comme un composant Python auquel il faut ajouter plusieurs attributs
333 importants.
334
335      - l'attribut *python_path* : il indique le chemin du répertoire contenant le module aster (astermodule.so)
336      - l'attribut *aster_dir* : il indique le chemin du répertoire d'installation d'Aster
337      - l'attribut *argv* : il initialise les paramètres de la ligne de commande.  On y mettra, par exemple la valeur 
338        de memjeveux (``argv=["-memjeveux","10"]``) ou de rep_outils.
339
340 Voici un petit exemple de description de composant Aster avec un seul service doté de 3 ports dataflow d'entrée, 
341 d'un port dataflow de sortie, de 7 ports datastream d'entrée et d'un port datastream de sortie::
342
343     c1=ASTERComponent("caster",
344                       services=[
345                                 Service("s1",
346                                         inport=[("a","double"),("b","long"),("c","string")],
347                                         outport=[("d","double")],
348                                         instream=[("aa","CALCIUM_double","T"),
349                                                   ("ab","CALCIUM_double","I"),
350                                                   ("ac","CALCIUM_integer","I"),
351                                                   ("ad","CALCIUM_real","I"),
352                                                   ("ae","CALCIUM_string","I"),
353                                                   ("af","CALCIUM_complex","I"),
354                                                   ("ag","CALCIUM_logical","I"),
355                                                  ],
356                                        outstream=[("ba","CALCIUM_double","T"),
357                                                   ("bb","CALCIUM_double","I")],
358                                       ),
359                                ],
360                       aster_dir="/local/chris/ASTER/instals/NEW9",
361                       python_path=["/local/chris/modulegen/YACSGEN/aster/bibpyt"],
362                       argv=["-memjeveux","10",
363                             "-rep_outils","/local/chris/ASTER/instals/outils"],
364                      )
365
366 Attention à ne pas appeler le composant "aster" car ce nom est réservé au module python de Code_Aster. En cas 
367 d'utilisation du nom "aster", le comportement est complètement erratique.
368
369 Bien que sa description soit très semblable à celle d'un composant Python, il y a une différence importante à l'utilisation. 
370 En effet, le composant Aster a besoin de la description d'un jeu de commandes pour fonctionner. Ce jeu de commandes 
371 est passé sous la forme d'un texte à chaque service du composant dans un port dataflow d'entrée de nom "jdc" et 
372 de type "string". 
373 Après génération, ce composant Aster aura donc 4 ports dataflow d'entrée ("jdc","a","b","c") et non 3 comme indiqué 
374 dans la description. Il ne faut pas oublier d'initialiser le port "jdc" dans le fichier de couplage avec un jeu de commandes.
375
376 Le superviseur de commandes a été intégré dans un composant SALOME et les variables reçues dans les ports dataflow 
377 sont disponibles lors de l'exécution du jeu de commandes. 
378 De même pour les ports dataflow de sortie, ils sont alimentés par les valeurs des variables issues de l'exécution 
379 du jeu de commandes.
380
381 **Attention au mode d'exécution**. Le superviseur de commandes a 2 modes d'exécution (PAR_LOT="OUI" ou PAR_LOT="NON"
382 que l'on spécifie dans la commande DEBUT). En mode PAR_LOT="OUI", il est obligatoire de terminer le jeu de commandes 
383 par une commande FIN ce qui a pour effet d'interrompre l'exécution. Ce n'est pas le fonctionnement à privilégier
384 avec YACS. Il est préférable d'utiliser le mode PAR_LOT="NON" sans mettre de commande FIN ce qui évite d'interrompre
385 l'exécution prématurément.
386
387 Module Aster dynamiquement importable et lien avec YACS
388 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
389 Ces deux points ne sont pas pris en charge par *module_generator.py*. Ils doivent être traités séparément dans un contexte
390 proche de celui d'un développeur Aster.
391
392 On suppose que l'on dispose d'une installation d'Aster, que l'on veut créer un module Python aster dynamiquement importable
393 et que l'on veut ajouter à Aster quelques commandes pour échanger des données via des ports datastream de YACS.
394
395 Pour rester simple, on ajoute 3 commandes : YACS_INIT, ECRIRE_MAILLAGE et LECTURE_FORCE dont les catalogues sont::
396
397              YACS_INIT=PROC(nom="YACS_INIT",op=181, fr="Initialisation YACS",
398                                   COMPO=SIMP(statut='o',typ='I'),
399                            )
400              ECRIRE_MAILLAGE=PROC(nom="ECRIRE_MAILLAGE",op=78, fr="Ecriture du maillage")
401              LECTURE_FORCE=PROC(nom="LECTURE_FORCE",op=189, fr="Lecture de la force")
402
403 La première commande YACS_INIT sert à initialiser Aster dans le contexte YACS. Elle a un seul mot-clé simple COMPO
404 (de type entier) qui sera utilisé pour passer aux autres commandes l'identificateur du composant SALOME. Cet
405 identificateur sera stocké dans un COMMON fortran. Il est indispensable pour les appels aux sous programmes
406 CPLxx et CPExx qui seront utilisés dans les 2 autres commandes ECRIRE_MAILLAGE et LECTURE_FORCE. 
407
408 Les 2 autres commandes ne prennent n'ont aucun mot-clé et récupèrent l'identificateur dans le COMMON.
409
410 Les opérateurs seront écrits comme suit (sans les déclarations)::
411
412           SUBROUTINE OP0189 ( IER )
413     C     COMMANDE:  LECTURE_FORCE
414           include 'calcium.hf'
415           COMMON/YACS/ICOMPO
416           CALL cpldb(ICOMPO,CP_TEMPS,t0,t1,iter,'aa',1,n,ss,info)
417           CALL cpldb(ICOMPO,CP_ITERATION,t0,t1,iter,'ab',1,n,zz,info)
418           CALL cplen(ICOMPO,CP_ITERATION,t0,t1,iter,'ac',1,n,zn,info)
419           CALL cplre(ICOMPO,CP_ITERATION,t0,t1,iter,'ad',1,n,yr,info)
420           CALL cplch(ICOMPO,CP_ITERATION,t0,t1,iter,'ae',1,n,tch,info)
421           CALL cplcp(ICOMPO,CP_ITERATION,t0,t1,iter,'af',1,n,tcp,info)
422           CALL cpllo(ICOMPO,CP_ITERATION,t0,t1,iter,'ag',3,n,tlo,info)
423           END
424
425           SUBROUTINE OP0078 ( IER )
426     C     COMMANDE:  ECRIRE_MAILLAGE
427           include 'calcium.hf'
428           COMMON/YACS/ICOMPO
429           CALL cpeDB(ICOMPO,CP_TEMPS,t0,1,'ba',1,tt,info)
430           CALL cpeDB(ICOMPO,CP_ITERATION,t0,1,'bb',1,tp,info)
431           END
432
433 Enfin, il faut construire une bibliothèque dynamique astermodule.so, et placer tous les modules Python
434 nécessaires dans un répertoire que l'on indiquera dans l'attribut *python_path*.
435 On peut utiliser différentes méthodes pour obtenir ce résultat. Le Makefile suivant en est une::
436
437      #compilateur
438      FC=gfortran
439      #SALOME
440      KERNEL_ROOT_DIR=/local/chris/SALOME2/RELEASES/Install/KERNEL_V4_0
441      KERNEL_INCLUDES=-I$(KERNEL_ROOT_DIR)/include/salome
442      KERNEL_LIBS= -L$(KERNEL_ROOT_DIR)/lib/salome -lCalciumC -lSalomeDSCSuperv \
443                   -lSalomeDSCContainer -lSalomeDatastream -lSalomeDSCSupervBasic \
444                   -Wl,--rpath -Wl,$(KERNEL_ROOT_DIR)/lib/salome
445      #ASTER
446      ASTER_ROOT=/local/chris/ASTER/instals
447      ASTER_INSTALL=$(ASTER_ROOT)/NEW9
448      ASTER_PUB=$(ASTER_ROOT)/public
449      ASTER_LIBS = -L$(ASTER_INSTALL)/lib -laster \
450              -L$(ASTER_PUB)/scotch_4.0/bin -lscotch -lscotcherr \
451              -lferm -llapack -lhdf5
452      SOURCES=src/op0078.f src/op0189.f
453      CATAPY=catalo/ecrire_maillage.capy  catalo/lecture_force.capy
454
455      all:pyth cata astermodule
456      pyth:
457        cp -rf $(ASTER_INSTALL)/bibpyt .
458      cata: commande/cata.py
459        cp -rf commande/cata.py* bibpyt/Cata
460      commande/cata.py:$(CATAPY)
461        $(ASTER_ROOT)/ASTK/ASTK_SERV/bin/as_run make-cmd
462      astermodule:astermodule.so pyth
463        cp -rf astermodule.so bibpyt
464      astermodule.so: $(SOURCES)
465        $(FC) -shared -o $@ $(SOURCES) $(KERNEL_INCLUDES) $(ASTER_LIBS) $(KERNEL_LIBS)
466
467 Modifier les paramètres de la ligne de commande à l'exécution
468 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
469 L'attribut *argv* permet de donner des valeurs initiales aux arguments comme "memjeveux" mais
470 ces valeurs sont utilisées par le générateur pour construire le composant et restent donc constantes
471 par la suite, à l'exécution.
472
473 Pour modifier ces valeurs à l'exécution, il faut ajouter un port d'entrée de nom "argv" et de type "string".
474 La chaine de caractère qui sera donnée comme valeur de ce port sera utilisée par le composant pour
475 modifier les arguments de la ligne de commande (voir `Exemple d'exécution de composant Aster`_
476 pour un exemple d'utilisation).
477
478 Gestion du fichier elements
479 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
480 Le fichier des éléments finis est copié automatiquement dans le répertoire de travail sous le
481 nom elem.1. Le composant utilise l'attribut *aster_dir* pour localiser le fichier d'origine.
482
483 Version d'Aster supportées
484 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
485 Module_generator.py peut fonctionner avec Aster 9.0 et 9.2 (probablement avec 9.1 mais
486 ce n'est pas testé).
487
488 Générateur de module SALOME
489 -----------------------------------------------------------
490 Le module SALOME est créé par un générateur construit à partir de la description du module SALOME (m) vue
491 précédemment et d'un dictionnaire Python (context) qui fournit quelques paramètres d'environnement ::
492
493      g=Generator(m,context)
494
495 Les paramètres indispensables pour context sont :
496
497     - "prerequisites" : indique le chemin d'un shell script qui positionne les variables d'environnement
498       des prérequis de SALOME
499     - "kernel" : indique le chemin d'installation du module KERNEL de SALOME
500     - "update" : mettre à 1 pour le moment (futurs développements)
501
502 Exemple de création de générateur ::
503
504      context={'update':1,
505               "prerequisites":"/local/cchris/.packages.d/envSalome40",
506               "kernel":"/local/chris/SALOME2/RELEASES/Install/KERNEL_V4_0"
507               }
508      g=Generator(m,context)
509
510 Une fois ce générateur créé, il suffit d'appeler ses commandes pour réaliser les opérations nécessaires.
511
512     - génération du module SALOME : ``g.generate()``
513     - initialisation d'automake : ``g.bootstrap()``
514     - exécution du script configure : ``g.configure()``
515     - compilation : ``g.make()``
516     - installation dans le répertoire <prefix> : ``g.install()``
517     - création d'une application SALOME dans le répertoire appli_dir ::
518
519         g.make_appli(appli_dir,restrict=<liste de modules>,
520                                altmodules=<dictionnaire de modules>)
521
522 Ces commandes ne prennent pas de paramètres sauf make_appli qui en prend 3 :
523
524     - **appliname** : le nom du répertoire qui contiendra l'application SALOME
525     - **restrict** : une liste de noms de modules SALOME à mettre dans l'application. Par défaut, make_appli
526       met dans l'application tous les modules SALOME qu'il est capable de détecter (répertoire voisins de
527       KERNEL avec le même suffixe que KERNEL. Si le répertoire du module KERNEL s'appelle KERNEL_V41, il
528       retiendra GUI_V41, GEOM_V41, etc.). Si restrict est fourni, make_appli ne retiendra que les modules listés.
529     - **altmodules** : un dictionnaire de modules autres. La clé donne le nom du module. La valeur correspondante
530       donne le chemin du répertoire d'installation du module. Exemple : ``altmodules={"monmodule":"/local/chris/unmodule"}``
531
532
533 Fabrication du module SALOME
534 -----------------------------------------------------
535 Le module sera fabriqué en exécutant un fichier Python qui contient sa description, la mise en données du 
536 générateur et les commandes du générateur.
537
538 Ce qui donne quelque chose comme ce qui suit pour un module avec un seul composant Fortran::
539
540   from module_generator import Generator,Module
541   from module_generator import PYComponent,CPPComponent,Service,F77Component
542
543   context={"update":1,
544                    "prerequisites":"/local/cchris/.packages.d/envSalome40",
545                    "kernel":"/local/chris/SALOME2/RELEASES/Install/KERNEL_V4_0"
546                  }
547   c3=F77Component("compo",
548                   services=[
549                             Service("s1",
550                                     inport=[("a","double"),("b","long"),("c","string")],
551                                     outport=[("d","double"),("e","long"),("f","string")],
552                                     instream=[("a","CALCIUM_double","T"),
553                                               ("b","CALCIUM_double","I")],
554                                     outstream=[("ba","CALCIUM_double","T"),
555                                                ("bb","CALCIUM_double","I")],
556                                     defs="#include <unistd.h>",
557                                     body="chdir(c);"
558                                    ),
559                            ],
560                   libs="-L/local/chris/modulegen/YACSGEN/fcompo -lfcompo"
561                   rlibs="-Wl,--rpath -Wl,/local/chris/modulegen/YACSGEN/fcompo")
562
563   m=Module("toto",components=[c1],prefix="Install")
564   g=Generator(m,context)
565   g.generate()
566   g.bootstrap()
567   g.configure()
568   g.make()
569   g.install()
570   g.make_appli("appli",restrict=["KERNEL","GUI","YACS"])
571
572 Si cette description est dans le fichier monmodule.py, il suffit d'exécuter::
573
574     python monmodule.py
575
576 ce qui a pour effet de créer le répertoire source du module (toto_SRC), le répertoire d'installation du module (Instal)
577 et un répertoire d'application SALOME (appli).
578
579 Il faut bien sûr que le module module_generator.py puisse être importé soit en étant dans le répertoire courant soit en étant
580 dans le PYTHONPATH.
581
582 Il est toujours préférable (bien que non indispensable) de faire le ménage dans le répertoire de travail avant d'exécuter
583 le générateur.
584
585 Mise en oeuvre du composant dans un couplage
586 -----------------------------------------------------------------------------------------
587 Creation du fichier de couplage YACS
588 ++++++++++++++++++++++++++++++++++++++++
589 Un fichier de couplage YACS est un fichier XML qui décrit la façon dont des composants SALOME préalablement
590 installés dans une application SALOME sont couplés et exécutés.
591
592 Pour une documentation sur la façon d'écrire un fichier XML YACS, voir :ref:`schemaxml`.
593
594 Voici un exemple de fichier YACS mettant en oeuvre le composant Fortran défini ci-dessus ::
595
596   <proc>
597   <container name="A"> </container>
598   <container name="B"> </container>
599
600   <service name="pipo1" >
601     <component>compo</component>
602     <method>s1</method>
603     <load container="A"/>
604     <inport name="a" type="double"/>
605     <inport name="b" type="int"/>
606     <inport name="c" type="string"/>
607     <outport name="d" type="double"/>
608     <outport name="e" type="int"/>
609     <outport name="f" type="string"/>
610     <instream name="a" type="CALCIUM_double"/>
611     <instream name="b" type="CALCIUM_double"/>
612     <outstream name="ba" type="CALCIUM_double"/>
613     <outstream name="bb" type="CALCIUM_double"/>
614   </service>
615   <service name="pipo2" >
616     <component>compo</component>
617     <method>s1</method>
618     <load container="B"/>
619     <inport name="a" type="double"/>
620     <inport name="b" type="int"/>
621     <inport name="c" type="string"/>
622     <outport name="d" type="double"/>
623     <outport name="e" type="int"/>
624     <outport name="f" type="string"/>
625     <instream name="a" type="CALCIUM_double"/>
626     <instream name="b" type="CALCIUM_double"/>
627     <outstream name="ba" type="CALCIUM_double"/>
628     <outstream name="bb" type="CALCIUM_double"/>
629   </service>
630
631   <stream>
632     <fromnode>pipo1</fromnode><fromport>ba</fromport>
633     <tonode>pipo2</tonode><toport>a</toport>
634   </stream>
635   <stream>
636     <fromnode>pipo1</fromnode><fromport>bb</fromport>
637     <tonode>pipo2</tonode><toport>b</toport>
638   </stream>
639   <stream>
640     <fromnode>pipo2</fromnode><fromport>ba</fromport>
641     <tonode>pipo1</tonode><toport>a</toport>
642   </stream>
643   <stream>
644     <fromnode>pipo2</fromnode><fromport>bb</fromport>
645     <tonode>pipo1</tonode><toport>b</toport>
646   </stream>
647   <parameter>
648     <tonode>pipo1</tonode> <toport>a</toport>
649     <value><double>23</double> </value>
650   </parameter>
651   <parameter>
652     <tonode>pipo1</tonode> <toport>b</toport>
653     <value><int>23</int> </value>
654   </parameter>
655   <parameter>
656     <tonode>pipo1</tonode> <toport>c</toport>
657     <value><string>/local/cchris/SALOME2/SUPERV/YACS/modulegen/data1</string> </value>
658   </parameter>
659   <parameter>
660     <tonode>pipo2</tonode> <toport>a</toport>
661     <value><double>23</double> </value>
662   </parameter>
663   <parameter>
664     <tonode>pipo2</tonode> <toport>b</toport>
665     <value><int>23</int> </value>
666   </parameter>
667   <parameter>
668     <tonode>pipo2</tonode> <toport>c</toport>
669     <value><string>/local/cchris/SALOME2/SUPERV/YACS/modulegen/data2</string> </value>
670   </parameter>
671
672   </proc>
673
674 Dans les grandes lignes, le couplage fait intervenir 2 instances du composant compo (pipo1 et pipo2) dont on exécute
675 le service s1. Les ports datastream de ces services sont connectés au moyen des informations fromnode, fromport, tonode, toport
676 dans les sections stream.
677 Les ports dataflow sont initialisés par les sections parameter. En particulier, le répertoire de travail de chaque instance
678 de composant est initialisé à travers le port d'entrée "c" de chaque instance de composant.
679 Chaque instance de composant est exécuté dans un container différent (A et B). Ces noms sont virtuels. C'est SALOME qui au
680 moment du lancement décidera du nom effectif des containers. On ne donne ici que des contraintes sur les containers à utiliser.
681 En l'occurrence, il n'y en a qu'une : containers différents.
682
683 Exécution du couplage
684 +++++++++++++++++++++++++++++++++++++++++++++
685 Une fois le fichier de couplage écrit au moyen d'un éditeur classique ou de l'éditeur graphique YACS, il est possible
686 de lancer l'exécution.
687
688 Elle se passe en plusieurs temps :
689
690   - le lancement de SALOME : exécution du script runAppli de l'application SALOME (``./appli/runAppli -t``). L'application tourne
691     en tâche de fond jusqu'à ce qu'elle soit arrêtée.
692   - le lancement du couplage : exécution du coupleur YACS dans l'environnement de l'application SALOME
693     lancée (``./appli/runSession driver test.xml``) avec test.xml le fichier de couplage.
694   - l'arrêt de l'application : ``./appli/runSession killSalome.py``
695
696 Les sorties du couplage sont multiples :
697
698   - la sortie du coupleur lui-même. Si aucune erreur d'exécution ne remonte jusqu'à lui, elle ne contient qu'une information
699     utile : le nom des containers lancé par SALOME pour exécuter les composants. Si des erreurs d'exécution sont remontées
700     jusqu'au coupleur elles sont listées en fin d'exécution.
701   - les sorties des containers. Elles se retrouvent dans le répertoire /tmp avec un nom construit sur la base du nom du container
702     lu dans la sortie du coupleur.
703
704 Attention : lors de l'arrêt de l'application les containers sont arrêtés brutalement ce qui peut provoquer des pertes d'informations 
705 dans leurs fichiers de sortie.
706
707 La question du répertoire de travail
708 ++++++++++++++++++++++++++++++++++++++
709 Chaque instance de composant est hébergée par un container. Toutes les instances hébergées par un container s'exécutent donc 
710 dans un même répertoire qui est celui du container. A partir de la version 4.1.1 de SALOME il est possible de spécifier le répertoire
711 de travail d'un container dans le fichier de couplage. Il suffit d'ajouter la propriété *workingdir* au container. Voici quelques
712 exemples::
713
714    <container name="A">
715      <property name="workingdir" value="/home/user/w1"/>
716    </container>
717    <container name="B">
718      <property name="workingdir" value="$TEMPDIR"/>
719    </container>
720    <container name="C">
721      <property name="workingdir" value="a/b"/>
722    </container>
723
724 Le container A s'exécutera dans le répertoire "/home/user/w1". S'il n'existe pas il sera créé.
725 Le container B s'exécutera dans un nouveau répertoire temporaire.
726 Le container C s'exécutera dans le répertoire relatif "a/b" (par rapport au répertoire de l'application utilisée pour l'exécution). 
727 S'il n'existe pas il sera créé.
728
729 La question des fichiers
730 ++++++++++++++++++++++++++++
731 Les composants sont des bibliothèques dynamiques ou des modules Python, il n'est pas possible de les lancer dans des scripts shell.
732 Pour les composants qui utilisent des fichiers en entrée et en sortie, il est possible de spécifier dans le fichier de couplage
733 des ports "fichiers" qui effectueront le transfert des fichiers et le nommage local adéquat.
734 Par exemple, un service qui utilise un fichier d'entrée a et produit un fichier de sortie b sera déclaré comme suit::
735
736     <service name="pipo1">
737       <component>caster</component>
738       <method>s1</method>
739       <inport name="a" type="file"/>
740       <outport name="b" type="file"/>
741     </service>
742
743 Ces ports pourront être initialisés ou connectés à d'autres ports "fichiers" comme des ports ordinaires.
744 Par exemple, l'initialisation pour le fichier d'entrée prendra la forme suivante::
745
746     <parameter>
747       <tonode>pipo1</tonode> <toport>a</toport>
748       <value><objref>/local/chris/tmp/unfichier</objref> </value>
749     </parameter>
750
751 Il n'est pas possible d'initialiser directement un port fichier de sortie. Il faut passer par un noeud spécial qui
752 collecte les sorties. On créera un noeud "dataout" et un lien entre le noeud "pipo1" et le noeud "dataout"::
753
754     <outnode name="dataout" >
755       <parameter name="f1" type="file" ref="monfichier"/>
756     </outnode>
757     <datalink>
758        <fromnode>pipo1</fromnode><fromport>b</fromport>
759        <tonode>dataout</tonode> <toport>f1</toport>
760     </datalink>
761
762 ATTENTION: il n'est pas possible d'utiliser le caractère '.' dans les noms des ports. Ceci interdit l'utilisation de noms
763 tels que fort.8 qui sont assez fréquents. Un contournement existe : il suffit de remplacer le '.' par le caractère ':' (donc
764 fort:8 dans notre exemple) pour obtenir le résultat attendu. Bien entendu, les noms contenant des caractères ':' ne sont pas 
765 utilisables. Ils devraient être très rares.
766
767 Exemple d'exécution de composant Aster
768 +++++++++++++++++++++++++++++++++++++++++++
769 L'exécution d'un composant Aster présente quelques particularités qui sont exposées ici.
770
771          - prise en charge du jeu de commande
772          - spécification des paramètres de la ligne de commande
773          - spécification d'un fichier maillage (.mail)
774          - spécification de variables d'environnement (également valable pour les autres types de composant)
775
776 Voici un exemple simplifié de schéma YACS comportant un noeud de calcul devant exécuter le service s1 du 
777 composant caster (de type Aster) avec une variable d'environnement, un fichier mail un fichier comm
778 et des paramètres de la ligne de commande. Pour un exemple plus complet, voir les fichiers aster.xml et f.comm 
779 de la distribution::
780
781     <service name="pipo1" >
782       <component>caster</component>
783       <property name="MYENVAR" value="25"/>
784       <method>s1</method>
785       <load container="A"/>
786       <inport name="jdc" type="string"/>
787       <inport name="argv" type="string"/>
788       <inport name="a" type="double"/>
789       <inport name="fort:20" type="file"/>
790       <outport name="d" type="double"/>
791       <instream name="aa" type="CALCIUM_double"/>
792       <outstream name="ba" type="CALCIUM_double"/>
793     </service>
794
795     <inline name="ljdc" >
796        <script>
797        <code>f=open(comm)</code>
798        <code>jdc=f.read()</code>
799        <code>f.close()</code>
800        </script>
801        <inport name="comm" type="string"/>
802        <outport name="jdc" type="string"/>
803     </inline>
804
805     <parameter>
806       <tonode>ljdc</tonode> <toport>comm</toport>
807       <value><string>/home/chris/jdc.comm</string> </value>
808     </parameter>
809
810     <datalink>
811        <fromnode>ljdc</fromnode><fromport>jdc</fromport>
812        <tonode>pipo1</tonode> <toport>jdc</toport>
813     </datalink>
814
815     <parameter>
816       <tonode>pipo1</tonode> <toport>argv</toport>
817       <value><string>-rep_outils /aster/outils</string> </value>
818     </parameter>
819
820     <parameter>
821        <tonode>pipo1</tonode> <toport>fort:20</toport>
822        <value><objref>/local/chris/ASTER/instals/NEW9/astest/forma01a.mmed</objref> </value>
823     </parameter>
824
825 Tout d'abord, il faut spécifier le jeu de commande. Comme indiqué ci-dessus (`Composant Aster`_), il faut 
826 déclarer un port supplémentaire "jdc" de type "string" et l'initialiser ou le connecter. Ici, le port jdc est connecté à
827 un port de sortie d'un noeud python (ljdc) qui lira le fichier .comm dont le chemin lui est donné par
828 son port d'entrée comm. Le transfert de l'identificateur du composant à la commande YACS_INIT est réalisé au moyen
829 de la variable "component" qui est ajoutée automatiquement par le générateur et est disponible
830 pour écrire le fichier .comm.
831
832 Exemple succinct de .comm ::
833
834    DEBUT(PAR_LOT="NON")
835    YACS_INIT(COMPO=component)
836    ECRIRE_MAILLAGE()
837    LECTURE_FORCE()
838
839 Pour spécifier des valeurs de paramètres de la ligne de commande, il faut avoir créer un composant
840 avec un port de nom "argv" de type "string". Il suffit alors de donner une valeur à ce port. Ici, on modifie
841 le chemin du répertoire des outils avec le paramètre rep_outils.
842
843 Pour spécifier un fichier de maillage (.mail) à un composant Aster, il faut ajouter un port fichier au noeud de
844 calcul::
845
846       <inport name="fort:20" type="file"/>
847
848 Ce port fichier doit avoir comme nom le nom local du fichier tel qu'attendu par Aster. En général Aster utilise
849 le fichier fort.20 comme entrée de LIRE_MAILLAGE. Comme indiqué plus haut, le point de fort.20 ne peut pas être
850 utilisé dans un nom de port, on donnera donc comme nom fort:20. Il faut ensuite donner une valeur à ce port
851 qui correspond au chemin du fichier à utiliser. Ceci est réalisé par une directive parameter::
852
853     <parameter>
854        <tonode>pipo1</tonode> <toport>fort:20</toport>
855        <value><objref>/local/chris/ASTER/instals/NEW9/astest/forma01a.mmed</objref> </value>
856     </parameter>
857
858 Pour spécifier des variables d'environnement, on passe par les properties du noeud de calcul. Ici, on
859 définit la variable d'environnement MYENVAR de valeur 25.
860
861 Composants standalone
862 --------------------------------------------------
863 Jusqu'à la version 4.1 de Salome, la seule méthode pour intégrer un composant était de produire
864 une bibliothèque dynamique (\*.so) ou un module python (\*.py).  Ce composant est chargé par un
865 exécutable Salome nommé Container soit par dlopen dans le cas de la bibliothèque soit par 
866 import dans le cas du module python. Cette méthode est un peu contraignante pour les codes de
867 calcul comme Code_Aster ou Code_Saturne qui sont exécutés dans un environnement particulier
868 de préférence à partir d'un shell script.
869
870 A partir de la version 4.1.3, il est possible d'intégrer un composant en tant qu'exécutable ou shell
871 script. Cette nouvelle fonctionnalité est pour le moment expérimentale et demande à être testée
872 plus complètement. Elle est cependant utilisable et module_generator a été adapté (à partir de 
873 la version 0.3) pour générer des composants standalone. On décrit ci-après les opérations à réaliser
874 pour passer au mode standalone pour chaque type de composant (C/C++, Python, Fortran ou Aster).
875
876 Composant C/C++
877 ++++++++++++++++++++++++++++++++++++++++
878 Pour transformer un composant C/C++ qui se présente de façon standard sous forme d'une
879 bibliothèque dynamique en composant standalone, il suffit d'ajouter deux attributs à sa 
880 description :
881
882   - l'attribut **kind** : en lui donnant la valeur "exe"
883   - l'attribut **exe_path** : en lui donnant comme valeur le chemin de l'exécutable ou du script shell
884     qui sera utilisé au lancement du composant
885
886 Voici un exemple de composant C++ modifié pour en faire un composant standalone::
887
888       c1=CPPComponent("compo1",services=[
889                       Service("monservice",inport=[("portentrant","double"),],
890                                outport=[("portsortant","double")],
891                              ),
892                             ],
893          kind="exe",
894          exe_path="/local/chris/SALOME2/SUPERV/YACS/modulegen/execpp_essai/prog",
895                      )
896
897 Le chemin donné pour exe_path correspond à un exécutable dont le source est le suivant::
898
899    #include "compo1.hxx"
900
901    int main(int argc, char* argv[])
902    {
903      yacsinit();
904      return 0;
905    }
906
907 Il doit être compilé et linké en utilisant l'include compo1.hxx et la librairie libcompo1Exelib.so
908 que l'on trouvera dans l'installation du module généré respectivement dans include/salome
909 et dans lib/salome. On pourra consulter un exemple plus complet dans les sources de la distribution
910 dans le répertoire cppcompo.
911
912 Il est possible de remplacer l'exécutable par un script shell intermédiaire mais il est bon de savoir que l'appel
913 à yacsinit récupère dans 3 variables d'environnement ( *SALOME_CONTAINERNAME*, *SALOME_INSTANCE*,
914 *SALOME_CONTAINER*), les informations nécessaires à l'initialisation du composant.
915
916 Composant Fortran
917 ++++++++++++++++++++++++++++++++++++++++
918 Pour un composant Fortran, la méthode est identique. On ajoute les deux mêmes attributs :
919
920   - l'attribut **kind** : en lui donnant la valeur "exe"
921   - l'attribut **exe_path** : en lui donnant comme valeur le chemin de l'exécutable ou du script shell
922     qui sera utilisé au lancement du composant
923
924 Voici un exemple de composant Fortran standalone::
925
926      c3=F77Component("compo3",services=[
927           Service("s1",inport=[("a","double"),("b","long"),
928                                ("c","string")],
929                        outport=[("d","double"),("e","long"),
930                                 ("f","string")],
931                        instream=[("a","CALCIUM_double","T"),
932                                  ("b","CALCIUM_double","I")],
933                        outstream=[("ba","CALCIUM_double","T"),
934                                   ("bb","CALCIUM_double","I")],
935                              ),
936                              ],
937          kind="exe",
938          exe_path="/local/chris/SALOME2/SUPERV/YACS/modulegen/YACSGEN/fcompo/prog",
939                                      )
940
941 Le chemin donné pour exe_path correspond à un exécutable dont le source est le suivant::
942
943        PROGRAM P
944        CALL YACSINIT()
945        END
946
947 Il doit être compilé et linké en utilisant la librairie libcompo3Exelib.so que l'on trouvera dans l'installation 
948 du module généré dans lib/salome ainsi qu'avec le source Fortran contenant la subroutine S1. 
949 On pourra consulter un exemple plus complet dans les sources de la distribution
950 dans le répertoire fcompo.
951
952 Composant Python
953 ++++++++++++++++++++++++++++++++++++++++
954 Pour un composant Python, un générateur très rudimentaire a été codé. Il n'est possible que
955 d'ajouter l'attribut **kind** avec la valeur "exe". L'exécutable est automatiquement généré dans l'installation 
956 du module. Il n'est pas possible, sauf à modifier l'installation, de le remplacer par un script.
957
958 Composant Aster standalone
959 ++++++++++++++++++++++++++++++++++++++++
960 Pour un composant Aster, il faut un peu plus de travail. Il faut spécifier 4 attributs :
961
962   - l'attribut **aster_dir** : qui donne le chemin de l'installation de Code_Aster
963   - l'attribut **kind** : avec la valeur "exe"
964   - l'attribut **asrun** : qui donne le chemin d'accès au lanceur as_run
965   - l'attribut **exe_path** : qui donne le chemin d'un REPERTOIRE dans lequel le générateur va
966     produire plusieurs fichiers qui serviront au lancement de l'exécution de Code_Aster.
967
968 Voici un exemple de description d'un composant Aster standalone::
969
970       c1=ASTERComponent("caster",services=[
971                   Service("s1",inport=[("argv","string"),("a","double"),
972                                        ("b","long"),("c","string")],
973                                outport=[("d","double")],
974                                instream=[("aa","CALCIUM_double","T"),
975                                          ("ab","CALCIUM_double","I"),
976                                          ("ac","CALCIUM_integer","I"),
977                                          ("ad","CALCIUM_real","I"),
978                                          ("ae","CALCIUM_string","I"),
979                                          ("af","CALCIUM_complex","I"),
980                                          ("ag","CALCIUM_logical","I"),
981                                        ],
982                                outstream=[("ba","CALCIUM_double","T"),
983                                           ("bb","CALCIUM_double","I")],
984                  ),
985          ],
986          aster_dir="/aster/NEW9",
987          exe_path="/home/pora/CCAR/SALOME4/exeaster_essai",
988          asrun="/aster/ASTK/ASTK_SERV/bin/as_run",
989          kind="exe",
990          )
991
992 Le générateur produit les fichiers suivants, dans le répertoire **exe_path** :
993
994   - **aster_component.py** : qui est l'exécutable python qui remplace l'exécutable standard 
995     E_SUPERV.py. Il n'a pas à être modifié.
996   - **E_SUPERV.py** : une modification du fichier original contenu dans 
997     ``bibpyt/Execution``. Il n'a pas à être modifié.
998   - **config.txt** : le fichier config.txt de l'installation de Code_Aster modifié pour changer 
999     l'exécutable python (ARGPYT). Il peut être modifié en dehors de ARGPYT.
1000   - **profile.sh** : une copie du fichier profile.sh de l'installation de Code_Aster (pour que çà marche).
1001   - **caster.comm** : un fichier de commande d'amorçage qui ne contient que la commande DEBUT 
1002     en mode PAR_LOT="NON". Il n'a pas à être modifié.
1003   - **make_etude.export** : un fichier de commande pour as_run simplifié. Il est complété 
1004     dynamiquement au lancement pour rediriger les fichiers 6,8 et 9 dans REP/messages, REP/resu 
1005     et REP/erre. REP est le répertoire d'exécution du composant standalone qui a pour 
1006     nom : <composant>_inst_<N>. <N> est un numéro d'exécution qui démarre à 1. 
1007     <composant> est le nom du composant (caster, dans notre exemple). Ce fichier peut être 
1008     modifié en particulier si on a modifié ou ajouté des commandes Aster.   
1009
1010 Bien que l'exécution soit lancée avec un fichier de commandes (caster.comm), il est toujours 
1011 nécessaire de spécifier le fichier de commandes "effectif" dans le fichier de couplage xml. 
1012 La seule différence avec un composant sous forme de bibliothèque est que ce dernier fichier de 
1013 commandes NE DOIT PAS contenir de commande DEBUT (sinon, plantage inexplicable).
1014  
1015 Exemple de couplage avec composants standalone
1016 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1017 En rassemblant tous les éléments ci-dessus, le couplage d'un composant Aster standalone avec un composant
1018 Fortran standalone s'écrit comme suit (fichier astexe.py dans la distribution) ::
1019
1020   from module_generator import Generator,Module
1021   from module_generator import ASTERComponent,Service,F77Component
1022
1023   context={'update':1,"prerequisites":"/home/caremoli/pkg/env.sh",
1024           "kernel":"/home/pora/CCAR/SALOME4/Install/KERNEL_V4_1"}
1025
1026   install_prefix="./exe_install"
1027   appli_dir="exe_appli"
1028
1029   c1=ASTERComponent("caster",services=[
1030           Service("s1",inport=[("a","double"),("b","long"),
1031                                ("c","string")],
1032                        outport=[("d","double")],
1033                    instream=[("aa","CALCIUM_double","T"),
1034                              ("ab","CALCIUM_double","I"),
1035                              ("ac","CALCIUM_integer","I"),
1036                              ("ad","CALCIUM_real","I"),
1037                              ("ae","CALCIUM_string","I"),
1038                              ("af","CALCIUM_complex","I"),
1039                              ("ag","CALCIUM_logical","I"),
1040                          ],
1041                    outstream=[("ba","CALCIUM_double","T"),
1042                               ("bb","CALCIUM_double","I")],
1043                  ),
1044          ],
1045          aster_dir="/aster/NEW9",
1046          exe_path="/home/pora/CCAR/SALOME4/exeaster_essai",
1047          asrun="/aster/ASTK/ASTK_SERV/bin/as_run",
1048          kind="exe",
1049          )
1050
1051   c2=F77Component("cedyos",services=[
1052           Service("s1",inport=[("a","double"),("b","long"),
1053                                ("c","string")],
1054                        outport=[("d","double"),("e","long"),
1055                                 ("f","string")],
1056                   instream=[("a","CALCIUM_double","T"),
1057                             ("b","CALCIUM_double","I")],
1058                   outstream=[("ba","CALCIUM_double","T"),
1059                              ("bb","CALCIUM_double","I"),
1060                              ("bc","CALCIUM_integer","I"),
1061                              ("bd","CALCIUM_real","I"),
1062                              ("be","CALCIUM_string","I"),
1063                              ("bf","CALCIUM_complex","I"),
1064                              ("bg","CALCIUM_logical","I"),
1065                          ],
1066                        defs="",body="",
1067                  ),
1068          ],
1069            exe_path="/home/pora/CCAR/SALOME4/exeedyos_essai/prog",
1070            kind="exe")
1071
1072   g=Generator(Module("titi",components=[c1,c2],prefix=install_prefix),context)
1073   g.generate()
1074   g.bootstrap()
1075   g.configure()
1076   g.make()
1077   g.install()
1078   g.make_appli(appli_dir,restrict=["KERNEL","YACS"])
1079
1080 Le fichier de couplage xml et le fichier de commandes Aster correspondants peuvent être consultés
1081 dans la distribution (asterexe.xml et fexe.xml).
1082 On trouvera les éléments complémentaires d'implantation dans le répertoire fcompo (composant cedyos)
1083 et dans le répertoire aster (composant caster).
1084