Package solvcon :: Package io :: Module genesis
[hide private]
[frames] | no frames]

Source Code for Module solvcon.io.genesis

  1  # -*- coding: UTF-8 -*- 
  2  # 
  3  # Copyright (C) 2011 Yung-Yu Chen <yyc@solvcon.net>. 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18   
 19  """ 
 20  Adapter to Genesis/ExodusII format. 
 21  """ 
 22   
 23  from .core import FormatIO 
 24  from .netcdf import NetCDF 
 25   
26 -class Genesis(NetCDF):
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 """
48 - def __init__(self, *arg, **kw):
49 super(Genesis, self).__init__(*arg, **kw) 50 # shape data. 51 self.ndim = None 52 self.nnode = None 53 self.ncell = None 54 # blocks and BCs. 55 self.blks = None 56 self.bcs = None 57 # coordinate. 58 self.ndcrd = None 59 # mapper. 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 # get value ID. 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 # get text. 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
87 - def load(self):
88 """ 89 Load mesh data. 90 91 @return: nothing 92 """ 93 from ctypes import c_int, byref 94 from numpy import hstack 95 # meta data. 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 # blocks. 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 # BCs. 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 # coordinate. 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 # mapper. 130 self.emap = self.get_array('elem_map', (self.ncell,), 'int32')
131
132 - def toblock(self, onlybcnames=None, bcname_mapper=None, fpdtype=None):
133 """ 134 Convert Cubit/Genesis/ExodusII object to Block object. 135 136 @keyword onlybcnames: positively list wanted names of BCs. 137 @type onlybcnames: list 138 @keyword bcname_mapper: map name to bc type number. 139 @type bcname_mapper: dict 140 @keyword fpdtype: floating-point dtype. 141 @type fpdtype: str 142 @return: Block object. 143 @rtype: solvcon.block.Block 144 """ 145 from ..block import Block 146 blk = Block(ndim=self.ndim, nnode=self.nnode, ncell=self.ncell, 147 fpdtype=fpdtype) 148 self._convert_interior_to(blk) 149 blk.build_interior() 150 self._convert_bc_to(blk, 151 onlynames=onlybcnames, name_mapper=bcname_mapper) 152 blk.build_boundary() 153 blk.build_ghost() 154 return blk
155 156 CLTPN_MAP = { 157 'QUAD': 2, 158 'TRI3': 3, 159 'HEX8': 4, 160 'TETRA': 5, 161 'WEDGE': 6, 162 'PYRAMID': 7, 163 }
164 - def _convert_interior_to(self, blk):
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 # coordinate. 174 blk.ndcrd[:] = self.ndcrd[:] 175 # node definition. 176 ien = 0 177 for name, tname, clnds in self.blks: 178 ist = ien 179 ien += clnds.shape[0] 180 # type. 181 blk.cltpn[ist:ien] = self.CLTPN_MAP[tname] 182 # nodes. 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 # groups. 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
205 - def _convert_bc_to(self, blk, onlynames=None, name_mapper=None):
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 # process all neutral bc objects. 219 for ibc in range(len(self.bcs)): 220 # extract boundary faces. 221 bc = self._tobc(ibc, blk) 222 # skip unwanted BCs. 223 if onlynames: 224 if bc.name not in onlynames: 225 continue 226 # recreate BC according to name mapping. 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 # save to block object. 233 bc.sern = len(blk.bclist) 234 bc.blk = blk 235 blk.bclist.append(bc)
236 237 # define map for clfcs. 238 CLFCS_MAP = {} 239 CLFCS_MAP[2] = [1,2,3,4] # quadrilateral. 240 CLFCS_MAP[3] = [1,2,3] # triangle. 241 CLFCS_MAP[4] = [5,2,6,4,1,3] # hexahedron. 242 CLFCS_MAP[5] = [2,4,3,1] # tetrahedron. 243 CLFCS_MAP[6] = [4,5,3,1,2] # prism. 244 CLFCS_MAP[7] = [2,3,4,1,5] # pyramid.
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 # extrace boundary face list. 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 # craft BC object. 275 bc = BC(fpdtype=blk.fpdtype) 276 bc.name = name 277 slct = facn[:,0].argsort() # sort face list for bc object. 278 bc.facn = facn[slct] 279 # finish. 280 return bc
281
282 -class GenesisIO(FormatIO):
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 # load file into memory. 298 assert isinstance(stream, basestring) 299 gn = Genesis(stream) 300 gn.load() 301 gn.close_file() 302 # convert loaded neutral object into block object. 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