1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Adapter to Genesis/ExodusII format.
21 """
22
23 from .core import FormatIO
24 from .netcdf import NetCDF
25
27 """
28 Model of Genesis/ExodusII file, based on netCDF reader wrapper. The
29 Genesis/ExodusII file must meet the following criteria: (i) have at least
30 one block, (ii) each block needs a name, and (iii) each sideset (BC) needs
31 a name.
32
33 @ivar ndim: dimension (2 or 3).
34 @itype ndim: int
35 @ivar nnode: number of nodes.
36 @itype nnode: int
37 @ivar ncell: number of cells/elements.
38 @itype ncell: int
39 @ivar blks: list of tuples of (name, type_name, clnds) for each Genesis
40 block.
41 @itype blks: list
42 @ivar bcs: list of tuples of (name, elem, side) for each BC (Genesis
43 sideset).
44 @itype bcs: list
45 @ivar ndcrd: coordiate array.
46 @itype ndcrd: numpy.ndarray
47 """
49 super(Genesis, self).__init__(*arg, **kw)
50
51 self.ndim = None
52 self.nnode = None
53 self.ncell = None
54
55 self.blks = None
56 self.bcs = None
57
58 self.ndcrd = None
59
60 self.emap = None
61
62 - def get_attr_text(self, name, varname):
63 """
64 Get the attribute text attached to an variable.
65
66 @param name: name of the attribute.
67 @type name: str
68 @param varname: name of the variable.
69 @type varname: str
70 @return: the text.
71 @rtype: str
72 """
73 from ctypes import POINTER, c_int, c_char, byref, create_string_buffer
74
75 varid = c_int()
76 retval = self.nc_inq_varid(self.ncid, varname, byref(varid))
77 if retval != self.NC_NOERR:
78 raise IOError(self.nc_strerror(retval))
79
80 slen = self.get_dim('len_string')
81 buf = create_string_buffer(slen)
82 retval = self.nc_get_att_text(self.ncid, varid, name, buf)
83 if retval != self.NC_NOERR:
84 raise IOError(self.nc_strerror(retval))
85 return buf.value
86
88 """
89 Load mesh data.
90
91 @return: nothing
92 """
93 from ctypes import c_int, byref
94 from numpy import hstack
95
96 self.ndim = ndim = self.get_dim('num_dim')
97 self.nnode = nnode = self.get_dim('num_nodes')
98 self.ncell = self.get_dim('num_elem')
99
100 nblk = self.get_dim('num_el_blk')
101 slen = self.get_dim('len_string')
102 self.blks = self.get_lines('eb_names', (nblk, slen))
103 for iblk in range(nblk):
104 ncell = self.get_dim('num_el_in_blk%d' % (iblk+1))
105 clnnd = self.get_dim('num_nod_per_el%d' % (iblk+1))
106 clnds = self.get_array('connect%d' % (iblk+1),
107 (ncell, clnnd), 'int32')
108 type_name = self.get_attr_text('elem_type', 'connect%d' % (iblk+1))
109 self.blks[iblk] = (self.blks[iblk], type_name, clnds)
110
111 nbc = self.get_dim('num_side_sets')
112 self.bcs = self.get_lines('ss_names', (nbc, slen))
113 for ibc in range(nbc):
114 nface = self.get_dim('num_side_ss%d'%(ibc+1))
115 elem = self.get_array('elem_ss%d'%(ibc+1), (nface,), 'int32')
116 side = self.get_array('side_ss%d'%(ibc+1), (nface,), 'int32')
117 self.bcs[ibc] = (self.bcs[ibc], elem, side)
118
119 large = c_int()
120 self.nc_get_att_int(self.ncid, self.NC_GLOBAL, 'file_size',
121 byref(large))
122 if large.value:
123 vnames = ['coord%s' % ('xyz'[idm]) for idm in range(ndim)]
124 crds = [self.get_array(vn, nnode, 'float64') for vn in vnames]
125 self.ndcrd = hstack([crd.reshape((nnode,1)) for crd in crds])
126 else:
127 self.ndcrd = self.get_array('coord', (ndim, nnode),
128 'float64').T.copy()
129
130 self.emap = self.get_array('elem_map', (self.ncell,), 'int32')
131
132 - def toblock(self, onlybcnames=None, bcname_mapper=None, fpdtype=None):
155
156 CLTPN_MAP = {
157 'QUAD': 2,
158 'TRI3': 3,
159 'HEX8': 4,
160 'TETRA': 5,
161 'WEDGE': 6,
162 'PYRAMID': 7,
163 }
165 """
166 Convert interior connectivities to Block object.
167
168 @param blk: to-be-written Block object.
169 @type blk: solvcon.block.Block
170 @return: nothing
171 """
172 from ..block import elemtype
173
174 blk.ndcrd[:] = self.ndcrd[:]
175
176 ien = 0
177 for name, tname, clnds in self.blks:
178 ist = ien
179 ien += clnds.shape[0]
180
181 blk.cltpn[ist:ien] = self.CLTPN_MAP[tname]
182
183 nnd = elemtype[self.CLTPN_MAP[tname],2]
184 sclnds = blk.clnds[ist:ien]
185 sclnds[:,0] = nnd
186 sclnds[:,1:nnd+1] = clnds
187 sclnds[:,1:nnd+1] -= 1
188 if tname == 'PRISM':
189 arr = sclnds[:,2].copy()
190 sclnds[:,2] = sclnds[:,3]
191 sclnds[:,3] = arr
192 arr[:] = sclnds[:,5]
193 sclnds[:,5] = sclnds[:,6]
194 sclnds[:,6] = arr
195
196 blk.grpnames = [it[0] for it in self.blks]
197 iblk = 0
198 ien = 0
199 for name, tname, clnds in self.blks:
200 ist = ien
201 ien += clnds.shape[0]
202 blk.clgrp[ist:ien] = iblk
203 iblk += 1
204
206 """
207 Convert boundary condition information into Block object.
208
209 @param blk: to-be-written Block object.
210 @type blk: solvcon.block.Block
211 @keyword onlynames: positively list wanted names of BCs.
212 @type onlynames: list
213 @keyword name_mapper: map name to bc type and value dictionary; the two
214 objects are organized in a tuple.
215 @type name_mapper: dict
216 @return: nothing.
217 """
218
219 for ibc in range(len(self.bcs)):
220
221 bc = self._tobc(ibc, blk)
222
223 if onlynames:
224 if bc.name not in onlynames:
225 continue
226
227 if name_mapper is not None:
228 bct, vdict = name_mapper.get(bc.name, None)
229 if bct is not None:
230 bc = bct(bc=bc)
231 bc.feedValue(vdict)
232
233 bc.sern = len(blk.bclist)
234 bc.blk = blk
235 blk.bclist.append(bc)
236
237
238 CLFCS_MAP = {}
239 CLFCS_MAP[2] = [1,2,3,4]
240 CLFCS_MAP[3] = [1,2,3]
241 CLFCS_MAP[4] = [5,2,6,4,1,3]
242 CLFCS_MAP[5] = [2,4,3,1]
243 CLFCS_MAP[6] = [4,5,3,1,2]
244 CLFCS_MAP[7] = [2,3,4,1,5]
245 - def _tobc(self, ibc, blk):
246 """
247 Extract boundary condition information from self to become a BC object.
248 Only process element/cell type of boundary information.
249
250 @param ibc: index of the BC to be extracted.
251 @type ibc: int
252 @param blk: Block object for reference, nothing will be altered.
253 @type blk: solvcon.block.Block
254 @return: generic BC object.
255 @rtype: solvcon.boundcond.BC
256 """
257 from numpy import empty
258 from ..boundcond import BC
259 clfcs_map = self.CLFCS_MAP
260 cltpn = blk.cltpn
261 clfcs = blk.clfcs
262 name, elem, side = self.bcs[ibc]
263 nbnd = elem.shape[0]
264
265 facn = empty((nbnd,3), dtype='int32')
266 facn.fill(-1)
267 ibnd = 0
268 while ibnd < nbnd:
269 icl = elem[ibnd] - 1
270 tpn = cltpn[icl]
271 ifl = clfcs_map[tpn][side[ibnd]-1]
272 facn[ibnd,0] = clfcs[icl,ifl]
273 ibnd += 1
274
275 bc = BC(fpdtype=blk.fpdtype)
276 bc.name = name
277 slct = facn[:,0].argsort()
278 bc.facn = facn[slct]
279
280 return bc
281
283 """
284 Proxy to Cubit/Genesis/ExodusII file format.
285 """
286 - def load(self, stream, bcrej=None):
287 """
288 Load block from stream with BC mapper applied.
289
290 @keyword stream: file name to be read.
291 @type stream: str
292 @keyword bcrej: names of the BC to reject.
293 @type bcrej: list
294 @return: the loaded block.
295 @rtype: solvcon.block.Block
296 """
297
298 assert isinstance(stream, basestring)
299 gn = Genesis(stream)
300 gn.load()
301 gn.close_file()
302
303 if bcrej:
304 onlybcnames = list()
305 for name, elem, side in gn.bcs:
306 if name not in bcrej:
307 onlybcnames.append(name)
308 else:
309 onlybcnames = None
310 blk = gn.toblock(onlybcnames=onlybcnames)
311 return blk
312