def solve(self): # Tikhonov Inversion #################### # Initial model values m0 = np.median(self.ln_sigback) * np.ones(self.mapping.nP) # Misfit functional dmis = DataMisfit.l2_DataMisfit(self.survey.simpeg_survey) # Regularization functional regT = Regularization.Simple(self.mesh, indActive=self.actind) # Personal preference for this solver with a Jacobi preconditioner opt = Optimization.ProjectedGNCG(maxIter=20, lower=-10, upper=10, maxIterLS=20, maxIterCG=30, tolCG=1e-4) # 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 run(plotIt=True): H0 = (50000., 90., 0.) # Create a mesh dx = 5. hxind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)] hyind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)] hzind = [(dx, 5, -1.3), (dx, 10)] mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCC') # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -np.exp((xx**2 + yy**2) / 75**2) + mesh.vectorNz[-1] # We would usually load a topofile topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Go from topo to array of indices of active cells actv = Utils.surface2ind_topo(mesh, topo, 'N') actv = np.where(actv)[0] # Create and array of observation points xr = np.linspace(-20., 20., 20) yr = np.linspace(-20., 20., 20) X, Y = np.meshgrid(xr, yr) # Move the observation points 5m above the topo Z = -np.exp((X**2 + Y**2) / 75**2) + mesh.vectorNz[-1] + 5. # Create a MAGsurvey rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseMag.RxObs(rxLoc) srcField = PF.BaseMag.SrcField([rxLoc], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # We can now create a susceptibility model and generate data model = np.zeros(mesh.nC) # Change values in half the domain model[mesh.gridCC[:, 0] < 0] = 0.01 # Add a block in half-space model = Utils.ModelBuilder.addBlock(mesh.gridCC, model, np.r_[-10, -10, 20], np.r_[10, 10, 40], 0.05) model = Utils.mkvc(model) model = model[actv] # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, np.nan) # Create reduced identity map idenMap = Maps.IdentityMap(nP=len(actv)) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data d = prob.fields(model) # Add noise and uncertainties # We add some random Gaussian noise (1nT) data = d + np.random.randn(len(d)) wd = np.ones(len(data)) * 1. # Assign flat uncertainties survey.dobs = data survey.std = wd survey.mtrue = model # Plot the data rxLoc = survey.srcField.rxList[0].locs # Create a homogenous maps for the two domains domains = [mesh.gridCC[actv, 0] < 0, mesh.gridCC[actv, 0] >= 0] homogMap = Maps.SurjectUnits(domains) # Create a wire map for a second model space, voxel based wires = Maps.Wires(('h**o', len(domains)), ('hetero', len(actv))) # Create Sum map sumMap = Maps.SumMap([homogMap * wires.h**o, wires.hetero]) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=sumMap, actInd=actv) # Pair the survey and problem survey.unpair() survey.pair(prob) # Make depth weighting wr = np.zeros(sumMap.shape[1]) # Take the cell number out of the scaling. # Want to keep high sens for large volumes scale = Utils.sdiag(np.r_[Utils.mkvc(1. / homogMap.P.sum(axis=0)), np.ones_like(actv)]) for ii in range(survey.nD): wr += ((prob.G[ii, :] * prob.chiMap.deriv(np.ones(sumMap.shape[1]) * 1e-4) * scale) / survey.std[ii])**2. # Scale the model spaces independently wr[wires.h**o.index] /= (np.max((wires.h**o * wr))) wr[wires.hetero.index] /= (np.max(wires.hetero * wr)) wr = wr**0.5 ## Create a regularization # For the homogeneous model regMesh = Mesh.TensorMesh([len(domains)]) reg_m1 = Regularization.Sparse(regMesh, mapping=wires.h**o) reg_m1.cell_weights = wires.h**o * wr reg_m1.norms = np.c_[0, 2, 2, 2] reg_m1.mref = np.zeros(sumMap.shape[1]) # Regularization for the voxel model reg_m2 = Regularization.Sparse(mesh, indActive=actv, mapping=wires.hetero) reg_m2.cell_weights = wires.hetero * wr reg_m2.norms = np.c_[0, 1, 1, 1] reg_m2.mref = np.zeros(sumMap.shape[1]) reg = reg_m1 + reg_m2 # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1 / wd # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=100, lower=0., upper=1., maxIterLS=20, maxIterCG=10, tolCG=1e-3, tolG=1e-3, eps=1e-6) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) betaest = Directives.BetaEstimate_ByEig() # Here is where the norms are applied # Use pick a threshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1) update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi]) # Run the inversion m0 = np.ones(sumMap.shape[1]) * 1e-4 # Starting model prob.model = m0 mrecSum = inv.run(m0) if plotIt: mesh.plot_3d_slicer(actvMap * model, aspect="equal", zslice=30, pcolorOpts={"cmap": 'inferno_r'}, transparent='slider') mesh.plot_3d_slicer(actvMap * sumMap * mrecSum, aspect="equal", zslice=30, pcolorOpts={"cmap": 'inferno_r'}, transparent='slider')
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
regT = Regularization.Simple(mesh, 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)
reg.mref = np.zeros(nC) # Specify how the optimization will proceed, set susceptibility bounds to inf opt = Optimization.ProjectedGNCG(maxIter=25, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=20, tolCG=1e-3) # 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)
def run(plotIt=True): cs, ncx, ncz, npad = 5., 25, 15, 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') layerz = -100. active = mesh.vectorCCz < 0. layer = (mesh.vectorCCz < 0.) & (mesh.vectorCCz >= layerz) actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap sig_half = 2e-2 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]) if plotIt: fig, ax = plt.subplots(1, 1, figsize=(3, 6)) plt.semilogx(sigma[active], mesh.vectorCCz[active]) ax.set_ylim(-500, 0) ax.set_xlim(1e-3, 1e-1) ax.set_xlabel('Conductivity (S/m)', fontsize=14) ax.set_ylabel('Depth (m)', fontsize=14) ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5) rxOffset = 10. bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag') freqs = np.logspace(1, 3, 10) srcLoc = np.array([0., 0., 10.]) srcList = [ EM.FDEM.Src.MagDipole([bzi], freq, srcLoc, orientation='Z') for freq in freqs ] survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prb.pair(survey) std = 0.05 survey.makeSyntheticData(mtrue, std) survey.std = std survey.eps = np.linalg.norm(survey.dtrue) * 1e-5 if plotIt: fig, ax = plt.subplots(1, 1, figsize=(6, 6)) ax.semilogx(freqs, survey.dtrue[:freqs.size], 'b.-') ax.semilogx(freqs, survey.dobs[:freqs.size], 'r.-') ax.legend(('Noisefree', '$d^{obs}$'), fontsize=16) ax.set_xlabel('Time (s)', fontsize=14) ax.set_ylabel('$B_z$ (T)', fontsize=16) ax.set_xlabel('Time (s)', fontsize=14) ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5) dmisfit = DataMisfit.l2_DataMisfit(survey) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Tikhonov(regMesh) opt = Optimization.InexactGaussNewton(maxIter=6) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Create an inversion object beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest]) m0 = np.log(np.ones(mtrue.size) * sig_half) reg.alpha_s = 1e-3 reg.alpha_x = 1. prb.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') mopt = inv.run(m0) if plotIt: fig, ax = plt.subplots(1, 1, figsize=(3, 6)) plt.semilogx(sigma[active], mesh.vectorCCz[active]) plt.semilogx(np.exp(mopt), mesh.vectorCCz[active]) ax.set_ylim(-500, 0) ax.set_xlim(1e-3, 1e-1) ax.set_xlabel('Conductivity (S/m)', fontsize=14) ax.set_ylabel('Depth (m)', fontsize=14) ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5) plt.legend(['$\sigma_{true}$', '$\sigma_{pred}$'], loc='best')
def setUp(self): np.random.seed(0) H0 = (50000., 90., 0.) # The magnetization is set along a different # direction (induced + remanence) M = np.array([45., 90.]) # Create grid of points for topography # Lets create a simple Gaussian topo # and set the active cells [xx, yy] = np.meshgrid( np.linspace(-200, 200, 50), np.linspace(-200, 200, 50) ) b = 100 A = 50 zz = A*np.exp(-0.5*((xx/b)**2. + (yy/b)**2.)) # We would usually load a topofile topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Create and array of observation points xr = np.linspace(-100., 100., 20) yr = np.linspace(-100., 100., 20) X, Y = np.meshgrid(xr, yr) Z = A*np.exp(-0.5*((X/b)**2. + (Y/b)**2.)) + 5 # Create a MAGsurvey xyzLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseMag.RxObs(xyzLoc) srcField = PF.BaseMag.SrcField([rxLoc], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [2, 4, 2] # Get extent of points limx = np.r_[topo[:, 0].max(), topo[:, 0].min()] limy = np.r_[topo[:, 1].max(), topo[:, 1].min()] limz = np.r_[topo[:, 2].max(), topo[:, 2].min()] # Get center of the mesh midX = np.mean(limx) midY = np.mean(limy) midZ = np.mean(limz) nCx = int(limx[0]-limx[1]) / h[0] nCy = int(limy[0]-limy[1]) / h[1] nCz = int(limz[0]-limz[1]+int(np.min(np.r_[nCx, nCy])/3)) / h[2] # Figure out full extent required from input extent = np.max(np.r_[nCx * h[0] + padDist[0, :].sum(), nCy * h[1] + padDist[1, :].sum(), nCz * h[2] + padDist[2, :].sum()]) maxLevel = int(np.log2(extent/h[0]))+1 # Number of cells at the small octree level nCx, nCy, nCz = 2**(maxLevel), 2**(maxLevel), 2**(maxLevel) # Define the mesh and origin # For now cubic cells mesh = Mesh.TreeMesh([np.ones(nCx)*h[0], np.ones(nCx)*h[1], np.ones(nCx)*h[2]]) # Set origin mesh.x0 = np.r_[ -nCx*h[0]/2.+midX, -nCy*h[1]/2.+midY, -nCz*h[2]/2.+midZ ] # Refine the mesh around topography # Get extent of points F = NearestNDInterpolator(topo[:, :2], topo[:, 2]) zOffset = 0 # Cycle through the first 3 octree levels for ii in range(3): dx = mesh.hx.min()*2**ii nCx = int((limx[0]-limx[1]) / dx) nCy = int((limy[0]-limy[1]) / dx) # Create a grid at the octree level in xy CCx, CCy = np.meshgrid( np.linspace(limx[1], limx[0], nCx), np.linspace(limy[1], limy[0], nCy) ) z = F(mkvc(CCx), mkvc(CCy)) # level means number of layers in current OcTree level for level in range(int(nCpad[ii])): mesh.insert_cells( np.c_[ mkvc(CCx), mkvc(CCy), z-zOffset ], np.ones_like(z)*maxLevel-ii, finalize=False ) zOffset += dx mesh.finalize() self.mesh = mesh # Define an active cells from topo actv = Utils.surface2ind_topo(mesh, topo) nC = int(actv.sum()) model = np.zeros((mesh.nC, 3)) # Convert the inclination declination to vector in Cartesian M_xyz = Utils.matutils.dip_azimuth2cartesian(M[0], M[1]) # Get the indicies of the magnetized block ind = Utils.ModelBuilder.getIndicesBlock( np.r_[-20, -20, -10], np.r_[20, 20, 25], mesh.gridCC, )[0] # Assign magnetization values model[ind, :] = np.kron( np.ones((ind.shape[0], 1)), M_xyz*0.05 ) # Remove air cells self.model = model[actv, :] # Create active map to go from reduce set to full self.actvMap = Maps.InjectActiveCells(mesh, actv, np.nan) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=nC*3) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral( mesh, chiMap=idenMap, actInd=actv, modelType='vector' ) # Pair the survey and problem survey.pair(prob) # Compute some data and add some random noise data = prob.fields(Utils.mkvc(self.model)) std = 5 # nT data += np.random.randn(len(data))*std wd = np.ones(len(data))*std # Assigne data and uncertainties to the survey survey.dobs = data survey.std = wd # Create an projection matrix for plotting later actvPlot = Maps.InjectActiveCells(mesh, actv, np.nan) # Create sensitivity weights from our linear forward operator rxLoc = survey.srcField.rxList[0].locs # This Mapping connects the regularizations for the three-component # vector model wires = Maps.Wires(('p', nC), ('s', nC), ('t', nC)) # Create sensitivity weights from our linear forward operator # so that all cells get equal chance to contribute to the solution wr = np.sum(prob.G**2., axis=0)**0.5 wr = (wr/np.max(wr)) # Create three regularization for the different components # of magnetization reg_p = Regularization.Sparse(mesh, indActive=actv, mapping=wires.p) reg_p.mref = np.zeros(3*nC) reg_p.cell_weights = (wires.p * wr) reg_s = Regularization.Sparse(mesh, indActive=actv, mapping=wires.s) reg_s.mref = np.zeros(3*nC) reg_s.cell_weights = (wires.s * wr) reg_t = Regularization.Sparse(mesh, indActive=actv, mapping=wires.t) reg_t.mref = np.zeros(3*nC) reg_t.cell_weights = (wires.t * wr) reg = reg_p + reg_s + reg_t reg.mref = np.zeros(3*nC) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1./survey.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=30, lower=-10, upper=10., maxIterLS=20, maxIterCG=20, tolCG=1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # A list of directive to control the inverson betaest = Directives.BetaEstimate_ByEig() # Here is where the norms are applied # Use pick a treshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS( f_min_change=1e-3, maxIRLSiter=0, beta_tol=5e-1 ) # Pre-conditioner update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, update_Jacobi, betaest]) # Run the inversion m0 = np.ones(3*nC) * 1e-4 # Starting model mrec_MVIC = inv.run(m0) self.mstart = Utils.matutils.cartesian2spherical(mrec_MVIC.reshape((nC, 3), order='F')) beta = invProb.beta dmis.prob.coordinate_system = 'spherical' dmis.prob.model = self.mstart # Create a block diagonal regularization wires = Maps.Wires(('amp', nC), ('theta', nC), ('phi', nC)) # Create a Combo Regularization # Regularize the amplitude of the vectors reg_a = Regularization.Sparse(mesh, indActive=actv, mapping=wires.amp) reg_a.norms = np.c_[0., 0., 0., 0.] # Sparse on the model and its gradients reg_a.mref = np.zeros(3*nC) # Regularize the vertical angle of the vectors reg_t = Regularization.Sparse(mesh, indActive=actv, mapping=wires.theta) reg_t.alpha_s = 0. # No reference angle reg_t.space = 'spherical' reg_t.norms = np.c_[2., 0., 0., 0.] # Only norm on gradients used # Regularize the horizontal angle of the vectors reg_p = Regularization.Sparse(mesh, indActive=actv, mapping=wires.phi) reg_p.alpha_s = 0. # No reference angle reg_p.space = 'spherical' reg_p.norms = np.c_[2., 0., 0., 0.] # Only norm on gradients used reg = reg_a + reg_t + reg_p reg.mref = np.zeros(3*nC) Lbound = np.kron(np.asarray([0, -np.inf, -np.inf]), np.ones(nC)) Ubound = np.kron(np.asarray([10, np.inf, np.inf]), np.ones(nC)) # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=20, lower=Lbound, upper=Ubound, maxIterLS=20, maxIterCG=30, tolCG=1e-3, stepOffBoundsFact=1e-3, ) opt.approxHinv = None invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=beta*10.) # Here is where the norms are applied IRLS = Directives.Update_IRLS(f_min_change=1e-4, maxIRLSiter=20, minGNiter=1, beta_tol=0.5, coolingRate=1, coolEps_q=True, betaSearch=False) # Special directive specific to the mag amplitude problem. The sensitivity # weights are update between each iteration. ProjSpherical = Directives.ProjectSphericalBounds() update_SensWeight = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner() self.inv = Inversion.BaseInversion( invProb, directiveList=[ ProjSpherical, IRLS, update_SensWeight, update_Jacobi ] )
def run(plotIt=True): # Define the inducing field parameter H0 = (50000, 90, 0) # Create a mesh dx = 5. hxind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)] hyind = [(dx, 5, -1.3), (dx, 10), (dx, 5, 1.3)] hzind = [(dx, 5, -1.3), (dx, 10)] mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCC') # Get index of the center midx = int(mesh.nCx / 2) midy = int(mesh.nCy / 2) # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -np.exp((xx**2 + yy**2) / 75**2) + mesh.vectorNz[-1] # We would usually load a topofile topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Go from topo to array of indices of active cells actv = Utils.surface2ind_topo(mesh, topo, 'N') actv = np.where(actv)[0] nC = len(actv) # Create and array of observation points xr = np.linspace(-20., 20., 20) yr = np.linspace(-20., 20., 20) X, Y = np.meshgrid(xr, yr) # Move the observation points 5m above the topo Z = -np.exp((X**2 + Y**2) / 75**2) + mesh.vectorNz[-1] + 5. # Create a MAGsurvey rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseMag.RxObs(rxLoc) srcField = PF.BaseMag.SrcField([rxLoc], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # We can now create a susceptibility model and generate data # Here a simple block in half-space model = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz)) model[(midx - 2):(midx + 2), (midy - 2):(midy + 2), -6:-2] = 0.02 model = Utils.mkvc(model) model = model[actv] # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) # Create reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data d = prob.fields(model) # Add noise and uncertainties # We add some random Gaussian noise (1nT) data = d + np.random.randn(len(d)) wd = np.ones(len(data)) * 1. # Assign flat uncertainties survey.dobs = data survey.std = wd survey.mtrue = model # Create sensitivity weights from our linear forward operator rxLoc = survey.srcField.rxList[0].locs wr = np.sum(prob.G**2., axis=0)**0.5 wr = (wr / np.max(wr)) # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wr reg.mref = np.zeros(nC) reg.norms = np.c_[0, 0, 0, 0] # reg.eps_p, reg.eps_q = 1e-0, 1e-0 # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1 / wd # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=100, lower=0., upper=1., maxIterLS=20, maxIterCG=20, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e-1) # Here is where the norms are applied # Use pick a threshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS(f_min_change=1e-4, maxIRLSiter=40) saveDict = Directives.SaveOutputEveryIteration(save_txt=False) update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion( invProb, directiveList=[IRLS, betaest, update_Jacobi, saveDict]) # Run the inversion m0 = np.ones(nC) * 1e-4 # Starting model mrec = inv.run(m0) if plotIt: # Here is the recovered susceptibility model ypanel = midx zpanel = -5 m_l2 = actvMap * invProb.l2model m_l2[m_l2 == -100] = np.nan m_lp = actvMap * mrec m_lp[m_lp == -100] = np.nan m_true = actvMap * model m_true[m_true == -100] = np.nan # Plot the data Utils.PlotUtils.plot2Ddata(rxLoc, d) plt.figure() # Plot L2 model ax = plt.subplot(321) mesh.plotSlice(m_l2, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan l2-model.') plt.gca().set_aspect('equal') plt.ylabel('y') ax.xaxis.set_visible(False) plt.gca().set_aspect('equal', adjustable='box') # Vertica section ax = plt.subplot(322) mesh.plotSlice(m_l2, ax=ax, normal='Y', ind=midx, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W l2-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box') # Plot Lp model ax = plt.subplot(323) mesh.plotSlice(m_lp, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan lp-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('y') plt.gca().set_aspect('equal', adjustable='box') # Vertical section ax = plt.subplot(324) mesh.plotSlice(m_lp, ax=ax, normal='Y', ind=midx, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W lp-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box') # Plot True model ax = plt.subplot(325) mesh.plotSlice(m_true, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan true model.') plt.gca().set_aspect('equal') plt.xlabel('x') plt.ylabel('y') plt.gca().set_aspect('equal', adjustable='box') # Vertical section ax = plt.subplot(326) mesh.plotSlice(m_true, ax=ax, normal='Y', ind=midx, grid=True, clim=(model.min(), model.max())) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W true model.') plt.gca().set_aspect('equal') plt.xlabel('x') plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box') # Plot convergence curves fig, axs = plt.figure(), plt.subplot() axs.plot(saveDict.phi_d, 'k', lw=2) axs.plot(np.r_[IRLS.iterStart, IRLS.iterStart], np.r_[0, np.max(saveDict.phi_d)], 'k:') twin = axs.twinx() twin.plot(saveDict.phi_m, 'k--', lw=2) axs.text(IRLS.iterStart, 0, 'IRLS Steps', va='bottom', ha='center', rotation='vertical', size=12, bbox={'facecolor': 'white'}) axs.set_ylabel('$\phi_d$', size=16, rotation=0) axs.set_xlabel('Iterations', size=14) twin.set_ylabel('$\phi_m$', size=16, rotation=0)
def run(plotIt=True): """ EM: TDEM: 1D: Inversion ======================= Here we will create and run a TDEM 1D inversion. """ cs, ncx, ncz, npad = 5., 25, 15, 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 < 0.) & (mesh.vectorCCz >= -100.) actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap sig_half = 2e-3 sig_air = 1e-8 sig_layer = 1e-3 sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half sigma[layer] = sig_layer mtrue = np.log(sigma[active]) rxOffset = 1e-3 rx = EM.TDEM.Rx.Point_b(np.array([[rxOffset, 0., 30]]), np.logspace(-5, -3, 31), 'z') src = EM.TDEM.Src.MagDipole([rx], loc=np.array([0., 0., 80])) survey = EM.TDEM.Survey([src]) prb = EM.TDEM.Problem3D_b(mesh, sigmaMap=mapping) prb.Solver = SolverLU prb.timeSteps = [(1e-06, 20), (1e-05, 20), (0.0001, 20)] prb.pair(survey) # create observed data std = 0.05 survey.dobs = survey.makeSyntheticData(mtrue, std) survey.std = std survey.eps = 1e-5 * np.linalg.norm(survey.dobs) dmisfit = DataMisfit.l2_DataMisfit(survey) regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Tikhonov(regMesh, alpha_s=1e-2, alpha_x=1.) opt = Optimization.InexactGaussNewton(maxIter=5, LSshorten=0.5) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Create an inversion object beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest]) 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)) ax[0].loglog(rx.times, survey.dtrue, 'b.-') ax[0].loglog(rx.times, survey.dobs, 'r.-') ax[0].legend(('Noisefree', '$d^{obs}$'), fontsize=16) ax[0].set_xlabel('Time (s)', fontsize=14) ax[0].set_ylabel('$B_z$ (T)', 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-2) 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_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
def run(N=100, plotIt=True): np.random.seed(1) std_noise = 1e-2 mesh = Mesh.TensorMesh([N]) m0 = np.ones(mesh.nC) * 1e-4 mref = np.zeros(mesh.nC) 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.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk) wd = np.ones(nk) * std_noise # Distance weighting wr = np.sum(prob.G**2., axis=0)**0.5 wr = wr / np.max(wr) dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1. / wd betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e-2) reg = Regularization.Sparse(mesh) reg.mref = mref reg.cell_weights = wr reg.mref = np.zeros(mesh.nC) opt = Optimization.ProjectedGNCG(maxIter=100, lower=-2., upper=2., maxIterLS=20, maxIterCG=10, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) update_Jacobi = Directives.Update_lin_PreCond() # Set the IRLS directive, penalize the lowest 25 percentile of model values # Start with an l2-l2, then switch to lp-norms norms = [0., 0., 2., 2.] IRLS = Directives.Update_IRLS(norms=norms, prctile=25, maxIRLSiter=15, minGNiter=3) inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi]) # Run inversion mrec = inv.run(m0) print("Final misfit:" + str(invProb.dmisfit.eval(mrec))) 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(mesh.vectorCCx, mtrue, 'b-') axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-') # axes[1].legend(('True Model', 'Recovered Model')) axes[1].set_ylim(-1.0, 1.25) axes[1].plot(mesh.vectorCCx, mrec, 'k-', lw=2) axes[1].legend(('True Model', 'Smooth l2-l2', 'Sparse lp: {0}, lqx: {1}'.format(*reg.norms)), fontsize=12) return prob, survey, mesh, mrec
def run(N=100, plotIt=True): np.random.seed(1) std_noise = 1e-2 mesh = Mesh.TensorMesh([N]) m0 = np.ones(mesh.nC) * 1e-4 mref = np.zeros(mesh.nC) 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.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk) wd = np.ones(nk) * std_noise # Distance weighting wr = np.sum(prob.getJ(m0)**2., axis=0)**0.5 wr = wr/np.max(wr) dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1./wd betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=mesh.nC) reg = Regularization.Sparse(mesh, mapping=idenMap) reg.mref = mref reg.cell_weights = wr reg.norms = np.c_[0., 0., 2., 2.] reg.mref = np.zeros(mesh.nC) opt = Optimization.ProjectedGNCG( maxIter=100, lower=-2., upper=2., maxIterLS=20, maxIterCG=10, tolCG=1e-3 ) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) update_Jacobi = Directives.UpdatePreconditioner() # Set the IRLS directive, penalize the lowest 25 percentile of model values # Start with an l2-l2, then switch to lp-norms IRLS = Directives.Update_IRLS( maxIRLSiter=40, minGNiter=1, f_min_change=1e-4) saveDict = Directives.SaveOutputEveryIteration(save_txt=False) inv = Inversion.BaseInversion( invProb, directiveList=[IRLS, betaest, update_Jacobi, saveDict] ) # Run inversion mrec = inv.run(m0) print("Final misfit:" + str(invProb.dmisfit(mrec))) if plotIt: fig, axes = plt.subplots(2, 2, figsize=(12*1.2, 8*1.2)) for i in range(prob.G.shape[0]): axes[0, 0].plot(prob.G[i, :]) axes[0, 0].set_title('Columns of matrix G') axes[0, 1].plot(mesh.vectorCCx, mtrue, 'b-') axes[0, 1].plot(mesh.vectorCCx, invProb.l2model, 'r-') # axes[0, 1].legend(('True Model', 'Recovered Model')) axes[0, 1].set_ylim(-1.0, 1.25) axes[0, 1].plot(mesh.vectorCCx, mrec, 'k-', lw=2) axes[0, 1].legend( ( 'True Model', 'Smooth l2-l2', 'Sparse norms: {0}'.format(*reg.norms) ), fontsize=12 ) axes[1, 1].plot(saveDict.phi_d, 'k', lw=2) twin = axes[1, 1].twinx() twin.plot(saveDict.phi_m, 'k--', lw=2) axes[1, 1].plot( np.r_[IRLS.iterStart, IRLS.iterStart], np.r_[0, np.max(saveDict.phi_d)], 'k:' ) axes[1, 1].text( IRLS.iterStart, 0., 'IRLS Start', va='bottom', ha='center', rotation='vertical', size=12, bbox={'facecolor': 'white'} ) axes[1, 1].set_ylabel('$\phi_d$', size=16, rotation=0) axes[1, 1].set_xlabel('Iterations', size=14) axes[1, 0].axis('off') twin.set_ylabel('$\phi_m$', size=16, rotation=0) return prob, survey, mesh, mrec
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): init_t = time() np.random.seed(0) input_file = sys.argv[1] # read json file with open(input_file, "r") as json_file: input_dict = json.load(json_file) work_dir = os.path.abspath(os.path.dirname(input_file)) path_sep = os.path.sep if "example" in list(input_dict.keys()): if input_dict["example"] == "horse": work_dir = os.path.sep.join([work_dir, "Example2_horseShoe"]) work_dir += path_sep elif input_dict["example"] == "spheric": work_dir = os.path.sep.join([work_dir, "Example1_spheric"]) work_dir += path_sep else: raise Exception("Missing the selection of examples") # read mesh file if "mesh_file" in list(input_dict.keys()): mesh = Mesh.TensorMesh._readUBC_3DMesh(work_dir + input_dict["mesh_file"]) else: raise Exception("Missing mesh file") # read data file if "data_file" in list(input_dict.keys()): # Create a MAGsurvey survey = Utils.io_utils.readUBCgravityObservations( work_dir + input_dict["data_file"]) xyzLoc = survey.rxLoc dobs = survey.dobs print("Number of data points: ", dobs.size) std = survey.std else: raise Exception("Missing observed data file") # load the topo if "topography" in list(input_dict.keys()): # Load topo topo = np.genfromtxt(work_dir + input_dict["topography"], skip_header=1) F = NearestNDInterpolator(topo[:, :2], topo[:, 2]) newTopo = np.c_[xyzLoc[:, :2], F(xyzLoc[:, :2])] # without topo else: newTopo = np.c_[xyzLoc[:, :2], np.zeros(xyzLoc.shape[0])] actv = Utils.surface2ind_topo(mesh, newTopo, gridLoc='CC') actv = np.where(actv)[0] nC = len(actv) print("Number of active cells: ", nC) # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, np.nan) # Create reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Gravity.GravityGradient(mesh, components=['gzz'], rhoMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Create depth weighting z0 = 0 v = 3 # exponent parameter temp1 = np.abs(np.max(topo[:, 2]) - mesh.vectorNz) index = temp1.argmin() sum_factor = mesh.vectorNz[index] wz = np.power(-mesh.vectorCCz + sum_factor + z0, -v) wz = wz / np.nanmax(wz) wz = wz**0.5 # allocate depth decay to all the cells tmp1 = (np.outer(np.ones(mesh.nCx), np.ones(mesh.nCy))).flatten('F') wz_depth = (np.outer(tmp1, wz)).flatten('F') wz_depth = actvMap.P.T * wz_depth # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wz_depth if "norm_p" and "norm_q" in list(input_dict.keys()): p, q = input_dict["norm_p"], input_dict["norm_q"] else: raise Exception("Missing norm values") norms = [p, q, q, q] reg.norms = [norms] if "alpha_s" in list(input_dict.keys()): alpha_s = input_dict["alpha_s"] else: raise Exception("Missing alpha_s") if "alpha_x" in list(input_dict.keys()): alpha_x = input_dict["alpha_x"] else: raise Exception("Missing alpha_x") if "alpha_y" in list(input_dict.keys()): alpha_y = input_dict["alpha_y"] else: raise Exception("Missing alpha_y") if "alpha_z" in list(input_dict.keys()): alpha_z = input_dict["alpha_z"] else: raise Exception("Missing alpha_z") reg.alpha_s = alpha_s reg.alpha_x = alpha_x reg.alpha_y = alpha_y reg.alpha_z = alpha_z # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = Utils.sdiag(1 / std) printers = [ IterationPrinters.iteration, IterationPrinters.beta, IterationPrinters.phi_d, IterationPrinters.phi_m, IterationPrinters.f, IterationPrinters.iterationCG, IterationPrinters.totalLS ] stoppers = [StoppingCriteria.iteration] if "lower_bound" and "upper_bound" in list(input_dict.keys()): lb = input_dict["lower_bound"] ub = input_dict["upper_bound"] else: raise Exception("Missing lower, upper bounds") # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=1000, lower=lb, upper=ub, maxIterLS=100, maxIterCG=2000, tolCG=1e-3, printers=printers, stoppers=stoppers) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e-1) IRLS = Directives.Update_IRLS(f_min_change=1e-3, maxIRLSiter=100) update_Jacobi = Directives.UpdatePreconditioner() save_output = Directives.SaveOutputEveryIteration_Single() inv = Inversion.BaseInversion( invProb, directiveList=[IRLS, update_Jacobi, betaest, save_output]) # Run the inversion m0 = np.ones(nC) * 1e-8 # Starting model mrec = inv.run(m0) # make directories (path) data_dir = os.path.join( work_dir, "Data-{}".format(datetime.now().strftime("%Y-%m-%d-%H-%M"))) os.mkdir(data_dir) data_dir += path_sep fig_dir = os.path.join( work_dir, "Figs-{}".format(datetime.now().strftime("%Y-%m-%d-%H-%M"))) os.mkdir(fig_dir) fig_dir += path_sep # save data files dpred = prob.fields(mrec) np.savetxt(data_dir + "data_predicted.txt", dpred) dnres = (dobs - dpred) / std np.savetxt(data_dir + "data_residual_nor.txt", dnres) model_dens = actvMap * mrec mesh.writeModelUBC(data_dir + "model_rec_dens.txt", model_dens) if plotIt: # dobs fig = plt.figure(figsize=(14, 14)) ax = plt.subplot() im = Utils.PlotUtils.plot2Ddata(xyzLoc, dobs, ax=ax, contourOpts={"cmap": "jet"}) ax.set_xlabel("Easting (m)", size=22) ax.set_ylabel("Northing (m)", size=22) ax.set_title("") ax.tick_params(labelsize=16) ax.ticklabel_format(useOffset=False, style="plain") ax.locator_params(nbins=10, axis="x") ax.set_title("Observed gravity gradient anomaly", size=22) plt.gca().set_aspect("equal", adjustable="box") pos = ax.get_position() cb_ax = fig.add_axes( [pos.x0 + 0.8, pos.y0 + 0.06, pos.width * 0.02, pos.height * 0.8]) cb = plt.colorbar(im[0], cax=cb_ax, orientation="vertical") cb.ax.tick_params(labelsize=16) cb.ax.set_title("E", size=22) plt.savefig(fig_dir + "plot_obs_grav.png", bbox_inches="tight", dpi=300) # dpred fig = plt.figure(figsize=(14, 14)) ax = plt.subplot() im = Utils.PlotUtils.plot2Ddata(xyzLoc, dpred, ax=ax, contourOpts={"cmap": "jet"}) ax.set_xlabel("Easting (m)", size=22) ax.set_ylabel("Northing (m)", size=22) ax.set_title("") ax.tick_params(labelsize=16) ax.ticklabel_format(useOffset=False, style="plain") ax.locator_params(nbins=10, axis="x") ax.set_title("Predicted gravity gradient anomaly", size=22) plt.gca().set_aspect("equal", adjustable='box') pos = ax.get_position() cb_ax = fig.add_axes( [pos.x0 + 0.8, pos.y0 + 0.06, pos.width * 0.02, pos.height * 0.8]) cb = plt.colorbar(im[0], cax=cb_ax, orientation="vertical") cb.ax.tick_params(labelsize=16) cb.ax.set_title("E", size=22) plt.savefig(fig_dir + "plot_pred_grav.png", bbox_inches="tight", dpi=300) # nor residual fig = plt.figure(figsize=(14, 14)) ax = plt.subplot() im = Utils.PlotUtils.plot2Ddata(xyzLoc, dnres, ax=ax, contourOpts={"cmap": "jet"}) ax.set_xlabel("Easting (m)", size=22) ax.set_ylabel("Northing (m)", size=22) ax.set_title("") ax.tick_params(labelsize=16) ax.ticklabel_format(useOffset=False, style="plain") ax.locator_params(nbins=10, axis="x") ax.set_title("Normalized residual", size=22) plt.gca().set_aspect("equal", adjustable="box") pos = ax.get_position() cb_ax = fig.add_axes( [pos.x0 + 0.8, pos.y0 + 0.06, pos.width * 0.02, pos.height * 0.8]) cb = plt.colorbar(im[0], cax=cb_ax, orientation="vertical") cb.ax.tick_params(labelsize=16) cb.ax.set_title("E", size=22) plt.savefig(fig_dir + "plot_residual_grav.png", bbox_inches="tight", dpi=300) if input_dict["example"] == "horse": # plot inverted model vmax, vmin = np.nanmax(model_dens), np.nanmin(model_dens) fig = plt.figure(figsize=(18, 6)) # Plot horizontal section of inverted grav model ax1 = plt.subplot(121) slicePosition = -2000 #meter in z direction sliceInd = int( round(np.searchsorted(mesh.vectorCCz, slicePosition))) mesh.plotSlice(model_dens, ax=ax1, normal="Z", ind=sliceInd, grid=False, clim=(vmin, vmax), pcolorOpts={"cmap": "jet"}) ax1.set_xlabel("Easting (m)", size=22) ax1.set_ylabel("Northing (m)", size=22) ax1.set_title("") ax1.set_title("(a), z={}m".format(slicePosition + 430), loc="left", size=22) ax1.tick_params(labelsize=16) ax1.ticklabel_format(useOffset=False, style="plain") ax1.locator_params(nbins=8, axis="x") ax1.set_aspect("equal", adjustable="box") pos1 = ax1.get_position() # Vertical section ax2 = plt.subplot(122) slicePosition = 4790800 #meter in y direction sliceInd = int( round(np.searchsorted(mesh.vectorCCy, slicePosition))) im = mesh.plotSlice(model_dens, ax=ax2, normal="Y", ind=sliceInd, grid=False, clim=(vmin, vmax), pcolorOpts={"cmap": "jet"}) ax2.set_xlabel("Easting (m)", size=22) ax2.set_ylabel("Depth (m)", size=22) ax2.set_title("") ax2.set_title("(b), y={}".format(slicePosition), loc="left", size=22) ax2.tick_params(labelsize=16) ax2.ticklabel_format(useOffset=False, style="plain") ax2.locator_params(nbins=8, axis="x") ax2.set_aspect("equal", adjustable="box") pos2 = ax2.get_position() pos2_new = [pos2.x0 + 0.02, pos1.y0, pos2.width, pos2.height] ax2.set_position(pos2_new) cb_ax = fig.add_axes([ pos2.x0 + 0.09, pos2.y0 + 0.35, pos2.width * 0.6, pos2.height * 0.1 ]) kwargs = {'format': '%.3f'} cb = plt.colorbar(im[0], cax=cb_ax, orientation="horizontal", ticks=np.linspace(vmin, vmax, 4), **kwargs) cb.ax.tick_params(labelsize=16) cb.set_label("Density (g/cc)", size=22) plt.savefig(fig_dir + "plot_model_dens.png", bbox_inches="tight", dpi=300) else: # plot inverted model vmax, vmin = np.nanmax(model_dens), 0 fig = plt.figure(figsize=(20, 8)) # Plot horizontal section of inverted grav model ax1 = plt.subplot(121) slicePosition = -375 #meter in z direction sliceInd = int( round(np.searchsorted(mesh.vectorCCz, slicePosition))) mesh.plotSlice(model_dens, ax=ax1, normal="Z", ind=sliceInd, grid=False, clim=(vmin, vmax), pcolorOpts={"cmap": "jet"}) circle = plt.Circle((1525, 1525), 275, color='white', linewidth=3, fill=False) ax1.add_patch(circle) ax1.set_xlabel("Easting (m)", size=24) ax1.set_ylabel("Northing (m)", size=24) ax1.set_title("") ax1.set_title("(a), z={}m".format(slicePosition), loc="left", size=24) ax1.tick_params(labelsize=24) ax1.ticklabel_format(useOffset=False, style="plain") ax1.locator_params(nbins=8, axis="x") ax1.set_aspect("equal", adjustable="box") pos1 = ax1.get_position() # Vertical section ax2 = plt.subplot(122) slicePosition = 1525 #meter in y direction sliceInd = int( round(np.searchsorted(mesh.vectorCCy, slicePosition))) im = mesh.plotSlice(model_dens, ax=ax2, normal="Y", ind=sliceInd, grid=False, clim=(vmin, vmax), pcolorOpts={"cmap": "jet"}) circle = plt.Circle((1525, -375), 275, color='white', linewidth=3, fill=False) ax2.add_patch(circle) ax2.set_xlabel("Easting (m)", size=24) ax2.set_ylabel("Depth (m)", size=24) ax2.set_title("") ax2.set_title("(b), y={}".format(slicePosition), loc="left", size=24) ax2.tick_params(labelsize=24) ax2.ticklabel_format(useOffset=False, style="plain") ax2.locator_params(nbins=8, axis="x") ax2.set_aspect("equal", adjustable="box") pos2 = ax2.get_position() pos2_new = [pos2.x0 + 0.02, pos1.y0, pos2.width, pos2.height] ax2.set_position(pos2_new) cb_ax = fig.add_axes([ pos2.x0 + 0.09, pos2.y0 + 0.35, pos2.width * 0.6, pos2.height * 0.1 ]) kwargs = {'format': '%.3f'} cb = plt.colorbar(im[0], cax=cb_ax, orientation="horizontal", ticks=np.linspace(vmin, vmax, 4), **kwargs) cb.ax.tick_params(labelsize=24) cb.set_label("Density (g/cc)", size=24) plt.savefig(fig_dir + "plot_model_dens.png", bbox_inches="tight", dpi=300) elapse = time() - init_t print("elapsed time: ", str(timedelta(seconds=elapse)))
def run(plotIt=False): O = np.r_[-1.2, -1.] D = np.r_[10., 10.] x = np.r_[0., 1.] y = np.r_[0., 1.] print('length:', StraightRay.lengthInCell(O, D, x, y, plotIt=plotIt)) O = np.r_[0, -1.] D = np.r_[1., 1.] * 1.5 print('length:', StraightRay.lengthInCell(O, D, x * 2, y * 2, plotIt=plotIt)) nC = 20 M = Mesh.TensorMesh([nC, nC]) y = np.linspace(0., 1., nC / 2) rlocs = np.c_[y * 0 + M.vectorCCx[-1], y] rx = StraightRay.Rx(rlocs, None) srcList = [ StraightRay.Src(loc=np.r_[M.vectorCCx[0], yi], rxList=[rx]) for yi in y ] survey = StraightRay.Survey(srcList) problem = StraightRay.Problem(M, slownessMap=Maps.IdentityMap(M)) problem.pair(survey) s = Utils.mkvc(Utils.ModelBuilder.randomModel(M.vnC)) + 1. survey.dobs = survey.dpred(s) survey.std = 0.01 # Create an optimization program reg = Regularization.Tikhonov(M) dmis = DataMisfit.l2_DataMisfit(survey) opt = Optimization.InexactGaussNewton(maxIter=40) opt.remember('xc') invProb = InvProblem.BaseInvProblem(dmis, reg, opt) beta = Directives.BetaSchedule() betaest = Directives.BetaEstimate_ByEig() inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest]) # Start the inversion with a model of zeros, and run the inversion m0 = np.ones(M.nC) * 1.5 mopt = inv.run(m0) if plotIt is True: fig, ax = plt.subplots(1, 2, figsize=(8, 4)) ax[1].plot(survey.dobs) ax[1].plot(survey.dpred(m0), 's') ax[1].plot(survey.dpred(mopt), 'o') ax[1].legend(['dobs', 'starting dpred', 'dpred']) M.plotImage(s, ax=ax[0]) survey.plot(ax=ax[0]) ax[0].set_title('survey') plt.tight_layout() if plotIt is True: fig, ax = plt.subplots(1, 3, figsize=(12, 4)) plt.colorbar(M.plotImage(m0, ax=ax[0])[0], ax=ax[0]) plt.colorbar(M.plotImage(mopt, ax=ax[1])[0], ax=ax[1]) plt.colorbar(M.plotImage(s, ax=ax[2])[0], ax=ax[2]) ax[0].set_title('Starting Model') ax[1].set_title('Recovered Model') ax[2].set_title('True Model') plt.tight_layout()
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)
def run(plotIt=True): # Create a mesh dx = 5. hxind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)] hyind = [(dx, 5, -1.3), (dx, 15), (dx, 5, 1.3)] hzind = [(dx, 5, -1.3), (dx, 7), (3.5, 1), (2, 5)] mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCC') # Get index of the center midx = int(mesh.nCx/2) midy = int(mesh.nCy/2) # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -np.exp((xx**2 + yy**2) / 75**2) + mesh.vectorNz[-1] # We would usually load a topofile topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Go from topo to actv cells actv = Utils.surface2ind_topo(mesh, topo, 'N') actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem], dtype=int) - 1 # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) nC = len(actv) # Create and array of observation points xr = np.linspace(-30., 30., 20) yr = np.linspace(-30., 30., 20) X, Y = np.meshgrid(xr, yr) # Move the observation points 5m above the topo Z = -np.exp((X**2 + Y**2) / 75**2) + mesh.vectorNz[-1] + 0.1 # Create a MAGsurvey rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseGrav.RxObs(rxLoc) srcField = PF.BaseGrav.SrcField([rxLoc]) survey = PF.BaseGrav.LinearSurvey(srcField) # We can now create a susceptibility model and generate data # Here a simple block in half-space model = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz)) model[(midx-5):(midx-1), (midy-2):(midy+2), -10:-6] = 0.5 model[(midx+1):(midx+5), (midy-2):(midy+2), -10:-6] = -0.5 model = Utils.mkvc(model) model = model[actv] # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) # Create reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Gravity.GravityIntegral(mesh, rhoMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data d = prob.fields(model) # Add noise and uncertainties # We add some random Gaussian noise (1nT) data = d + np.random.randn(len(d))*1e-3 wd = np.ones(len(data))*1e-3 # Assign flat uncertainties survey.dobs = data survey.std = wd survey.mtrue = model # Create sensitivity weights from our linear forward operator rxLoc = survey.srcField.rxList[0].locs wr = np.sum(prob.G**2., axis=0)**0.5 wr = (wr/np.max(wr)) # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wr reg.norms = [0, 1, 1, 1] # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = Utils.sdiag(1/wd) # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=100, lower=-1., upper=1., maxIterLS=20, maxIterCG=10, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) betaest = Directives.BetaEstimate_ByEig() # Here is where the norms are applied # Use pick a treshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS(f_min_change=1e-2, minGNiter=2) update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi]) # Run the inversion m0 = np.ones(nC)*1e-4 # Starting model mrec = inv.run(m0) if plotIt: # Here is the recovered susceptibility model ypanel = midx zpanel = -7 m_l2 = actvMap * invProb.l2model m_l2[m_l2 == -100] = np.nan m_lp = actvMap * mrec m_lp[m_lp == -100] = np.nan m_true = actvMap * model m_true[m_true == -100] = np.nan vmin, vmax = mrec.min(), mrec.max() # Plot the data PF.Gravity.plot_obs_2D(rxLoc, d=data) plt.figure() # Plot L2 model ax = plt.subplot(321) mesh.plotSlice(m_l2, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan l2-model.') plt.gca().set_aspect('equal') plt.ylabel('y') ax.xaxis.set_visible(False) plt.gca().set_aspect('equal', adjustable='box') # Vertica section ax = plt.subplot(322) mesh.plotSlice(m_l2, ax=ax, normal='Y', ind=midx, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W l2-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box') # Plot Lp model ax = plt.subplot(323) mesh.plotSlice(m_lp, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan lp-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('y') plt.gca().set_aspect('equal', adjustable='box') # Vertical section ax = plt.subplot(324) mesh.plotSlice(m_lp, ax=ax, normal='Y', ind=midx, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W lp-model.') plt.gca().set_aspect('equal') ax.xaxis.set_visible(False) plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box') # Plot True model ax = plt.subplot(325) mesh.plotSlice(m_true, ax=ax, normal='Z', ind=zpanel, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCy[ypanel], mesh.vectorCCy[ypanel]]), color='w') plt.title('Plan true model.') plt.gca().set_aspect('equal') plt.xlabel('x') plt.ylabel('y') plt.gca().set_aspect('equal', adjustable='box') # Vertical section ax = plt.subplot(326) mesh.plotSlice(m_true, ax=ax, normal='Y', ind=midx, grid=True, clim=(vmin, vmax)) plt.plot(([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), ([mesh.vectorCCz[zpanel], mesh.vectorCCz[zpanel]]), color='w') plt.title('E-W true model.') plt.gca().set_aspect('equal') plt.xlabel('x') plt.ylabel('z') plt.gca().set_aspect('equal', adjustable='box')
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
inversion_type=input_dict["inversion_type"], chifact_target=1.) ) directiveList.append( Directives.Update_IRLS( f_min_change=1e-4, maxIRLSiter=max_irls_iterations, minGNiter=1, beta_tol=0.5, prctile=90, floorEpsEnforced=True, coolingRate=1, coolEps_q=True, coolEpsFact=1.2, betaSearch=False ) ) if initial_beta is None: directiveList.append(Directives.BetaEstimate_ByEig(beta0_ratio=1e+1)) directiveList.append(Directives.UpdatePreconditioner()) directiveList.append( Directives.SaveUBCModelEveryIteration( mapping=activeCellsMap * model_map, mesh=mesh, fileName=outDir + input_dict["inversion_type"], vector=input_dict["inversion_type"][0:3] == 'mvi' ) ) directiveList.append( Directives.SaveUBCPredictedEveryIteration( survey=survey,
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, cleanAfterRun=True): # Start by downloading files from the remote repository # directory where the downloaded files are url = "https://storage.googleapis.com/simpeg/Chile_GRAV_4_Miller/Chile_GRAV_4_Miller.tar.gz" downloads = download(url, overwrite=True) basePath = downloads.split(".")[0] # unzip the tarfile tar = tarfile.open(downloads, "r") tar.extractall() tar.close() input_file = basePath + os.path.sep + 'LdM_input_file.inp' # %% User input # Plotting parameters, max and min densities in g/cc vmin = -0.6 vmax = 0.6 # weight exponent for default weighting wgtexp = 3. # %% # Read in the input file which included all parameters at once # (mesh, topo, model, survey, inv param, etc.) driver = PF.GravityDriver.GravityDriver_Inv(input_file) # %% # Now we need to create the survey and model information. # Access the mesh and survey information mesh = driver.mesh survey = driver.survey # define gravity survey locations rxLoc = survey.srcField.rxList[0].locs # define gravity data and errors d = survey.dobs wd = survey.std # Get the active cells active = driver.activeCells nC = len(active) # Number of active cells # Create active map to go from reduce set to full activeMap = Maps.InjectActiveCells(mesh, active, -100) # Create static map static = driver.staticCells dynamic = driver.dynamicCells staticCells = Maps.InjectActiveCells(None, dynamic, driver.m0[static], nC=nC) mstart = driver.m0[dynamic] # Get index of the center midx = int(mesh.nCx / 2) # %% # Now that we have a model and a survey we can build the linear system ... # Create the forward model operator prob = PF.Gravity.GravityIntegral(mesh, rhoMap=staticCells, actInd=active) prob.solverOpts['accuracyTol'] = 1e-4 # Pair the survey and problem survey.pair(prob) # Apply depth weighting wr = PF.Magnetics.get_dist_wgt(mesh, rxLoc, active, wgtexp, np.min(mesh.hx) / 4.) wr = wr**2. # %% Create inversion objects reg = Regularization.Sparse(mesh, indActive=active, mapping=staticCells, gradientType='total') reg.mref = driver.mref[dynamic] reg.cell_weights = wr * mesh.vol[active] reg.norms = np.c_[0., 1., 1., 1.] # reg.norms = driver.lpnorms # Specify how the optimization will proceed opt = Optimization.ProjectedGNCG(maxIter=20, lower=driver.bounds[0], upper=driver.bounds[1], maxIterLS=10, maxIterCG=20, tolCG=1e-3) # Define misfit function (obs-calc) dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1. / wd # 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(beta0_ratio=1e-2) # IRLS sets up the Lp inversion problem # Set the eps parameter parameter in Line 11 of the # input file based on the distribution of model (DEFAULT = 95th %ile) IRLS = Directives.Update_IRLS(f_min_change=1e-4, maxIRLSiter=40, beta_tol=5e-1) # Preconditioning refreshing for each IRLS iteration update_Jacobi = Directives.UpdatePreconditioner() # Create combined the L2 and Lp problem inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, update_Jacobi, betaest]) # %% # Run L2 and Lp inversion mrec = inv.run(mstart) if cleanAfterRun: os.remove(downloads) shutil.rmtree(basePath) # %% if plotIt: # Plot observed data PF.Magnetics.plot_obs_2D(rxLoc, d, 'Observed Data') # %% # Write output model and data files and print misft stats. # reconstructing l2 model mesh with air cells and active dynamic cells L2out = activeMap * invProb.l2model # reconstructing lp model mesh with air cells and active dynamic cells Lpout = activeMap * mrec # %% # Plot out sections and histograms of the smooth l2 model. # The ind= parameter is the slice of the model from top down. yslice = midx + 1 L2out[L2out == -100] = np.nan # set "air" to nan plt.figure(figsize=(10, 7)) plt.suptitle('Smooth Inversion: Depth weight = ' + str(wgtexp)) ax = plt.subplot(221) dat1 = mesh.plotSlice(L2out, ax=ax, normal='Z', ind=-16, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.plot(np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]), c='gray', linestyle='--') plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color='k', s=1) plt.title('Z: ' + str(mesh.vectorCCz[-16]) + ' m') plt.xlabel('Easting (m)') plt.ylabel('Northing (m)') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat1[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4)) cb.set_label('Density (g/cc$^3$)') ax = plt.subplot(222) dat = mesh.plotSlice(L2out, ax=ax, normal='Z', ind=-27, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.plot(np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]), c='gray', linestyle='--') plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color='k', s=1) plt.title('Z: ' + str(mesh.vectorCCz[-27]) + ' m') plt.xlabel('Easting (m)') plt.ylabel('Northing (m)') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat1[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4)) cb.set_label('Density (g/cc$^3$)') ax = plt.subplot(212) mesh.plotSlice(L2out, ax=ax, normal='Y', ind=yslice, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.title('Cross Section') plt.xlabel('Easting(m)') plt.ylabel('Elevation') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat1[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4), cmap='bwr') cb.set_label('Density (g/cc$^3$)') # %% # Make plots of Lp model yslice = midx + 1 Lpout[Lpout == -100] = np.nan # set "air" to nan plt.figure(figsize=(10, 7)) plt.suptitle('Compact Inversion: Depth weight = ' + str(wgtexp) + ': $\epsilon_p$ = ' + str(round(reg.eps_p, 1)) + ': $\epsilon_q$ = ' + str(round(reg.eps_q, 2))) ax = plt.subplot(221) dat = mesh.plotSlice(Lpout, ax=ax, normal='Z', ind=-16, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.plot(np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]), c='gray', linestyle='--') plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color='k', s=1) plt.title('Z: ' + str(mesh.vectorCCz[-16]) + ' m') plt.xlabel('Easting (m)') plt.ylabel('Northing (m)') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4)) cb.set_label('Density (g/cc$^3$)') ax = plt.subplot(222) dat = mesh.plotSlice(Lpout, ax=ax, normal='Z', ind=-27, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.plot(np.array([mesh.vectorCCx[0], mesh.vectorCCx[-1]]), np.array([mesh.vectorCCy[yslice], mesh.vectorCCy[yslice]]), c='gray', linestyle='--') plt.scatter(rxLoc[0:, 0], rxLoc[0:, 1], color='k', s=1) plt.title('Z: ' + str(mesh.vectorCCz[-27]) + ' m') plt.xlabel('Easting (m)') plt.ylabel('Northing (m)') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4)) cb.set_label('Density (g/cc$^3$)') ax = plt.subplot(212) dat = mesh.plotSlice(Lpout, ax=ax, normal='Y', ind=yslice, clim=(vmin, vmax), pcolorOpts={'cmap': 'bwr'}) plt.title('Cross Section') plt.xlabel('Easting (m)') plt.ylabel('Elevation (m)') plt.gca().set_aspect('equal', adjustable='box') cb = plt.colorbar(dat[0], orientation="vertical", ticks=np.linspace(vmin, vmax, 4)) cb.set_label('Density (g/cc$^3$)')
def setUp(self): # We will assume a vertical inducing field H0 = (50000., 90., 0.) # The magnetization is set along a different direction (induced + remanence) M = np.array([90., 0.]) # Block with an effective susceptibility chi_e = 0.05 # Create grid of points for topography # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(np.linspace(-200, 200, 50), np.linspace(-200, 200, 50)) b = 100 A = 50 zz = A * np.exp(-0.5 * ((xx / b)**2. + (yy / b)**2.)) topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Create and array of observation points xr = np.linspace(-100., 100., 20) yr = np.linspace(-100., 100., 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2. + (Y / b)**2.)) + 5 # Create a MAGsurvey rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] Rx = PF.BaseMag.RxObs(rxLoc) srcField = PF.BaseMag.SrcField([Rx], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [4, 4, 2] # Get extent of points limx = np.r_[topo[:, 0].max(), topo[:, 0].min()] limy = np.r_[topo[:, 1].max(), topo[:, 1].min()] limz = np.r_[topo[:, 2].max(), topo[:, 2].min()] # Get center of the mesh midX = np.mean(limx) midY = np.mean(limy) midZ = np.mean(limz) nCx = int(limx[0] - limx[1]) / h[0] nCy = int(limy[0] - limy[1]) / h[1] nCz = int(limz[0] - limz[1] + int(np.min(np.r_[nCx, nCy]) / 3)) / h[2] # Figure out full extent required from input extent = np.max(np.r_[nCx * h[0] + padDist[0, :].sum(), nCy * h[1] + padDist[1, :].sum(), nCz * h[2] + padDist[2, :].sum()]) maxLevel = int(np.log2(extent / h[0])) + 1 # Number of cells at the small octree level # For now equal in 3D nCx, nCy, nCz = 2**(maxLevel), 2**(maxLevel), 2**(maxLevel) # Define the mesh and origin mesh = Mesh.TreeMesh( [np.ones(nCx) * h[0], np.ones(nCx) * h[1], np.ones(nCx) * h[2]]) # Set origin mesh.x0 = np.r_[-nCx * h[0] / 2. + midX, -nCy * h[1] / 2. + midY, -nCz * h[2] / 2. + midZ] # Refine the mesh around topography # Get extent of points F = NearestNDInterpolator(topo[:, :2], topo[:, 2]) zOffset = 0 # Cycle through the first 3 octree levels for ii in range(3): dx = mesh.hx.min() * 2**ii nCx = int((limx[0] - limx[1]) / dx) nCy = int((limy[0] - limy[1]) / dx) # Create a grid at the octree level in xy CCx, CCy = np.meshgrid(np.linspace(limx[1], limx[0], nCx), np.linspace(limy[1], limy[0], nCy)) z = F(mkvc(CCx), mkvc(CCy)) # level means number of layers in current OcTree level for level in range(int(nCpad[ii])): mesh.insert_cells(np.c_[mkvc(CCx), mkvc(CCy), z - zOffset], np.ones_like(z) * maxLevel - ii, finalize=False) zOffset += dx mesh.finalize() # Define an active cells from topo actv = Utils.surface2ind_topo(mesh, topo) nC = int(actv.sum()) # Convert the inclination declination to vector in Cartesian M_xyz = Utils.matutils.dip_azimuth2cartesian( np.ones(nC) * M[0], np.ones(nC) * M[1]) # Get the indicies of the magnetized block ind = Utils.ModelBuilder.getIndicesBlock( np.r_[-20, -20, -10], np.r_[20, 20, 25], mesh.gridCC, )[0] # Assign magnetization value, inducing field strength will # be applied in by the :class:`SimPEG.PF.Magnetics` problem model = np.zeros(mesh.nC) model[ind] = chi_e # Remove air cells self.model = model[actv] # Create active map to go from reduce set to full self.actvPlot = Maps.InjectActiveCells(mesh, actv, np.nan) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, M=M_xyz, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute some data and add some random noise data = prob.fields(self.model) # Split the data in components nD = rxLoc.shape[0] std = 5 # nT data += np.random.randn(nD) * std wd = np.ones(nD) * std # Assigne data and uncertainties to the survey survey.dobs = data survey.std = wd ###################################################################### # Equivalent Source # Get the active cells for equivalent source is the top only surf = Utils.modelutils.surface_layer_index(mesh, topo) # Get the layer of cells directyl below topo nC = np.count_nonzero(surf) # Number of active cells # Create active map to go from reduce set to full surfMap = Maps.InjectActiveCells(mesh, surf, np.nan) # Create identity map idenMap = Maps.IdentityMap(nP=nC) # Create static map prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=surf, parallelized=False, equiSourceLayer=True) prob.solverOpts['accuracyTol'] = 1e-4 # Pair the survey and problem if survey.ispaired: survey.unpair() survey.pair(prob) # Create a regularization function, in this case l2l2 reg = Regularization.Sparse(mesh, indActive=surf, mapping=Maps.IdentityMap(nP=nC), scaledIRLS=False) reg.mref = np.zeros(nC) # Specify how the optimization will proceed, # set susceptibility bounds to inf opt = Optimization.ProjectedGNCG(maxIter=20, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=20, tolCG=1e-3) # 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() # Target misfit to stop the inversion, # try to fit as much as possible of the signal, # we don't want to lose anything IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, beta_tol=1e-1) update_Jacobi = Directives.UpdatePreconditioner() # Put all the parts together inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_Jacobi]) # Run the equivalent source inversion mstart = np.ones(nC) * 1e-4 mrec = inv.run(mstart) # Won't store the sensitivity and output 'xyz' data. prob.forwardOnly = True prob.rx_type = 'xyz' prob._G = None prob.modelType = 'amplitude' prob.model = mrec pred = prob.fields(mrec) bx = pred[:nD] by = pred[nD:2 * nD] bz = pred[2 * nD:] bAmp = (bx**2. + by**2. + bz**2.)**0.5 # AMPLITUDE INVERSION # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) nC = int(actv.sum()) # Create identity map idenMap = Maps.IdentityMap(nP=nC) self.mstart = np.ones(nC) * 1e-4 # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv, modelType='amplitude', rx_type='xyz') prob.model = self.mstart # Change the survey to xyz components surveyAmp = PF.BaseMag.LinearSurvey(survey.srcField) # Pair the survey and problem surveyAmp.pair(prob) # Create a regularization function, in this case l2l2 wr = np.sum(prob.G**2., axis=0)**0.5 wr = (wr / np.max(wr)) # Re-set the observations to |B| surveyAmp.dobs = bAmp surveyAmp.std = wd # Create a sparse regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.mref = np.zeros(nC) reg.cell_weights = wr # Data misfit function dmis = DataMisfit.l2_DataMisfit(surveyAmp) dmis.W = 1. / surveyAmp.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=30, lower=0., upper=1., maxIterLS=20, maxIterCG=20, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # Here is the list of directives betaest = Directives.BetaEstimate_ByEig() # Specify the sparse norms IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, coolingRate=1, betaSearch=False) # The sensitivity weights are update between each iteration. update_SensWeight = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner(threshold=1 - 3) # Put all together self.inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_SensWeight, update_Jacobi]) self.mesh = mesh
def setUp(self): np.random.seed(0) # Define the inducing field parameter H0 = (50000, 90, 0) # Create a mesh dx = 5. hxind = [(dx, 5, -1.3), (dx, 5), (dx, 5, 1.3)] hyind = [(dx, 5, -1.3), (dx, 5), (dx, 5, 1.3)] hzind = [(dx, 5, -1.3), (dx, 6)] mesh = Mesh.TensorMesh([hxind, hyind, hzind], 'CCC') # Get index of the center midx = int(mesh.nCx / 2) midy = int(mesh.nCy / 2) # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -np.exp((xx**2 + yy**2) / 75**2) + mesh.vectorNz[-1] # Go from topo to actv cells topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] actv = Utils.surface2ind_topo(mesh, topo, 'N') actv = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem], dtype=int) - 1 # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) nC = len(actv) # Create and array of observation points xr = np.linspace(-20., 20., 20) yr = np.linspace(-20., 20., 20) X, Y = np.meshgrid(xr, yr) # Move the observation points 5m above the topo Z = -np.exp((X**2 + Y**2) / 75**2) + mesh.vectorNz[-1] + 5. # Create a MAGsurvey rxLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseMag.RxObs(rxLoc) srcField = PF.BaseMag.SrcField([rxLoc], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # We can now create a susceptibility model and generate data # Here a simple block in half-space model = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz)) model[(midx - 2):(midx + 2), (midy - 2):(midy + 2), -6:-2] = 0.02 model = Utils.mkvc(model) self.model = model[actv] # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, -100) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(mesh, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data d = prob.fields(self.model) # Add noise and uncertainties (1nT) data = d + np.random.randn(len(d)) wd = np.ones(len(data)) * 1. survey.dobs = data survey.std = wd # Create sensitivity weights from our linear forward operator wr = np.sum(prob.G**2., axis=0)**0.5 wr = (wr / np.max(wr)) # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wr reg.norms = np.c_[0, 0, 0, 0] reg.gradientType = 'component' # reg.eps_p, reg.eps_q = 1e-3, 1e-3 # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1 / wd # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=100, lower=0., upper=1., maxIterLS=20, maxIterCG=10, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) betaest = Directives.BetaEstimate_ByEig() # Here is where the norms are applied IRLS = Directives.Update_IRLS(f_min_change=1e-4, minGNiter=1) update_Jacobi = Directives.UpdatePreconditioner() self.inv = Inversion.BaseInversion( invProb, directiveList=[IRLS, betaest, update_Jacobi])
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
survey.dpred(mtrue) survey.makeSyntheticData(mtrue, std=0.05, force=True) print '# of data: ', survey.dobs.shape #Simple Inversion regmesh = mesh m0 = (-5.) * np.ones(mapping.nP) dmis = DataMisfit.l2_DataMisfit(survey) reg = Regularization.Tikhonov(regmesh) #,mapping = mapping)#,indActive=actind) reg.mref = m0 opt = Optimization.InexactGaussNewton(maxIter=20, tolX=1e-6) opt.remember('xc') invProb = InvProblem.BaseInvProblem(dmis, reg, opt) beta = Directives.BetaEstimate_ByEig(beta0=10., beta0_ratio=1e0) reg.alpha_s = 1e-2 #beta = 0. #invProb.beta = beta betaSched = Directives.BetaSchedule(coolingFactor=5, coolingRate=2) #sav0 = Directives.SaveEveryIteration() #sav1 = Directives.SaveModelEveryIteration() sav2 = Directives.SaveOutputDictEveryIteration() inv = Inversion.BaseInversion(invProb, directiveList=[sav2, beta, betaSched]) #sav0,sav1, mtest = np.load('../Update_W_each_3it_5s_rademacher/finalresult.npy') print "check misfit with W: ", dmis.eval(mtest) / survey.nD mm = meshCore.plotImage(mtest[actind]) plt.colorbar(mm[0]) plt.show()
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()
# Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1. / survey.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=30, lower=-10, upper=10., maxIterLS=20, maxIterCG=20, tolCG=1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # A list of directive to control the inverson betaest = Directives.BetaEstimate_ByEig() # Here is where the norms are applied # Use pick a treshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS(f_min_change=1e-3, maxIRLSiter=0, beta_tol=5e-1) # Pre-conditioner update_Jacobi = Directives.UpdatePreconditioner() inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, update_Jacobi, betaest]) # Run the inversion m0 = np.ones(3 * nC) * 1e-4 # Starting model mrec_MVIC = inv.run(m0)
def setUp(self): # We will assume a vertical inducing field H0 = (50000., 90., 0.) # The magnetization is set along a different direction (induced + remanence) M = np.array([90., 0.]) # Block with an effective susceptibility chi_e = 0.05 # Create grid of points for topography # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(np.linspace(-200, 200, 50), np.linspace(-200, 200, 50)) b = 100 A = 50 zz = A * np.exp(-0.5 * ((xx / b)**2. + (yy / b)**2.)) topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Create and array of observation points xr = np.linspace(-100., 100., 20) yr = np.linspace(-100., 100., 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2. + (Y / b)**2.)) + 5 # Create a MAGsurvey xyzLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] Rx = PF.BaseMag.RxObs(xyzLoc) srcField = PF.BaseMag.SrcField([Rx], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [4, 4, 2] self.mesh = meshutils.mesh_builder_xyz( xyzLoc, h, padding_distance=padDist, mesh_type='TREE', ) self.mesh = meshutils.refine_tree_xyz( self.mesh, topo, method='surface', octree_levels=nCpad, octree_levels_padding=nCpad, finalize=True, ) # Define an active cells from topo actv = Utils.surface2ind_topo(self.mesh, topo) nC = int(actv.sum()) # Convert the inclination declination to vector in Cartesian M_xyz = Utils.matutils.dip_azimuth2cartesian( np.ones(nC) * M[0], np.ones(nC) * M[1]) # Get the indicies of the magnetized block ind = Utils.ModelBuilder.getIndicesBlock( np.r_[-20, -20, -15], np.r_[20, 20, 20], self.mesh.gridCC, )[0] # Assign magnetization value, inducing field strength will # be applied in by the :class:`SimPEG.PF.Magnetics` problem model = np.zeros(self.mesh.nC) model[ind] = chi_e # Remove air cells self.model = model[actv] # Create active map to go from reduce set to full self.actvPlot = Maps.InjectActiveCells(self.mesh, actv, np.nan) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(self.mesh, M=M_xyz, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute some data and add some random noise data = prob.fields(self.model) # Split the data in components nD = xyzLoc.shape[0] std = 5 # nT data += np.random.randn(nD) * std wd = np.ones(nD) * std # Assigne data and uncertainties to the survey survey.dobs = data survey.std = wd ###################################################################### # Equivalent Source # Get the active cells for equivalent source is the top only surf = Utils.modelutils.surface_layer_index(self.mesh, topo) # Get the layer of cells directyl below topo nC = np.count_nonzero(surf) # Number of active cells # Create active map to go from reduce set to full surfMap = Maps.InjectActiveCells(self.mesh, surf, np.nan) # Create identity map idenMap = Maps.IdentityMap(nP=nC) # Create static map prob = PF.Magnetics.MagneticIntegral(self.mesh, chiMap=idenMap, actInd=surf, parallelized=False, equiSourceLayer=True) prob.solverOpts['accuracyTol'] = 1e-4 # Pair the survey and problem if survey.ispaired: survey.unpair() survey.pair(prob) # Create a regularization function, in this case l2l2 reg = Regularization.Sparse(self.mesh, indActive=surf, mapping=Maps.IdentityMap(nP=nC), scaledIRLS=False) reg.mref = np.zeros(nC) # Specify how the optimization will proceed, # set susceptibility bounds to inf opt = Optimization.ProjectedGNCG(maxIter=20, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=20, tolCG=1e-3) # 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() # Target misfit to stop the inversion, # try to fit as much as possible of the signal, # we don't want to lose anything IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, beta_tol=1e-1) update_Jacobi = Directives.UpdatePreconditioner() # Put all the parts together inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_Jacobi]) # Run the equivalent source inversion mstart = np.ones(nC) * 1e-4 mrec = inv.run(mstart) # Won't store the sensitivity and output 'xyz' data. prob.forwardOnly = True prob.rx_type = 'xyz' prob._G = None prob.modelType = 'amplitude' prob.model = mrec pred = prob.fields(mrec) bx = pred[:nD] by = pred[nD:2 * nD] bz = pred[2 * nD:] bAmp = (bx**2. + by**2. + bz**2.)**0.5 # AMPLITUDE INVERSION # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(self.mesh, actv, -100) nC = int(actv.sum()) # Create identity map idenMap = Maps.IdentityMap(nP=nC) self.mstart = np.ones(nC) * 1e-4 # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(self.mesh, chiMap=idenMap, actInd=actv, modelType='amplitude', rx_type='xyz') prob.model = self.mstart # Change the survey to xyz components surveyAmp = PF.BaseMag.LinearSurvey(survey.srcField) # Pair the survey and problem surveyAmp.pair(prob) # Create a regularization function, in this case l2l2 wr = np.sum(prob.G**2., axis=0)**0.5 wr /= np.max(wr) # Re-set the observations to |B| surveyAmp.dobs = bAmp surveyAmp.std = wd # Create a sparse regularization reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.mref = np.zeros(nC) reg.cell_weights = wr # Data misfit function dmis = DataMisfit.l2_DataMisfit(surveyAmp) dmis.W = 1. / surveyAmp.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=30, lower=0., upper=1., maxIterLS=20, maxIterCG=20, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # Here is the list of directives betaest = Directives.BetaEstimate_ByEig() # Specify the sparse norms IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, coolingRate=1, betaSearch=False) # The sensitivity weights are update between each iteration. update_SensWeight = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner() # Put all together self.inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_SensWeight, update_Jacobi])