/[escript]/trunk/pycad/py_src/design.py
ViewVC logotype

Contents of /trunk/pycad/py_src/design.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6939 - (show annotations)
Mon Jan 20 03:37:18 2020 UTC (3 years, 1 month ago) by uqaeller
File MIME type: text/x-python
File size: 13905 byte(s)
Updated the copyright header.


1
2 ##############################################################################
3 #
4 # Copyright (c) 2003-2020 by The University of Queensland
5 # http://www.uq.edu.au
6 #
7 # Primary Business: Queensland, Australia
8 # Licensed under the Apache License, version 2.0
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12 # Development 2012-2013 by School of Earth Sciences
13 # Development from 2014 by Centre for Geoscience Computing (GeoComp)
14 # Development from 2019 by School of Earth and Environmental Sciences
15 #
16 ##############################################################################
17
18 from __future__ import print_function, division
19
20 __copyright__="""Copyright (c) 2003-2020 by The University of Queensland
21 http://www.uq.edu.au
22 Primary Business: Queensland, Australia"""
23 __license__="""Licensed under the Apache License, version 2.0
24 http://www.apache.org/licenses/LICENSE-2.0"""
25 __url__="https://launchpad.net/escript-finley"
26
27 """
28 Template for the Design which defines regions and features
29 for a mesh generator.
30
31 :var __author__: name of author
32 :var __copyright__: copyrights
33 :var __license__: licence agreement
34 :var __url__: url entry point on documentation
35 :var __version__: version
36 :var __date__: date of the version
37 """
38
39 __author__="Lutz Gross, l.gross@uq.edu.au"
40
41 from .primitives import Primitive, ReversePrimitive, PropertySet, Point, Manifold1D, Manifold2D, Manifold3D
42 from xml.dom import minidom
43 import tempfile, os
44
45 class TagMap(object):
46 """
47 A class that allows to map tags to names.
48
49 Example::
50
51 tm=TagMap({5 : x })
52 tm.setMap(a=1,x=4)
53 assert tm.getTags("a") == [ 1 ]
54 assert tm.getTags("x") == [ 5, 4 ]
55 assert tm.map(x=10., a=20.) == { 5 : 10, 4: 10, 1 : 20 }
56
57 """
58 def __init__(self, mapping={}):
59 """
60 Initializes the mapping. ``mapping`` defines an initial mapping from tag
61 to a name.
62 """
63 self.__mapping={}
64 for tag, name in sorted(mapping.items(), key=lambda x: x[1]):
65 if not isinstance(tag, int):
66 raise TypeError("tag needs to be an int")
67 if not isinstance(name, str):
68 raise TypeError("name needs to be a str.")
69 self.__mapping[tag]=name
70
71 def setMap(self,**kwargs):
72 """
73 Sets a new map where <name>=<tag> assigns the tag <tag> to name <name>.
74 <tag> has to be an integer. If <tag> has been assigned to a name before
75 the mapping will be overwritten. Otherwise a new mapping <tag> -> <name>
76 is set. Notice that a single name can be assigned to different tags.
77 """
78 for name, tag in sorted(kwargs.items(), key=lambda x: x[0]):
79 if not isinstance(tag, int):
80 raise TypeError("tag needs to be an int")
81 self.__mapping[tag]=name
82
83 def getTags(self,name=None):
84 """
85 Returns a list of the tags assigned to ``name``. If name is not present
86 a list of all tags is returned.
87 """
88 if name == None:
89 out=sorted(self.__mapping.keys())
90 else:
91 out=[]
92 for tag, arg in sorted(self.__mapping.items(), key=lambda x: x[0]):
93 if arg == name: out.append(tag)
94 return out
95
96 def getName(self,tag=None):
97 """
98 Returns the name of a tag. If ``tag`` is not present a list of all names
99 is returned.
100 """
101 if tag == None:
102 return sorted(list(set(self.__mapping.values())))
103 else:
104 return self.__mapping[tag]
105
106 def getMapping(self):
107 """
108 Returns a dictionary where the tags define the keys and the values the
109 corresponding names.
110 """
111 return self.__mapping
112
113 def map(self,default=0,**kwargs):
114 """
115 Returns a dictionary where the tags define the keys and the values give
116 the values assigned to the tag via name and kwargs::
117
118 tm=TagMap(x=5)
119 tm.setMap(a=1,x=4)
120 print tm.map(x=10., a=20.)
121 { 5 : 10, 4: 10, 1 : 20 }
122
123 The default is used for tags which map onto name with unspecified
124 values.
125 """
126 out={}
127 for tag in self.__mapping:
128 if self.__mapping[tag] in kwargs:
129 out[tag]=kwargs[self.__mapping[tag]]
130 else:
131 out[tag]=default
132 return out
133
134 def insert(self,data,default=0,**kwargs):
135 """
136 Inserts values into the `esys.escript.Data` object according to the
137 given values assigned to the keywords. The default is used for tags
138 which map onto name with unspecified values.
139 """
140 d=self.map(default=default,**kwargs)
141 for t,v in sorted(d.items(), key=lambda x: x[0]):
142 data.setTaggedValue(t,v)
143
144 def passToDomain(self,domain):
145 """
146 Passes the tag map to the `esys.escript.Domain` ``domain``.
147 """
148 for tag, name in sorted(self.__mapping.items(), key=lambda x: x[1]):
149 print("Tag",name, "is mapped to id ", tag)
150 domain.setTagMap(name,tag)
151
152 def toDOM(self,dom):
153 """
154 Adds object to ``dom``.
155 """
156 tm=dom.createElement("TagMap")
157 dom.appendChild(tm)
158 for tag,name in sorted(self.getMapping().items(), key=lambda x: x[1]):
159 item_dom=dom.createElement("map")
160 tag_dom=dom.createElement("tag")
161 name_dom=dom.createElement("name")
162 tag_dom.appendChild(dom.createTextNode(str(tag)))
163 name_dom.appendChild(dom.createTextNode(str(name)))
164 item_dom.appendChild(tag_dom)
165 item_dom.appendChild(name_dom)
166 tm.appendChild(item_dom)
167 return tm
168
169 def fromDom(self,node):
170 """
171 Fills names and tags from dom ``node``.
172 """
173 for node in node.childNodes:
174 if isinstance(node, minidom.Element):
175 if node.tagName == 'map':
176 tag=int(node.getElementsByTagName("tag")[0].firstChild.nodeValue.strip())
177 name=str(node.getElementsByTagName("name")[0].firstChild.nodeValue.strip())
178 self.setMap(**{ name : tag })
179 return
180
181 def fillFromXML(self,iostream):
182 """
183 Uses the XML file or string to set the mapping.
184 """
185 if isinstance(iostream,str):
186 dom=minidom.parseString(iostream)
187 else:
188 dom=minidom.parse(iostream)
189 root=dom.getElementsByTagName('ESys')[0]
190 for node in root.childNodes:
191 if isinstance(node, minidom.Element):
192 if node.tagName == 'TagMap':
193 self.fromDom(node)
194 return
195
196 def writeXML(self,iostream=None):
197 """
198 Serializes self as XML into ``iostream`` or if not present returns the
199 XML as string.
200 """
201 dom=minidom.Document()
202 esys=dom.createElement('ESys')
203 esys.appendChild(self.toDOM(dom))
204 dom.appendChild(esys)
205 if iostream == None:
206 return dom.toprettyxml()
207 else:
208 iostream.write(dom.toprettyxml())
209
210 class AbstractDesign(object):
211 """
212 Template for a design which defines the input for a mesh generator.
213
214 :note: class variable GMSH - `gmsh <http://www.geuz.org/gmsh/>`_ file format
215 :note: class variable IDEAS - `I_DEAS <http://www.plm.automation.siemens.com/en_us/products/nx/>`_ universal file format
216 :note: class variable VRML - `VRML <http://www.w3.org/MarkUp/VRML/>`_ file format
217 :note: class variable STL - `STL <http://en.wikipedia.org/wiki/STL_(file_format)>`_ file format
218 :note: class variable NASTRAN - `Nastran <http://simcompanion.mscsoftware.com/infocenter/index?page=content&channel=DOCUMENTATION>`_ bulk data format
219 :note: class variable MEDIT - `Medit <http://www-rocq.inria.fr/OpenFEM/Doc/>`_ file format
220 :note: class variable CGNS - `CGNS <http://cgns.sourceforge.net/>`_ file format
221 :note: class variable PLOT3D - `Plot3D <http://www.plot3d.net/>`_ file format
222 :note: class variable DIFFPACK- `Diffpack <http://www.diffpack.com/>`_ file format
223 """
224 GMSH="msh"
225 IDEAS="unv"
226 VRML="vrml"
227 STL="stl"
228 NASTRAN="bdf"
229 MEDIT="mesh"
230 CGNS="cgns"
231 PLOT3D="p3d"
232 DIFFPACK="diff"
233 def __init__(self,dim=3,element_size=1.,order=1,keep_files=False):
234 """
235 Initializes a design.
236
237 :param dim: spatial dimension
238 :param element_size: global element size
239 :param order: element order
240 :param keep_files: flag to keep work files
241 """
242 self.clearItems()
243 self.setElementSize(element_size)
244 self.setDim(dim)
245 self.setElementOrder(order)
246 self.setFileFormat()
247 if keep_files:
248 self.setKeepFilesOn()
249 else:
250 self.setKeepFilesOff()
251 self.__mshname=""
252 self.setMeshFileName()
253
254 def setDim(self,dim=3):
255 """
256 Sets the spatial dimension.
257 """
258 if not dim in [1,2,3]:
259 raise ValueError("only dimension 1, 2, 3 are supported.")
260 self.__dim=dim
261
262 def getDim(self,dim=3):
263 """
264 Returns the spatial dimension.
265 """
266 return self.__dim
267
268 def setElementOrder(self,order=1):
269 """
270 Sets the element order.
271 """
272 if not order in [1,2]:
273 raise ValueError("only element order 1 or 2 is supported.")
274 self.__order=order
275
276 def getElementOrder(self):
277 """
278 Returns the element order.
279 """
280 return self.__order
281
282 def setElementSize(self,element_size=1.):
283 """
284 Sets the global element size.
285 """
286 if element_size<=0.:
287 raise ValueError("element size needs to be positive.")
288 self.__element_size=element_size
289
290 def getElementSize(self):
291 """
292 Returns the global element size.
293 """
294 return self.__element_size
295
296 def setKeepFilesOn(self):
297 """
298 Work files are kept at the end of the generation.
299 """
300 self.__keep_files=True
301
302 def setKeepFilesOff(self):
303 """
304 Work files are deleted at the end of the generation
305 """
306 self.__keep_files=False
307
308 def keepFiles(self):
309 """
310 Returns True if work files are kept, False otherwise.
311 """
312 return self.__keep_files
313
314 def addItems(self,*items):
315 """
316 Adds items to the design.
317 """
318 new_items=[]
319 for i in range(len(items)):
320 if not isinstance(items[i],(Primitive, ReversePrimitive)):
321 raise TypeError("%s-th argument is not a Primitive object"%i)
322 if isinstance(items[i],PropertySet):
323 q=items[i]
324 else:
325 q=PropertySet("__%s__"%(items[i].getID()), items[i])
326 for p in self.getAllPrimitives():
327 if isinstance(p, PropertySet):
328 if q.getName() == p.getName():
329 raise ValueError("Property set name %s is allready in use."%q.getName())
330 new_items.append(q)
331 for q in new_items: self.__items.append(q)
332
333 def getItems(self):
334 """
335 Returns a list of the items used in the design.
336 """
337 return self.__items
338
339 def clearItems(self):
340 """
341 Removes all items from the design.
342 """
343 self.__items=[]
344
345 def getAllPrimitives(self):
346 """
347 Returns a list of all primitives used to create the design.
348 Each primitive appears once. The primitives are ordered by their
349 order of generation.
350 """
351 prims=[]
352 for i in self.getItems():
353 for p in i.getPrimitives():
354 if not p in prims: prims.append(p)
355 prims.sort()
356 return prims
357
358 def setOptions(self,**kwargs):
359 """
360 Sets options of the mesh generator.
361
362 :note: this method is typically overwritten by a particular design
363 implementation.
364 """
365 pass
366 def generate(self):
367 """
368 generate output file
369
370 :note: this method may be overwritten by a particular design
371 implementation.
372 """
373 self.getMeshHandler()
374
375 def getMeshHandler(self):
376 """
377 Returns a handle to a mesh meshing the design.
378
379 :note: this method has to be overwritten by a particular design
380 implementation.
381 """
382 raise NotImplementedError()
383
384 def getTagMap(self):
385 """
386 Returns a `TagMap` to map the names of `PropertySet` s to tags.
387 """
388 m={}
389 for p in self.getAllPrimitives():
390 if isinstance(p, PropertySet): m[ p.getTag() ] = p.getName()
391 return TagMap(m)
392
393 def setFileFormat(self,format='msh'):
394 """
395 Sets the file format to be used.
396
397 :param format: format to be used. needs to be one of
398
399 """
400 if not format in [ self.GMSH, self.IDEAS, self.VRML, self.STL, self.NASTRAN, self.MEDIT, self.CGNS, self.PLOT3D, self.DIFFPACK] :
401 raise ValueError("unknown file format %s."%format)
402 self.__fileformat=format
403
404 def getFileFormat(self):
405 """
406 Returns the file format
407 """
408 return self.__fileformat
409
410 def setMeshFileName(self, name=None):
411 """
412 Sets the name for the mesh file. If no name is given a name is generated.
413 """
414 if self.__mshname:
415 os.unlink(self.__mshname)
416 if name == None:
417 self.__mshname_set=False
418 tmp_f_id=tempfile.mkstemp(suffix="."+self.getFileFormat())
419 self.__mshname=tmp_f_id[1]
420 os.close(tmp_f_id[0])
421 else:
422 self.__mshname=name
423 self.__mshname_set=True
424
425 def getMeshFileName(self):
426 """
427 Returns the name of the mesh file.
428 """
429 return self.__mshname
430
431
432

  ViewVC Help
Powered by ViewVC 1.1.26