1 |
# $Id:$ |
2 |
|
3 |
""" |
4 |
template for the Design which defines a regions and features |
5 |
for a mesh generator. |
6 |
|
7 |
@var __author__: name of author |
8 |
@var __copyright__: copyrights |
9 |
@var __license__: licence agreement |
10 |
@var __url__: url entry point on documentation |
11 |
@var __version__: version |
12 |
@var __date__: date of the version |
13 |
""" |
14 |
|
15 |
|
16 |
__author__="Lutz Gross, l.gross@uq.edu.au" |
17 |
__copyright__=""" Copyright (c) 2007 by ACcESS MNRF |
18 |
http://www.access.edu.au |
19 |
Primary Business: Queensland, Australia""" |
20 |
__license__="""Licensed under the Open Software License version 3.0 |
21 |
http://www.opensource.org/licenses/osl-3.0.php""" |
22 |
__url__="http://www.iservo.edu.au/esys/escript" |
23 |
__version__="$Revision:$" |
24 |
__date__="$Date:$" |
25 |
|
26 |
|
27 |
from primitives import Primitive, ReversePrimitive, PropertySet, Point, Manifold1D, Manifold2D, Manifold3D |
28 |
from xml.dom import minidom |
29 |
|
30 |
class TagMap(object): |
31 |
""" |
32 |
a class that allows to map tags to names |
33 |
|
34 |
tm=TagMap({5 : x }) |
35 |
tm.setMap(a=1,x=4) |
36 |
assert tm.getTags("a") == [ 1 ] |
37 |
assert tm.getTags("x") == [ 5, 4 ] |
38 |
assert tm.map(x=10., a=20.) == { 5 : 10, 4: 10, 1 : 20 } |
39 |
|
40 |
""" |
41 |
def __init__(self, mapping={}): |
42 |
""" |
43 |
initizlizes the mapping. map defines an initial mapping from tag to a name. |
44 |
""" |
45 |
self.__mapping={} |
46 |
for tag, name in mapping.items(): |
47 |
if not isinstance(tag, int): |
48 |
raise TypeError("tag needs to be int") |
49 |
if not isinstance(name, str): |
50 |
raise TypeError("name needs to be a str.") |
51 |
self.__mapping[tag]=name |
52 |
def setMap(self,**kwargs): |
53 |
""" |
54 |
set a new map where <name>=<tag> assigns the tag <tag> to name <name>. <tag> has to be integer. |
55 |
If <tag> has been assigned to a name before the mapping will be overwritten. Otherwise a new |
56 |
mapping <tag> -> <name> is set. Notice that a single name can be assigned to different tags. |
57 |
""" |
58 |
for name, tag in kwargs.items(): |
59 |
if not isinstance(tag, int): |
60 |
raise TypeError("tag needs to be int") |
61 |
self.__mapping[tag]=name |
62 |
def getTags(self,name=None): |
63 |
""" |
64 |
returns a list of the tags assigned to name. If name is not present a list of tags is returned. |
65 |
""" |
66 |
if name == None: |
67 |
out=self.__mapping.keys() |
68 |
else: |
69 |
out=[] |
70 |
for tag, arg in self.__mapping.items(): |
71 |
if arg == name: out.append(tag) |
72 |
return out |
73 |
def getName(self,tag=None): |
74 |
""" |
75 |
returns the name of a tag. If tag is not present a list of names is returned. |
76 |
""" |
77 |
if tag == None: |
78 |
return list(set(self.__mapping.values())) |
79 |
else: |
80 |
return self.__mapping[tag] |
81 |
|
82 |
def getMapping(self): |
83 |
""" |
84 |
returns a dictionary where the tags define the keys and the values the corresposnding names. |
85 |
""" |
86 |
return self.__mapping |
87 |
|
88 |
def map(self,default=0,**kwargs): |
89 |
""" |
90 |
returns a dictionary where the tags define the keys and the values give the values assigned to the tag via name |
91 |
and kwargs: |
92 |
|
93 |
tm=TagMap(x=5) |
94 |
tm.setMap(a=1,x=4) |
95 |
print tm.map(x=10., a=20.) |
96 |
{ 5 : 10, 4: 10, 1 : 20 } |
97 |
|
98 |
the default is used for tags which map onto name with unspecified values |
99 |
""" |
100 |
out={} |
101 |
for tag in self.__mapping: |
102 |
if kwargs.has_key(self.__mapping[tag]): |
103 |
out[tag]=kwargs[self.__mapping[tag]] |
104 |
else: |
105 |
out[tag]=default |
106 |
return out |
107 |
|
108 |
def insert(self,data,default=0,**kwargs): |
109 |
""" |
110 |
inserts values into the L{esys.escript.Data} object according to the given values assigned to the keywords. |
111 |
the default is used for tags which map onto name with unspecified values |
112 |
""" |
113 |
d=self.map(default=default,**kwargs) |
114 |
for t,v in d.items(): |
115 |
data.setTaggedValue(t,v) |
116 |
def passToDomain(self,domain): |
117 |
""" |
118 |
passes the tag map to L{esys.escript.Domain} domain. |
119 |
""" |
120 |
for tag, name in self.__mapping.items(): |
121 |
domain.setTagMap(name,tag) |
122 |
|
123 |
def toDOM(self,dom): |
124 |
""" |
125 |
adds object to dom |
126 |
""" |
127 |
tm=dom.createElement("TagMap") |
128 |
dom.appendChild(tm) |
129 |
for tag,name in self.getMapping().items(): |
130 |
item_dom=dom.createElement("map") |
131 |
tag_dom=dom.createElement("tag") |
132 |
name_dom=dom.createElement("name") |
133 |
tag_dom.appendChild(dom.createTextNode(str(tag))) |
134 |
name_dom.appendChild(dom.createTextNode(str(name))) |
135 |
item_dom.appendChild(tag_dom) |
136 |
item_dom.appendChild(name_dom) |
137 |
tm.appendChild(item_dom) |
138 |
return tm |
139 |
def fromDom(self,node): |
140 |
""" |
141 |
fills from dom node |
142 |
""" |
143 |
for node in node.childNodes: |
144 |
if isinstance(node, minidom.Element): |
145 |
if node.tagName == 'map': |
146 |
tag=int(node.getElementsByTagName("tag")[0].firstChild.nodeValue.strip()) |
147 |
name=str(node.getElementsByTagName("name")[0].firstChild.nodeValue.strip()) |
148 |
self.setMap(**{ name : tag }) |
149 |
return |
150 |
|
151 |
def fillFromXML(self,iostream): |
152 |
""" |
153 |
uses the xml file or string to set the mapping |
154 |
""" |
155 |
if isinstance(iostream,str): |
156 |
dom=minidom.parseString(iostream) |
157 |
else: |
158 |
dom=minidom.parse(iostream) |
159 |
root=dom.getElementsByTagName('ESys')[0] |
160 |
for node in root.childNodes: |
161 |
if isinstance(node, minidom.Element): |
162 |
if node.tagName == 'TagMap': |
163 |
self.fromDom(node) |
164 |
return |
165 |
|
166 |
|
167 |
|
168 |
def writeXML(self,iostream=None): |
169 |
""" |
170 |
writes XML serialization into the iostream or if not present returns the XML as string |
171 |
""" |
172 |
dom=minidom.Document() |
173 |
esys=dom.createElement('ESys') |
174 |
esys.appendChild(self.toDOM(dom)) |
175 |
dom.appendChild(esys) |
176 |
if iostream == None: |
177 |
return dom.toprettyxml() |
178 |
else: |
179 |
iostream.write(dom.toprettyxml()) |
180 |
|
181 |
class Design(object): |
182 |
""" |
183 |
template for a design which defines the input for a mesh generator |
184 |
""" |
185 |
def __init__(self,dim=3,element_size=1.,order=1,keep_files=False): |
186 |
""" |
187 |
initializes a design |
188 |
|
189 |
@param dim: patial dimension |
190 |
@param element_size: global element size |
191 |
@param order: element order |
192 |
@param keep_files: flag to keep work files. |
193 |
""" |
194 |
self.clearItems() |
195 |
self.setElementSize(element_size) |
196 |
self.setDim(dim) |
197 |
self.setElementOrder(order) |
198 |
if keep_files: |
199 |
self.setKeepFilesOn() |
200 |
else: |
201 |
self.setKeepFilesOff() |
202 |
def setDim(self,dim=3): |
203 |
""" |
204 |
sets the spatial dimension |
205 |
""" |
206 |
if not dim in [1,2,3]: |
207 |
raise ValueError("only dimension 1, 2, 3 are supported.") |
208 |
self.__dim=dim |
209 |
def getDim(self,dim=3): |
210 |
""" |
211 |
returns the spatial dimension |
212 |
""" |
213 |
return self.__dim |
214 |
def setElementOrder(self,order=1): |
215 |
""" |
216 |
sets the element order |
217 |
""" |
218 |
if not order in [1,2]: |
219 |
raise ValueError("only element orser 1 or 2 is supported.") |
220 |
self.__order=order |
221 |
|
222 |
def getElementOrder(self): |
223 |
""" |
224 |
returns the element order |
225 |
""" |
226 |
return self.__order |
227 |
|
228 |
def setElementSize(self,element_size=1.): |
229 |
""" |
230 |
set the global element size. |
231 |
""" |
232 |
if element_size<=0.: |
233 |
raise ValueError("element size needs to be positive.") |
234 |
self.__element_size=element_size |
235 |
|
236 |
def getElementSize(self): |
237 |
""" |
238 |
returns the global element size. |
239 |
""" |
240 |
return self.__element_size |
241 |
|
242 |
def setKeepFilesOn(self): |
243 |
""" |
244 |
work files are kept at the end of the generation |
245 |
""" |
246 |
self.__keep_files=True |
247 |
def setKeepFilesOff(self): |
248 |
""" |
249 |
work files are deleted at the end of the generation |
250 |
""" |
251 |
self.__keep_files=False |
252 |
def keepFiles(self): |
253 |
""" |
254 |
returns True if work files are kept |
255 |
""" |
256 |
return self.__keep_files |
257 |
def addItems(self,*items): |
258 |
""" |
259 |
adds items to the design |
260 |
""" |
261 |
for i in range(len(items)): |
262 |
if not isinstance(items[i],(Primitive, ReversePrimitive)): |
263 |
raise TypeError("%s-th argument is not a Primitive object"%i) |
264 |
for i in items: |
265 |
self.__items.append(i) |
266 |
def getItems(self): |
267 |
""" |
268 |
returns a list of the items used in the design |
269 |
""" |
270 |
return self.__items |
271 |
def clearItems(self): |
272 |
""" |
273 |
resets the items in design |
274 |
""" |
275 |
self.__items=[] |
276 |
def getAllPrimitives(self): |
277 |
""" |
278 |
returns a list of all primitives used to create the design. |
279 |
each primitve appears once. The primitives are ordered by their |
280 |
order of generation |
281 |
""" |
282 |
prims=[] |
283 |
for i in self.getItems(): |
284 |
for p in i.getPrimitives(): |
285 |
if not p in prims: prims.append(p) |
286 |
prims.sort() |
287 |
return prims |
288 |
|
289 |
def setOptions(self,**kwargs): |
290 |
""" |
291 |
sets options of the mesh generator |
292 |
|
293 |
@note: this method is typically overwritten by a particular Design implementation |
294 |
""" |
295 |
pass |
296 |
def getMeshHandler(self): |
297 |
""" |
298 |
returns a handle to a mesh meshing the design |
299 |
|
300 |
@note: this method has to be overwritten by a particular Design implementation |
301 |
""" |
302 |
raise NotImplementedError() |
303 |
|
304 |
def getTagMap(self): |
305 |
""" |
306 |
returns a L{TagMap} to map the names of L{PropertySet}s to tags |
307 |
""" |
308 |
m={} |
309 |
for p in self.getAllPrimitives(): |
310 |
if isinstance(p, PropertySet): m[ p.getTag() ] = p.getName() |
311 |
return TagMap(m) |