def test_updateMultipliers(self): nP = 10 m = np.random.rand(nP) W1 = utils.sdiag(np.random.rand(nP)) W2 = utils.sdiag(np.random.rand(nP)) phi1 = objective_function.L2ObjectiveFunction(W=W1) phi2 = objective_function.L2ObjectiveFunction(W=W2) phi = phi1 + phi2 self.assertTrue(phi(m) == phi1(m) + phi2(m)) phi.multipliers[0] = utils.Zero() self.assertTrue(phi(m) == phi2(m)) phi.multipliers[0] = 1.0 phi.multipliers[1] = utils.Zero() self.assertTrue(len(phi.objfcts) == 2) self.assertTrue(len(phi.multipliers) == 2) self.assertTrue(len(phi) == 2) self.assertTrue(phi(m) == phi1(m))
def solve_2D_J(rho1, rho2, h, A, B): ex, ez, V = solve_2D_E(rho1, rho2, h, A, B) sigma = 1.0 / rho2 * np.ones(mesh.nC) sigma[mesh.gridCC[:, 1] >= -h] = 1.0 / rho1 # since the model is 2D return utils.sdiag(sigma) * ex, utils.sdiag(sigma) * ez, V
def M(self): """ M: ndarray Magnetization matrix """ if getattr(self, "_M", None) is None: if self.modelType == "vector": self._M = sp.identity(self.nC) * self.survey.source_field.parameters[0] else: mag = mat_utils.dip_azimuth2cartesian( np.ones(self.nC) * self.survey.source_field.parameters[1], np.ones(self.nC) * self.survey.source_field.parameters[2], ) self._M = sp.vstack( ( sdiag(mag[:, 0] * self.survey.source_field.parameters[0]), sdiag(mag[:, 1] * self.survey.source_field.parameters[0]), sdiag(mag[:, 2] * self.survey.source_field.parameters[0]), ) ) return self._M
def solve_2D_potentials(rho1, rho2, h, A, B): """ Here we solve the 2D DC problem for potentials (using SimPEG Mesh Class) """ sigma = 1.0 / rho2 * np.ones(mesh.nC) sigma[mesh.gridCC[:, 1] >= -h] = 1.0 / rho1 # since the model is 2D q = np.zeros(mesh.nC) a = utils.closestPoints(mesh, A[:2]) q[a] = 1.0 / mesh.vol[a] if B is not None: b = utils.closestPoints(mesh, B[:2]) q[b] = -1.0 / mesh.vol[b] # Use a Neumann Boundary Condition (so pole source is reasonable) fxm, fxp, fym, fyp = mesh.faceBoundaryInd n_xm = fxm.sum() n_xp = fxp.sum() n_ym = fym.sum() n_yp = fyp.sum() xBC_xm = np.zeros(n_xm) # 0.5*a_xm xBC_xp = np.zeros(n_xp) # 0.5*a_xp/b_xp yBC_xm = np.ones(n_xm) # 0.5*(1.-b_xm) yBC_xp = np.ones(n_xp) # 0.5*(1.-1./b_xp) xBC_ym = np.zeros(n_ym) # 0.5*a_ym xBC_yp = np.zeros(n_yp) # 0.5*a_yp/b_yp yBC_ym = np.ones(n_ym) # 0.5*(1.-b_ym) yBC_yp = np.ones(n_yp) # 0.5*(1.-1./b_yp) sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]]) sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]]) xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx] xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy] yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx] yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy] x_BC = np.r_[xBC_x, xBC_y] y_BC = np.r_[yBC_x, yBC_y] V = utils.sdiag(mesh.vol) Div = V * mesh.faceDiv P_BC, B = mesh.getBCProjWF_simple() M = B * mesh.aveCC2F Grad = Div.T - P_BC * utils.sdiag(y_BC) * M A = (Div * utils.sdiag(1.0 / (mesh.dim * mesh.aveF2CC.T * (1.0 / sigma))) * Grad) A[0, 0] = A[0, 0] + 1. # Because Neumann Ainv = Pardiso(A) V = Ainv * q return V
def M(self, M): """ Create magnetization matrix from unit vector orientation :parameter M: array (3*nC,) or (nC, 3) """ if self.modelType == "vector": self._M = sdiag(mkvc(M) * self.survey.source_field.parameters[0]) else: M = M.reshape((-1, 3)) self._M = sp.vstack(( sdiag(M[:, 0] * self.survey.source_field.parameters[0]), sdiag(M[:, 1] * self.survey.source_field.parameters[0]), sdiag(M[:, 2] * self.survey.source_field.parameters[0]), ))
def BiotSavartFun(mesh, r_pts, component="z"): """ Compute systematrix G using Biot-Savart Law G = np.vstack((G1,G2,G3..,Gnpts) .. math:: """ if r_pts.ndim == 1: npts = 1 else: npts = r_pts.shape[0] e = np.ones((mesh.nC, 1)) o = np.zeros((mesh.nC, 1)) const = mu_0 / 4 / np.pi G = np.zeros((npts, mesh.nC * 3)) for i in range(npts): if npts == 1: r_rx = np.repeat(utils.mkvc(r_pts).reshape([1, -1]), mesh.nC, axis=0) else: r_rx = np.repeat(r_pts[i, :].reshape([1, -1]), mesh.nC, axis=0) r_CC = mesh.gridCC r = r_rx - r_CC r_abs = np.sqrt((r**2).sum(axis=1)) rxind = r_abs == 0.0 # r_abs[rxind] = mesh.vol.min()**(1./3.)*0.5 r_abs[rxind] = 1e20 Sx = const * utils.sdiag(mesh.vol * r[:, 0] / r_abs**3) Sy = const * utils.sdiag(mesh.vol * r[:, 1] / r_abs**3) Sz = const * utils.sdiag(mesh.vol * r[:, 2] / r_abs**3) # G_temp = sp.vstack((sp.hstack(( o.T, e.T*Sz, -e.T*Sy)), \ # sp.hstack((-e.T*Sz, o.T, e.T*Sx)), \ # sp.hstack((-e.T*Sy, e.T*Sx, o.T )))) if component == "x": G_temp = np.hstack((o.T, e.T * Sz, -e.T * Sy)) elif component == "y": G_temp = np.hstack((-e.T * Sz, o.T, e.T * Sx)) elif component == "z": G_temp = np.hstack((e.T * Sy, -e.T * Sx, o.T)) G[i, :] = G_temp return G
def solve_2D_potentials(rho1, rho2, h, A, B): """ Here we solve the 2D DC problem for potentials (using SimPEG Mesg Class) """ sigma = 1.0 / rho2 * np.ones(mesh.nC) sigma[mesh.gridCC[:, 1] >= -h] = 1.0 / rho1 # since the model is 2D q = np.zeros(mesh.nC) a = utils.closestPoints(mesh, A[:2]) b = utils.closestPoints(mesh, B[:2]) q[a] = 1.0 / mesh.vol[a] q[b] = -1.0 / mesh.vol[b] # q = q * 1./mesh.vol A = ( mesh.cellGrad.T * utils.sdiag(1.0 / (mesh.dim * mesh.aveF2CC.T * (1.0 / sigma))) * mesh.cellGrad ) Ainv = Pardiso(A) V = Ainv * q return V
def test_basic(self): expMap = maps.ExpMap(discretize.TensorMesh((3,))) assert expMap.nP == 3 for Example in [SimpleExample, ShortcutExample]: PM = Example(sigmaMap=expMap) assert PM.sigmaMap is not None assert PM.sigmaMap is expMap # There is currently no model, so sigma, which is mapped, fails self.assertRaises(AttributeError, getattr, PM, "sigma") PM.model = np.r_[1.0, 2.0, 3.0] assert np.all(PM.sigma == np.exp(np.r_[1.0, 2.0, 3.0])) # PM = pickle.loads(pickle.dumps(PM)) # PM = maps.ExpMap.deserialize(PM.serialize()) assert np.all( PM.sigmaDeriv.todense() == utils.sdiag(np.exp(np.r_[1.0, 2.0, 3.0])).todense() ) # If we set sigma, we should delete the mapping PM.sigma = np.r_[1.0, 2.0, 3.0] assert np.all(PM.sigma == np.r_[1.0, 2.0, 3.0]) # PM = pickle.loads(pickle.dumps(PM)) assert PM.sigmaMap is None assert PM.sigmaDeriv == 0 del PM.model # sigma is not changed assert np.all(PM.sigma == np.r_[1.0, 2.0, 3.0])
def getJtJdiag(self, m, W=None): """ Return the diagonal of JtJ """ self.model = m if W is None: W = np.ones(self.survey.nD) else: W = W.diagonal() ** 2 if getattr(self, "_gtg_diagonal", None) is None: diag = np.zeros(self.G.shape[1]) if not self.is_amplitude_data: for i in range(len(W)): diag += W[i] * (self.G[i] * self.G[i]) else: fieldDeriv = self.fieldDeriv Gx = self.G[::3] Gy = self.G[1::3] Gz = self.G[2::3] for i in range(len(W)): row = ( fieldDeriv[0, i] * Gx[i] + fieldDeriv[1, i] * Gy[i] + fieldDeriv[2, i] * Gz[i] ) diag += W[i] * (row * row) self._gtg_diagonal = diag else: diag = self._gtg_diagonal return mkvc((sdiag(np.sqrt(diag)) @ self.chiDeriv).power(2).sum(axis=0))
def makeMassMatrices(self, m): mu = self.muMap * m self._MfMui = self.mesh.getFaceInnerProduct(1.0 / mu) / self.mesh.dim # self._MfMui = self.mesh.getFaceInnerProduct(1./mu) # TODO: this will break if tensor mu self._MfMuI = sdiag(1.0 / self._MfMui.diagonal()) self._MfMu0 = self.mesh.getFaceInnerProduct(1.0 / mu_0) / self.mesh.dim
def test_early_exits(self): nP = 10 m = np.random.rand(nP) v = np.random.rand(nP) W1 = utils.sdiag(np.random.rand(nP)) phi1 = objective_function.L2ObjectiveFunction(W=W1) phi2 = Error_if_Hit_ObjFct() objfct = phi1 + 0 * phi2 self.assertTrue(len(objfct) == 2) self.assertTrue(np.all(objfct.multipliers == np.r_[1, 0])) self.assertTrue(objfct(m) == phi1(m)) self.assertTrue(np.all(objfct.deriv(m) == phi1.deriv(m))) self.assertTrue(np.all(objfct.deriv2(m, v) == phi1.deriv2(m, v))) objfct.multipliers[1] = utils.Zero() self.assertTrue(len(objfct) == 2) self.assertTrue(np.all(objfct.multipliers == np.r_[1, 0])) self.assertTrue(objfct(m) == phi1(m)) self.assertTrue(np.all(objfct.deriv(m) == phi1.deriv(m))) self.assertTrue(np.all(objfct.deriv2(m, v) == phi1.deriv2(m, v)))
def __init__(self, mesh, **kwargs): super().__init__(mesh, **kwargs) Pbc, Pin, self._Pout = self.mesh.getBCProjWF("neumann", discretization="CC") Dface = self.mesh.faceDiv Mc = sdiag(self.mesh.vol) self._Div = Mc * Dface * Pin.T * Pin
def test_sum_fail(self): nP1 = 10 nP2 = 30 phi1 = objective_function.L2ObjectiveFunction( W=utils.sdiag(np.random.rand(nP1)) ) phi2 = objective_function.L2ObjectiveFunction( W=utils.sdiag(np.random.rand(nP2)) ) with self.assertRaises(Exception): phi = phi1 + phi2 with self.assertRaises(Exception): phi = phi1 + 100 * phi2
def getRHS(self, m): """""" Mc = utils.sdiag(self.mesh.vol) self.model = m rho = self.rho return Mc * rho
def CasingMagDipoleDeriv_z(z): obsloc = np.vstack([xobs, yobs, z]).T f = Casing._getCasingHertzMagDipole(srcloc, obsloc, freq, sigma, a, b, mu) g = utils.sdiag( Casing._getCasingHertzMagDipoleDeriv_z(srcloc, obsloc, freq, sigma, a, b, mu)) return f, g
def test_NewtonRoot(self): fun = (lambda x, return_g=True: np.sin(x) if not return_g else (np.sin(x), sdiag(np.cos(x)))) x = np.array([np.pi - 0.3, np.pi + 0.1, 0]) xopt = optimization.NewtonRoot(comments=False).root(fun, x) x_true = np.array([np.pi, np.pi, 0]) print("Newton Root Finding") print("xopt: ", xopt) print("x_true: ", x_true) self.assertTrue(np.linalg.norm(xopt - x_true, 2) < TOL, True)
def getFields(self, bType="b", ifreq=0): src = self.srcList[ifreq] Pfx = self.mesh.getInterpolationMat(self.mesh.gridCC[self.activeCC, :], locType="Fx") Pfz = self.mesh.getInterpolationMat(self.mesh.gridCC[self.activeCC, :], locType="Fz") Ey = self.mesh.aveE2CC * self.f[src, "e"] Jy = utils.sdiag(self.sim.sigma) * Ey self.Ey = utils.mkvc(self.mirrorArray(Ey[self.activeCC], direction="y")) self.Jy = utils.mkvc(self.mirrorArray(Jy[self.activeCC], direction="y")) self.Bx = utils.mkvc( self.mirrorArray(Pfx * self.f[src, bType], direction="x")) self.Bz = utils.mkvc( self.mirrorArray(Pfz * self.f[src, bType], direction="z"))
def test_scalarmul(self): scalar = 10.0 nP = 100 objfct_a = objective_function.L2ObjectiveFunction( W=utils.sdiag(np.random.randn(nP)) ) objfct_b = scalar * objfct_a m = np.random.rand(nP) objfct_c = objfct_a + objfct_b self.assertTrue(scalar * objfct_a(m) == objfct_b(m)) self.assertTrue(objfct_b.test()) self.assertTrue(objfct_c(m) == objfct_a(m) + objfct_b(m)) self.assertTrue(len(objfct_c.objfcts) == 2) self.assertTrue(len(objfct_c.multipliers) == 2) self.assertTrue(len(objfct_c) == 2)
def getJtJdiag(self, m, W=None): """ Return the diagonal of JtJ """ self.model = m if W is None: W = np.ones(self.survey.nD) else: W = W.diagonal() ** 2 if getattr(self, "_gtg_diagonal", None) is None: diag = np.zeros(self.G.shape[1]) for i in range(len(W)): diag += W[i] * (self.G[i] * self.G[i]) self._gtg_diagonal = diag else: diag = self._gtg_diagonal return mkvc((sdiag(np.sqrt(diag)) @ self.rhoDeriv).power(2).sum(axis=0))
def test_mappings_and_cell_weights(self): mesh = discretize.TensorMesh([8, 7, 6]) m = np.random.rand(2 * mesh.nC) v = np.random.rand(2 * mesh.nC) cell_weights = np.random.rand(mesh.nC) wires = maps.Wires(("sigma", mesh.nC), ("mu", mesh.nC)) reg = regularization.SimpleSmall(mesh, mapping=wires.sigma, cell_weights=cell_weights) objfct = objective_function.L2ObjectiveFunction(W=utils.sdiag( np.sqrt(cell_weights)), mapping=wires.sigma) self.assertTrue(reg(m) == objfct(m)) self.assertTrue(np.all(reg.deriv(m) == objfct.deriv(m))) self.assertTrue(np.all(reg.deriv2(m, v=v) == objfct.deriv2(m, v=v)))
def test_2sum(self): nP = 80 alpha1 = 100 alpha2 = 200 phi1 = ( objective_function.L2ObjectiveFunction(W=utils.sdiag(np.random.rand(nP))) + alpha1 * objective_function.L2ObjectiveFunction() ) phi2 = objective_function.L2ObjectiveFunction() + alpha2 * phi1 self.assertTrue(phi2.test(eps=EPS)) self.assertTrue(len(phi1.multipliers) == 2) self.assertTrue(len(phi2.multipliers) == 2) self.assertTrue(len(phi1.objfcts) == 2) self.assertTrue(len(phi2.objfcts) == 2) self.assertTrue(len(phi2) == 2) self.assertTrue(len(phi1) == 2) self.assertTrue(len(phi2) == 2) self.assertTrue(np.all(phi1.multipliers == np.r_[1.0, alpha1])) self.assertTrue(np.all(phi2.multipliers == np.r_[1.0, alpha2]))
def getFields(self, itime): src = self.srcList[0] Ey = self.mesh.aveE2CC * self.f[src, "e", itime] Jy = utils.sdiag(self.sim.sigma) * Ey self.Ey = utils.mkvc(self.mirrorArray(Ey[self.activeCC], direction="y")) self.Jy = utils.mkvc(self.mirrorArray(Jy[self.activeCC], direction="y")) self.Bx = utils.mkvc( self.mirrorArray(self.Pfx * self.f[src, "b", itime], direction="x")) self.Bz = utils.mkvc( self.mirrorArray(self.Pfz * self.f[src, "b", itime], direction="z")) self.dBxdt = utils.mkvc( self.mirrorArray(-self.Pfx * self.mesh.edgeCurl * self.f[src, "e", itime], direction="x")) self.dBzdt = utils.mkvc( self.mirrorArray(-self.Pfz * self.mesh.edgeCurl * self.f[src, "e", itime], direction="z"))
# Define the Inverse Problem # -------------------------- # # The inverse problem is defined by 3 things: # # 1) Data Misfit: a measure of how well our recovered model explains the field data # 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis = data_misfit.L2DataMisfit(data=data_object, simulation=simulation) dmis.W = utils.sdiag(1 / uncertainties) # Define the regularization (model objective function). reg = regularization.Sparse(mesh, indActive=ind_active, mapping=model_map) reg.norms = np.c_[0, 2, 2, 2] # Define how the optimization problem is solved. Here we will use a projected # Gauss-Newton approach that employs the conjugate gradient solver. opt = optimization.ProjectedGNCG(maxIter=100, lower=-1.0, upper=1.0, maxIterLS=20, maxIterCG=10, tolCG=1e-3) # Here we define the inverse problem that is to be solved
def Jtvec(self, m, v, u=None): """ Computing Jacobian^T multiplied by vector. .. math :: (\\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}})^{T} = \left[ \mathbf{P}_{deriv}\\frac{\partial \mathbf{\mu} } {\partial \mathbf{m} } \left[ \diag(\M^f_{\mu_{0}^{-1} } \mathbf{B}_0) \dMfMuI \\ - \diag (\Div^T\mathbf{u})\dMfMuI \\right ]\\right]^{T} - \left[\mathbf{P}_{deriv}(\MfMui)^{-1}\Div^T\\frac{\delta\mathbf{u}}{\delta \mathbf{m}} \\right]^{T} where .. math :: \mathbf{P}_{derv} = \\frac{\partial \mathbf{P}}{\partial\mathbf{B}} .. note :: Here we only want to compute .. math :: \mathbf{J}^{T}\mathbf{v} = (\\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}})^{T} \mathbf{v} """ if u is None: u = self.fields(m) B, u = u["B"], u["u"] mu = self.mapping * (m) dmu_dm = self.mapping.deriv(m) # dchidmu = sdiag(1 / mu_0 * np.ones(self.mesh.nC)) vol = self.mesh.vol Div = self._Div Dface = self.mesh.faceDiv P = self.survey.projectFieldsDeriv(B) # Projection matrix B0 = self.getB0() MfMuIvec = 1 / self.MfMui.diagonal() dMfMuI = sdiag(MfMuIvec ** 2) * self.mesh.aveF2CC.T * sdiag(vol * 1.0 / mu ** 2) # A = self._Div*self.MfMuI*self._Div.T # RHS = Div*MfMuI*MfMu0*B0 - Div*B0 + Mc*Dface*Pout.T*Bbc # C(m,u) = A*m-rhs # dudm = -(dCdu)^(-1)dCdm dCdu = self.getA(m) s = Div * (self.MfMuI.T * (P.T * v)) Ainv = self.solver(dCdu.T, **self.solver_opts) sol = Ainv * s Ainv.clean() # dCdm_A = Div * ( sdiag( Div.T * u )* dMfMuI *dmu_dm ) # dCdm_Atsol = ( dMfMuI.T*( sdiag( Div.T * u ) * (Div.T * dmu_dm)) ) * sol dCdm_Atsol = (dmu_dm.T * dMfMuI.T * (sdiag(Div.T * u) * Div.T)) * sol # dCdm_RHS1 = Div * (sdiag( self.MfMu0*B0 ) * dMfMuI) # dCdm_RHS1tsol = (dMfMuI.T*( sdiag( self.MfMu0*B0 ) ) * Div.T * dmu_dm) * sol dCdm_RHS1tsol = (dmu_dm.T * dMfMuI.T * (sdiag(self.MfMu0 * B0)) * Div.T) * sol # temp1 = (Dface*(self._Pout.T*self.Bbc_const*self.Bbc)) # temp1sol = (Dface.T * (sdiag(vol) * sol)) # temp2 = self.Bbc_const * (self._Pout.T * self.Bbc).T # dCdm_RHS2v = (sdiag(vol)*temp1)*np.inner(vol, dchidmu*dmu_dm*v) # dCdm_RHS2tsol = (dmu_dm.T * dchidmu.T * vol) * np.inner(temp2, temp1sol) # dCdm_RHSv = dCdm_RHS1*(dmu_dm*v) + dCdm_RHS2v # temporary fix # dCdm_RHStsol = dCdm_RHS1tsol - dCdm_RHS2tsol dCdm_RHStsol = dCdm_RHS1tsol # dCdm_RHSv = dCdm_RHS1*(dmu_dm*v) + dCdm_RHS2v # dCdm_v = dCdm_A*v - dCdm_RHSv Ctv = dCdm_Atsol - dCdm_RHStsol # B = self.MfMuI*self.MfMu0*B0-B0-self.MfMuI*self._Div.T*u # dBdm = d\mudm*dBd\mu # dPBdm^T*v = Atemp^T*P^T*v - Btemp^T*P^T*v - Ctv Atemp = sdiag(self.MfMu0 * B0) * (dMfMuI * (dmu_dm)) Btemp = sdiag(Div.T * u) * (dMfMuI * (dmu_dm)) Jtv = Atemp.T * (P.T * v) - Btemp.T * (P.T * v) - Ctv return mkvc(Jtv)
def Jvec(self, m, v, u=None): """ Computing Jacobian multiplied by vector By setting our problem as .. math :: \mathbf{C}(\mathbf{m}, \mathbf{u}) = \mathbf{A}\mathbf{u} - \mathbf{rhs} = 0 And taking derivative w.r.t m .. math :: \\nabla \mathbf{C}(\mathbf{m}, \mathbf{u}) = \\nabla_m \mathbf{C}(\mathbf{m}) \delta \mathbf{m} + \\nabla_u \mathbf{C}(\mathbf{u}) \delta \mathbf{u} = 0 \\frac{\delta \mathbf{u}}{\delta \mathbf{m}} = - [\\nabla_u \mathbf{C}(\mathbf{u})]^{-1}\\nabla_m \mathbf{C}(\mathbf{m}) With some linear algebra we can have .. math :: \\nabla_u \mathbf{C}(\mathbf{u}) = \mathbf{A} \\nabla_m \mathbf{C}(\mathbf{m}) = \\frac{\partial \mathbf{A}}{\partial \mathbf{m}}(\mathbf{m})\mathbf{u} - \\frac{\partial \mathbf{rhs}(\mathbf{m})}{\partial \mathbf{m}} .. math :: \\frac{\partial \mathbf{A}}{\partial \mathbf{m}}(\mathbf{m})\mathbf{u} = \\frac{\partial \mathbf{\mu}}{\partial \mathbf{m}} \left[\Div \diag (\Div^T \mathbf{u}) \dMfMuI \\right] \dMfMuI = \diag(\MfMui)^{-1}_{vec} \mathbf{Av}_{F2CC}^T\diag(\mathbf{v})\diag(\\frac{1}{\mu^2}) \\frac{\partial \mathbf{rhs}(\mathbf{m})}{\partial \mathbf{m}} = \\frac{\partial \mathbf{\mu}}{\partial \mathbf{m}} \left[ \Div \diag(\M^f_{\mu_{0}^{-1}}\mathbf{B}_0) \dMfMuI \\right] - \diag(\mathbf{v})\mathbf{D} \mathbf{P}_{out}^T\\frac{\partial B_{sBC}}{\partial \mathbf{m}} In the end, .. math :: \\frac{\delta \mathbf{u}}{\delta \mathbf{m}} = - [ \mathbf{A} ]^{-1}\left[ \\frac{\partial \mathbf{A}}{\partial \mathbf{m}}(\mathbf{m})\mathbf{u} - \\frac{\partial \mathbf{rhs}(\mathbf{m})}{\partial \mathbf{m}} \\right] A little tricky point here is we are not interested in potential (u), but interested in magnetic flux (B). Thus, we need sensitivity for B. Now we take derivative of B w.r.t m and have .. math :: \\frac{\delta \mathbf{B}} {\delta \mathbf{m}} = \\frac{\partial \mathbf{\mu} } {\partial \mathbf{m} } \left[ \diag(\M^f_{\mu_{0}^{-1} } \mathbf{B}_0) \dMfMuI \\ - \diag (\Div^T\mathbf{u})\dMfMuI \\right ] - (\MfMui)^{-1}\Div^T\\frac{\delta\mathbf{u}}{\delta \mathbf{m}} Finally we evaluate the above, but we should remember that .. note :: We only want to evalute .. math :: \mathbf{J}\mathbf{v} = \\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}}\mathbf{v} Since forming sensitivity matrix is very expensive in that this monster is "big" and "dense" matrix!! """ if u is None: u = self.fields(m) B, u = u["B"], u["u"] mu = self.muMap * (m) dmu_dm = self.muDeriv # dchidmu = sdiag(1 / mu_0 * np.ones(self.mesh.nC)) vol = self.mesh.vol Div = self._Div P = self.survey.projectFieldsDeriv(B) # Projection matrix B0 = self.getB0() MfMuIvec = 1 / self.MfMui.diagonal() dMfMuI = sdiag(MfMuIvec ** 2) * self.mesh.aveF2CC.T * sdiag(vol * 1.0 / mu ** 2) # A = self._Div*self.MfMuI*self._Div.T # RHS = Div*MfMuI*MfMu0*B0 - Div*B0 + Mc*Dface*Pout.T*Bbc # C(m,u) = A*m-rhs # dudm = -(dCdu)^(-1)dCdm dCdu = self.getA(m) # = A dCdm_A = Div * (sdiag(Div.T * u) * dMfMuI * dmu_dm) dCdm_RHS1 = Div * (sdiag(self.MfMu0 * B0) * dMfMuI) # temp1 = (Dface * (self._Pout.T * self.Bbc_const * self.Bbc)) # dCdm_RHS2v = (sdiag(vol) * temp1) * \ # np.inner(vol, dchidmu * dmu_dm * v) # dCdm_RHSv = dCdm_RHS1*(dmu_dm*v) + dCdm_RHS2v dCdm_RHSv = dCdm_RHS1 * (dmu_dm * v) dCdm_v = dCdm_A * v - dCdm_RHSv Ainv = self.solver(dCdu, **self.solver_opts) sol = Ainv * dCdm_v dudm = -sol dBdmv = ( sdiag(self.MfMu0 * B0) * (dMfMuI * (dmu_dm * v)) - sdiag(Div.T * u) * (dMfMuI * (dmu_dm * v)) - self.MfMuI * (Div.T * (dudm)) ) Ainv.clean() return mkvc(P * dBdmv)
def run(runIt=False, plotIt=True, saveIt=False, saveFig=False, cleanup=True): """ Run the bookpurnong 1D stitched RESOLVE inversions. :param bool runIt: re-run the inversions? Default downloads and plots saved results :param bool plotIt: show the plots? :param bool saveIt: save the re-inverted results? :param bool saveFig: save the figure :param bool cleanup: remove the downloaded results """ # download the data downloads, directory = download_and_unzip_data() # Load resolve data resolve = h5py.File(os.path.sep.join([directory, "booky_resolve.hdf5"]), "r") river_path = resolve["river_path"][()] # River path nSounding = resolve["data"].shape[0] # the # of soundings # Bird height from surface b_height_resolve = resolve["src_elevation"][()] # fetch the frequencies we are considering cpi_inds = [0, 2, 6, 8, 10] # Indices for HCP in-phase cpq_inds = [1, 3, 7, 9, 11] # Indices for HCP quadrature frequency_cp = resolve["frequency_cp"][()] # build a mesh cs, ncx, ncz, npad = 1.0, 10.0, 10.0, 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.0), np.log10(12.0), 19) temp_pad = temp[-1] * 1.3**np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = discretize.CylMesh([hx, 1, hz], "00C") active = mesh.vectorCCz < 0.0 # survey parameters rxOffset = 7.86 # tx-rx separation bp = -mu_0 / (4 * np.pi * rxOffset**3) # primary magnetic field # re-run the inversion if runIt: # set up the mappings - we are inverting for 1D log conductivity # below the earth's surface. actMap = maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = maps.ExpMap(mesh) * maps.SurjectVertical1D(mesh) * actMap # build starting and reference model sig_half = 1e-1 sig_air = 1e-8 sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half m0 = np.log(1e-1) * np.ones(active.sum()) # starting model mref = np.log(1e-1) * np.ones(active.sum()) # reference model # initalize empty lists for storing inversion results mopt_re = [] # recovered model dpred_re = [] # predicted data dobs_re = [] # observed data # downsample the data for the inversion nskip = 40 # set up a noise model # 10% for the 3 lowest frequencies, 15% for the two highest relative = np.repeat(np.r_[np.ones(3) * 0.1, np.ones(2) * 0.15], 2) floor = abs(20 * bp * 1e-6) # floor of 20ppm # loop over the soundings and invert each for rxind in range(nSounding): # convert data from ppm to magnetic field (A/m^2) dobs = (np.c_[resolve["data"][rxind, :][cpi_inds].astype(float), resolve["data"][ rxind, :][cpq_inds].astype(float), ].flatten() * bp * 1e-6) # perform the inversion src_height = b_height_resolve[rxind].astype(float) mopt, dpred, dobs = resolve_1Dinversions( mesh, dobs, src_height, frequency_cp, m0, mref, mapping, relative=relative, floor=floor, ) # add results to our list mopt_re.append(mopt) dpred_re.append(dpred) dobs_re.append(dobs) # save results mopt_re = np.vstack(mopt_re) dpred_re = np.vstack(dpred_re) dobs_re = np.vstack(dobs_re) if saveIt: np.save("mopt_re_final", mopt_re) np.save("dobs_re_final", dobs_re) np.save("dpred_re_final", dpred_re) mopt_re = resolve["mopt"][()] dobs_re = resolve["dobs"][()] dpred_re = resolve["dpred"][()] sigma = np.exp(mopt_re) indz = -7 # depth index # so that we can visually compare with literature (eg Viezzoli, 2010) cmap = "jet" # dummy figure for colobar fig = plt.figure() out = plt.scatter(np.ones(3), np.ones(3), c=np.linspace(-2, 1, 3), cmap=cmap) plt.close(fig) # plot from the paper fs = 13 # fontsize # matplotlib.rcParams['font.size'] = fs plt.figure(figsize=(13, 7)) ax0 = plt.subplot2grid((2, 3), (0, 0), rowspan=2, colspan=2) ax1 = plt.subplot2grid((2, 3), (0, 2)) ax2 = plt.subplot2grid((2, 3), (1, 2)) # titles of plots title = [ ("(a) Recovered model, %.1f m depth") % (-mesh.vectorCCz[active][indz]), "(b) Obs (Real 400 Hz)", "(c) Pred (Real 400 Hz)", ] temp = sigma[:, indz] tree = cKDTree(list(zip(resolve["xy"][:, 0], resolve["xy"][:, 1]))) d, d_inds = tree.query(list(zip(resolve["xy"][:, 0], resolve["xy"][:, 1])), k=20) w = 1.0 / (d + 100.0)**2.0 w = utils.sdiag(1.0 / np.sum(w, axis=1)) * (w) xy = resolve["xy"] temp = (temp.flatten()[d_inds] * w).sum(axis=1) utils.plot2Ddata( xy, temp, ncontour=100, scale="log", dataloc=False, contourOpts={ "cmap": cmap, "vmin": 1e-2, "vmax": 1e1 }, ax=ax0, ) ax0.plot(resolve["xy"][:, 0], resolve["xy"][:, 1], "k.", alpha=0.02, ms=1) cb = plt.colorbar(out, ax=ax0, ticks=np.linspace(-2, 1, 4), format="$10^{%.1f}$") cb.set_ticklabels(["0.01", "0.1", "1", "10"]) cb.set_label("Conductivity (S/m)") ax0.plot(river_path[:, 0], river_path[:, 1], "k-", lw=0.5) # plot observed and predicted data freq_ind = 0 axs = [ax1, ax2] temp_dobs = dobs_re[:, freq_ind].copy() ax1.plot(river_path[:, 0], river_path[:, 1], "k-", lw=0.5) inf = temp_dobs / abs(bp) * 1e6 print(inf.min(), inf.max()) out = utils.plot2Ddata( resolve["xy"][()], temp_dobs / abs(bp) * 1e6, ncontour=100, scale="log", dataloc=False, ax=ax1, contourOpts={"cmap": "viridis"}, ) vmin, vmax = out[0].get_clim() print(vmin, vmax) cb = plt.colorbar( out[0], ticks=np.logspace(np.log10(vmin), np.log10(vmax), 3), ax=ax1, format="%.1e", fraction=0.046, pad=0.04, ) cb.set_label("Bz (ppm)") temp_dpred = dpred_re[:, freq_ind].copy() # temp_dpred[mask_:_data] = np.nan ax2.plot(river_path[:, 0], river_path[:, 1], "k-", lw=0.5) utils.plot2Ddata( resolve["xy"][()], temp_dpred / abs(bp) * 1e6, ncontour=100, scale="log", dataloc=False, contourOpts={ "vmin": vmin, "vmax": vmax, "cmap": "viridis" }, ax=ax2, ) cb = plt.colorbar( out[0], ticks=np.logspace(np.log10(vmin), np.log10(vmax), 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04, ) cb.set_label("Bz (ppm)") for i, ax in enumerate([ax0, ax1, ax2]): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] xloc, yloc = 462100.0, 6196500.0 ax.set_xticks(xticks) ax.set_yticks(yticks) # ax.plot(xloc, yloc, 'wo') ax.plot(river_path[:, 0], river_path[:, 1], "k", lw=0.5) ax.set_aspect("equal") ax.plot(resolve["xy"][:, 0], resolve["xy"][:, 1], "k.", alpha=0.02, ms=1) ax.set_yticklabels([str(f) for f in yticks]) ax.set_ylabel("Northing (m)") ax.set_xlabel("Easting (m)") ax.set_title(title[i]) plt.tight_layout() if plotIt: plt.show() if saveFig is True: fig.savefig("obspred_resolve.png", dpi=200) resolve.close() if cleanup: os.remove(downloads) shutil.rmtree(directory)
def test_CylMeshEBDipoles(self, plotIt=plotIt): print("Testing CylMesh Electric and Magnetic Dipoles in a wholespace-" " Analytic: J-formulation") sigmaback = 1.0 mur = 2.0 freq = 1.0 skdpth = 500.0 / np.sqrt(sigmaback * freq) csx, ncx, npadx = 5, 50, 25 csz, ncz, npadz = 5, 50, 25 hx = utils.meshTensor([(csx, ncx), (csx, npadx, 1.3)]) hz = utils.meshTensor([(csz, npadz, -1.3), (csz, ncz), (csz, npadz, 1.3)]) # define the cylindrical mesh mesh = discretize.CylMesh([hx, 1, hz], [0.0, 0.0, -hz.sum() / 2]) if plotIt: mesh.plotGrid() # make sure mesh is big enough self.assertTrue(mesh.hz.sum() > skdpth * 2.0) self.assertTrue(mesh.hx.sum() > skdpth * 2.0) # set up source # test electric dipole src_loc = np.r_[0.0, 0.0, 0.0] s_ind = utils.closestPoints(mesh, src_loc, "Fz") + mesh.nFx de = np.zeros(mesh.nF, dtype=complex) de[s_ind] = 1.0 / csz de_p = [fdem.Src.RawVec_e([], freq, de / mesh.area)] dm_p = [fdem.Src.MagDipole([], freq, src_loc)] # Pair the problem and survey surveye = fdem.Survey(de_p) surveym = fdem.Survey(dm_p) prbe = fdem.Simulation3DMagneticField(mesh, survey=surveye, sigma=sigmaback, mu=mur * mu_0) prbm = fdem.Simulation3DElectricField(mesh, survey=surveym, sigma=sigmaback, mu=mur * mu_0) # solve fieldsBackE = prbe.fields() fieldsBackM = prbm.fields() rlim = [20.0, 500.0] # lookAtTx = de_p r = mesh.vectorCCx[np.argmin(np.abs(mesh.vectorCCx - rlim[0])):np. argmin(np.abs(mesh.vectorCCx - rlim[1]))] z = 100.0 # where we choose to measure XYZ = utils.ndgrid(r, np.r_[0.0], np.r_[z]) Pf = mesh.getInterpolationMat(XYZ, "CC") Zero = sp.csr_matrix(Pf.shape) Pfx, Pfz = sp.hstack([Pf, Zero]), sp.hstack([Zero, Pf]) jn = fieldsBackE[de_p, "j"] bn = fieldsBackM[dm_p, "b"] SigmaBack = sigmaback * np.ones((mesh.nC)) Rho = utils.sdiag(1.0 / SigmaBack) Rho = sp.block_diag([Rho, Rho]) en = Rho * mesh.aveF2CCV * jn bn = mesh.aveF2CCV * bn ex, ez = Pfx * en, Pfz * en bx, bz = Pfx * bn, Pfz * bn # get analytic solution exa, eya, eza = analytics.FDEM.ElectricDipoleWholeSpace(XYZ, src_loc, sigmaback, freq, "Z", mu_r=mur) exa = utils.mkvc(exa, 2) eya = utils.mkvc(eya, 2) eza = utils.mkvc(eza, 2) bxa, bya, bza = analytics.FDEM.MagneticDipoleWholeSpace(XYZ, src_loc, sigmaback, freq, "Z", mu_r=mur) bxa = utils.mkvc(bxa, 2) bya = utils.mkvc(bya, 2) bza = utils.mkvc(bza, 2) print( " comp, anayltic, numeric, num - ana, (num - ana)/ana" ) print( " ex:", np.linalg.norm(exa), np.linalg.norm(ex), np.linalg.norm(exa - ex), np.linalg.norm(exa - ex) / np.linalg.norm(exa), ) print( " ez:", np.linalg.norm(eza), np.linalg.norm(ez), np.linalg.norm(eza - ez), np.linalg.norm(eza - ez) / np.linalg.norm(eza), ) print( " bx:", np.linalg.norm(bxa), np.linalg.norm(bx), np.linalg.norm(bxa - bx), np.linalg.norm(bxa - bx) / np.linalg.norm(bxa), ) print( " bz:", np.linalg.norm(bza), np.linalg.norm(bz), np.linalg.norm(bza - bz), np.linalg.norm(bza - bz) / np.linalg.norm(bza), ) if plotIt is True: # Edipole plt.subplot(221) plt.plot(r, ex.real, "o", r, exa.real, linewidth=2) plt.grid(which="both") plt.title("Ex Real") plt.xlabel("r (m)") plt.subplot(222) plt.plot(r, ex.imag, "o", r, exa.imag, linewidth=2) plt.grid(which="both") plt.title("Ex Imag") plt.legend(["Num", "Ana"], bbox_to_anchor=(1.5, 0.5)) plt.xlabel("r (m)") plt.subplot(223) plt.plot(r, ez.real, "o", r, eza.real, linewidth=2) plt.grid(which="both") plt.title("Ez Real") plt.xlabel("r (m)") plt.subplot(224) plt.plot(r, ez.imag, "o", r, eza.imag, linewidth=2) plt.grid(which="both") plt.title("Ez Imag") plt.xlabel("r (m)") plt.tight_layout() # Bdipole plt.subplot(221) plt.plot(r, bx.real, "o", r, bxa.real, linewidth=2) plt.grid(which="both") plt.title("Bx Real") plt.xlabel("r (m)") plt.subplot(222) plt.plot(r, bx.imag, "o", r, bxa.imag, linewidth=2) plt.grid(which="both") plt.title("Bx Imag") plt.legend(["Num", "Ana"], bbox_to_anchor=(1.5, 0.5)) plt.xlabel("r (m)") plt.subplot(223) plt.plot(r, bz.real, "o", r, bza.real, linewidth=2) plt.grid(which="both") plt.title("Bz Real") plt.xlabel("r (m)") plt.subplot(224) plt.plot(r, bz.imag, "o", r, bza.imag, linewidth=2) plt.grid(which="both") plt.title("Bz Imag") plt.xlabel("r (m)") plt.tight_layout() self.assertTrue( np.linalg.norm(exa - ex) / np.linalg.norm(exa) < tol_EBdipole) self.assertTrue( np.linalg.norm(eza - ez) / np.linalg.norm(eza) < tol_EBdipole) self.assertTrue( np.linalg.norm(bxa - bx) / np.linalg.norm(bxa) < tol_EBdipole) self.assertTrue( np.linalg.norm(bza - bz) / np.linalg.norm(bza) < tol_EBdipole)
def getEBJcore(src0): B0 = np.r_[Pfx * f[src0, "b"], Pfy * f[src0, "b"], Pfz * f[src0, "b"]] E0 = np.r_[Pex * f[src0, "e"], Pey * f[src0, "e"], Pez * f[src0, "e"]] J0 = utils.sdiag(np.r_[sigma_core, sigma_core, sigma_core]) * E0 return E0, B0, J0
def simpleFail(x): return np.sin(x), -sdiag(np.cos(x))
def simpleFunction(x): return np.sin(x), lambda xi: sdiag(np.cos(x)) * xi