From f0f59c107e6648b123d4049feacd0944bd35d3a3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 18 Dec 2013 18:36:49 -0800 Subject: [PATCH 01/42] Counting Cells working! --- SimPEG/mesh/QuadTreeMesh.py | 125 ++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 SimPEG/mesh/QuadTreeMesh.py diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py new file mode 100644 index 00000000..1881d02f --- /dev/null +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -0,0 +1,125 @@ +import numpy as np +import matplotlib.pyplot as plt + + + +class TreeNode(object): + """docstring for TreeNode""" + def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None): + self.mesh = mesh + self.x0 = np.array(x0,dtype=float) + self.dim = dim + self.depth = depth + self.sz = np.array(sz,dtype=float) + self.parent = parent + self.children = None + self.numCell = None + + @property + def parent(self): + return self._parent + @parent.setter + def parent(self, value): + self._parent = value + + @property + def branchdepth(self): + if self.isleaf: + return self.depth + else: + return np.max([node.branchdepth for node in self.children.flatten('F')]) + + + def refine(self): + if self.isleaf: + x0, sz = self.x0, self.sz + corners = [np.r_[x0[0] , x0[1] ], + np.r_[x0[0]+sz[0]/2, x0[1] ], + np.r_[x0[0] , x0[1]+sz[1]/2], + np.r_[x0[0]+sz[0]/2, x0[1]+sz[1]/2]] + + children = np.array([TreeNode(self.mesh, x0=corners[i],dim=self.dim, depth=self.depth+1, sz=sz/2, parent=self) for i in range(2*self.dim)]) + self.children = children.reshape([2,2],order='F') + + + + def countCell(self, COUNTER, column, maxColumns): + if self.isleaf: + if self.numCell is None: + self.numCell = COUNTER + return COUNTER + 1 + else: + return COUNTER + if column < maxColumns/2: + COUNTER = self.children[0,0].countCell(COUNTER, column, maxColumns/2) + COUNTER = self.children[1,0].countCell(COUNTER, column, maxColumns/2) + return COUNTER + else: + column = column - maxColumns/2 + COUNTER = self.children[0,1].countCell(COUNTER, column, maxColumns/2) + COUNTER = self.children[1,1].countCell(COUNTER, column, maxColumns/2) + return COUNTER + + + @property + def isleaf(self): return self.children is None + + def viz(self, ax): + if self.isleaf: + x0, sz = self.x0, self.sz + corners = np.c_[np.r_[x0[0] , x0[1] ], + np.r_[x0[0]+sz[0], x0[1] ], + np.r_[x0[0]+sz[0], x0[1]+sz[1]], + np.r_[x0[0] , x0[1]+sz[1]], + np.r_[x0[0] , x0[1] ]].T + ax.plot(corners[:,1],corners[:,0], 'b') + if self.numCell is not None: + ax.text(x0[1]+sz[1]/2,x0[0]+sz[0]/2,'%d'%self.numCell) + else: + [node.viz(ax) for node in self.children.flatten('F')] + + + + +class QuadTreeMesh(object): + """docstring for QuadTreeMesh""" + def __init__(self, cells, sz): + children = range(cells[0]) + for i, row in enumerate(children): + children[i] = [TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz) for j in range(cells[1])] + self.children = np.array(children,dtype=TreeNode) + + + @property + def branchdepth(self): + return np.max([node.branchdepth for node in self.children.flatten('F')]) + + + def number(self): + COUNTER = 0 + for col in range(self.children.shape[1]): + coldepth = np.max([node.branchdepth for node in self.children[:,col]]) + maxColumns = 2**coldepth + for COL in range(maxColumns): + for row in range(self.children.shape[0]): + COUNTER = self.children[row,col].countCell(COUNTER, COL, maxColumns) + + def viz(self): + ax = plt.subplot(111) + for row in self.children: + for node in row: + node.viz(ax) + + +if __name__ == '__main__': + M = QuadTreeMesh([2,3],[1,2]) + M.children[0,0].refine() + M.children[1,1].refine() + M.children[0,0].children[0,0].refine() + M.children[0,0].children[0,0].children[0,1].refine() + M.number() + + + M.viz() + plt.gca().invert_yaxis() + plt.show() From 529bf363671778fbde0ec4df98b56493499a0af0 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 09:33:19 -0800 Subject: [PATCH 02/42] Faces! --- SimPEG/mesh/QuadTreeMesh.py | 124 +++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 23 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 1881d02f..5d5c6f41 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -2,10 +2,48 @@ import numpy as np import matplotlib.pyplot as plt +class TreeFace(object): + """docstring for TreeFace""" + def __init__(self, mesh, x0=[0,0], faceType=None, dim=2, sz=1, depth=0, parent=None): + self.mesh = mesh + self.children = None + self.x0 = np.array(x0,dtype=float) + self.faceType = faceType + self.sz = sz + self.dim = dim + mesh.faces.add(self) + self.tangent = np.zeros(dim) + self.tangent[1 if faceType is 'x' else 0] = 1 + self.normal = np.zeros(dim) + self.normal[0 if faceType is 'x' else 1] = 1 + + @property + def isleaf(self): return self.children is None + + def refine(self): + if not self.isleaf: return + self.children = np.empty(2,dtype=TreeFace) + # Create refined x0's + x0r_0 = self.x0 + x0r_1 = self.x0+self.tangent*self.sz/2 + self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=self.sz/2, depth=self.depth+1,parent=self) + self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=self.sz/2, depth=self.depth+1,parent=self) + self.mesh.faces.remove(self) + + + def viz(self, ax): + ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'rx-') + class TreeNode(object): """docstring for TreeNode""" - def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None): + def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None, fXm=None, fXp=None, fYm=None, fYp=None): + + self.fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) + self.fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) + self.fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) + self.fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) + self.mesh = mesh self.x0 = np.array(x0,dtype=float) self.dim = dim @@ -14,6 +52,7 @@ class TreeNode(object): self.parent = parent self.children = None self.numCell = None + mesh.cells.add(self) @property def parent(self): @@ -31,15 +70,18 @@ class TreeNode(object): def refine(self): - if self.isleaf: - x0, sz = self.x0, self.sz - corners = [np.r_[x0[0] , x0[1] ], - np.r_[x0[0]+sz[0]/2, x0[1] ], - np.r_[x0[0] , x0[1]+sz[1]/2], - np.r_[x0[0]+sz[0]/2, x0[1]+sz[1]/2]] + if not self.isleaf: return - children = np.array([TreeNode(self.mesh, x0=corners[i],dim=self.dim, depth=self.depth+1, sz=sz/2, parent=self) for i in range(2*self.dim)]) - self.children = children.reshape([2,2],order='F') + x0, sz = self.x0, self.sz + corners = [np.r_[x0[0] , x0[1] ], + np.r_[x0[0]+sz[0]/2, x0[1] ], + np.r_[x0[0] , x0[1]+sz[1]/2], + np.r_[x0[0]+sz[0]/2, x0[1]+sz[1]/2]] + + children = [TreeNode(self.mesh, x0=corners[i],dim=self.dim, depth=self.depth+1, sz=sz/2, parent=self) for i in range(2*self.dim)] + self.mesh.cells.remove(self) + self.mesh.cells = self.mesh.cells.union(set(children)) + self.children = np.array(children,dtype=TreeNode).reshape([2,2],order='F') @@ -72,9 +114,10 @@ class TreeNode(object): np.r_[x0[0]+sz[0], x0[1]+sz[1]], np.r_[x0[0] , x0[1]+sz[1]], np.r_[x0[0] , x0[1] ]].T - ax.plot(corners[:,1],corners[:,0], 'b') + ax.plot(corners[:,0],corners[:,1], 'b') + self.fXm.viz(ax) if self.numCell is not None: - ax.text(x0[1]+sz[1]/2,x0[0]+sz[0]/2,'%d'%self.numCell) + ax.text(x0[0]+sz[0]/2,x0[1]+sz[1]/2,'%d'%self.numCell) else: [node.viz(ax) for node in self.children.flatten('F')] @@ -84,10 +127,15 @@ class TreeNode(object): class QuadTreeMesh(object): """docstring for QuadTreeMesh""" def __init__(self, cells, sz): - children = range(cells[0]) - for i, row in enumerate(children): - children[i] = [TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz) for j in range(cells[1])] - self.children = np.array(children,dtype=TreeNode) + self.faces = set() + self.cells = set() + + self.children = np.empty(cells,dtype=TreeNode) + for i in range(cells[0]): + for j in range(cells[1]): + fXm = None if i is 0 else self.children[i-1][j].fXp + fYm = None if j is 0 else self.children[i][j-1].fYp + self.children[i][j] = TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz, fXm=fXm, fYm=fYm) @property @@ -106,20 +154,50 @@ class QuadTreeMesh(object): def viz(self): ax = plt.subplot(111) - for row in self.children: - for node in row: - node.viz(ax) + [node.viz(ax) for node in self.cells] + [node.viz(ax) for node in self.faces] if __name__ == '__main__': - M = QuadTreeMesh([2,3],[1,2]) + M = QuadTreeMesh([4,6],[1,2]) M.children[0,0].refine() M.children[1,1].refine() - M.children[0,0].children[0,0].refine() - M.children[0,0].children[0,0].children[0,1].refine() - M.number() + for ii in range(3): + M.children[ii,ii].refine() + M.children[ii,ii].children[0,0].refine() + eps = 1e-7 + def mycmp(c1,c2): + if np.abs(c1.x0[1] - c2.x0[1]) < eps: + return c1.x0[0] - c2.x0[0] + return c1.x0[1] - c2.x0[1] + + def cmp_to_key(mycmp): + 'Convert a cmp= function into a key= function' + 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 K + + # M.number() + sortCells = sorted(M.cells,key=cmp_to_key(mycmp)) + for i, sc in enumerate(sortCells): + sc.numCell = i + + print M.children[0,0].fXp is M.children[1,0].fXm M.viz() - plt.gca().invert_yaxis() + # plt.gca().invert_yaxis() plt.show() From f25d5bd524f0391e1f711e2c91648714ac1099b5 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 14:25:34 -0800 Subject: [PATCH 03/42] Testing and Face numbering (shared faces are shared!) --- SimPEG/__init__.py | 2 +- SimPEG/mesh/QuadTreeMesh.py | 157 +++++++++++++++++++++------------- SimPEG/mesh/__init__.py | 1 + SimPEG/tests/test_QuadTree.py | 21 +++++ 4 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 SimPEG/tests/test_QuadTree.py diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index f421bc82..70f29c46 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -6,7 +6,7 @@ import mesh import data import forward import inverse -import visualize +# import visualize import examples import scipy.version as _v diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 5d5c6f41..934147d9 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -2,16 +2,45 @@ import numpy as np import matplotlib.pyplot as plt + +def SortByX0(): + eps = 1e-7 + def mycmp(c1,c2): + if np.abs(c1.x0[1] - c2.x0[1]) < eps: + return c1.x0[0] - c2.x0[0] + return c1.x0[1] - c2.x0[1] + 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 K + + class TreeFace(object): """docstring for TreeFace""" def __init__(self, mesh, x0=[0,0], faceType=None, dim=2, sz=1, depth=0, parent=None): self.mesh = mesh self.children = None + self.numFace = None self.x0 = np.array(x0,dtype=float) self.faceType = faceType self.sz = sz self.dim = dim + self.depth = depth mesh.faces.add(self) + if faceType is 'x': self.mesh.faceX.add(self) + elif faceType is 'y': self.mesh.faceY.add(self) self.tangent = np.zeros(dim) self.tangent[1 if faceType is 'x' else 0] = 1 self.normal = np.zeros(dim) @@ -25,30 +54,40 @@ class TreeFace(object): self.children = np.empty(2,dtype=TreeFace) # Create refined x0's x0r_0 = self.x0 - x0r_1 = self.x0+self.tangent*self.sz/2 - self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=self.sz/2, depth=self.depth+1,parent=self) - self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=self.sz/2, depth=self.depth+1,parent=self) + x0r_1 = self.x0+0.5*self.tangent*self.sz + self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1,parent=self) + self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1,parent=self) self.mesh.faces.remove(self) + if self.faceType is 'x': + self.mesh.faceX.remove(self) + elif self.faceType is 'y': + self.mesh.faceY.remove(self) def viz(self, ax): + if not self.isleaf: return ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'rx-') + if self.faceType is 'y': + ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) + class TreeNode(object): """docstring for TreeNode""" def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None, fXm=None, fXp=None, fYm=None, fYp=None): - self.fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) - self.fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) - self.fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) - self.fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) + fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) + fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) + fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) + fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) + + self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} self.mesh = mesh - self.x0 = np.array(x0,dtype=float) + self.x0 = np.array(x0, dtype=float) self.dim = dim self.depth = depth - self.sz = np.array(sz,dtype=float) + self.sz = np.array(sz, dtype=float) self.parent = parent self.children = None self.numCell = None @@ -72,17 +111,33 @@ class TreeNode(object): def refine(self): if not self.isleaf: return + self.children = np.empty((2,2),dtype=TreeNode) x0, sz = self.x0, self.sz - corners = [np.r_[x0[0] , x0[1] ], - np.r_[x0[0]+sz[0]/2, x0[1] ], - np.r_[x0[0] , x0[1]+sz[1]/2], - np.r_[x0[0]+sz[0]/2, x0[1]+sz[1]/2]] - children = [TreeNode(self.mesh, x0=corners[i],dim=self.dim, depth=self.depth+1, sz=sz/2, parent=self) for i in range(2*self.dim)] + for faceName in self.faces: + self.faces[faceName].refine() + + i, j = 0, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] + fXm, fXp, fYm, fYp = self.faces['fXm'].children[0], None, self.faces['fYm'].children[0], None + self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + + i, j = 1, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] + fXm, fXp, fYm, fYp = self.children[0,0].faces['fXp'], self.faces['fXp'].children[0], self.faces['fYm'].children[1], None + self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + + i, j = 0, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] + fXm, fXp, fYm, fYp = self.faces['fXm'].children[1], None, self.children[0,0].faces['fYp'], self.faces['fYp'].children[0] + self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + + i, j = 1, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] + fXm, fXp, fYm, fYp = self.children[0,1].faces['fXp'], self.faces['fXp'].children[1], self.children[1,0].faces['fYp'], self.faces['fYp'].children[1] + self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.mesh.cells.remove(self) - self.mesh.cells = self.mesh.cells.union(set(children)) - self.children = np.array(children,dtype=TreeNode).reshape([2,2],order='F') - def countCell(self, COUNTER, column, maxColumns): @@ -115,7 +170,6 @@ class TreeNode(object): np.r_[x0[0] , x0[1]+sz[1]], np.r_[x0[0] , x0[1] ]].T ax.plot(corners[:,0],corners[:,1], 'b') - self.fXm.viz(ax) if self.numCell is not None: ax.text(x0[0]+sz[0]/2,x0[1]+sz[1]/2,'%d'%self.numCell) else: @@ -128,13 +182,15 @@ class QuadTreeMesh(object): """docstring for QuadTreeMesh""" def __init__(self, cells, sz): self.faces = set() + self.faceX = set() + self.faceY = set() self.cells = set() self.children = np.empty(cells,dtype=TreeNode) for i in range(cells[0]): for j in range(cells[1]): - fXm = None if i is 0 else self.children[i-1][j].fXp - fYm = None if j is 0 else self.children[i][j-1].fYp + fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] + fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] self.children[i][j] = TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz, fXm=fXm, fYm=fYm) @@ -144,13 +200,21 @@ class QuadTreeMesh(object): def number(self): - COUNTER = 0 - for col in range(self.children.shape[1]): - coldepth = np.max([node.branchdepth for node in self.children[:,col]]) - maxColumns = 2**coldepth - for COL in range(maxColumns): - for row in range(self.children.shape[0]): - COUNTER = self.children[row,col].countCell(COUNTER, COL, maxColumns) + # COUNTER = 0 + # for col in range(self.children.shape[1]): + # coldepth = np.max([node.branchdepth for node in self.children[:,col]]) + # maxColumns = 2**coldepth + # for COL in range(maxColumns): + # for row in range(self.children.shape[0]): + # COUNTER = self.children[row,col].countCell(COUNTER, COL, maxColumns) + + sortCells = sorted(M.cells,key=SortByX0()) + sortFaceX = sorted(M.faceX,key=SortByX0()) + sortFaceY = sorted(M.faceY,key=SortByX0()) + nFx = len(sortFaceX) + for i, sc in enumerate(sortCells): sc.numCell = i + for i, sfx in enumerate(sortFaceX): sfx.numFace = i + for i, sfy in enumerate(sortFaceY): sfy.numFace = i + nFx def viz(self): ax = plt.subplot(111) @@ -159,45 +223,18 @@ class QuadTreeMesh(object): if __name__ == '__main__': - M = QuadTreeMesh([4,6],[1,2]) - M.children[0,0].refine() - M.children[1,1].refine() - for ii in range(3): + M = QuadTreeMesh([3,2],[1,2]) + for ii in range(1): M.children[ii,ii].refine() - M.children[ii,ii].children[0,0].refine() + # M.children[ii,ii].children[0,0].refine() - eps = 1e-7 - def mycmp(c1,c2): - if np.abs(c1.x0[1] - c2.x0[1]) < eps: - return c1.x0[0] - c2.x0[0] - return c1.x0[1] - c2.x0[1] - def cmp_to_key(mycmp): - 'Convert a cmp= function into a key= function' - 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 K - # M.number() - sortCells = sorted(M.cells,key=cmp_to_key(mycmp)) - for i, sc in enumerate(sortCells): - sc.numCell = i + M.number() - print M.children[0,0].fXp is M.children[1,0].fXm + print M.children[0,0].faces['fXp'] is M.children[1,0].faces['fXm'] + print len(M.faces) M.viz() # plt.gca().invert_yaxis() plt.show() diff --git a/SimPEG/mesh/__init__.py b/SimPEG/mesh/__init__.py index 3b8e1eef..66ee88c8 100644 --- a/SimPEG/mesh/__init__.py +++ b/SimPEG/mesh/__init__.py @@ -1,5 +1,6 @@ from Cyl1DMesh import Cyl1DMesh from TensorMesh import TensorMesh +from QuadTreeMesh import QuadTreeMesh from LogicallyOrthogonalMesh import LogicallyOrthogonalMesh from BaseMesh import BaseMesh from TensorView import TensorView diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py new file mode 100644 index 00000000..c085c7ae --- /dev/null +++ b/SimPEG/tests/test_QuadTree.py @@ -0,0 +1,21 @@ +from SimPEG import mesh, np +import unittest + + + +class TestCheckDerivative(unittest.TestCase): + + def setUp(self): + M = mesh.QuadTreeMesh([3,2],[1,2]) + for ii in range(1): + M.children[ii,ii].refine() + self.M = M + + def test_MeshSizes(self): + self.assertTrue(len(self.M.faces)==25) + self.assertTrue(len(self.M.cells)==9) + + + +if __name__ == '__main__': + unittest.main() From 27cc75c557039bd58c6242cdf2ab87f07eff0432 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 14:26:29 -0800 Subject: [PATCH 04/42] Removed FAST COUNTING for EASY COUNTING --- SimPEG/mesh/QuadTreeMesh.py | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 934147d9..5615f7a7 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -139,25 +139,6 @@ class TreeNode(object): self.mesh.cells.remove(self) - - def countCell(self, COUNTER, column, maxColumns): - if self.isleaf: - if self.numCell is None: - self.numCell = COUNTER - return COUNTER + 1 - else: - return COUNTER - if column < maxColumns/2: - COUNTER = self.children[0,0].countCell(COUNTER, column, maxColumns/2) - COUNTER = self.children[1,0].countCell(COUNTER, column, maxColumns/2) - return COUNTER - else: - column = column - maxColumns/2 - COUNTER = self.children[0,1].countCell(COUNTER, column, maxColumns/2) - COUNTER = self.children[1,1].countCell(COUNTER, column, maxColumns/2) - return COUNTER - - @property def isleaf(self): return self.children is None @@ -200,14 +181,6 @@ class QuadTreeMesh(object): def number(self): - # COUNTER = 0 - # for col in range(self.children.shape[1]): - # coldepth = np.max([node.branchdepth for node in self.children[:,col]]) - # maxColumns = 2**coldepth - # for COL in range(maxColumns): - # for row in range(self.children.shape[0]): - # COUNTER = self.children[row,col].countCell(COUNTER, COL, maxColumns) - sortCells = sorted(M.cells,key=SortByX0()) sortFaceX = sorted(M.faceX,key=SortByX0()) sortFaceY = sorted(M.faceY,key=SortByX0()) From 7d19f8cae47ec8277f0998fc880635bed4342956 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 15:25:01 -0800 Subject: [PATCH 05/42] Divergence Operator (structure) --- SimPEG/mesh/QuadTreeMesh.py | 68 ++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 5615f7a7..ec9ac3f3 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -49,8 +49,16 @@ class TreeFace(object): @property def isleaf(self): return self.children is None + @property + def index(self): + if self.isleaf: return np.r_[self.numFace] + return np.concatenate([face.index for face in self.children]) + + def refine(self): if not self.isleaf: return + self.mesh.isNumbered = False + self.children = np.empty(2,dtype=TreeFace) # Create refined x0's x0r_0 = self.x0 @@ -67,8 +75,8 @@ class TreeFace(object): def viz(self, ax): if not self.isleaf: return ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'rx-') - if self.faceType is 'y': - ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) + # if self.faceType is 'y': + ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) @@ -110,6 +118,7 @@ class TreeNode(object): def refine(self): if not self.isleaf: return + self.mesh.isNumbered = False self.children = np.empty((2,2),dtype=TreeNode) x0, sz = self.x0, self.sz @@ -142,6 +151,19 @@ class TreeNode(object): @property def isleaf(self): return self.children is None + @property + def faceIndex(self): + I, J, V = np.empty(0,dtype=float), np.empty(0,dtype=float), np.empty(0,dtype=float) + for face in self.faces: + j = self.faces[face].index + i = j*0+self.numCell + v = j*0+1 + if 'p' in face: + v *= -1 + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + return I, J, V + + def viz(self, ax): if self.isleaf: x0, sz = self.x0, self.sz @@ -166,7 +188,7 @@ class QuadTreeMesh(object): self.faceX = set() self.faceY = set() self.cells = set() - + self.isNumbered = False self.children = np.empty(cells,dtype=TreeNode) for i in range(cells[0]): for j in range(cells[1]): @@ -181,6 +203,7 @@ class QuadTreeMesh(object): def number(self): + if self.isNumbered: return sortCells = sorted(M.cells,key=SortByX0()) sortFaceX = sorted(M.faceX,key=SortByX0()) sortFaceY = sorted(M.faceY,key=SortByX0()) @@ -189,11 +212,23 @@ class QuadTreeMesh(object): for i, sfx in enumerate(sortFaceX): sfx.numFace = i for i, sfy in enumerate(sortFaceY): sfy.numFace = i + nFx - def viz(self): - ax = plt.subplot(111) + self.sortCells = sortCells + self.sortFaceX = sortFaceX + self.sortFaceY = sortFaceY + + self.isNumbered = True + + def viz(self, ax=None): + if ax is None: ax = plt.subplot(111) [node.viz(ax) for node in self.cells] [node.viz(ax) for node in self.faces] + @property + def nC(self): return len(self.cells) + @property + def nF(self): return len(self.faces) + + if __name__ == '__main__': M = QuadTreeMesh([3,2],[1,2]) @@ -204,10 +239,27 @@ if __name__ == '__main__': - M.number() - print M.children[0,0].faces['fXp'] is M.children[1,0].faces['fXm'] + + M.number() + M.sortCells[5].refine() + M.number() + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in M.cells: + i, j, v = cell.faceIndex + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + + print J + import scipy.sparse as sp + + DIV = sp.csr_matrix((V,(I,J)), shape=(M.nC, M.nF)) + plt.subplot(211) + plt.spy(DIV) + + # print M.sortCells[6].faces['fYm'].index + + # print M.children[0,0].faces['fXp'] is M.children[1,0].faces['fXm'] print len(M.faces) - M.viz() + M.viz(ax=plt.subplot(212)) # plt.gca().invert_yaxis() plt.show() From b29a4ed68cc7d76202e557900fec9e59896c2021 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 17:09:18 -0700 Subject: [PATCH 06/42] col area and correct divergence calculation. --- SimPEG/mesh/QuadTreeMesh.py | 57 +++++++++++++++++++++++-------------- SimPEG/utils/__init__.py | 1 + 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index ec9ac3f3..3d4450ff 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -1,4 +1,4 @@ -import numpy as np +from SimPEG import np, sp, utils import matplotlib.pyplot as plt @@ -54,6 +54,9 @@ class TreeFace(object): if self.isleaf: return np.r_[self.numFace] return np.concatenate([face.index for face in self.children]) + @property + def area(self): return self.sz + def refine(self): if not self.isleaf: return @@ -163,6 +166,9 @@ class TreeNode(object): I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] return I, J, V + @property + def vol(self): return self.sz.prod() + def viz(self, ax): if self.isleaf: @@ -188,7 +194,6 @@ class QuadTreeMesh(object): self.faceX = set() self.faceY = set() self.cells = set() - self.isNumbered = False self.children = np.empty(cells,dtype=TreeNode) for i in range(cells[0]): for j in range(cells[1]): @@ -196,6 +201,7 @@ class QuadTreeMesh(object): fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] self.children[i][j] = TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz, fXm=fXm, fYm=fYm) + isNumbered = utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @property def branchdepth(self): @@ -204,6 +210,7 @@ class QuadTreeMesh(object): def number(self): if self.isNumbered: return + sortCells = sorted(M.cells,key=SortByX0()) sortFaceX = sorted(M.faceX,key=SortByX0()) sortFaceY = sorted(M.faceY,key=SortByX0()) @@ -228,6 +235,31 @@ class QuadTreeMesh(object): @property def nF(self): return len(self.faces) + @property + def vol(self): + self.number() + return np.array([cell.vol for cell in self.sortCells]) + + @property + def area(self): + self.number() + return np.concatenate(([face.area for face in self.sortFaceX],[face.area for face in self.sortFaceY])) + + @property + def faceDiv(self): + if getattr(self, '_faceDiv', None) is None: + self.number() + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in M.cells: + i, j, v = cell.faceIndex + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + + VOL = self.vol + D = sp.csr_matrix((V,(I,J)), shape=(M.nC, M.nF)) + S = self.area + self._faceDiv = utils.sdiag(1/VOL)*D*utils.sdiag(S) + return self._faceDiv + if __name__ == '__main__': @@ -237,29 +269,10 @@ if __name__ == '__main__': # M.children[ii,ii].children[0,0].refine() - - - - - M.number() - M.sortCells[5].refine() - M.number() - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in M.cells: - i, j, v = cell.faceIndex - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - - print J - import scipy.sparse as sp - - DIV = sp.csr_matrix((V,(I,J)), shape=(M.nC, M.nF)) + DIV = M.faceDiv plt.subplot(211) plt.spy(DIV) - # print M.sortCells[6].faces['fYm'].index - - # print M.children[0,0].faces['fXp'] is M.children[1,0].faces['fXm'] - print len(M.faces) M.viz(ax=plt.subplot(212)) # plt.gca().invert_yaxis() plt.show() diff --git a/SimPEG/utils/__init__.py b/SimPEG/utils/__init__.py index 8d9b0504..32d2231f 100644 --- a/SimPEG/utils/__init__.py +++ b/SimPEG/utils/__init__.py @@ -127,6 +127,7 @@ def callHooks(match): def dependentProperty(name, value, children, doc): def fget(self): return getattr(self,name,value) def fset(self, val): + if getattr(self,name,value) == val: return # it is the same! for child in children: if hasattr(self, child): delattr(self, child) From a01b8057133644be8ae8f0a8e29a7a0a91d0be63 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 19 Dec 2013 18:30:29 -0700 Subject: [PATCH 07/42] Updates to visualization, gridCC, and refine functionality --- SimPEG/mesh/QuadTreeMesh.py | 106 ++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 3d4450ff..6fe6189d 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -75,11 +75,10 @@ class TreeFace(object): self.mesh.faceY.remove(self) - def viz(self, ax): + def viz(self, ax, text=True): if not self.isleaf: return - ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'rx-') - # if self.faceType is 'y': - ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) + ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'r-') + if text: ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) @@ -118,9 +117,16 @@ class TreeNode(object): else: return np.max([node.branchdepth for node in self.children.flatten('F')]) + @property + def gridCC(self): return self.x0 + 0.5*self.sz + + def refine(self, function=None): + if not self.isleaf and function is None: return + + if function is not None: + do = function(self.gridCC) > self.depth + if not do: return - def refine(self): - if not self.isleaf: return self.mesh.isNumbered = False self.children = np.empty((2,2),dtype=TreeNode) @@ -151,6 +157,11 @@ class TreeNode(object): self.mesh.cells.remove(self) + # pass the refine function to the children + if function is not None: + for child in self.children.flatten(): + child.refine(function) + @property def isleaf(self): return self.children is None @@ -170,7 +181,7 @@ class TreeNode(object): def vol(self): return self.sz.prod() - def viz(self, ax): + def viz(self, ax, text=True): if self.isleaf: x0, sz = self.x0, self.sz corners = np.c_[np.r_[x0[0] , x0[1] ], @@ -179,7 +190,7 @@ class TreeNode(object): np.r_[x0[0] , x0[1]+sz[1]], np.r_[x0[0] , x0[1] ]].T ax.plot(corners[:,0],corners[:,1], 'b') - if self.numCell is not None: + if self.numCell is not None and text: ax.text(x0[0]+sz[0]/2,x0[1]+sz[1]/2,'%d'%self.numCell) else: [node.viz(ax) for node in self.children.flatten('F')] @@ -189,17 +200,20 @@ class TreeNode(object): class QuadTreeMesh(object): """docstring for QuadTreeMesh""" - def __init__(self, cells, sz): + def __init__(self, h, x0=[0,0]): self.faces = set() self.faceX = set() self.faceY = set() self.cells = set() - self.children = np.empty(cells,dtype=TreeNode) - for i in range(cells[0]): - for j in range(cells[1]): + self.x0 = np.array(x0,dtype=float) + self.children = np.empty([hi.size for hi in h],dtype=TreeNode) + for i in range(h[0].size): + for j in range(h[1].size): fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] - self.children[i][j] = TreeNode(self, x0=[i*sz[0],j*sz[1]], dim=2, depth=0, sz=sz, fXm=fXm, fYm=fYm) + x0i = (np.r_[x0[0], h[0][:i]]).sum() + x0j = (np.r_[x0[1], h[1][:j]]).sum() + self.children[i][j] = TreeNode(self, x0=[x0i, x0j], dim=len(h), depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) isNumbered = utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @@ -207,50 +221,66 @@ class QuadTreeMesh(object): def branchdepth(self): return np.max([node.branchdepth for node in self.children.flatten('F')]) + def refine(self, function): + for node in self.children.flatten(): + node.refine(function) def number(self): if self.isNumbered: return - sortCells = sorted(M.cells,key=SortByX0()) - sortFaceX = sorted(M.faceX,key=SortByX0()) - sortFaceY = sorted(M.faceY,key=SortByX0()) - nFx = len(sortFaceX) - for i, sc in enumerate(sortCells): sc.numCell = i - for i, sfx in enumerate(sortFaceX): sfx.numFace = i - for i, sfy in enumerate(sortFaceY): sfy.numFace = i + nFx + sortedCells = sorted(M.cells,key=SortByX0()) + sortedFaceX = sorted(M.faceX,key=SortByX0()) + sortedFaceY = sorted(M.faceY,key=SortByX0()) + nFx = len(sortedFaceX) + for i, sc in enumerate(sortedCells): sc.numCell = i + for i, sfx in enumerate(sortedFaceX): sfx.numFace = i + for i, sfy in enumerate(sortedFaceY): sfy.numFace = i + nFx - self.sortCells = sortCells - self.sortFaceX = sortFaceX - self.sortFaceY = sortFaceY + self.sortedCells = sortedCells + self.sortedFaceX = sortedFaceX + self.sortedFaceY = sortedFaceY self.isNumbered = True - def viz(self, ax=None): + def viz(self, ax=None, text=True): if ax is None: ax = plt.subplot(111) - [node.viz(ax) for node in self.cells] - [node.viz(ax) for node in self.faces] + # [node.viz(ax, text=text) for node in self.cells] + [node.viz(ax, text=text) for node in self.faces] @property def nC(self): return len(self.cells) @property def nF(self): return len(self.faces) + @property + def nFx(self): return len(self.facesX) + @property + def nFy(self): return len(self.facesY) + + @property + def gridCC(self): + if getattr(self, '_gridCC', None) is None: + self.number() + self._gridCC = np.empty((self.nC,self.dim)) + for ii, cell in enumerate(self.sortedCells): + self._gridCC[ii,:] = cell.gridCC + return self._gridCC @property def vol(self): self.number() - return np.array([cell.vol for cell in self.sortCells]) + return np.array([cell.vol for cell in self.sortedCells]) @property def area(self): self.number() - return np.concatenate(([face.area for face in self.sortFaceX],[face.area for face in self.sortFaceY])) + return np.concatenate(([face.area for face in self.sortedFaceX],[face.area for face in self.sortedFaceY])) @property def faceDiv(self): if getattr(self, '_faceDiv', None) is None: self.number() I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in M.cells: + for cell in M.sortedCells: i, j, v = cell.faceIndex I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] @@ -263,16 +293,24 @@ class QuadTreeMesh(object): if __name__ == '__main__': - M = QuadTreeMesh([3,2],[1,2]) - for ii in range(1): - M.children[ii,ii].refine() - # M.children[ii,ii].children[0,0].refine() + M = QuadTreeMesh([np.ones(x) for x in [4,10]]) + def function(xc): + r = xc - np.r_[2.,6.] + dist = np.sqrt(r.dot(r)) + if dist < 1.0: + return 3 + if dist < 1.5: + return 2 + else: + return 1 + + M.refine(function) DIV = M.faceDiv plt.subplot(211) plt.spy(DIV) - M.viz(ax=plt.subplot(212)) + M.viz(ax=plt.subplot(212),text=False) # plt.gca().invert_yaxis() plt.show() From e2b345ae8925b489e2b99acdff07db69c31c839c Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 20 Dec 2013 11:44:20 -0700 Subject: [PATCH 08/42] Visualization. --- SimPEG/mesh/QuadTreeMesh.py | 66 ++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/mesh/QuadTreeMesh.py index 6fe6189d..1ac0f5eb 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/mesh/QuadTreeMesh.py @@ -1,5 +1,7 @@ from SimPEG import np, sp, utils import matplotlib.pyplot as plt +import matplotlib.colors as colors +import matplotlib.cm as cmx @@ -33,7 +35,7 @@ class TreeFace(object): self.mesh = mesh self.children = None self.numFace = None - self.x0 = np.array(x0,dtype=float) + self.x0 = np.array(x0, dtype=float) self.faceType = faceType self.sz = sz self.dim = dim @@ -95,9 +97,9 @@ class TreeNode(object): self.mesh = mesh self.x0 = np.array(x0, dtype=float) + self.sz = np.array(sz, dtype=float) self.dim = dim self.depth = depth - self.sz = np.array(sz, dtype=float) self.parent = parent self.children = None self.numCell = None @@ -181,19 +183,11 @@ class TreeNode(object): def vol(self): return self.sz.prod() - def viz(self, ax, text=True): - if self.isleaf: - x0, sz = self.x0, self.sz - corners = np.c_[np.r_[x0[0] , x0[1] ], - np.r_[x0[0]+sz[0], x0[1] ], - np.r_[x0[0]+sz[0], x0[1]+sz[1]], - np.r_[x0[0] , x0[1]+sz[1]], - np.r_[x0[0] , x0[1] ]].T - ax.plot(corners[:,0],corners[:,1], 'b') - if self.numCell is not None and text: - ax.text(x0[0]+sz[0]/2,x0[1]+sz[1]/2,'%d'%self.numCell) - else: - [node.viz(ax) for node in self.children.flatten('F')] + def viz(self, ax, color='none', text=False): + if not self.isleaf: return + x0, sz = self.x0, self.sz + ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=color, edgecolor='k')) + if text: ax.text(self.gridCC[0],self.gridCC[1],self.numCell) @@ -206,6 +200,7 @@ class QuadTreeMesh(object): self.faceY = set() self.cells = set() self.x0 = np.array(x0,dtype=float) + self.h = h self.children = np.empty([hi.size for hi in h],dtype=TreeNode) for i in range(h[0].size): for j in range(h[1].size): @@ -242,11 +237,9 @@ class QuadTreeMesh(object): self.isNumbered = True - def viz(self, ax=None, text=True): - if ax is None: ax = plt.subplot(111) - # [node.viz(ax, text=text) for node in self.cells] - [node.viz(ax, text=text) for node in self.faces] + @property + def dim(self): return len(self.x0) @property def nC(self): return len(self.cells) @property @@ -291,6 +284,28 @@ class QuadTreeMesh(object): return self._faceDiv + def plotGrid(self, ax=None, text=True, plotC=True, plotF=False): + if ax is None: ax = plt.subplot(111) + + if plotC: [node.viz(ax, text=text) for node in self.cells] + if plotF: [node.viz(ax, text=text) for node in self.faces] + ax.set_xlim((self.x0[0], self.h[0].sum())) + ax.set_ylim((self.x0[1], self.h[1].sum())) + + + def plotImage(self, I, ax=None): + if ax is None: ax = plt.subplot(111) + jet = cm = plt.get_cmap('jet') + cNorm = colors.Normalize(vmin=I.min(), vmax=I.max()) + 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): + node.viz(ax=ax, color=scalarMap.to_rgba(I[ii])) + scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots + plt.colorbar(scalarMap) + + if __name__ == '__main__': M = QuadTreeMesh([np.ones(x) for x in [4,10]]) @@ -308,9 +323,16 @@ if __name__ == '__main__': M.refine(function) DIV = M.faceDiv - plt.subplot(211) - plt.spy(DIV) + # plt.subplot(211) + # plt.spy(DIV) + M.plotGrid(ax=plt.subplot(111),text=True) - M.viz(ax=plt.subplot(212),text=False) + q = np.zeros(M.nC) + q[208] = -1.0 + q[291] = 1.0 + b = utils.Solver(-DIV*DIV.T).solve(q) + plt.figure() + M.plotImage(b) # plt.gca().invert_yaxis() + print M.vol plt.show() From 2f52e15e41eeb0e7cd4d907b182ac49cae43458b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 16:28:03 -0800 Subject: [PATCH 09/42] Grid updates for TreeMesh, initial generalizations for OcTree --- .../QuadTreeMesh.py => Mesh/TreeMesh.py} | 181 +++++++++++++----- SimPEG/Mesh/__init__.py | 2 +- SimPEG/tests/test_QuadTree.py | 32 +++- 3 files changed, 159 insertions(+), 56 deletions(-) rename SimPEG/{mesh/QuadTreeMesh.py => Mesh/TreeMesh.py} (62%) diff --git a/SimPEG/mesh/QuadTreeMesh.py b/SimPEG/Mesh/TreeMesh.py similarity index 62% rename from SimPEG/mesh/QuadTreeMesh.py rename to SimPEG/Mesh/TreeMesh.py index 1ac0f5eb..34519225 100644 --- a/SimPEG/mesh/QuadTreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1,4 +1,4 @@ -from SimPEG import np, sp, utils +from SimPEG import np, sp, Utils, Solver import matplotlib.pyplot as plt import matplotlib.colors as colors import matplotlib.cm as cmx @@ -35,14 +35,16 @@ class TreeFace(object): self.mesh = mesh self.children = None self.numFace = None + self.x0 = np.array(x0, dtype=float) self.faceType = faceType - self.sz = sz + self.sz = np.array(sz, dtype=float) self.dim = dim self.depth = depth mesh.faces.add(self) - if faceType is 'x': self.mesh.faceX.add(self) - elif faceType is 'y': self.mesh.faceY.add(self) + if faceType is 'x': self.mesh.facesX.add(self) + elif faceType is 'y': self.mesh.facesY.add(self) + elif faceType is 'z': self.mesh.facesZ.add(self) self.tangent = np.zeros(dim) self.tangent[1 if faceType is 'x' else 0] = 1 self.normal = np.zeros(dim) @@ -53,12 +55,15 @@ class TreeFace(object): @property def index(self): + if not self.mesh.isNumbered: raise Exception('Mesh is not numbered.') if self.isleaf: return np.r_[self.numFace] return np.concatenate([face.index for face in self.children]) - @property - def area(self): return self.sz + @property + def area(self): + """area of the face""" + return self.sz.prod() def refine(self): if not self.isleaf: return @@ -68,32 +73,30 @@ class TreeFace(object): # Create refined x0's x0r_0 = self.x0 x0r_1 = self.x0+0.5*self.tangent*self.sz - self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1,parent=self) - self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1,parent=self) + self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1, parent=self) self.mesh.faces.remove(self) if self.faceType is 'x': - self.mesh.faceX.remove(self) + self.mesh.facesX.remove(self) elif self.faceType is 'y': - self.mesh.faceY.remove(self) - + self.mesh.facesY.remove(self) def viz(self, ax, text=True): if not self.isleaf: return ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'r-') if text: ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) + @property + def center(self): + return self.x0 + 0.5*self.tangent*self.sz class TreeNode(object): """docstring for TreeNode""" - def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None, fXm=None, fXp=None, fYm=None, fYp=None): + children = None #: + numCell = None - fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) - fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=sz[1], depth=depth, parent=parent) - fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) - fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=sz[0], depth=depth, parent=parent) - - self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} + def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None, fXm=None, fXp=None, fYm=None, fYp=None, fZm=None, fZp=None): self.mesh = mesh self.x0 = np.array(x0, dtype=float) @@ -101,8 +104,22 @@ class TreeNode(object): self.dim = dim self.depth = depth self.parent = parent - self.children = None - self.numCell = None + if dim == 2: + fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=np.r_[sz[1]], depth=depth, parent=parent) + fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=np.r_[sz[1]], depth=depth, parent=parent) + fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=np.r_[sz[0]], depth=depth, parent=parent) + fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=np.r_[sz[0]], depth=depth, parent=parent) + self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} + + elif dim == 3: + fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', dim=dim, sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) + fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', dim=dim, sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) + fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', dim=dim, sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) + fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', dim=dim, sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) + fZm = fZm if fZm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', dim=dim, sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) + fZp = fZp if fZp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', dim=dim, sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) + self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} + mesh.cells.add(self) @property @@ -120,13 +137,17 @@ class TreeNode(object): return np.max([node.branchdepth for node in self.children.flatten('F')]) @property - def gridCC(self): return self.x0 + 0.5*self.sz + def center(self): return self.x0 + 0.5*self.sz def refine(self, function=None): + if self.dim == 2: + return self._refine2D(function=function) + + def _refine2D(self, function=None): if not self.isleaf and function is None: return if function is not None: - do = function(self.gridCC) > self.depth + do = function(self.center) > self.depth if not do: return self.mesh.isNumbered = False @@ -187,20 +208,32 @@ class TreeNode(object): if not self.isleaf: return x0, sz = self.x0, self.sz ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=color, edgecolor='k')) - if text: ax.text(self.gridCC[0],self.gridCC[1],self.numCell) + if text: ax.text(self.center[0],self.center[1],self.numCell) -class QuadTreeMesh(object): - """docstring for QuadTreeMesh""" - def __init__(self, h, x0=[0,0]): - self.faces = set() - self.faceX = set() - self.faceY = set() - self.cells = set() - self.x0 = np.array(x0,dtype=float) +class TreeMesh(object): + """TreeMesh""" + def __init__(self, h, x0=None): + + assert type(h) is list, 'h must be a list' + self.h = h + if x0 is None: + x0 = np.zeros(self.dim) + else: + assert type(x0) in [list, np.ndarray], 'x0 must be a numpy array or a list' + assert len(x0) == self.dim, 'x0 must have the same dimensions as the mesh' + self.x0 = np.array(x0, dtype=float) + + # set the sets for holding the faces and cells + self.cells = set() + self.faces = set() + self.facesX = set() + self.facesY = set() + if self.dim == 3: self.facesZ = set() + self.children = np.empty([hi.size for hi in h],dtype=TreeNode) for i in range(h[0].size): for j in range(h[1].size): @@ -210,7 +243,7 @@ class QuadTreeMesh(object): x0j = (np.r_[x0[1], h[1][:j]]).sum() self.children[i][j] = TreeNode(self, x0=[x0i, x0j], dim=len(h), depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) - isNumbered = utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') + isNumbered = Utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @property def branchdepth(self): @@ -223,41 +256,81 @@ class QuadTreeMesh(object): def number(self): if self.isNumbered: return - sortedCells = sorted(M.cells,key=SortByX0()) - sortedFaceX = sorted(M.faceX,key=SortByX0()) - sortedFaceY = sorted(M.faceY,key=SortByX0()) - nFx = len(sortedFaceX) - for i, sc in enumerate(sortedCells): sc.numCell = i - for i, sfx in enumerate(sortedFaceX): sfx.numFace = i - for i, sfy in enumerate(sortedFaceY): sfy.numFace = i + nFx + self.sortedCells = sorted(self.cells,key=SortByX0()) + for i, sc in enumerate(self.sortedCells): sc.numCell = i - self.sortedCells = sortedCells - self.sortedFaceX = sortedFaceX - self.sortedFaceY = sortedFaceY + self.sortedFaceX = sorted(self.facesX,key=SortByX0()) + for i, sfx in enumerate(self.sortedFaceX): sfx.numFace = i + + self.sortedFaceY = sorted(self.facesY,key=SortByX0()) + for i, sfy in enumerate(self.sortedFaceY): sfy.numFace = i + self.nFx + + if self.dim == 3: + self.sortedFaceZ = sorted(self.facesZ,key=SortByX0()) + for i, sfz in enumerate(self.sortedFaceZ): sfz.numFace = i + self.nFx + self.nFy self.isNumbered = True + @property + def dim(self): return len(self.h) - @property - def dim(self): return len(self.x0) @property def nC(self): return len(self.cells) + @property def nF(self): return len(self.faces) + @property def nFx(self): return len(self.facesX) + @property def nFy(self): return len(self.facesY) + @property + def nFz(self): return len(self.facesZ) + + @property + def nE(self): return len(self.faces) + + @property + def nEx(self): + if self.dim == 2: + return len(self.facesY) + else: raise NotImplementedError('nEx') + + @property + def nEy(self): + if self.dim == 2: + return len(self.facesX) + else: raise NotImplementedError('nEy') + @property def gridCC(self): if getattr(self, '_gridCC', None) is None: self.number() self._gridCC = np.empty((self.nC,self.dim)) for ii, cell in enumerate(self.sortedCells): - self._gridCC[ii,:] = cell.gridCC + self._gridCC[ii,:] = cell.center return self._gridCC + @property + def gridFx(self): + if getattr(self, '_gridFx', None) is None: + self.number() + self._gridFx = np.empty((self.nFx,self.dim)) + for ii, face in enumerate(self.sortedFaceX): + self._gridFx[ii,:] = face.center + return self._gridFx + + @property + def gridFy(self): + if getattr(self, '_gridFy', None) is None: + self.number() + self._gridFy = np.empty((self.nFy,self.dim)) + for ii, face in enumerate(self.sortedFaceY): + self._gridFy[ii,:] = face.center + return self._gridFy + @property def vol(self): self.number() @@ -280,20 +353,27 @@ class QuadTreeMesh(object): VOL = self.vol D = sp.csr_matrix((V,(I,J)), shape=(M.nC, M.nF)) S = self.area - self._faceDiv = utils.sdiag(1/VOL)*D*utils.sdiag(S) + self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv - def plotGrid(self, ax=None, text=True, plotC=True, plotF=False): + def plotGrid(self, ax=None, text=True, plotC=True, plotF=False, showIt=False): if ax is None: ax = plt.subplot(111) if plotC: [node.viz(ax, text=text) for node in self.cells] if plotF: [node.viz(ax, text=text) for node in self.faces] ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) + if showIt: plt.show() - def plotImage(self, I, ax=None): + def plotImage(self, I, ax=None, showIt=True): + if self.dim == 2: + self._plotImage2D(I, ax=ax, showIt=showIt) + elif self.dim == 3: + raise NotImplementedError('3D visualization is not yet implemented.') + + def _plotImage2D(self, I, ax=None, showIt=True): if ax is None: ax = plt.subplot(111) jet = cm = plt.get_cmap('jet') cNorm = colors.Normalize(vmin=I.min(), vmax=I.max()) @@ -304,11 +384,12 @@ class QuadTreeMesh(object): node.viz(ax=ax, color=scalarMap.to_rgba(I[ii])) scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots plt.colorbar(scalarMap) + if showIt: plt.show() if __name__ == '__main__': - M = QuadTreeMesh([np.ones(x) for x in [4,10]]) + M = TreeMesh([np.ones(x) for x in [4,10]]) def function(xc): r = xc - np.r_[2.,6.] @@ -330,7 +411,7 @@ if __name__ == '__main__': q = np.zeros(M.nC) q[208] = -1.0 q[291] = 1.0 - b = utils.Solver(-DIV*DIV.T).solve(q) + b = Solver(-DIV*DIV.T).solve(q) plt.figure() M.plotImage(b) # plt.gca().invert_yaxis() diff --git a/SimPEG/Mesh/__init__.py b/SimPEG/Mesh/__init__.py index 66ee88c8..3da22a01 100644 --- a/SimPEG/Mesh/__init__.py +++ b/SimPEG/Mesh/__init__.py @@ -1,6 +1,6 @@ from Cyl1DMesh import Cyl1DMesh from TensorMesh import TensorMesh -from QuadTreeMesh import QuadTreeMesh +from TreeMesh import TreeMesh from LogicallyOrthogonalMesh import LogicallyOrthogonalMesh from BaseMesh import BaseMesh from TensorView import TensorView diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index c085c7ae..2fef3fdd 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -1,19 +1,41 @@ -from SimPEG import mesh, np +from SimPEG import Mesh, np import unittest -class TestCheckDerivative(unittest.TestCase): +class TestQuadTreeMesh(unittest.TestCase): def setUp(self): - M = mesh.QuadTreeMesh([3,2],[1,2]) + M = Mesh.TreeMesh([np.ones(x) for x in [3,2]]) for ii in range(1): M.children[ii,ii].refine() self.M = M + M.number() + # M.plotGrid(showIt=True) def test_MeshSizes(self): - self.assertTrue(len(self.M.faces)==25) - self.assertTrue(len(self.M.cells)==9) + self.assertTrue(self.M.nC==9) + self.assertTrue(self.M.nF==25) + self.assertTrue(self.M.nFx==12) + self.assertTrue(self.M.nFy==13) + self.assertTrue(self.M.nE==25) + self.assertTrue(self.M.nEx==13) + self.assertTrue(self.M.nEy==12) + + def test_gridCC(self): + x = np.r_[0.25,0.75,1.5,2.5,0.25,0.75,0.5,1.5,2.5] + y = np.r_[0.25,0.25,0.5,0.5,0.75,0.75,1.5,1.5,1.5] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridCC).flatten()) == 0) + + def test_gridFx(self): + x = np.r_[0.0,0.5,1.0,2.0,3.0,0.0,0.5,1.0,0.0,1.0,2.0,3.0] + y = np.r_[0.25,0.25,0.25,0.5,0.5,0.75,0.75,0.75,1.5,1.5,1.5,1.5] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridFx).flatten()) == 0) + + def test_gridFy(self): + x = np.r_[0.25,0.75,1.5,2.5,0.25,0.75,0.25,0.75,1.5,2.5,0.5,1.5,2.5] + y = np.r_[0,0,0,0,0.5,0.5,1,1,1,1,2,2,2] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridFy).flatten()) == 0) From b39525c6653e4ac081d5bd13f4cdf181c35e32d8 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 13:32:12 -0800 Subject: [PATCH 10/42] pointer testing and nodes! --- SimPEG/Mesh/TreeMesh.py | 241 ++++++++++++++++++++++++---------- SimPEG/tests/test_QuadTree.py | 93 ++++++++++++- 2 files changed, 261 insertions(+), 73 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 34519225..a8ce9ec5 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -29,37 +29,75 @@ def SortByX0(): return K -class TreeFace(object): - """docstring for TreeFace""" - def __init__(self, mesh, x0=[0,0], faceType=None, dim=2, sz=1, depth=0, parent=None): - self.mesh = mesh - self.children = None - self.numFace = None +class TreeObject(object): + """docstring for TreeObject""" - self.x0 = np.array(x0, dtype=float) - self.faceType = faceType - self.sz = np.array(sz, dtype=float) - self.dim = dim - self.depth = depth - mesh.faces.add(self) - if faceType is 'x': self.mesh.facesX.add(self) - elif faceType is 'y': self.mesh.facesY.add(self) - elif faceType is 'z': self.mesh.facesZ.add(self) - self.tangent = np.zeros(dim) - self.tangent[1 if faceType is 'x' else 0] = 1 - self.normal = np.zeros(dim) - self.normal[0 if faceType is 'x' else 1] = 1 + children = None #: children of the tree object + num = None + + def __init__(self, mesh, parent): + self.mesh = mesh + self._parent = parent + + @property + def parent(self): return self._parent + + @property + def dim(self): return self.mesh.dim @property def isleaf(self): return self.children is None + @property + def center(self): return self.x0 + + +class TreeNode(TreeObject): + """docstring for TreeNode""" + def __init__(self, mesh, x0=[0,0], depth=0, parent=None): + TreeObject.__init__(self, mesh, parent) + self.x0 = x0 + self.mesh.nodes.add(self) + + + +class TreeFace(TreeObject): + """docstring for TreeFace""" + def __init__(self, mesh, x0=[0,0], faceType=None, sz=[1,], depth=0, + node0=None, node1=None, node2=None, node3=None, + parent=None): + TreeObject.__init__(self, mesh, parent) + + self.x0 = np.array(x0, dtype=float) + self.faceType = faceType + self.sz = np.array(sz, dtype=float) + self.depth = depth + mesh.faces.add(self) + if faceType is 'x': self.mesh.facesX.add(self) + elif faceType is 'y': self.mesh.facesY.add(self) + elif faceType is 'z': self.mesh.facesZ.add(self) + # Add the nodes: + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent*self.sz) + + @property + def tangent(self): + t = np.zeros(self.dim) + t[1 if self.faceType is 'x' else 0] = 1 + return t + + @property + def normal(self): + if self.faceType is 'x': return np.r_[1.,0,0] + elif self.faceType is 'y': return np.r_[0,1.,0] + elif self.faceType is 'z': return np.r_[0,0,1.] + @property def index(self): if not self.mesh.isNumbered: raise Exception('Mesh is not numbered.') - if self.isleaf: return np.r_[self.numFace] + if self.isleaf: return np.r_[self.num] return np.concatenate([face.index for face in self.children]) - @property def area(self): """area of the face""" @@ -73,8 +111,8 @@ class TreeFace(object): # Create refined x0's x0r_0 = self.x0 x0r_1 = self.x0+0.5*self.tangent*self.sz - self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1, parent=self) - self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, dim=self.dim, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) + self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.children[0].node1, node1=self.node1) self.mesh.faces.remove(self) if self.faceType is 'x': self.mesh.facesX.remove(self) @@ -84,51 +122,64 @@ class TreeFace(object): def viz(self, ax, text=True): if not self.isleaf: return ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'r-') - if text: ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.numFace) + if text: ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.num) @property def center(self): return self.x0 + 0.5*self.tangent*self.sz -class TreeNode(object): - """docstring for TreeNode""" +class TreeCell(TreeObject): + """docstring for TreeCell""" children = None #: - numCell = None - def __init__(self, mesh, x0=[0,0], dim=2, depth=0, sz=[1,1], parent=None, fXm=None, fXp=None, fYm=None, fYp=None, fZm=None, fZp=None): + def __init__(self, mesh, x0=[0,0], depth=0, sz=[1,1], + fXm=None, fXp=None, + fYm=None, fYp=None, + fZm=None, fZp=None, + parent=None): + TreeObject.__init__(self, mesh, parent) - self.mesh = mesh self.x0 = np.array(x0, dtype=float) self.sz = np.array(sz, dtype=float) - self.dim = dim self.depth = depth - self.parent = parent - if dim == 2: - fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', dim=dim, sz=np.r_[sz[1]], depth=depth, parent=parent) - fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', dim=dim, sz=np.r_[sz[1]], depth=depth, parent=parent) - fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', dim=dim, sz=np.r_[sz[0]], depth=depth, parent=parent) - fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', dim=dim, sz=np.r_[sz[0]], depth=depth, parent=parent) + if self.dim == 2: + # + # 2___________3 + # | fYp | + # | | + # fXm| x |fXp y + # | | ^ + # |___________| |___> x + # 0 fYm 1 + # + self.nodes = {} + + self.nodes["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) + self.nodes["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) + self.nodes["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) + self.nodes["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=self.nodes['n0'], node1=self.nodes['n2']) + self.nodes["n0"], self.nodes["n2"] = fXm.node0, fXm.node1 + fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=self.nodes['n1'], node1=self.nodes['n3']) + self.nodes["n1"], self.nodes["n3"] = fXp.node0, fXp.node1 + fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=self.nodes['n0'], node1=self.nodes['n1']) + self.nodes["n0"], self.nodes["n1"] = fYm.node0, fYm.node1 + fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=self.nodes['n2'], node1=self.nodes['n3']) + self.nodes["n2"], self.nodes["n3"] = fYp.node0, fYp.node1 self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} - elif dim == 3: - fXm = fXm if fXm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', dim=dim, sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) - fXp = fXp if fXp is not None else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', dim=dim, sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) - fYm = fYm if fYm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', dim=dim, sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) - fYp = fYp if fYp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', dim=dim, sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) - fZm = fZm if fZm is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', dim=dim, sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) - fZp = fZp if fZp is not None else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', dim=dim, sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) + elif self.dim == 3: + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) + fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) + fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) + fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) + fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) + fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} mesh.cells.add(self) - @property - def parent(self): - return self._parent - @parent.setter - def parent(self, value): - self._parent = value - @property def branchdepth(self): if self.isleaf: @@ -152,7 +203,7 @@ class TreeNode(object): self.mesh.isNumbered = False - self.children = np.empty((2,2),dtype=TreeNode) + self.children = np.empty((2,2),dtype=TreeCell) x0, sz = self.x0, self.sz for faceName in self.faces: @@ -161,22 +212,22 @@ class TreeNode(object): i, j = 0, 0 x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] fXm, fXp, fYm, fYp = self.faces['fXm'].children[0], None, self.faces['fYm'].children[0], None - self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) i, j = 1, 0 x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] fXm, fXp, fYm, fYp = self.children[0,0].faces['fXp'], self.faces['fXp'].children[0], self.faces['fYm'].children[1], None - self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) i, j = 0, 1 x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] fXm, fXp, fYm, fYp = self.faces['fXm'].children[1], None, self.children[0,0].faces['fYp'], self.faces['fYp'].children[0] - self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) i, j = 1, 1 x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] fXm, fXp, fYm, fYp = self.children[0,1].faces['fXp'], self.faces['fXp'].children[1], self.children[1,0].faces['fYp'], self.faces['fYp'].children[1] - self.children[i,j] = TreeNode(self.mesh, x0=x0r,dim=self.dim, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) self.mesh.cells.remove(self) @@ -185,15 +236,12 @@ class TreeNode(object): for child in self.children.flatten(): child.refine(function) - @property - def isleaf(self): return self.children is None - @property def faceIndex(self): I, J, V = np.empty(0,dtype=float), np.empty(0,dtype=float), np.empty(0,dtype=float) for face in self.faces: j = self.faces[face].index - i = j*0+self.numCell + i = j*0+self.num v = j*0+1 if 'p' in face: v *= -1 @@ -208,18 +256,24 @@ class TreeNode(object): if not self.isleaf: return x0, sz = self.x0, self.sz ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=color, edgecolor='k')) - if text: ax.text(self.center[0],self.center[1],self.numCell) - + if text: ax.text(self.center[0],self.center[1],self.num) class TreeMesh(object): """TreeMesh""" - def __init__(self, h, x0=None): - - assert type(h) is list, 'h must be a list' - + def __init__(self, h_in, x0=None): + assert type(h_in) is list, 'h_in must be a list' + h = range(len(h_in)) + for i, h_i in enumerate(h_in): + if type(h_i) in [int, long, float]: + # This gives you something over the unit cube. + h_i = np.ones(int(h_i))/int(h_i) + assert type(h_i) == np.ndarray, ("h[%i] is not a numpy array." % i) + assert len(h_i.shape) == 1, ("h[%i] must be a 1D numpy array." % i) + h[i] = h_i[:] # make a copy. self.h = h + if x0 is None: x0 = np.zeros(self.dim) else: @@ -229,19 +283,24 @@ class TreeMesh(object): # set the sets for holding the faces and cells self.cells = set() + self.nodes = set() self.faces = set() self.facesX = set() self.facesY = set() if self.dim == 3: self.facesZ = set() + self.edges = set() + self.edgesX = set() + self.edgesY = set() + if self.dim == 3: self.edgesZ = set() - self.children = np.empty([hi.size for hi in h],dtype=TreeNode) + self.children = np.empty([hi.size for hi in h],dtype=TreeCell) for i in range(h[0].size): for j in range(h[1].size): fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] x0i = (np.r_[x0[0], h[0][:i]]).sum() x0j = (np.r_[x0[1], h[1][:j]]).sum() - self.children[i][j] = TreeNode(self, x0=[x0i, x0j], dim=len(h), depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) + self.children[i][j] = TreeCell(self, x0=[x0i, x0j], depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) isNumbered = Utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @@ -257,17 +316,20 @@ class TreeMesh(object): if self.isNumbered: return self.sortedCells = sorted(self.cells,key=SortByX0()) - for i, sc in enumerate(self.sortedCells): sc.numCell = i + for i, sc in enumerate(self.sortedCells): sc.num = i + + self.sortedNodes = sorted(self.nodes,key=SortByX0()) + for i, sn in enumerate(self.sortedNodes): sn.num = i self.sortedFaceX = sorted(self.facesX,key=SortByX0()) - for i, sfx in enumerate(self.sortedFaceX): sfx.numFace = i + for i, sfx in enumerate(self.sortedFaceX): sfx.num = i self.sortedFaceY = sorted(self.facesY,key=SortByX0()) - for i, sfy in enumerate(self.sortedFaceY): sfy.numFace = i + self.nFx + for i, sfy in enumerate(self.sortedFaceY): sfy.num = i + self.nFx if self.dim == 3: self.sortedFaceZ = sorted(self.facesZ,key=SortByX0()) - for i, sfz in enumerate(self.sortedFaceZ): sfz.numFace = i + self.nFx + self.nFy + for i, sfz in enumerate(self.sortedFaceZ): sfz.num = i + self.nFx + self.nFy self.isNumbered = True @@ -277,6 +339,9 @@ class TreeMesh(object): @property def nC(self): return len(self.cells) + @property + def nN(self): return len(self.nodes) + @property def nF(self): return len(self.faces) @@ -313,6 +378,15 @@ class TreeMesh(object): self._gridCC[ii,:] = cell.center return self._gridCC + @property + def gridN(self): + if getattr(self, '_gridN', None) is None: + self.number() + self._gridN = np.empty((self.nN,self.dim)) + for ii, node in enumerate(self.sortedNodes): + self._gridN[ii,:] = node.center + return self._gridN + @property def gridFx(self): if getattr(self, '_gridFx', None) is None: @@ -331,6 +405,31 @@ class TreeMesh(object): self._gridFy[ii,:] = face.center return self._gridFy + @property + def gridFz(self): + if self.dim == 2: return None + if getattr(self, '_gridFz', None) is None: + self.number() + self._gridFz = np.emptz((self.nFz,self.dim)) + for ii, face in enumerate(self.sortedFaceZ): + self._gridFz[ii,:] = face.center + return self._gridFz + + @property + def gridEx(self): + if self.dim == 2: return self.gridFy + else: raise NotImplementedError('Edge Grid not yet implemented') + + @property + def gridEy(self): + if self.dim == 2: return self.gridFx + else: raise NotImplementedError('Edge Grid not yet implemented') + + @property + def gridEz(self): + if self.dim == 2: return None + else: raise NotImplementedError('Edge Grid not yet implemented') + @property def vol(self): self.number() diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index 2fef3fdd..92c3dd71 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -1,12 +1,86 @@ -from SimPEG import Mesh, np +from SimPEG.Mesh.TreeMesh import TreeMesh, TreeFace, TreeCell +import numpy as np import unittest +class TestQuadTreeObjects(unittest.TestCase): + + def setUp(self): + self.M = TreeMesh([2,1]) + self.Mr = TreeMesh([2,1]) + self.Mr.children[0,0].refine() + self.Mr.number() + # self.Mr.plotGrid(showIt=True) + + def test_pointersM(self): + c0 = self.M.children[0,0] + c0fXm = c0.faces['fXm'] + c0fXp = c0.faces['fXp'] + c0fYm = c0.faces['fYm'] + c0fYp = c0.faces['fYp'] + + c1 = self.M.children[1,0] + c1fXm = c1.faces['fXm'] + c1fXp = c1.faces['fXp'] + c1fYm = c1.faces['fYm'] + c1fYp = c1.faces['fYp'] + + self.assertTrue(c0fXp is c1fXm) + self.assertTrue(c0fYp is not c1fYm) + self.assertTrue(c0fXm is not c1fXm) + + self.assertTrue(c0fXm.area == 1) + self.assertTrue(c0fYm.area == 0.5) + + self.assertTrue(c0.nodes['n1'] is c1.nodes['n0']) + self.assertTrue(c0.nodes['n3'] is c1.nodes['n2']) + self.assertTrue(self.M.nN == 6) + + + def test_pointersMr(self): + c0 = self.Mr.sortedCells[0] + c0fXm = c0.faces['fXm'] + c0fXp = c0.faces['fXp'] + c0fYm = c0.faces['fYm'] + c0fYp = c0.faces['fYp'] + + c1 = self.Mr.sortedCells[1] + c1fXm = c1.faces['fXm'] + c1fXp = c1.faces['fXp'] + c1fYm = c1.faces['fYm'] + c1fYp = c1.faces['fYp'] + + c2 = self.Mr.sortedCells[2] + c2fXm = c2.faces['fXm'] + c2fXp = c2.faces['fXp'] + c2fYm = c2.faces['fYm'] + c2fYp = c2.faces['fYp'] + + c4 = self.Mr.sortedCells[4] + c4fXm = c4.faces['fXm'] + c4fXp = c4.faces['fXp'] + c4fYm = c4.faces['fYm'] + c4fYp = c4.faces['fYp'] + + self.assertTrue(c0fXp is c1fXm) + self.assertTrue(c1fXp.parent is c2fXm) + self.assertTrue(c1fXp.node0 is c2fXm.node0) + self.assertTrue(c1fXp.node0 is c2fXm.node0) + self.assertTrue(c4fYm is c1fYp) + self.assertTrue(c4fXp.parent is c2fXm) + self.assertTrue(c4fXp.node1 is c2fXm.node1) + self.assertTrue(c4fXp.node0 is c1fYp.node1) + self.assertTrue(c0fXp.node1 is c4fYm.node0) + + self.assertTrue(self.Mr.nN == 11) + + self.assertTrue(np.all(c1fXp.node0.x0 == np.r_[0.5,0])) + self.assertTrue(np.all(c1fYp.node0.x0 == np.r_[0.25,0.5])) class TestQuadTreeMesh(unittest.TestCase): def setUp(self): - M = Mesh.TreeMesh([np.ones(x) for x in [3,2]]) + M = TreeMesh([np.ones(x) for x in [3,2]]) for ii in range(1): M.children[ii,ii].refine() self.M = M @@ -27,6 +101,11 @@ class TestQuadTreeMesh(unittest.TestCase): y = np.r_[0.25,0.25,0.5,0.5,0.75,0.75,1.5,1.5,1.5] self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridCC).flatten()) == 0) + def test_gridN(self): + x = np.r_[0,0.5,1,2,3,0,0.5,1,0,0.5,1,2,3,0,1,2,3] + y = np.r_[0,0,0,0,0,.5,.5,.5,1,1,1,1,1,2,2,2,2] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridN).flatten()) == 0) + def test_gridFx(self): x = np.r_[0.0,0.5,1.0,2.0,3.0,0.0,0.5,1.0,0.0,1.0,2.0,3.0] y = np.r_[0.25,0.25,0.25,0.5,0.5,0.75,0.75,0.75,1.5,1.5,1.5,1.5] @@ -37,6 +116,16 @@ class TestQuadTreeMesh(unittest.TestCase): y = np.r_[0,0,0,0,0.5,0.5,1,1,1,1,2,2,2] self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridFy).flatten()) == 0) + def test_gridEx(self): + x = np.r_[0.25,0.75,1.5,2.5,0.25,0.75,0.25,0.75,1.5,2.5,0.5,1.5,2.5] + y = np.r_[0,0,0,0,0.5,0.5,1,1,1,1,2,2,2] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridEx).flatten()) == 0) + + def test_gridEy(self): + x = np.r_[0.0,0.5,1.0,2.0,3.0,0.0,0.5,1.0,0.0,1.0,2.0,3.0] + y = np.r_[0.25,0.25,0.25,0.5,0.5,0.75,0.75,0.75,1.5,1.5,1.5,1.5] + self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridEy).flatten()) == 0) + if __name__ == '__main__': From d347600bb768c0668b9624404872a2a180a33d6a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 14:42:55 -0800 Subject: [PATCH 11/42] refactoring and visualization --- SimPEG/Mesh/TreeMesh.py | 135 ++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 46 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index a8ce9ec5..0606d12a 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -56,10 +56,30 @@ class TreeNode(TreeObject): """docstring for TreeNode""" def __init__(self, mesh, x0=[0,0], depth=0, parent=None): TreeObject.__init__(self, mesh, parent) - self.x0 = x0 + self.x0 = np.array(x0, dtype=float) self.mesh.nodes.add(self) +class TreeEdge(TreeObject): + """docstring for TreeEdge""" + def __init__(self, mesh, x0=[0,0], edgeType=None, sz=[1,], depth=0, + node0=None, node1=None, + parent=None): + TreeObject.__init__(self, mesh, parent) + + self.x0 = np.array(x0, dtype=float) + self.depth = depth + self.edgeType = edgeType + self.sz = np.array(sz, dtype=float) + + mesh.edges.add(self) + if edgeType is 'x': mesh.edgesX.add(self) + elif edgeType is 'y': mesh.edgesY.add(self) + elif edgeType is 'z': mesh.edgesZ.add(self) + + self.node0 = node0 + self.node1 = node1 + class TreeFace(TreeObject): """docstring for TreeFace""" @@ -69,28 +89,41 @@ class TreeFace(TreeObject): TreeObject.__init__(self, mesh, parent) self.x0 = np.array(x0, dtype=float) + self.depth = depth self.faceType = faceType self.sz = np.array(sz, dtype=float) - self.depth = depth + mesh.faces.add(self) - if faceType is 'x': self.mesh.facesX.add(self) - elif faceType is 'y': self.mesh.facesY.add(self) - elif faceType is 'z': self.mesh.facesZ.add(self) + if faceType is 'x': mesh.facesX.add(self) + elif faceType is 'y': mesh.facesY.add(self) + elif faceType is 'z': mesh.facesZ.add(self) # Add the nodes: - self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) - self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent*self.sz) + if self.dim == 2: + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz) @property - def tangent(self): - t = np.zeros(self.dim) - t[1 if self.faceType is 'x' else 0] = 1 - return t + def tangent0(self): + if self.faceType is 'x': t = np.r_[0,1.,0] + elif self.faceType is 'y': t = np.r_[1.,0,0] + elif self.faceType is 'z': t = np.r_[1.,0,0] + return t[:self.dim] + + @property + def tangent1(self): + if self.dim == 2: return + if self.faceType is 'x': t = np.r_[0,0,1.] + elif self.faceType is 'y': t = np.r_[0,0,1.] + elif self.faceType is 'z': t = np.r_[0,1.,0] + return t[:self.dim] @property def normal(self): - if self.faceType is 'x': return np.r_[1.,0,0] - elif self.faceType is 'y': return np.r_[0,1.,0] - elif self.faceType is 'z': return np.r_[0,0,1.] + if self.faceType is 'x': n = np.r_[1.,0,0] + elif self.faceType is 'y': n = np.r_[0,1.,0] + elif self.faceType is 'z': n = np.r_[0,0,1.] + return n[:self.dim] + @property def index(self): @@ -110,7 +143,7 @@ class TreeFace(TreeObject): self.children = np.empty(2,dtype=TreeFace) # Create refined x0's x0r_0 = self.x0 - x0r_1 = self.x0+0.5*self.tangent*self.sz + x0r_1 = self.x0+0.5*self.tangent0*self.sz self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.children[0].node1, node1=self.node1) self.mesh.faces.remove(self) @@ -119,14 +152,14 @@ class TreeFace(TreeObject): elif self.faceType is 'y': self.mesh.facesY.remove(self) - def viz(self, ax, text=True): + def plotGrid(self, ax, text=True): if not self.isleaf: return - ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent[1]*self.sz],'r-') - if text: ax.text(self.x0[0]+0.5*self.tangent[0]*self.sz, self.x0[1]+0.5*self.tangent[1]*self.sz,self.num) + ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent0[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent0[1]*self.sz],'r-') + if text: ax.text(self.x0[0]+0.5*self.tangent0[0]*self.sz, self.x0[1]+0.5*self.tangent0[1]*self.sz,self.num) @property def center(self): - return self.x0 + 0.5*self.tangent*self.sz + return self.x0 + 0.5*self.tangent0*self.sz class TreeCell(TreeObject): @@ -153,21 +186,26 @@ class TreeCell(TreeObject): # |___________| |___> x # 0 fYm 1 # - self.nodes = {} + N = {} + N["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) + N["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) + N["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) + N["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) + + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n0'], node1=N['n2']) + N["n0"], N["n2"] = fXm.node0, fXm.node1 + + fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n1'], node1=N['n3']) + N["n1"], N["n3"] = fXp.node0, fXp.node1 + + fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n0'], node1=N['n1']) + N["n0"], N["n1"] = fYm.node0, fYm.node1 + + fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n2'], node1=N['n3']) + N["n2"], N["n3"] = fYp.node0, fYp.node1 - self.nodes["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) - self.nodes["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) - self.nodes["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) - self.nodes["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) - fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=self.nodes['n0'], node1=self.nodes['n2']) - self.nodes["n0"], self.nodes["n2"] = fXm.node0, fXm.node1 - fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=self.nodes['n1'], node1=self.nodes['n3']) - self.nodes["n1"], self.nodes["n3"] = fXp.node0, fXp.node1 - fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=self.nodes['n0'], node1=self.nodes['n1']) - self.nodes["n0"], self.nodes["n1"] = fYm.node0, fYm.node1 - fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=self.nodes['n2'], node1=self.nodes['n3']) - self.nodes["n2"], self.nodes["n3"] = fYp.node0, fYp.node1 self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} + self.nodes = N elif self.dim == 3: fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) @@ -191,16 +229,22 @@ class TreeCell(TreeObject): def center(self): return self.x0 + 0.5*self.sz def refine(self, function=None): - if self.dim == 2: - return self._refine2D(function=function) - - def _refine2D(self, function=None): if not self.isleaf and function is None: return if function is not None: do = function(self.center) > self.depth if not do: return + if self.dim == 2: + return self._refine2D() + + # pass the refine function to the children + if function is not None: + for child in self.children.flatten(): + child.refine(function) + + def _refine2D(self): + self.mesh.isNumbered = False self.children = np.empty((2,2),dtype=TreeCell) @@ -231,13 +275,9 @@ class TreeCell(TreeObject): self.mesh.cells.remove(self) - # pass the refine function to the children - if function is not None: - for child in self.children.flatten(): - child.refine(function) - @property def faceIndex(self): + #TODO: preallocate I, J, V = np.empty(0,dtype=float), np.empty(0,dtype=float), np.empty(0,dtype=float) for face in self.faces: j = self.faces[face].index @@ -258,6 +298,11 @@ class TreeCell(TreeObject): ax.add_patch(plt.Rectangle((x0[0], x0[1]), sz[0], sz[1], facecolor=color, edgecolor='k')) if text: ax.text(self.center[0],self.center[1],self.num) + def plotGrid(self, ax, text=False): + if not self.isleaf: return + ax.plot(self.center[0],self.center[1],'b.') + if text: ax.text(self.center[0],self.center[1],self.num) + class TreeMesh(object): @@ -455,17 +500,15 @@ class TreeMesh(object): self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv - - def plotGrid(self, ax=None, text=True, plotC=True, plotF=False, showIt=False): + def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, showIt=False): if ax is None: ax = plt.subplot(111) - if plotC: [node.viz(ax, text=text) for node in self.cells] - if plotF: [node.viz(ax, text=text) for node in self.faces] + if plotC: [node.plotGrid(ax, text=text) for node in self.cells] + if plotF: [node.plotGrid(ax, text=text) for node in self.faces] ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) if showIt: plt.show() - def plotImage(self, I, ax=None, showIt=True): if self.dim == 2: self._plotImage2D(I, ax=ax, showIt=showIt) From 599a05cfe708f39d62384633eaa16471e5188ed6 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 16:12:24 -0800 Subject: [PATCH 12/42] testing octree --- SimPEG/Mesh/TreeMesh.py | 234 ++++++++++++++++++++++++++++------ SimPEG/tests/test_QuadTree.py | 29 +++++ 2 files changed, 225 insertions(+), 38 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 0606d12a..cf45be6c 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1,5 +1,6 @@ from SimPEG import np, sp, Utils, Solver import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors import matplotlib.cm as cmx @@ -8,9 +9,17 @@ import matplotlib.cm as cmx def SortByX0(): eps = 1e-7 def mycmp(c1,c2): - if np.abs(c1.x0[1] - c2.x0[1]) < eps: - return c1.x0[0] - c2.x0[0] - return c1.x0[1] - c2.x0[1] + if c1.x0.size == 2: + if np.abs(c1.x0[1] - c2.x0[1]) < eps: + return c1.x0[0] - c2.x0[0] + return c1.x0[1] - c2.x0[1] + elif c1.x0.size == 3: + if np.abs(c1.x0[2] - c2.x0[2]) < eps: + if np.abs(c1.x0[1] - c2.x0[1]) < eps: + return c1.x0[0] - c2.x0[0] + return c1.x0[1] - c2.x0[1] + return c1.x0[2] - c2.x0[2] + class K(object): def __init__(self, obj, *args): self.obj = obj @@ -98,9 +107,11 @@ class TreeFace(TreeObject): elif faceType is 'y': mesh.facesY.add(self) elif faceType is 'z': mesh.facesZ.add(self) # Add the nodes: - if self.dim == 2: - self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) - self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz) + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0]) + if self.dim == 3: + self.node2 = node2 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent1*self.sz[1]) + self.node3 = node3 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0] + self.tangent1*self.sz[1]) @property def tangent0(self): @@ -124,7 +135,6 @@ class TreeFace(TreeObject): elif self.faceType is 'z': n = np.r_[0,0,1.] return n[:self.dim] - @property def index(self): if not self.mesh.isNumbered: raise Exception('Mesh is not numbered.') @@ -139,7 +149,12 @@ class TreeFace(TreeObject): def refine(self): if not self.isleaf: return self.mesh.isNumbered = False + if self.dim == 2: + self._refine2D() + elif self.dim == 3: + self._refine3D() + def _refine2D(self): self.children = np.empty(2,dtype=TreeFace) # Create refined x0's x0r_0 = self.x0 @@ -152,14 +167,43 @@ class TreeFace(TreeObject): elif self.faceType is 'y': self.mesh.facesY.remove(self) + def _refine3D(self): + self.children = np.empty((2,2),dtype=TreeFace) + # Create refined x0's + x0r_0 = self.x0 + x0r_1 = self.x0+0.5*self.tangent0*self.sz[0] + x0r_2 = self.x0+0.5*self.tangent1*self.sz[1] + x0r_3 = self.x0+0.5*self.tangent0*self.sz[0]+0.5*self.tangent1*self.sz[1] + # TODO: Set nodes + self.children[0,0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.children[1,0] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.children[0,1] = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.children[1,1] = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) + self.mesh.faces.remove(self) + if self.faceType is 'x': + self.mesh.facesX.remove(self) + elif self.faceType is 'y': + self.mesh.facesY.remove(self) + elif self.faceType is 'z': + self.mesh.facesZ.remove(self) + def plotGrid(self, ax, text=True): if not self.isleaf: return - ax.plot(np.r_[self.x0[0],self.x0[0]+self.tangent0[0]*self.sz], np.r_[self.x0[1], self.x0[1]+self.tangent0[1]*self.sz],'r-') - if text: ax.text(self.x0[0]+0.5*self.tangent0[0]*self.sz, self.x0[1]+0.5*self.tangent0[1]*self.sz,self.num) + if self.dim == 2: + line = np.c_[self.node0.x0, self.node1.x0].T + ax.plot(line[:,0], line[:,1],'r-') + if text: ax.text(self.center[0], self.center[1],self.num) + elif self.dim == 3: + line = np.c_[self.node0.x0, self.node1.x0, self.node3.x0, self.node2.x0, self.node0.x0].T + ax.plot(line[:,0], line[:,1],'r-', zs=line[:,2]) + if text: ax.text(self.center[0], self.center[1], self.center[2], self.num) @property def center(self): - return self.x0 + 0.5*self.tangent0*self.sz + if self.dim == 2: + return self.x0 + 0.5*self.tangent0*self.sz[0] + elif self.dim == 3: + return self.x0 + 0.5*self.tangent0*self.sz[0] + 0.5*self.tangent1*self.sz[1] class TreeCell(TreeObject): @@ -208,6 +252,32 @@ class TreeCell(TreeObject): self.nodes = N elif self.dim == 3: + # fZp + # | + # 6 --------------- 7 + # /| | / | + # / | . / | + # / | fYp / | + # / | / fXp| + # 4 -------------- 5 | + # |fXm 2 ----------|---- 3 z + # | / | / ^ y + # | / fYm . | / | / + # | / | | / | / + # 0 -------------- 1 o----> x + # | + # fZm + # + N = {} + N["n0"] = None #getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) or getattr(fZm, 'node0', None) + N["n1"] = None #getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) or getattr(fZm, 'node1', None) + N["n2"] = None #getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) or getattr(fZp, 'node0', None) + N["n3"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + N["n4"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + N["n5"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + N["n6"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + N["n7"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) @@ -237,6 +307,8 @@ class TreeCell(TreeObject): if self.dim == 2: return self._refine2D() + elif self.dim == 3: + return self._refine3D() # pass the refine function to the children if function is not None: @@ -275,6 +347,60 @@ class TreeCell(TreeObject): self.mesh.cells.remove(self) + + def _refine3D(self): + + self.mesh.isNumbered = False + + self.children = np.empty((2,2,2),dtype=TreeCell) + x0, sz = self.x0, self.sz + + for faceName in self.faces: + self.faces[faceName].refine() + + i, j, k = 0, 0, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 1, 0, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 0, 1, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 1, 1, 0 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + # Upper layer + i, j, k = 0, 0, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 1, 0, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 0, 1, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + i, j, k = 1, 1, 1 + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + + self.mesh.cells.remove(self) + @property def faceIndex(self): #TODO: preallocate @@ -300,9 +426,12 @@ class TreeCell(TreeObject): def plotGrid(self, ax, text=False): if not self.isleaf: return - ax.plot(self.center[0],self.center[1],'b.') - if text: ax.text(self.center[0],self.center[1],self.num) - + if self.dim == 2: + ax.plot(self.center[0],self.center[1],'b.') + if text: ax.text(self.center[0],self.center[1],self.num) + elif self.dim == 3: + ax.plot([self.center[0]],[self.center[1]],'b.', zs=[self.center[2]]) + if text: ax.text(self.center[0], self.center[1], self.center[2], self.num) class TreeMesh(object): @@ -323,29 +452,45 @@ class TreeMesh(object): x0 = np.zeros(self.dim) else: assert type(x0) in [list, np.ndarray], 'x0 must be a numpy array or a list' + x0 = np.array(x0, dtype=float) assert len(x0) == self.dim, 'x0 must have the same dimensions as the mesh' - self.x0 = np.array(x0, dtype=float) + self.x0 = x0 - # set the sets for holding the faces and cells - self.cells = set() - self.nodes = set() - self.faces = set() + # set the sets for holding the cells, nodes, faces, and edges + self.cells = set() + self.nodes = set() + self.faces = set() self.facesX = set() self.facesY = set() - if self.dim == 3: self.facesZ = set() - self.edges = set() - self.edgesX = set() - self.edgesY = set() - if self.dim == 3: self.edgesZ = set() + if self.dim == 3: + self.facesZ = set() + self.edges = set() + self.edgesX = set() + self.edgesY = set() + self.edgesZ = set() self.children = np.empty([hi.size for hi in h],dtype=TreeCell) - for i in range(h[0].size): - for j in range(h[1].size): - fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] - fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] - x0i = (np.r_[x0[0], h[0][:i]]).sum() - x0j = (np.r_[x0[1], h[1][:j]]).sum() - self.children[i][j] = TreeCell(self, x0=[x0i, x0j], depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) + + if self.dim == 2: + for i in range(h[0].size): + for j in range(h[1].size): + fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] + fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] + x0i = (np.r_[x0[0], h[0][:i]]).sum() + x0j = (np.r_[x0[1], h[1][:j]]).sum() + self.children[i][j] = TreeCell(self, x0=[x0i, x0j], depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) + + elif self.dim == 3: + for i in range(h[0].size): + for j in range(h[1].size): + for k in range(h[2].size): + fXm = None if i is 0 else self.children[i-1][j][k].faces['fXp'] + fYm = None if j is 0 else self.children[i][j-1][k].faces['fYp'] + fZm = None if k is 0 else self.children[i][j][k-1].faces['fZp'] + x0i = (np.r_[x0[0], h[0][:i]]).sum() + x0j = (np.r_[x0[1], h[1][:j]]).sum() + x0k = (np.r_[x0[2], h[2][:k]]).sum() + self.children[i][j] = TreeCell(self, x0=[x0i, x0j, x0k], depth=0, sz=[h[0][i], h[1][j], h[2][k]], fXm=fXm, fYm=fYm, fZm=fZm) isNumbered = Utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @@ -361,20 +506,29 @@ class TreeMesh(object): if self.isNumbered: return self.sortedCells = sorted(self.cells,key=SortByX0()) - for i, sc in enumerate(self.sortedCells): sc.num = i + for i, sC in enumerate(self.sortedCells): sC.num = i self.sortedNodes = sorted(self.nodes,key=SortByX0()) - for i, sn in enumerate(self.sortedNodes): sn.num = i + for i, sN in enumerate(self.sortedNodes): sN.num = i self.sortedFaceX = sorted(self.facesX,key=SortByX0()) - for i, sfx in enumerate(self.sortedFaceX): sfx.num = i + for i, sFx in enumerate(self.sortedFaceX): sFx.num = i self.sortedFaceY = sorted(self.facesY,key=SortByX0()) - for i, sfy in enumerate(self.sortedFaceY): sfy.num = i + self.nFx + for i, sFy in enumerate(self.sortedFaceY): sFy.num = i + self.nFx if self.dim == 3: self.sortedFaceZ = sorted(self.facesZ,key=SortByX0()) - for i, sfz in enumerate(self.sortedFaceZ): sfz.num = i + self.nFx + self.nFy + for i, sFz in enumerate(self.sortedFaceZ): sFz.num = i + self.nFx + self.nFy + + self.sortedEdgeX = sorted(self.edgesX,key=SortByX0()) + for i, sEx in enumerate(self.sortedEdgeX): sEx.num = i + + self.sortedEdgeY = sorted(self.edgesY,key=SortByX0()) + for i, sEy in enumerate(self.sortedEdgeY): sEy.num = i + self.nEx + + self.sortedEdgeZ = sorted(self.edgesZ,key=SortByX0()) + for i, sEz in enumerate(self.sortedEdgeZ): sEz.num = i + self.nEx + self.nEy self.isNumbered = True @@ -501,12 +655,16 @@ class TreeMesh(object): return self._faceDiv def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, showIt=False): - if ax is None: ax = plt.subplot(111) + axOpts = {'projection':'3d'} if self.dim == 3 else {} + if ax is None: ax = plt.subplot(111, **axOpts) + + if plotC: [c.plotGrid(ax, text=text) for c in self.cells] + if plotF: [f.plotGrid(ax, text=text) for f in self.faces] - if plotC: [node.plotGrid(ax, text=text) for node in self.cells] - if plotF: [node.plotGrid(ax, text=text) for node in self.faces] ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) + if self.dim == 3: + ax.set_zlim((self.x0[2], self.h[2].sum())) if showIt: plt.show() def plotImage(self, I, ax=None, showIt=True): diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index 92c3dd71..54a45030 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -2,6 +2,35 @@ from SimPEG.Mesh.TreeMesh import TreeMesh, TreeFace, TreeCell import numpy as np import unittest +class TestOcTreeObjects(unittest.TestCase): + + def setUp(self): + self.M = TreeMesh([2,1,1]) + self.Mr = TreeMesh([2,1,1]) + self.Mr.children[0,0,0].refine() + self.Mr.number() + # self.Mr.plotGrid(showIt=True,plotC=True,plotF=True) + + def test_counts(self): + self.assertTrue(self.M.nC == 2) + self.assertTrue(self.M.nFx == 3) + self.assertTrue(self.M.nFy == 4) + self.assertTrue(self.M.nFz == 4) + self.assertTrue(self.M.nF == 11) + # self.assertTrue(self.M.nN == 12) + + self.assertTrue(self.Mr.nC == 9) + + def test_pointersM(self): + c0 = self.M.children[0,0,0] + c0fXm = c0.faces['fXm'] + c0fXp = c0.faces['fXp'] + c0fYm = c0.faces['fYm'] + c0fYp = c0.faces['fYp'] + + + + class TestQuadTreeObjects(unittest.TestCase): def setUp(self): From 298999a4f715b3e3565f3e287100014fb5b953e8 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 16:43:41 -0800 Subject: [PATCH 13/42] Sharing of nodes in OcTree --- SimPEG/Mesh/TreeMesh.py | 59 ++++++++++++++++++++++++++--------- SimPEG/tests/test_QuadTree.py | 3 +- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index cf45be6c..efacccbe 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -174,6 +174,7 @@ class TreeFace(TreeObject): x0r_1 = self.x0+0.5*self.tangent0*self.sz[0] x0r_2 = self.x0+0.5*self.tangent1*self.sz[1] x0r_3 = self.x0+0.5*self.tangent0*self.sz[0]+0.5*self.tangent1*self.sz[1] + # TODO: Set nodes self.children[0,0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) self.children[1,0] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) @@ -268,22 +269,50 @@ class TreeCell(TreeObject): # | # fZm # - N = {} - N["n0"] = None #getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) or getattr(fZm, 'node0', None) - N["n1"] = None #getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) or getattr(fZm, 'node1', None) - N["n2"] = None #getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) or getattr(fZp, 'node0', None) - N["n3"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) - N["n4"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) - N["n5"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) - N["n6"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) - N["n7"] = None #getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZp, 'node1', None) + # + # fX fY fZ + # 2___________3 2___________3 2___________3 + # | eYp | | eXp | | eXp | + # | | | | | | + # eZm| x |eZp z eZm| x |eZp z eYm| x |eYp y + # | | ^ | | ^ | | ^ + # |___________| |___> y |___________| |___> x |___________| |___> x + # 0 eYm 1 0 eXm 1 0 eXm 1 + # + # Mappings: numOnFace > numOnCell + # + # fXm 0>0, 1>2, 2>4, 3>6 fYm 0>0, 1>1, 2>4, 3>5 fZm 0>0, 1>1, 2>2, 3>3 + # fXp 0>1, 1>3, 2>5, 3>7 fYp 0>2, 1>3, 2>6, 3>7 fZp 0>4, 1>5, 2>6, 3>7 + + N = {} + N["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) or getattr(fZm, 'node0', None) + N["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) or getattr(fZm, 'node1', None) + N["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) or getattr(fZm, 'node2', None) + N["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZm, 'node3', None) + N["n4"] = getattr(fXm, 'node2', None) or getattr(fYm, 'node2', None) or getattr(fZp, 'node0', None) + N["n5"] = getattr(fXp, 'node2', None) or getattr(fYm, 'node3', None) or getattr(fZp, 'node1', None) + N["n6"] = getattr(fXm, 'node3', None) or getattr(fYp, 'node2', None) or getattr(fZp, 'node2', None) + N["n7"] = getattr(fXp, 'node3', None) or getattr(fYp, 'node3', None) or getattr(fZp, 'node3', None) + + + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, node0=N["n0"], node1=N["n2"], node2=N["n4"], node3=N["n6"]) + N["n0"], N["n2"], N["n4"], N["n6"] = fXm.node0, fXm.node1, fXm.node2, fXm.node3 + + fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, node0=N["n1"], node1=N["n3"], node2=N["n5"], node3=N["n7"]) + N["n1"], N["n3"], N["n5"], N["n7"] = fXp.node0, fXp.node1, fXp.node2, fXp.node3 + + fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, node0=N["n0"], node1=N["n1"], node2=N["n4"], node3=N["n5"]) + N["n0"], N["n1"], N["n4"], N["n5"] = fYm.node0, fYm.node1, fYm.node2, fYm.node3 + + fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, node0=N["n2"], node1=N["n3"], node2=N["n6"], node3=N["n7"]) + N["n2"], N["n3"], N["n6"], N["n7"] = fYp.node0, fYp.node1, fYp.node2, fYp.node3 + + fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, node0=N["n0"], node1=N["n1"], node2=N["n2"], node3=N["n3"]) + N["n0"], N["n1"], N["n2"], N["n3"] = fZm.node0, fZm.node1, fZm.node2, fZm.node3 + + fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, node0=N["n4"], node1=N["n5"], node2=N["n6"], node3=N["n7"]) + N["n4"], N["n5"], N["n6"], N["n7"] = fZp.node0, fZp.node1, fZp.node2, fZp.node3 - fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) - fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent) - fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) - fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent) - fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) - fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent) self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} mesh.cells.add(self) diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index 54a45030..2a925556 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -17,8 +17,7 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(self.M.nFy == 4) self.assertTrue(self.M.nFz == 4) self.assertTrue(self.M.nF == 11) - # self.assertTrue(self.M.nN == 12) - + self.assertTrue(self.M.nN == 12) self.assertTrue(self.Mr.nC == 9) def test_pointersM(self): From 0cc782d8f0fc17936d7b541f45cb6e7b15162109 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 17:44:25 -0800 Subject: [PATCH 14/42] Ascii drawing skillz --- SimPEG/Mesh/TreeMesh.py | 53 +++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index efacccbe..f76d657c 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -175,11 +175,26 @@ class TreeFace(TreeObject): x0r_2 = self.x0+0.5*self.tangent1*self.sz[1] x0r_3 = self.x0+0.5*self.tangent0*self.sz[0]+0.5*self.tangent1*self.sz[1] - # TODO: Set nodes - self.children[0,0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) - self.children[1,0] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) - self.children[0,1] = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) - self.children[1,1] = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self) + # + # 2_______________3 _______________ + # | | | | | + # ^ | | | (1,0) | (1,1) | + # | | | | | | + # | | x | ---> |-------+-------| + # t1 | | | | | + # | | | (0,0) | (0,1) | + # |_______________| |_______|_______| + # 0 t0--> 1 + + c00 = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) + c10 = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node2, node1=c00.node3, node2=self.node2) + c01 = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node1, node1=self.node1, node2=c00.node3) + c11 = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node3, node1=c01.node3, node2=c10.node3, node3=self.node3) + + C = np.empty((2,2), dtype=TreeFace) + C[0,0], C[1,0], C[0,1], C[1,1] = c00, c10, c01, c11 + self.children = C + self.mesh.faces.remove(self) if self.faceType is 'x': self.mesh.facesX.remove(self) @@ -279,7 +294,7 @@ class TreeCell(TreeObject): # |___________| |___> y |___________| |___> x |___________| |___> x # 0 eYm 1 0 eXm 1 0 eXm 1 # - # Mappings: numOnFace > numOnCell + # Mapping Nodes: numOnFace > numOnCell # # fXm 0>0, 1>2, 2>4, 3>6 fYm 0>0, 1>1, 2>4, 3>5 fZm 0>0, 1>1, 2>2, 3>3 # fXp 0>1, 1>3, 2>5, 3>7 fYp 0>2, 1>3, 2>6, 3>7 fZp 0>4, 1>5, 2>6, 3>7 @@ -378,10 +393,34 @@ class TreeCell(TreeObject): def _refine3D(self): + # .----------------.----------------. + # /| /| /| + # / | / | / | + # / | 011 / | 111 / | + # / | / | / | + # .----------------.----+-----------. | + # /| . ---------/|----.----------/|----. + # / | / / | / / | /| + # / | / / | / / | / | + # / | / / | / / | / | + # . -------------- .----------------. |/ | + # | . ----------|----.-----------|----. 110| + # | /| 001 | /| 101 | /| . + # | / | | / | | / | / + # | / | | / | | / | / + # . ---+---------- . ---+---------- . | / + # | | | | | |/ z + # | . ----------|----.-----------|----. ^ y + # | / 000 | / 100 | / | / + # | / | / | / | / + # | / | / | / o----> x + # . -------------- . -------------- . + # + # self.mesh.isNumbered = False - self.children = np.empty((2,2,2),dtype=TreeCell) + self.children = np.empty((2,2,2), dtype=TreeCell) x0, sz = self.x0, self.sz for faceName in self.faces: From 13767ecbe135c539dace3e16257d5661d92362a7 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 18:37:04 -0800 Subject: [PATCH 15/42] counting and linking xFaces --- SimPEG/Mesh/TreeMesh.py | 99 ++++++++++++++++------------------- SimPEG/tests/test_QuadTree.py | 23 +++++--- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index f76d657c..0ff2e01e 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -178,21 +178,21 @@ class TreeFace(TreeObject): # # 2_______________3 _______________ # | | | | | - # ^ | | | (1,0) | (1,1) | + # ^ | | | (0,1) | (1,1) | # | | | | | | # | | x | ---> |-------+-------| # t1 | | | | | - # | | | (0,0) | (0,1) | + # | | | (0,0) | (1,0) | # |_______________| |_______|_______| # 0 t0--> 1 c00 = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) - c10 = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node2, node1=c00.node3, node2=self.node2) - c01 = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node1, node1=self.node1, node2=c00.node3) - c11 = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node3, node1=c01.node3, node2=c10.node3, node3=self.node3) + c01 = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node2, node1=c00.node3, node2=self.node2) + c10 = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node1, node1=self.node1, node2=c00.node3) + c11 = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node3, node1=c10.node3, node2=c01.node3, node3=self.node3) C = np.empty((2,2), dtype=TreeFace) - C[0,0], C[1,0], C[0,1], C[1,1] = c00, c10, c01, c11 + C[0,0], C[0,1], C[1,0], C[1,1] = c00, c01, c10, c11 self.children = C self.mesh.faces.remove(self) @@ -400,16 +400,16 @@ class TreeCell(TreeObject): # / | / | / | # .----------------.----+-----------. | # /| . ---------/|----.----------/|----. - # / | / / | / / | /| - # / | / / | / / | / | - # / | / / | / / | / | + # / | /| / | /| / | /| + # / | / | 001 / | / | 101 / | / | + # / | / | / | / | / | / | # . -------------- .----------------. |/ | - # | . ----------|----.-----------|----. 110| - # | /| 001 | /| 101 | /| . - # | / | | / | | / | / - # | / | | / | | / | / + # | . ---+------|----.----+------|----. | + # | /| .______|___/|____.______|___/|____. + # | / | / 010 | / | / 110| / | / + # | / | / | / | / | / | / # . ---+---------- . ---+---------- . | / - # | | | | | |/ z + # | |/ | |/ | |/ z # | . ----------|----.-----------|----. ^ y # | / 000 | / 100 | / | / # | / | / | / | / @@ -417,6 +417,27 @@ class TreeCell(TreeObject): # . -------------- . -------------- . # # + # Face Refinement: + # + # 2_______________3 _______________ + # | | | | | + # ^ | | | (0,1) | (1,1) | + # | | | | | | + # | | x | ---> |-------+-------| + # t1 | | | | | + # | | | (0,0) | (1,0) | + # |_______________| |_______|_______| + # 0 t0--> 1 + + + order = [{'c':[0,0,0], 'fXm': ('p', 'fXm', [0,0]), 'fXp': 'new' }, + {'c':[1,0,0], 'fXm': ('c', 'fXp', [0,0,0]), 'fXp': ('p', 'fXp', [0,0])}, + {'c':[0,1,0], 'fXm': ('p', 'fXm', [1,0]), 'fXp': 'new' }, + {'c':[1,1,0], 'fXm': ('c', 'fXp', [0,1,0]), 'fXp': ('p', 'fXp', [1,0])}, + {'c':[0,0,1], 'fXm': ('p', 'fXm', [0,1]), 'fXp': 'new' }, + {'c':[1,0,1], 'fXm': ('c', 'fXp', [0,0,1]), 'fXp': ('p', 'fXp', [0,1])}, + {'c':[0,1,1], 'fXm': ('p', 'fXm', [1,1]), 'fXp': 'new' }, + {'c':[1,1,1], 'fXm': ('c', 'fXp', [0,1,1]), 'fXp': ('p', 'fXp', [1,1])}] self.mesh.isNumbered = False @@ -426,46 +447,18 @@ class TreeCell(TreeObject): for faceName in self.faces: self.faces[faceName].refine() - i, j, k = 0, 0, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + def getFace(pointer): + if pointer is 'new': return None + if pointer[0] == 'p': + return self.faces[pointer[1]].children[pointer[2][0],pointer[2][1]] + if pointer[0] == 'c': + return self.children[pointer[2][0],pointer[2][1],pointer[2][2]].faces[pointer[1]] - i, j, k = 1, 0, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - i, j, k = 0, 1, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - i, j, k = 1, 1, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - # Upper layer - i, j, k = 0, 0, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - i, j, k = 1, 0, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - i, j, k = 0, 1, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) - - i, j, k = 1, 1, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = None, None, None, None, None, None - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + for O in order: + i, j, k = O['c'] + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] + fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), None, None, None, None + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) self.mesh.cells.remove(self) diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index 2a925556..5e128cca 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -18,14 +18,23 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(self.M.nFz == 4) self.assertTrue(self.M.nF == 11) self.assertTrue(self.M.nN == 12) - self.assertTrue(self.Mr.nC == 9) - def test_pointersM(self): - c0 = self.M.children[0,0,0] - c0fXm = c0.faces['fXm'] - c0fXp = c0.faces['fXp'] - c0fYm = c0.faces['fYm'] - c0fYp = c0.faces['fYp'] + self.assertTrue(self.Mr.nC == 9) + print self.Mr.nFx + self.assertTrue(self.Mr.nFx == 13) + self.assertTrue(self.Mr.nFy == 14) + self.assertTrue(self.Mr.nFz == 14) + self.assertTrue(self.Mr.nF == 41) + + print self.Mr.nN + self.assertTrue(self.Mr.nN == 22) + + # def test_pointersM(self): + # c0 = self.M.children[0,0,0] + # c0fXm = c0.faces['fXm'] + # c0fXp = c0.faces['fXp'] + # c0fYm = c0.faces['fYm'] + # c0fYp = c0.faces['fYp'] From c4775284529da8c1dcfe66e68c87be231631b8a9 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 18:49:01 -0800 Subject: [PATCH 16/42] count and link Y faces --- SimPEG/Mesh/TreeMesh.py | 41 +++++++++++++++++++++++++++-------- SimPEG/tests/test_QuadTree.py | 3 +-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 0ff2e01e..90204e48 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -430,14 +430,37 @@ class TreeCell(TreeObject): # 0 t0--> 1 - order = [{'c':[0,0,0], 'fXm': ('p', 'fXm', [0,0]), 'fXp': 'new' }, - {'c':[1,0,0], 'fXm': ('c', 'fXp', [0,0,0]), 'fXp': ('p', 'fXp', [0,0])}, - {'c':[0,1,0], 'fXm': ('p', 'fXm', [1,0]), 'fXp': 'new' }, - {'c':[1,1,0], 'fXm': ('c', 'fXp', [0,1,0]), 'fXp': ('p', 'fXp', [1,0])}, - {'c':[0,0,1], 'fXm': ('p', 'fXm', [0,1]), 'fXp': 'new' }, - {'c':[1,0,1], 'fXm': ('c', 'fXp', [0,0,1]), 'fXp': ('p', 'fXp', [0,1])}, - {'c':[0,1,1], 'fXm': ('p', 'fXm', [1,1]), 'fXp': 'new' }, - {'c':[1,1,1], 'fXm': ('c', 'fXp', [0,1,1]), 'fXp': ('p', 'fXp', [1,1])}] + order = [{'c':[0,0,0], + 'fXm': ('p', 'fXm', [0,0]), 'fXp': 'new' , + 'fYm': ('p', 'fYm', [0,0]), 'fYp': 'new' ,}, + + {'c':[1,0,0], + 'fXm': ('c', 'fXp', [0,0,0]), 'fXp': ('p', 'fXp', [0,0]), + 'fYm': ('p', 'fYm', [1,0]), 'fYp': 'new' ,}, + + {'c':[0,1,0], + 'fXm': ('p', 'fXm', [1,0]), 'fXp': 'new' , + 'fYm': ('c', 'fYp', [0,0,0]), 'fYp': ('p', 'fYp', [0,0])}, + + {'c':[1,1,0], + 'fXm': ('c', 'fXp', [0,1,0]), 'fXp': ('p', 'fXp', [1,0]), + 'fYm': ('c', 'fYp', [1,0,0]), 'fYp': ('p', 'fYp', [1,0])}, + + {'c':[0,0,1], + 'fXm': ('p', 'fXm', [0,1]), 'fXp': 'new' , + 'fYm': ('p', 'fYm', [0,1]), 'fYp': 'new' ,}, + + {'c':[1,0,1], + 'fXm': ('c', 'fXp', [0,0,1]), 'fXp': ('p', 'fXp', [0,1]), + 'fYm': ('p', 'fYm', [1,1]), 'fYp': 'new' ,}, + + {'c':[0,1,1], + 'fXm': ('p', 'fXm', [1,1]), 'fXp': 'new' , + 'fYm': ('c', 'fYp', [0,0,1]), 'fYp': ('p', 'fYp', [0,1])}, + + {'c':[1,1,1], + 'fXm': ('c', 'fXp', [0,1,1]), 'fXp': ('p', 'fXp', [1,1]), + 'fYm': ('c', 'fYp', [1,0,1]), 'fYp': ('p', 'fYp', [1,1])}] self.mesh.isNumbered = False @@ -457,7 +480,7 @@ class TreeCell(TreeObject): for O in order: i, j, k = O['c'] x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), None, None, None, None + fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), None, None self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) self.mesh.cells.remove(self) diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/tests/test_QuadTree.py index 5e128cca..6c2ffdcd 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/tests/test_QuadTree.py @@ -19,14 +19,13 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(self.M.nF == 11) self.assertTrue(self.M.nN == 12) + print self.Mr.nN self.assertTrue(self.Mr.nC == 9) - print self.Mr.nFx self.assertTrue(self.Mr.nFx == 13) self.assertTrue(self.Mr.nFy == 14) self.assertTrue(self.Mr.nFz == 14) self.assertTrue(self.Mr.nF == 41) - print self.Mr.nN self.assertTrue(self.Mr.nN == 22) # def test_pointersM(self): From 57409c443bec82b6795af162a65e194ad4cfd437 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 18:56:41 -0800 Subject: [PATCH 17/42] Count and link Z faces --- SimPEG/Mesh/TreeMesh.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 90204e48..eb1f8cb2 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -432,35 +432,36 @@ class TreeCell(TreeObject): order = [{'c':[0,0,0], 'fXm': ('p', 'fXm', [0,0]), 'fXp': 'new' , - 'fYm': ('p', 'fYm', [0,0]), 'fYp': 'new' ,}, - + 'fYm': ('p', 'fYm', [0,0]), 'fYp': 'new' , + 'fZm': ('p', 'fZm', [0,0]), 'fZp': 'new' ,}, {'c':[1,0,0], 'fXm': ('c', 'fXp', [0,0,0]), 'fXp': ('p', 'fXp', [0,0]), - 'fYm': ('p', 'fYm', [1,0]), 'fYp': 'new' ,}, - + 'fYm': ('p', 'fYm', [1,0]), 'fYp': 'new' , + 'fZm': ('p', 'fZm', [1,0]), 'fZp': 'new' }, {'c':[0,1,0], 'fXm': ('p', 'fXm', [1,0]), 'fXp': 'new' , - 'fYm': ('c', 'fYp', [0,0,0]), 'fYp': ('p', 'fYp', [0,0])}, - + 'fYm': ('c', 'fYp', [0,0,0]), 'fYp': ('p', 'fYp', [0,0]), + 'fZm': ('p', 'fZm', [0,1]), 'fZp': 'new' }, {'c':[1,1,0], 'fXm': ('c', 'fXp', [0,1,0]), 'fXp': ('p', 'fXp', [1,0]), - 'fYm': ('c', 'fYp', [1,0,0]), 'fYp': ('p', 'fYp', [1,0])}, - + 'fYm': ('c', 'fYp', [1,0,0]), 'fYp': ('p', 'fYp', [1,0]), + 'fZm': ('p', 'fZm', [1,1]), 'fZp': 'new' }, {'c':[0,0,1], 'fXm': ('p', 'fXm', [0,1]), 'fXp': 'new' , - 'fYm': ('p', 'fYm', [0,1]), 'fYp': 'new' ,}, - + 'fYm': ('p', 'fYm', [0,1]), 'fYp': 'new' , + 'fZm': ('c', 'fZp', [0,0,0]), 'fZp': ('p', 'fZp', [0,0])}, {'c':[1,0,1], 'fXm': ('c', 'fXp', [0,0,1]), 'fXp': ('p', 'fXp', [0,1]), - 'fYm': ('p', 'fYm', [1,1]), 'fYp': 'new' ,}, - + 'fYm': ('p', 'fYm', [1,1]), 'fYp': 'new' , + 'fZm': ('c', 'fZp', [1,0,0]), 'fZp': ('p', 'fZp', [1,0])}, {'c':[0,1,1], 'fXm': ('p', 'fXm', [1,1]), 'fXp': 'new' , - 'fYm': ('c', 'fYp', [0,0,1]), 'fYp': ('p', 'fYp', [0,1])}, - + 'fYm': ('c', 'fYp', [0,0,1]), 'fYp': ('p', 'fYp', [0,1]), + 'fZm': ('c', 'fZp', [0,1,0]), 'fZp': ('p', 'fZp', [0,1])}, {'c':[1,1,1], 'fXm': ('c', 'fXp', [0,1,1]), 'fXp': ('p', 'fXp', [1,1]), - 'fYm': ('c', 'fYp', [1,0,1]), 'fYp': ('p', 'fYp', [1,1])}] + 'fYm': ('c', 'fYp', [1,0,1]), 'fYp': ('p', 'fYp', [1,1]), + 'fZm': ('c', 'fZp', [1,1,0]), 'fZp': ('p', 'fZp', [1,1])}] self.mesh.isNumbered = False @@ -480,7 +481,7 @@ class TreeCell(TreeObject): for O in order: i, j, k = O['c'] x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), None, None + fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), getFace(O['fZm']), getFace(O['fZp']), self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) self.mesh.cells.remove(self) From 4a7b157f5e630f952db3c7dcca2b305ac74d24f4 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 19:04:18 -0800 Subject: [PATCH 18/42] refactor quad tree face numbering --- SimPEG/Mesh/TreeMesh.py | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index eb1f8cb2..f322f183 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -369,25 +369,31 @@ class TreeCell(TreeObject): for faceName in self.faces: self.faces[faceName].refine() - i, j = 0, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] - fXm, fXp, fYm, fYp = self.faces['fXm'].children[0], None, self.faces['fYm'].children[0], None - self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + order = [{'c':[0,0], + 'fXm': ('p', 'fXm', [0]), 'fXp': 'new' , + 'fYm': ('p', 'fYm', [0]), 'fYp': 'new' }, + {'c':[1,0], + 'fXm': ('c', 'fXp', [0,0]), 'fXp': ('p', 'fXp', [0]), + 'fYm': ('p', 'fYm', [1]), 'fYp': 'new' }, + {'c':[0,1], + 'fXm': ('p', 'fXm', [1]), 'fXp': 'new' , + 'fYm': ('c', 'fYp', [0,0]), 'fYp': ('p', 'fYp', [0])}, + {'c':[1,1], + 'fXm': ('c', 'fXp', [0,1]), 'fXp': ('p', 'fXp', [1]), + 'fYm': ('c', 'fYp', [1,0]), 'fYp': ('p', 'fYp', [1])}] - i, j = 1, 0 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] - fXm, fXp, fYm, fYp = self.children[0,0].faces['fXp'], self.faces['fXp'].children[0], self.faces['fYm'].children[1], None - self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + def getFace(pointer): + if pointer is 'new': return None + if pointer[0] == 'p': + return self.faces[pointer[1]].children[pointer[2][0],] + if pointer[0] == 'c': + return self.children[pointer[2][0],pointer[2][1]].faces[pointer[1]] - i, j = 0, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] - fXm, fXp, fYm, fYp = self.faces['fXm'].children[1], None, self.children[0,0].faces['fYp'], self.faces['fYp'].children[0] - self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) - - i, j = 1, 1 - x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] - fXm, fXp, fYm, fYp = self.children[0,1].faces['fXp'], self.faces['fXp'].children[1], self.children[1,0].faces['fYp'], self.faces['fYp'].children[1] - self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + for O in order: + i, j = O['c'] + x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] + fXm, fXp, fYm, fYp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) self.mesh.cells.remove(self) @@ -481,7 +487,7 @@ class TreeCell(TreeObject): for O in order: i, j, k = O['c'] x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] - fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), getFace(O['fZm']), getFace(O['fZp']), + fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), getFace(O['fZm']), getFace(O['fZp']) self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) self.mesh.cells.remove(self) From fd154c500508ac05d21ae77a3f25e1747687ebe2 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Sun, 9 Feb 2014 23:11:40 -0800 Subject: [PATCH 19/42] Switch to Edges (few bugs in the refinement code..) --- SimPEG/Mesh/TreeMesh.py | 249 +++++++++++++----- .../test_TreeMesh.py} | 144 +++++++++- 2 files changed, 311 insertions(+), 82 deletions(-) rename SimPEG/{tests/test_QuadTree.py => Tests/test_TreeMesh.py} (50%) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index f322f183..9d616480 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -86,14 +86,44 @@ class TreeEdge(TreeObject): elif edgeType is 'y': mesh.edgesY.add(self) elif edgeType is 'z': mesh.edgesZ.add(self) - self.node0 = node0 - self.node1 = node1 + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent*self.sz[0]) + + + def refine(self): + if not self.isleaf: return + self.mesh.isNumbered = False + + self.children = np.empty(2,dtype=TreeFace) + # Create refined x0's + x0r_0 = self.x0 + x0r_1 = self.x0+0.5*self.tangent*self.sz + self.children[0] = TreeEdge(self.mesh, x0=x0r_0, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) + self.children[1] = TreeEdge(self.mesh, x0=x0r_1, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.children[0].node1, node1=self.node1) + self.mesh.edges.remove(self) + if self.edgeType is 'x': + self.mesh.edgesX.remove(self) + elif self.edgeType is 'y': + self.mesh.edgesY.remove(self) + elif self.edgeType is 'z': + self.mesh.edgesZ.remove(self) + + @property + def tangent(self): + if self.edgeType is 'x': return np.r_[1.,0,0] + elif self.edgeType is 'y': return np.r_[0,1.,0] + elif self.edgeType is 'z': return np.r_[0,0,1.] + + def plotGrid(self, ax, text=False): + line = np.c_[self.node0.x0, self.node1.x0].T + ax.plot(line[:,0], line[:,1],'r-', zs=line[:,2]) class TreeFace(TreeObject): """docstring for TreeFace""" def __init__(self, mesh, x0=[0,0], faceType=None, sz=[1,], depth=0, - node0=None, node1=None, node2=None, node3=None, + node0=None, node1=None, + edge0=None, edge1=None, edge2=None, edge3=None, parent=None): TreeObject.__init__(self, mesh, parent) @@ -106,12 +136,46 @@ class TreeFace(TreeObject): if faceType is 'x': mesh.facesX.add(self) elif faceType is 'y': mesh.facesY.add(self) elif faceType is 'z': mesh.facesZ.add(self) - # Add the nodes: - self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) - self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0]) + if self.dim == 2: + # Add the nodes: + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0]) if self.dim == 3: - self.node2 = node2 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent1*self.sz[1]) - self.node3 = node3 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0] + self.tangent1*self.sz[1]) + #TODO: Change this to edges + + # + # 2___________3 + # | e1 | + # | | + # e2| x |e3 t1 + # | | ^ + # |___________| |___> t0 + # 0 e0 1 + # + + N = {} + N["n0"] = getattr(edge0, 'node0', None) or getattr(edge2, 'node0', None) + N["n1"] = getattr(edge0, 'node1', None) or getattr(edge3, 'node0', None) + N["n2"] = getattr(edge1, 'node0', None) or getattr(edge2, 'node1', None) + N["n3"] = getattr(edge1, 'node1', None) or getattr(edge3, 'node1', None) + + eType = ['x', 'y'] if self.faceType == 'z' else ['x', 'z'] if self.faceType == 'y' else ['y', 'z'] + + e0 = edge0 if isinstance(edge0,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n0'], node1=N['n1']) + N["n0"], N["n1"] = e0.node0, e0.node1 + + e1 = edge1 if isinstance(edge1,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent1*self.sz[1], edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n2'], node1=N['n3']) + N["n2"], N["n3"] = e1.node0, e1.node1 + + e2 = edge2 if isinstance(edge2,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n0'], node1=N['n2']) + N["n0"], N["n2"] = e2.node0, e2.node1 + + e3 = edge3 if isinstance(edge3,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent0*self.sz[0], edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n1'], node1=N['n3']) + N["n1"], N["n3"] = e3.node0, e3.node1 + + self.nodes = N + self.edges = {'e0':e0, 'e1':e1, 'e2':e2, 'e3':e3} + @property def tangent0(self): @@ -169,31 +233,48 @@ class TreeFace(TreeObject): def _refine3D(self): self.children = np.empty((2,2),dtype=TreeFace) - # Create refined x0's - x0r_0 = self.x0 - x0r_1 = self.x0+0.5*self.tangent0*self.sz[0] - x0r_2 = self.x0+0.5*self.tangent1*self.sz[1] - x0r_3 = self.x0+0.5*self.tangent0*self.sz[0]+0.5*self.tangent1*self.sz[1] + + for edgeName in self.edges: + self.edges[edgeName].refine() # # 2_______________3 _______________ - # | | | | | - # ^ | | | (0,1) | (1,1) | - # | | | | | | - # | | x | ---> |-------+-------| - # t1 | | | | | + # | e1--> | | | | + # ^ | | ^ | (0,1) | (1,1) | + # | | | | | | | + # | | x | | ---> |-------+-------| + # e2 | | e3 | | | # | | | (0,0) | (1,0) | # |_______________| |_______|_______| - # 0 t0--> 1 + # 0 e0--> 1 - c00 = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) - c01 = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node2, node1=c00.node3, node2=self.node2) - c10 = TreeFace(self.mesh, x0=x0r_2, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node1, node1=self.node1, node2=c00.node3) - c11 = TreeFace(self.mesh, x0=x0r_3, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=c00.node3, node1=c10.node3, node2=c01.node3, node3=self.node3) - C = np.empty((2,2), dtype=TreeFace) - C[0,0], C[0,1], C[1,0], C[1,1] = c00, c01, c10, c11 - self.children = C + order = [{'c':[0,0], + 'e0': ('p', 'e0', [0]), 'e1': 'new' , + 'e2': ('p', 'e2', [0]), 'e3': 'new' }, + {'c':[1,0], + 'e0': ('p', 'e0', [1]), 'e1': 'new' , + 'e2': ('c', 'e3', [0,0]), 'e3': ('p', 'e3', [0])}, + {'c':[0,1], + 'e0': ('c', 'e1', [0,0]), 'e1': ('p', 'e1', [0]), + 'e2': ('p', 'e2', [1]), 'e3': 'new' }, + {'c':[1,1], + 'e0': ('c', 'e1', [1,0]), 'e1': ('p', 'e1', [1]), + 'e2': ('c', 'e3', [0,1]), 'e3': ('p', 'e3', [1])}] + + def getEdge(pointer): + return + if pointer is 'new': return + if pointer[0] == 'p': + return self.edges[pointer[1]].children[pointer[2][0]] + if pointer[0] == 'c': + return self.children[pointer[2][0],pointer[2][1]].edges[pointer[1]] + + for O in order: + i, j = O['c'] + x0r = 0.5*i*self.tangent0*self.sz[0] + 0.5*j*self.tangent1*self.sz[1] + e0, e1, e2, e3 = getEdge(O['e0']), getEdge(O['e1']), getEdge(O['e2']), getEdge(O['e3']) + self.children[i,j] = TreeFace(self.mesh, x0=x0r, faceType=self.faceType, depth=self.depth+1, sz=0.5*self.sz, parent=self, edge0=e0, edge1=e1, edge2=e2, edge3=e3) self.mesh.faces.remove(self) if self.faceType is 'x': @@ -210,8 +291,6 @@ class TreeFace(TreeObject): ax.plot(line[:,0], line[:,1],'r-') if text: ax.text(self.center[0], self.center[1],self.num) elif self.dim == 3: - line = np.c_[self.node0.x0, self.node1.x0, self.node3.x0, self.node2.x0, self.node0.x0].T - ax.plot(line[:,0], line[:,1],'r-', zs=line[:,2]) if text: ax.text(self.center[0], self.center[1], self.center[2], self.num) @property @@ -270,65 +349,76 @@ class TreeCell(TreeObject): elif self.dim == 3: # fZp # | - # 6 --------------- 7 + # 6 ------eX3------ 7 # /| | / | - # / | . / | - # / | fYp / | + # /eZ2 . / eZ3 + # eY2 | fYp eY3 | # / | / fXp| - # 4 -------------- 5 | - # |fXm 2 ----------|---- 3 z - # | / | / ^ y - # | / fYm . | / | / - # | / | | / | / - # 0 -------------- 1 o----> x - # | - # fZm + # 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 - # | eYp | | eXp | | eXp | + # | e1 | | e1 | | e1 | # | | | | | | - # eZm| x |eZp z eZm| x |eZp z eYm| x |eYp y + # e2 | x | e3 z e2 | x | e3 z e2 | x | e3 y # | | ^ | | ^ | | ^ # |___________| |___> y |___________| |___> x |___________| |___> x - # 0 eYm 1 0 eXm 1 0 eXm 1 + # 0 e0 1 0 e0 1 0 e0 1 # # Mapping Nodes: numOnFace > numOnCell # # fXm 0>0, 1>2, 2>4, 3>6 fYm 0>0, 1>1, 2>4, 3>5 fZm 0>0, 1>1, 2>2, 3>3 # fXp 0>1, 1>3, 2>5, 3>7 fYp 0>2, 1>3, 2>6, 3>7 fZp 0>4, 1>5, 2>6, 3>7 - N = {} - N["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) or getattr(fZm, 'node0', None) - N["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) or getattr(fZm, 'node1', None) - N["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) or getattr(fZm, 'node2', None) - N["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) or getattr(fZm, 'node3', None) - N["n4"] = getattr(fXm, 'node2', None) or getattr(fYm, 'node2', None) or getattr(fZp, 'node0', None) - N["n5"] = getattr(fXp, 'node2', None) or getattr(fYm, 'node3', None) or getattr(fZp, 'node1', None) - N["n6"] = getattr(fXm, 'node3', None) or getattr(fYp, 'node2', None) or getattr(fZp, 'node2', None) - N["n7"] = getattr(fXp, 'node3', None) or getattr(fYp, 'node3', None) or getattr(fZp, 'node3', None) + def getEdge(face, key): + if face is None: return + return face.edges[key] + + E = {} + eX0 = getEdge(fYm, 'e0') or getEdge(fZm, 'e0') + eX1 = getEdge(fYp, 'e0') or getEdge(fZm, 'e1') + eX2 = getEdge(fYm, 'e1') or getEdge(fZp, 'e0') + eX3 = getEdge(fYp, 'e1') or getEdge(fZp, 'e1') + + eY0 = getEdge(fXm, 'e0') or getEdge(fZm, 'e2') + eY1 = getEdge(fXp, 'e0') or getEdge(fZm, 'e3') + eY2 = getEdge(fXm, 'e1') or getEdge(fZp, 'e2') + eY3 = getEdge(fXp, 'e1') or getEdge(fZp, 'e3') + + eZ0 = getEdge(fXm, 'e2') or getEdge(fYm, 'e2') + eZ1 = getEdge(fXp, 'e2') or getEdge(fYm, 'e3') + eZ2 = getEdge(fXm, 'e3') or getEdge(fYp, 'e2') + eZ3 = getEdge(fXp, 'e3') or getEdge(fYp, 'e3') - fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, node0=N["n0"], node1=N["n2"], node2=N["n4"], node3=N["n6"]) - N["n0"], N["n2"], N["n4"], N["n6"] = fXm.node0, fXm.node1, fXm.node2, fXm.node3 + fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, edge0=eY0, edge1=eY2, edge2=eZ0, edge3=eZ2) + eY0, eY2, eZ0, eZ2 = fXm.edges['e0'], fXm.edges['e1'], fXm.edges['e2'], fXm.edges['e3'] - fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, node0=N["n1"], node1=N["n3"], node2=N["n5"], node3=N["n7"]) - N["n1"], N["n3"], N["n5"], N["n7"] = fXp.node0, fXp.node1, fXp.node2, fXp.node3 + fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, edge0=eY1, edge1=eY3, edge2=eZ1, edge3=eZ3) + eY1, eY3, eZ1, eZ3 = fXp.edges['e0'], fXp.edges['e1'], fXp.edges['e2'], fXp.edges['e3'] - fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, node0=N["n0"], node1=N["n1"], node2=N["n4"], node3=N["n5"]) - N["n0"], N["n1"], N["n4"], N["n5"] = fYm.node0, fYm.node1, fYm.node2, fYm.node3 + fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, edge0=eX0, edge1=eX2, edge2=eZ0, edge3=eZ1) + eX0, eX2, eZ0, eZ1 = fYm.edges['e0'], fYm.edges['e1'], fYm.edges['e2'], fYm.edges['e3'] - fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, node0=N["n2"], node1=N["n3"], node2=N["n6"], node3=N["n7"]) - N["n2"], N["n3"], N["n6"], N["n7"] = fYp.node0, fYp.node1, fYp.node2, fYp.node3 + fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, edge0=eX1, edge1=eX3, edge2=eZ2, edge3=eZ3) + eX1, eX3, eZ2, eZ3 = fYp.edges['e0'], fYp.edges['e1'], fYp.edges['e2'], fYp.edges['e3'] - fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, node0=N["n0"], node1=N["n1"], node2=N["n2"], node3=N["n3"]) - N["n0"], N["n1"], N["n2"], N["n3"] = fZm.node0, fZm.node1, fZm.node2, fZm.node3 + fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, edge0=eX0, edge1=eX1, edge2=eY0, edge3=eY1) + eX0, eX1, eY0, eY1 = fZm.edges['e0'], fZm.edges['e1'], fZm.edges['e2'], fZm.edges['e3'] - fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, node0=N["n4"], node1=N["n5"], node2=N["n6"], node3=N["n7"]) - N["n4"], N["n5"], N["n6"], N["n7"] = fZp.node0, fZp.node1, fZp.node2, fZp.node3 + fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, edge0=eX2, edge1=eX3, edge2=eY2, edge3=eY3) + eX2, eX3, eY2, eY3 = fZp.edges['e0'], fZp.edges['e1'], fZp.edges['e2'], fZp.edges['e3'] self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} + self.edges = {"eX0":eX0, "eX1":eX1, "eX2":eX2, "eX3":eX3, "eY0":eY0, "eY1":eY1, "eY2":eY2, "eY3":eY3, "eZ0":eZ0, "eZ1":eZ1, "eZ2":eZ2, "eZ3":eZ3} mesh.cells.add(self) @@ -350,9 +440,9 @@ class TreeCell(TreeObject): if not do: return if self.dim == 2: - return self._refine2D() + self._refine2D() elif self.dim == 3: - return self._refine3D() + self._refine3D() # pass the refine function to the children if function is not None: @@ -590,8 +680,8 @@ class TreeMesh(object): return np.max([node.branchdepth for node in self.children.flatten('F')]) def refine(self, function): - for node in self.children.flatten(): - node.refine(function) + for cell in self.children.flatten(): + cell.refine(function) def number(self): if self.isNumbered: return @@ -642,22 +732,31 @@ class TreeMesh(object): def nFy(self): return len(self.facesY) @property - def nFz(self): return len(self.facesZ) + def nFz(self): return None if self.dim < 3 else len(self.facesZ) @property - def nE(self): return len(self.faces) + def nE(self): + if self.dim == 2: + return len(self.faces) + elif self.dim == 3: + return len(self.edges) @property def nEx(self): if self.dim == 2: return len(self.facesY) - else: raise NotImplementedError('nEx') + elif self.dim == 3: + return len(self.edgesX) @property def nEy(self): if self.dim == 2: return len(self.facesX) - else: raise NotImplementedError('nEy') + elif self.dim == 3: + return len(self.edgesY) + + @property + def nEz(self): return None if self.dim < 3 else len(self.edgesZ) @property def gridCC(self): @@ -745,12 +844,16 @@ class TreeMesh(object): self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv - def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, showIt=False): + def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, plotE=False, plotEx=False, plotEy=False, plotEz=False, showIt=False): axOpts = {'projection':'3d'} if self.dim == 3 else {} if ax is None: ax = plt.subplot(111, **axOpts) if plotC: [c.plotGrid(ax, text=text) for c in self.cells] if plotF: [f.plotGrid(ax, text=text) for f in self.faces] + if plotE and self.dim==3: [e.plotGrid(ax, text=text) for e in self.edges] + if plotEx and self.dim==3: [e.plotGrid(ax, text=text) for e in self.edgesX] + if plotEy and self.dim==3: [e.plotGrid(ax, text=text) for e in self.edgesY] + if plotEz and self.dim==3: [e.plotGrid(ax, text=text) for e in self.edgesZ] ax.set_xlim((self.x0[0], self.h[0].sum())) ax.set_ylim((self.x0[1], self.h[1].sum())) @@ -797,7 +900,7 @@ if __name__ == '__main__': DIV = M.faceDiv # plt.subplot(211) # plt.spy(DIV) - M.plotGrid(ax=plt.subplot(111),text=True) + M.plotGrid(ax=plt.subplot(111),text=True,showIt=True) q = np.zeros(M.nC) q[208] = -1.0 diff --git a/SimPEG/tests/test_QuadTree.py b/SimPEG/Tests/test_TreeMesh.py similarity index 50% rename from SimPEG/tests/test_QuadTree.py rename to SimPEG/Tests/test_TreeMesh.py index 6c2ffdcd..3c10b64a 100644 --- a/SimPEG/tests/test_QuadTree.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -1,6 +1,7 @@ from SimPEG.Mesh.TreeMesh import TreeMesh, TreeFace, TreeCell import numpy as np import unittest +import matplotlib.pyplot as plt class TestOcTreeObjects(unittest.TestCase): @@ -9,31 +10,156 @@ class TestOcTreeObjects(unittest.TestCase): self.Mr = TreeMesh([2,1,1]) self.Mr.children[0,0,0].refine() self.Mr.number() - # self.Mr.plotGrid(showIt=True,plotC=True,plotF=True) def test_counts(self): + ax = plt.subplot(111,projection='3d') + # self.Mr.plotGrid(showIt=False,plotC=True,plotEy=True) + + cell = self.Mr.sortedCells[1] + [cell.edges[e].plotGrid(ax) for e in cell.edges] + cell.plotGrid(ax) + plt.show() + self.assertTrue(self.M.nC == 2) self.assertTrue(self.M.nFx == 3) self.assertTrue(self.M.nFy == 4) self.assertTrue(self.M.nFz == 4) self.assertTrue(self.M.nF == 11) + self.assertTrue(self.M.nEx == 8) + self.assertTrue(self.M.nEy == 6) + self.assertTrue(self.M.nEz == 6) + self.assertTrue(self.M.nE == 20) self.assertTrue(self.M.nN == 12) - print self.Mr.nN self.assertTrue(self.Mr.nC == 9) self.assertTrue(self.Mr.nFx == 13) self.assertTrue(self.Mr.nFy == 14) self.assertTrue(self.Mr.nFz == 14) self.assertTrue(self.Mr.nF == 41) - self.assertTrue(self.Mr.nN == 22) + cell = self.Mr.sortedCells[1] + self.assertTrue(cell.edges['eX0'].edgeType=='x') + self.assertTrue(cell.edges['eX1'].edgeType=='x') + self.assertTrue(cell.edges['eX2'].edgeType=='x') + self.assertTrue(cell.edges['eX3'].edgeType=='x') + self.assertTrue(cell.edges['eY0'].edgeType=='y') + self.assertTrue(cell.edges['eY1'].edgeType=='y') + self.assertTrue(cell.edges['eY2'].edgeType=='y') + self.assertTrue(cell.edges['eY3'].edgeType=='y') + self.assertTrue(cell.edges['eZ0'].edgeType=='z') + self.assertTrue(cell.edges['eZ1'].edgeType=='z') + self.assertTrue(cell.edges['eZ2'].edgeType=='z') + self.assertTrue(cell.edges['eZ3'].edgeType=='z') - # def test_pointersM(self): - # c0 = self.M.children[0,0,0] - # c0fXm = c0.faces['fXm'] - # c0fXp = c0.faces['fXp'] - # c0fYm = c0.faces['fYm'] - # c0fYp = c0.faces['fYp'] + print self.Mr.nN + # self.assertTrue(self.Mr.nN == 22) + + def test_pointersM(self): + c0 = self.M.children[0,0,0] + c0fXm = c0.faces['fXm'] + c0fXp = c0.faces['fXp'] + c0fYm = c0.faces['fYm'] + c0fYp = c0.faces['fYp'] + + c1 = self.M.children[1,0,0] + c1fXm = c1.faces['fXm'] + c1fXp = c1.faces['fXp'] + c1fYm = c1.faces['fYm'] + c1fYp = c1.faces['fYp'] + + self.assertTrue(c0fXp is c1fXm) + self.assertTrue(c0fXp.edges['e0'] is c1fXm.edges['e0']) + self.assertTrue(c0fXp.edges['e1'] is c1fXm.edges['e1']) + self.assertTrue(c0fXp.edges['e2'] is c1fXm.edges['e2']) + self.assertTrue(c0fXp.edges['e3'] is c1fXm.edges['e3']) + self.assertTrue(c0fYp is not c1fYm) + self.assertTrue(c0fXm is not c1fXm) + + + def test_pointersMr(self): + c0 = self.Mr.sortedCells[0] + c0fXm = c0.faces['fXm'] + c0fXp = c0.faces['fXp'] + c0fYm = c0.faces['fYm'] + c0fYp = c0.faces['fYp'] + c0fZm = c0.faces['fZm'] + c0fZp = c0.faces['fZp'] + self.assertTrue(np.all(c0.center==np.r_[0.125,0.25,0.25])) + + c1 = self.Mr.sortedCells[1] + c1fXm = c1.faces['fXm'] + c1fXp = c1.faces['fXp'] + c1fYm = c1.faces['fYm'] + c1fYp = c1.faces['fYp'] + c1fZm = c1.faces['fZm'] + c1fZp = c1.faces['fZp'] + self.assertTrue(np.all(c1.center==np.r_[0.375,0.25,0.25])) + + c2 = self.Mr.sortedCells[2] + c2fXm = c2.faces['fXm'] + c2fXp = c2.faces['fXp'] + c2fYm = c2.faces['fYm'] + c2fYp = c2.faces['fYp'] + c2fZm = c2.faces['fZm'] + c2fZp = c2.faces['fZp'] + self.assertTrue(np.all(c2.center==np.r_[0.75,0.5,0.5])) + + c4 = self.Mr.sortedCells[4] + c4fXm = c4.faces['fXm'] + c4fXp = c4.faces['fXp'] + c4fYm = c4.faces['fYm'] + c4fYp = c4.faces['fYp'] + c4fZm = c4.faces['fZm'] + c4fZp = c4.faces['fZp'] + self.assertTrue(np.all(c4.center==np.r_[0.375,0.75,0.25])) + + c6 = self.Mr.sortedCells[6] + c6fXm = c6.faces['fXm'] + c6fXp = c6.faces['fXp'] + c6fYm = c6.faces['fYm'] + c6fYp = c6.faces['fYp'] + c6fZm = c6.faces['fZm'] + c6fZp = c6.faces['fZp'] + self.assertTrue(np.all(c6.center==np.r_[0.375,0.25,0.75])) + + self.assertTrue(c0fXp is c1fXm) + self.assertTrue(c0fYp is not c1fYm) + self.assertTrue(c0fXm is not c1fXm) + + self.assertTrue(c1fXp is c2fXm.children[0,0]) + self.assertTrue(c1fXp.parent is c2fXm) + + self.assertTrue(c1fYp is c4fYm) + self.assertTrue(c1fZp is c6fZm) + + self.assertTrue(c6fXp is c2fXm.children[0,1]) + self.assertTrue(c6fXp.parent is c2fXm) + + self.assertTrue(c4fXp is c2fXm.children[1,0]) + self.assertTrue(c4fXp.parent is c2fXm) + + def test_gridCC(self): + x = np.r_[0.25,0.75] + y = np.r_[0.5,0.5] + z = np.r_[0.5,0.5] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridCC).flatten()) == 0) + + x = np.r_[0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.125,0.375] + y = np.r_[0.25,0.25,0.5,0.75,0.75,0.25,0.25,0.75,0.75] + z = np.r_[0.25,0.25,0.5,0.25,0.25,0.75,0.75,0.75,0.75] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridCC).flatten()) == 0) + + def test_gridFx(self): + x = np.r_[0.0,0.5,1.0] + y = np.r_[0.5,0.5,0.5] + z = np.r_[0.5,0.5,0.5] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridFx).flatten()) == 0) + + x = np.r_[0.0,0.25,0.5,1.0,0.0,0.25,0.5,0.0,0.25,0.5,0.0,0.25,0.5] + y = np.r_[0.25,0.25,0.25,0.5,0.75,0.75,0.75,0.25,0.25,0.25,0.75,0.75,0.75] + z = np.r_[0.25,0.25,0.25,0.5,0.25,0.25,0.25,0.75,0.75,0.75,0.75,0.75,0.75] + # print self.Mr.gridFx - np.c_[x,y,z] + # self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFx).flatten()) == 0) From b3c653a2359604257aaa10f67717735423f8c94b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 12:25:46 -0800 Subject: [PATCH 20/42] bug fixes to face centre locations. Lots more testing.. --- SimPEG/Mesh/TreeMesh.py | 37 ++++--- SimPEG/Tests/test_TreeMesh.py | 176 ++++++++++++++++++++-------------- 2 files changed, 123 insertions(+), 90 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 9d616480..82b2e5a7 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -43,10 +43,12 @@ class TreeObject(object): children = None #: children of the tree object num = None + depth = 0 - def __init__(self, mesh, parent): + def __init__(self, mesh, parent, depth): self.mesh = mesh self._parent = parent + self.depth = depth @property def parent(self): return self._parent @@ -60,11 +62,18 @@ class TreeObject(object): @property def center(self): return self.x0 + @property + def branchdepth(self): + if self.isleaf: + return self.depth + else: + return np.max([node.branchdepth for node in self.children.flatten('F')]) + class TreeNode(TreeObject): """docstring for TreeNode""" - def __init__(self, mesh, x0=[0,0], depth=0, parent=None): - TreeObject.__init__(self, mesh, parent) + def __init__(self, mesh, x0=[0,0], parent=None): + TreeObject.__init__(self, mesh, parent, 0) self.x0 = np.array(x0, dtype=float) self.mesh.nodes.add(self) @@ -74,10 +83,9 @@ class TreeEdge(TreeObject): def __init__(self, mesh, x0=[0,0], edgeType=None, sz=[1,], depth=0, node0=None, node1=None, parent=None): - TreeObject.__init__(self, mesh, parent) + TreeObject.__init__(self, mesh, parent, depth) self.x0 = np.array(x0, dtype=float) - self.depth = depth self.edgeType = edgeType self.sz = np.array(sz, dtype=float) @@ -114,9 +122,9 @@ class TreeEdge(TreeObject): elif self.edgeType is 'y': return np.r_[0,1.,0] elif self.edgeType is 'z': return np.r_[0,0,1.] - def plotGrid(self, ax, text=False): + def plotGrid(self, ax, text=False, lineOpts={'color':'r', 'ls': '-'}): line = np.c_[self.node0.x0, self.node1.x0].T - ax.plot(line[:,0], line[:,1],'r-', zs=line[:,2]) + ax.plot(line[:,0], line[:,1], zs=line[:,2], **lineOpts) class TreeFace(TreeObject): @@ -125,10 +133,9 @@ class TreeFace(TreeObject): node0=None, node1=None, edge0=None, edge1=None, edge2=None, edge3=None, parent=None): - TreeObject.__init__(self, mesh, parent) + TreeObject.__init__(self, mesh, parent, depth) self.x0 = np.array(x0, dtype=float) - self.depth = depth self.faceType = faceType self.sz = np.array(sz, dtype=float) @@ -272,7 +279,7 @@ class TreeFace(TreeObject): for O in order: i, j = O['c'] - x0r = 0.5*i*self.tangent0*self.sz[0] + 0.5*j*self.tangent1*self.sz[1] + x0r = self.x0 + 0.5*i*self.tangent0*self.sz[0] + 0.5*j*self.tangent1*self.sz[1] e0, e1, e2, e3 = getEdge(O['e0']), getEdge(O['e1']), getEdge(O['e2']), getEdge(O['e3']) self.children[i,j] = TreeFace(self.mesh, x0=x0r, faceType=self.faceType, depth=self.depth+1, sz=0.5*self.sz, parent=self, edge0=e0, edge1=e1, edge2=e2, edge3=e3) @@ -310,11 +317,10 @@ class TreeCell(TreeObject): fYm=None, fYp=None, fZm=None, fZp=None, parent=None): - TreeObject.__init__(self, mesh, parent) + TreeObject.__init__(self, mesh, parent, depth) self.x0 = np.array(x0, dtype=float) self.sz = np.array(sz, dtype=float) - self.depth = depth if self.dim == 2: # # 2___________3 @@ -422,13 +428,6 @@ class TreeCell(TreeObject): mesh.cells.add(self) - @property - def branchdepth(self): - if self.isleaf: - return self.depth - else: - return np.max([node.branchdepth for node in self.children.flatten('F')]) - @property def center(self): return self.x0 + 0.5*self.sz diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 3c10b64a..e906ec3e 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -7,19 +7,13 @@ class TestOcTreeObjects(unittest.TestCase): def setUp(self): self.M = TreeMesh([2,1,1]) + self.M.number() + self.Mr = TreeMesh([2,1,1]) self.Mr.children[0,0,0].refine() self.Mr.number() def test_counts(self): - ax = plt.subplot(111,projection='3d') - # self.Mr.plotGrid(showIt=False,plotC=True,plotEy=True) - - cell = self.Mr.sortedCells[1] - [cell.edges[e].plotGrid(ax) for e in cell.edges] - cell.plotGrid(ax) - plt.show() - self.assertTrue(self.M.nC == 2) self.assertTrue(self.M.nFx == 3) self.assertTrue(self.M.nFy == 4) @@ -37,22 +31,14 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(self.Mr.nFz == 14) self.assertTrue(self.Mr.nF == 41) - cell = self.Mr.sortedCells[1] - self.assertTrue(cell.edges['eX0'].edgeType=='x') - self.assertTrue(cell.edges['eX1'].edgeType=='x') - self.assertTrue(cell.edges['eX2'].edgeType=='x') - self.assertTrue(cell.edges['eX3'].edgeType=='x') - self.assertTrue(cell.edges['eY0'].edgeType=='y') - self.assertTrue(cell.edges['eY1'].edgeType=='y') - self.assertTrue(cell.edges['eY2'].edgeType=='y') - self.assertTrue(cell.edges['eY3'].edgeType=='y') - self.assertTrue(cell.edges['eZ0'].edgeType=='z') - self.assertTrue(cell.edges['eZ1'].edgeType=='z') - self.assertTrue(cell.edges['eZ2'].edgeType=='z') - self.assertTrue(cell.edges['eZ3'].edgeType=='z') - print self.Mr.nN + for cell in self.Mr.sortedCells: + for e in cell.edges: + self.assertTrue(cell.edges[e].edgeType==e[1].lower()) + + # print self.Mr.nEx # self.assertTrue(self.Mr.nN == 22) + # self.assertTrue(self.Mr.nEx == 22) def test_pointersM(self): c0 = self.M.children[0,0,0] @@ -60,12 +46,16 @@ class TestOcTreeObjects(unittest.TestCase): c0fXp = c0.faces['fXp'] c0fYm = c0.faces['fYm'] c0fYp = c0.faces['fYp'] + c0fZm = c0.faces['fZm'] + c0fZp = c0.faces['fZp'] c1 = self.M.children[1,0,0] c1fXm = c1.faces['fXm'] c1fXp = c1.faces['fXp'] c1fYm = c1.faces['fYm'] c1fYp = c1.faces['fYp'] + c1fZm = c1.faces['fZm'] + c1fZp = c1.faces['fZp'] self.assertTrue(c0fXp is c1fXm) self.assertTrue(c0fXp.edges['e0'] is c1fXm.edges['e0']) @@ -75,68 +65,112 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(c0fYp is not c1fYm) self.assertTrue(c0fXm is not c1fXm) + # Test connectivity of shared edges + self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e0']) + self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e1']) + self.assertTrue(c0fZp.edges['e3'] is c1fZp.edges['e2']) + self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e3']) + + self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e0']) + self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e1']) + self.assertTrue(c0fZm.edges['e3'] is c1fZm.edges['e2']) + self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e3']) + + self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e0']) + self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e1']) + self.assertTrue(c0fYp.edges['e3'] is c1fYp.edges['e2']) + self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e3']) + + self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e0']) + self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e1']) + self.assertTrue(c0fYm.edges['e3'] is c1fYm.edges['e2']) + self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e3']) + + self.assertTrue(c0fZm.edges['e3'] is c1fXm.edges['e0']) + self.assertTrue(c0fZp.edges['e3'] is c1fXm.edges['e1']) + self.assertTrue(c0fYm.edges['e3'] is c1fXm.edges['e2']) + self.assertTrue(c0fYp.edges['e3'] is c1fXm.edges['e3']) + + self.assertTrue(c0fZm.edges['e3'] is c0fXp.edges['e0']) + self.assertTrue(c0fZp.edges['e3'] is c0fXp.edges['e1']) + self.assertTrue(c0fYm.edges['e3'] is c0fXp.edges['e2']) + self.assertTrue(c0fYp.edges['e3'] is c0fXp.edges['e3']) + + self.assertTrue(c1fZm.edges['e2'] is c1fXm.edges['e0']) + self.assertTrue(c1fZp.edges['e2'] is c1fXm.edges['e1']) + self.assertTrue(c1fYm.edges['e2'] is c1fXm.edges['e2']) + self.assertTrue(c1fYp.edges['e2'] is c1fXm.edges['e3']) + + self.assertTrue(c1fZm.edges['e2'] is c0fXp.edges['e0']) + self.assertTrue(c1fZp.edges['e2'] is c0fXp.edges['e1']) + self.assertTrue(c1fYm.edges['e2'] is c0fXp.edges['e2']) + self.assertTrue(c1fYp.edges['e2'] is c0fXp.edges['e3']) + + def test_pointersMr(self): + ax = plt.subplot(111, projection='3d') + self.Mr.plotGrid(ax=ax,showIt=False,plotC=True,plotEy=True, text=False) + + cell = self.Mr.sortedCells[1] + [cell.edges[e].plotGrid(ax,lineOpts={'color':'b','ls':'-'}) for e in cell.edges] + cell.plotGrid(ax) + plt.show() + + def q(s): + c = self.Mr.sortedCells[int(s[1])] + if len(s) == 2: return c + if s[2] == 'f': return c.faces[s[2:]] + if s[2] == 'e': return c.edges[s[2:]] + c0 = self.Mr.sortedCells[0] c0fXm = c0.faces['fXm'] - c0fXp = c0.faces['fXp'] - c0fYm = c0.faces['fYm'] - c0fYp = c0.faces['fYp'] - c0fZm = c0.faces['fZm'] - c0fZp = c0.faces['fZp'] - self.assertTrue(np.all(c0.center==np.r_[0.125,0.25,0.25])) + c0eX0 = c0.edges['eX0'] + self.assertTrue(c0 is q('c0')) + self.assertTrue(c0fXm is q('c0fXm')) + self.assertTrue(c0eX0 is q('c0eX0')) - c1 = self.Mr.sortedCells[1] - c1fXm = c1.faces['fXm'] - c1fXp = c1.faces['fXp'] - c1fYm = c1.faces['fYm'] - c1fYp = c1.faces['fYp'] - c1fZm = c1.faces['fZm'] - c1fZp = c1.faces['fZp'] - self.assertTrue(np.all(c1.center==np.r_[0.375,0.25,0.25])) + self.assertTrue(q('c0').depth == 1) + self.assertTrue(q('c1').depth == 1) + self.assertTrue(q('c2').depth == 0) - c2 = self.Mr.sortedCells[2] - c2fXm = c2.faces['fXm'] - c2fXp = c2.faces['fXp'] - c2fYm = c2.faces['fYm'] - c2fYp = c2.faces['fYp'] - c2fZm = c2.faces['fZm'] - c2fZp = c2.faces['fZp'] - self.assertTrue(np.all(c2.center==np.r_[0.75,0.5,0.5])) + # Make sure we know where the center of the cells are. + self.assertTrue(np.all(q('c0').center == np.r_[0.125,0.25,0.25])) + self.assertTrue(np.all(q('c1').center == np.r_[0.375,0.25,0.25])) + self.assertTrue(np.all(q('c2').center == np.r_[0.75,0.5,0.5])) + self.assertTrue(np.all(q('c3').center == np.r_[0.125,0.75,0.25])) + self.assertTrue(np.all(q('c4').center == np.r_[0.375,0.75,0.25])) + self.assertTrue(np.all(q('c5').center == np.r_[0.125,0.25,0.75])) + self.assertTrue(np.all(q('c6').center == np.r_[0.375,0.25,0.75])) + self.assertTrue(np.all(q('c7').center == np.r_[0.125,0.75,0.75])) + self.assertTrue(np.all(q('c8').center == np.r_[0.375,0.75,0.75])) - c4 = self.Mr.sortedCells[4] - c4fXm = c4.faces['fXm'] - c4fXp = c4.faces['fXp'] - c4fYm = c4.faces['fYm'] - c4fYp = c4.faces['fYp'] - c4fZm = c4.faces['fZm'] - c4fZp = c4.faces['fZp'] - self.assertTrue(np.all(c4.center==np.r_[0.375,0.75,0.25])) + self.assertTrue(np.all(q('c0fXm').center == np.r_[0,0.25,0.25])) + self.assertTrue(np.all(q('c0fXp').center == np.r_[0.25,0.25,0.25])) + self.assertTrue(q('c0fXp') is q('c1fXm')) + self.assertTrue(np.all(q('c1fXp').center == np.r_[0.5,0.25,0.25])) + self.assertTrue(np.all(q('c2fXm').center == np.r_[0.5,0.5,0.5])) + self.assertTrue(q('c2fXm').branchdepth == 1) + self.assertTrue(q('c1fXp').parent is q('c2fXm')) + self.assertTrue(q('c2fXm').children[0,0] is q('c1fXp')) - c6 = self.Mr.sortedCells[6] - c6fXm = c6.faces['fXm'] - c6fXp = c6.faces['fXp'] - c6fYm = c6.faces['fYm'] - c6fYp = c6.faces['fYp'] - c6fZm = c6.faces['fZm'] - c6fZp = c6.faces['fZp'] - self.assertTrue(np.all(c6.center==np.r_[0.375,0.25,0.75])) + self.assertTrue(q('c0fXp') is q('c1fXm')) + self.assertTrue(q('c0fYp') is not q('c1fYm')) + self.assertTrue(q('c0fXm') is not q('c1fXm')) - self.assertTrue(c0fXp is c1fXm) - self.assertTrue(c0fYp is not c1fYm) - self.assertTrue(c0fXm is not c1fXm) + self.assertTrue(q('c1fXp') is q('c2fXm').children[0,0]) + self.assertTrue(q('c1fXp').parent is q('c2fXm')) - self.assertTrue(c1fXp is c2fXm.children[0,0]) - self.assertTrue(c1fXp.parent is c2fXm) + self.assertTrue(q('c1fYp') is q('c4fYm')) + self.assertTrue(q('c1fZp') is q('c6fZm')) - self.assertTrue(c1fYp is c4fYm) - self.assertTrue(c1fZp is c6fZm) + self.assertTrue(q('c6fXp') is q('c2fXm').children[0,1]) + self.assertTrue(q('c6fXp').parent is q('c2fXm')) - self.assertTrue(c6fXp is c2fXm.children[0,1]) - self.assertTrue(c6fXp.parent is c2fXm) + self.assertTrue(q('c4fXp') is q('c2fXm').children[1,0]) + self.assertTrue(q('c4fXp').parent is q('c2fXm')) - self.assertTrue(c4fXp is c2fXm.children[1,0]) - self.assertTrue(c4fXp.parent is c2fXm) + #TEST EDGES! def test_gridCC(self): x = np.r_[0.25,0.75] From cd30c0a4550c65eafbcd994bee55e9d27d8e4ebf Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 12:43:10 -0800 Subject: [PATCH 21/42] Refactor gridding code. --- SimPEG/Mesh/TreeMesh.py | 60 ++++++++++++++++++++--------------- SimPEG/Tests/test_TreeMesh.py | 5 ++- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 82b2e5a7..dacc5c66 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -59,9 +59,6 @@ class TreeObject(object): @property def isleaf(self): return self.children is None - @property - def center(self): return self.x0 - @property def branchdepth(self): if self.isleaf: @@ -77,6 +74,8 @@ class TreeNode(TreeObject): self.x0 = np.array(x0, dtype=float) self.mesh.nodes.add(self) + @property + def center(self): return self.x0 class TreeEdge(TreeObject): """docstring for TreeEdge""" @@ -126,6 +125,9 @@ class TreeEdge(TreeObject): line = np.c_[self.node0.x0, self.node1.x0].T ax.plot(line[:,0], line[:,1], zs=line[:,2], **lineOpts) + @property + def center(self): + return 0.5*(self.node0.x0 + self.node1.x0) class TreeFace(TreeObject): """docstring for TreeFace""" @@ -757,66 +759,72 @@ class TreeMesh(object): @property def nEz(self): return None if self.dim < 3 else len(self.edgesZ) + def _grid(self, key): + self.number() + sObjs = {'CC':self.sortedCells, + 'N':self.sortedNodes, + 'Fx': self.sortedFaceX, + 'Fy': self.sortedFaceY, + 'Fz': getattr(self,'sortedFaceZ', None), + 'Ex': getattr(self,'sortedEdgeX', self.sortedFaceY), + 'Ey': getattr(self,'sortedEdgeY', self.sortedFaceX), + 'Ez': getattr(self,'sortedEdgeZ', None)}[key] + G = np.empty((len(sObjs),self.dim)) + for ii, obj in enumerate(sObjs): + G[ii,:] = obj.center + return G + @property def gridCC(self): if getattr(self, '_gridCC', None) is None: - self.number() - self._gridCC = np.empty((self.nC,self.dim)) - for ii, cell in enumerate(self.sortedCells): - self._gridCC[ii,:] = cell.center + self._gridCC = self._grid('CC') return self._gridCC @property def gridN(self): if getattr(self, '_gridN', None) is None: - self.number() - self._gridN = np.empty((self.nN,self.dim)) - for ii, node in enumerate(self.sortedNodes): - self._gridN[ii,:] = node.center + self._gridN = self._grid('N') return self._gridN @property def gridFx(self): if getattr(self, '_gridFx', None) is None: - self.number() - self._gridFx = np.empty((self.nFx,self.dim)) - for ii, face in enumerate(self.sortedFaceX): - self._gridFx[ii,:] = face.center + self._gridFx = self._grid('Fx') return self._gridFx @property def gridFy(self): if getattr(self, '_gridFy', None) is None: - self.number() - self._gridFy = np.empty((self.nFy,self.dim)) - for ii, face in enumerate(self.sortedFaceY): - self._gridFy[ii,:] = face.center + self._gridFy = self._grid('Fy') return self._gridFy @property def gridFz(self): if self.dim == 2: return None if getattr(self, '_gridFz', None) is None: - self.number() - self._gridFz = np.emptz((self.nFz,self.dim)) - for ii, face in enumerate(self.sortedFaceZ): - self._gridFz[ii,:] = face.center + self._gridFz = self._grid('Fz') return self._gridFz @property def gridEx(self): if self.dim == 2: return self.gridFy - else: raise NotImplementedError('Edge Grid not yet implemented') + if getattr(self, '_gridEx', None) is None: + self._gridEx = self._grid('Ex') + return self._gridEx @property def gridEy(self): if self.dim == 2: return self.gridFx - else: raise NotImplementedError('Edge Grid not yet implemented') + if getattr(self, '_gridEy', None) is None: + self._gridEy = self._grid('Ey') + return self._gridEy @property def gridEz(self): if self.dim == 2: return None - else: raise NotImplementedError('Edge Grid not yet implemented') + if getattr(self, '_gridEz', None) is None: + self._gridEz = self._grid('Ez') + return self._gridEz @property def vol(self): diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index e906ec3e..71d020c1 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -36,7 +36,7 @@ class TestOcTreeObjects(unittest.TestCase): for e in cell.edges: self.assertTrue(cell.edges[e].edgeType==e[1].lower()) - # print self.Mr.nEx + print self.Mr.nEx # self.assertTrue(self.Mr.nN == 22) # self.assertTrue(self.Mr.nEx == 22) @@ -192,8 +192,7 @@ class TestOcTreeObjects(unittest.TestCase): x = np.r_[0.0,0.25,0.5,1.0,0.0,0.25,0.5,0.0,0.25,0.5,0.0,0.25,0.5] y = np.r_[0.25,0.25,0.25,0.5,0.75,0.75,0.75,0.25,0.25,0.25,0.75,0.75,0.75] z = np.r_[0.25,0.25,0.25,0.5,0.25,0.25,0.25,0.75,0.75,0.75,0.75,0.75,0.75] - # print self.Mr.gridFx - np.c_[x,y,z] - # self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFx).flatten()) == 0) + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFx).flatten()) == 0) From 1600058cb59016a720764f74eb7f2a5fc5059dde Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 14:49:08 -0800 Subject: [PATCH 22/42] 114 more tests! --- SimPEG/Mesh/TreeMesh.py | 11 ++-- SimPEG/Tests/test_TreeMesh.py | 120 ++++++++++++++++++++++++++++++++-- 2 files changed, 119 insertions(+), 12 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index dacc5c66..6ee3c76c 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -241,11 +241,6 @@ class TreeFace(TreeObject): self.mesh.facesY.remove(self) def _refine3D(self): - self.children = np.empty((2,2),dtype=TreeFace) - - for edgeName in self.edges: - self.edges[edgeName].refine() - # # 2_______________3 _______________ # | e1--> | | | | @@ -272,13 +267,17 @@ class TreeFace(TreeObject): 'e2': ('c', 'e3', [0,1]), 'e3': ('p', 'e3', [1])}] def getEdge(pointer): - return if pointer is 'new': return if pointer[0] == 'p': return self.edges[pointer[1]].children[pointer[2][0]] if pointer[0] == 'c': return self.children[pointer[2][0],pointer[2][1]].edges[pointer[1]] + self.children = np.empty((2,2), dtype=TreeFace) + + for edgeName in self.edges: + self.edges[edgeName].refine() + for O in order: i, j = O['c'] x0r = self.x0 + 0.5*i*self.tangent0*self.sz[0] + 0.5*j*self.tangent1*self.sz[1] diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 71d020c1..d2778974 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -36,9 +36,10 @@ class TestOcTreeObjects(unittest.TestCase): for e in cell.edges: self.assertTrue(cell.edges[e].edgeType==e[1].lower()) - print self.Mr.nEx # self.assertTrue(self.Mr.nN == 22) - # self.assertTrue(self.Mr.nEx == 22) + self.assertTrue(self.Mr.nEx == 22) + self.assertTrue(self.Mr.nEy == 20) + self.assertTrue(self.Mr.nEz == 20) def test_pointersM(self): c0 = self.M.children[0,0,0] @@ -112,23 +113,31 @@ class TestOcTreeObjects(unittest.TestCase): ax = plt.subplot(111, projection='3d') self.Mr.plotGrid(ax=ax,showIt=False,plotC=True,plotEy=True, text=False) - cell = self.Mr.sortedCells[1] + cell = self.Mr.sortedCells[0] [cell.edges[e].plotGrid(ax,lineOpts={'color':'b','ls':'-'}) for e in cell.edges] cell.plotGrid(ax) - plt.show() + # plt.show() def q(s): - c = self.Mr.sortedCells[int(s[1])] + if s[0] == 'M': + m = self.M + s = s[1:] + else: + m = self.Mr + c = m.sortedCells[int(s[1])] if len(s) == 2: return c - if s[2] == 'f': return c.faces[s[2:]] + if s[2] == 'f' and len(s) == 5: return c.faces[s[2:]] + if s[2] == 'f': return c.faces[s[2:5]].edges[s[5:]] if s[2] == 'e': return c.edges[s[2:]] c0 = self.Mr.sortedCells[0] c0fXm = c0.faces['fXm'] c0eX0 = c0.edges['eX0'] + c0fYme0 = c0.faces['fYm'].edges['e0'] self.assertTrue(c0 is q('c0')) self.assertTrue(c0fXm is q('c0fXm')) self.assertTrue(c0eX0 is q('c0eX0')) + self.assertTrue(c0fYme0 is q('c0fYme0')) self.assertTrue(q('c0').depth == 1) self.assertTrue(q('c1').depth == 1) @@ -145,6 +154,7 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(np.all(q('c7').center == np.r_[0.125,0.75,0.75])) self.assertTrue(np.all(q('c8').center == np.r_[0.375,0.75,0.75])) + # Test X face connectivity and locations and stuff... self.assertTrue(np.all(q('c0fXm').center == np.r_[0,0.25,0.25])) self.assertTrue(np.all(q('c0fXp').center == np.r_[0.25,0.25,0.25])) self.assertTrue(q('c0fXp') is q('c1fXm')) @@ -153,6 +163,75 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(q('c2fXm').branchdepth == 1) self.assertTrue(q('c1fXp').parent is q('c2fXm')) self.assertTrue(q('c2fXm').children[0,0] is q('c1fXp')) + self.assertTrue(np.all(q('c3fXm').center == np.r_[0,0.75,0.25])) + self.assertTrue(np.all(q('c3fXp').center == np.r_[0.25,0.75,0.25])) + self.assertTrue(q('c4fXm') is q('c3fXp')) + self.assertTrue(q('c2fXm').children[1,0] is q('c4fXp')) + + #Test some internal stuff (edges held by cell should be same as inside) + for key in ['Mc0', 'Mc1'] + ['c%d'%i for i in range(9)]: + self.assertTrue(q(key+'eX0') is q(key+'fZme0')) + self.assertTrue(q(key+'eX1') is q(key+'fZme1')) + self.assertTrue(q(key+'eX2') is q(key+'fZpe0')) + self.assertTrue(q(key+'eX3') is q(key+'fZpe1')) + + self.assertTrue(q(key+'eX0') is q(key+'fYme0')) + self.assertTrue(q(key+'eX1') is q(key+'fYpe0')) + self.assertTrue(q(key+'eX2') is q(key+'fYme1')) + self.assertTrue(q(key+'eX3') is q(key+'fYpe1')) + + self.assertTrue(q(key+'eY0') is q(key+'fXme0')) + self.assertTrue(q(key+'eY1') is q(key+'fXpe0')) + self.assertTrue(q(key+'eY2') is q(key+'fXme1')) + self.assertTrue(q(key+'eY3') is q(key+'fXpe1')) + + self.assertTrue(q(key+'eY0') is q(key+'fZme2')) + self.assertTrue(q(key+'eY1') is q(key+'fZme3')) + self.assertTrue(q(key+'eY2') is q(key+'fZpe2')) + self.assertTrue(q(key+'eY3') is q(key+'fZpe3')) + + self.assertTrue(q(key+'eZ0') is q(key+'fXme2')) + self.assertTrue(q(key+'eZ1') is q(key+'fXpe2')) + self.assertTrue(q(key+'eZ2') is q(key+'fXme3')) + self.assertTrue(q(key+'eZ3') is q(key+'fXpe3')) + + self.assertTrue(q(key+'eZ0') is q(key+'fYme2')) + self.assertTrue(q(key+'eZ1') is q(key+'fYme3')) + self.assertTrue(q(key+'eZ2') is q(key+'fYpe2')) + self.assertTrue(q(key+'eZ3') is q(key+'fYpe3')) + + #Test some edge stuff + self.assertTrue(np.all(q('c0eX0').center == np.r_[0.125,0,0])) + self.assertTrue(np.all(q('c0eX1').center == np.r_[0.125,0.5,0])) + self.assertTrue(np.all(q('c0eX2').center == np.r_[0.125,0,0.5])) + self.assertTrue(np.all(q('c0eX3').center == np.r_[0.125,0.5,0.5])) + + self.assertTrue(np.all(q('c5eX0').center == np.r_[0.125,0,0.5])) + self.assertTrue(np.all(q('c5eX1').center == np.r_[0.125,0.5,0.5])) + self.assertTrue(q('c5eX0') is q('c0eX2')) + self.assertTrue(q('c5eX1') is q('c0eX3')) + + self.assertTrue(np.all(q('c0eY0').center == np.r_[0,0.25,0])) + self.assertTrue(np.all(q('c0eY1').center == np.r_[0.25,0.25,0])) + self.assertTrue(np.all(q('c0eY2').center == np.r_[0,0.25,0.5])) + self.assertTrue(np.all(q('c0eY3').center == np.r_[0.25,0.25,0.5])) + + self.assertTrue(np.all(q('c1eY0').center == np.r_[0.25,0.25,0])) + self.assertTrue(np.all(q('c1eY2').center == np.r_[0.25,0.25,0.5])) + self.assertTrue(q('c1eY0') is q('c0eY1')) + self.assertTrue(q('c1eY2') is q('c0eY3')) + + + self.assertTrue(np.all(q('c0eZ0').center == np.r_[0,0,0.25])) + self.assertTrue(np.all(q('c0eZ1').center == np.r_[0.25,0,0.25])) + self.assertTrue(np.all(q('c0eZ2').center == np.r_[0,0.5,0.25])) + self.assertTrue(np.all(q('c0eZ3').center == np.r_[0.25,0.5,0.25])) + + self.assertTrue(np.all(q('c3eZ0').center == np.r_[0,0.5,0.25])) + self.assertTrue(np.all(q('c3eZ1').center == np.r_[0.25,0.5,0.25])) + self.assertTrue(q('c3eZ0') is q('c0eZ2')) + self.assertTrue(q('c3eZ1') is q('c0eZ3')) + self.assertTrue(q('c0fXp') is q('c1fXm')) self.assertTrue(q('c0fYp') is not q('c1fYm')) @@ -194,6 +273,35 @@ class TestOcTreeObjects(unittest.TestCase): z = np.r_[0.25,0.25,0.25,0.5,0.25,0.25,0.25,0.75,0.75,0.75,0.75,0.75,0.75] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFx).flatten()) == 0) + def test_gridFy(self): + x = np.r_[0.25,0.75,0.25,0.75] + y = np.r_[0,0,1.,1.] + z = np.r_[0.5,0.5,0.5,0.5] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridFy).flatten()) == 0) + + def test_gridFz(self): + x = np.r_[0.25,0.75,0.25,0.75] + y = np.r_[0.5,0.5,0.5,0.5] + z = np.r_[0,0,1.,1.] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridFz).flatten()) == 0) + + def test_gridEx(self): + x = np.r_[0.25,0.75,0.25,0.75,0.25,0.75,0.25,0.75] + y = np.r_[0,0,1.,1.,0,0,1.,1.] + z = np.r_[0,0,0,0,1.,1.,1.,1.] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEx).flatten()) == 0) + + def test_gridEy(self): + x = np.r_[0,0.5,1,0,0.5,1] + y = np.r_[0.5,0.5,0.5,0.5,0.5,0.5] + z = np.r_[0,0,0,1.,1.,1.] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEy).flatten()) == 0) + + def test_gridEz(self): + x = np.r_[0,0.5,1,0,0.5,1] + y = np.r_[0,0,0,1.,1.,1.] + z = np.r_[0.5,0.5,0.5,0.5,0.5,0.5] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEz).flatten()) == 0) From cd64da86d386768ab2b703541486aefaf91fa387 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 16:06:55 -0800 Subject: [PATCH 23/42] nodal grid test. --- SimPEG/Tests/test_TreeMesh.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index d2778974..2d5367c1 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -36,7 +36,7 @@ class TestOcTreeObjects(unittest.TestCase): for e in cell.edges: self.assertTrue(cell.edges[e].edgeType==e[1].lower()) - # self.assertTrue(self.Mr.nN == 22) + self.assertTrue(self.Mr.nN == 31) self.assertTrue(self.Mr.nEx == 22) self.assertTrue(self.Mr.nEy == 20) self.assertTrue(self.Mr.nEz == 20) @@ -262,6 +262,17 @@ class TestOcTreeObjects(unittest.TestCase): z = np.r_[0.25,0.25,0.5,0.25,0.25,0.75,0.75,0.75,0.75] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridCC).flatten()) == 0) + def test_gridN(self): + x = np.r_[0,0.5,1,0,0.5,1,0,0.5,1,0,0.5,1] + y = np.r_[0,0,0,1,1,1,0,0,0,1,1,1.] + z = np.r_[0,0,0,0,0,0,1,1,1,1,1,1.] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridN).flatten()) == 0) + + x = np.r_[0,0.25,0.5,1,0,0.25,0.5,0,0.25,0.5,1,0,0.25,0.5,0,0.25,0.5,0,0.25,0.5,0,0.25,0.5,1,0,0.25,0.5,0,0.25,0.5,1] + y = np.r_[0,0,0,0,0.5,0.5,0.5,1,1,1,1,0,0,0,0.5,0.5,0.5,1,1,1,0,0,0,0,0.5,0.5,0.5,1,1,1,1] + z = np.r_[0,0,0,0,0,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,1,1,1,1,1,1,1,1,1,1,1] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridN).flatten()) == 0) + def test_gridFx(self): x = np.r_[0.0,0.5,1.0] y = np.r_[0.5,0.5,0.5] From db73e4c018617d1379792f936ce0eb83c99d38a6 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 16:35:53 -0800 Subject: [PATCH 24/42] test all grids. --- SimPEG/Tests/test_TreeMesh.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 2d5367c1..cbeeaf6a 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -249,7 +249,6 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(q('c4fXp') is q('c2fXm').children[1,0]) self.assertTrue(q('c4fXp').parent is q('c2fXm')) - #TEST EDGES! def test_gridCC(self): x = np.r_[0.25,0.75] @@ -290,30 +289,55 @@ class TestOcTreeObjects(unittest.TestCase): z = np.r_[0.5,0.5,0.5,0.5] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridFy).flatten()) == 0) + x = np.r_[0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.125,0.375] + y = np.r_[0,0,0,0.5,0.5,1,1,1,0,0,0.5,0.5,1,1] + z = np.r_[0.25,0.25,0.5,0.25,0.25,0.25,0.25,0.5,0.75,0.75,0.75,0.75,0.75,0.75] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFy).flatten()) == 0) + def test_gridFz(self): x = np.r_[0.25,0.75,0.25,0.75] y = np.r_[0.5,0.5,0.5,0.5] z = np.r_[0,0,1.,1.] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridFz).flatten()) == 0) + x = np.r_[0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.125,0.375,0.125,0.375,0.75,0.125,0.375] + y = np.r_[0.25,0.25,0.5,0.75,0.75,0.25,0.25,0.75,0.75,0.25,0.25,0.5,0.75,0.75] + z = np.r_[0,0,0,0,0,0.5,0.5,0.5,0.5,1,1,1,1,1] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridFz).flatten()) == 0) + + def test_gridEx(self): x = np.r_[0.25,0.75,0.25,0.75,0.25,0.75,0.25,0.75] y = np.r_[0,0,1.,1.,0,0,1.,1.] z = np.r_[0,0,0,0,1.,1.,1.,1.] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEx).flatten()) == 0) + x = np.r_[0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.125,0.375,0.125,0.375,0.75,0.125,0.375,0.125,0.375,0.75] + y = np.r_[0,0,0,0.5,0.5,1,1,1,0,0,0.5,0.5,1,1,0,0,0,0.5,0.5,1,1,1] + z = np.r_[0,0,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0.5,0.5,1,1,1,1,1,1,1,1] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridEx).flatten()) == 0) + def test_gridEy(self): x = np.r_[0,0.5,1,0,0.5,1] y = np.r_[0.5,0.5,0.5,0.5,0.5,0.5] z = np.r_[0,0,0,1.,1.,1.] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEy).flatten()) == 0) + x = np.r_[0,0.25,0.5,1,0,0.25,0.5,0,0.25,0.5,0,0.25,0.5,0,0.25,0.5,1,0,0.25,0.5] + y = np.r_[0.25,0.25,0.25,0.5,0.75,0.75,0.75,0.25,0.25,0.25,0.75,0.75,0.75,0.25,0.25,0.25,0.5,0.75,0.75,0.75] + z = np.r_[0,0,0,0,0,0,0,0.5,0.5,0.5,0.5,0.5,0.5,1,1,1,1,1,1,1] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridEy).flatten()) == 0) + def test_gridEz(self): x = np.r_[0,0.5,1,0,0.5,1] y = np.r_[0,0,0,1.,1.,1.] z = np.r_[0.5,0.5,0.5,0.5,0.5,0.5] self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.M.gridEz).flatten()) == 0) + x = np.r_[0,0.25,0.5,1,0 ,0.25,0.5,0,0.25,0.5,1,0,0.25,0.5,0 ,0.25,0.5,0 ,0.25,0.5] + y = np.r_[0,0 ,0 ,0,0.5,0.5 ,0.5,1,1 ,1 ,1,0,0 ,0 ,0.5,0.5 ,0.5,1 ,1 ,1 ] + z = np.r_[0.25,0.25,0.25,0.5,0.25,0.25,0.25,0.25,0.25,0.25,0.5,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75] + self.assertTrue(np.linalg.norm((np.c_[x,y,z]-self.Mr.gridEz).flatten()) == 0) class TestQuadTreeObjects(unittest.TestCase): From 3bd4b0ee596bde2ba8fd797a8249da99cb2026b3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 17:35:55 -0800 Subject: [PATCH 25/42] bug fixes. --- SimPEG/Mesh/TreeMesh.py | 17 +++++++---- SimPEG/Tests/test_TreeMesh.py | 53 +++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 6ee3c76c..dec87423 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -212,7 +212,7 @@ class TreeFace(TreeObject): def index(self): if not self.mesh.isNumbered: raise Exception('Mesh is not numbered.') if self.isleaf: return np.r_[self.num] - return np.concatenate([face.index for face in self.children]) + return np.concatenate([face.index for face in self.children.flatten(order='F')]) @property def area(self): @@ -590,7 +590,7 @@ class TreeCell(TreeObject): j = self.faces[face].index i = j*0+self.num v = j*0+1 - if 'p' in face: + if 'm' in face: v *= -1 I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] return I, J, V @@ -671,7 +671,7 @@ class TreeMesh(object): x0i = (np.r_[x0[0], h[0][:i]]).sum() x0j = (np.r_[x0[1], h[1][:j]]).sum() x0k = (np.r_[x0[2], h[2][:k]]).sum() - self.children[i][j] = TreeCell(self, x0=[x0i, x0j, x0k], depth=0, sz=[h[0][i], h[1][j], h[2][k]], fXm=fXm, fYm=fYm, fZm=fZm) + self.children[i][j][k] = TreeCell(self, x0=[x0i, x0j, x0k], depth=0, sz=[h[0][i], h[1][j], h[2][k]], fXm=fXm, fYm=fYm, fZm=fZm) isNumbered = Utils.dependentProperty('_isNumbered', False, ['_faceDiv'], 'Setting this to False will delete all operators.') @@ -833,19 +833,24 @@ class TreeMesh(object): @property def area(self): self.number() - return np.concatenate(([face.area for face in self.sortedFaceX],[face.area for face in self.sortedFaceY])) + if self.dim == 2: + faces = self.sortedFaceX + self.sortedFaceY + elif self.dim == 3: + faces = self.sortedFaceX + self.sortedFaceY + self.sortedFaceZ + return np.array([face.area for face in faces], dtype=float) @property def faceDiv(self): if getattr(self, '_faceDiv', None) is None: self.number() + # TODO: Preallocate! I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in M.sortedCells: + for cell in self.sortedCells: i, j, v = cell.faceIndex I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] VOL = self.vol - D = sp.csr_matrix((V,(I,J)), shape=(M.nC, M.nF)) + D = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) S = self.area self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index cbeeaf6a..4abdfd05 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -1,3 +1,4 @@ +from SimPEG.Mesh import TensorMesh from SimPEG.Mesh.TreeMesh import TreeMesh, TreeFace, TreeCell import numpy as np import unittest @@ -13,6 +14,21 @@ class TestOcTreeObjects(unittest.TestCase): self.Mr.children[0,0,0].refine() self.Mr.number() + + def q(s): + if s[0] == 'M': + m = self.M + s = s[1:] + else: + m = self.Mr + c = m.sortedCells[int(s[1])] + if len(s) == 2: return c + if s[2] == 'f' and len(s) == 5: return c.faces[s[2:]] + if s[2] == 'f': return c.faces[s[2:5]].edges[s[5:]] + if s[2] == 'e': return c.edges[s[2:]] + + self.q = q + def test_counts(self): self.assertTrue(self.M.nC == 2) self.assertTrue(self.M.nFx == 3) @@ -41,6 +57,18 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(self.Mr.nEy == 20) self.assertTrue(self.Mr.nEz == 20) + def test_sizes(self): + q = self.q + + for key in ['Mc0','Mc1']: + self.assertTrue(q(key).vol == 0.5) + self.assertTrue(q(key+'fXm').area == 1.) + self.assertTrue(q(key+'fXp').area == 1.) + self.assertTrue(q(key+'fYm').area == 0.5) + self.assertTrue(q(key+'fYp').area == 0.5) + self.assertTrue(q(key+'fZm').area == 0.5) + self.assertTrue(q(key+'fZp').area == 0.5) + def test_pointersM(self): c0 = self.M.children[0,0,0] c0fXm = c0.faces['fXm'] @@ -118,17 +146,7 @@ class TestOcTreeObjects(unittest.TestCase): cell.plotGrid(ax) # plt.show() - def q(s): - if s[0] == 'M': - m = self.M - s = s[1:] - else: - m = self.Mr - c = m.sortedCells[int(s[1])] - if len(s) == 2: return c - if s[2] == 'f' and len(s) == 5: return c.faces[s[2:]] - if s[2] == 'f': return c.faces[s[2:5]].edges[s[5:]] - if s[2] == 'e': return c.edges[s[2:]] + q = self.q c0 = self.Mr.sortedCells[0] c0fXm = c0.faces['fXm'] @@ -465,6 +483,19 @@ class TestQuadTreeMesh(unittest.TestCase): self.assertTrue(np.linalg.norm((np.c_[x,y]-self.M.gridEy).flatten()) == 0) +class SimpleOctreeOperatorTests(unittest.TestCase): + + def setUp(self): + h1 = np.random.rand(5) + h2 = np.random.rand(7) + h3 = np.random.rand(3) + self.tM = TensorMesh([h1,h2,1]) + self.oM = TreeMesh([h1,h2,1]) + + def test_faceDiv(self): + print (self.tM.faceDiv - self.oM.faceDiv) + self.assertTrue((self.tM.faceDiv - self.oM.faceDiv).toarray().sum() == 0) + if __name__ == '__main__': unittest.main() From 534e229ab61d407134f3ddf88219c064562d21fd Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 18:53:15 -0800 Subject: [PATCH 26/42] refactor faceInnerProduct2D code to get ready for octree --- SimPEG/Mesh/InnerProducts.py | 126 ++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 45 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 9e7c1d93..7c16f9d0 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -230,8 +230,78 @@ def getFaceInnerProduct(mesh, mu=None, returnP=False): else: return A +def _getFacePxx(M): + return _getFacePxx_Rectangular(M) -def getFaceInnerProduct2D(mesh, mu=None, returnP=False): +def _getFacePxx_Rectangular(M): + """returns a function for creating projection matrices + + Mats takes you from faces a subset of all faces on only the + faces that you ask for. + + These are centered around a single nodes. + + For example, if this was your entire mesh: + + f3(Yp) + 2_______________3 + | | + | | + | | + f0(Xm) | x | f1(Xp) + | | + | | + |_______________| + 0 1 + f2(Ym) + + Pxx('m','m') = | 1, 0, 0, 0 | + | 0, 0, 1, 0 | + + Pxx('p','m') = | 0, 1, 0, 0 | + | 0, 0, 1, 0 | + + """ + i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) + + iijj = ndgrid(i, j) + ii, jj = iijj[:, 0], iijj[:, 1] + + if M._meshType == 'LOM': + fN1 = M.r(M.normals, 'F', 'Fx', 'M') + fN2 = M.r(M.normals, 'F', 'Fy', 'M') + + def Pxx(xFace, yFace): + """ + xFace is 'p' or 'm' + yFace is 'p' or 'm' + """ + # no | node | f1 | f2 + # 00 | i ,j | i , j | i, j + # 10 | i+1,j | i+1, j | i, j + # 01 | i ,j+1 | i , j | i, j+1 + # 11 | i+1,j+1 | i+1, j | i, j+1 + + posFx = 0 if xFace == 'm' else 1 + posFy = 0 if yFace == 'm' else 1 + + ind1 = sub2ind(M.nFx, np.c_[ii + posFx, jj]) + ind2 = sub2ind(M.nFy, np.c_[ii, jj + posFy]) + M.nFv[0] + + IND = np.r_[ind1, ind2].flatten() + + PXX = sp.csr_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nF))) + + if M._meshType == 'LOM': + I2x2 = inv2X2BlockDiagonal(getSubArray(fN1[0], [i + posFx, j]), getSubArray(fN1[1], [i + posFx, j]), + getSubArray(fN2[0], [i, j + posFy]), getSubArray(fN2[1], [i, j + posFy])) + PXX = I2x2 * PXX + + return PXX + + return Pxx + +def getFaceInnerProduct2D(M, mu=None, returnP=False): """ :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 2, or 3)) :param bool returnP: returns the projection matrices @@ -270,51 +340,20 @@ def getFaceInnerProduct2D(mesh, mu=None, returnP=False): """ if mu is None: # default is ones - mu = np.ones((mesh.nC, 1)) + mu = np.ones((M.nC, 1)) - m = np.array([mesh.nCx, mesh.nCy]) - nc = mesh.nC - - i, j = np.int64(range(m[0])), np.int64(range(m[1])) - - iijj = ndgrid(i, j) - ii, jj = iijj[:, 0], iijj[:, 1] - - if mesh._meshType == 'LOM': - fN1 = mesh.r(mesh.normals, 'F', 'Fx', 'M') - fN2 = mesh.r(mesh.normals, 'F', 'Fy', 'M') - - def Pxx(pos): - ind1 = sub2ind(mesh.nFx, np.c_[ii + pos[0][0], jj + pos[0][1]]) - ind2 = sub2ind(mesh.nFy, np.c_[ii + pos[1][0], jj + pos[1][1]]) + mesh.nFv[0] - - IND = np.r_[ind1, ind2].flatten() - - PXX = sp.coo_matrix((np.ones(2*nc), (range(2*nc), IND)), shape=(2*nc, np.sum(mesh.nF))).tocsr() - - if mesh._meshType == 'LOM': - I2x2 = inv2X2BlockDiagonal(getSubArray(fN1[0], [i + pos[0][0], j + pos[0][1]]), getSubArray(fN1[1], [i + pos[0][0], j + pos[0][1]]), - getSubArray(fN2[0], [i + pos[1][0], j + pos[1][1]]), getSubArray(fN2[1], [i + pos[1][0], j + pos[1][1]])) - PXX = I2x2 * PXX - - return PXX - - # no | node | f1 | f2 - # 00 | i ,j | i , j | i, j - # 10 | i+1,j | i+1, j | i, j - # 01 | i ,j+1 | i , j | i, j+1 - # 11 | i+1,j+1 | i+1, j | i, j+1 + Pxx = _getFacePxx(M) # Square root of cell volume multiplied by 1/4 - v = np.sqrt(0.25*mesh.vol) + v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - P00 = V2*Pxx([[0, 0], [0, 0]]) - P10 = V2*Pxx([[1, 0], [0, 0]]) - P01 = V2*Pxx([[0, 0], [0, 1]]) - P11 = V2*Pxx([[1, 0], [0, 1]]) + P00 = V2*Pxx('m', 'm') + P10 = V2*Pxx('p', 'm') + P01 = V2*Pxx('m', 'p') + P11 = V2*Pxx('p', 'p') - if mu.size == mesh.nC: # Isotropic! + if mu.size == M.nC: # Isotropic! mu = mkvc(mu) # ensure it is a vector. Mu = sdiag(np.r_[mu, mu]) elif mu.shape[1] == 2: # Diagonal tensor @@ -372,10 +411,7 @@ def getEdgeInnerProduct(mesh, sigma=None, returnP=False): if sigma is None: # default is ones sigma = np.ones((mesh.nC, 1)) - m = np.array([mesh.nCx, mesh.nCy, mesh.nCz]) - nc = mesh.nC - - i, j, k = np.int64(range(m[0])), np.int64(range(m[1])), np.int64(range(m[2])) + i, j, k = np.int64(range(mesh.nCx)), np.int64(range(mesh.nCy)), np.int64(range(mesh.nCz)) iijjkk = ndgrid(i, j, k) ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] @@ -392,7 +428,7 @@ def getEdgeInnerProduct(mesh, sigma=None, returnP=False): IND = np.r_[ind1, ind2, ind3].flatten() - PXXX = sp.coo_matrix((np.ones(3*nc), (range(3*nc), IND)), shape=(3*nc, np.sum(mesh.nE))).tocsr() + PXXX = sp.coo_matrix((np.ones(3*mesh.nC), (range(3*mesh.nC), IND)), shape=(3*mesh.nC, np.sum(mesh.nE))).tocsr() if mesh._meshType == 'LOM': I3x3 = inv3X3BlockDiagonal(getSubArray(eT1[0], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(eT1[1], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(eT1[2], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), From dba255b64e7c990de1dd50515351a29ce47e4d3c Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 21:01:00 -0800 Subject: [PATCH 27/42] refactoring --- SimPEG/Mesh/InnerProducts.py | 159 +++++++++++++++++------------------ 1 file changed, 78 insertions(+), 81 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 7c16f9d0..f2109f52 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -122,7 +122,7 @@ class InnerProducts(object): # node(i+1,j,k) ------ edge2(i+1,j,k) ----- node(i+1,j+1,k) -def getFaceInnerProduct(mesh, mu=None, returnP=False): +def getFaceInnerProduct(M, mu=None, returnP=False): """ :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) :param bool returnP: returns the projection matrices @@ -157,34 +157,31 @@ def getFaceInnerProduct(mesh, mu=None, returnP=False): """ if mu is None: # default is ones - mu = np.ones((mesh.nC, 1)) + mu = np.ones((M.nC, 1)) - m = np.array([mesh.nCx, mesh.nCy, mesh.nCz]) - nc = mesh.nC - - i, j, k = np.int64(range(m[0])), np.int64(range(m[1])), np.int64(range(m[2])) + i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) iijjkk = ndgrid(i, j, k) ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] - if mesh._meshType == 'LOM': - fN1 = mesh.r(mesh.normals, 'F', 'Fx', 'M') - fN2 = mesh.r(mesh.normals, 'F', 'Fy', 'M') - fN3 = mesh.r(mesh.normals, 'F', 'Fz', 'M') + if M._meshType == 'LOM': + fN1 = M.r(M.normals, 'F', 'Fx', 'M') + fN2 = M.r(M.normals, 'F', 'Fy', 'M') + fN3 = M.r(M.normals, 'F', 'Fz', 'M') - def Pxxx(pos): - ind1 = sub2ind(mesh.nFx, np.c_[ii + pos[0][0], jj + pos[0][1], kk + pos[0][2]]) - ind2 = sub2ind(mesh.nFy, np.c_[ii + pos[1][0], jj + pos[1][1], kk + pos[1][2]]) + mesh.nFv[0] - ind3 = sub2ind(mesh.nFz, np.c_[ii + pos[2][0], jj + pos[2][1], kk + pos[2][2]]) + mesh.nFv[0] + mesh.nFv[1] + def Pxxx(posX, posY, posZ): + ind1 = sub2ind(M.nFx, np.c_[ii + posX[0], jj + posX[1], kk + posX[2]]) + ind2 = sub2ind(M.nFy, np.c_[ii + posY[0], jj + posY[1], kk + posY[2]]) + M.nFv[0] + ind3 = sub2ind(M.nFz, np.c_[ii + posZ[0], jj + posZ[1], kk + posZ[2]]) + M.nFv[0] + M.nFv[1] IND = np.r_[ind1, ind2, ind3].flatten() - PXXX = sp.coo_matrix((np.ones(3*nc), (range(3*nc), IND)), shape=(3*nc, np.sum(mesh.nF))).tocsr() + PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nF))).tocsr() - if mesh._meshType == 'LOM': - I3x3 = inv3X3BlockDiagonal(getSubArray(fN1[0], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(fN1[1], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(fN1[2], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), - getSubArray(fN2[0], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), getSubArray(fN2[1], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), getSubArray(fN2[2], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), - getSubArray(fN3[0], [i + pos[2][0], j + pos[2][1], k + pos[2][2]]), getSubArray(fN3[1], [i + pos[2][0], j + pos[2][1], k + pos[2][2]]), getSubArray(fN3[2], [i + pos[2][0], j + pos[2][1], k + pos[2][2]])) + if M._meshType == 'LOM': + I3x3 = inv3X3BlockDiagonal(getSubArray(fN1[0], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(fN1[1], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(fN1[2], [i + posX[0], j + posX[1], k + posX[2]]), + getSubArray(fN2[0], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(fN2[1], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(fN2[2], [i + posY[0], j + posY[1], k + posY[2]]), + getSubArray(fN3[0], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(fN3[1], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(fN3[2], [i + posZ[0], j + posZ[1], k + posZ[2]])) PXXX = I3x3 * PXXX return PXXX @@ -200,19 +197,19 @@ def getFaceInnerProduct(mesh, mu=None, returnP=False): # 111 | i+1,j+1,k+1 | i+1, j, k | i, j+1, k | i, j, k+1 # Square root of cell volume multiplied by 1/8 - v = np.sqrt(0.125*mesh.vol) + v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - P000 = V3*Pxxx([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) - P100 = V3*Pxxx([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) - P010 = V3*Pxxx([[0, 0, 0], [0, 1, 0], [0, 0, 0]]) - P110 = V3*Pxxx([[1, 0, 0], [0, 1, 0], [0, 0, 0]]) - P001 = V3*Pxxx([[0, 0, 0], [0, 0, 0], [0, 0, 1]]) - P101 = V3*Pxxx([[1, 0, 0], [0, 0, 0], [0, 0, 1]]) - P011 = V3*Pxxx([[0, 0, 0], [0, 1, 0], [0, 0, 1]]) - P111 = V3*Pxxx([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) + P000 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 0]) + P100 = V3*Pxxx([1, 0, 0], [0, 0, 0], [0, 0, 0]) + P010 = V3*Pxxx([0, 0, 0], [0, 1, 0], [0, 0, 0]) + P110 = V3*Pxxx([1, 0, 0], [0, 1, 0], [0, 0, 0]) + P001 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 1]) + P101 = V3*Pxxx([1, 0, 0], [0, 0, 0], [0, 0, 1]) + P011 = V3*Pxxx([0, 0, 0], [0, 1, 0], [0, 0, 1]) + P111 = V3*Pxxx([1, 0, 0], [0, 1, 0], [0, 0, 1]) - if mu.size == mesh.nC: # Isotropic! + if mu.size == M.nC: # Isotropic! mu = mkvc(mu) # ensure it is a vector. Mu = sdiag(np.r_[mu, mu, mu]) elif mu.shape[1] == 3: # Diagonal tensor @@ -231,6 +228,9 @@ def getFaceInnerProduct(mesh, mu=None, returnP=False): return A def _getFacePxx(M): + if M._meshType == 'TREE': + return M._getFacePxx + return _getFacePxx_Rectangular(M) def _getFacePxx_Rectangular(M): @@ -371,7 +371,7 @@ def getFaceInnerProduct2D(M, mu=None, returnP=False): return A -def getEdgeInnerProduct(mesh, sigma=None, returnP=False): +def getEdgeInnerProduct(M, sigma=None, returnP=False): """ :param numpy.array sigma: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) :param bool returnP: returns the projection matrices @@ -409,31 +409,31 @@ def getEdgeInnerProduct(mesh, sigma=None, returnP=False): """ if sigma is None: # default is ones - sigma = np.ones((mesh.nC, 1)) + sigma = np.ones((M.nC, 1)) - i, j, k = np.int64(range(mesh.nCx)), np.int64(range(mesh.nCy)), np.int64(range(mesh.nCz)) + i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) iijjkk = ndgrid(i, j, k) ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] - if mesh._meshType == 'LOM': - eT1 = mesh.r(mesh.tangents, 'E', 'Ex', 'M') - eT2 = mesh.r(mesh.tangents, 'E', 'Ey', 'M') - eT3 = mesh.r(mesh.tangents, 'E', 'Ez', 'M') + if M._meshType == 'LOM': + eT1 = M.r(M.tangents, 'E', 'Ex', 'M') + eT2 = M.r(M.tangents, 'E', 'Ey', 'M') + eT3 = M.r(M.tangents, 'E', 'Ez', 'M') - def Pxxx(pos): - ind1 = sub2ind(mesh.nEx, np.c_[ii + pos[0][0], jj + pos[0][1], kk + pos[0][2]]) - ind2 = sub2ind(mesh.nEy, np.c_[ii + pos[1][0], jj + pos[1][1], kk + pos[1][2]]) + mesh.nEv[0] - ind3 = sub2ind(mesh.nEz, np.c_[ii + pos[2][0], jj + pos[2][1], kk + pos[2][2]]) + mesh.nEv[0] + mesh.nEv[1] + def Pxxx(posX, posY, posZ): + ind1 = sub2ind(M.nEx, np.c_[ii + posX[0], jj + posX[1], kk + posX[2]]) + ind2 = sub2ind(M.nEy, np.c_[ii + posY[0], jj + posY[1], kk + posY[2]]) + M.nEv[0] + ind3 = sub2ind(M.nEz, np.c_[ii + posZ[0], jj + posZ[1], kk + posZ[2]]) + M.nEv[0] + M.nEv[1] IND = np.r_[ind1, ind2, ind3].flatten() - PXXX = sp.coo_matrix((np.ones(3*mesh.nC), (range(3*mesh.nC), IND)), shape=(3*mesh.nC, np.sum(mesh.nE))).tocsr() + PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nE))).tocsr() - if mesh._meshType == 'LOM': - I3x3 = inv3X3BlockDiagonal(getSubArray(eT1[0], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(eT1[1], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), getSubArray(eT1[2], [i + pos[0][0], j + pos[0][1], k + pos[0][2]]), - getSubArray(eT2[0], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), getSubArray(eT2[1], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), getSubArray(eT2[2], [i + pos[1][0], j + pos[1][1], k + pos[1][2]]), - getSubArray(eT3[0], [i + pos[2][0], j + pos[2][1], k + pos[2][2]]), getSubArray(eT3[1], [i + pos[2][0], j + pos[2][1], k + pos[2][2]]), getSubArray(eT3[2], [i + pos[2][0], j + pos[2][1], k + pos[2][2]])) + if M._meshType == 'LOM': + I3x3 = inv3X3BlockDiagonal(getSubArray(eT1[0], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(eT1[1], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(eT1[2], [i + posX[0], j + posX[1], k + posX[2]]), + getSubArray(eT2[0], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(eT2[1], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(eT2[2], [i + posY[0], j + posY[1], k + posY[2]]), + getSubArray(eT3[0], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(eT3[1], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(eT3[2], [i + posZ[0], j + posZ[1], k + posZ[2]])) PXXX = I3x3 * PXXX return PXXX @@ -449,19 +449,19 @@ def getEdgeInnerProduct(mesh, sigma=None, returnP=False): # 111 | i+1,j+1,k+1 | i ,j+1,k+1 | i+1,j ,k+1 | i+1,j+1,k # Square root of cell volume multiplied by 1/8 - v = np.sqrt(0.125*mesh.vol) + v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - P000 = V3*Pxxx([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) - P100 = V3*Pxxx([[0, 0, 0], [1, 0, 0], [1, 0, 0]]) - P010 = V3*Pxxx([[0, 1, 0], [0, 0, 0], [0, 1, 0]]) - P110 = V3*Pxxx([[0, 1, 0], [1, 0, 0], [1, 1, 0]]) - P001 = V3*Pxxx([[0, 0, 1], [0, 0, 1], [0, 0, 0]]) - P101 = V3*Pxxx([[0, 0, 1], [1, 0, 1], [1, 0, 0]]) - P011 = V3*Pxxx([[0, 1, 1], [0, 0, 1], [0, 1, 0]]) - P111 = V3*Pxxx([[0, 1, 1], [1, 0, 1], [1, 1, 0]]) + P000 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 0]) + P100 = V3*Pxxx([0, 0, 0], [1, 0, 0], [1, 0, 0]) + P010 = V3*Pxxx([0, 1, 0], [0, 0, 0], [0, 1, 0]) + P110 = V3*Pxxx([0, 1, 0], [1, 0, 0], [1, 1, 0]) + P001 = V3*Pxxx([0, 0, 1], [0, 0, 1], [0, 0, 0]) + P101 = V3*Pxxx([0, 0, 1], [1, 0, 1], [1, 0, 0]) + P011 = V3*Pxxx([0, 1, 1], [0, 0, 1], [0, 1, 0]) + P111 = V3*Pxxx([0, 1, 1], [1, 0, 1], [1, 1, 0]) - if sigma.size == mesh.nC: # Isotropic! + if sigma.size == M.nC: # Isotropic! sigma = mkvc(sigma) # ensure it is a vector. Sigma = sdiag(np.r_[sigma, sigma, sigma]) elif sigma.shape[1] == 3: # Diagonal tensor @@ -480,7 +480,7 @@ def getEdgeInnerProduct(mesh, sigma=None, returnP=False): return A -def getEdgeInnerProduct2D(mesh, sigma=None, returnP=False): +def getEdgeInnerProduct2D(M, sigma=None, returnP=False): """ :param numpy.array sigma: material property (tensor properties are possible) at each cell center (nC, (1, 2, or 3)) :param bool returnP: returns the projection matrices @@ -519,31 +519,28 @@ def getEdgeInnerProduct2D(mesh, sigma=None, returnP=False): """ if sigma is None: # default is ones - sigma = np.ones((mesh.nC, 1)) + sigma = np.ones((M.nC, 1)) - m = np.array([mesh.nCx, mesh.nCy]) - nc = mesh.nC - - i, j = np.int64(range(m[0])), np.int64(range(m[1])) + i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) iijj = ndgrid(i, j) ii, jj = iijj[:, 0], iijj[:, 1] - if mesh._meshType == 'LOM': - eT1 = mesh.r(mesh.tangents, 'E', 'Ex', 'M') - eT2 = mesh.r(mesh.tangents, 'E', 'Ey', 'M') + if M._meshType == 'LOM': + eT1 = M.r(M.tangents, 'E', 'Ex', 'M') + eT2 = M.r(M.tangents, 'E', 'Ey', 'M') - def Pxx(pos): - ind1 = sub2ind(mesh.nEx, np.c_[ii + pos[0][0], jj + pos[0][1]]) - ind2 = sub2ind(mesh.nEy, np.c_[ii + pos[1][0], jj + pos[1][1]]) + mesh.nEv[0] + def Pxx(posX, posY): + ind1 = sub2ind(M.nEx, np.c_[ii + posX[0], jj + posX[1]]) + ind2 = sub2ind(M.nEy, np.c_[ii + posY[0], jj + posY[1]]) + M.nEv[0] IND = np.r_[ind1, ind2].flatten() - PXX = sp.coo_matrix((np.ones(2*nc), (range(2*nc), IND)), shape=(2*nc, np.sum(mesh.nE))).tocsr() + PXX = sp.coo_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nE))).tocsr() - if mesh._meshType == 'LOM': - I2x2 = inv2X2BlockDiagonal(getSubArray(eT1[0], [i + pos[0][0], j + pos[0][1]]), getSubArray(eT1[1], [i + pos[0][0], j + pos[0][1]]), - getSubArray(eT2[0], [i + pos[1][0], j + pos[1][1]]), getSubArray(eT2[1], [i + pos[1][0], j + pos[1][1]])) + if M._meshType == 'LOM': + I2x2 = inv2X2BlockDiagonal(getSubArray(eT1[0], [i + posX[0], j + posX[1]]), getSubArray(eT1[1], [i + posX[0], j + posX[1]]), + getSubArray(eT2[0], [i + posY[0], j + posY[1]]), getSubArray(eT2[1], [i + posY[0], j + posY[1]])) PXX = I2x2 * PXX return PXX @@ -555,15 +552,15 @@ def getEdgeInnerProduct2D(mesh, sigma=None, returnP=False): # 11 | i+1,j+1 | i ,j+1 | i+1,j # Square root of cell volume multiplied by 1/4 - v = np.sqrt(0.25*mesh.vol) + v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - P00 = V2*Pxx([[0, 0], [0, 0]]) - P10 = V2*Pxx([[0, 0], [1, 0]]) - P01 = V2*Pxx([[0, 1], [0, 0]]) - P11 = V2*Pxx([[0, 1], [1, 0]]) + P00 = V2*Pxx([0, 0], [0, 0]) + P10 = V2*Pxx([0, 0], [1, 0]) + P01 = V2*Pxx([0, 1], [0, 0]) + P11 = V2*Pxx([0, 1], [1, 0]) - if sigma.size == mesh.nC: # Isotropic! + if sigma.size == M.nC: # Isotropic! sigma = mkvc(sigma) # ensure it is a vector. Sigma = sdiag(np.r_[sigma, sigma]) elif sigma.shape[1] == 2: # Diagonal tensor @@ -584,7 +581,7 @@ def getEdgeInnerProduct2D(mesh, sigma=None, returnP=False): if __name__ == '__main__': from TensorMesh import TensorMesh h = [np.array([1, 2, 3, 4]), np.array([1, 2, 1, 4, 2]), np.array([1, 1, 4, 1])] - mesh = TensorMesh(h) - mu = np.ones((mesh.nC, 6)) - A, P = mesh.getFaceInnerProduct(mu, returnP=True) - B, P = mesh.getEdgeInnerProduct(mu, returnP=True) + M = TensorMesh(h) + mu = np.ones((M.nC, 6)) + A, P = M.getFaceInnerProduct(mu, returnP=True) + B, P = M.getEdgeInnerProduct(mu, returnP=True) From f729d1f4f986fefb96d594e3e93b0d17f302e2ba Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 21:12:08 -0800 Subject: [PATCH 28/42] refactor faceInProd 3D --- SimPEG/Mesh/InnerProducts.py | 106 ++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index f2109f52..73ad25eb 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -121,6 +121,57 @@ class InnerProducts(object): # | |/ # node(i+1,j,k) ------ edge2(i+1,j,k) ----- node(i+1,j+1,k) +def _getFacePxxx(M): + if M._meshType == 'TREE': + return M._getFacePxxx + + return _getFacePxxx_Rectangular(M) + +def _getFacePxxx_Rectangular(M): + + i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) + + iijjkk = ndgrid(i, j, k) + ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] + + if M._meshType == 'LOM': + fN1 = M.r(M.normals, 'F', 'Fx', 'M') + fN2 = M.r(M.normals, 'F', 'Fy', 'M') + fN3 = M.r(M.normals, 'F', 'Fz', 'M') + + def Pxxx(xFace, yFace, zFace): + + # no | node | f1 | f2 | f3 + # 000 | i ,j ,k | i , j, k | i, j , k | i, j, k + # 100 | i+1,j ,k | i+1, j, k | i, j , k | i, j, k + # 010 | i ,j+1,k | i , j, k | i, j+1, k | i, j, k + # 110 | i+1,j+1,k | i+1, j, k | i, j+1, k | i, j, k + # 001 | i ,j ,k+1 | i , j, k | i, j , k | i, j, k+1 + # 101 | i+1,j ,k+1 | i+1, j, k | i, j , k | i, j, k+1 + # 011 | i ,j+1,k+1 | i , j, k | i, j+1, k | i, j, k+1 + # 111 | i+1,j+1,k+1 | i+1, j, k | i, j+1, k | i, j, k+1 + + posX = 0 if xFace == 'm' else 1 + posY = 0 if yFace == 'm' else 1 + posZ = 0 if zFace == 'm' else 1 + + ind1 = sub2ind(M.nFx, np.c_[ii + posX, jj, kk]) + ind2 = sub2ind(M.nFy, np.c_[ii, jj + posY, kk]) + M.nFv[0] + ind3 = sub2ind(M.nFz, np.c_[ii, jj, kk + posZ]) + M.nFv[0] + M.nFv[1] + + IND = np.r_[ind1, ind2, ind3].flatten() + + PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nF))).tocsr() + + if M._meshType == 'LOM': + I3x3 = inv3X3BlockDiagonal(getSubArray(fN1[0], [i + posX, j, k]), getSubArray(fN1[1], [i + posX, j, k]), getSubArray(fN1[2], [i + posX, j, k]), + getSubArray(fN2[0], [i, j + posY, k]), getSubArray(fN2[1], [i, j + posY, k]), getSubArray(fN2[2], [i, j + posY, k]), + getSubArray(fN3[0], [i, j, k + posZ]), getSubArray(fN3[1], [i, j, k + posZ]), getSubArray(fN3[2], [i, j, k + posZ])) + PXXX = I3x3 * PXXX + + return PXXX + return Pxxx + def getFaceInnerProduct(M, mu=None, returnP=False): """ @@ -159,55 +210,20 @@ def getFaceInnerProduct(M, mu=None, returnP=False): if mu is None: # default is ones mu = np.ones((M.nC, 1)) - i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) - - iijjkk = ndgrid(i, j, k) - ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] - - if M._meshType == 'LOM': - fN1 = M.r(M.normals, 'F', 'Fx', 'M') - fN2 = M.r(M.normals, 'F', 'Fy', 'M') - fN3 = M.r(M.normals, 'F', 'Fz', 'M') - - def Pxxx(posX, posY, posZ): - ind1 = sub2ind(M.nFx, np.c_[ii + posX[0], jj + posX[1], kk + posX[2]]) - ind2 = sub2ind(M.nFy, np.c_[ii + posY[0], jj + posY[1], kk + posY[2]]) + M.nFv[0] - ind3 = sub2ind(M.nFz, np.c_[ii + posZ[0], jj + posZ[1], kk + posZ[2]]) + M.nFv[0] + M.nFv[1] - - IND = np.r_[ind1, ind2, ind3].flatten() - - PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nF))).tocsr() - - if M._meshType == 'LOM': - I3x3 = inv3X3BlockDiagonal(getSubArray(fN1[0], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(fN1[1], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(fN1[2], [i + posX[0], j + posX[1], k + posX[2]]), - getSubArray(fN2[0], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(fN2[1], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(fN2[2], [i + posY[0], j + posY[1], k + posY[2]]), - getSubArray(fN3[0], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(fN3[1], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(fN3[2], [i + posZ[0], j + posZ[1], k + posZ[2]])) - PXXX = I3x3 * PXXX - - return PXXX - - # no | node | f1 | f2 | f3 - # 000 | i ,j ,k | i , j, k | i, j , k | i, j, k - # 100 | i+1,j ,k | i+1, j, k | i, j , k | i, j, k - # 010 | i ,j+1,k | i , j, k | i, j+1, k | i, j, k - # 110 | i+1,j+1,k | i+1, j, k | i, j+1, k | i, j, k - # 001 | i ,j ,k+1 | i , j, k | i, j , k | i, j, k+1 - # 101 | i+1,j ,k+1 | i+1, j, k | i, j , k | i, j, k+1 - # 011 | i ,j+1,k+1 | i , j, k | i, j+1, k | i, j, k+1 - # 111 | i+1,j+1,k+1 | i+1, j, k | i, j+1, k | i, j, k+1 - # Square root of cell volume multiplied by 1/8 v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - P000 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 0]) - P100 = V3*Pxxx([1, 0, 0], [0, 0, 0], [0, 0, 0]) - P010 = V3*Pxxx([0, 0, 0], [0, 1, 0], [0, 0, 0]) - P110 = V3*Pxxx([1, 0, 0], [0, 1, 0], [0, 0, 0]) - P001 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 1]) - P101 = V3*Pxxx([1, 0, 0], [0, 0, 0], [0, 0, 1]) - P011 = V3*Pxxx([0, 0, 0], [0, 1, 0], [0, 0, 1]) - P111 = V3*Pxxx([1, 0, 0], [0, 1, 0], [0, 0, 1]) + Pxxx = _getFacePxxx(M) + + P000 = V3*Pxxx('m', 'm', 'm') + P100 = V3*Pxxx('p', 'm', 'm') + P010 = V3*Pxxx('m', 'p', 'm') + P110 = V3*Pxxx('p', 'p', 'm') + P001 = V3*Pxxx('m', 'm', 'p') + P101 = V3*Pxxx('p', 'm', 'p') + P011 = V3*Pxxx('m', 'p', 'p') + P111 = V3*Pxxx('p', 'p', 'p') if mu.size == M.nC: # Isotropic! mu = mkvc(mu) # ensure it is a vector. From ac758f1a65a861609d9e0cd1295225a2a90e5a88 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 21:42:16 -0800 Subject: [PATCH 29/42] finished pulling out projection code. --- SimPEG/Mesh/InnerProducts.py | 377 +++++++++++++++++++---------------- 1 file changed, 206 insertions(+), 171 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 73ad25eb..4a746cb2 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -121,13 +121,107 @@ class InnerProducts(object): # | |/ # node(i+1,j,k) ------ edge2(i+1,j,k) ----- node(i+1,j+1,k) + +def _getFacePxx(M): + if M._meshType == 'TREE': + return M._getFacePxx + + return _getFacePxx_Rectangular(M) + def _getFacePxxx(M): if M._meshType == 'TREE': return M._getFacePxxx return _getFacePxxx_Rectangular(M) +def _getEdgePxx(M): + if M._meshType == 'TREE': + return M._getEdgePxx + + return _getEdgePxx_Rectangular(M) + +def _getEdgePxxx(M): + if M._meshType == 'TREE': + return M._getEdgePxxx + + return _getEdgePxxx_Rectangular(M) + +def _getFacePxx_Rectangular(M): + """returns a function for creating projection matrices + + Mats takes you from faces a subset of all faces on only the + faces that you ask for. + + These are centered around a single nodes. + + For example, if this was your entire mesh: + + f3(Yp) + 2_______________3 + | | + | | + | | + f0(Xm) | x | f1(Xp) + | | + | | + |_______________| + 0 1 + f2(Ym) + + Pxx('m','m') = | 1, 0, 0, 0 | + | 0, 0, 1, 0 | + + Pxx('p','m') = | 0, 1, 0, 0 | + | 0, 0, 1, 0 | + + """ + i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) + + iijj = ndgrid(i, j) + ii, jj = iijj[:, 0], iijj[:, 1] + + if M._meshType == 'LOM': + fN1 = M.r(M.normals, 'F', 'Fx', 'M') + fN2 = M.r(M.normals, 'F', 'Fy', 'M') + + def Pxx(xFace, yFace): + """ + xFace is 'fXp' or 'fXm' + yFace is 'fYp' or 'fYm' + """ + # no | node | f1 | f2 + # 00 | i ,j | i , j | i, j + # 10 | i+1,j | i+1, j | i, j + # 01 | i ,j+1 | i , j | i, j+1 + # 11 | i+1,j+1 | i+1, j | i, j+1 + + posFx = 0 if xFace == 'fXm' else 1 + posFy = 0 if yFace == 'fYm' else 1 + + ind1 = sub2ind(M.nFx, np.c_[ii + posFx, jj]) + ind2 = sub2ind(M.nFy, np.c_[ii, jj + posFy]) + M.nFv[0] + + IND = np.r_[ind1, ind2].flatten() + + PXX = sp.csr_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nF))) + + if M._meshType == 'LOM': + I2x2 = inv2X2BlockDiagonal(getSubArray(fN1[0], [i + posFx, j]), getSubArray(fN1[1], [i + posFx, j]), + getSubArray(fN2[0], [i, j + posFy]), getSubArray(fN2[1], [i, j + posFy])) + PXX = I2x2 * PXX + + return PXX + + return Pxx + def _getFacePxxx_Rectangular(M): + """returns a function for creating projection matrices + + Mats takes you from faces a subset of all faces on only the + faces that you ask for. + + These are centered around a single nodes. + """ i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) @@ -140,6 +234,11 @@ def _getFacePxxx_Rectangular(M): fN3 = M.r(M.normals, 'F', 'Fz', 'M') def Pxxx(xFace, yFace, zFace): + """ + xFace is 'fXp' or 'fXm' + yFace is 'fYp' or 'fYm' + zFace is 'fZp' or 'fZm' + """ # no | node | f1 | f2 | f3 # 000 | i ,j ,k | i , j, k | i, j , k | i, j, k @@ -151,9 +250,9 @@ def _getFacePxxx_Rectangular(M): # 011 | i ,j+1,k+1 | i , j, k | i, j+1, k | i, j, k+1 # 111 | i+1,j+1,k+1 | i+1, j, k | i, j+1, k | i, j, k+1 - posX = 0 if xFace == 'm' else 1 - posY = 0 if yFace == 'm' else 1 - posZ = 0 if zFace == 'm' else 1 + posX = 0 if xFace == 'fXm' else 1 + posY = 0 if yFace == 'fYm' else 1 + posZ = 0 if zFace == 'fZm' else 1 ind1 = sub2ind(M.nFx, np.c_[ii + posX, jj, kk]) ind2 = sub2ind(M.nFy, np.c_[ii, jj + posY, kk]) + M.nFv[0] @@ -172,6 +271,83 @@ def _getFacePxxx_Rectangular(M): return PXXX return Pxxx +def _getEdgePxx_Rectangular(M): + i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) + + iijj = ndgrid(i, j) + ii, jj = iijj[:, 0], iijj[:, 1] + + if M._meshType == 'LOM': + eT1 = M.r(M.tangents, 'E', 'Ex', 'M') + eT2 = M.r(M.tangents, 'E', 'Ey', 'M') + + def Pxx(xEdge, yEdge): + # no | node | e1 | e2 + # 00 | i ,j | i ,j | i ,j + # 10 | i+1,j | i ,j | i+1,j + # 01 | i ,j+1 | i ,j+1 | i ,j + # 11 | i+1,j+1 | i ,j+1 | i+1,j + posX = 0 if xEdge == 'eX0' else 1 + posY = 0 if yEdge == 'eY0' else 1 + + ind1 = sub2ind(M.nEx, np.c_[ii, jj + posX]) + ind2 = sub2ind(M.nEy, np.c_[ii + posY, jj]) + M.nEv[0] + + IND = np.r_[ind1, ind2].flatten() + + PXX = sp.coo_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nE))).tocsr() + + if M._meshType == 'LOM': + I2x2 = inv2X2BlockDiagonal(getSubArray(eT1[0], [i, j + posX]), getSubArray(eT1[1], [i, j + posX]), + getSubArray(eT2[0], [i + posY, j]), getSubArray(eT2[1], [i + posY, j])) + PXX = I2x2 * PXX + + return PXX + return Pxx + +def _getEdgePxxx_Rectangular(M): + i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) + + iijjkk = ndgrid(i, j, k) + ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] + + if M._meshType == 'LOM': + eT1 = M.r(M.tangents, 'E', 'Ex', 'M') + eT2 = M.r(M.tangents, 'E', 'Ey', 'M') + eT3 = M.r(M.tangents, 'E', 'Ez', 'M') + + def Pxxx(xEdge, yEdge, zEdge): + + # no | node | e1 | e2 | e3 + # 000 | i ,j ,k | i ,j ,k | i ,j ,k | i ,j ,k + # 100 | i+1,j ,k | i ,j ,k | i+1,j ,k | i+1,j ,k + # 010 | i ,j+1,k | i ,j+1,k | i ,j ,k | i ,j+1,k + # 110 | i+1,j+1,k | i ,j+1,k | i+1,j ,k | i+1,j+1,k + # 001 | i ,j ,k+1 | i ,j ,k+1 | i ,j ,k+1 | i ,j ,k + # 101 | i+1,j ,k+1 | i ,j ,k+1 | i+1,j ,k+1 | i+1,j ,k + # 011 | i ,j+1,k+1 | i ,j+1,k+1 | i ,j ,k+1 | i ,j+1,k + # 111 | i+1,j+1,k+1 | i ,j+1,k+1 | i+1,j ,k+1 | i+1,j+1,k + + posX = [0,0] if xEdge == 'eX0' else [1, 0] if xEdge == 'eX1' else [0,1] if xEdge == 'eX2' else [1,1] + posY = [0,0] if yEdge == 'eY0' else [1, 0] if yEdge == 'eY1' else [0,1] if yEdge == 'eY2' else [1,1] + posZ = [0,0] if zEdge == 'eZ0' else [1, 0] if zEdge == 'eZ1' else [0,1] if zEdge == 'eZ2' else [1,1] + + ind1 = sub2ind(M.nEx, np.c_[ii, jj + posX[0], kk + posX[1]]) + ind2 = sub2ind(M.nEy, np.c_[ii + posY[0], jj, kk + posY[1]]) + M.nEv[0] + ind3 = sub2ind(M.nEz, np.c_[ii + posZ[0], jj + posZ[1], kk]) + M.nEv[0] + M.nEv[1] + + IND = np.r_[ind1, ind2, ind3].flatten() + + PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nE))).tocsr() + + if M._meshType == 'LOM': + I3x3 = inv3X3BlockDiagonal(getSubArray(eT1[0], [i, j + posX[0], k + posX[1]]), getSubArray(eT1[1], [i, j + posX[0], k + posX[1]]), getSubArray(eT1[2], [i, j + posX[0], k + posX[1]]), + getSubArray(eT2[0], [i + posY[0], j, k + posY[1]]), getSubArray(eT2[1], [i + posY[0], j, k + posY[1]]), getSubArray(eT2[2], [i + posY[0], j, k + posY[1]]), + getSubArray(eT3[0], [i + posZ[0], j + posZ[1], k]), getSubArray(eT3[1], [i + posZ[0], j + posZ[1], k]), getSubArray(eT3[2], [i + posZ[0], j + posZ[1], k])) + PXXX = I3x3 * PXXX + + return PXXX + return Pxxx def getFaceInnerProduct(M, mu=None, returnP=False): """ @@ -215,15 +391,14 @@ def getFaceInnerProduct(M, mu=None, returnP=False): V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry Pxxx = _getFacePxxx(M) - - P000 = V3*Pxxx('m', 'm', 'm') - P100 = V3*Pxxx('p', 'm', 'm') - P010 = V3*Pxxx('m', 'p', 'm') - P110 = V3*Pxxx('p', 'p', 'm') - P001 = V3*Pxxx('m', 'm', 'p') - P101 = V3*Pxxx('p', 'm', 'p') - P011 = V3*Pxxx('m', 'p', 'p') - P111 = V3*Pxxx('p', 'p', 'p') + P000 = V3*Pxxx('fXm', 'fYm', 'fZm') + P100 = V3*Pxxx('fXp', 'fYm', 'fZm') + P010 = V3*Pxxx('fXm', 'fYp', 'fZm') + P110 = V3*Pxxx('fXp', 'fYp', 'fZm') + P001 = V3*Pxxx('fXm', 'fYm', 'fZp') + P101 = V3*Pxxx('fXp', 'fYm', 'fZp') + P011 = V3*Pxxx('fXm', 'fYp', 'fZp') + P111 = V3*Pxxx('fXp', 'fYp', 'fZp') if mu.size == M.nC: # Isotropic! mu = mkvc(mu) # ensure it is a vector. @@ -243,80 +418,6 @@ def getFaceInnerProduct(M, mu=None, returnP=False): else: return A -def _getFacePxx(M): - if M._meshType == 'TREE': - return M._getFacePxx - - return _getFacePxx_Rectangular(M) - -def _getFacePxx_Rectangular(M): - """returns a function for creating projection matrices - - Mats takes you from faces a subset of all faces on only the - faces that you ask for. - - These are centered around a single nodes. - - For example, if this was your entire mesh: - - f3(Yp) - 2_______________3 - | | - | | - | | - f0(Xm) | x | f1(Xp) - | | - | | - |_______________| - 0 1 - f2(Ym) - - Pxx('m','m') = | 1, 0, 0, 0 | - | 0, 0, 1, 0 | - - Pxx('p','m') = | 0, 1, 0, 0 | - | 0, 0, 1, 0 | - - """ - i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) - - iijj = ndgrid(i, j) - ii, jj = iijj[:, 0], iijj[:, 1] - - if M._meshType == 'LOM': - fN1 = M.r(M.normals, 'F', 'Fx', 'M') - fN2 = M.r(M.normals, 'F', 'Fy', 'M') - - def Pxx(xFace, yFace): - """ - xFace is 'p' or 'm' - yFace is 'p' or 'm' - """ - # no | node | f1 | f2 - # 00 | i ,j | i , j | i, j - # 10 | i+1,j | i+1, j | i, j - # 01 | i ,j+1 | i , j | i, j+1 - # 11 | i+1,j+1 | i+1, j | i, j+1 - - posFx = 0 if xFace == 'm' else 1 - posFy = 0 if yFace == 'm' else 1 - - ind1 = sub2ind(M.nFx, np.c_[ii + posFx, jj]) - ind2 = sub2ind(M.nFy, np.c_[ii, jj + posFy]) + M.nFv[0] - - IND = np.r_[ind1, ind2].flatten() - - PXX = sp.csr_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nF))) - - if M._meshType == 'LOM': - I2x2 = inv2X2BlockDiagonal(getSubArray(fN1[0], [i + posFx, j]), getSubArray(fN1[1], [i + posFx, j]), - getSubArray(fN2[0], [i, j + posFy]), getSubArray(fN2[1], [i, j + posFy])) - PXX = I2x2 * PXX - - return PXX - - return Pxx - def getFaceInnerProduct2D(M, mu=None, returnP=False): """ :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 2, or 3)) @@ -358,16 +459,15 @@ def getFaceInnerProduct2D(M, mu=None, returnP=False): if mu is None: # default is ones mu = np.ones((M.nC, 1)) - Pxx = _getFacePxx(M) - # Square root of cell volume multiplied by 1/4 v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - P00 = V2*Pxx('m', 'm') - P10 = V2*Pxx('p', 'm') - P01 = V2*Pxx('m', 'p') - P11 = V2*Pxx('p', 'p') + Pxx = _getFacePxx(M) + P00 = V2*Pxx('fXm', 'fYm') + P10 = V2*Pxx('fXp', 'fYm') + P01 = V2*Pxx('fXm', 'fYp') + P11 = V2*Pxx('fXp', 'fYp') if mu.size == M.nC: # Isotropic! mu = mkvc(mu) # ensure it is a vector. @@ -427,55 +527,19 @@ def getEdgeInnerProduct(M, sigma=None, returnP=False): if sigma is None: # default is ones sigma = np.ones((M.nC, 1)) - i, j, k = np.int64(range(M.nCx)), np.int64(range(M.nCy)), np.int64(range(M.nCz)) - - iijjkk = ndgrid(i, j, k) - ii, jj, kk = iijjkk[:, 0], iijjkk[:, 1], iijjkk[:, 2] - - if M._meshType == 'LOM': - eT1 = M.r(M.tangents, 'E', 'Ex', 'M') - eT2 = M.r(M.tangents, 'E', 'Ey', 'M') - eT3 = M.r(M.tangents, 'E', 'Ez', 'M') - - def Pxxx(posX, posY, posZ): - ind1 = sub2ind(M.nEx, np.c_[ii + posX[0], jj + posX[1], kk + posX[2]]) - ind2 = sub2ind(M.nEy, np.c_[ii + posY[0], jj + posY[1], kk + posY[2]]) + M.nEv[0] - ind3 = sub2ind(M.nEz, np.c_[ii + posZ[0], jj + posZ[1], kk + posZ[2]]) + M.nEv[0] + M.nEv[1] - - IND = np.r_[ind1, ind2, ind3].flatten() - - PXXX = sp.coo_matrix((np.ones(3*M.nC), (range(3*M.nC), IND)), shape=(3*M.nC, np.sum(M.nE))).tocsr() - - if M._meshType == 'LOM': - I3x3 = inv3X3BlockDiagonal(getSubArray(eT1[0], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(eT1[1], [i + posX[0], j + posX[1], k + posX[2]]), getSubArray(eT1[2], [i + posX[0], j + posX[1], k + posX[2]]), - getSubArray(eT2[0], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(eT2[1], [i + posY[0], j + posY[1], k + posY[2]]), getSubArray(eT2[2], [i + posY[0], j + posY[1], k + posY[2]]), - getSubArray(eT3[0], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(eT3[1], [i + posZ[0], j + posZ[1], k + posZ[2]]), getSubArray(eT3[2], [i + posZ[0], j + posZ[1], k + posZ[2]])) - PXXX = I3x3 * PXXX - - return PXXX - - # no | node | e1 | e2 | e3 - # 000 | i ,j ,k | i ,j ,k | i ,j ,k | i ,j ,k - # 100 | i+1,j ,k | i ,j ,k | i+1,j ,k | i+1,j ,k - # 010 | i ,j+1,k | i ,j+1,k | i ,j ,k | i ,j+1,k - # 110 | i+1,j+1,k | i ,j+1,k | i+1,j ,k | i+1,j+1,k - # 001 | i ,j ,k+1 | i ,j ,k+1 | i ,j ,k+1 | i ,j ,k - # 101 | i+1,j ,k+1 | i ,j ,k+1 | i+1,j ,k+1 | i+1,j ,k - # 011 | i ,j+1,k+1 | i ,j+1,k+1 | i ,j ,k+1 | i ,j+1,k - # 111 | i+1,j+1,k+1 | i ,j+1,k+1 | i+1,j ,k+1 | i+1,j+1,k - # Square root of cell volume multiplied by 1/8 v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - P000 = V3*Pxxx([0, 0, 0], [0, 0, 0], [0, 0, 0]) - P100 = V3*Pxxx([0, 0, 0], [1, 0, 0], [1, 0, 0]) - P010 = V3*Pxxx([0, 1, 0], [0, 0, 0], [0, 1, 0]) - P110 = V3*Pxxx([0, 1, 0], [1, 0, 0], [1, 1, 0]) - P001 = V3*Pxxx([0, 0, 1], [0, 0, 1], [0, 0, 0]) - P101 = V3*Pxxx([0, 0, 1], [1, 0, 1], [1, 0, 0]) - P011 = V3*Pxxx([0, 1, 1], [0, 0, 1], [0, 1, 0]) - P111 = V3*Pxxx([0, 1, 1], [1, 0, 1], [1, 1, 0]) + Pxxx = _getEdgePxxx(M) + P000 = V3*Pxxx('eX0', 'eY0', 'eZ0') + P100 = V3*Pxxx('eX0', 'eY1', 'eZ1') + P010 = V3*Pxxx('eX1', 'eY0', 'eZ2') + P110 = V3*Pxxx('eX1', 'eY1', 'eZ3') + P001 = V3*Pxxx('eX2', 'eY2', 'eZ0') + P101 = V3*Pxxx('eX2', 'eY3', 'eZ1') + P011 = V3*Pxxx('eX3', 'eY2', 'eZ2') + P111 = V3*Pxxx('eX3', 'eY3', 'eZ3') if sigma.size == M.nC: # Isotropic! sigma = mkvc(sigma) # ensure it is a vector. @@ -537,44 +601,15 @@ def getEdgeInnerProduct2D(M, sigma=None, returnP=False): if sigma is None: # default is ones sigma = np.ones((M.nC, 1)) - i, j = np.int64(range(M.nCx)), np.int64(range(M.nCy)) - - iijj = ndgrid(i, j) - ii, jj = iijj[:, 0], iijj[:, 1] - - if M._meshType == 'LOM': - eT1 = M.r(M.tangents, 'E', 'Ex', 'M') - eT2 = M.r(M.tangents, 'E', 'Ey', 'M') - - def Pxx(posX, posY): - ind1 = sub2ind(M.nEx, np.c_[ii + posX[0], jj + posX[1]]) - ind2 = sub2ind(M.nEy, np.c_[ii + posY[0], jj + posY[1]]) + M.nEv[0] - - IND = np.r_[ind1, ind2].flatten() - - PXX = sp.coo_matrix((np.ones(2*M.nC), (range(2*M.nC), IND)), shape=(2*M.nC, np.sum(M.nE))).tocsr() - - if M._meshType == 'LOM': - I2x2 = inv2X2BlockDiagonal(getSubArray(eT1[0], [i + posX[0], j + posX[1]]), getSubArray(eT1[1], [i + posX[0], j + posX[1]]), - getSubArray(eT2[0], [i + posY[0], j + posY[1]]), getSubArray(eT2[1], [i + posY[0], j + posY[1]])) - PXX = I2x2 * PXX - - return PXX - - # no | node | e1 | e2 - # 00 | i ,j | i ,j | i ,j - # 10 | i+1,j | i ,j | i+1,j - # 01 | i ,j+1 | i ,j+1 | i ,j - # 11 | i+1,j+1 | i ,j+1 | i+1,j - # Square root of cell volume multiplied by 1/4 v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - P00 = V2*Pxx([0, 0], [0, 0]) - P10 = V2*Pxx([0, 0], [1, 0]) - P01 = V2*Pxx([0, 1], [0, 0]) - P11 = V2*Pxx([0, 1], [1, 0]) + Pxx = _getEdgePxx(M) + P00 = V2*Pxx('eX0', 'eY0') + P10 = V2*Pxx('eX0', 'eY1') + P01 = V2*Pxx('eX1', 'eY0') + P11 = V2*Pxx('eX1', 'eY1') if sigma.size == M.nC: # Isotropic! sigma = mkvc(sigma) # ensure it is a vector. From 53cf9bdd77e4c85510a4861727f84d5ba6bab788 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 21:50:51 -0800 Subject: [PATCH 30/42] pulled out tensor creation code. --- SimPEG/Mesh/InnerProducts.py | 88 ++++++++++++------------------------ 1 file changed, 30 insertions(+), 58 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 4a746cb2..06aa7f81 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -121,6 +121,32 @@ class InnerProducts(object): # | |/ # node(i+1,j,k) ------ edge2(i+1,j,k) ----- node(i+1,j+1,k) +def _makeTensor(M, sigma): + if sigma is None: # default is ones + sigma = np.ones((M.nC, 1)) + + if M.dim == 2: + if sigma.size == M.nC: # Isotropic! + sigma = mkvc(sigma) # ensure it is a vector. + Sigma = sdiag(np.r_[sigma, sigma]) + elif sigma.shape[1] == 2: # Diagonal tensor + Sigma = sdiag(np.r_[sigma[:, 0], sigma[:, 1]]) + elif sigma.shape[1] == 3: # Fully anisotropic + row1 = sp.hstack((sdiag(sigma[:, 0]), sdiag(sigma[:, 2]))) + row2 = sp.hstack((sdiag(sigma[:, 2]), sdiag(sigma[:, 1]))) + Sigma = sp.vstack((row1, row2)) + elif M.dim == 3: + if sigma.size == M.nC: # Isotropic! + sigma = mkvc(sigma) # ensure it is a vector. + Sigma = sdiag(np.r_[sigma, sigma, sigma]) + elif sigma.shape[1] == 3: # Diagonal tensor + Sigma = sdiag(np.r_[sigma[:, 0], sigma[:, 1], sigma[:, 2]]) + elif sigma.shape[1] == 6: # Fully anisotropic + row1 = sp.hstack((sdiag(sigma[:, 0]), sdiag(sigma[:, 3]), sdiag(sigma[:, 4]))) + row2 = sp.hstack((sdiag(sigma[:, 3]), sdiag(sigma[:, 1]), sdiag(sigma[:, 5]))) + row3 = sp.hstack((sdiag(sigma[:, 4]), sdiag(sigma[:, 5]), sdiag(sigma[:, 2]))) + Sigma = sp.vstack((row1, row2, row3)) + return Sigma def _getFacePxx(M): if M._meshType == 'TREE': @@ -382,10 +408,6 @@ def getFaceInnerProduct(M, mu=None, returnP=False): Note that this is completed for each cell in the mesh at the same time. """ - - if mu is None: # default is ones - mu = np.ones((M.nC, 1)) - # Square root of cell volume multiplied by 1/8 v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry @@ -400,17 +422,7 @@ def getFaceInnerProduct(M, mu=None, returnP=False): P011 = V3*Pxxx('fXm', 'fYp', 'fZp') P111 = V3*Pxxx('fXp', 'fYp', 'fZp') - if mu.size == M.nC: # Isotropic! - mu = mkvc(mu) # ensure it is a vector. - Mu = sdiag(np.r_[mu, mu, mu]) - elif mu.shape[1] == 3: # Diagonal tensor - Mu = sdiag(np.r_[mu[:, 0], mu[:, 1], mu[:, 2]]) - elif mu.shape[1] == 6: # Fully anisotropic - row1 = sp.hstack((sdiag(mu[:, 0]), sdiag(mu[:, 3]), sdiag(mu[:, 4]))) - row2 = sp.hstack((sdiag(mu[:, 3]), sdiag(mu[:, 1]), sdiag(mu[:, 5]))) - row3 = sp.hstack((sdiag(mu[:, 4]), sdiag(mu[:, 5]), sdiag(mu[:, 2]))) - Mu = sp.vstack((row1, row2, row3)) - + Mu = _makeTensor(M, mu) A = P000.T*Mu*P000 + P001.T*Mu*P001 + P010.T*Mu*P010 + P011.T*Mu*P011 + P100.T*Mu*P100 + P101.T*Mu*P101 + P110.T*Mu*P110 + P111.T*Mu*P111 P = [P000, P001, P010, P011, P100, P101, P110, P111] if returnP: @@ -455,10 +467,6 @@ def getFaceInnerProduct2D(M, mu=None, returnP=False): Note that this is completed for each cell in the mesh at the same time. """ - - if mu is None: # default is ones - mu = np.ones((M.nC, 1)) - # Square root of cell volume multiplied by 1/4 v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry @@ -469,16 +477,7 @@ def getFaceInnerProduct2D(M, mu=None, returnP=False): P01 = V2*Pxx('fXm', 'fYp') P11 = V2*Pxx('fXp', 'fYp') - if mu.size == M.nC: # Isotropic! - mu = mkvc(mu) # ensure it is a vector. - Mu = sdiag(np.r_[mu, mu]) - elif mu.shape[1] == 2: # Diagonal tensor - Mu = sdiag(np.r_[mu[:, 0], mu[:, 1]]) - elif mu.shape[1] == 3: # Fully anisotropic - row1 = sp.hstack((sdiag(mu[:, 0]), sdiag(mu[:, 2]))) - row2 = sp.hstack((sdiag(mu[:, 2]), sdiag(mu[:, 1]))) - Mu = sp.vstack((row1, row2)) - + Mu = _makeTensor(M, mu) A = P00.T*Mu*P00 + P10.T*Mu*P10 + P01.T*Mu*P01 + P11.T*Mu*P11 P = [P00, P10, P01, P11] if returnP: @@ -523,10 +522,6 @@ def getEdgeInnerProduct(M, sigma=None, returnP=False): Note that this is completed for each cell in the mesh at the same time. """ - - if sigma is None: # default is ones - sigma = np.ones((M.nC, 1)) - # Square root of cell volume multiplied by 1/8 v = np.sqrt(0.125*M.vol) V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry @@ -541,17 +536,7 @@ def getEdgeInnerProduct(M, sigma=None, returnP=False): P011 = V3*Pxxx('eX3', 'eY2', 'eZ2') P111 = V3*Pxxx('eX3', 'eY3', 'eZ3') - if sigma.size == M.nC: # Isotropic! - sigma = mkvc(sigma) # ensure it is a vector. - Sigma = sdiag(np.r_[sigma, sigma, sigma]) - elif sigma.shape[1] == 3: # Diagonal tensor - Sigma = sdiag(np.r_[sigma[:, 0], sigma[:, 1], sigma[:, 2]]) - elif sigma.shape[1] == 6: # Fully anisotropic - row1 = sp.hstack((sdiag(sigma[:, 0]), sdiag(sigma[:, 3]), sdiag(sigma[:, 4]))) - row2 = sp.hstack((sdiag(sigma[:, 3]), sdiag(sigma[:, 1]), sdiag(sigma[:, 5]))) - row3 = sp.hstack((sdiag(sigma[:, 4]), sdiag(sigma[:, 5]), sdiag(sigma[:, 2]))) - Sigma = sp.vstack((row1, row2, row3)) - + Sigma = _makeTensor(M, sigma) A = P000.T*Sigma*P000 + P001.T*Sigma*P001 + P010.T*Sigma*P010 + P011.T*Sigma*P011 + P100.T*Sigma*P100 + P101.T*Sigma*P101 + P110.T*Sigma*P110 + P111.T*Sigma*P111 P = [P000, P001, P010, P011, P100, P101, P110, P111] if returnP: @@ -597,10 +582,6 @@ def getEdgeInnerProduct2D(M, sigma=None, returnP=False): Note that this is completed for each cell in the mesh at the same time. """ - - if sigma is None: # default is ones - sigma = np.ones((M.nC, 1)) - # Square root of cell volume multiplied by 1/4 v = np.sqrt(0.25*M.vol) V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry @@ -611,16 +592,7 @@ def getEdgeInnerProduct2D(M, sigma=None, returnP=False): P01 = V2*Pxx('eX1', 'eY0') P11 = V2*Pxx('eX1', 'eY1') - if sigma.size == M.nC: # Isotropic! - sigma = mkvc(sigma) # ensure it is a vector. - Sigma = sdiag(np.r_[sigma, sigma]) - elif sigma.shape[1] == 2: # Diagonal tensor - Sigma = sdiag(np.r_[sigma[:, 0], sigma[:, 1]]) - elif sigma.shape[1] == 3: # Fully anisotropic - row1 = sp.hstack((sdiag(sigma[:, 0]), sdiag(sigma[:, 2]))) - row2 = sp.hstack((sdiag(sigma[:, 2]), sdiag(sigma[:, 1]))) - Sigma = sp.vstack((row1, row2)) - + Sigma = _makeTensor(M, sigma) A = P00.T*Sigma*P00 + P10.T*Sigma*P10 + P01.T*Sigma*P01 + P11.T*Sigma*P11 P = [P00, P10, P01, P11] if returnP: From c1a6fc950bb4a61b7144fcf8c073f0c5c13cd64a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 22:10:34 -0800 Subject: [PATCH 31/42] combine edge inner products 2D and 3D --- SimPEG/Mesh/InnerProducts.py | 226 ++++++++++++++++------------------- 1 file changed, 101 insertions(+), 125 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index 06aa7f81..c863969c 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -90,17 +90,108 @@ class InnerProducts(object): elif self.dim == 3: return getFaceInnerProduct(self, mu, returnP) - def getEdgeInnerProduct(self, sigma=None, returnP=False): - """Wrapper function, - - :py:func:`SimPEG.mesh.InnerProducts.InnerProducts.getEdgeInnerProduct` - - :py:func:`SimPEG.mesh.InnerProducts.InnerProducts.getEdgeInnerProduct2D` + def getEdgeInnerProduct(M, sigma=None, returnP=False): """ - if self.dim == 2: - return getEdgeInnerProduct2D(self, sigma, returnP) - elif self.dim == 3: - return getEdgeInnerProduct(self, sigma, returnP) + :param numpy.array sigma: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) + :param bool returnP: returns the projection matrices + :rtype: scipy.csr_matrix + :return: M, the inner product matrix (sum(nE), sum(nE)) + + + Depending on the number of columns (either 1, 3, or 6) of sigma, the material property is interpreted as follows: + + .. math:: + \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 & 0 \\\\ 0 & \sigma_{1} & 0 \\\\ 0 & 0 & \sigma_{1} \end{matrix}\\right] + + \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 & 0 \\\\ 0 & \sigma_{2} & 0 \\\\ 0 & 0 & \sigma_{3} \end{matrix}\\right] + + \Sigma = \left[\\begin{matrix} \sigma_{1} & \sigma_{4} & \sigma_{5} \\\\ \sigma_{4} & \sigma_{2} & \sigma_{6} \\\\ \sigma_{5} & \sigma_{6} & \sigma_{3} \end{matrix}\\right] + + What is returned: + + .. math:: + \mathbf{M}(\Sigma) = {1\over 8} + \left(\sum_{i=1}^8 + \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \Sigma \sqrt{v_{\\text{cell}}} \mathbf{J}_c + \\right) + + If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: + + P = [P000, P001, P010, P011, P100, P101, P110, P111] + + Here each P (3*nC, sum(nE)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: + + .. math:: + \mathbf{P}_{(i)} = \sqrt{ {1\over 8} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} + + Note that this is completed for each cell in the mesh at the same time. + + **For 2D:** + + Depending on the number of columns (either 1, 2, or 3) of sigma, the material property is interpreted as follows: + + .. math:: + \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 \\\\ 0 & \sigma_{1} \end{matrix}\\right] + + \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 \\\\ 0 & \sigma_{2} \end{matrix}\\right] + + \Sigma = \left[\\begin{matrix} \sigma_{1} & \sigma_{3} \\\\ \sigma_{3} & \sigma_{2} \end{matrix}\\right] + + + .. math:: + + \mathbf{M}(\Sigma) = {1\over 4} + \left(\sum_{i=1}^4 + \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \Sigma \sqrt{v_{\\text{cell}}} \mathbf{J}_c + \\right) + + + If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: + + P = [P00, P10, P01, P11] + + Here each P (2*nC, sum(nE)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: + + .. math:: + \mathbf{P}_{(i)} = \sqrt{ {1\over 4} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} + + Note that this is completed for each cell in the mesh at the same time. + + """ + # We will multiply by V on each side to keep symmetry + if M.dim == 2: + # Square root of cell volume multiplied by 1/4 + v = np.sqrt(0.25*M.vol) + V = sdiag(np.r_[v, v]) + eP = _getEdgePxx(M) + P000 = V*eP('eX0', 'eY0') + P100 = V*eP('eX0', 'eY1') + P010 = V*eP('eX1', 'eY0') + P110 = V*eP('eX1', 'eY1') + elif M.dim == 3: + # Square root of cell volume multiplied by 1/8 + v = np.sqrt(0.125*M.vol) + V = sdiag(np.r_[v, v, v]) + eP = _getEdgePxxx(M) + P000 = V*eP('eX0', 'eY0', 'eZ0') + P100 = V*eP('eX0', 'eY1', 'eZ1') + P010 = V*eP('eX1', 'eY0', 'eZ2') + P110 = V*eP('eX1', 'eY1', 'eZ3') + P001 = V*eP('eX2', 'eY2', 'eZ0') + P101 = V*eP('eX2', 'eY3', 'eZ1') + P011 = V*eP('eX3', 'eY2', 'eZ2') + P111 = V*eP('eX3', 'eY3', 'eZ3') + + Sigma = _makeTensor(M, sigma) + A = P000.T*Sigma*P000 + P100.T*Sigma*P100 + P010.T*Sigma*P010 + P110.T*Sigma*P110 + P = [P000, P100, P010, P110] + if M.dim == 3: + A = A + P001.T*Sigma*P001 + P101.T*Sigma*P101 + P011.T*Sigma*P011 + P111.T*Sigma*P111 + P += [P001, P101, P011, P111] + if returnP: + return A, P + else: + return A # ------------------------ Geometries ------------------------------ # @@ -486,121 +577,6 @@ def getFaceInnerProduct2D(M, mu=None, returnP=False): return A -def getEdgeInnerProduct(M, sigma=None, returnP=False): - """ - :param numpy.array sigma: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) - :param bool returnP: returns the projection matrices - :rtype: scipy.csr_matrix - :return: M, the inner product matrix (sum(nE), sum(nE)) - - - Depending on the number of columns (either 1, 3, or 6) of sigma, the material property is interpreted as follows: - - .. math:: - \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 & 0 \\\\ 0 & \sigma_{1} & 0 \\\\ 0 & 0 & \sigma_{1} \end{matrix}\\right] - - \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 & 0 \\\\ 0 & \sigma_{2} & 0 \\\\ 0 & 0 & \sigma_{3} \end{matrix}\\right] - - \Sigma = \left[\\begin{matrix} \sigma_{1} & \sigma_{4} & \sigma_{5} \\\\ \sigma_{4} & \sigma_{2} & \sigma_{6} \\\\ \sigma_{5} & \sigma_{6} & \sigma_{3} \end{matrix}\\right] - - What is returned: - - .. math:: - \mathbf{M}(\Sigma) = {1\over 8} - \left(\sum_{i=1}^8 - \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \Sigma \sqrt{v_{\\text{cell}}} \mathbf{J}_c - \\right) - - If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - - P = [P000, P001, P010, P011, P100, P101, P110, P111] - - Here each P (3*nC, sum(nE)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: - - .. math:: - \mathbf{P}_{(i)} = \sqrt{ {1\over 8} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} - - Note that this is completed for each cell in the mesh at the same time. - """ - # Square root of cell volume multiplied by 1/8 - v = np.sqrt(0.125*M.vol) - V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - - Pxxx = _getEdgePxxx(M) - P000 = V3*Pxxx('eX0', 'eY0', 'eZ0') - P100 = V3*Pxxx('eX0', 'eY1', 'eZ1') - P010 = V3*Pxxx('eX1', 'eY0', 'eZ2') - P110 = V3*Pxxx('eX1', 'eY1', 'eZ3') - P001 = V3*Pxxx('eX2', 'eY2', 'eZ0') - P101 = V3*Pxxx('eX2', 'eY3', 'eZ1') - P011 = V3*Pxxx('eX3', 'eY2', 'eZ2') - P111 = V3*Pxxx('eX3', 'eY3', 'eZ3') - - Sigma = _makeTensor(M, sigma) - A = P000.T*Sigma*P000 + P001.T*Sigma*P001 + P010.T*Sigma*P010 + P011.T*Sigma*P011 + P100.T*Sigma*P100 + P101.T*Sigma*P101 + P110.T*Sigma*P110 + P111.T*Sigma*P111 - P = [P000, P001, P010, P011, P100, P101, P110, P111] - if returnP: - return A, P - else: - return A - - -def getEdgeInnerProduct2D(M, sigma=None, returnP=False): - """ - :param numpy.array sigma: material property (tensor properties are possible) at each cell center (nC, (1, 2, or 3)) - :param bool returnP: returns the projection matrices - :rtype: scipy.csr_matrix - :return: M, the inner product matrix (sum(nE), sum(nE)) - - Depending on the number of columns (either 1, 2, or 3) of sigma, the material property is interpreted as follows: - - .. math:: - \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 \\\\ 0 & \sigma_{1} \end{matrix}\\right] - - \Sigma = \left[\\begin{matrix} \sigma_{1} & 0 \\\\ 0 & \sigma_{2} \end{matrix}\\right] - - \Sigma = \left[\\begin{matrix} \sigma_{1} & \sigma_{3} \\\\ \sigma_{3} & \sigma_{2} \end{matrix}\\right] - - - .. math:: - - \mathbf{M}(\Sigma) = {1\over 4} - \left(\sum_{i=1}^4 - \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \Sigma \sqrt{v_{\\text{cell}}} \mathbf{J}_c - \\right) - - - If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - - P = [P00, P10, P01, P11] - - Here each P (2*nC, sum(nE)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: - - .. math:: - \mathbf{P}_{(i)} = \sqrt{ {1\over 4} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} - - Note that this is completed for each cell in the mesh at the same time. - - """ - # Square root of cell volume multiplied by 1/4 - v = np.sqrt(0.25*M.vol) - V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - - Pxx = _getEdgePxx(M) - P00 = V2*Pxx('eX0', 'eY0') - P10 = V2*Pxx('eX0', 'eY1') - P01 = V2*Pxx('eX1', 'eY0') - P11 = V2*Pxx('eX1', 'eY1') - - Sigma = _makeTensor(M, sigma) - A = P00.T*Sigma*P00 + P10.T*Sigma*P10 + P01.T*Sigma*P01 + P11.T*Sigma*P11 - P = [P00, P10, P01, P11] - if returnP: - return A, P - else: - return A - - if __name__ == '__main__': from TensorMesh import TensorMesh h = [np.array([1, 2, 3, 4]), np.array([1, 2, 1, 4, 2]), np.array([1, 1, 4, 1])] From 61e86c2dd9b2e53978635d6cff781a43b61fbada Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 22:16:37 -0800 Subject: [PATCH 32/42] combine edge inner product code --- SimPEG/Mesh/InnerProducts.py | 219 ++++++++++++++++------------------- 1 file changed, 98 insertions(+), 121 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index c863969c..a6fb21f7 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -78,17 +78,105 @@ class InnerProducts(object): def __init__(self): raise Exception('InnerProducts is a base class providing inner product matrices for meshes and cannot run on its own. Inherit to your favorite Mesh class.') - def getFaceInnerProduct(self, mu=None, returnP=False): - """Wrapper function, - - :py:func:`SimPEG.mesh.InnerProducts.InnerProducts.getFaceInnerProduct` - - :py:func:`SimPEG.mesh.InnerProducts.InnerProducts.getFaceInnerProduct2D` + def getFaceInnerProduct(M, mu=None, returnP=False): """ - if self.dim == 2: - return getFaceInnerProduct2D(self, mu, returnP) - elif self.dim == 3: - return getFaceInnerProduct(self, mu, returnP) + :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) + :param bool returnP: returns the projection matrices + :rtype: scipy.csr_matrix + :return: M, the inner product matrix (sum(nF), sum(nF)) + + Depending on the number of columns (either 1, 3, or 6) of mu, the material property is interpreted as follows: + + .. math:: + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 & 0 \\\\ 0 & \mu_{1} & 0 \\\\ 0 & 0 & \mu_{1} \end{matrix}\\right] + + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 & 0 \\\\ 0 & \mu_{2} & 0 \\\\ 0 & 0 & \mu_{3} \end{matrix}\\right] + + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & \mu_{4} & \mu_{5} \\\\ \mu_{4} & \mu_{2} & \mu_{6} \\\\ \mu_{5} & \mu_{6} & \mu_{3} \end{matrix}\\right] + + \mathbf{M}(\\vec{\mu}) = {1\over 8} + \left(\sum_{i=1}^8 + \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \\vec{\mu} \sqrt{v_{\\text{cell}}} \mathbf{J}_c + \\right) + + If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: + + P = [P000, P001, P010, P011, P100, P101, P110, P111] + + Here each P (3*nC, sum(nF)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: + + .. math:: + \mathbf{P}_{(i)} = \sqrt{ {1\over 8} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} + + Note that this is completed for each cell in the mesh at the same time. + + **For 2D:** + + Depending on the number of columns (either 1, 2, or 3) of mu, the material property is interpreted as follows: + + .. math:: + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 \\\\ 0 & \mu_{1} \end{matrix}\\right] + + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 \\\\ 0 & \mu_{2} \end{matrix}\\right] + + \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & \mu_{3} \\\\ \mu_{3} & \mu_{2} \end{matrix}\\right] + + + .. math:: + + \mathbf{M}(\\vec{\mu}) = {1\over 4} + \left(\sum_{i=1}^4 + \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \\vec{\mu} \sqrt{v_{\\text{cell}}} \mathbf{J}_c + \\right) + + + If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: + + P = [P00, P10, P01, P11] + + Here each P (2*nC, sum(nF)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: + + .. math:: + \mathbf{P}_{(i)} = \sqrt{ {1\over 4} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} + + Note that this is completed for each cell in the mesh at the same time. + + """ + if M.dim == 2: + # Square root of cell volume multiplied by 1/4 + v = np.sqrt(0.25*M.vol) + V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry + + Pxx = _getFacePxx(M) + P000 = V2*Pxx('fXm', 'fYm') + P100 = V2*Pxx('fXp', 'fYm') + P010 = V2*Pxx('fXm', 'fYp') + P110 = V2*Pxx('fXp', 'fYp') + elif M.dim == 3: + # Square root of cell volume multiplied by 1/8 + v = np.sqrt(0.125*M.vol) + V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry + + Pxxx = _getFacePxxx(M) + P000 = V3*Pxxx('fXm', 'fYm', 'fZm') + P100 = V3*Pxxx('fXp', 'fYm', 'fZm') + P010 = V3*Pxxx('fXm', 'fYp', 'fZm') + P110 = V3*Pxxx('fXp', 'fYp', 'fZm') + P001 = V3*Pxxx('fXm', 'fYm', 'fZp') + P101 = V3*Pxxx('fXp', 'fYm', 'fZp') + P011 = V3*Pxxx('fXm', 'fYp', 'fZp') + P111 = V3*Pxxx('fXp', 'fYp', 'fZp') + + Mu = _makeTensor(M, mu) + A = P000.T*Mu*P000 + P100.T*Mu*P100 + P010.T*Mu*P010 + P110.T*Mu*P110 + P = [P000, P100, P010, P110] + if M.dim == 3: + A = A + P001.T*Mu*P001 + P101.T*Mu*P101 + P011.T*Mu*P011 + P111.T*Mu*P111 + P += [P001, P101, P011, P111] + if returnP: + return A, P + else: + return A def getEdgeInnerProduct(M, sigma=None, returnP=False): """ @@ -466,117 +554,6 @@ def _getEdgePxxx_Rectangular(M): return PXXX return Pxxx -def getFaceInnerProduct(M, mu=None, returnP=False): - """ - :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6)) - :param bool returnP: returns the projection matrices - :rtype: scipy.csr_matrix - :return: M, the inner product matrix (sum(nF), sum(nF)) - - Depending on the number of columns (either 1, 3, or 6) of mu, the material property is interpreted as follows: - - .. math:: - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 & 0 \\\\ 0 & \mu_{1} & 0 \\\\ 0 & 0 & \mu_{1} \end{matrix}\\right] - - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 & 0 \\\\ 0 & \mu_{2} & 0 \\\\ 0 & 0 & \mu_{3} \end{matrix}\\right] - - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & \mu_{4} & \mu_{5} \\\\ \mu_{4} & \mu_{2} & \mu_{6} \\\\ \mu_{5} & \mu_{6} & \mu_{3} \end{matrix}\\right] - - \mathbf{M}(\\vec{\mu}) = {1\over 8} - \left(\sum_{i=1}^8 - \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \\vec{\mu} \sqrt{v_{\\text{cell}}} \mathbf{J}_c - \\right) - - If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - - P = [P000, P001, P010, P011, P100, P101, P110, P111] - - Here each P (3*nC, sum(nF)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: - - .. math:: - \mathbf{P}_{(i)} = \sqrt{ {1\over 8} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} - - Note that this is completed for each cell in the mesh at the same time. - - """ - # Square root of cell volume multiplied by 1/8 - v = np.sqrt(0.125*M.vol) - V3 = sdiag(np.r_[v, v, v]) # We will multiply on each side to keep symmetry - - Pxxx = _getFacePxxx(M) - P000 = V3*Pxxx('fXm', 'fYm', 'fZm') - P100 = V3*Pxxx('fXp', 'fYm', 'fZm') - P010 = V3*Pxxx('fXm', 'fYp', 'fZm') - P110 = V3*Pxxx('fXp', 'fYp', 'fZm') - P001 = V3*Pxxx('fXm', 'fYm', 'fZp') - P101 = V3*Pxxx('fXp', 'fYm', 'fZp') - P011 = V3*Pxxx('fXm', 'fYp', 'fZp') - P111 = V3*Pxxx('fXp', 'fYp', 'fZp') - - Mu = _makeTensor(M, mu) - A = P000.T*Mu*P000 + P001.T*Mu*P001 + P010.T*Mu*P010 + P011.T*Mu*P011 + P100.T*Mu*P100 + P101.T*Mu*P101 + P110.T*Mu*P110 + P111.T*Mu*P111 - P = [P000, P001, P010, P011, P100, P101, P110, P111] - if returnP: - return A, P - else: - return A - -def getFaceInnerProduct2D(M, mu=None, returnP=False): - """ - :param numpy.array mu: material property (tensor properties are possible) at each cell center (nC, (1, 2, or 3)) - :param bool returnP: returns the projection matrices - :rtype: scipy.csr_matrix - :return: M, the inner product matrix (sum(nF), sum(nF)) - - Depending on the number of columns (either 1, 2, or 3) of mu, the material property is interpreted as follows: - - .. math:: - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 \\\\ 0 & \mu_{1} \end{matrix}\\right] - - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & 0 \\\\ 0 & \mu_{2} \end{matrix}\\right] - - \\vec{\mu} = \left[\\begin{matrix} \mu_{1} & \mu_{3} \\\\ \mu_{3} & \mu_{2} \end{matrix}\\right] - - - .. math:: - - \mathbf{M}(\\vec{\mu}) = {1\over 4} - \left(\sum_{i=1}^4 - \mathbf{J}_c^{-\\top} \sqrt{v_{\\text{cell}}} \\vec{\mu} \sqrt{v_{\\text{cell}}} \mathbf{J}_c - \\right) - - - If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - - P = [P00, P10, P01, P11] - - Here each P (2*nC, sum(nF)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: - - .. math:: - \mathbf{P}_{(i)} = \sqrt{ {1\over 4} v_{\\text{cell}}} \overbrace{\mathbf{N}_{(i)}^{-1}}^{\\text{LOM only}} \mathbf{Q}_{(i)} - - Note that this is completed for each cell in the mesh at the same time. - - """ - # Square root of cell volume multiplied by 1/4 - v = np.sqrt(0.25*M.vol) - V2 = sdiag(np.r_[v, v]) # We will multiply on each side to keep symmetry - - Pxx = _getFacePxx(M) - P00 = V2*Pxx('fXm', 'fYm') - P10 = V2*Pxx('fXp', 'fYm') - P01 = V2*Pxx('fXm', 'fYp') - P11 = V2*Pxx('fXp', 'fYp') - - Mu = _makeTensor(M, mu) - A = P00.T*Mu*P00 + P10.T*Mu*P10 + P01.T*Mu*P01 + P11.T*Mu*P11 - P = [P00, P10, P01, P11] - if returnP: - return A, P - else: - return A - - if __name__ == '__main__': from TensorMesh import TensorMesh h = [np.array([1, 2, 3, 4]), np.array([1, 2, 1, 4, 2]), np.array([1, 1, 4, 1])] From a808aa57742211c3dda3804f1124333369dda0c6 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Mon, 10 Feb 2014 22:35:28 -0800 Subject: [PATCH 33/42] FaceInnerProducts for TreeMesh --- SimPEG/Mesh/InnerProducts.py | 4 +-- SimPEG/Mesh/TreeMesh.py | 58 ++++++++++++++++++++++++++++++----- SimPEG/Tests/test_TreeMesh.py | 8 +++-- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/SimPEG/Mesh/InnerProducts.py b/SimPEG/Mesh/InnerProducts.py index a6fb21f7..43d6c31f 100644 --- a/SimPEG/Mesh/InnerProducts.py +++ b/SimPEG/Mesh/InnerProducts.py @@ -101,7 +101,7 @@ class InnerProducts(object): If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - P = [P000, P001, P010, P011, P100, P101, P110, P111] + P = [P000, P100, P010, P110, P001, P101, P011, P111] Here each P (3*nC, sum(nF)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: @@ -205,7 +205,7 @@ class InnerProducts(object): If requested (returnP=True) the projection matricies are returned as well (ordered by nodes):: - P = [P000, P001, P010, P011, P100, P101, P110, P111] + P = [P000, P100, P010, P110, P001, P101, P011, P111] Here each P (3*nC, sum(nE)) is a combination of the projection, volume, and any normalization to Cartesian coordinates: diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index dec87423..ebd089ef 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -1,4 +1,6 @@ from SimPEG import np, sp, Utils, Solver +from BaseMesh import BaseMesh +from InnerProducts import InnerProducts import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import matplotlib.colors as colors @@ -582,15 +584,16 @@ class TreeCell(TreeObject): self.mesh.cells.remove(self) - @property - def faceIndex(self): + def faceIndex(self, theseFaces='all', addDirection=True): #TODO: preallocate I, J, V = np.empty(0,dtype=float), np.empty(0,dtype=float), np.empty(0,dtype=float) for face in self.faces: + thisFace = 'all' == theseFaces or face in theseFaces + if not thisFace: continue j = self.faces[face].index i = j*0+self.num v = j*0+1 - if 'm' in face: + if addDirection and 'm' in face: v *= -1 I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] return I, J, V @@ -598,7 +601,6 @@ class TreeCell(TreeObject): @property def vol(self): return self.sz.prod() - def viz(self, ax, color='none', text=False): if not self.isleaf: return x0, sz = self.x0, self.sz @@ -615,8 +617,11 @@ class TreeCell(TreeObject): if text: ax.text(self.center[0], self.center[1], self.center[2], self.num) -class TreeMesh(object): +class TreeMesh(InnerProducts, BaseMesh): """TreeMesh""" + + _meshType = 'TREE' + def __init__(self, h_in, x0=None): assert type(h_in) is list, 'h_in must be a list' h = range(len(h_in)) @@ -635,7 +640,9 @@ class TreeMesh(object): assert type(x0) in [list, np.ndarray], 'x0 must be a numpy array or a list' x0 = np.array(x0, dtype=float) assert len(x0) == self.dim, 'x0 must have the same dimensions as the mesh' - self.x0 = x0 + + # TODO: this has a lot of stuff which doesn't work for this style of mesh... + BaseMesh.__init__(self, np.array([x.size for x in h]), x0) # set the sets for holding the cells, nodes, faces, and edges self.cells = set() @@ -846,7 +853,7 @@ class TreeMesh(object): # TODO: Preallocate! I, J, V = np.empty(0), np.empty(0), np.empty(0) for cell in self.sortedCells: - i, j, v = cell.faceIndex + i, j, v = cell.faceIndex('all') I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] VOL = self.vol @@ -855,6 +862,43 @@ class TreeMesh(object): self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv + def _getFacePxx(self, xFace, yFace): + self.number() + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in self.sortedCells: + i, j, v = cell.faceIndex('fX'+xFace) + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + xP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in self.sortedCells: + i, j, v = cell.faceIndex('fY'+yFace) + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + yP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + return sp.vstack((xP, yP)) + + def _getFacePxxx(self, xFace, yFace, zFace): + self.number() + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in self.sortedCells: + i, j, v = cell.faceIndex('fX'+xFace) + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + xP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in self.sortedCells: + i, j, v = cell.faceIndex('fY'+yFace) + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + yP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + + I, J, V = np.empty(0), np.empty(0), np.empty(0) + for cell in self.sortedCells: + i, j, v = cell.faceIndex('fZ'+zFace) + I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] + zP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + + return sp.vstack((xP, yP, zP)) + def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, plotE=False, plotEx=False, plotEy=False, plotEz=False, showIt=False): axOpts = {'projection':'3d'} if self.dim == 3 else {} if ax is None: ax = plt.subplot(111, **axOpts) diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 4abdfd05..10d1dba6 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -489,13 +489,15 @@ class SimpleOctreeOperatorTests(unittest.TestCase): h1 = np.random.rand(5) h2 = np.random.rand(7) h3 = np.random.rand(3) - self.tM = TensorMesh([h1,h2,1]) - self.oM = TreeMesh([h1,h2,1]) + self.tM = TensorMesh([h1,h2,h3]) + self.oM = TreeMesh([h1,h2,h3]) def test_faceDiv(self): - print (self.tM.faceDiv - self.oM.faceDiv) self.assertTrue((self.tM.faceDiv - self.oM.faceDiv).toarray().sum() == 0) + def test_InnerProducts(self): + self.assertTrue((self.tM.getFaceInnerProduct() - self.oM.getFaceInnerProduct()).toarray().sum() == 0) + if __name__ == '__main__': unittest.main() From 53c2dcd3ba1c8e13d05ec1d25b21b4e8c14587ea Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 11:02:39 -0800 Subject: [PATCH 34/42] refactor numbering code for faces and fix inner product bug --- SimPEG/Mesh/TreeMesh.py | 90 ++++++++++++++++------------------- SimPEG/Tests/test_TreeMesh.py | 13 ++--- 2 files changed, 45 insertions(+), 58 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index ebd089ef..601449ad 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -212,9 +212,12 @@ class TreeFace(TreeObject): @property def index(self): - if not self.mesh.isNumbered: raise Exception('Mesh is not numbered.') - if self.isleaf: return np.r_[self.num] - return np.concatenate([face.index for face in self.children.flatten(order='F')]) + if self.isleaf: return [self.num] + l = [face.index for face in self.children.flatten(order='F')] + # Flatten the list + # e.g. + # [[1,3],[4]] --> [1, 3, 4] + return [item for sublist in l for item in sublist] @property def area(self): @@ -584,19 +587,12 @@ class TreeCell(TreeObject): self.mesh.cells.remove(self) - def faceIndex(self, theseFaces='all', addDirection=True): - #TODO: preallocate - I, J, V = np.empty(0,dtype=float), np.empty(0,dtype=float), np.empty(0,dtype=float) + @property + def faceIndex(self): + F = {} for face in self.faces: - thisFace = 'all' == theseFaces or face in theseFaces - if not thisFace: continue - j = self.faces[face].index - i = j*0+self.num - v = j*0+1 - if addDirection and 'm' in face: - v *= -1 - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - return I, J, V + F[face] = self.faces[face].index + return F @property def vol(self): return self.sz.prod() @@ -851,52 +847,47 @@ class TreeMesh(InnerProducts, BaseMesh): if getattr(self, '_faceDiv', None) is None: self.number() # TODO: Preallocate! - I, J, V = np.empty(0), np.empty(0), np.empty(0) + I, J, V = [], [], [] for cell in self.sortedCells: - i, j, v = cell.faceIndex('all') - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - + for face in cell.faces: + j = cell.faces[face].index + I += [cell.num]*len(j) + J += j + V += [-1 if 'm' in face else 1]*len(j) VOL = self.vol D = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) S = self.area self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv + def _getFaceP(self, face0, face1, face2): + I, J, V = [], [], [] + for cell in self.sortedCells: + face = cell.faces[face0] + if face.isleaf: + j = face.index + elif self.dim == 2: + j = face.children[0 if 'm' in face1 else 1].index + elif self.dim == 3: + j = face.children[0 if 'm' in face1 else 1, + 0 if 'm' in face2 else 1].index + lenj = len(j) + I += [cell.num]*lenj + J += j + V += [1./lenj]*lenj + return sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + def _getFacePxx(self, xFace, yFace): self.number() - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in self.sortedCells: - i, j, v = cell.faceIndex('fX'+xFace) - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - xP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) - - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in self.sortedCells: - i, j, v = cell.faceIndex('fY'+yFace) - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - yP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + xP = self._getFaceP(xFace, yFace, None) + yP = self._getFaceP(yFace, xFace, None) return sp.vstack((xP, yP)) def _getFacePxxx(self, xFace, yFace, zFace): self.number() - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in self.sortedCells: - i, j, v = cell.faceIndex('fX'+xFace) - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - xP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) - - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in self.sortedCells: - i, j, v = cell.faceIndex('fY'+yFace) - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - yP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) - - I, J, V = np.empty(0), np.empty(0), np.empty(0) - for cell in self.sortedCells: - i, j, v = cell.faceIndex('fZ'+zFace) - I, J, V = np.r_[I,i], np.r_[J,j], np.r_[V,v] - zP = sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) - + xP = self._getFaceP(xFace, yFace, zFace) + yP = self._getFaceP(yFace, xFace, zFace) + zP = self._getFaceP(zFace, xFace, yFace) return sp.vstack((xP, yP, zP)) def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, plotE=False, plotEx=False, plotEy=False, plotEz=False, showIt=False): @@ -953,6 +944,7 @@ if __name__ == '__main__': M.refine(function) DIV = M.faceDiv + Mf = M.getFaceInnerProduct() # plt.subplot(211) # plt.spy(DIV) M.plotGrid(ax=plt.subplot(111),text=True,showIt=True) @@ -960,7 +952,7 @@ if __name__ == '__main__': q = np.zeros(M.nC) q[208] = -1.0 q[291] = 1.0 - b = Solver(-DIV*DIV.T).solve(q) + b = Solver(-DIV*Mf*DIV.T).solve(q) plt.figure() M.plotImage(b) # plt.gca().invert_yaxis() diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 10d1dba6..f55e6deb 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -14,7 +14,6 @@ class TestOcTreeObjects(unittest.TestCase): self.Mr.children[0,0,0].refine() self.Mr.number() - def q(s): if s[0] == 'M': m = self.M @@ -138,14 +137,6 @@ class TestOcTreeObjects(unittest.TestCase): def test_pointersMr(self): - ax = plt.subplot(111, projection='3d') - self.Mr.plotGrid(ax=ax,showIt=False,plotC=True,plotEy=True, text=False) - - cell = self.Mr.sortedCells[0] - [cell.edges[e].plotGrid(ax,lineOpts={'color':'b','ls':'-'}) for e in cell.edges] - cell.plotGrid(ax) - # plt.show() - q = self.q c0 = self.Mr.sortedCells[0] @@ -491,12 +482,16 @@ class SimpleOctreeOperatorTests(unittest.TestCase): h3 = np.random.rand(3) self.tM = TensorMesh([h1,h2,h3]) self.oM = TreeMesh([h1,h2,h3]) + self.tM2 = TensorMesh([h1,h2]) + self.oM2 = TreeMesh([h1,h2]) def test_faceDiv(self): self.assertTrue((self.tM.faceDiv - self.oM.faceDiv).toarray().sum() == 0) + self.assertTrue((self.tM2.faceDiv - self.oM2.faceDiv).toarray().sum() == 0) def test_InnerProducts(self): self.assertTrue((self.tM.getFaceInnerProduct() - self.oM.getFaceInnerProduct()).toarray().sum() == 0) + self.assertTrue((self.tM2.getFaceInnerProduct() - self.oM2.getFaceInnerProduct()).toarray().sum() == 0) if __name__ == '__main__': From aa122eaa195b3bf09b45294874894d820b5fb27c Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 11:39:48 -0800 Subject: [PATCH 35/42] Edge Innerproducts --- SimPEG/Mesh/TreeMesh.py | 52 +++++++++++++++++++++++++++++++++++ SimPEG/Tests/test_TreeMesh.py | 2 ++ 2 files changed, 54 insertions(+) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 601449ad..f3d0f23b 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -131,6 +131,15 @@ class TreeEdge(TreeObject): def center(self): return 0.5*(self.node0.x0 + self.node1.x0) + @property + def index(self): + if self.isleaf: return [self.num] + l = [edge.index for edge in self.children.flatten(order='F')] + # Flatten the list + # e.g. + # [[1,3],[4]] --> [1, 3, 4] + return [item for sublist in l for item in sublist] + class TreeFace(TreeObject): """docstring for TreeFace""" def __init__(self, mesh, x0=[0,0], faceType=None, sz=[1,], depth=0, @@ -877,12 +886,48 @@ class TreeMesh(InnerProducts, BaseMesh): V += [1./lenj]*lenj return sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nF)) + def _getEdgeP(self, edge0, edge1, edge2): + I, J, V = [], [], [] + for cell in self.sortedCells: + if self.dim == 2: + e2f = lambda e: ('f' + {'X':'Y','Y':'X'}[e[1]] + + {'0':'m','1':'p'}[e[2]]) + face = cell.faces[e2f(edge0)] + if face.isleaf: + j = face.index + else: + j = face.children[0 if 'm' in e2f(edge1) else 1].index + # Need to flip the numbering for edges + if 'X' in edge0: + j = [jj - self.nFx for jj in j] + elif 'Y' in edge0: + j = [jj + self.nFy for jj in j] + elif self.dim == 3: + edge = cell.edges[edge0] + if edge.isleaf: + j = edge.index + else: + mSide = lambda e: {'0':True,'1':True,'2':False,'3':False}[e[2]] + j = edge.children[0 if mSide(edge1) else 1, + 0 if mSide(edge2) else 1].index + lenj = len(j) + I += [cell.num]*lenj + J += j + V += [1./lenj]*lenj + return sp.csr_matrix((V,(I,J)), shape=(self.nC, self.nE)) + def _getFacePxx(self, xFace, yFace): self.number() xP = self._getFaceP(xFace, yFace, None) yP = self._getFaceP(yFace, xFace, None) return sp.vstack((xP, yP)) + def _getEdgePxx(self, xEdge, yEdge): + self.number() + xP = self._getEdgeP(xEdge, yEdge, None) + yP = self._getEdgeP(yEdge, xEdge, None) + return sp.vstack((xP, yP)) + def _getFacePxxx(self, xFace, yFace, zFace): self.number() xP = self._getFaceP(xFace, yFace, zFace) @@ -890,6 +935,13 @@ class TreeMesh(InnerProducts, BaseMesh): zP = self._getFaceP(zFace, xFace, yFace) return sp.vstack((xP, yP, zP)) + def _getEdgePxxx(self, xEdge, yEdge, zEdge): + self.number() + xP = self._getEdgeP(xEdge, yEdge, zEdge) + yP = self._getEdgeP(yEdge, xEdge, zEdge) + zP = self._getEdgeP(zEdge, xEdge, yEdge) + return sp.vstack((xP, yP, zP)) + def plotGrid(self, ax=None, text=True, plotC=True, plotF=True, plotE=False, plotEx=False, plotEy=False, plotEz=False, showIt=False): axOpts = {'projection':'3d'} if self.dim == 3 else {} if ax is None: ax = plt.subplot(111, **axOpts) diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index f55e6deb..865757ef 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -492,6 +492,8 @@ class SimpleOctreeOperatorTests(unittest.TestCase): def test_InnerProducts(self): self.assertTrue((self.tM.getFaceInnerProduct() - self.oM.getFaceInnerProduct()).toarray().sum() == 0) self.assertTrue((self.tM2.getFaceInnerProduct() - self.oM2.getFaceInnerProduct()).toarray().sum() == 0) + self.assertTrue((self.tM2.getEdgeInnerProduct() - self.oM2.getEdgeInnerProduct()).toarray().sum() == 0) + self.assertTrue((self.tM.getEdgeInnerProduct() - self.oM.getEdgeInnerProduct()).toarray().sum() == 0) if __name__ == '__main__': From 87a88901336551043f58f1ceb7ff6763ebf6f3b3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 13:35:05 -0800 Subject: [PATCH 36/42] nodes in 3D cell --- SimPEG/Mesh/TreeMesh.py | 1 + SimPEG/Tests/test_TreeMesh.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index f3d0f23b..0cc349b6 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -440,6 +440,7 @@ class TreeCell(TreeObject): self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} self.edges = {"eX0":eX0, "eX1":eX1, "eX2":eX2, "eX3":eX3, "eY0":eY0, "eY1":eY1, "eY2":eY2, "eY3":eY3, "eZ0":eZ0, "eZ1":eZ1, "eZ2":eZ2, "eZ3":eZ3} + self.nodes = {"n0": fZm.nodes['n0'], "n1": fZm.nodes['n1'], "n2": fZm.nodes['n2'], "n3": fZm.nodes['n3'], "n4": fZp.nodes['n0'], "n5": fZp.nodes['n1'], "n6": fZp.nodes['n2'], "n7": fZp.nodes['n3']} mesh.cells.add(self) diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 865757ef..254cf127 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -25,6 +25,7 @@ class TestOcTreeObjects(unittest.TestCase): if s[2] == 'f' and len(s) == 5: return c.faces[s[2:]] if s[2] == 'f': return c.faces[s[2:5]].edges[s[5:]] if s[2] == 'e': return c.edges[s[2:]] + if s[2] == 'n': return c.nodes[s[2:]] self.q = q @@ -135,6 +136,20 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(c1fYp.edges['e2'] is c0fXp.edges['e3']) + def test_nodePointers(self): + q = self.q + c0 = self.Mr.sortedCells[0] + c0n0 = c0.nodes['n0'] + self.assertTrue(c0n0 is q('c0n0')) + self.assertTrue(np.all(q('c0n0').center == np.r_[0,0,0.])) + self.assertTrue(q('c0n0').num == 0) + self.assertTrue(q('c0n1').num == 1) + self.assertTrue(q('c0n2').num == 4) + self.assertTrue(q('c0n3').num == 5) + self.assertTrue(q('c0n4').num == 11) + self.assertTrue(q('c0n5').num == 12) + self.assertTrue(q('c0n6').num == 14) + self.assertTrue(q('c0n7').num == 15) def test_pointersMr(self): q = self.q From aa539462a1aa5f959088eb00da61d220223a1bff Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 13:58:31 -0800 Subject: [PATCH 37/42] Nodal Gradient! --- SimPEG/Mesh/TreeMesh.py | 43 +++++++++++++++++++++++++++++++---- SimPEG/Tests/test_TreeMesh.py | 4 ++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 0cc349b6..63280076 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -97,7 +97,7 @@ class TreeEdge(TreeObject): self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent*self.sz[0]) - + self.nodes = {'n0':node0, 'n1':node1} def refine(self): if not self.isleaf: return @@ -131,6 +131,10 @@ class TreeEdge(TreeObject): def center(self): return 0.5*(self.node0.x0 + self.node1.x0) + @property + def length(self): + return np.sqrt(((self.node1.x0 - self.node0.x0)**2).sum()) + @property def index(self): if self.isleaf: return [self.num] @@ -233,6 +237,11 @@ class TreeFace(TreeObject): """area of the face""" return self.sz.prod() + @property + def length(self): + if self.dim == 3: raise Exception('face.length is not defined for 2D face') + return np.sqrt(((self.node1.x0 - self.node0.x0)**2).sum()) + def refine(self): if not self.isleaf: return self.mesh.isNumbered = False @@ -846,12 +855,20 @@ class TreeMesh(InnerProducts, BaseMesh): @property def area(self): self.number() - if self.dim == 2: - faces = self.sortedFaceX + self.sortedFaceY - elif self.dim == 3: - faces = self.sortedFaceX + self.sortedFaceY + self.sortedFaceZ + faces = self.sortedFaceX + self.sortedFaceY + if self.dim == 3: + faces += self.sortedFaceZ return np.array([face.area for face in faces], dtype=float) + @property + def edge(self): + self.number() + if self.dim == 2: + edges = self.sortedFaceY + self.sortedFaceX + elif self.dim == 3: + edges = self.sortedEdgeX + self.sortedEdgeY + self.sortedEdgeZ + return np.array([e.length for e in edges], dtype=float) + @property def faceDiv(self): if getattr(self, '_faceDiv', None) is None: @@ -870,6 +887,22 @@ class TreeMesh(InnerProducts, BaseMesh): self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) return self._faceDiv + @property + def nodalGrad(self): + if getattr(self, '_nodalGrad', None) is None: + self.number() + # TODO: Preallocate! + I, J, V = [], [], [] + edges = self.faces if self.dim == 2 else self.edges + for edge in edges: + I += [edge.num, edge.num] + J += [edge.node0.num, edge.node1.num] + V += [-1, 1] + G = sp.csr_matrix((V,(I,J)), shape=(self.nE, self.nN)) + L = self.edge + self._nodalGrad = Utils.sdiag(1/L)*G + return self._nodalGrad + def _getFaceP(self, face0, face1, face2): I, J, V = [], [], [] for cell in self.sortedCells: diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 254cf127..acdc4308 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -504,6 +504,10 @@ class SimpleOctreeOperatorTests(unittest.TestCase): self.assertTrue((self.tM.faceDiv - self.oM.faceDiv).toarray().sum() == 0) self.assertTrue((self.tM2.faceDiv - self.oM2.faceDiv).toarray().sum() == 0) + def test_nodalGrad(self): + self.assertTrue((self.tM.nodalGrad - self.oM.nodalGrad).toarray().sum() == 0) + self.assertTrue((self.tM2.nodalGrad - self.oM2.nodalGrad).toarray().sum() == 0) + def test_InnerProducts(self): self.assertTrue((self.tM.getFaceInnerProduct() - self.oM.getFaceInnerProduct()).toarray().sum() == 0) self.assertTrue((self.tM2.getFaceInnerProduct() - self.oM2.getFaceInnerProduct()).toarray().sum() == 0) From 62f00004eb1ffde42c593b64848285a584770051 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 15:02:30 -0800 Subject: [PATCH 38/42] bug fix. --- SimPEG/Mesh/TreeMesh.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 63280076..0cd0cca3 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -893,9 +893,16 @@ class TreeMesh(InnerProducts, BaseMesh): self.number() # TODO: Preallocate! I, J, V = [], [], [] + # kinda a hack for the 2D gradient + # because edges are not stored edges = self.faces if self.dim == 2 else self.edges for edge in edges: - I += [edge.num, edge.num] + if self.dim == 3: + I += [edge.num, edge.num] + elif self.dim == 2 and edge.faceType == 'x': + I += [edge.num + self.nFy, edge.num + self.nFy] + elif self.dim == 2 and edge.faceType == 'y': + I += [edge.num - self.nFx, edge.num - self.nFx] J += [edge.node0.num, edge.node1.num] V += [-1, 1] G = sp.csr_matrix((V,(I,J)), shape=(self.nE, self.nN)) From 12e885f5ce2d46136a6f36569cbad7b88ee684cb Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 18:45:06 -0800 Subject: [PATCH 39/42] change field--> fields --- SimPEG/Data.py | 6 +++--- SimPEG/Examples/DC.py | 8 ++++---- SimPEG/Examples/Linear.py | 2 +- SimPEG/ObjFunction.py | 6 +++--- SimPEG/Parameters.py | 2 +- SimPEG/Problem.py | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index fa37b09a..7a793065 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -56,12 +56,12 @@ class BaseData(object): Where P is a projection of the fields onto the data space. """ - if u is None: u = self.prob.field(m) - return Utils.mkvc(self.projectField(u)) + if u is None: u = self.prob.fields(m) + return Utils.mkvc(self.projectFields(u)) @Utils.count - def projectField(self, u): + def projectFields(self, u): """ This function projects the fields onto the data space. diff --git a/SimPEG/Examples/DC.py b/SimPEG/Examples/DC.py index 074f5e3d..ee8a427f 100644 --- a/SimPEG/Examples/DC.py +++ b/SimPEG/Examples/DC.py @@ -69,7 +69,7 @@ class DCProblem(Problem.BaseProblem): A = D*Msig*G return A.tocsc() - def field(self, m): + def fields(self, m): A = self.createMatrix(m) solve = Solver(A) phi = solve.solve(self.data.RHS) @@ -98,7 +98,7 @@ class DCProblem(Problem.BaseProblem): J(v) = - P ( A(m)^{-1} ( G\\text{sdiag}(Du)\\nabla_m(M(mT(m))) v ) ) """ if u is None: - u = self.field(m) + u = self.fields(m) u = self.data.reshapeFields(u) @@ -123,7 +123,7 @@ class DCProblem(Problem.BaseProblem): """Takes data, turns it into a model..ish""" if u is None: - u = self.field(m) + u = self.fields(m) u = self.data.reshapeFields(u) v = self.data.reshapeFields(v) @@ -214,7 +214,7 @@ if __name__ == '__main__': # Create some data data = prob.createSyntheticData(mSynth, std=0.05, P=P, RHS=q) - u = prob.field(mSynth) + u = prob.fields(mSynth) u = data.reshapeFields(u) M.plotImage(u[:,10]) plt.show() diff --git a/SimPEG/Examples/Linear.py b/SimPEG/Examples/Linear.py index a83b26f1..e18750c1 100644 --- a/SimPEG/Examples/Linear.py +++ b/SimPEG/Examples/Linear.py @@ -9,7 +9,7 @@ class LinearProblem(Problem.BaseProblem): Problem.BaseProblem.__init__(self, mesh, model, **kwargs) self.G = G - def field(self, m, u=None): + def fields(self, m, u=None): return self.G.dot(m) def J(self, m, v, u=None): diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index ea2fe831..91722b68 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -73,7 +73,7 @@ class BaseObjFunction(object): self.u_current = None self.m_current = m - u = self.data.prob.field(m) + u = self.data.prob.fields(m) self.u_current = u phi_d = self.dataObj(m, u=u) @@ -160,7 +160,7 @@ class BaseObjFunction(object): \\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R} """ - if u is None: u = self.data.prob.field(m) + if u is None: u = self.data.prob.fields(m) R = self.data.residualWeighted(m, u=u) @@ -204,7 +204,7 @@ class BaseObjFunction(object): \\frac{\partial^2 \mu_\\text{data}}{\partial^2 \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ W J} """ - if u is None: u = self.data.prob.field(m) + if u is None: u = self.data.prob.fields(m) R = self.data.residualWeighted(m, u=u) diff --git a/SimPEG/Parameters.py b/SimPEG/Parameters.py index 2a07aa69..9b12d8d1 100644 --- a/SimPEG/Parameters.py +++ b/SimPEG/Parameters.py @@ -137,7 +137,7 @@ class BetaEstimate(Parameter): u = objFunc.u_current if u is None: - u = data.prob.field(m) + u = data.prob.fields(m) x0 = np.random.rand(*m.shape) t = x0.dot(objFunc.dataObj2Deriv(m,x0,u=u)) diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index 386fac9d..df37d05a 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -142,7 +142,7 @@ class BaseProblem(object): """ return self.Jt(m, v, u) - def field(self, m): + def fields(self, m): """ The field given the model. From a89535781fc13ebdc51fb3f8cbccd515a54dbfc2 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 19:10:29 -0800 Subject: [PATCH 40/42] edgeCurl on ocTree --- SimPEG/Mesh/TreeMesh.py | 22 ++++++++++++++++++++++ SimPEG/Tests/test_TreeMesh.py | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 0cd0cca3..b35dac1a 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -887,6 +887,28 @@ class TreeMesh(InnerProducts, BaseMesh): self._faceDiv = Utils.sdiag(1/VOL)*D*Utils.sdiag(S) 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 = [], [], [] + for face in self.faces: + for edge in face.edges: + j = face.edges[edge].index + I += [face.num]*len(j) + J += j + isNeg = lambda e: {'0':True,'1':False,'2':True,'3':False}[e[1]] + V += [-1 if isNeg(edge) else 1]*len(j) + C = sp.csr_matrix((V,(I,J)), shape=(self.nF, self.nE)) + S = self.area + L = self.edge + self._edgeCurl = Utils.sdiag(1/S)*C*Utils.sdiag(L) + return self._edgeCurl + @property def nodalGrad(self): if getattr(self, '_nodalGrad', None) is None: diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index acdc4308..7a744d0a 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -508,6 +508,10 @@ class SimpleOctreeOperatorTests(unittest.TestCase): self.assertTrue((self.tM.nodalGrad - self.oM.nodalGrad).toarray().sum() == 0) self.assertTrue((self.tM2.nodalGrad - self.oM2.nodalGrad).toarray().sum() == 0) + def test_edgeCurl(self): + self.assertTrue((self.tM.edgeCurl - self.oM.edgeCurl).toarray().sum() == 0) + # self.assertTrue((self.tM2.edgeCurl - self.oM2.edgeCurl).toarray().sum() == 0) + def test_InnerProducts(self): self.assertTrue((self.tM.getFaceInnerProduct() - self.oM.getFaceInnerProduct()).toarray().sum() == 0) self.assertTrue((self.tM2.getFaceInnerProduct() - self.oM2.getFaceInnerProduct()).toarray().sum() == 0) From 7b025ed95a31f3b4983864fd2b5066ab96cb7f9d Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 23:31:01 -0800 Subject: [PATCH 41/42] Memory optimizations: use __slots__ to save 1GB of ram on modest sized problem. Get rid of dictionaries (they are expensive here). --- SimPEG/Mesh/TreeMesh.py | 345 +++++++++++++++++++--------------- SimPEG/Tests/test_TreeMesh.py | 172 ++++++++--------- 2 files changed, 268 insertions(+), 249 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index b35dac1a..15780b53 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -40,55 +40,31 @@ def SortByX0(): return K -class TreeObject(object): - """docstring for TreeObject""" - - children = None #: children of the tree object - num = None - depth = 0 - - def __init__(self, mesh, parent, depth): - self.mesh = mesh - self._parent = parent - self.depth = depth - - @property - def parent(self): return self._parent - - @property - def dim(self): return self.mesh.dim - - @property - def isleaf(self): return self.children is None - - @property - def branchdepth(self): - if self.isleaf: - return self.depth - else: - return np.max([node.branchdepth for node in self.children.flatten('F')]) - - -class TreeNode(TreeObject): +class TreeNode(object): """docstring for TreeNode""" - def __init__(self, mesh, x0=[0,0], parent=None): - TreeObject.__init__(self, mesh, parent, 0) + + __slots__ = ['x0', 'num'] + + def __init__(self, mesh, x0=[0,0]): self.x0 = np.array(x0, dtype=float) - self.mesh.nodes.add(self) + mesh.nodes.add(self) @property def center(self): return self.x0 -class TreeEdge(TreeObject): +class TreeEdge(object): """docstring for TreeEdge""" - def __init__(self, mesh, x0=[0,0], edgeType=None, sz=[1,], depth=0, - node0=None, node1=None, - parent=None): - TreeObject.__init__(self, mesh, parent, depth) - self.x0 = np.array(x0, dtype=float) + __slots__ = ['mesh', 'children', 'depth', 'x0', 'num', 'edgeType', 'sz', 'node0', 'node1'] + + def __init__(self, mesh, x0=[0,0], edgeType=None, sz=[1,], depth=0, + node0=None, node1=None): + self.mesh = mesh + self.depth = depth + + self.x0 = x0 + self.sz = sz self.edgeType = edgeType - self.sz = np.array(sz, dtype=float) mesh.edges.add(self) if edgeType is 'x': mesh.edgesX.add(self) @@ -97,7 +73,9 @@ class TreeEdge(TreeObject): self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent*self.sz[0]) - self.nodes = {'n0':node0, 'n1':node1} + + @property + def isleaf(self): return getattr(self, 'children', None) is None def refine(self): if not self.isleaf: return @@ -107,8 +85,8 @@ class TreeEdge(TreeObject): # Create refined x0's x0r_0 = self.x0 x0r_1 = self.x0+0.5*self.tangent*self.sz - self.children[0] = TreeEdge(self.mesh, x0=x0r_0, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) - self.children[1] = TreeEdge(self.mesh, x0=x0r_1, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.children[0].node1, node1=self.node1) + self.children[0] = TreeEdge(self.mesh, x0=x0r_0, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, node0=self.node0) + self.children[1] = TreeEdge(self.mesh, x0=x0r_1, edgeType=self.edgeType, sz=0.5*self.sz, depth=self.depth+1, node0=self.children[0].node1, node1=self.node1) self.mesh.edges.remove(self) if self.edgeType is 'x': self.mesh.edgesX.remove(self) @@ -144,17 +122,21 @@ class TreeEdge(TreeObject): # [[1,3],[4]] --> [1, 3, 4] return [item for sublist in l for item in sublist] -class TreeFace(TreeObject): +class TreeFace(object): """docstring for TreeFace""" + + __slots__ = ['mesh', 'children', 'depth', 'x0', 'num', 'faceType', 'sz', 'node0', 'node1', 'node2', 'node3', 'edge0', 'edge1', 'edge2', 'edge3', '_tangent0', '_tangent1'] + def __init__(self, mesh, x0=[0,0], faceType=None, sz=[1,], depth=0, node0=None, node1=None, - edge0=None, edge1=None, edge2=None, edge3=None, - parent=None): - TreeObject.__init__(self, mesh, parent, depth) + edge0=None, edge1=None, edge2=None, edge3=None): - self.x0 = np.array(x0, dtype=float) + self.mesh = mesh + self.depth = depth + + self.x0 = x0 self.faceType = faceType - self.sz = np.array(sz, dtype=float) + self.sz = sz mesh.faces.add(self) if faceType is 'x': mesh.facesX.add(self) @@ -178,43 +160,61 @@ class TreeFace(TreeObject): # N = {} - N["n0"] = getattr(edge0, 'node0', None) or getattr(edge2, 'node0', None) - N["n1"] = getattr(edge0, 'node1', None) or getattr(edge3, 'node0', None) - N["n2"] = getattr(edge1, 'node0', None) or getattr(edge2, 'node1', None) - N["n3"] = getattr(edge1, 'node1', None) or getattr(edge3, 'node1', None) + n0 = getattr(edge0, 'node0', None) or getattr(edge2, 'node0', None) + n1 = getattr(edge0, 'node1', None) or getattr(edge3, 'node0', None) + n2 = getattr(edge1, 'node0', None) or getattr(edge2, 'node1', None) + n3 = getattr(edge1, 'node1', None) or getattr(edge3, 'node1', None) eType = ['x', 'y'] if self.faceType == 'z' else ['x', 'z'] if self.faceType == 'y' else ['y', 'z'] - e0 = edge0 if isinstance(edge0,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n0'], node1=N['n1']) - N["n0"], N["n1"] = e0.node0, e0.node1 + e0 = edge0 if isinstance(edge0,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n0, node1=n1) + n0, n1 = e0.node0, e0.node1 - e1 = edge1 if isinstance(edge1,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent1*self.sz[1], edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n2'], node1=N['n3']) - N["n2"], N["n3"] = e1.node0, e1.node1 + e1 = edge1 if isinstance(edge1,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent1*self.sz[1], edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n2, node1=n3) + n2, n3 = e1.node0, e1.node1 - e2 = edge2 if isinstance(edge2,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n0'], node1=N['n2']) - N["n0"], N["n2"] = e2.node0, e2.node1 + e2 = edge2 if isinstance(edge2,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n0, node1=n2) + n0, n2 = e2.node0, e2.node1 - e3 = edge3 if isinstance(edge3,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent0*self.sz[0], edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n1'], node1=N['n3']) - N["n1"], N["n3"] = e3.node0, e3.node1 + e3 = edge3 if isinstance(edge3,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent0*self.sz[0], edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n1, node1=n3) + n1, n3 = e3.node0, e3.node1 - self.nodes = N - self.edges = {'e0':e0, 'e1':e1, 'e2':e2, 'e3':e3} + # self.nodes = N + self.node0, self.node1, self.node2, self.node3 = n0, n1, n2, n3 + self.edge0, self.edge1, self.edge2, self.edge3 = e0, e1, e2, e3 + # self.edges = {'e0':e0, 'e1':e1, 'e2':e2, 'e3':e3} + @property + def dim(self): return self.mesh.dim + + @property + def isleaf(self): return getattr(self, 'children', None) is None + + @property + def branchdepth(self): + if self.isleaf: + return self.depth + else: + return np.max([node.branchdepth for node in self.children.flatten('F')]) @property def tangent0(self): - if self.faceType is 'x': t = np.r_[0,1.,0] - elif self.faceType is 'y': t = np.r_[1.,0,0] - elif self.faceType is 'z': t = np.r_[1.,0,0] - return t[:self.dim] + if getattr(self,'_tangent0',None) is None: + if self.faceType is 'x': t = np.r_[0,1.,0] + elif self.faceType is 'y': t = np.r_[1.,0,0] + elif self.faceType is 'z': t = np.r_[1.,0,0] + self._tangent0 = t[:self.dim] + return self._tangent0 @property def tangent1(self): if self.dim == 2: return - if self.faceType is 'x': t = np.r_[0,0,1.] - elif self.faceType is 'y': t = np.r_[0,0,1.] - elif self.faceType is 'z': t = np.r_[0,1.,0] - return t[:self.dim] + if getattr(self,'_tangent1',None) is None: + if self.faceType is 'x': t = np.r_[0,0,1.] + elif self.faceType is 'y': t = np.r_[0,0,1.] + elif self.faceType is 'z': t = np.r_[0,1.,0] + self._tangent1 = t + return self._tangent1 @property def normal(self): @@ -255,8 +255,8 @@ class TreeFace(TreeObject): # Create refined x0's x0r_0 = self.x0 x0r_1 = self.x0+0.5*self.tangent0*self.sz - self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.node0) - self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, parent=self, node0=self.children[0].node1, node1=self.node1) + self.children[0] = TreeFace(self.mesh, x0=x0r_0, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, node0=self.node0) + self.children[1] = TreeFace(self.mesh, x0=x0r_1, faceType=self.faceType, sz=0.5*self.sz, depth=self.depth+1, node0=self.children[0].node1, node1=self.node1) self.mesh.faces.remove(self) if self.faceType is 'x': self.mesh.facesX.remove(self) @@ -292,20 +292,21 @@ class TreeFace(TreeObject): def getEdge(pointer): if pointer is 'new': return if pointer[0] == 'p': - return self.edges[pointer[1]].children[pointer[2][0]] + return getattr(self, 'edg' + pointer[1]).children[pointer[2][0]] if pointer[0] == 'c': - return self.children[pointer[2][0],pointer[2][1]].edges[pointer[1]] + f = self.children[pointer[2][0],pointer[2][1]] + return getattr(f, 'edg' + pointer[1]) self.children = np.empty((2,2), dtype=TreeFace) - for edgeName in self.edges: - self.edges[edgeName].refine() + for edge in [self.edge0, self.edge1, self.edge2, self.edge3]: + edge.refine() for O in order: i, j = O['c'] x0r = self.x0 + 0.5*i*self.tangent0*self.sz[0] + 0.5*j*self.tangent1*self.sz[1] e0, e1, e2, e3 = getEdge(O['e0']), getEdge(O['e1']), getEdge(O['e2']), getEdge(O['e3']) - self.children[i,j] = TreeFace(self.mesh, x0=x0r, faceType=self.faceType, depth=self.depth+1, sz=0.5*self.sz, parent=self, edge0=e0, edge1=e1, edge2=e2, edge3=e3) + self.children[i,j] = TreeFace(self.mesh, x0=x0r, faceType=self.faceType, depth=self.depth+1, sz=0.5*self.sz, edge0=e0, edge1=e1, edge2=e2, edge3=e3) self.mesh.faces.remove(self) if self.faceType is 'x': @@ -332,18 +333,24 @@ class TreeFace(TreeObject): return self.x0 + 0.5*self.tangent0*self.sz[0] + 0.5*self.tangent1*self.sz[1] -class TreeCell(TreeObject): - """docstring for TreeCell""" - children = None #: +class TreeCell(object): + + __slots__ = ['mesh', 'children', 'depth', 'num', 'sz', + 'node0', 'node1', 'node2', 'node3', + 'node4', 'node5', 'node6', 'node7', + 'fXm', 'fXp', 'fYm', 'fYp', 'fZm', 'fZp', + 'eX0','eX1','eX2','eX3', + 'eY0','eY1','eY2','eY3', + 'eZ0','eZ1','eZ2','eZ3'] def __init__(self, mesh, x0=[0,0], depth=0, sz=[1,1], fXm=None, fXp=None, fYm=None, fYp=None, - fZm=None, fZp=None, - parent=None): - TreeObject.__init__(self, mesh, parent, depth) + fZm=None, fZp=None): + + self.mesh = mesh + self.depth = depth - self.x0 = np.array(x0, dtype=float) self.sz = np.array(sz, dtype=float) if self.dim == 2: # @@ -355,26 +362,24 @@ class TreeCell(TreeObject): # |___________| |___> x # 0 fYm 1 # - N = {} - N["n0"] = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) - N["n1"] = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) - N["n2"] = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) - N["n3"] = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) + n0 = getattr(fXm, 'node0', None) or getattr(fYm, 'node0', None) + n1 = getattr(fXp, 'node0', None) or getattr(fYm, 'node1', None) + n2 = getattr(fXm, 'node1', None) or getattr(fYp, 'node0', None) + n3 = getattr(fXp, 'node1', None) or getattr(fYp, 'node1', None) - fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n0'], node1=N['n2']) - N["n0"], N["n2"] = fXm.node0, fXm.node1 + self.fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, node0=n0, node1=n2) + n0, n2 = self.fXm.node0, self.fXm.node1 - fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, parent=parent, node0=N['n1'], node1=N['n3']) - N["n1"], N["n3"] = fXp.node0, fXp.node1 + self.fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] ], faceType='x', sz=np.r_[sz[1]], depth=depth, node0=n1, node1=n3) + n1, n3 = self.fXp.node0, self.fXp.node1 - fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n0'], node1=N['n1']) - N["n0"], N["n1"] = fYm.node0, fYm.node1 + self.fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] ], faceType='y', sz=np.r_[sz[0]], depth=depth, node0=n0, node1=n1) + n0, n1 = self.fYm.node0, self.fYm.node1 - fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', sz=np.r_[sz[0]], depth=depth, parent=parent, node0=N['n2'], node1=N['n3']) - N["n2"], N["n3"] = fYp.node0, fYp.node1 + self.fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1]], faceType='y', sz=np.r_[sz[0]], depth=depth, node0=n2, node1=n3) + n2, n3 = self.fYp.node0, self.fYp.node1 - self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp} - self.nodes = N + self.node0, self.node1, self.node2, self.node3 = n0, n1, n2, n3 elif self.dim == 3: # fZp @@ -410,52 +415,85 @@ class TreeCell(TreeObject): def getEdge(face, key): if face is None: return - return face.edges[key] + return getattr(face, key) E = {} - eX0 = getEdge(fYm, 'e0') or getEdge(fZm, 'e0') - eX1 = getEdge(fYp, 'e0') or getEdge(fZm, 'e1') - eX2 = getEdge(fYm, 'e1') or getEdge(fZp, 'e0') - eX3 = getEdge(fYp, 'e1') or getEdge(fZp, 'e1') + eX0 = getEdge(fYm, 'edge0') or getEdge(fZm, 'edge0') + eX1 = getEdge(fYp, 'edge0') or getEdge(fZm, 'edge1') + eX2 = getEdge(fYm, 'edge1') or getEdge(fZp, 'edge0') + eX3 = getEdge(fYp, 'edge1') or getEdge(fZp, 'edge1') - eY0 = getEdge(fXm, 'e0') or getEdge(fZm, 'e2') - eY1 = getEdge(fXp, 'e0') or getEdge(fZm, 'e3') - eY2 = getEdge(fXm, 'e1') or getEdge(fZp, 'e2') - eY3 = getEdge(fXp, 'e1') or getEdge(fZp, 'e3') + eY0 = getEdge(fXm, 'edge0') or getEdge(fZm, 'edge2') + eY1 = getEdge(fXp, 'edge0') or getEdge(fZm, 'edge3') + eY2 = getEdge(fXm, 'edge1') or getEdge(fZp, 'edge2') + eY3 = getEdge(fXp, 'edge1') or getEdge(fZp, 'edge3') - eZ0 = getEdge(fXm, 'e2') or getEdge(fYm, 'e2') - eZ1 = getEdge(fXp, 'e2') or getEdge(fYm, 'e3') - eZ2 = getEdge(fXm, 'e3') or getEdge(fYp, 'e2') - eZ3 = getEdge(fXp, 'e3') or getEdge(fYp, 'e3') + eZ0 = getEdge(fXm, 'edge2') or getEdge(fYm, 'edge2') + eZ1 = getEdge(fXp, 'edge2') or getEdge(fYm, 'edge3') + eZ2 = getEdge(fXm, 'edge3') or getEdge(fYp, 'edge2') + eZ3 = getEdge(fXp, 'edge3') or getEdge(fYp, 'edge3') - fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, edge0=eY0, edge1=eY2, edge2=eZ0, edge3=eZ2) - eY0, eY2, eZ0, eZ2 = fXm.edges['e0'], fXm.edges['e1'], fXm.edges['e2'], fXm.edges['e3'] + self.fXm = fXm if isinstance(fXm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, edge0=eY0, edge1=eY2, edge2=eZ0, edge3=eZ2) + eY0, eY2, eZ0, eZ2 = self.fXm.edge0, self.fXm.edge1, self.fXm.edge2, self.fXm.edge3 - fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, parent=parent, edge0=eY1, edge1=eY3, edge2=eZ1, edge3=eZ3) - eY1, eY3, eZ1, eZ3 = fXp.edges['e0'], fXp.edges['e1'], fXp.edges['e2'], fXp.edges['e3'] + self.fXp = fXp if isinstance(fXp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0]+sz[0], x0[1] , x0[2] ], faceType='x', sz=np.r_[sz[1], sz[2]], depth=depth, edge0=eY1, edge1=eY3, edge2=eZ1, edge3=eZ3) + eY1, eY3, eZ1, eZ3 = self.fXp.edge0, self.fXp.edge1, self.fXp.edge2, self.fXp.edge3 - fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, edge0=eX0, edge1=eX2, edge2=eZ0, edge3=eZ1) - eX0, eX2, eZ0, eZ1 = fYm.edges['e0'], fYm.edges['e1'], fYm.edges['e2'], fYm.edges['e3'] + self.fYm = fYm if isinstance(fYm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, edge0=eX0, edge1=eX2, edge2=eZ0, edge3=eZ1) + eX0, eX2, eZ0, eZ1 = self.fYm.edge0, self.fYm.edge1, self.fYm.edge2, self.fYm.edge3 - fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, parent=parent, edge0=eX1, edge1=eX3, edge2=eZ2, edge3=eZ3) - eX1, eX3, eZ2, eZ3 = fYp.edges['e0'], fYp.edges['e1'], fYp.edges['e2'], fYp.edges['e3'] + self.fYp = fYp if isinstance(fYp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1]+sz[1], x0[2] ], faceType='y', sz=np.r_[sz[0], sz[2]], depth=depth, edge0=eX1, edge1=eX3, edge2=eZ2, edge3=eZ3) + eX1, eX3, eZ2, eZ3 = self.fYp.edge0, self.fYp.edge1, self.fYp.edge2, self.fYp.edge3 - fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, edge0=eX0, edge1=eX1, edge2=eY0, edge3=eY1) - eX0, eX1, eY0, eY1 = fZm.edges['e0'], fZm.edges['e1'], fZm.edges['e2'], fZm.edges['e3'] + self.fZm = fZm if isinstance(fZm, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2] ], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, edge0=eX0, edge1=eX1, edge2=eY0, edge3=eY1) + eX0, eX1, eY0, eY1 = self.fZm.edge0, self.fZm.edge1, self.fZm.edge2, self.fZm.edge3 - fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, parent=parent, edge0=eX2, edge1=eX3, edge2=eY2, edge3=eY3) - eX2, eX3, eY2, eY3 = fZp.edges['e0'], fZp.edges['e1'], fZp.edges['e2'], fZp.edges['e3'] + self.fZp = fZp if isinstance(fZp, TreeFace) else TreeFace(mesh, x0=np.r_[x0[0] , x0[1] , x0[2]+sz[2]], faceType='z', sz=np.r_[sz[0], sz[1]], depth=depth, edge0=eX2, edge1=eX3, edge2=eY2, edge3=eY3) + eX2, eX3, eY2, eY3 = self.fZp.edge0, self.fZp.edge1, self.fZp.edge2, self.fZp.edge3 - self.faces = {"fXm":fXm, "fXp":fXp, "fYm":fYm, "fYp":fYp, "fZm":fZm, "fZp":fZp} - self.edges = {"eX0":eX0, "eX1":eX1, "eX2":eX2, "eX3":eX3, "eY0":eY0, "eY1":eY1, "eY2":eY2, "eY3":eY3, "eZ0":eZ0, "eZ1":eZ1, "eZ2":eZ2, "eZ3":eZ3} - self.nodes = {"n0": fZm.nodes['n0'], "n1": fZm.nodes['n1'], "n2": fZm.nodes['n2'], "n3": fZm.nodes['n3'], "n4": fZp.nodes['n0'], "n5": fZp.nodes['n1'], "n6": fZp.nodes['n2'], "n7": fZp.nodes['n3']} + self.eX0, self.eX1, self.eX2, self.eX3, self.eY0, self.eY1, self.eY2, self.eY3, self.eZ0, self.eZ1, self.eZ2, self.eZ3 = eX0, eX1, eX2, eX3, eY0, eY1, eY2, eY3, eZ0, eZ1, eZ2, eZ3 + self.node0, self.node1, self.node2, self.node3, self.node4, self.node5, self.node6, self.node7 = self.fZm.node0, self.fZm.node1, self.fZm.node2, self.fZm.node3, self.fZp.node0, self.fZp.node1, self.fZp.node2, self.fZp.node3 mesh.cells.add(self) + @property + def x0(self): return self.node0.x0 + @property def center(self): return self.x0 + 0.5*self.sz + @property + def dim(self): return self.mesh.dim + + @property + def faceDict(self): + d = {"fXm":self.fXm, "fXp":self.fXp, "fYm":self.fYm, "fYp":self.fYp} + if self.dim == 3: + d["fZm"] = self.fZm + d["fZp"] = self.fZp + return d + + @property + def edgeDict(self): + if self.dim == 2: return None + return {'eX0': self.eX0, 'eX1': self.eX1, 'eX2': self.eX2, 'eX3': self.eX3, 'eY0': self.eY0, 'eY1': self.eY1, 'eY2': self.eY2, 'eY3': self.eY3, 'eZ0': self.eZ0, 'eZ1': self.eZ1, 'eZ2': self.eZ2, 'eZ3': self.eZ3} + + @property + def faceList(self): + l = [self.fXm, self.fXp, self.fYm, self.fYp] + if self.dim == 3: + l += [self.fZm, self.fZp] + return l + + @property + def edgeList(self): + if self.dim == 2: return None + return [self.eX0, self.eX1, self.eX2, self.eX3, self.eY0, self.eY1, self.eY2, self.eY3, self.eZ0, self.eZ1, self.eZ2, self.eZ3] + + @property + def isleaf(self): return getattr(self, 'children', None) is None + def refine(self, function=None): if not self.isleaf and function is None: return @@ -477,11 +515,11 @@ class TreeCell(TreeObject): self.mesh.isNumbered = False - self.children = np.empty((2,2),dtype=TreeCell) + self.children = np.empty((2,2), dtype=TreeCell) x0, sz = self.x0, self.sz - for faceName in self.faces: - self.faces[faceName].refine() + for face in self.faceList: + face.refine() order = [{'c':[0,0], 'fXm': ('p', 'fXm', [0]), 'fXp': 'new' , @@ -499,15 +537,15 @@ class TreeCell(TreeObject): def getFace(pointer): if pointer is 'new': return None if pointer[0] == 'p': - return self.faces[pointer[1]].children[pointer[2][0],] + return self.faceDict[pointer[1]].children[pointer[2][0],] if pointer[0] == 'c': - return self.children[pointer[2][0],pointer[2][1]].faces[pointer[1]] + return self.children[pointer[2][0],pointer[2][1]].faceDict[pointer[1]] for O in order: i, j = O['c'] x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1]] fXm, fXp, fYm, fYp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']) - self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) + self.children[i,j] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp) self.mesh.cells.remove(self) @@ -588,21 +626,21 @@ class TreeCell(TreeObject): self.children = np.empty((2,2,2), dtype=TreeCell) x0, sz = self.x0, self.sz - for faceName in self.faces: - self.faces[faceName].refine() + for face in self.faceList: + face.refine() def getFace(pointer): if pointer is 'new': return None if pointer[0] == 'p': - return self.faces[pointer[1]].children[pointer[2][0],pointer[2][1]] + return self.faceDict[pointer[1]].children[pointer[2][0],pointer[2][1]] if pointer[0] == 'c': - return self.children[pointer[2][0],pointer[2][1],pointer[2][2]].faces[pointer[1]] + return self.children[pointer[2][0],pointer[2][1],pointer[2][2]].faceDict[pointer[1]] for O in order: i, j, k = O['c'] x0r = np.r_[x0[0] + 0.5*i*sz[0], x0[1] + 0.5*j*sz[1], x0[2] + 0.5*k*sz[2]] fXm, fXp, fYm, fYp, fZm, fZp = getFace(O['fXm']), getFace(O['fXp']), getFace(O['fYm']), getFace(O['fYp']), getFace(O['fZm']), getFace(O['fZp']) - self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, parent=self, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) + self.children[i,j,k] = TreeCell(self.mesh, x0=x0r, depth=self.depth+1, sz=0.5*sz, fXm=fXm, fXp=fXp, fYm=fYm, fYp=fYp, fZm=fZm, fZp=fZp) self.mesh.cells.remove(self) @@ -677,8 +715,8 @@ class TreeMesh(InnerProducts, BaseMesh): if self.dim == 2: for i in range(h[0].size): for j in range(h[1].size): - fXm = None if i is 0 else self.children[i-1][j].faces['fXp'] - fYm = None if j is 0 else self.children[i][j-1].faces['fYp'] + fXm = None if i is 0 else self.children[i-1][j].fXp + fYm = None if j is 0 else self.children[i][j-1].fYp x0i = (np.r_[x0[0], h[0][:i]]).sum() x0j = (np.r_[x0[1], h[1][:j]]).sum() self.children[i][j] = TreeCell(self, x0=[x0i, x0j], depth=0, sz=[h[0][i], h[1][j]], fXm=fXm, fYm=fYm) @@ -687,9 +725,9 @@ class TreeMesh(InnerProducts, BaseMesh): for i in range(h[0].size): for j in range(h[1].size): for k in range(h[2].size): - fXm = None if i is 0 else self.children[i-1][j][k].faces['fXp'] - fYm = None if j is 0 else self.children[i][j-1][k].faces['fYp'] - fZm = None if k is 0 else self.children[i][j][k-1].faces['fZp'] + fXm = None if i is 0 else self.children[i-1][j][k].fXp + fYm = None if j is 0 else self.children[i][j-1][k].fYp + fZm = None if k is 0 else self.children[i][j][k-1].fZp x0i = (np.r_[x0[0], h[0][:i]]).sum() x0j = (np.r_[x0[1], h[1][:j]]).sum() x0k = (np.r_[x0[2], h[2][:k]]).sum() @@ -876,8 +914,9 @@ class TreeMesh(InnerProducts, BaseMesh): # TODO: Preallocate! I, J, V = [], [], [] for cell in self.sortedCells: - for face in cell.faces: - j = cell.faces[face].index + faces = cell.faceDict + for face in faces: + j = faces[face].index I += [cell.num]*len(j) J += j V += [-1 if 'm' in face else 1]*len(j) @@ -897,12 +936,12 @@ class TreeMesh(InnerProducts, BaseMesh): # TODO: Preallocate! I, J, V = [], [], [] for face in self.faces: - for edge in face.edges: - j = face.edges[edge].index + for ii, edge in enumerate([face.edge0, face.edge1, face.edge2, face.edge3]): + j = edge.index I += [face.num]*len(j) J += j - isNeg = lambda e: {'0':True,'1':False,'2':True,'3':False}[e[1]] - V += [-1 if isNeg(edge) else 1]*len(j) + isNeg = [True, False, True, False] + V += [-1 if isNeg[ii] else 1]*len(j) C = sp.csr_matrix((V,(I,J)), shape=(self.nF, self.nE)) S = self.area L = self.edge @@ -935,7 +974,7 @@ class TreeMesh(InnerProducts, BaseMesh): def _getFaceP(self, face0, face1, face2): I, J, V = [], [], [] for cell in self.sortedCells: - face = cell.faces[face0] + face = cell.faceDict[face0] if face.isleaf: j = face.index elif self.dim == 2: @@ -955,7 +994,7 @@ class TreeMesh(InnerProducts, BaseMesh): if self.dim == 2: e2f = lambda e: ('f' + {'X':'Y','Y':'X'}[e[1]] + {'0':'m','1':'p'}[e[2]]) - face = cell.faces[e2f(edge0)] + face = cell.faceDict[e2f(edge0)] if face.isleaf: j = face.index else: @@ -966,7 +1005,7 @@ class TreeMesh(InnerProducts, BaseMesh): elif 'Y' in edge0: j = [jj + self.nFy for jj in j] elif self.dim == 3: - edge = cell.edges[edge0] + edge = cell.edgeDict[edge0] if edge.isleaf: j = edge.index else: diff --git a/SimPEG/Tests/test_TreeMesh.py b/SimPEG/Tests/test_TreeMesh.py index 7a744d0a..f8120859 100644 --- a/SimPEG/Tests/test_TreeMesh.py +++ b/SimPEG/Tests/test_TreeMesh.py @@ -22,10 +22,10 @@ class TestOcTreeObjects(unittest.TestCase): m = self.Mr c = m.sortedCells[int(s[1])] if len(s) == 2: return c - if s[2] == 'f' and len(s) == 5: return c.faces[s[2:]] - if s[2] == 'f': return c.faces[s[2:5]].edges[s[5:]] - if s[2] == 'e': return c.edges[s[2:]] - if s[2] == 'n': return c.nodes[s[2:]] + if s[2] == 'f' and len(s) == 5: return c.faceDict[s[2:]] + if s[2] == 'f': return getattr(c.faceDict[s[2:5]], 'edg' +s[5:]) + if s[2] == 'e': return getattr(c,s[2:]) + if s[2] == 'n': return getattr(c,'node'+s[3:]) self.q = q @@ -49,8 +49,8 @@ class TestOcTreeObjects(unittest.TestCase): for cell in self.Mr.sortedCells: - for e in cell.edges: - self.assertTrue(cell.edges[e].edgeType==e[1].lower()) + for e in cell.edgeDict: + self.assertTrue(cell.edgeDict[e].edgeType==e[1].lower()) self.assertTrue(self.Mr.nN == 31) self.assertTrue(self.Mr.nEx == 22) @@ -70,76 +70,62 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(q(key+'fZp').area == 0.5) def test_pointersM(self): - c0 = self.M.children[0,0,0] - c0fXm = c0.faces['fXm'] - c0fXp = c0.faces['fXp'] - c0fYm = c0.faces['fYm'] - c0fYp = c0.faces['fYp'] - c0fZm = c0.faces['fZm'] - c0fZp = c0.faces['fZp'] + q = self.q - c1 = self.M.children[1,0,0] - c1fXm = c1.faces['fXm'] - c1fXp = c1.faces['fXp'] - c1fYm = c1.faces['fYm'] - c1fYp = c1.faces['fYp'] - c1fZm = c1.faces['fZm'] - c1fZp = c1.faces['fZp'] - - self.assertTrue(c0fXp is c1fXm) - self.assertTrue(c0fXp.edges['e0'] is c1fXm.edges['e0']) - self.assertTrue(c0fXp.edges['e1'] is c1fXm.edges['e1']) - self.assertTrue(c0fXp.edges['e2'] is c1fXm.edges['e2']) - self.assertTrue(c0fXp.edges['e3'] is c1fXm.edges['e3']) - self.assertTrue(c0fYp is not c1fYm) - self.assertTrue(c0fXm is not c1fXm) + self.assertTrue(q('Mc0fXp') is q('Mc1fXm')) + self.assertTrue(q('Mc0fXpe0') is q('Mc1fXme0')) + self.assertTrue(q('Mc0fXpe1') is q('Mc1fXme1')) + self.assertTrue(q('Mc0fXpe2') is q('Mc1fXme2')) + self.assertTrue(q('Mc0fXpe3') is q('Mc1fXme3')) + self.assertTrue(q('Mc0fYp') is not q('c1fYm')) + self.assertTrue(q('Mc0fXm') is not q('c1fXm')) # Test connectivity of shared edges - self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e0']) - self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e1']) - self.assertTrue(c0fZp.edges['e3'] is c1fZp.edges['e2']) - self.assertTrue(c0fZp.edges['e3'] is not c1fZp.edges['e3']) + self.assertTrue(q('Mc0fZpe3') is not q('c1fZpe0')) + self.assertTrue(q('Mc0fZpe3') is not q('c1fZpe1')) + self.assertTrue(q('Mc0fZpe3') is q('Mc1fZpe2')) + self.assertTrue(q('Mc0fZpe3') is not q('c1fZpe3')) - self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e0']) - self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e1']) - self.assertTrue(c0fZm.edges['e3'] is c1fZm.edges['e2']) - self.assertTrue(c0fZm.edges['e3'] is not c1fZm.edges['e3']) + self.assertTrue(q('Mc0fZme3') is not q('c1fZme0')) + self.assertTrue(q('Mc0fZme3') is not q('c1fZme1')) + self.assertTrue(q('Mc0fZme3') is q('Mc1fZme2')) + self.assertTrue(q('Mc0fZme3') is not q('c1fZme3')) - self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e0']) - self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e1']) - self.assertTrue(c0fYp.edges['e3'] is c1fYp.edges['e2']) - self.assertTrue(c0fYp.edges['e3'] is not c1fYp.edges['e3']) + self.assertTrue(q('Mc0fYpe3') is not q('c1fYpe0')) + self.assertTrue(q('Mc0fYpe3') is not q('c1fYpe1')) + self.assertTrue(q('Mc0fYpe3') is q('Mc1fYpe2')) + self.assertTrue(q('Mc0fYpe3') is not q('c1fYpe3')) - self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e0']) - self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e1']) - self.assertTrue(c0fYm.edges['e3'] is c1fYm.edges['e2']) - self.assertTrue(c0fYm.edges['e3'] is not c1fYm.edges['e3']) + self.assertTrue(q('Mc0fYme3') is not q('c1fYme0')) + self.assertTrue(q('Mc0fYme3') is not q('c1fYme1')) + self.assertTrue(q('Mc0fYme3') is q('Mc1fYme2')) + self.assertTrue(q('Mc0fYme3') is not q('c1fYme3')) - self.assertTrue(c0fZm.edges['e3'] is c1fXm.edges['e0']) - self.assertTrue(c0fZp.edges['e3'] is c1fXm.edges['e1']) - self.assertTrue(c0fYm.edges['e3'] is c1fXm.edges['e2']) - self.assertTrue(c0fYp.edges['e3'] is c1fXm.edges['e3']) + self.assertTrue(q('Mc0fZme3') is q('Mc1fXme0')) + self.assertTrue(q('Mc0fZpe3') is q('Mc1fXme1')) + self.assertTrue(q('Mc0fYme3') is q('Mc1fXme2')) + self.assertTrue(q('Mc0fYpe3') is q('Mc1fXme3')) - self.assertTrue(c0fZm.edges['e3'] is c0fXp.edges['e0']) - self.assertTrue(c0fZp.edges['e3'] is c0fXp.edges['e1']) - self.assertTrue(c0fYm.edges['e3'] is c0fXp.edges['e2']) - self.assertTrue(c0fYp.edges['e3'] is c0fXp.edges['e3']) + self.assertTrue(q('Mc0fZme3') is q('Mc0fXpe0')) + self.assertTrue(q('Mc0fZpe3') is q('Mc0fXpe1')) + self.assertTrue(q('Mc0fYme3') is q('Mc0fXpe2')) + self.assertTrue(q('Mc0fYpe3') is q('Mc0fXpe3')) - self.assertTrue(c1fZm.edges['e2'] is c1fXm.edges['e0']) - self.assertTrue(c1fZp.edges['e2'] is c1fXm.edges['e1']) - self.assertTrue(c1fYm.edges['e2'] is c1fXm.edges['e2']) - self.assertTrue(c1fYp.edges['e2'] is c1fXm.edges['e3']) + self.assertTrue(q('Mc1fZme2') is q('Mc1fXme0')) + self.assertTrue(q('Mc1fZpe2') is q('Mc1fXme1')) + self.assertTrue(q('Mc1fYme2') is q('Mc1fXme2')) + self.assertTrue(q('Mc1fYpe2') is q('Mc1fXme3')) - self.assertTrue(c1fZm.edges['e2'] is c0fXp.edges['e0']) - self.assertTrue(c1fZp.edges['e2'] is c0fXp.edges['e1']) - self.assertTrue(c1fYm.edges['e2'] is c0fXp.edges['e2']) - self.assertTrue(c1fYp.edges['e2'] is c0fXp.edges['e3']) + self.assertTrue(q('Mc1fZme2') is q('Mc0fXpe0')) + self.assertTrue(q('Mc1fZpe2') is q('Mc0fXpe1')) + self.assertTrue(q('Mc1fYme2') is q('Mc0fXpe2')) + self.assertTrue(q('Mc1fYpe2') is q('Mc0fXpe3')) def test_nodePointers(self): q = self.q c0 = self.Mr.sortedCells[0] - c0n0 = c0.nodes['n0'] + c0n0 = c0.node0 self.assertTrue(c0n0 is q('c0n0')) self.assertTrue(np.all(q('c0n0').center == np.r_[0,0,0.])) self.assertTrue(q('c0n0').num == 0) @@ -155,9 +141,9 @@ class TestOcTreeObjects(unittest.TestCase): q = self.q c0 = self.Mr.sortedCells[0] - c0fXm = c0.faces['fXm'] - c0eX0 = c0.edges['eX0'] - c0fYme0 = c0.faces['fYm'].edges['e0'] + c0fXm = c0.fXm + c0eX0 = c0.eX0 + c0fYme0 = c0.fYm.edge0 self.assertTrue(c0 is q('c0')) self.assertTrue(c0fXm is q('c0fXm')) self.assertTrue(c0eX0 is q('c0eX0')) @@ -185,7 +171,6 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(np.all(q('c1fXp').center == np.r_[0.5,0.25,0.25])) self.assertTrue(np.all(q('c2fXm').center == np.r_[0.5,0.5,0.5])) self.assertTrue(q('c2fXm').branchdepth == 1) - self.assertTrue(q('c1fXp').parent is q('c2fXm')) self.assertTrue(q('c2fXm').children[0,0] is q('c1fXp')) self.assertTrue(np.all(q('c3fXm').center == np.r_[0,0.75,0.25])) self.assertTrue(np.all(q('c3fXp').center == np.r_[0.25,0.75,0.25])) @@ -262,16 +247,13 @@ class TestOcTreeObjects(unittest.TestCase): self.assertTrue(q('c0fXm') is not q('c1fXm')) self.assertTrue(q('c1fXp') is q('c2fXm').children[0,0]) - self.assertTrue(q('c1fXp').parent is q('c2fXm')) self.assertTrue(q('c1fYp') is q('c4fYm')) self.assertTrue(q('c1fZp') is q('c6fZm')) self.assertTrue(q('c6fXp') is q('c2fXm').children[0,1]) - self.assertTrue(q('c6fXp').parent is q('c2fXm')) self.assertTrue(q('c4fXp') is q('c2fXm').children[1,0]) - self.assertTrue(q('c4fXp').parent is q('c2fXm')) def test_gridCC(self): @@ -375,16 +357,16 @@ class TestQuadTreeObjects(unittest.TestCase): def test_pointersM(self): c0 = self.M.children[0,0] - c0fXm = c0.faces['fXm'] - c0fXp = c0.faces['fXp'] - c0fYm = c0.faces['fYm'] - c0fYp = c0.faces['fYp'] + c0fXm = c0.fXm + c0fXp = c0.fXp + c0fYm = c0.fYm + c0fYp = c0.fYp c1 = self.M.children[1,0] - c1fXm = c1.faces['fXm'] - c1fXp = c1.faces['fXp'] - c1fYm = c1.faces['fYm'] - c1fYp = c1.faces['fYp'] + c1fXm = c1.fXm + c1fXp = c1.fXp + c1fYm = c1.fYm + c1fYp = c1.fYp self.assertTrue(c0fXp is c1fXm) self.assertTrue(c0fYp is not c1fYm) @@ -393,42 +375,40 @@ class TestQuadTreeObjects(unittest.TestCase): self.assertTrue(c0fXm.area == 1) self.assertTrue(c0fYm.area == 0.5) - self.assertTrue(c0.nodes['n1'] is c1.nodes['n0']) - self.assertTrue(c0.nodes['n3'] is c1.nodes['n2']) + self.assertTrue(c0.node1 is c1.node0) + self.assertTrue(c0.node3 is c1.node2) self.assertTrue(self.M.nN == 6) def test_pointersMr(self): c0 = self.Mr.sortedCells[0] - c0fXm = c0.faces['fXm'] - c0fXp = c0.faces['fXp'] - c0fYm = c0.faces['fYm'] - c0fYp = c0.faces['fYp'] + c0fXm = c0.fXm + c0fXp = c0.fXp + c0fYm = c0.fYm + c0fYp = c0.fYp c1 = self.Mr.sortedCells[1] - c1fXm = c1.faces['fXm'] - c1fXp = c1.faces['fXp'] - c1fYm = c1.faces['fYm'] - c1fYp = c1.faces['fYp'] + c1fXm = c1.fXm + c1fXp = c1.fXp + c1fYm = c1.fYm + c1fYp = c1.fYp c2 = self.Mr.sortedCells[2] - c2fXm = c2.faces['fXm'] - c2fXp = c2.faces['fXp'] - c2fYm = c2.faces['fYm'] - c2fYp = c2.faces['fYp'] + c2fXm = c2.fXm + c2fXp = c2.fXp + c2fYm = c2.fYm + c2fYp = c2.fYp c4 = self.Mr.sortedCells[4] - c4fXm = c4.faces['fXm'] - c4fXp = c4.faces['fXp'] - c4fYm = c4.faces['fYm'] - c4fYp = c4.faces['fYp'] + c4fXm = c4.fXm + c4fXp = c4.fXp + c4fYm = c4.fYm + c4fYp = c4.fYp self.assertTrue(c0fXp is c1fXm) - self.assertTrue(c1fXp.parent is c2fXm) self.assertTrue(c1fXp.node0 is c2fXm.node0) self.assertTrue(c1fXp.node0 is c2fXm.node0) self.assertTrue(c4fYm is c1fYp) - self.assertTrue(c4fXp.parent is c2fXm) self.assertTrue(c4fXp.node1 is c2fXm.node1) self.assertTrue(c4fXp.node0 is c1fYp.node1) self.assertTrue(c0fXp.node1 is c4fYm.node0) From 703737131103b15b58c847896aea49f8544130e7 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 12 Feb 2014 08:55:13 -0800 Subject: [PATCH 42/42] pointer to x0 --- SimPEG/Mesh/TreeMesh.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 15780b53..3d2c2794 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -125,7 +125,7 @@ class TreeEdge(object): class TreeFace(object): """docstring for TreeFace""" - __slots__ = ['mesh', 'children', 'depth', 'x0', 'num', 'faceType', 'sz', 'node0', 'node1', 'node2', 'node3', 'edge0', 'edge1', 'edge2', 'edge3', '_tangent0', '_tangent1'] + __slots__ = ['mesh', 'children', 'depth', 'num', 'faceType', 'sz', 'node0', 'node1', 'node2', 'node3', 'edge0', 'edge1', 'edge2', 'edge3', '_tangent0', '_tangent1'] def __init__(self, mesh, x0=[0,0], faceType=None, sz=[1,], depth=0, node0=None, node1=None, @@ -134,7 +134,6 @@ class TreeFace(object): self.mesh = mesh self.depth = depth - self.x0 = x0 self.faceType = faceType self.sz = sz @@ -144,8 +143,8 @@ class TreeFace(object): elif faceType is 'z': mesh.facesZ.add(self) if self.dim == 2: # Add the nodes: - self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=self.x0) - self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=self.x0 + self.tangent0*self.sz[0]) + self.node0 = node0 if isinstance(node0,TreeNode) else TreeNode(mesh, x0=x0) + self.node1 = node1 if isinstance(node1,TreeNode) else TreeNode(mesh, x0=x0 + self.tangent0*self.sz[0]) if self.dim == 3: #TODO: Change this to edges @@ -167,16 +166,16 @@ class TreeFace(object): eType = ['x', 'y'] if self.faceType == 'z' else ['x', 'z'] if self.faceType == 'y' else ['y', 'z'] - e0 = edge0 if isinstance(edge0,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n0, node1=n1) + e0 = edge0 if isinstance(edge0,TreeEdge) else TreeEdge(mesh, x0=x0, edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n0, node1=n1) n0, n1 = e0.node0, e0.node1 - e1 = edge1 if isinstance(edge1,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent1*self.sz[1], edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n2, node1=n3) + e1 = edge1 if isinstance(edge1,TreeEdge) else TreeEdge(mesh, x0=x0 + self.tangent1*self.sz[1], edgeType=eType[0], sz=np.r_[sz[0]], depth=depth, node0=n2, node1=n3) n2, n3 = e1.node0, e1.node1 - e2 = edge2 if isinstance(edge2,TreeEdge) else TreeEdge(mesh, x0=self.x0, edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n0, node1=n2) + e2 = edge2 if isinstance(edge2,TreeEdge) else TreeEdge(mesh, x0=x0, edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n0, node1=n2) n0, n2 = e2.node0, e2.node1 - e3 = edge3 if isinstance(edge3,TreeEdge) else TreeEdge(mesh, x0=self.x0 + self.tangent0*self.sz[0], edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n1, node1=n3) + e3 = edge3 if isinstance(edge3,TreeEdge) else TreeEdge(mesh, x0=x0 + self.tangent0*self.sz[0], edgeType=eType[1], sz=np.r_[sz[1]], depth=depth, node0=n1, node1=n3) n1, n3 = e3.node0, e3.node1 # self.nodes = N @@ -187,6 +186,9 @@ class TreeFace(object): @property def dim(self): return self.mesh.dim + @property + def x0(self): return self.node0.x0 + @property def isleaf(self): return getattr(self, 'children', None) is None