From 05a85018de792c16c8e728f4ab893c715bcd52de Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 21:59:08 -0800 Subject: [PATCH 01/56] Create a Simple and a SparseRegularization class. The SparseRegularization class allows implementation of p-q norms. --- SimPEG/Regularization.py | 210 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 677fba5c..6a65860d 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -282,3 +282,213 @@ class Tikhonov(BaseRegularization): out = mD.T * ( self.W.T * r ) return out + +class Simple(BaseRegularization): + """ + Only for tensor mesh + """ + + smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + + def __init__(self, mesh, mapping=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) + + @property + def Ws(self): + """Regularization matrix Ws""" + if getattr(self,'_Ws', None) is None: + self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + return self._Ws + + @property + def Wx(self): + """Regularization matrix Wx""" + if getattr(self, '_Wx', None) is None: + self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x)**0.5)*self.mesh.unitCellGradx + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + if getattr(self, '_Wy', None) is None: + self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y)**0.5)*self.mesh.unitCellGrady + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + if getattr(self, '_Wz', None) is None: + self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z)**0.5)*self.mesh.unitCellGradz + return self._Wz + + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx,) + if self.mesh.dim > 1: + wlist += (self.Wy,) + if self.mesh.dim > 2: + wlist += (self.Wz,) + self._Wsmooth = sp.vstack(wlist) + return self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W + + @Utils.timeIt + def eval(self, m): + if self.smoothModel == True: + r1 = self.Wsmooth * ( self.mapping * (m) ) + r2 = self.Ws * ( self.mapping * (m - self.mref) ) + return 0.5*(r1.dot(r1)+r2.dot(r2)) + elif self.smoothModel == False: + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) + + + @Utils.timeIt + def evalDeriv(self, m): + """ + + The regularization is: + + .. math:: + + R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} + + So the derivative is straight forward: + + .. math:: + + R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} + + """ + if self.smoothModel == True: + mD1 = self.mapping.deriv(m) + mD2 = self.mapping.deriv(m - self.mref) + r1 = self.Wsmooth * ( self.mapping * (m)) + r2 = self.Ws * ( self.mapping * (m - self.mref) ) + out1 = mD1.T * ( self.Wsmooth.T * r1 ) + out2 = mD2.T * ( self.Ws.T * r2 ) + out = out1+out2 + elif self.smoothModel == False: + mD = self.mapping.deriv(m - self.mref) + r = self.W * ( self.mapping * (m - self.mref) ) + out = mD.T * ( self.W.T * r ) + return out + + +class SparseRegularization(Simple): + + eps = 1e-1 + m = None + gamma = 1. + p = 0. + qx = 2. + qy = 2. + qz = 2. + + def __init__(self, mesh, mapping=None, **kwargs): + Simple.__init__(self, mesh, mapping=mapping, **kwargs) + + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx, self.Wxx) + if self.mesh.dim > 1: + wlist += (self.Wy, self.Wyy) + if self.mesh.dim > 2: + wlist += (self.Wz, self.Wzz) + self._Wsmooth = sp.vstack(wlist) + return self._Wsmooth + + @property + def W(self): + """Full regularization matrix W""" + if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W + + @property + def Ws(self): + """Regularization matrix Ws""" + if getattr(self, 'm', None) is None: + self.Rs = Utils.speye(self.mesh.nC) + + else: + f_m = self.m + self.rs = self.R(f_m , self.p, self.eps) + #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) + self.Rs = Utils.sdiag( self.rs ) + + self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + + return self._Ws + + @property + def Wx(self): + """Regularization matrix Wx""" + + if getattr(self, 'm', None) is None: + self.Rx = Utils.speye(self.mesh.unitCellGradx.shape[0]) + + else: + f_m = self.mesh.unitCellGradx * self.m + self.rx = self.R( f_m , self.qx, self.eps) + self.Rx = Utils.sdiag( self.rx ) + + if getattr(self, '_Wx', None) is None: + self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x*self.gamma)**0.5)*self.Rx*self.mesh.unitCellGradx + return self._Wx + + @property + def Wy(self): + """Regularization matrix Wy""" + + if getattr(self, 'm', None) is None: + self.Ry = Utils.speye(self.mesh.unitCellGrady.shape[0]) + + else: + f_m = self.mesh.unitCellGrady * self.m + self.ry = self.R( f_m , self.qy, self.eps) + self.Ry = Utils.sdiag( self.ry ) + + if getattr(self, '_Wy', None) is None: + self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y*self.gamma)**0.5)*self.Ry*self.mesh.unitCellGrady + return self._Wy + + @property + def Wz(self): + """Regularization matrix Wz""" + + if getattr(self, 'm', None) is None: + self.Rz = Utils.speye(self.mesh.unitCellGradz.shape[0]) + + else: + f_m = self.mesh.unitCellGradz * self.m + self.rz = self.R( f_m , self.qz, self.eps) + self.Rz = Utils.sdiag( self.rz ) + + if getattr(self, '_Wz', None) is None: + self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z*self.gamma)**0.5)*self.Rz*self.mesh.unitCellGradz + return self._Wz + + + def R(self, f_m , p, dec): + + eta = (self.eps**(1-p/2.))**0.5 + r = eta / (f_m**2.+self.eps**2.)**((1-p/2.)/2.) + + return r From c10777a245510e95329dd020f6567ce26aa60f41 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 22:00:12 -0800 Subject: [PATCH 02/56] Addition of unitCellGrad. Possibly rename to cellGradStencil? --- SimPEG/Mesh/DiffOperators.py | 50 ++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 00bf0259..22b87edd 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -565,6 +565,56 @@ class DiffOperators(object): return Pbc, Pin, Pout + def unitCellGradx(): + doc = """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGradx', None) is None: + + n = self.vnC + gx = ddx(n[0]-1) + gx_square = sp.vstack((gx,gx[-1,:]*-1), format="csr") + + self._unitCellGradx = kron3(speye(n[2]), speye(n[1]), gx_square) + + return self._unitCellGradx + return locals() + unitCellGradx = property(**unitCellGradx()) + + def unitCellGrady(): + doc = """Cell centered Gradient in they dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGrady', None) is None: + + n = self.vnC + gy = ddx(n[1]-1) + gy_square = sp.vstack((gy,gy[-1,:]*-1), format="csr") + + self._unitCellGrady = kron3(speye(n[2]), gy_square, speye(n[0])) + + return self._unitCellGrady + return locals() + unitCellGrady = property(**unitCellGrady()) + + def unitCellGradz(): + doc = """Cell centered Gradient in they dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + def fget(self): + if self.dim < 3: return None + if getattr(self, '_unitCellGradz', None) is None: + + n = self.vnC + gz = ddx(n[2]-1) + gz_square = sp.vstack((gz,gz[-1,:]*-1), format="csr") + + self._unitCellGradz = kron3( gz_square , speye(n[1]), speye(n[0])) + + return self._unitCellGradz + return locals() + unitCellGradz = property(**unitCellGradz()) # --------------- Averaging --------------------- From 1c2fecf3a24e5a90918451fdd5a0ec3f013bff62 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Tue, 16 Feb 2016 22:07:33 -0800 Subject: [PATCH 03/56] Add the IRLS Directive. --- SimPEG/Directives.py | 50 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 2ed27c20..476c5916 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -271,7 +271,6 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - # class UpdateReferenceModel(Parameter): # mref0 = None @@ -283,3 +282,52 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # mref = self.mref0 # self.m_prev = self.invProb.m_current # return mref + +class update_IRLS(InversionDirective): + + m = None + eps_min = None + factor = None + gamma = None + phi_m_last = None + + def initialize(self): + + # Scale the regularization for changes in norm + if getattr(self, 'phi_m_last', None) is not None: + self.reg.gamma = 1. + phim_new = self.reg.eval(self.invProb.curModel) + self.gamma = self.phi_m_last / phim_new + + self.reg.gamma = self.gamma + + def endIter(self): + # Cool the threshold parameter + if getattr(self, 'factor', None) is not None: + eps = self.reg.eps / self.factor + + if getattr(self, 'eps_min', None) is not None: + self.reg.eps = np.max([self.eps_min,eps]) + else: + self.reg.eps = eps + + + # Update the model used for the IRLS weights + if getattr(self, 'm', None) is None: + self.reg.m = self.invProb.curModel + + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.prob.mesh.nC))**2. + PC = Utils.sdiag(diagA**-1.) + + self.opt.approxHinv = PC + + phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + +#============================================================================== +# import pylab as plt +# plt.figure() +# ax = plt.subplot(221) +# self.prob.mesh.plotSlice(self.invProb.curModel, ax = ax, normal = 'Z', ind=-5, clim = (0, 0.005)) +#============================================================================== From e4a3e0a16d3e07b9a2217fd30f0fc5274a8d9d8a Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 19 Feb 2016 16:23:26 -0800 Subject: [PATCH 04/56] break out the Pac, Pafx, ... and make part of base regularization --- SimPEG/Regularization.py | 121 ++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6a65860d..0a6f2622 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -55,8 +55,47 @@ class BaseRegularization(object): @property def W(self): """Full regularization weighting matrix W.""" - return sp.identity(self.mapping.nP) + return self._Pac.T * sp.identity(self.mesh.nC) * self. # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + @property + def _Pac(self): + if getattr(self, '__Pac', None) is None: + if self.indActive is None: + self.__Pac = Utils.speye(self.mesh.nC) + else: + self.__Pac = Utils.speye(self.mesh.nC)[:,self.indActive] + return self.__Pac + + @property + def _Pafx(self): + if getattr(self, '__Pafx', None) is None: + if self.indActive is None: + self.__Pafx = Utils.speye(self.mesh.nFx) + else: + indActive_Fx = (self.mesh.aveFx2CC.T * self.indActive) == 1 + self.__Pafx = Utils.speye(self.mesh.nFx)[:,indActive_Fx] + return self.__Pafx + + @property + def _Pafy(self): + if getattr(self, '__Pafy', None) is None: + if self.indActive is None: + self.__Pafy = Utils.speye(self.mesh.nFy) + else: + indActive_Fy = (self.mesh.aveFy2CC.T * self.indActive) == 1 + self.__Pafy = Utils.speye(self.mesh.nFy)[:,indActive_Fy] + return self.__Pafy + + @property + def _Pafz(self): + if getattr(self, '__Pafz', None) is None: + if self.indActive is None: + self.__Pafz = Utils.speye(self.mesh.nFz) + else: + indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 + self.__Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] + return self.__Pafz + @Utils.timeIt def eval(self, m): @@ -133,10 +172,8 @@ class Tikhonov(BaseRegularization): def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Ws = Pac.T * self._Ws * Pac + Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + self._Ws = self._Pac.T * Ws * self._Pac return self._Ws @property @@ -144,14 +181,8 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.mesh.aveF2CC[:,:self.mesh.nFx].T*self.mesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx - - if self.indActive is not None: - indActive_Fx = (self.mesh.aveFx2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafx = Utils.speye(self.mesh.nFx)[:,indActive_Fx] - self._Wx = Pafx.T*self._Wx*Pac - + Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx + self._Wx = self._Pafx.T*Wx*self.self._Pac return self._Wx @property @@ -159,14 +190,8 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: Ave_y_vol = self.mesh.aveF2CC[:,self.mesh.nFx:np.sum(self.mesh.vnF[:2])].T*self.mesh.vol - self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady - - if self.indActive is not None: - indActive_Fy = (self.mesh.aveFy2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafy = Utils.speye(self.mesh.nFy)[:,indActive_Fy] - self._Wy = Pafy.T*self._Wy*Pac - + Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady + self._Wy = self._Pafy.T*Wy*self._Pac return self._Wy @property @@ -174,50 +199,32 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: Ave_z_vol = self.mesh.aveF2CC[:,np.sum(self.mesh.vnF[:2]):].T*self.mesh.vol - self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz - - if self.indActive is not None: - indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] - self._Wz = Pafz.T*self._Wz*Pac - + Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz + self._Wz = self._Pafz.T*Wz*self._Pac return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - self._Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wxx = Pac.T*self._Wxx*Pac - + Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx + self._Wxx = self._Pac.T*Wxx*self._Pac return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - self._Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wyy = Pac.T*self._Wyy*Pac - + Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady + self._Wyy = self._Pac.T*self._Wyy*self._Pac return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - self._Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz - - if self.indActive is not None: - Pac = Utils.speye(self.mesh.nC)[:,self.indActive] - self._Wzz = Pac.T*self._Wzz*Pac - + Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz + self._Wzz = self._Pac.T*Wzz*self._Pac return self._Wzz @property @@ -346,14 +353,26 @@ class Simple(BaseRegularization): return self._W @Utils.timeIt - def eval(self, m): + def _evalSmall(self, m): + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) + + @Utils.timeIt + def _evalSmooth(self, m): if self.smoothModel == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) + else: + return None + + @Utils.timeIt + def eval(self, m): + phim = self._evalSmall(m) + if self.smoothModel is True: + phim += self._evalSmooth(m) + return phim + @Utils.timeIt From b5f4d8e9997456b4bb6ef2ce84274d59bb8f49a6 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 19 Feb 2016 17:43:50 -0800 Subject: [PATCH 05/56] typo in Regularization.py --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 0a6f2622..d6780c45 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -55,7 +55,7 @@ class BaseRegularization(object): @property def W(self): """Full regularization weighting matrix W.""" - return self._Pac.T * sp.identity(self.mesh.nC) * self. # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + return self._Pac.T * sp.identity(self.mesh.nC) * self._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @property def _Pac(self): From 4e871a43a9f7e756e47ca4e7ba5e6d9b558aea01 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 24 Feb 2016 18:03:42 -0800 Subject: [PATCH 06/56] prototype of defining regularization mesh within Regularization.py for constructing operators for regularization that are not true differential operators --- SimPEG/Mesh/DiffOperators.py | 129 +++++------ SimPEG/Regularization.py | 344 +++++++++++++++++++----------- tests/base/test_regularization.py | 121 ++++++----- 3 files changed, 344 insertions(+), 250 deletions(-) diff --git a/SimPEG/Mesh/DiffOperators.py b/SimPEG/Mesh/DiffOperators.py index 22b87edd..10ed2268 100644 --- a/SimPEG/Mesh/DiffOperators.py +++ b/SimPEG/Mesh/DiffOperators.py @@ -307,24 +307,28 @@ class DiffOperators(object): return BC _cellGradBC_list = 'neumann' + def _cellGradStencil(self): + BC = self.setCellGradBC(self._cellGradBC_list) + n = self.vnC + if(self.dim == 1): + G = ddxCellGrad(n[0], BC[0]) + elif(self.dim == 2): + G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0])) + G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0])) + G = sp.vstack((G1, G2), format="csr") + elif(self.dim == 3): + G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0])) + G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0])) + G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0])) + G = sp.vstack((G1, G2, G3), format="csr") + return G + def cellGrad(): doc = "The cell centered Gradient, takes you to cell faces." def fget(self): if(self._cellGrad is None): - BC = self.setCellGradBC(self._cellGradBC_list) - n = self.vnC - if(self.dim == 1): - G = ddxCellGrad(n[0], BC[0]) - elif(self.dim == 2): - G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0])) - G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0])) - G = sp.vstack((G1, G2), format="csr") - elif(self.dim == 3): - G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0])) - G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0])) - G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0])) - G = sp.vstack((G1, G2, G3), format="csr") + G = self._cellGradStencil() # Compute areas of cell faces & volumes S = self.area V = self.aveCC2F*self.vol # Average volume between adjacent cells @@ -361,19 +365,24 @@ class DiffOperators(object): _cellGradBC = None cellGradBC = property(**cellGradBC()) + def _cellGradxStencil(self): + BC = ['neumann', 'neumann'] + n = self.vnC + if(self.dim == 1): + G1 = ddxCellGrad(n[0], BC) + elif(self.dim == 2): + G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC)) + elif(self.dim == 3): + G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC)) + return G1 + + def cellGradx(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if getattr(self, '_cellGradx', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - if(self.dim == 1): - G1 = ddxCellGrad(n[0], BC) - elif(self.dim == 2): - G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC)) - elif(self.dim == 3): - G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC)) + G1 = self._cellGradxStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fx', 'V') @@ -382,17 +391,22 @@ class DiffOperators(object): return locals() cellGradx = property(**cellGradx()) + def _cellGradyStencil(self): + if self.dim < 2: return None + BC = ['neumann', 'neumann'] + n = self.vnC + if(self.dim == 2): + G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0])) + elif(self.dim == 3): + G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0])) + return G2 + def cellGrady(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if self.dim < 2: return None if getattr(self, '_cellGrady', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - if(self.dim == 2): - G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0])) - elif(self.dim == 3): - G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0])) + G2 = self._cellGradyStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fy', 'V') @@ -401,14 +415,19 @@ class DiffOperators(object): return locals() cellGrady = property(**cellGrady()) + def _cellGradzStencil(self): + if self.dim < 3: return None + BC = ['neumann', 'neumann'] + n = self.vnC + G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0])) + return G3 + def cellGradz(): doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions." def fget(self): if self.dim < 3: return None if getattr(self, '_cellGradz', None) is None: - BC = ['neumann', 'neumann'] - n = self.vnC - G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0])) + G3 = self._cellGradzStencil() # Compute areas of cell faces & volumes V = self.aveCC2F*self.vol L = self.r(self.area/V, 'F','Fz', 'V') @@ -565,56 +584,6 @@ class DiffOperators(object): return Pbc, Pin, Pout - def unitCellGradx(): - doc = """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGradx', None) is None: - - n = self.vnC - gx = ddx(n[0]-1) - gx_square = sp.vstack((gx,gx[-1,:]*-1), format="csr") - - self._unitCellGradx = kron3(speye(n[2]), speye(n[1]), gx_square) - - return self._unitCellGradx - return locals() - unitCellGradx = property(**unitCellGradx()) - - def unitCellGrady(): - doc = """Cell centered Gradient in they dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGrady', None) is None: - - n = self.vnC - gy = ddx(n[1]-1) - gy_square = sp.vstack((gy,gy[-1,:]*-1), format="csr") - - self._unitCellGrady = kron3(speye(n[2]), gy_square, speye(n[0])) - - return self._unitCellGrady - return locals() - unitCellGrady = property(**unitCellGrady()) - - def unitCellGradz(): - doc = """Cell centered Gradient in they dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - def fget(self): - if self.dim < 3: return None - if getattr(self, '_unitCellGradz', None) is None: - - n = self.vnC - gz = ddx(n[2]-1) - gz_square = sp.vstack((gz,gz[-1,:]*-1), format="csr") - - self._unitCellGradz = kron3( gz_square , speye(n[1]), speye(n[0])) - - return self._unitCellGradz - return locals() - unitCellGradz = property(**unitCellGradz()) # --------------- Averaging --------------------- diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index d6780c45..31013dc5 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,61 +1,35 @@ import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp -class BaseRegularization(object): - """ - **Base Regularization Class** +class RegularizationMesh(object): - This is used to regularize the model space:: - - reg = Regularization(mesh) - - """ - - __metaclass__ = Utils.SimPEGMetaClass - - counter = None - - mapPair = Maps.IdentityMap #: A SimPEG.Map Class - - mapping = None #: A SimPEG.Map instance. - mesh = None #: A SimPEG.Mesh instance. - mref = None #: Reference model. - - def __init__(self, mesh, mapping=None, indActive=None, **kwargs): - Utils.setKwargs(self, **kwargs) + def __init__(self, mesh, indActive=None): self.mesh = mesh - assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." - self.mapping = mapping or self.mapPair(mesh) - self.mapping._assertMatchesPair(self.mapPair) self.indActive = indActive @property - def parent(self): - """This is the parent of the regularization.""" - return getattr(self,'_parent',None) - @parent.setter - def parent(self, p): - if getattr(self,'_parent',None) is not None: - print 'Regularization has switched to a new parent!' - self._parent = p + def vol(self): + if getattr(self, '_vol', None) is None: + self._vol = self._Pac.T * self.mesh.vol + return self._vol @property - def inv(self): return self.parent.inv - @property - def invProb(self): return self.parent - @property - def reg(self): return self - @property - def opt(self): return self.parent.opt - @property - def prob(self): return self.parent.prob - @property - def survey(self): return self.parent.survey - + def nC(self): + if getattr(self, '_nC', None) is None: + if self.indActive is None: + self._nC = self.mesh.nC + else: + if self.indActive.dtype == 'bool': + self._nC = sum(self.indActive) + else: + self._nC = len(self.indActive) # you shouldn't pass a vector of int 0, 1 's + return self._nC @property - def W(self): - """Full regularization weighting matrix W.""" - return self._Pac.T * sp.identity(self.mesh.nC) * self._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? + def dim(self): + if getattr(self, '_dim', None) is None: + self._dim = self.mesh.dim + return self._dim + @property def _Pac(self): @@ -95,7 +69,170 @@ class BaseRegularization(object): indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) == 1 self.__Pafz = Utils.speye(self.mesh.nFz)[:,indActive_Fz] return self.__Pafz + + @property + def aveFx2CC(self): + if getattr(self, '_aveFx2CC', None) is None: + self._aveFx2CC = self._Pac.T * self.mesh.aveFx2CC * self._Pafx + return self._aveFx2CC + + @property + def aveCC2Fx(self): + if getattr(self, '_aveCC2Fx', None) is None: + self._aveCC2Fx = Utils.sdiag(1./(self.aveFx2CC.T).sum(1)) * self.aveFx2CC.T + return self._aveCC2Fx + + @property + def aveFy2CC(self): + if getattr(self, '_aveFy2CC', None) is None: + self._aveFy2CC = self._Pac.T * self.mesh.aveFy2CC * self._Pafy + return self._aveFy2CC + + @property + def aveCC2Fy(self): + if getattr(self, '_aveCC2Fy', None) is None: + self._aveCC2Fy = Utils.sdiag(1./(self.aveFy2CC.T).sum(1)) * self.aveFy2CC.T + return self._aveCC2Fy + + @property + def aveFz2CC(self): + if getattr(self, '_aveFz2CC', None) is None: + self._aveFz2CC = self._Pac.T * self.mesh.aveFz2CC * self._Pafz + return self._aveFz2CC + + @property + def aveCC2Fz(self): + if getattr(self, '_aveCC2Fz', None) is None: + self._aveCC2Fz = Utils.sdiag(1./(self.aveFz2CC.T).sum(1)) * self.aveFz2CC.T + return self._aveCC2Fz + + @property + def cellGradx(self): + if getattr(self, '_cellGradx', None) is None: + self._cellGradx = self._Pafx.T * self.mesh.cellGradx * self._Pac + return self._cellGradx + + @property + def cellGrady(self): + if getattr(self, '_cellGrady', None) is None: + self._cellGrady = self._Pafy.T * self.mesh.cellGrady * self._Pac + return self._cellGrady + + @property + def cellGradz(self): + if getattr(self, '_cellGradz', None) is None: + self._cellGradz = self._Pafz.T * self.mesh.cellGradz * self._Pac + return self._cellGradz + @property + def faceDivx(self): + if getattr(self, '_faceDivx', None) is None: + self._faceDivx = self._Pac.T * self.mesh.faceDivx * self._Pafx + return self._faceDivx + + @property + def faceDivy(self): + if getattr(self, '_faceDivy', None) is None: + self._faceDivy = self._Pac.T * self.mesh.faceDivy * self._Pafy + return self._faceDivy + + @property + def faceDivz(self): + if getattr(self, '_faceDivz', None) is None: + self._faceDivz = self._Pac.T * self.mesh.faceDivz * self._Pafz + return self._faceDivz + + @property + def cellGradxStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + # if self.dim < 3: return None + if getattr(self, '_cellGradxStencil', None) is None: + + self._cellGradxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac + return self._cellGradxStencil + + @property + def cellGradyStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + if self.dim < 2: return None + if getattr(self, '_cellGradyStencil', None) is None: + + self._cellGradyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac + return self._cellGradyStencil + + @property + def cellGradzStencil(self): + """Cell centered Gradient in the x dimension used for + regularization. The gradient operator is square (nC-by-nC)""" + + if self.dim < 3: return None + if getattr(self, '_cellGradzStencil', None) is None: + + self._cellGradzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac + return self._cellGradzStencil + + +class BaseRegularization(object): + """ + **Base Regularization Class** + + This is used to regularize the model space:: + + reg = Regularization(mesh) + + """ + + __metaclass__ = Utils.SimPEGMetaClass + + counter = None + + mapPair = Maps.IdentityMap #: A SimPEG.Map Class + + mapping = None #: A SimPEG.Map instance. + mesh = None #: A SimPEG.Mesh instance. + mref = None #: Reference model. + + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + Utils.setKwargs(self, **kwargs) + assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." + self.regmesh = RegularizationMesh(mesh,indActive) + self.mapping = mapping or self.mapPair(mesh) + self.mapping._assertMatchesPair(self.mapPair) + self.indActive = indActive + + @property + def parent(self): + """This is the parent of the regularization.""" + return getattr(self,'_parent',None) + @parent.setter + def parent(self, p): + if getattr(self,'_parent',None) is not None: + print 'Regularization has switched to a new parent!' + self._parent = p + + @property + def inv(self): return self.parent.inv + @property + def invProb(self): return self.parent + @property + def reg(self): return self + @property + def opt(self): return self.parent.opt + @property + def prob(self): return self.parent.prob + @property + def survey(self): return self.parent.survey + + + @property + def W(self): + """Full regularization weighting matrix W.""" + return sp.identity(self.regmesh.nC) + # self.regmesh._Pac.T * sp.identity(self.regmesh.nC) * self.regmesh._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @Utils.timeIt def eval(self, m): @@ -151,7 +288,6 @@ class BaseRegularization(object): return mD.T * ( self.W.T * ( self.W * ( mD * v) ) ) - class Tikhonov(BaseRegularization): """ """ @@ -165,66 +301,58 @@ class Tikhonov(BaseRegularization): alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") def __init__(self, mesh, mapping=None, indActive = None, **kwargs): - BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) - self.indActive = indActive + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) - self._Ws = self._Pac.T * Ws * self._Pac + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - Ave_x_vol = self.mesh.aveF2CC[:,:self.mesh.nFx].T*self.mesh.vol - Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.mesh.cellGradx - self._Wx = self._Pafx.T*Wx*self.self._Pac + Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellGradx return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - Ave_y_vol = self.mesh.aveF2CC[:,self.mesh.nFx:np.sum(self.mesh.vnF[:2])].T*self.mesh.vol - Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.mesh.cellGrady - self._Wy = self._Pafy.T*Wy*self._Pac + Ave_y_vol = self.regmesh.aveCC2Fy * self.regmesh.vol + self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellGrady return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - Ave_z_vol = self.mesh.aveF2CC[:,np.sum(self.mesh.vnF[:2]):].T*self.mesh.vol - Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.mesh.cellGradz - self._Wz = self._Pafz.T*Wz*self._Pac + Ave_z_vol = self.regmesh.aveCC2Fz * self.regmesh.vol + self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellGradz return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - Wxx = Utils.sdiag((self.mesh.vol*self.alpha_xx)**0.5)*self.mesh.faceDivx*self.mesh.cellGradx - self._Wxx = self._Pac.T*Wxx*self._Pac + self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDivx*self.regmesh.cellGradx return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - Wyy = Utils.sdiag((self.mesh.vol*self.alpha_yy)**0.5)*self.mesh.faceDivy*self.mesh.cellGrady - self._Wyy = self._Pac.T*self._Wyy*self._Pac + self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDivy*self.regmesh.cellGrady return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - Wzz = Utils.sdiag((self.mesh.vol*self.alpha_zz)**0.5)*self.mesh.faceDivz*self.mesh.cellGradz - self._Wzz = self._Pac.T*Wzz*self._Pac + self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDivz*self.regmesh.cellGradz return self._Wzz @property @@ -232,9 +360,9 @@ class Tikhonov(BaseRegularization): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: wlist = (self.Wx, self.Wxx) - if self.mesh.dim > 1: + if self.regmesh.dim > 1: wlist += (self.Wy, self.Wyy) - if self.mesh.dim > 2: + if self.regmesh.dim > 2: wlist += (self.Wz, self.Wzz) self._Wsmooth = sp.vstack(wlist) return self._Wsmooth @@ -301,35 +429,35 @@ class Simple(BaseRegularization): alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - def __init__(self, mesh, mapping=None, **kwargs): - BaseRegularization.__init__(self, mesh, mapping=mapping, **kwargs) + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s)**0.5) + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x)**0.5)*self.mesh.unitCellGradx + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellGradxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y)**0.5)*self.mesh.unitCellGrady + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellGradyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z)**0.5)*self.mesh.unitCellGradz + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellGradzStencil return self._Wz @property @@ -337,9 +465,9 @@ class Simple(BaseRegularization): """Full smoothness regularization matrix W""" if getattr(self, '_Wsmooth', None) is None: wlist = (self.Wx,) - if self.mesh.dim > 1: + if self.regmesh.dim > 1: wlist += (self.Wy,) - if self.mesh.dim > 2: + if self.regmesh.dim > 2: wlist += (self.Wz,) self._Wsmooth = sp.vstack(wlist) return self._Wsmooth @@ -352,25 +480,16 @@ class Simple(BaseRegularization): self._W = sp.vstack(wlist) return self._W - @Utils.timeIt - def _evalSmall(self, m): - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) @Utils.timeIt - def _evalSmooth(self, m): + def eval(self, m): if self.smoothModel == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - else: - return None - - @Utils.timeIt - def eval(self, m): - phim = self._evalSmall(m) - if self.smoothModel is True: - phim += self._evalSmooth(m) + elif self.smoothModel == False: + r = self.W * ( self.mapping * (m - self.mref) ) + return 0.5*r.dot(r) return phim @@ -417,34 +536,15 @@ class SparseRegularization(Simple): qy = 2. qz = 2. - def __init__(self, mesh, mapping=None, **kwargs): - Simple.__init__(self, mesh, mapping=mapping, **kwargs) + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): + Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - @property - def Wsmooth(self): - """Full smoothness regularization matrix W""" - if getattr(self, '_Wsmooth', None) is None: - wlist = (self.Wx, self.Wxx) - if self.mesh.dim > 1: - wlist += (self.Wy, self.Wyy) - if self.mesh.dim > 2: - wlist += (self.Wz, self.Wzz) - self._Wsmooth = sp.vstack(wlist) - return self._Wsmooth - - @property - def W(self): - """Full regularization matrix W""" - if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) - self._W = sp.vstack(wlist) - return self._W @property def Ws(self): """Regularization matrix Ws""" if getattr(self, 'm', None) is None: - self.Rs = Utils.speye(self.mesh.nC) + self.Rs = Utils.speye(self.regmesh.nC) else: f_m = self.m @@ -452,7 +552,7 @@ class SparseRegularization(Simple): #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - self._Ws = Utils.sdiag((self.mesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs return self._Ws @@ -461,15 +561,15 @@ class SparseRegularization(Simple): """Regularization matrix Wx""" if getattr(self, 'm', None) is None: - self.Rx = Utils.speye(self.mesh.unitCellGradx.shape[0]) + self.Rx = Utils.speye(self.regmesh.cellGradxStencil.shape[0]) else: - f_m = self.mesh.unitCellGradx * self.m + f_m = self.regmesh.cellGradxStencil * self.m self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.mesh.vol*self.alpha_x*self.gamma)**0.5)*self.Rx*self.mesh.unitCellGradx + self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellGradxStencil return self._Wx @property @@ -477,15 +577,15 @@ class SparseRegularization(Simple): """Regularization matrix Wy""" if getattr(self, 'm', None) is None: - self.Ry = Utils.speye(self.mesh.unitCellGrady.shape[0]) + self.Ry = Utils.speye(self.regmesh.cellGradyStencil.shape[0]) else: - f_m = self.mesh.unitCellGrady * self.m + f_m = self.regmesh.cellGradyStencil * self.m self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.mesh.vol*self.alpha_y*self.gamma)**0.5)*self.Ry*self.mesh.unitCellGrady + self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellGradyStencil return self._Wy @property @@ -493,15 +593,15 @@ class SparseRegularization(Simple): """Regularization matrix Wz""" if getattr(self, 'm', None) is None: - self.Rz = Utils.speye(self.mesh.unitCellGradz.shape[0]) + self.Rz = Utils.speye(self.regmesh.cellGradzStencil.shape[0]) else: - f_m = self.mesh.unitCellGradz * self.m + f_m = self.regmesh.cellGradzStencil * self.m self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.mesh.vol*self.alpha_z*self.gamma)**0.5)*self.Rz*self.mesh.unitCellGradz + self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellGradzStencil return self._Wz diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 050c46ac..614d3158 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -5,6 +5,8 @@ from scipy.sparse.linalg import dsolve import inspect TOL = 1e-20 +testReg = True +testRegMesh = True class RegularizationTests(unittest.TestCase): @@ -16,69 +18,92 @@ class RegularizationTests(unittest.TestCase): mesh3 = Mesh.TensorMesh([hx, hy, hz]) self.meshlist = [mesh1,mesh2, mesh3] - def test_regularization(self): - for R in dir(Regularization): - r = getattr(Regularization, R) - if not inspect.isclass(r): continue - if not issubclass(r, Regularization.BaseRegularization): - continue + if testReg: + def test_regularization(self): + for R in dir(Regularization): + r = getattr(Regularization, R) + if not inspect.isclass(r): continue + if not issubclass(r, Regularization.BaseRegularization): + continue - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing %iD'%mesh.dim + print 'Testing %iD'%mesh.dim - mapping = r.mapPair(mesh) - reg = r(mesh, mapping=mapping) - m = np.random.rand(mapping.nP) - reg.mref = np.ones_like(m)*np.mean(m) + mapping = r.mapPair(mesh) + reg = r(mesh, mapping=mapping) + m = np.random.rand(mapping.nP) + reg.mref = np.ones_like(m)*np.mean(m) - print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) - passed = reg.eval(reg.mref) < TOL - self.assertTrue(passed) + print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) + passed = reg.eval(reg.mref) < TOL + self.assertTrue(passed) - print 'Check:', R - passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check:', R + passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) + self.assertTrue(passed) - print 'Check 2 Deriv:', R - passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check 2 Deriv:', R + passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) + self.assertTrue(passed) - def test_regularization_ActiveCells(self): - for R in dir(Regularization): - r = getattr(Regularization, R) - if not inspect.isclass(r): continue - if not issubclass(r, Regularization.BaseRegularization): - continue + def test_regularization_ActiveCells(self): + for R in dir(Regularization): + r = getattr(Regularization, R) + if not inspect.isclass(r): continue + if not issubclass(r, Regularization.BaseRegularization): + continue - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing Active Cells %iD'%(mesh.dim) + print 'Testing Active Cells %iD'%(mesh.dim) - if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) - elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) - elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) + mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) - reg = r(mesh, mapping=mapping, indActive=indAct) - m = np.random.rand(mesh.nC)[indAct] - reg.mref = np.ones_like(m)*np.mean(m) + reg = r(mesh, mapping=mapping, indActive=indAct) + m = np.random.rand(mesh.nC)[indAct] + reg.mref = np.ones_like(m)*np.mean(m) - print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) - passed = reg.eval(reg.mref) < TOL - self.assertTrue(passed) + print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) + passed = reg.eval(reg.mref) < TOL + self.assertTrue(passed) - print 'Check:', R - passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check:', R + passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) + self.assertTrue(passed) - print 'Check 2 Deriv:', R - passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) - self.assertTrue(passed) + print 'Check 2 Deriv:', R + passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) + self.assertTrue(passed) + + if testRegMesh: + def test_regularizationMesh(self): + + for i, mesh in enumerate(self.meshlist): + + print 'Testing %iD'%mesh.dim + + # mapping = r.mapPair(mesh) + # reg = r(mesh, mapping=mapping) + # m = np.random.rand(mapping.nP) + + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + + regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) + + assert (regmesh.vol == mesh.vol[indAct]).all() if __name__ == '__main__': From e3af1fd94e9828caa57a931074fa01a91a3ebf1b Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 24 Feb 2016 20:28:09 -0800 Subject: [PATCH 07/56] convert indActive to a bool if an integer list is provided --- SimPEG/Regularization.py | 10 ++++++---- tests/base/test_regularization.py | 15 ++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 31013dc5..d0fc21b1 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -4,6 +4,7 @@ class RegularizationMesh(object): def __init__(self, mesh, indActive=None): self.mesh = mesh + assert indActive is None or indActive.dtype == 'bool', 'indActive needs to be None or a bool' self.indActive = indActive @property @@ -18,10 +19,7 @@ class RegularizationMesh(object): if self.indActive is None: self._nC = self.mesh.nC else: - if self.indActive.dtype == 'bool': - self._nC = sum(self.indActive) - else: - self._nC = len(self.indActive) # you shouldn't pass a vector of int 0, 1 's + self._nC = sum(self.indActive) return self._nC @property @@ -199,6 +197,10 @@ class BaseRegularization(object): def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Utils.setKwargs(self, **kwargs) assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object." + if indActive is not None and indActive.dtype != 'bool': + tmp = indActive + indActive = np.zeros(mesh.nC, dtype=bool) + indActive[tmp] = True self.regmesh = RegularizationMesh(mesh,indActive) self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 614d3158..52cef349 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -59,17 +59,18 @@ class RegularizationTests(unittest.TestCase): print 'Testing Active Cells %iD'%(mesh.dim) if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) + indActive = Utils.mkvc(mesh.gridCC <= 0.8) elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size) + mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size) - reg = r(mesh, mapping=mapping, indActive=indAct) - m = np.random.rand(mesh.nC)[indAct] - reg.mref = np.ones_like(m)*np.mean(m) + for indAct in [indActive, indActive.nonzero()[0]]: # test both bool and integers + reg = r(mesh, mapping=mapping, indActive=indAct) + m = np.random.rand(mesh.nC)[indAct] + reg.mref = np.ones_like(m)*np.mean(m) print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) passed = reg.eval(reg.mref) < TOL From 63bf8b9e4d6d16b7d3f3d9271246f86b337df626 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 24 Feb 2016 20:59:51 -0800 Subject: [PATCH 08/56] Add linear survey --- SimPEG/Survey.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index 47a88ae2..cc877c69 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -375,3 +375,11 @@ class BaseSurvey(object): self.dobs = self.dtrue+noise self.std = self.dobs*0 + std return self.dobs + +class LinearSurvey(BaseSurvey): + def projectFields(self, u): + return u + + @property + def nD(self): + return self.prob.G.shape[0] \ No newline at end of file From 6c33455d15ee6d937029ecb7b7ccc3306f09b0c4 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 25 Feb 2016 08:56:18 -0800 Subject: [PATCH 09/56] update Directive for sparse norm --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 476c5916..9ba38e4e 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -317,7 +317,7 @@ class update_IRLS(InversionDirective): self.reg.m = self.invProb.curModel # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.prob.mesh.nC))**2. + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC From 5e5c7ba0fb408645eb5c2fa85340b3af75f01098 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 1 Mar 2016 17:31:37 -0800 Subject: [PATCH 10/56] docs for regmesh, cellGrad--> cellDiff, faceDiv--> faceDiff for regmesh --- SimPEG/Regularization.py | 238 ++++++++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 64 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index d0fc21b1..acd6c68d 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -1,6 +1,16 @@ import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp class RegularizationMesh(object): + """ + **Regularization Mesh** + + This contains the operators used in the regularization. Note that these + are not necessarily true differential operators, but are constructed from + a SimPEG Mesh. + + :param Mesh mesh: problem mesh + :param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells + """ def __init__(self, mesh, indActive=None): self.mesh = mesh @@ -9,12 +19,22 @@ class RegularizationMesh(object): @property def vol(self): + """ + reduced volume vector + :rtype: numpy.array + :return: reduced cell volume + """ if getattr(self, '_vol', None) is None: self._vol = self._Pac.T * self.mesh.vol return self._vol @property def nC(self): + """ + reduced number of cells + :rtype: int + :return: number of cells being regularized + """ if getattr(self, '_nC', None) is None: if self.indActive is None: self._nC = self.mesh.nC @@ -24,6 +44,11 @@ class RegularizationMesh(object): @property def dim(self): + """ + dimension of regularization mesh (1D, 2D, 3D) + :rtype: int + :return: dimension + """ if getattr(self, '_dim', None) is None: self._dim = self.mesh.dim return self._dim @@ -31,6 +56,11 @@ class RegularizationMesh(object): @property def _Pac(self): + """ + projection matrix that takes from the reduced space of active cells to full modelling space (ie. nC x nindActive) + :rtype: scipy.sparse.csr_matrix + :return: active cell projection matrix + """ if getattr(self, '__Pac', None) is None: if self.indActive is None: self.__Pac = Utils.speye(self.mesh.nC) @@ -40,6 +70,11 @@ class RegularizationMesh(object): @property def _Pafx(self): + """ + projection matrix that takes from the reduced space of active x-faces to full modelling space (ie. nFx x nindActive_Fx ) + :rtype: scipy.sparse.csr_matrix + :return: active face-x projection matrix + """ if getattr(self, '__Pafx', None) is None: if self.indActive is None: self.__Pafx = Utils.speye(self.mesh.nFx) @@ -50,6 +85,11 @@ class RegularizationMesh(object): @property def _Pafy(self): + """ + projection matrix that takes from the reduced space of active y-faces to full modelling space (ie. nFy x nindActive_Fy ) + :rtype: scipy.sparse.csr_matrix + :return: active face-y projection matrix + """ if getattr(self, '__Pafy', None) is None: if self.indActive is None: self.__Pafy = Utils.speye(self.mesh.nFy) @@ -60,6 +100,11 @@ class RegularizationMesh(object): @property def _Pafz(self): + """ + projection matrix that takes from the reduced space of active z-faces to full modelling space (ie. nFz x nindActive_Fz ) + :rtype: scipy.sparse.csr_matrix + :return: active face-z projection matrix + """ if getattr(self, '__Pafz', None) is None: if self.indActive is None: self.__Pafz = Utils.speye(self.mesh.nFz) @@ -70,108 +115,173 @@ class RegularizationMesh(object): @property def aveFx2CC(self): + """ + averaging from active cell centers to active x-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active x-faces + """ if getattr(self, '_aveFx2CC', None) is None: self._aveFx2CC = self._Pac.T * self.mesh.aveFx2CC * self._Pafx return self._aveFx2CC @property def aveCC2Fx(self): + """ + averaging from active x-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active x-faces to active cell centers + """ if getattr(self, '_aveCC2Fx', None) is None: self._aveCC2Fx = Utils.sdiag(1./(self.aveFx2CC.T).sum(1)) * self.aveFx2CC.T return self._aveCC2Fx @property def aveFy2CC(self): + """ + averaging from active cell centers to active y-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active y-faces + """ if getattr(self, '_aveFy2CC', None) is None: self._aveFy2CC = self._Pac.T * self.mesh.aveFy2CC * self._Pafy return self._aveFy2CC @property def aveCC2Fy(self): + """ + averaging from active y-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active y-faces to active cell centers + """ if getattr(self, '_aveCC2Fy', None) is None: self._aveCC2Fy = Utils.sdiag(1./(self.aveFy2CC.T).sum(1)) * self.aveFy2CC.T return self._aveCC2Fy @property def aveFz2CC(self): + """ + averaging from active cell centers to active z-faces + :rtype: scipy.sparse.csr_matrix + :return: averaging from active cell centers to active z-faces + """ if getattr(self, '_aveFz2CC', None) is None: self._aveFz2CC = self._Pac.T * self.mesh.aveFz2CC * self._Pafz return self._aveFz2CC @property def aveCC2Fz(self): + """ + averaging from active z-faces to active cell centers + :rtype: scipy.sparse.csr_matrix + :return: averaging matrix from active z-faces to active cell centers + """ if getattr(self, '_aveCC2Fz', None) is None: self._aveCC2Fz = Utils.sdiag(1./(self.aveFz2CC.T).sum(1)) * self.aveFz2CC.T return self._aveCC2Fz @property - def cellGradx(self): - if getattr(self, '_cellGradx', None) is None: - self._cellGradx = self._Pafx.T * self.mesh.cellGradx * self._Pac - return self._cellGradx + def cellDiffx(self): + """ + cell centered difference in the x-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the x-direction + """ + if getattr(self, '_cellDiffx', None) is None: + self._cellDiffx = self._Pafx.T * self.mesh.cellGradx * self._Pac + return self._cellDiffx @property - def cellGrady(self): - if getattr(self, '_cellGrady', None) is None: - self._cellGrady = self._Pafy.T * self.mesh.cellGrady * self._Pac - return self._cellGrady + def cellDiffy(self): + """ + cell centered difference in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ + if getattr(self, '_cellDiffy', None) is None: + self._cellDiffy = self._Pafy.T * self.mesh.cellGrady * self._Pac + return self._cellDiffy @property - def cellGradz(self): - if getattr(self, '_cellGradz', None) is None: - self._cellGradz = self._Pafz.T * self.mesh.cellGradz * self._Pac - return self._cellGradz + def cellDiffz(self): + """ + cell centered difference in the z-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the z-direction + """ + if getattr(self, '_cellDiffz', None) is None: + self._cellDiffz = self._Pafz.T * self.mesh.cellGradz * self._Pac + return self._cellDiffz @property - def faceDivx(self): - if getattr(self, '_faceDivx', None) is None: - self._faceDivx = self._Pac.T * self.mesh.faceDivx * self._Pafx - return self._faceDivx + def faceDiffx(self): + """ + x-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the x-direction + """ + if getattr(self, '_faceDiffx', None) is None: + self._faceDiffx = self._Pac.T * self.mesh.faceDivx * self._Pafx + return self._faceDiffx @property - def faceDivy(self): - if getattr(self, '_faceDivy', None) is None: - self._faceDivy = self._Pac.T * self.mesh.faceDivy * self._Pafy - return self._faceDivy + def faceDiffy(self): + """ + y-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the y-direction + """ + if getattr(self, '_faceDiffy', None) is None: + self._faceDiffy = self._Pac.T * self.mesh.faceDivy * self._Pafy + return self._faceDiffy @property - def faceDivz(self): - if getattr(self, '_faceDivz', None) is None: - self._faceDivz = self._Pac.T * self.mesh.faceDivz * self._Pafz - return self._faceDivz + def faceDiffz(self): + """ + z-face differences + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active faces in the z-direction + """ + if getattr(self, '_faceDiffz', None) is None: + self._faceDiffz = self._Pac.T * self.mesh.faceDivz * self._Pafz + return self._faceDiffz @property - def cellGradxStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" + def cellDiffxStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the x-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the x-direction + """ + if getattr(self, '_cellDiffxStencil', None) is None: - # if self.dim < 3: return None - if getattr(self, '_cellGradxStencil', None) is None: - - self._cellGradxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac - return self._cellGradxStencil + self._cellDiffxStencil = self._Pafx.T * self.mesh._cellGradxStencil() * self._Pac + return self._cellDiffxStencil @property - def cellGradyStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - + def cellDiffyStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ if self.dim < 2: return None - if getattr(self, '_cellGradyStencil', None) is None: + if getattr(self, '_cellDiffyStencil', None) is None: - self._cellGradyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac - return self._cellGradyStencil + self._cellDiffyStencil = self._Pafy.T * self.mesh._cellGradyStencil() * self._Pac + return self._cellDiffyStencil @property - def cellGradzStencil(self): - """Cell centered Gradient in the x dimension used for - regularization. The gradient operator is square (nC-by-nC)""" - + def cellDiffzStencil(self): + """ + cell centered difference stencil (no cell lengths include) in the y-direction + :rtype: scipy.sparse.csr_matrix + :return: differencing matrix for active cells in the y-direction + """ if self.dim < 3: return None - if getattr(self, '_cellGradzStencil', None) is None: + if getattr(self, '_cellDiffzStencil', None) is None: - self._cellGradzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac - return self._cellGradzStencil + self._cellDiffzStencil = self._Pafz.T * self.mesh._cellGradzStencil() * self._Pac + return self._cellDiffzStencil class BaseRegularization(object): @@ -317,7 +427,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellGradx + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx return self._Wx @property @@ -325,7 +435,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: Ave_y_vol = self.regmesh.aveCC2Fy * self.regmesh.vol - self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellGrady + self._Wy = Utils.sdiag((Ave_y_vol*self.alpha_y)**0.5)*self.regmesh.cellDiffy return self._Wy @property @@ -333,28 +443,28 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: Ave_z_vol = self.regmesh.aveCC2Fz * self.regmesh.vol - self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellGradz + self._Wz = Utils.sdiag((Ave_z_vol*self.alpha_z)**0.5)*self.regmesh.cellDiffz return self._Wz @property def Wxx(self): """Regularization matrix Wxx""" if getattr(self, '_Wxx', None) is None: - self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDivx*self.regmesh.cellGradx + self._Wxx = Utils.sdiag((self.regmesh.vol*self.alpha_xx)**0.5)*self.regmesh.faceDiffx*self.regmesh.cellDiffx return self._Wxx @property def Wyy(self): """Regularization matrix Wyy""" if getattr(self, '_Wyy', None) is None: - self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDivy*self.regmesh.cellGrady + self._Wyy = Utils.sdiag((self.regmesh.vol*self.alpha_yy)**0.5)*self.regmesh.faceDiffy*self.regmesh.cellDiffy return self._Wyy @property def Wzz(self): """Regularization matrix Wzz""" if getattr(self, '_Wzz', None) is None: - self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDivz*self.regmesh.cellGradz + self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz return self._Wzz @property @@ -445,21 +555,21 @@ class Simple(BaseRegularization): def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellGradxStencil + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellDiffxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellGradyStencil + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellDiffyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellGradzStencil + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellDiffzStencil return self._Wz @property @@ -563,15 +673,15 @@ class SparseRegularization(Simple): """Regularization matrix Wx""" if getattr(self, 'm', None) is None: - self.Rx = Utils.speye(self.regmesh.cellGradxStencil.shape[0]) + self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: - f_m = self.regmesh.cellGradxStencil * self.m + f_m = self.regmesh.cellDiffxStencil * self.m self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellGradxStencil + self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil return self._Wx @property @@ -579,15 +689,15 @@ class SparseRegularization(Simple): """Regularization matrix Wy""" if getattr(self, 'm', None) is None: - self.Ry = Utils.speye(self.regmesh.cellGradyStencil.shape[0]) + self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) else: - f_m = self.regmesh.cellGradyStencil * self.m + f_m = self.regmesh.cellDiffyStencil * self.m self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellGradyStencil + self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil return self._Wy @property @@ -595,15 +705,15 @@ class SparseRegularization(Simple): """Regularization matrix Wz""" if getattr(self, 'm', None) is None: - self.Rz = Utils.speye(self.regmesh.cellGradzStencil.shape[0]) + self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) else: - f_m = self.regmesh.cellGradzStencil * self.m + f_m = self.regmesh.cellDiffzStencil * self.m self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellGradzStencil + self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil return self._Wz From 2f8b8a36bf71e1ca2e501540b09ee539c4502e01 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 2 Mar 2016 09:46:50 -0800 Subject: [PATCH 11/56] smoothModel --> mrefInSmooth --- SimPEG/Directives.py | 4 ++-- SimPEG/Examples/MT_1D_ForwardAndInversion.py | 2 +- SimPEG/Regularization.py | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 9ba38e4e..0a98bc09 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -216,7 +216,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the data. ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) phi_ms = 0.5*ms.dot(ms) - if self.reg.smoothModel == True: + if self.reg.mrefInSmooth == True: mref = self.reg.mref else: mref = 0 @@ -249,7 +249,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the data. ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) phi_ms = 0.5*ms.dot(ms) - if self.reg.smoothModel == True: + if self.reg.mrefInSmooth == True: mref = self.reg.mref else: mref = 0 diff --git a/SimPEG/Examples/MT_1D_ForwardAndInversion.py b/SimPEG/Examples/MT_1D_ForwardAndInversion.py index cf17e77b..69cedd98 100644 --- a/SimPEG/Examples/MT_1D_ForwardAndInversion.py +++ b/SimPEG/Examples/MT_1D_ForwardAndInversion.py @@ -100,7 +100,7 @@ def run(plotIt=True): # Regularization - with a regularization mesh regMesh = simpeg.Mesh.TensorMesh([m1d.hx[problem.mapping.sigmaMap.maps[-1].indActive]],m1d.x0) reg = simpeg.Regularization.Tikhonov(regMesh) - reg.smoothModel = True + reg.mrefInSmooth = True reg.alpha_s = 1e-7 reg.alpha_x = 1. # Inversion problem diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index acd6c68d..990b79c3 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -403,7 +403,7 @@ class BaseRegularization(object): class Tikhonov(BaseRegularization): """ """ - smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") @@ -489,11 +489,11 @@ class Tikhonov(BaseRegularization): @Utils.timeIt def eval(self, m): - if self.smoothModel == True: + if self.mrefInSmooth == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: + elif self.mrefInSmooth == False: r = self.W * ( self.mapping * (m - self.mref) ) return 0.5*r.dot(r) @@ -515,7 +515,7 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.smoothModel == True: + if self.mrefInSmooth == True: mD1 = self.mapping.deriv(m) mD2 = self.mapping.deriv(m - self.mref) r1 = self.Wsmooth * ( self.mapping * (m)) @@ -523,7 +523,7 @@ class Tikhonov(BaseRegularization): out1 = mD1.T * ( self.Wsmooth.T * r1 ) out2 = mD2.T * ( self.Ws.T * r2 ) out = out1+out2 - elif self.smoothModel == False: + elif self.mrefInSmooth == False: mD = self.mapping.deriv(m - self.mref) r = self.W * ( self.mapping * (m - self.mref) ) out = mD.T * ( self.W.T * r ) @@ -535,7 +535,7 @@ class Simple(BaseRegularization): Only for tensor mesh """ - smoothModel = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") @@ -595,11 +595,11 @@ class Simple(BaseRegularization): @Utils.timeIt def eval(self, m): - if self.smoothModel == True: + if self.mrefInSmooth == True: r1 = self.Wsmooth * ( self.mapping * (m) ) r2 = self.Ws * ( self.mapping * (m - self.mref) ) return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.smoothModel == False: + elif self.mrefInSmooth == False: r = self.W * ( self.mapping * (m - self.mref) ) return 0.5*r.dot(r) return phim @@ -623,7 +623,7 @@ class Simple(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.smoothModel == True: + if self.mrefInSmooth == True: mD1 = self.mapping.deriv(m) mD2 = self.mapping.deriv(m - self.mref) r1 = self.Wsmooth * ( self.mapping * (m)) @@ -631,7 +631,7 @@ class Simple(BaseRegularization): out1 = mD1.T * ( self.Wsmooth.T * r1 ) out2 = mD2.T * ( self.Ws.T * r2 ) out = out1+out2 - elif self.smoothModel == False: + elif self.mrefInSmooth == False: mD = self.mapping.deriv(m - self.mref) r = self.W * ( self.mapping * (m - self.mref) ) out = mD.T * ( self.W.T * r ) From 33c9059e4e2b9fae8375923197d23d2dafaa62a7 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 8 Mar 2016 16:40:02 -0800 Subject: [PATCH 12/56] SparseRegularization --> Sparse --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 990b79c3..db1bc39b 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -638,7 +638,7 @@ class Simple(BaseRegularization): return out -class SparseRegularization(Simple): +class Sparse(Simple): eps = 1e-1 m = None From 1946e1f69e7ec756ab64c5bc75d2f43cc0c361d9 Mon Sep 17 00:00:00 2001 From: seogi_macbook Date: Wed, 9 Mar 2016 15:49:08 -0800 Subject: [PATCH 13/56] minor change for plotting --- SimPEG/DCIP/DCIPUtils.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 90bbbca0..eb9d1c44 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype): +def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -230,10 +230,13 @@ def plot_pseudoSection(DCsurvey, axs, stype): elif stype == 'dpdp': leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) - midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) - rho = np.hstack([rho,leg]) + #TODO ... let stick to list then finally convert to array. + if dtype =="voltage": + rho = np.hstack([rho,leg]) + elif dtype =="appr": + rho = np.hstack([rho,data]) ax = axs @@ -242,8 +245,12 @@ def plot_pseudoSection(DCsurvey, axs, stype): grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)] grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear') + if clim == None: + vmin, vmax = rho.min(), rho.max() + else: + vmin, vmax = clim[0], clim[1] - plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin = np.min(rho), vmax = np.max(rho)) + plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal") cmin,cmax = cbar.get_clim() @@ -251,14 +258,14 @@ def plot_pseudoSection(DCsurvey, axs, stype): cbar.set_ticks(ticks) # Plot apparent resistivity - plt.scatter(midx,midz,s=50,c=rho.T) + plt.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) ax.set_xticklabels([]) ax.set_ylabel('Z') ax.yaxis.tick_right() ax.yaxis.set_label_position('right') - plt.gca().set_aspect('equal', adjustable='box') + # plt.gca().set_aspect('equal', adjustable='box') return ax From 4fefccc97dbd5249d68b7b490fb227d423d6c0ee Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 10 Mar 2016 14:25:27 -0800 Subject: [PATCH 14/56] Add readPUBC_DC2Dpre --- SimPEG/DCIP/DCIPUtils.py | 80 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 90bbbca0..996cf8ec 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -249,15 +249,17 @@ def plot_pseudoSection(DCsurvey, axs, stype): cmin,cmax = cbar.get_clim() ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) - + cbar.ax.tick_params(labelsize=10) + # Plot apparent resistivity plt.scatter(midx,midz,s=50,c=rho.T) ax.set_xticklabels([]) - - ax.set_ylabel('Z') - ax.yaxis.tick_right() - ax.yaxis.set_label_position('right') + ax.set_yticklabels([]) + + #ax.set_ylabel('Z') + #ax.yaxis.tick_right() + #ax.yaxis.set_label_position('right') plt.gca().set_aspect('equal', adjustable='box') @@ -735,6 +737,73 @@ def readUBC_DC2Dobs(fileName): return tx, rx, d, wd +def readUBC_DC2Dpre(fileName): + """ + Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + + Input: + :param fileName, path to the UBC GIF 3D obs file + + Output: + DCsurvey + :return + + Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >> + + @author: dominiquef + + """ + + # Load file + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') + + # Pre-allocate + srcLists = [] + Rx = [] + d = [] + zflag = True # Flag for z value provided + + for ii in range(obsfile.shape[0]): + + if not obsfile[ii]: + continue + + # First line is transmitter with number of receivers + + + temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T) + + + # Check if z value is provided, if False -> nan + if len(temp)==5: + tx = np.r_[temp[0],np.nan,np.nan,temp[1],np.nan,np.nan] + zflag = False + + else: + tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]] + + + if zflag: + rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]] + + + else: + rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan] + # Check if there is data with the location + + d.append(temp[-1]) + + + Rx = DC.RxDipole(rx[:,:3],rx[:,3:]) + srcLists.append( DC.SrcDipole( [Rx], tx[:3],tx[3:]) ) + + # Create survey class + survey = DC.SurveyDC(srcLists) + + survey.dobs = np.asarray(d) + + return {'DCsurvey':survey} + def readUBC_DC2DMesh(fileName): """ Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg @@ -928,7 +997,6 @@ def getSrc_locs(DCsurvey): srcMat = np.zeros((DCsurvey.nSrc,2,3)) for ii in range(DCsurvey.nSrc): - print np.asarray(DCsurvey.srcList[ii].loc).shape srcMat[ii,:,:] = np.asarray(DCsurvey.srcList[ii].loc) return srcMat From ef4513bcd42a0ddaba6b52f6c2fba6af4e70c6a0 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 10 Mar 2016 14:25:53 -0800 Subject: [PATCH 15/56] some cleanup inside of sparse regularization --- SimPEG/Directives.py | 54 ++++++++++++------------- SimPEG/Regularization.py | 66 ++++++++++++++----------------- tests/base/test_regularization.py | 2 +- 3 files changed, 57 insertions(+), 65 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 0a98bc09..46b0b087 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -285,45 +285,43 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): class update_IRLS(InversionDirective): - m = None - eps_min = None - factor = None - gamma = None - phi_m_last = None + eps_min = None + factor = None + gamma = None + phi_m_last = None - def initialize(self): + def initialize(self): - # Scale the regularization for changes in norm - if getattr(self, 'phi_m_last', None) is not None: - self.reg.gamma = 1. - phim_new = self.reg.eval(self.invProb.curModel) - self.gamma = self.phi_m_last / phim_new + # Scale the regularization for changes in norm + if getattr(self, 'phi_m_last', None) is not None: + self.reg.gamma = 1. + phim_new = self.reg.eval(self.invProb.curModel) + self.gamma = self.phi_m_last / phim_new - self.reg.gamma = self.gamma + self.reg.gamma = self.gamma - def endIter(self): - # Cool the threshold parameter - if getattr(self, 'factor', None) is not None: - eps = self.reg.eps / self.factor + def endIter(self): + # Cool the threshold parameter + if getattr(self, 'factor', None) is not None: + eps = self.reg.eps / self.factor - if getattr(self, 'eps_min', None) is not None: - self.reg.eps = np.max([self.eps_min,eps]) - else: - self.reg.eps = eps + if getattr(self, 'eps_min', None) is not None: + self.reg.eps = np.max([self.eps_min,eps]) + else: + self.reg.eps = eps # Update the model used for the IRLS weights - if getattr(self, 'm', None) is None: - self.reg.m = self.invProb.curModel + self.reg.curModel = self.invProb.curModel - # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. - PC = Utils.sdiag(diagA**-1.) + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. + PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC + self.opt.approxHinv = PC - phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new #============================================================================== # import pylab as plt diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index db1bc39b..6ad94caf 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -6,7 +6,7 @@ class RegularizationMesh(object): This contains the operators used in the regularization. Note that these are not necessarily true differential operators, but are constructed from - a SimPEG Mesh. + a SimPEG Mesh. :param Mesh mesh: problem mesh :param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells @@ -52,7 +52,7 @@ class RegularizationMesh(object): if getattr(self, '_dim', None) is None: self._dim = self.mesh.dim return self._dim - + @property def _Pac(self): @@ -64,7 +64,7 @@ class RegularizationMesh(object): if getattr(self, '__Pac', None) is None: if self.indActive is None: self.__Pac = Utils.speye(self.mesh.nC) - else: + else: self.__Pac = Utils.speye(self.mesh.nC)[:,self.indActive] return self.__Pac @@ -211,7 +211,7 @@ class RegularizationMesh(object): if getattr(self, '_cellDiffz', None) is None: self._cellDiffz = self._Pafz.T * self.mesh.cellGradz * self._Pac return self._cellDiffz - + @property def faceDiffx(self): """ @@ -233,7 +233,7 @@ class RegularizationMesh(object): if getattr(self, '_faceDiffy', None) is None: self._faceDiffy = self._Pac.T * self.mesh.faceDivy * self._Pafy return self._faceDiffy - + @property def faceDiffz(self): """ @@ -310,7 +310,7 @@ class BaseRegularization(object): if indActive is not None and indActive.dtype != 'bool': tmp = indActive indActive = np.zeros(mesh.nC, dtype=bool) - indActive[tmp] = True + indActive[tmp] = True self.regmesh = RegularizationMesh(mesh,indActive) self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) @@ -427,7 +427,7 @@ class Tikhonov(BaseRegularization): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: Ave_x_vol = self.regmesh.aveCC2Fx * self.regmesh.vol - self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx + self._Wx = Utils.sdiag((Ave_x_vol*self.alpha_x)**0.5)*self.regmesh.cellDiffx return self._Wx @property @@ -640,13 +640,14 @@ class Simple(BaseRegularization): class Sparse(Simple): - eps = 1e-1 - m = None - gamma = 1. - p = 0. - qx = 2. - qy = 2. - qz = 2. + # set default values + eps = 1e-1 + curModel = None # use a model to compute the weights + gamma = 1. + p = 0. + qx = 2. + qy = 2. + qz = 2. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @@ -655,71 +656,64 @@ class Sparse(Simple): @property def Ws(self): """Regularization matrix Ws""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rs = Utils.speye(self.regmesh.nC) else: - f_m = self.m + f_m = self.curModel self.rs = self.R(f_m , self.p, self.eps) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs - return self._Ws @property def Wx(self): """Regularization matrix Wx""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: - f_m = self.regmesh.cellDiffxStencil * self.m + f_m = self.regmesh.cellDiffxStencil * self.curModel self.rx = self.R( f_m , self.qx, self.eps) self.Rx = Utils.sdiag( self.rx ) - if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil - return self._Wx + return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil @property def Wy(self): """Regularization matrix Wy""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0]) else: - f_m = self.regmesh.cellDiffyStencil * self.m + f_m = self.regmesh.cellDiffyStencil * self.curModel self.ry = self.R( f_m , self.qy, self.eps) self.Ry = Utils.sdiag( self.ry ) - if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil - return self._Wy + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property def Wz(self): """Regularization matrix Wz""" - if getattr(self, 'm', None) is None: + if getattr(self, 'curModel', None) is None: self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0]) else: - f_m = self.regmesh.cellDiffzStencil * self.m + f_m = self.regmesh.cellDiffzStencil * self.curModel self.rz = self.R( f_m , self.qz, self.eps) self.Rz = Utils.sdiag( self.rz ) - if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil - return self._Wz + return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil - def R(self, f_m , p, dec): + def R(self, f_m , exponent): - eta = (self.eps**(1-p/2.))**0.5 - r = eta / (f_m**2.+self.eps**2.)**((1-p/2.)/2.) + eta = (self.eps**(1-exponent/2.))**0.5 + r = eta / (f_m**2.+self.eps**2.)**((1-exponent/2.)/2.) return r diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 52cef349..97223015 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -18,7 +18,7 @@ class RegularizationTests(unittest.TestCase): mesh3 = Mesh.TensorMesh([hx, hy, hz]) self.meshlist = [mesh1,mesh2, mesh3] - if testReg: + if testReg: def test_regularization(self): for R in dir(Regularization): r = getattr(Regularization, R) From 838035adaef7991dd48f8c6984b32951b032eea7 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 10 Mar 2016 14:30:43 -0800 Subject: [PATCH 16/56] fixed indentation level on test_regularization --- tests/base/test_regularization.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 97223015..5aa21ad5 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -87,24 +87,24 @@ class RegularizationTests(unittest.TestCase): if testRegMesh: def test_regularizationMesh(self): - for i, mesh in enumerate(self.meshlist): + for i, mesh in enumerate(self.meshlist): - print 'Testing %iD'%mesh.dim + print 'Testing %iD'%mesh.dim - # mapping = r.mapPair(mesh) - # reg = r(mesh, mapping=mapping) - # m = np.random.rand(mapping.nP) + # mapping = r.mapPair(mesh) + # reg = r(mesh, mapping=mapping) + # m = np.random.rand(mapping.nP) - if mesh.dim == 1: - indAct = Utils.mkvc(mesh.gridCC <= 0.8) - elif mesh.dim == 2: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) - elif mesh.dim == 3: - indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) + if mesh.dim == 1: + indAct = Utils.mkvc(mesh.gridCC <= 0.8) + elif mesh.dim == 2: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5) + elif mesh.dim == 3: + indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) + regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct) - assert (regmesh.vol == mesh.vol[indAct]).all() + assert (regmesh.vol == mesh.vol[indAct]).all() if __name__ == '__main__': From 38b4079f0bdb23eaa7b5810ed925e2a4f32102ce Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 11 Mar 2016 11:40:47 -0800 Subject: [PATCH 17/56] Move cell-based weights (i.e. distance weighting) inside regularization. Fix gamma parameter update TO DO: Check inversion print screen -> values don't match reality. --- SimPEG/Directives.py | 8 ++++-- SimPEG/Regularization.py | 60 ++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 46b0b087..dbb525f7 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -298,6 +298,7 @@ class update_IRLS(InversionDirective): phim_new = self.reg.eval(self.invProb.curModel) self.gamma = self.phi_m_last / phim_new + self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma def endIter(self): @@ -315,13 +316,14 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.m.size))**2. + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC - + + self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.reg.gamma * self.invProb.phi_m_last / phim_new + self.reg.gamma = self.invProb.phi_m_last / phim_new #============================================================================== # import pylab as plt diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6ad94caf..6c6b4b4b 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -540,36 +540,40 @@ class Simple(BaseRegularization): alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - + wght = 1. + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) + + if isinstance(self.wght,float): + self.wght = np.ones(self.regmesh.nC) * self.wght @property def Ws(self): """Regularization matrix Ws""" if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) + self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) return self._Ws @property def Wx(self): """Regularization matrix Wx""" if getattr(self, '_Wx', None) is None: - self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x)**0.5)*self.regmesh.cellDiffxStencil + self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil return self._Wx @property def Wy(self): """Regularization matrix Wy""" if getattr(self, '_Wy', None) is None: - self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y)**0.5)*self.regmesh.cellDiffyStencil + self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil return self._Wy @property def Wz(self): """Regularization matrix Wz""" if getattr(self, '_Wz', None) is None: - self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z)**0.5)*self.regmesh.cellDiffzStencil + self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil return self._Wz @property @@ -648,10 +652,13 @@ class Sparse(Simple): qx = 2. qy = 2. qz = 2. + wght = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + + if isinstance(self.wght,float): + self.wght = np.ones(self.regmesh.nC) * self.wght @property def Ws(self): @@ -661,26 +668,26 @@ class Sparse(Simple): else: f_m = self.curModel - self.rs = self.R(f_m , self.p, self.eps) + self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - - return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma)**0.5)*self.Rs + + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs @property def Wx(self): """Regularization matrix Wx""" - + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) else: f_m = self.regmesh.cellDiffxStencil * self.curModel - self.rx = self.R( f_m , self.qx, self.eps) + self.rx = self.R( f_m , self.qx) self.Rx = Utils.sdiag( self.rx ) - return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma)**0.5)*self.Rx*self.regmesh.cellDiffxStencil + return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil @property def Wy(self): @@ -691,10 +698,10 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffyStencil * self.curModel - self.ry = self.R( f_m , self.qy, self.eps) + self.ry = self.R( f_m , self.qy) self.Ry = Utils.sdiag( self.ry ) - - return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma)**0.5)*self.Ry*self.regmesh.cellDiffyStencil + + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property def Wz(self): @@ -705,12 +712,31 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffzStencil * self.curModel - self.rz = self.R( f_m , self.qz, self.eps) + self.rz = self.R( f_m , self.qz) self.Rz = Utils.sdiag( self.rz ) - return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma)**0.5)*self.Rz*self.regmesh.cellDiffzStencil + return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil + @property + def Wsmooth(self): + """Full smoothness regularization matrix W""" + #if getattr(self, '_Wsmooth', None) is None: + wlist = (self.Wx,) + if self.regmesh.dim > 1: + wlist += (self.Wy,) + if self.regmesh.dim > 2: + wlist += (self.Wz,) + #self._Wsmooth = sp.vstack(wlist) + return sp.vstack(wlist) + @property + def W(self): + """Full regularization matrix W""" + #if getattr(self, '_W', None) is None: + wlist = (self.Ws, self.Wsmooth) + #self._W = sp.vstack(wlist) + return sp.vstack(wlist) + def R(self, f_m , exponent): eta = (self.eps**(1-exponent/2.))**0.5 From d226186c8e68c33657a318db0de41ec2f9a0a16e Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 11 Mar 2016 15:09:31 -0800 Subject: [PATCH 18/56] Add auto-beta adjustment. --- SimPEG/Directives.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index dbb525f7..de1c60c1 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -289,7 +289,8 @@ class update_IRLS(InversionDirective): factor = None gamma = None phi_m_last = None - + phi_d_last = None + def initialize(self): # Scale the regularization for changes in norm @@ -300,7 +301,10 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma - + + if getattr(self, 'phi_d_last', None) is None: + self.phi_d_last = self.invProb.phi_d + def endIter(self): # Cool the threshold parameter if getattr(self, 'factor', None) is not None: @@ -311,20 +315,28 @@ class update_IRLS(InversionDirective): else: self.reg.eps = eps - + # Get phi_m at the end of current iteration + self.phi_m_last = self.invProb.phi_m_last + # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC - + + # Temporarely set gamma to 1. self.reg.gamma = 1. + + # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) - self.reg.gamma = self.invProb.phi_m_last / phim_new - + self.reg.gamma = self.phi_m_last / phim_new + print self.reg.gamma + + # TO DO: Re-scale beta if too much change in misfit + self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d + #============================================================================== # import pylab as plt # plt.figure() From ef467efce03fb02025bc81712c689f3b3f2c8f11 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 15 Mar 2016 20:56:38 -0700 Subject: [PATCH 19/56] Small change to directive --- SimPEG/Directives.py | 1 - 1 file changed, 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index de1c60c1..e5a63547 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -332,7 +332,6 @@ class update_IRLS(InversionDirective): # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) self.reg.gamma = self.phi_m_last / phim_new - print self.reg.gamma # TO DO: Re-scale beta if too much change in misfit self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d From d302a59b2c7b977be1e2264c9f7e66c09e1805d2 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 16 Mar 2016 11:43:25 -0700 Subject: [PATCH 20/56] Change the projection from 3D to 2D --- SimPEG/DCIP/DCIPUtils.py | 56 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 12e13169..3cbf558c 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -523,7 +523,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.close() -def convertObs_DC3D_to_2D(DCsurvey,lineID): +def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): """ Read DC survey and data and change coordinate system to distance along line assuming @@ -580,26 +580,40 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID): Rx = DCsurvey.srcList[indx[ii]].rxList[0].locs nrx = Rx[0].shape[0] - # Find A electrode along line - vec, r = r_unit(x0,Tx[ii][0,0:2]) - A = stn_id(vecTx,vec,r) - - # Find B electrode along line - vec, r = r_unit(x0,Tx[ii][1,0:2]) - B = stn_id(vecTx,vec,r) - - M = np.zeros(nrx) - N = np.zeros(nrx) - for kk in range(nrx): - - # Find all M electrodes along line - vec, r = r_unit(x0,Rx[0][kk,0:2]) - M[kk] = stn_id(vecTx,vec,r) - - # Find all N electrodes along line - vec, r = r_unit(x0,Rx[1][kk,0:2]) - N[kk] = stn_id(vecTx,vec,r) - + if flag == 'local': + # Find A electrode along line + vec, r = r_unit(x0,Tx[ii][0,0:2]) + A = stn_id(vecTx,vec,r) + + # Find B electrode along line + vec, r = r_unit(x0,Tx[ii][1,0:2]) + B = stn_id(vecTx,vec,r) + + M = np.zeros(nrx) + N = np.zeros(nrx) + for kk in range(nrx): + + # Find all M electrodes along line + vec, r = r_unit(x0,Rx[0][kk,0:2]) + M[kk] = stn_id(vecTx,vec,r) + + # Find all N electrodes along line + vec, r = r_unit(x0,Rx[1][kk,0:2]) + N[kk] = stn_id(vecTx,vec,r) + elif flag == 'Yloc': + """ Flip the XY axis locs""" + A = Tx[ii][0,1] + B = Tx[ii][1,1] + M = Rx[0][:,1] + N = Rx[1][:,1] + + elif flag == 'Xloc': + """ Copy the rx-tx locs""" + A = Tx[ii][0,0] + B = Tx[ii][1,0] + M = Rx[0][:,0] + N = Rx[1][:,0] + Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]]) srcLists.append( DC.SrcDipole( [Rx], np.asarray([A,0,Tx[ii][0,2]]),np.asarray([B,0,Tx[ii][1,2]]) ) ) From f92ff1301db92f5dda32125177281064ec59c17f Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 17 Mar 2016 18:45:09 -0700 Subject: [PATCH 21/56] Add reference model in compact term. --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 6c6b4b4b..c20ed973 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -667,7 +667,7 @@ class Sparse(Simple): self.Rs = Utils.speye(self.regmesh.nC) else: - f_m = self.curModel + f_m = self.curModel - self.reg.mref self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) From b765699d2fb4cc40bf26ba909f0bc093eb8307fc Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Fri, 25 Mar 2016 23:26:52 -0700 Subject: [PATCH 22/56] seperated out smallness and smoothness contributions --- SimPEG/Regularization.py | 198 +++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 100 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index c20ed973..a91da269 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -344,7 +344,6 @@ class BaseRegularization(object): def W(self): """Full regularization weighting matrix W.""" return sp.identity(self.regmesh.nC) - # self.regmesh._Pac.T * sp.identity(self.regmesh.nC) * self.regmesh._Pac # or do we want sp.identity(self.mesh.nC) or even just Utils.Identity() ? @Utils.timeIt def eval(self, m): @@ -375,11 +374,12 @@ class BaseRegularization(object): @Utils.timeIt def eval2Deriv(self, m, v=None): """ + Second derivative - :param numpy.array m: geophysical model - :param numpy.array v: vector to multiply - :rtype: scipy.sparse.csr_matrix or numpy.ndarray - :return: WtW or WtW*v + :param numpy.array m: geophysical model + :param numpy.array v: vector to multiply + :rtype: scipy.sparse.csr_matrix or numpy.ndarray + :return: WtW or WtW*v The regularization is: @@ -402,25 +402,48 @@ class BaseRegularization(object): class Tikhonov(BaseRegularization): """ + L2 Tikhonov regularization with both smallness and smoothness (first order + derivative) contributions. + + .. math:: + \phi_m(\mathbf{m}) = \\alpha_s \| W_s (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_x \| W_x \\frac{\partial}{\partial x} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_y \| W_y \\frac{\partial}{\partial y} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + \\alpha_z \| W_z \\frac{\partial}{\partial z} (\mathbf{m} - \mathbf{m_{ref}} ) \|^2 + + Note if the key word argument `mrefInSmooth` is False, then mref is not + included in the smoothness contribution. + + :param Mesh mesh: SimPEG mesh + :param Maps mapping: regularization mapping, takes the model from model space to the thing you want to regularize + :param numpy.ndarray indActive: active cell indices for reducing the size of differential operators in the definition of a regularization mesh + :param bool mrefInSmooth: (default = False) put mref in the smoothness component? + :param float alpha_s: (default 1e-6) smallness weight + :param float alpha_x: (default 1) smoothness weight for first derivative in the x-direction + :param float alpha_y: (default 1) smoothness weight for first derivative in the y-direction + :param float alpha_z: (default 1) smoothness weight for first derivative in the z-direction + :param float alpha_xx: (default 1) smoothness weight for second derivative in the x-direction + :param float alpha_yy: (default 1) smoothness weight for second derivative in the y-direction + :param float alpha_zz: (default 1) smoothness weight for second derivative in the z-direction """ - mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Ws'], "Smallness weight") - alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") - alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") - alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") - alpha_xx = Utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") - alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") - alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") + mrefInSmooth = False # put mref in the smoothness contribution + alpha_s = Utils.dependentProperty('_alpha_s', 1e-6, ['_W', '_Wsmall'], "Smallness weight") + alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") + alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") + alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") + alpha_xx = Utils.dependentProperty('_alpha_xx', 0.0, ['_W', '_Wxx'], "Weight for the second derivative in the x direction") + alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction") + alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction") def __init__(self, mesh, mapping=None, indActive = None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) @property - def Ws(self): - """Regularization matrix Ws""" - if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) - return self._Ws + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s)**0.5) + return self._Wsmall @property def Wx(self): @@ -483,25 +506,44 @@ class Tikhonov(BaseRegularization): def W(self): """Full regularization matrix W""" if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) self._W = sp.vstack(wlist) return self._W @Utils.timeIt - def eval(self, m): - if self.mrefInSmooth == True: - r1 = self.Wsmooth * ( self.mapping * (m) ) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - return 0.5*(r1.dot(r1)+r2.dot(r2)) - elif self.mrefInSmooth == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) + @Utils.timeIt + def _evalSmooth(self, m): + if self.mrefInSmooth == True: + r = self.Wsmooth * ( self.mapping * (m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wsmooth * ( self.mapping * (m) ) + return 0.5 * r.dot(r) + + @Utils.timeIt + def eval(self, m): + return self._evalSmall(m) + self._evalSmooth(m) + + @Utils.timeIt + def _evalSmallDeriv(self,m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) ) + + @Utils.timeIt + def _evalSmoothDeriv(self,m): + if self.mrefInSmooth == True: + r = self.Wsmooth * ( self.mapping * ( m - self.mref ) ) + return r.T * ( self.Wsmooth * self.mapping.deriv(m - self.mref) ) + elif self.mrefInSmooth == False: + r = self.Wsmooth * ( self.mapping * m ) + return r.T * ( self.Wsmooth * self.mapping.deriv(m) ) @Utils.timeIt def evalDeriv(self, m): """ - The regularization is: .. math:: @@ -515,45 +557,33 @@ class Tikhonov(BaseRegularization): R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} """ - if self.mrefInSmooth == True: - mD1 = self.mapping.deriv(m) - mD2 = self.mapping.deriv(m - self.mref) - r1 = self.Wsmooth * ( self.mapping * (m)) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - out1 = mD1.T * ( self.Wsmooth.T * r1 ) - out2 = mD2.T * ( self.Ws.T * r2 ) - out = out1+out2 - elif self.mrefInSmooth == False: - mD = self.mapping.deriv(m - self.mref) - r = self.W * ( self.mapping * (m - self.mref) ) - out = mD.T * ( self.W.T * r ) - return out + return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) -class Simple(BaseRegularization): +class Simple(Tikhonov): """ - Only for tensor mesh + Simple regularization that does not include length scales in the derivatives. """ mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options - alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Ws'], "Smallness weight") + alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction") wght = 1. - + def __init__(self, mesh, mapping=None, indActive=None, **kwargs): BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + if isinstance(self.wght,float): self.wght = np.ones(self.regmesh.nC) * self.wght @property - def Ws(self): - """Regularization matrix Ws""" - if getattr(self,'_Ws', None) is None: - self._Ws = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) - return self._Ws + def Wsmall(self): + """Regularization matrix Wsmall""" + if getattr(self,'_Wsmall', None) is None: + self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5) + return self._Wsmall @property def Wx(self): @@ -592,54 +622,22 @@ class Simple(BaseRegularization): def W(self): """Full regularization matrix W""" if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) self._W = sp.vstack(wlist) return self._W + @Utils.timeIt + def _evalSmall(self, m): + r = self.Wsmall * ( self.mapping * (m - self.mref) ) + return 0.5 * r.dot(r) @Utils.timeIt - def eval(self, m): + def _evalSmooth(self, m): if self.mrefInSmooth == True: - r1 = self.Wsmooth * ( self.mapping * (m) ) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - return 0.5*(r1.dot(r1)+r2.dot(r2)) + r = self.Wsmooth * ( self.mapping * (m - self.mref) ) elif self.mrefInSmooth == False: - r = self.W * ( self.mapping * (m - self.mref) ) - return 0.5*r.dot(r) - return phim - - - - @Utils.timeIt - def evalDeriv(self, m): - """ - - The regularization is: - - .. math:: - - R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})} - - So the derivative is straight forward: - - .. math:: - - R(m) = \mathbf{W^\\top W (m-m_\\text{ref})} - - """ - if self.mrefInSmooth == True: - mD1 = self.mapping.deriv(m) - mD2 = self.mapping.deriv(m - self.mref) - r1 = self.Wsmooth * ( self.mapping * (m)) - r2 = self.Ws * ( self.mapping * (m - self.mref) ) - out1 = mD1.T * ( self.Wsmooth.T * r1 ) - out2 = mD2.T * ( self.Ws.T * r2 ) - out = out1+out2 - elif self.mrefInSmooth == False: - mD = self.mapping.deriv(m - self.mref) - r = self.W * ( self.mapping * (m - self.mref) ) - out = mD.T * ( self.W.T * r ) - return out + r = self.Wsmooth * ( self.mapping * m) + return 0.5 * r.dot(r) class Sparse(Simple): @@ -656,13 +654,13 @@ class Sparse(Simple): def __init__(self, mesh, mapping=None, indActive=None, **kwargs): Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs) - + if isinstance(self.wght,float): self.wght = np.ones(self.regmesh.nC) * self.wght @property - def Ws(self): - """Regularization matrix Ws""" + def Wsmall(self): + """Regularization matrix Wsmall""" if getattr(self, 'curModel', None) is None: self.Rs = Utils.speye(self.regmesh.nC) @@ -671,14 +669,14 @@ class Sparse(Simple): self.rs = self.R(f_m , self.p) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) - + return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs @property def Wx(self): """Regularization matrix Wx""" - + if getattr(self, 'curModel', None) is None: self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0]) @@ -700,7 +698,7 @@ class Sparse(Simple): f_m = self.regmesh.cellDiffyStencil * self.curModel self.ry = self.R( f_m , self.qy) self.Ry = Utils.sdiag( self.ry ) - + return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @property @@ -733,10 +731,10 @@ class Sparse(Simple): def W(self): """Full regularization matrix W""" #if getattr(self, '_W', None) is None: - wlist = (self.Ws, self.Wsmooth) + wlist = (self.Wsmall, self.Wsmooth) #self._W = sp.vstack(wlist) return sp.vstack(wlist) - + def R(self, f_m , exponent): eta = (self.eps**(1-exponent/2.))**0.5 From 9c220ef37cde8c7faf1f67dfff622687c22e98dd Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 29 Mar 2016 23:05:04 -0700 Subject: [PATCH 23/56] default is mrefInSmooth = False --- SimPEG/Regularization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index a91da269..e43670d2 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -565,7 +565,7 @@ class Simple(Tikhonov): Simple regularization that does not include length scales in the derivatives. """ - mrefInSmooth = True #: SMOOTH and SMOOTH_MOD_DIF options + mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight") alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction") alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction") From 8f73b2e7be524a15411b4ab6765fae8b9fc5b81d Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sun, 3 Apr 2016 17:18:39 -0700 Subject: [PATCH 24/56] Update directives Add IRLS example --- SimPEG/Directives.py | 101 +++++++++++++--------- SimPEG/Examples/Inversion_IRLS.py | 134 ++++++++++++++++++++---------- SimPEG/Regularization.py | 22 +++-- SimPEG/Survey.py | 2 +- 4 files changed, 160 insertions(+), 99 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index e5a63547..de7e0b6b 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -237,39 +237,41 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the file as a npz np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) -class SaveOutputDictEveryIteration(_SaveEveryIteration): - """SaveOutputDictEveryIteration - A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). - """ - - def initialize(self): - print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName - - def endIter(self): - # Save the data. - ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) - phi_ms = 0.5*ms.dot(ms) - if self.reg.mrefInSmooth == True: - mref = self.reg.mref - else: - mref = 0 - mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim==2: - my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_my = 0.5 * my.dot(my) - else: - phi_my = 'NaN' - if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType: - mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mz = 0.5 * mz.dot(mz) - else: - phi_mz = 'NaN' - - - # Save the file as a npz - np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - +#============================================================================== +# class SaveOutputDictEveryIteration(_SaveEveryIteration): +# """SaveOutputDictEveryIteration +# A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). +# """ +# +# def initialize(self): +# print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName +# +# def endIter(self): +# # Save the data. +# ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) +# phi_ms = 0.5*ms.dot(ms) +# if self.reg.mrefInSmooth == True: +# mref = self.reg.mref +# else: +# mref = 0 +# mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_mx = 0.5 * mx.dot(mx) +# if self.prob.mesh.dim==2: +# my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_my = 0.5 * my.dot(my) +# else: +# phi_my = 'NaN' +# if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType: +# mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) ) +# phi_mz = 0.5 * mz.dot(mz) +# else: +# phi_mz = 'NaN' +# +# +# # Save the file as a npz +# np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) +# +#============================================================================== # class UpdateReferenceModel(Parameter): @@ -295,6 +297,8 @@ class update_IRLS(InversionDirective): # Scale the regularization for changes in norm if getattr(self, 'phi_m_last', None) is not None: + + self.reg.curModel = self.invProb.curModel self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) self.gamma = self.phi_m_last / phim_new @@ -320,22 +324,39 @@ class update_IRLS(InversionDirective): # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - - # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. - PC = Utils.sdiag(diagA**-1.) - self.opt.approxHinv = PC # Temporarely set gamma to 1. self.reg.gamma = 1. # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) + self.reg.gamma = self.phi_m_last / phim_new - # TO DO: Re-scale beta if too much change in misfit - self.invProb.beta = self.invProb.beta * self.phi_d_last / self.invProb.phi_d + # TO DO: Check optimization class, data misfit not matching reality + #dpred = self.prob.fields(self.invProb.curModel) + #phid = self.invProb.dmisfit.eval(self.invProb.curModel) + #print self.survey.std[0] + #print phid + #print self.invProb.phi_d + #print self.invProb.phi_d_last + + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + +class update_lin_PreCond(InversionDirective): + + + def endIter(self): + # Cool the threshold parameter + + if getattr(self.opt, 'approxHinv', None) is not None: + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. + PC = Utils.sdiag(diagA**-1.) + self.opt.approxHinv = PC + print 'Updated pre-cond' + #============================================================================== # import pylab as plt # plt.figure() diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index a7f5bd54..53240139 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -1,7 +1,7 @@ from SimPEG import * -def run(N=100, plotIt=True): +def run(N=200, plotIt=True): """ Inversion: Linear Problem ========================= @@ -9,39 +9,21 @@ def run(N=100, plotIt=True): Here we go over the basics of creating a linear problem and inversion. """ - - class LinearSurvey(Survey.BaseSurvey): - def projectFields(self, u): - return u - - class LinearProblem(Problem.BaseProblem): - - surveyPair = LinearSurvey - - def __init__(self, mesh, G, **kwargs): - Problem.BaseProblem.__init__(self, mesh, **kwargs) - self.G = G - - def fields(self, m, u=None): - return self.G.dot(m) - - def Jvec(self, m, v, u=None): - return self.G.dot(v) - - def Jtvec(self, m, v, u=None): - return self.G.T.dot(v) - - + + np.random.seed(1) + std_noise = 1e-2 + mesh = Mesh.TensorMesh([N]) + + m0 = np.ones(mesh.nC) * 1e-4 + nk = 10 + jk = np.linspace(1.,nk,nk) + p = -2. + q = 1. - nk = 20 - jk = np.linspace(1.,20.,nk) - p = -0.25 - q = 0.25 - - g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(2*np.pi*q*jk[k]*mesh.vectorCCx) + g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(np.pi*q*jk[k]*mesh.vectorCCx) G = np.empty((nk, mesh.nC)) @@ -52,25 +34,43 @@ def run(N=100, plotIt=True): mtrue[mesh.vectorCCx > 0.3] = 1. mtrue[mesh.vectorCCx > 0.45] = -0.5 mtrue[mesh.vectorCCx > 0.6] = 0 + - prob = LinearProblem(mesh, G) - survey = LinearSurvey() + prob = Problem.LinearProblem(mesh, G) + survey = Survey.LinearSurvey() survey.pair(prob) - survey.makeSyntheticData(mtrue, std=0.01) - - M = prob.mesh - - reg = Regularization.Tikhonov(mesh) + survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk) + #survey.makeSyntheticData(mtrue, std=std_noise) + + wd = np.ones(nk) * std_noise + + #print survey.std[0] + #M = prob.mesh + # Distance weighting + wr = np.sum(prob.G**2.,axis=0)**0.5 + wr = ( wr/np.max(wr) )**0 + + reg = Regularization.Simple(mesh) + reg.wght = wr + dmis = DataMisfit.l2_DataMisfit(survey) - opt = Optimization.ProjectedGNCG(maxIter=20,lower=-1.,upper=1., maxIterCG= 20, tolCG = 1e-3) + dmis.Wd = 1./wd + + opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, tolCG = 1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) - beta = Directives.BetaSchedule() + invProb.curModel = m0 + + beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) + target = Directives.TargetMisfit() + betaest = Directives.BetaEstimate_ByEig() - inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest]) - m0 = np.zeros_like(survey.mtrue) + inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) + mrec = inv.run(m0) - + + print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + if plotIt: import matplotlib.pyplot as plt @@ -78,12 +78,54 @@ def run(N=100, plotIt=True): for i in range(prob.G.shape[0]): axes[0].plot(prob.G[i,:]) axes[0].set_title('Columns of matrix G') - - axes[1].plot(M.vectorCCx, survey.mtrue, 'b-') - axes[1].plot(M.vectorCCx, mrec, 'r-') - axes[1].legend(('True Model', 'Recovered Model')) + + axes[1].plot(mesh.vectorCCx, mtrue, 'b-') + axes[1].plot(mesh.vectorCCx, mrec, 'r-') + #axes[1].legend(('True Model', 'Recovered Model')) + axes[1].set_ylim(-1.0,1.25) plt.show() + + # Switch regularization to sparse + phim = invProb.phi_m_last + phid = invProb.phi_d + + reg = Regularization.Sparse(mesh) + +#============================================================================== +# fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) +# dmdx = reg.mesh.cellDiffxStencil * mrec +# plt.plot(np.sort(dmdx)) +#============================================================================== + + #reg.recModel = mrec + reg.wght = np.ones(mesh.nC) + reg.mref = np.zeros(mesh.nC) + reg.eps_p = 2e-3 + reg.eps_q = 2e-3 + reg.norms = [0., 0., 2., 2.] + reg.wght = wr + + opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterCG= 200, tolCG = 1e-3) + invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) + beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) + #betaest = Directives.BetaEstimate_ByEig() + target = Directives.TargetMisfit() + IRLS =Directives.update_IRLS( phi_m_last = phim, phi_d_last = phid ) + + inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) + m0 = mrec + + # Run inversion + mrec = inv.run(m0) + + print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + + if plotIt: + axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2) + axes[1].legend(('True Model', 'Smooth l2-l2', + 'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12) + return prob, survey, mesh, mrec if __name__ == '__main__': diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index ed75ada6..195e6203 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -643,13 +643,11 @@ class Simple(Tikhonov): class Sparse(Simple): # set default values - eps = 1e-1 + eps_p = 1e-1 + eps_q = 1e-1 curModel = None # use a model to compute the weights gamma = 1. - norms = [0., .2, 2., 2., 1.] - qx = 2. - qy = 2. - qz = 2. + norms = [0., 2., 2., 2.] wght = 1. def __init__(self, mesh, mapping=None, indActive=None, **kwargs): @@ -666,7 +664,7 @@ class Sparse(Simple): else: f_m = self.curModel - self.reg.mref - self.rs = self.R(f_m , self.norms[0]) + self.rs = self.R(f_m , self.eps_p, self.norms[0]) #print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs)) self.Rs = Utils.sdiag( self.rs ) @@ -682,7 +680,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffxStencil * self.curModel - self.rx = self.R( f_m , self.qx) + self.rx = self.R( f_m , self.eps_q, self.norms[1]) self.Rx = Utils.sdiag( self.rx ) return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil @@ -696,7 +694,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffyStencil * self.curModel - self.ry = self.R( f_m , self.qy) + self.ry = self.R( f_m , self.eps_q, self.norms[2]) self.Ry = Utils.sdiag( self.ry ) return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil @@ -710,7 +708,7 @@ class Sparse(Simple): else: f_m = self.regmesh.cellDiffzStencil * self.curModel - self.rz = self.R( f_m , self.qz) + self.rz = self.R( f_m , self.eps_q, self.norms[3]) self.Rz = Utils.sdiag( self.rz ) return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil @@ -735,9 +733,9 @@ class Sparse(Simple): #self._W = sp.vstack(wlist) return sp.vstack(wlist) - def R(self, f_m , exponent): + def R(self, f_m , eps, exponent): - eta = (self.eps**(1-exponent/2.))**0.5 - r = eta / (f_m**2.+self.eps**2.)**((1-exponent/2.)/2.) + eta = (eps**(1-exponent/2.))**0.5 + r = eta / (f_m**2.+ eps**2.)**((1-exponent/2.)/2.) return r diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index 9f307c3f..eee2d538 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -372,7 +372,7 @@ class BaseSurvey(object): self.dtrue = self.dpred(m, u=u) noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape) self.dobs = self.dtrue+noise - self.std = self.dobs*0 + std + self.std = self.dobs*0. + std return self.dobs class LinearSurvey(BaseSurvey): From 2ee158e5d77f74603f58b98e054fdb4f343fa685 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sun, 3 Apr 2016 17:26:04 -0700 Subject: [PATCH 25/56] Add distance weighting to example TO DO: Create example with and without distance weights --- SimPEG/Examples/Inversion_IRLS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 53240139..2cb75f31 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -48,7 +48,7 @@ def run(N=200, plotIt=True): #M = prob.mesh # Distance weighting wr = np.sum(prob.G**2.,axis=0)**0.5 - wr = ( wr/np.max(wr) )**0 + wr = ( wr/np.max(wr) ) reg = Regularization.Simple(mesh) reg.wght = wr From df620b42bd97fc8398806050b05881fbc995bbaa Mon Sep 17 00:00:00 2001 From: D Fournier Date: Tue, 5 Apr 2016 13:23:08 -0700 Subject: [PATCH 26/56] Fix plotting for Linear_IRLS example --- SimPEG/Examples/Inversion_IRLS.py | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index 2cb75f31..f5475680 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -68,23 +68,9 @@ def run(N=200, plotIt=True): mrec = inv.run(m0) - + ml2 = mrec print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) - - if plotIt: - import matplotlib.pyplot as plt - - fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) - for i in range(prob.G.shape[0]): - axes[0].plot(prob.G[i,:]) - axes[0].set_title('Columns of matrix G') - - axes[1].plot(mesh.vectorCCx, mtrue, 'b-') - axes[1].plot(mesh.vectorCCx, mrec, 'r-') - #axes[1].legend(('True Model', 'Recovered Model')) - axes[1].set_ylim(-1.0,1.25) - plt.show() - + # Switch regularization to sparse phim = invProb.phi_m_last phid = invProb.phi_d @@ -105,7 +91,7 @@ def run(N=200, plotIt=True): reg.norms = [0., 0., 2., 2.] reg.wght = wr - opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterCG= 200, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=5 ,lower=-2.,upper=2., maxIterCG= 100, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() @@ -121,10 +107,24 @@ def run(N=200, plotIt=True): print "Final misfit:" + str(invProb.dmisfit.eval(mrec)) + if plotIt: + import matplotlib.pyplot as plt + + fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2)) + for i in range(prob.G.shape[0]): + axes[0].plot(prob.G[i,:]) + axes[0].set_title('Columns of matrix G') + + axes[1].plot(mesh.vectorCCx, mtrue, 'b-') + axes[1].plot(mesh.vectorCCx, ml2, 'r-') + #axes[1].legend(('True Model', 'Recovered Model')) + axes[1].set_ylim(-1.0,1.25) + axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2) axes[1].legend(('True Model', 'Smooth l2-l2', 'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12) + plt.show() return prob, survey, mesh, mrec From ba977206eaa43d10b5df49c99631b4c78db9948c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 07:22:18 -0700 Subject: [PATCH 27/56] Create sensitivity re-weighting directive Adapt Map/polymap for actInd (topography) --- SimPEG/Directives.py | 31 ++++++++++++++++++++++++------ SimPEG/Maps.py | 45 ++++++++++++++++++++++++++++---------------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index de7e0b6b..ec77b7a1 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -356,10 +356,29 @@ class update_lin_PreCond(InversionDirective): PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC print 'Updated pre-cond' + +class update_Wj(InversionDirective): + """ + Create approx-sensitivity base weighting + """ + k = None -#============================================================================== -# import pylab as plt -# plt.figure() -# ax = plt.subplot(221) -# self.prob.mesh.plotSlice(self.invProb.curModel, ax = ax, normal = 'Z', ind=-5, clim = (0, 0.005)) -#============================================================================== + def endIter(self): + + if self.opt.iter == 2: + m = self.invProb.curModel + if self.k is None: + self.k = int(self.survey.nD/10) + + def JtJv(v): + + Jv = self.prob.Jvec(m, v) + + return self.prob.Jtvec(m,Jv) + + JtJdiag = Utils.diagEst(JtJv,6,k=100) + JtJdiag = JtJdiag + JtJdiag = JtJdiag / max(JtJdiag) + + + self.reg.wght = JtJdiag diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index 5f71d87c..f6b24f10 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -759,15 +759,27 @@ class PolyMap(IdentityMap): m = [\sigma_1, \sigma_2, c] - """ - def __init__(self, mesh, order, logSigma=True, normal='X'): + """ + def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None): IdentityMap.__init__(self, mesh) self.logSigma = logSigma self.order = order - self.normal = normal - - slope = 1e4 - + self.normal = normal + self.actInd = actInd + + if getattr(self, 'actInd', None) is None: + self.actInd = range(self.mesh.nC) + self.nC = self.mesh.nC + + else: + self.nC = len(self.actInd) + + slope = 1e4 + + @property + def shape(self): + return (self.nC, self.nP) + @property def nP(self): if np.isscalar(self.order): @@ -785,8 +797,8 @@ class PolyMap(IdentityMap): sig1, sig2 = np.exp(sig1), np.exp(sig2) #2D if self.mesh.dim == 2: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] if self.normal =='X': f = polynomial.polyval(Y, c) - X elif self.normal =='Y': @@ -795,9 +807,9 @@ class PolyMap(IdentityMap): raise(Exception("Input for normal = X or Y or Z")) #3D elif self.mesh.dim == 3: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] - Z = self.mesh.gridCC[:,2] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] + Z = self.mesh.gridCC[self.actInd,2] if self.normal =='X': f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X elif self.normal =='Y': @@ -806,6 +818,7 @@ class PolyMap(IdentityMap): f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z else: raise(Exception("Input for normal = X or Y or Z")) + else: raise(Exception("Only supports 2D")) @@ -819,8 +832,8 @@ class PolyMap(IdentityMap): sig1, sig2 = np.exp(sig1), np.exp(sig2) #2D if self.mesh.dim == 2: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] if self.normal =='X': f = polynomial.polyval(Y, c) - X @@ -832,9 +845,9 @@ class PolyMap(IdentityMap): raise(Exception("Input for normal = X or Y or Z")) #3D elif self.mesh.dim == 3: - X = self.mesh.gridCC[:,0] - Y = self.mesh.gridCC[:,1] - Z = self.mesh.gridCC[:,2] + X = self.mesh.gridCC[self.actInd,0] + Y = self.mesh.gridCC[self.actInd,1] + Z = self.mesh.gridCC[self.actInd,2] if self.normal =='X': f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X From e646211e7d4e300e0bde758505179da45912be4c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 08:55:52 -0700 Subject: [PATCH 28/56] Review Utils.gen_DCIPsurvey ... lets keep it. --- SimPEG/DCIP/DCIPUtils.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 3cbf558c..1c109559 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -371,16 +371,6 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:]) SrcList.append(srcClass) -#============================================================================== -# elif re.match(stype,'dpdp'): -# -# for ii in range(0, int(nstn)-2): -# -# indx = np.min([ii+n+1,nstn]) -# Tx.append(np.c_[M[ii,:],N[ii,:]]) -# Rx.append(np.c_[M[ii+2:indx,:],N[ii+2:indx,:]]) -#============================================================================== - elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square @@ -533,10 +523,10 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): Assumes flat topo for now... Input: - :param Tx, Rx + :param survey3D Output: - :figure Tx2d, Rx2d + :figure survey2D Edited Feb 17th, 2016 From 15d59a5b50511ae6396d7b74c455e68c1da44878 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 09:00:13 -0700 Subject: [PATCH 29/56] Fix typos in Directives.update_Wj. overseer @lheagy --- SimPEG/Directives.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index ec77b7a1..9926055a 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -376,9 +376,7 @@ class update_Wj(InversionDirective): return self.prob.Jtvec(m,Jv) - JtJdiag = Utils.diagEst(JtJv,6,k=100) - JtJdiag = JtJdiag + JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k) JtJdiag = JtJdiag / max(JtJdiag) - self.reg.wght = JtJdiag From 8b94cd4dfe239318acb4469d6e0958c7dbd3bd76 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 09:14:14 -0700 Subject: [PATCH 30/56] Change flag for convertObs_DC3D_to_2D, which broke the example --- SimPEG/DCIP/DCIPUtils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 1c109559..d8cf04bf 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -513,7 +513,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): fid.close() -def convertObs_DC3D_to_2D(DCsurvey,lineID,flag): +def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ Read DC survey and data and change coordinate system to distance along line assuming From 2bd5829b42b48108c205d07dc3bec20a416a21ad Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Wed, 6 Apr 2016 13:15:03 -0700 Subject: [PATCH 31/56] Add gitter chat --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 1c645334..c9b30a78 100644 --- a/README.rst +++ b/README.rst @@ -25,6 +25,10 @@ SimPEG :target: https://coveralls.io/r/simpeg/simpeg?branch=master :alt: Coverage status +.. image:: http://img.shields.io/badge/GITTER-JOIN_CHAT-brightgreen.svg?style=flat-square + :alt: gitter chat room at https://gitter.im/simpeg/simpeg + :target: https://gitter.im/simpeg/simpeg + Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications. The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features: From f799733a9d9c59961b34e5d6dfcb558daed3bc60 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 14:43:33 -0700 Subject: [PATCH 32/56] Fix TwoSphere example and Utils.pseudoPlot --- SimPEG/DCIP/DCIPUtils.py | 50 ++++++++++--------- SimPEG/Examples/DC_Forward_PseudoSection.py | 55 ++++++++++++++------- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index d8cf04bf..af94ad4e 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): +def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -230,12 +230,14 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): elif stype == 'dpdp': leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + leg = np.log10(abs(1/leg)) + midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) #TODO ... let stick to list then finally convert to array. - if dtype =="voltage": + if dtype =="appr": rho = np.hstack([rho,leg]) - elif dtype =="appr": + elif dtype =="voltage": rho = np.hstack([rho,data]) @@ -250,28 +252,27 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="voltage",clim=None): else: vmin, vmax = clim[0], clim[1] - plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) - cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal") + grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho) + ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, clim=(vmin, vmax)) + cbar = plt.colorbar(format="$10^{%.1f}$",fraction=0.04,orientation="horizontal") cmin,cmax = cbar.get_clim() ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - - # Plot apparent resistivity - plt.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + cbar.set_label("App. Conductivity",size=12) - ax.set_xticklabels([]) - ax.set_yticklabels([]) + # Plot apparent resistivity + ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + + #ax.set_xticklabels([]) + #ax.set_yticklabels([]) - #ax.set_ylabel('Z') - #ax.yaxis.tick_right() - #ax.yaxis.set_label_position('right') plt.gca().set_aspect('equal', adjustable='box') - return ax + return ph def gen_DCIPsurvey(endl, mesh, stype, a, b, n): """ @@ -515,12 +516,12 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ - Read DC survey and data and change - coordinate system to distance along line assuming - all data is acquired along line. - First transmitter pole is assumed to be at the origin + Read DC survey and projects the coordinate system + according to the flag = 'Xloc' | 'Yloc' | 'local' (default) + In the 'local' system, station coordinates are referenced + to distance from the first srcLoc[0].loc[0] - Assumes flat topo for now... + The Z value is preserved, but Y coordinates zeroed. Input: :param survey3D @@ -528,7 +529,7 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): Output: :figure survey2D - Edited Feb 17th, 2016 + Edited April 6th, 2016 @author: dominiquef @@ -618,16 +619,16 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): def readUBC_DC3Dobs(fileName): """ - Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + Read UBC GIF DCIP 3D observation file and generate survey Input: :param fileName, path to the UBC GIF 3D obs file Output: - :param rx, tx, d, wd + :param DCIPsurvey :return - Created on Mon December 7th, 2015 + Created on Mon April 6th, 2015 @author: dominiquef @@ -702,6 +703,7 @@ def readUBC_DC3Dobs(fileName): def readUBC_DC2Dobs(fileName): """ + ------- NEEDS TO BE UPDATED ------ Read UBC GIF 2D observation file and generate arrays for tx-rx location Input: @@ -751,7 +753,7 @@ def readUBC_DC2Dobs(fileName): def readUBC_DC2Dpre(fileName): """ - Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location + Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location Input: :param fileName, path to the UBC GIF 3D obs file diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 2f198238..904dcbd3 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -56,7 +56,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Plot the model for reference # Define core mesh extent xlim = 200 - zlim = 125 + zlim = 100 # Specify the survey type: "pdp" | "dpdp" @@ -77,7 +77,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len - azm = np.arctan(dl_y/dl_x) + #azm = np.arctan(dl_y/dl_x) #Set boundary conditions mesh.setCellGradBC('neumann') @@ -146,39 +146,60 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Let's just convert the 3D format into 2D (distance along line) and plot # [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) - survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) + survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc') survey2D.dobs =np.hstack(data) # Here is an example for the first tx-rx array if plotIt: import matplotlib.pyplot as plt - fig = plt.figure() + fig = plt.figure(figsize=(7,7)) ax = plt.subplot(2,1,1, aspect='equal') - mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True) - ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m') + # Plot the location of the spheres for reference + circle1=plt.Circle((loc[0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) + circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) + ax.add_artist(circle1) + ax.add_artist(circle2) + + dat = mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', + ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()])) + + ax.set_title('3-D model') plt.gca().set_aspect('equal', adjustable='box') - + plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') plt.xlim([-xlim,xlim]) plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - ax = plt.subplot(2,1,2, aspect='equal') + + + pos = ax.get_position() + ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height]) + pos = ax.get_position() + cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set + cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal", + ax = ax, ticks=np.linspace(np.log10(sig.min()), + np.log10(sig.max()), 3), format="$10^{%.1f}$") + cb.set_label("Conductivity (S/m)",size=12) + cb.ax.tick_params(labelsize=12) + + # Second plot for the predicted apparent resistivity data + ax2 = plt.subplot(2,1,2, aspect='equal') # Plot the location of the spheres for reference - circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) - circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) - ax.add_artist(circle1) - ax.add_artist(circle2) - + circle1=plt.Circle((loc[0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) + circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) + ax2.add_artist(circle1) + ax2.add_artist(circle2) + + # Add the speudo section - DC.plot_pseudoSection(survey2D,ax,stype) + dat = DC.plot_pseudoSection(survey2D,ax2,stype) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') # plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') # plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') + ax2.set_title('Apparent Conductivity data') + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - plt.show() return fig, ax From 636d178fbf06ccdc30cd4bb8833bbce0e5d3a204 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Wed, 6 Apr 2016 16:19:39 -0700 Subject: [PATCH 33/56] removed examples that are in Examples PR --- SimPEG/Directives.py | 48 +- SimPEG/Examples/EM_FDEM_SusEffects.py | 148 ---- .../Examples/MT_1D_analytic_nlayer_Earth.py | 443 ---------- SimPEG/Examples/__init__.py | 5 +- .../Examples/sphereElectrostatic_example.py | 775 ------------------ docs/examples/EM_FDEM_SusEffects.rst | 41 - docs/examples/MT_1D_analytic_nlayer_Earth.rst | 21 - 7 files changed, 25 insertions(+), 1456 deletions(-) delete mode 100644 SimPEG/Examples/EM_FDEM_SusEffects.py delete mode 100644 SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py delete mode 100644 SimPEG/Examples/sphereElectrostatic_example.py delete mode 100644 docs/examples/EM_FDEM_SusEffects.rst delete mode 100644 docs/examples/MT_1D_analytic_nlayer_Earth.rst diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index acccb224..8f93c70a 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -242,10 +242,10 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # """SaveOutputDictEveryIteration # A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). # """ -# +# # def initialize(self): # print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName -# +# # def endIter(self): # # Save the data. # ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) @@ -266,11 +266,11 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # phi_mz = 0.5 * mz.dot(mz) # else: # phi_mz = 'NaN' -# -# +# +# # # Save the file as a npz # np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) -# +# #============================================================================== # class UpdateReferenceModel(Parameter): @@ -292,12 +292,12 @@ class update_IRLS(InversionDirective): gamma = None phi_m_last = None phi_d_last = None - + def initialize(self): # Scale the regularization for changes in norm if getattr(self, 'phi_m_last', None) is not None: - + self.reg.curModel = self.invProb.curModel self.reg.gamma = 1. phim_new = self.reg.eval(self.invProb.curModel) @@ -305,10 +305,10 @@ class update_IRLS(InversionDirective): self.reg.curModel = self.invProb.curModel self.reg.gamma = self.gamma - + if getattr(self, 'phi_d_last', None) is None: self.phi_d_last = self.invProb.phi_d - + def endIter(self): # Cool the threshold parameter if getattr(self, 'factor', None) is not None: @@ -321,35 +321,35 @@ class update_IRLS(InversionDirective): # Get phi_m at the end of current iteration self.phi_m_last = self.invProb.phi_m_last - + # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - + # Temporarely set gamma to 1. self.reg.gamma = 1. - + # Compute change in model objective function and update scaling phim_new = self.reg.eval(self.invProb.curModel) self.reg.gamma = self.phi_m_last / phim_new - - - # TO DO: Check optimization class, data misfit not matching reality + + + # TO DO: Check optimization class, data misfit not matching reality #dpred = self.prob.fields(self.invProb.curModel) #phid = self.invProb.dmisfit.eval(self.invProb.curModel) #print self.survey.std[0] #print phid #print self.invProb.phi_d #print self.invProb.phi_d_last - + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d class update_lin_PreCond(InversionDirective): - - + + def endIter(self): # Cool the threshold parameter - + if getattr(self.opt, 'approxHinv', None) is not None: # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. @@ -362,20 +362,20 @@ class update_Wj(InversionDirective): Create approx-sensitivity base weighting """ k = None - + def endIter(self): - + if self.opt.iter == 2: m = self.invProb.curModel if self.k is None: self.k = int(self.survey.nD/10) - + def JtJv(v): Jv = self.prob.Jvec(m, v) - + return self.prob.Jtvec(m,Jv) - + JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k) JtJdiag = JtJdiag / max(JtJdiag) diff --git a/SimPEG/Examples/EM_FDEM_SusEffects.py b/SimPEG/Examples/EM_FDEM_SusEffects.py deleted file mode 100644 index 1abbb16f..00000000 --- a/SimPEG/Examples/EM_FDEM_SusEffects.py +++ /dev/null @@ -1,148 +0,0 @@ -from SimPEG import * -from SimPEG import EM -from pymatsolver import MumpsSolver -from scipy.constants import mu_0 - -def run(plotIt=True): - """ - EM: FDEM: Effects of susceptibility - =================================== - - When airborne freqeuncy domain EM (AFEM) survey is flown over - the earth including significantly susceptible bodies (magnetite-rich rocks), - negative data is often observed in the real part of the lowest frequency - (e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization - occurs due to a susceptible body when the magnetic field is applied. - - To clarify what is happening in the earth when we are exciting the earth with - a loop source in the frequency domain we run three forward modelling: - - - F[:math:`\sigma`, :math:`\mu`]: Anomalous conductivity and susceptibility - - F[:math:`\sigma`, :math:`\mu_0`]: Anomalous conductivity - - F[:math:`\sigma_{air}`, :math:`\mu_0`]: primary field - - We plot vector magnetic fields in the earth. For secondary fields we provide - F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following - figure show both real and parts. - - """ - # Generate Cylindrical mesh - cs, ncx, ncz, npad = 5, 25, 24, 20. - hx = [(cs,ncx), (cs,npad,1.3)] - hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)] - mesh = Mesh.CylMesh([hx,1,hz], '00C') - sighalf = 1e-3 - sigma = np.ones(mesh.nC)*1e-8 - sigmahomo = sigma.copy() - mu = np.ones(mesh.nC)*mu_0 - sigma[mesh.gridCC[:,-1]<0.] = sighalf - blkind = np.logical_and(mesh.gridCC[:,0]<30., (mesh.gridCC[:,2]<0)&(mesh.gridCC[:,2]>-150)&(mesh.gridCC[:,2]<-50)) - sigma[blkind] = 1e-1 - mu[blkind] = mu_0*1.1 - offset = 0. - frequency = np.r_[10., 100., 1000.] - rx0 = EM.FDEM.Rx(np.array([[8., 0., 30.]]), 'bzr') - rx1 = EM.FDEM.Rx(np.array([[8., 0., 30.]]), 'bzi') - srcLists = [] - nfreq = frequency.size - for ifreq in range(nfreq): - src = EM.FDEM.Src.CircularLoop([rx0, rx1], frequency[ifreq], np.array([[0., 0., 30.]]), radius=5.) - srcLists.append(src) - survey = EM.FDEM.Survey(srcLists) - iMap = Maps.IdentityMap(nP=int(mesh.nC)) - # Use PhysPropMap - maps = [('sigma', iMap), ('mu', iMap)] - prob = EM.FDEM.Problem_b(mesh, mapping=maps) - prob.Solver = MumpsSolver - survey.pair(prob) - m = np.r_[sigma, mu] - survey0 = EM.FDEM.Survey(srcLists) - prob0 = EM.FDEM.Problem_b(mesh, mapping=maps) - prob0.Solver = MumpsSolver - survey0.pair(prob0) - m = np.r_[sigma, mu] - m0 = np.r_[sigma, np.ones(mesh.nC)*mu_0] - m00 = np.r_[np.ones(mesh.nC)*1e-8, np.ones(mesh.nC)*mu_0] - # Anomalous conductivity and susceptibility - F = prob.fields(m) - # Only anomalous conductivity - F0 = prob.fields(m0) - # Primary field - F00 = prob.fields(m00) - - if plotIt: - import matplotlib.pyplot as plt - def vizfields(ifreq=0, primsec="secondary",realimag="real"): - - titles = ["F[$\sigma$, $\mu$]", "F[$\sigma$, $\mu_0$]", "F[$\sigma$, $\mu$]-F[$\sigma$, $\mu_0$]"] - actind = np.logical_and(mesh.gridCC[:,0]<200., (mesh.gridCC[:,2]>-400)&(mesh.gridCC[:,2]<200)) - - if primsec=="secondary": - bCCprim = (mesh.aveF2CCV*F00[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - bCC = (mesh.aveF2CCV*F[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F')-bCCprim - bCC0 = (mesh.aveF2CCV*F0[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F')-bCCprim - elif primsec=="primary": - bCC = (mesh.aveF2CCV*F[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - bCC0 = (mesh.aveF2CCV*F0[:,'b'][:,ifreq]).reshape(mesh.nC, 2, order='F') - - XYZ = mesh.gridCC[actind,:] - X = XYZ[:,0].reshape((31,43), order='F') - Z = XYZ[:,2].reshape((31,43), order='F') - bx = bCC[actind,0].reshape((31,43), order='F') - bz = bCC[actind,1].reshape((31,43), order='F') - bx0 = bCC0[actind,0].reshape((31,43), order='F') - bz0 = bCC0[actind,1].reshape((31,43), order='F') - - bxsec = (bCC[actind,0]-bCC0[actind,0]).reshape((31,43), order='F') - bzsec = (bCC[actind,1]-bCC0[actind,1]).reshape((31,43), order='F') - - absbreal = np.sqrt(bx.real**2+bz.real**2) - absbimag = np.sqrt(bx.imag**2+bz.imag**2) - absb0real = np.sqrt(bx0.real**2+bz0.real**2) - absb0imag = np.sqrt(bx0.imag**2+bz0.imag**2) - - absbrealsec = np.sqrt(bxsec.real**2+bzsec.real**2) - absbimagsec = np.sqrt(bxsec.imag**2+bzsec.imag**2) - - fig = plt.figure(figsize=(15,5)) - ax1 = plt.subplot(131) - ax2 = plt.subplot(132) - ax3 = plt.subplot(133) - typefield="real" - scale=20 - if realimag=="real": - ax1.contourf(X, Z,np.log10(absbreal), 100) - ax1.quiver(X, Z,bx.real/absbreal,bz.real/absbreal,scale=scale,width=0.005, alpha = 0.5) - ax2.contourf(X, Z,np.log10(absb0real), 100) - ax2.quiver(X, Z,bx0.real/absb0real,bz0.real/absb0real,scale=scale,width=0.005, alpha = 0.5) - ax3.contourf(X, Z,np.log10(absbrealsec), 100) - ax3.quiver(X, Z,bxsec.real/absbrealsec,bzsec.real/absbrealsec,scale=scale,width=0.005, alpha = 0.5) - elif realimag=="imag": - ax1.contourf(X, Z,np.log10(absbimag), 100) - ax1.quiver(X, Z,bx.imag/absbimag,bz.imag/absbimag,scale=scale,width=0.005, alpha = 0.5) - ax2.contourf(X, Z,np.log10(absb0imag), 100) - ax2.quiver(X, Z,bx0.imag/absb0imag,bz0.imag/absb0imag,scale=scale,width=0.005, alpha = 0.5) - ax3.contourf(X, Z,np.log10(absbimagsec), 100) - ax3.quiver(X, Z,bxsec.imag/absbimagsec,bzsec.imag/absbimagsec,scale=scale,width=0.005, alpha = 0.5) - - ax = [ax1, ax2, ax3] - ax3.text(30, 50, ("Frequency=%5.2f Hz")%(frequency[ifreq]), color="k", fontsize=18) - ax2.text(30, 50, primsec, color="k", fontsize=18) - ax1.text(30, 50, realimag, color="k", fontsize=18) - for i, axtemp in enumerate(ax): - axtemp.plot(np.r_[0, 29.75], np.r_[-50, -50], 'w', lw=3) - - axtemp.plot(np.r_[29.5, 29.5], np.r_[-50, -142.5], 'w', lw=3) - axtemp.plot(np.r_[0, 29.5], np.r_[-142.5, -142.5], 'w', lw=3) - axtemp.plot(np.r_[0, 100.], np.r_[0, 0], 'w', lw=3) - axtemp.set_ylim(-200, 100.) - axtemp.set_xlim(10, 100.) - axtemp.set_title(titles[i]) - plt.show() - return fig, ax - fig1, ax1 = vizfields(1, primsec="primary", realimag="real") - fig2, ax2 = vizfields(1, primsec="secondary", realimag="real") - fig4, ax4 = vizfields(1, primsec="secondary", realimag="imag") - -if __name__ == '__main__': - run() diff --git a/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py b/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py deleted file mode 100644 index 0cccc5f1..00000000 --- a/SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py +++ /dev/null @@ -1,443 +0,0 @@ -from scipy.constants import epsilon_0, mu_0 -import matplotlib.pyplot as plt -import numpy as np -from ipywidgets import * -#from SimPEG.EM.Utils import k, omega - -""" -MT1D: n layered earth problem -***************************** - -Author: Thibaut Astic -Contact: thast@eos.ubc.ca -Date: January 2016 - -This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics). - -We start by looking at Maxwell's equations in the electric -field \\\(\\\mathbf{E}\\) and the magnetic flux -\\\(\\\mathbf{H}\\) to write the wave equations -\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) & -\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\) - -Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of -\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\) -\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\) - -With U and D the Up and Down components of the E-field. - -The iteration from one layer to another is ensure by: - -\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) = - P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\) - -And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0) -and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability) - -The layer 0 is assumed to be the air layer. - -""" - -#Frequency conversion -omega = lambda f: 2.*np.pi*f - -#Evaluate k wavenumber -k = lambda mu,sig,eps,f: np.sqrt(mu*mu_0*eps*epsilon_0*(2.*np.pi*f)**2.-1.j*mu*mu_0*sig*omega(f)) - -#Define a frquency range for a survey -frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.) - -#Functions to create random physical Perties for a n-layered earth -thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]), - np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1) - ,decimals =1)) - -sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]), - np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1) - ,decimals=3)) - -mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]), - np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1) - ,decimals=1)) - -eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]), - np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1) - ,decimals=1)) - -#Evaluate Impedance Z of a layer -ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k - -#Complex Cole-Cole Conductivity - EM utils -PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c))) - - -#Converted thickness array into top of layer array -def top(thick): - topv= np.zeros(len(thick)+1) - - topv[0]=-thick[0] - - for i in range(1,len(topv),1): - topv[i] = topv[i-1] + thick[i-1] - - return topv - -#Propagation Matrix and theirs inverses - -#matrix T for transition of Up and Down components accross a layer -T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_') - -Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_') - -#transition of Up and Down components accross a layer -UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD - - -#matrix P relating Up and Down components with E and H fields -P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_') - -Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2. - - -#Time Variation of E and H -E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D) -H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U) - -#Plot the configuration of the problem -def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z): - - topn = top(thick) - widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.) - - ax.set_ylim([z.min(),z.max()]) - ax.set_xlim([-widthg,widthg]) - - ax.set_ylabel("Depth (m)", fontsize=16.) - ax.yaxis.tick_right() - ax.yaxis.set_label_position("right") - - #define filling for the different layers - hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ] - - #Write the physical properties of air - ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)), - xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data', - xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[0]), - xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', - xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1i")%(mu[0]), - xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data', - xytext=(0, -np.abs(z.max())/3.), textcoords='data', - fontsize=14.) - - #Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern - for i in range(1,len(topn)-1,1): - if topn[i] == topn[i+1]: - pass - else: - ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)), - xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[i]), - xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1.2f")%(mu[i]), - xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data', - xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data', - fontsize=14.) - - ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black') - ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10]) - - #Write the physical properties of the n-th layer and fill it with pattern - ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black') - ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10]) - - ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)), - xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]), - xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]), - xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data', - xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data', - fontsize=14.) - - #plot Trees! - ax.annotate("", - xy=(widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(1.2*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.) - ) - - ax.annotate("", - xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data', - xytext=(1.5*widthg/2., 0.), textcoords='data', - arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.) - ) - - - ax.invert_yaxis() - - return ax - -#Propagate Up and Down component for a certain frequency & evaluate E and H field - -def Propagate(f,H,sig,chg,taux,c,mu,eps,n): - - sigcm = np.zeros_like(sig,dtype='complex_') - - for j in range(1,len(sig)): - sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f) - - K = k(mu,sigcm,eps,f) - Z = ImpZ(f,mu,K) - - EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') - UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_') - - UD[1,-1] = 1. - - for i in range(-2,-(n+2),-1): - - UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1] - UD = UD/((np.abs(UD[0,:]+UD[1,:])).max()) - - for j in range(0,n+1): - EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j] - - return UD, EH, Z ,K - - -#Evaluate the apparent resistivity and phase for a frequency range -def appres(F,H,sig,chg,taux,c,mu,eps,n): - - Res = np.zeros_like(F) - Phase = np.zeros_like(F) - App_ImpZ= np.zeros_like(F,dtype='complex_') - - for i in range(0,len(F)): - - UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n) - - App_ImpZ[i] = EH[0,1]/EH[1,1] - - Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i])) - Phase[i] = np.angle(App_ImpZ[i], deg = True) - - return Res,Phase - -#Evaluate Up, Down components, E and H field, for a frequency range, -#a discretized depth range and a time range (use to calculate envelope) -def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample): - - topc = top(H) - - layer = np.zeros(len(zsample),dtype=np.int)-1 - - Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_') - UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_') - - for i in range(0,n+1,1): - layer = layer+(zsample>=topc[i])*1 - - for j in range(0,len(F)): - - UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n) - - for p in range(0,len(zsample)): - - UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]]) - - for q in range(0,len(tsample)): - - Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F) - Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F) - Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) - Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F) - - return Exzt,Hyzt,Uz,Dz,UDaux,layer - - -#Function to Plot Apparent Resistivity and Phase -def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope): - - Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n) - - fig,ax = plt.subplots(1,2,figsize=(16,10)) - - ax[0].scatter(Res,F,color='black') - ax[0].set_xscale('Log') - ax[0].set_yscale('Log') - ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)]) - ax[0].set_ylim([F.min(),F.max()]) - ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black") - ax[0].set_ylabel('Frequency (Hz)',fontsize=16.) - ax[0].grid(which='major') - - ax0 = ax[0].twiny() - - ax0.set_xlim([0.,90.]) - ax0.set_ylim([F.min(),F.max()]) - ax0.scatter(Phase,F,color='purple') - ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple") - - zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.) - - ax[0].tick_params(labelsize=16) - ax[1].tick_params(labelsize=16) - ax0.tick_params(labelsize=16) - - if PlotEnvelope: - - widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0) - fenvelope1n=np.ones(100)*fenvelope - ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black') - - tc=np.arange(0.,1./fenvelope,0.01/(fenvelope)) - Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc) - - ax1=ax[1].twiny() - - ax[1].tick_params(labelsize=16) - ax1.tick_params(labelsize=16) - - ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16) - - ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16) - - ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))), - np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))), - color='blue', alpha=0.1) - - ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))), - np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))), - color='red', alpha=0.1) - - ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc) - ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) - ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()]) - else: - print 'No envelop (if True, might be slow)' - ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc) - ax[1].get_xaxis().set_ticks([]) - - plt.show() - -#Interactive MT for Notebook -def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope): - - frangn=frange(-5,5,100.) - sig3= np.array([0.,0.001,0.1, 0.001]) - thick3 = np.array([120000.,50.,50.]) - eps3=np.array([1.,1.,1.,1]) - mu3=np.array([1.,1.,1.,1]) - chg3=np.array([0.,0.1,0.,0.2]) - chg3_0=np.array([0.,0.1,0.,0.]) - taux3=np.array([0.,0.1,0.,0.1]) - c3=np.array([1.,1.,1.,1.]) - - sig3[1]=sigl1 - sig3[1]=10.**sig3[1] - sig3[2]=sigl2 - sig3[2]=10.**sig3[2] - sig3[3]=sigl3 - sig3[3]=10.**sig3[3] - mu3[1]=mul1 - mu3[2]=mul2 - mu3[3]=mul3 - eps3[1]=epsl1 - eps3[2]=epsl2 - eps3[3]=epsl3 - thick3[1]=h1 - thick3[2]=h2 - - PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope) - - -def run(n,plotIt=True): - # something to make a plot - - F = frange(-5.,5.,20) - H = thick(50.,100.,n) - sign = sig(-5.,0.,n) - mun = mu(1.,2.,n) - epsn = eps(1.,9.,n) - chg = np.zeros_like(sign) - taux = np.zeros_like(sign) - c = np.zeros_like(sign) - - Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n) - - if plotIt: - - PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True) - - return Res, Phase - -if __name__ == '__main__': - run(3) - - - - - diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index a95bc194..b06bb3a7 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -6,7 +6,6 @@ import DC_Forward_PseudoSection import DC_PseudoSection_Simulation import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace -import EM_FDEM_SusEffects import EM_Schenkel_Morrison_Casing import EM_TDEM_1D_Inversion import FLOW_Richards_1D_Celia1990 @@ -20,12 +19,10 @@ import Mesh_QuadTree_Creation import Mesh_QuadTree_FaceDiv import Mesh_QuadTree_HangingNodes import Mesh_Tensor_Creation -import MT_1D_analytic_nlayer_Earth import MT_1D_ForwardAndInversion import MT_3D_Foward -import sphereElectrostatic_example -__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_FDEM_SusEffects", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_analytic_nlayer_Earth", "MT_1D_ForwardAndInversion", "MT_3D_Foward", "sphereElectrostatic_example"] +__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] ##### AUTOIMPORTS ##### diff --git a/SimPEG/Examples/sphereElectrostatic_example.py b/SimPEG/Examples/sphereElectrostatic_example.py deleted file mode 100644 index 7ff1ead1..00000000 --- a/SimPEG/Examples/sphereElectrostatic_example.py +++ /dev/null @@ -1,775 +0,0 @@ -from scipy.constants import epsilon_0 -import matplotlib.pyplot as plt -import matplotlib.colors as colors -import numpy as np -from SimPEG.Utils import ndgrid, mkvc - -''' -Authors: Thibaut Astic, Lindsey Heagy, Sanna Tyrvainen, Ronghua Peng -Date: December 2015 - -This code defines function to resolve analytically the electrostatic sphere problem. -We first define a problem configuration, with a conductive or resistive sphere in a -wholespace background. -We then calculate the potential, then the electric field, then the current density and -finally the charges accumulation. - -Several plotting functions are defined for data visualisation. - - -''' - -# Plot options -ftsize_title = 18 #font size for titles -ftsize_axis = 14 #font size for axis ticks -ftsize_label = 14 #font size for axis labels - -# Radius function, useful sigma ratio, and log scale converter -r = lambda x,y,z: np.sqrt(x**2.+y**2.+z**2.) -sigf = lambda sig0,sig1: (sig1-sig0)/(sig1+2.*sig0) - -#tools to convert log conductivity in conductivity -def conductivity_log_wrapper(log_sig0,log_sig1): - sig0 = 10.**log_sig0 - sig1 = 10.**log_sig1 - - return sig0,sig1 - -# Examples -#Plot the configuration. Label=False is used to generate a general case figure -def get_Setup(XYZ,sig0,sig1,R,E0,ax,label,colorsphere): - ''' - XYZ: ndgrid - sig0: conductivity of the background - sig1: conductivity of the sphere - R: radius of the sphere - E0: Amplitude of the uniform electrostatic field - ax: ax where to plot the configuration - label: True: plot real values, False: plot general case - colorsphere: color of the sphere, format [x,x,x] - ''' - - xplt = np.linspace(-R, R, num=100) - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - dx = xr[1]-xr[0] - top = np.sqrt(R**2-xplt**2) - bot = -np.sqrt(R**2-xplt**2) - - if R != 0: - ax.plot(xplt, top, xplt, bot, color=colorsphere,linewidth=1.5) - ax.fill_between(xplt,bot,top,color=colorsphere,alpha=0.5 ) - ax.arrow(0.,0.,np.sqrt(2.)*R/2.,np.sqrt(2.)*R/2.,head_width=0.,head_length=0.) - - if label: - ax.annotate(("$\sigma_1$=%3.3f mS/m")%(sig1*10.**(3.)), - xy=(0.,-R/2.), xycoords='data', - xytext=(0.,-R/2.), textcoords='data', - fontsize=14.) - ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), - xy=(0.,-1.5*R), xycoords='data', - xytext=(0.,-1.5*R), textcoords='data', - fontsize=14.) - ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.annotate(('$R$ = %1i m')%(R), - xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', - xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', - fontsize=14.) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - - else: - ax.set_xticklabels([]) - ax.set_yticklabels([]) - ax.text(-1.,-np.sqrt(R)/2.-10.,'$\sigma_1$',fontsize=14) - ax.text(-0.05,-R-10,'$\sigma_0$',fontsize=14) - ax.annotate(('$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m'), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.annotate(('$R$'), - xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data', - xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data', - fontsize=14.) - ax.set_xlabel('x',fontsize=12) - ax.set_ylabel('y',fontsize=12) - - else: - if label: - ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)), - xy=(0.,-1.5*R), xycoords='data', - xytext=(0.,-1.5*R), textcoords='data', - fontsize=14.) - ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0), - xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data', - xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data', - fontsize=14.) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - - else: - ax.set_xticklabels([]) - ax.set_yticklabels([]) - ax.text(-0.05,-10,'$\sigma_0$',fontsize=14) - ax.text(xr.min()+np.abs(xr.max()-xr.min())/20., 0, '$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m', fontsize=14) - ax.set_xlabel('x',fontsize=12) - ax.set_ylabel('y',fontsize=12) - - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - [ax.arrow(xr.min(),_,np.abs(xr.max()-xr.min())/20.,0.,head_width=5.,head_length=2.,color='k') for _ in np.linspace(yr.min(),yr.max(),num=10)] - ax.patch.set_facecolor([0.4,0.7,0.4]) - ax.patch.set_alpha(0.2) - - ax.set_aspect('equal') - - - - return ax - -def get_Conductivity(XYZ,sig0,sig1,R): - ''' - Define the conductivity for each point of the space - ''' - x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] - r_view=r(x,y,z) - - ind0= (r_view>R) - ind1= (r_view<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Sigma = np.zeros_like(x) - - Sigma[ind0] = sig0 - Sigma[ind1] = sig1 - - return Sigma - - -def get_Potential(XYZ,sig0,sig1,R,E0): - - ''' - Function that returns the total, the primary and the secondary potentials, assumes an x-oriented inducing field and that the sphere is at the origin - :input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field - ''' - - x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2] - - sig_cur = sigf(sig0,sig1) - - r_cur = r(x,y,z) # current radius - - ind0 = (r_cur > R) - ind1 = (r_cur <= R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Vt = np.zeros_like(x) - Vp = np.zeros_like(x) - Vs = np.zeros_like(x) - - Vt[ind0] = -E0*x[ind0]*(1.-sig_cur*R**3./r_cur[ind0]**3.) # total potential outside the sphere - Vt[ind1] = -E0*x[ind1]*3.*sig0/(sig1+2.*sig0) # inside the sphere - - - Vp = - E0*x # primary potential - - Vs = Vt - Vp # secondary potential - - return Vt,Vp,Vs - -#plot the primary potential on ax -def Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - Pplot = ax.pcolor(xr,yr,Vp.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Primary Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - -#plot the total potential on ax -def Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - - Pplot = ax.pcolor(xr,yr,Vt.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Total Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - -#plot the secondary potential on ax -def Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax): - - Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - Pplot = ax.pcolor(xr,yr,Vs.reshape(xr.size,yr.size)) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Secondary Potential',fontsize=ftsize_title) - cb = plt.colorbar(Pplot,ax=ax) - cb.set_label(label= 'Potential ($V$)',size=ftsize_label) - cb.ax.tick_params(labelsize=ftsize_axis) - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.set_aspect('equal') - ax.tick_params(labelsize=ftsize_axis) - - return ax - - -def get_ElectricField(XYZ,sig0,sig1,R,E0): - ''' - Function that returns the total, the primary and the secondary electric fields, - input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - r_cur=r(x,y,z) # current radius - - ind0= (r_cur>R) - ind1= (r_cur<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Ep = np.zeros(shape=(len(x),3)) - Ep[:,0] = E0 - - Et = np.zeros(shape=(len(x),3)) - - Et[ind0,0] = E0 + E0*R**3./(r_cur[ind0]**5.)*sigf(sig0,sig1)*(2.*x[ind0]**2.-y[ind0]**2.-z[ind0]**2.); - Et[ind0,1] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*y[ind0]*sigf(sig0,sig1); - Et[ind0,2] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*z[ind0]*sigf(sig0,sig1); - - Et[ind1,0] = 3.*sig0/(sig1+2.*sig0)*E0; - Et[ind1,1] = 0.; - Et[ind1,2] = 0.; - - Es = Et - Ep - - return Et, Ep, Es - -#plot the total electric field on ax -def Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax): - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - EtXr = Et[:,0].reshape(xr.size, yr.size) - EtYr = Et[:,1].reshape(xr.size, yr.size) - EtAmp = np.sqrt(Et[:,0]**2+Et[:,1]**2 + Et[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Eplot = ax.pcolor(xr,yr,EtAmp) - cb = plt.colorbar(Eplot,ax=ax) - cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,EtXr,EtYr,color='gray',linewidth=2.,density=0.75)#angles='xy',scale_units='xy',scale=0.05) - ax.set_title('Total Field',fontsize=ftsize_title) - - - return ax - -#plot the secondary electric field on ax -def Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax): - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - xcirc = xr[np.abs(xr) <= R] - - EsXr = Es[:,0].reshape(xr.size, yr.size) - EsYr = Es[:,1].reshape(xr.size, yr.size) - EsAmp = np.sqrt(Es[:,0]**2+Es[:,1]**2+Es[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Eplot = ax.pcolor(xr,yr,EsAmp) - cb = plt.colorbar(Eplot,ax=ax) - cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,EsXr,EsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=0.05) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_title('Secondary Field',fontsize=ftsize_title) - - return ax - - -def get_Current(XYZ,sig0,sig1,R,Et,Ep,Es): - ''' - Function that returns the total, the primary and the secondary current densities, - :input: grid, outer sigma, inner sigma, radius of the sphere, total, the primary and the seconadry electric fields, - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - r_cur=r(x,y,z) - - ind0= (r_cur>R) - ind1= (r_cur<=R) - - assert (ind0 + ind1).all(), 'Some indicies not included' - - Jt = np.zeros(shape=(len(x),3)) - J0 = np.zeros(shape=(len(x),3)) - Js = np.zeros(shape=(len(x),3)) - - - Jp = sig0*Ep - - Jt[ind0,:] = sig0*Et[ind0,:] - Jt[ind1,:] = sig1*Et[ind1,:] - - Js[ind0,:] = sig0*(Et[ind0,:]-Ep[ind0,:]) - Js[ind1,:] = sig1*Et[ind1,:]-sig0*Ep[ind1,:] - - return Jt,Jp,Js - -#plot the total currents density on ax -def Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax): - - Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - JtXr = Jt[:,0].reshape(xr.size, yr.size) - JtYr = Jt[:,1].reshape(xr.size, yr.size) - JtAmp = np.sqrt(Jt[:,0]**2+Jt[:,1]**2+Jt[:,2]**2).reshape(xr.size, yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Jplot = ax.pcolor(xr,yr,JtAmp.reshape(xr.size,yr.size)) - cb = plt.colorbar(Jplot,ax=ax) - cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,JtXr,JtYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) - ax.set_title('Total Current Density',fontsize=ftsize_title) - - return ax - - -#plot the secondary currents density on ax -def Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax): - - Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - Jt,Jp,Js = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es) - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - JsXr = Js[:,0].reshape(xr.size, yr.size) - JsYr = Js[:,1].reshape(xr.size, yr.size) - JsAmp = np.sqrt(Js[:,1]**2+Js[:,0]**2+Jt[:,2]**2).reshape(xr.size,yr.size) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_aspect('equal') - - Jplot = ax.pcolor(xr,yr,JsAmp.reshape(xr.size,yr.size)) - cb = plt.colorbar(Jplot,ax=ax) - cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold') - cb.ax.tick_params(labelsize=ftsize_axis) - ax.streamplot(xr,yr,JsXr,JsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1) - ax.set_title('Secondary Current Density',fontsize=ftsize_title) - - return ax - - -def get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep): - ''' - Function that returns the charges accumulation at the background/sphere interface, - :input: grid, outer sigma, inner sigma, radius of the sphere, total and the primary electric fields, - ''' - - x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2] - - dx = x[1]-x[0] - - r_cur=r(x,y,z) - - ind0 = (r_cur > R) - ind1 = (r_cur < R) - ind2 = ((r_cur < (R+dx/2)) & (r_cur > (R-dx/2)) ) - - assert (ind0 + ind1 + ind2).all(), 'Some indicies not included' - - rho = np.zeros_like(x) - - rho[ind0] = 0 - rho[ind1] = 0 - rho[ind2] = epsilon_0*3.*Ep[ind2,0]*sigf(sig0,sig1)*x[ind2]/(np.sqrt(x[ind2]**2.+y[ind2]**2.)) - - return rho - -#Plot charges density on ax -def Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax): - - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - xcirc = xr[np.abs(xr) <= R] - - Et, Ep, Es = get_ElectricField(XYZ,sig0,sig1,R,E0) - rho = get_ChargesDensity(XYZ,sig0,sig1,R,Et,Ep) - - ax.set_xlim([xr.min(),xr.max()]) - ax.set_ylim([yr.min(),yr.max()]) - ax.set_aspect('equal') - Cplot = ax.pcolor(xr,yr,rho.reshape(xr.size, yr.size)) - cb1 = plt.colorbar(Cplot,ax=ax) - cb1.set_label(label= 'Charge Density ($C/m^2$)',size=ftsize_label) #weight='bold') - cb1.ax.tick_params(labelsize=ftsize_axis) - ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k') - ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label) - ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label) - ax.tick_params(labelsize=ftsize_axis) - ax.set_title('Charges Density', fontsize=ftsize_title) - - return ax - -def MN_Potential_total(sig0,sig1,R,E0,start,end,nbmp,mn): - - ''' - Function that return array of midpoints electrodes, electrodes positions, - potentials differences for total and secondary potentials fields, unormalized and - normalized to electrodes distances. - sig0: background conductivity - sig1: sphere conductivity - R: Sphere's radius - E0: uniform E field value - start: start point for the profile start.shape = (2,) - end: end point for the profile end.shape = (2,) - nbmp: number of dipoles - mn: Space between the M and N electrodes - ''' - - #D: total distance from start to end - D = np.sqrt((start[0]-end[0])**2.+(start[1]-end[1])**2.) - - #MP: dipoles'midpoint positions (x,y) - MP = np.zeros(shape=(nbmp,2)) - MP[:,0] = np.linspace(start[0],end[0],nbmp) - MP[:,1] = np.linspace(start[1],end[1],nbmp) - - #Dipoles'Electrodes positions around each midpoints - EL = np.zeros(shape=(2*nbmp,2)) - for n in range(0,len(EL),2): - EL[n,0] = MP[n/2,0] - ((end[0]-start[0])/D)*mn/2. - EL[n+1,0] = MP[n/2,0] + ((end[0]-start[0])/D)*mn/2. - EL[n,1] = MP[n/2,1] - ((end[1]-start[1])/D)*mn/2. - EL[n+1,1] = MP[n/2,1] + ((end[1]-start[1])/D)*mn/2. - - VtEL = np.zeros(2*nbmp) #Total Potential (Vt-) at each electrode (-EL) - VsEL = np.zeros(2*nbmp) #Secondary Potential (Vt-) at each electrode (-EL) - dVtMP = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) - dVtMPn = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - dVsMP = np.zeros(nbmp) #Diffence (d-) of Secondaty Potential (Vt-) at each dipole (-MP) - dVsMPn = np.zeros(nbmp) #Diffence (d-) of Secondary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - dVpMP = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) - dVpMPn = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n) - - #Computing VtEL - for m in range(0,2*nbmp): - if (r(EL[m,0],EL[m,1],0) > R): - VtEL[m] = -E0*EL[m,0]*(1.-sigf(sig0,sig1)*R**3./r(EL[m,0],EL[m,1],0)**3.) - else: - VtEL[m] = -E0*EL[m,0]*3.*sig0/(sig1+2.*sig0) - - #Computing VsEL - VsEL = VtEL + E0*EL[:,0] - - #Computing dVtMP, dVsMP - for p in range(0,nbmp): - dVtMP[p] = VtEL[2*p]-VtEL[2*p+1] - dVtMPn[p] = dVtMP[p]/mn - dVsMP[p] = VsEL[2*p]-VsEL[2*p+1] - dVsMPn[p] = dVsMP[p]/mn - - return MP,EL,dVtMP,dVtMPn,dVsMP,dVsMPn - -#Compare the DC response of two configurations -def two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,nb_dipole,electrode_spacing,PlotOpt):#,linearcolor): - - #Define the mesh - xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2]) - - #Defining the Profile - start = np.array([xstart,ystart]) - end = np.array([xend,yend]) - - #Calculating the data from the defined survey line for Configuration 0 and 1 - MP0,EL0,VtdMP0,VtdMPn0,VsdMP0,VsdMPn0 = MN_Potential_total(sig0,sig1,R0,E0,start,end,nb_dipole,electrode_spacing) - MP1,EL1,VtdMP1,VtdMPn1,VsdMP1,VsdMPn1 = MN_Potential_total(sig0,sig2,R1,E0,start,end,nb_dipole,electrode_spacing) - - - # Initializing the figure - fig = plt.figure(figsize=(20,20)) - ax0 = plt.subplot2grid((20,12), (0, 0),colspan=6,rowspan=6) - ax1 = plt.subplot2grid((20,12), (0, 6),colspan=6,rowspan=6) - ax2 = plt.subplot2grid((20,12), (16, 2), colspan=9,rowspan=4) - ax3 = plt.subplot2grid((20,12), (8, 0),colspan=6,rowspan=6) - ax4 = plt.subplot2grid((20,12), (8, 6),colspan=6,rowspan=6) - - #Plotting the Configuration 0 - ax0 = get_Setup(XYZ,sig0,sig1,R0,E0,ax0,True,[0.6,0.1,0.1]) - - #Plotting the Configuration 1 - ax1 = get_Setup(XYZ,sig0,sig2,R1,E0,ax1,True,[0.1,0.1,0.6]) - - #Plotting the Data (Legends) - ax2.set_title('Potential Differences',fontsize=ftsize_title) - ax2.set_ylabel('Potential difference ($V$)',fontsize=ftsize_label) - ax2.set_xlabel('Distance from start point ($m$)',fontsize=ftsize_label) - ax2.tick_params(labelsize=ftsize_axis) - ax2.grid() - - if PlotOpt == 'Total': - ax3= Plot_Total_Potential(XYZ,sig0,sig1,R0,E0,ax3) - ax4= Plot_Total_Potential(XYZ,sig0,sig2,R1,E0,ax4) - - #Plot the Data (from Configuration 0) - gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VtdMP0 - ,marker='o',color='blue',linewidth=3.,label ='Left Model Response' ) - - #Plot the Data (from Configuration 1) - gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VtdMP1 - ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) - ax2.legend(('Left Model Response','Right Model Response'),loc=4) - - elif PlotOpt == 'Secondary': - #plot the secondary potentials - ax3= Plot_Secondary_Potential(XYZ,sig0,sig1,R0,E0,ax3) - ax4= Plot_Secondary_Potential(XYZ,sig0,sig2,R1,E0,ax4) - - #Plot the data(from configuration 0) - gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VsdMP0,color='blue' - ,marker='o',linewidth=3.,label ='Left Model Response' ) - - - #Plot the Data (from Configuration 1) - gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VsdMP1 - ,marker='o',color='red',linewidth=2.,label ='Right Model Response' ) - ax2.legend(('Left Model Response','Right Model Response'),loc=4 ) - - else: - print('What dont you get? Total or Secondary?') - - #Legends - ax3.plot(MP0[:,0],MP0[:,1],color='gray') - Dip_Midpoint0 = ax3.scatter(MP0[:,0],MP0[:,1],color='black') - Electrodes0 = ax3.scatter(EL0[:,0],EL0[:,1],color='red') - ax3.legend([Dip_Midpoint0,Electrodes0], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) - - ax4.plot(MP1[:,0],MP1[:,1],color='gray') - Dip_Midpoint1 = ax4.scatter(MP1[:,0],MP1[:,1],color='black') - Electrodes1 = ax4.scatter(EL1[:,0],EL1[:,1],color='red') - ax4.legend([Dip_Midpoint1,Electrodes1], ["Dipole Midpoint", "Electrodes"],scatterpoints=1) - - return fig - -#Function to visualise and compare any two meaningful plots for the sphere in a uniform backgound with an unifom Electric Field -def interact_conductiveSphere(R,log_sig0,log_sig1,Figure1a,Figure1b,Figure2a,Figure2b): - - sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) - E0 = 1. # inducing field strength in V/m - n = 100 #level of discretisation - xr = np.linspace(-200., 200., n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - - fig, ax = plt.subplots(1,2,figsize=(18,6)) - - #Setup figure 1 with options Configuration, Total or Secondary, - #then Potential, ElectricField, Current Density or Charges Density - if Figure1a == 'Configuration': - ax[0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0],True,[0.1,0.1,0.6]) - - elif Figure1a == 'Total': - - if Figure1b == 'Potential': - ax[0] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ElectricField': - ax[0] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'CurrentDensity': - ax[0] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ChargesDensity': - ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1a == 'Secondary': - - if Figure1b == 'Potential': - ax[0] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ElectricField': - ax[0] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'CurrentDensity': - ax[0] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[0]) - - elif Figure1b == 'ChargesDensity': - ax[0] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[0]) - - - if Figure1a== 'Configuration': - ax[1] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - print 'While figure1 is plotting Configuration, figure2 plots the primary field' - - elif Figure2a == 'Total': - if Figure2b == 'Potential': - ax[1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ElectricField': - ax[1] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'CurrentDensity': - ax[1]=Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ChargesDensity': - ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) - - - elif Figure2a == 'Secondary': - if Figure2b == 'Potential': - ax[1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ElectricField': - ax[1] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'CurrentDensity': - ax[1] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1]) - - elif Figure2b == 'ChargesDensity': - ax[1] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1]) - - plt.tight_layout(True) - plt.show() - -#Interactive Visualisation of the responses of two configurations to a (pseudo) DC resistivity survey -def interactive_two_configurations_comparison(log_sig0,log_sig1,log_sig2,R0,R1,xstart,ystart,xend,yend,dipole_number,electrode_spacing,matching_spheres_example): - - sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1) - sig2 = 10.**log_sig2 - E0 = 1. # inducing field strength in V/m - n = 100 #level of discretisation - xr = np.linspace(-200., 200., n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - PlotOpt = 'Total' - - if matching_spheres_example: - sig0 = 10.**(-3) - sig1 = 10.**(-2) - sig2 = 1.310344828 * 10**(-3) - R0 = 20. - R1 = 40. - - two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) - - else: - two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt) - - plt.tight_layout(True) - plt.show() - - - -if __name__ == '__main__': - sig0 = -3. # conductivity of the wholespace - sig1 = -1. # conductivity of the sphere - sig0, sig1 = conductivity_log_wrapper(sig0,sig1) - R = 50. # radius of the sphere - E0 = 1. # inducing field strength - n = 100 #level of discretisation - xr = np.linspace(-2.*R, 2.*R, n) # X-axis discretization - yr = xr.copy() # Y-axis discretization - zr = np.r_[0] # identical to saying `zr = np.array([0])` - XYZ = ndgrid(xr,yr,zr) # Space Definition - - fig, ax = plt.subplots(2,5,figsize=(50,10)) - ax[0,0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0,0],True,[0.6,0.1,0.1]) - ax[1,0] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[1,0]) - ax[0,1] = Plot_Total_Potential(XYZ,sig0,sig1,R,E0,ax[0,1]) - ax[1,1] = Plot_Secondary_Potential(XYZ,sig0,sig1,R,E0,ax[1,1]) - ax[0,2] = Plot_Total_ElectricField(XYZ,sig0,sig1,R,E0,ax[0,2]) - ax[1,2] = Plot_Secondary_ElectricField(XYZ,sig0,sig1,R,E0,ax[1,2]) - ax[0,3] = Plot_Total_Currents(XYZ,sig0,sig1,R,E0,ax[0,3]) - ax[1,3] = Plot_Secondary_Currents(XYZ,sig0,sig1,R,E0,ax[1,3]) - ax[0,4] = Plot_Primary_Potential(XYZ,sig0,sig1,R,E0,ax[0,4]) - ax[1,4] = Plot_ChargesDensity(XYZ,sig0,sig1,R,E0,ax[1,4]) - - - plt.show() - diff --git a/docs/examples/EM_FDEM_SusEffects.rst b/docs/examples/EM_FDEM_SusEffects.rst deleted file mode 100644 index 3e7dea80..00000000 --- a/docs/examples/EM_FDEM_SusEffects.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _examples_EM_FDEM_SusEffects: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - - -EM: FDEM: Effects of susceptibility -=================================== - -When airborne freqeuncy domain EM (AFEM) survey is flown over -the earth including significantly susceptible bodies (magnetite-rich rocks), -negative data is often observed in the real part of the lowest frequency -(e.g. Dighem system 900 Hz). This phenomenon mostly based upon magnetization -occurs due to a susceptible body when the magnetic field is applied. - -To clarify what is happening in the earth when we are exciting the earth with -a loop source in the frequency domain we run three forward modelling: - - - F[:math:`\sigma`, :math:`\mu`]: Anomalous conductivity and susceptibility - - F[:math:`\sigma`, :math:`\mu_0`]: Anomalous conductivity - - F[:math:`\sigma_{air}`, :math:`\mu_0`]: primary field - -We plot vector magnetic fields in the earth. For secondary fields we provide -F[:math:`\sigma`, :math:`\mu`]-F[:math:`\sigma`, :math:`\mu_0`]. Following -figure show both real and parts. - - - -.. plot:: - - from SimPEG import Examples - Examples.EM_FDEM_SusEffects.run() - -.. literalinclude:: ../../SimPEG/Examples/EM_FDEM_SusEffects.py - :language: python - :linenos: diff --git a/docs/examples/MT_1D_analytic_nlayer_Earth.rst b/docs/examples/MT_1D_analytic_nlayer_Earth.rst deleted file mode 100644 index 834121a9..00000000 --- a/docs/examples/MT_1D_analytic_nlayer_Earth.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _examples_MT_1D_analytic_nlayer_Earth: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - -MT 1D analytic nlayer Earth -=========================== - -.. plot:: - - from SimPEG import Examples - Examples.MT_1D_analytic_nlayer_Earth.run() - -.. literalinclude:: ../../SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py - :language: python - :linenos: From 16c6cc8d74ab7ce4e61980cfd009cfedab44dc8f Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 22:17:34 -0700 Subject: [PATCH 34/56] Update speudo plot and allow app_res, app_con, volt --- SimPEG/DCIP/DCIPUtils.py | 80 +++++++++++++-------- SimPEG/Examples/DC_Forward_PseudoSection.py | 54 +++++++------- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index af94ad4e..9b637d82 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): +def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -179,7 +179,7 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): Input: :param d2D, z0 :switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole) - + :switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential) Output: :figure scatter plot overlayed on image @@ -221,25 +221,43 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): Cmid = (Tx[0][0] + Tx[1][0])/2 Pmid = (Rx[0][:,0] + Rx[1][:,0])/2 - # Compute pant leg of apparent rho - if stype == 'pdp': - leg = data * 2*np.pi * MA * ( MA + MN ) / MN + # Change output for dtype + if dtype == 'volt': - leg = np.log10(abs(1/leg)) + rho = np.hstack([rho,data]) - elif stype == 'dpdp': - leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + else: - leg = np.log10(abs(1/leg)) + # Compute pant leg of apparent rho + if stype == 'pdp': + + leg = data * 2*np.pi * MA * ( MA + MN ) / MN + + elif stype == 'dpdp': + + leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA ) + + else: + print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """ + break + + + if dtype == 'appc': + + leg = np.log10(abs(1./leg)) + rho = np.hstack([rho,leg]) + + elif dtype == 'appr': + + leg = np.log10(abs(leg)) + rho = np.hstack([rho,leg]) + + else: + print """dtype must be 'appr' | 'appc' | 'volt' """ + break midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) - #TODO ... let stick to list then finally convert to array. - if dtype =="appr": - rho = np.hstack([rho,leg]) - elif dtype =="voltage": - rho = np.hstack([rho,data]) - ax = axs @@ -260,14 +278,20 @@ def plot_pseudoSection(DCsurvey, axs, stype, dtype="appr",clim=None): ticks = np.linspace(cmin,cmax,3) cbar.set_ticks(ticks) cbar.ax.tick_params(labelsize=10) - cbar.set_label("App. Conductivity",size=12) + + if dtype == 'appc': + cbar.set_label("App.Cond",size=12) + elif dtype == 'appr': + cbar.set_label("App.Res.",size=12) + elif dtype == 'volt': + cbar.set_label("Potential (V)",size=12) # Plot apparent resistivity ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) #ax.set_xticklabels([]) #ax.set_yticklabels([]) - + plt.gca().set_aspect('equal', adjustable='box') @@ -516,7 +540,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): """ - Read DC survey and projects the coordinate system + Read DC survey and projects the coordinate system according to the flag = 'Xloc' | 'Yloc' | 'local' (default) In the 'local' system, station coordinates are referenced to distance from the first srcLoc[0].loc[0] @@ -575,19 +599,19 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): # Find A electrode along line vec, r = r_unit(x0,Tx[ii][0,0:2]) A = stn_id(vecTx,vec,r) - + # Find B electrode along line vec, r = r_unit(x0,Tx[ii][1,0:2]) B = stn_id(vecTx,vec,r) - + M = np.zeros(nrx) N = np.zeros(nrx) for kk in range(nrx): - + # Find all M electrodes along line vec, r = r_unit(x0,Rx[0][kk,0:2]) M[kk] = stn_id(vecTx,vec,r) - + # Find all N electrodes along line vec, r = r_unit(x0,Rx[1][kk,0:2]) N[kk] = stn_id(vecTx,vec,r) @@ -597,14 +621,14 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): B = Tx[ii][1,1] M = Rx[0][:,1] N = Rx[1][:,1] - + elif flag == 'Xloc': """ Copy the rx-tx locs""" A = Tx[ii][0,0] B = Tx[ii][1,0] M = Rx[0][:,0] N = Rx[1][:,0] - + Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]]) srcLists.append( DC.SrcDipole( [Rx], np.asarray([A,0,Tx[ii][0,2]]),np.asarray([B,0,Tx[ii][1,2]]) ) ) @@ -796,15 +820,15 @@ def readUBC_DC2Dpre(fileName): else: tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]] - + if zflag: rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]] - + else: rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan] # Check if there is data with the location - + d.append(temp[-1]) @@ -817,7 +841,7 @@ def readUBC_DC2Dpre(fileName): survey.dobs = np.asarray(d) return {'DCsurvey':survey} - + def readUBC_DC2DMesh(fileName): """ Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 904dcbd3..e1763da6 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -2,19 +2,27 @@ from SimPEG import Mesh, Utils, np, sp import SimPEG.DCIP as DC import time -def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): +def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', plotIt=True): """ DC Forward Simulation ===================== - Forward model conductive spheres in a half-space and plot a pseudo-section - + Forward model two conductive spheres in a half-space and plot a + pseudo-section. Assumes an infinite line source and measures along the + center of the spheres. + + INPUT: + loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] + radi = Radius of spheres [r1,r2] + param = Conductivity of background and two spheres [m0,m1,m2] + stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) + dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) Created by @fourndo on Mon Feb 01 19:28:06 2016 """ assert stype in ['pdp', 'dpdp'], "Source type (stype) must be pdp or dpdp (pole dipole or dipole dipole)" - + assert dtype in ['appr', 'appc', 'volt'], "Data type (dtype) must be appr (app res) or appc (app cond) or volt (potential)" if loc is None: loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]] @@ -27,7 +35,6 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # First we need to create a mesh and a model. - # This is our mesh dx = 5. @@ -52,15 +59,11 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): # Get index of the center indy = int(mesh.nCy/2) - # Plot the model for reference # Define core mesh extent xlim = 200 zlim = 100 - # Specify the survey type: "pdp" | "dpdp" - - # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh ends = [(-175,0),(175,0)] ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] @@ -82,7 +85,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): #Set boundary conditions mesh.setCellGradBC('neumann') - # Define the differential operators needed for the DC problem + # Define the linear system needed for the DC problem. We assume an infitite + # line source for simplicity. Div = mesh.faceDiv Grad = mesh.cellGrad Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) @@ -145,10 +149,9 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): print 'Forward completed' # Let's just convert the 3D format into 2D (distance along line) and plot - # [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc') survey2D.dobs =np.hstack(data) - # Here is an example for the first tx-rx array + if plotIt: import matplotlib.pyplot as plt fig = plt.figure(figsize=(7,7)) @@ -158,29 +161,29 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) ax.add_artist(circle1) ax.add_artist(circle2) - + dat = mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()])) - + ax.set_title('3-D model') plt.gca().set_aspect('equal', adjustable='box') - + plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') plt.xlim([-xlim,xlim]) plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - pos = ax.get_position() + + + pos = ax.get_position() ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height]) pos = ax.get_position() - cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set + cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal", ax = ax, ticks=np.linspace(np.log10(sig.min()), np.log10(sig.max()), 3), format="$10^{%.1f}$") cb.set_label("Conductivity (S/m)",size=12) - cb.ax.tick_params(labelsize=12) - + cb.ax.tick_params(labelsize=12) + # Second plot for the predicted apparent resistivity data ax2 = plt.subplot(2,1,2, aspect='equal') @@ -189,16 +192,15 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): circle2=plt.Circle((loc[0,1],loc[2,1]),radi[1],color='k',fill=False, lw=3) ax2.add_artist(circle1) ax2.add_artist(circle2) - - + # Add the speudo section - dat = DC.plot_pseudoSection(survey2D,ax2,stype) + dat = DC.plot_pseudoSection(survey2D,ax2,stype=stype, dtype = dtype) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') # plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') # plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') - ax2.set_title('Apparent Conductivity data') - + ax2.set_title('Apparent Conductivity data') + plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) plt.show() From 822f6d333d56499398942dcb9be3ab7eda2fe9ef Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 6 Apr 2016 22:29:57 -0700 Subject: [PATCH 35/56] Minor revisions + remove trailing white spaces --- SimPEG/Maps.py | 22 ++++++++++++---------- SimPEG/Survey.py | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/SimPEG/Maps.py b/SimPEG/Maps.py index f6b24f10..f17d2314 100644 --- a/SimPEG/Maps.py +++ b/SimPEG/Maps.py @@ -759,27 +759,29 @@ class PolyMap(IdentityMap): m = [\sigma_1, \sigma_2, c] - """ + Can take in an actInd vector to account for topography. + + """ def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None): IdentityMap.__init__(self, mesh) self.logSigma = logSigma self.order = order - self.normal = normal + self.normal = normal self.actInd = actInd - + if getattr(self, 'actInd', None) is None: self.actInd = range(self.mesh.nC) self.nC = self.mesh.nC - + else: - self.nC = len(self.actInd) - - slope = 1e4 - + self.nC = len(self.actInd) + + slope = 1e4 + @property def shape(self): return (self.nC, self.nP) - + @property def nP(self): if np.isscalar(self.order): @@ -818,7 +820,7 @@ class PolyMap(IdentityMap): f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z else: raise(Exception("Input for normal = X or Y or Z")) - + else: raise(Exception("Only supports 2D")) diff --git a/SimPEG/Survey.py b/SimPEG/Survey.py index f1ec8225..fbc88276 100644 --- a/SimPEG/Survey.py +++ b/SimPEG/Survey.py @@ -375,7 +375,7 @@ class BaseSurvey(object): self.dtrue = self.dpred(m, f=f) noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape) self.dobs = self.dtrue+noise - self.std = self.dobs*0. + std + self.std = self.dobs*0 + std return self.dobs class LinearSurvey(BaseSurvey): From fb60f45a3c5201992969a518ade32c64dd7ccee8 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 08:46:51 -0700 Subject: [PATCH 36/56] Fixed osr import in ediFilesUtils, moved into class which imports only on build up. Fixed the boolean error in Directives. --- SimPEG/Directives.py | 2 +- SimPEG/MT/Utils/ediFilesUtils.py | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 2ed27c20..7e412781 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -255,7 +255,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): mref = 0 mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim==2: + if self.prob.mesh.dim>2: my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_my = 0.5 * my.dot(my) else: diff --git a/SimPEG/MT/Utils/ediFilesUtils.py b/SimPEG/MT/Utils/ediFilesUtils.py index 55818a87..cc8aef8a 100644 --- a/SimPEG/MT/Utils/ediFilesUtils.py +++ b/SimPEG/MT/Utils/ediFilesUtils.py @@ -7,17 +7,21 @@ from SimPEG.MT.Utils.dataUtils import rec2ndarr # Import modules import numpy as np import os, sys, re -try: - import osr -except ImportError as e: - print 'Could not import osr, missing the gdal package' - pass + class EDIimporter: """ A class to import EDIfiles. """ + # Import the coordinate projections + try: + import osr + except ImportError as e: + print 'Could not import osr, missing the gdal package' + raise e + + # Define data converters _impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit _impUnitSI2EDI = 1./_impUnitEDI2SI # ConvertZ[V/A] SI unit to Z[mV/km/nT] (as in EDI) @@ -26,8 +30,8 @@ class EDIimporter: comps = None # Hidden properties - _outEPSG = None - _2out = None + _outEPSG = None # Project info + _2out = None # The projection operator def __init__(self, EDIfilesList, compList=None, outEPSG=None): From f15a628136264bdcf49b86009204be7c81866450 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 09:01:30 -0700 Subject: [PATCH 37/56] Moved the osr import into the projection function. --- SimPEG/MT/Utils/ediFilesUtils.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SimPEG/MT/Utils/ediFilesUtils.py b/SimPEG/MT/Utils/ediFilesUtils.py index cc8aef8a..d8f5e0ad 100644 --- a/SimPEG/MT/Utils/ediFilesUtils.py +++ b/SimPEG/MT/Utils/ediFilesUtils.py @@ -14,12 +14,7 @@ class EDIimporter: A class to import EDIfiles. """ - # Import the coordinate projections - try: - import osr - except ImportError as e: - print 'Could not import osr, missing the gdal package' - raise e + # Define data converters _impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit @@ -117,6 +112,12 @@ class EDIimporter: # nOutData=length(obj.data); # obj.data(nOutData+1:nOutData+length(TEMP.data),:) = TEMP.data; def _transfromPoints(self,longD,latD): + # Import the coordinate projections + try: + import osr + except ImportError as e: + print 'Could not import osr, missing the gdal package\nCan not project coordinates' + raise e # Coordinates convertor if self._2out is None: src = osr.SpatialReference() From d13c540be0e2cfa49fe137eaaba77270c7dd4219 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 09:25:20 -0700 Subject: [PATCH 38/56] Uppercase on class names. Add flag for Directive.Update_Wj. Remove trailing spaces. Remove old DC example. --- SimPEG/Directives.py | 23 +- SimPEG/Examples/DC_Forward_PseudoSection.py | 4 +- .../Examples/DC_PseudoSection_Simulation.py | 220 ------------------ SimPEG/Examples/Inversion_IRLS.py | 2 +- 4 files changed, 11 insertions(+), 238 deletions(-) delete mode 100644 SimPEG/Examples/DC_PseudoSection_Simulation.py diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 8f93c70a..98357492 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -285,7 +285,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # self.m_prev = self.invProb.m_current # return mref -class update_IRLS(InversionDirective): +class Update_IRLS(InversionDirective): eps_min = None factor = None @@ -333,18 +333,9 @@ class update_IRLS(InversionDirective): self.reg.gamma = self.phi_m_last / phim_new - - # TO DO: Check optimization class, data misfit not matching reality - #dpred = self.prob.fields(self.invProb.curModel) - #phid = self.invProb.dmisfit.eval(self.invProb.curModel) - #print self.survey.std[0] - #print phid - #print self.invProb.phi_d - #print self.invProb.phi_d_last - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d -class update_lin_PreCond(InversionDirective): +class Update_lin_PreCond(InversionDirective): def endIter(self): @@ -357,15 +348,17 @@ class update_lin_PreCond(InversionDirective): self.opt.approxHinv = PC print 'Updated pre-cond' -class update_Wj(InversionDirective): +class Update_Wj(InversionDirective): """ - Create approx-sensitivity base weighting + Create approx-sensitivity base weighting using the probing method """ - k = None + k = None # Number of probing cycles + itr = None # Iteration number to update Wj, or always update if None def endIter(self): - if self.opt.iter == 2: + if self.itr is None or self.itr == self.opt.iter: + m = self.invProb.curModel if self.k is None: self.k = int(self.survey.nD/10) diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index e1763da6..06858e38 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -7,10 +7,10 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p DC Forward Simulation ===================== - Forward model two conductive spheres in a half-space and plot a + Forward model two conductive spheres in a half-space and plot a pseudo-section. Assumes an infinite line source and measures along the center of the spheres. - + INPUT: loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] radi = Radius of spheres [r1,r2] diff --git a/SimPEG/Examples/DC_PseudoSection_Simulation.py b/SimPEG/Examples/DC_PseudoSection_Simulation.py deleted file mode 100644 index 3b9c4c05..00000000 --- a/SimPEG/Examples/DC_PseudoSection_Simulation.py +++ /dev/null @@ -1,220 +0,0 @@ -from SimPEG import * -# import simpegDCIP as DC -from SimPEG import DCIP as DC -import scipy.interpolate as interpolation -import matplotlib.pyplot as plt -import time -import re - -def run(loc=np.c_[[-50.,0.,-50.],[50.,0.,-50.]], sig=np.r_[1e-2,1e-1,1e-3], radi=np.r_[25.,25.], param = np.r_[30.,30.,5], stype = 'dpdp', plotIt=True): - """ - - DC Forward Simulation - ===================== - - Forward model conductive spheres in a half-space and plot a pseudo-section - - Created on Mon Feb 01 19:28:06 2016 - - @fourndo - - """ - - def getIndicesSphere(center,radius,ccMesh): - """ - Creates a vector containing the sphere indices in the cell centers mesh. - Returns a tuple - - The sphere is defined by the points - - p0, describe the position of the center of the cell - - r, describe the radius of the sphere. - - ccMesh represents the cell-centered mesh - - The points p0 must live in the the same dimensional space as the mesh. - - """ - - # Validation: mesh and point (p0) live in the same dimensional space - dimMesh = np.size(ccMesh[0,:]) - assert len(center) == dimMesh, "Dimension mismatch. len(p0) != dimMesh" - - if dimMesh == 1: - # Define the reference points - - ind = np.abs(center[0] - ccMesh[:,0]) < radius - - elif dimMesh == 2: - # Define the reference points - - ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 ) < radius - - elif dimMesh == 3: - # Define the points - ind = np.sqrt( ( center[0] - ccMesh[:,0] )**2 + ( center[1] - ccMesh[:,1] )**2 + ( center[2] - ccMesh[:,2] )**2 ) < radius - - # Return a tuple - return ind - # First we need to create a mesh and a model. - - # This is our mesh - dx = 5. - - hxind = [(dx,15,-1.3), (dx, 75), (dx,15,1.3)] - hyind = [(dx,15,-1.3), (dx, 10), (dx,15,1.3)] - hzind = [(dx,15,-1.3),(dx, 15)] - - mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCN') - - - # Set background conductivity - model = np.ones(mesh.nC) * sig[0] - - # First anomaly - ind = getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) - model[ind] = sig[1] - - # Second anomaly - ind = getIndicesSphere(loc[:,1],radi[1],mesh.gridCC) - model[ind] = sig[2] - - # Get index of the center - indy = int(mesh.nCy/2) - - - # Plot the model for reference - # Define core mesh extent - xlim = 200 - zlim = 125 - - # Specify the survey type: "pdp" | "dpdp" - - - # Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh - ends = [(-175,0),(175,0)] - ends = np.c_[np.asarray(ends),np.ones(2).T*mesh.vectorNz[-1]] - - # Snap the endpoints to the grid. Easier to create 2D section. - indx = Utils.closestPoints(mesh, ends ) - locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]] - - # We will handle the geometry of the survey for you and create all the combination of tx-rx along line - [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2]) - - # Define some global geometry - dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) ) - dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len - dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len - azm = np.arctan(dl_y/dl_x) - - #Set boundary conditions - mesh.setCellGradBC('neumann') - - # Define the differential operators needed for the DC problem - Div = mesh.faceDiv - Grad = mesh.cellGrad - Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model))) - - A = Div*Msig*Grad - - # Change one corner to deal with nullspace - A[0,0] = 1 - A = sp.csc_matrix(A) - - # We will solve the system iteratively, so a pre-conditioner is helpful - # This is simply a Jacobi preconditioner (inverse of the main diagonal) - dA = A.diagonal() - P = sp.spdiags(1/dA,0,A.shape[0],A.shape[0]) - - # Now we can solve the system for all the transmitters - # We want to store the data - data = [] - - # There is probably a more elegant way to do this, but we can just for-loop through the transmitters - for ii in range(len(Tx)): - - start_time = time.time() # Let's time the calculations - - #print("Transmitter %i / %i\r" % (ii+1,len(Tx))) - - # Select dipole locations for receiver - rxloc_M = np.asarray(Rx[ii][:,0:3]) - rxloc_N = np.asarray(Rx[ii][:,3:]) - - - # For usual cases "dpdp" or "gradient" - if not re.match(stype,'pdp'): - inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T ) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) - - else: - - # Create an "inifinity" pole - tx = np.squeeze(Tx[ii][:,0:1]) - tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2 - inds = Utils.closestPoints(mesh, np.c_[tx,tinf].T) - RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1] / mesh.vol[inds] ) - - - # Iterative Solve - Ainvb = sp.linalg.bicgstab(P*A,P*RHS, tol=1e-5) - - # We now have the potential everywhere - phi = mkvc(Ainvb[0]) - - # Solve for phi on pole locations - P1 = mesh.getInterpolationMat(rxloc_M, 'CC') - P2 = mesh.getInterpolationMat(rxloc_N, 'CC') - - # Compute the potential difference - dtemp = (P1*phi - P2*phi)*np.pi - - data.append( dtemp ) - print '\rTransmitter {0} of {1} -> Time:{2} sec'.format(ii,len(Tx),time.time()- start_time), - - print 'Transmitter {0} of {1}'.format(ii,len(Tx)) - print 'Forward completed' - - - # Let's just convert the 3D format into 2D (distance along line) and plot - [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(Tx,Rx) - - - # Here is an example for the first tx-rx array - if plotIt: - fig = plt.figure() - ax = plt.subplot(2,1,1, aspect='equal') - mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True) - ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m') - plt.gca().set_aspect('equal', adjustable='box') - - plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v') - plt.scatter(Rx[0][:,0::3],Rx[0][:,2::3],s=40,c='y') - plt.xlim([-xlim,xlim]) - plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - - ax = plt.subplot(2,1,2, aspect='equal') - - # Plot the location of the spheres for reference - circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3) - circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3) - ax.add_artist(circle1) - ax.add_artist(circle2) - - # Add the speudo section - DC.plot_pseudoSection(Tx2d,Rx2d,data,mesh.vectorNz[-1],stype) - - plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v') - plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y') - plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k') - plt.ylim([-zlim,mesh.vectorNz[-1]+dx]) - - plt.show() - - return fig, ax - -if __name__ == '__main__': - run() diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index a4d9204a..c236860d 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -96,7 +96,7 @@ def run(N=200, plotIt=True): beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() target = Directives.TargetMisfit() - IRLS =Directives.update_IRLS( phi_m_last = phim, phi_d_last = phid ) + IRLS =Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid ) inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS]) From 8a18e479ab5f31994c0e3641954b0dcdb94729ff Mon Sep 17 00:00:00 2001 From: GudniRos Date: Thu, 7 Apr 2016 11:48:17 -0700 Subject: [PATCH 39/56] Removed the testProjDeriv (not needed, included in Jvec). --- tests/mt/test_Problem3D_againstAnalytic.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/mt/test_Problem3D_againstAnalytic.py b/tests/mt/test_Problem3D_againstAnalytic.py index f68e515f..602dbaeb 100644 --- a/tests/mt/test_Problem3D_againstAnalytic.py +++ b/tests/mt/test_Problem3D_againstAnalytic.py @@ -242,9 +242,6 @@ class TestAnalytics(unittest.TestCase): def test_appRes1en3(self):self.assertTrue(appResPhsHalfspace_eFrom_ps_Norm(1e-3)) def test_appPhs1en3(self):self.assertTrue(appResPhsHalfspace_eFrom_ps_Norm(1e-3,False)) - # Do a derivative test - def test_derivProj1(self):self.assertTrue(DerivProjfieldsTest(halfSpace(1e-2))) - # Do a derivative test of Jvec # def test_derivJvec_zxxr(self):self.assertTrue(DerivJvecTest(random(1e-2),'zxxr',.1)) # def test_derivJvec_zxxi(self):self.assertTrue(DerivJvecTest(random(1e-2),'zxxi',.1)) From e305600de516a8f8afa83f3a2b388e9be17111ee Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 7 Apr 2016 13:09:28 -0700 Subject: [PATCH 40/56] Update example list. Add comments for the DC_Forward_PseudoSection example. Fix Z of pseudo section plot. --- SimPEG/DCIP/DCIPUtils.py | 2 +- SimPEG/Examples/DC_Forward_PseudoSection.py | 2 +- SimPEG/Examples/__init__.py | 3 +- docs/examples/DC_Forward_PseudoSection.rst | 10 +++++- docs/examples/DC_PseudoSection_Simulation.rst | 31 ------------------- 5 files changed, 12 insertions(+), 36 deletions(-) delete mode 100644 docs/examples/DC_PseudoSection_Simulation.rst diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index 9b637d82..e94b930f 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -257,7 +257,7 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): break midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) - midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ]) + midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ]) ax = axs diff --git a/SimPEG/Examples/DC_Forward_PseudoSection.py b/SimPEG/Examples/DC_Forward_PseudoSection.py index 06858e38..53467826 100644 --- a/SimPEG/Examples/DC_Forward_PseudoSection.py +++ b/SimPEG/Examples/DC_Forward_PseudoSection.py @@ -17,7 +17,7 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p param = Conductivity of background and two spheres [m0,m1,m2] stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) - Created by @fourndo on Mon Feb 01 19:28:06 2016 + Created by @fourndo """ diff --git a/SimPEG/Examples/__init__.py b/SimPEG/Examples/__init__.py index b06bb3a7..c67652a2 100644 --- a/SimPEG/Examples/__init__.py +++ b/SimPEG/Examples/__init__.py @@ -3,7 +3,6 @@ ##### AUTOIMPORTS ##### import DC_Analytic_Dipole import DC_Forward_PseudoSection -import DC_PseudoSection_Simulation import EM_FDEM_1D_Inversion import EM_FDEM_Analytic_MagDipoleWholespace import EM_Schenkel_Morrison_Casing @@ -22,7 +21,7 @@ import Mesh_Tensor_Creation import MT_1D_ForwardAndInversion import MT_3D_Foward -__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "DC_PseudoSection_Simulation", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] +__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"] ##### AUTOIMPORTS ##### diff --git a/docs/examples/DC_Forward_PseudoSection.rst b/docs/examples/DC_Forward_PseudoSection.rst index 1a500cae..80cf0307 100644 --- a/docs/examples/DC_Forward_PseudoSection.rst +++ b/docs/examples/DC_Forward_PseudoSection.rst @@ -12,8 +12,16 @@ DC Forward Simulation ===================== -Forward model conductive spheres in a half-space and plot a pseudo-section +Forward model two conductive spheres in a half-space and plot a +pseudo-section. Assumes an infinite line source and measures along the +center of the spheres. +INPUT: +loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]] +radi = Radius of spheres [r1,r2] +param = Conductivity of background and two spheres [m0,m1,m2] +stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole) +dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential) Created by @fourndo on Mon Feb 01 19:28:06 2016 diff --git a/docs/examples/DC_PseudoSection_Simulation.rst b/docs/examples/DC_PseudoSection_Simulation.rst deleted file mode 100644 index 1d4330a1..00000000 --- a/docs/examples/DC_PseudoSection_Simulation.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _examples_DC_PseudoSection_Simulation: - -.. --------------------------------- .. -.. .. -.. THIS FILE IS AUTO GENEREATED .. -.. .. -.. SimPEG/Examples/__init__.py .. -.. .. -.. --------------------------------- .. - - - -DC Forward Simulation -===================== - -Forward model conductive spheres in a half-space and plot a pseudo-section - -Created on Mon Feb 01 19:28:06 2016 - -@fourndo - - - -.. plot:: - - from SimPEG import Examples - Examples.DC_PseudoSection_Simulation.run() - -.. literalinclude:: ../../SimPEG/Examples/DC_PseudoSection_Simulation.py - :language: python - :linenos: From 3e4f47711c57b99f1164d7eab94920a079e7f576 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Thu, 7 Apr 2016 16:35:47 -0700 Subject: [PATCH 41/56] remove mutable arguments. --- SimPEG/Inversion.py | 4 ++- SimPEG/Mesh/TreeMesh.py | 12 +++++-- SimPEG/Mesh/View.py | 36 +++++++++++++++------ SimPEG/Utils/ModelBuilder.py | 18 ++++++++--- SimPEG/Utils/codeutils.py | 4 ++- tests/em/tdem/test_TDEM_forward_Analytic.py | 4 ++- 6 files changed, 59 insertions(+), 19 deletions(-) diff --git a/SimPEG/Inversion.py b/SimPEG/Inversion.py index 3fe9cfd0..3e92374f 100644 --- a/SimPEG/Inversion.py +++ b/SimPEG/Inversion.py @@ -33,7 +33,9 @@ class BaseInversion(object): self._directiveList = value self._directiveList.inversion = self - def __init__(self, invProb, directiveList=[], **kwargs): + def __init__(self, invProb, directiveList=None, **kwargs): + if directiveList is None: + directiveList = [] self.directiveList = directiveList Utils.setKwargs(self, **kwargs) diff --git a/SimPEG/Mesh/TreeMesh.py b/SimPEG/Mesh/TreeMesh.py index 02c23dee..2c75fda1 100644 --- a/SimPEG/Mesh/TreeMesh.py +++ b/SimPEG/Mesh/TreeMesh.py @@ -2131,10 +2131,16 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO): def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=True, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k', 'alpha':0.5}): + pcolorOpts=None, + streamOpts=None, + gridOpts=None): + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k', 'alpha':0.5} assert vType in ['CC','F','E'] assert self.dim == 3 diff --git a/SimPEG/Mesh/View.py b/SimPEG/Mesh/View.py index 089d7d9a..8eb22098 100644 --- a/SimPEG/Mesh/View.py +++ b/SimPEG/Mesh/View.py @@ -42,9 +42,9 @@ class TensorView(object): def plotImage(self, v, vType='CC', grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k'}, + pcolorOpts=None, + streamOpts=None, + gridOpts=None, numbering=True, annotationColor='w' ): """ @@ -84,6 +84,12 @@ class TensorView(object): M.plotImage(v, annotationColor='k', showIt=True) """ + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k'} if ax is None: fig = plt.figure() @@ -174,9 +180,9 @@ class TensorView(object): def plotSlice(self, v, vType='CC', normal='Z', ind=None, grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k', 'alpha':0.5} + pcolorOpts=None, + streamOpts=None, + gridOpts=None ): """ @@ -197,6 +203,12 @@ class TensorView(object): M.plotSlice(M.cellGrad*b, 'F', view='vec', grid=True, showIt=True, pcolorOpts={'alpha':0.8}) """ + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k', 'alpha':0.5} if type(vType) in [list, tuple]: assert ax is None, "cannot specify an axis to plot on with this function." fig, axs = plt.subplots(1,len(vType)) @@ -289,11 +301,17 @@ class TensorView(object): def _plotImage2D(self, v, vType='CC', grid=False, view='real', ax=None, clim=None, showIt=False, - pcolorOpts={}, - streamOpts={'color':'k'}, - gridOpts={'color':'k'} + pcolorOpts=None, + streamOpts=None, + gridOpts=None ): + if pcolorOpts is None: + pcolorOpts = {} + if streamOpts is None: + streamOpts = {'color':'k'} + if gridOpts is None: + gridOpts = {'color':'k'} vTypeOptsCC = ['N','CC','Fx','Fy','Ex','Ey'] vTypeOptsV = ['CCv','F','E'] vTypeOpts = vTypeOptsCC + vTypeOptsV diff --git a/SimPEG/Utils/ModelBuilder.py b/SimPEG/Utils/ModelBuilder.py index 435856f7..1b868fe5 100644 --- a/SimPEG/Utils/ModelBuilder.py +++ b/SimPEG/Utils/ModelBuilder.py @@ -88,12 +88,14 @@ def getIndicesBlock(p0,p1,ccMesh): # Return a tuple return ind -def defineBlock(ccMesh,p0,p1,vals=[0,1]): +def defineBlock(ccMesh,p0,p1,vals=None): """ Build a block with the conductivity specified by condVal. Returns an array. vals[0] conductivity of the block vals[1] conductivity of the ground """ + if vals is None: + vals = [0,1] sigma = np.zeros(ccMesh.shape[0]) + vals[1] ind = getIndicesBlock(p0,p1,ccMesh) @@ -101,7 +103,11 @@ def defineBlock(ccMesh,p0,p1,vals=[0,1]): return mkvc(sigma) -def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.): +def defineElipse(ccMesh, center=None, anisotropy=None, slope=10., theta=0.): + if center is None: + center = [0,0,0] + if anisotropy is None: + anisotropy = [1,1,1] G = ccMesh.copy() dim = ccMesh.shape[1] for i in range(dim): @@ -156,7 +162,7 @@ def getIndicesSphere(center,radius,ccMesh): # Return a tuple return ind -def defineTwoLayers(ccMesh,depth,vals=[0,1]): +def defineTwoLayers(ccMesh,depth,vals=None): """ Define a two layered model. Depth of the first layer must be specified. CondVals vector with the conductivity values of the layers. Eg: @@ -167,6 +173,8 @@ def defineTwoLayers(ccMesh,depth,vals=[0,1]): 0 depth zf 1st layer 2nd layer """ + if vals is None: + vals = [0,1] sigma = np.zeros(ccMesh.shape[0]) + vals[1] dim = np.size(ccMesh[0,:]) @@ -252,7 +260,7 @@ def layeredModel(ccMesh, layerTops, layerValues): -def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): +def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None): """ Create a random model by convolving a kernel with a uniformly distributed model. @@ -276,6 +284,8 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]): """ + if bounds is None: + bounds = [0,1] if seed is None: seed = np.random.randint(1e3) diff --git a/SimPEG/Utils/codeutils.py b/SimPEG/Utils/codeutils.py index bfd00889..6151c540 100644 --- a/SimPEG/Utils/codeutils.py +++ b/SimPEG/Utils/codeutils.py @@ -55,8 +55,10 @@ def hook(obj, method, name=None, overwrite=False, silent=False): print 'Method '+name+' was not overwritten.' -def setKwargs(obj, ignore=[], **kwargs): +def setKwargs(obj, ignore=None, **kwargs): """Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist.""" + if ignore is None: + ignore = [] for attr in kwargs: if attr in ignore: continue diff --git a/tests/em/tdem/test_TDEM_forward_Analytic.py b/tests/em/tdem/test_TDEM_forward_Analytic.py index dc3696ef..7748b5fc 100644 --- a/tests/em/tdem/test_TDEM_forward_Analytic.py +++ b/tests/em/tdem/test_TDEM_forward_Analytic.py @@ -10,7 +10,9 @@ except ImportError, e: MumpsSolver = SolverLU -def halfSpaceProblemAnaDiff(meshType, sig_half=1e-2, rxOffset=50., bounds=[1e-5,1e-3], showIt=False): +def halfSpaceProblemAnaDiff(meshType, sig_half=1e-2, rxOffset=50., bounds=None, showIt=False): + if bounds is None: + bounds = [1e-5,1e-3] if meshType == 'CYL': cs, ncx, ncz, npad = 5., 30, 10, 15 hx = [(cs,ncx), (cs,npad,1.3)] From 083742cb40923ebfd488f037b4730b4786c57df0 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Fri, 8 Apr 2016 09:34:30 -0700 Subject: [PATCH 42/56] Removing repeated directives --- SimPEG/Directives.py | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 7e412781..5e83dc82 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -222,7 +222,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): mref = 0 mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim==2: + if self.prob.mesh.dim < 2: my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_my = 0.5 * my.dot(my) else: @@ -237,40 +237,6 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): # Save the file as a npz np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) -class SaveOutputDictEveryIteration(_SaveEveryIteration): - """SaveOutputDictEveryIteration - A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info). - """ - - def initialize(self): - print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName - - def endIter(self): - # Save the data. - ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) ) - phi_ms = 0.5*ms.dot(ms) - if self.reg.smoothModel == True: - mref = self.reg.mref - else: - mref = 0 - mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim>2: - my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_my = 0.5 * my.dot(my) - else: - phi_my = 'NaN' - if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType: - mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) ) - phi_mz = 0.5 * mz.dot(mz) - else: - phi_mz = 'NaN' - - - # Save the file as a npz - np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred) - - # class UpdateReferenceModel(Parameter): From 90b030140899a84296dee5373b0e291d05bcd067 Mon Sep 17 00:00:00 2001 From: GudniRos Date: Fri, 8 Apr 2016 09:40:26 -0700 Subject: [PATCH 43/56] Fixing bug in write out. --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 5e83dc82..d6cab804 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -222,7 +222,7 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration): mref = 0 mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_mx = 0.5 * mx.dot(mx) - if self.prob.mesh.dim < 2: + if self.prob.mesh.dim >= 2: my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) ) phi_my = 0.5 * my.dot(my) else: From 606488d152591605876c1f767b0c0afcac355034 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Thu, 21 Apr 2016 21:58:40 -0700 Subject: [PATCH 44/56] Major fix to IRLS. --- SimPEG/DCIP/DCIPUtils.py | 152 +++++++++++++++++++----------- SimPEG/Directives.py | 4 +- SimPEG/Examples/Inversion_IRLS.py | 6 +- SimPEG/Regularization.py | 12 +-- 4 files changed, 109 insertions(+), 65 deletions(-) diff --git a/SimPEG/DCIP/DCIPUtils.py b/SimPEG/DCIP/DCIPUtils.py index e94b930f..97c30e89 100644 --- a/SimPEG/DCIP/DCIPUtils.py +++ b/SimPEG/DCIP/DCIPUtils.py @@ -169,7 +169,7 @@ def readUBC_DC2DModel(fileName): return model -def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): +def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None): """ Read list of 2D tx-rx location and plot a speudo-section of apparent resistivity. @@ -192,9 +192,6 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): from scipy.interpolate import griddata import pylab as plt - # Set depth to 0 for now - z0 = 0. - # Pre-allocate midx = [] midz = [] @@ -259,38 +256,53 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None): midx = np.hstack([midx, ( Cmid + Pmid )/2 ]) midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ]) - ax = axs - # Grid points grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)] grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear') - + + # Scale the color scheme if clim == None: vmin, vmax = rho.min(), rho.max() else: vmin, vmax = clim[0], clim[1] + # Plot data grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho) - ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, clim=(vmin, vmax)) - cbar = plt.colorbar(format="$10^{%.1f}$",fraction=0.04,orientation="horizontal") - - cmin,cmax = cbar.get_clim() - ticks = np.linspace(cmin,cmax,3) - cbar.set_ticks(ticks) - cbar.ax.tick_params(labelsize=10) + ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, vmin = vmin, vmax = vmax) + plt.gca().tick_params(axis='both', which='major', labelsize=8) - if dtype == 'appc': - cbar.set_label("App.Cond",size=12) - elif dtype == 'appr': - cbar.set_label("App.Res.",size=12) - elif dtype == 'volt': - cbar.set_label("Potential (V)",size=12) + if contour is not None: + plt.contour(grid_x,grid_z,grid_rho,levels = contour,colors = 'r', vmin = vmin, vmax = vmax) + + # Add scatter points + axs.scatter(midx,midz,s=10,c=rho.T, vmin = vmin, vmax = vmax) + + if colorbar: + + if dtype == 'volt': + cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal") - # Plot apparent resistivity - ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax)) + else: + cbar = plt.colorbar(ph, ax = axs, format="$10^{%.1f}$",fraction=0.04,orientation="horizontal") + + cmin,cmax = cbar.get_clim() + ticks = np.linspace(cmin,cmax,3) + cbar.set_ticks(ticks) + cbar.ax.tick_params(labelsize=10) + + if cblabel: + if dtype == 'appc': + cbar.set_label("App.Cond",size=12) + elif dtype == 'appr': + cbar.set_label("App.Res.",size=12) + elif dtype == 'volt': + cbar.set_label("Potential (V)",size=12) - #ax.set_xticklabels([]) - #ax.set_yticklabels([]) + + + if not axlabel: + axs.set_xticklabels([]) + axs.set_yticklabels([]) plt.gca().set_aspect('equal', adjustable='box') @@ -448,15 +460,15 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n): survey = DC.SurveyDC(SrcList) return survey, Tx, Rx -def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): +def writeUBC_DCobs(fileName, DCsurvey, dtype='3D', stype='SURFACE', iptype = 0): """ Write UBC GIF DCIP 2D or 3D observation file Input: - :string fileName -> including path where the file is written out - :DCsurvey -> DC survey class object - :string dtype -> either '2D' | '3D' - :string stype -> either 'SURFACE' | 'GENERAL' + :string fileName -> including path where the file is written out + :DCsurvey DC survey class object + :string dtype -> either '2D' | '3D' + :string stype -> either 'SURFACE' | 'GENERAL' Output: :param UBC2D-Data file @@ -471,10 +483,16 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'" assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'" - + fid = open(fileName,'w') - fid.write('! ' + stype + ' FORMAT\n') - + + + if iptype!=0: + fid.write('IPTYPE=%i\n'%iptype) + + else: + fid.write('! ' + stype + ' FORMAT\n') + count = 0 for ii in range(DCsurvey.nSrc): @@ -498,7 +516,7 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): B = np.repeat(tx[0,1],M.shape[0],axis=0) M = M[:,0] N = N[:,0] - + np.savetxt(fid, np.c_[A, B, M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') @@ -506,18 +524,25 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): if stype == 'SURFACE': - fid.writelines("%e " % ii for ii in mkvc(tx[0,:])) + fid.writelines("%f " % ii for ii in mkvc(tx[0,:])) M = M[:,0] N = N[:,0] if stype == 'GENERAL': + # Flip sign for z-elevation to depth + tx[2::2,:] = -tx[2::2,:] + fid.writelines("%e " % ii for ii in mkvc(tx[::2,:])) M = M[:,0::2] N = N[:,0::2] + # Flip sign for z-elevation to depth + M[:,1::2] = -M[:,1::2] + N[:,1::2] = -N[:,1::2] + fid.write('%i\n'% nD) - np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') + np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%f',delimiter=' ',newline='\n') if dtype=='3D': @@ -529,11 +554,12 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype): if stype == 'GENERAL': - fid.writelines("%e " % ii for ii in mkvc(tx)) + fid.writelines("%e " % ii for ii in mkvc(tx[0:3,:])) fid.write('%i\n'% nD) np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n') - + fid.write('\n') + count += nD fid.close() @@ -640,51 +666,59 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'): DCsurvey2D.std = np.asarray(DCsurvey.std) return DCsurvey2D - -def readUBC_DC3Dobs(fileName): + +def readUBC_DC3Dobs(fileName, dtype = 'DC'): """ - Read UBC GIF DCIP 3D observation file and generate survey + Read UBC GIF IP 3D observation file and generate survey Input: :param fileName, path to the UBC GIF 3D obs file Output: - :param DCIPsurvey + :param IPsurvey :return - Created on Mon April 6th, 2015 - @author: dominiquef """ - + zflag = True # Flag for z value provided + # Load file - obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') - + if dtype == 'IP': + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE') + + elif dtype == 'DC': + obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!') + + else: + print "dtype must be 'DC'(default) | 'IP'" + # Pre-allocate srcLists = [] Rx = [] d = [] wd = [] - zflag = True # Flag for z value provided + # Countdown for number of obs/tx count = 0 for ii in range(obsfile.shape[0]): + # Skip if blank line if not obsfile[ii]: continue - # First line is transmitter with number of receivers + # First line or end of a transmitter block, read transmitter info if count==0: - - temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T) + # Read the line + temp = (np.fromstring(obsfile[ii], dtype=float, sep=' ').T) count = int(temp[-1]) # Check if z value is provided, if False -> nan if len(temp)==5: - tx = np.r_[temp[0:2],np.nan,temp[0:2],np.nan] - zflag = False + tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan] + + zflag = False # Pass on the flag to the receiver loc else: tx = temp[:-1] @@ -692,8 +726,16 @@ def readUBC_DC3Dobs(fileName): rx = [] continue - temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') + temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string + # Filter out negative IP +# if temp[-2] < 0: +# count = count -1 +# print "Negative!" +# +# else: + + # If the Z-location is provided, otherwise put nan if zflag: rx.append(temp[:-2]) @@ -703,7 +745,7 @@ def readUBC_DC3Dobs(fileName): wd.append(temp[-1]) else: - rx.append(np.r_[temp[0:2],np.nan,temp[0:2],np.nan] ) + rx.append(np.r_[temp[0:2],np.nan,temp[2:4],np.nan] ) # Check if there is data with the location if len(temp)==6: d.append(temp[-2]) @@ -711,7 +753,7 @@ def readUBC_DC3Dobs(fileName): count = count -1 - # Reach the end of transmitter block + # Reach the end of transmitter block, append the src, rx and continue if count == 0: rx = np.asarray(rx) Rx = DC.RxDipole(rx[:,:3],rx[:,3:]) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index b694a2f1..193911fe 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -300,6 +300,8 @@ class Update_IRLS(InversionDirective): self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d + self.reg._W = None + class Update_lin_PreCond(InversionDirective): @@ -308,7 +310,7 @@ class Update_lin_PreCond(InversionDirective): if getattr(self.opt, 'approxHinv', None) is not None: # Update the pre-conditioner - diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() * (self.reg.mapping * np.ones(self.reg.curModel.size))**2. + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC print 'Updated pre-cond' diff --git a/SimPEG/Examples/Inversion_IRLS.py b/SimPEG/Examples/Inversion_IRLS.py index c236860d..06ef4be4 100644 --- a/SimPEG/Examples/Inversion_IRLS.py +++ b/SimPEG/Examples/Inversion_IRLS.py @@ -86,12 +86,12 @@ def run(N=200, plotIt=True): #reg.recModel = mrec reg.wght = np.ones(mesh.nC) reg.mref = np.zeros(mesh.nC) - reg.eps_p = 2e-3 - reg.eps_q = 2e-3 + reg.eps_p = 5e-2 + reg.eps_q = 1e-2 reg.norms = [0., 0., 2., 2.] reg.wght = wr - opt = Optimization.ProjectedGNCG(maxIter=5 ,lower=-2.,upper=2., maxIterCG= 100, tolCG = 1e-3) + opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.) beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1) #betaest = Directives.BetaEstimate_ByEig() diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 195e6203..ed1039ec 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -728,14 +728,14 @@ class Sparse(Simple): @property def W(self): """Full regularization matrix W""" - #if getattr(self, '_W', None) is None: - wlist = (self.Wsmall, self.Wsmooth) - #self._W = sp.vstack(wlist) - return sp.vstack(wlist) + if getattr(self, '_W', None) is None: + wlist = (self.Wsmall, self.Wsmooth) + self._W = sp.vstack(wlist) + return self._W def R(self, f_m , eps, exponent): - eta = (eps**(1-exponent/2.))**0.5 - r = eta / (f_m**2.+ eps**2.)**((1-exponent/2.)/2.) + eta = (eps**(1.-exponent/2.))**0.5 + r = eta / (f_m**2.+ eps**2.)**((1.-exponent/2.)/2.) return r From 79183ae9fbfc06d0e0575d1b90a12f35dfc5b91c Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 22 Apr 2016 16:05:43 -0700 Subject: [PATCH 45/56] fIX MESH io --- SimPEG/Mesh/MeshIO.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimPEG/Mesh/MeshIO.py b/SimPEG/Mesh/MeshIO.py index 7501a66f..1c042237 100644 --- a/SimPEG/Mesh/MeshIO.py +++ b/SimPEG/Mesh/MeshIO.py @@ -21,10 +21,9 @@ class TensorMeshIO(object): if '*' in seg: st = seg sp = seg.split('*') - re = np.array(sp[0],dtype=int)*(' ' + sp[1]) + re = int(sp[0])*(' ' + sp[1]) line = line.replace(st,re.strip()) return np.array(line.split(),dtype=float) - # Read the file as line strings, remove lines with comment = ! msh = np.genfromtxt(fileName,delimiter='\n',dtype=np.str,comments='!') From d8bfb27415ad6f34a38e8097f32dae8c473caddf Mon Sep 17 00:00:00 2001 From: D Fournier Date: Sat, 23 Apr 2016 15:25:44 -0700 Subject: [PATCH 46/56] Quick fix to MeshIO --- SimPEG/Directives.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 193911fe..3cdb5000 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -301,7 +301,7 @@ class Update_IRLS(InversionDirective): self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d self.reg._W = None - + class Update_lin_PreCond(InversionDirective): @@ -313,7 +313,7 @@ class Update_lin_PreCond(InversionDirective): diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. PC = Utils.sdiag(diagA**-1.) self.opt.approxHinv = PC - print 'Updated pre-cond' + class Update_Wj(InversionDirective): """ From 225394f74e8c03ba5d938cd9eed70f726d4f27b7 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 11:10:04 -0700 Subject: [PATCH 47/56] Latest commit --- SimPEG/Directives.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index 3cdb5000..ee29e770 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -258,6 +258,7 @@ class Update_IRLS(InversionDirective): phi_m_last = None phi_d_last = None + def initialize(self): # Scale the regularization for changes in norm @@ -275,7 +276,7 @@ class Update_IRLS(InversionDirective): self.phi_d_last = self.invProb.phi_d def endIter(self): - # Cool the threshold parameter + # Cool the threshold parameter if required if getattr(self, 'factor', None) is not None: eps = self.reg.eps / self.factor @@ -290,16 +291,17 @@ class Update_IRLS(InversionDirective): # Update the model used for the IRLS weights self.reg.curModel = self.invProb.curModel - # Temporarely set gamma to 1. + # Temporarely set gamma to 1. to get raw phi_m self.reg.gamma = 1. - # Compute change in model objective function and update scaling + # Compute new model objective function value phim_new = self.reg.eval(self.invProb.curModel) + # Update gamma to scale the regularization between IRLS iterations self.reg.gamma = self.phi_m_last / phim_new - self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d - + # Set the weighting matrix to None so that it is recomputed next time + # it is called in the inversion self.reg._W = None class Update_lin_PreCond(InversionDirective): @@ -340,3 +342,19 @@ class Update_Wj(InversionDirective): JtJdiag = JtJdiag / max(JtJdiag) self.reg.wght = JtJdiag + +class Scale_Beta(InversionDirective): + """ + Instead of a linear cooling schedule, beta is allowed to change based + on the ratio between the target misfit and the current data misfit. The + update is done only if the misfit is outside some threshold bounds. + """ + tol = 0.05 + + def endIter(self): + + # Check if misfit is within the tolerance, otherwise adjust beta + val = self.invProb.phi_d / (self.survey.nD*0.5) + + if np.abs(1.-val) > self.tol: + self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d From c83b460672df464598600f7b793927d26e4a4605 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:43:31 -0700 Subject: [PATCH 48/56] Surface to Indices (GoCAD and VTK) --- SimPEG/Utils/io_utils.py | 132 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 SimPEG/Utils/io_utils.py diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py new file mode 100644 index 00000000..f68ee68c --- /dev/null +++ b/SimPEG/Utils/io_utils.py @@ -0,0 +1,132 @@ +from SimPEG import np, Mesh +import time as tm +import vtk, vtk.util.numpy_support as npsup +import re + +def read_GOCAD_ts(tsfile): + """ + + Read GOCAD triangulated surface (*.ts) file + INPUT: + tsfile: Triangulated surface + + OUTPUT: + vrts : Array of vertices in XYZ coordinates [n x 3] + trgl : Array of index for triangles [m x 3]. The order of the vertices + is important and describes the normal + n = cross( (P2 - P1 ) , (P3 - P1) ) + + Author: @fourndo + + """ + + + fid = open(tsfile,'r') + line = fid.readline() + + # Skip all the lines until the vertices + while re.match('TFACE',line)==None: + line = fid.readline() + + line = fid.readline() + vrtx = [] + + # Run down all the vertices and save in array + while re.match('VRTX',line): + l_input = re.split('[\s*]',line) + temp = np.array(l_input[2:5]) + vrtx.append(temp.astype(np.float)) + + # Read next line + line = fid.readline() + + vrtx = np.asarray(vrtx) + + # Skip lines to the triangles + while re.match('TRGL',line)==None: + line = fid.readline() + + # Run down the list of triangles + trgl = [] + + # Run down all the vertices and save in array + while re.match('TRGL',line): + l_input = re.split('[\s*]',line) + temp = np.array(l_input[1:4]) + trgl.append(temp.astype(np.int)) + + # Read next line + line = fid.readline() + + trgl = np.asarray(trgl) + + return vrtx, trgl + +def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True): + """" + Function to read gocad polystructure file and output indexes of mesh with in the structure. + + """ + # Adjust the index + trgl = trgl - 1 + + # Make vtk pts + ptsvtk = vtk.vtkPoints() + ptsvtk.SetData(npsup.numpy_to_vtk(vrtx,deep=1)) + + # Make the polygon connection + polys = vtk.vtkCellArray() + for face in trgl: + poly = vtk.vtkPolygon() + poly.GetPointIds().SetNumberOfIds(len(face)) + for nrv, vert in enumerate(face): + poly.GetPointIds().SetId(nrv,vert) + polys.InsertNextCell(poly) + + # Make the polydata, structure of connections and vrtx + polyData = vtk.vtkPolyData() + polyData.SetPoints(ptsvtk) + polyData.SetPolys(polys) + + # Make implicit func + ImpDistFunc = vtk.vtkImplicitPolyDataDistance() + ImpDistFunc.SetInput(polyData) + + # Convert the mesh + vtkMesh = vtk.vtkRectilinearGrid() + vtkMesh.SetDimensions(mesh.nNx,mesh.nNy,mesh.nNz) + vtkMesh.SetXCoordinates(npsup.numpy_to_vtk(mesh.vectorNx, deep=1)) + vtkMesh.SetYCoordinates(npsup.numpy_to_vtk(mesh.vectorNy, deep=1)) + vtkMesh.SetZCoordinates(npsup.numpy_to_vtk(mesh.vectorNz, deep=1)) + # Add indexes + vtkInd = npsup.numpy_to_vtk(np.arange(mesh.nC), deep=1) + vtkInd.SetName('Index') + vtkMesh.GetCellData().AddArray(vtkInd) + + extractImpDistRectGridFilt = vtk.vtkExtractGeometry() # Object constructor + extractImpDistRectGridFilt.SetImplicitFunction(ImpDistFunc) # + extractImpDistRectGridFilt.SetInputData(vtkMesh) + + if boundaries is True: + extractImpDistRectGridFilt.ExtractBoundaryCellsOn() + + else: + extractImpDistRectGridFilt.ExtractBoundaryCellsOff() + + if internal=True is True: + extractImpDistRectGridFilt.ExtractInsideOn() + + else: + extractImpDistRectGridFilt.ExtractInsideOff() + + print "Extracting indices from grid..." + # Executing the pipe + extractImpDistRectGridFilt.Update() + + # Get index inside + insideGrid = extractImpDistRectGridFilt.GetOutput() + insideGrid = npsup.vtk_to_numpy(insideGrid.GetCellData().GetArray('Index')) + + + # Return the indexes inside + return insideGrid From 028a16a45a3f0306e4911f675e29f5acee120de1 Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:44:42 -0700 Subject: [PATCH 49/56] Syntax bug. --- SimPEG/Utils/io_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py index f68ee68c..e46c13db 100644 --- a/SimPEG/Utils/io_utils.py +++ b/SimPEG/Utils/io_utils.py @@ -113,7 +113,7 @@ def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True): else: extractImpDistRectGridFilt.ExtractBoundaryCellsOff() - if internal=True is True: + if internal is True: extractImpDistRectGridFilt.ExtractInsideOn() else: From 00db6746d4272dd953773300dc815c0a0ee0008e Mon Sep 17 00:00:00 2001 From: Rowan Cockett Date: Fri, 29 Apr 2016 11:50:56 -0700 Subject: [PATCH 50/56] Add a warnign about mesh attributes --- SimPEG/Utils/io_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SimPEG/Utils/io_utils.py b/SimPEG/Utils/io_utils.py index e46c13db..323feb0c 100644 --- a/SimPEG/Utils/io_utils.py +++ b/SimPEG/Utils/io_utils.py @@ -18,6 +18,11 @@ def read_GOCAD_ts(tsfile): Author: @fourndo + + .. note:: + + Remove all attributes from the GoCAD surface before exporting it! + """ From 056dc09fa63a3cc0e6582a915b5605f1f4206338 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 15:10:30 -0700 Subject: [PATCH 51/56] Fix Update_Precondition directive --- SimPEG/Directives.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index ee29e770..b32cd798 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -305,11 +305,24 @@ class Update_IRLS(InversionDirective): self.reg._W = None class Update_lin_PreCond(InversionDirective): - - + """ + Create a Jacobi preconditioner for the linear problem + """ + onlyOnStart=True + + def initialize(self): + + if getattr(self.opt, 'approxHinv', None) is None: + # Update the pre-conditioner + diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. + PC = Utils.sdiag(diagA**-1.) + self.opt.approxHinv = PC + def endIter(self): # Cool the threshold parameter - + if self.onlyOnStart==True: + return + if getattr(self.opt, 'approxHinv', None) is not None: # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. From 3d1dfc13d7a2d5aee0f0859c1df28fb3be617fcd Mon Sep 17 00:00:00 2001 From: D Fournier Date: Fri, 29 Apr 2016 15:49:44 -0700 Subject: [PATCH 52/56] Change Update_PreConditioner to default False --- SimPEG/Directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index b32cd798..e51c904e 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -308,7 +308,7 @@ class Update_lin_PreCond(InversionDirective): """ Create a Jacobi preconditioner for the linear problem """ - onlyOnStart=True + onlyOnStart=False def initialize(self): From 00bbe0f35ee9318b3f1c370322aa3f01e54aa9ce Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Tue, 3 May 2016 15:04:36 -0700 Subject: [PATCH 53/56] if mapping is none, create an identity map that is size indactive.nonzero for regularization --- SimPEG/Regularization.py | 3 +++ tests/base/test_regularization.py | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/SimPEG/Regularization.py b/SimPEG/Regularization.py index 195e6203..7fe976fc 100644 --- a/SimPEG/Regularization.py +++ b/SimPEG/Regularization.py @@ -311,6 +311,9 @@ class BaseRegularization(object): tmp = indActive indActive = np.zeros(mesh.nC, dtype=bool) indActive[tmp] = True + if indActive is not None and mapping is None: + mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size) + self.regmesh = RegularizationMesh(mesh,indActive) self.mapping = mapping or self.mapPair(mesh) self.mapping._assertMatchesPair(self.mapPair) diff --git a/tests/base/test_regularization.py b/tests/base/test_regularization.py index 5aa21ad5..6dddfb74 100644 --- a/tests/base/test_regularization.py +++ b/tests/base/test_regularization.py @@ -65,10 +65,8 @@ class RegularizationTests(unittest.TestCase): elif mesh.dim == 3: indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5) - mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size) - for indAct in [indActive, indActive.nonzero()[0]]: # test both bool and integers - reg = r(mesh, mapping=mapping, indActive=indAct) + reg = r(mesh, indActive=indAct) m = np.random.rand(mesh.nC)[indAct] reg.mref = np.ones_like(m)*np.mean(m) From 4e296c4cd5194495b9b397fc87a724925ca608a6 Mon Sep 17 00:00:00 2001 From: D Fournier Date: Wed, 4 May 2016 16:01:29 -0700 Subject: [PATCH 54/56] Update PreCond Directive to allow inactive cells mapping --- SimPEG/Directives.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimPEG/Directives.py b/SimPEG/Directives.py index e51c904e..4fc1ffc5 100644 --- a/SimPEG/Directives.py +++ b/SimPEG/Directives.py @@ -315,7 +315,7 @@ class Update_lin_PreCond(InversionDirective): if getattr(self.opt, 'approxHinv', None) is None: # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. - PC = Utils.sdiag(diagA**-1.) + PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC def endIter(self): @@ -326,7 +326,7 @@ class Update_lin_PreCond(InversionDirective): if getattr(self.opt, 'approxHinv', None) is not None: # Update the pre-conditioner diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2. - PC = Utils.sdiag(diagA**-1.) + PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.) self.opt.approxHinv = PC From 069127333d641fa2e4173825a59a1508f5299665 Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Thu, 5 May 2016 16:41:21 -0700 Subject: [PATCH 55/56] allow interpolation to different cartsian grid locations --- SimPEG/Mesh/CylMesh.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/SimPEG/Mesh/CylMesh.py b/SimPEG/Mesh/CylMesh.py index ecdf36ac..802b13a3 100644 --- a/SimPEG/Mesh/CylMesh.py +++ b/SimPEG/Mesh/CylMesh.py @@ -330,7 +330,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): raise NotImplementedError('wrapping in the averaging is not yet implemented') return self._aveF2CCV - def getInterpolationMatCartMesh(self, Mrect, locType='CC'): + def getInterpolationMatCartMesh(self, Mrect, locType='CC', locTypeTo=None): """ Takes a cartesian mesh and returns a projection to translate onto the cartesian grid. """ @@ -338,19 +338,22 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): assert self.isSymmetric, "Currently we have not taken into account other projections for more complicated CylMeshes" + if locTypeTo is None: + locTypeTo = locType + if locType == 'F': # do this three times for each component - X = self.getInterpolationMatCartMesh(Mrect, locType='Fx') - Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy') - Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz') + X = self.getInterpolationMatCartMesh(Mrect, locType='Fx', locTypeTo=locTypeTo+'x') + Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy', locTypeTo=locTypeTo+'y') + Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz', locTypeTo=locTypeTo+'z') return sp.vstack((X,Y,Z)) if locType == 'E': - X = self.getInterpolationMatCartMesh(Mrect, locType='Ex') - Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey') + X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x') + Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y') Z = spzeros(Mrect.nEz, self.nE) return sp.vstack((X,Y,Z)) - grid = getattr(Mrect, 'grid' + locType) + grid = getattr(Mrect, 'grid' + locTypeTo) # This is unit circle stuff, 0 to 2*pi, starting at x-axis, rotating counter clockwise in an x-y slice theta = - np.arctan2(grid[:,0] - self.cartesianOrigin[0], grid[:,1] - self.cartesianOrigin[1]) + np.pi/2 theta[theta < 0] += np.pi*2.0 @@ -366,7 +369,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): 'Ex': Mrect.tangents[:Mrect.nEx,:], 'Ey': Mrect.tangents[Mrect.nEx:(Mrect.nEx+Mrect.nEy),:], 'Ez': Mrect.tangents[-Mrect.nEz:,:], - }[locType] + }[locTypeTo] if 'F' in locType: normals = np.c_[np.cos(theta), np.sin(theta), np.zeros(theta.size)] proj = ( normals * dotMe ).sum(axis=1) From 82782304767f423cd24545d8a151b6a5715d763d Mon Sep 17 00:00:00 2001 From: Lindsey Heagy Date: Sun, 8 May 2016 10:35:27 -0700 Subject: [PATCH 56/56] Use LocTypeTo to allow interpolation to different grid locations --- SimPEG/Mesh/CylMesh.py | 2 +- tests/mesh/test_cylMesh.py | 84 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/SimPEG/Mesh/CylMesh.py b/SimPEG/Mesh/CylMesh.py index 802b13a3..f0b6751e 100644 --- a/SimPEG/Mesh/CylMesh.py +++ b/SimPEG/Mesh/CylMesh.py @@ -350,7 +350,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView): if locType == 'E': X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x') Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y') - Z = spzeros(Mrect.nEz, self.nE) + Z = spzeros(getattr(Mrect, 'n' + locTypeTo + 'z'), self.nE) return sp.vstack((X,Y,Z)) grid = getattr(Mrect, 'grid' + locTypeTo) diff --git a/tests/mesh/test_cylMesh.py b/tests/mesh/test_cylMesh.py index 5a963398..c7cd44ae 100644 --- a/tests/mesh/test_cylMesh.py +++ b/tests/mesh/test_cylMesh.py @@ -146,6 +146,20 @@ class TestCyl2DMesh(unittest.TestCase): assert np.abs(Pr*(Pc2r*mc) - Pc*mc).max() < 1e-3 + def test_getInterpMatCartMesh_Cells2Nodes(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + mc = np.arange(Mc.nC) + xr = np.linspace(0,0.4,50) + xc = np.linspace(0,0.4,50) + 0.2 + Pr = Mr.getInterpolationMat(np.c_[xr,np.ones(50)*-0.2,np.ones(50)*0.5],'N') + Pc = Mc.getInterpolationMat(np.c_[xc,np.zeros(50),np.ones(50)*0.5],'CC') + Pc2r = Mc.getInterpolationMatCartMesh(Mr, 'CC', locTypeTo='N') + + assert np.abs(Pr*(Pc2r*mc) - Pc*mc).max() < 1e-3 + def test_getInterpMatCartMesh_Faces(self): Mr = Mesh.TensorMesh([100,100,2], x0='CC0') @@ -177,6 +191,37 @@ class TestCyl2DMesh(unittest.TestCase): assert np.abs(mag[dist > 0.1].min() - 1) < TOL + def test_getInterpMatCartMesh_Faces2Edges(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + Pf2e = Mc.getInterpolationMatCartMesh(Mr, 'F', locTypeTo='E') + mf = np.ones(Mc.nF) + + ecart = Pf2e * mf + + excc = Mr.aveEx2CC*Mr.r(ecart, 'E', 'Ex') + eycc = Mr.aveEy2CC*Mr.r(ecart, 'E', 'Ey') + ezcc = Mr.r(ecart, 'E', 'Ez') + + indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) + indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5]) + + TOL = 1e-2 + assert np.abs(float(excc[indX]) - 1) < TOL + assert np.abs(float(excc[indY]) - 0) < TOL + assert np.abs(float(eycc[indX]) - 0) < TOL + assert np.abs(float(eycc[indY]) - 1) < TOL + assert np.abs((ezcc - 1).sum()) < TOL + + mag = (excc**2 + eycc**2)**0.5 + dist = ((Mr.gridCC[:,0] + 0.2)**2 + (Mr.gridCC[:,1] + 0.2)**2)**0.5 + + assert np.abs(mag[dist > 0.1].max() - 1) < TOL + assert np.abs(mag[dist > 0.1].min() - 1) < TOL + + def test_getInterpMatCartMesh_Edges(self): Mr = Mesh.TensorMesh([100,100,2], x0='CC0') @@ -185,11 +230,42 @@ class TestCyl2DMesh(unittest.TestCase): Pe = Mc.getInterpolationMatCartMesh(Mr, 'E') me = np.ones(Mc.nE) - erect = Pe * me + ecart = Pe * me - excc = Mr.aveEx2CC*Mr.r(erect, 'E', 'Ex') - eycc = Mr.aveEy2CC*Mr.r(erect, 'E', 'Ey') - ezcc = Mr.r(erect, 'E', 'Ez') + excc = Mr.aveEx2CC*Mr.r(ecart, 'E', 'Ex') + eycc = Mr.aveEy2CC*Mr.r(ecart, 'E', 'Ey') + ezcc = Mr.aveEz2CC*Mr.r(ecart, 'E', 'Ez') + + indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) + indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5]) + + TOL = 1e-2 + assert np.abs(float(excc[indX]) - 0) < TOL + assert np.abs(float(excc[indY]) + 1) < TOL + assert np.abs(float(eycc[indX]) - 1) < TOL + assert np.abs(float(eycc[indY]) - 0) < TOL + assert np.abs(ezcc.sum()) < TOL + + mag = (excc**2 + eycc**2)**0.5 + dist = ((Mr.gridCC[:,0] + 0.2)**2 + (Mr.gridCC[:,1] + 0.2)**2)**0.5 + + assert np.abs(mag[dist > 0.1].max() - 1) < TOL + assert np.abs(mag[dist > 0.1].min() - 1) < TOL + + + def test_getInterpMatCartMesh_Edges2Faces(self): + + Mr = Mesh.TensorMesh([100,100,2], x0='CC0') + Mc = Mesh.CylMesh([np.ones(10)/5,1,10],x0='0C0',cartesianOrigin=[-0.2,-0.2,0]) + + Pe2f = Mc.getInterpolationMatCartMesh(Mr, 'E', locTypeTo='F') + me = np.ones(Mc.nE) + + frect = Pe2f * me + + excc = Mr.aveFx2CC*Mr.r(frect, 'F', 'Fx') + eycc = Mr.aveFy2CC*Mr.r(frect, 'F', 'Fy') + ezcc = Mr.r(frect, 'F', 'Fz') indX = Utils.closestPoints(Mr, [0.45, -0.2, 0.5]) indY = Utils.closestPoints(Mr, [-0.2, 0.45, 0.5])