1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
78 self.sbc = sbc
79 self.cache = dict()
80
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
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
91 assert hasattr(sbc, 'glue')
92 sbc.glue = self
93
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
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
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()
171
172
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_ = []
206
207 vnames = []
208 vdefaults = {}
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
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
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
239 self.facn = empty((0,3), dtype='int32')
240
241 self.value = empty((0,self.nvalue), dtype=self.fpdtype)
242 else:
243 bc.cloneTo(self)
244 super(BC, self).__init__()
245
246 @property
250
251 @property
254
256 return self.facn.shape[0]
257
259 return "[%s#%s \"%s\": %d faces with %d values]" % (
260 self.__class__.__name__, self.sern, self.name,
261 len(self), self.nvalue)
262
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
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
291 vpairs = self.vdefaults.copy()
292 for vn in vdict:
293 if vn in self.vnames:
294 vpairs[vn] = vdict[vn]
295
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
303 self.value = values
304
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
325 """
326 Finalizer.
327 """
328 pass
329
331 """
332 Abstract BC type for unspecified boundary conditions.
333 """
334
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
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
356 super(interface, self).cloneTo(another)
357 another.rblkn = self.rblkn
358 another.rblkinfo = self.rblkinfo.copy()
359 another.rclp = self.rclp.copy()
360
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
375 self.rblkinfo[:] = (rblk.nnode, rblk.ngstnode,
376 rblk.nface, rblk.ngstface, rblk.ncell, rblk.ngstcell)
377
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
383 assert (self.rclp[:,0]<0).all()
384 assert (self.rclp[:,1]>=0).all()
385 assert (self.rclp[:,2]>=0).all()
386
388 """
389 BC type for periodic boundary condition.
390 """
391
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
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
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
427 self.rblkinfo[:] = (blk.nnode, blk.ngstnode,
428 blk.nface, blk.ngstface, blk.ncell, blk.ngstcell)
429
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
435 assert (self.rclp[:,0]<0).all()
436 assert (self.rclp[:,1]>=0).all()
437 assert (self.rclp[:,2]>=0).all()
438
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
445 shf = blk.shclcnd[slctr,:] - blk.fccnd[facn[:,2],:]
446 blk.shclcnd[slctm,:] = self.blk.fccnd[facn[:,0],:] + shf
447
448 @staticmethod
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