def test_nC_residual(self): # x-direction cs, ncx, ncz, npad = 1.0, 10.0, 10.0, 20 hx = [(cs, ncx), (cs, npad, 1.3)] # z direction 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 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 regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh) self.assertTrue(reg._nC_residual == regMesh.nC) self.assertTrue( all([fct._nC_residual == regMesh.nC for fct in reg.objfcts]))
def fit_colecole_with_se(self, eta_cc=0.8, tau_cc=0.003, c_cc=0.6): def ColeColeSeigel(f, sigmaInf, eta, tau, c): w = 2 * np.pi * f return sigmaInf * (1 - eta / (1 + (1j * w * tau)**c)) # Step1: Fit Cole-Cole with Stretched Exponential function time = np.logspace(-6, np.log10(0.01), 41) wt, tbase, omega_int = DigFilter.setFrequency(time) frequency = omega_int / (2 * np.pi) # Cole-Cole parameters siginf = 1. self.eta_cc = eta_cc self.tau_cc = tau_cc self.c_cc = c_cc sigma = ColeColeSeigel(frequency, siginf, eta_cc, tau_cc, c_cc) sigTCole = DigFilter.transFiltImpulse(sigma, wt, tbase, omega_int, time, tol=1e-12) wires = Maps.Wires(('eta', 1), ('tau', 1), ('c', 1)) taumap = Maps.ExpMap(nP=1) * wires.tau survey = SESurvey() dtrue = -sigTCole survey.dobs = dtrue m1D = Mesh.TensorMesh([np.ones(3)]) prob = SEInvImpulseProblem(m1D, etaMap=wires.eta, tauMap=taumap, cMap=wires.c) update_sens = Directives.UpdateSensitivityWeights() prob.time = time prob.pair(survey) m0 = np.r_[eta_cc, np.log(tau_cc), c_cc] perc = 0.05 dmisfitpeta = DataMisfit.l2_DataMisfit(survey) dmisfitpeta.W = 1 / (abs(survey.dobs) * perc) reg = regularization.Simple(m1D) opt = Optimization.ProjectedGNCG(maxIter=10) invProb = InvProblem.BaseInvProblem(dmisfitpeta, reg, opt) # Create an inversion object target = Directives.TargetMisfit() invProb.beta = 0. inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.mref = 0. * m0 prob.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') opt.tolX = 1e-20 opt.tolF = 1e-20 opt.tolG = 1e-20 opt.eps = 1e-20 mopt = inv.run(m0) return mopt
def test_indActive_nc_residual(self): # x-direction cs, ncx, ncz, npad = 1.0, 10.0, 10.0, 20 hx = [(cs, ncx), (cs, npad, 1.3)] # z direction 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 reg = regularization.Simple(mesh, indActive=active) self.assertTrue(reg._nC_residual == len(active.nonzero()[0]))
def test_addition(self): mesh = discretize.TensorMesh([8, 7, 6]) m = np.random.rand(mesh.nC) reg1 = regularization.Tikhonov(mesh) reg2 = regularization.Simple(mesh) reg_a = reg1 + reg2 self.assertTrue(len(reg_a) == 2) self.assertTrue(reg1(m) + reg2(m) == reg_a(m)) reg_a.test(eps=TOL) reg_b = 2 * reg1 + reg2 self.assertTrue(len(reg_b) == 2) self.assertTrue(2 * reg1(m) + reg2(m) == reg_b(m)) reg_b.test(eps=TOL) reg_c = reg1 + reg2 / 2 self.assertTrue(len(reg_c) == 2) self.assertTrue(reg1(m) + 0.5 * reg2(m) == reg_c(m)) reg_c.test(eps=TOL)
def run(plotIt=True): cs, ncx, ncz, npad = 5.0, 25, 24, 15 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") active = mesh.vectorCCz < 0.0 layer = (mesh.vectorCCz < -50.0) & (mesh.vectorCCz >= -150.0) actMap = maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = maps.ExpMap(mesh) * maps.SurjectVertical1D(mesh) * actMap sig_half = 1e-3 sig_air = 1e-8 sig_layer = 1e-2 sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer mtrue = np.log(sigma[active]) x = np.r_[30, 50, 70, 90] rxloc = np.c_[x, x * 0.0, np.zeros_like(x)] prb = TDEM.Simulation3DMagneticFluxDensity(mesh, sigmaMap=mapping, solver=Solver) prb.time_steps = [ (1e-3, 5), (1e-4, 5), (5e-5, 10), (5e-5, 5), (1e-4, 10), (5e-4, 10), ] # Use VTEM waveform out = EMutils.VTEMFun(prb.times, 0.00595, 0.006, 100) # Forming function handle for waveform using 1D linear interpolation wavefun = interp1d(prb.times, out) t0 = 0.006 waveform = TDEM.Src.RawWaveform(offTime=t0, waveFct=wavefun) rx = TDEM.Rx.PointMagneticFluxTimeDerivative( rxloc, np.logspace(-4, -2.5, 11) + t0, "z") src = TDEM.Src.CircularLoop([rx], waveform=waveform, loc=np.array([0.0, 0.0, 0.0]), radius=10.0) survey = TDEM.Survey([src]) prb.survey = survey # create observed data data = prb.make_synthetic_data(mtrue, relative_error=0.02, noise_floor=1e-11) dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data) regMesh = discretize.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = regularization.Simple(regMesh) opt = optimization.InexactGaussNewton(maxIter=5, LSshorten=0.5) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) target = directives.TargetMisfit() # Create an inversion object beta = directives.BetaSchedule(coolingFactor=1.0, coolingRate=2.0) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e0) invProb.beta = 1e2 inv = inversion.BaseInversion(invProb, directiveList=[beta, target]) m0 = np.log(np.ones(mtrue.size) * sig_half) prb.counter = opt.counter = utils.Counter() opt.remember("xc") mopt = inv.run(m0) if plotIt: fig, ax = plt.subplots(1, 2, figsize=(10, 6)) Dobs = data.dobs.reshape((len(rx.times), len(x))) Dpred = invProb.dpred.reshape((len(rx.times), len(x))) for i in range(len(x)): ax[0].loglog(rx.times - t0, -Dobs[:, i].flatten(), "k") ax[0].loglog(rx.times - t0, -Dpred[:, i].flatten(), "k.") if i == 0: ax[0].legend(("$d^{obs}$", "$d^{pred}$"), fontsize=16) ax[0].set_xlabel("Time (s)", fontsize=14) ax[0].set_ylabel("$db_z / dt$ (nT/s)", fontsize=16) ax[0].set_xlabel("Time (s)", fontsize=14) ax[0].grid(color="k", alpha=0.5, linestyle="dashed", linewidth=0.5) plt.semilogx(sigma[active], mesh.vectorCCz[active]) plt.semilogx(np.exp(mopt), mesh.vectorCCz[active]) ax[1].set_ylim(-600, 0) ax[1].set_xlim(1e-4, 1e-1) ax[1].set_xlabel("Conductivity (S/m)", fontsize=14) ax[1].set_ylabel("Depth (m)", fontsize=14) ax[1].grid(color="k", alpha=0.5, linestyle="dashed", linewidth=0.5) plt.legend(["$\sigma_{true}$", "$\sigma_{pred}$"])
# # We create the data misfit, simple regularization # (a Tikhonov-style regularization, :class:`SimPEG.regularization.Simple`) # The smoothness and smallness contributions can be set by including # `alpha_s, alpha_x, alpha_y` as input arguments when the regularization is # created. The default reference model in the regularization is the starting # model. To set something different, you can input an `mref` into the # regularization. # # We estimate the trade-off parameter, beta, between the data # misfit and regularization by the largest eigenvalue of the data misfit and # the regularization. Here, we use a fixed beta, but could alternatively # employ a beta-cooling schedule using :class:`SimPEG.directives.BetaSchedule` dmisfit = data_misfit.L2DataMisfit(simulation=prob, data=data) reg = regularization.Simple(inversion_mesh) opt = optimization.InexactGaussNewton(maxIterCG=10, remember="xc") invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) betaest = directives.BetaEstimate_ByEig(beta0_ratio=0.05, n_pw_iter=1, seed=1) target = directives.TargetMisfit() directiveList = [betaest, target] inv = inversion.BaseInversion(invProb, directiveList=directiveList) print("The target misfit is {:1.2f}".format(target.target)) ############################################################################### # Run the inversion # ------------------ #
def run( plotIt=True, survey_type="dipole-dipole", rho_background=1e3, rho_block=1e2, block_x0=100, block_dx=10, block_y0=-10, block_dy=5, ): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0.0, 200.0 ymin, ymax = 0.0, 0.0 zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DCutils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey = IO.from_ambn_locations_to_survey( survey.locations_a, survey.locations_b, survey.locations_m, survey.locations_n, survey_type, data_dc_type="volt", ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() # Flat topography actind = utils.surface2ind_topo( mesh, np.c_[mesh.vectorCCx, mesh.vectorCCx * 0.0]) survey.drape_electrodes_on_topography(mesh, actind, option="top") # Use Exponential Map: m = log(rho) actmap = maps.InjectActiveCells(mesh, indActive=actind, valInactive=np.log(1e8)) parametric_block = maps.ParametricBlock(mesh, slopeFact=1e2) mapping = maps.ExpMap(mesh) * parametric_block # Set true model # val_background,val_block, block_x0, block_dx, block_y0, block_dy mtrue = np.r_[np.log(1e3), np.log(10), 100, 10, -20, 10] # Set initial model m0 = np.r_[np.log(rho_background), np.log(rho_block), block_x0, block_dx, block_y0, block_dy, ] rho = mapping * mtrue rho0 = mapping * m0 # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={"alpha": 0.2}, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ) ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "k.") ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect("equal") ax.set_title("True resistivity model") plt.show() # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho0.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={"alpha": 0.2}, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ) ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "k.") ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect("equal") ax.set_title("Initial resistivity model") plt.show() # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Simulation2DNodal(mesh, survey=survey, rhoMap=mapping, storeJ=True, solver=Solver) # Make synthetic DC data with 5% Gaussian noise data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True) # Show apparent resisitivty pseudo-section IO.plotPseudoSection(data=data.dobs / IO.G, data_type="apparent_resistivity") # Show apparent resisitivty histogram fig = plt.figure() out = hist(data.dobs / IO.G, bins=20) plt.show() # Set standard_deviation # floor eps = 10**(-3.2) # percentage relative = 0.05 dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data) uncert = abs(data.dobs) * relative + eps dmisfit.standard_deviation = uncert # Map for a regularization mesh_1d = discretize.TensorMesh([parametric_block.nP]) # Related to inversion reg = regularization.Simple(mesh_1d, alpha_x=0.0) opt = optimization.InexactGaussNewton(maxIter=10) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) beta = directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e0) target = directives.TargetMisfit() updateSensW = directives.UpdateSensitivityWeights() update_Jacobi = directives.UpdatePreconditioner() invProb.beta = 0.0 inv = inversion.BaseInversion(invProb, directiveList=[target]) prb.counter = opt.counter = utils.Counter() opt.LSshorten = 0.5 opt.remember("xc") # Run inversion mopt = inv.run(m0) # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping * mopt rho_true = rho.copy() # show recovered conductivity vmin, vmax = rho.min(), rho.max() fig, ax = plt.subplots(2, 1, figsize=(20, 6)) out1 = mesh.plotImage( rho_true, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[0], ) out2 = mesh.plotImage( rho_est, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[1], ) out = [out1, out2] for i in range(2): ax[i].plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "kv") ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[i][0], ax=ax[i]) cb.set_label("Resistivity ($\Omega$m)") ax[i].set_xlabel("Northing (m)") ax[i].set_ylabel("Elevation (m)") ax[i].set_aspect("equal") ax[0].set_title("True resistivity model") ax[1].set_title("Recovered resistivity model") plt.tight_layout() plt.show()
data = problem.make_synthetic_data(mtrue[actind], relative_error=0.05, add_noise=True) # Tikhonov Inversion #################### # Initial Model m0 = np.median(ln_sigback) * np.ones(mapping.nP) # Data Misfit dmis = data_misfit.L2DataMisfit(simulation=problem, data=data) # Regularization regT = regularization.Simple(mesh, indActive=actind, alpha_s=1e-6, alpha_x=1.0, alpha_y=1.0, alpha_z=1.0) # Optimization Scheme opt = optimization.InexactGaussNewton(maxIter=10) # Form the problem opt.remember("xc") invProb = inverse_problem.BaseInvProblem(dmis, regT, opt) # Directives for Inversions beta = directives.BetaEstimate_ByEig(beta0_ratio=1.0) Target = directives.TargetMisfit() betaSched = directives.BetaSchedule(coolingFactor=5.0, coolingRate=2)
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
# 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis = data_misfit.L2DataMisfit(data=dc_data, simulation=simulation) # Define the regularization (model objective function) reg = regularization.Simple( mesh, indActive=ind_active, mref=starting_conductivity_model, alpha_s=0.01, alpha_x=1, alpha_y=1, ) # Define how the optimization problem is solved. Here we will use a projected # Gauss-Newton approach that employs the conjugate gradient solver. opt = optimization.ProjectedGNCG(maxIter=5, lower=-10.0, upper=2.0, maxIterLS=20, maxIterCG=10, tolCG=1e-3) # Here we define the inverse problem that is to be solved inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)
# # The inverse problem is defined by 3 things: # # 1) Data Misfit: a measure of how well our recovered model explains the field data # 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis = data_misfit.L2DataMisfit(data=data_object, simulation=simulation) # Define the regularization (model objective function). reg = regularization.Simple(mesh, indActive=ind_active, mapping=model_map) # Define how the optimization problem is solved. Here we will use a projected # Gauss-Newton approach that employs the conjugate gradient solver. opt = optimization.ProjectedGNCG(maxIter=10, lower=-1.0, upper=1.0, maxIterLS=20, maxIterCG=10, tolCG=1e-3) # Here we define the inverse problem that is to be solved inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt) ####################################################################### # Define Inversion Directives
# 3) Coupling: a connection of two different physical property models # 4) Optimization: the numerical approach used to solve the inverse problem # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis_grav = data_misfit.L2DataMisfit(data=data_object_grav, simulation=simulation_grav) dmis_mag = data_misfit.L2DataMisfit(data=data_object_mag, simulation=simulation_mag) # Define the regularization (model objective function). reg_grav = regularization.Simple(mesh, indActive=ind_active, mapping=wires.density) reg_mag = regularization.Simple(mesh, indActive=ind_active, mapping=wires.susceptibility) # Define the coupling term to connect two different physical property models lamda = 2e12 # weight for coupling term cross_grad = regularization.CrossGradient(mesh, wires, indActive=ind_active) # combo dmis = dmis_grav + dmis_mag reg = reg_grav + reg_mag + lamda * cross_grad # Define how the optimization problem is solved. Here we will use a projected # Gauss-Newton approach that employs the conjugate gradient solver.
# 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # The weighting is defined by the reciprocal of the uncertainties. dmis = data_misfit.L2DataMisfit(data=data_object, simulation=simulation) dmis.W = utils.sdiag(1 / uncertainties) # Define the regularization (model objective function) reg = regularization.Simple( mesh, indActive=ind_active, mref=starting_model, alpha_s=1e-2, alpha_x=1, alpha_y=1, alpha_z=1, ) # Define how the optimization problem is solved. Here we will use a projected # Gauss-Newton approach that employs the conjugate gradient solver. # opt = optimization.ProjectedGNCG( # maxIterCG=5, tolCG=1e-2, lower=-10, upper=5 # ) opt = optimization.InexactGaussNewton(maxIterCG=5, tolCG=1e-2) # Here we define the inverse problem that is to be solved inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt)
# # 1) Data Misfit: a measure of how well our recovered model explains the field data # 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_object) # Define the regularization (model objective function) reg = regularization.Simple(mesh, alpha_s=1.0, alpha_x=1.0, mref=starting_model) # Define how the optimization problem is solved. Here we will use an inexact # Gauss-Newton approach that employs the conjugate gradient solver. opt = optimization.InexactGaussNewton(maxIter=30, maxIterCG=20) # Define the inverse problem inv_prob = inverse_problem.BaseInvProblem(dmis, reg, opt) ####################################################################### # Define Inversion Directives # --------------------------- # # Here we define any directives that are carried out during the inversion. This # includes the cooling schedule for the trade-off parameter (beta), stopping
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)
# 1) Data Misfit: a measure of how well our recovered model explains the field data # 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_object) # Define the regularization on the parameters related to resistivity mesh_rho = TensorMesh([mesh.hx.size]) reg_rho = regularization.Simple(mesh_rho, alpha_s=0.01, alpha_x=1, mapping=wire_map.rho) # Define the regularization on the parameters related to layer thickness mesh_t = TensorMesh([mesh.hx.size - 1]) reg_t = regularization.Simple(mesh_t, alpha_s=0.01, alpha_x=1, mapping=wire_map.t) # Combine to make regularization for the inversion problem reg = reg_rho + reg_t # Define how the optimization problem is solved. Here we will use an inexact # Gauss-Newton approach that employs the conjugate gradient solver. opt = optimization.InexactGaussNewton(maxIter=50, maxIterCG=30)
def test_basic_inversion(self): """ Test to see if inversion recovers model """ h = [(2, 30)] meshObj = discretize.TensorMesh((h, h, [(2, 10)]), x0="CCN") mod = 0.00025 * np.ones(meshObj.nC) mod[(meshObj.gridCC[:, 0] > -4.0) & (meshObj.gridCC[:, 1] > -4.0) & (meshObj.gridCC[:, 0] < 4.0) & (meshObj.gridCC[:, 1] < 4.0)] = 0.001 times = np.logspace(-4, -2, 5) waveObj = vrm.waveforms.SquarePulse(delt=0.02) x, y = np.meshgrid(np.linspace(-17, 17, 16), np.linspace(-17, 17, 16)) x, y, z = mkvc(x), mkvc(y), 0.5 * np.ones(np.size(x)) receiver_list = [ vrm.Rx.Point(np.c_[x, y, z], times=times, fieldType="dbdt", orientation="z") ] txNodes = np.array([ [-20, -20, 0.001], [20, -20, 0.001], [20, 20, 0.001], [-20, 20, 0.01], [-20, -20, 0.001], ]) txList = [vrm.Src.LineCurrent(receiver_list, txNodes, 1.0, waveObj)] Survey = vrm.Survey(txList) Survey.t_active = np.zeros(Survey.nD, dtype=bool) Survey.set_active_interval(-1e6, 1e6) Problem = vrm.Simulation3DLinear(meshObj, survey=Survey, refinement_factor=2) dobs = Problem.make_synthetic_data(mod) Survey.noise_floor = 1e-11 dmis = data_misfit.L2DataMisfit(data=dobs, simulation=Problem) W = mkvc((np.sum(np.array(Problem.A)**2, axis=0)))**0.25 reg = regularization.Simple(meshObj, alpha_s=0.01, alpha_x=1.0, alpha_y=1.0, alpha_z=1.0, cell_weights=W) opt = optimization.ProjectedGNCG(maxIter=20, lower=0.0, upper=1e-2, maxIterLS=20, tolCG=1e-4) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt) directives = [ BetaSchedule(coolingFactor=2, coolingRate=1), TargetMisfit() ] inv = inversion.BaseInversion(invProb, directiveList=directives) m0 = 1e-6 * np.ones(len(mod)) mrec = inv.run(m0) dmis_final = np.sum( (dmis.W.diagonal() * (mkvc(dobs) - Problem.fields(mrec)))**2) mod_err_2 = np.sqrt(np.sum((mrec - mod)**2)) / np.size(mod) mod_err_inf = np.max(np.abs(mrec - mod)) self.assertTrue(dmis_final < Survey.nD and mod_err_2 < 5e-6 and mod_err_inf < np.max(mod))
def setup_and_run_std_inv(mesh, dc_survey, dc_data, std_dc, conductivity_map, ind_active, starting_conductivity_model): """Code to setup and run a standard inversion. Parameters ---------- mesh : TYPE DESCRIPTION. dc_survey : TYPE DESCRIPTION. dc_data : TYPE DESCRIPTION. std_dc : TYPE DESCRIPTION. conductivity_map : TYPE DESCRIPTION. ind_active : TYPE DESCRIPTION. starting_conductivity_model : TYPE DESCRIPTION. Returns ------- save_iteration : TYPE DESCRIPTION. save_dict_iteration : TYPE DESCRIPTION. """ # Add standard deviations to data object dc_data.standard_deviation = std_dc # Define the simulation (physics of the problem) dc_simulation = dc.simulation_2d.Simulation2DNodal( mesh, survey=dc_survey, sigmaMap=conductivity_map, Solver=Solver) # Define the data misfit. dc_data_misfit = data_misfit.L2DataMisfit(data=dc_data, simulation=dc_simulation) # Define the regularization (model objective function) dc_regularization = regularization.Simple(mesh, indActive=ind_active, mref=starting_conductivity_model, alpha_s=0.01, alpha_x=1, alpha_y=1) # Define how the optimization problem is solved. Here we will use a # projected. Gauss-Newton approach that employs the conjugate gradient # solver. dc_optimization = optimization.ProjectedGNCG(maxIter=15, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=10, tolCG=1e-3) # Here we define the inverse problem that is to be solved dc_inverse_problem = inverse_problem.BaseInvProblem( dc_data_misfit, dc_regularization, dc_optimization) # Define inversion directives # Apply and update sensitivity weighting as the model updates update_sensitivity_weighting = directives.UpdateSensitivityWeights() # Defining a starting value for the trade-off parameter (beta) between the # data misfit and the regularization. starting_beta = directives.BetaEstimate_ByEig(beta0_ratio=1e2) # Set the rate of reduction in trade-off parameter (beta) each time the # the inverse problem is solved. And set the number of Gauss-Newton # iterations for each trade-off paramter value. beta_schedule = directives.BetaSchedule(coolingFactor=10, coolingRate=1) # Options for outputting recovered models and predicted data for each beta. save_iteration = directives.SaveOutputEveryIteration(save_txt=False) # save results from each iteration in a dict save_dict_iteration = directives.SaveOutputDictEveryIteration( saveOnDisk=False) directives_list = [ update_sensitivity_weighting, starting_beta, beta_schedule, save_iteration, save_dict_iteration, ] # Here we combine the inverse problem and the set of directives dc_inversion = inversion.BaseInversion(dc_inverse_problem, directiveList=directives_list) # Run inversion _ = dc_inversion.run(starting_conductivity_model) return save_iteration, save_dict_iteration
def run_inversion( m0, survey, actind, mesh, wires, std, eps, maxIter=15, beta0_ratio=1e0, coolingFactor=2, coolingRate=2, maxIterLS=20, maxIterCG=10, LSshorten=0.5, eta_lower=1e-5, eta_upper=1, tau_lower=1e-6, tau_upper=10.0, c_lower=1e-2, c_upper=1.0, is_log_tau=True, is_log_c=True, is_log_eta=True, mref=None, alpha_s=1e-4, alpha_x=1e0, alpha_y=1e0, alpha_z=1e0, ): """ Run Spectral Spectral IP inversion """ dmisfit = data_misfit.L2DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1.0 / uncert # Map for a regularization # Related to inversion # Set Upper and Lower bounds e = np.ones(actind.sum()) if np.isscalar(eta_lower): eta_lower = e * eta_lower if np.isscalar(tau_lower): tau_lower = e * tau_lower if np.isscalar(c_lower): c_lower = e * c_lower if np.isscalar(eta_upper): eta_upper = e * eta_upper if np.isscalar(tau_upper): tau_upper = e * tau_upper if np.isscalar(c_upper): c_upper = e * c_upper if is_log_eta: eta_upper = np.log(eta_upper) eta_lower = np.log(eta_lower) if is_log_tau: tau_upper = np.log(tau_upper) tau_lower = np.log(tau_lower) if is_log_c: c_upper = np.log(c_upper) c_lower = np.log(c_lower) m_upper = np.r_[eta_upper, tau_upper, c_upper] m_lower = np.r_[eta_lower, tau_lower, c_lower] # Set up regularization reg_eta = regularization.Simple(mesh, mapping=wires.eta, indActive=actind) reg_tau = regularization.Simple(mesh, mapping=wires.tau, indActive=actind) reg_c = regularization.Simple(mesh, mapping=wires.c, indActive=actind) # Todo: reg_eta.alpha_s = alpha_s reg_tau.alpha_s = 0.0 reg_c.alpha_s = 0.0 reg_eta.alpha_x = alpha_x reg_tau.alpha_x = alpha_x reg_c.alpha_x = alpha_x reg_eta.alpha_y = alpha_y reg_tau.alpha_y = alpha_y reg_c.alpha_y = alpha_y reg_eta.alpha_z = alpha_z reg_tau.alpha_z = alpha_z reg_c.alpha_z = alpha_z reg = reg_eta + reg_tau + reg_c # Use Projected Gauss Newton scheme opt = optimization.ProjectedGNCG( maxIter=maxIter, upper=m_upper, lower=m_lower, maxIterLS=maxIterLS, maxIterCG=maxIterCG, LSshorten=LSshorten, ) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) beta = directives.BetaSchedule(coolingFactor=coolingFactor, coolingRate=coolingRate) betaest = directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio) target = directives.TargetMisfit() directiveList = [beta, betaest, target] inv = inversion.BaseInversion(invProb, directiveList=directiveList) opt.LSshorten = 0.5 opt.remember("xc") # Run inversion mopt = inv.run(m0) return mopt, invProb.dpred
def setUp(self): cs = 25.0 hx = [(cs, 0, -1.3), (cs, 21), (cs, 0, 1.3)] hz = [(cs, 0, -1.3), (cs, 20)] mesh = discretize.TensorMesh([hx, hz], x0="CN") blkind0 = utils.model_builder.getIndicesSphere( np.r_[-100.0, -200.0], 75.0, mesh.gridCC ) blkind1 = utils.model_builder.getIndicesSphere( np.r_[100.0, -200.0], 75.0, mesh.gridCC ) sigma = np.ones(mesh.nC) * 1e-2 eta = np.zeros(mesh.nC) tau = np.ones_like(sigma) * 1.0 c = np.ones_like(sigma) eta[blkind0] = 0.1 eta[blkind1] = 0.1 tau[blkind0] = 0.1 tau[blkind1] = 0.1 x = mesh.vectorCCx[(mesh.vectorCCx > -155.0) & (mesh.vectorCCx < 155.0)] Aloc = np.r_[-200.0, -50] Bloc = np.r_[200.0, -50] M = utils.ndgrid(x - 25.0, np.r_[0.0]) N = utils.ndgrid(x + 25.0, np.r_[0.0]) airind = mesh.gridCC[:, 1] > -40 actmapeta = maps.InjectActiveCells(mesh, ~airind, 0.0) actmaptau = maps.InjectActiveCells(mesh, ~airind, 1.0) actmapc = maps.InjectActiveCells(mesh, ~airind, 1.0) times = np.arange(10) * 1e-3 + 1e-3 rx = sip.receivers.Dipole(M, N, times) src = sip.sources.Dipole([rx], Aloc, Bloc) survey = sip.Survey([src]) wires = maps.Wires( ("eta", actmapeta.nP), ("taui", actmaptau.nP), ("c", actmapc.nP) ) problem = sip.Simulation2DNodal( mesh, sigma=sigma, etaMap=actmapeta * wires.eta, tauiMap=actmaptau * wires.taui, cMap=actmapc * wires.c, actinds=~airind, solver=Solver, survey=survey, ) mSynth = np.r_[eta[~airind], 1.0 / tau[~airind], c[~airind]] dobs = problem.make_synthetic_data(mSynth, add_noise=True) # Now set up the problem to do some minimization dmis = data_misfit.L2DataMisfit(data=dobs, simulation=problem) reg_eta = regularization.Simple(mesh, mapping=wires.eta, indActive=~airind) reg_taui = regularization.Simple(mesh, mapping=wires.taui, indActive=~airind) reg_c = regularization.Simple(mesh, mapping=wires.c, indActive=~airind) reg = reg_eta + reg_taui + reg_c opt = optimization.InexactGaussNewton( maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6 ) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=1e4) inv = inversion.BaseInversion(invProb) self.inv = inv self.reg = reg self.p = problem self.mesh = mesh self.m0 = mSynth self.survey = survey self.dmis = dmis self.dobs = 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)
# 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dc_data_misfit = data_misfit.L2DataMisfit(data=dc_data, simulation=dc_simulation) # Define the regularization (model objective function) dc_regularization = regularization.Simple(mesh, indActive=ind_active, mref=starting_conductivity_model, alpha_s=1e-2, alpha_x=1, alpha_y=1, alpha_z=1) dc_regularization.mrefInSmooth = True # Include reference model in smoothness # Define how the optimization problem is solved. dc_optimization = optimization.InexactGaussNewton(maxIter=15, maxIterLS=20, maxIterCG=30, tolCG=1e-2) # Here we define the inverse problem that is to be solved dc_inverse_problem = inverse_problem.BaseInvProblem(dc_data_misfit, dc_regularization,
# 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dc_data_misfit = data_misfit.L2DataMisfit(data=dc_data, simulation=dc_simulation) # Define the regularization (model objective function) dc_regularization = regularization.Simple( mesh, indActive=ind_active, mref=starting_conductivity_model, ) dc_regularization.mrefInSmooth = True # Include reference model in smoothness # Define how the optimization problem is solved. dc_optimization = optimization.InexactGaussNewton(maxIter=15, maxIterCG=30, tolCG=1e-2) # Here we define the inverse problem that is to be solved dc_inverse_problem = inverse_problem.BaseInvProblem(dc_data_misfit, dc_regularization, dc_optimization)
# 1) Data Misfit: a measure of how well our recovered model explains the field data # 2) Regularization: constraints placed on the recovered model and a priori information # 3) Optimization: the numerical approach used to solve the inverse problem # # # Define the data misfit. Here the data misfit is the L2 norm of the weighted # residual between the observed data and the data predicted for a given model. # Within the data misfit, the residual between predicted and observed data are # normalized by the data's standard deviation. dc_data_misfit = data_misfit.L2DataMisfit(data=dc_data, simulation=dc_simulation) # Define the regularization (model objective function) dc_regularization = regularization.Simple( mesh, indActive=ind_active, mref=starting_conductivity_model, ) dc_regularization.mrefInSmooth = True # Include reference model in smoothness # Define how the optimization problem is solved. dc_optimization = optimization.InexactGaussNewton( maxIter=15, maxIterLS=20, maxIterCG=30, tolCG=1e-2 ) # Here we define the inverse problem that is to be solved dc_inverse_problem = inverse_problem.BaseInvProblem( dc_data_misfit, dc_regularization, dc_optimization ) #################################################