# ___ ___ ___ ___ ___ # /\ \ ___ /\__\ /\ \ /\ \ /\ \ # /::\ \ /\ \ /::| | /::\ \ /::\ \ /::\ \ # /:/\ \ \ \:\ \ /:|:| | /:/\:\ \ /:/\:\ \ /:/\:\ \ # _\:\~\ \ \ /::\__\ /:/|:|__|__ /::\~\:\ \ /::\~\:\ \ /:/ \:\ \ # /\ \:\ \ \__\ __/:/\/__//:/ |::::\__\/:/\:\ \:\__\/:/\:\ \:\__\/:/__/_\:\__\ # \:\ \:\ \/__//\/:/ / \/__/~~/:/ /\/__\:\/:/ /\:\~\:\ \/__/\:\ /\ \/__/ # \:\ \:\__\ \::/__/ /:/ / \::/ / \:\ \:\__\ \:\ \:\__\ # \:\/:/ / \:\__\ /:/ / \/__/ \:\ \/__/ \:\/:/ / # \::/ / \/__/ /:/ / \:\__\ \::/ / # \/__/ \/__/ \/__/ \/__/ # ___ ___ ___ ___ ___ ___ # /\ \ /\ \ /\ \ /\ \ /\ \ /\ \ # /::\ \ /::\ \ \:\ \ /::\ \ /::\ \ /::\ \ # /:/\:\ \ /:/\:\ \ \:\ \ /:/\:\ \ /:/\:\ \ /:/\:\ \ # /:/ \:\ \ /:/ \:\ \ /::\ \ /::\~\:\ \ /::\~\:\ \ /::\~\:\ \ # /:/__/ \:\__\/:/__/ \:\__\ /:/\:\__\/:/\:\ \:\__\/:/\:\ \:\__\/:/\:\ \:\__\ # \:\ \ /:/ /\:\ \ \/__//:/ \/__/\/_|::\/:/ /\:\~\:\ \/__/\:\~\:\ \/__/ # \:\ /:/ / \:\ \ /:/ / |:|::/ / \:\ \:\__\ \:\ \:\__\ # \:\/:/ / \:\ \ \/__/ |:|\/__/ \:\ \/__/ \:\ \/__/ # \::/ / \:\__\ |:| | \:\__\ \:\__\ # \/__/ \/__/ \|__| \/__/ \/__/ # # # # .----------------.----------------. # /| /| /| # / | / | / | # / | 011 / | 111 / | # / | / | / | # .----------------.----+-----------. | # /| . ---------/|----.----------/|----. # / | /| / | /| / | /| # / | / | 001 / | / | 101 / | / | # / | / | / | / | / | / | # . -------------- .----------------. |/ | # | . ---+------|----.----+------|----. | # | /| .______|___/|____.______|___/|____. # | / | / 010 | / | / 110| / | / # | / | / | / | / | / | / # . ---+---------- . ---+---------- . | / # | |/ | |/ | |/ z # | . ----------|----.-----------|----. ^ y # | / 000 | / 100 | / | / # | / | / | / | / # | / | / | / o----> x # . -------------- . -------------- . # # # Face Refinement: # # 2_______________3 _______________ # | | | | | # ^ | | | (0,1) | (1,1) | # | | | | | | # | | x | ---> |-------+-------| # t1 | | | | | # | | | (0,0) | (1,0) | # |_______________| |_______|_______| # 0 t0--> 1 # # # Face and Edge naming conventions: # # fZp # | # 6 ------eX3------ 7 # /| | / | # /eZ2 . / eZ3 # eY2 | fYp eY3 | # / | / fXp| # 4 ------eX2----- 5 | # |fXm 2 -----eX1--|---- 3 z # eZ0 / | eY1 ^ y # | eY0 . fYm eZ1 / | / # | / | | / | / # 0 ------eX0------1 o----> x # | # fZm # # # fX fY fZ # 2___________3 2___________3 2___________3 # | e1 | | e1 | | e1 | # | | | | | | # e2 | x | e3 z e2 | x | e3 z e2 | x | e3 y # | | ^ | | ^ | | ^ # |___________| |___> y |___________| |___> x |___________| |___> x # 0 e0 1 0 e0 1 0 e0 1 # from SimPEG import np, sp, Utils, Solver try: import TreeUtils _IMPORT_TREEUTILS = True except Exception, e: _IMPORT_TREEUTILS = False from InnerProducts import InnerProducts from TensorMesh import TensorMesh, BaseTensorMesh from MeshIO import TreeMeshIO import time MAX_BITS = 20 class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO): _meshType = 'TREE' def __init__(self, h, x0=None, levels=None): if not _IMPORT_TREEUTILS: raise Exception('Could not import the Cython code to run the TreeMesh Try:.\n\npython setup.py build_ext --inplace') assert type(h) is list, 'h must be a list' assert len(h) in [2,3], "There is only support for TreeMesh in 2D or 3D." BaseTensorMesh.__init__(self, h, x0) if levels is None:levels = int(np.log2(len(self._h[0]))) assert np.all(len(_) == 2**levels for _ in self._h), "must make h and levels match" self._levels = levels self._levelBits = int(np.ceil(np.sqrt(levels)))+1 self.__dirty__ = True #: The numbering is dirty! self._cells = set() self._cells.add(0) @property def __dirty__(self): return (self.__dirtyFaces__ or self.__dirtyEdges__ or self.__dirtyNodes__ or self.__dirtyCells__ or self.__dirtyHanging__ or self.__dirtySets__) @__dirty__.setter def __dirty__(self, val): assert val is True self.__dirtyFaces__ = True self.__dirtyEdges__ = True self.__dirtyNodes__ = True self.__dirtyCells__ = True self.__dirtyHanging__ = True self.__dirtySets__ = True deleteThese = [ '__sortedCells', '_gridCC', '_gridN', '_gridFx', '_gridFy', '_gridFz', '_gridEx', '_gridEy', '_gridEz', '_area', '_edge', '_vol', '_faceDiv', '_edgeCurl', '_nodalGrad', '_aveFx2CC', '_aveFy2CC', '_aveFz2CC', '_aveF2CC', '_aveF2CCV', '_aveEx2CC', '_aveEy2CC', '_aveEz2CC', '_aveE2CC', '_aveE2CCV', '_aveN2CC', ] for p in deleteThese: if hasattr(self, p): delattr(self, p) @property def levels(self): return self._levels @property def fill(self): """How filled is the mesh compared to a TensorMesh? As a fraction: [0,1].""" return float(self.nC)/((2**self.maxLevel)**self.dim) @property def maxLevel(self): """The maximum level used, which may be less than `levels`.""" l = 0 for cell in self._cells: p = self._pointer(cell) l = max(l,p[-1]) return l def __str__(self): outStr = ' ---- %sTreeMesh ---- '%('Oc' if self.dim == 3 else 'Quad') def printH(hx, outStr=''): i = -1 while True: i = i + 1 if i > hx.size: break elif i == hx.size: break h = hx[i] n = 1 for j in range(i+1, hx.size): if hx[j] == h: n = n + 1 i = i + 1 else: break if n == 1: outStr += ' {0:.2f},'.format(h) else: outStr += ' {0:d}*{1:.2f},'.format(n,h) return outStr[:-1] if self.dim == 2: outStr += '\n x0: {0:.2f}'.format(self.x0[0]) outStr += '\n y0: {0:.2f}'.format(self.x0[1]) outStr += printH(self.hx, outStr='\n hx:') outStr += printH(self.hy, outStr='\n hy:') elif self.dim == 3: outStr += '\n x0: {0:.2f}'.format(self.x0[0]) outStr += '\n y0: {0:.2f}'.format(self.x0[1]) outStr += '\n z0: {0:.2f}'.format(self.x0[2]) outStr += printH(self.hx, outStr='\n hx:') outStr += printH(self.hy, outStr='\n hy:') outStr += printH(self.hz, outStr='\n hz:') outStr += '\n nC: {0:d}'.format(self.nC) outStr += '\n Fill: %2.2f%%'%(self.fill*100) return outStr @property def nC(self): return len(self._cells) @property def nN(self): self.number() return len(self._nodes) - len(self._hangingN) @property def nF(self): return self.nFx + self.nFy + (0 if self.dim == 2 else self.nFz) @property def nFx(self): self.number() return len(self._facesX) - len(self._hangingFx) @property def nFy(self): self.number() return len(self._facesY) - len(self._hangingFy) @property def nFz(self): if self.dim == 2: return None self.number() return len(self._facesZ) - len(self._hangingFz) @property def nE(self): return self.nEx + self.nEy + (0 if self.dim == 2 else self.nEz) @property def nEx(self): if self.dim == 2:return self.nFy self.number() return len(self._edgesX) - len(self._hangingEx) @property def nEy(self): if self.dim == 2:return self.nFx self.number() return len(self._edgesY) - len(self._hangingEy) @property def nEz(self): if self.dim == 2: return None self.number() return len(self._edgesZ) - len(self._hangingEz) @property def nhN(self): self.number() return len(self._hangingN) @property def nhF(self): return self.nhFx + self.nhFy + (0 if self.dim == 2 else self.nhFz) @property def nhFx(self): self.number() return len(self._hangingFx) @property def nhFy(self): self.number() return len(self._hangingFy) @property def nhFz(self): if self.dim == 2: return None self.number() return len(self._hangingFz) @property def nhE(self): return self.nhEx + self.nhEy + (0 if self.dim == 2 else self.nhEz) @property def nhEx(self): if self.dim == 2:return self.nhFy self.number() return len(self._hangingEx) @property def nhEy(self): if self.dim == 2:return self.nhFx self.number() return len(self._hangingEy) @property def nhEz(self): if self.dim == 2: return None self.number() return len(self._hangingEz) @property def ntN(self): self.number() return len(self._nodes) @property def ntF(self): return self.ntFx + self.ntFy + (0 if self.dim == 2 else self.ntFz) @property def vntF(self): return [self.ntFx, self.ntFy] + ([] if self.dim == 2 else [self.ntFz]) @property def ntFx(self): self.number() return len(self._facesX) @property def ntFy(self): self.number() return len(self._facesY) @property def ntFz(self): if self.dim == 2: return None self.number() return len(self._facesZ) @property def ntE(self): return self.ntEx + self.ntEy + (0 if self.dim == 2 else self.ntEz) @property def vntE(self): return [self.ntEx, self.ntEy] + ([] if self.dim == 2 else [self.ntEz]) @property def ntEx(self): if self.dim == 2:return self.ntFy self.number() return len(self._edgesX) @property def ntEy(self): if self.dim == 2:return self.ntFx self.number() return len(self._edgesY) @property def ntEz(self): if self.dim == 2: return None self.number() return len(self._edgesZ) @property def _sortedCells(self): if getattr(self, '__sortedCells', None) is None: self.__sortedCells = sorted(self._cells) return self.__sortedCells @property def permuteCC(self): #TODO: cache these? P = SortGrid(self.gridCC) return sp.identity(self.nC).tocsr()[P,:] @property def permuteF(self): #TODO: cache these? P = SortGrid(self.gridFx) P += SortGrid(self.gridFy, offset=self.nFx) if self.dim == 3: P += SortGrid(self.gridFz, offset=self.nFx+self.nFy) return sp.identity(self.nF).tocsr()[P,:] @property def permuteE(self): #TODO: cache these? if self.dim == 2: P = SortGrid(self.gridFy) P += SortGrid(self.gridFx, offset=self.nEx) return sp.identity(self.nE).tocsr()[P,:] if self.dim == 3: P = SortGrid(self.gridEx) P += SortGrid(self.gridEy, offset=self.nEx) P += SortGrid(self.gridEz, offset=self.nEx+self.nEy) return sp.identity(self.nE).tocsr()[P,:] def _index(self, pointer): assert len(pointer) is self.dim+1 assert pointer[-1] <= self.levels return TreeUtils.index(self.dim, MAX_BITS, self._levelBits, pointer[:-1], pointer[-1]) def _pointer(self, index): assert type(index) in [int, long] return TreeUtils.point(self.dim, MAX_BITS, self._levelBits, index) def __contains__(self, v): return self._asIndex(v) in self._cells def refine(self, function=None, recursive=True, cells=None, balance=True, verbose=False, _inRecursion=False): if type(function) in [int, long]: level = function function = lambda cell: level if not _inRecursion: self.__dirty__ = True if verbose: print 'Refining Mesh' cells = cells if cells is not None else sorted(self._cells) recurse = [] tic = time.time() for cell in cells: p = self._pointer(cell) if p[-1] >= self.levels: continue result = function(Cell(self, cell, p)) if type(result) is bool: do = result elif type(result) in [int,long]: do = result > p[-1] else: raise Exception('You must tell the program what to refine. Use BOOL or INT (level)') if do: recurse += self._refineCell(cell, p) if verbose: print ' ', time.time() - tic if recursive and len(recurse) > 0: recurse += self.refine(function=function, recursive=True, cells=recurse, balance=balance, verbose=verbose, _inRecursion=True) if balance and not _inRecursion: self.balance() return recurse def corsen(self, function=None, recursive=True, cells=None, balance=True, verbose=False, _inRecursion=False): if type(function) in [int, long]: level = function function = lambda cell: level if not _inRecursion: self.__dirty__ = True if verbose: print 'Corsening Mesh' cells = cells if cells is not None else sorted(self._cells) recurse = [] tic = time.time() for cell in cells: if cell not in self._cells: continue # already removed p = self._pointer(cell) if p[-1] >= self.levels: continue result = function(Cell(self, cell, p)) if type(result) is bool: do = result elif type(result) in [int,long]: do = result < p[-1] else: raise Exception('You must tell the program what to corsen. Use BOOL or INT (level)') if do: recurse += self._corsenCell(cell, p) if verbose: print ' ', time.time() - tic if recursive and len(recurse) > 0: recurse += self.corsen(function=function, recursive=True, cells=recurse, balance=balance, verbose=verbose, _inRecursion=True) if balance and not _inRecursion: self.balance() return recurse def _refineCell(self, ind, pointer=None): ind = self._asIndex(ind) pointer = self._asPointer(pointer if pointer is not None else ind) if ind not in self: raise CellLookUpException(ind) children = self._childPointers(pointer, returnAll=True) for child in children: self._cells.add(self._asIndex(child)) self._cells.remove(ind) return [self._asIndex(child) for child in children] def _corsenCell(self, ind, pointer=None): ind = self._asIndex(ind) pointer = self._asPointer(pointer if pointer is not None else ind) if ind not in self: raise CellLookUpException(ind) parent = self._parentPointer(pointer) children = self._childPointers(parent, returnAll=True) for child in children: self._cells.remove(self._asIndex(child)) parentInd = self._asIndex(parent) self._cells.add(parentInd) return [parentInd] def _asPointer(self, ind): if type(ind) in [int, long]: return self._pointer(ind) if type(ind) is list: assert len(ind) == (self.dim + 1), str(ind) +' is not valid pointer' assert ind[-1] <= self.levels, str(ind) +' is not valid pointer' return ind if isinstance(ind, np.ndarray): return ind.tolist() raise Exception def _asIndex(self, pointer): if type(pointer) in [int, long]: return pointer if type(pointer) is list: return self._index(pointer) raise Exception def _childPointers(self, pointer, direction=0, positive=True, returnAll=False): l = self._levelWidth(pointer[-1] + 1) if self.dim == 2: children = [ [pointer[0] , pointer[1] , pointer[-1] + 1], [pointer[0] + l, pointer[1] , pointer[-1] + 1], [pointer[0] , pointer[1] + l, pointer[-1] + 1], [pointer[0] + l, pointer[1] + l, pointer[-1] + 1] ] elif self.dim == 3: children = [ [pointer[0] , pointer[1] , pointer[2] , pointer[-1] + 1], [pointer[0] + l, pointer[1] , pointer[2] , pointer[-1] + 1], [pointer[0] , pointer[1] + l, pointer[2] , pointer[-1] + 1], [pointer[0] + l, pointer[1] + l, pointer[2] , pointer[-1] + 1], [pointer[0] , pointer[1] , pointer[2] + l, pointer[-1] + 1], [pointer[0] + l, pointer[1] , pointer[2] + l, pointer[-1] + 1], [pointer[0] , pointer[1] + l, pointer[2] + l, pointer[-1] + 1], [pointer[0] + l, pointer[1] + l, pointer[2] + l, pointer[-1] + 1] ] if direction == 0: ind = [0,2,4,6] if not positive else [1,3,5,7] if direction == 1: ind = [0,1,4,5] if not positive else [2,3,6,7] if direction == 2: ind = [0,1,2,3] if not positive else [4,5,6,7] if returnAll: return children return [children[_] for _ in ind[:(self.dim-1)*2]] def _parentPointer(self, pointer): if pointer[-1] == 0: return None mod = self._levelWidth(pointer[-1] - 1) return [p - (p % mod) for p in pointer[:-1]] + [pointer[-1]-1] def _cellN(self, p): """Node location [x,y(,z)] of a single cell, closest to origin, given a pointer.""" p = self._asPointer(p) return [hi[:p[ii]].sum() for ii, hi in enumerate(self.h)] def _cellH(self, p): """Widths of a single cell given a pointer.""" p = self._asPointer(p) w = self._levelWidth(p[-1]) return [hi[p[ii]:p[ii]+w].sum() for ii, hi in enumerate(self.h)] def _cellC(self, p): """Cell center of a single cell (without origin correction), given a pointer.""" return (np.array(self._cellH(p))/2.0 + self._cellN(p)).tolist() def _levelWidth(self, level): return 2**(self.levels - level) def _isInsideMesh(self, pointer): inside = True for p in pointer[:-1]: inside = inside and p >= 0 and p < 2**self.levels return inside def _getNextCell(self, ind, direction=0, positive=True, _lookUp=True): """ Returns a None, int, list, or nested list The int is the cell number. """ if direction >= self.dim: return None pointer = self._asPointer(ind) if pointer[-1] > self.levels: return None step = (1 if positive else -1) * self._levelWidth(pointer[-1]) nextCell = [p if ii is not direction else p + step for ii, p in enumerate(pointer)] # raise Exception(pointer, nextCell) if not self._isInsideMesh(nextCell): return None # it might be the same size as me? if nextCell in self: return self._index(nextCell) if nextCell[-1] + 1 <= self.levels: # if I am not the smallest. children = self._childPointers(pointer, direction=direction, positive=positive) nextCells = [self._getNextCell(child, direction=direction, positive=positive, _lookUp=False) for child in children] if nextCells[0] is not None: return nextCells if not _lookUp: return None # it might be bigger than me? return self._getNextCell(self._parentPointer(pointer), direction=direction, positive=positive) def balance(self, recursive=True, cells=None, verbose=False, _inRecursion=False): tic = time.time() if not _inRecursion: self.__dirty__ = True if verbose: print 'Balancing Mesh:' cells = cells if cells is not None else sorted(self._cells) # calcDepth = lambda i: lambda A: i if type(A) is not list else max(map(calcDepth(i+1), A)) # flatten = lambda A: A if calcDepth(0)(A) == 1 else flatten([_ for __ in A for _ in (__ if type(__) is list else [__])]) recurse = set() for cell in cells: p = self._asPointer(cell) if p[-1] == self.levels: continue cs = range(6) cs[0] = self._getNextCell(cell, direction=0, positive=False) cs[1] = self._getNextCell(cell, direction=0, positive=True) cs[2] = self._getNextCell(cell, direction=1, positive=False) cs[3] = self._getNextCell(cell, direction=1, positive=True) cs[4] = self._getNextCell(cell, direction=2, positive=False) # this will be None if in 2D cs[5] = self._getNextCell(cell, direction=2, positive=True) # this will be None if in 2D do = np.any([ type(c) is list and np.any([type(_) is list for _ in c]) for c in cs if c is not None ]) # depth = calcDepth(0)(cs) # print depth, depth > 2, do, [jj for jj in flatten(cs) if jj is not None] # recurse += [jj for jj in flatten(cs) if jj is not None] if do and cell in self: newCells = self._refineCell(cell) recurse.update([_ for _ in cs if type(_) in [int, long]]) # only add the bigger ones! recurse.update(newCells) if verbose: print ' ', len(cells), time.time() - tic if recursive and len(recurse) > 0: self.balance(cells=sorted(recurse), _inRecursion=True) @property def gridCC(self): if getattr(self, '_gridCC', None) is None: self._gridCC = np.zeros((len(self._cells),self.dim)) for ii, ind in enumerate(self._sortedCells): p = self._asPointer(ind) self._gridCC[ii, :] = self._cellC(p) + self.x0 return self._gridCC @property def gridN(self): self.number() R = self._deflationMatrix('N', withHanging=False) return R.T * self._gridN + np.repeat([self.x0],self.nN,axis=0) @property def gridFx(self): self.number() R = self._deflationMatrix('Fx', withHanging=False) return R.T * self._gridFx + np.repeat([self.x0],self.nFx,axis=0) @property def gridFy(self): self.number() R = self._deflationMatrix('Fy', withHanging=False) return R.T * self._gridFy + np.repeat([self.x0],self.nFy,axis=0) @property def gridFz(self): if self.dim < 3: return None self.number() R = self._deflationMatrix('Fz', withHanging=False) return R.T * self._gridFz + np.repeat([self.x0],self.nFz,axis=0) @property def gridEx(self): if self.dim == 2: return self.gridFy self.number() R = self._deflationMatrix('Ex', withHanging=False) return R.T * self._gridEx + np.repeat([self.x0],self.nEx,axis=0) @property def gridEy(self): if self.dim == 2: return self.gridFx self.number() R = self._deflationMatrix('Ey', withHanging=False) return R.T * self._gridEy + np.repeat([self.x0],self.nEy,axis=0) @property def gridEz(self): if self.dim < 3: return None self.number() R = self._deflationMatrix('Ez', withHanging=False) return R.T * self._gridEz + np.repeat([self.x0],self.nEz,axis=0) @property def vol(self): if getattr(self, '_vol', None) is None: self._vol = np.zeros(len(self._cells)) for ii, ind in enumerate(self._sortedCells): p = self._asPointer(ind) self._vol[ii] = np.prod(self._cellH(p)) return self._vol @property def area(self): self.number() if getattr(self, '_area', None) is None: Rf = self._deflationMatrix('F', withHanging=False) self._area = Rf.T * ( np.r_[self._areaFxFull, self._areaFyFull] if self.dim == 2 else np.r_[self._areaFxFull, self._areaFyFull, self._areaFzFull] ) return self._area @property def edge(self): self.number() if self.dim == 2: return np.r_[self.area[self.nFx:], self.area[:self.nFx]] if getattr(self, '_edge', None) is None: Re = self._deflationMatrix('E', withHanging=False) self._edge = Re.T * np.r_[self._edgeExFull, self._edgeEyFull, self._edgeEzFull] return self._edge def _createNumberingSets(self, force=False): if not self.__dirtySets__ and not force: return self._nodes = set() self._facesX = set() self._facesY = set() if self.dim == 3: self._facesZ = set() self._edgesX = set() self._edgesY = set() self._edgesZ = set() for ind in self._cells: p = self._asPointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: i00 = ind iw0 = self._index([p[0] + w, p[1] , p[2]]) i0w = self._index([p[0] , p[1] + w, p[2]]) iww = self._index([p[0] + w, p[1] + w, p[2]]) self._nodes.add(i00) self._nodes.add(iw0) self._nodes.add(i0w) self._nodes.add(iww) self._facesX.add(i00) self._facesX.add(iw0) self._facesY.add(i00) self._facesY.add(i0w) elif self.dim == 3: i000 = ind iw00 = self._index([p[0] + w, p[1] , p[2] , p[3]]) i0w0 = self._index([p[0] , p[1] + w, p[2] , p[3]]) i00w = self._index([p[0] , p[1] , p[2] + w, p[3]]) iww0 = self._index([p[0] + w, p[1] + w, p[2] , p[3]]) iw0w = self._index([p[0] + w, p[1] , p[2] + w, p[3]]) i0ww = self._index([p[0] , p[1] + w, p[2] + w, p[3]]) iwww = self._index([p[0] + w, p[1] + w, p[2] + w, p[3]]) self._nodes.add(i000) self._nodes.add(iw00) self._nodes.add(i0w0) self._nodes.add(iww0) self._nodes.add(i00w) self._nodes.add(iw0w) self._nodes.add(i0ww) self._nodes.add(iwww) self._facesX.add(i000) self._facesX.add(iw00) self._facesY.add(i000) self._facesY.add(i0w0) self._facesZ.add(i000) self._facesZ.add(i00w) self._edgesX.add(i000) self._edgesX.add(i0w0) self._edgesX.add(i00w) self._edgesX.add(i0ww) self._edgesY.add(i000) self._edgesY.add(iw00) self._edgesY.add(i00w) self._edgesY.add(iw0w) self._edgesZ.add(i000) self._edgesZ.add(iw00) self._edgesZ.add(i0w0) self._edgesZ.add(iww0) self.__dirtySets__ = False def _numberCells(self, force=False): if not self.__dirtyCells__ and not force: return self._cc2i = dict() self._i2cc = dict() for ii, c in enumerate(sorted(self._cells)): self._cc2i[c] = ii self._i2cc[ii] = c self.__dirtyCells__ = False def _numberNodes(self, force=False): if not self.__dirtyNodes__ and not force: return self._createNumberingSets(force=force) gridN = [] self._n2i = dict() for ii, n in enumerate(sorted(self._nodes)): self._n2i[n] = ii gridN.append( self._cellN( self._pointer(n) ) ) self._gridN = np.array(gridN) self.__dirtyNodes__ = False def _numberFaces(self, force=False): if not self.__dirtyFaces__ and not force: return self._createNumberingSets(force=force) for ind in self._cells: p = self._asPointer(ind) w = self._levelWidth(p[-1]) gridFx = [] areaFx = [] self._fx2i = dict() for ii, fx in enumerate(sorted(self._facesX)): self._fx2i[fx] = ii p = self._pointer(fx) n, h = self._cellN(p), self._cellH(p) if self.dim == 2: gridFx.append( [n[0], n[1] + h[1]/2.0] ) areaFx.append( h[1] ) elif self.dim == 3: gridFx.append( [n[0], n[1] + h[1]/2.0, n[2] + h[2]/2.0] ) areaFx.append( h[1]*h[2] ) self._gridFx = np.array(gridFx) self._areaFxFull = np.array(areaFx) gridFy = [] areaFy = [] self._fy2i = dict() for ii, fy in enumerate(sorted(self._facesY)): self._fy2i[fy] = ii p = self._pointer(fy) n, h = self._cellN(p), self._cellH(p) if self.dim == 2: gridFy.append( [n[0] + h[0]/2.0, n[1]] ) areaFy.append( h[0] ) elif self.dim == 3: gridFy.append( [n[0] + h[0]/2.0, n[1], n[2] + h[2]/2.0] ) areaFy.append( h[0]*h[2] ) self._gridFy = np.array(gridFy) self._areaFyFull = np.array(areaFy) if self.dim == 2: self.__dirtyFaces__ = False return gridFz = [] areaFz = [] self._fz2i = dict() for ii, fz in enumerate(sorted(self._facesZ)): self._fz2i[fz] = ii p = self._pointer(fz) n, h = self._cellN(p), self._cellH(p) gridFz.append( [n[0] + h[0]/2.0, n[1] + h[1]/2.0, n[2]] ) areaFz.append(h[0]*h[1]) self._gridFz = np.array(gridFz) self._areaFzFull = np.array(areaFz) self.__dirtyFaces__ = False def _numberEdges(self, force=False): if self.dim == 2: self.__dirtyEdges__ = False return if not self.__dirtyEdges__ and not force: return self._createNumberingSets(force=force) gridEx = [] edgeEx = [] self._ex2i = dict() for ii, ex in enumerate(sorted(self._edgesX)): self._ex2i[ex] = ii p = self._pointer(ex) n, h = self._cellN(p), self._cellH(p) gridEx.append( [n[0] + h[0]/2.0, n[1], n[2]] ) edgeEx.append( h[0] ) self._gridEx = np.array(gridEx) self._edgeExFull = np.array(edgeEx) gridEy = [] edgeEy = [] self._ey2i = dict() for ii, ey in enumerate(sorted(self._edgesY)): self._ey2i[ey] = ii p = self._pointer(ey) n, h = self._cellN(p), self._cellH(p) gridEy.append( [n[0], n[1] + h[1]/2.0, n[2]] ) edgeEy.append( h[1] ) self._gridEy = np.array(gridEy) self._edgeEyFull = np.array(edgeEy) gridEz = [] edgeEz = [] self._ez2i = dict() for ii, ez in enumerate(sorted(self._edgesZ)): self._ez2i[ez] = ii p = self._pointer(ez) n, h = self._cellN(p), self._cellH(p) gridEz.append( [n[0], n[1], n[2] + h[2]/2.0] ) edgeEz.append( h[2] ) self._gridEz = np.array(gridEz) self._edgeEzFull = np.array(edgeEz) self.__dirtyEdges__ = False def _hanging(self, force=False): if not self.__dirtyHanging__ and not force: return self._numberCells(force=force) self._numberNodes(force=force) self._numberFaces(force=force) self._numberEdges(force=force) self._hangingN = dict() self._hangingFx = dict() self._hangingFy = dict() if self.dim == 3: self._hangingFz = dict() self._hangingEx = dict() self._hangingEy = dict() self._hangingEz = dict() # Compute from x faces for fx in self._facesX: p = self._pointer(fx) if p[-1] + 1 > self.levels: continue sl = p[-1] + 1 #: small level test = self._index(p[:-1] + [sl]) if test not in self._facesX: # Return early without checking the other faces continue w = self._levelWidth(sl) if self.dim == 2: chy0 = self._cellH([p[0] , p[1] , sl])[1] chy1 = self._cellH([p[0] , p[1] + w, sl])[1] A = (chy0 + chy1) self._hangingFx[self._fx2i[test ]] = ([self._fx2i[fx], chy0 / A], ) self._hangingFx[self._fx2i[self._index([p[0] , p[1] + w, sl])]] = ([self._fx2i[fx], chy1 / A], ) n0, n1 = fx, self._index([p[0], p[1] + 2*w, p[-1]]) self._hangingN[self._n2i[test ]] = ([self._n2i[n0], 1.0], ) self._hangingN[self._n2i[self._index([p[0] , p[1] + w, sl])]] = ([self._n2i[n0], 1.0 - chy0 / A], [self._n2i[n1], 1.0 - chy1 / A]) self._hangingN[self._n2i[self._index([p[0] , p[1] + 2*w, sl])]] = ([self._n2i[n1], 1.0], ) elif self.dim == 3: chy0 = self._cellH([p[0] , p[1] , p[2] , sl])[1] chy1 = self._cellH([p[0] , p[1] + w, p[2] , sl])[1] chz0 = self._cellH([p[0] , p[1] , p[2] , sl])[2] chz1 = self._cellH([p[0] , p[1] , p[2] + w, sl])[2] lenY = chy0 + chy1 lenZ = chz0 + chz1 A = lenY * lenZ ey0 = fx ey1 = self._index([p[0], p[1] , p[2] + 2*w, p[-1]]) ez0 = fx ez1 = self._index([p[0], p[1] + 2*w, p[2] , p[-1]]) n0 = fx n1 = self._index([p[0], p[1] + 2*w, p[2] , p[-1]]) n2 = self._index([p[0], p[1] , p[2] + 2*w, p[-1]]) n3 = self._index([p[0], p[1] + 2*w, p[2] + 2*w, p[-1]]) i000 = test i010 = self._index([p[0], p[1] + w, p[2] , sl]) i001 = self._index([p[0], p[1] , p[2] + w, sl]) i011 = self._index([p[0], p[1] + w, p[2] + w, sl]) i020 = self._index([p[0], p[1] + 2*w, p[2] , sl]) i021 = self._index([p[0], p[1] + 2*w, p[2] + w, sl]) i002 = self._index([p[0], p[1] , p[2] + 2*w, sl]) i012 = self._index([p[0], p[1] + w, p[2] + 2*w, sl]) i022 = self._index([p[0], p[1] + 2*w, p[2] + 2*w, sl]) self._hangingFx[self._fx2i[i000]] = ([self._fx2i[fx], chy0*chz0 / A ], ) self._hangingFx[self._fx2i[i010]] = ([self._fx2i[fx], chy1*chz0 / A ], ) self._hangingFx[self._fx2i[i001]] = ([self._fx2i[fx], chy0*chz1 / A ], ) self._hangingFx[self._fx2i[i011]] = ([self._fx2i[fx], chy1*chz1 / A ], ) self._hangingEy[self._ey2i[i000]] = ([self._ey2i[ey0], 1.0], ) self._hangingEy[self._ey2i[i010]] = ([self._ey2i[ey0], 1.0], ) self._hangingEy[self._ey2i[i001]] = ([self._ey2i[ey0], 0.5], [self._ey2i[ey1], 0.5]) self._hangingEy[self._ey2i[i011]] = ([self._ey2i[ey0], 0.5], [self._ey2i[ey1], 0.5]) self._hangingEy[self._ey2i[i002]] = ([self._ey2i[ey1], 1.0], ) self._hangingEy[self._ey2i[i012]] = ([self._ey2i[ey1], 1.0], ) self._hangingEz[self._ez2i[i000]] = ([self._ez2i[ez0], 1.0], ) self._hangingEz[self._ez2i[i001]] = ([self._ez2i[ez0], 1.0], ) self._hangingEz[self._ez2i[i010]] = ([self._ez2i[ez0], 0.5], [self._ez2i[ez1], 0.5]) self._hangingEz[self._ez2i[i011]] = ([self._ez2i[ez0], 0.5], [self._ez2i[ez1], 0.5]) self._hangingEz[self._ez2i[i020]] = ([self._ez2i[ez1], 1.0], ) self._hangingEz[self._ez2i[i021]] = ([self._ez2i[ez1], 1.0], ) # self._hangingEy[self._ey2i[i000]] = ([self._ey2i[ey0], chy0 / lenY], ) # self._hangingEy[self._ey2i[i010]] = ([self._ey2i[ey0], chy1 / lenY], ) # self._hangingEy[self._ey2i[i001]] = ([self._ey2i[ey0], chy0 / lenY / 2.0], [self._ey2i[ey1], chy0 / lenY / 2.0]) # self._hangingEy[self._ey2i[i011]] = ([self._ey2i[ey0], chy1 / lenY / 2.0], [self._ey2i[ey1], chy1 / lenY / 2.0]) # self._hangingEy[self._ey2i[i002]] = ([self._ey2i[ey1], chy0 / lenY], ) # self._hangingEy[self._ey2i[i012]] = ([self._ey2i[ey1], chy1 / lenY], ) # self._hangingEz[self._ez2i[i000]] = ([self._ez2i[ez0], chz0 / lenZ], ) # self._hangingEz[self._ez2i[i001]] = ([self._ez2i[ez0], chz1 / lenZ], ) # self._hangingEz[self._ez2i[i010]] = ([self._ez2i[ez0], chz0 / lenZ / 2.0], [self._ez2i[ez1], chz0 / lenZ / 2.0]) # self._hangingEz[self._ez2i[i011]] = ([self._ez2i[ez0], chz1 / lenZ / 2.0], [self._ez2i[ez1], chz1 / lenZ / 2.0]) # self._hangingEz[self._ez2i[i020]] = ([self._ez2i[ez1], chz0 / lenZ], ) # self._hangingEz[self._ez2i[i021]] = ([self._ez2i[ez1], chz1 / lenZ], ) self._hangingN[ self._n2i[ i000]] = ([self._n2i[n0], 1.0], ) self._hangingN[ self._n2i[ i010]] = ([self._n2i[n0], 0.5], [self._n2i[n1], 0.5]) self._hangingN[ self._n2i[ i020]] = ([self._n2i[n1], 1.0], ) self._hangingN[ self._n2i[ i001]] = ([self._n2i[n0], 0.5], [self._n2i[n2], 0.5]) self._hangingN[ self._n2i[ i011]] = ([self._n2i[n0], 0.25], [self._n2i[n1], 0.25], [self._n2i[n2], 0.25], [self._n2i[n3], 0.25]) self._hangingN[ self._n2i[ i021]] = ([self._n2i[n1], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i002]] = ([self._n2i[n2], 1.0], ) self._hangingN[ self._n2i[ i012]] = ([self._n2i[n2], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i022]] = ([self._n2i[n3], 1.0], ) # Compute from y faces for fy in self._facesY: p = self._pointer(fy) if p[-1] + 1 > self.levels: continue sl = p[-1] + 1 #: small level test = self._index(p[:-1] + [sl]) if test not in self._facesY: # Return early without checking the other faces continue w = self._levelWidth(sl) if self.dim == 2: chx0 = self._cellH([p[0] , p[1] , sl])[0] chx1 = self._cellH([p[0] + w, p[1] , sl])[0] self._hangingFy[self._fy2i[test ]] = ([self._fy2i[fy], chx0 / (chx0 + chx1)], ) self._hangingFy[self._fy2i[self._index([p[0] + w, p[1] , sl])]] = ([self._fy2i[fy], chx1 / (chx0 + chx1)], ) n0, n1 = fy, self._index([p[0] + 2*w, p[1], p[-1]]) self._hangingN[self._n2i[test ]] = ([self._n2i[n0], 1.0], ) self._hangingN[self._n2i[self._index([p[0] + w, p[1] , sl])]] = ([self._n2i[n0], 0.5], [self._n2i[n1], 0.5]) self._hangingN[self._n2i[self._index([p[0] + 2*w, p[1] , sl])]] = ([self._n2i[n1], 1.0], ) elif self.dim == 3: chx0 = self._cellH([p[0] , p[1] , p[2] , sl])[0] chx1 = self._cellH([p[0] + w, p[1] , p[2] , sl])[0] chz0 = self._cellH([p[0] , p[1] , p[2] , sl])[2] chz1 = self._cellH([p[0] , p[1] , p[2] + w, sl])[2] lenX = chx0 + chx1 lenZ = chz0 + chz1 A = lenX * lenZ ex0 = fy ex1 = self._index([p[0] , p[1], p[2] + 2*w, p[-1]]) ez0 = fy ez1 = self._index([p[0] + 2*w, p[1], p[2] , p[-1]]) n0 = fy n1 = self._index([p[0] + 2*w, p[1], p[2] , p[-1]]) n2 = self._index([p[0] , p[1], p[2] + 2*w, p[-1]]) n3 = self._index([p[0] + 2*w, p[1], p[2] + 2*w, p[-1]]) i000 = test i100 = self._index([p[0] + w, p[1], p[2] , sl]) i001 = self._index([p[0] , p[1], p[2] + w, sl]) i101 = self._index([p[0] + w, p[1], p[2] + w, sl]) i200 = self._index([p[0] + 2*w, p[1], p[2] , sl]) i201 = self._index([p[0] + 2*w, p[1], p[2] + w, sl]) i002 = self._index([p[0] , p[1], p[2] + 2*w, sl]) i102 = self._index([p[0] + w, p[1], p[2] + 2*w, sl]) i202 = self._index([p[0] + 2*w, p[1], p[2] + 2*w, sl]) self._hangingFy[self._fy2i[i000]] = ([self._fy2i[fy], chx0*chz0 / A ], ) self._hangingFy[self._fy2i[i100]] = ([self._fy2i[fy], chx1*chz0 / A ], ) self._hangingFy[self._fy2i[i001]] = ([self._fy2i[fy], chx0*chz1 / A ], ) self._hangingFy[self._fy2i[i101]] = ([self._fy2i[fy], chx1*chz1 / A ], ) self._hangingEx[self._ex2i[i000]] = ([self._ex2i[ex0], 1.0], ) self._hangingEx[self._ex2i[i100]] = ([self._ex2i[ex0], 1.0], ) self._hangingEx[self._ex2i[i001]] = ([self._ex2i[ex0], 0.5], [self._ex2i[ex1], 0.5]) self._hangingEx[self._ex2i[i101]] = ([self._ex2i[ex0], 0.5], [self._ex2i[ex1], 0.5]) self._hangingEx[self._ex2i[i002]] = ([self._ex2i[ex1], 1.0], ) self._hangingEx[self._ex2i[i102]] = ([self._ex2i[ex1], 1.0], ) self._hangingEz[self._ez2i[i000]] = ([self._ez2i[ez0], 1.0], ) self._hangingEz[self._ez2i[i001]] = ([self._ez2i[ez0], 1.0], ) self._hangingEz[self._ez2i[i100]] = ([self._ez2i[ez0], 0.5], [self._ez2i[ez1], 0.5]) self._hangingEz[self._ez2i[i101]] = ([self._ez2i[ez0], 0.5], [self._ez2i[ez1], 0.5]) self._hangingEz[self._ez2i[i200]] = ([self._ez2i[ez1], 1.0], ) self._hangingEz[self._ez2i[i201]] = ([self._ez2i[ez1], 1.0], ) # self._hangingEx[self._ex2i[i000]] = ([self._ex2i[ex0], chx0 / lenX], ) # self._hangingEx[self._ex2i[i100]] = ([self._ex2i[ex0], chx1 / lenX], ) # self._hangingEx[self._ex2i[i001]] = ([self._ex2i[ex0], chx0 / lenX / 2.0], [self._ex2i[ex1], chx0 / lenX / 2.0]) # self._hangingEx[self._ex2i[i101]] = ([self._ex2i[ex0], chx1 / lenX / 2.0], [self._ex2i[ex1], chx1 / lenX / 2.0]) # self._hangingEx[self._ex2i[i002]] = ([self._ex2i[ex1], chx0 / lenX], ) # self._hangingEx[self._ex2i[i102]] = ([self._ex2i[ex1], chx1 / lenX], ) # self._hangingEz[self._ez2i[i000]] = ([self._ez2i[ez0], chz0 / lenZ], ) # self._hangingEz[self._ez2i[i001]] = ([self._ez2i[ez0], chz1 / lenZ], ) # self._hangingEz[self._ez2i[i100]] = ([self._ez2i[ez0], chz0 / lenZ / 2.0], [self._ez2i[ez1], chz0 / lenZ / 2.0]) # self._hangingEz[self._ez2i[i101]] = ([self._ez2i[ez0], chz1 / lenZ / 2.0], [self._ez2i[ez1], chz1 / lenZ / 2.0]) # self._hangingEz[self._ez2i[i200]] = ([self._ez2i[ez1], chz0 / lenZ], ) # self._hangingEz[self._ez2i[i201]] = ([self._ez2i[ez1], chz1 / lenZ], ) self._hangingN[ self._n2i[ i000]] = ([self._n2i[n0], 1.0], ) self._hangingN[ self._n2i[ i100]] = ([self._n2i[n0], 0.5], [self._n2i[n1], 0.5]) self._hangingN[ self._n2i[ i200]] = ([self._n2i[n1], 1.0], ) self._hangingN[ self._n2i[ i001]] = ([self._n2i[n0], 0.5], [self._n2i[n2], 0.5]) self._hangingN[ self._n2i[ i101]] = ([self._n2i[n0], 0.25], [self._n2i[n1], 0.25], [self._n2i[n2], 0.25], [self._n2i[n3], 0.25]) self._hangingN[ self._n2i[ i201]] = ([self._n2i[n1], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i002]] = ([self._n2i[n2], 1.0], ) self._hangingN[ self._n2i[ i102]] = ([self._n2i[n2], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i202]] = ([self._n2i[n3], 1.0], ) if self.dim == 2: self.__dirtyHanging__ = False return # Compute from z faces for fz in self._facesZ: p = self._pointer(fz) if p[-1] + 1 > self.levels: continue sl = p[-1] + 1 #: small level test = self._index(p[:-1] + [sl]) if test not in self._facesZ: # Return early without checking the other faces continue w = self._levelWidth(sl) chx0 = self._cellH([p[0] , p[1] , p[2] , sl])[0] chx1 = self._cellH([p[0] + w, p[1] , p[2] , sl])[0] chy0 = self._cellH([p[0] , p[1] , p[2] , sl])[1] chy1 = self._cellH([p[0] , p[1] + w, p[2] , sl])[1] lenX = chx0 + chx1 lenY = chy0 + chy1 A = lenX * lenY ex0 = fz ex1 = self._index([p[0] , p[1] + 2*w, p[2], p[-1]]) ey0 = fz ey1 = self._index([p[0] + 2*w, p[1] , p[2], p[-1]]) n0 = fz n1 = self._index([p[0] + 2*w, p[1] , p[2], p[-1]]) n2 = self._index([p[0] , p[1] + 2*w, p[2], p[-1]]) n3 = self._index([p[0] + 2*w, p[1] + 2*w, p[2], p[-1]]) i000 = test i100 = self._index([p[0] + w, p[1] , p[2], sl]) i010 = self._index([p[0] , p[1] + w, p[2], sl]) i110 = self._index([p[0] + w, p[1] + w, p[2], sl]) i200 = self._index([p[0] + 2*w, p[1] , p[2], sl]) i210 = self._index([p[0] + 2*w, p[1] + w, p[2], sl]) i020 = self._index([p[0] , p[1] + 2*w, p[2], sl]) i120 = self._index([p[0] + w, p[1] + 2*w, p[2], sl]) i220 = self._index([p[0] + 2*w, p[1] + 2*w, p[2], sl]) self._hangingFz[self._fz2i[i000]] = ([self._fz2i[fz], chx0*chy0 / A ], ) self._hangingFz[self._fz2i[i100]] = ([self._fz2i[fz], chx1*chy0 / A ], ) self._hangingFz[self._fz2i[i010]] = ([self._fz2i[fz], chx0*chy1 / A ], ) self._hangingFz[self._fz2i[i110]] = ([self._fz2i[fz], chx1*chy1 / A ], ) self._hangingEx[self._ex2i[i000]] = ([self._ex2i[ex0], 1.0], ) self._hangingEx[self._ex2i[i100]] = ([self._ex2i[ex0], 1.0], ) self._hangingEx[self._ex2i[i010]] = ([self._ex2i[ex0], 0.5], [self._ex2i[ex1], 0.5]) self._hangingEx[self._ex2i[i110]] = ([self._ex2i[ex0], 0.5], [self._ex2i[ex1], 0.5]) self._hangingEx[self._ex2i[i020]] = ([self._ex2i[ex1], 1.0], ) self._hangingEx[self._ex2i[i120]] = ([self._ex2i[ex1], 1.0], ) self._hangingEy[self._ey2i[i000]] = ([self._ey2i[ey0], 1.0], ) self._hangingEy[self._ey2i[i010]] = ([self._ey2i[ey0], 1.0], ) self._hangingEy[self._ey2i[i100]] = ([self._ey2i[ey0], 0.5], [self._ey2i[ey1], 0.5]) self._hangingEy[self._ey2i[i110]] = ([self._ey2i[ey0], 0.5], [self._ey2i[ey1], 0.5]) self._hangingEy[self._ey2i[i200]] = ([self._ey2i[ey1], 1.0], ) self._hangingEy[self._ey2i[i210]] = ([self._ey2i[ey1], 1.0], ) # self._hangingEx[self._ex2i[i000]] = ([self._ex2i[ex0], chx0 / lenX], ) # self._hangingEx[self._ex2i[i100]] = ([self._ex2i[ex0], chx1 / lenX], ) # self._hangingEx[self._ex2i[i010]] = ([self._ex2i[ex0], chx0 / lenX / 2.0], [self._ex2i[ex1], chx0 / lenX / 2.0]) # self._hangingEx[self._ex2i[i110]] = ([self._ex2i[ex0], chx1 / lenX / 2.0], [self._ex2i[ex1], chx1 / lenX / 2.0]) # self._hangingEx[self._ex2i[i020]] = ([self._ex2i[ex1], chx0 / lenX], ) # self._hangingEx[self._ex2i[i120]] = ([self._ex2i[ex1], chx1 / lenX], ) # self._hangingEy[self._ey2i[i000]] = ([self._ey2i[ey0], chy0 / lenY], ) # self._hangingEy[self._ey2i[i010]] = ([self._ey2i[ey0], chy1 / lenY], ) # self._hangingEy[self._ey2i[i100]] = ([self._ey2i[ey0], chy0 / lenY / 2.0], [self._ey2i[ey1], chy0 / lenY / 2.0]) # self._hangingEy[self._ey2i[i110]] = ([self._ey2i[ey0], chy1 / lenY / 2.0], [self._ey2i[ey1], chy1 / lenY / 2.0]) # self._hangingEy[self._ey2i[i200]] = ([self._ey2i[ey1], chy0 / lenY], ) # self._hangingEy[self._ey2i[i210]] = ([self._ey2i[ey1], chy1 / lenY], ) self._hangingN[ self._n2i[ i000]] = ([self._n2i[n0], 1.0], ) self._hangingN[ self._n2i[ i100]] = ([self._n2i[n0], 0.5], [self._n2i[n1], 0.5]) self._hangingN[ self._n2i[ i200]] = ([self._n2i[n1], 1.0], ) self._hangingN[ self._n2i[ i010]] = ([self._n2i[n0], 0.5], [self._n2i[n2], 0.5]) self._hangingN[ self._n2i[ i110]] = ([self._n2i[n0], 0.25], [self._n2i[n1], 0.25], [self._n2i[n2], 0.25], [self._n2i[n3], 0.25]) self._hangingN[ self._n2i[ i210]] = ([self._n2i[n1], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i020]] = ([self._n2i[n2], 1.0], ) self._hangingN[ self._n2i[ i120]] = ([self._n2i[n2], 0.5], [self._n2i[n3], 0.5]) self._hangingN[ self._n2i[ i220]] = ([self._n2i[n3], 1.0], ) self.__dirtyHanging__ = False def number(self, balance=True, force=False): if not self.__dirty__ and not force: return if balance: self.balance() self._hanging(force=force) def _deflationMatrix(self, location, withHanging=True, asOnes=False): assert location in ['N','F','Fx','Fy','E','Ex','Ey'] + (['Fz','Ez'] if self.dim == 3 else []) args = dict() args['N'] = (self._nodes, self._hangingN, self._n2i ) args['Fx'] = (self._facesX, self._hangingFx, self._fx2i) args['Fy'] = (self._facesY, self._hangingFy, self._fy2i) if self.dim == 3: args['Fz'] = (self._facesZ, self._hangingFz, self._fz2i) args['Ex'] = (self._edgesX, self._hangingEx, self._ex2i) args['Ey'] = (self._edgesY, self._hangingEy, self._ey2i) args['Ez'] = (self._edgesZ, self._hangingEz, self._ez2i) elif self.dim == 2: args['Ex'] = (self._facesY, self._hangingFy, self._fy2i) args['Ey'] = (self._facesX, self._hangingFx, self._fx2i) if location in ['F', 'E']: Rlist = [self._deflationMatrix(location + subLoc, withHanging=withHanging, asOnes=asOnes) for subLoc in ['x','y','z'][:self.dim]] return sp.block_diag(Rlist) return self.__deflationMatrix(*args[location], withHanging=withHanging, asOnes=asOnes) def __deflationMatrix(self, theSet, theHang, theIndex, withHanging=True, asOnes=False): reducedInd = dict() # final reduced index ii = 0 I,J,V = [],[],[] for fx in sorted(theSet): if theIndex[fx] not in theHang: reducedInd[theIndex[fx]] = ii I += [theIndex[fx]] J += [ii] V += [1.0] ii += 1 if withHanging: for hfkey in theHang.keys(): hf = theHang[hfkey] I += [hfkey]*len(hf) J += [reducedInd[_[0]] for _ in hf] if asOnes: V += [1.0]*len(hf) else: V += [_[1] for _ in hf] return sp.csr_matrix((V,(I,J)), shape=(len(theSet), len(reducedInd))) @property def faceDiv(self): if getattr(self, '_faceDiv', None) is None: self.number() # TODO: Preallocate! I, J, V = [], [], [] PM = [-1,1]*self.dim # plus / minus # TODO total number of faces? offset = [0]*2 + [self.ntFx]*2 + [self.ntFx+self.ntFy]*2 for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: faces = [ self._fx2i[self._index([ p[0] , p[1] , p[2]])], self._fx2i[self._index([ p[0] + w, p[1] , p[2]])], self._fy2i[self._index([ p[0] , p[1] , p[2]])], self._fy2i[self._index([ p[0] , p[1] + w, p[2]])] ] elif self.dim == 3: faces = [ self._fx2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fx2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], self._fy2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fy2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], self._fz2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fz2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])] ] for off, pm, face in zip(offset,PM,faces): I += [ii] J += [face + off] V += [pm] D = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntF)) R = self._deflationMatrix('F',asOnes=True) VOL = self.vol if self.dim == 2: S = np.r_[self._areaFxFull, self._areaFyFull] elif self.dim == 3: S = np.r_[self._areaFxFull, self._areaFyFull, self._areaFzFull] self._faceDiv = Utils.sdiag(1.0/VOL)*D*Utils.sdiag(S)*R return self._faceDiv @property def edgeCurl(self): """Construct the 3D curl operator.""" assert self.dim > 2, "Edge Curl only programed for 3D." if getattr(self, '_edgeCurl', None) is None: self.number() # TODO: Preallocate! I, J, V = [], [], [] faceOffset = 0 offset = [self.ntEx]*2 + [self.ntEx+self.ntEy]*2 PM = [1, -1, -1, 1] for ii, fx in enumerate(sorted(self._facesX)): p = self._pointer(fx) w = self._levelWidth(p[-1]) edges = [ self._ey2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ey2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])], self._ez2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ez2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], ] for off, pm, edge in zip(offset,PM,edges): I += [ii + faceOffset] J += [edge + off] V += [pm] faceOffset = self.ntFx offset = [0]*2 + [self.ntEx+self.ntEy]*2 PM = [-1, 1, 1, -1] for ii, fy in enumerate(sorted(self._facesY)): p = self._pointer(fy) w = self._levelWidth(p[-1]) edges = [ self._ex2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ex2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])], self._ez2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ez2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], ] for off, pm, edge in zip(offset,PM,edges): I += [ii + faceOffset] J += [edge + off] V += [pm] faceOffset = self.ntFx + self.ntFy offset = [0]*2 + [self.ntEx]*2 PM = [1, -1, -1, 1] for ii, fz in enumerate(sorted(self._facesZ)): p = self._pointer(fz) w = self._levelWidth(p[-1]) edges = [ self._ex2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ex2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], self._ey2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ey2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], ] for off, pm, edge in zip(offset,PM,edges): I += [ii + faceOffset] J += [edge + off] V += [pm] Rf = self._deflationMatrix('F', withHanging=True, asOnes=False) Re = self._deflationMatrix('E') Rf_ave = Utils.sdiag(1./Rf.sum(axis=0)) * Rf.T C = sp.csr_matrix((V,(I,J)), shape=(self.ntF, self.ntE)) S = np.r_[self._areaFxFull, self._areaFyFull, self._areaFzFull] L = np.r_[self._edgeExFull, self._edgeEyFull, self._edgeEzFull] self._edgeCurl = Rf_ave*Utils.sdiag(1.0/S)*C*Utils.sdiag(L)*Re return self._edgeCurl @property def nodalGrad(self): if getattr(self, '_nodalGrad', None) is None: self.number() # TODO: Preallocate! I, J, V = [], [], [] # kinda a hack for the 2D gradient # because edges are not stored edgesX = self._facesY if self.dim == 2 else self._edgesX offset = 0 for ex in edgesX: p = self._pointer(ex) w = self._levelWidth(p[-1]) if self.dim == 2: I += [self._fy2i[ex] + offset]*2 nodePlus = self._index([ p[0] + w, p[1], p[2]]) elif self.dim == 3: I += [self._ex2i[ex] + offset]*2 nodePlus = self._index([ p[0] + w, p[1], p[2], p[3]]) J += [self._n2i[ex], self._n2i[nodePlus]] V += [-1, 1] edgesY = self._facesX if self.dim == 2 else self._edgesY offset = self.ntFy if self.dim == 2 else self.ntEx for ey in edgesY: p = self._pointer(ey) w = self._levelWidth(p[-1]) if self.dim == 2: I += [self._fx2i[ey] + offset]*2 nodePlus = self._index([ p[0], p[1] + w, p[2]]) elif self.dim == 3: I += [self._ey2i[ey] + offset]*2 nodePlus = self._index([ p[0], p[1] + w, p[2], p[3]]) J += [self._n2i[ey], self._n2i[nodePlus]] V += [-1, 1] if self.dim == 3: edgesZ = self._edgesZ offset = self.ntEx + self.ntEy for ez in edgesZ: p = self._pointer(ez) w = self._levelWidth(p[-1]) I += [self._ez2i[ez] + offset]*2 nodePlus = self._index([ p[0], p[1], p[2] + w, p[3]]) J += [self._n2i[ez], self._n2i[nodePlus]] V += [-1, 1] G = sp.csr_matrix((V,(I,J)), shape=(self.ntE, self.ntN)) if self.dim == 2: L = np.r_[self._areaFyFull, self._areaFxFull] elif self.dim == 3: L = np.r_[self._edgeExFull, self._edgeEyFull, self._edgeEzFull] Rn = self._deflationMatrix('N') Re = self._deflationMatrix('E', withHanging=True, asOnes=False) Re_ave = Utils.sdiag(1./Re.sum(axis=0)) * Re.T self._nodalGrad = Re_ave*Utils.sdiag(1/L)*G*Rn return self._nodalGrad @property def aveEx2CC(self): if getattr(self, '_aveEx2CC', None) is None: I, J, V = [], [], [] if self.dim == 2: raise Exception('aveEx2CC not implemented in 2D') if self.dim == 3: PM = [1./4.]*4 for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) edgesx = [ self._ex2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ex2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], self._ex2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])], self._ex2i[self._index([ p[0] , p[1] + w, p[2] + w, p[3]])], ] for pm, edge in zip(PM,edgesx): I += [ii] J += [edge] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntEx)) Re = self._deflationMatrix('Ex',asOnes=False,withHanging=True) self._aveEx2CC = Av*Re return self._aveEx2CC @property def aveEy2CC(self): "Construct the averaging operator on cell edges to cell centers." if getattr(self, '_aveEy2CC', None) is None: I, J, V = [], [], [] if self.dim == 2: raise NotImplementedError('aveEy2CC not implemented in 2D') if self.dim == 3: PM = [1./4.]*4 # plus / plus for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) edgesy = [ self._ey2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ey2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], self._ey2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])], self._ey2i[self._index([ p[0] + w, p[1] , p[2] + w, p[3]])], ] for pm, edge in zip(PM,edgesy): I += [ii] J += [edge] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntEy)) Re = self._deflationMatrix('Ey',asOnes=False,withHanging=True) self._aveEy2CC = Av*Re return self._aveEy2CC @property def aveEz2CC(self): "Construct the averaging operator on cell edges to cell centers." # raise Exception('Not yet implemented!') if getattr(self, '_aveEz2CC', None) is None: I, J, V = [], [], [] if self.dim == 2: raise Exception('There are no z edges in 2D') if self.dim == 3: PM = [1./4.]*4 # plus / plus for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) edgesz = [ self._ez2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._ez2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], self._ez2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], self._ez2i[self._index([ p[0] + w, p[1] + w, p[2] , p[3]])], ] for pm, edge in zip(PM,edgesz): I += [ii] J += [edge] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntEz)) Re = self._deflationMatrix('Ez',asOnes=False,withHanging=True) self._aveEz2CC = Av*Re return self._aveEz2CC @property def aveE2CC(self): "Construct the averaging operator on cell edges to cell centers." if getattr(self, '_aveE2CC', None) is None: if self.dim == 2: raise Exception('aveE2CC not implemented in 2D') elif self.dim == 3: self._aveE2CC = 1./self.dim*sp.hstack([self.aveEx2CC, self.aveEy2CC, self.aveEz2CC]) return self._aveE2CC @property def aveE2CCV(self): "Construct the averaging operator on cell edges to cell centers." # raise Exception('Not yet implemented!') if getattr(self, '_aveE2CCV', None) is None: if self.dim == 2: raise Exception('aveE2CC not implemented in 2D') elif self.dim == 3: self._aveE2CCV = sp.block_diag([self.aveEx2CC, self.aveEy2CC, self.aveEz2CC]) return self._aveE2CCV @property def aveFx2CC(self): if getattr(self, '_aveFx2CC', None) is None: I, J, V = [], [], [] PM = [1./2.]*self.dim # 0.5, 0.5 for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: facesx = [ self._fx2i[self._index([ p[0] , p[1] , p[2]])], self._fx2i[self._index([ p[0] + w, p[1] , p[2]])], ] elif self.dim == 3: facesx = [ self._fx2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fx2i[self._index([ p[0] + w, p[1] , p[2] , p[3]])], ] for pm, face in zip(PM,facesx): I += [ii] J += [face] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntFx)) Rf = self._deflationMatrix('Fx',asOnes=True,withHanging=True) self._aveFx2CC = Av*Rf return self._aveFx2CC @property def aveFy2CC(self): if getattr(self, '_aveFy2CC', None) is None: I, J, V = [], [], [] PM = [1./2.]*2 # 0.5, 0.5 for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: facesy = [ self._fy2i[self._index([ p[0] , p[1] , p[2]])], self._fy2i[self._index([ p[0] , p[1] + w, p[2]])], ] elif self.dim == 3: facesy = [ self._fy2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fy2i[self._index([ p[0] , p[1] + w, p[2] , p[3]])], ] for pm, face in zip(PM,facesy): I += [ii] J += [face] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntFy)) Rf = self._deflationMatrix('Fy',asOnes=True,withHanging=True) self._aveFy2CC = Av*Rf return self._aveFy2CC @property def aveFz2CC(self): if getattr(self, '_aveFz2CC', None) is None: I, J, V = [], [], [] PM = [1./2.]*2 # 0.5, 0.5 for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: raise Exception('There are no z-faces in 2D') elif self.dim == 3: facesz = [ self._fz2i[self._index([ p[0] , p[1] , p[2] , p[3]])], self._fz2i[self._index([ p[0] , p[1] , p[2] + w, p[3]])], ] for pm, face in zip(PM,facesz): I += [ii] J += [face] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntFz)) Rf = self._deflationMatrix('Fz',asOnes=True,withHanging=True) self._aveFz2CC = Av*Rf return self._aveFz2CC @property def aveF2CC(self): "Construct the averaging operator on cell faces to cell centers." if getattr(self, '_aveF2CC', None) is None: if self.dim == 2: self._aveF2CC = 1./self.dim*sp.hstack([self.aveFx2CC, self.aveFy2CC]).tocsr() elif self.dim == 3: self._aveF2CC = 1./self.dim*sp.hstack([self.aveFx2CC, self.aveFy2CC, self.aveFz2CC]).tocsr() return self._aveF2CC @property def aveF2CCV(self): "Construct the averaging operator on cell faces to cell centers." if getattr(self, '_aveF2CCV', None) is None: if self.dim == 2: self._aveF2CCV = sp.block_diag([self.aveFx2CC, self.aveFy2CC]).tocsr() elif self.dim == 3: self._aveF2CCV = sp.block_diag([self.aveFx2CC, self.aveFy2CC, self.aveFz2CC]).tocsr() return self._aveF2CCV @property def aveN2CC(self): if getattr(self, '_aveN2CC', None) is None: I, J, V = [], [], [] PM = [1./2.**self.dim] * 2**self.dim for ii, ind in enumerate(self._sortedCells): p = self._pointer(ind) w = self._levelWidth(p[-1]) if self.dim == 2: nodes = [ self._n2i[self._index([ p[0] , p[1] , p[2] ])], self._n2i[self._index([ p[0] + w, p[1] , p[2] ])], self._n2i[self._index([ p[0] , p[1] + w, p[2] ])], self._n2i[self._index([ p[0] + w, p[1] + w, p[2] ])], ] if self.dim == 3: nodes = [ self._n2i[self._index([ p[0] , p[1] , p[2] , p[3] ])], self._n2i[self._index([ p[0] + w, p[1] , p[2] , p[3] ])], self._n2i[self._index([ p[0] , p[1] + w, p[2] , p[3] ])], self._n2i[self._index([ p[0] + w, p[1] + w, p[2] , p[3] ])], self._n2i[self._index([ p[0] , p[1] , p[2] + w, p[3] ])], self._n2i[self._index([ p[0] + w, p[1] , p[2] + w, p[3] ])], self._n2i[self._index([ p[0] , p[1] + w, p[2] + w, p[3] ])], self._n2i[self._index([ p[0] + w, p[1] + w, p[2] + w, p[3] ])], ] for pm, node in zip(PM,nodes): I += [ii] J += [node] V += [pm] Av = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.ntN)) Re = self._deflationMatrix('N',asOnes=False,withHanging=True) self._aveN2CC = Av*Re return self._aveN2CC def _getFaceP(self, xFace, yFace, zFace): ind1, ind2, ind3 = [], [], [] for ind in self._sortedCells: p = self._pointer(ind) w = self._levelWidth(p[-1]) posX = 0 if xFace == 'fXm' else w posY = 0 if yFace == 'fYm' else w if self.dim == 3: posZ = 0 if zFace == 'fZm' else w ind1.append( self._fx2i[self._index([ p[0] + posX, p[1]] + p[2:])] ) ind2.append( self._fy2i[self._index([ p[0], p[1] + posY] + p[2:])] + self.ntFx ) if self.dim == 3: ind3.append( self._fz2i[self._index([ p[0], p[1], p[2] + posZ, p[3]])] + self.ntFx + self.ntFy ) if self.dim == 2: IND = np.r_[ind1, ind2] if self.dim == 3: IND = np.r_[ind1, ind2, ind3] PXXX = sp.coo_matrix((np.ones(self.dim*self.nC), (range(self.dim*self.nC), IND)), shape=(self.dim*self.nC, self.ntF)).tocsr() Rf = self._deflationMatrix('F', withHanging=True, asOnes=True) return PXXX * Rf def _getFacePxx(self): self.number() def Pxx(xFace, yFace): return self._getFaceP(xFace, yFace, None) return Pxx def _getFacePxxx(self): self.number() def Pxxx(xFace, yFace, zFace): return self._getFaceP(xFace, yFace, zFace) return Pxxx def _getEdgeP(self, xEdge, yEdge, zEdge): if self.dim == 2: raise Exception('Not implemented') # this should be a reordering of the face inner product? ind1, ind2, ind3 = [], [], [] for ind in self._sortedCells: p = self._pointer(ind) w = self._levelWidth(p[-1]) posX = [0,0] if xEdge == 'eX0' else [w, 0] if xEdge == 'eX1' else [0,w] if xEdge == 'eX2' else [w,w] posY = [0,0] if yEdge == 'eY0' else [w, 0] if yEdge == 'eY1' else [0,w] if yEdge == 'eY2' else [w,w] posZ = [0,0] if zEdge == 'eZ0' else [w, 0] if zEdge == 'eZ1' else [0,w] if zEdge == 'eZ2' else [w,w] ind1.append( self._ex2i[self._index([ p[0] , p[1] + posX[0], p[2] + posX[1], p[3]])] ) ind2.append( self._ey2i[self._index([ p[0] + posY[0], p[1] , p[2] + posY[1], p[3]])] + self.ntEx ) ind3.append( self._ez2i[self._index([ p[0] + posZ[0], p[1] + posZ[1], p[2] , p[3]])] + self.ntEx + self.ntEy ) IND = np.r_[ind1, ind2, ind3] PXXX = sp.coo_matrix((np.ones(self.dim*self.nC), (range(self.dim*self.nC), IND)), shape=(self.dim*self.nC, self.ntE)).tocsr() Re = self._deflationMatrix('E') return PXXX * Re def _getEdgePxx(self): raise Exception('Not implemented') # this should be a reordering of the face inner product? def _getEdgePxxx(self): self.number() def Pxxx(xEdge, yEdge, zEdge): return self._getEdgeP(xEdge, yEdge, zEdge) return Pxxx def point2index(self, locs): locs = Utils.asArray_N_x_Dim(locs, self.dim) TOL = 1e-10 Nx = self.vectorNx Ny = self.vectorNy Nz = self.vectorNz pointers = range(self.dim) Nx = np.r_[Nx[0] - TOL, Nx[1:-1], Nx[-1] + TOL] pointers[0] = np.searchsorted(Nx, locs[:,0]) Ny = np.r_[Ny[0] - TOL, Ny[1:-1], Ny[-1] + TOL] pointers[1] = np.searchsorted(Ny, locs[:,1]) if self.dim == 3: Nz = np.r_[Nz[0] - TOL, Nz[1:-1], Nz[-1] + TOL] pointers[2] = np.searchsorted(Nz, locs[:,2]) if np.any([np.any(P == len(N)) or np.any(P == 0) for P,N in zip(pointers,[Nx,Ny,Nz])]): raise Exception('There are points outside of the mesh.') out = [] for pointer in zip(*pointers): for level in range(self.levels+1): width = self._levelWidth(level) testPointer = [((p-1)//width)*width for p in pointer] + [level] test = self._index(testPointer) if test in self: out += [test] break return out def getInterpolationMat(self, locs, locType, zerosOutside=False): """ Produces interpolation matrix :param numpy.ndarray locs: Location of points to interpolate to :param str locType: What to interpolate (see below) :rtype: scipy.sparse.csr.csr_matrix :return: M, the interpolation matrix locType can be:: 'Ex' -> x-component of field defined on edges 'Ey' -> y-component of field defined on edges 'Ez' -> z-component of field defined on edges 'Fx' -> x-component of field defined on faces 'Fy' -> y-component of field defined on faces 'Fz' -> z-component of field defined on faces 'N' -> scalar field defined on nodes 'CC' -> scalar field defined on cell centers """ if 'E' in locType and self.dim == 2: raise Exception('Interpolation for edges is not supported in 2D.') locs = Utils.asArray_N_x_Dim(locs, self.dim) TOL = 1e-10 self.number() cells = self.point2index(locs) I,J,V=[],[],[] numberer = getattr(self, '_'+locType.lower()+'2i') if zerosOutside is False: assert np.all(self.isInside(locs)), "Points outside of mesh" else: indZeros = np.logical_not(self.isInside(locs)) locs[indZeros, :] = np.array([v.mean() for v in self.getTensor('CC')]) if locType in ['Fx','Fy','Fz','Ex','Ey','Ez']: ind = {'x':0, 'y':1, 'z':2}[locType[1]] assert self.dim >= ind, 'mesh is not high enough dimension.' antiInd = {'x':[1,2], 'y':[0,2], 'z':[0,1]}[locType[1]][:self.dim-1] nF_nE = self.vntF if 'F' in locType else self.vntE components = [Utils.spzeros(locs.shape[0], n) for n in nF_nE] for ii, cell in enumerate(cells): loc = locs[ii,:] p = self._asPointer(cell) h, n = self._cellH(p), self._cellN(p) w = self._levelWidth(p[-1]) if 'E' in locType: iLocs, weights = Utils.interputils._interpmat2D(np.array([(loc-n-self.x0)[antiInd]]),np.r_[0.,h[antiInd[0]]+TOL],np.r_[0.,h[antiInd[1]]+TOL]) newJ = [numberer[self._index([__+w*iLocs[IND][0] if _ == antiInd[0] else __+w*iLocs[IND][1] if _ == antiInd[1] else __ for _, __ in enumerate(p[:-1])] + [p[-1]])] for IND in range(4)] #sorry elif 'F' in locType: _, weights = Utils.interputils._interpmat1D(np.r_[(loc-n-self.x0)[ind]],np.r_[0.,h[ind]+TOL]) plusFace = self._index([__+w if _ == ind else __ for _, __ in enumerate(p[:-1])] + [p[-1]]) newJ = [numberer[cell], numberer[plusFace]] I += [ii]*len(newJ) J += newJ V += weights components[ind] = sp.csr_matrix((V,(I,J)), shape=(locs.shape[0], nF_nE[ind])) # remove any zero blocks (hstack complains) components = [comp for comp in components if comp.shape[1] > 0] Q = sp.hstack(components).tocsr() if 'E' in locType: R = self._deflationMatrix(locType[0],asOnes=False,withHanging=True) else: # faces R = self._deflationMatrix(locType[0],asOnes=True,withHanging=True) elif locType == 'N': for ii, cell in enumerate(cells): loc = locs[ii,:] p = self._asPointer(cell) h, n = self._cellH(p), self._cellN(p) w = self._levelWidth(p[-1]) iLocs, weights = Utils.interputils._interpmat3D(np.array([(loc-n-self.x0)]),*[np.r_[0.,h[_]+TOL] for _ in range(3)]) newJ = [numberer[self._index([__+w*iLocs[IND][_] for _, __ in enumerate(p[:-1])] + [p[-1]])] for IND in range(8)] #sorry I += [ii]*len(newJ) J += newJ V += weights Q = sp.csr_matrix((V,(I,J)), shape=(locs.shape[0], self.ntN)) R = self._deflationMatrix('N',withHanging=True) elif locType == 'CC': for ii, cell in enumerate(cells): I += [ii] J += [numberer[cell]] V += [1.0] Q = sp.csr_matrix((V,(I,J)), shape=(locs.shape[0], self.nC)) R = Utils.Identity() else: raise NotImplementedError('getInterpolationMat: locType=='+locType+' and mesh.dim=='+str(self.dim)) if zerosOutside: Q[indZeros, :] = 0 return Q * R def plotGrid(self, ax=None, showIt=False, grid=True, cells=False, cellLine=False, nodes=False, facesX=False, facesY=False, facesZ=False, edgesX=False, edgesY=False, edgesZ=False): import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors import matplotlib.cm as cmx # self.number() axOpts = {'projection':'3d'} if self.dim == 3 else {} if ax is None: ax = plt.subplot(111, **axOpts) else: assert isinstance(ax,matplotlib.axes.Axes), "ax must be an Axes!" fig = ax.figure if grid: X, Y, Z = [], [], [] for ind in self._sortedCells: p = self._asPointer(ind) n = self._cellN(p) h = self._cellH(p) if self.dim == 2: X += [n[0] , n[0] + h[0], n[0] + h[0], n[0] , n[0], np.nan] Y += [n[1] , n[1] , n[1] + h[1], n[1] + h[1], n[1], np.nan] elif self.dim == 3: X += [n[0] , n[0] + h[0], n[0] + h[0], n[0] , n[0], np.nan]*2 Y += [n[1] , n[1] , n[1] + h[1], n[1] + h[1], n[1], np.nan]*2 Z += [n[2]]*5+[np.nan] Z += [n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2], n[2] + h[2], np.nan] sides = [0,0], [h[0],0], [0,h[1]], [h[0],h[1]] for s in sides: X += [n[0] + s[0], n[0] + s[0]] Y += [n[1] + s[1], n[1] + s[1]] Z += [n[2] , n[2] + h[2]] if self.dim == 2: ax.plot(X,Y, 'b-') elif self.dim == 3: ax.plot(X,Y, 'b-', zs=Z) if self.dim == 2: if cells: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r.') if cellLine: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r:') ax.plot(self.gridCC[[0,-1],0], self.gridCC[[0,-1],1], 'ro') if nodes: ax.plot(self._gridN[:,0], self._gridN[:,1], 'ms') ax.plot(self._gridN[self._hangingN.keys(),0], self._gridN[self._hangingN.keys(),1], 'ms', ms=10, mfc='none', mec='m') if facesX: ax.plot(self._gridFx[:,0], self._gridFx[:,1], 'g>') ax.plot(self._gridFx[self._hangingFx.keys(),0], self._gridFx[self._hangingFx.keys(),1], 'gs', ms=10, mfc='none', mec='g') if facesY: ax.plot(self._gridFy[:,0], self._gridFy[:,1], 'g^') ax.plot(self._gridFy[self._hangingFy.keys(),0], self._gridFy[self._hangingFy.keys(),1], 'gs', ms=10, mfc='none', mec='g') ax.set_xlabel('x1') ax.set_ylabel('x2') elif self.dim == 3: if cells: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r.', zs=self.gridCC[:,2]) if cellLine: ax.plot(self.gridCC[:,0], self.gridCC[:,1], 'r:', zs=self.gridCC[:,2]) ax.plot(self.gridCC[[0,-1],0], self.gridCC[[0,-1],1], 'ro', zs=self.gridCC[[0,-1],2]) if nodes: ax.plot(self._gridN[:,0], self._gridN[:,1], 'ms', zs=self._gridN[:,2]) ax.plot(self._gridN[self._hangingN.keys(),0], self._gridN[self._hangingN.keys(),1], 'ms', ms=10, mfc='none', mec='m', zs=self._gridN[self._hangingN.keys(),2]) for key in self._hangingN.keys(): for hf in self._hangingN[key]: ind = [key, hf[0]] ax.plot(self._gridN[ind,0], self._gridN[ind,1], 'm:', zs=self._gridN[ind,2]) if facesX: ax.plot(self._gridFx[:,0], self._gridFx[:,1], 'g>', zs=self._gridFx[:,2]) ax.plot(self._gridFx[self._hangingFx.keys(),0], self._gridFx[self._hangingFx.keys(),1], 'gs', ms=10, mfc='none', mec='g', zs=self._gridFx[self._hangingFx.keys(),2]) for key in self._hangingFx.keys(): for hf in self._hangingFx[key]: ind = [key, hf[0]] ax.plot(self._gridFx[ind,0], self._gridFx[ind,1], 'g:', zs=self._gridFx[ind,2]) if facesY: ax.plot(self._gridFy[:,0], self._gridFy[:,1], 'g^', zs=self._gridFy[:,2]) ax.plot(self._gridFy[self._hangingFy.keys(),0], self._gridFy[self._hangingFy.keys(),1], 'gs', ms=10, mfc='none', mec='g', zs=self._gridFy[self._hangingFy.keys(),2]) for key in self._hangingFy.keys(): for hf in self._hangingFy[key]: ind = [key, hf[0]] ax.plot(self._gridFy[ind,0], self._gridFy[ind,1], 'g:', zs=self._gridFy[ind,2]) if facesZ: ax.plot(self._gridFz[:,0], self._gridFz[:,1], 'g^', zs=self._gridFz[:,2]) ax.plot(self._gridFz[self._hangingFz.keys(),0], self._gridFz[self._hangingFz.keys(),1], 'gs', ms=10, mfc='none', mec='g', zs=self._gridFz[self._hangingFz.keys(),2]) for key in self._hangingFz.keys(): for hf in self._hangingFz[key]: ind = [key, hf[0]] ax.plot(self._gridFz[ind,0], self._gridFz[ind,1], 'g:', zs=self._gridFz[ind,2]) if edgesX: ax.plot(self._gridEx[:,0], self._gridEx[:,1], 'k>', zs=self._gridEx[:,2]) ax.plot(self._gridEx[self._hangingEx.keys(),0], self._gridEx[self._hangingEx.keys(),1], 'ks', ms=10, mfc='none', mec='k', zs=self._gridEx[self._hangingEx.keys(),2]) for key in self._hangingEx.keys(): for hf in self._hangingEx[key]: ind = [key, hf[0]] ax.plot(self._gridEx[ind,0], self._gridEx[ind,1], 'k:', zs=self._gridEx[ind,2]) if edgesY: ax.plot(self._gridEy[:,0], self._gridEy[:,1], 'k<', zs=self._gridEy[:,2]) ax.plot(self._gridEy[self._hangingEy.keys(),0], self._gridEy[self._hangingEy.keys(),1], 'ks', ms=10, mfc='none', mec='k', zs=self._gridEy[self._hangingEy.keys(),2]) for key in self._hangingEy.keys(): for hf in self._hangingEy[key]: ind = [key, hf[0]] ax.plot(self._gridEy[ind,0], self._gridEy[ind,1], 'k:', zs=self._gridEy[ind,2]) if edgesZ: ax.plot(self._gridEz[:,0], self._gridEz[:,1], 'k^', zs=self._gridEz[:,2]) ax.plot(self._gridEz[self._hangingEz.keys(),0], self._gridEz[self._hangingEz.keys(),1], 'ks', ms=10, mfc='none', mec='k', zs=self._gridEz[self._hangingEz.keys(),2]) for key in self._hangingEz.keys(): for hf in self._hangingEz[key]: ind = [key, hf[0]] ax.plot(self._gridEz[ind,0], self._gridEz[ind,1], 'k:', zs=self._gridEz[ind,2]) ax.set_xlabel('x1') ax.set_ylabel('x2') ax.set_zlabel('x3') ax.grid(True) if showIt:plt.show() def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None): if self.dim == 3: raise Exception('Use plot slice?') import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors import matplotlib.cm as cmx if ax is None: ax = plt.subplot(111) jet = cm = plt.get_cmap('jet') cNorm = colors.Normalize( vmin=I.min() if clim is None else clim[0], vmax=I.max() if clim is None else clim[1]) scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet) ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) for ii, node in enumerate(self._sortedCells): x0, sz = self._cellN(node), self._cellH(node) ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=scalarMap.to_rgba(I[ii]), edgecolor='k' if grid else 'none')) # if text: ax.text(self.center[0],self.center[1],self.num) scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots ax.set_xlabel('x') ax.set_ylabel('y') if showIt: plt.show() return [scalarMap] def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=True, view='real', ax=None, clim=None, showIt=False, pcolorOpts={}, streamOpts={'color':'k'}, gridOpts={'color':'k', 'alpha':0.5}): assert vType in ['CC','F','E'] assert self.dim == 3 import matplotlib.pyplot as plt import matplotlib from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors import matplotlib.cm as cmx szSliceDim = len(getattr(self, 'h'+normal.lower())) #: Size of the sliced dimension if ind is None: ind = int(szSliceDim/2) assert type(ind) in [int, long], 'ind must be an integer' indLoc = getattr(self,'vectorCC'+normal.lower())[ind] normalInd = {'X':0,'Y':1,'Z':2}[normal] antiNormalInd = {'X':[1,2],'Y':[0,2],'Z':[0,1]}[normal] h2d = [] x2d = [] if 'X' not in normal: h2d.append(self.hx) x2d.append(self.x0[0]) if 'Y' not in normal: h2d.append(self.hy) x2d.append(self.x0[1]) if 'Z' not in normal: h2d.append(self.hz) x2d.append(self.x0[2]) tM = TensorMesh(h2d, x2d) #: Temp Mesh def getLocs(*args): if len(args) == 1: grids = (args[0],args[0],args[0]) else: assert len(args) == 3 grids = args one = np.ones((grids[0].shape[0],1))*indLoc if normal == 'X': return np.hstack((one, grids[0][:,[0]], grids[1][:,[1]])) if normal == 'Y': return np.hstack((grids[0][:,[0]], one, grids[1][:,[1]])) if normal == 'Z': return np.hstack((grids[0][:,[0]], grids[1][:,[1]], one)) def doSlice(v): if vType == 'CC': P = self.getInterpolationMat(getLocs(tM.gridCC),'CC') elif vType in ['F', 'E']: Ps = [] gridX = getLocs(getattr(tM, 'grid' + vType + 'x')) gridY = getLocs(getattr(tM, 'grid' + vType + 'y')) Ps += [self.getInterpolationMat(gridX,vType + ('y' if normal == 'X' else 'x'))] Ps += [self.getInterpolationMat(gridY,vType + ('y' if normal == 'Z' else 'z'))] P = sp.vstack(Ps) return P*v v2d = doSlice(v) if ax is None: fig = plt.figure() ax = plt.subplot(111) else: assert isinstance(ax, matplotlib.axes.Axes), "ax must be an matplotlib.axes.Axes" fig = ax.figure out = tM._plotImage2D(v2d, vType=vType, view=view, ax=ax, clim=clim, pcolorOpts=pcolorOpts, streamOpts=streamOpts) ax.set_xlabel('y' if normal == 'X' else 'x') ax.set_ylabel('y' if normal == 'Z' else 'z') ax.set_title('Slice %d, %s = %4.2f' % (ind,normal,indLoc)) if grid: _ = antiNormalInd X = [] Y = [] for cell in self._cells: p = self._pointer(cell) n, h = self._cellN(p), self._cellH(p) if n[normalInd]indLoc: X += [n[_[0]] , n[_[0]] + h[_[0]], n[_[0]] + h[_[0]], n[_[0]] , n[_[0]], np.nan] Y += [n[_[1]] , n[_[1]] , n[_[1]] + h[_[1]], n[_[1]] + h[_[1]], n[_[1]], np.nan] out = list(out) out += ax.plot(X,Y, **gridOpts) if len(out) > 2: # this is not robust, searching for the streamlines would be better out[1].lines.set_zorder(200) out[1].arrows.set_zorder(201) if showIt: plt.show() return tuple(out) def __len__(self): return self.nC def __getitem__(self, key): if isinstance( key, slice ) : #Get the start, stop, and step from the slice return [self[ii] for ii in xrange(*key.indices(len(self)))] elif isinstance( key, int ) : if key < 0 : #Handle negative indices key += len( self ) if key >= len( self ) : raise IndexError, "The index (%d) is out of range."%key self._numberCells() # no-op if numbered index = self._i2cc[key] pointer = self._asPointer(index) return Cell(self, index, pointer) else: raise TypeError, "Invalid argument type." class Cell(object): def __init__(self, mesh, index, pointer): self.mesh = mesh self._index = index self._pointer = pointer @property def nodes(self): """The node index in _gridN (this may include hanging nodes).""" M = self.mesh M._numberNodes() p = self._pointer i = self._index w = M._levelWidth(p[-1]) if M.dim == 2: n = [ i, M._index([ p[0] + w, p[1] , p[2]]), M._index([ p[0] , p[1]+ w, p[2]]), M._index([ p[0] + w, p[1]+ w, p[2]]), ] elif self.dim == 3: n = [ i, M._index([ p[0] + w, p[1] , p[2] ,p[3]]), M._index([ p[0] , p[1] + w, p[2] ,p[3]]), M._index([ p[0] + w, p[1] + w, p[2] ,p[3]]), M._index([ p[0] , p[1] , p[2] + w,p[3]]), M._index([ p[0] + w, p[1] , p[2] + w,p[3]]), M._index([ p[0] , p[1] + w, p[2] + w,p[3]]), M._index([ p[0] + w, p[1] + w, p[2] + w,p[3]]), ] return [M._n2i[_] for _ in n] @property def center(self): if getattr(self, '_center', None) is None: self._center = np.array(self.mesh._cellC(self._pointer)) return self._center @property def h(self): return self.mesh._cellH(self._pointer) @property def x0(self): return self.mesh._cellN(self._pointer) @property def dim(self): return self.mesh.dim def SortGrid(grid, offset=0): """ Sorts a grid by the x0 location. """ eps = 1e-7 def mycmp(c1,c2): c1 = grid[c1-offset] c2 = grid[c2-offset] if c1.size == 2: if np.abs(c1[1] - c2[1]) < eps: return c1[0] - c2[0] return c1[1] - c2[1] elif c1.size == 3: if np.abs(c1[2] - c2[2]) < eps: if np.abs(c1[1] - c2[1]) < eps: return c1[0] - c2[0] return c1[1] - c2[1] return c1[2] - c2[2] class K(object): def __init__(self, obj, *args): self.obj = obj def __lt__(self, other): return mycmp(self.obj, other.obj) < 0 def __gt__(self, other): return mycmp(self.obj, other.obj) > 0 def __eq__(self, other): return mycmp(self.obj, other.obj) == 0 def __le__(self, other): return mycmp(self.obj, other.obj) <= 0 def __ge__(self, other): return mycmp(self.obj, other.obj) >= 0 def __ne__(self, other): return mycmp(self.obj, other.obj) != 0 return sorted(range(offset,grid.shape[0]+offset), key=K) class TreeException(Exception): pass class NotBalancedException(TreeException): pass class CellLookUpException(TreeException): pass