6 YACSGEN: SALOME module generator
7 ==================================================
9 YACSGEN is a python package (module_generator) that automatically fabricates a SALOME module starting
10 from a synthetic description of the components that it will contain. This description is made in the python language.
12 YACSGEN includes since version 6.5 the HXX2SALOME functionalities, and is therefore able to also generate the
13 implementation of C++ dataflow components.
15 The characteristics of these components are not general but they should facilitate integration of many scientific
16 calculation components.
19 -----------------------------------------------------------------
20 It is a module (named YACSGEN) in the SALOME CVS TOOLS base that is distributed with main SALOME modules.
22 Supported versions and architectures
23 -----------------------------------------------------------------
24 YACSGEN needs a Python version >= 2.4 and < 3.0. It runs on a 32-bit and 64-bit
28 ----------------------------
29 If you get the source archive, simply decompress and untar the archive (YACSGEN-x.y.tar.gz)
30 and add the directory thus created to PYTHONPATH. YACSGEN is also provided with binaries installation of SALOME.
32 Description of a SALOME module
33 --------------------------------------------------------
34 A SALOME module is described using Python instructions and definitions contained in the Python module_generator package.
36 The first action to be done is to import these definitions::
38 from module_generator import Generator,Module,PYComponent
39 from module_generator import CPPComponent,Service,F77Component
40 from module_generator import Library
42 If you want to import all definitions, you can do that::
44 from module_generator import *
46 A SALOME module is described by giving its name <modulename> together with the list of its
47 components (<components list>) and the name of the directory in which it will be installed (<prefix>).
49 Its description is in the following form::
51 m=Module(<modulename>,components=<components list>,prefix=<prefix>)
53 The statement for a module named "mymodule" with a component c1 (see below for a description of components) that
54 will be installed in the "Install" directory will be::
56 m=Module("mymodule",components=[c1],prefix="Install")
58 Description of components
59 ------------------------------------------------
60 Several types of components can be created:
67 All these types have a similar description. We will begin with the C++ type and then describe the main differences for the other types.
70 ++++++++++++++++++++++++++++++++++++++++
71 Firstly, a C++ component has a name. This name will be used subsequently when it is required to create instances of this component.
72 Once compiled and installed, the SALOME module will contain a dynamic library named lib<compo>Engine.so, in which <compo> is the component name.
73 A C++ component is implemented as a remote executable C++ object.
75 A C++ component has one or several services. Each service has a name that is the name of the method of the C++ object
76 that corresponds to the component. Each service may have input and output dataflow ports and input and output datastream ports.
78 A first service with dataflow ports
79 """""""""""""""""""""""""""""""""""""""""""""""""""""""
80 The only possible types for dataflow ports for the moment are:
82 - double: scalar equivalent to a C double
83 - long: scalar equivalent to a C long
84 - string: equivalent to a C char* (character string with arbitrary length)
86 - dblevec: doubles vector
87 - stringvec: strings vector
88 - intvec: longs vector
89 - pyobj: python object serialised with pickle (only works with components implemented in Python).
91 A port is described by a python tuple with length 2, the first value is the name of the port and the second value is the type name.
92 Input ports are described by a list of these tuples as well as the output ports.
94 A small example is better than a long description. A component named “mycompo” with a service named “myservice” which has
95 an input dataflow port named “inputport” of the double type and an output data flow port with name “outputport” of the double
96 type will have the following description::
99 c1=CPPComponent("mycompo",
102 inport=[("inputport","double"),],
103 outport=[("outputport","double")],
108 c1 is an intermediate Python variable that will be used to describe the list of components of a
109 module: (components=[c1]) for a module with a single component.
111 In fact, this component is not particularly useful because during execution, it will take a double at the input to the
112 execution and will provide a double at the output from the execution, but it does nothing in the meantime.
113 Therefore, a content has to be added to it. This content will be specified in two service attributes, **defs** and **body**.
115 - defs will contain the C++ definition code (for example, #include<iostream>)
116 - body will contain the C++ code that will be executed between the input and the output (for example, outputport=2*inputport).
118 The final description becomes::
120 c1=CPPComponent("mycompo",
123 inport=[("inputport","double"),],
124 outport=[("outputport","double")],
125 defs="#include <iostream>",
126 body="outputport=2*inputport;",
131 Adding datastream ports to the service
132 """"""""""""""""""""""""""""""""""""""""""""""
133 Datastream ports are added to the “myservice” service by adding **instream** and **outstream** attributes to the description.
134 These attributes must be lists of triplets with the following elements:
138 3. the time (“T”) or iteration (“I”) dependency mode (refer to :ref:`calcium` for further details)
140 Possible types are “CALCIUM_double”, “CALCIUM_integer”, "CALCIUM_long", “CALCIUM_real”, “CALCIUM_string”, “CALCIUM_logical” and “CALCIUM_complex”.
142 The description for an input datastream port and an output port in time dependency becomes::
144 c1=CPPComponent("mycompo",
147 inport=[("inputport","double"),],
148 outport=[("outputport","double")],
149 instream=[("porta","CALCIUM_double","T")],
150 outstream=[("portb","CALCIUM_double","T")],
151 defs="#include <iostream>",
152 body="ouputport=2*inputport;",
157 Obviously, calls to the CALCIUM library have to be added into body to make the service genuinely functional.
159 Adding a second service to the component
160 """""""""""""""""""""""""""""""""""""""""""""""""
161 If a second service has to be added for the component, simply add another service description::
163 c1=CPPComponent("mycompo",
166 inport=[("inputport","double"),],
167 outport=[("outputport","double")],
168 instream=[("porta","CALCIUM_double","T")],
169 outstream=[("portb","CALCIUM_double","T")],
170 defs="#include <iostream>",
171 body="ouputport=2*inputport;",
174 inport=[("a","double"),("b","long")],
175 outport=[("c","double")],
181 In this description, a second service name “serv2” has been added with 2 input dataflow ports (a and b) and an output dataflow port (c).
182 The service is reduced to its simplest expression: it returns the product of its 2 inputs.
184 Link with external libraries
185 """"""""""""""""""""""""""""""""""""""""""""""""""""
186 We have seen that the **defs** and **body** attributes are sufficient to define the body of the service but it is often more practical
187 to use external libraries rather than put everything into these 2 attributes. This is possible provided that everything necessary
188 for the component link step is indicated in the **libs** and **rlibs** attributes of the component.
190 For example, we can have::
193 c1=CPPComponent("mycompo",
196 inport=[("inputport","double"),],
197 outport=[("outputport","double")],
198 defs="extern double myfunc(double);",
199 body="outputport=myfunc(inputport);",
202 libs=[Library(name="mybib", path="/usr/local/mysoft")],
203 rlibs="/usr/local/mysoft"
206 **libs** contains a list of **Library** objects. On linux, if the name of the file is "libmybib.so",
207 the **name** of the library will be "mybib". The *path* shows where the library is installed.
209 The **rlibs** attribute is not compulsory but it can be used to indicate a search path for dynamic libraries in execution.
210 **libs** is used during the link phase. **rlibs** is only used during execution, it avoids the need to set the LD_LIBRARY_PATH
211 environment variable to find the dynamic library.
214 """"""""""""""""""""""""""""""""""""""""""""""""""""
215 Includes will be added using the **defs** attribute. For example::
217 defs="""#include "myinclude.h" """
219 The include paths will be specified in the **includes** attribute of the component in the following form::
222 defs="""#include "myinclude.h"
223 extern double myfunc(double);
225 c1=CPPComponent("mycompo",
228 inport=[("inputport","double"),],
229 outport=[("outputport","double")],
231 body="outputport=myfunc(inputport);",
234 libs=[Library(name="mybib", path="/usr/local/mysoft")],
235 rlibs="/usr/local/mysoft",
236 includes="/usr/local/mysoft/include",
239 Multiple include paths should be separated by spaces or end of line character (\\n).
242 """"""""""""""""""""""""""""""""""""""""""""""""""""
243 It is possible to add some source files with the **sources** attribute (a list of source files will be given).
245 For example, instead of using an external library, we could implement the function myfunc in a file
246 named myfunc.cpp. The description will be::
248 defs="""#include "myinclude.h"
249 extern double myfunc(double);
251 c1=CPPComponent("mycompo",
254 inport=[("inputport","double"),],
255 outport=[("outputport","double")],
257 body="outputport=myfunc(inputport);",
260 sources=["myfunc.cpp"],
261 includes="/usr/local/mysoft/include",
265 HXX2SALOME components
266 +++++++++++++++++++++
268 For computational codes which exchange arrays, MED meshes and fields, the implementation of the SALOME component is more complex.
269 hxx2salome is a Salome generation tool for dataflow C++ components, which is available in SALOME since version 4.
271 Its principle is to start the integration of a code (written in Fortran/C/C++ or any C-compatible language)
272 by writing a C++ layer (a class), which purpose is to drive the underlying code, and exchange data at C++ standard
273 (c++ integral types, STL strings and vectors) and MED types for numerical meshes and fields.
275 Then the Salome CORBA layer (a SALOME C++ component) is generated automatically by the tool.
276 The implementation of the component, which has to be provided in standard YACSGEN through the defs and body attributes,
277 is generated here through analysing the interface of the c++ layer written above the code.
279 hxx2salome tool, although still available in Salome 6 as a standalone tool, was merged within YACSGEN.
280 For the general principles of HXX2SALOME, and the detailed documentation, please refer to
281 the HXX2SALOME chapter of this documentation (:ref:`hxx2salome`). We will only present here the embedded use of HXX2SALOME within YACSGEN.
284 The tool can be used in two different ways:
286 - within a YACSGEN python script, by using the **HXX2SALOMEComponent** class combined with other YACSGEN CLASSES.
287 - with the **hxx2salome.py** script, a python executable which use YACSGEN classes to reproduce the interface of the former former hxx2salome bash script.
290 using the **HXX2SALOMEComponent** class
291 """""""""""""""""""""""""""""""""""""""
293 The merge of hxx2salome within YACSGEN was done by adding a new class, called **HXX2SALOMEComponent**, to the YACSGEN package.
294 Given a C++ component (a C++ layer which wraps a computational code), HXX2SALOMEComponent class parses its interface
295 (as defined in its .hxx header), extracts the public methods, analyses the types of these methods,
296 and uses this type information to generate the implementation. All the information is then given to YACSGEN which generate a ready-to-use component.
298 As an example, let's suppose we have a code called mycode, wrapped by a C++ layer
299 (a dynamic library libmycodeCXX.so, and its interface "mycode.hxx", both located in directory mycodecpp_root_dir).
300 To generate the SALOME C++ component, one should add in his YACS script: ::
302 from module_generator HXX2SALOMEComponent
303 c1=HXX2SALOMEComponent("mycode.hxx",
305 mycodecpp_root_dir ) )
307 The HXX2SALOMEComponent takes three arguments : the C++ header, the C++ library, and the path where to find them. The class does the parsing of c++ and generate all the necessary information for YACSGEN to generate the SALOME module.
309 Finally, if the code is parallel (mpi), one has to use instead the **HXX2SALOMEParaComponent**. This class work exactly in the same way, but generates also
310 the mpi code necessary for a parallel SALOME component.
313 Using **hxx2salome.py** executable
314 """"""""""""""""""""""""""""""""""
316 **hxx2salome.py** script is a python executable which use YACSGEN classes to reproduce the interface of the former hxx2salome bash script.
317 The script takes optional arguments, followed by four mandatory arguments: ::
322 hxx2salome.py [options] <CPPCOMPO>_root_dir lib<CPPCOMPO>.hxx <CPPCOMPO>.so installDir
324 generate a SALOME component that wrapps given the C++ component
328 - <CPPCOMPO>_root_dir : install directory (absolute path) of the c++ component
329 - <CPPCOMPO>.hxx : header of the c++ component"
330 - lib<CPPCOMPO>.so : the shared library containing the c++ component
331 - installDir : directory where the generated files and the build should be installed
333 Note that <CPPCOMPO>.hxx and lib<CPPCOMPO>.so should be found in <CPPCOMPO>_root_dir)
338 -h, --help show this help message and exit
339 -e ENVIRON_FILE specify the name of a environment file (bash/sh) that will
341 -g to create a generic gui in your component building tree
342 -c to compile after generation
345 The mandatory argument are respectively :
346 - the path where the C++ component was installed,
347 - within this path the name of the interface header,
348 - the name of the dynamic library,
349 - and finally the location where to generate and compile the Salome component.
351 As an example, the command to generate the mycode component would be: ::
353 hxx2salome.py -c -g -e salome.sh
354 mycodecpp_root_dir mycode.hxx
355 libmycodeCXX.so <absolute path where to install generated component>
361 ++++++++++++++++++++++++++++++++++++++++
362 A Fortran component is described like a C++ component, except that there are a few differences. Firstly, the F77Component
363 definition object is used instead of the CPPComponent. Then, a special additional interface is made in Fortran.
364 It is assumed that Fortran functions are implemented in a library (dynamic or static) that will be linked with the component and
365 that will have several entry points with the same names as the component services. The call to this entry point will be added
366 automatically after the C++ code supplied by the user in the **body** attribute.
368 This makes it possible to decouple practically the entire implementation of the Fortran component that will be in
369 the external library or sources, from the implementation of the SALOME component that will only be used for encapsulation.
371 The following example will be used to specify these final concepts::
373 c3=F77Component("compo3",
376 inport=[("a","double"),("b","long"),
378 outport=[("d","double"),("e","long"),
380 instream=[("a","CALCIUM_double","T"),
381 ("b","CALCIUM_double","I")],
382 outstream=[("ba","CALCIUM_double","T"),
383 ("bb","CALCIUM_double","I")],
384 defs="#include <unistd.h>",
388 libs=[Library(name="fcompo", path="/usr/local/fcompo")],
389 rlibs="/usr/local/fcompo"
392 The Fortran “compo3” component has dataflow and datastream ports like the C++ component. The Fortran dynamic library
393 that contains the Fortran entry point *s1* will be linked by means of the **libs** and **rlibs** attributes of the description.
394 The Fortran component also supports the **includes** and **sources** attributes.
396 The Fortran subroutine with name **s1** must have a signature with a first argument that is used to transmit the address of
397 the component and all following arguments that are used to transmit the values of the inport and outport ports. The instream and
398 outstream ports are managed internally to the subroutine through calls to the CALCIUM API with the address of the component
401 An example of subroutine for the above definition follows:
403 .. code-block:: fortran
405 SUBROUTINE S1(compo,A,B,C,D,E,F)
406 C implementation of service s1 with inport a,b,c and outport d,e,f and stream ports
413 CALL cpldb(COMPO,CP_TEMPS,t0,t1,iter,'aa',1,n,ss,info)
414 CALL cpldb(COMPO,CP_ITERATION,t0,t1,iter,'ab',1,n,zz,info)
415 CALL cplen(COMPO,CP_ITERATION,t0,t1,iter,'ac',1,n,zn,info)
416 CALL cplre(COMPO,CP_ITERATION,t0,t1,iter,'ad',1,n,yr,info)
417 CALL cplch(COMPO,CP_ITERATION,t0,t1,iter,'ae',1,n,tch,info)
418 CALL cplcp(COMPO,CP_ITERATION,t0,t1,iter,'af',1,n,tcp,info)
419 CALL cpllo(COMPO,CP_ITERATION,t0,t1,iter,'ag',3,n,tlo,info)
421 CALL cpeDB(COMPO,CP_TEMPS,t0,1,'ba',1,tt,info)
422 CALL cpeDB(COMPO,CP_ITERATION,t0,1,'bb',1,tp,info)
430 As a special case, since version 5.1.4, the first argument (address of the component) is not included, if there is no
431 instream and outstream ports.
433 Same example without stream ports:
435 .. code-block:: fortran
437 SUBROUTINE S1(A,B,C,D,E,F)
438 C implementation of service s1 with inport a,b,c and outport d,e,f
447 A piece of C++ code can be added before the call to the Fortran entry point. This piece of code must be put into the **body**
448 attribute with any definitions in **defs**. In this case, we use the “c” input dataflow variable to change the directory with the call to chdir.
451 ++++++++++++++++++++++++++++++++++++++++
452 A Python component is also described like a C++ component. The only differences are in the Python object to be used to
453 define it: PYComponent instead of CPPComponent and in the content of the **defs** and **body** attributes that must contain
454 Python code and not C++.
457 The indentation of the complete block of code is automatically handled but not the internal indentation of the block.
459 Example Python component::
461 pyc1=PYComponent("mycompo",
464 inport=[("inputport","double"),],
465 outport=[("outputport","double")],
467 body=" outputport=2*inputport;",
472 The equivalent of the assembly with external libraries is done in this case with the possibility of importing external
473 Python modules. Simply add the **python_path** attribute to the description of the component to obtain this possibility.
474 The value to be given is a list of directories that might contain modules to be imported.
478 pyc1=PYComponent("mycompo",
481 inport=[("inputport","double"),],
482 outport=[("outputport","double")],
485 python_path=["/usr/local/mysoft","/home/chris/monsoft"],
491 ++++++++++++++++++++++++++++++++++++++++
492 *Code_Aster* is a software package for finite element analysis and numeric simulation in structural mechanics developed by EDF.
494 An Aster component is a component that is a little bit special because the software functions are implemented in Fortran but
495 they are activated by a command supervisor written in Python. Finally, this supervisor executes a Python script but the data
496 transfer between Python and Fortran and the integration of the command supervisor into a SALOME component have to be managed.
498 The start point is that it is assumed that there is an Aster installation that provides an aster python module in the form of
499 an importable dynamic library (astermodule.so) and not a specific Python interpreter linked with this module, as is the case
500 in the existing installation.
502 An Aster component is described as a Python component to which several important attributes have to be added.
504 - the **python_path** attribute: this indicates the path of the directory containing the aster module (astermodule.so)
505 - the **aster_dir** attribute: this indicates the path of the Aster installation directory
506 - the **argv** attribute: this initialises command line parameters. For example, it will be set equal to the value
507 of memjeveux (``argv=[“-memjeveux”,”10”]``) or rep_outils.
509 The following shows a small example description of an Aster component with a single service provided with 3 input dataflow
510 ports, one output dataflow port, 7 input datastream ports and one output datastream port::
512 c1=ASTERComponent("caster",
515 inport=[("a","double"),("b","long"),
517 outport=[("d","double")],
518 instream=[("aa","CALCIUM_double","T"),
519 ("ab","CALCIUM_double","I"),
520 ("ac","CALCIUM_integer","I"),
521 ("ad","CALCIUM_real","I"),
522 ("ae","CALCIUM_string","I"),
523 ("af","CALCIUM_complex","I"),
524 ("ag","CALCIUM_logical","I"),
526 outstream=[("ba","CALCIUM_double","T"),
527 ("bb","CALCIUM_double","I")],
530 aster_dir="/local/chris/ASTER/instals/NEW9",
531 python_path=["/local/chris/modulegen/YACSGEN/aster/bibpyt"],
532 argv=["-memjeveux","10",
533 "-rep_outils","/local/chris/ASTER/instals/outils"],
537 Do not use the name “aster” for the component because this name is reserved for the *Code_Aster* python module.
538 If the name “aster” is used, the behaviour will be completely erratic.
540 Although its description is very similar to the behaviour of a Python component, there is an important difference in use.
541 The Aster component needs the description of a command set to run. This command set is transferred to each service of the
542 component in the form of a text in an input dataflow port named “jdc” with type “string”. Therefore after generation, this
543 Aster component will have four input dataflow ports (“jdc”, “a”, “b”, “c”) and not three as indicated in the description.
544 It is important not to forget to initialise the “jdc” port in the coupling file with a command set.
546 The command supervisor has been integrated into a SALOME component and the variables received in the dataflow ports are available
547 during execution of the command set. Similarly, values for output dataflow ports are defined by values of variables derived
548 from execution of the command set.
551 **Beware with the execution mode**. The command supervisor has 2 execution modes (PAR_LOT=”OUI” or PAR_LOT=”NON” that are
552 specified in the DEBUT command) (PAR_LOT = BY_BATCH). In PAR_LOT=”OUI” mode, it is compulsory to terminate the command set
553 with a FIN (END) command which has the effect of interrupting execution. This is not the preferred method of operation with YACS.
554 It is preferable to use PAR_LOT=”NON” mode without adding the FIN command, which avoids interrupting the execution prematurely.
556 Dynamically importable Aster module and link with YACS
557 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
558 These two points are not handled by YACSGEN. They must be processed separately in a context similar to the context of an Aster developer.
560 It is assumed that there is an Aster installation, that it is required to create a dynamically importable Python Aster module, and
561 that a few commands are to be added to Aster to exchange data through YACS datastream ports.
563 To remain simple, three commands: YACS_INIT, ECRIRE_MAILLAGE and LECTURE_FORCE are added, for which the catalogs are::
565 YACS_INIT=PROC(nom="YACS_INIT",op=181, fr="YACS initialisation",
566 COMPO=SIMP(statut='o',typ='I'),
568 ECRIRE_MAILLAGE=PROC(nom="ECRIRE_MAILLAGE",op=78, fr="write mesh")
569 LECTURE_FORCE=PROC(nom="LECTURE_FORCE",op=189, fr="read force")
571 The first YACS_INIT command initialises Aster in the YACS context. It has a single simple keyword COMPO (integer type) that
572 will be used to transfer the SALOME component identifier to other commands. This identifier will be stored in a Fortran COMMON.
573 It is essential for calls to subprograms CPLxx and CPExx that will be used in the other two ECRIRE_MAILLAGE and LECTURE_FORCE commands.
575 The other two commands do not have any keyword and they retrieve the identifier from the COMMON.
577 The operators will be written as follows (without the declarations):
579 .. code-block:: fortran
581 SUBROUTINE OP0189 ( IER )
582 C COMMANDE: LECTURE_FORCE
585 CALL cpldb(ICOMPO,CP_TEMPS,t0,t1,iter,'aa',1,n,ss,info)
586 CALL cpldb(ICOMPO,CP_ITERATION,t0,t1,iter,'ab',1,n,zz,info)
587 CALL cplen(ICOMPO,CP_ITERATION,t0,t1,iter,'ac',1,n,zn,info)
588 CALL cplre(ICOMPO,CP_ITERATION,t0,t1,iter,'ad',1,n,yr,info)
589 CALL cplch(ICOMPO,CP_ITERATION,t0,t1,iter,'ae',1,n,tch,info)
590 CALL cplcp(ICOMPO,CP_ITERATION,t0,t1,iter,'af',1,n,tcp,info)
591 CALL cpllo(ICOMPO,CP_ITERATION,t0,t1,iter,'ag',3,n,tlo,info)
594 SUBROUTINE OP0078 ( IER )
595 C COMMANDE: ECRIRE_MAILLAGE
598 CALL cpeDB(ICOMPO,CP_TEMPS,t0,1,'ba',1,tt,info)
599 CALL cpeDB(ICOMPO,CP_ITERATION,t0,1,'bb',1,tp,info)
602 Finally, an astermodule.so dynamic library must be constructed, and all necessary Python modules must be placed in a directory
603 that will be indicated in the **python_path** attribute. Different methods can be used to obtain this result.
604 The following Makefile is one of them:
611 KERNEL_ROOT_DIR=/local/chris/SALOME/RELEASES/Install/KERNEL_V5
612 KERNEL_INCLUDES=-I$(KERNEL_ROOT_DIR)/include/salome
613 KERNEL_LIBS= -L$(KERNEL_ROOT_DIR)/lib/salome -lCalciumC -lSalomeDSCSuperv \
614 -lSalomeDSCContainer -lSalomeDatastream -lSalomeDSCSupervBasic \
615 -Wl,--rpath -Wl,$(KERNEL_ROOT_DIR)/lib/salome
617 ASTER_ROOT=/local/chris/ASTER/instals
618 ASTER_INSTALL=$(ASTER_ROOT)/NEW9
619 ASTER_PUB=$(ASTER_ROOT)/public
620 ASTER_LIBS = -L$(ASTER_INSTALL)/lib -laster \
621 -L$(ASTER_PUB)/scotch_4.0/bin -lscotch -lscotcherr \
622 -lferm -llapack -lhdf5
623 SOURCES=src/op0078.f src/op0189.f
624 CATAPY=catalo/ecrire_maillage.capy catalo/lecture_force.capy
626 all:pyth cata astermodule
628 cp -rf $(ASTER_INSTALL)/bibpyt .
629 cata: commande/cata.py
630 cp -rf commande/cata.py* bibpyt/Cata
631 commande/cata.py:$(CATAPY)
632 $(ASTER_ROOT)/ASTK/ASTK_SERV/bin/as_run make-cmd
633 astermodule:astermodule.so pyth
634 cp -rf astermodule.so bibpyt
635 astermodule.so: $(SOURCES)
636 $(FC) -shared -o $@ $(SOURCES) $(KERNEL_INCLUDES) $(ASTER_LIBS) $(KERNEL_LIBS)
638 Modify command line parameters during execution
639 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
640 The **argv** attribute gives initial values to arguments such as “memjeveux” but these values are used by the generator to
641 build the component and therefore remain constant afterwards during execution.
643 If you want to modify these values during execution, you need to add an input port named “argv” with type “string”. The character
644 string that will be given as the value of this port will be used by the component to modify the arguments of the command
645 line (see :ref:`execaster` for an example use).
647 Management of the elements file
648 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
649 The finite elements file is automatically copied into the working directory under the name elem.1.
650 The component uses the **aster_dir** attribute to locate the origin file.
652 Supported Aster versions
653 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
654 YACSGEN can function with Aster 9 and higher versions.
656 SALOME module generator
657 -----------------------------------------------------------
658 The SALOME module is created by a generator constructed from the description of the SALOME module (m) seen previously
659 and a Python dictionary (context) that provides some environment parameters::
661 g=Generator(m,context)
663 The following parameters are mandatory for this context:
665 - **prerequisites**: indicates the path of a shell script that sets the environment variables of SALOME prerequisites
666 - **kernel**: indicates the installation path of the SALOME KERNEL module
667 - **update**: set equal to 1 at the moment (future development)
669 Example creation of generator::
672 "prerequisites":"/local/cchris/.packages.d/envSalome",
673 "kernel":"/local/chris/SALOME/RELEASES/Install/KERNEL_V5"
675 g=Generator(m,context)
677 Once this generator has been created, simply call its commands to perform the necessary operations.
679 - SALOME module generation: ``g.generate()``
680 - build configuration: ``g.configure()``
681 - compilation: ``g.make()``
682 - installation in the directory <prefix>: ``g.install()``
683 - create a SALOME application in the directory **appli_dir**::
685 g.make_appli(appli_dir,restrict=<liste de modules>,
686 altmodules=<dictionnaire de modules>)
688 These commands do not use any parameters except for make_appli that uses 3 parameters:
690 - **appliname**: the name of the directory that will contain the SALOME application
691 - **restrict**: a list of SALOME module names to put into the application. By default, make_appli puts all SALOME modules
692 that it can detect into the application (neighbour directories of KERNEL with the same suffix as KERNEL. If the directory
693 of the KERNEL module is called KERNEL_V5, then it will use GUI_V5, GEOM_V5, etc.). If restrict is provided, make_appli will
694 only use the modules listed.
695 - **altmodules**: a dictionary of other modules. The key gives the name of the module. The corresponding value gives the path
696 of the module installation directory. For example ``altmodules={"mymodule":"/local/chris/amodule"}``
698 Fabrication of the SALOME module
699 -----------------------------------------------------
700 The module will be fabricated by executing a Python file that contains its description, by inputting data into the generator
701 and generator commands.
703 This gives something like the following for a module with a single Fortran component:
705 .. code-block:: python
707 from module_generator import Generator,Module
708 from module_generator import PYComponent,CPPComponent,Service,F77Component
711 "prerequisites":"/local/cchris/.packages.d/envSalome",
712 "kernel":"/local/chris/SALOME/RELEASES/Install/KERNEL_V5"
716 c1=F77Component("compo",
719 inport=[("a","double"),
722 outport=[("d","double"),("e","long"),
724 instream=[("a","CALCIUM_double","T"),
725 ("b","CALCIUM_double","I")],
726 outstream=[("ba","CALCIUM_double","T"),
727 ("bb","CALCIUM_double","I")],
728 defs="#include <unistd.h>",
732 libs=[Library(name="fcompo", path="/local/chris/modulegen/YACSGEN/fcompo")],
733 rlibs="/local/chris/modulegen/YACSGEN/fcompo")
735 m=Module("mymodule",components=[c1],prefix="Install")
736 g=Generator(m,context)
741 g.make_appli("appli",restrict=["KERNEL","GUI","YACS"])
743 If this description is in the mymodule.py file, all that is required is to execute::
747 which has the effect of creating the module source directory (mymodule_SRC), the module installation directory (Install) and a
748 SALOME application directory (appli).
750 Obviously, it must be possible to import the **module_generator** package either while being in the current directory or in the PYTHONPATH.
752 It is always preferable (although not essential) to clean up the working directory before executing the generator.
754 Using the component in a coupling
755 -----------------------------------------------------------------------------------------
756 Create the YACS coupling file
757 ++++++++++++++++++++++++++++++++++++++++
758 A YACS coupling file is an XML file that describes how SALOME components previously installed in a SALOME application are coupled and executed.
760 See :ref:`schemaxml` for documentation about how to write a YACS XML file.
762 The following is an example of a YACS file using the Fortran component defined above:
767 <container name="A"> </container>
768 <container name="B"> </container>
770 <service name="pipo1" >
771 <component>compo</component>
773 <load container="A"/>
774 <inport name="a" type="double"/>
775 <inport name="b" type="int"/>
776 <inport name="c" type="string"/>
777 <outport name="d" type="double"/>
778 <outport name="e" type="int"/>
779 <outport name="f" type="string"/>
780 <instream name="a" type="CALCIUM_double"/>
781 <instream name="b" type="CALCIUM_double"/>
782 <outstream name="ba" type="CALCIUM_double"/>
783 <outstream name="bb" type="CALCIUM_double"/>
785 <service name="pipo2" >
786 <component>compo</component>
788 <load container="B"/>
789 <inport name="a" type="double"/>
790 <inport name="b" type="int"/>
791 <inport name="c" type="string"/>
792 <outport name="d" type="double"/>
793 <outport name="e" type="int"/>
794 <outport name="f" type="string"/>
795 <instream name="a" type="CALCIUM_double"/>
796 <instream name="b" type="CALCIUM_double"/>
797 <outstream name="ba" type="CALCIUM_double"/>
798 <outstream name="bb" type="CALCIUM_double"/>
802 <fromnode>pipo1</fromnode><fromport>ba</fromport>
803 <tonode>pipo2</tonode><toport>a</toport>
806 <fromnode>pipo1</fromnode><fromport>bb</fromport>
807 <tonode>pipo2</tonode><toport>b</toport>
810 <fromnode>pipo2</fromnode><fromport>ba</fromport>
811 <tonode>pipo1</tonode><toport>a</toport>
814 <fromnode>pipo2</fromnode><fromport>bb</fromport>
815 <tonode>pipo1</tonode><toport>b</toport>
818 <tonode>pipo1</tonode> <toport>a</toport>
819 <value><double>23</double> </value>
822 <tonode>pipo1</tonode> <toport>b</toport>
823 <value><int>23</int> </value>
826 <tonode>pipo1</tonode> <toport>c</toport>
827 <value><string>/local/cchris/SALOME/SUPERV/YACS/modulegen/data1</string> </value>
830 <tonode>pipo2</tonode> <toport>a</toport>
831 <value><double>23</double> </value>
834 <tonode>pipo2</tonode> <toport>b</toport>
835 <value><int>23</int> </value>
838 <tonode>pipo2</tonode> <toport>c</toport>
839 <value><string>/local/cchris/SALOME/SUPERV/YACS/modulegen/data2</string> </value>
844 In general terms, coupling uses two instances of the component compo (pipo1 and pipo2) of which the service s1 is executed.
845 The datastream ports of these services are connected using fromnode, fromport, tonode, toport information in the stream sections.
846 The dataflow ports are initialised by the parameter sections. In particular, the working directory of each component instance
847 is initialised through input port “c” of each component instance. Each component instance is executed in a different container (A and B).
848 These names are virtual. SALOME will decide on the effective name of the containers at the time of the startup. The following simply
849 describes constraints on containers to be used. In fact, there is only one constraint, which is that the containers have to be different.
852 +++++++++++++++++++++++++++++++++++++++++++++
853 Once the coupling file has been written using a classical editor or the YACS graphic editor, execution can be started.
855 It takes place in several steps:
857 - start SALOME: execute the runAppli script of the SALOME application (``./appli/runAppli –t``). The application runs
858 as a background task until it is stopped.
859 - start coupling: execute the YACS coupler in the environment of the running SALOME application (``./appli/runSession driver test.xml``)
860 with test.xml as the coupling file.
861 - stop the application: ``./appli/runSession killSalome.py``
863 There are many coupling outputs:
865 - the output from the coupler itself. If no execution error is returned to the coupler, the output will only contain one useful
866 item of information: the name of containers started by SALOME to execute the components. If execution errors are returned to
867 the coupler, they will be listed at the end of execution.
868 - container outputs: these outputs are located in the /tmp directory with a name constructed based on the container name read
869 in the coupler output.
872 When the application is stopped, the containers are killed, and this can cause information losses in their output files.
874 The working directory
875 ++++++++++++++++++++++++++++++++++++++
876 Each component instance is hosted in a container. Therefore all instances hosted in a container are executed in the same
877 directory, which is the container directory. Starting from version 4.1.1 of SALOME, the working directory of a container
878 can be specified in the coupling file. All that is necessary is to add the **workingdir** property to the container.
879 The following gives a few examples:
884 <property name="workingdir" value="/home/user/w1"/>
887 <property name="workingdir" value="$TEMPDIR"/>
890 <property name="workingdir" value="a/b"/>
893 The container A is executed in directory “/home/user/w1”. This directory will be created if it does not exist.
894 The container B will be executed in a new temporary directory.
895 Container C will be executed in the relative directory “a/b” (starting from the directory of the application used
896 for the execution). This directory will be created if it does not already exist.
899 ++++++++++++++++++++++++++++
900 Components are dynamic libraries or Python modules, and they cannot be run in shell scripts. For components that use input and
901 output files, “files” ports can be specified in the coupling file through which file transfers will be made and appropriate
902 local names will be given. For example, a service that uses an input file a and produces an output file b will be declared as follows:
906 <service name="pipo1">
907 <component>caster</component>
909 <inport name="a" type="file"/>
910 <outport name="b" type="file"/>
913 These ports can be initialised or connected to other “files” ports like ordinary ports. For example, initialisation for the input
914 file will be in the following form:
919 <tonode>pipo1</tonode> <toport>a</toport>
920 <value><objref>/local/chris/tmp/unfichier</objref> </value>
923 It is impossible to initialise an output file port directly. A special node has to be used that collects outputs.
924 A “dataout” node and the link between node “pipo1” and node “dataout” will be created:
928 <outnode name="dataout" >
929 <parameter name="f1" type="file" ref="myfile"/>
932 <fromnode>pipo1</fromnode><fromport>b</fromport>
933 <tonode>dataout</tonode> <toport>f1</toport>
937 It is impossible to use the “.” character in port names. This prevents the use of names such as fort.8 that are
938 fairly frequent. There is a simple workaround solution, which is to replace the “.” by the “:”character (therefore fort:8 in
939 our example) to obtain the expected result.
940 Obviously, names containing the “:” characters cannot be used. They must be very rare.
944 Example execution of an Aster component
945 +++++++++++++++++++++++++++++++++++++++++++
946 There are a few unusual features when executing an Aster component that are presented below:
948 - handling the command set
949 - specification of parameters in the command line
950 - specification of a mesh file (.mail)
951 - specification of environment variables (also valid for other component types).
953 The following is a simplified example of a YACS scheme comprising a calculation node that should execute service s1 of
954 the caster component (type Aster) with an environment variable, a mail file, a comm file and command line parameters.
955 A more complete example is given in the directory Examples/ast1 in the distribution:
959 <service name="pipo1" >
960 <component>caster</component>
961 <property name="MYENVAR" value="25"/>
963 <load container="A"/>
964 <inport name="jdc" type="string"/>
965 <inport name="argv" type="string"/>
966 <inport name="a" type="double"/>
967 <inport name="fort:20" type="file"/>
968 <outport name="d" type="double"/>
969 <instream name="aa" type="CALCIUM_double"/>
970 <outstream name="ba" type="CALCIUM_double"/>
973 <inline name="ljdc" >
975 <code>f=open(comm)</code>
976 <code>jdc=f.read()</code>
977 <code>f.close()</code>
979 <inport name="comm" type="string"/>
980 <outport name="jdc" type="string"/>
984 <tonode>ljdc</tonode> <toport>comm</toport>
985 <value><string>/home/chris/jdc.comm</string> </value>
989 <fromnode>ljdc</fromnode><fromport>jdc</fromport>
990 <tonode>pipo1</tonode> <toport>jdc</toport>
994 <tonode>pipo1</tonode> <toport>argv</toport>
995 <value><string>-rep_outils /aster/outils</string> </value>
999 <tonode>pipo1</tonode> <toport>fort:20</toport>
1001 <objref>/local/chris/ASTER/instals/NEW9/astest/forma01a.mmed</objref>
1005 Firstly, the command set has to be specified. As mentioned above (:ref:`aster`), an additional “jdc” “string” type port
1006 has to be declared and it has to be initialised or connected. In this case, the jdc port is connected to an output port
1007 from a python node (ljdc) that will read the .comm file, for which the path is given to it by its comm input port.
1008 The component identifier is transferred to the YACS_INIT command by means of the “component” variable that is
1009 automatically added by the generator and is available to write the .comm file.
1011 Brief example of .comm::
1013 DEBUT(PAR_LOT="NON")
1014 YACS_INIT(COMPO=component)
1018 Before values of command line parameters can be specified, a component must have been created with a “string” type port named “argv”.
1019 A value then has to be given to this port. In this case, we modify the tools directory path using the **rep_outils** parameter.
1021 A mesh file (.mail) is specified to an Aster component by adding a file port to the calculation node:
1025 <inport name="fort:20" type="file"/>
1027 The name of this file port must be the same as the local file name as expected by Aster. Usually, Aster uses
1028 the fort.20 file as an input to LIRE_MAILLAGE. As mentioned above, the dot in fort.20 cannot be used in a port
1029 name, and therefore it will be given the name fort:20. A value will then have to be given to this port that will
1030 correspond to the path of the file to be used. This is done by a parameter directive:
1035 <tonode>pipo1</tonode> <toport>fort:20</toport>
1037 <objref>/local/chris/ASTER/instals/NEW9/astest/forma01a.mmed</objref>
1041 Environment variables are specified by using properties of the calculation node. In this case, we define
1042 the MYENVAR environment variable with value 25.
1044 Standalone components
1045 --------------------------------------------------
1046 Before SALOME version 4.1, the only method for integrating a component was to produce a dynamic library (\*.so) or a python
1047 module (\*.py). This component is loaded by a SALOME executable named Container, either by dlopen in the case of the
1048 library or by import in the case of the Python module. This method is a little constraining for calculation codes
1049 like *Code_Aster* or *Code_Saturne* that are executed in a particular environment, and preferably from a shell script.
1051 Starting from version 4.1.3, a component can be integrated as an executable or shell script. This new function is
1052 experimental at the moment and it will have to be tested more completely. However, it can be used and module_generator
1053 was adapted (starting from version 0.3) to generate standalone components. The following describes operations to be carried out
1054 to change to standalone mode for each type of component (C/C++, Python, Fortran or Aster).
1057 ++++++++++++++++++++++++++++++++++++++++
1058 All that is necessary to transform a standard C/C++ component in the form of a dynamic library into a standalone component, is
1059 to add two attributes to its description:
1061 - the **kind** attribute: by setting the value “exe”
1062 - the **exe_path** attribute: by setting its value equal to the path of the executable or the shell script that will be used
1063 when the component is started
1065 The following is an example of a C++ component modified to make it a standalone component::
1067 c1=CPPComponent("compo1",services=[
1068 Service("myservice",inport=[("inputport","double"),],
1069 outport=[("outputport","double")],
1073 exe_path="/local/SALOME/execpp/prog",
1076 The path given for **exe_path** corresponds to an executable with the following source:
1080 #include "compo1.hxx"
1082 int main(int argc, char* argv[])
1088 It must be compiled and linked using the compo1.hxx include and the libcompo1Exelib.so library that are given
1089 in the installation of the module generated in include/salome and in lib/salome respectively.
1093 the SALOME module must be generated before compiling and linking the standalone component.
1095 A more complete example is given in the distribution sources in the Examples/cpp2 directory.
1097 The executable can be replaced by an intermediary shell script, but it is good to know that the call to yacsinit
1098 retrieves information necessary to initialise the component in the three environment variables (*SALOME_CONTAINERNAME*,
1099 *SALOME_INSTANCE*, *SALOME_CONTAINER*).
1102 ++++++++++++++++++++++++++++++++++++++++
1103 The method for a Fortran component is exactly the same. The same two attributes are added:
1105 - The **kind** attribute: by setting the value “exe”
1106 - The **exe_path** attribute: by setting its value equal to the path of the executable or the shell script that will
1107 be used when the component is started
1109 The following is an example of a standalone Fortran component::
1111 c3=F77Component("compo3",services=[
1112 Service("s1",inport=[("a","double"),("b","long"),
1114 outport=[("d","double"),("e","long"),
1116 instream=[("a","CALCIUM_double","T"),
1117 ("b","CALCIUM_double","I")],
1118 outstream=[("ba","CALCIUM_double","T"),
1119 ("bb","CALCIUM_double","I")],
1123 exe_path="/local/SALOME/fcompo/prog",
1126 The path given for **exe_path** corresponds to an executable with the following source:
1128 .. code-block:: fortran
1134 It must be compiled and linked using the libcompo3Exelib.so library that is located in the installation of the module
1135 generated in lib/salome, and with the Fortran source containing subroutine S1.
1136 Refer to a more complete example in distribution sources in the Examples/fort2 directory.
1139 ++++++++++++++++++++++++++++++++++++++++
1140 A very rudimentary generator has been coded for a Python component. The only possible action is to add the **kind**
1141 attribute (with the value "exe"). The executable is automatically generated in the module installation.
1142 It cannot be replaced by a script, unless the installation is modified.
1144 Standalone Aster component
1145 ++++++++++++++++++++++++++++++++++++++++
1146 Slightly more work is necessary for an Aster component. Three attributes have to be specified:
1148 - the **aster_dir** attribute: that gives the path of the *Code_Aster* installation
1149 - the **kind** attribute: with the “exe” value
1150 - the **exe_path** attribute: that gives the path of the shell script that will be used when the component is started
1152 The following is an example description of a standalone Aster component::
1154 c1=ASTERComponent("caster",services=[
1155 Service("s1",inport=[("argv","string"),("a","double"),
1156 ("b","long"),("c","string")],
1157 outport=[("d","double")],
1158 instream=[("aa","CALCIUM_double","T"),
1159 ("ab","CALCIUM_double","I"),
1160 ("ac","CALCIUM_integer","I"),
1161 ("ad","CALCIUM_real","I"),
1162 ("ae","CALCIUM_string","I"),
1163 ("af","CALCIUM_complex","I"),
1164 ("ag","CALCIUM_logical","I"),
1166 outstream=[("ba","CALCIUM_double","T"),
1167 ("bb","CALCIUM_double","I")],
1170 aster_dir="/aster/NEW9",
1172 exe_path="/home/SALOME5/exeaster",
1175 The “effective” command file always has to be specified in the XML coupling file.
1177 Example coupling with standalone components
1178 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1179 By collecting all the above elements, coupling of a standalone Aster component with a standalone Fortran component is
1180 written as follows::
1182 from module_generator import Generator,Module
1183 from module_generator import ASTERComponent,Service,F77Component
1185 context={'update':1,"prerequisites":"/home/SALOME5/env.sh",
1186 "kernel":"/home/SALOME5/Install/KERNEL_V5"}
1188 install_prefix="./exe_install"
1189 appli_dir="exe_appli"
1191 c1=ASTERComponent("caster",services=[
1192 Service("s1",inport=[("a","double"),("b","long"),
1194 outport=[("d","double")],
1195 instream=[("aa","CALCIUM_double","T"),
1196 ("ab","CALCIUM_double","I"),
1197 ("ac","CALCIUM_integer","I"),
1198 ("ad","CALCIUM_real","I"),
1199 ("ae","CALCIUM_string","I"),
1200 ("af","CALCIUM_complex","I"),
1201 ("ag","CALCIUM_logical","I"),
1203 outstream=[("ba","CALCIUM_double","T"),
1204 ("bb","CALCIUM_double","I")],
1208 aster_dir="/aster/NEW9",
1209 exe_path="/home/SALOME5/exeaster",
1212 c2=F77Component("cfort",services=[
1213 Service("s1",inport=[("a","double"),("b","long"),
1215 outport=[("d","double"),("e","long"),
1217 instream=[("a","CALCIUM_double","T"),
1218 ("b","CALCIUM_double","I")],
1219 outstream=[("ba","CALCIUM_double","T"),
1220 ("bb","CALCIUM_double","I"),
1221 ("bc","CALCIUM_integer","I"),
1222 ("bd","CALCIUM_real","I"),
1223 ("be","CALCIUM_string","I"),
1224 ("bf","CALCIUM_complex","I"),
1225 ("bg","CALCIUM_logical","I"),
1230 exe_path="/home/SALOME5/fcompo/prog",
1233 g=Generator(Module("astmod",components=[c1,c2],prefix=install_prefix),context)
1238 g.make_appli(appli_dir,restrict=["KERNEL","YACS"])
1240 The corresponding xml coupling file and Aster command file may be viewed in the distribution (Examples/ast2 directory).
1241 The complementary implantation elements are located in the fcompo directory (cfort component) and in the myaster directory (caster component).
1244 -----------------------------------------------------------------
1245 YACSGEN is mainly targeted to the integration of Python, C++ or Fortran calculation codes.
1246 Nevertheless, if you want to generate a complete module with GUI, documentation and persistence,
1247 there are some minimal options to do that.
1250 ++++++++++++++++++++++++++++++++++++++++
1251 It is possible to add a C++ or a Python GUI to the module with the *gui* parameter of the module.
1252 This parameter must be a list of file names. These files can be source files (\*.cxx, \*.hxx or \*.h for C++, \*.py for python),
1253 image files (\*.png, ...) and qt designer files (\*.ui). You can't mix python and C++ source files.
1254 In C++, include files with .h extension are processed with the moc qt tool.
1256 Here is an excerpt from pygui1 example that shows how to add a python GUI to a module::
1258 modul=Module("pycompos",components=[c1],prefix="./install",
1259 gui=["pycomposGUI.py","demo.ui","*.png"],
1262 The GUI is implemented in the pycomposGUI.py (that must be named <module name>GUI.py) python module. It uses a qt designer
1263 file demo.ui that is dynamically loaded and several images in PNG files.
1265 Here is an excerpt from cppgui1 example that shows how to add a C++ GUI to a module::
1267 modul=Module("cppcompos",components=[c1],prefix="./install",
1268 gui=["cppcomposGUI.cxx","cppcomposGUI.h","demo.ui","*.png"],
1271 The C++ GUI is very similar to the python GUI except that the cppcomposGUI.h file is processed by the moc and the demo.ui
1272 is processed by the uic qt tool.
1274 By default, a CMakeLists.txt and a SalomeApp.xml files are generated but you can put your own CMakeLists.txt or SalomeApp.xml
1275 in the list to override this default.
1277 Add an online documentation
1278 ++++++++++++++++++++++++++++++++++++++++
1279 It is possible to add an online documentation that is made with the sphinx tool (http://sphinx.pocoo.org). You need a well installed
1280 sphinx tool (1.0.x or 0.6.x).
1281 To add a documentation use the *doc* parameter of the module. It must be a list of file names. These files can be text files
1282 (name with extension .rst) in the reStructured format (see http://docutils.sourceforge.net/) and image files (\*.png, ...).
1283 The main file must be named index.rst.
1285 By default, a sphinx configuration file conf.py and a CMakeLists.txt are generated but you can put your own CMakeLists.txt or conf.py
1286 in the list to override this default.
1288 Here is an excerpt from pygui1 example that shows how to add a documentation to a module::
1290 modul=Module("pycompos",components=[c1],prefix="./install",
1291 doc=["*.rst","*.png"],
1295 The online documentation will only appear in the SALOME GUI, if your module has a minimal GUI but not if it has no GUI.
1297 Add extra methods to your components
1298 ++++++++++++++++++++++++++++++++++++++++
1299 If you have a C++ or Python class or some methods that you want to add to your components, it is possible to do that by
1300 using the *compodefs* and *inheritedclass* parameters of the component (:class:`module_generator.CPPComponent` or
1301 :class:`module_generator.PYComponent`).
1303 The *inheritedclass* parameter gives the name of the class that will be included in the parent classes of the component and
1304 the *compodefs* parameter is a fragment of code that will be inserted in the definition section of the component. It can be used
1305 to add definitions such as include or even a complete class.
1307 Here is an excerpt from pygui1 example that shows how to add a method named createObject to the component pycompos::
1311 def createObject( self, study, name ):
1313 builder = study.NewBuilder()
1314 father = study.FindComponent( "pycompos" )
1316 father = builder.NewComponent( "pycompos" )
1317 attr = builder.FindOrCreateAttribute( father, "AttributeName" )
1318 attr.SetValue( "pycompos" )
1319 object = builder.NewObject( father )
1320 attr = builder.FindOrCreateAttribute( object, "AttributeName" )
1321 attr.SetValue( name )
1324 c1=PYComponent("pycompos",services=[
1325 Service("s1",inport=[("a","double"),("b","double")],
1326 outport=[("c","double"),("d","double")],
1329 compodefs=compodefs,
1335 If you have special characters in your code fragments such as backslash, think about using python raw strings (r"...")
1337 For a C++ component, the method is exactly the same. There is only one case that can be handled in Python with this method and not in C++.
1338 It's when you want to redefine one of the component methods (DumpPython, for example). In this case, adding a class in the inheritance tree
1339 does not override the default implementation. So, for this special case, there is another parameter (*addmethods*) that is a code
1340 fragment that will be included in the component class to effectively redefine the method.
1342 Here is an excerpt from cppgui1 example that shows how to redefine the DumpPython method in a C++ component::
1345 Engines::TMPFile* DumpPython(CORBA::Object_ptr theStudy, CORBA::Boolean isPublished,
1346 CORBA::Boolean& isValidScript)
1348 SALOMEDS::Study_var aStudy = SALOMEDS::Study::_narrow(theStudy);
1349 if(CORBA::is_nil(aStudy))
1350 return new Engines::TMPFile(0);
1351 SALOMEDS::SObject_var aSO = aStudy->FindComponent("cppcompos");
1352 if(CORBA::is_nil(aSO))
1353 return new Engines::TMPFile(0);
1354 std::string Script = "import cppcompos_ORB\n";
1355 Script += "import salome\n";
1356 Script += "compo = salome.lcc.FindOrLoadComponent('FactoryServer','cppcompos')\n";
1357 Script += "def RebuildData(theStudy):\n";
1358 Script += " compo.SetCurrentStudy(theStudy)\n";
1359 const char* aScript=Script.c_str();
1360 char* aBuffer = new char[strlen(aScript)+1];
1361 strcpy(aBuffer, aScript);
1362 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
1363 int aBufferSize = strlen(aBuffer)+1;
1364 Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aBufferSize, aBufferSize, anOctetBuf, 1);
1365 isValidScript = true;
1366 return aStreamFile._retn();
1370 c1=CPPComponent("cppcompos",services=[ Service("s1",
1371 inport=[("a","double"),("b","double")],
1372 outport=[("c","double")],
1375 addedmethods=compomethods,
1379 Add extra idl corba interfaces to your components
1380 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1381 If you want to add pure CORBA methods (not SALOME services) to your components or even complete IDL interface (SALOMEDS::Driver, for
1382 example), you can do that by using the *idls*, *interfacedefs* and *inheritedinterface* parameters of the component.
1384 The *idls* parameter must be a list of CORBA idl file names. The *inheritedinterface* parameter gives the name of the CORBA
1385 interface that will be included in the parent interfaces of the component interface. The *interfacedefs* parameter is a fragment
1386 of code that will be inserted in the idl file of the module. It can be used to add definitions such as include or even a complete interface.
1388 Here is an excerpt from pygui1 example that shows how to add the SALOMEDS::Driver interface (with its default
1389 implementation from SALOME KERNEL) and an extra method (createObject) to a python component::
1392 #include "myinterface.idl"
1396 import SALOME_DriverPy
1398 class A(SALOME_DriverPy.SALOME_DriverPy_i):
1400 SALOME_DriverPy.SALOME_DriverPy_i.__init__(self,"pycompos")
1403 def createObject( self, study, name ):
1405 builder = study.NewBuilder()
1406 father = study.FindComponent( "pycompos" )
1408 father = builder.NewComponent( "pycompos" )
1409 attr = builder.FindOrCreateAttribute( father, "AttributeName" )
1410 attr.SetValue( "pycompos" )
1412 object = builder.NewObject( father )
1413 attr = builder.FindOrCreateAttribute( object, "AttributeName" )
1414 attr.SetValue( name )
1417 c1=PYComponent("pycompos",services=[ Service("s1",
1418 inport=[("a","double"),("b","double")],
1419 outport=[("c","double"),("d","double")],
1423 interfacedefs=idldefs,
1424 inheritedinterface="Idl_A",
1425 compodefs=compodefs,
1429 The idl file names can contain shell-style wildcards that are accepted by the python glob module. Here, there is only
1430 one file (myinterface.idl) that contains the definition of interface Idl_A::
1432 #include "SALOMEDS.idl"
1433 #include "SALOME_Exception.idl"
1435 interface Idl_A : SALOMEDS::Driver
1437 void createObject(in SALOMEDS::Study theStudy, in string name) raises (SALOME::SALOME_Exception);
1440 In this simple case, it is also possible to include directly the content of the file with the *interfacedefs* parameter.
1442 For a C++ component, the method is exactly the same, except that there is no default implementation of the Driver interface
1443 so you have to implement it.
1445 Add YACS type definition to YACSGEN
1446 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1447 If you define a port, you need to give a type name. YACSGEN knows about a limited set of types (see :ref:`yacstypes`).
1448 If you want to add more types either because they have been forgotten or you want to use one from a new module, it is possible
1449 to add them with the function :func:`module_generator.add_type`. This function can also overload an existing type.
1451 For example, to overload the definition of type GEOM_Object in GEOM module::
1453 from module_generator import add_type
1454 add_type("GEOM_Object", "GEOM::GEOM_Object_ptr", "GEOM::GEOM_Object_out", "GEOM", "GEOM::GEOM_Object","GEOM::GEOM_Object_ptr")
1456 Add YACS module definition to YACSGEN
1457 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1458 Now if you want to add a new type from a new module (unknown to YACSGEN), you need to add a module definition to YACSGEN.
1459 You can add it with the function :func:`module_generator.add_module`. This function can also overload the definition
1460 of an existing module.
1462 For example, to overload the definition of module GEOM::
1464 from module_generator import add_module
1467 #include "GEOM_Gen.idl"
1472 GEOM_IDL_INCLUDES = -I$(GEOM_ROOT_DIR)/idl/salome
1473 GEOM_INCLUDES= -I$(GEOM_ROOT_DIR)/include/salome
1474 GEOM_IDL_LIBS= -L$(GEOM_ROOT_DIR)/lib/salome -lSalomeIDLGEOM
1475 GEOM_LIBS= -L$(GEOM_ROOT_DIR)/lib/salome
1476 SALOME_LIBS += ${GEOM_LIBS}
1477 SALOME_IDL_LIBS += ${GEOM_IDL_LIBS}
1478 SALOME_INCLUDES += ${GEOM_INCLUDES}
1479 IDL_INCLUDES += ${GEOM_IDL_INCLUDES}
1483 if test "x${GEOM_ROOT_DIR}" != "x" && test -d ${GEOM_ROOT_DIR} ; then
1484 AC_MSG_RESULT(Using GEOM installation in ${GEOM_ROOT_DIR})
1486 AC_MSG_ERROR([Cannot find module GEOM. Have you set GEOM_ROOT_DIR ?],1)
1490 add_module("GEOM",idldefs,makefiledefs,configdefs)
1494 -----------------------------------------------------------------
1496 .. automodule:: module_generator
1497 :synopsis: YACSGEN interface
1499 The module provides the following classes:
1501 .. autoclass:: Service
1503 .. autoclass:: CPPComponent
1505 .. autoclass:: PYComponent
1507 .. autoclass:: F77Component
1509 .. autoclass:: ASTERComponent
1511 .. autoclass:: Module
1513 .. autoclass:: Generator
1514 :members: generate, configure, make, install, make_appli
1516 .. autofunction:: add_type
1518 .. autofunction:: add_module
1522 Supported SALOME types
1523 ----------------------------
1525 ======================= =============================== ================================ ===================== ==========================
1526 SALOME module YACS type name IDL type name Implementation Comment
1527 ======================= =============================== ================================ ===================== ==========================
1528 GEOM GEOM_Object GEOM::GEOM_Object C++, Python
1529 SMESH SMESH_Mesh SMESH::SMESH_Mesh C++, Python
1530 SMESH SMESH_Hypothesis SMESH::SMESH_Hypothesis C++, Python
1531 MED SALOME_MED/MED SALOME_MED::MED C++, Python
1532 MED SALOME_MED/MESH SALOME_MED::MESH C++, Python
1533 MED SALOME_MED/SUPPORT SALOME_MED::SUPPORT C++, Python
1534 MED SALOME_MED/FIELD SALOME_MED::FIELD C++, Python
1535 MED SALOME_MED/FIELDDOUBLE SALOME_MED::FIELDDOUBLE C++, Python
1536 MED SALOME_MED/FIELDINT SALOME_MED::FIELDINT C++, Python
1537 KERNEL double double C++, Python, F77
1538 KERNEL long long C++, Python, F77
1539 KERNEL string string C++, Python, F77
1540 KERNEL dblevec dblevec C++, Python, F77 list of double
1541 KERNEL stringvec stringvec C++, Python, F77 list of string
1542 KERNEL intvec intvec C++, Python, F77 list of long
1543 KERNEL pyobj Python a pickled python object
1544 KERNEL file C++, Python, F77 to transfer a file
1545 KERNEL SALOME_TYPES/Parameter SALOME_TYPES::Parameter C++, Python
1546 KERNEL SALOME_TYPES/ParameterList SALOME_TYPES::ParameterList C++, Python
1547 KERNEL SALOME_TYPES/Variable SALOME_TYPES::Variable C++, Python
1548 KERNEL SALOME_TYPES/VariableSequence SALOME_TYPES::VariableSequence C++, Python
1549 KERNEL SALOME_TYPES/StateSequence SALOME_TYPES::StateSequence C++, Python
1550 KERNEL SALOME_TYPES/TimeSequence SALOME_TYPES::TimeSequence C++, Python
1551 KERNEL SALOME_TYPES/VarList SALOME_TYPES::VarList C++, Python
1552 KERNEL SALOME_TYPES/ParametricInput SALOME_TYPES::ParametricInput C++, Python
1553 KERNEL SALOME_TYPES/ParametricOutput SALOME_TYPES::ParametricOutput C++, Python
1554 ======================= =============================== ================================ ===================== ==========================