def setUp(self): cs = 10.0 ncx, ncy, ncz = 30.0, 30.0, 30.0 npad = 10.0 hx = [(cs, npad, -1.5), (cs, ncx), (cs, npad, 1.5)] hy = [(cs, npad, -1.5), (cs, ncy), (cs, npad, 1.5)] hz = [(cs, npad, -1.5), (cs, ncz), (cs, npad, 1.5)] self.mesh = discretize.TensorMesh([hx, hy, hz], "CCC") mapping = maps.ExpMap(self.mesh) self.frequency = 1.0 self.prob_e = fdem.Simulation3DElectricField(self.mesh, sigmaMap=mapping) self.prob_b = fdem.Simulation3DMagneticFluxDensity(self.mesh, sigmaMap=mapping) self.prob_h = fdem.Simulation3DMagneticField(self.mesh, sigmaMap=mapping) self.prob_j = fdem.Simulation3DCurrentDensity(self.mesh, sigmaMap=mapping) loc = np.r_[0.0, 0.0, 0.0] self.location = utils.mkvc( self.mesh.gridCC[utils.closestPoints(self.mesh, loc, "CC"), :])
def run(plotIt=True): # ------------------ MODEL ------------------ sigmaair = 1e-8 # air sigmaback = 1e-2 # background sigmacasing = 1e6 # casing sigmainside = sigmaback # inside the casing casing_t = 0.006 # 1cm thickness casing_l = 300 # length of the casing casing_r = 0.1 casing_a = casing_r - casing_t / 2.0 # inner radius casing_b = casing_r + casing_t / 2.0 # outer radius casing_z = np.r_[-casing_l, 0.0] # ------------------ SURVEY PARAMETERS ------------------ freqs = np.r_[1e-6] # [1e-1, 1, 5] # frequencies dsz = -300 # down-hole z source location src_loc = np.r_[0.0, 0.0, dsz] inf_loc = np.r_[0.0, 0.0, 1e4] print("Skin Depth: ", [(500.0 / np.sqrt(sigmaback * _)) for _ in freqs]) # ------------------ MESH ------------------ # fine cells near well bore csx1, csx2 = 2e-3, 60.0 pfx1, pfx2 = 1.3, 1.3 ncx1 = np.ceil(casing_b / csx1 + 2) # pad nicely to second cell size npadx1 = np.floor(np.log(csx2 / csx1) / np.log(pfx1)) hx1a = utils.meshTensor([(csx1, ncx1)]) hx1b = utils.meshTensor([(csx1, npadx1, pfx1)]) dx1 = sum(hx1a) + sum(hx1b) dx1 = np.floor(dx1 / csx2) hx1b *= (dx1 * csx2 - sum(hx1a)) / sum(hx1b) # second chunk of mesh dx2 = 300.0 # uniform mesh out to here ncx2 = np.ceil((dx2 - dx1) / csx2) npadx2 = 45 hx2a = utils.meshTensor([(csx2, ncx2)]) hx2b = utils.meshTensor([(csx2, npadx2, pfx2)]) hx = np.hstack([hx1a, hx1b, hx2a, hx2b]) # z-direction csz = 0.05 nza = 10 # cell size, number of core cells, number of padding cells in the # x-direction ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0] / csz)) + 10, 68, 68 # vector of cell widths in the z-direction hz = utils.meshTensor([(csz, npadzd, -1.3), (csz, ncz), (csz, npadzu, 1.3)]) # Mesh mesh = discretize.CylMesh( [hx, 1.0, hz], [0.0, 0.0, -np.sum(hz[: npadzu + ncz - nza])] ) print( "Mesh Extent xmax: {0:f},: zmin: {1:f}, zmax: {2:f}".format( mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max() ) ) print("Number of cells", mesh.nC) if plotIt is True: fig, ax = plt.subplots(1, 1, figsize=(6, 4)) ax.set_title("Simulation Mesh") mesh.plotGrid(ax=ax) # Put the model on the mesh sigWholespace = sigmaback * np.ones((mesh.nC)) sigBack = sigWholespace.copy() sigBack[mesh.gridCC[:, 2] > 0.0] = sigmaair sigCasing = sigBack.copy() iCasingZ = (mesh.gridCC[:, 2] <= casing_z[1]) & (mesh.gridCC[:, 2] >= casing_z[0]) iCasingX = (mesh.gridCC[:, 0] >= casing_a) & (mesh.gridCC[:, 0] <= casing_b) iCasing = iCasingX & iCasingZ sigCasing[iCasing] = sigmacasing if plotIt is True: # plotting parameters xlim = np.r_[0.0, 0.2] zlim = np.r_[-350.0, 10.0] clim_sig = np.r_[-8, 6] # plot models fig, ax = plt.subplots(1, 1, figsize=(4, 4)) im = mesh.plotImage(np.log10(sigCasing), ax=ax)[0] im.set_clim(clim_sig) plt.colorbar(im, ax=ax) ax.grid(which="both") ax.set_title("Log_10 (Sigma)") ax.set_xlim(xlim) ax.set_ylim(zlim) # -------------- Sources -------------------- # Define Custom Current Sources # surface source sg_x = np.zeros(mesh.vnF[0], dtype=complex) sg_y = np.zeros(mesh.vnF[1], dtype=complex) sg_z = np.zeros(mesh.vnF[2], dtype=complex) nza = 2 # put the wire two cells above the surface # vertically directed wire # hook it up to casing at the surface sgv_indx = (mesh.gridFz[:, 0] > casing_a) & (mesh.gridFz[:, 0] < casing_a + csx1) sgv_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] >= -csz * 2) sgv_ind = sgv_indx & sgv_indz sg_z[sgv_ind] = -1.0 # horizontally directed wire sgh_indx = (mesh.gridFx[:, 0] > casing_a) & (mesh.gridFx[:, 0] <= inf_loc[2]) sgh_indz = (mesh.gridFx[:, 2] > csz * (nza - 0.5)) & ( mesh.gridFx[:, 2] < csz * (nza + 0.5) ) sgh_ind = sgh_indx & sgh_indz sg_x[sgh_ind] = -1.0 # hook it up to casing at the surface sgv2_indx = (mesh.gridFz[:, 0] >= mesh.gridFx[sgh_ind, 0].max()) & ( mesh.gridFz[:, 0] <= inf_loc[2] * 1.2 ) sgv2_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] >= -csz * 2) sgv2_ind = sgv2_indx & sgv2_indz sg_z[sgv2_ind] = 1.0 # assemble the source sg = np.hstack([sg_x, sg_y, sg_z]) sg_p = [FDEM.Src.RawVec_e([], _, sg / mesh.area) for _ in freqs] # downhole source dg_x = np.zeros(mesh.vnF[0], dtype=complex) dg_y = np.zeros(mesh.vnF[1], dtype=complex) dg_z = np.zeros(mesh.vnF[2], dtype=complex) # vertically directed wire dgv_indx = mesh.gridFz[:, 0] < csx1 # go through the center of the well dgv_indz = (mesh.gridFz[:, 2] <= +csz * nza) & (mesh.gridFz[:, 2] > dsz + csz / 2.0) dgv_ind = dgv_indx & dgv_indz dg_z[dgv_ind] = -1.0 # couple to the casing downhole dgh_indx = mesh.gridFx[:, 0] < casing_a + csx1 dgh_indz = (mesh.gridFx[:, 2] < dsz + csz) & (mesh.gridFx[:, 2] >= dsz) dgh_ind = dgh_indx & dgh_indz dg_x[dgh_ind] = 1.0 # horizontal part at surface dgh2_indx = mesh.gridFx[:, 0] <= inf_loc[2] * 1.2 dgh2_indz = sgh_indz.copy() dgh2_ind = dgh2_indx & dgh2_indz dg_x[dgh2_ind] = -1.0 # vertical part at surface dgv2_ind = sgv2_ind.copy() dg_z[dgv2_ind] = 1.0 # assemble the source dg = np.hstack([dg_x, dg_y, dg_z]) dg_p = [FDEM.Src.RawVec_e([], _, dg / mesh.area) for _ in freqs] # ------------ Problem and Survey --------------- survey = FDEM.Survey(sg_p + dg_p) problem = FDEM.Simulation3DMagneticField( mesh, survey=survey, sigmaMap=maps.IdentityMap(mesh), solver=Solver ) # ------------- Solve --------------------------- t0 = time.time() fieldsCasing = problem.fields(sigCasing) print("Time to solve 2 sources", time.time() - t0) # Plot current # current density jn0 = fieldsCasing[dg_p, "j"] jn1 = fieldsCasing[sg_p, "j"] # current in0 = [mesh.area * fieldsCasing[dg_p, "j"][:, i] for i in range(len(freqs))] in1 = [mesh.area * fieldsCasing[sg_p, "j"][:, i] for i in range(len(freqs))] in0 = np.vstack(in0).T in1 = np.vstack(in1).T # integrate to get z-current inside casing inds_inx = (mesh.gridFz[:, 0] >= casing_a) & (mesh.gridFz[:, 0] <= casing_b) inds_inz = (mesh.gridFz[:, 2] >= dsz) & (mesh.gridFz[:, 2] <= 0) inds_fz = inds_inx & inds_inz indsx = [False] * mesh.nFx inds = list(indsx) + list(inds_fz) in0_in = in0[np.r_[inds]] in1_in = in1[np.r_[inds]] z_in = mesh.gridFz[inds_fz, 2] in0_in = in0_in.reshape([in0_in.shape[0] // 3, 3]) in1_in = in1_in.reshape([in1_in.shape[0] // 3, 3]) z_in = z_in.reshape([z_in.shape[0] // 3, 3]) I0 = in0_in.sum(1).real I1 = in1_in.sum(1).real z_in = z_in[:, 0] if plotIt is True: fig, ax = plt.subplots(1, 2, figsize=(12, 4)) ax[0].plot(z_in, np.absolute(I0), z_in, np.absolute(I1)) ax[0].legend(["top casing", "bottom casing"], loc="best") ax[0].set_title("Magnitude of Vertical Current in Casing") ax[1].semilogy(z_in, np.absolute(I0), z_in, np.absolute(I1)) ax[1].legend(["top casing", "bottom casing"], loc="best") ax[1].set_title("Magnitude of Vertical Current in Casing") ax[1].set_ylim([1e-2, 1.0])
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 getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False): cs = 10.0 ncx, ncy, ncz = 0, 0, 0 npad = 8 hx = [(cs, npad, -1.3), (cs, ncx), (cs, npad, 1.3)] hy = [(cs, npad, -1.3), (cs, ncy), (cs, npad, 1.3)] hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)] mesh = TensorMesh([hx, hy, hz], ["C", "C", "C"]) if useMu is True: mapping = [("sigma", maps.ExpMap(mesh)), ("mu", maps.IdentityMap(mesh))] else: mapping = maps.ExpMap(mesh) x = ( np.array([ np.linspace(-5.0 * cs, -2.0 * cs, 3), np.linspace(5.0 * cs, 2.0 * cs, 3) ]) + cs / 4.0 ) # don't sample right by the source, slightly off alignment from either staggered grid XYZ = utils.ndgrid(x, x, np.linspace(-2.0 * cs, 2.0 * cs, 5)) Rx0 = getattr(fdem.Rx, "Point" + comp[0]) if comp[-1] == "r": real_or_imag = "real" elif comp[-1] == "i": real_or_imag = "imag" rx0 = Rx0(XYZ, comp[1], real_or_imag) Src = [] for SrcType in SrcList: if SrcType == "MagDipole": Src.append( fdem.Src.MagDipole([rx0], frequency=freq, location=np.r_[0.0, 0.0, 0.0])) elif SrcType == "MagDipole_Bfield": Src.append( fdem.Src.MagDipole_Bfield([rx0], frequency=freq, location=np.r_[0.0, 0.0, 0.0])) elif SrcType == "CircularLoop": Src.append( fdem.Src.CircularLoop([rx0], frequency=freq, location=np.r_[0.0, 0.0, 0.0])) elif SrcType == "LineCurrent": Src.append( fdem.Src.LineCurrent( [rx0], frequency=freq, location=np.array([[0.0, 0.0, 0.0], [20.0, 0.0, 0.0]]), )) elif SrcType == "RawVec": if fdemType == "e" or fdemType == "b": S_m = np.zeros(mesh.nF) S_e = np.zeros(mesh.nE) S_m[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Fz") + np.sum(mesh.vnF[:1])] = 1e-3 S_e[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Ez") + np.sum(mesh.vnE[:1])] = 1e-3 Src.append( fdem.Src.RawVec([rx0], freq, S_m, mesh.getEdgeInnerProduct() * S_e)) elif fdemType == "h" or fdemType == "j": S_m = np.zeros(mesh.nE) S_e = np.zeros(mesh.nF) S_m[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Ez") + np.sum(mesh.vnE[:1])] = 1e-3 S_e[utils.closestPoints(mesh, [0.0, 0.0, 0.0], "Fz") + np.sum(mesh.vnF[:1])] = 1e-3 Src.append( fdem.Src.RawVec([rx0], freq, mesh.getEdgeInnerProduct() * S_m, S_e)) if verbose: print(" Fetching {0!s} problem".format((fdemType))) if fdemType == "e": survey = fdem.Survey(Src) prb = fdem.Simulation3DElectricField(mesh, sigmaMap=mapping) elif fdemType == "b": survey = fdem.Survey(Src) prb = fdem.Simulation3DMagneticFluxDensity(mesh, sigmaMap=mapping) elif fdemType == "j": survey = fdem.Survey(Src) prb = fdem.Simulation3DCurrentDensity(mesh, sigmaMap=mapping) elif fdemType == "h": survey = fdem.Survey(Src) prb = fdem.Simulation3DMagneticField(mesh, sigmaMap=mapping) else: raise NotImplementedError() prb.pair(survey) try: from pymatsolver import Pardiso prb.solver = Pardiso except ImportError: prb.solver = SolverLU # prb.solver_opts = dict(check_accuracy=True) return prb