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
38 class ASTERComponent(Component):
40 A :class:`ASTERComponent` instance represents an ASTER SALOME component (special component for Code_Aster that is a mix of
41 Fortran and Python code) with services given as a list of :class:`Service` instances with the parameter *services*.
43 :param name: gives the name of the component.
45 :param services: the list of services (:class:`Service`) of the component.
46 :param kind: If it is given and has the value "exe", the component will be built as a standalone
47 component (executable or shell script). The default is to build the component as a dynamic library.
48 :param libs: gives all the libraries options to add when linking the generated component (-L...).
49 :param rlibs: gives all the runtime libraries options to add when linking the generated component (-R...).
50 :param exe_path: is only used when kind is "exe" and gives the path to the standalone component.
51 :param aster_dir: gives the Code_Aster installation directory.
52 :param python_path: If it is given (as a list of paths), all the paths are added to the python path (sys.path).
53 :param argv: is a list of strings that gives the command line parameters for Code_Aster. This parameter is only useful when
56 For example, the following call defines a Code_Aster component named "mycompo" with one service s1 (it must have been defined before).
57 This standalone component takes some command line arguments::
59 >>> c1 = module_generator.ASTERComponent('mycompo', services=[s1,], kind="exe",
61 argv=["-memjeveux","4"])
63 def __init__(self, name, services=None, libs="", rlibs="", aster_dir="",
64 python_path=None, argv=None, kind="lib", exe_path=None, aster_version_type="stable"):
65 """initialise component attributes"""
66 self.aster_dir = aster_dir
67 self.python_path = python_path or []
68 self.argv = argv or []
69 self.exe_path = exe_path
70 self.aster_version_type = aster_version_type
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 getAsterPythonPath(self):
104 """Directory of aster python modules
106 python_version_dir = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
107 aster_python_path = os.path.join(self.aster_dir, "lib", python_version_dir, "site-packages")
109 if not os.path.exists(aster_python_path) :
110 aster_python_path = os.path.join(self.aster_dir, "bibpyt")
112 return aster_python_path
114 # def getConfig(self, gen):
115 # """Content of the config.txt file
117 # path_compo=os.path.join(os.path.abspath(gen.module.prefix),'lib',
118 # 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
119 # 'site-packages','salome','%s_component.py'%self.name)
120 # conf="""ENV_SH | env | - | $ASTER_VERSION_DIR/share/aster/profile.sh
121 #BINELE | bin | - | $ASTER_VERSION_DIR/share/aster/elements
122 #SRCPY | src | - | %s
123 #ARGPYT | exec | - | %s
124 #""" % (self.getAsterPythonPath(), path_compo)
128 def makeCompo(self, gen):
129 """drive the generation of SALOME module files and code files
130 depending on the choosen component kind
132 filename = "%s.py" % self.name
133 #on suppose que les composants ASTER sont homogenes (utilisent meme install)
134 gen.aster = self.aster_dir
137 # f = os.path.join(self.aster_dir, self.getAsterPythonPath(), 'Accas', 'properties.py')
138 # self.version=(0,0,0)
139 # if os.path.isfile(f):
141 # execfile(f, mydict)
142 # v,r,p = mydict['version'].split('.')
143 # self.version=(int(v),int(r),int(p))
145 if self.kind == "lib":
146 return {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
147 filename:self.makeaster(gen)}
148 elif self.kind == "cexe":
149 fdict=self.makecexepath(gen)
150 d= {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
151 self.name+".exe":cexe.substitute(compoexe=self.exe_path),
152 filename:self.makecexeaster(gen)
156 elif self.kind == "exe":
157 fdict=self.makeexepath(gen)
158 d= {"Makefile.am":gen.makeMakefile(self.getMakefileItems(gen)),
159 self.name+".exe":exeaster.substitute(compoexe=self.exe_path),
160 self.name+"_module.py":self.makeexeaster(gen)
165 def getMakefileItems(self,gen):
166 makefileItems={"header":"include $(top_srcdir)/adm_local/make_common_starter.am"}
167 if self.kind == "lib":
168 makefileItems["salomepython_PYTHON"]=[self.name+".py"]
169 elif self.kind == "exe":
170 makefileItems["salomepython_PYTHON"]=[self.name+"_module.py",self.name+"_component.py"]
171 # if self.version < (10,1,2):
172 # makefileItems["salomepython_PYTHON"].append("E_SUPERV.py")
173 makefileItems["dist_salomescript_SCRIPTS"]=[self.name+".exe"]
174 # makefileItems["salomeres_DATA"]=[self.name+"_config.txt"]
175 elif self.kind == "cexe":
176 makefileItems["salomepython_PYTHON"]=[self.name+".py",self.name+"_container.py"]
177 # if self.version < (10,1,2):
178 # makefileItems["salomepython_PYTHON"].append("E_SUPERV.py")
179 makefileItems["dist_salomescript_SCRIPTS"]=[self.name+".exe"]
180 # makefileItems["salomeres_DATA"]=[self.name+"_config.txt"]
184 def makeexepath(self, gen):
185 """standalone component: generate files for calculation code"""
189 # if self.version < (10,1,2):
190 #patch to E_SUPERV.py
191 # fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
192 # esuperv = fil.read()
194 # esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
195 # esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
196 # esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
197 # esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
198 # esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
199 # fdict["E_SUPERV.py"]=esuperv
201 #use a specific main program (modification of config.txt file)
203 # path_config = os.path.join(self.aster_dir, "config.txt")
204 # if os.path.exists(path_config) :
205 # old aster version - old mechanism kept for compatibility
206 # fil = open(path_config)
207 # config = fil.read()
209 # config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
210 # path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
211 # 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
212 # 'site-packages','salome','%s_component.py'%self.name)
213 # config = re.sub("Execution\/E_SUPERV.py", path, config)
215 # getConfig doesn't work with older versions of aster
216 # config = self.getConfig(gen)
218 # fdict["%s_config.txt" % self.name] = config
219 fdict["%s_component.py" % self.name] = component.substitute(component=self.name)
223 def makecexepath(self, gen):
224 """specific container: generate files"""
228 # if self.version < (10,1,2):
229 #patch to E_SUPERV.py
230 # fil = open(os.path.join(self.aster_dir, "bibpyt", "Execution", "E_SUPERV.py"))
231 # esuperv = fil.read()
233 # esuperv = re.sub("def Execute\(self\)", "def Execute(self, params)", esuperv)
234 # esuperv = re.sub("j=self.JdC", "self.jdc=j=self.JdC", esuperv)
235 # esuperv = re.sub("\*\*args", "context_ini=params, **args", esuperv)
236 # esuperv = re.sub("def main\(self\)", "def main(self,params={})", esuperv)
237 # esuperv = re.sub("return self.Execute\(\)", "return self.Execute(params)", esuperv)
238 # fdict["E_SUPERV.py"]=esuperv
240 #use a specific main program
242 # path_config = os.path.join(self.aster_dir, "config.txt")
243 # if os.path.exists(path_config) :
244 # old aster version - old mechanism kept for compatibility
245 # fil = open(path_config)
246 # config = fil.read()
248 # config = re.sub(" profile.sh", os.path.join(self.aster_dir, "profile.sh"), config)
249 # path=os.path.join(os.path.abspath(gen.module.prefix),'lib',
250 # 'python%s.%s' % (sys.version_info[0], sys.version_info[1]),
251 # 'site-packages','salome','%s_container.py' % self.name)
252 # config = re.sub("Execution\/E_SUPERV.py", path, config)
254 # getConfig doesn't work with older versions of aster
255 # config = self.getConfig(gen)
257 fdict["%s_container.py" % self.name] = container
258 # fdict["%s_config.txt" % self.name] = config
262 def getImportESuperv(self):
265 import os.path as osp
266 from asrun.run import AsRunFactory
267 from asrun.config import AsterConfig
270 path = run.get_version_path(VERS)
271 cfg = AsterConfig(osp.join(path, 'config.txt'))
272 pypath = cfg['REPPY'][0]
274 sys.path.insert(0, pypath)
275 from Execution.E_SUPERV import SUPERV
276 """ % self.aster_version_type
280 def makeexeaster(self, gen):
281 """standalone component: generate SALOME component source"""
285 for serv in self.services:
286 defs.append(serv.defs)
289 for name, typ in serv.inport:
290 if typ=="file":continue #files are not passed through service interface
293 datas.append('"%s":cPickle.loads(%s)' % (name, name))
295 datas.append('"%s":%s' % (name, name))
296 #ajout de l'adresse du composant
297 datas.append('"component":self.proxy.ptr()')
298 dvars = "{"+','.join(datas)+"}"
299 inparams = ",".join(params)
303 for name, typ in serv.outport:
304 if typ=="file":continue #files are not passed through service interface
307 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
309 datas.append('j.g_context["%s"]'%name)
310 outparams = ",".join(params)
311 rvars = ",".join(datas)
313 service = asterEXEService.substitute(component=self.name,
318 dvars=dvars, rvars=rvars)
320 for name, typ, dep in serv.instream:
321 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
322 instream = "\n".join(streams)
324 for name, typ, dep in serv.outstream:
325 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
326 outstream = "\n".join(streams)
328 init = pyinitEXEService.substitute(component=self.name, service=serv.name,
329 instream=instream, outstream=outstream)
330 services.append(service)
333 importesuperv = self.getImportESuperv()
335 return asterEXECompo.substitute(component=self.name, module=gen.module.name,
336 servicesdef="\n".join(defs),
337 servicesimpl="\n".join(services),
338 initservice='\n'.join(inits),
339 aster_dir=self.aster_dir,
340 importesuperv=importesuperv,
343 def makecexeaster(self, gen):
344 """specific container: generate SALOME component source"""
348 for serv in self.services:
349 defs.append(serv.defs)
352 for name, typ in serv.inport:
353 if typ=="file":continue #files are not passed through service interface
356 datas.append('"%s":cPickle.loads(%s)' % (name, name))
358 datas.append('"%s":%s' % (name, name))
359 #ajout de l'adresse du composant
360 datas.append('"component":self.proxy.ptr()')
361 dvars = "{"+','.join(datas)+"}"
362 inparams = ",".join(params)
366 for name, typ in serv.outport:
369 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
371 datas.append('j.g_context["%s"]'%name)
372 outparams = ",".join(params)
373 rvars = ",".join(datas)
375 service = asterCEXEService.substitute(component=self.name,
380 dvars=dvars, rvars=rvars)
382 for name, typ, dep in serv.instream:
383 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
384 instream = "\n".join(streams)
386 for name, typ, dep in serv.outstream:
387 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
388 outstream = "\n".join(streams)
390 init = pyinitCEXEService.substitute(component=self.name,
394 services.append(service)
397 importesuperv = self.getImportESuperv()
399 return asterCEXECompo.substitute(component=self.name,
400 module=gen.module.name,
401 servicesdef="\n".join(defs),
402 servicesimpl="\n".join(services),
403 initservice='\n'.join(inits),
404 aster_dir=self.aster_dir,
405 importesuperv=importesuperv,
409 if self.kind == "cexe":
410 return "CEXE", self.name+".exe"
414 def makeaster(self, gen):
415 """library component: generate SALOME component source"""
419 for serv in self.services:
420 defs.append(serv.defs)
423 for name, typ in serv.inport:
424 if typ=="file":continue #files are not passed through service interface
427 datas.append('"%s":cPickle.loads(%s)' % (name, name))
429 datas.append('"%s":%s' % (name, name))
430 #ajout de l'adresse du composant
431 datas.append('"component":self.proxy.ptr()')
432 dvars = "{"+','.join(datas)+"}"
433 inparams = ",".join(params)
437 for name, typ in serv.outport:
440 datas.append('cPickle.dumps(j.g_context["%s"],-1)'%name)
442 datas.append('j.g_context["%s"]'%name)
443 outparams = ",".join(params)
444 rvars = ",".join(datas)
446 service = asterService.substitute(component=self.name, service=serv.name,
447 inparams=inparams, outparams=outparams,
449 dvars=dvars, rvars=rvars)
451 for name, typ, dep in serv.instream:
452 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","IN","%s")'% (name, typ, dep))
453 instream = "\n".join(streams)
455 for name, typ, dep in serv.outstream:
456 streams.append(' calcium.create_calcium_port(self.proxy,"%s","%s","OUT","%s")'% (name, typ, dep))
457 outstream = "\n".join(streams)
459 init = pyinitService.substitute(component=self.name, service=serv.name,
460 instream=instream, outstream=outstream)
461 services.append(service)
464 python_path = ",".join([repr(p) for p in self.python_path])
465 argv = ",".join([repr(p) for p in self.argv])
466 return asterCompo.substitute(component=self.name, module=gen.module.name,
467 servicesdef="\n".join(defs),
468 servicesimpl="\n".join(services),
469 initservice='\n'.join(inits),
470 aster_dir=self.aster_dir,
471 python_path=python_path, argv=argv)