def activeCells(self): if getattr(self, "_activeCells", None) is None: if getattr(self, "topofile", None) is not None: topo = np.genfromtxt(self.basePath + self.topofile, skip_header=1) # Find the active cells active = utils.surface2ind_topo(self.mesh, topo, "N") elif isinstance(self._staticInput, float): active = self.m0 != self._staticInput else: # Read from file active cells with 0:air, 1:dynamic, -1 static active = self.activeModel != 0 inds = np.where(active)[0] self._activeCells = inds # Reduce m0 to active space if len(self.m0) > len(self._activeCells): self._m0 = self.m0[self._activeCells] return self._activeCells
def test_Tile(self): """ Test for TileMap """ rxLocs = np.random.randn(3, 3) * 20 h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 local_meshes = [] for ii in range(rxLocs.shape[0]): local_mesh = mesh_builder_xyz(rxLocs, h, padding_distance=padDist, mesh_type="tree") local_mesh = refine_tree_xyz( local_mesh, rxLocs[ii, :].reshape((1, -1)), method="radial", octree_levels=[1], finalize=True, ) local_meshes.append(local_mesh) mesh = mesh_builder_xyz(rxLocs, h, padding_distance=padDist, mesh_type="tree") # This garantees that the local meshes are always coarser or equal for local_mesh in local_meshes: mesh.insert_cells( local_mesh.gridCC, local_mesh.cell_levels_by_index(np.arange(local_mesh.nC)), finalize=False, ) mesh.finalize() # Define an active cells from topo activeCells = utils.surface2ind_topo(mesh, rxLocs) model = np.random.randn(int(activeCells.sum())) total_mass = (model * mesh.vol[activeCells]).sum() for local_mesh in local_meshes: tile_map = maps.TileMap( mesh, activeCells, local_mesh, ) local_mass = ((tile_map * model) * local_mesh.vol[tile_map.local_active]).sum() self.assertTrue((local_mass - total_mass) / total_mass < 1e-8)
def test_surface2ind_topo(self): file_url = ( "https://storage.googleapis.com/simpeg/tests/utils/vancouver_topo.xyz" ) file2load = download(file_url) vancouver_topo = np.loadtxt(file2load) mesh_topo = discretize.TensorMesh( [[(500.0, 24)], [(500.0, 20)], [(10.0, 30)]], x0="CCC") indtopoCC = surface2ind_topo(mesh_topo, vancouver_topo, gridLoc="CC", method="nearest") indtopoN = surface2ind_topo(mesh_topo, vancouver_topo, gridLoc="N", method="nearest") assert len(np.where(indtopoCC)[0]) == 8729 assert len(np.where(indtopoN)[0]) == 8212
h, padding_distance=padDist, depth_core=100, mesh_type="tree") # This garantees that the local meshes are always coarser or equal for local_mesh in local_meshes: mesh.insert_cells( local_mesh.gridCC, local_mesh.cell_levels_by_index(np.arange(local_mesh.nC)), finalize=False, ) mesh.finalize() # Define an active cells from topo activeCells = utils.surface2ind_topo(mesh, topo) nC = int(activeCells.sum()) # We can now create a density model and generate data # Here a simple block in half-space # Get the indices of the magnetized block model = np.zeros(mesh.nC) ind = utils.ModelBuilder.getIndicesBlock( np.r_[-10, -10, -30], np.r_[10, 10, -10], mesh.gridCC, )[0] # Assign magnetization values model[ind] = 0.3
def setUp(self): # We will assume a vertical inducing field H0 = (50000.0, 90.0, 0.0) # The magnetization is set along a different direction (induced + remanence) M = np.array([45.0, 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.0 + (yy / b)**2.0)) topo = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)] # Create an array of observation points xr = np.linspace(-100.0, 100.0, 20) yr = np.linspace(-100.0, 100.0, 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 10 # Create a MAGsurvey rxLoc = np.c_[mkvc(X.T), mkvc(Y.T), mkvc(Z.T)] rxList = magnetics.receivers.Point(rxLoc) srcField = magnetics.sources.SourceField(receiver_list=[rxList], parameters=H0) survey = magnetics.survey.Survey(srcField) ############################################################################### # Inversion Mesh # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 mesh = mesh_builder_xyz(rxLoc, h, padding_distance=padDist, depth_core=100, mesh_type="tree") mesh = refine_tree_xyz(mesh, topo, method="surface", octree_levels=[4, 4], finalize=True) # 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.mat_utils.dip_azimuth2cartesian( np.ones(nC) * M[0], np.ones(nC) * M[1]) # Get the indicies of the magnetized block ind = utils.model_builder.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 model = model[actv] # Creat reduced identity map idenMap = maps.IdentityMap(nP=nC) # Create the forward model operator simulation = magnetics.Simulation3DIntegral( survey=survey, mesh=mesh, chiMap=idenMap, actInd=actv, store_sensitivities="forward_only", ) simulation.M = M_xyz # Compute some data and add some random noise synthetic_data = simulation.dpred(model) # Split the data in components nD = rxLoc.shape[0] std = 5 # nT synthetic_data += np.random.randn(nD) * std wd = np.ones(nD) * std # Assigne data and uncertainties to the survey data_object = data.Data(survey, dobs=synthetic_data, noise_floor=wd) ###################################################################### # Equivalent Source # Get the active cells for equivalent source is the top only surf = utils.model_utils.surface_layer_index(mesh, topo) nC = np.count_nonzero(surf) # Number of active cells mstart = np.ones(nC) * 1e-4 # 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 simulation = magnetics.simulation.Simulation3DIntegral( mesh=mesh, survey=survey, chiMap=idenMap, actInd=surf, store_sensitivities="ram", ) simulation.model = mstart # Create a regularization function, in this case l2l2 reg = regularization.Sparse(mesh, indActive=surf, mapping=maps.IdentityMap(nP=nC), alpha_z=0) reg.mref = np.zeros(nC) # Specify how the optimization will proceed, set susceptibility bounds to inf opt = optimization.ProjectedGNCG( maxIter=10, lower=-np.inf, upper=np.inf, maxIterLS=5, maxIterCG=5, tolCG=1e-3, ) # Define misfit function (obs-calc) dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_object) # Create the default L2 inverse problem from the above objects invProb = inverse_problem.BaseInvProblem(dmis, reg, opt) # Specify how the initial beta is found betaest = directives.BetaEstimate_ByEig(beta0_ratio=2) # 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, max_irls_iterations=5) update_Jacobi = directives.UpdatePreconditioner() # Put all the parts together inv = inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_Jacobi]) # Run the equivalent source inversion print("Solving for Equivalent Source") mrec = inv.run(mstart) ######################################################## # Forward Amplitude Data # ---------------------- # # Now that we have an equialent source layer, we can forward model alh three # components of the field and add them up: :math:`|B| = \sqrt{( Bx^2 + Bx^2 + Bx^2 )}` # rxList = magnetics.receivers.Point(rxLoc, components=["bx", "by", "bz"]) srcField = magnetics.sources.SourceField(receiver_list=[rxList], parameters=H0) surveyAmp = magnetics.survey.Survey(srcField) simulation = magnetics.simulation.Simulation3DIntegral( mesh=mesh, survey=surveyAmp, chiMap=idenMap, actInd=surf, is_amplitude_data=True, store_sensitivities="forward_only", ) bAmp = simulation.fields(mrec) ###################################################################### # Amplitude Inversion # ------------------- # # Now that we have amplitude data, we can invert for an effective # susceptibility. This is a non-linear 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) mstart = np.ones(nC) * 1e-4 # Create the forward model operator simulation = magnetics.simulation.Simulation3DIntegral( survey=surveyAmp, mesh=mesh, chiMap=idenMap, actInd=actv, is_amplitude_data=True, ) data_obj = data.Data(survey, dobs=bAmp, noise_floor=wd) # Create a sparse regularization reg = regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[1, 0, 0, 0] reg.mref = np.zeros(nC) # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_obj) # Add directives to the inversion opt = optimization.ProjectedGNCG(maxIter=10, lower=0.0, upper=1.0, maxIterLS=5, maxIterCG=5, tolCG=1e-3) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt) # Here is the list of directives betaest = directives.BetaEstimate_ByEig(beta0_ratio=1) # Specify the sparse norms IRLS = directives.Update_IRLS( max_irls_iterations=5, f_min_change=1e-3, minGNiter=1, coolingRate=1, beta_search=False, ) # Special directive specific to the mag amplitude problem. 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=[update_SensWeight, betaest, IRLS, update_Jacobi]) self.mstart = mstart self.model = model self.sim = simulation
# Finalize the mesh mesh.finalize() ####################################################### # Project Electrodes to Discretized Topography # -------------------------------------------- # # It is important that electrodes are not modeled as being in the air. Even if the # electrodes are properly located along surface topography, they may lie above # the discretized topography. This step is carried out to ensure all electrodes # lie on the discretized surface. # # Find cells that lie below surface topography ind_active = surface2ind_topo(mesh, topo_xyz) # Extract survey from data object dc_survey = dc_data.survey ip_survey = ip_data.survey # Shift electrodes to the surface of discretized topography dc_survey.drape_electrodes_on_topography(mesh, ind_active, option="top") ip_survey.drape_electrodes_on_topography(mesh, ind_active, option="top") # Reset survey in data object dc_data.survey = dc_survey ip_data.survey = ip_survey ################################################################# # Starting/Reference Model and Mapping on OcTree Mesh
def run(plotIt=True, survey_type="dipole-dipole", p=0.0, qx=2.0, qz=2.0): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0.0, 200.0 ymin, ymax = 0.0, 0.0 zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey = IO.from_abmn_locations_to_survey( survey.locations_a, survey.locations_b, survey.locations_m, survey.locations_n, survey_type, data_dc_type="volt", ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() topo, mesh1D = genTopography(mesh, -10, 0, its=100) actind = utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo]) survey.drape_electrodes_on_topography(mesh, actind, option="top") # Build a conductivity model blk_inds_c = utils.model_builder.getIndicesSphere(np.r_[60.0, -25.0], 12.5, mesh.gridCC) blk_inds_r = utils.model_builder.getIndicesSphere(np.r_[140.0, -25.0], 12.5, mesh.gridCC) layer_inds = mesh.gridCC[:, 1] > -5.0 sigma = np.ones(mesh.nC) * 1.0 / 100.0 sigma[blk_inds_c] = 1.0 / 10.0 sigma[blk_inds_r] = 1.0 / 1000.0 sigma[~actind] = 1.0 / 1e8 rho = 1.0 / 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.Simulation2DNodal(mesh, survey=survey, rhoMap=mapping, storeJ=True, Solver=Solver, verbose=True) # Make synthetic DC data with 5% Gaussian noise data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True) IO.data_dc = data.dobs # Show apparent resisitivty pseudo-section if plotIt: IO.plotPseudoSection(data=data.dobs / IO.G, data_type="apparent_resistivity") # Show apparent resisitivty histogram if plotIt: fig = plt.figure() out = hist(data.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.0) # Set standard_deviation # floor eps = 10**(-3.2) # percentage relative = 0.05 dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data) uncert = abs(data.dobs) * relative + eps dmisfit.standard_deviation = uncert # Map for a regularization 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.0] IRLS = directives.Update_IRLS(max_irls_iterations=20, minGNiter=1, beta_search=False, fix_Jmatrix=True) opt = optimization.InexactGaussNewton(maxIter=40) invProb = inverse_problem.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(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.0, 200.0 ymin, ymax = 0.0, 0.0 zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey = IO.from_ambn_locations_to_survey( survey.locations_a, survey.locations_b, survey.locations_m, survey.locations_n, survey_type, data_dc_type="volt", ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() topo, mesh1D = genTopography(mesh, -10, 0, its=100) actind = utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo]) survey.drape_electrodes_on_topography(mesh, actind, option="top") # Build a conductivity model blk_inds_c = utils.model_builder.getIndicesSphere(np.r_[60.0, -25.0], 12.5, mesh.gridCC) blk_inds_r = utils.model_builder.getIndicesSphere(np.r_[140.0, -25.0], 12.5, mesh.gridCC) layer_inds = mesh.gridCC[:, 1] > -5.0 sigma = np.ones(mesh.nC) * 1.0 / 100.0 sigma[blk_inds_c] = 1.0 / 10.0 sigma[blk_inds_r] = 1.0 / 1000.0 sigma[~actind] = 1.0 / 1e8 rho = 1.0 / 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.Simulation2DNodal(mesh, survey=survey, rhoMap=mapping, storeJ=True, Solver=Solver, verbose=True) 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 data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True) IO.data_dc = data.dobs # Show apparent resisitivty pseudo-section if plotIt: IO.plotPseudoSection(data=data.dobs, data_type="apparent_resistivity") # Show apparent resisitivty histogram if plotIt: fig = plt.figure() out = hist(data.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.0) # Set standard_deviation # floor (10 ohm-m) eps = 1.0 # percentage relative = 0.05 dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data) uncert = abs(data.dobs) * relative + eps dmisfit.standard_deviation = uncert # Map for a regularization regmap = maps.IdentityMap(nP=int(actind.sum())) # Related to inversion reg = regularization.Sparse(mesh, indActive=actind, mapping=regmap) opt = optimization.InexactGaussNewton(maxIter=15) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) beta = directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e0) target = directives.TargetMisfit() updateSensW = directives.UpdateSensitivityWeights() update_Jacobi = directives.UpdatePreconditioner() inv = inversion.BaseInversion( invProb, directiveList=[beta, target, updateSensW, betaest, 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()
# ----------------------------------------------------- # # It is important that electrodes are not modeled as being in the air. Even if the # electrodes are properly located along surface topography, they may lie above # the discretized topography. This step is carried out to ensure all electrodes # lie on the discretized surface. # # Define conductivity model in S/m (or resistivity model in Ohm m) air_conductivity = 1e-8 background_conductivity = 1e-2 conductor_conductivity = 1e-1 resistor_conductivity = 1e-3 # Find active cells in forward modeling (cell below surface) ind_active = surface2ind_topo(mesh, xyz_topo[:, [0, 2]]) # Define mapping from model to active cells nC = int(ind_active.sum()) conductivity_map = maps.InjectActiveCells(mesh, ind_active, air_conductivity) # Define model conductivity_model = background_conductivity * np.ones(nC) ind_conductor = model_builder.getIndicesSphere(np.r_[-120.0, -180.0], 60.0, mesh.gridCC) ind_conductor = ind_conductor[ind_active] conductivity_model[ind_conductor] = conductor_conductivity ind_resistor = model_builder.getIndicesSphere(np.r_[120.0, -180.0], 60.0, mesh.gridCC)
h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 mesh = mesh_builder_xyz(xyzLoc, h, padding_distance=padDist, depth_core=100, mesh_type="tree") mesh = refine_tree_xyz(mesh, topo, method="surface", octree_levels=[4, 4], finalize=True) # Define an active cells from topo actv = utils.surface2ind_topo(mesh, topo) nC = int(actv.sum()) ########################################################################### # A simple function to plot vectors in TreeMesh # # Should eventually end up on discretize # def plotVectorSectionsOctree( mesh, m, normal="X", ind=0, vmin=None,
def setUp(self): np.random.seed(0) # First we need to define the direction of the inducing field # As a simple case, we pick a vertical inducing field of magnitude # 50,000nT. # From old convention, field orientation is given as an # azimuth from North (positive clockwise) # and dip from the horizontal (positive downward). H0 = (50000.0, 90.0, 0.0) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [2, 4, 2] # Create grid of points for topography # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(np.linspace(-200.0, 200.0, 50), np.linspace(-200.0, 200.0, 50)) b = 100 A = 50 zz = A * np.exp(-0.5 * ((xx / b)**2.0 + (yy / b)**2.0)) # 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.0, 100.0, 20) yr = np.linspace(-100.0, 100.0, 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 5 # Create a MAGsurvey xyzLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = mag.Point(xyzLoc) srcField = mag.SourceField([rxLoc], parameters=H0) survey = mag.Survey(srcField) # self.mesh.finalize() 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()) # We can now create a susceptibility model and generate data # Lets start with a simple block in half-space self.model = utils.model_builder.addBlock( self.mesh.gridCC, np.zeros(self.mesh.nC), np.r_[-20, -20, -15], np.r_[20, 20, 20], 0.05, )[actv] # Create active map to go from reduce set to full self.actvMap = maps.InjectActiveCells(self.mesh, actv, np.nan) # Creat reduced identity map idenMap = maps.IdentityMap(nP=nC) # Create the forward model operator sim = mag.Simulation3DIntegral( self.mesh, survey=survey, chiMap=idenMap, actInd=actv, store_sensitivities="ram", ) self.sim = sim data = sim.make_synthetic_data(self.model, relative_error=0.0, noise_floor=1.0, add_noise=True) # Create a regularization reg = regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.mref = np.zeros(nC) # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=sim, data=data) # Add directives to the inversion opt = optimization.ProjectedGNCG( maxIter=10, lower=0.0, upper=10.0, maxIterLS=5, maxIterCG=5, tolCG=1e-4, stepOffBoundsFact=1e-4, ) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=1e6) # 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, max_irls_iterations=20, beta_tol=1e-1, beta_search=False) update_Jacobi = directives.UpdatePreconditioner() sensitivity_weights = directives.UpdateSensitivityWeights() self.inv = inversion.BaseInversion( invProb, directiveList=[IRLS, sensitivity_weights, update_Jacobi])
def iterator(mesh, domain, surface, cell_width, objct, coordinates, receiver_locations, source_locations, survey, par_background, par_object, ind_object, frequency=1, omega=2 * np.pi, parameter='resistivity', interpolation='rbf', type_object='block', lim_iterations=5, factor_object=2, factor_receiver=3, factor_source=3, refine_percentage=0.05, axis='x', degrees_rad=0, radius=1, Ex=None, Ey=None, Ez=None, diff_list=np.array([[0, 0]]), r_a_o_list=None, r_a_r_list=None, r_a_s_list=None): """An iteration scheme that implements an error estimator to adaptively refine a mesh, in order to reduce the error of the electric field solution. This function is mainly used for small objects in a domain. If you want to continue from previous iteration, you have to give the mesh, field values, convergence list and previous refinements as input arguments.""" # Find cells that are active in the forward modeling (cells below surface) ind_active = surface2ind_topo(mesh, surface) # Define mapping from model to active cells model_map = maps.InjectActiveCells(mesh, ind_active, par_background) # Define model. Models in SimPEG are vector arrays model = par_background * np.ones(ind_active.sum()) if type_object == 'block': ind_object = get_ind_block(mesh, ind_active, coordinates, axis, degrees_rad) if type_object == 'sphere': ind_object = get_ind_sphere(mesh, ind_active, coordinates, radius) model[ind_object] = par_object diff = 10 if diff_list[0, 0] == 0: i = 0 av_diff_list = [] refine_at_object_list = [] refine_at_receivers_list = [] refine_at_sources_list = [] # Starting after the pause else: i = diff_list[-1, 0] av_diff_list = list(diff_list) refine_at_object_list = r_a_o_list refine_at_receivers_list = r_a_r_list refine_at_sources_list = r_a_s_list lim_iterations = lim_iterations + i ef_old_x = Ex ef_old_y = Ey ef_old_z = Ez def ef_interpolator(x): return np.array([ef_x(*x), ef_y(*x), ef_z(*x)]) def ef_old_interpolator(x): return np.array([ef_old_x(*x), ef_old_y(*x), ef_old_z(*x)]) while diff > 0.01 and i < lim_iterations: # Maximum relative difference between current and previous iteration should fall below 1% in order to converge. # Define search areas search_area_obj = search_area_object(mesh, objct, factor=factor_object) search_area_receiv = search_area_receivers(mesh, receiver_locations, factor=factor_receiver) search_area_sourc = search_area_sources(mesh, source_locations, factor=factor_source) # Interpolate curl and electric field curl_x, curl_y, curl_z, ef_x, ef_y, ef_z = estimate_curl_electric_field( mesh, survey, model_map, model, interpolation=interpolation, frequency=frequency, omega=omega, parameter=parameter) # Compare electric field values until relative difference falls below 1% if diff_list[0, 0] == 0: if i > 0: relative_difference_Efield = [] for cell in search_area_obj: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) for cell in search_area_receiv: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) for cell in search_area_sourc: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) diff = sum(relative_difference_Efield) / len( relative_difference_Efield) av_diff_list.append([i + 1, diff]) print("Average relative difference is ", diff) else: relative_difference_Efield = [] for cell in search_area_obj: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) for cell in search_area_receiv: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) for cell in search_area_sourc: # This equation is sensitive to catastrophic failure form = np.abs( (ef_old_interpolator(cell) - ef_interpolator(cell)) / ef_old_interpolator(cell)) relative_difference_Efield.append(np.linalg.norm(form)) diff = sum(relative_difference_Efield) / len( relative_difference_Efield) av_diff_list.append([i + 1, diff]) print("Average relative difference is ", diff) ef_old_x = ef_x ef_old_y = ef_y ef_old_z = ef_z # Define cells to refine near object cells_to_refine_object = estimate_error( search_area_obj, curl_x, curl_y, curl_z, ef_x, ef_y, ef_z, refine_percentage=refine_percentage) refine_at_object_list.append(cells_to_refine_object) # Define cells to refine near receivers cells_to_refine_receivers = estimate_error( search_area_receiv, curl_x, curl_y, curl_z, ef_x, ef_y, ef_z, refine_percentage=refine_percentage) refine_at_receivers_list.append(cells_to_refine_receivers) # Define cells to refine near sources cells_to_refine_sources = estimate_error( search_area_sourc, curl_x, curl_y, curl_z, ef_x, ef_y, ef_z, refine_percentage=refine_percentage) refine_at_sources_list.append(cells_to_refine_sources) # Refine the mesh mesh = create_octree_mesh(domain, cell_width, objct, 'surface') refine_at_locations(mesh, source_locations) refine_at_locations(mesh, receiver_locations) for refo in refine_at_object_list: refine_at_locations(mesh, refo) for refr in refine_at_receivers_list: refine_at_locations(mesh, refr) for refs in refine_at_sources_list: refine_at_locations(mesh, refs) mesh.finalize() # Find cells that are active in the forward modeling (cells below surface) ind_active = surface2ind_topo(mesh, surface) # Define mapping from model to active cells model_map = maps.InjectActiveCells(mesh, ind_active, par_background) # Define model. Models in SimPEG are vector arrays model = par_background * np.ones(ind_active.sum()) if type_object == 'block': ind_object = get_ind_block(mesh, ind_active, coordinates) if type_object == 'sphere': ind_object = get_ind_sphere(mesh, ind_active, coordinates, radius) model[ind_object] = par_object print(i) i += 1 if diff < 0.01: return mesh, ef_x, ef_y, ef_z, np.array(av_diff_list) else: return mesh, ef_x, ef_y, ef_z, np.array( av_diff_list ), refine_at_object_list, refine_at_receivers_list, refine_at_sources_list
def setUp(self): np.random.seed(0) H0 = (50000.0, 90.0, 0.0) # The magnetization is set along a different # direction (induced + remanence) M = np.array([45.0, 90.0]) # 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.0 + (yy / b)**2.0)) # 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.0, 100.0, 20) yr = np.linspace(-100.0, 100.0, 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 5 # Create a MAGsurvey xyzLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = mag.Point(xyzLoc) srcField = mag.SourceField([rxLoc], parameters=H0) survey = mag.Survey(srcField) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 mesh = mesh_builder_xyz(xyzLoc, h, padding_distance=padDist, depth_core=100, mesh_type="tree") mesh = refine_tree_xyz(mesh, topo, method="surface", octree_levels=[4, 4], finalize=True) 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.mat_utils.dip_azimuth2cartesian(M[0], M[1]) # Get the indicies of the magnetized block ind = utils.model_builder.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 sim = mag.Simulation3DIntegral( self.mesh, survey=survey, model_type="vector", chiMap=idenMap, actInd=actv, store_sensitivities="disk", ) self.sim = sim # Compute some data and add some random noise data = sim.make_synthetic_data(utils.mkvc(self.model), relative_error=0.0, noise_floor=5.0, add_noise=True) # This Mapping connects the regularizations for the three-component # vector model wires = maps.Wires(("p", nC), ("s", nC), ("t", nC)) # 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_s = regularization.Sparse(mesh, indActive=actv, mapping=wires.s) reg_s.mref = np.zeros(3 * nC) reg_t = regularization.Sparse(mesh, indActive=actv, mapping=wires.t) reg_t.mref = np.zeros(3 * nC) reg = reg_p + reg_s + reg_t reg.mref = np.zeros(3 * nC) # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=sim, data=data) # dmis.W = 1./survey.std # Add directives to the inversion opt = optimization.ProjectedGNCG(maxIter=10, lower=-10, upper=10.0, maxIterLS=5, maxIterCG=5, tolCG=1e-4) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt) # A list of directive to control the inverson betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e1) # 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, max_irls_iterations=0, beta_tol=5e-1) # Pre-conditioner update_Jacobi = directives.UpdatePreconditioner() sensitivity_weights = directives.UpdateSensitivityWeights( everyIter=False) inv = inversion.BaseInversion( invProb, directiveList=[sensitivity_weights, IRLS, update_Jacobi, betaest]) # Run the inversion m0 = np.ones(3 * nC) * 1e-4 # Starting model mrec_MVIC = inv.run(m0) sim.chiMap = maps.SphericalSystem(nP=nC * 3) self.mstart = sim.chiMap.inverse(mrec_MVIC) dmis.simulation.model = self.mstart beta = invProb.beta # 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, 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.0 # No reference angle reg_t.space = "spherical" reg_t.norms = np.c_[2.0, 0.0, 0.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.0 # No reference angle reg_p.space = "spherical" reg_p.norms = np.c_[2.0, 0.0, 0.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=5, lower=Lbound, upper=Ubound, maxIterLS=5, maxIterCG=5, tolCG=1e-3, stepOffBoundsFact=1e-3, ) opt.approxHinv = None invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=beta) # Here is where the norms are applied IRLS = directives.Update_IRLS( f_min_change=1e-4, max_irls_iterations=5, minGNiter=1, beta_tol=0.5, coolingRate=1, coolEps_q=True, sphericalDomain=True, ) # Special directive specific to the mag amplitude problem. The sensitivity # weights are update between each iteration. ProjSpherical = directives.ProjectSphericalBounds() sensitivity_weights = directives.UpdateSensitivityWeights() update_Jacobi = directives.UpdatePreconditioner() self.inv = inversion.BaseInversion( invProb, directiveList=[ ProjSpherical, IRLS, sensitivity_weights, update_Jacobi ], )
def setUp(self): ndv = -100 # Create a self.mesh dx = 5.0 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)] self.mesh = discretize.TensorMesh([hxind, hyind, hzind], "CCC") # Get index of the center midx = int(self.mesh.nCx / 2) midy = int(self.mesh.nCy / 2) # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(self.mesh.vectorNx, self.mesh.vectorNy) zz = -np.exp((xx**2 + yy**2) / 75**2) + self.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(self.mesh, topo, "N") actv = np.where(actv)[0] # Create active map to go from reduce space to full self.actvMap = maps.InjectActiveCells(self.mesh, actv, -100) nC = len(actv) # Create and array of observation points xr = np.linspace(-20.0, 20.0, 20) yr = np.linspace(-20.0, 20.0, 20) X, Y = np.meshgrid(xr, yr) # Move the observation points 5m above the topo Z = -np.exp((X**2 + Y**2) / 75**2) + self.mesh.vectorNz[-1] + 5.0 # Create a MAGsurvey locXYZ = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = gravity.Point(locXYZ) srcField = gravity.SourceField([rxLoc]) survey = gravity.Survey(srcField) # We can now create a density model and generate data # Here a simple block in half-space model = np.zeros((self.mesh.nCx, self.mesh.nCy, self.mesh.nCz)) model[(midx - 2):(midx + 2), (midy - 2):(midy + 2), -6:-2] = 0.5 model = utils.mkvc(model) self.model = model[actv] # Create active map to go from reduce set to full actvMap = maps.InjectActiveCells(self.mesh, actv, ndv) # Create reduced identity map idenMap = maps.IdentityMap(nP=nC) # Create the forward model operator sim = gravity.Simulation3DIntegral( self.mesh, survey=survey, rhoMap=idenMap, actInd=actv, store_sensitivities="ram", ) # Compute linear forward operator and compute some data # computing sensitivities to ram is best using dask processes with dask.config.set(scheduler="processes"): data = sim.make_synthetic_data(self.model, relative_error=0.0, noise_floor=0.001, add_noise=True) print(sim.G) # Create a regularization reg = regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.gradientType = "component" # reg.eps_p, reg.eps_q = 5e-2, 1e-2 # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=sim, data=data) # Add directives to the inversion opt = optimization.ProjectedGNCG(maxIter=100, lower=-1.0, upper=1.0, maxIterLS=20, maxIterCG=10, tolCG=1e-3) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=1e8) # Here is where the norms are applied IRLS = directives.Update_IRLS(f_min_change=1e-4, minGNiter=1) update_Jacobi = directives.UpdatePreconditioner() sensitivity_weights = directives.UpdateSensitivityWeights( everyIter=False) self.inv = inversion.BaseInversion( invProb, directiveList=[IRLS, sensitivity_weights, update_Jacobi]) self.sim = sim
def run(plotIt=True): # Define the inducing field parameter H0 = (50000, 90, 0) # Create a mesh dx = 5.0 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 = 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.0, 20.0, 20) yr = np.linspace(-20.0, 20.0, 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.0 # Create a MAGsurvey rxLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = magnetics.receivers.Point(rxLoc, components=["tmi"]) srcField = magnetics.sources.SourceField(receiver_list=[rxLoc], parameters=H0) survey = magnetics.survey.Survey(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 simulation = magnetics.simulation.Simulation3DIntegral( survey=survey, mesh=mesh, chiMap=idenMap, actInd=actv, ) # Compute linear forward operator and compute some data d = simulation.dpred(model) # Add noise and uncertainties # We add some random Gaussian noise (1nT) synthetic_data = d + np.random.randn(len(d)) wd = np.ones(len(synthetic_data)) * 1.0 # Assign flat uncertainties data_object = data.Data(survey, dobs=synthetic_data, noise_floor=wd) # Create a regularization reg = regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.mref = np.zeros(nC) reg.norms = np.c_[0, 0, 0, 0] # reg.eps_p, reg.eps_q = 1e-0, 1e-0 # Create sensitivity weights from our linear forward operator rxLoc = survey.source_field.receiver_list[0].locations m0 = np.ones(nC) * 1e-4 # Starting model # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=simulation, data=data_object) dmis.W = 1 / wd # Add directives to the inversion opt = optimization.ProjectedGNCG(maxIter=20, lower=0.0, upper=1.0, maxIterLS=20, maxIterCG=20, tolCG=1e-3) invProb = inverse_problem.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-3, max_irls_iterations=40) saveDict = directives.SaveOutputEveryIteration(save_txt=False) update_Jacobi = directives.UpdatePreconditioner() # Add sensitivity weights sensitivity_weights = directives.UpdateSensitivityWeights(everyIter=False) inv = inversion.BaseInversion( invProb, directiveList=[ sensitivity_weights, IRLS, betaest, update_Jacobi, saveDict ], ) # Run the inversion 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.plot_utils.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)
frequencies = [1.0] # Frequency (Hz) omegas = [2.0 * np.pi] # Radial frequency (Hz) survey = utils.define_survey(frequencies, receiver_locations, source_locations, ntx) # Refine at certain locations M.refine_at_locations(mesh, source_locations) M.refine_at_locations(mesh, receiver_locations) mesh.finalize() # Resistivity in Ohm m res_background = 1.0 res_block = 100.0 # Find cells that are active in the forward modeling (cells below surface) ind_active = surface2ind_topo(mesh, surface) # Define mapping from model to active cells model_map = maps.InjectActiveCells(mesh, ind_active, res_background) # Define model. Models in SimPEG are vector arrays model = res_background * np.ones(ind_active.sum()) ind_block = utils.get_ind_block(mesh, ind_active, box_coordinates) model[ind_block] = res_block # Run the adaptive meshing algorithm mesh, ex, ey, ez, diff_list = iterator(mesh, domain, surface, cell_width, box_surface,
def run( plotIt=True, survey_type="dipole-dipole", rho_background=1e3, rho_block=1e2, block_x0=100, block_dx=10, block_y0=-10, block_dy=5, ): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0.0, 200.0 ymin, ymax = 0.0, 0.0 zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DCutils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey = IO.from_ambn_locations_to_survey( survey.locations_a, survey.locations_b, survey.locations_m, survey.locations_n, survey_type, data_dc_type="volt", ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() # Flat topography actind = utils.surface2ind_topo( mesh, np.c_[mesh.vectorCCx, mesh.vectorCCx * 0.0]) survey.drape_electrodes_on_topography(mesh, actind, option="top") # Use Exponential Map: m = log(rho) actmap = maps.InjectActiveCells(mesh, indActive=actind, valInactive=np.log(1e8)) parametric_block = maps.ParametricBlock(mesh, slopeFact=1e2) mapping = maps.ExpMap(mesh) * parametric_block # Set true model # val_background,val_block, block_x0, block_dx, block_y0, block_dy mtrue = np.r_[np.log(1e3), np.log(10), 100, 10, -20, 10] # Set initial model m0 = np.r_[np.log(rho_background), np.log(rho_block), block_x0, block_dx, block_y0, block_dy, ] rho = mapping * mtrue rho0 = mapping * m0 # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={"alpha": 0.2}, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ) ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "k.") ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect("equal") ax.set_title("True resistivity model") plt.show() # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho0.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={"alpha": 0.2}, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ) ax.plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "k.") ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect("equal") ax.set_title("Initial resistivity model") plt.show() # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Simulation2DNodal(mesh, survey=survey, rhoMap=mapping, storeJ=True, solver=Solver) # Make synthetic DC data with 5% Gaussian noise data = prb.make_synthetic_data(mtrue, relative_error=0.05, add_noise=True) # Show apparent resisitivty pseudo-section IO.plotPseudoSection(data=data.dobs / IO.G, data_type="apparent_resistivity") # Show apparent resisitivty histogram fig = plt.figure() out = hist(data.dobs / IO.G, bins=20) plt.show() # Set standard_deviation # floor eps = 10**(-3.2) # percentage relative = 0.05 dmisfit = data_misfit.L2DataMisfit(simulation=prb, data=data) uncert = abs(data.dobs) * relative + eps dmisfit.standard_deviation = uncert # Map for a regularization mesh_1d = discretize.TensorMesh([parametric_block.nP]) # Related to inversion reg = regularization.Simple(mesh_1d, alpha_x=0.0) opt = optimization.InexactGaussNewton(maxIter=10) invProb = inverse_problem.BaseInvProblem(dmisfit, reg, opt) beta = directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = directives.BetaEstimate_ByEig(beta0_ratio=1e0) target = directives.TargetMisfit() updateSensW = directives.UpdateSensitivityWeights() update_Jacobi = directives.UpdatePreconditioner() invProb.beta = 0.0 inv = inversion.BaseInversion(invProb, directiveList=[target]) prb.counter = opt.counter = utils.Counter() opt.LSshorten = 0.5 opt.remember("xc") # Run inversion mopt = inv.run(m0) # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping * mopt rho_true = rho.copy() # show recovered conductivity vmin, vmax = rho.min(), rho.max() fig, ax = plt.subplots(2, 1, figsize=(20, 6)) out1 = mesh.plotImage( rho_true, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[0], ) out2 = mesh.plotImage( rho_est, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ax=ax[1], ) out = [out1, out2] for i in range(2): ax[i].plot(survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], "kv") ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[i][0], ax=ax[i]) cb.set_label("Resistivity ($\Omega$m)") ax[i].set_xlabel("Northing (m)") ax[i].set_ylabel("Elevation (m)") ax[i].set_aspect("equal") ax[0].set_title("True resistivity model") ax[1].set_title("Recovered resistivity model") plt.tight_layout() plt.show()
mesh.finalize() ############################################################### # Project Surveys to Discretized Topography # ----------------------------------------- # # It is important that electrodes are not model as being in the air. Even if the # electrodes are properly located along surface topography, they may lie above # the discretized topography. This step is carried out to ensure all electrodes # like on the discretized surface. # # Find cells that lie below surface topography ind_active = surface2ind_topo(mesh, topo_xyz[:, [0, 2]]) # Shift electrodes to the surface of discretized topography survey.drape_electrodes_on_topography(mesh, ind_active, option="top") ######################################################## # Starting/Reference Model and Mapping on OcTree Mesh # --------------------------------------------------- # # Here, we would create starting and/or reference models for the DC inversion as # well as the mapping from the model space to the active cells. Starting and # reference models can be a constant background value or contain a-priori # structures. Here, the starting model is the natural log of 0.01 S/m. # # Define conductivity model in S/m (or resistivity model in Ohm m)
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.0, 200.0 ymin, ymax = 0.0, 0.0 zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey_dc = gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey_dc = IO.from_abmn_locations_to_survey( survey_dc.locations_a, survey_dc.locations_b, survey_dc.locations_m, survey_dc.locations_n, survey_type, data_dc_type="volt", data_ip_type="volt", ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() topo, mesh1D = genTopography(mesh, -10, 0, its=100) actind = utils.surface2ind_topo(mesh, np.c_[mesh1D.vectorCCx, topo]) survey_dc.drape_electrodes_on_topography(mesh, actind, option="top") # Build conductivity and chargeability model blk_inds_c = utils.model_builder.getIndicesSphere(np.r_[60.0, -25.0], 12.5, mesh.gridCC) blk_inds_r = utils.model_builder.getIndicesSphere(np.r_[140.0, -25.0], 12.5, mesh.gridCC) blk_inds_charg = utils.model_builder.getIndicesSphere( np.r_[100.0, -25], 12.5, mesh.gridCC) sigma = np.ones(mesh.nC) * 1.0 / 100.0 sigma[blk_inds_c] = 1.0 / 10.0 sigma[blk_inds_r] = 1.0 / 1000.0 sigma[~actind] = 1.0 / 1e8 rho = 1.0 / sigma charg = np.zeros(mesh.nC) charg[blk_inds_charg] = 0.1 # Show the true conductivity model if plotIt: fig, axs = plt.subplots(2, 1, figsize=(12, 6)) temp_rho = rho.copy() temp_rho[~actind] = np.nan temp_charg = charg.copy() temp_charg[~actind] = np.nan out1 = mesh.plotImage( temp_rho, grid=True, ax=axs[0], gridOpts={"alpha": 0.2}, clim=(10, 1000), pcolorOpts={ "cmap": "viridis", "norm": colors.LogNorm() }, ) out2 = mesh.plotImage( temp_charg, grid=True, ax=axs[1], gridOpts={"alpha": 0.2}, clim=(0, 0.1), pcolorOpts={"cmap": "magma"}, ) for i in range(2): axs[i].plot( survey_dc.electrode_locations[:, 0], survey_dc.electrode_locations[:, 1], "kv", ) axs[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) axs[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) axs[i].set_aspect("equal") cb = plt.colorbar(out1[0], ax=axs[0]) cb.set_label("Resistivity (ohm-m)") cb = plt.colorbar(out2[0], ax=axs[1]) cb.set_label("Chargeability") 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_dc for resistivity mtrue_dc = np.log(rho[actind]) # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Simulation2DNodal(mesh, survey=survey_dc, rhoMap=mapping, storeJ=True, solver=Solver) # Make synthetic DC data with 5% Gaussian noise data_dc = prb.make_synthetic_data(mtrue_dc, relative_error=0.05, add_noise=True) IO.data_dc = data_dc.dobs # Generate mtrue_ip for chargability mtrue_ip = charg[actind] # Generate 2.5D DC problem # "N" means potential is defined at nodes survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="2.5D") prb_ip = IP.Simulation2DNodal(mesh, survey=survey_ip, etaMap=actmap, storeJ=True, rho=rho, solver=Solver) data_ip = prb_ip.make_synthetic_data(mtrue_ip, relative_error=0.05, add_noise=True) IO.data_ip = data_ip.dobs # Show apparent resisitivty pseudo-section if plotIt: IO.plotPseudoSection(data_type="apparent_resistivity", scale="log", cmap="viridis") plt.show() # Show apparent chargeability pseudo-section if plotIt: IO.plotPseudoSection(data_type="apparent_chargeability", scale="linear", cmap="magma") plt.show() # Show apparent resisitivty histogram if plotIt: fig = plt.figure(figsize=(10, 4)) ax1 = plt.subplot(121) out = hist(np.log10(abs(IO.voltages)), bins=20) ax1.set_xlabel("log10 DC voltage (V)") ax2 = plt.subplot(122) out = hist(IO.apparent_resistivity, bins=20) ax2.set_xlabel("Apparent Resistivity ($\Omega$m)") plt.tight_layout() plt.show() # Set initial model based upon histogram m0_dc = np.ones(actmap.nP) * np.log(100.0) # Set standard deviation # floor data_dc.noise_floor = 10**(-3.2) # percentage data_dc.relative_error = 0.05 mopt_dc, pred_dc = DC.run_inversion(m0_dc, prb, data_dc, actind, mesh, beta0_ratio=1e0, use_sensitivity_weight=True) # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping * mopt_dc rho_est[~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(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_dc.electrode_locations[:, 0], survey_dc.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() # Show apparent resisitivty histogram if plotIt: fig = plt.figure(figsize=(10, 4)) ax1 = plt.subplot(121) out = hist(np.log10(abs(IO.voltages_ip)), bins=20) ax1.set_xlabel("log10 IP voltage (V)") ax2 = plt.subplot(122) out = hist(IO.apparent_chargeability, bins=20) ax2.set_xlabel("Apparent Chargeability (V/V)") plt.tight_layout() plt.show() # Set initial model based upon histogram m0_ip = np.ones(actmap.nP) * 1e-10 # Set standard deviation # floor data_ip.noise_floor = 10**(-4) # percentage data_ip.relative_error = 0.05 # Clean sensitivity function formed with true resistivity prb_ip._Jmatrix = None # Input obtained resistivity to form sensitivity prb_ip.rho = mapping * mopt_dc mopt_ip, _ = IP.run_inversion( m0_ip, prb_ip, data_ip, actind, mesh, upper=np.Inf, lower=0.0, beta0_ratio=1e0, use_sensitivity_weight=True, ) # Convert obtained inversion model to chargeability # charg = M(m), where M(.) is a mapping for cells below topography charg_est = actmap * mopt_ip charg_est[~actind] = np.nan charg_true = charg.copy() charg_true[~actind] = np.nan # show recovered chargeability if plotIt: fig, ax = plt.subplots(2, 1, figsize=(20, 6)) out1 = mesh.plotImage(charg_true, clim=(0, 0.1), pcolorOpts={"cmap": "magma"}, ax=ax[0]) out2 = mesh.plotImage(charg_est, clim=(0, 0.1), pcolorOpts={"cmap": "magma"}, ax=ax[1]) out = [out1, out2] for i in range(2): ax[i].plot( survey_dc.electrode_locations[:, 0], survey_dc.electrode_locations[:, 1], "rv", ) 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()
# Starting/Reference Model and Mapping on Tensor Mesh # --------------------------------------------------- # # Here, we create starting and/or reference models for the inversion as # well as the mapping from the model space to the active cells. Starting and # reference models can be a constant background value or contain a-priori # structures. Here, the background is 1e-6 g/cc. # # Define density contrast values for each unit in g/cc. Don't make this 0! # Otherwise the gradient for the 1st iteration is zero and the inversion will # not converge. background_density = 1e-6 # Find the indecies of the active cells in forward model (ones below surface) ind_active = surface2ind_topo(mesh, xyz_topo) # Define mapping from model to active cells nC = int(ind_active.sum()) model_map = maps.IdentityMap( nP=nC) # model consists of a value for each active cell # Define and plot starting model starting_model = background_density * np.ones(nC) ############################################## # Define the Physics # ------------------ # # Here, we define the physics of the gravity problem by using the simulation # class.
mesh = refine_box(mesh) mesh.finalize() background_value = 100.0 dyke_value = 40.0 block_value = 70.0 # Define surface topography as an (N, 3) np.array. You could also load a file # containing the xyz points [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -3 * np.exp((xx**2 + yy**2) / 60**2) + 45.0 topo = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)] # Find cells below topography and define mapping air_value = 0.0 ind_active = surface2ind_topo(mesh, topo) model_map = maps.InjectActiveCells(mesh, ind_active, air_value) # Define the model on subsurface cells model = background_value * np.ones(ind_active.sum()) ind_dyke = (mesh.gridCC[ind_active, 0] > 20.0) & (mesh.gridCC[ind_active, 0] < 40.0) model[ind_dyke] = dyke_value ind_block = ((mesh.gridCC[ind_active, 0] > -40.0) & (mesh.gridCC[ind_active, 0] < -10.0) & (mesh.gridCC[ind_active, 1] > -30.0) & (mesh.gridCC[ind_active, 1] < 30.0) & (mesh.gridCC[ind_active, 2] > -40.0) & (mesh.gridCC[ind_active, 2] < 0.0)) model[ind_block] = block_value
"colors": "k", "linewidths": 2, "linestyles": "--" }, method="nearest", ) plt.subplots_adjust(hspace=-0.25, wspace=0.1) plt.show() # Load Topo topo_file = io_utils.download( "https://storage.googleapis.com/simpeg/pgi_tutorial_assets/CDED_Lake_warp.xyz" ) topo = np.genfromtxt(topo_file, skip_header=1) # find the active cells actv = utils.surface2ind_topo(mesh, topo, gridLoc="CC") # Create active map to go from reduce set to full ndv = np.nan actvMap = maps.InjectActiveCells(mesh, actv, ndv) nactv = int(actv.sum()) # Create simulations and data misfits # Wires mapping wires = maps.Wires(("den", actvMap.nP), ("sus", actvMap.nP)) gravmap = actvMap * wires.den magmap = actvMap * wires.sus idenMap = maps.IdentityMap(nP=nactv) # Grav problem simulation_grav = pf.gravity.simulation.Simulation3DIntegral( survey=data_grav.survey, mesh=mesh,
def run(plotIt=True): H0 = (50000.0, 90.0, 0.0) # Create a mesh dx = 5.0 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 = discretize.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.0, 20.0, 20) yr = np.linspace(-20.0, 20.0, 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.0 # Create a MAGsurvey rxLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = magnetics.Point(rxLoc) srcField = magnetics.SourceField([rxLoc], parameters=H0) survey = magnetics.Survey(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.model_builder.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 = magnetics.Simulation3DIntegral( mesh, survey=survey, chiMap=idenMap, actInd=actv, store_sensitivities="forward_only", ) # Compute linear forward operator and compute some data data = prob.make_synthetic_data( model, relative_error=0.0, noise_floor=1, add_noise=True ) # 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 = magnetics.Simulation3DIntegral( mesh, survey=survey, chiMap=sumMap, actInd=actv, store_sensitivities="ram" ) # Make depth weighting wr = np.zeros(sumMap.shape[1]) print(prob.nC) # print(prob.M.shape) # why does this reset nC G = prob.G # Take the cell number out of the scaling. # Want to keep high sens for large volumes scale = utils.sdiag( np.r_[utils.mkvc(1.0 / 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) / data.standard_deviation[ii] ) ** 2.0 # 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 = discretize.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 = data_misfit.L2DataMisfit(simulation=prob, data=data) # Add directives to the inversion opt = optimization.ProjectedGNCG( maxIter=100, lower=0.0, upper=1.0, maxIterLS=20, maxIterCG=10, tolCG=1e-3, tolG=1e-3, eps=1e-6, ) invProb = inverse_problem.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", )