Package solvcon :: Module boundcond
[hide private]
[frames] | no frames]

Source Code for Module solvcon.boundcond

  1  # -*- coding: UTF-8 -*- 
  2  # 
  3  # Copyright (C) 2008-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  Primitive boundary condition definition. 
 21   
 22  Basic supportive logic for interface BCs, periodic BCs, and glued BCs is 
 23  defined here. 
 24  """ 
 25   
 26  from .gendata import TypeNameRegistry, TypeWithBinder 
27 28 -class Glue(object):
29 """ 30 Glue two boundary conditions which are considered to be collocated. 31 32 @cvar CACHE_KEYS_ENABLER: names of arrays whose original values to be 33 cached when the glue is enabled. 34 @ctype CACHE_KEYS_ENABLER: tuple 35 @ivar sbc: source BC object. 36 @itype sbc: solvcon.boundcond.BC 37 @ivar reciprocal: the glue object on the other side. 38 @itype reciprocal: Glue 39 @ivar ref: a reference point for matching bounding faces. 40 @itype ref: numpy.ndarray 41 @ivar cache: cache for mesh data. 42 @itype cache: dict 43 @ivar scls: source cell list shifted by ngstcell. 44 @itype scls: numpy.ndarray 45 @ivar dcls: destination cell list shifted by ngstcell. 46 @itype dcls: numpy.ndarray 47 """ 48 49 CACHE_KEYS_ENABLER = ('cltpn', 'clgrp', 'clvol', 'clcnd') 50
51 - def __init__(self, sbc, dbc, ref=None, reciprocal=None):
52 """ 53 The constructor will create a PAIR of Glue objects attached to the 54 input source BC object (sbc) and destination BC object (dbc). Each 55 Glue object in the pair is the reciprocal of the other. The 56 constructor DOES NOT modify associated BC or BlockSolver objects except 57 setting BC objects' glue property to self. If no reference point is 58 given through ref keyword, a random reference point is generated for 59 sorting boundary faces to be glued. 60 61 @param sbc: source BC object. 62 @type sbc: solvcon.boundcond.BC 63 @param dbc: destination BC object. 64 @type dbc: solvcon.boundcond.BC 65 @keyword ref: a reference point for matching bounding faces. 66 @type ref: numpy.ndarray 67 @keyword reciprocal: the glue object on the other side. 68 @type reciprocal: Glue 69 """ 70 from random import random 71 from numpy import array 72 svr = sbc.svr 73 ngstface = svr.ngstface 74 ngstcell = svr.ngstcell 75 ndim = svr.ndim 76 fpdtype = svr.fpdtype 77 # set source BC object and cache container. 78 self.sbc = sbc 79 self.cache = dict() 80 # calculate and set a reference point and use it to sort faces. 81 if ref is None: 82 ref = array([random() for it in range(ndim)], dtype=fpdtype) 83 assert len(ref) == ndim 84 self.ref = ref 85 # calculate and set cell lists. 86 self.scls = svr.fccls[self.__sortfcs(sbc,ref),1] + ngstcell 87 self.dcls = svr.fccls[self.__sortfcs(dbc,ref),0] + ngstcell 88 assert (self.scls<ngstcell).all() 89 assert (self.dcls>=ngstcell).all() 90 # set properties to source BC. 91 assert hasattr(sbc, 'glue') 92 sbc.glue = self 93 # create and set reciprocal if self is the first in a pair. 94 if reciprocal is None: 95 self.reciprocal = Glue(dbc, sbc, ref=ref, reciprocal=self) 96 else: 97 assert isinstance(reciprocal, Glue) 98 self.reciprocal = reciprocal
99 100 @staticmethod
101 - def __sortfcs(bc, ref):
102 """ 103 Get the sorted face list of a BC object according to the reference 104 point. 105 106 @param bc: a BC object. 107 @type bc: solvcon.boundcond.BC 108 @param ref: reference point. 109 @type ref: numpy.ndarray 110 @return: sorted face indices shifted by ngstface. 111 @rtype: numpy.ndarray 112 """ 113 cnd = bc.svr.fccnd[bc.facn[:,0]+bc.svr.ngstface,:] 114 dist = ((cnd - ref)**2).sum(axis=1) 115 return bc.facn[dist.argsort(),0]+bc.svr.ngstface
116
117 - def enable(self, *args, **kw):
118 """ 119 Enable this glue by setting ghost information from interior and store 120 original values in a cache. Arguments are the keys of arrays to be 121 cached. 122 123 @keyword with_default: use CACHE_KEYS_ENABLER anyway. Default True. 124 @type with_default: bool 125 @return: nothing 126 """ 127 keys = list(args) 128 if args and kw.get('with_default', True): 129 keys.extend(self.CACHE_KEYS_ENABLER) 130 for key in keys: 131 arr = getattr(self.sbc.svr, key) 132 self.cache[key] = arr[self.scls].copy() 133 self.take(key)
134
135 - def disable(self, *args, **kw):
136 """ 137 Disable this glue by restoring ghost information from cached values. 138 Arguments are the keys of cached arrays. 139 140 @keyword with_default: use CACHE_KEYS_ENABLER anyway. Default True. 141 @type with_default: bool 142 @return: nothing 143 """ 144 keys = list(args) 145 if args and kw.get('with_default', True): 146 keys.extend(self.CACHE_KEYS_ENABLER) 147 for key in keys: 148 arr = getattr(self.sbc.svr, key) 149 arr[self.scls] = self.cache[key]
150
151 - def take(self, key):
152 """ 153 Take array values from interior cells to ghost cells. 154 155 @param key: the name of the array. 156 @type key: str 157 @return: nothing 158 """ 159 arr = getattr(self.sbc.svr, key) 160 arr[self.scls] = arr[self.dcls]
161 162 bctregy = TypeNameRegistry() # registry singleton.
163 -class BCMeta(TypeWithBinder):
164 """ 165 Meta class for boundary condition class. 166 """
167 - def __new__(cls, name, bases, namespace):
168 newcls = super(BCMeta, cls).__new__(cls, name, bases, namespace) 169 bctregy.register(newcls) 170 return newcls
171
172 # Base/abstract BC type. 173 -class BC(object):
174 """ 175 Generic boundary condition abstract class. It's the base class that all 176 boundary condition class should subclass. 177 178 @cvar vnames: settable value names. 179 @type vnames: list 180 @cvar vdefaults: default values. 181 @type vdefaults: dict 182 183 @ivar sern: serial number (for certain block). 184 @type sern: int 185 @ivar name: name. 186 @type name: str 187 @ivar blk: the block associated with this BC object. 188 @type blk: solvcon.block.Block 189 @ivar blkn: serial number of self block. 190 @type blkn: int 191 @ivar svr: solver object. 192 @type svr: solvcon.solver.BaseSolver 193 @ivar glue: glue for two collocated BC objects. 194 @type glue: Glue 195 @ivar facn: list of faces. First column is the face index in block. The 196 second column is the face index in bndfcs. The third column is the 197 face index of the related block (if exists). 198 @type facn: numpy.ndarray 199 @ivar value: attached value for each boundary face. 200 @type value: numpy.ndarray 201 """ 202 203 __metaclass__ = BCMeta 204 205 _pointers_ = [] # for binder. 206 207 vnames = [] # settable value names. 208 vdefaults = {} # defaults to values. 209
210 - def __init__(self, bc=None, fpdtype=None):
211 """ 212 Initialize object with empty values or from another BC object. 213 214 @param bc: Another BC object. 215 @type bc: solvcon.boundcond.BC 216 """ 217 import numpy as np 218 from numpy import empty 219 from .conf import env 220 # determine fpdtype. 221 if fpdtype == None: 222 if bc == None: 223 self.fpdtype = env.fpdtype 224 else: 225 self.fpdtype = bc.fpdtype 226 else: 227 self.fpdtype = fpdtype 228 if isinstance(self.fpdtype, str): 229 self.fpdtype = getattr(np, self.fpdtype) 230 if bc is None: 231 # general data. 232 self.sern = None 233 self.name = None 234 self.blk = None 235 self.blkn = None 236 self.svr = None 237 self.glue = None 238 # face list. 239 self.facn = empty((0,3), dtype='int32') 240 # attached (specified) value. 241 self.value = empty((0,self.nvalue), dtype=self.fpdtype) 242 else: 243 bc.cloneTo(self) 244 super(BC, self).__init__()
245 246 @property
247 - def fpdtypestr(self):
248 from .dependency import str_of 249 return str_of(self.fpdtype)
250 251 @property
252 - def nvalue(self):
253 return len(self.vnames)
254
255 - def __len__(self):
256 return self.facn.shape[0]
257
258 - def __str__(self):
259 return "[%s#%s \"%s\": %d faces with %d values]" % ( 260 self.__class__.__name__, self.sern, self.name, 261 len(self), self.nvalue)
262
263 - def cloneTo(self, another):
264 """ 265 Clone self to passed-in another BC object. 266 267 @param another: Another BC object. 268 @type another: solvcon.boundcond.BC 269 """ 270 assert issubclass(type(another), type(self)) 271 assert another.fpdtype == self.fpdtype 272 another.sern = self.sern 273 another.name = self.name 274 another.blk = self.blk 275 another.blkn = self.blkn 276 another.svr = self.svr 277 another.glue = None 278 another.facn = self.facn.copy() 279 another.value = self.value.copy()
280
281 - def feedValue(self, vdict):
282 """ 283 Get feed values to self boundary condition. 284 285 @param vdict: name and value pairs. 286 @type vdict: dict 287 @return: nothing. 288 """ 289 from numpy import empty 290 # get name-value pairs for each value. 291 vpairs = self.vdefaults.copy() 292 for vn in vdict: 293 if vn in self.vnames: 294 vpairs[vn] = vdict[vn] 295 # set values to array. 296 nbfcs = len(self) 297 nvalue = len(self.vnames) 298 values = empty((nbfcs, nvalue), dtype=self.fpdtype) 299 for iv in range(nvalue): 300 vn = self.vnames[iv] 301 values[:,iv].fill(vpairs[vn]) 302 # save set array. 303 self.value = values
304
305 - def gluetake(self, key):
306 """ 307 Use the attached Glue object to update the array specified by key. 308 309 @param key: array name. 310 @type key: str 311 @return: nothing 312 """ 313 svr = self.svr 314 if svr.scu: svr.cumgr.arr_from_gpu(key) 315 self.glue.take(key) 316 if svr.scu: svr.cumgr.arr_to_gpu(key)
317
318 - def init(self, **kw):
319 """ 320 Initializer. 321 """ 322 pass
323
324 - def final(self, **kw):
325 """ 326 Finalizer. 327 """ 328 pass
329
330 -class unspecified(BC):
331 """ 332 Abstract BC type for unspecified boundary conditions. 333 """
334
335 -class interface(BC):
336 """ 337 Abstract BC type for interface between blocks. 338 339 @ivar rblkn: index number of related block. 340 @itype rblkn: int 341 @ivar rclp: list of related cell pairs. The first column is for the 342 indices of the ghost cells belong to self block. The second column is 343 for the indices of the cells belong to the related block. The third 344 column is for the indices of the cells belong to self block. 345 @itype rclp: numpy.ndarray 346 """ 347
348 - def __init__(self, **kw):
349 from numpy import empty 350 super(interface, self).__init__(**kw) 351 self.rblkn = getattr(self, 'rblkn', -1) 352 self.rblkinfo = empty(6, dtype='int32') 353 self.rclp = empty((0,3), dtype='int32')
354
355 - def cloneTo(self, another):
356 super(interface, self).cloneTo(another) 357 another.rblkn = self.rblkn 358 another.rblkinfo = self.rblkinfo.copy() 359 another.rclp = self.rclp.copy()
360
361 - def relateCells(self, dom):
362 """ 363 Calculate self.rclp[:,:] form the information about related block 364 provided by dom parameter. 365 366 @param dom: Collective domain for information about related block. 367 @type dom: solvcon.domain.Collective 368 @return: nothing. 369 """ 370 from numpy import empty 371 facn = self.facn 372 blk = self.blk 373 rblk = dom[self.rblkn] 374 # fill informations from related block. 375 self.rblkinfo[:] = (rblk.nnode, rblk.ngstnode, 376 rblk.nface, rblk.ngstface, rblk.ncell, rblk.ngstcell) 377 # calculate indices of related cells. 378 self.rclp = empty((len(self),3), dtype='int32') 379 self.rclp[:,0] = blk.fccls[facn[:,0],1] 380 self.rclp[:,1] = rblk.fccls[facn[:,2],0] 381 self.rclp[:,2] = blk.fccls[facn[:,0],0] 382 # assertion. 383 assert (self.rclp[:,0]<0).all() 384 assert (self.rclp[:,1]>=0).all() 385 assert (self.rclp[:,2]>=0).all()
386
387 -class periodic(BC):
388 """ 389 BC type for periodic boundary condition. 390 """ 391
392 - def __init__(self, **kw):
393 from numpy import empty 394 super(periodic, self).__init__(**kw) 395 self.rblkn = getattr(self, 'rblkn', -1) 396 self.rblkinfo = empty(6, dtype='int32') 397 self.rclp = empty((0,3), dtype='int32')
398
399 - def cloneTo(self, another):
400 super(periodic, self).cloneTo(another) 401 another.rblkn = self.rblkn 402 another.rblkinfo = self.rblkinfo.copy() 403 another.rclp = self.rclp.copy()
404
405 - def sort(self, ref):
406 if ref is None: 407 return 408 from numpy import sqrt 409 dist = sqrt(((self.blk.fccnd[self.facn[:,0],:] - ref)**2).sum(axis=1)) 410 slct = dist.argsort() 411 self.facn = self.facn[slct,:]
412
413 - def couple(self, rbc):
414 """ 415 Calculate self.rclp[:,:] form the information about related BC object 416 provided by rbc parameter. 417 418 @param rbc: Related BC object. 419 @type rbc: solvcon.boundcond.periodic 420 @return: nothing. 421 """ 422 from numpy import empty 423 blk = self.blk 424 facn = self.facn 425 facn[:,2] = rbc.facn[:,0] 426 # fill informations from related block. 427 self.rblkinfo[:] = (blk.nnode, blk.ngstnode, 428 blk.nface, blk.ngstface, blk.ncell, blk.ngstcell) 429 # calculate indices of related cells. 430 self.rclp = empty((len(self),3), dtype='int32') 431 self.rclp[:,0] = blk.fccls[facn[:,0],1] 432 self.rclp[:,1] = blk.fccls[facn[:,2],0] 433 self.rclp[:,2] = blk.fccls[facn[:,0],0] 434 # assertion. 435 assert (self.rclp[:,0]<0).all() 436 assert (self.rclp[:,1]>=0).all() 437 assert (self.rclp[:,2]>=0).all() 438 # copy metrics. 439 slctm = self.rclp[:,0] + blk.ngstcell 440 slctr = self.rclp[:,1] + blk.ngstcell 441 blk.shcltpn[slctm] = blk.shcltpn[slctr] 442 blk.shclgrp[slctm] = blk.shclgrp[slctr] 443 blk.shclvol[slctm] = blk.shclvol[slctr] 444 # move coordinates. 445 shf = blk.shclcnd[slctr,:] - blk.fccnd[facn[:,2],:] 446 blk.shclcnd[slctm,:] = self.blk.fccnd[facn[:,0],:] + shf
447 448 @staticmethod
449 - def couple_all(blk, bcmap):
450 """ 451 Couple all periodic boundary conditions. 452 453 @param blk: the block having periodic BCs to be coupled. 454 @type blk: solvcon.block.Block 455 @param bcmap: mapper for periodic BCs. 456 @type bcmap: dict 457 @return: nothing 458 """ 459 from solvcon.boundcond import periodic 460 nmidx = dict([(blk.bclist[idx].name, idx) for idx in 461 range(len(blk.bclist))]) 462 npidx = list() 463 for key in bcmap: 464 bct, vdict = bcmap[key] 465 if not issubclass(bct, periodic): 466 try: 467 if key in nmidx: 468 npidx.append(nmidx[key]) 469 except Exception as e: 470 args = list(e.args) 471 args.append(str(nmidx)) 472 e.args = tuple(args) 473 raise 474 continue 475 val = vdict['link'] 476 ibc0 = nmidx[key] 477 ibc1 = nmidx[val] 478 pbc0 = blk.bclist[ibc0] = bct(bc=blk.bclist[ibc0]) 479 pbc1 = blk.bclist[ibc1] = bct(bc=blk.bclist[ibc1]) 480 ref = vdict.get('ref', None) 481 pbc0.sort(ref) 482 pbc1.sort(ref) 483 pbc0.couple(pbc1) 484 pbc1.couple(pbc0)
485