def setUpClass(self): print("\n------- Testing Primary Secondary Source EB -> EB --------\n") # receivers self.rxlist = [] for rxtype in ["MagneticFluxDensity", "ElectricField"]: rx = getattr(fdem.Rx, "Point{}".format(rxtype)) for orientation in ["x", "y", "z"]: for comp in ["real", "imag"]: self.rxlist.append( rx(rx_locs, component=comp, orientation=orientation)) # primary self.primarySimulation = fdem.Simulation3DMagneticFluxDensity( meshp, sigmaMap=primaryMapping) self.primarySimulation.solver = Solver primarySrc = fdem.Src.MagDipole(self.rxlist, frequency=freq, location=src_loc) self.primarySurvey = fdem.Survey([primarySrc]) self.secondarySrc = fdem.Src.PrimSecMappedSigma( self.rxlist, freq, self.primarySimulation, self.primarySurvey, primaryMap2Meshs, ) self.secondarySurvey = fdem.Survey([self.secondarySrc]) # Secondary Problem self.secondarySimulation = fdem.Simulation3DMagneticFluxDensity( meshs, survey=self.secondarySurvey, sigmaMap=mapping) self.secondarySimulation.solver = Solver # Full 3D problem to compare with self.survey3D = fdem.Survey([primarySrc]) self.simulation3D = fdem.Simulation3DMagneticFluxDensity( meshs, survey=self.survey3D, sigmaMap=mapping) self.simulation3D.solver = Solver # solve and store fields print(" solving primary - secondary") self.fields_primsec = self.secondarySimulation.fields(model) print(" ... done") self.fields_primsec = self.secondarySimulation.fields(model) print(" solving 3D") self.fields_3D = self.simulation3D.fields(model) print(" ... done") return None
def define_survey(frequencies, receiver_locations, source_locations, num_transmitters): """Defines a survey of a model with the receivers and the transmitters.""" source_list = [] for i in range(len(frequencies)): for j in range(num_transmitters): # Define receivers of different type at each location bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[j, :], "z", "real") bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[j, :], "z", "imag") receivers_list = [bzr_receiver, bzi_receiver] # Must define the transmitter properties and associated receivers source_list.append( fdem.sources.MagDipole( receivers_list, frequencies[i], source_locations[j], orientation="z", moment=1, )) survey = fdem.Survey(source_list) return survey
def setUp(self): print("\nTesting Transect for analytic") cs = 10.0 ncx, ncy, ncz = 10, 10, 10 npad = 5 freq = 1e2 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 = discretize.TensorMesh([hx, hy, hz], "CCC") x = np.linspace(-10, 10, 5) XYZ = utils.ndgrid(x, np.r_[0], np.r_[0]) rxList = fdem.Rx.PointElectricField(XYZ, orientation="x", component="imag") SrcList = [ fdem.Src.MagDipole([rxList], location=np.r_[0.0, 0.0, 0.0], frequency=freq), fdem.Src.CircularLoop( [rxList], location=np.r_[0.0, 0.0, 0.0], frequency=freq, radius=np.sqrt(1.0 / np.pi), ), # fdem.Src.MagDipole_Bfield( # [rxList], loc=np.r_[0., 0., 0.], # freq=freq # ), # less accurate ] survey = fdem.Survey(SrcList) sig = 1e-1 sigma = np.ones(mesh.nC) * sig sigma[mesh.gridCC[:, 2] > 0] = 1e-8 prb = fdem.Simulation3DMagneticFluxDensity(mesh, sigma=sigma) prb.pair(survey) try: from pymatsolver import Pardiso prb.Solver = Pardiso except ImportError: prb.Solver = SolverLU self.prb = prb self.mesh = mesh self.sig = sig print(" starting solve ...") u = self.prb.fields() print(" ... done") self.u = u
def setUpClass(self): print("\n------- Testing Primary Secondary Source HJ -> EB --------\n") # receivers self.rxlist = [] for rxtype in ["MagneticFluxDensity", "ElectricField"]: rx = getattr(fdem.Rx, "Point{}".format(rxtype)) for orientation in ["x", "y", "z"]: for comp in ["real", "imag"]: self.rxlist.append( rx(rx_locs, component=comp, orientation=orientation)) # primary self.primarySimulation = fdem.Simulation3DCurrentDensity( meshp, sigmaMap=primaryMapping) self.primarySimulation.solver = Solver s_e = np.zeros(meshp.nF) inds = meshp.nFx + utils.closestPoints(meshp, src_loc, gridLoc="Fz") s_e[inds] = 1.0 / csz primarySrc = fdem.Src.RawVec_e(self.rxlist, freq=freq, s_e=s_e / meshp.area) self.primarySurvey = fdem.Survey([primarySrc]) # Secondary Problem self.secondarySimulation = fdem.Simulation3DElectricField( meshs, sigmaMap=mapping) self.secondarySimulation.Solver = Solver self.secondarySrc = fdem.Src.PrimSecMappedSigma( self.rxlist, freq, self.primarySimulation, self.primarySurvey, primaryMap2Meshs, ) self.secondarySurvey = fdem.Survey([self.secondarySrc]) self.secondarySimulation.pair(self.secondarySurvey) # Full 3D problem to compare with self.simulation3D = fdem.Simulation3DElectricField(meshs, sigmaMap=mapping) self.simulation3D.Solver = Solver s_e3D = np.zeros(meshs.nE) inds = meshs.nEx + meshs.nEy + utils.closestPoints( meshs, src_loc, gridLoc="Ez") s_e3D[inds] = [1.0 / (len(inds))] * len(inds) self.simulation3D.model = model src3D = fdem.Src.RawVec_e(self.rxlist, freq=freq, s_e=s_e3D) self.survey3D = fdem.Survey([src3D]) self.simulation3D.pair(self.survey3D) # solve and store fields print(" solving primary - secondary") self.fields_primsec = self.secondarySimulation.fields(model) print(" ... done") self.fields_primsec = self.secondarySimulation.fields(model) print(" solving 3D") self.fields_3D = self.simulation3D.fields(model) print(" ... done") return None
def resolve_1Dinversions( mesh, dobs, src_height, freqs, m0, mref, mapping, relative=0.08, floor=1e-14, rxOffset=7.86, ): """ Perform a single 1D inversion for a RESOLVE sounding for Horizontal Coplanar Coil data (both real and imaginary). :param discretize.CylMesh mesh: mesh used for the forward simulation :param numpy.ndarray dobs: observed data :param float src_height: height of the source above the ground :param numpy.ndarray freqs: frequencies :param numpy.ndarray m0: starting model :param numpy.ndarray mref: reference model :param maps.IdentityMap mapping: mapping that maps the model to electrical conductivity :param float relative: percent error used to construct the data misfit term :param float floor: noise floor used to construct the data misfit term :param float rxOffset: offset between source and receiver. """ # ------------------- Forward Simulation ------------------- # # set up the receivers bzr = FDEM.Rx.PointMagneticFluxDensitySecondary(np.array( [[rxOffset, 0.0, src_height]]), orientation="z", component="real") bzi = FDEM.Rx.PointMagneticFluxDensity(np.array( [[rxOffset, 0.0, src_height]]), orientation="z", component="imag") # source location srcLoc = np.array([0.0, 0.0, src_height]) srcList = [ FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z") for freq in freqs ] # construct a forward simulation survey = FDEM.Survey(srcList) prb = FDEM.Simulation3DMagneticFluxDensity(mesh, sigmaMap=mapping, Solver=PardisoSolver) prb.survey = survey # ------------------- Inversion ------------------- # # data misfit term uncert = abs(dobs) * relative + floor dat = data.Data(dobs=dobs, standard_deviation=uncert) dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=dat) # regularization regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh) reg.mref = mref # optimization opt = optimization.InexactGaussNewton(maxIter=10) # statement of the inverse problem invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = directives.TargetMisfit() inv = inversion.BaseInversion(invProb, directiveList=[target]) invProb.beta = 2.0 # Fix beta in the nonlinear iterations reg.alpha_s = 1e-3 reg.alpha_x = 1.0 prb.counter = opt.counter = utils.Counter() opt.LSshorten = 0.5 opt.remember("xc") # run the inversion mopt = inv.run(m0) return mopt, invProb.dpred, survey.dobs
def run(plotIt=True, saveFig=False): # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10.0, 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 = discretize.CylMesh([hx, 1, hz], "00C") # Conductivity model layerz = np.r_[-200.0, -100.0] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0.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.0], np.r_[0], np.r_[0.0]]) bzr = FDEM.Rx.PointMagneticFluxDensitySecondary(rxlocs, "z", "real") bzi = FDEM.Rx.PointMagneticFluxDensitySecondary(rxlocs, "z", "imag") freqs = np.logspace(2, 3, 5) srcLoc = np.array([0.0, 0.0, 0.0]) print( "min skin depth = ", 500.0 / np.sqrt(freqs.max() * sig_half), "max skin depth = ", 500.0 / np.sqrt(freqs.min() * sig_half), ) print( "max x ", mesh.vectorCCx.max(), "min z ", mesh.vectorCCz.min(), "max z ", mesh.vectorCCz.max(), ) source_list = [ FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z") for freq in freqs ] surveyFD = FDEM.Survey(source_list) prbFD = FDEM.Simulation3DMagneticFluxDensity( mesh, survey=surveyFD, sigmaMap=mapping, solver=Solver ) rel_err = 0.03 dataFD = prbFD.make_synthetic_data(mtrue, relative_error=rel_err, add_noise=True) dataFD.noise_floor = np.linalg.norm(dataFD.dclean) * 1e-5 # FDEM inversion np.random.seed(1) dmisfit = data_misfit.L2DataMisfit(simulation=prbFD, data=dataFD) regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh) opt = optimization.InexactGaussNewton(maxIterCG=10) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives beta = directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, seed=518936) 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.0 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.PointMagneticFluxDensity(rxlocs, times, "z") src = TDEM.Src.MagDipole( [rx], waveform=TDEM.Src.StepOffWaveform(), location=srcLoc, # same src location as FDEM problem ) surveyTD = TDEM.Survey([src]) prbTD = TDEM.Simulation3DMagneticFluxDensity( mesh, survey=surveyTD, sigmaMap=mapping, solver=Solver ) prbTD.time_steps = [(5e-5, 10), (1e-4, 10), (5e-4, 10)] rel_err = 0.03 dataTD = prbTD.make_synthetic_data(mtrue, relative_error=rel_err, add_noise=True) dataTD.noise_floor = np.linalg.norm(dataTD.dclean) * 1e-5 # TDEM inversion dmisfit = data_misfit.L2DataMisfit(simulation=prbTD, data=dataTD) regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh) opt = optimization.InexactGaussNewton(maxIterCG=10) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) # directives beta = directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1.0, seed=518936) 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.0 prbTD.counter = opt.counter = utils.Counter() opt.remember("xc") moptTD = inv.run(m0) # Plot the results 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 # z_true = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0) # z_true = np.r_[mesh.vectorCCz[active][0], z_true, mesh.vectorCCz[active][-1]] activeN = mesh.vectorNz <= 0.0 + cs / 2.0 z_true = np.repeat(mesh.vectorNz[activeN][1:-1], 2, axis=0) z_true = np.r_[mesh.vectorNz[activeN][0], z_true, mesh.vectorNz[activeN][-1]] sigma_true = np.repeat(sigma[active], 2, axis=0) ax0.semilogx(sigma_true, z_true, "k-", lw=2, label="True") ax0.semilogx( np.exp(moptFD), mesh.vectorCCz[active], "bo", ms=6, markeredgecolor="k", markeredgewidth=0.5, label="FDEM", ) ax0.semilogx( np.exp(moptTD), mesh.vectorCCz[active], "r*", ms=10, markeredgecolor="k", markeredgewidth=0.5, label="TDEM", ) 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(fontsize=fs, loc=4) # plot the data misfits - negative b/c we choose positive to be in the # direction of primary ax1.plot(freqs, -dataFD.dobs[::2], "k-", lw=2, label="Obs (real)") ax1.plot(freqs, -dataFD.dobs[1::2], "k--", lw=2, label="Obs (imag)") dpredFD = prbFD.dpred(moptTD) ax1.loglog( freqs, -dpredFD[::2], "bo", ms=6, markeredgecolor="k", markeredgewidth=0.5, label="Pred (real)", ) ax1.loglog( freqs, -dpredFD[1::2], "b+", ms=10, markeredgewidth=2.0, label="Pred (imag)" ) ax2.loglog(times, dataTD.dobs, "k-", lw=2, label="Obs") ax2.loglog( times, prbTD.dpred(moptTD), "r*", ms=10, markeredgecolor="k", markeredgewidth=0.5, label="Pred", ) ax2.set_xlim(times.min() - 1e-5, times.max() + 1e-4) # 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(fontsize=fs, loc=3) ax1.legend(fontsize=fs, loc=3) ax1.set_xlim(freqs.max() + 1e2, freqs.min() - 1e1) 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) if saveFig is True: plt.savefig("example1.png", dpi=600)
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 run(plotIt=True, saveFig=False, cleanup=True): """ Run 1D inversions for a single sounding of the RESOLVE and SkyTEM bookpurnong data :param bool plotIt: show the plots? :param bool saveFig: save the figure :param bool cleanup: remove the downloaded results """ downloads, directory = download_and_unzip_data() resolve = h5py.File(os.path.sep.join([directory, "booky_resolve.hdf5"]), "r") skytem = h5py.File(os.path.sep.join([directory, "booky_skytem.hdf5"]), "r") river_path = resolve["river_path"].value # Choose a sounding location to invert xloc, yloc = 462100.0, 6196500.0 rxind_skytem = np.argmin( abs(skytem["xy"][:, 0] - xloc) + abs(skytem["xy"][:, 1] - yloc)) rxind_resolve = np.argmin( abs(resolve["xy"][:, 0] - xloc) + abs(resolve["xy"][:, 1] - yloc)) # Plot both resolve and skytem data on 2D plane fig = plt.figure(figsize=(13, 6)) title = ["RESOLVE In-phase 400 Hz", "SkyTEM High moment 156 $\mu$s"] ax1 = plt.subplot(121) ax2 = plt.subplot(122) axs = [ax1, ax2] out_re = utils.plot2Ddata( resolve["xy"], resolve["data"][:, 0], ncontour=100, contourOpts={"cmap": "viridis"}, ax=ax1, ) vmin, vmax = out_re[0].get_clim() cb_re = plt.colorbar(out_re[0], ticks=np.linspace(vmin, vmax, 3), ax=ax1, fraction=0.046, pad=0.04) temp_skytem = skytem["data"][:, 5].copy() temp_skytem[skytem["data"][:, 5] > 7e-10] = 7e-10 out_sky = utils.plot2Ddata( skytem["xy"][:, :2], temp_skytem, ncontour=100, contourOpts={ "cmap": "viridis", "vmax": 7e-10 }, ax=ax2, ) vmin, vmax = out_sky[0].get_clim() cb_sky = plt.colorbar( out_sky[0], ticks=np.linspace(vmin, vmax * 0.99, 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04, ) cb_re.set_label("Bz (ppm)") cb_sky.set_label("dB$_z$ / dt (V/A-m$^4$)") for i, ax in enumerate(axs): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] 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") if i == 1: ax.plot(skytem["xy"][:, 0], skytem["xy"][:, 1], "k.", alpha=0.02, ms=1) ax.set_yticklabels([str(" ") for f in yticks]) else: 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]) ax.axis("equal") # plt.tight_layout() if saveFig is True: fig.savefig("resolve_skytem_data.png", dpi=600) # ------------------ Mesh ------------------ # # Step1: Set 2D cylindrical 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 # Step2: Set a SurjectVertical1D mapping # Note: this sets our inversion model as 1D log conductivity # below subsurface active = mesh.vectorCCz < 0.0 actMap = maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = maps.ExpMap(mesh) * maps.SurjectVertical1D(mesh) * actMap sig_half = 1e-1 sig_air = 1e-8 sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half # Initial and reference model m0 = np.log(sigma[active]) # ------------------ RESOLVE Forward Simulation ------------------ # # Step3: Invert Resolve data # Bird height from the surface b_height_resolve = resolve["src_elevation"].value src_height_resolve = b_height_resolve[rxind_resolve] # Set Rx (In-phase and Quadrature) rxOffset = 7.86 bzr = FDEM.Rx.PointMagneticFluxDensitySecondary( np.array([[rxOffset, 0.0, src_height_resolve]]), orientation="z", component="real", ) bzi = FDEM.Rx.PointMagneticFluxDensity( np.array([[rxOffset, 0.0, src_height_resolve]]), orientation="z", component="imag", ) # Set Source (In-phase and Quadrature) frequency_cp = resolve["frequency_cp"].value freqs = frequency_cp.copy() srcLoc = np.array([0.0, 0.0, src_height_resolve]) srcList = [ FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation="Z") for freq in freqs ] # Set FDEM survey (In-phase and Quadrature) survey = FDEM.Survey(srcList) prb = FDEM.Simulation3DMagneticFluxDensity(mesh, sigmaMap=mapping, Solver=Solver) prb.survey = survey # ------------------ RESOLVE Inversion ------------------ # # Primary field bp = -mu_0 / (4 * np.pi * rxOffset**3) # Observed data cpi_inds = [0, 2, 6, 8, 10] cpq_inds = [1, 3, 7, 9, 11] dobs_re = (np.c_[resolve["data"][rxind_resolve, :][cpi_inds], resolve["data"][rxind_resolve, :][cpq_inds], ].flatten() * bp * 1e-6) # Uncertainty relative = np.repeat(np.r_[np.ones(3) * 0.1, np.ones(2) * 0.15], 2) floor = 20 * abs(bp) * 1e-6 std = abs(dobs_re) * relative + floor # Data Misfit data_resolve = data.Data(dobs=dobs_re, survey=survey, standard_deviation=std) dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data_resolve) # Regularization regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh, mapping=maps.IdentityMap(regMesh)) # Optimization opt = optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = directives.TargetMisfit() # stop when we hit target misfit invProb.beta = 2.0 inv = inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-3 reg.alpha_x = 1.0 reg.mref = m0.copy() opt.LSshorten = 0.5 opt.remember("xc") # run the inversion mopt_re = inv.run(m0) dpred_re = invProb.dpred # ------------------ SkyTEM Forward Simulation ------------------ # # Step4: Invert SkyTEM data # Bird height from the surface b_height_skytem = skytem["src_elevation"].value src_height = b_height_skytem[rxind_skytem] srcLoc = np.array([0.0, 0.0, src_height]) # Radius of the source loop area = skytem["area"].value radius = np.sqrt(area / np.pi) rxLoc = np.array([[radius, 0.0, src_height]]) # Parameters for current waveform t0 = skytem["t0"].value times = skytem["times"].value waveform_skytem = skytem["waveform"].value offTime = t0 times_off = times - t0 # Note: we are Using theoretical VTEM waveform, # but effectively fits SkyTEM waveform peakTime = 1.0000000e-02 a = 3.0 dbdt_z = TDEM.Rx.PointMagneticFluxTimeDerivative( locations=rxLoc, times=times_off[:-3] + offTime, orientation="z") # vertical db_dt rxList = [dbdt_z] # list of receivers srcList = [ TDEM.Src.CircularLoop( rxList, loc=srcLoc, radius=radius, orientation="z", waveform=TDEM.Src.VTEMWaveform(offTime=offTime, peakTime=peakTime, a=3.0), ) ] # solve the problem at these times timeSteps = [ (peakTime / 5, 5), ((offTime - peakTime) / 5, 5), (1e-5, 5), (5e-5, 5), (1e-4, 10), (5e-4, 15), ] prob = TDEM.Simulation3DElectricField(mesh, time_steps=timeSteps, sigmaMap=mapping, Solver=Solver) survey = TDEM.Survey(srcList) prob.survey = survey src = srcList[0] rx = src.receiver_list[0] wave = [] for time in prob.times: wave.append(src.waveform.eval(time)) wave = np.hstack(wave) out = prob.dpred(m0) # plot the waveform fig = plt.figure(figsize=(5, 3)) times_off = times - t0 plt.plot(waveform_skytem[:, 0], waveform_skytem[:, 1], "k.") plt.plot(prob.times, wave, "k-", lw=2) plt.legend(("SkyTEM waveform", "Waveform (fit)"), fontsize=10) for t in rx.times: plt.plot(np.ones(2) * t, np.r_[-0.03, 0.03], "k-") plt.ylim(-0.1, 1.1) plt.grid(True) plt.xlabel("Time (s)") plt.ylabel("Normalized current") if saveFig: fig.savefig("skytem_waveform", dpi=200) # Observed data dobs_sky = skytem["data"][rxind_skytem, :-3] * area # ------------------ SkyTEM Inversion ------------------ # # Uncertainty relative = 0.12 floor = 7.5e-12 std = abs(dobs_sky) * relative + floor # Data Misfit data_sky = data.Data(dobs=-dobs_sky, survey=survey, standard_deviation=std) dmisfit = data_misfit.L2DataMisfit(simulation=prob, data=data_sky) # Regularization regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh, mapping=maps.IdentityMap(regMesh)) # Optimization opt = optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) # Directives and Inversion Parameters target = directives.TargetMisfit() invProb.beta = 20.0 inv = inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-1 reg.alpha_x = 1.0 opt.LSshorten = 0.5 opt.remember("xc") reg.mref = mopt_re # Use RESOLVE model as a reference model # run the inversion mopt_sky = inv.run(m0) dpred_sky = invProb.dpred # Plot the figure from the paper plt.figure(figsize=(12, 8)) fs = 13 # fontsize matplotlib.rcParams["font.size"] = fs ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) ax1 = plt.subplot2grid((2, 2), (0, 1)) ax2 = plt.subplot2grid((2, 2), (1, 1)) # Recovered Models sigma_re = np.repeat(np.exp(mopt_re), 2, axis=0) sigma_sky = np.repeat(np.exp(mopt_sky), 2, axis=0) z = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0) z = np.r_[mesh.vectorCCz[active][0], z, mesh.vectorCCz[active][-1]] ax0.semilogx(sigma_re, z, "k", lw=2, label="RESOLVE") ax0.semilogx(sigma_sky, z, "b", lw=2, label="SkyTEM") ax0.set_ylim(-50, 0) # ax0.set_xlim(5e-4, 1e2) ax0.grid(True) ax0.set_ylabel("Depth (m)") ax0.set_xlabel("Conducivity (S/m)") ax0.legend(loc=3) ax0.set_title("(a) Recovered Models") # RESOLVE Data ax1.loglog(frequency_cp, dobs_re.reshape((5, 2))[:, 0] / bp * 1e6, "k-", label="Obs (real)") ax1.loglog( frequency_cp, dobs_re.reshape((5, 2))[:, 1] / bp * 1e6, "k--", label="Obs (imag)", ) ax1.loglog( frequency_cp, dpred_re.reshape((5, 2))[:, 0] / bp * 1e6, "k+", ms=10, markeredgewidth=2.0, label="Pred (real)", ) ax1.loglog( frequency_cp, dpred_re.reshape((5, 2))[:, 1] / bp * 1e6, "ko", ms=6, markeredgecolor="k", markeredgewidth=0.5, label="Pred (imag)", ) ax1.set_title("(b) RESOLVE") ax1.set_xlabel("Frequency (Hz)") ax1.set_ylabel("Bz (ppm)") ax1.grid(True) ax1.legend(loc=3, fontsize=11) # SkyTEM data ax2.loglog(times_off[3:] * 1e6, dobs_sky / area, "b-", label="Obs") ax2.loglog( times_off[3:] * 1e6, -dpred_sky / area, "bo", ms=4, markeredgecolor="k", markeredgewidth=0.5, label="Pred", ) ax2.set_xlim(times_off.min() * 1e6 * 1.2, times_off.max() * 1e6 * 1.1) ax2.set_xlabel("Time ($\mu s$)") ax2.set_ylabel("dBz / dt (V/A-m$^4$)") ax2.set_title("(c) SkyTEM High-moment") ax2.grid(True) ax2.legend(loc=3) a3 = plt.axes([0.86, 0.33, 0.1, 0.09], facecolor=[0.8, 0.8, 0.8, 0.6]) a3.plot(prob.times * 1e6, wave, "k-") a3.plot(rx.times * 1e6, np.zeros_like(rx.times), "k|", markeredgewidth=1, markersize=12) a3.set_xlim([prob.times.min() * 1e6 * 0.75, prob.times.max() * 1e6 * 1.1]) a3.set_title("(d) Waveform", fontsize=11) a3.set_xticks([prob.times.min() * 1e6, t0 * 1e6, prob.times.max() * 1e6]) a3.set_yticks([]) # a3.set_xticklabels(['0', '2e4']) a3.set_xticklabels(["-1e4", "0", "1e4"]) plt.tight_layout() if saveFig: plt.savefig("booky1D_time_freq.png", dpi=600) if plotIt: plt.show() resolve.close() skytem.close() if cleanup: print(os.path.split(directory)[:-1]) os.remove( os.path.sep.join(directory.split()[:-1] + ["._bookpurnong_inversion"])) os.remove(downloads) shutil.rmtree(directory)
) rx_imag = FDEM.Rx.PointMagneticFluxDensitySecondary( locations=rx_locs, orientation=orientation, component="imag" ) src = FDEM.Src.MagDipole( receiver_list=[rx_real, rx_imag], loc=src_loc, orientation=orientation, freq=freq, ) srcList.append(src) # create the survey and problem objects for running the forward simulation survey = FDEM.Survey(srcList) prob = FDEM.Simulation3DMagneticFluxDensity( mesh, survey=survey, sigmaMap=mapping, Solver=Solver ) ############################################################################### # Set up data for inversion # ------------------------- # # Generate clean, synthetic data. Later we will invert the clean data, and # assign a standard deviation of 0.05, and a floor of 1e-11. t = time.time() data = prob.make_synthetic_data( m_true, relative_error=0.05, noise_floor=1e-11, add_noise=False
def survey(self): _survey = fdem.Survey(self.source.source_list) return _survey
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
bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[ii, :], "z", "imag") bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[ii, :], "z", "imag") receivers_list = [bzr_receiver, bzi_receiver] # Must define the transmitter properties and associated receivers source_location = receiver_locations[ii, :] + np.c_[0, 0, 20] source_list.append( fdem.sources.MagDipole(receivers_list, frequencies[ii], source_location, orientation="z")) survey = fdem.Survey(source_list) ############################################# # Defining the Data # ----------------- # # Here is where we define the data that are inverted. The data are defined by # the survey, the observation values and the uncertainties. # mu0 = 4 * np.pi * 1e-7 dobs = mkvc(np.c_[dobs_real, dobs_imag].T) uncertainties = mkvc(np.c_[uncertainties_real, uncertainties_imag].T) data_object = data.Data(survey, dobs=dobs, noise_floor=uncertainties)
def setupProblem( mesh, muMod, sigmaMod, prbtype="ElectricField", invertMui=False, sigmaInInversion=False, freq=1.0, ): rxcomp = ["real", "imag"] loc = utils.ndgrid([mesh.vectorCCx, np.r_[0.0], mesh.vectorCCz]) if prbtype in ["ElectricField", "MagneticFluxDensity"]: rxfields_y = ["ElectricField", "CurrentDensity"] rxfields_xz = ["MagneticFluxDensity", "MagneticField"] elif prbtype in ["MagneticField", "CurrentDensity"]: rxfields_y = ["MagneticFluxDensity", "MagneticField"] rxfields_xz = ["ElectricField", "CurrentDensity"] receiver_list_edge = [ getattr(fdem.receivers, "Point{f}".format(f=f))(loc, component=comp, orientation=orient) for f in rxfields_y for comp in rxcomp for orient in ["y"] ] receiver_list_face = [ getattr(fdem.receivers, "Point{f}".format(f=f))(loc, component=comp, orientation=orient) for f in rxfields_xz for comp in rxcomp for orient in ["x", "z"] ] receiver_list = receiver_list_edge + receiver_list_face src_loc = np.r_[0.0, 0.0, 0.0] if prbtype in ["ElectricField", "MagneticFluxDensity"]: src = fdem.sources.MagDipole(receiver_list=receiver_list, location=src_loc, frequency=freq) elif prbtype in ["MagneticField", "CurrentDensity"]: ind = utils.closestPoints(mesh, src_loc, "Fz") + mesh.vnF[0] vec = np.zeros(mesh.nF) vec[ind] = 1.0 src = fdem.sources.RawVec_e(receiver_list=receiver_list, frequency=freq, s_e=vec) survey = fdem.Survey([src]) if sigmaInInversion: wires = maps.Wires(("mu", mesh.nC), ("sigma", mesh.nC)) muMap = maps.MuRelative(mesh) * wires.mu sigmaMap = maps.ExpMap(mesh) * wires.sigma if invertMui: muiMap = maps.ReciprocalMap(mesh) * muMap prob = getattr(fdem, "Simulation3D{}".format(prbtype))(mesh, muiMap=muiMap, sigmaMap=sigmaMap) # m0 = np.hstack([1./muMod, sigmaMod]) else: prob = getattr(fdem, "Simulation3D{}".format(prbtype))(mesh, muMap=muMap, sigmaMap=sigmaMap) m0 = np.hstack([muMod, sigmaMod]) else: muMap = maps.MuRelative(mesh) if invertMui: muiMap = maps.ReciprocalMap(mesh) * muMap prob = getattr(fdem, "Simulation3D{}".format(prbtype))(mesh, sigma=sigmaMod, muiMap=muiMap) # m0 = 1./muMod else: prob = getattr(fdem, "Simulation3D{}".format(prbtype))(mesh, sigma=sigmaMod, muMap=muMap) m0 = muMod prob.survey = survey return m0, prob, survey
rx_real = FDEM.Rx.PointMagneticFluxDensitySecondary( locations=rx_locs, orientation=orientation, component="real") rx_imag = FDEM.Rx.PointMagneticFluxDensitySecondary( locations=rx_locs, orientation=orientation, component="imag") src = FDEM.Src.MagDipole( receiver_list=[rx_real, rx_imag], location=src_loc, orientation=orientation, frequency=freq, ) source_list.append(src) # create the survey and problem objects for running the forward simulation survey = FDEM.Survey(source_list) prob = FDEM.Simulation3DMagneticFluxDensity(mesh, survey=survey, sigmaMap=mapping, solver=Solver) ############################################################################### # Set up data for inversion # ------------------------- # # Generate clean, synthetic data. Later we will invert the clean data, and # assign a standard deviation of 0.05, and a floor of 1e-11. t = time.time() data = prob.make_synthetic_data(m_true,
def fdem_forward_simulation(detector, target, collection): """ Get FDEM simulation data using SimPEG. Parameters ---------- detector : class Detector target : class Target collention : class Collection Returns ------- receiver_locations : numpy.ndarray, shape(N * 3) All acquisition locations of the detector. Each row represents an acquisition location and the three columns represent x, y and z axis locations of an acquisition location. mag_data : numpy.ndarray, shape(N*3) All secondary fields of acquisition locations. mesh : SimPEG mesh mapped_model : numpy.ndarray References ---------- https://docs.simpeg.xyz/content/tutorials/01-models_mapping/plot_1_tensor_models.html#sphx-glr-content-tutorials-01-models-mapping-plot-1-tensor-models-py http://discretize.simpeg.xyz/en/master/tutorials/mesh_generation/4_tree_mesh.html#sphx-glr-tutorials-mesh-generation-4-tree-mesh-py https://docs.simpeg.xyz/content/tutorials/07-fdem/plot_fwd_2_fem_cyl.html#sphx-glr-content-tutorials-07-fdem-plot-fwd-2-fem-cyl-py https://docs.simpeg.xyz/content/examples/05-fdem/plot_inv_fdem_loop_loop_2Dinversion.html#sphx-glr-content-examples-05-fdem-plot-inv-fdem-loop-loop-2dinversion-py """ # Frequencies being predicted frequencies = [detector.frequency] # Conductivity in S/m (or resistivity in Ohm m) background_conductivity = 1e-6 air_conductivity = 1e-8 # Permeability in H/m background_permeability = mu_0 air_permeability = mu_0 """Survey""" # Defining transmitter locations acquisition_spacing = collection.spacing acq_area_xmin, acq_area_xmax = collection.x_min, collection.x_max acq_area_ymin, acq_area_ymax = collection.y_min, collection.y_max Nx = int((acq_area_xmax - acq_area_xmin) / acquisition_spacing + 1) Ny = int((acq_area_ymax - acq_area_ymin) / acquisition_spacing + 1) xtx, ytx, ztx = np.meshgrid(np.linspace(acq_area_xmin, acq_area_xmax, Nx), np.linspace(acq_area_ymin, acq_area_ymax, Ny), [collection.height]) source_locations = np.c_[mkvc(xtx), mkvc(ytx), mkvc(ztx)] ntx = np.size(xtx) # Define receiver locations xrx, yrx, zrx = np.meshgrid(np.linspace(acq_area_xmin, acq_area_xmax, Nx), np.linspace(acq_area_ymin, acq_area_ymax, Ny), [collection.height]) receiver_locations = np.c_[mkvc(xrx), mkvc(yrx), mkvc(zrx)] # Create empty list to store sources source_list = [] # Each unique location and frequency defines a new transmitter for ii in range(len(frequencies)): for jj in range(ntx): # Define receivers of different type at each location bxr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "x", "real") bxi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "x", "imag") byr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "y", "real") byi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "y", "imag") bzr_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "z", "real") bzi_receiver = fdem.receivers.PointMagneticFluxDensitySecondary( receiver_locations[jj, :], "z", "imag") receivers_list = [ bxr_receiver, bxi_receiver, byr_receiver, byi_receiver, bzr_receiver, bzi_receiver ] # Must define the transmitter properties and associated receivers source_list.append( fdem.sources.MagDipole(receivers_list, frequencies[ii], source_locations[jj], orientation="z", moment=detector.get_mag_moment())) survey = fdem.Survey(source_list) '''Mesh''' dh = 0.1 # base cell width dom_width = 20.0 # domain width # num. base cells nbc = 2**int(np.round(np.log(dom_width / dh) / np.log(2.0))) # Define the base mesh h = [(dh, nbc)] mesh = TreeMesh([h, h, h], x0="CCC") # Mesh refinement near transmitters and receivers mesh = refine_tree_xyz(mesh, receiver_locations, octree_levels=[2, 4], method="radial", finalize=False) # Refine core mesh region xp, yp, zp = np.meshgrid([-1.5, 1.5], [-1.5, 1.5], [-6, -4]) xyz = np.c_[mkvc(xp), mkvc(yp), mkvc(zp)] mesh = refine_tree_xyz(mesh, xyz, octree_levels=[0, 6], method="box", finalize=False) mesh.finalize() '''Maps''' # Find cells that are active in the forward modeling (cells below surface) ind_active = mesh.gridCC[:, 2] < 0 # Define mapping from model to active cells active_sigma_map = maps.InjectActiveCells(mesh, ind_active, air_conductivity) active_mu_map = maps.InjectActiveCells(mesh, ind_active, air_permeability) # Define model. Models in SimPEG are vector arrays N = int(ind_active.sum()) model = np.kron(np.ones((N, 1)), np.c_[background_conductivity, background_permeability]) ind_cylinder = getIndicesCylinder( [target.position[0], target.position[1], target.position[2]], target.radius, target.length, [target.pitch, target.roll], mesh.gridCC) ind_cylinder = ind_cylinder[ind_active] model[ind_cylinder, :] = np.c_[target.conductivity, target.permeability] # Create model vector and wires model = mkvc(model) wire_map = maps.Wires(("sigma", N), ("mu", N)) # Use combo maps to map from model to mesh sigma_map = active_sigma_map * wire_map.sigma mu_map = active_mu_map * wire_map.mu '''Simulation''' simulation = fdem.simulation.Simulation3DMagneticFluxDensity( mesh, survey=survey, sigmaMap=sigma_map, muMap=mu_map, Solver=Solver) '''Predict''' # Compute predicted data for a your model. dpred = simulation.dpred(model) dpred = dpred * 1e9 # Data are organized by frequency, transmitter location, then by receiver. # We had nFreq transmitters and each transmitter had 2 receivers (real and # imaginary component). So first we will pick out the real and imaginary # data bx_real = dpred[0:len(dpred):6] bx_imag = dpred[1:len(dpred):6] bx_total = np.sqrt(np.square(bx_real) + np.square(bx_imag)) by_real = dpred[2:len(dpred):6] by_imag = dpred[3:len(dpred):6] by_total = np.sqrt(np.square(by_real) + np.square(by_imag)) bz_real = dpred[4:len(dpred):6] bz_imag = dpred[5:len(dpred):6] bz_total = np.sqrt(np.square(bz_real) + np.square(bz_imag)) mag_data = np.c_[mkvc(bx_total), mkvc(by_total), mkvc(bz_total)] return receiver_locations, mag_data, mesh, sigma_map * model