def test_basic_inversion(self): """ Test to see if inversion recovers model """ h = [(2, 30)] meshObj = Mesh.TensorMesh((h, h, [(2, 10)]), x0='CCN') mod = 0.00025 * np.ones(meshObj.nC) mod[(meshObj.gridCC[:, 0] > -4.) & (meshObj.gridCC[:, 1] > -4.) & (meshObj.gridCC[:, 0] < 4.) & (meshObj.gridCC[:, 1] < 4.)] = 0.001 times = np.logspace(-4, -2, 5) waveObj = VRM.WaveformVRM.SquarePulse(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)) rxList = [VRM.Rx.Point(np.c_[x, y, z], times, 'dbdt', '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(rxList, txNodes, 1., waveObj)] Survey = VRM.Survey(txList) Problem = VRM.Problem_Linear(meshObj, refFact=2) Problem.pair(Survey) Survey.makeSyntheticData(mod) Survey.eps = 1e-11 dmis = DataMisfit.l2_DataMisfit(Survey) W = mkvc((np.sum(np.array(Problem.A)**2, axis=0)))**0.25 reg = Regularization.Simple(meshObj, alpha_s=0.01, alpha_x=1., alpha_y=1., alpha_z=1., cell_weights=W) opt = Optimization.ProjectedGNCG(maxIter=20, lower=0., upper=1e-2, maxIterLS=20, tolCG=1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) directives = [ Directives.BetaSchedule(coolingFactor=2, coolingRate=1), Directives.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() * (Survey.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 run(N=100, plotIt=True): np.random.seed(1) mesh = Mesh.TensorMesh([N]) nk = 20 jk = np.linspace(1., 60., nk) p = -0.25 q = 0.25 def g(k): return (np.exp(p * jk[k] * mesh.vectorCCx) * np.cos(np.pi * q * jk[k] * mesh.vectorCCx)) G = np.empty((nk, mesh.nC)) for i in range(nk): G[i, :] = g(i) mtrue = np.zeros(mesh.nC) mtrue[mesh.vectorCCx > 0.3] = 1. mtrue[mesh.vectorCCx > 0.45] = -0.5 mtrue[mesh.vectorCCx > 0.6] = 0 prob = Problem.LinearProblem(mesh, G=G) survey = Survey.LinearSurvey() survey.pair(prob) survey.makeSyntheticData(mtrue, std=0.01) M = prob.mesh reg = Regularization.Tikhonov(mesh, alpha_s=1., alpha_x=1.) dmis = DataMisfit.l2_DataMisfit(survey) opt = Optimization.InexactGaussNewton(maxIter=60) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) directives = [ Directives.BetaEstimate_ByEig(beta0_ratio=1e-2), Directives.TargetMisfit() ] inv = Inversion.BaseInversion(invProb, directiveList=directives) m0 = np.zeros_like(survey.mtrue) mrec = inv.run(m0) if plotIt: fig, axes = plt.subplots(1, 2, figsize=(12 * 1.2, 4 * 1.2)) for i in range(prob.G.shape[0]): axes[0].plot(prob.G[i, :]) axes[0].set_title('Columns of matrix G') axes[1].plot(M.vectorCCx, survey.mtrue, 'b-') axes[1].plot(M.vectorCCx, mrec, 'r-') axes[1].legend(('True Model', 'Recovered Model')) axes[1].set_ylim([-2, 2]) return prob, survey, mesh, mrec
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 solve(self): # Tikhonov Inversion #################### # Initial model values m0 = np.median(self.ln_sigback) * np.ones(self.mapping.nP) m0 += np.random.randn(m0.size) # Misfit functional dmis = DataMisfit.l2_DataMisfit(self.survey.simpeg_survey) # Regularization functional regT = Regularization.Simple(self.mesh, alpha_s=10.0, alpha_x=10.0, alpha_y=10.0, alpha_z=10.0, indActive=self.actind) # Personal preference for this solver with a Jacobi preconditioner opt = Optimization.ProjectedGNCG(maxIter=8, tolX=1, maxIterCG=30) #opt = Optimization.ProjectedGradient(maxIter=100, tolX=1e-2, # maxIterLS=20, maxIterCG=30, tolCG=1e-4) opt.printers.append(Optimization.IterationPrinters.iterationLS) #print(opt.printersLS) # Optimization class keeps value of 'xc'. Seems to be solution for the model parameters opt.remember('xc') invProb = InvProblem.BaseInvProblem(dmis, regT, opt) # Options for the inversion algorithm in particular selection of Beta weight for regularization. # How to choose initial estimate for beta beta = Directives.BetaEstimate_ByEig(beta0_ratio=1.) Target = Directives.TargetMisfit() # Beta changing algorithm. betaSched = Directives.BetaSchedule(coolingFactor=5., coolingRate=2) # Change model weights, seems sensitivity of conductivity ?? Not sure. updateSensW = Directives.UpdateSensitivityWeights(threshold=1e-3) # Use Jacobi preconditioner ( the only available). update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[ beta, Target, betaSched, updateSensW, update_Jacobi ]) self.minv = inv.run(m0)
def solve(self): # initial values/model m0 = numpy.median(-4) * numpy.ones(self.mapping.nP) # Data Misfit dataMisfit = DataMisfit.l2_DataMisfit(self.survey) # Regularization regT = Regularization.Simple(self.mesh, indActive=self.activeCellIndices, alpha_s=1e-6, alpha_x=1., alpha_y=1., alpha_z=1.) # Optimization Scheme opt = Optimization.InexactGaussNewton(maxIter=10) # Form the problem opt.remember('xc') invProb = InvProblem.BaseInvProblem(dataMisfit, regT, opt) # Directives for Inversions beta = Directives.BetaEstimate_ByEig(beta0_ratio=0.5e+1) Target = Directives.TargetMisfit() betaSched = Directives.BetaSchedule(coolingFactor=5., coolingRate=2) inversion = Inversion.BaseInversion(invProb, directiveList=[beta, Target, betaSched]) # Run Inversion self.invModelOnActiveCells = inversion.run(m0) self.invModelOnAllCells = self.givenModelCond * numpy.ones_like(self.givenModelCond) self.invModelOnAllCells[self.activeCellIndices] = self.invModelOnActiveCells self.invModelOnCoreCells = self.invModelOnAllCells[self.coreMeshCellIndices] pass
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., 200. ymin, ymax = 0., 0. zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey.getABMN_locations() survey = IO.from_ambn_locations_to_survey(survey.a_locations, survey.b_locations, survey.m_locations, survey.n_locations, 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.]) survey.drapeTopo(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.Problem2D_N(mesh, rhoMap=mapping, storeJ=True, Solver=Solver) # Pair problem with survey try: prb.pair(survey) except: survey.unpair() prb.pair(survey) # Make synthetic DC data with 5% Gaussian noise dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True) # Show apparent resisitivty pseudo-section IO.plotPseudoSection(data=survey.dobs / IO.G, data_type='apparent_resistivity') # Show apparent resisitivty histogram fig = plt.figure() out = hist(survey.dobs / IO.G, bins=20) plt.show() # Set uncertainty # floor eps = 10**(-3.2) # percentage std = 0.05 dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1. / uncert # Map for a regularization mesh_1d = Mesh.TensorMesh([parametric_block.nP]) # Related to inversion reg = Regularization.Simple(mesh_1d, alpha_x=0.) opt = Optimization.InexactGaussNewton(maxIter=10) invProb = InvProblem.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. 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()
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., c_lower=1e-2, c_upper=1., 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 = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1. / 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.Tikhonov(mesh, mapping=wires.eta, indActive=actind) reg_tau = Regularization.Tikhonov(mesh, mapping=wires.tau, indActive=actind) reg_c = Regularization.Tikhonov(mesh, mapping=wires.c, indActive=actind) # Todo: reg_eta.alpha_s = alpha_s reg_tau.alpha_s = alpha_s reg_c.alpha_s = alpha_s 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 = InvProblem.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 run(plotIt=True): """ 1D FDEM Mu Inversion ==================== 1D inversion of Magnetic Susceptibility from FDEM data assuming a fixed electrical conductivity """ # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10., 15, 25, 13 # padded cyl mesh hx = [(cs, ncx), (cs, npad, 1.3)] hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)] mesh = Mesh.CylMesh([hx, 1, hz], '00C') # Geologic Parameters model layerz = np.r_[-100., -50.] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0. # Electrical Conductivity sig_half = 1e-2 # Half-space conductivity sig_air = 1e-8 # Air conductivity sig_layer = 1e-2 # Layer conductivity sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer # mur - relative magnetic permeability mur_half = 1. mur_air = 1. mur_layer = 2. mur = np.ones(mesh.nCz) * mur_air mur[active] = mur_half mur[layer] = mur_layer mtrue = mur[active] # Maps actMap = Maps.InjectActiveCells(mesh, active, mur_air, nC=mesh.nCz) surj1Dmap = Maps.SurjectVertical1D(mesh) murMap = Maps.MuRelative(mesh) # Mapping muMap = murMap * surj1Dmap * actMap # ----- FDEM problem & survey ----- rxlocs = Utils.ndgrid([np.r_[10.], np.r_[0], np.r_[30.]]) bzr = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'real') # bzi = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'imag') freqs = np.linspace(2000, 10000, 10) #np.logspace(3, 4, 10) srcLoc = np.array([0., 0., 30.]) print('min skin depth = ', 500. / np.sqrt(freqs.max() * sig_half), 'max skin depth = ', 500. / np.sqrt(freqs.min() * sig_half)) print('max x ', mesh.vectorCCx.max(), 'min z ', mesh.vectorCCz.min(), 'max z ', mesh.vectorCCz.max()) srcList = [ FDEM.Src.MagDipole([bzr], freq, srcLoc, orientation='Z') for freq in freqs ] surveyFD = FDEM.Survey(srcList) prbFD = FDEM.Problem3D_b(mesh, sigma=surj1Dmap * sigma, muMap=muMap, Solver=Solver) prbFD.pair(surveyFD) std = 0.03 surveyFD.makeSyntheticData(mtrue, std) surveyFD.eps = np.linalg.norm(surveyFD.dtrue) * 1e-6 # FDEM inversion np.random.seed(13472) dmisfit = DataMisfit.l2_DataMisfit(surveyFD) regMesh = Mesh.TensorMesh([mesh.hz[muMap.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() directiveList = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = mur_half * np.ones(mtrue.size) reg.alpha_s = 2e-2 reg.alpha_x = 1. prbFD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptFD = inv.run(m0) dpredFD = surveyFD.dpred(moptFD) if plotIt: fig, ax = plt.subplots(1, 3, figsize=(10, 6)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs # Plot the conductivity model ax[0].semilogx(sigma[active], mesh.vectorCCz[active], 'k-', lw=2) ax[0].set_ylim(-500, 0) ax[0].set_xlim(5e-3, 1e-1) ax[0].set_xlabel('Conductivity (S/m)', fontsize=fs) ax[0].set_ylabel('Depth (m)', fontsize=fs) ax[0].grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax[0].legend(['Conductivity Model'], fontsize=fs, loc=4) # Plot the permeability model ax[1].plot(mur[active], mesh.vectorCCz[active], 'k-', lw=2) ax[1].plot(moptFD, mesh.vectorCCz[active], 'b-', lw=2) ax[1].set_ylim(-500, 0) ax[1].set_xlim(0.5, 2.1) ax[1].set_xlabel('Relative Permeability', fontsize=fs) ax[1].set_ylabel('Depth (m)', fontsize=fs) ax[1].grid(which='both', color='k', alpha=0.5, linestyle='-', linewidth=0.2) ax[1].legend(['True', 'Predicted'], fontsize=fs, loc=4) # plot the data misfits - negative b/c we choose positive to be in the # direction of primary ax[2].plot(freqs, -surveyFD.dobs, 'k-', lw=2) # ax[2].plot(freqs, -surveyFD.dobs[1::2], 'k--', lw=2) ax[2].loglog(freqs, -dpredFD, 'bo', ms=6) # ax[2].loglog(freqs, -dpredFD[1::2], 'b+', markeredgewidth=2., ms=10) # Labels, gridlines, etc ax[2].grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax[2].grid(which='both', alpha=0.5, linestyle='-', linewidth=0.2) ax[2].set_xlabel('Frequency (Hz)', fontsize=fs) ax[2].set_ylabel('Vertical magnetic field (-T)', fontsize=fs) # ax[2].legend(("Obs", "Pred"), fontsize=fs) ax[2].legend(("z-Obs (real)", "z-Pred (real)"), fontsize=fs) ax[2].set_xlim(freqs.max(), freqs.min()) ax[0].set_title("(a) Conductivity Model", fontsize=fs) ax[1].set_title("(b) $\mu_r$ Model", fontsize=fs) ax[2].set_title("(c) FDEM observed vs. predicted", fontsize=fs) # ax[2].set_title("(c) TDEM observed vs. predicted", fontsize=fs) plt.tight_layout(pad=1.5)
def run(plotIt=True): M = Mesh.TensorMesh([np.ones(40)], x0='N') M.setCellGradBC('dirichlet') # We will use the haverkamp empirical model with parameters from Celia1990 k_fun, theta_fun = Richards.Empirical.haverkamp(M, A=1.1750e+06, gamma=4.74, alpha=1.6110e+06, theta_s=0.287, theta_r=0.075, beta=3.96) # Here we are making saturated hydraulic conductivity # an exponential mapping to the model (defined below) k_fun.KsMap = Maps.ExpMap(nP=M.nC) # Setup the boundary and initial conditions bc = np.array([-61.5, -20.7]) h = np.zeros(M.nC) + bc[0] prob = Richards.RichardsProblem(M, hydraulic_conductivity=k_fun, water_retention=theta_fun, boundary_conditions=bc, initial_conditions=h, do_newton=False, method='mixed', debug=False) prob.timeSteps = [(5, 25, 1.1), (60, 40)] # Create the survey locs = -np.arange(2, 38, 4.) times = np.arange(30, prob.timeMesh.vectorCCx[-1], 60) rxSat = Richards.SaturationRx(locs, times) survey = Richards.RichardsSurvey([rxSat]) survey.pair(prob) # Create a simple model for Ks Ks = 1e-3 mtrue = np.ones(M.nC) * np.log(Ks) mtrue[15:20] = np.log(5e-2) mtrue[20:35] = np.log(3e-3) mtrue[35:40] = np.log(1e-2) m0 = np.ones(M.nC) * np.log(Ks) # Create some synthetic data and fields stdev = 0.02 # The standard deviation for the noise Hs = prob.fields(mtrue) survey.makeSyntheticData(mtrue, std=stdev, f=Hs, force=True) # Setup a pretty standard inversion reg = Regularization.Tikhonov(M, alpha_s=1e-1) dmis = DataMisfit.l2_DataMisfit(survey) opt = Optimization.InexactGaussNewton(maxIter=20, maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) beta = Directives.BetaSchedule(coolingFactor=4) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e2) target = Directives.TargetMisfit() dir_list = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=dir_list) mopt = inv.run(m0) Hs_opt = prob.fields(mopt) if plotIt: plt.figure(figsize=(14, 9)) ax = plt.subplot(121) plt.semilogx(np.exp(np.c_[mopt, mtrue]), M.gridCC) plt.xlabel('Saturated Hydraulic Conductivity, $K_s$') plt.ylabel('Depth, cm') plt.semilogx([10**-3.9] * len(locs), locs, 'ro') plt.legend(('$m_{rec}$', '$m_{true}$', 'Data locations'), loc=4) ax = plt.subplot(222) mesh2d = Mesh.TensorMesh([prob.timeMesh.hx / 60, prob.mesh.hx], '0N') sats = [theta_fun(_) for _ in Hs] clr = mesh2d.plotImage(np.c_[sats][1:, :], ax=ax) cmap0 = matplotlib.cm.RdYlBu_r clr[0].set_cmap(cmap0) c = plt.colorbar(clr[0]) c.set_label('Saturation $\\theta$') plt.xlabel('Time, minutes') plt.ylabel('Depth, cm') plt.title('True saturation over time') ax = plt.subplot(224) mesh2d = Mesh.TensorMesh([prob.timeMesh.hx / 60, prob.mesh.hx], '0N') sats = [theta_fun(_) for _ in Hs_opt] clr = mesh2d.plotImage(np.c_[sats][1:, :], ax=ax) cmap0 = matplotlib.cm.RdYlBu_r clr[0].set_cmap(cmap0) c = plt.colorbar(clr[0]) c.set_label('Saturation $\\theta$') plt.xlabel('Time, minutes') plt.ylabel('Depth, cm') plt.title('Recovered saturation over time') plt.tight_layout()
def run_inversion_cg( self, maxIter=60, m0=0.0, mref=0.0, percentage=5, floor=0.1, chifact=1, beta0_ratio=1.0, coolingFactor=1, coolingRate=1, alpha_s=1.0, alpha_x=1.0, use_target=False, ): survey, prob = self.get_problem_survey() survey.eps = percentage survey.std = floor survey.dobs = self.data.copy() self.uncertainty = percentage * abs(survey.dobs) * 0.01 + floor m0 = np.ones(self.M) * m0 mref = np.ones(self.M) * mref reg = Regularization.Tikhonov( self.mesh, alpha_s=alpha_s, alpha_x=alpha_x, mref=mref ) dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1.0 / self.uncertainty opt = Optimization.InexactGaussNewton(maxIter=maxIter, maxIterCG=20) opt.remember("xc") opt.tolG = 1e-10 opt.eps = 1e-10 invProb = InvProblem.BaseInvProblem(dmis, reg, opt) save = Directives.SaveOutputEveryIteration() beta_schedule = Directives.BetaSchedule( coolingFactor=coolingFactor, coolingRate=coolingRate ) target = Directives.TargetMisfit(chifact=chifact) if use_target: directives = [ Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio), beta_schedule, target, save, ] else: directives = [ Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio), beta_schedule, save, ] inv = Inversion.BaseInversion(invProb, directiveList=directives) mopt = inv.run(m0) model = opt.recall("xc") model.append(mopt) pred = [] for m in model: pred.append(survey.dpred(m)) return model, pred, save
# Define misfit function (obs-calc) dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1./survey.std # Create the default L2 inverse problem from the above objects invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # Specify how the initial beta is found betaest = Directives.BetaEstimate_ByEig() # Beta schedule for inversion betaSchedule = Directives.BetaSchedule(coolingFactor=2., coolingRate=1) # Target misfit to stop the inversion, # try to fit as much as possible of the signal, we don't want to lose anything targetMisfit = Directives.TargetMisfit(chifact=0.1) # Put all the parts together inv = Inversion.BaseInversion(invProb, directiveList=[betaest, betaSchedule, targetMisfit]) # Run the equivalent source inversion mstart = np.zeros(nC) mrec = inv.run(mstart) # Ouput result Mesh.TensorMesh.writeModelUBC(mesh, work_dir + out_dir + "EquivalentSource.sus", surfMap*mrec) # %% STEP 2: COMPUTE AMPLITUDE DATA # Now that we have an equialent source layer, we can forward model alh three
def run(plotIt=True, saveFig=False): # Set up cylindrically symmeric mesh cs, ncx, ncz, npad = 10., 15, 25, 13 # padded cyl mesh hx = [(cs, ncx), (cs, npad, 1.3)] hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)] mesh = Mesh.CylMesh([hx, 1, hz], '00C') # Conductivity model layerz = np.r_[-200., -100.] layer = (mesh.vectorCCz >= layerz[0]) & (mesh.vectorCCz <= layerz[1]) active = mesh.vectorCCz < 0. sig_half = 1e-2 # Half-space conductivity sig_air = 1e-8 # Air conductivity sig_layer = 5e-2 # Layer conductivity sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer # Mapping actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap mtrue = np.log(sigma[active]) # ----- FDEM problem & survey ----- # rxlocs = Utils.ndgrid([np.r_[50.], np.r_[0], np.r_[0.]]) bzr = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'real') bzi = FDEM.Rx.Point_bSecondary(rxlocs, 'z', 'imag') freqs = np.logspace(2, 3, 5) srcLoc = np.array([0., 0., 0.]) print('min skin depth = ', 500. / np.sqrt(freqs.max() * sig_half), 'max skin depth = ', 500. / np.sqrt(freqs.min() * sig_half)) print('max x ', mesh.vectorCCx.max(), 'min z ', mesh.vectorCCz.min(), 'max z ', mesh.vectorCCz.max()) srcList = [ FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs ] surveyFD = FDEM.Survey(srcList) prbFD = FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prbFD.pair(surveyFD) std = 0.03 surveyFD.makeSyntheticData(mtrue, std) surveyFD.eps = np.linalg.norm(surveyFD.dtrue) * 1e-5 # FDEM inversion np.random.seed(1) dmisfit = DataMisfit.l2_DataMisfit(surveyFD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion Directives beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() directiveList = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = np.log(np.ones(mtrue.size) * sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. prbFD.counter = opt.counter = Utils.Counter() opt.remember('xc') moptFD = inv.run(m0) # TDEM problem times = np.logspace(-4, np.log10(2e-3), 10) print('min diffusion distance ', 1.28 * np.sqrt(times.min() / (sig_half * mu_0)), 'max diffusion distance ', 1.28 * np.sqrt(times.max() / (sig_half * mu_0))) rx = TDEM.Rx.Point_b(rxlocs, times, 'z') src = TDEM.Src.MagDipole( [rx], waveform=TDEM.Src.StepOffWaveform(), loc=srcLoc # same src location as FDEM problem ) surveyTD = TDEM.Survey([src]) prbTD = TDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prbTD.timeSteps = [(5e-5, 10), (1e-4, 10), (5e-4, 10)] prbTD.pair(surveyTD) std = 0.03 surveyTD.makeSyntheticData(mtrue, std) surveyTD.std = std surveyTD.eps = np.linalg.norm(surveyTD.dtrue) * 1e-5 # TDEM inversion dmisfit = DataMisfit.l2_DataMisfit(surveyTD) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # directives beta = Directives.BetaSchedule(coolingFactor=4, coolingRate=3) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=2.) target = Directives.TargetMisfit() directiveList = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=directiveList) m0 = np.log(np.ones(mtrue.size) * sig_half) reg.alpha_s = 5e-1 reg.alpha_x = 1. 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 ax0.semilogx(sigma[active], mesh.vectorCCz[active], '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, -surveyFD.dobs[::2], 'k-', lw=2, label="Obs (real)") ax1.plot(freqs, -surveyFD.dobs[1::2], 'k--', lw=2, label="Obs (imag)") dpredFD = surveyFD.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., label="Pred (imag)") ax2.loglog(times, surveyTD.dobs, 'k-', lw=2, label='Obs') ax2.loglog(times, surveyTD.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)
hz, dim=3, use_cell_weights=True, minimum_distance=1e3) np.random.seed(1) dmisfit = DataMisfit.l2_DataMisfit(survey) dmisfit.W = 1. / uncert opt = Optimization.ProjectedGNCG(maxIter=10, maxIterCG=20) # opt.upper = m_upper # opt.lower = m_lower invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1.) target = Directives.TargetMisfit(chifact=1.) save_model = Directives.SaveOutputDictEveryIteration( directory=output_dir.as_posix()) inv = Inversion.BaseInversion( invProb, directiveList=[beta, betaest, target, save_model]) prob.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') try: save_model.outDict = {} except: pass print('Target misfit:', target.target) ## Run it!
def run(plotIt=True, survey_type="dipole-dipole"): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0., 200. ymin, ymax = 0., 0. zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey.getABMN_locations() survey = IO.from_ambn_locations_to_survey( survey.a_locations, survey.b_locations, survey.m_locations, survey.n_locations, survey_type, data_dc_type='volt' ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() topo, mesh1D = DC.Utils.genTopography(mesh, -10, 0, its=100) actind = Utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo]) survey.drapeTopo(mesh, actind, option="top") # Build a conductivity model blk_inds_c = Utils.ModelBuilder.getIndicesSphere( np.r_[60., -25.], 12.5, mesh.gridCC ) blk_inds_r = Utils.ModelBuilder.getIndicesSphere( np.r_[140., -25.], 12.5, mesh.gridCC ) layer_inds = mesh.gridCC[:, 1] > -5. sigma = np.ones(mesh.nC)*1./100. sigma[blk_inds_c] = 1./10. sigma[blk_inds_r] = 1./1000. sigma[~actind] = 1./1e8 rho = 1./sigma # Show the true conductivity model if plotIt: fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=True, 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') plt.show() # Use Exponential Map: m = log(rho) actmap = Maps.InjectActiveCells( mesh, indActive=actind, valInactive=np.log(1e8) ) mapping = Maps.ExpMap(mesh) * actmap # Generate mtrue mtrue = np.log(rho[actind]) # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Problem2D_N( mesh, rhoMap=mapping, storeJ=True, Solver=Solver ) # Pair problem with survey try: prb.pair(survey) except: survey.unpair() prb.pair(survey) geometric_factor = survey.set_geometric_factor( data_type="apparent_resistivity", survey_type='dipole-dipole', space_type='half-space' ) # Make synthetic DC data with 5% Gaussian noise dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True) IO.data_dc = dtrue # Show apparent resisitivty pseudo-section if plotIt: IO.plotPseudoSection( data=survey.dobs, data_type='apparent_resistivity' ) # Show apparent resisitivty histogram if plotIt: fig = plt.figure() out = hist(survey.dobs, bins=20) plt.xlabel("Apparent Resisitivty ($\Omega$m)") plt.show() # Set initial model based upon histogram m0 = np.ones(actmap.nP)*np.log(100.) # Set uncertainty # floor (10 ohm-m) eps = 1. # percentage std = 0.05 dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1./uncert # Map for a regularization regmap = Maps.IdentityMap(nP=int(actind.sum())) # Related to inversion reg = Regularization.Sparse(mesh, indActive=actind, mapping=regmap) opt = Optimization.InexactGaussNewton(maxIter=15) invProb = InvProblem.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() inv = Inversion.BaseInversion( invProb, directiveList=[ beta, betaest, target, updateSensW, update_Jacobi ] ) prb.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') # Run inversion mopt = inv.run(m0) # Get diag(JtJ) mask_inds = np.ones(mesh.nC, dtype=bool) jtj = np.sqrt(updateSensW.JtJdiag[0]) jtj /= jtj.max() temp = np.ones_like(jtj, dtype=bool) temp[jtj > 0.005] = False mask_inds[actind] = temp actind_final = np.logical_and(actind, ~mask_inds) jtj_cc = np.ones(mesh.nC)*np.nan jtj_cc[actind] = jtj # Show the sensitivity if plotIt: fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage( jtj_cc, grid=True, ax=ax, gridOpts={'alpha': 0.2}, clim=(0.005, 0.5), 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("Sensitivity") ax.set_aspect('equal') plt.show() # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping*mopt rho_est[~actind_final] = np.nan rho_true = rho.copy() rho_true[~actind_final] = np.nan # show recovered conductivity if plotIt: 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') plt.tight_layout() plt.show()
def run(plotIt=True): """ EM: TDEM: 1D: Inversion with VTEM waveform ========================================== Here we will create and run a TDEM 1D inversion, with VTEM waveform of which initial condition is zero, but have some on- and off-time. """ cs, ncx, ncz, npad = 5., 25, 24, 15 hx = [(cs, ncx), (cs, npad, 1.3)] hz = [(cs, npad, -1.3), (cs, ncz), (cs, npad, 1.3)] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. layer = (mesh.vectorCCz < -50.) & (mesh.vectorCCz >= -150.) 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., np.zeros_like(x)] prb = EM.TDEM.Problem3D_b(mesh, sigmaMap=mapping) prb.Solver = Solver prb.timeSteps = [(1e-3, 5), (1e-4, 5), (5e-5, 10), (5e-5, 5), (1e-4, 10), (5e-4, 10)] # Use VTEM waveform out = EM.Utils.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 = EM.TDEM.Src.RawWaveform(offTime=t0, waveFct=wavefun) rx = EM.TDEM.Rx.Point_dbdt(rxloc, np.logspace(-4, -2.5, 11) + t0, 'z') src = EM.TDEM.Src.CircularLoop([rx], waveform=waveform, loc=np.array([0., 0., 0.]), radius=10.) survey = EM.TDEM.Survey([src]) prb.pair(survey) # create observed data std = 0.02 survey.dobs = survey.makeSyntheticData(mtrue, std) # dobs = survey.dpred(mtrue) survey.std = std survey.eps = 1e-11 dmisfit = DataMisfit.l2_DataMisfit(survey) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) opt = Optimization.InexactGaussNewton(maxIter=5, LSshorten=0.5) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) target = Directives.TargetMisfit() # Create an inversion object beta = Directives.BetaSchedule(coolingFactor=1., coolingRate=2.) 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 = survey.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}$'])
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., 10., 10., 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.), np.log10(12.), 19) temp_pad = temp[-1] * 1.3 ** np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. # Step2: Set a SurjectVertical1D mapping # Note: this sets our inversion model as 1D log conductivity # below subsurface active = mesh.vectorCCz < 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 = EM.FDEM.Rx.Point_bSecondary( np.array([[rxOffset, 0., src_height_resolve]]), orientation='z', component='real' ) bzi = EM.FDEM.Rx.Point_b( np.array([[rxOffset, 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., src_height_resolve]) srcList = [EM.FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs] # Set FDEM survey (In-phase and Quadrature) survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prb.pair(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 std = np.repeat(np.r_[np.ones(3)*0.1, np.ones(2)*0.15], 2) floor = 20 * abs(bp) * 1e-6 uncert = abs(dobs_re) * std + floor # Data Misfit survey.dobs = dobs_re dmisfit = DataMisfit.l2_DataMisfit(survey) dmisfit.W = 1./uncert # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = Directives.TargetMisfit() # stop when we hit target misfit invProb.beta = 2. # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-3 reg.alpha_x = 1. 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., src_height]]) # Radius of the source loop area = skytem["area"].value radius = np.sqrt(area/np.pi) rxLoc = np.array([[radius, 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. dbdt_z = EM.TDEM.Rx.Point_dbdt( locs=rxLoc, times=times_off[:-3]+offTime, orientation='z' ) # vertical db_dt rxList = [dbdt_z] # list of receivers srcList = [ EM.TDEM.Src.CircularLoop( rxList, loc=srcLoc, radius=radius, orientation='z', waveform=EM.TDEM.Src.VTEMWaveform( offTime=offTime, peakTime=peakTime, a=3. ) ) ] # 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 = EM.TDEM.Problem3D_e( mesh, timeSteps=timeSteps, sigmaMap=mapping, Solver=Solver ) survey = EM.TDEM.Survey(srcList) prob.pair(survey) src = srcList[0] rx = src.rxList[0] wave = [] for time in prob.times: wave.append(src.waveform.eval(time)) wave = np.hstack(wave) out = survey.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 std = 0.12 floor = 7.5e-12 uncert = abs(dobs_sky) * std + floor # Data Misfit survey.dobs = -dobs_sky dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = 0.12*abs(dobs_sky) + 7.5e-12 dmisfit.W = Utils.sdiag(1./uncert) # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Directives and Inversion Parameters target = Directives.TargetMisfit() # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) invProb.beta = 20. inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-1 reg.alpha_x = 1. 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., 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, .33, .1, .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() 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)
def run_inversion( m0, survey, actind, mesh, std, eps, maxIter=15, beta0_ratio=1e0, coolingFactor=5, coolingRate=2, upper=np.inf, lower=-np.inf, use_sensitivity_weight=False, alpha_s=1e-4, alpha_x=1., alpha_y=1., alpha_z=1., ): """ Run IP inversion """ dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1./uncert # Map for a regularization regmap = Maps.IdentityMap(nP=int(actind.sum())) # Related to inversion if use_sensitivity_weight: reg = Regularization.Sparse( mesh, indActive=actind, mapping=regmap ) reg.alpha_s = alpha_s reg.alpha_x = alpha_x reg.alpha_y = alpha_y reg.alpha_z = alpha_z else: reg = Regularization.Sparse( mesh, indActive=actind, mapping=regmap, cell_weights=mesh.vol[actind] ) reg.alpha_s = alpha_s reg.alpha_x = alpha_x reg.alpha_y = alpha_y reg.alpha_z = alpha_z opt = Optimization.ProjectedGNCG(maxIter=maxIter, upper=upper, lower=lower) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) beta = Directives.BetaSchedule( coolingFactor=coolingFactor, coolingRate=coolingRate ) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio) target = Directives.TargetMisfit() # Need to have basice saving function if use_sensitivity_weight: updateSensW = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner() directiveList = [ beta, betaest, target, update_Jacobi ] else: 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
opt = Optimization.ProjectedGNCG(maxIter=25, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=30, tolCG=1e-3) # Create the default L2 inverse problem from the above objects invProb = InvProblem.BaseInvProblem(ComboMisfit, reg, opt) # Specify how the initial beta is found betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1) # Target misfit to stop the inversion, # try to fit as much as possible of the signal, we don't want to lose anything targetMisfit = Directives.TargetMisfit(chifact=targetChi) # Pre-conditioner update_Jacobi = Directives.UpdatePreconditioner() IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, beta_tol=0.25, maxIRLSiter=1, chifact_target=targetChi) # Save model saveIt = Directives.SaveUBCModelEveryIteration(mapping=activeCellsMap, fileName=workDir + dsep + outDir + driver["dataFile"][0]) # Put all the parts together
def run(plotIt=True, survey_type="dipole-dipole", p=0., qx=2., qz=2.): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0., 200. ymin, ymax = 0., 0. zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey.getABMN_locations() survey = IO.from_ambn_locations_to_survey(survey.a_locations, survey.b_locations, survey.m_locations, survey.n_locations, survey_type, data_dc_type='volt') # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() topo, mesh1D = DC.Utils.genTopography(mesh, -10, 0, its=100) actind = Utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo]) survey.drapeTopo(mesh, actind, option="top") # Build a conductivity model blk_inds_c = Utils.ModelBuilder.getIndicesSphere(np.r_[60., -25.], 12.5, mesh.gridCC) blk_inds_r = Utils.ModelBuilder.getIndicesSphere(np.r_[140., -25.], 12.5, mesh.gridCC) layer_inds = mesh.gridCC[:, 1] > -5. sigma = np.ones(mesh.nC) * 1. / 100. sigma[blk_inds_c] = 1. / 10. sigma[blk_inds_r] = 1. / 1000. sigma[~actind] = 1. / 1e8 rho = 1. / sigma # Show the true conductivity model if plotIt: fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage(temp, grid=True, 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') plt.show() # Use Exponential Map: m = log(rho) actmap = Maps.InjectActiveCells(mesh, indActive=actind, valInactive=np.log(1e8)) mapping = Maps.ExpMap(mesh) * actmap # Generate mtrue mtrue = np.log(rho[actind]) # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Problem2D_N(mesh, rhoMap=mapping, storeJ=True, Solver=Solver, verbose=True) # Pair problem with survey try: prb.pair(survey) except: survey.unpair() prb.pair(survey) # Make synthetic DC data with 5% Gaussian noise dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True) IO.data_dc = dtrue # Show apparent resisitivty pseudo-section if plotIt: IO.plotPseudoSection(data=survey.dobs / IO.G, data_type='apparent_resistivity') # Show apparent resisitivty histogram if plotIt: fig = plt.figure() out = hist(survey.dobs / IO.G, bins=20) plt.xlabel("Apparent Resisitivty ($\Omega$m)") plt.show() # Set initial model based upon histogram m0 = np.ones(actmap.nP) * np.log(100.) # Set uncertainty # floor eps = 10**(-3.2) # percentage std = 0.05 dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1. / uncert # Map for a regularization regmap = Maps.IdentityMap(nP=int(actind.sum())) # Related to inversion reg = Regularization.Sparse(mesh, indActive=actind, mapping=regmap, gradientType='components') # gradientType = 'components' reg.norms = np.c_[p, qx, qz, 0.] IRLS = Directives.Update_IRLS(maxIRLSiter=20, minGNiter=1, betaSearch=False, fix_Jmatrix=True) opt = Optimization.InexactGaussNewton(maxIter=40) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) target = Directives.TargetMisfit() update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[betaest, IRLS]) prb.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') # Run inversion mopt = inv.run(m0) rho_est = mapping * mopt rho_est_l2 = mapping * invProb.l2model rho_est[~actind] = np.nan rho_est_l2[~actind] = np.nan rho_true = rho.copy() rho_true[~actind] = np.nan # show recovered conductivity if plotIt: vmin, vmax = rho.min(), rho.max() fig, ax = plt.subplots(3, 1, figsize=(20, 9)) out1 = mesh.plotImage(rho_true, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[0]) out2 = mesh.plotImage(rho_est_l2, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[1]) out3 = mesh.plotImage(rho_est, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[2]) out = [out1, out2, out3] titles = ["True", "L2", ("L%d, Lx%d, Lz%d") % (p, qx, qz)] for i in range(3): 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[i].set_title(titles[i]) plt.tight_layout() plt.show()
def run_inversion( self, maxIter=60, m0=0.0, mref=0.0, percentage=5, floor=0.1, chifact=1, beta0_ratio=1.0, coolingFactor=1, n_iter_per_beta=1, alpha_s=1.0, alpha_x=1.0, alpha_z=1.0, use_target=False, use_tikhonov=True, use_irls=False, p_s=2, p_x=2, p_y=2, p_z=2, beta_start=None, ): self.uncertainty = percentage * abs(self.survey.dobs) * 0.01 + floor m0 = np.ones(self.mesh.nC) * m0 mref = np.ones(self.mesh.nC) * mref if ~use_tikhonov: reg = Regularization.Sparse( self.mesh, alpha_s=alpha_s, alpha_x=alpha_x, alpha_y=alpha_z, mref=mref, mapping=Maps.IdentityMap(self.mesh), cell_weights=self.mesh.vol, ) else: reg = Regularization.Tikhonov( self.mesh, alpha_s=alpha_s, alpha_x=alpha_x, alpha_y=alpha_z, mref=mref, mapping=Maps.IdentityMap(self.mesh), ) dmis = DataMisfit.l2_DataMisfit(self.survey) dmis.W = 1.0 / self.uncertainty opt = Optimization.ProjectedGNCG(maxIter=maxIter, maxIterCG=20) opt.lower = 0.0 opt.remember("xc") opt.tolG = 1e-10 opt.eps = 1e-10 invProb = InvProblem.BaseInvProblem(dmis, reg, opt) save = Directives.SaveOutputEveryIteration() beta_schedule = Directives.BetaSchedule(coolingFactor=coolingFactor, coolingRate=n_iter_per_beta) if use_irls: IRLS = Directives.Update_IRLS( f_min_change=1e-4, minGNiter=1, silent=False, maxIRLSiter=40, beta_tol=5e-1, coolEpsFact=1.3, chifact_start=chifact, ) if beta_start is None: directives = [ Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio), IRLS, save, ] else: directives = [IRLS, save] invProb.beta = beta_start reg.norms = np.c_[p_s, p_x, p_z, 2] else: target = Directives.TargetMisfit(chifact=chifact) directives = [ Directives.BetaEstimate_ByEig(beta0_ratio=beta0_ratio), beta_schedule, save, ] if use_target: directives.append(target) inv = Inversion.BaseInversion(invProb, directiveList=directives) mopt = inv.run(m0) model = opt.recall("xc") model.append(mopt) pred = [] for m in model: pred.append(self.survey.dpred(m)) return model, pred, save
indActive=actind, alpha_s=1e-6, alpha_x=1., alpha_y=1., alpha_z=1.) # Optimization Scheme opt = Optimization.InexactGaussNewton(maxIter=10) # Form the problem opt.remember('xc') invProb = InvProblem.BaseInvProblem(dmis, regT, opt) # Directives for Inversions beta = Directives.BetaEstimate_ByEig(beta0_ratio=1e+1) Target = Directives.TargetMisfit() betaSched = Directives.BetaSchedule(coolingFactor=5., coolingRate=2) inv = Inversion.BaseInversion(invProb, directiveList=[beta, Target, betaSched]) # Run Inversion minv = inv.run(m0) # Final Plot ############ fig, ax = plt.subplots(2, 2, figsize=(12, 6)) ax = Utils.mkvc(ax) cyl0v = getCylinderPoints(x0, z0, r0) cyl1v = getCylinderPoints(x1, z1, r1)
def fitWithStretchedExponetial(time, survey_ip, sources, Rho, start_time=None): if start_time is None: start_time = 0 # Choose all time channels tinds = time > start_time nLoc = survey_ip.dobs.T[tinds, :].shape[1] # Setup wire for different properties wires = Maps.Wires(('eta', nLoc), ('tau', nLoc), ('c', nLoc)) taumap = Maps.ExpMap(nP=nLoc) * wires.tau etamap = Maps.ExpMap(nP=nLoc) * wires.eta cmap = Maps.ExpMap(nP=nLoc) * wires.c # This is almost dummmy mesh and xyz loc at the moment # But, there is potential use later m1D = Mesh.TensorMesh([np.ones(nLoc)]) # # Set survey survey = SEMultiSurvey(time[tinds] * 1e-3, sources[:, :], n_pulse=2, T=4) survey.dobs = (survey_ip.dobs.T[tinds, :]).flatten(order='F') # Set problem prob = SEMultiInvProblem(m1D, etaMap=etamap, tauMap=taumap, cMap=cmap) prob.pair(survey) # Set initial model eta0, tau0, c0 = abs( survey_ip.dobs.T[0, :].T), 1. * np.ones(nLoc), 1. * np.ones(nLoc) m0 = np.r_[np.log(eta0), np.log(tau0), np.log(c0)] std = 0.02 plt.plot(survey.dpred(m0)) plt.plot(survey.dobs, '.') plt.title("Obs & pred") plt.xlabel("data point") plt.ylabel("value") plt.show() mreg = Mesh.TensorMesh([len(m0)]) dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = (abs(survey.dobs) * std + 0.01) * 1.1 dmisfit.W = 1. / uncert reg = Regularization.Simple(mreg) opt = Optimization.ProjectedGNCG(maxIter=20) invProb = InvProblem.BaseInvProblem(dmisfit, 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 m_upper = np.r_[np.ones_like(tau0) * np.log(200), np.ones_like(tau0) * np.log(10.), np.ones_like(tau0) * np.log(1.)] m_lower = np.r_[np.ones_like(tau0) * np.log(1), np.ones_like(tau0) * np.log(1e-2), np.ones_like(tau0) * np.log(0.1)] opt.lower = m_lower opt.upper = m_upper mopt = inv.run(m0) eta = etamap * mopt tau = taumap * mopt c = cmap * mopt DPRED = invProb.dpred.reshape((nLoc, time[tinds].size)) DOBS = survey.dobs.reshape((nLoc, time[tinds].size)) UNCERT = uncert.reshape((nLoc, time[tinds].size)) error = ((eta * 1e-3) / np.sqrt(np.sum((DOBS - DPRED)**2, axis=1) / time[tinds].size)) from matplotlib import colors fig = plt.figure(figsize=(6, 5)) active_inds = (Rho[:, 0] > 10.) & (Rho[:, 0] < 1e3) & (abs( (DPRED - DOBS) / UNCERT).sum(axis=1) / time[tinds].size < 1.) out = plt.scatter(tau[active_inds], c[active_inds], c=eta[active_inds], norm=colors.LogNorm(), cmap="magma", s=2) cb = plt.colorbar(out) plt.xscale('log') plt.yscale('log') plt.xlabel("Tau") plt.ylabel("c") cb.set_label("Eta (mV/V)") plt.show() inds = (abs((DPRED - DOBS) / UNCERT).sum(axis=1) / time[tinds].size < 20.) # print(inds) inds = np.arange(survey.n_location)[inds] out = plt.loglog(time[tinds], DPRED[inds[::2], :].T, 'r') out = plt.loglog(time[tinds], DOBS[inds[::2], :].T, 'kx') print(np.sum((DPRED - DOBS)**2) / time.size) fig, axs = plt.subplots(4, 1) properties = [ Rho[:, 0][active_inds], eta[active_inds], tau[active_inds], c[active_inds] ] titles = ["$\\rho_{a}$", "$\\eta_{a}$", "$\\tau_{a}$", "$c_{a}$"] colors = ['#1f77b4', 'seagreen', 'crimson', 'gold'] for i, ax in enumerate(axs): out = ax.hist(np.log10(properties[i]), bins=50, color=colors[i]) ax.set_title(titles[i]) ax.set_xticklabels([("%.1f") % (10**tick) for tick in ax.get_xticks()]) plt.tight_layout() plt.show() return eta, tau, c, error
def resolve_1Dinversions(mesh, dobs, src_height, freqs, m0, mref, mapping, std=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.array dobs: observed data :param float src_height: height of the source above the ground :param numpy.array freqs: frequencies :param numpy.array m0: starting model :param numpy.array mref: reference model :param Maps.IdentityMap mapping: mapping that maps the model to electrical conductivity :param float std: 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 = EM.FDEM.Rx.Point_bSecondary(np.array([[rxOffset, 0., src_height]]), orientation='z', component='real') bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., src_height]]), orientation='z', component='imag') # source location srcLoc = np.array([0., 0., src_height]) srcList = [ EM.FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs ] # construct a forward simulation survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=PardisoSolver) prb.pair(survey) # ------------------- Inversion ------------------- # # data misfit term survey.dobs = dobs dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(dobs) * std + floor dmisfit.W = 1. / uncert # regularization regMesh = Mesh.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 = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = Directives.TargetMisfit() inv = Inversion.BaseInversion(invProb, directiveList=[target]) invProb.beta = 2. # Fix beta in the nonlinear iterations reg.alpha_s = 1e-3 reg.alpha_x = 1. 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): """ FLOW: Richards: 1D: Inversion ============================= The example shows an inversion of Richards equation in 1D with a heterogeneous hydraulic conductivity function. The haverkamp model is used with the same parameters as Celia1990_ the boundary and initial conditions are also the same. The simulation domain is 40cm deep and is run for an hour with an exponentially increasing time step that has a maximum of one minute. The general setup of the experiment is an infiltration front that advances downward through the model over time. The model chosen is the saturated hydraulic conductivity inside the hydraulic conductivity function (using haverkamp). The initial model is chosen to be the background (1e-3 cm/s). The saturation data has 2% random Gaussian noise added. The figure shows the recovered saturated hydraulic conductivity next to the true model. The other two figures show the saturation field for the entire simulation for the true and recovered models. Rowan Cockett - 21/12/2016 .. _Celia1990: http://www.webpages.uidaho.edu/ch/papers/Celia.pdf """ M = Mesh.TensorMesh([np.ones(40)], x0='N') M.setCellGradBC('dirichlet') # We will use the haverkamp empirical model with parameters from Celia1990 k_fun, theta_fun = Richards.Empirical.haverkamp(M, A=1.1750e+06, gamma=4.74, alpha=1.6110e+06, theta_s=0.287, theta_r=0.075, beta=3.96) # Here we are making saturated hydraulic conductivity # an exponential mapping to the model (defined below) k_fun.KsMap = Maps.ExpMap(nP=M.nC) # Setup the boundary and initial conditions bc = np.array([-61.5, -20.7]) h = np.zeros(M.nC) + bc[0] prob = Richards.RichardsProblem(M, hydraulic_conductivity=k_fun, water_retention=theta_fun, boundary_conditions=bc, initial_conditions=h, do_newton=False, method='mixed', debug=False) prob.timeSteps = [(5, 25, 1.1), (60, 40)] # Create the survey locs = -np.arange(2, 38, 4.) times = np.arange(30, prob.timeMesh.vectorCCx[-1], 60) rxSat = Richards.SaturationRx(locs, times) survey = Richards.RichardsSurvey([rxSat]) survey.pair(prob) # Create a simple model for Ks Ks = 1e-3 mtrue = np.ones(M.nC) * np.log(Ks) mtrue[15:20] = np.log(5e-2) mtrue[20:35] = np.log(3e-3) mtrue[35:40] = np.log(1e-2) m0 = np.ones(M.nC) * np.log(Ks) # Create some synthetic data and fields stdev = 0.02 # The standard deviation for the noise Hs = prob.fields(mtrue) survey.makeSyntheticData(mtrue, std=stdev, f=Hs, force=True) # Setup a pretty standard inversion reg = Regularization.Tikhonov(M, alpha_s=1e-1) dmis = DataMisfit.l2_DataMisfit(survey) opt = Optimization.InexactGaussNewton(maxIter=20, maxIterCG=10) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) beta = Directives.BetaSchedule(coolingFactor=4) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e2) target = Directives.TargetMisfit() dir_list = [beta, betaest, target] inv = Inversion.BaseInversion(invProb, directiveList=dir_list) mopt = inv.run(m0) Hs_opt = prob.fields(mopt) if plotIt: plt.figure(figsize=(14, 9)) ax = plt.subplot(121) plt.semilogx(np.exp(np.c_[mopt, mtrue]), M.gridCC) plt.xlabel('Saturated Hydraulic Conductivity, $K_s$') plt.ylabel('Depth, cm') plt.semilogx([10**-3.9] * len(locs), locs, 'ro') plt.legend(('$m_{rec}$', '$m_{true}$', 'Data locations'), loc=4) ax = plt.subplot(222) mesh2d = Mesh.TensorMesh([prob.timeMesh.hx / 60, prob.mesh.hx], '0N') sats = [theta_fun(_) for _ in Hs] clr = mesh2d.plotImage(np.c_[sats][1:, :], ax=ax) cmap0 = matplotlib.cm.RdYlBu_r clr[0].set_cmap(cmap0) c = plt.colorbar(clr[0]) c.set_label('Saturation $\\theta$') plt.xlabel('Time, minutes') plt.ylabel('Depth, cm') plt.title('True saturation over time') ax = plt.subplot(224) mesh2d = Mesh.TensorMesh([prob.timeMesh.hx / 60, prob.mesh.hx], '0N') sats = [theta_fun(_) for _ in Hs_opt] clr = mesh2d.plotImage(np.c_[sats][1:, :], ax=ax) cmap0 = matplotlib.cm.RdYlBu_r clr[0].set_cmap(cmap0) c = plt.colorbar(clr[0]) c.set_label('Saturation $\\theta$') plt.xlabel('Time, minutes') plt.ylabel('Depth, cm') plt.title('Recovered saturation over time') plt.tight_layout()