From f0f59c107e6648b123d4049feacd0944bd35d3a3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 18 Dec 2013 18:36:49 -0800 Subject: [PATCH 01/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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/66] 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 78e49c283eec0d72ce7f84f47da73982f636cb86 Mon Sep 17 00:00:00 2001 From: Dave Marchant Date: Wed, 5 Feb 2014 12:29:53 -0800 Subject: [PATCH 09/66] Moved em sources to simpegEM. --- SimPEG/Utils/Geophysics/__init__.py | 1 - SimPEG/Utils/Geophysics/emSources/__init__.py | 1 - .../Utils/Geophysics/emSources/emSources.py | 40 ------------------- SimPEG/Utils/__init__.py | 1 - 4 files changed, 43 deletions(-) delete mode 100644 SimPEG/Utils/Geophysics/__init__.py delete mode 100644 SimPEG/Utils/Geophysics/emSources/__init__.py delete mode 100644 SimPEG/Utils/Geophysics/emSources/emSources.py diff --git a/SimPEG/Utils/Geophysics/__init__.py b/SimPEG/Utils/Geophysics/__init__.py deleted file mode 100644 index bcf01943..00000000 --- a/SimPEG/Utils/Geophysics/__init__.py +++ /dev/null @@ -1 +0,0 @@ -import emSources \ No newline at end of file diff --git a/SimPEG/Utils/Geophysics/emSources/__init__.py b/SimPEG/Utils/Geophysics/emSources/__init__.py deleted file mode 100644 index c05fda69..00000000 --- a/SimPEG/Utils/Geophysics/emSources/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from emSources import MagneticDipoleVectorPotential \ No newline at end of file diff --git a/SimPEG/Utils/Geophysics/emSources/emSources.py b/SimPEG/Utils/Geophysics/emSources/emSources.py deleted file mode 100644 index db492a94..00000000 --- a/SimPEG/Utils/Geophysics/emSources/emSources.py +++ /dev/null @@ -1,40 +0,0 @@ -import numpy as np -from scipy.constants import mu_0, pi - -def MagneticDipoleVectorPotential(txLoc, obsLoc, component, dipoleMoment=(0., 0., 1.)): - """ - Calculate the vector potential of a set of magnetic dipoles - at given locations 'ref. ' - - :param numpy.ndarray txLoc: Location of the transmitter(s) (x, y, z) - :param numpy.ndarray obsLoc: Where the potentials will be calculated (x, y, z) - :param str component: The component to calculate - 'x', 'y', or 'z' - :param numpy.ndarray dipoleMoment: The vector dipole moment - :rtype: numpy.ndarray - :return: The vector potential each dipole at each observation location - """ - - if component=='x': - dimInd = 0 - elif component=='y': - dimInd = 1 - elif component=='z': - dimInd = 2 - else: - raise ValueError('Invalid component') - - txLoc = np.atleast_2d(txLoc) - obsLoc = np.atleast_2d(obsLoc) - dipoleMoment = np.atleast_2d(dipoleMoment) - - nEdges = obsLoc.shape[0] - nTx = txLoc.shape[0] - - m = np.array(dipoleMoment).repeat(nEdges, axis=0) - A = np.empty((nEdges, nTx)) - for i in range(nTx): - dR = obsLoc - txLoc[i, np.newaxis].repeat(nEdges, axis=0) - mCr = np.cross(m, dR) - r = np.sqrt((dR**2).sum(axis=1)) - A[:, i] = -(mu_0/(4*pi)) * mCr[:,dimInd]/(r**3) - return A \ No newline at end of file diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 1daa2e29..269cfdc5 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -5,7 +5,6 @@ from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagona from interputils import interpmat from ipythonutils import easyAnimate as animate import Save -import Geophysics import ModelBuilder import types From f97eced6393022e63f9754e0f9f92fc9257d03bd Mon Sep 17 00:00:00 2001 From: Dave Marchant Date: Wed, 5 Feb 2014 15:28:02 -0800 Subject: [PATCH 10/66] Added CylModel class. --- SimPEG/Model.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 33cfeef8..3ef96036 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -127,3 +127,17 @@ class LogModel(BaseModel): \\frac{\partial \exp{m}}{\partial m} = \\text{sdiag}(\exp{m}) """ return Utils.sdiag(np.exp(Utils.mkvc(m))) + +class CylModel(BaseModel): + """SimPEG LogModel""" + + def __init__(self, mesh, **kwargs): + BaseModel.__init__(self, mesh, **kwargs) + + def transform(self, m): + """ + :param numpy.array m: model + :rtype: numpy.array + :return: transformed model + """ + return m.repeat(self.mesh.nCx) From c128be8af3477629bb992241c77f38508d9ca320 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 5 Feb 2014 20:27:25 -0800 Subject: [PATCH 11/66] Clean up BaseMesh --- SimPEG/Mesh/BaseMesh.py | 308 ++++++++++++++++------------------------ 1 file changed, 120 insertions(+), 188 deletions(-) diff --git a/SimPEG/Mesh/BaseMesh.py b/SimPEG/Mesh/BaseMesh.py index 672b5c02..2dd82808 100644 --- a/SimPEG/Mesh/BaseMesh.py +++ b/SimPEG/Mesh/BaseMesh.py @@ -27,18 +27,16 @@ class BaseMesh(object): # Ensure x0 & n are 1D vectors self._n = np.array(n, dtype=int).ravel() self._x0 = np.array(x0).ravel() - self._dim = len(n) - def x0(): - doc = """ + @property + def x0(self): + """ Origin of the mesh :rtype: numpy.array (dim, ) :return: x0 """ - fget = lambda self: self._x0 - return locals() - x0 = property(**x0()) + return self._x0 def r(self, x, xType='CC', outType='CC', format='V'): """ @@ -147,61 +145,57 @@ class BaseMesh(object): else: return switchKernal(x) - - def dim(): - doc = """ + @property + def dim(self): + """ The dimension of the mesh (1, 2, or 3). :rtype: int :return: dim """ - fget = lambda self: self._dim - return locals() - dim = property(**dim()) + return len(self._n) - def nCx(): - doc = """ + @property + def nCx(self): + """ Number of cells in the x direction :rtype: int :return: nCx """ - fget = lambda self: self._n[0] - return locals() - nCx = property(**nCx()) + return self._n[0] - def nCy(): - doc = """ + @property + def nCy(self): + """ Number of cells in the y direction :rtype: int :return: nCy or None if dim < 2 """ + return None if self.dim < 2 else self._n[1] - def fget(self): - if self.dim > 1: - return self._n[1] - else: - return None - return locals() - nCy = property(**nCy()) - - def nCz(): - doc = """Number of cells in the z direction + @property + def nCz(self): + """Number of cells in the z direction :rtype: int :return: nCz or None if dim < 3 """ + return None if self.dim < 3 else self._n[2] - def fget(self): - if self.dim > 2: - return self._n[2] - else: - return None - return locals() - nCz = property(**nCz()) + @property + def nCv(self): + """ + Total number of cells in each direction - def nC(): + :rtype: numpy.array (dim, ) + :return: [nCx, nCy, nCz] + """ + return np.array([x for x in [self.nCx, self.nCy, self.nCz] if not x is None]) + + @property + def nC(self): doc = """ Total number of cells in the model. @@ -214,65 +208,50 @@ class BaseMesh(object): from SimPEG import Mesh, np Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(centers=True,showIt=True) """ - fget = lambda self: np.prod(self._n) - return locals() - nC = property(**nC()) + return self.nCv.prod() - def nCv(): - doc = """ - Total number of cells in each direction - - :rtype: numpy.array (dim, ) - :return: [nCx, nCy, nCz] + @property + def nNx(self): """ - fget = lambda self: np.array([x for x in [self.nCx, self.nCy, self.nCz] if not x is None]) - return locals() - nCv = property(**nCv()) - - def nNx(): - doc = """ Number of nodes in the x-direction :rtype: int :return: nNx """ - fget = lambda self: self.nCx + 1 - return locals() - nNx = property(**nNx()) + return self.nCx + 1 - def nNy(): - doc = """ + @property + def nNy(self): + """ Number of noes in the y-direction :rtype: int :return: nNy or None if dim < 2 """ + return None if self.dim < 2 else self.nCy + 1 - def fget(self): - if self.dim > 1: - return self._n[1] + 1 - else: - return None - return locals() - nNy = property(**nNy()) - - def nNz(): - doc = """ + @property + def nNz(self): + """ Number of nodes in the z-direction :rtype: int :return: nNz or None if dim < 3 """ + return None if self.dim < 3 else self.nCz + 1 - def fget(self): - if self.dim > 2: - return self._n[2] + 1 - else: - return None - return locals() - nNz = property(**nNz()) + @property + def nNv(self): + """ + Total number of nodes in each direction - def nN(): + :rtype: numpy.array (dim, ) + :return: [nNx, nNy, nNz] + """ + return np.array([x for x in [self.nNx, self.nNy, self.nNz] if not x is None]) + + @property + def nN(self): doc = """ Total number of nodes @@ -285,66 +264,41 @@ class BaseMesh(object): from SimPEG import Mesh, np Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(nodes=True,showIt=True) """ - fget = lambda self: np.prod(self.nCv + 1) - return locals() - nN = property(**nN()) + return self.nNv.prod() - def nNv(): - doc = """ - Total number of nodes in each direction - - :rtype: numpy.array (dim, ) - :return: [nNx, nNy, nNz] + @property + def nEx(self): """ - fget = lambda self: np.array([x for x in [self.nNx, self.nNy, self.nNz] if not x is None]) - return locals() - nNv = property(**nNv()) - - def nEx(): - doc = """ Number of x-edges in each direction :rtype: numpy.array (dim, ) :return: nEx """ - fget = lambda self: np.array([x for x in [self.nCx, self.nNy, self.nNz] if not x is None]) - return locals() - nEx = property(**nEx()) + return np.array([x for x in [self.nCx, self.nNy, self.nNz] if not x is None]) - def nEy(): - doc = """ + @property + def nEy(self): + """ Number of y-edges in each direction :rtype: numpy.array (dim, ) :return: nEy or None if dim < 2 """ + return None if self.dim < 2 else np.array([x for x in [self.nNx, self.nCy, self.nNz] if not x is None]) - def fget(self): - if self.dim > 1: - return np.array([x for x in [self.nNx, self.nCy, self.nNz] if not x is None]) - else: - return None - return locals() - nEy = property(**nEy()) - - def nEz(): - doc = """ + @property + def nEz(self): + """ Number of z-edges in each direction :rtype: numpy.array (dim, ) :return: nEz or None if dim < 3 """ + return None if self.dim < 3 else np.array([x for x in [self.nNx, self.nNy, self.nCz] if not x is None]) - def fget(self): - if self.dim > 2: - return np.array([x for x in [self.nNx, self.nNy, self.nCz] if not x is None]) - else: - return None - return locals() - nEz = property(**nEz()) - - def nEv(): - doc = """ + @property + def nEv(self): + """ Total number of edges in each direction :rtype: numpy.array (dim, ) @@ -356,67 +310,53 @@ class BaseMesh(object): from SimPEG import Mesh, np Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(edges=True,showIt=True) """ - fget = lambda self: np.array([np.prod(x) for x in [self.nEx, self.nEy, self.nEz] if not x is None]) - return locals() - nEv = property(**nEv()) + return np.array([np.prod(x) for x in [self.nEx, self.nEy, self.nEz] if not x is None]) - def nE(): - doc = """ + + @property + def nE(self): + """ Total number of edges. :rtype: int :return: sum([prod(nEx), prod(nEy), prod(nEz)]) """ - fget = lambda self: np.sum(self.nEv) - return locals() - nE = property(**nE()) + return self.nEv.sum() - def nFx(): - doc = """ + @property + def nFx(self): + """ Number of x-faces in each direction :rtype: numpy.array (dim, ) :return: nFx """ - fget = lambda self: np.array([x for x in [self.nNx, self.nCy, self.nCz] if not x is None]) - return locals() - nFx = property(**nFx()) + return np.array([x for x in [self.nNx, self.nCy, self.nCz] if not x is None]) - def nFy(): - doc = """ + @property + def nFy(self): + """ Number of y-faces in each direction :rtype: numpy.array (dim, ) :return: nFy or None if dim < 2 """ + return None if self.dim < 2 else np.array([x for x in [self.nCx, self.nNy, self.nCz] if not x is None]) - def fget(self): - if self.dim > 1: - return np.array([x for x in [self.nCx, self.nNy, self.nCz] if not x is None]) - else: - return None - return locals() - nFy = property(**nFy()) - - def nFz(): - doc = """ + @property + def nFz(self): + """ Number of z-faces in each direction :rtype: numpy.array (dim, ) :return: nFz or None if dim < 3 """ + return None if self.dim < 3 else np.array([x for x in [self.nCx, self.nCy, self.nNz] if not x is None]) - def fget(self): - if self.dim > 2: - return np.array([x for x in [self.nCx, self.nCy, self.nNz] if not x is None]) - else: - return None - return locals() - nFz = property(**nFz()) - - def nFv(): - doc = """ + @property + def nFv(self): + """ Total number of faces in each direction :rtype: numpy.array (dim, ) @@ -428,64 +368,56 @@ class BaseMesh(object): from SimPEG import Mesh, np Mesh.TensorMesh([np.ones(n) for n in [2,3]]).plotGrid(faces=True,showIt=True) """ - fget = lambda self: np.array([np.prod(x) for x in [self.nFx, self.nFy, self.nFz] if not x is None]) - return locals() - nFv = property(**nFv()) + return np.array([np.prod(x) for x in [self.nFx, self.nFy, self.nFz] if not x is None]) - def nF(): - doc = """ + @property + def nF(self): + """ Total number of faces. :rtype: int - :return: sum([prod(nFx), prod(nFy), prod(nFz)]) + :return: sum([nFx, nFy, nFz]) """ - fget = lambda self: np.sum(self.nFv) - return locals() - nF = property(**nF()) + return self.nFv.sum() - def normals(): - doc = """ + @property + def normals(self): + """ Face Normals :rtype: numpy.array (sum(nF), dim) :return: normals """ + if self.dim == 2: + nX = np.c_[np.ones(self.nFv[0]), np.zeros(self.nFv[0])] + nY = np.c_[np.zeros(self.nFv[1]), np.ones(self.nFv[1])] + return np.r_[nX, nY] + elif self.dim == 3: + nX = np.c_[np.ones(self.nFv[0]), np.zeros(self.nFv[0]), np.zeros(self.nFv[0])] + nY = np.c_[np.zeros(self.nFv[1]), np.ones(self.nFv[1]), np.zeros(self.nFv[1])] + nZ = np.c_[np.zeros(self.nFv[2]), np.zeros(self.nFv[2]), np.ones(self.nFv[2])] + return np.r_[nX, nY, nZ] - def fget(self): - if self.dim == 2: - nX = np.c_[np.ones(self.nFv[0]), np.zeros(self.nFv[0])] - nY = np.c_[np.zeros(self.nFv[1]), np.ones(self.nFv[1])] - return np.r_[nX, nY] - elif self.dim == 3: - nX = np.c_[np.ones(self.nFv[0]), np.zeros(self.nFv[0]), np.zeros(self.nFv[0])] - nY = np.c_[np.zeros(self.nFv[1]), np.ones(self.nFv[1]), np.zeros(self.nFv[1])] - nZ = np.c_[np.zeros(self.nFv[2]), np.zeros(self.nFv[2]), np.ones(self.nFv[2])] - return np.r_[nX, nY, nZ] - return locals() - normals = property(**normals()) - - def tangents(): - doc = """ + @property + def tangents(self): + """ Edge Tangents :rtype: numpy.array (sum(nE), dim) :return: normals """ + if self.dim == 2: + tX = np.c_[np.ones(self.nEv[0]), np.zeros(self.nEv[0])] + tY = np.c_[np.zeros(self.nEv[1]), np.ones(self.nEv[1])] + return np.r_[tX, tY] + elif self.dim == 3: + tX = np.c_[np.ones(self.nEv[0]), np.zeros(self.nEv[0]), np.zeros(self.nEv[0])] + tY = np.c_[np.zeros(self.nEv[1]), np.ones(self.nEv[1]), np.zeros(self.nEv[1])] + tZ = np.c_[np.zeros(self.nEv[2]), np.zeros(self.nEv[2]), np.ones(self.nEv[2])] + return np.r_[tX, tY, tZ] - def fget(self): - if self.dim == 2: - tX = np.c_[np.ones(self.nEv[0]), np.zeros(self.nEv[0])] - tY = np.c_[np.zeros(self.nEv[1]), np.ones(self.nEv[1])] - return np.r_[tX, tY] - elif self.dim == 3: - tX = np.c_[np.ones(self.nEv[0]), np.zeros(self.nEv[0]), np.zeros(self.nEv[0])] - tY = np.c_[np.zeros(self.nEv[1]), np.ones(self.nEv[1]), np.zeros(self.nEv[1])] - tZ = np.c_[np.zeros(self.nEv[2]), np.zeros(self.nEv[2]), np.ones(self.nEv[2])] - return np.r_[tX, tY, tZ] - return locals() - tangents = property(**tangents()) def projectFaceVector(self, fV): """ From aa1faa9505e46ac4c08a663148135dafde039eee Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 5 Feb 2014 21:29:35 -0800 Subject: [PATCH 12/66] Changed CylModel --> Vertical1DModel (not tested on Cyl1DMesh) --- SimPEG/Model.py | 47 +++++++++++++++++++++++++++++++++----- SimPEG/Tests/test_model.py | 13 +++++------ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 3ef96036..2438490f 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -1,5 +1,5 @@ import Utils, Parameters, numpy as np, scipy.sparse as sp - +from Tests import checkDerivative class BaseModel(object): """ @@ -55,9 +55,13 @@ class BaseModel(object): """Number of parameters in the model.""" return self.mesh.nC - def example(self, modelType=None): - return np.random.rand(self.mesh.nC) + def example(self): + return np.random.rand(self.nP) + def test(self): + print 'Testing the %s Class!' % self.__class__.__name__ + m = self.example() + return checkDerivative(lambda m : [self.transform(m), self.transformDeriv(m)], m, plotIt=False) class LogModel(BaseModel): @@ -128,16 +132,47 @@ class LogModel(BaseModel): """ return Utils.sdiag(np.exp(Utils.mkvc(m))) -class CylModel(BaseModel): - """SimPEG LogModel""" +class Vertical1DModel(BaseModel): + """Vertical1DModel + + Given a 1D vector through the last dimension + of the mesh, this will extend to the full + model space. + """ def __init__(self, mesh, **kwargs): BaseModel.__init__(self, mesh, **kwargs) + @property + def nP(self): + """The number of cells in the + last dimension of the mesh.""" + return self.mesh.nCv[self.mesh.dim-1] + def transform(self, m): """ :param numpy.array m: model :rtype: numpy.array :return: transformed model """ - return m.repeat(self.mesh.nCx) + repNum = self.mesh.nCv[:self.mesh.dim-2].prod() + return Utils.mkvc(m).repeat(repNum) + + def transformDeriv(self, m): + """ + :param numpy.array m: model + :rtype: scipy.csr_matrix + :return: derivative of transformed model + """ + repNum = self.mesh.nCv[:self.mesh.dim-2].prod() + repVec = sp.csr_matrix( + (np.ones(repNum), + (range(repNum), np.zeros(repNum)) + ), shape=(repNum, 1)) + return sp.kron(repVec, sp.identity(self.nP)) + +if __name__ == '__main__': + from SimPEG import * + mesh = Mesh.TensorMesh([10,8]) + model = BaseModel(mesh) + model.test() diff --git a/SimPEG/Tests/test_model.py b/SimPEG/Tests/test_model.py index 0c3b2c54..df957ecc 100644 --- a/SimPEG/Tests/test_model.py +++ b/SimPEG/Tests/test_model.py @@ -11,17 +11,16 @@ class ModelTests(unittest.TestCase): a = np.array([1, 1, 1]) b = np.array([1, 2]) - c = np.array([1, 4]) self.mesh2 = Mesh.TensorMesh([a, b], np.array([3, 5])) def test_modelTransforms(self): - print 'SimPEG.Model.BaseModel: Testing Model Transform' for M in dir(Model): - if 'Model' not in M: continue - model = getattr(Model, M)(self.mesh2) - m = model.example() - passed = checkDerivative(lambda m : [model.transform(m), model.transformDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + try: + model = getattr(Model, M)(self.mesh2) + assert isinstance(model, Model.BaseModel) + except Exception, e: + continue + self.assertTrue(model.test()) if __name__ == '__main__': unittest.main() From 72c93cd48b2eddb132399537c10975bc4752d22a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 5 Feb 2014 21:33:18 -0800 Subject: [PATCH 13/66] Minor updates to Cyl1DMesh --- SimPEG/Mesh/Cyl1DMesh.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SimPEG/Mesh/Cyl1DMesh.py b/SimPEG/Mesh/Cyl1DMesh.py index 2b291c54..cd232cf6 100644 --- a/SimPEG/Mesh/Cyl1DMesh.py +++ b/SimPEG/Mesh/Cyl1DMesh.py @@ -37,6 +37,9 @@ class Cyl1DMesh(object): return locals() h = property(**h()) + @property + def dim(self): return 2 + def z0(): doc = "The z-origin" def fget(self): From e56ca4fcbb4f8a11ae7be0c5aa0e1dd24b09a04b Mon Sep 17 00:00:00 2001 From: Dave Marchant Date: Wed, 5 Feb 2014 21:48:25 -0800 Subject: [PATCH 14/66] Added sdInv to utils. --- SimPEG/Utils/__init__.py | 2 +- SimPEG/Utils/sputils.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 269cfdc5..1331cc8c 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -1,5 +1,5 @@ from matutils import getSubArray, mkvc, ndgrid, ind2sub, sub2ind -from sputils import spzeros, kron3, speye, sdiag, ddx, av, avExtrap +from sputils import spzeros, kron3, speye, sdiag, sdInv, ddx, av, avExtrap from meshutils import exampleLomGird, meshTensors from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagonal, indexCube from interputils import interpmat diff --git a/SimPEG/Utils/sputils.py b/SimPEG/Utils/sputils.py index 06eef80d..f671be43 100644 --- a/SimPEG/Utils/sputils.py +++ b/SimPEG/Utils/sputils.py @@ -7,6 +7,9 @@ def sdiag(h): """Sparse diagonal matrix""" return sp.spdiags(mkvc(h), 0, h.size, h.size, format="csr") +def sdInv(M): + "Inverse of a sparse diagonal matrix" + return sdiag(1/M.diagonal()) def speye(n): """Sparse identity""" From ef6ad1d08348c65a14404f1536e6a602b104fb2a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 5 Feb 2014 22:09:24 -0800 Subject: [PATCH 15/66] Bug fixes to VerticalModel --- SimPEG/Model.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 2438490f..0b1b3c03 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -145,7 +145,9 @@ class Vertical1DModel(BaseModel): @property def nP(self): - """The number of cells in the + """Number of model properties. + + The number of cells in the last dimension of the mesh.""" return self.mesh.nCv[self.mesh.dim-1] @@ -155,7 +157,7 @@ class Vertical1DModel(BaseModel): :rtype: numpy.array :return: transformed model """ - repNum = self.mesh.nCv[:self.mesh.dim-2].prod() + repNum = self.mesh.nCv[:self.mesh.dim-1].prod() return Utils.mkvc(m).repeat(repNum) def transformDeriv(self, m): @@ -164,15 +166,9 @@ class Vertical1DModel(BaseModel): :rtype: scipy.csr_matrix :return: derivative of transformed model """ - repNum = self.mesh.nCv[:self.mesh.dim-2].prod() + repNum = self.mesh.nCv[:self.mesh.dim-1].prod() repVec = sp.csr_matrix( (np.ones(repNum), (range(repNum), np.zeros(repNum)) ), shape=(repNum, 1)) - return sp.kron(repVec, sp.identity(self.nP)) - -if __name__ == '__main__': - from SimPEG import * - mesh = Mesh.TensorMesh([10,8]) - model = BaseModel(mesh) - model.test() + return sp.kron(sp.identity(self.nP), repVec) From 27213be0b45947f7e45763c6ac7aac9777bdc86c Mon Sep 17 00:00:00 2001 From: Dave Marchant Date: Wed, 5 Feb 2014 22:42:05 -0800 Subject: [PATCH 16/66] Fix bug when trying to use scipy backend with factorize=True and a nx1 rhs. --- SimPEG/Solver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Solver.py b/SimPEG/Solver.py index 3e9c2d02..60ca5558 100644 --- a/SimPEG/Solver.py +++ b/SimPEG/Solver.py @@ -156,7 +156,7 @@ class Solver(object): if len(b.shape) == 1 or b.shape[1] == 1: # Just one RHS if factorize: - return self.dsolve(b) + return self.dsolve(b.flatten()) else: return linalg.dsolve.spsolve(self.A, b) From e3f5b6c16e32d6c5e5256c9e79e719926f7874d7 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 5 Feb 2014 22:42:16 -0800 Subject: [PATCH 17/66] ComboModels! e.g.: combo = ComboModel(mesh, [LogModel, Vertical1DModel]) --- SimPEG/Model.py | 41 ++++++++++++++++++++++++++++++++++++-- SimPEG/Tests/test_model.py | 7 +++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 0b1b3c03..44dc3908 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -58,9 +58,10 @@ class BaseModel(object): def example(self): return np.random.rand(self.nP) - def test(self): + def test(self, m=None): print 'Testing the %s Class!' % self.__class__.__name__ - m = self.example() + if m is None: + m = self.example() return checkDerivative(lambda m : [self.transform(m), self.transformDeriv(m)], m, plotIt=False) @@ -172,3 +173,39 @@ class Vertical1DModel(BaseModel): (range(repNum), np.zeros(repNum)) ), shape=(repNum, 1)) return sp.kron(sp.identity(self.nP), repVec) + +class ComboModel(BaseModel): + """Combination of various models.""" + + def __init__(self, mesh, models, **kwargs): + BaseModel.__init__(self, mesh, **kwargs) + self.models = [m(mesh, **kwargs) for m in models] + + @property + def nP(self): + """Number of model properties. + + The number of cells in the + last dimension of the mesh.""" + return self.models[-1].nP + + def transform(self, m): + for model in reversed(self.models): + m = model.transform(m) + return m + + def transformDeriv(self, m): + deriv = 1 + mi = m + for model in reversed(self.models): + deriv = model.transformDeriv(mi) * deriv + mi = model.transform(mi) + return deriv + +if __name__ == '__main__': + from SimPEG import * + mesh = Mesh.TensorMesh([10,8]) + combo = ComboModel(mesh, [LogModel, Vertical1DModel]) + m = combo.example() + print m.shape + print combo.test(np.arange(8)) diff --git a/SimPEG/Tests/test_model.py b/SimPEG/Tests/test_model.py index df957ecc..e6a8844b 100644 --- a/SimPEG/Tests/test_model.py +++ b/SimPEG/Tests/test_model.py @@ -22,5 +22,12 @@ class ModelTests(unittest.TestCase): continue self.assertTrue(model.test()) + def test_comboModels(self): + combos = [(Model.LogModel, Model.Vertical1DModel)] + for combo in combos: + model = Model.ComboModel(self.mesh2, combo) + self.assertTrue(model.test()) + + if __name__ == '__main__': unittest.main() From e72defbb54840981556395437cf1b747339c2f6a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 6 Feb 2014 15:00:06 -0800 Subject: [PATCH 18/66] Averaging updates. --- SimPEG/Mesh/DiffOperators.py | 220 +++++++++++++++++------------------ 1 file changed, 107 insertions(+), 113 deletions(-) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 492d628e..8b431a65 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -462,126 +462,120 @@ class DiffOperators(object): # --------------- Averaging --------------------- - def aveF2CC(): - doc = "Construct the averaging operator on cell faces to cell centers." + @property + def aveF2CC(self): + "Construct the averaging operator on cell faces to cell centers." + if getattr(self, '_aveF2CC', None) is None: + n = self.nCv + if(self.dim == 1): + self._aveF2CC = av(n[0]) + elif(self.dim == 2): + self._aveF2CC = (0.5)*sp.hstack((sp.kron(speye(n[1]), av(n[0])), + sp.kron(av(n[1]), speye(n[0]))), format="csr") + elif(self.dim == 3): + self._aveF2CC = (1./3.)*sp.hstack((kron3(speye(n[2]), speye(n[1]), av(n[0])), + kron3(speye(n[2]), av(n[1]), speye(n[0])), + kron3(av(n[2]), speye(n[1]), speye(n[0]))), format="csr") + return self._aveF2CC - def fget(self): - if(self._aveF2CC is None): - n = self.nCv - if(self.dim == 1): - self._aveF2CC = av(n[0]) - elif(self.dim == 2): - self._aveF2CC = (0.5)*sp.hstack((sp.kron(speye(n[1]), av(n[0])), - sp.kron(av(n[1]), speye(n[0]))), format="csr") - elif(self.dim == 3): - self._aveF2CC = (1./3.)*sp.hstack((kron3(speye(n[2]), speye(n[1]), av(n[0])), - kron3(speye(n[2]), av(n[1]), speye(n[0])), - kron3(av(n[2]), speye(n[1]), speye(n[0]))), format="csr") - return self._aveF2CC - return locals() - _aveF2CC = None - aveF2CC = property(**aveF2CC()) + @property + def aveCC2F(self): + "Construct the averaging operator on cell cell centers to faces." + if getattr(self, '_aveCC2F', None) is None: + n = self.nCv + if(self.dim == 1): + self._aveCC2F = avExtrap(n[0]) + elif(self.dim == 2): + self._aveCC2F = sp.vstack((sp.kron(speye(n[1]), avExtrap(n[0])), + sp.kron(avExtrap(n[1]), speye(n[0]))), format="csr") + elif(self.dim == 3): + self._aveCC2F = sp.vstack((kron3(speye(n[2]), speye(n[1]), avExtrap(n[0])), + kron3(speye(n[2]), avExtrap(n[1]), speye(n[0])), + kron3(avExtrap(n[2]), speye(n[1]), speye(n[0]))), format="csr") + return self._aveCC2F - def aveCC2F(): - doc = "Construct the averaging operator on cell cell centers to faces." + @property + def aveE2CC(self): + "Construct the averaging operator on cell edges to cell centers." + if getattr(self, '_aveE2CC', None) is None: + # The number of cell centers in each direction + n = self.nCv + if(self.dim == 1): + raise Exception('Edge Averaging does not make sense in 1D: Use Identity?') + elif(self.dim == 2): + self._aveE2CC = 0.5*sp.hstack((sp.kron(av(n[1]), speye(n[0])), + sp.kron(speye(n[1]), av(n[0]))), format="csr") + elif(self.dim == 3): + self._aveE2CC = (1./3)*sp.hstack((kron3(av(n[2]), av(n[1]), speye(n[0])), + kron3(av(n[2]), speye(n[1]), av(n[0])), + kron3(speye(n[2]), av(n[1]), av(n[0]))), format="csr") + return self._aveE2CC - def fget(self): - if(self._aveCC2F is None): - n = self.nCv - if(self.dim == 1): - self._aveCC2F = avExtrap(n[0]) - elif(self.dim == 2): - self._aveCC2F = sp.vstack((sp.kron(speye(n[1]), avExtrap(n[0])), - sp.kron(avExtrap(n[1]), speye(n[0]))), format="csr") - elif(self.dim == 3): - self._aveCC2F = sp.vstack((kron3(speye(n[2]), speye(n[1]), avExtrap(n[0])), - kron3(speye(n[2]), avExtrap(n[1]), speye(n[0])), - kron3(avExtrap(n[2]), speye(n[1]), speye(n[0]))), format="csr") - return self._aveCC2F - return locals() - _aveCC2F = None - aveCC2F = property(**aveCC2F()) + @property + def aveE2CCV(self): + "Construct the averaging operator on cell edges to cell centers." + if getattr(self, '_aveE2CCV', None) is None: + # The number of cell centers in each direction + n = self.nCv + if(self.dim == 1): + raise Exception('Edge Averaging does not make sense in 1D: Use Identity?') + elif(self.dim == 2): + self._aveE2CCV = sp.block_diag((sp.kron(av(n[1]), speye(n[0])), + sp.kron(speye(n[1]), av(n[0]))), format="csr") + elif(self.dim == 3): + self._aveE2CCV = sp.block_diag((kron3(av(n[2]), av(n[1]), speye(n[0])), + kron3(av(n[2]), speye(n[1]), av(n[0])), + kron3(speye(n[2]), av(n[1]), av(n[0]))), format="csr") + return self._aveE2CCV - def aveE2CC(): - doc = "Construct the averaging operator on cell edges to cell centers." + @property + def aveN2CC(self): + "Construct the averaging operator on cell nodes to cell centers." + if getattr(self, '_aveN2CC', None) is None: + # The number of cell centers in each direction + n = self.nCv + if(self.dim == 1): + self._aveN2CC = av(n[0]) + elif(self.dim == 2): + self._aveN2CC = sp.kron(av(n[1]), av(n[0])).tocsr() + elif(self.dim == 3): + self._aveN2CC = kron3(av(n[2]), av(n[1]), av(n[0])).tocsr() + return self._aveN2CC - def fget(self): - if(self._aveE2CC is None): - # The number of cell centers in each direction - n = self.nCv - if(self.dim == 1): - raise Exception('Edge Averaging does not make sense in 1D: Use Identity?') - elif(self.dim == 2): - self._aveE2CC = 0.5*sp.hstack((sp.kron(av(n[1]), speye(n[0])), - sp.kron(speye(n[1]), av(n[0]))), format="csr") - elif(self.dim == 3): - self._aveE2CC = (1./3)*sp.hstack((kron3(av(n[2]), av(n[1]), speye(n[0])), - kron3(av(n[2]), speye(n[1]), av(n[0])), - kron3(speye(n[2]), av(n[1]), av(n[0]))), format="csr") - return self._aveE2CC - return locals() - _aveE2CC = None - aveE2CC = property(**aveE2CC()) + @property + def aveN2E(self): + "Construct the averaging operator on cell nodes to cell edges, keeping each dimension separate." - def aveN2CC(): - doc = "Construct the averaging operator on cell nodes to cell centers." + if getattr(self, '_aveN2E', None) is None: + # The number of cell centers in each direction + n = self.nCv + if(self.dim == 1): + self._aveN2E = av(n[0]) + elif(self.dim == 2): + self._aveN2E = sp.vstack((sp.kron(speye(n[1]+1), av(n[0])), + sp.kron(av(n[1]), speye(n[0]+1))), format="csr") + elif(self.dim == 3): + self._aveN2E = sp.vstack((kron3(speye(n[2]+1), speye(n[1]+1), av(n[0])), + kron3(speye(n[2]+1), av(n[1]), speye(n[0]+1)), + kron3(av(n[2]), speye(n[1]+1), speye(n[0]+1))), format="csr") + return self._aveN2E - def fget(self): - if(self._aveN2CC is None): - # The number of cell centers in each direction - n = self.nCv - if(self.dim == 1): - self._aveN2CC = av(n[0]) - elif(self.dim == 2): - self._aveN2CC = sp.kron(av(n[1]), av(n[0])).tocsr() - elif(self.dim == 3): - self._aveN2CC = kron3(av(n[2]), av(n[1]), av(n[0])).tocsr() - return self._aveN2CC - return locals() - _aveN2CC = None - aveN2CC = property(**aveN2CC()) - - def aveN2E(): - doc = "Construct the averaging operator on cell nodes to cell edges, keeping each dimension separate." - - def fget(self): - if(self._aveN2E is None): - # The number of cell centers in each direction - n = self.nCv - if(self.dim == 1): - self._aveN2E = av(n[0]) - elif(self.dim == 2): - self._aveN2E = sp.vstack((sp.kron(speye(n[1]+1), av(n[0])), - sp.kron(av(n[1]), speye(n[0]+1))), format="csr") - elif(self.dim == 3): - self._aveN2E = sp.vstack((kron3(speye(n[2]+1), speye(n[1]+1), av(n[0])), - kron3(speye(n[2]+1), av(n[1]), speye(n[0]+1)), - kron3(av(n[2]), speye(n[1]+1), speye(n[0]+1))), format="csr") - return self._aveN2E - return locals() - _aveN2E = None - aveN2E = property(**aveN2E()) - - def aveN2F(): - doc = "Construct the averaging operator on cell nodes to cell faces, keeping each dimension separate." - - def fget(self): - if(self._aveN2F is None): - # The number of cell centers in each direction - n = self.nCv - if(self.dim == 1): - self._aveN2F = av(n[0]) - elif(self.dim == 2): - self._aveN2F = sp.vstack((sp.kron(av(n[1]), speye(n[0]+1)), - sp.kron(speye(n[1]+1), av(n[0]))), format="csr") - elif(self.dim == 3): - self._aveN2F = sp.vstack((kron3(av(n[2]), av(n[1]), speye(n[0]+1)), - kron3(av(n[2]), speye(n[1]+1), av(n[0])), - kron3(speye(n[2]+1), av(n[1]), av(n[0]))), format="csr") - return self._aveN2F - return locals() - _aveN2F = None - aveN2F = property(**aveN2F()) + @property + def aveN2F(self): + "Construct the averaging operator on cell nodes to cell faces, keeping each dimension separate." + if getattr(self, '_aveN2F', None) is None: + # The number of cell centers in each direction + n = self.nCv + if(self.dim == 1): + self._aveN2F = av(n[0]) + elif(self.dim == 2): + self._aveN2F = sp.vstack((sp.kron(av(n[1]), speye(n[0]+1)), + sp.kron(speye(n[1]+1), av(n[0]))), format="csr") + elif(self.dim == 3): + self._aveN2F = sp.vstack((kron3(av(n[2]), av(n[1]), speye(n[0]+1)), + kron3(av(n[2]), speye(n[1]+1), av(n[0])), + kron3(speye(n[2]+1), av(n[1]), av(n[0]))), format="csr") + return self._aveN2F # --------------- Methods --------------------- From 8ec21210fb692ca7bcc61276dd6f8fa1c122835a Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 09:27:35 -0800 Subject: [PATCH 19/66] aveF2CCV and aveE2CCV and tested. Faces/Edges to cell-centered vectors. --- SimPEG/Mesh/DiffOperators.py | 17 +++++++++++++++ SimPEG/Tests/test_operators.py | 38 +++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 8b431a65..7a965e0f 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -478,6 +478,23 @@ class DiffOperators(object): kron3(av(n[2]), speye(n[1]), speye(n[0]))), format="csr") return self._aveF2CC + + @property + def aveF2CCV(self): + "Construct the averaging operator on cell faces to cell centers." + if getattr(self, '_aveF2CCV', None) is None: + n = self.nCv + if(self.dim == 1): + self._aveF2CCV = av(n[0]) + elif(self.dim == 2): + self._aveF2CCV = sp.block_diag((sp.kron(speye(n[1]), av(n[0])), + sp.kron(av(n[1]), speye(n[0]))), format="csr") + elif(self.dim == 3): + self._aveF2CCV = sp.block_diag((kron3(speye(n[2]), speye(n[1]), av(n[0])), + kron3(speye(n[2]), av(n[1]), speye(n[0])), + kron3(av(n[2]), speye(n[1]), speye(n[0]))), format="csr") + return self._aveF2CCV + @property def aveCC2F(self): "Construct the averaging operator on cell cell centers to faces." diff --git a/SimPEG/Tests/test_operators.py b/SimPEG/Tests/test_operators.py index d1c38443..67741aa7 100644 --- a/SimPEG/Tests/test_operators.py +++ b/SimPEG/Tests/test_operators.py @@ -338,6 +338,15 @@ class TestAveraging2D(OrderTest): self.getAve = lambda M: M.aveF2CC self.orderTest() + def test_orderF2CCV(self): + self.name = "Averaging 2D: F2CCV" + funX = lambda x, y: (np.cos(x)+np.sin(y)) + funY = lambda x, y: (np.cos(y)*np.sin(x)) + self.getHere = lambda M: np.r_[call2(funX, M.gridFx), call2(funY, M.gridFy)] + self.getThere = lambda M: np.r_[call2(funX, M.gridCC), call2(funY, M.gridCC)] + self.getAve = lambda M: M.aveF2CCV + self.orderTest() + def test_orderCC2F(self): self.name = "Averaging 2D: CC2F" fun = lambda x, y: (np.cos(x)+np.sin(y)) @@ -348,7 +357,6 @@ class TestAveraging2D(OrderTest): self.orderTest() self.expectedOrders = 2 - def test_orderE2CC(self): self.name = "Averaging 2D: E2CC" fun = lambda x, y: (np.cos(x)+np.sin(y)) @@ -357,6 +365,15 @@ class TestAveraging2D(OrderTest): self.getAve = lambda M: M.aveE2CC self.orderTest() + def test_orderE2CCV(self): + self.name = "Averaging 2D: E2CCV" + funX = lambda x, y: (np.cos(x)+np.sin(y)) + funY = lambda x, y: (np.cos(y)*np.sin(x)) + self.getHere = lambda M: np.r_[call2(funX, M.gridEx), call2(funY, M.gridEy)] + self.getThere = lambda M: np.r_[call2(funX, M.gridCC), call2(funY, M.gridCC)] + self.getAve = lambda M: M.aveE2CCV + self.orderTest() + class TestAveraging3D(OrderTest): name = "Averaging 3D" @@ -400,6 +417,15 @@ class TestAveraging3D(OrderTest): self.getAve = lambda M: M.aveF2CC self.orderTest() + def test_orderF2CCV(self): + self.name = "Averaging 3D: F2CCV" + funX = lambda x, y, z: (np.cos(x)+np.sin(y)+np.exp(z)) + funY = lambda x, y, z: (np.cos(x)+np.sin(y)*np.exp(z)) + funZ = lambda x, y, z: (np.cos(x)*np.sin(y)+np.exp(z)) + self.getHere = lambda M: np.r_[call3(funX, M.gridFx), call3(funY, M.gridFy), call3(funZ, M.gridFz)] + self.getThere = lambda M: np.r_[call3(funX, M.gridCC), call3(funY, M.gridCC), call3(funZ, M.gridCC)] + self.getAve = lambda M: M.aveF2CCV + self.orderTest() def test_orderE2CC(self): self.name = "Averaging 3D: E2CC" @@ -409,6 +435,16 @@ class TestAveraging3D(OrderTest): self.getAve = lambda M: M.aveE2CC self.orderTest() + def test_orderE2CCV(self): + self.name = "Averaging 3D: E2CCV" + funX = lambda x, y, z: (np.cos(x)+np.sin(y)+np.exp(z)) + funY = lambda x, y, z: (np.cos(x)+np.sin(y)*np.exp(z)) + funZ = lambda x, y, z: (np.cos(x)*np.sin(y)+np.exp(z)) + self.getHere = lambda M: np.r_[call3(funX, M.gridEx), call3(funY, M.gridEy), call3(funZ, M.gridEz)] + self.getThere = lambda M: np.r_[call3(funX, M.gridCC), call3(funY, M.gridCC), call3(funZ, M.gridCC)] + self.getAve = lambda M: M.aveE2CCV + self.orderTest() + def test_orderCC2F(self): self.name = "Averaging 3D: CC2F" fun = lambda x, y, z: (np.cos(x)+np.sin(y)+np.exp(z)) From f40b32f2abe9980c26a8bd84f64b70c4fa48cbb0 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 09:42:18 -0800 Subject: [PATCH 20/66] Upgrade Scipy on travis. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1918d175..bd99b28e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,9 @@ python: virtualenv: system_site_packages: true before_install: - - sudo apt-get install -qq python-numpy python-scipy python-matplotlib + - sudo apt-get install -qq python-numpy python-scipy python-matplotlib python-pip + - sudo pip install scipy --upgrade + - sudo pip install numpy --upgrade - python SimPEG/setup.py # command to install dependencies install: "pip install -r requirements.txt --use-mirrors" From e29e87c7c44ca621335d1f483366638d5b62795f Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 09:49:37 -0800 Subject: [PATCH 21/66] install blas on travis VM? --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bd99b28e..f0133a9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,8 @@ python: virtualenv: system_site_packages: true before_install: - - sudo apt-get install -qq python-numpy python-scipy python-matplotlib python-pip + - sudo apt-get install -qq gcc gfortran python-numpy python-scipy python-matplotlib python-pip + - sudo apt-get -qq install libblas-dev liblapack-dev - sudo pip install scipy --upgrade - sudo pip install numpy --upgrade - python SimPEG/setup.py From cc2ab82f78994b9d829fe75c0b1ab23cedf36e81 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 14:02:56 -0800 Subject: [PATCH 22/66] Make simpeg setup work. --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f0133a9a..4fd51fd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,12 @@ python: virtualenv: system_site_packages: true before_install: - - sudo apt-get install -qq gcc gfortran python-numpy python-scipy python-matplotlib python-pip - - sudo apt-get -qq install libblas-dev liblapack-dev + - sudo apt-get install -qq gcc gfortran libblas-dev liblapack-dev python-numpy python-scipy python-matplotlib python-pip - sudo pip install scipy --upgrade - sudo pip install numpy --upgrade - - python SimPEG/setup.py + - cd SimPEG + - python setup.py + - cd ../ # command to install dependencies install: "pip install -r requirements.txt --use-mirrors" # command to run tests From 2f52e15e41eeb0e7cd4d907b182ac49cae43458b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Fri, 7 Feb 2014 16:28:03 -0800 Subject: [PATCH 23/66] 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 24/66] 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 25/66] 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 26/66] 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 27/66] Sharing of nodes in OcTree --- SimPEG/Mesh/TreeMesh.py | 57 ++++++++++++++++++++++++++--------- SimPEG/tests/test_QuadTree.py | 3 +- 2 files changed, 44 insertions(+), 16 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 # + # + # 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"] = 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) + 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 28/66] 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 29/66] 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 30/66] 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 31/66] 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 32/66] 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 33/66] 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 34/66] 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 35/66] 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 36/66] 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 37/66] 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 38/66] 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 39/66] 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 40/66] 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 41/66] 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 42/66] 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 43/66] 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 44/66] 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 45/66] 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 46/66] 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 47/66] 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 48/66] 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 49/66] 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 f6b85ca17380632ba2cda438a995a85ccb33c07b Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 13:20:46 -0800 Subject: [PATCH 50/66] getEdgeMassDeriv --- SimPEG/Mesh/DiffOperators.py | 4 ++++ SimPEG/Mesh/TensorView.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 7a965e0f..87b6aac3 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -644,3 +644,7 @@ class DiffOperators(object): def getFaceMassDeriv(self): Av = self.aveF2CC return Av.T * sdiag(self.vol) + + def getEdgeMassDeriv(self): + Av = self.aveE2CC + return Av.T * sdiag(self.vol) diff --git a/SimPEG/Mesh/TensorView.py b/SimPEG/Mesh/TensorView.py index 7446aecd..a664501a 100644 --- a/SimPEG/Mesh/TensorView.py +++ b/SimPEG/Mesh/TensorView.py @@ -404,7 +404,7 @@ class TensorView(object): :: def function(var, ax, clim, tlt, i): - tlt.set_text('%%d'%%i) + tlt.set_text('%d'%i) return mesh.plotImage(var, imageType='CC', ax=ax, clim=clim) mesh.video([model1, model2, ..., modeln],function) From 87a88901336551043f58f1ceb7ff6763ebf6f3b3 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 13:35:05 -0800 Subject: [PATCH 51/66] 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 52/66] 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 53/66] 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 54/66] 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 b63675c0d8092b34a3459949771d419be8bb93e2 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 18:55:17 -0800 Subject: [PATCH 55/66] patch develop branch --- 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 56/66] 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 38e1d5a1ebf9ffad6eef1cf72bcb85cf554ab3c7 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 19:16:11 -0800 Subject: [PATCH 57/66] lower tolerance on testing random meshes for 1D interpolation --- SimPEG/Tests/test_interpolation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Tests/test_interpolation.py b/SimPEG/Tests/test_interpolation.py index d01dcbc3..018f9091 100644 --- a/SimPEG/Tests/test_interpolation.py +++ b/SimPEG/Tests/test_interpolation.py @@ -4,7 +4,7 @@ from TestUtils import OrderTest from SimPEG.Utils import mkvc MESHTYPES = ['uniformTensorMesh', 'randomTensorMesh'] -TOLERANCES = [0.9, 0.55] +TOLERANCES = [0.9, 0.5] call1 = lambda fun, xyz: fun(xyz) call2 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1]) call3 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1], xyz[:, 2]) @@ -23,7 +23,7 @@ class TestInterpolation1D(OrderTest): meshTypes = MESHTYPES tolerance = TOLERANCES meshDimension = 1 - meshSizes = [8, 16, 32] + meshSizes = [8, 16, 32, 64, 128] def getError(self): funX = lambda x: np.cos(2*np.pi*x) From 34a4d5cb64e19d721c7fc68e0f62aa3295cc2ab0 Mon Sep 17 00:00:00 2001 From: Dave Marchant Date: Tue, 11 Feb 2014 21:29:25 -0800 Subject: [PATCH 58/66] Mass derivs in cylindrical mesh. --- SimPEG/Mesh/Cyl1DMesh.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SimPEG/Mesh/Cyl1DMesh.py b/SimPEG/Mesh/Cyl1DMesh.py index cd232cf6..418a866b 100644 --- a/SimPEG/Mesh/Cyl1DMesh.py +++ b/SimPEG/Mesh/Cyl1DMesh.py @@ -293,6 +293,15 @@ class Cyl1DMesh(object): _aveF2CC = None aveF2CC = property(**aveF2CC()) + def getFaceMassDeriv(self): + Av = self.aveF2CC + return Av.T * sdiag(self.vol) + + def getEdgeMassDeriv(self): + Av = self.aveE2CC + return Av.T * sdiag(self.vol) + + #################################################### # Methods #################################################### From 7b025ed95a31f3b4983864fd2b5066ab96cb7f9d Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Tue, 11 Feb 2014 23:31:01 -0800 Subject: [PATCH 59/66] 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 60/66] 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 From 20cb359e82433a5e5b9ebbfece3428e75e18e33f Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 12 Feb 2014 09:56:20 -0800 Subject: [PATCH 61/66] Removed (now broken) database stuff. --- SimPEG/Data.py | 2 +- SimPEG/Inversion.py | 2 +- SimPEG/Mesh/LogicallyOrthogonalMesh.py | 2 +- SimPEG/Mesh/TensorMesh.py | 2 +- SimPEG/Model.py | 2 +- SimPEG/ObjFunction.py | 2 +- SimPEG/Optimization.py | 2 +- SimPEG/Problem.py | 2 +- SimPEG/Regularization.py | 2 +- SimPEG/Utils/Save.py | 352 ------------------------- SimPEG/Utils/__init__.py | 7 +- 11 files changed, 15 insertions(+), 362 deletions(-) delete mode 100644 SimPEG/Utils/Save.py diff --git a/SimPEG/Data.py b/SimPEG/Data.py index 7a793065..7b0145dc 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -4,7 +4,7 @@ import Utils, numpy as np class BaseData(object): """Data holds the observed data, and the standard deviations.""" - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass std = None #: Estimated Standard Deviations dobs = None #: Observed data diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 56a00f8f..64445ab2 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -7,7 +7,7 @@ class BaseInversion(object): """BaseInversion(objFunc, opt, **kwargs) """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass name = 'BaseInversion' diff --git a/SimPEG/Mesh/LogicallyOrthogonalMesh.py b/SimPEG/Mesh/LogicallyOrthogonalMesh.py index e39c0f54..a8b4207f 100644 --- a/SimPEG/Mesh/LogicallyOrthogonalMesh.py +++ b/SimPEG/Mesh/LogicallyOrthogonalMesh.py @@ -26,7 +26,7 @@ class LogicallyOrthogonalMesh(BaseMesh, DiffOperators, InnerProducts, LomView): M.plotGrid(showIt=True) """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass _meshType = 'LOM' diff --git a/SimPEG/Mesh/TensorMesh.py b/SimPEG/Mesh/TensorMesh.py index 341cfba7..b2981bdd 100644 --- a/SimPEG/Mesh/TensorMesh.py +++ b/SimPEG/Mesh/TensorMesh.py @@ -33,7 +33,7 @@ class TensorMesh(BaseMesh, TensorView, DiffOperators, InnerProducts): """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass _meshType = 'TENSOR' diff --git a/SimPEG/Model.py b/SimPEG/Model.py index 44dc3908..6941607d 100644 --- a/SimPEG/Model.py +++ b/SimPEG/Model.py @@ -7,7 +7,7 @@ class BaseModel(object): """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass counter = None #: A SimPEG.Utils.Counter object mesh = None #: A SimPEG Mesh diff --git a/SimPEG/ObjFunction.py b/SimPEG/ObjFunction.py index 91722b68..7d08b9fc 100644 --- a/SimPEG/ObjFunction.py +++ b/SimPEG/ObjFunction.py @@ -3,7 +3,7 @@ import Utils, Parameters, numpy as np, scipy.sparse as sp class BaseObjFunction(object): """BaseObjFunction(data, reg, **kwargs)""" - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass beta = Parameters.ParameterProperty('beta', default=1, doc='Regularization trade-off parameter') diff --git a/SimPEG/Optimization.py b/SimPEG/Optimization.py index 4e5963f6..8e08250b 100644 --- a/SimPEG/Optimization.py +++ b/SimPEG/Optimization.py @@ -82,7 +82,7 @@ class Minimize(object): Minimize is a general class for derivative based optimization. """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass name = "General Optimization Algorithm" #: The name of the optimization algorithm diff --git a/SimPEG/Problem.py b/SimPEG/Problem.py index df37d05a..314af81f 100644 --- a/SimPEG/Problem.py +++ b/SimPEG/Problem.py @@ -34,7 +34,7 @@ class BaseProblem(object): to (locally) find how model parameters change the data, and optimize! """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass counter = None #: A SimPEG.Utils.Counter object diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index aa62449a..b360d726 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -10,7 +10,7 @@ class BaseRegularization(object): """ - __metaclass__ = Utils.Save.Savable + __metaclass__ = Utils.SimPEGMetaClass modelPair = Model.BaseModel #: Some regularizations only work on specific models diff --git a/SimPEG/Utils/Save.py b/SimPEG/Utils/Save.py deleted file mode 100644 index a9c77191..00000000 --- a/SimPEG/Utils/Save.py +++ /dev/null @@ -1,352 +0,0 @@ -import numpy as np -import time -import re - -try: - import h5py -except Exception, e: - print 'Warning: SimPEG.Utils.Save needs h5py to be installed.' - - -SAVEABLES = {} - -def natural_keys(text): - ''' - alist.sort(key=natural_keys) sorts in human order - http://nedbatchelder.com/blog/200712/human_sorting.html - (See Toothy's implementation in the comments) - ''' - atoi = lambda text: int(text) if text.isdigit() else text - return [ atoi(c) for c in re.split('(\d+)', text) ] - - -def preIteration(group): - group.attrs['complete'] = False - group.attrs['time'] = time.time() - -def postIteration(group): - group.attrs['time'] = time.time() - group.attrs['time'] - group.attrs['date'] = time.ctime() - group.attrs['complete'] = True - -class SimPEGTable: - """ - This is a wrapper class on the HDF5 file. - """ - def __init__(self, name, mode='a'): - if '.hdf5' not in name: - name += '.hdf5' - self.f = h5py.File(name, mode) - self.root = hdf5Group(self,self.f) - - self.inversions = hdf5InversionGroup(self,self.root.addGroup('inversions',soft=True)) - - def show(self): self.root.show() - - def saveInversion(self, invObj): - - # Create a new inversion anytime this is run. - def _startup_hdf5_inv(invObj, m0): - node = self.inversions.addGroup('%d'%self.inversions.numChildren) - saveSavable(invObj,node.addGroup('rebuild')) - results = node.addGroup('results') - preIteration(results) - invObj._invNode = results - self.f.flush() - invObj.hook(_startup_hdf5_inv, overwrite=True) - - # At the start of every iteration we will create a inversion iteration node. - def _doStartIteration_hdf5_inv(invObj): - invObj._invNodeIt = invObj._invNode.addGroup('%d'%(invObj.iter+1)) - preIteration(invObj._invNodeIt) - invObj.hook(_doStartIteration_hdf5_inv, overwrite=True) - - def _doEndIteration_hdf5_inv(invObj): - invObj.save(invObj._invNodeIt) - postIteration(invObj._invNodeIt) - self.f.flush() - invObj.hook(_doEndIteration_hdf5_inv, overwrite=True) - - # Delete all iterates that did not finish. - def _finish_hdf5_inv(invObj): - postIteration(invObj._invNode) - for it in invObj._invNode: - if not it.attrs['complete']: - del self.f[it.path] - del invObj._invNode - self.f.flush() - invObj.hook(_finish_hdf5_inv, overwrite=True) - - def _doStartIteration_hdf5_opt(optObj): - optObj._optNodeIt = optObj.parent._invNode.addGroup('%d.%d'%(optObj.parent.iter, optObj.iter)) - preIteration(optObj._optNodeIt) - invObj.opt.hook(_doStartIteration_hdf5_opt, overwrite=True) - - def _doEndIteration_hdf5_opt(optObj, xt): - optObj.save(optObj._optNodeIt) - postIteration(optObj._optNodeIt) - self.f.flush() - invObj.opt.hook(_doEndIteration_hdf5_opt, overwrite=True) - - - -class hdf5Group(object): - """Has some low level support for wrapping the native HDF5-Group class""" - - def __init__(self, T, groupNode): - self.T = T - # check if you are inputing a hdf5Group rather than a raw node, and act accordingly - if issubclass(groupNode.__class__, hdf5Group): - self.node = groupNode.node - else: - self.node = groupNode - - self.childClass = hdf5Group - self.parentClass = hdf5Group - - @property - def children(self): - """Children names in a list - - Use obj[name] to return the actual node. - """ - myChildren = [c for c in self.node] - myChildren.sort(key=natural_keys) - return myChildren - - @property - def numChildren(self): - """Returns the len(children)""" - return len(self.children) - - @property - def parent(self): - """Returns parent node""" - return self.parentClass(self.T, self.node.parent) - - @property - def name(self): - return self.path.split('/')[-1] - - @property - def path(self): - """Returns the root path of the group""" - return self.node.name - - @property - def attrs(self): - """Returns a list of attributes in the group""" - return self.node.attrs - - def addGroup(self, name, soft=False): - """Adds a child group to the current node.""" - if name in self.children and soft: - return self[name] - assert name not in self.children, 'Already a child called: '+self.path+'/'+name - return self.childClass(self.T, self.node.create_group(name)) - - def setArray(self, name, data): - a = self.node.create_dataset(name, data.shape) - a[...] = data - return a - - def __getitem__(self, val): - if type(val) is int: - val = self.children[val] - child = self.node[val] - if type(child) is h5py.Group: - child = self.childClass(self.T, child) - return child - - def __contains__(self, key): - return key in self.children - - def show(self, pad='', maxDepth=1, depth=0): - """ - Recursively show the structure of the database. - - For example:: - - - - - - - - - - - - - """ - s = self.__str__() - pad += ' '*4 - if maxDepth <= 0: print s - if depth >= maxDepth: return s - - for c in self.children: - if issubclass(self[c].__class__, hdf5Group): - s += '\n%s- %s' % (pad, self[c].show(pad=pad,depth=depth+1,maxDepth=maxDepth)) - else: - s += '\n%s- %s' % (pad, self[c].__str__()) - if depth is 0: - print s - else: - return s - - def __str__(self): - return '<%s "%s" (%d member%s, attrs=[%s])>' % (self.__class__.__name__, self.path, self.numChildren, '' if self.numChildren == 1 else 's',', '.join([a for a in self.attrs])) - - - -class hdf5InversionGroup(hdf5Group): - def __init__(self, T, groupNode): - hdf5Group.__init__(self, T, groupNode) - self.childClass = hdf5Inversion - -class hdf5Inversion(hdf5Group): - def __init__(self, T, groupNode): - hdf5Group.__init__(self, T, groupNode) - self.parentClass = hdf5InversionGroup - self.childClass = hdf5InversionResults - - def rebuild(self): - return loadSavable(self['rebuild']) - - @property - def results(self): return self['results'] - - -class hdf5InversionResults(hdf5Group): - def __init__(self, T, groupNode): - hdf5Group.__init__(self, T, groupNode) - self.parentClass = hdf5Inversion - self.childClass = hdf5InversionIteration - -class hdf5InversionIteration(hdf5Group): - def __init__(self, T, groupNode): - hdf5Group.__init__(self, T, groupNode) - self.parentClass = hdf5InversionResults - - - -class Savable(type): - def __new__(cls, name, bases, attrs): - __init__ = attrs['__init__'] - def init_wrapper(self, *args, **kwargs): - self._args_init = args - self._kwargs_init = kwargs - return __init__(self, *args,**kwargs) - attrs['__init__'] = init_wrapper - - newClass = super(Savable, cls).__new__(cls, name, bases, attrs) - SAVEABLES[name] = newClass - return newClass - - -def saveSavable(obj, group, debug=False): - """ - This creates softlinks if _savable exists in children object. - - The first object is always created. - """ - assert type(obj.__class__) is Savable, 'Can only save objects that are Savable objects.' - - def doSave(grp, name, val): - if debug: print name, val - if type(val.__class__) is Savable: - link = getattr(val,'_savable',None) - if link is not None: - group.node[name] = h5py.SoftLink(link.path) - if debug: 'Created a softlink path to %s' % link.path - else: - subgrp = grp.addGroup(name) - saveSavable(val, subgrp, debug=debug) - elif type(val) in [list, tuple]: - # Split up, and save each element - for i, v in enumerate(val): - doSave(grp, name + '[%d]'%i, v) - elif type(val) is np.ndarray: - grp.setArray(name, val) - elif val is None: - grp.attrs[name] = 'None' - else: - # just try saving it as an attr - try: - grp.attrs[name] = val - except Exception, e: - print 'Warning: Could not save %s, problems may arise in loading.' % name - - group.attrs['__class__'] = obj.__class__.__name__ - for arg in obj._kwargs_init: - doSave(group, '_kwarg_'+arg, obj._kwargs_init[arg]) - for i, arg in enumerate(obj._args_init): - doSave(group, '_arg%d'%i, arg) - obj._savable = group - - -def loadSavable(node, pointers=None): - """ - pointers allow things that point to the same node in the h5py file to - be returned as the same object, if they have already been created. - """ - - if pointers is None: pointers = [] - for pointer in pointers: - if pointer._savable.node == node.node: return pointer - - args = ([a for a in node.attrs if '_arg' in a] + [a for a in node.children if '_arg' in a]) - kwargs = ([a for a in node.attrs if '_kwarg' in a] + [a for a in node.children if '_kwarg' in a]) - args.sort(key=natural_keys) - kwargs.sort(key=natural_keys) - - def get(node,key): - if key in node.children: return node[key] - elif key in node.attrs: return node.attrs[key] - - ARGS = [] - for name in args: - val = get(node, name) - if val.__class__ is h5py.Dataset: val = val[:] - if val is 'None': val = None - if '[' in name: # We are reloading a list - ind = int(name[4:name.index('[')]) - if len(ARGS) is ind: # Create the list - ARGS.append([val]) - else: - ARGS[ind].append(val) - elif issubclass(val.__class__,hdf5Group): - ARGS.append(loadSavable(val,pointers=pointers)) - else: - ind = int(name[4:]) - ARGS.append(val) - - KWARGS = {} - for name in kwargs: - val = get(node, name) - if val.__class__ is h5py.Dataset: val = val[:] - if val is 'None': val = None - if '[' in name: # We are reloading a list - key = name[7:name.index('[')] - if key not in KWARGS: # Create the list - KWARGS[key] = [val] - else: - KWARGS[key].append(val) - elif issubclass(val.__class__,hdf5Group): - key = name[7:] - KWARGS[key] = loadSavable(val,pointers=pointers) - else: - key = name[7:] - KWARGS[key] = val - - cls = get(node, '__class__') - if cls in SAVEABLES: - try: - out = SAVEABLES[cls](*ARGS, **KWARGS) - out._savable = node - pointers.append(out) # Because this is recursive. - return out - except Exception, e: - print 'Warning: %s Class could not be initiated.' % cls - print 'ARGS: ', ARGS - print 'KWARGS: ', KWARGS - return (cls, ARGS, KWARGS, node) - else: - print 'Warning: %s Class not found in SimPEG.Utils.Save.SAVABLES' % cls - return (cls, ARGS, KWARGS, node) - diff --git a/SimPEG/Utils/__init__.py b/SimPEG/Utils/__init__.py index 1331cc8c..8ed65c84 100644 --- a/SimPEG/Utils/__init__.py +++ b/SimPEG/Utils/__init__.py @@ -4,7 +4,6 @@ from meshutils import exampleLomGird, meshTensors from lomutils import volTetra, faceInfo, inv2X2BlockDiagonal, inv3X3BlockDiagonal, indexCube from interputils import interpmat from ipythonutils import easyAnimate as animate -import Save import ModelBuilder import types @@ -12,6 +11,12 @@ import time import numpy as np from functools import wraps + +class SimPEGMetaClass(type): + def __new__(cls, name, bases, attrs): + return super(SimPEGMetaClass, cls).__new__(cls, name, bases, attrs) + + def hook(obj, method, name=None, overwrite=False, silent=False): """ This dynamically binds a method to the instance of the class. From e6d6297488d09e8e520c57379f1a5451885273b2 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 12 Feb 2014 10:23:38 -0800 Subject: [PATCH 62/66] Removed Examples dir, and put it up a level (outside SimPEG path) renamed to tutorials for future tutorial development. --- SimPEG/Examples/DC.py | 249 ----------------------- SimPEG/Examples/__init__.py | 2 - SimPEG/Tests/test_forward_DCproblem.py | 85 -------- SimPEG/__init__.py | 1 - {SimPEG/Examples => Tutorials}/Linear.py | 0 5 files changed, 337 deletions(-) delete mode 100644 SimPEG/Examples/DC.py delete mode 100644 SimPEG/Examples/__init__.py delete mode 100644 SimPEG/Tests/test_forward_DCproblem.py rename {SimPEG/Examples => Tutorials}/Linear.py (100%) diff --git a/SimPEG/Examples/DC.py b/SimPEG/Examples/DC.py deleted file mode 100644 index ee8a427f..00000000 --- a/SimPEG/Examples/DC.py +++ /dev/null @@ -1,249 +0,0 @@ -from SimPEG import * - - - -class DCData(Data.BaseData): - """ - **DCData** - - Geophysical DC resistivity data. - - """ - - P = None #: projection - - def __init__(self, **kwargs): - Data.BaseData.__init__(self, **kwargs) - Utils.setKwargs(self, **kwargs) - - def reshapeFields(self, u): - if len(u.shape) == 1: - u = u.reshape([-1, self.RHS.shape[1]], order='F') - return u - - def projectField(self, u): - """ - Predicted data. - - .. math:: - d_\\text{pred} = Pu(m) - """ - u = self.reshapeFields(u) - return Utils.mkvc(self.P*u) - - - -class DCProblem(Problem.BaseProblem): - """ - **DCProblem** - - Geophysical DC resistivity problem. - - """ - - dataPair = DCData - - def __init__(self, mesh, model, **kwargs): - Problem.BaseProblem.__init__(self, mesh, model) - self.mesh.setCellGradBC('neumann') - Utils.setKwargs(self, **kwargs) - - - def createMatrix(self, m): - """ - Makes the matrix A(m) for the DC resistivity problem. - - :param numpy.array m: model - :rtype: scipy.csc_matrix - :return: A(m) - - .. math:: - c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0 - - Where M() is the mass matrix and mT is the model transform. - """ - D = self.mesh.faceDiv - G = self.mesh.cellGrad - sigma = self.model.transform(m) - Msig = self.mesh.getFaceMass(sigma) - A = D*Msig*G - return A.tocsc() - - def fields(self, m): - A = self.createMatrix(m) - solve = Solver(A) - phi = solve.solve(self.data.RHS) - return Utils.mkvc(phi) - - def J(self, m, v, u=None): - """ - :param numpy.array m: model - :param numpy.array v: vector to multiply - :param numpy.array u: fields - :rtype: numpy.array - :return: Jv - - .. math:: - c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0 - - \\nabla_u (A(m)u - q) = A(m) - - \\nabla_m (A(m)u - q) = G\\text{sdiag}(Du)\\nabla_m(M(mT(m))) - - Where M() is the mass matrix and mT is the model transform. - - .. math:: - J = - P \left( \\nabla_u c(m, u) \\right)^{-1} \\nabla_m c(m, u) - - J(v) = - P ( A(m)^{-1} ( G\\text{sdiag}(Du)\\nabla_m(M(mT(m))) v ) ) - """ - if u is None: - u = self.fields(m) - - u = self.data.reshapeFields(u) - - P = self.data.P - D = self.mesh.faceDiv - G = self.mesh.cellGrad - A = self.createMatrix(m) - Av_dm = self.mesh.getFaceMassDeriv() - mT_dm = self.model.transformDeriv(m) - - dCdu = A - - dCdm = np.empty_like(u) - for i, ui in enumerate(u.T): # loop over each column - dCdm[:, i] = D * ( Utils.sdiag( G * ui ) * ( Av_dm * ( mT_dm * v ) ) ) - - solve = Solver(dCdu) - Jv = - P * solve.solve(dCdm) - return Utils.mkvc(Jv) - - def Jt(self, m, v, u=None): - """Takes data, turns it into a model..ish""" - - if u is None: - u = self.fields(m) - - u = self.data.reshapeFields(u) - v = self.data.reshapeFields(v) - - P = self.data.P - D = self.mesh.faceDiv - G = self.mesh.cellGrad - A = self.createMatrix(m) - Av_dm = self.mesh.getFaceMassDeriv() - mT_dm = self.model.transformDeriv(m) - - dCdu = A.T - solve = Solver(dCdu) - - w = solve.solve(P.T*v) - - Jtv = 0 - for i, ui in enumerate(u.T): # loop over each column - Jtv += Utils.sdiag( G * ui ) * ( D.T * w[:,i] ) - - Jtv = - mT_dm.T * ( Av_dm.T * Jtv ) - return Jtv - - - -def genTxRxmat(nelec, spacelec, surfloc, elecini, mesh): - """ Generate projection matrix (Q) and """ - elecend = 0.5+spacelec*(nelec-1) - elecLocR = np.linspace(elecini, elecend, nelec) - elecLocT = elecLocR+1 - nrx = nelec-1 - ntx = nelec-1 - q = np.zeros((mesh.nC, ntx)) - Q = np.zeros((mesh.nC, nrx)) - - for i in range(nrx): - - rxind1 = np.argwhere((mesh.gridCC[:,0]==surfloc) & (mesh.gridCC[:,1]==elecLocR[i])) - rxind2 = np.argwhere((mesh.gridCC[:,0]==surfloc) & (mesh.gridCC[:,1]==elecLocR[i+1])) - - txind1 = np.argwhere((mesh.gridCC[:,0]==surfloc) & (mesh.gridCC[:,1]==elecLocT[i])) - txind2 = np.argwhere((mesh.gridCC[:,0]==surfloc) & (mesh.gridCC[:,1]==elecLocT[i+1])) - - q[txind1,i] = 1 - q[txind2,i] = -1 - Q[rxind1,i] = 1 - Q[rxind2,i] = -1 - - Q = sp.csr_matrix(Q) - rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 - return q, Q, rxmidLoc - - -if __name__ == '__main__': - import matplotlib.pyplot as plt - - # Create the mesh - h1 = np.ones(20) - h2 = np.ones(100) - M = Mesh.TensorMesh([h1,h2]) - - # Create some parameters for the model - sig1 = np.log(1) - sig2 = np.log(0.01) - - # Create a synthetic model from a block in a half-space - p0 = [5, 10] - p1 = [15, 50] - condVals = [sig1, sig2] - mSynth = Utils.ModelBuilder.defineBlockConductivity(M.gridCC,p0,p1,condVals) - plt.colorbar(M.plotImage(mSynth)) - # plt.show() - - # Set up the projection - nelec = 50 - spacelec = 2 - surfloc = 0.5 - elecini = 0.5 - elecend = 0.5+spacelec*(nelec-1) - elecLocR = np.linspace(elecini, elecend, nelec) - rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 - q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, M) - P = Q.T - - model = Model.LogModel(M) - prob = DCProblem(M, model) - - # Create some data - data = prob.createSyntheticData(mSynth, std=0.05, P=P, RHS=q) - - u = prob.fields(mSynth) - u = data.reshapeFields(u) - M.plotImage(u[:,10]) - plt.show() - - # Now set up the prob to do some minimization - # prob.dobs = dobs - # prob.std = dobs*0 + 0.05 - m0 = M.gridCC[:,0]*0+sig2 - - reg = Regularization.Tikhonov(model) - objFunc = ObjFunction.BaseObjFunction(data, reg) - opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=3, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) - inv = Inversion.BaseInversion(objFunc, opt) - - # Check Derivative - derChk = lambda m: [objFunc.dataObj(m), objFunc.dataObjDeriv(m)] - # Tests.checkDerivative(derChk, mSynth) - - print objFunc.dataObj(m0) - print objFunc.dataObj(mSynth) - - m = inv.run(m0) - - plt.colorbar(M.plotImage(m)) - print m - plt.show() - - - - - - diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py deleted file mode 100644 index a5c37345..00000000 --- a/SimPEG/Examples/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import DC -import Linear diff --git a/SimPEG/Tests/test_forward_DCproblem.py b/SimPEG/Tests/test_forward_DCproblem.py deleted file mode 100644 index 1a44b350..00000000 --- a/SimPEG/Tests/test_forward_DCproblem.py +++ /dev/null @@ -1,85 +0,0 @@ -# import numpy as np -# import unittest -# from SimPEG.mesh import TensorMesh -# from SimPEG.Utils import ModelBuilder, sdiag -# from SimPEG.forward import Problem -# from SimPEG.examples.DC import * -# from TestUtils import checkDerivative -# from scipy.sparse.linalg import dsolve -# from SimPEG import inverse - - -# class DCProblemTests(unittest.TestCase): - -# def setUp(self): -# # Create the mesh -# h1 = np.ones(20) -# h2 = np.ones(20) -# mesh = TensorMesh([h1,h2]) - -# # Create some parameters for the model -# sig1 = 1 -# sig2 = 0.01 - -# # Create a synthetic model from a block in a half-space -# p0 = [2, 2] -# p1 = [5, 5] -# condVals = [sig1, sig2] -# mSynth = ModelBuilder.defineBlockConductivity(p0,p1,mesh.gridCC,condVals) - -# # Set up the projection -# nelec = 10 -# spacelec = 2 -# surfloc = 0.5 -# elecini = 0.5 -# elecend = 0.5+spacelec*(nelec-1) -# elecLocR = np.linspace(elecini, elecend, nelec) -# rxmidLoc = (elecLocR[0:nelec-1]+elecLocR[1:nelec])*0.5 -# q, Q, rxmidloc = genTxRxmat(nelec, spacelec, surfloc, elecini, mesh) -# P = Q.T - -# # Create some data - -# problem = DCProblem(mesh) -# problem.P = P -# problem.RHS = q -# data = problem.createSyntheticData(mSynth, std=0.05) - -# # Now set up the problem to do some minimization -# opt = inverse.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6) -# reg = inverse.Regularization(mesh) -# inv = inverse.Inversion(problem, reg, opt, data, beta0=1e4) - -# self.inv = inv -# self.reg = reg -# self.p = problem -# self.mesh = mesh -# self.m0 = mSynth -# self.data = data - -# def test_misfit(self): -# derChk = lambda m: [self.p.dpred(m), lambda mx: self.p.J(self.m0, mx)] -# passed = checkDerivative(derChk, self.m0, plotIt=False) -# self.assertTrue(passed) - -# def test_adjoint(self): -# # Adjoint Test -# u = np.random.rand(self.mesh.nC*self.p.RHS.shape[1]) -# v = np.random.rand(self.mesh.nC) -# w = np.random.rand(self.data.dobs.shape[0]) -# wtJv = w.dot(self.p.J(self.m0, v, u=u)) -# vtJtw = v.dot(self.p.Jt(self.m0, w, u=u)) -# passed = (wtJv - vtJtw) < 1e-10 -# self.assertTrue(passed) - -# def test_dataObj(self): -# derChk = lambda m: [self.inv.dataObj(m), self.inv.dataObjDeriv(m)] -# checkDerivative(derChk, self.m0, plotIt=False) - -# def test_modelObj(self): -# derChk = lambda m: [self.reg.modelObj(m), self.reg.modelObjDeriv(m)] -# checkDerivative(derChk, self.m0, plotIt=False) - - -# if __name__ == '__main__': -# unittest.main() diff --git a/SimPEG/__init__.py b/SimPEG/__init__.py index 4967608e..17f64d54 100644 --- a/SimPEG/__init__.py +++ b/SimPEG/__init__.py @@ -11,7 +11,6 @@ import ObjFunction import Optimization import Inversion import Parameters -import Examples import Tests diff --git a/SimPEG/Examples/Linear.py b/Tutorials/Linear.py similarity index 100% rename from SimPEG/Examples/Linear.py rename to Tutorials/Linear.py From 82edde7f71d62c756a99e883e28044bff2eaef7d Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 12 Feb 2014 19:14:11 -0800 Subject: [PATCH 63/66] Move to own repo. --- SimPEG/visualize/__init__.py | 2 - SimPEG/visualize/vtk/__init__.py | 2 - SimPEG/visualize/vtk/vtkTools.py | 385 ------------------------------- SimPEG/visualize/vtk/vtkView.py | 350 ---------------------------- 4 files changed, 739 deletions(-) delete mode 100644 SimPEG/visualize/__init__.py delete mode 100644 SimPEG/visualize/vtk/__init__.py delete mode 100644 SimPEG/visualize/vtk/vtkTools.py delete mode 100644 SimPEG/visualize/vtk/vtkView.py diff --git a/SimPEG/visualize/__init__.py b/SimPEG/visualize/__init__.py deleted file mode 100644 index 485f9782..00000000 --- a/SimPEG/visualize/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import vtk -#import mpl diff --git a/SimPEG/visualize/vtk/__init__.py b/SimPEG/visualize/vtk/__init__.py deleted file mode 100644 index 6d60ed5c..00000000 --- a/SimPEG/visualize/vtk/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from vtkTools import vtkTools -from vtkView import vtkView \ No newline at end of file diff --git a/SimPEG/visualize/vtk/vtkTools.py b/SimPEG/visualize/vtk/vtkTools.py deleted file mode 100644 index 68326662..00000000 --- a/SimPEG/visualize/vtk/vtkTools.py +++ /dev/null @@ -1,385 +0,0 @@ -import numpy as np -try: - import vtk, vtk.util.numpy_support as npsup, pdb -except Exception, e: - print 'VTK import error. Please ensure you have VTK installed to use this visualization package.' -from SimPEG.Utils import mkvc - - -class vtkTools(object): - """ - Class that interacts with VTK visulization toolkit. - - """ - - def __init__(self): - """ Initializes the VTK vtkTools. - - """ - - pass - - @staticmethod - def makeCellVTKObject(mesh,model): - """ - Make and return a cell based VTK object for a simpeg mesh and model. - - Input: - :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK - :param model, dictionary of numpy.array - Name('s) and array('s). Match number of cells - - Output: - :rtype: vtkRecilinearGrid object - :return: vtkObj - """ - - # Deal with dimensionalities - if mesh.dim >= 1: - vX = mesh.vectorNx - xD = mesh.nNx - yD,zD = 1,1 - vY, vZ = np.array([0,0]) - if mesh.dim >= 2: - vY = mesh.vectorNy - yD = mesh.nNy - if mesh.dim == 3: - vZ = mesh.vectorNz - zD = mesh.nNz - # Use rectilinear VTK grid. - # Assign the spatial information. - vtkObj = vtk.vtkRectilinearGrid() - vtkObj.SetDimensions(xD,yD,zD) - vtkObj.SetXCoordinates(npsup.numpy_to_vtk(vX,deep=1)) - vtkObj.SetYCoordinates(npsup.numpy_to_vtk(vY,deep=1)) - vtkObj.SetZCoordinates(npsup.numpy_to_vtk(vZ,deep=1)) - - # Assign the model('s) to the object - for item in model.iteritems(): - # Convert numpy array - vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) - vtkDoubleArr.SetName(item[0]) - vtkObj.GetCellData().AddArray(vtkDoubleArr) - - vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) - vtkObj.Update() - return vtkObj - - @staticmethod - def makeFaceVTKObject(mesh,model): - """ - Make and return a face based VTK object for a simpeg mesh and model. - - Input: - :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK - :param model, dictionary of numpy.array - Name('s) and array('s). - Property array must be order hstack(Fx,Fy,Fz) - - Output: - :rtype: vtkUnstructuredGrid object - :return: vtkObj - """ - - ## Convert simpeg mesh to VTK properties - # Convert mesh nodes to vtkPoints - vtkPts = vtk.vtkPoints() - vtkPts.SetData(npsup.numpy_to_vtk(mesh.gridN,deep=1)) - - # Define the face "cells" - # Using VTK_QUAD cell for faces (see VTK file format) - nodeMat = mesh.r(np.arange(mesh.nN,dtype='int64'),'N','N','M') - def faceR(mat,length): - return mat.T.reshape((length,1)) - # First direction - nTFx = np.prod(mesh.nFx) - FxCellBlock = np.hstack([ 4*np.ones((nTFx,1),dtype='int64'),faceR(nodeMat[:,:-1,:-1],nTFx),faceR(nodeMat[:,1: ,:-1],nTFx),faceR(nodeMat[:,1: ,1: ],nTFx),faceR(nodeMat[:,:-1,1: ],nTFx)] ) - FyCellBlock = np.array([],dtype='int64') - FzCellBlock = np.array([],dtype='int64') - # Second direction - if mesh.dim >= 2: - nTFy = np.prod(mesh.nFy) - FyCellBlock = np.hstack([ 4*np.ones((nTFy,1),dtype='int64'),faceR(nodeMat[:-1,:,:-1],nTFy),faceR(nodeMat[1: ,:,:-1],nTFy),faceR(nodeMat[1: ,:,1: ],nTFy),faceR(nodeMat[:-1,:,1: ],nTFy)] ) - # Third direction - if mesh.dim == 3: - nTFz = np.prod(mesh.nFz) - FzCellBlock = np.hstack([ 4*np.ones((nTFz,1),dtype='int64'),faceR(nodeMat[:-1,:-1,:],nTFz),faceR(nodeMat[1: ,:-1,:],nTFz),faceR(nodeMat[1: ,1: ,:],nTFz),faceR(nodeMat[:-1,1: ,:],nTFz)] ) - # Cells -cell array - FCellArr = vtk.vtkCellArray() - FCellArr.SetNumberOfCells(mesh.nF) - FCellArr.SetCells(mesh.nF,npsup.numpy_to_vtkIdTypeArray(np.vstack([FxCellBlock,FyCellBlock,FzCellBlock]),deep=1)) - # Cell type - FCellType = npsup.numpy_to_vtk(vtk.VTK_QUAD*np.ones(mesh.nF,dtype='uint8'),deep=1) - # Cell location - FCellLoc = npsup.numpy_to_vtkIdTypeArray(np.arange(0,mesh.nF*5,5,dtype='int64'),deep=1) - - ## Make the object - vtkObj = vtk.vtkUnstructuredGrid() - # Set the objects properties - vtkObj.SetPoints(vtkPts) - vtkObj.SetCells(FCellType,FCellLoc,FCellArr) - - # Assign the model('s) to the object - for item in model.iteritems(): - # Convert numpy array - vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) - vtkDoubleArr.SetName(item[0]) - vtkObj.GetCellData().AddArray(vtkDoubleArr) - - vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) - vtkObj.Update() - return vtkObj - - @staticmethod - def makeEdgeVTKObject(mesh,model): - """ - Make and return a edge based VTK object for a simpeg mesh and model. - - Input: - :param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK - :param model, dictionary of numpy.array - Name('s) and array('s). - Property array must be order hstack(Ex,Ey,Ez) - - Output: - :rtype: vtkUnstructuredGrid object - :return: vtkObj - """ - - ## Convert simpeg mesh to VTK properties - # Convert mesh nodes to vtkPoints - vtkPts = vtk.vtkPoints() - vtkPts.SetData(npsup.numpy_to_vtk(mesh.gridN,deep=1)) - - # Define the face "cells" - # Using VTK_QUAD cell for faces (see VTK file format) - nodeMat = mesh.r(np.arange(mesh.nN,dtype='int64'),'N','N','M') - def edgeR(mat,length): - return mat.T.reshape((length,1)) - # First direction - nTEx = np.prod(mesh.nEx) - ExCellBlock = np.hstack([ 2*np.ones((nTEx,1),dtype='int64'),edgeR(nodeMat[:-1,:,:],nTEx),edgeR(nodeMat[1:,:,:],nTEx)]) - # Second direction - if mesh.dim >= 2: - nTEy = np.prod(mesh.nEy) - EyCellBlock = np.hstack([ 2*np.ones((nTEy,1),dtype='int64'),edgeR(nodeMat[:,:-1,:],nTEy),edgeR(nodeMat[:,1:,:],nTEy)]) - # Third direction - if mesh.dim == 3: - nTEz = np.prod(mesh.nEz) - EzCellBlock = np.hstack([ 2*np.ones((nTEz,1),dtype='int64'),edgeR(nodeMat[:,:,:-1],nTEz),edgeR(nodeMat[:,:,1:],nTEz)]) - # Cells -cell array - ECellArr = vtk.vtkCellArray() - ECellArr.SetNumberOfCells(mesh.nE) - ECellArr.SetCells(mesh.nE,npsup.numpy_to_vtkIdTypeArray(np.vstack([ExCellBlock,EyCellBlock,EzCellBlock]),deep=1)) - # Cell type - ECellType = npsup.numpy_to_vtk(vtk.VTK_LINE*np.ones(mesh.nE,dtype='uint8'),deep=1) - # Cell location - ECellLoc = npsup.numpy_to_vtkIdTypeArray(np.arange(0,mesh.nE*3,3,dtype='int64'),deep=1) - - ## Make the object - vtkObj = vtk.vtkUnstructuredGrid() - # Set the objects properties - vtkObj.SetPoints(vtkPts) - vtkObj.SetCells(ECellType,ECellLoc,ECellArr) - - # Assign the model('s) to the object - for item in model.iteritems(): - # Convert numpy array - vtkDoubleArr = npsup.numpy_to_vtk(item[1],deep=1) - vtkDoubleArr.SetName(item[0]) - vtkObj.GetCellData().AddArray(vtkDoubleArr) - - vtkObj.GetCellData().SetActiveScalars(model.keys()[0]) - vtkObj.Update() - return vtkObj - - @staticmethod - def makeRenderWindow(ren): - renwin = vtk.vtkRenderWindow() - renwin.AddRenderer(ren) - iren = vtk.vtkRenderWindowInteractor() - iren.GetInteractorStyle().SetCurrentStyleToTrackballCamera() - iren.SetRenderWindow(renwin) - - return iren, renwin - - - @staticmethod - def closeRenderWindow(iren): - renwin = iren.GetRenderWindow() - renwin.Finalize() - iren.TerminateApp() - - del iren, renwin - - @staticmethod - def makeVTKActor(vtkObj): - """ Makes a vtk mapper and Actor""" - mapper = vtk.vtkDataSetMapper() - mapper.SetInput(vtkObj) - actor = vtk.vtkActor() - actor.SetMapper(mapper) - actor.GetProperty().SetColor(0,0,0) - actor.GetProperty().SetRepresentationToWireframe() - return actor - - @staticmethod - def makeVTKLODActor(vtkObj,clipper): - """Make LOD vtk Actor""" - selectMapper = vtk.vtkDataSetMapper() - selectMapper.SetInputConnection(clipper.GetOutputPort()) - selectMapper.SetScalarVisibility(1) - selectMapper.SetColorModeToMapScalars() - selectMapper.SetScalarModeToUseCellData() - selectMapper.SetScalarRange(clipper.GetInputDataObject(0,0).GetCellData().GetArray(0).GetRange()) - - selectActor = vtk.vtkLODActor() - selectActor.SetMapper(selectMapper) - selectActor.GetProperty().SetEdgeColor(1,0.5,0) - selectActor.GetProperty().SetEdgeVisibility(0) - selectActor.VisibilityOn() - selectActor.SetScale(1.01, 1.01, 1.01) - return selectActor - - @staticmethod - def setScalar2View(vtkObj,scalarName): - """ Sets the sclar to view """ - useArr = vtkObj.GetCellData().GetArray(scalarName) - if useArr == None: - raise IOError('Nerty array {:s} in the vtkObject'.format(scalarName)) - vtkObj.GetCellData().SetActiveScalars(scalarName) - - @staticmethod - def makeRectiVTKVOIThres(vtkObj,VOI,limits): - """Make volume of interest and threshold for rectilinear grid.""" - # Check for the input - cellCore = vtk.vtkExtractRectilinearGrid() - cellCore.SetVOI(VOI) - cellCore.SetInput(vtkObj) - - cellThres = vtk.vtkThreshold() - cellThres.AllScalarsOn() - cellThres.SetInputConnection(cellCore.GetOutputPort()) - cellThres.ThresholdBetween(limits[0],limits[1]) - cellThres.Update() - return cellThres.GetOutput(), cellCore.GetOutput() - - @staticmethod - def makeUnstructVTKVOIThres(vtkObj,extent,limits): - """Make volume of interest and threshold for rectilinear grid.""" - # Check for the input - cellCore = vtk.vtkExtractUnstructuredGrid() - cellCore.SetExtent(extent) - cellCore.SetInput(vtkObj) - - cellThres = vtk.vtkThreshold() - cellThres.AllScalarsOn() - cellThres.SetInputConnection(cellCore.GetOutputPort()) - cellThres.ThresholdBetween(limits[0],limits[1]) - cellThres.Update() - return cellThres.GetOutput(), cellCore.GetOutput() - - @staticmethod - def makePlaneClipper(vtkObj): - """Makes a plane and clipper """ - plane = vtk.vtkPlane() - clipper = vtk.vtkClipDataSet() - clipper.SetInputConnection(vtkObj.GetProducerPort()) - clipper.SetClipFunction(plane) - clipper.InsideOutOff() - return clipper, plane - - @staticmethod - def makePlaneWidget(vtkObj,iren,plane,actor): - """Make an interactive planeWidget""" - - # Callback function - def movePlane(obj, events): - obj.GetPlane(intPlane) - intActor.VisibilityOn() - - # Associate the line widget with the interactor - planeWidget = vtk.vtkImplicitPlaneWidget() - planeWidget.SetInteractor(iren) - planeWidget.SetPlaceFactor(1.25) - planeWidget.SetInput(vtkObj) - planeWidget.PlaceWidget() - #planeWidget.AddObserver("InteractionEvent", movePlane) - planeWidget.SetScaleEnabled(0) - planeWidget.SetEnabled(1) - planeWidget.SetOutlineTranslation(0) - planeWidget.GetPlaneProperty().SetOpacity(0.1) - return planeWidget - - - @staticmethod - def startRenderWindow(iren): - """ Start a vtk rendering window""" - iren.Initialize() - renwin = iren.GetRenderWindow() - renwin.Render() - iren.Start() - - - # Simple write/read VTK xml model functions. - @staticmethod - def writeVTPFile(fileName,vtkPolyObject): - '''Function to write vtk polydata file (vtp).''' - polyWriter = vtk.vtkXMLPolyDataWriter() - polyWriter.SetInput(vtkPolyObject) - polyWriter.SetFileName(fileName) - polyWriter.Update() - - @staticmethod - def writeVTUFile(fileName,vtkUnstructuredGrid): - '''Function to write vtk unstructured grid (vtu).''' - Writer = vtk.vtkXMLUnstructuredGridWriter() - Writer.SetInput(vtkUnstructuredGrid) - Writer.SetFileName(fileName) - Writer.Update() - - @staticmethod - def writeVTRFile(fileName,vtkRectilinearGrid): - '''Function to write vtk rectilinear grid (vtr).''' - Writer = vtk.vtkXMLRectilinearGridWriter() - Writer.SetInput(vtkRectilinearGrid) - Writer.SetFileName(fileName) - Writer.Update() - - @staticmethod - def writeVTSFile(fileName,vtkStructuredGrid): - '''Function to write vtk structured grid (vts).''' - Writer = vtk.vtkXMLStructuredGridWriter() - Writer.SetInput(vtkStructuredGrid) - Writer.SetFileName(fileName) - Writer.Update() - - @staticmethod - def readVTSFile(fileName): - '''Function to read vtk structured grid (vts) and return a grid object.''' - Reader = vtk.vtkXMLStructuredGridReader() - Reader.SetFileName(fileName) - Reader.Update() - return Reader.GetOutput() - - @staticmethod - def readVTUFile(fileName): - '''Function to read vtk structured grid (vtu) and return a grid object.''' - Reader = vtk.vtkXMLUnstructuredGridReader() - Reader.SetFileName(fileName) - Reader.Update() - return Reader.GetOutput() - - @staticmethod - def readVTRFile(fileName): - '''Function to read vtk structured grid (vtr) and return a grid object.''' - Reader = vtk.vtkXMLRectilinearGridReader() - Reader.SetFileName(fileName) - Reader.Update() - return Reader.GetOutput() - - @staticmethod - def readVTPFile(fileName): - '''Function to read vtk structured grid (vtp) and return a grid object.''' - Reader = vtk.vtkXMLPolyDataReader() - Reader.SetFileName(fileName) - Reader.Update() - return Reader.GetOutput() - diff --git a/SimPEG/visualize/vtk/vtkView.py b/SimPEG/visualize/vtk/vtkView.py deleted file mode 100644 index 3b52b992..00000000 --- a/SimPEG/visualize/vtk/vtkView.py +++ /dev/null @@ -1,350 +0,0 @@ -import numpy as np, matplotlib as mpl -try: - import vtk, vtk.util.numpy_support as npsup - #import SimPEG.visualize.vtk.vtkTools as vtkSP # Always get an error for this import -except Exception, e: - print 'VTK import error. Please ensure you have VTK installed to use this visualization package.' -import SimPEG as simpeg - -class vtkView(object): - """ - Class for storing and view of SimPEG models in VTK (visualization toolkit). - - Inputs: - :param mesh, SimPEG mesh. - :param propdict, dictionary of property models. - Can have these dictionary names: - 'C' - cell model; 'F' - face model; 'E' - edge model; ('V' - vector field : NOT SUPPORTED) - The dictionary values are given as dictionaries with: - {'NameOfThePropertyModel': np.array of the properties}. - The property np.array has to be ordered in compliance with SimPEG standards. - - :: - Example of usages. - - ToDo - - """ - - def __init__(self,mesh,propdict): - """ - """ - - # Setup hidden properties, used for the visualization - self._ren = None - self._iren = None - self._renwin = None - self._core = None - self._viewobj = None - self._plane = None - self._clipper = None - self._widget = None - self._actor = None - self._lut = None - # Set vtk object containers - self._cells = None - self._faces = None - self._edges = None - self._vectors = None # Not implemented - # Set default values - self.name = 'VTK figure of SimPEG model' - - - - # Error check the input mesh - if type(mesh).__name__ != 'TensorMesh': - raise Exception('The input {:s} to vtkView has to be a TensorMesh object'.format(mesh)) - # Set the mesh - self._mesh = mesh - - # Read the property dictionary - self._readPropertyDictionary(propdict) - - - - - # Set/Get properties - @property - def cmap(self): - ''' Colormap to use in vtkView. Colormap is a matplotlib cmap(cm) array, has to be uint8(use flag bytes=True during cmap generation).''' - if getattr(self,'_cmap',None) is None: - # Set default - self._cmap = mpl.cm.hsv(np.arange(0.,1.,0.05),bytes=True) - return self._cmap - @cmap.setter - def cmap(self,value): - if value.min() > 0 or value.max() < 255 or value.shape[1] != 4 or value.dtype != np.uint8: - raise Exception('Input not an allowed array.\n Use matplotlib.cm to generate an array of size [nrColors,4] and dtype = uint8(flag bytes=True).') - self._cmap = value - - @property - def range(self): - ''' Range of the colors in vtkView.''' - if getattr(self,'_range',None) is None: - self._range = np.array(self._getActiveVTKobj().GetArray(self.viewprop.values()[0]).GetRange()) - return self._range - @range.setter - def range(self,value): - if type(value) not in [tuple, list, np.ndarray] or len(value) != 2 or np.array(value).dtype is not np.dtype('float'): - raise Exception('Input not in correct format. \n Has to be a list, tuple or np.arry of 2 floats.') - self._range = np.array(value) - - @property - def extent(self): - ''' Extent of the sub-domain of the model to view''' - if getattr(self,'_extent',None) is None: - self._extent = [0,self._mesh.nCx-1,0,self._mesh.nCy-1,0,self._mesh.nCz-1] - return self._extent - @extent.setter - def extent(self,value): - - import warnings - # Error check - valnp = np.array(value,dtype=int) - if valnp.dtype != int or len(valnp) != 6: - raise Exception('.extent has to be list or nparray of 6 integers.') - # Test the range of the values - loB = np.zeros(3,dtype=int) - upB = np.array(self._mesh.nCv - np.ones(3),dtype=int) - # Test the bounds - change = 0 - # Test for lower bounds, can't be smaller the 0 - tlb = valnp[::2] < loB - if tlb.any(): - valnp[::2][tlb] = loB[tlb] - change = 1 - warnings.warn('Lower bounds smaller then 0') - # Test for lower bounds, can't be larger then upB - tlub = valnp[::2] > upB - if tlub.any(): - valnp[::2][tlub] = upB[tlub] - 1 - change = 1 - warnings.warn('Lower bounds larger then uppermost bounds') - # Test for upper bounds, can't be larger the extent of the mesh - tub = valnp[1::2] > upB - if tub.any(): - valnp[1::2][tub] = upB[tub] - change = 1 - warnings.warn('Upper bounds greater then number of cells') - # Test if lower is smaller the upper - tgt = valnp[::2] > valnp[1::2] - if tgt.any(): - valnp[1::2][tgt] = valnp[::2][tgt] + 1 - change = 1 - warnings.warn('Lower bounds greater the Upper bounds') - # Print a warning - if change: - warnings.warn('Changed given extent from {:s} to {:s}'.format(value,valnp.tolist())) - - # Set extent - self._extent = valnp - - @property - def limits(self): - ''' Lower and upper limits (cutoffs) of the values to view. ''' - return getattr(self,'_limits',None) - @limits.setter - def limits(self,value): - if value is None: - self._limits = None - else: - valnp = np.array(value) - if valnp.dtype != float or len(valnp) != 2: - raise Exception('.limits has to be list or numpy array of 2 floats.') - self._limits = valnp - - - @property - def viewprop(self): - ''' Controls the property that will be viewed.''' - - if getattr(self,'_viewprop',None) is None: - self._viewprop = {'C':0} # Name of the type and Int order of the array or name of the vector. - return self._viewprop - @viewprop.setter - def viewprop(self,value): - if type(value) != dict: - raise Exception('{:s} has to be a python dictionary containing property type and name index. ') - if len(value) > 1: - raise Exception('Too many input items in the viewprop dictionary') - if value.keys()[0] not in ['C','F','E']: - raise Exception('\"{:s}\" is not allowed as a dictionary key. Can be \'C\',\'F\',\'E\'.'.format(propitem[0])) - if not(type(self.viewprop.values()[0]) is int or type(self.viewprop.values()[0]) is str): - raise Exception('The vtkView.viewprop.values()[0] has the wrong format. Has to be integer or a string with the index.') - - - self._viewprop = value - - def _getActiveVTKobj(self): - """ - Finds the active VTK object. - """ - - if self.viewprop.keys()[0] is 'C': - vtkCellData = self._cells.GetCellData() - elif self.viewprop.keys()[0] is 'F': - vtkCellData = self._faces.GetCellData() - elif self.viewprop.keys()[0] is 'E': - vtkCellData = self._edges.GetCellData() - - return vtkCellData - - def _getActiveArrayName(self): - """ - Finds the name of the active array. - """ - actArr = self.viewprop.values()[0] - if type(actArr) is str: - activeName = actArr - elif type(actArr) is int: - activeName = self._getActiveVTKobj().GetArrayName(actArr) - return activeName - - def _readPropertyDictionary(self,propdict): - """ - Reads the property and assigns to the object - """ - import SimPEG.visualize.vtk.vtkTools as vtkSP - - # Test the property dictionary - if type(propdict) != dict: - raise Exception('{:s} has to be a python dictionary containing property models. ') - if len(propdict) > 4: - raise Exception('Too many input items in the property dictionary') - for propitem in propdict.iteritems(): - if propitem[0] in ['C','F','E']: - if propitem[0] == 'C': - self._cells = vtkSP.makeCellVTKObject(self._mesh,propitem[1]) - if propitem[0] == 'F': - self._faces = vtkSP.makeFaceVTKObject(self._mesh,propitem[1]) - if propitem[0] == 'E': - self._edges = vtkSP.makeEdgeVTKObject(self._mesh,propitem[1]) - else: - raise Exception('\"{:s}\" is not allowed as a dictionary key. Can be \'C\',\'F\',\'E\'.'.format(propitem[0])) - - def Show(self): - """ - Open the VTK figure window and show the mesh. - """ - #vtkSP = simpeg.visualize.vtk.vtkTools - import SimPEG.visualize.vtk.vtkTools as vtkSP - - # Make a renderer - self._ren = vtk.vtkRenderer() - # Make renderwindow. Returns the interactor. - self._iren, self._renwin = vtkSP.makeRenderWindow(self._ren) - - - # Set the active scalar. - if type(self.viewprop.values()[0]) == int: - actScalar = self._getActiveVTKobj().GetArrayName(self.viewprop.values()[0]) - elif type(self.viewprop.values()[0]) == str: - actScalar = self.viewprop.values()[0] - else : - raise Exception('The vtkView.viewprop.values()[0] has the wrong format. Has to be interger or a string.') - self._getActiveVTKobj().SetActiveScalars(actScalar) - # Sort out the actor - imageType = self.viewprop.keys()[0] - if imageType == 'C': - if self.limits is None: - self.limits = self._cells.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() - self._vtkobj, self._core = vtkSP.makeRectiVTKVOIThres(self._cells,self.extent,self.limits) - elif imageType == 'F': - if self.limits is None: - self.limits = self._faces.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() - extent = [self._mesh.vectorNx[self.extent[0]], self._mesh.vectorNx[self.extent[1]], self._mesh.vectorNy[self.extent[2]], self._mesh.vectorNy[self.extent[3]], self._mesh.vectorNz[self.extent[4]], self._mesh.vectorNz[self.extent[5]] ] - self._vtkobj, self._core = vtkSP.makeUnstructVTKVOIThres(self._faces,extent,self.limits) - elif imageType == 'E': - if self.limits is None: - self.limits = self._edges.GetCellData().GetArray(self.viewprop.values()[0]).GetRange() - extent = [self._mesh.vectorNx[self.extent[0]], self._mesh.vectorNx[self.extent[1]], self._mesh.vectorNy[self.extent[2]], self._mesh.vectorNy[self.extent[3]], self._mesh.vectorNz[self.extent[4]], self._mesh.vectorNz[self.extent[5]] ] - self._vtkobj, self._core = vtkSP.makeUnstructVTKVOIThres(self._edges,extent,self.limits) - else: - raise Exception("{:s} is not a valid viewprop. Has to be 'C':'F':'E'".format(imageType)) - #self._vtkobj.GetCellData().SetActiveScalars(actScalar) - # Set up the plane, clipper and the user interaction. - global intPlane, intActor - self._clipper, intPlane = vtkSP.makePlaneClipper(self._vtkobj) - intActor = vtkSP.makeVTKLODActor(self._vtkobj,self._clipper) - self._widget = vtkSP.makePlaneWidget(self._vtkobj,self._iren,self._clipper.GetClipFunction(),self._actor) - # Callback function - self._plane = intPlane - self._actor = intActor - def movePlane(obj, events): - global intPlane, intActor - obj.GetPlane(intPlane) - intActor.VisibilityOn() - - self._widget.AddObserver("InteractionEvent",movePlane) - lut = vtk.vtkLookupTable() - lut.SetNumberOfColors(len(self.cmap)) - lut.SetTable(npsup.numpy_to_vtk(self.cmap)) - lut.Build() - self._lut = lut - scalarBar = vtk.vtkScalarBarActor() - scalarBar.SetLookupTable(lut) - scalarBar.SetTitle(self._getActiveArrayName()) - scalarBar.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() - scalarBar.GetPositionCoordinate().SetValue(0.1,0.01) - scalarBar.SetOrientationToHorizontal() - scalarBar.SetWidth(0.8) - scalarBar.SetHeight(0.17) - - self._actor.GetMapper().SetScalarRange(self.range) - self._actor.GetMapper().SetLookupTable(lut) - - # Set renderer options - self._ren.SetBackground(.5,.5,.5) - self._ren.AddActor(self._actor) - self._ren.AddActor2D(scalarBar) - self._renwin.SetSize(450,450) - - # Start the render Window - vtkSP.startRenderWindow(self._iren) - # Close the window when exited - vtkSP.closeRenderWindow(self._iren) - del self._iren, self._renwin - - - -if __name__ == '__main__': - - - #Make a mesh and model - x0 = np.zeros(3) - h1 = np.ones(60)*50 - h2 = np.ones(60)*100 - h3 = np.ones(50)*200 - - mesh = simpeg.mesh.TensorMesh([h1,h2,h3],x0) - - # Make a models that correspond to the cells, faces and edges. - t = np.ones(mesh.nC) - t[10000:50000] = 100 - t[100000:120000] = 100 - t[100000:120000] = 50 - models = {'C':{'Test':np.arange(0,mesh.nC),'Model':t, 'AllOnce':np.ones(mesh.nC)},'F':{'Test':np.arange(0,mesh.nF),'AllOnce':np.ones(mesh.nF)},'E':{'Test':np.arange(0,mesh.nE),'AllOnce':np.ones(mesh.nE)}} - # Make the vtk viewer object. - vtkViewer = simpeg.visualize.vtk.vtkView(mesh,models) - # Set the .viewprop for which model to view - vtkViewer.viewprop = {'F':'Test'} - # Show the image - vtkViewer.Show() - - # Set subset of the mesh to view (remove padding) - vtkViewer.extent = [4,14,0,7,0,3] - vtkViewer.Show() - - # Change viewing property - vtkViewer.viewprop = {'C':'Model'} - # Set the color range - # Reset extent. - vtkViewer.extent = [-1,1000,-1,1000,-1,1000] - vtkViewer.range = [0.,100.] - vtkViewer.Show() - # Change color scale, has to be set to bytes=True. - vtkViewer.cmap = mpl.cm.copper(np.arange(0.,1.,0.01),bytes=True) - vtkViewer.Show() - # Set limits of values to view - vtkViewer.limits = [5.0,100.0] - vtkViewer.Show() \ No newline at end of file From 842a3c367e8c76578980f50c4e87575cf898a091 Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Wed, 12 Feb 2014 19:28:38 -0800 Subject: [PATCH 64/66] Speed up tensor mesh test. --- SimPEG/Tests/test_tensorMesh.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SimPEG/Tests/test_tensorMesh.py b/SimPEG/Tests/test_tensorMesh.py index 3e01181b..45c03399 100644 --- a/SimPEG/Tests/test_tensorMesh.py +++ b/SimPEG/Tests/test_tensorMesh.py @@ -2,7 +2,7 @@ import numpy as np import unittest from SimPEG.Mesh import TensorMesh from TestUtils import OrderTest -from scipy.sparse.linalg import dsolve +from SimPEG import Solver class BasicTensorMeshTests(unittest.TestCase): @@ -58,7 +58,7 @@ class BasicTensorMeshTests(unittest.TestCase): class TestPoissonEqn(OrderTest): name = "Poisson Equation" - meshSizes = [16, 20, 24] + meshSizes = [10, 16, 20] def getError(self): # Create some functions to integrate @@ -75,7 +75,7 @@ class TestPoissonEqn(OrderTest): err = np.linalg.norm((sA - sN), np.inf) else: fA = fun(self.M.gridCC) - fN = dsolve.spsolve(D*G, sol(self.M.gridCC)) + fN = Solver(D*G).solve(sol(self.M.gridCC)) err = np.linalg.norm((fA - fN), np.inf) return err From 9b3e1900920fa9fc391411a3cb47f6745967406f Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 13 Feb 2014 16:13:20 -0800 Subject: [PATCH 65/66] added email notifications to travis --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4fd51fd4..1094912b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,3 +14,10 @@ before_install: install: "pip install -r requirements.txt --use-mirrors" # command to run tests script: nosetests -v + +notifications: + email: + - rowanc1@gmail.com + - sgkang09@gmail.com + - dwfmarchant@gmail.com + - lindseyheagy@gmail.com From 7f9a5075d9697d39c2a4731c1ebb8c7dc5c162cb Mon Sep 17 00:00:00 2001 From: rowanc1 Date: Thu, 13 Feb 2014 16:53:38 -0800 Subject: [PATCH 66/66] added projectFieldsAdjoint --- SimPEG/Data.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/SimPEG/Data.py b/SimPEG/Data.py index 7b0145dc..0290be36 100644 --- a/SimPEG/Data.py +++ b/SimPEG/Data.py @@ -67,10 +67,28 @@ class BaseData(object): .. math:: - d_\\text{pred} = P(u(m)) + d_\\text{pred} = \mathbf{P} u(m) """ return u + + @Utils.count + def projectFieldsAdjoint(self, d): + """ + This function is the adjoint of the projection. + **projectFieldsAdjoint** is used in the + calculation of the sensitivities. + + .. math:: + u = \mathbf{P}^\\top d + + :param numpy.array d: data + :param numpy.array u: fields (ish) + :rtype: fields like object + :return: data + """ + return d + #TODO: def projectFieldDeriv(self, u): Does this need to be made??! @Utils.count