def _evalCross(self, m): if self.crossgrad == False: return 0. elif self.crossgrad == True: M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F") ax = self.regmesh.aveFx2CC * self.regmesh.wx[0] * M[:, 0] ay = self.regmesh.aveFy2CC * self.regmesh.wy[0] * M[:, 0] az = self.regmesh.aveFz2CC * self.regmesh.wz[0] * M[:, 0] bx = self.regmesh.aveFx2CC * self.regmesh.wx[1] * M[:, 1] by = self.regmesh.aveFy2CC * self.regmesh.wy[1] * M[:, 1] bz = self.regmesh.aveFz2CC * self.regmesh.wz[1] * M[:, 1] #ab out_ab = cross([ax, ay, az], [bx, by, bz]) r = np.r_[out_ab[0], out_ab[1], out_ab[2]] * np.sqrt( self.betacross) if self.nModels == 3: cx = self.regmesh.aveFx2CC * self.regmesh.wx[1] * M[:, 1] cy = self.regmesh.aveFy2CC * self.regmesh.wy[1] * M[:, 1] cz = self.regmesh.aveFz2CC * self.regmesh.wz[1] * M[:, 1] #ac out_ac = cross([ax, ay, az], [cx, cy, cz]) #bc out_bc = cross([bx, by, bz], [cx, cy, cz]) r = np.r_[r, np.hstack(out_ac) * np.sqrt(self.betacross), np.hstack(out_bc) * np.sqrt(self.betacross)] return 0.5 * r.dot(r)
def _getCasingHertzMagDipole2Deriv_z_r(srcloc, obsloc, freq, sigma, a, b, mu=mu_0 * np.ones(3), eps=epsilon_0, moment=1.): HertzZ = _getCasingHertzMagDipole(srcloc, obsloc, freq, sigma, a, b, mu, eps, moment) dHertzZdr = _getCasingHertzMagDipoleDeriv_r(srcloc, obsloc, freq, sigma, a, b, mu, eps, moment) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)] * np.r_[srcloc] r2 = _r2(dxyz[:, :2]) r = np.sqrt(r2) z = dxyz[:, 2] sqrtr2z2 = np.sqrt(r2 + z**2) k2 = k(freq, sigma[2], mu[2], eps) return dHertzZdr * (-z / sqrtr2z2) * (1j * k2 + 1. / sqrtr2z2) + HertzZ * ( z * r / sqrtr2z2**3) * (1j * k2 + 2. / sqrtr2z2)
def _evalCross(self, m): if self.crossgrad == False: return 0.0 elif self.crossgrad == True: M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F") ax = self.regmesh.aveFx2CC * self.regmesh.wx[0] * M[:, 0] ay = self.regmesh.aveFy2CC * self.regmesh.wy[0] * M[:, 0] az = self.regmesh.aveFz2CC * self.regmesh.wz[0] * M[:, 0] bx = self.regmesh.aveFx2CC * self.regmesh.wx[1] * M[:, 1] by = self.regmesh.aveFy2CC * self.regmesh.wy[1] * M[:, 1] bz = self.regmesh.aveFz2CC * self.regmesh.wz[1] * M[:, 1] # ab out_ab = cross([ax, ay, az], [bx, by, bz]) r = np.r_[out_ab[0], out_ab[1], out_ab[2]] * np.sqrt(self.betacross) if self.nModels == 3: cx = self.regmesh.aveFx2CC * self.regmesh.wx[1] * M[:, 1] cy = self.regmesh.aveFy2CC * self.regmesh.wy[1] * M[:, 1] cz = self.regmesh.aveFz2CC * self.regmesh.wz[1] * M[:, 1] # ac out_ac = cross([ax, ay, az], [cx, cy, cz]) # bc out_bc = cross([bx, by, bz], [cx, cy, cz]) r = np.r_[r, np.hstack(out_ac) * np.sqrt(self.betacross), np.hstack(out_bc) * np.sqrt(self.betacross)] return 0.5 * r.dot(r)
def _getCasingHertzMagDipoleDeriv_r(srcloc,obsloc,freq,sigma,a,b,mu=mu_0*np.ones(3),eps=epsilon_0,moment=1.): HertzZ = _getCasingHertzMagDipole(srcloc,obsloc,freq,sigma,a,b,mu,eps,moment) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)]*np.r_[srcloc] r2 = _r2(dxyz[:,:2]) sqrtr2z2 = np.sqrt(r2 + dxyz[:,2]**2) k2 = k(freq,sigma[2],mu[2],eps) return -HertzZ * np.sqrt(r2) / sqrtr2z2 * (1j*k2 + 1./ sqrtr2z2)
def _getCasingHertzMagDipole2Deriv_z_z(srcloc,obsloc,freq,sigma,a,b,mu=mu_0*np.ones(3),eps=epsilon_0,moment=1.): HertzZ = _getCasingHertzMagDipole(srcloc,obsloc,freq,sigma,a,b,mu,eps,moment) dHertzZdz = _getCasingHertzMagDipoleDeriv_z(srcloc,obsloc,freq,sigma,a,b,mu,eps,moment) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)]*np.r_[srcloc] r2 = _r2(dxyz[:,:2]) r = np.sqrt(r2) z = dxyz[:,2] sqrtr2z2 = np.sqrt(r2 + z**2) k2 = k(freq,sigma[2],mu[2],eps) return (dHertzZdz*z + HertzZ)/sqrtr2z2*(-1j*k2 - 1./sqrtr2z2) + HertzZ*z/sqrtr2z2**3*(1j*k2*z + 2.*z/sqrtr2z2)
def test_ana_forward(self): # Compute 3-component mag data self.survey.pair(self.prob_xyz) d = self.prob_xyz.fields(self.model) ndata = self.locXyz.shape[0] dbx = d[0:ndata] dby = d[ndata:2*ndata] dbz = d[2*ndata:] # Compute tmi mag data self.survey.pair(self.prob_tmi) dtmi = self.prob_tmi.fields(self.model) # Compute analytical response from a magnetized sphere bxa, bya, bza = PF.MagAnalytics.MagSphereFreeSpace(self.locXyz[:, 0], self.locXyz[:, 1], self.locXyz[:, 2], self.rad, 0, 0, 0, self.chi, self.b0) # Projection matrix Ptmi = mkvc(self.b0)/np.sqrt(np.sum(self.b0**2.)) btmi = mkvc(Ptmi.dot(np.vstack((bxa, bya, bza)))) err_xyz = (np.linalg.norm(d-np.r_[bxa, bya, bza]) / np.linalg.norm(np.r_[bxa, bya, bza])) err_tmi = np.linalg.norm(dtmi-btmi)/np.linalg.norm(btmi) self.assertTrue(err_xyz < 0.005 and err_tmi < 0.005)
def run(plotIt=True): """ Mesh: Basic: Types ================== Here we show SimPEG used to create three different types of meshes. """ sz = [16, 16] tM = Mesh.TensorMesh(sz) qM = Mesh.TreeMesh(sz) qM.refine(lambda cell: 4 if np.sqrt(((np.r_[cell.center] - 0.5)**2).sum()) < 0.4 else 3) rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz, 'rotate')) if plotIt: import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 3, figsize=(14, 5)) opts = {} tM.plotGrid(ax=axes[0], **opts) axes[0].set_title('TensorMesh') qM.plotGrid(ax=axes[1], **opts) axes[1].set_title('TreeMesh') rM.plotGrid(ax=axes[2], **opts) axes[2].set_title('CurvilinearMesh') plt.show()
def projectFields(self, u): """ This function projects the fields onto the data space. Especially, here for we use total magnetic intensity (TMI) data, which is common in practice. First we project our B on to data location .. math:: \mathbf{B}_{rec} = \mathbf{P} \mathbf{B} then we take the dot product between B and b_0 .. math :: \\text{TMI} = \\vec{B}_s \cdot \hat{B}_0 """ # TODO: There can be some different tyes of data like |B| or B bfx = self.Qfx * u['B'] bfy = self.Qfy * u['B'] bfz = self.Qfz * u['B'] # Generate unit vector B0 = self.prob.survey.B0 Bot = np.sqrt(B0[0]**2 + B0[1]**2 + B0[2]**2) box = B0[0] / Bot boy = B0[1] / Bot boz = B0[2] / Bot # return bfx*box + bfx*boy + bfx*boz return bfx * box + bfy * boy + bfz * boz
def projectFields(self, u): """ This function projects the fields onto the data space. Especially, here for we use total magnetic intensity (TMI) data, which is common in practice. First we project our B on to data location .. math:: \mathbf{B}_{rec} = \mathbf{P} \mathbf{B} then we take the dot product between B and b_0 .. math :: \\text{TMI} = \\vec{B}_s \cdot \hat{B}_0 """ # TODO: There can be some different tyes of data like |B| or B bfx = self.Qfx*u['B'] bfy = self.Qfy*u['B'] bfz = self.Qfz*u['B'] # Generate unit vector B0 = self.prob.survey.B0 Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2) box = B0[0]/Bot boy = B0[1]/Bot boz = B0[2]/Bot # return bfx*box + bfx*boy + bfx*boz return bfx*box + bfy*boy + bfz*boz
def run(plotIt=True): """ Mesh: Basic: Types ================== Here we show SimPEG used to create three different types of meshes. """ sz = [16, 16] tM = Mesh.TensorMesh(sz) qM = Mesh.TreeMesh(sz) qM.refine(lambda cell: 4 if np.sqrt(((np.r_[cell.center]-0.5)**2).sum()) < 0.4 else 3) rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz, 'rotate')) if plotIt: import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 3, figsize=(14, 5)) opts = {} tM.plotGrid(ax=axes[0], **opts) axes[0].set_title('TensorMesh') qM.plotGrid(ax=axes[1], **opts) axes[1].set_title('TreeMesh') rM.plotGrid(ax=axes[2], **opts) axes[2].set_title('CurvilinearMesh') plt.show()
def test_ana_forward(self): # Compute 3-component mag data self.survey.pair(self.prob_xyz) d = self.prob_xyz.fields(self.model) ndata = self.locXyz.shape[0] dbx = d[0:ndata] dby = d[ndata:2 * ndata] dbz = d[2 * ndata:] # Compute tmi mag data self.survey.pair(self.prob_tmi) dtmi = self.prob_tmi.fields(self.model) # Compute analytical response from a magnetized sphere bxa, bya, bza = PF.MagAnalytics.MagSphereFreeSpace( self.locXyz[:, 0], self.locXyz[:, 1], self.locXyz[:, 2], self.rad, 0, 0, 0, self.chi, self.b0) # Projection matrix Ptmi = mkvc(self.b0) / np.sqrt(np.sum(self.b0**2.)) btmi = mkvc(Ptmi.dot(np.vstack((bxa, bya, bza)))) err_xyz = (np.linalg.norm(d - np.r_[bxa, bya, bza]) / np.linalg.norm(np.r_[bxa, bya, bza])) err_tmi = np.linalg.norm(dtmi - btmi) / np.linalg.norm(btmi) self.assertTrue(err_xyz < 0.005 and err_tmi < 0.005)
def function(xc): r = xc - np.r_[2.,6.] dist = np.sqrt(r.dot(r)) if dist < 1.0: return 3 if dist < 1.5: return 2 else: return 1
def convertObs_DC3D_to_2D(Tx,Rx): from SimPEG import np import numpy.matlib as npm """ Read list of 3D Tx Rx location 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 Assumes flat topo for now... Input: :param Tx, Rx Output: :figure Tx2d, Rx2d Created on Mon December 7th, 2015 @author: dominiquef """ Tx2d = [] Rx2d = [] for ii in range(len(Tx)): if ii == 0: endp = Tx[0][0:2,0] nrx = Rx[ii].shape[0] rP1 = np.sqrt( np.sum( ( endp - Tx[ii][0:2,0] )**2 , axis=0)) rP2 = np.sqrt( np.sum( ( endp - Tx[ii][0:2,1] )**2 , axis=0)) rC1 = np.sqrt( np.sum( ( npm.repmat(endp.T,nrx,1) - Rx[ii][:,0:2] )**2 , axis=1)) rC2 = np.sqrt( np.sum( ( npm.repmat(endp.T,nrx,1) - Rx[ii][:,3:5] )**2 , axis=1)) Tx2d.append( np.r_[rP1, rP2] ) Rx2d.append( np.c_[rC1, rC2] ) #np.savetxt(fid, data, fmt='%e',delimiter=' ',newline='\n') return Tx2d, Rx2d
def _getCasingHertzMagDipoleDeriv_r(srcloc, obsloc, freq, sigma, a, b, mu=mu_0 * np.ones(3), eps=epsilon_0, moment=1.): HertzZ = _getCasingHertzMagDipole(srcloc, obsloc, freq, sigma, a, b, mu, eps, moment) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)] * np.r_[srcloc] r2 = _r2(dxyz[:, :2]) sqrtr2z2 = np.sqrt(r2 + dxyz[:, 2]**2) k2 = k(freq, sigma[2], mu[2], eps) return -HertzZ * np.sqrt(r2) / sqrtr2z2 * (1j * k2 + 1. / sqrtr2z2)
def _getCasingHertzMagDipole(srcloc,obsloc,freq,sigma,a,b,mu=mu_0*np.ones(3),eps=epsilon_0,moment=1.): Kc1 = getKc(freq,sigma[1],a,b,mu[1],eps) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)]*np.r_[srcloc] r2 = _r2(dxyz[:,:2]) sqrtr2z2 = np.sqrt(r2 + dxyz[:,2]**2) k2 = k(freq,sigma[2],mu[2],eps) return Kc1 * moment / (4.*np.pi) *np.exp(-1j*k2*sqrtr2z2) / sqrtr2z2
def projectFieldsDeriv(self, B): """ This function projects the fields onto the data space. .. math:: \\frac{\partial d_\\text{pred}}{\partial \mathbf{B}} = \mathbf{P} Especially, this function is for TMI data type """ # Generate unit vector B0 = self.prob.survey.B0 Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2) box = B0[0]/Bot boy = B0[1]/Bot boz = B0[2]/Bot return self.Qfx*box+self.Qfy*boy+self.Qfz*boz
def projectFieldsDeriv(self, B): """ This function projects the fields onto the data space. .. math:: \\frac{\partial d_\\text{pred}}{\partial \mathbf{B}} = \mathbf{P} Especially, this function is for TMI data type """ # Generate unit vector B0 = self.prob.survey.B0 Bot = np.sqrt(B0[0]**2 + B0[1]**2 + B0[2]**2) box = B0[0] / Bot boy = B0[1] / Bot boz = B0[2] / Bot return self.Qfx * box + self.Qfy * boy + self.Qfz * boz
def _getCasingHertzMagDipole(srcloc, obsloc, freq, sigma, a, b, mu=mu_0 * np.ones(3), eps=epsilon_0, moment=1.): Kc1 = getKc(freq, sigma[1], a, b, mu[1], eps) nobs = obsloc.shape[0] dxyz = obsloc - np.c_[np.ones(nobs)] * np.r_[srcloc] r2 = _r2(dxyz[:, :2]) sqrtr2z2 = np.sqrt(r2 + dxyz[:, 2]**2) k2 = k(freq, sigma[2], mu[2], eps) return Kc1 * moment / (4. * np.pi) * np.exp(-1j * k2 * sqrtr2z2) / sqrtr2z2
def run(plotIt=True): """ 1D FDEM and TDEM inversions =========================== This example is used in the paper Heagy et al 2016 (in prep) """ # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10., 15, 25, 13 # padded cyl mesh 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') # Conductivity model layerz = np.r_[-200., -100.] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0. sig_half = 1e-2 # Half-space conductivity sig_air = 1e-8 # Air conductivity sig_layer = 5e-2 # Layer conductivity sigma = np.ones(mesh.nCz)*sig_air sigma[active] = sig_half sigma[layer] = sig_layer # Mapping actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap mtrue = np.log(sigma[active]) # ----- FDEM problem & survey ----- rxlocs = Utils.ndgrid([np.r_[50.], np.r_[0], np.r_[0.]]) bzi = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'real') bzr = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'imag') freqs = np.logspace(2, 3, 5) srcLoc = np.array([0., 0., 0.]) print('min skin depth = ', 500./np.sqrt(freqs.max() * sig_half), 'max skin depth = ', 500./np.sqrt(freqs.min() * sig_half)) print('max x ', mesh.vectorCCx.max(), 'min z ', mesh.vectorCCz.min(), 'max z ', mesh.vectorCCz.max()) srcList = [] [srcList.append(FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z')) for freq in freqs] surveyFD = FDEM.Survey(srcList) prbFD = FDEM.Problem3D_b(mesh, mapping=mapping) prbFD.pair(surveyFD) std = 0.03 surveyFD.makeSyntheticData(mtrue, std) surveyFD.eps = np.linalg.norm(surveyFD.dtrue)*1e-5 # FDEM inversion np.random.seed(1) dmisfit = DataMisfit.l2_DataMisfit(surveyFD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) m0 = np.log(np.ones(mtrue.size)*sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. prbFD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptFD = inv.run(m0) # TDEM problem times = np.logspace(-4, np.log10(2e-3), 10) print('min diffusion distance ', 1.28*np.sqrt(times.min()/(sig_half*mu_0)), 'max diffusion distance ', 1.28*np.sqrt(times.max()/(sig_half*mu_0))) rx = TDEM.Rx(rxlocs, times, 'bz') src = TDEM.Src.MagDipole([rx], waveform=TDEM.Src.StepOffWaveform(), loc=srcLoc) # same src location as FDEM problem surveyTD = TDEM.Survey([src]) prbTD = TDEM.Problem3D_b(mesh, mapping=mapping) prbTD.timeSteps = [(5e-5, 10), (1e-4, 10), (5e-4, 10)] prbTD.pair(surveyTD) prbTD.Solver = SolverLU std = 0.03 surveyTD.makeSyntheticData(mtrue, std) surveyTD.std = std surveyTD.eps = np.linalg.norm(surveyTD.dtrue)*1e-5 # TDEM inversion dmisfit = DataMisfit.l2_DataMisfit(surveyTD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target]) m0 = np.log(np.ones(mtrue.size)*sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. prbTD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptTD = inv.run(m0) if plotIt: import matplotlib fig = plt.figure(figsize = (10, 8)) ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) ax1 = plt.subplot2grid((2, 2), (0, 1)) ax2 = plt.subplot2grid((2, 2), (1, 1)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs # Plot the model ax0.semilogx(sigma[active], mesh.vectorCCz[active], 'k-', lw=2) ax0.semilogx(np.exp(moptFD), mesh.vectorCCz[active], 'bo', ms=6) ax0.semilogx(np.exp(moptTD), mesh.vectorCCz[active], 'r*', ms=10) ax0.set_ylim(-700, 0) ax0.set_xlim(5e-3, 1e-1) ax0.set_xlabel('Conductivity (S/m)', fontsize=fs) ax0.set_ylabel('Depth (m)', fontsize=fs) ax0.grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax0.legend(['True', 'FDEM', 'TDEM'], fontsize=fs, loc=4) # plot the data misfits - negative b/c we choose positive to be in the # direction of primary ax1.plot(freqs, -surveyFD.dobs[::2], 'k-', lw=2) ax1.plot(freqs, -surveyFD.dobs[1::2], 'k--', lw=2) dpredFD = surveyFD.dpred(moptTD) ax1.loglog(freqs, -dpredFD[::2], 'bo', ms=6) ax1.loglog(freqs, -dpredFD[1::2], 'b+', markeredgewidth=2., ms=10) ax2.loglog(times, surveyTD.dobs, 'k-', lw=2) ax2.loglog(times, surveyTD.dpred(moptTD), 'r*', ms=10) ax2.set_xlim(times.min(), times.max()) # Labels, gridlines, etc ax2.grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax1.grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax1.set_xlabel('Frequency (Hz)', fontsize=fs) ax1.set_ylabel('Vertical magnetic field (-T)', fontsize=fs) ax2.set_xlabel('Time (s)', fontsize=fs) ax2.set_ylabel('Vertical magnetic field (-T)', fontsize=fs) ax2.legend(("Obs", "Pred"), fontsize=fs) ax1.legend(("Obs (real)", "Obs (imag)", "Pred (real)", "Pred (imag)"), fontsize=fs) ax1.set_xlim(freqs.max(), freqs.min()) ax0.set_title("(a) Recovered Models", fontsize=fs) ax1.set_title("(b) FDEM observed vs. predicted", fontsize=fs) ax2.set_title("(c) TDEM observed vs. predicted", fontsize=fs) plt.tight_layout(pad=1.5) plt.show()
def MagneticDipoleVectorPotential(srcLoc, obsLoc, component, moment=1., orientation=np.r_[0., 0., 1.], mu=mu_0): """ Calculate the vector potential of a set of magnetic dipoles at given locations 'ref. <http://en.wikipedia.org/wiki/Dipole#Magnetic_vector_potential>' :param numpy.ndarray srcLoc: Location of the source(s) (x, y, z) :param numpy.ndarray,SimPEG.Mesh obsLoc: Where the potentials will be calculated (x, y, z) or a SimPEG Mesh :param str,list component: The component to calculate - 'x', 'y', or 'z' if an array, or grid type if mesh, can be a list :param numpy.ndarray orientation: The vector dipole moment :rtype: numpy.ndarray :return: The vector potential each dipole at each observation location """ # TODO: break this out! if isinstance(orientation, str): orientation = orientationDict[orientation] assert np.linalg.norm(np.array(orientation), 2) == 1., ("orientation must " "be a unit vector") if type(component) in [list, tuple]: out = range(len(component)) for i, comp in enumerate(component): out[i] = MagneticDipoleVectorPotential(srcLoc, obsLoc, comp, orientation=orientation, mu=mu) return np.concatenate(out) if isinstance(obsLoc, Mesh.BaseMesh): mesh = obsLoc assert component in ['Ex', 'Ey', 'Ez', 'Fx', 'Fy', 'Fz'], ("Components" "must be in: ['Ex','Ey','Ez','Fx','Fy','Fz']") return MagneticDipoleVectorPotential(srcLoc, getattr(mesh, 'grid' + component), component[1], orientation=orientation) if component == 'x': dimInd = 0 elif component == 'y': dimInd = 1 elif component == 'z': dimInd = 2 else: raise ValueError('Invalid component') srcLoc = np.atleast_2d(srcLoc) obsLoc = np.atleast_2d(obsLoc) orientation = np.atleast_2d(orientation) nObs = obsLoc.shape[0] nSrc = srcLoc.shape[0] m = moment*np.array(orientation).repeat(nObs, axis=0) A = np.empty((nObs, nSrc)) for i in range(nSrc): dR = obsLoc - srcLoc[i, np.newaxis].repeat(nObs, axis=0) mCr = np.cross(m, dR) r = np.sqrt((dR**2).sum(axis=1)) A[:, i] = +(mu/(4*np.pi)) * mCr[:, dimInd]/(r**3) if nSrc == 1: return A.flatten() return A
def gen_DCIPsurvey(endl, mesh, stype, a, b, n): """ Load in endpoints and survey specifications to generate Tx, Rx location stations. Assumes flat topo for now... Input: :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] :object mesh -> SimPEG mesh object :switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient' : param a, n -> pole seperation, number of rx dipoles per tx Output: :param Tx, Rx -> List objects for each tx location Lines: P1x, P1y, P1z, P2x, P2y, P2z Created on Wed December 9th, 2015 @author: dominiquef !! Require clean up to deal with DCsurvey """ from SimPEG import np def xy_2_r(x1,x2,y1,y2): r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) ) return r ## Evenly distribute electrodes and put on surface # Mesure survey length and direction dl_len = xy_2_r(endl[0,0],endl[1,0],endl[0,1],endl[1,1]) dl_x = ( endl[1,0] - endl[0,0] ) / dl_len dl_y = ( endl[1,1] - endl[0,1] ) / dl_len nstn = np.floor( dl_len / a ) # Compute discrete pole location along line stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a if mesh.dim==2: ztop = mesh.vectorNy[-1] # Create line of P1 locations M = np.c_[stn_x, np.ones(nstn).T*ztop] # Create line of P2 locations N = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop] elif mesh.dim==3: ztop = mesh.vectorNz[-1] # Create line of P1 locations M = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop] # Create line of P2 locations N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop] ## Build list of Tx-Rx locations depending on survey type # Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn] # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] SrcList = [] if stype != 'gradient': for ii in range(0, int(nstn)-1): if stype == 'dipole-dipole': tx = np.c_[M[ii,:],N[ii,:]] elif stype == 'pole-dipole': tx = np.c_[M[ii,:],M[ii,:]] else: raise Exception('The stype must be "dipole-dipole" or "pole-dipole"') # Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]]) # Current elctrode seperation AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1]) # Number of receivers to fit nstn = np.min([np.floor( (AB - b) / a ) , n]) # Check if there is enough space, else break the loop if nstn <= 0: continue # Compute discrete pole location along line stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a # Create receiver poles if mesh.dim==3: # Create line of P1 locations P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop] # Create line of P2 locations P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop] rxClass = DC.Rx.Dipole(P1, P2) elif mesh.dim==2: # Create line of P1 locations P1 = np.c_[stn_x, np.ones(nstn).T*ztop] # Create line of P2 locations P2 = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop] rxClass = DC.Rx.Dipole_ky(P1, P2) if stype == 'dipole-dipole': srcClass = DC.Src.Dipole([rxClass], M[ii,:],N[ii,:]) elif stype == 'pole-dipole': srcClass = DC.Src.Pole([rxClass], M[ii,:]) SrcList.append(srcClass) elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square # grid of receivers at in the middle at a pre-set minimum distance # Get the edge limit of survey area min_x = endl[0,0] + dl_x * b min_y = endl[0,1] + dl_y * b max_x = endl[1,0] - dl_x * b max_y = endl[1,1] - dl_y * b box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 ) box_w = box_l/2. nstn = np.floor( box_l / a ) # Compute discrete pole location along line stn_x = min_x + np.array(range(int(nstn)))*dl_x*a stn_y = min_y + np.array(range(int(nstn)))*dl_y*a # Define number of cross lines nlin = int(np.floor( box_w / a )) lind = list(range(-nlin,nlin+1)) ngrad = nstn * len(lind) rx = np.zeros([ngrad,6]) for ii in range( len(lind) ): # Move line in perpendicular direction by dipole spacing lxx = stn_x - lind[ii]*a*dl_y lyy = stn_y + lind[ii]*a*dl_x M = np.c_[ lxx, lyy , np.ones(nstn).T*ztop] N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*ztop] rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N] if mesh.dim==3: rxClass = DC.Rx.Dipole(rx[:,:3], rx[:,3:]) elif mesh.dim==2: M = M[:,[0,2]] N = N[:,[0,2]] rxClass = DC.Rx.Dipole_ky(rx[:,[0,2]], rx[:,[3,5]]) srcClass = DC.Src.Dipole([rxClass], M[0,:], N[-1,:]) SrcList.append(srcClass) else: print("""stype must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """) return SrcList
def run(plotIt=True): """ 1D FDEM Mu Inversion ==================== 1D inversion of Magnetic Susceptibility from FDEM data assuming a fixed electrical conductivity """ # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10., 15, 25, 13 # padded cyl mesh 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') # Geologic Parameters model layerz = np.r_[-100., -50.] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0. # Electrical Conductivity sig_half = 1e-2 # Half-space conductivity sig_air = 1e-8 # Air conductivity sig_layer = 1e-2 # Layer conductivity sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer # mur - relative magnetic permeability mur_half = 1. mur_air = 1. mur_layer = 2. mur = np.ones(mesh.nCz) * mur_air mur[active] = mur_half mur[layer] = mur_layer mtrue = mur[active] # Maps actMap = Maps.InjectActiveCells(mesh, active, mur_air, nC=mesh.nCz) surj1Dmap = Maps.SurjectVertical1D(mesh) murMap = Maps.MuRelative(mesh) # Mapping muMap = murMap * surj1Dmap * actMap # ----- FDEM problem & survey ----- rxlocs = Utils.ndgrid([np.r_[10.], np.r_[0], np.r_[30.]]) bzr = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'real') # bzi = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'imag') freqs = np.linspace(2000, 10000, 10) #np.logspace(3, 4, 10) srcLoc = np.array([0., 0., 30.]) print('min skin depth = ', 500. / np.sqrt(freqs.max() * sig_half), 'max skin depth = ', 500. / np.sqrt(freqs.min() * sig_half)) print('max x ', mesh.vectorCCx.max(), 'min z ', mesh.vectorCCz.min(), 'max z ', mesh.vectorCCz.max()) srcList = [ FDEM.Src.MagDipole([bzr], freq, srcLoc, orientation='Z') for freq in freqs ] surveyFD = FDEM.Survey(srcList) prbFD = FDEM.Problem3D_b(mesh, sigma=surj1Dmap * sigma, muMap=muMap, Solver=Solver) prbFD.pair(surveyFD) std = 0.03 surveyFD.makeSyntheticData(mtrue, std) surveyFD.eps = np.linalg.norm(surveyFD.dtrue) * 1e-6 # FDEM inversion np.random.seed(13472) dmisfit = DataMisfit.l2_DataMisfit(surveyFD) regMesh = Mesh.TensorMesh([mesh.hz[muMap.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() directiveList = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = mur_half * np.ones(mtrue.size) reg.alpha_s = 2e-2 reg.alpha_x = 1. prbFD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptFD = inv.run(m0) dpredFD = surveyFD.dpred(moptFD) if plotIt: fig, ax = plt.subplots(1, 3, figsize=(10, 6)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs # Plot the conductivity model ax[0].semilogx(sigma[active], mesh.vectorCCz[active], 'k-', lw=2) ax[0].set_ylim(-500, 0) ax[0].set_xlim(5e-3, 1e-1) ax[0].set_xlabel('Conductivity (S/m)', fontsize=fs) ax[0].set_ylabel('Depth (m)', fontsize=fs) ax[0].grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax[0].legend(['Conductivity Model'], fontsize=fs, loc=4) # Plot the permeability model ax[1].plot(mur[active], mesh.vectorCCz[active], 'k-', lw=2) ax[1].plot(moptFD, mesh.vectorCCz[active], 'b-', lw=2) ax[1].set_ylim(-500, 0) ax[1].set_xlim(0.5, 2.1) ax[1].set_xlabel('Relative Permeability', fontsize=fs) ax[1].set_ylabel('Depth (m)', fontsize=fs) ax[1].grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax[1].legend(['True', 'Predicted'], fontsize=fs, loc=4) # plot the data misfits - negative b/c we choose positive to be in the # direction of primary ax[2].plot(freqs, -surveyFD.dobs, 'k-', lw=2) # ax[2].plot(freqs, -surveyFD.dobs[1::2], 'k--', lw=2) ax[2].loglog(freqs, -dpredFD, 'bo', ms=6) # ax[2].loglog(freqs, -dpredFD[1::2], 'b+', markeredgewidth=2., ms=10) # Labels, gridlines, etc ax[2].grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax[2].grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax[2].set_xlabel('Frequency (Hz)', fontsize=fs) ax[2].set_ylabel('Vertical magnetic field (-T)', fontsize=fs) # ax[2].legend(("Obs", "Pred"), fontsize=fs) ax[2].legend(("z-Obs (real)", "z-Pred (real)"), fontsize=fs) ax[2].set_xlim(freqs.max(), freqs.min()) ax[0].set_title("(a) Conductivity Model", fontsize=fs) ax[1].set_title("(b) $\mu_r$ Model", fontsize=fs) ax[2].set_title("(c) FDEM observed vs. predicted", fontsize=fs) # ax[2].set_title("(c) TDEM observed vs. predicted", fontsize=fs) plt.tight_layout(pad=1.5)
def getKc(freq,sigma,a,b,mu=mu_0,eps=epsilon_0): a = float(a) b = float(b) # return 1./(2*np.pi) * np.sqrt(b / a) * np.exp(-1j*k(freq,sigma,mu,eps)*(b-a)) return np.sqrt(b / a) * np.exp(-1j*k(freq,sigma,mu,eps)*(b-a))
def xy_2_r(x1, x2, y1, y2): r = np.sqrt(np.sum((x2 - x1)**2 + (y2 - y1)**2)) return r
ylim = (546000, 546750) xlim = (422900, 423675) # Takes two points from ginput and create survey temp = plt.ginput(2) # Add z coordinate nz = mesh.vectorNz endp = np.c_[np.asarray(temp), np.ones(2).T * nz[-1]] # Create dipole survey receivers and plot nrx = 10 ab = 40 a = 20 # Evenly distribute transmitters for now and put on surface dplen = np.sqrt(np.sum((endp[1, :] - endp[0, :])**2)) dp_x = (endp[1, 0] - endp[0, 0]) / dplen dp_y = (endp[1, 1] - endp[0, 1]) / dplen nstn = np.floor(dplen / ab) stn_x = endp[0, 0] + np.cumsum(np.ones(nstn) * dp_x * ab) stn_y = endp[0, 1] + np.cumsum(np.ones(nstn) * dp_y * ab) plt.scatter(stn_x, stn_y, s=100, c='w') M = np.c_[stn_x - a * dp_x, stn_y - a * dp_y, np.ones(nstn).T * nz[-1]] N = np.c_[stn_x + a * dp_x, stn_y + a * dp_y, np.ones(nstn).T * nz[-1]] plt.scatter(M[:, 0], M[:, 1], s=10, c='r') plt.scatter(N[:, 0], N[:, 1], s=10, c='b')
def MagneticDipoleVectorPotential(srcLoc, obsLoc, component, moment=1., orientation=np.r_[0., 0., 1.], mu=mu_0): """ Calculate the vector potential of a set of magnetic dipoles at given locations 'ref. <http://en.wikipedia.org/wiki/Dipole#Magnetic_vector_potential>' :param numpy.ndarray srcLoc: Location of the source(s) (x, y, z) :param numpy.ndarray,SimPEG.Mesh obsLoc: Where the potentials will be calculated (x, y, z) or a SimPEG Mesh :param str,list component: The component to calculate - 'x', 'y', or 'z' if an array, or grid type if mesh, can be a list :param numpy.ndarray orientation: The vector dipole moment :rtype: numpy.ndarray :return: The vector potential each dipole at each observation location """ # TODO: break this out! if isinstance(orientation, str): orientation = orientationDict[orientation] assert np.linalg.norm(np.array(orientation), 2) == 1., ("orientation must " "be a unit vector") if type(component) in [list, tuple]: out = list(range(len(component))) for i, comp in enumerate(component): out[i] = MagneticDipoleVectorPotential(srcLoc, obsLoc, comp, orientation=orientation, mu=mu) return np.concatenate(out) if isinstance(obsLoc, Mesh.BaseMesh): mesh = obsLoc assert component in ['Ex', 'Ey', 'Ez', 'Fx', 'Fy', 'Fz'], ("Components" "must be in: ['Ex','Ey','Ez','Fx','Fy','Fz']") return MagneticDipoleVectorPotential(srcLoc, getattr(mesh, 'grid' + component), component[1], orientation=orientation) if component == 'x': dimInd = 0 elif component == 'y': dimInd = 1 elif component == 'z': dimInd = 2 else: raise ValueError('Invalid component') srcLoc = np.atleast_2d(srcLoc) obsLoc = np.atleast_2d(obsLoc) orientation = np.atleast_2d(orientation) nObs = obsLoc.shape[0] nSrc = srcLoc.shape[0] m = moment*np.array(orientation).repeat(nObs, axis=0) A = np.empty((nObs, nSrc)) for i in range(nSrc): dR = obsLoc - srcLoc[i, np.newaxis].repeat(nObs, axis=0) mCr = np.cross(m, dR) r = np.sqrt((dR**2).sum(axis=1)) A[:, i] = +(mu/(4*np.pi)) * mCr[:, dimInd]/(r**3) if nSrc == 1: return A.flatten() return A
def MagneticDipoleFields(srcLoc, obsLoc, component, orientation='Z', moment=1., mu=mu_0): """ Calculate the vector potential of a set of magnetic dipoles at given locations 'ref. <http://en.wikipedia.org/wiki/Dipole#Magnetic_vector_potential>' .. math:: B = \frac{\mu_0}{4 \pi r^3} \left( \frac{3 \vec{r} (\vec{m} \cdot \vec{r})}{r^2}) - \vec{m} \right) \cdot{\hat{rx}} :param numpy.ndarray srcLoc: Location of the source(s) (x, y, z) :param numpy.ndarray obsLoc: Where the potentials will be calculated (x, y, z) :param str component: The component to calculate - 'x', 'y', or 'z' :param numpy.ndarray moment: The vector dipole moment (vertical) :rtype: numpy.ndarray :return: The vector potential each dipole at each observation location """ if isinstance(orientation, str): assert orientation.upper() in ['X', 'Y', 'Z'], ("orientation must be 'x', " "'y', or 'z' or a vector" "not {}".format(orientation) ) elif (not np.allclose(np.r_[1., 0., 0.], orientation) or not np.allclose(np.r_[0., 1., 0.], orientation) or not np.allclose(np.r_[0., 0., 1.], orientation)): warnings.warn('Arbitrary trasnmitter orientations ({}) not thouroughly tested ' 'Pull request on a test anyone? bueller?').format(orientation) if isinstance(component, str): assert component.upper() in ['X', 'Y', 'Z'], ("component must be 'x', " "'y', or 'z' or a vector" "not {}".format(component) ) elif (not np.allclose(np.r_[1., 0., 0.], component) or not np.allclose(np.r_[0., 1., 0.], component) or not np.allclose(np.r_[0., 0., 1.], component)): warnings.warn('Arbitrary receiver orientations ({}) not thouroughly tested ' 'Pull request on a test anyone? bueller?').format(component) if isinstance(orientation, str): orientation = orientationDict[orientation.upper()] if isinstance(component, str): component = orientationDict[component.upper()] assert np.linalg.norm(orientation, 2) == 1., ('orientation must be a unit ' 'vector. Use "moment=X to ' 'scale source fields') if np.linalg.norm(component, 2) != 1.: warnings.warn('The magnitude of the receiver component vector is > 1, ' ' it is {}. The receiver fields will be scaled.' ).format(np.linalg.norm(component, 2)) srcLoc = np.atleast_2d(srcLoc) component = np.atleast_2d(component) obsLoc = np.atleast_2d(obsLoc) orientation = np.atleast_2d(orientation) nObs = obsLoc.shape[0] nSrc = int(srcLoc.size / 3.) # use outer product to construct an array of [x_src, y_src, z_src] m = moment*orientation.repeat(nObs, axis=0) B = [] for i in range(nSrc): srcLoc = srcLoc[i, np.newaxis].repeat(nObs, axis=0) rx = component.repeat(nObs, axis=0) dR = obsLoc - srcLoc r = np.sqrt((dR**2).sum(axis=1)) # mult each element and sum along the axis (vector dot product) m_dot_dR_div_r2 = (m * dR).sum(axis=1) / (r**2) # multiply the scalar m_dot_dR by the 3D vector r rvec_m_dot_dR_div_r2 = np.vstack([m_dot_dR_div_r2 * dR[:, i] for i in range(3)]).T inside = (3. * rvec_m_dot_dR_div_r2) - m # dot product with rx orientation inside_dot_rx = (inside * rx).sum(axis=1) front = (mu/(4.* np.pi * r**3)) B.append(Utils.mkvc(front * inside_dot_rx)) return np.vstack(B).T
def MagneticLoopVectorPotential(srcLoc, obsLoc, component, radius, orientation='Z', mu=mu_0): """ Calculate the vector potential of horizontal circular loop at given locations :param numpy.ndarray srcLoc: Location of the source(s) (x, y, z) :param numpy.ndarray,SimPEG.Mesh obsLoc: Where the potentials will be calculated (x, y, z) or a SimPEG Mesh :param str,list component: The component to calculate - 'x', 'y', or 'z' if an array, or grid type if mesh, can be a list :param numpy.ndarray I: Input current of the loop :param numpy.ndarray radius: radius of the loop :rtype: numpy.ndarray :return: The vector potential each dipole at each observation location """ if isinstance(orientation, str): if orientation.upper() != 'Z': raise NotImplementedError('Only Z oriented loops implemented') elif not np.allclose(orientation, np.r_[0., 0., 1.]): raise NotImplementedError('Only Z oriented loops implemented') if type(component) in [list, tuple]: out = list(range(len(component))) for i, comp in enumerate(component): out[i] = MagneticLoopVectorPotential(srcLoc, obsLoc, comp, radius, orientation, mu) return np.concatenate(out) if isinstance(obsLoc, Mesh.BaseMesh): mesh = obsLoc assert component in ['Ex','Ey','Ez','Fx','Fy','Fz'], "Components must be in: ['Ex','Ey','Ez','Fx','Fy','Fz']" return MagneticLoopVectorPotential(srcLoc, getattr(mesh,'grid'+component), component[1], radius, mu) srcLoc = np.atleast_2d(srcLoc) obsLoc = np.atleast_2d(obsLoc) n = obsLoc.shape[0] nSrc = srcLoc.shape[0] if component=='z': A = np.zeros((n, nSrc)) if nSrc ==1: return A.flatten() return A else: A = np.zeros((n, nSrc)) for i in range (nSrc): x = obsLoc[:, 0] - srcLoc[i, 0] y = obsLoc[:, 1] - srcLoc[i, 1] z = obsLoc[:, 2] - srcLoc[i, 2] r = np.sqrt(x**2 + y**2) m = (4 * radius * r) / ((radius + r)**2 + z**2) m[m > 1.] = 1. # m might be slightly larger than 1 due to rounding errors # but ellipke requires 0 <= m <= 1 K = ellipk(m) E = ellipe(m) ind = (r > 0) & (m < 1) # % 1/r singular at r = 0 and K(m) singular at m = 1 Aphi = np.zeros(n) # % Common factor is (mu * I) / pi with I = 1 and mu = 4e-7 * pi. Aphi[ind] = ((mu / (np.pi * np.sqrt(m[ind])) * np.sqrt(radius / r[ind]) *((1. - m[ind] / 2.) * K[ind] - E[ind]))) if component == 'x': A[ind, i] = Aphi[ind] * (-y[ind] / r[ind] ) elif component == 'y': A[ind, i] = Aphi[ind] * ( x[ind] / r[ind] ) else: raise ValueError('Invalid component') if nSrc == 1: return A.flatten() return A
# if not gin: # print 'SimPED - Simulation has ended with return' # break #============================================================================== # Add z coordinate to all survey... assume flat nz = mesh.vectorNz var = np.c_[np.asarray(gin),np.ones(2).T*nz[-1]] # Snap the endpoints to the grid. Easier to create 2D section. indx = Utils.closestPoints(mesh, var ) endl = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*nz[-1]] [Tx, Rx] = DC.gen_DCIPsurvey(endl, mesh, stype, a, b, n) dl_len = np.sqrt( np.sum((endl[0,:] - endl[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) # Plot stations along line plt.scatter(Tx[0][0,:],Tx[0][1,:],s=20,c='g') plt.scatter(Rx[0][:,0::3],Rx[0][:,1::3],s=20,c='y') #%% Forward model data data = []#np.zeros( nstn*nrx ) unct = [] problem = DC.ProblemDC_CC(mesh) for ii in range(len(Tx)): start_time = time.time()
def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): """ DC Forward Simulation ===================== Forward model conductive spheres in a half-space and plot a pseudo-section 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)" if loc is None: loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]] if sig is None: sig = np.r_[1e-2,1e-1,1e-3] if radi is None: radi = np.r_[25.,25.] if param is None: param = np.r_[30.,30.,5] # 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 = Utils.ModelBuilder.getIndicesSphere(loc[:,0],radi[0],mesh.gridCC) model[ind] = sig[1] # Second anomaly ind = Utils.ModelBuilder.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]) survey, 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 stype == 'pdp': # 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] ) else: inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T ) RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T*( [-1,1] / mesh.vol[inds] ) # Iterative Solve Ainvb = sp.linalg.bicgstab(P*A,P*RHS, tol=1e-5) # We now have the potential everywhere phi = Utils.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(survey, np.ones(survey.nSrc)) survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) 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() 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(survey2D,ax,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
def run(plotIt=True): """ 1D FDEM and TDEM inversions =========================== This example is used in the paper Heagy et al 2016 (in prep) """ # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10., 15, 25, 13 # padded cyl mesh 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') # Conductivity model layerz = np.r_[-200., -100.] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0. sig_half = 1e-2 # Half-space conductivity sig_air = 1e-8 # Air conductivity sig_layer = 5e-2 # Layer conductivity sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer # Mapping actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap mtrue = np.log(sigma[active]) # ----- FDEM problem & survey ----- rxlocs = Utils.ndgrid([np.r_[50.], np.r_[0], np.r_[0.]]) bzi = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'real') bzr = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'imag') freqs = np.logspace(2, 3, 5) srcLoc = np.array([0., 0., 0.]) print('min skin depth = ', 500. / np.sqrt(freqs.max() * sig_half), 'max skin depth = ', 500. / np.sqrt(freqs.min() * sig_half)) print('max x ', mesh.vectorCCx.max(), 'min z ', mesh.vectorCCz.min(), 'max z ', mesh.vectorCCz.max()) srcList = [ FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs ] surveyFD = FDEM.Survey(srcList) prbFD = FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prbFD.pair(surveyFD) std = 0.03 surveyFD.makeSyntheticData(mtrue, std) surveyFD.eps = np.linalg.norm(surveyFD.dtrue) * 1e-5 # FDEM inversion np.random.seed(1) dmisfit = DataMisfit.l2_DataMisfit(surveyFD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() directiveList = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = np.log(np.ones(mtrue.size) * sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. prbFD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptFD = inv.run(m0) # TDEM problem times = np.logspace(-4, np.log10(2e-3), 10) print('min diffusion distance ', 1.28 * np.sqrt(times.min() / (sig_half * mu_0)), 'max diffusion distance ', 1.28 * np.sqrt(times.max() / (sig_half * mu_0))) rx = TDEM.Rx.Point_b(rxlocs, times, 'z') src = TDEM.Src.MagDipole( [rx], waveform=TDEM.Src.StepOffWaveform(), loc=srcLoc # same src location as FDEM problem ) surveyTD = TDEM.Survey([src]) prbTD = TDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prbTD.timeSteps = [(5e-5, 10), (1e-4, 10), (5e-4, 10)] prbTD.pair(surveyTD) std = 0.03 surveyTD.makeSyntheticData(mtrue, std) surveyTD.std = std surveyTD.eps = np.linalg.norm(surveyTD.dtrue) * 1e-5 # TDEM inversion dmisfit = DataMisfit.l2_DataMisfit(surveyTD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = np.log(np.ones(mtrue.size) * sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. prbTD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptTD = inv.run(m0) if plotIt: plt.figure(figsize=(10, 8)) ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) ax1 = plt.subplot2grid((2, 2), (0, 1)) ax2 = plt.subplot2grid((2, 2), (1, 1)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs # Plot the model ax0.semilogx(sigma[active], mesh.vectorCCz[active], 'k-', lw=2) ax0.semilogx(np.exp(moptFD), mesh.vectorCCz[active], 'bo', ms=6) ax0.semilogx(np.exp(moptTD), mesh.vectorCCz[active], 'r*', ms=10) ax0.set_ylim(-700, 0) ax0.set_xlim(5e-3, 1e-1) ax0.set_xlabel('Conductivity (S/m)', fontsize=fs) ax0.set_ylabel('Depth (m)', fontsize=fs) ax0.grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax0.legend(['True', 'FDEM', 'TDEM'], fontsize=fs, loc=4) # plot the data misfits - negative b/c we choose positive to be in the # direction of primary ax1.plot(freqs, -surveyFD.dobs[::2], 'k-', lw=2) ax1.plot(freqs, -surveyFD.dobs[1::2], 'k--', lw=2) dpredFD = surveyFD.dpred(moptTD) ax1.loglog(freqs, -dpredFD[::2], 'bo', ms=6) ax1.loglog(freqs, -dpredFD[1::2], 'b+', markeredgewidth=2., ms=10) ax2.loglog(times, surveyTD.dobs, 'k-', lw=2) ax2.loglog(times, surveyTD.dpred(moptTD), 'r*', ms=10) ax2.set_xlim(times.min(), times.max()) # Labels, gridlines, etc ax2.grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax1.grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax1.set_xlabel('Frequency (Hz)', fontsize=fs) ax1.set_ylabel('Vertical magnetic field (-T)', fontsize=fs) ax2.set_xlabel('Time (s)', fontsize=fs) ax2.set_ylabel('Vertical magnetic field (-T)', fontsize=fs) ax2.legend(("Obs", "Pred"), fontsize=fs) ax1.legend(("Obs (real)", "Obs (imag)", "Pred (real)", "Pred (imag)"), fontsize=fs) ax1.set_xlim(freqs.max(), freqs.min()) ax0.set_title("(a) Recovered Models", fontsize=fs) ax1.set_title("(b) FDEM observed vs. predicted", fontsize=fs) ax2.set_title("(c) TDEM observed vs. predicted", fontsize=fs) plt.tight_layout(pad=1.5)
dby = d[ndata:2*ndata] dbz = d[2*ndata:] # Compute tmi mag data survey.pair(prob_tmi) dtmi = prob_tmi.fields(m) # Compute analytical response from a magnetized sphere bxa, bya, bza = PF.MagAnalytics.MagSphereFreeSpace(locXyz[:, 0], locXyz[:, 1], locXyz[:, 2], rad, 0, 0, 0, chi, b0) # Projection matrix Ptmi = mkvc(b0)/np.sqrt(np.sum(b0**2.)) btmi = mkvc(Ptmi.dot(np.vstack((bxa, bya, bza)))) err_xyz = (np.linalg.norm(d-np.r_[bxa, bya, bza]) / np.linalg.norm(np.r_[bxa, bya, bza])) err_tmi = np.linalg.norm(dtmi-btmi)/np.linalg.norm(btmi) #fig = plt.figure() #axs = plt.subplot(111) #mesh.plotSlice(model, normal='Z', ind = mesh.nCz/2, ax= axs) #axs.set_aspect('equal') #PF.Magnetics.plot_obs_2D(locXyz,dtmi)
def length(self): if self.dim == 3: raise Exception('face.length is not defined for 2D face') return np.sqrt(((self.node1.x0 - self.node0.x0)**2).sum())
def MagneticLoopVectorPotential(srcLoc, obsLoc, component, radius, orientation='Z', mu=mu_0): """ Calculate the vector potential of horizontal circular loop at given locations :param numpy.ndarray srcLoc: Location of the source(s) (x, y, z) :param numpy.ndarray,SimPEG.Mesh obsLoc: Where the potentials will be calculated (x, y, z) or a SimPEG Mesh :param str,list component: The component to calculate - 'x', 'y', or 'z' if an array, or grid type if mesh, can be a list :param numpy.ndarray I: Input current of the loop :param numpy.ndarray radius: radius of the loop :rtype: numpy.ndarray :return: The vector potential each dipole at each observation location """ if isinstance(orientation, str): if orientation.upper() != 'Z': raise NotImplementedError, 'Only Z oriented loops implemented' elif not np.allclose(orientation, np.r_[0., 0., 1.]): raise NotImplementedError, 'Only Z oriented loops implemented' if type(component) in [list, tuple]: out = range(len(component)) for i, comp in enumerate(component): out[i] = MagneticLoopVectorPotential(srcLoc, obsLoc, comp, radius, orientation, mu) return np.concatenate(out) if isinstance(obsLoc, Mesh.BaseMesh): mesh = obsLoc assert component in ['Ex','Ey','Ez','Fx','Fy','Fz'], "Components must be in: ['Ex','Ey','Ez','Fx','Fy','Fz']" return MagneticLoopVectorPotential(srcLoc, getattr(mesh,'grid'+component), component[1], radius, mu) srcLoc = np.atleast_2d(srcLoc) obsLoc = np.atleast_2d(obsLoc) n = obsLoc.shape[0] nSrc = srcLoc.shape[0] if component=='z': A = np.zeros((n, nSrc)) if nSrc ==1: return A.flatten() return A else: A = np.zeros((n, nSrc)) for i in range (nSrc): x = obsLoc[:, 0] - srcLoc[i, 0] y = obsLoc[:, 1] - srcLoc[i, 1] z = obsLoc[:, 2] - srcLoc[i, 2] r = np.sqrt(x**2 + y**2) m = (4 * radius * r) / ((radius + r)**2 + z**2) m[m > 1.] = 1. # m might be slightly larger than 1 due to rounding errors # but ellipke requires 0 <= m <= 1 K = ellipk(m) E = ellipe(m) ind = (r > 0) & (m < 1) # % 1/r singular at r = 0 and K(m) singular at m = 1 Aphi = np.zeros(n) # % Common factor is (mu * I) / pi with I = 1 and mu = 4e-7 * pi. Aphi[ind] = ((mu / (np.pi * np.sqrt(m[ind])) * np.sqrt(radius / r[ind]) *((1. - m[ind] / 2.) * K[ind] - E[ind]))) if component == 'x': A[ind, i] = Aphi[ind] * (-y[ind] / r[ind] ) elif component == 'y': A[ind, i] = Aphi[ind] * ( x[ind] / r[ind] ) else: raise ValueError('Invalid component') if nSrc == 1: return A.flatten() return A
def length(self): return np.sqrt(((self.node1.x0 - self.node0.x0)**2).sum())
def getKc(freq, sigma, a, b, mu=mu_0, eps=epsilon_0): a = float(a) b = float(b) # return 1./(2*np.pi) * np.sqrt(b / a) * np.exp(-1j*k(freq,sigma,mu,eps)*(b-a)) return np.sqrt(b / a) * np.exp(-1j * k(freq, sigma, mu, eps) * (b - a))
def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True): """ DC Forward Simulation ===================== Forward model conductive spheres in a half-space and plot a pseudo-section 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)" if loc is None: loc = np.c_[[-50., 0., -50.], [50., 0., -50.]] if sig is None: sig = np.r_[1e-2, 1e-1, 1e-3] if radi is None: radi = np.r_[25., 25.] if param is None: param = np.r_[30., 30., 5] # 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 = Utils.ModelBuilder.getIndicesSphere(loc[:, 0], radi[0], mesh.gridCC) model[ind] = sig[1] # Second anomaly ind = Utils.ModelBuilder.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]) survey, 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 stype == 'pdp': # 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]) else: inds = Utils.closestPoints(mesh, np.asarray(Tx[ii]).T) RHS = mesh.getInterpolationMat(np.asarray(Tx[ii]).T, 'CC').T * ([-1, 1] / mesh.vol[inds]) # Iterative Solve Ainvb = sp.linalg.bicgstab(P * A, P * RHS, tol=1e-5) # We now have the potential everywhere phi = Utils.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(survey, np.ones(survey.nSrc)) survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc)) 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() 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(survey2D, ax, 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
def gen_DCIPsurvey(endl, mesh, stype, a, b, n): """ Load in endpoints and survey specifications to generate Tx, Rx location stations. Assumes flat topo for now... Input: :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] :object mesh -> SimPEG mesh object :switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient' : param a, n -> pole seperation, number of rx dipoles per tx Output: :param Tx, Rx -> List objects for each tx location Lines: P1x, P1y, P1z, P2x, P2y, P2z Created on Wed December 9th, 2015 @author: dominiquef !! Require clean up to deal with DCsurvey """ from SimPEG import np def xy_2_r(x1, x2, y1, y2): r = np.sqrt(np.sum((x2 - x1)**2 + (y2 - y1)**2)) return r ## Evenly distribute electrodes and put on surface # Mesure survey length and direction dl_len = xy_2_r(endl[0, 0], endl[1, 0], endl[0, 1], endl[1, 1]) dl_x = (endl[1, 0] - endl[0, 0]) / dl_len dl_y = (endl[1, 1] - endl[0, 1]) / dl_len nstn = np.floor(dl_len / a) # Compute discrete pole location along line stn_x = endl[0, 0] + np.array(range(int(nstn))) * dl_x * a stn_y = endl[0, 1] + np.array(range(int(nstn))) * dl_y * a if mesh.dim == 2: ztop = mesh.vectorNy[-1] # Create line of P1 locations M = np.c_[stn_x, np.ones(nstn).T * ztop] # Create line of P2 locations N = np.c_[stn_x + a * dl_x, np.ones(nstn).T * ztop] elif mesh.dim == 3: ztop = mesh.vectorNz[-1] # Create line of P1 locations M = np.c_[stn_x, stn_y, np.ones(nstn).T * ztop] # Create line of P2 locations N = np.c_[stn_x + a * dl_x, stn_y + a * dl_y, np.ones(nstn).T * ztop] ## Build list of Tx-Rx locations depending on survey type # Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn] # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] SrcList = [] if stype != 'gradient': for ii in range(0, int(nstn) - 1): if stype == 'dipole-dipole': tx = np.c_[M[ii, :], N[ii, :]] elif stype == 'pole-dipole': tx = np.c_[M[ii, :], M[ii, :]] else: raise Exception( 'The stype must be "dipole-dipole" or "pole-dipole"') # Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]]) # Current elctrode seperation AB = xy_2_r(tx[0, 1], endl[1, 0], tx[1, 1], endl[1, 1]) # Number of receivers to fit nstn = np.min([np.floor((AB - b) / a), n]) # Check if there is enough space, else break the loop if nstn <= 0: continue # Compute discrete pole location along line stn_x = N[ii, 0] + dl_x * b + np.array(range(int(nstn))) * dl_x * a stn_y = N[ii, 1] + dl_y * b + np.array(range(int(nstn))) * dl_y * a # Create receiver poles if mesh.dim == 3: # Create line of P1 locations P1 = np.c_[stn_x, stn_y, np.ones(nstn).T * ztop] # Create line of P2 locations P2 = np.c_[stn_x + a * dl_x, stn_y + a * dl_y, np.ones(nstn).T * ztop] rxClass = DC.Rx.Dipole(P1, P2) elif mesh.dim == 2: # Create line of P1 locations P1 = np.c_[stn_x, np.ones(nstn).T * ztop] # Create line of P2 locations P2 = np.c_[stn_x + a * dl_x, np.ones(nstn).T * ztop] rxClass = DC.Rx.Dipole_ky(P1, P2) if stype == 'dipole-dipole': srcClass = DC.Src.Dipole([rxClass], M[ii, :], N[ii, :]) elif stype == 'pole-dipole': srcClass = DC.Src.Pole([rxClass], M[ii, :]) SrcList.append(srcClass) elif stype == 'gradient': # Gradient survey only requires Tx at end of line and creates a square # grid of receivers at in the middle at a pre-set minimum distance # Get the edge limit of survey area min_x = endl[0, 0] + dl_x * b min_y = endl[0, 1] + dl_y * b max_x = endl[1, 0] - dl_x * b max_y = endl[1, 1] - dl_y * b box_l = np.sqrt((min_x - max_x)**2 + (min_y - max_y)**2) box_w = box_l / 2. nstn = np.floor(box_l / a) # Compute discrete pole location along line stn_x = min_x + np.array(range(int(nstn))) * dl_x * a stn_y = min_y + np.array(range(int(nstn))) * dl_y * a # Define number of cross lines nlin = int(np.floor(box_w / a)) lind = range(-nlin, nlin + 1) ngrad = nstn * len(lind) rx = np.zeros([ngrad, 6]) for ii in range(len(lind)): # Move line in perpendicular direction by dipole spacing lxx = stn_x - lind[ii] * a * dl_y lyy = stn_y + lind[ii] * a * dl_x M = np.c_[lxx, lyy, np.ones(nstn).T * ztop] N = np.c_[lxx + a * dl_x, lyy + a * dl_y, np.ones(nstn).T * ztop] rx[(ii * nstn):((ii + 1) * nstn), :] = np.c_[M, N] if mesh.dim == 3: rxClass = DC.Rx.Dipole(rx[:, :3], rx[:, 3:]) elif mesh.dim == 2: M = M[:, [0, 2]] N = N[:, [0, 2]] rxClass = DC.Rx.Dipole_ky(rx[:, [0, 2]], rx[:, [3, 5]]) srcClass = DC.Src.Dipole([rxClass], M[0, :], N[-1, :]) SrcList.append(srcClass) else: print """stype must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """ return SrcList
def gen_DCIPsurvey(endl, mesh, stype, a, b, n): from SimPEG import np import re """ Load in endpoints and survey specifications to generate Tx, Rx location stations. Assumes flat topo for now... Input: :param endl -> input endpoints [x1, y1, z1, x2, y2, z2] :object mesh -> SimPEG mesh object :switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient' : param a, n -> pole seperation, number of rx dipoles per tx Output: :param Tx, Rx -> List objects for each tx location Lines: P1x, P1y, P1z, P2x, P2y, P2z Created on Wed December 9th, 2015 @author: dominiquef """ def xy_2_r(x1,x2,y1,y2): r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) ) return r ## Evenly distribute electrodes and put on surface # Mesure survey length and direction dl_len = xy_2_r(endl[0,0],endl[1,0],endl[0,1],endl[1,1]) dl_x = ( endl[1,0] - endl[0,0] ) / dl_len dl_y = ( endl[1,1] - endl[0,1] ) / dl_len nstn = np.floor( dl_len / a ) # Compute discrete pole location along line stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a # Create line of P1 locations M = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]] # Create line of P2 locations N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] ## Build list of Tx-Rx locations depending on survey type # Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn] # Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B] Tx = [] Rx = [] if not re.match(stype,'gradient'): for ii in range(0, int(nstn)-1): if re.match(stype,'dpdp'): tx = np.c_[M[ii,:],N[ii,:]] elif re.match(stype,'pdp'): tx = np.c_[M[ii,:],M[ii,:]] #Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]]) # Current elctrode seperation AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1]) # Number of receivers to fit nstn = np.min([np.floor( (AB - b) / a ) , n]) # Check if there is enough space, else break the loop if nstn <= 0: continue # Compute discrete pole location along line stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a # Create receiver poles # Create line of P1 locations P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]] # Create line of P2 locations P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] Rx.append(np.c_[P1,P2]) Tx.append(tx) #============================================================================== # 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 re.match(stype,'gradient'): # Gradient survey only requires Tx at end of line and creates a square # grid of receivers at in the middle at a pre-set minimum distance Tx.append(np.c_[M[0,:],N[-1,:]]) # Get the edge limit of survey area min_x = endl[0,0] + dl_x * b min_y = endl[0,1] + dl_y * b max_x = endl[1,0] - dl_x * b max_y = endl[1,1] - dl_y * b box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 ) box_w = box_l/2. nstn = np.floor( box_l / a ) # Compute discrete pole location along line stn_x = min_x + np.array(range(int(nstn)))*dl_x*a stn_y = min_y + np.array(range(int(nstn)))*dl_y*a # Define number of cross lines nlin = int(np.floor( box_w / a )) lind = range(-nlin,nlin+1) ngrad = nstn * len(lind) rx = np.zeros([ngrad,6]) for ii in range( len(lind) ): # Move line in perpendicular direction by dipole spacing lxx = stn_x - lind[ii]*a*dl_y lyy = stn_y + lind[ii]*a*dl_x M = np.c_[ lxx, lyy , np.ones(nstn).T*mesh.vectorNz[-1]] N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]] rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N] Rx.append(rx) else: print """stype must be either 'pdp', 'dpdp' or 'gradient'. """ return Tx, Rx
def xy_2_r(x1,x2,y1,y2): r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) ) return r
def refine(cell): if np.sqrt(((np.r_[cell.center] - 0.5)**2).sum()) < 0.4: return 4 return 3