1 # Copyright (C) 2009-2014 EDF R&D
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 This module defines the ASTERComponent class for ASTER component generation
22 An ASTER component comes in 3 flavors :
23 - implemented as a dynamic library (kind='lib')
24 - implemented as a standalone component (kind='exe')
25 - implemented as a specific container (kind='cexe')
29 from gener import Component, Invalid, makedirs
31 from pyth_tmpl import pyinitEXEService, pyinitCEXEService, pyinitService
33 from aster_tmpl import asterCEXEService, asterEXEService
34 from aster_tmpl import asterService, asterEXECompo, asterCEXECompo, asterCompo
35 from aster_tmpl import comm, make_etude, cexe, exeaster
36 from aster_tmpl import container, component
37 from aster_tmpl import cmake_src_compo_aster, cmake_src_compo_aster_lib
39 class ASTERComponent(Component):
41 A :class:`ASTERComponent` instance represents an ASTER SALOME component (special component for Code_Aster that is a mix of
42 Fortran and Python code) with services given as a list of :class:`Service` instances with the parameter *services*.
44 :param name: gives the name of the component.
46 :param services: the list of services (:class:`Service`) of the component.
47 :param kind: If it is given and has the value "exe", the component will be built as a standalone
48 component (executable or shell script). The default is to build the component as a dynamic library.
49 :param libs: gives all the libraries options to add when linking the generated component (-L...).
50 :param rlibs: gives all the runtime libraries options to add when linking the generated component (-R...).
51 :param exe_path: is only used when kind is "exe" and gives the path to the standalone component.
52 :param aster_dir: gives the Code_Aster installation directory.
53 :param python_path: If it is given (as a list of paths), all the paths are added to the python path (sys.path).
54 :param argv: is a list of strings that gives the command line parameters for Code_Aster. This parameter is only useful when
57 For example, the following call defines a Code_Aster component named "mycompo" with one service s1 (it must have been defined before).
58 This standalone component takes some command line arguments::
60 >>> c1 = module_generator.ASTERComponent('mycompo', services=[s1,], kind="exe",
62 argv=["-memjeveux","4"])
64 def __init__(self, name, services=None, libs=[], rlibs="", aster_dir="",
65 python_path=None, argv=None, kind="lib", exe_path=None):
66 """initialise component attributes"""
67 self.aster_dir = aster_dir
68 self.python_path = python_path or []
69 self.argv = argv or []
70 self.exe_path = exe_path
71 Component.__init__(self, name, services, impl="ASTER", libs=libs,
72 rlibs=rlibs, kind=kind)
75 """validate the component definition"""
76 Component.validate(self)
77 if not self.aster_dir:
78 raise Invalid("aster_dir must be defined for component %s" % self.name)
80 kinds = ("lib", "cexe", "exe")
81 if self.kind not in kinds:
82 raise Invalid("kind must be one of %s for component %s" % (kinds,self.name))
83 if self.kind == "lib" and not self.python_path:
84 raise Invalid("python_path must be defined for component %s" % self.name)
85 if self.kind == "cexe" :
87 raise Invalid("exe_path must be defined for component %s" % self.name)
88 if self.kind == "exe" :
90 raise Invalid("exe_path must be defined for component %s" % self.name)
92 #Si un port de nom jdc n'est pas defini dans la liste des inports du service,
93 #on en ajoute un de type string en premiere position
94 for serv in self.services:
96 for port_name,port_type in serv.inport:
97 if port_name == "jdc":
101 serv.inport.insert(0, ("jdc", "string"))
103 def libraryName(self):
104 """ Name of the target library
105 No library for an aster component
109 def getAsterPythonPath(self):
110 """Directory of aster python modules
112 python_version_dir = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
113 aster_python_path = os.path.join(self.aster_dir, "lib", python_version_dir, "site-packages")
115 if not os.path.exists(aster_python_path) :
116 aster_python_path = os.path.join(self.aster_dir, "bibpyt")
118 return aster_python_path
120 def getConfig(self, gen):
121 """Content of the config.txt file
123 path_compo=os.path.join(os.path.abspath(gen.module.prefix),'lib',
124 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
125 'site-packages','salome','%s_component.py'%self.name)
126 conf="""ENV_SH | env | - | $ASTER_VERSION_DIR/share/aster/profile.sh
127 BINELE | bin | - | $ASTER_VERSION_DIR/share/aster/elements
129 ARGPYT | exec | - | %s
130 """ % (self.getAsterPythonPath(), path_compo)
134 def makeCompo(self, gen):
135 """drive the generation of SALOME module files and code files
136 depending on the choosen component kind
138 filename = "%s.py" % self.name
139 #on suppose que les composants ASTER sont homogenes (utilisent meme install)
140 gen.aster = self.aster_dir
143 f = os.path.join(self.aster_dir, self.getAsterPythonPath(), 'Accas', 'properties.py')
145 if os.path.isfile(f):
148 v,r,p = mydict['version'].split('.')
149 self.version=(int(v),int(r),int(p))
151 if self.kind == "lib":
153 return {"CMakeLists.txt":cmake_src_compo_aster_lib.substitute(sources=f),
154 filename:self.makeaster(gen)}
155 elif self.kind == "cexe":
156 fdict=self.makecexepath(gen)
157 sources = self.name + ".py\n " + self.name + "_container.py"
158 if self.version < (10,1,2):
159 sources = sources + "\n E_SUPERV.py"
160 d= {"CMakeLists.txt":cmake_src_compo_aster.substitute(
162 module=gen.module.name,
163 resources=self.name+"_config.txt",
164 scripts=self.name+".exe"),
165 self.name+".exe":cexe.substitute(compoexe=self.exe_path),
166 filename:self.makecexeaster(gen)
170 elif self.kind == "exe":
171 fdict=self.makeexepath(gen)
172 sources = self.name + "_module.py\n "
173 sources = sources + self.name + "_component.py"
174 if self.version < (10,1,2):
175 sources = sources + "\n E_SUPERV.py"
176 d= {"CMakeLists.txt":cmake_src_compo_aster.substitute(
178 module=gen.module.name,
179 resources=self.name+"_config.txt",
180 scripts=self.name+".exe"),
181 self.name+".exe":exeaster.substitute(compoexe=self.exe_path),
182 self.name+"_module.py":self.makeexeaster(gen)
187 def makeexepath(self, gen):
188 """standalone component: generate files for calculation code"""
192 if self.version < (10,1,2):
193 #patch to E_SUPERV.py
194 fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
197 esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
198 esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
199 esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
200 esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
201 esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
202 fdict["E_SUPERV.py"]=esuperv
204 #use a specific main program (modification of config.txt file)
206 path_config = os.path.join(self.aster_dir, "config.txt")
207 if os.path.exists(path_config) :
208 # old aster version - old mechanism kept for compatibility
209 fil = open(path_config)
212 config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
213 path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
214 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
215 'site-packages','salome','%s_component.py'%self.name)
216 config = re.sub("Execution\/E_SUPERV.py", path, config)
218 # getConfig doesn't work with older versions of aster
219 config = self.getConfig(gen)
221 fdict["%s_config.txt" % self.name] = config
222 fdict["%s_component.py" % self.name] = component.substitute(component=self.name)
226 def makecexepath(self, gen):
227 """specific container: generate files"""
231 if self.version < (10,1,2):
232 #patch to E_SUPERV.py
233 fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
236 esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
237 esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
238 esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
239 esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
240 esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
241 fdict["E_SUPERV.py"]=esuperv
243 #use a specific main program
245 path_config = os.path.join(self.aster_dir, "config.txt")
246 if os.path.exists(path_config) :
247 # old aster version - old mechanism kept for compatibility
248 fil = open(path_config)
251 config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
252 path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
253 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
254 'site-packages','salome','%s_container.py' % self.name)
255 config = re.sub("Execution\/E_SUPERV.py", path, config)
257 # getConfig doesn't work with older versions of aster
258 config = self.getConfig(gen)
260 fdict["%s_container.py" % self.name] = container
261 fdict["%s_config.txt" % self.name] = config
265 def getImportESuperv(self):
267 if self.version < (10,1,2):
268 importesuperv="from E_SUPERV import SUPERV"
270 importesuperv="""sys.path=["%s"]+sys.path
271 from Execution.E_SUPERV import SUPERV
272 """ % self.getAsterPythonPath()
276 def makeexeaster(self, gen):
277 """standalone component: generate SALOME component source"""
281 for serv in self.services:
282 defs.append(serv.defs)
285 for name, typ in serv.inport:
286 if typ=="file":continue #files are not passed through service interface
289 datas.append('"%s":cPickle.loads(%s)' % (name, name))
291 datas.append('"%s":%s' % (name, name))
292 #ajout de l'adresse du composant
293 datas.append('"component":self.proxy.ptr()')
294 dvars = "{"+','.join(datas)+"}"
295 inparams = ",".join(params)
299 for name, typ in serv.outport:
300 if typ=="file":continue #files are not passed through service interface
303 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
305 datas.append('j.g_context["%s"]'%name)
306 outparams = ",".join(params)
307 rvars = ",".join(datas)
309 service = asterEXEService.substitute(component=self.name,
314 dvars=dvars, rvars=rvars)
316 for name, typ, dep in serv.instream:
317 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
318 instream = "\n".join(streams)
320 for name, typ, dep in serv.outstream:
321 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
322 outstream = "\n".join(streams)
324 init = pyinitEXEService.substitute(component=self.name, service=serv.name,
325 instream=instream, outstream=outstream)
326 services.append(service)
329 importesuperv = self.getImportESuperv()
331 return asterEXECompo.substitute(component=self.name, module=gen.module.name,
332 servicesdef="\n".join(defs),
333 servicesimpl="\n".join(services),
334 initservice='\n'.join(inits),
335 aster_dir=self.aster_dir,
336 importesuperv=importesuperv,
339 def makecexeaster(self, gen):
340 """specific container: generate SALOME component source"""
344 for serv in self.services:
345 defs.append(serv.defs)
348 for name, typ in serv.inport:
349 if typ=="file":continue #files are not passed through service interface
352 datas.append('"%s":cPickle.loads(%s)' % (name, name))
354 datas.append('"%s":%s' % (name, name))
355 #ajout de l'adresse du composant
356 datas.append('"component":self.proxy.ptr()')
357 dvars = "{"+','.join(datas)+"}"
358 inparams = ",".join(params)
362 for name, typ in serv.outport:
365 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
367 datas.append('j.g_context["%s"]'%name)
368 outparams = ",".join(params)
369 rvars = ",".join(datas)
371 service = asterCEXEService.substitute(component=self.name,
376 dvars=dvars, rvars=rvars)
378 for name, typ, dep in serv.instream:
379 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
380 instream = "\n".join(streams)
382 for name, typ, dep in serv.outstream:
383 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
384 outstream = "\n".join(streams)
386 init = pyinitCEXEService.substitute(component=self.name,
390 services.append(service)
393 importesuperv = self.getImportESuperv()
395 return asterCEXECompo.substitute(component=self.name,
396 module=gen.module.name,
397 servicesdef="\n".join(defs),
398 servicesimpl="\n".join(services),
399 initservice='\n'.join(inits),
400 aster_dir=self.aster_dir,
401 importesuperv=importesuperv,
405 if self.kind == "cexe":
406 return "CEXE", self.name+".exe"
410 def makeaster(self, gen):
411 """library component: generate SALOME component source"""
415 for serv in self.services:
416 defs.append(serv.defs)
419 for name, typ in serv.inport:
420 if typ=="file":continue #files are not passed through service interface
423 datas.append('"%s":cPickle.loads(%s)' % (name, name))
425 datas.append('"%s":%s' % (name, name))
426 #ajout de l'adresse du composant
427 datas.append('"component":self.proxy.ptr()')
428 dvars = "{"+','.join(datas)+"}"
429 inparams = ",".join(params)
433 for name, typ in serv.outport:
436 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
438 datas.append('j.g_context["%s"]'%name)
439 outparams = ",".join(params)
440 rvars = ",".join(datas)
442 service = asterService.substitute(component=self.name, service=serv.name,
443 inparams=inparams, outparams=outparams,
445 dvars=dvars, rvars=rvars)
447 for name, typ, dep in serv.instream:
448 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
449 instream = "\n".join(streams)
451 for name, typ, dep in serv.outstream:
452 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
453 outstream = "\n".join(streams)
455 init = pyinitService.substitute(component=self.name, service=serv.name,
456 instream=instream, outstream=outstream)
457 services.append(service)
460 python_path = ",".join([repr(p) for p in self.python_path])
461 argv = ",".join([repr(p) for p in self.argv])
462 return asterCompo.substitute(component=self.name, module=gen.module.name,
463 servicesdef="\n".join(defs),
464 servicesimpl="\n".join(services),
465 initservice='\n'.join(inits),
466 aster_dir=self.aster_dir,
467 python_path=python_path, argv=argv)