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.asarray( [inds for inds, elem in enumerate(active, 1) if elem], dtype=int) - 1 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 drapeTopotoLoc(mesh, pts, actind=None, option="top", topo=None): """ Drape location right below (cell center) the topography """ if mesh.dim == 2: if pts.ndim > 1: raise Exception("pts should be 1d array") elif mesh.dim == 3: if pts.shape[1] == 3: raise Exception("shape of pts should be (x,3)") else: raise NotImplementedError() if actind is None: actind = Utils.surface2ind_topo(mesh, topo) if mesh._meshType == "TENSOR": meshtemp, topoCC = gettopoCC(mesh, actind, option=option) inds = Utils.closestPoints(meshtemp, pts) elif mesh._meshType == "TREE": if mesh.dim == 3: uniqXYlocs, topoCC = gettopoCC(mesh, actind, option=option) inds = closestPointsGrid(uniqXYlocs, pts) else: raise NotImplementedError() else: raise NotImplementedError() out = np.c_[pts, topoCC[inds]] return out
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 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.asarray([inds for inds, elem in enumerate(active, 1) if elem], dtype=int) - 1 self._activeCells = inds # Reduce m0 to active space self._m0 = self.m0[self._activeCells] return self._activeCells
def create_local_mesh( src_location, rx_location, topo_location, topo, h = [10., 10., 5.], x_core_lim = (-100., 100.), y_core_lim = (-20., 20.), ): # TODO: All parameters used for generating this mesh should be input parameters # Currently fixed for a specific case xyz = np.vstack((rx_location, src_location)) x = np.linspace(x_core_lim[0], x_core_lim[1]) + src_location[0] y = np.linspace(y_core_lim[0], y_core_lim[1]) + src_location[1] dem = Utils.ndgrid(x, y, np.r_[topo_location[2]]) mesh_local = discretize.utils.mesh_builder_xyz( dem, h, padding_distance=[[2000., 2000.], [2000., 2000.], [2000., 2000.]], base_mesh=None, depth_core=None, expansion_factor=1.3, mesh_type='tree' ) mesh_local = discretize.utils.refine_tree_xyz( mesh_local, dem, method='surface', octree_levels=[5, 10, 10], octree_levels_padding=None, finalize=False, min_level=0, max_distance=np.inf, ) mesh_local = discretize.utils.refine_tree_xyz( mesh_local, xyz, method='radial', octree_levels=[2, 0, 0], octree_levels_padding=None, finalize=True, min_level=1, max_distance=np.inf, ) actv_local = Utils.surface2ind_topo(mesh_local, topo) return mesh_local, actv_local
def activeCells(self): if getattr(self, '_activeCells', None) is None: if self.topofile == 'null': self._activeCells = np.arange(mesh.nC) else: topo = np.genfromtxt(self.basePath + self.topofile, skip_header=1) # Find the active cells active = Utils.surface2ind_topo(self.mesh,topo,'N') inds = np.asarray([inds for inds, elem in enumerate(active, 1) if elem], dtype = int) - 1 self._activeCells = inds return self._activeCells
def readSeepageModel(fname, mesh=None, xsurf=None, ysurf=None): fluiddata = pd.read_csv(fname) header = fluiddata.keys() xyz = np.c_[fluiddata['X (m)'].values,fluiddata['Y (m)'].values] h = fluiddata['Total Head (m)'].values Ux = fluiddata['X-Velocity Magnitude (m/sec)'].values Uy = fluiddata['Y-Velocity Magnitude (m/sec)'].values Gradx = fluiddata['X-Gradient'].values Grady = fluiddata['Y-Gradient'].values Pressure = fluiddata['Pressure Head (m)'].values Sw = fluiddata[fluiddata.keys()[17]].values Kx = fluiddata["X-Conductivity (m/sec)"] Ky = fluiddata["Y-Conductivity (m/sec)"] if mesh is None: # TODO: this is a specific set up ... xmin, ymin = xyz[:,0].min(), xyz[:,1].min() cs = 0.5 ncx = 152*2 ncy = 36*2 npad = 5 hx = [(cs,npad, -1.3),(cs,ncx),(cs,npad, 1.3)] hy = [(cs,npad, -1.3),(cs,ncy)] mesh = Mesh.TensorMesh([hx, hy], x0 = [xmin, ymin]) mesh._x0 = np.r_[xmin-mesh.hx[:10].sum(), xmin-mesh.hy[:10].sum()] # ... xsurf = np.r_[-1e10, 55, 90, 94, 109, 112, 126.5, +1e10] ysurf = np.r_[27.5, 27.5, 43.2, 43.2, 35, 35, 27.5, 27.5] yup = np.ones_like(ysurf)*45 actind = Utils.surface2ind_topo(mesh, np.c_[xsurf, ysurf]) waterheight = 40. waterind = (np.logical_and(~actind, mesh.gridCC[:,1]<40.)) & (mesh.gridCC[:,0]<90.) F_hlin = LinearNDInterpolator(xyz, h) hccIn = F_hlin(mesh.gridCC[actind,:]) F_hnear = NearestNDInterpolator(mesh.gridCC[actind,:], hccIn) hcc = F_hnear(mesh.gridCC) fluiddata = {"xyz": xyz, "h":h, "Sw":Sw, "Kx":Kx, "Ky":Ky, "P":Pressure, "Ux":Ux, "Uy":Uy,\ "Gradx":Gradx, "Grady":Grady, \ "hcc": hcc, "mesh":mesh, "actind":actind, "waterind": waterind, \ "xsurf":xsurf, "ysurf":ysurf, "yup":yup} return fluiddata
def readSeepageModel(fname, mesh=None, xsurf=None, ysurf=None): fluiddata = pd.read_csv(fname) header = fluiddata.keys() xyz = np.c_[fluiddata['X (m)'].values, fluiddata['Y (m)'].values] h = fluiddata['Total Head (m)'].values Ux = fluiddata['X-Velocity Magnitude (m/sec)'].values Uy = fluiddata['Y-Velocity Magnitude (m/sec)'].values Gradx = fluiddata['X-Gradient'].values Grady = fluiddata['Y-Gradient'].values Pressure = fluiddata['Pressure Head (m)'].values Sw = fluiddata[fluiddata.keys()[17]].values Kx = fluiddata["X-Conductivity (m/sec)"] Ky = fluiddata["Y-Conductivity (m/sec)"] if mesh is None: # TODO: this is a specific set up ... xmin, ymin = xyz[:, 0].min(), xyz[:, 1].min() cs = 0.5 ncx = 152 * 2 ncy = 36 * 2 npad = 5 hx = [(cs, npad, -1.3), (cs, ncx), (cs, npad, 1.3)] hy = [(cs, npad, -1.3), (cs, ncy)] mesh = Mesh.TensorMesh([hx, hy], x0=[xmin, ymin]) mesh._x0 = np.r_[xmin - mesh.hx[:10].sum(), xmin - mesh.hy[:10].sum()] # ... xsurf = np.r_[-1e10, 55, 90, 94, 109, 112, 126.5, +1e10] ysurf = np.r_[27.5, 27.5, 43.2, 43.2, 35, 35, 27.5, 27.5] yup = np.ones_like(ysurf) * 45 actind = Utils.surface2ind_topo(mesh, np.c_[xsurf, ysurf]) waterheight = 40. waterind = (np.logical_and( ~actind, mesh.gridCC[:, 1] < 40.)) & (mesh.gridCC[:, 0] < 90.) F_hlin = LinearNDInterpolator(xyz, h) hccIn = F_hlin(mesh.gridCC[actind, :]) F_hnear = NearestNDInterpolator(mesh.gridCC[actind, :], hccIn) hcc = F_hnear(mesh.gridCC) fluiddata = {"xyz": xyz, "h":h, "Sw":Sw, "Kx":Kx, "Ky":Ky, "P":Pressure, "Ux":Ux, "Uy":Uy,\ "Gradx":Gradx, "Grady":Grady, \ "hcc": hcc, "mesh":mesh, "actind":actind, "waterind": waterind, \ "xsurf":xsurf, "ysurf":ysurf, "yup":yup} return fluiddata
def get_interpolation_matrix( self, npts=20, epsilon=None ): tree_2d = kdtree(self.topography[:, :2]) xy = Utils.ndgrid(self.mesh_3d.vectorCCx, self.mesh_3d.vectorCCy) distance, inds = tree_2d.query(xy, k=npts) if epsilon is None: epsilon = np.min([self.mesh_3d.hx.min(), self.mesh_3d.hy.min()]) w = 1. / (distance + epsilon)**2 w = Utils.sdiag(1./np.sum(w, axis=1)) * (w) I = Utils.mkvc( np.arange(inds.shape[0]).reshape([-1, 1]).repeat(npts, axis=1) ) J = Utils.mkvc(inds) self._P = sp.coo_matrix( (Utils.mkvc(w), (I, J)), shape=(inds.shape[0], self.topography.shape[0]) ) mesh_1d = Mesh.TensorMesh([np.r_[self.hz[:-1], 1e20]]) z = self.P*self.topography[:, 2] self._actinds = Utils.surface2ind_topo(self.mesh_3d, np.c_[xy, z]) Z = np.empty(self.mesh_3d.vnC, dtype=float, order='F') Z = self.mesh_3d.gridCC[:, 2].reshape( (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F' ) ACTIND = self._actinds.reshape( (self.mesh_3d.nCx*self.mesh_3d.nCy, self.mesh_3d.nCz), order='F' ) self._Pz = [] # This part can be cythonized or parallelized for i_xy in range(self.mesh_3d.nCx*self.mesh_3d.nCy): actind_temp = ACTIND[i_xy, :] z_temp = -(Z[i_xy, :] - z[i_xy]) self._Pz.append(mesh_1d.getInterpolationMat(z_temp[actind_temp]))
def drapeTopotoLoc(mesh, topo, pts): """ Drape """ if mesh.dim == 2: if pts.ndim > 1: raise Exception("pts should be 1d array") elif mesh.dim == 3: if pts.shape[1] == 3: raise Exception("shape of pts should be (x,3)") else: raise NotImplementedError() airind = Utils.surface2ind_topo(mesh, topo) meshtemp, topoCC = gettopoCC(mesh, ~airind) inds = Utils.closestPoints(meshtemp, pts) return np.c_[pts, topoCC[inds]]
def drapeTopotoLoc(mesh, topo, pts): """ Drape """ if mesh.dim ==2: if pts.ndim > 1: raise Exception("pts should be 1d array") elif mesh.dim ==3: if pts.shape[1] == 3: raise Exception("shape of pts should be (x,3)") else: raise NotImplementedError() airind = Utils.surface2ind_topo(mesh, topo) meshtemp, topoCC = gettopoCC(mesh, ~airind) inds = Utils.closestPoints(meshtemp, pts) return np.c_[pts, topoCC[inds]]
def setUp(self): ndv = -100 # Create a self.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)] self.mesh = Mesh.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., 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) + self.mesh.vectorNz[-1] + 5. # Create a MAGsurvey locXYZ = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseGrav.RxObs(locXYZ) srcField = PF.BaseGrav.SrcField([rxLoc]) survey = PF.BaseGrav.LinearSurvey(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 prob = PF.Gravity.GravityIntegral( self.mesh, rhoMap=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))*0.001 wd = np.ones(len(data))*.001 survey.dobs = data survey.std = wd # PF.Gravity.plot_obs_2D(survey.srcField.rxList[0].locs, d=data) # Create sensitivity weights from our linear forward operator wr = PF.Magnetics.get_dist_wgt(self.mesh, locXYZ, actv, 2., 2.) wr = wr**2. # Create a regularization reg = Regularization.Sparse(self.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 = 5e-2, 1e-2 # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 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, beta=1e+8) # 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, update_Jacobi])
# 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()) ########################################################################### # Forward modeling data # --------------------- # # We can now generate TMI data # # 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],
def set_mesh(self, topo=None, dx=None, dy=None, dz=None, n_spacing=None, corezlength=None, npad_x=7, npad_y=7, npad_z=7, pad_rate_x=1.3, pad_rate_y=1.3, pad_rate_z=1.3, ncell_per_dipole=4, mesh_type='TensorMesh', dimension=2, method='nearest' ): """ Set up a mesh for a given DC survey """ if mesh_type == 'TreeMesh': raise NotImplementedError() # 2D or 3D mesh if dimension in [2, 3]: if dimension == 2: z_ind = 1 else: z_ind = 2 a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min() lineLength = abs( self.electrode_locations[:, 0].max() - self.electrode_locations[:, 0].min() ) dx_ideal = a/ncell_per_dipole if dx is None: dx = dx_ideal warnings.warn( "dx is set to {} m (samllest electrode spacing ({}) / {})".format(dx, a, ncell_per_dipole) ) if dz is None: dz = dx*0.5 warnings.warn( "dz ({} m) is set to dx ({} m) / {}".format(dz, dx, 2) ) x0 = self.electrode_locations[:, 0].min() if topo is None: # For 2D mesh if dimension == 2: # sort by x row_idx = np.lexsort((self.electrode_locations[:, 0],)) # For 3D mesh else: # sort by x, then by y row_idx = np.lexsort((self.electrode_locations[:, 1], self.electrode_locations[:, 0])) locs = self.electrode_locations[row_idx, :] else: # For 2D mesh if dimension == 2: # sort by x mask = np.isin(self.electrode_locations[:, 0], topo[:, 0]) if np.any(mask): raise RuntimeError("the x coordinates of some topo and electrodes are the same.") locs_tmp = np.vstack((topo, self.electrode_locations[~mask, :])) row_idx = np.lexsort((locs_tmp[:, 0],)) # For 3D mesh else: # sort by x, then by y dtype = [('x', np.float64), ('y', np.float64)] mask = np.isin(self.electrode_locations[:, [0, 1]].copy().view(dtype), topo[:, [0, 1]].copy().view(dtype)).flatten() if np.any(mask): raise RuntimeError("the x and y coordinates of some topo and electrodes are the same.") locs_tmp = np.vstack((topo, self.electrode_locations[~mask, :])) row_idx = np.lexsort((locs_tmp[:, 1], locs_tmp[:, 0])) locs = locs_tmp[row_idx, :] if dx > dx_ideal: # warnings.warn( # "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a) # ) pass self.dx = dx self.dz = dz self.npad_x = npad_x self.npad_z = npad_z self.pad_rate_x = pad_rate_x self.pad_rate_z = pad_rate_z self.ncell_per_dipole = ncell_per_dipole zmax = locs[:, z_ind].max() zmin = locs[:, z_ind].min() # 3 cells each for buffer corexlength = lineLength + dx * 6 if corezlength is None: corezlength = self.grids[:, z_ind].max() ncx = np.round(corexlength/dx) ncz = np.round(corezlength/dz) hx = [ (dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x) ] hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)] x0_mesh = -( (dx * pad_rate_x ** (np.arange(npad_x)+1)).sum() + dx * 3 - x0 ) z0_mesh = -((dz * pad_rate_z ** (np.arange(npad_z)+1)).sum() + dz * ncz) + zmax # For 2D mesh if dimension == 2: h = [hx, hz] x0_for_mesh = [x0_mesh, z0_mesh] self.xyzlim = np.vstack(( np.r_[x0, x0+lineLength], np.r_[zmax-corezlength, zmax] )) fill_value = "extrapolate" # For 3D mesh else: if dy is None: raise Exception("You must input dy (m)") self.dy = dy self.npad_y = npad_y self.pad_rate_y = pad_rate_y ylocs = np.unique(self.electrode_locations[:, 1]) ymin, ymax = ylocs.min(), ylocs.max() # 3 cells each for buffer in y-direction coreylength = ymax-ymin+dy*6 ncy = np.round(coreylength/dy) hy = [ (dy, npad_y, -pad_rate_y), (dy, ncy), (dy, npad_y, pad_rate_y) ] y0 = ylocs.min()-dy/2. y0_mesh = -( (dy * pad_rate_y ** (np.arange(npad_y)+1)).sum() + dy*3 - y0 ) h = [hx, hy, hz] x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh] self.xyzlim = np.vstack(( np.r_[x0, x0+lineLength], np.r_[ymin-dy*3, ymax+dy*3], np.r_[zmax-corezlength, zmax] )) fill_value = np.nan mesh = Mesh.TensorMesh(h, x0=x0_for_mesh) actind = Utils.surface2ind_topo(mesh, locs, method=method, fill_value=fill_value) else: raise NotImplementedError() return mesh, actind
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 = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey_dc.getABMN_locations() survey_dc = IO.from_ambn_locations_to_survey(survey_dc.a_locations, survey_dc.b_locations, survey_dc.m_locations, survey_dc.n_locations, survey_type, data_dc_type='volt', data_ip_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_dc.drapeTopo(mesh, actind, option="top") # Build conductivity and chargeability 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) blk_inds_charg = Utils.ModelBuilder.getIndicesSphere( np.r_[100., -25], 12.5, mesh.gridCC) 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 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.Problem2D_N(mesh, rhoMap=mapping, storeJ=True, Solver=Solver) # Pair problem with survey try: prb.pair(survey_dc) except: survey_dc.unpair() prb.pair(survey_dc) # Make synthetic DC data with 5% Gaussian noise dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True) IO.data_dc = dtrue_dc # Generate mtrue_ip for chargability mtrue_ip = charg[actind] # Generate 2.5D DC problem # "N" means potential is defined at nodes prb_ip = IP.Problem2D_N(mesh, etaMap=actmap, storeJ=True, rho=rho, Solver=Solver) survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="2.5D") prb_ip.pair(survey_ip) dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05) IO.data_ip = dtrue_ip # 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.) # Set uncertainty # floor eps_dc = 10**(-3.2) # percentage std_dc = 0.05 mopt_dc, pred_dc = DC.run_inversion(m0_dc, survey_dc, actind, mesh, std_dc, eps_dc, 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 uncertainty # floor eps_ip = 10**(-4) # percentage std_ip = 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, survey_ip, actind, mesh, std_ip, eps_ip, upper=np.Inf, lower=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()
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, 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()
#%% ## TESTING CODE # Generate survey using two tiles, compute solution using UBC-DCIP3D # and compare by using the pre-computed grid padxy = np.r_[dx[1]*expf**(np.asarray(range(npadxy['DC']))+1)] padz = np.r_[dx[1]*expf**(np.asarray(range(npadz['DC']))+1)] hx = np.r_[padxy[::-1], core['DC'], padxy] hy = np.r_[padxy[::-1], core['DC'],core['DC'], padxy] hz = np.r_[padz[::-1],[33],np.ones(25)*30,[23,18,15,12], np.ones(15)*10,[12,15,18,23],30*expf**(np.asarray(range(npadz['DC'])))] mesh = Mesh.TensorMesh([hx,hy,hz], 'CC0') mesh._x0 = (mesh.x0[0] + np.mean(X[tID]), mesh.x0[1]+np.mean(Y[tID]), mesh.x0[2]-(np.sum(hz[:(npadz['DC']+20)]))) # Extract model from global tolocal mesh actv2 = Utils.surface2ind_topo(mesh, topo, 'N') P = Maps.Mesh2MeshTopo([mesh_global,mesh],[actv,actv2],nIterpPts = 12) model = mesh_global.readModelUBC(work_dir + '\\' + modelfile['DC']) model_Tile = P*(model[actv]) m = np.ones(mesh.nC)*1e-8 m[actv2] = model_Tile # mtemp = m.reshape(mesh.vnC, order='F') Mesh.TensorMesh.writeUBC(mesh,work_dir +'\\MeshTile.msh') Mesh.TensorMesh.writeModelUBC(mesh,work_dir +'\\MeshTile.mod',m) # Create survey
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(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 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(-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 GRAVsurvey 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 density 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.75 model[(midx+1):(midx+5), (midy-2):(midy+2), -10:-6] = -0.75 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 = np.c_[0, 0, 0, 0] # 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(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=30, coolEpsFact=1.5, beta_tol=1e-1, ) 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 = -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 Utils.PlotUtils.plot2Ddata(rxLoc, 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') # Vertical 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') # 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, np.max(saveDict.phi_d)/2., '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, survey_type="pole-dipole"): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations fileName1 = "/Users/juan/Documents/testData/fmdata-daf.con" # output mod fileName2 = "/Users/juan/Documents/testData/forwardmodel.msh" # input mesh mesh = Mesh.TensorMesh._readUBC_3DMesh(fileName2) # Read in/create mesh print("Starting forward modeling") start = clock() # Define model Background rx = getRxData() # rx locations tx = getTxData() # tx locations survey_dc = generateSurvey(rx, tx, 45, 55) # create survey object survey_dc.survey_type = "pole-dipole" survey_dc.getABMN_locations() # get locations # survey_dc = IO.from_ambn_locations_to_survey( # survey_dc.a_locations, survey_dc.b_locations, # survey_dc.m_locations, survey_dc.n_locations, # survey_type, data_dc_type='volt', data_ip_type='volt' # ) uniq = Utils.uniqueRows( np.vstack((survey_dc.a_locations, survey_dc.b_locations, survey_dc.m_locations, survey_dc.n_locations))) electrode_locations = uniq[0] # assign actinds = Utils.surface2ind_topo(mesh, electrode_locations, method='cubic') # active indicies # survey_dc.drapeTopo(mesh, actinds) IO.a_locations = survey_dc.a_locations.copy() IO.b_locations = survey_dc.b_locations.copy() IO.m_locations = survey_dc.m_locations.copy() IO.n_locations = survey_dc.n_locations.copy() # drape topo IO.data_dc_type = 'volt' IO.G = IO.geometric_factor(survey_dc) # ============================================================================= # create sphere for ice representation x0 = (np.max(mesh.gridCC[:, 0]) + np.min(mesh.gridCC[:, 0])) / 2. + 50 # x0 center point of sphere y0 = (np.max(mesh.gridCC[:, 1]) + np.min(mesh.gridCC[:, 1])) / 2. - 50 # y0 center point of sphere z0 = 2350 # x0 center point of sphere # (np.max(mesh.gridCC[:, 2]) + np.min(mesh.gridCC[:, 2])) / 2. r0 = 500 # radius of sphere print(x0, y0, z0) csph = (np.sqrt((mesh.gridCC[:, 0] - x0)**2. + (mesh.gridCC[:, 1] - y0)**2. + (mesh.gridCC[:, 2] - z0)**2.)) < r0 # indicies of sphere # sphere done ================================================================= # ============================================================================ # Create model mx = np.ones(mesh.nC) * 0.018 # chargeability sigma = np.ones(mesh.nC) * 1. / 15000. # create dipping structure parameters theta = 45. * np.pi / 180. # dipping angle x0_d = 374700. x1_d = 375000. y0_d = 6275850. y0_1d = 900. * np.sin(theta) + y0_d y1_d = 6275900. y1_1d = 900. * np.sin(theta) + y1_d z0_d = 1900. z1_d = z0_d - (900. * np.cos(theta)) m_ = (z0_d - z1_d) / (y0_1d - y0_d) # slope of dip # loop through mesh and assign dipping structure conductivity for idx in range(mesh.nC): if z1_d <= mesh.gridCC[idx, 2] <= z0_d: if (x0_d <= mesh.gridCC[idx, 0] <= x1_d): yslope1 = y0_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d) yslope2 = y1_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d) if yslope1 <= mesh.gridCC[idx, 1] <= yslope2: mx[idx] = 0.035 sigma[idx] = 1. / 300. # mx[csph] = ((0.025) * # np.ones_like(mx[csph])) # set sphere values mx[~actinds] = 1. / 1e8 # flag air values # sigma[csph] = ((5000.) * # np.ones_like(sigma[csph])) # set sphere values sigma[~actinds] = 1. / 1e8 # flag air values rho = 1. / sigma stop = clock() print(stop) # plot results # Show the true conductivity model if plotIt: ncy = mesh.nCy ncz = mesh.nCz ncx = mesh.nCx print(mesh.nC) clim = [0, 0.04] fig, ax = plt.subplots(2, 2, figsize=(12, 6)) ax = Utils.mkvc(ax) dat = mesh.plotSlice(((mx)), ax=ax[0], normal='Z', clim=clim, ind=int(ncz / 2 - 14), pcolorOpts={"cmap": "jet"}) ax[0].plot(rx[:, 0], rx[:, 1], 'or') ax[0].plot(tx[:, 0], tx[:, 1], 'dk') mesh.plotSlice(((mx)), ax=ax[1], normal='Y', clim=clim, ind=int(ncy / 2 + 2), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mx)), ax=ax[2], normal='X', clim=clim, ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mx)), ax=ax[3], normal='X', clim=clim, ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"}) cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7]) cb = plt.colorbar(dat[0], ax=cbar_ax) fig.subplots_adjust(right=0.85) cb.set_label('V/V') cbar_ax.axis('off') plt.show() # print(mtrue.min(), mtrue.max()) # clim = [0, 20000] # fig, ax = plt.subplots(2, 2, figsize=(12, 6)) # ax = Utils.mkvc(ax) # dat = mesh.plotSlice(((mtrue)), ax=ax[0], normal='Z', clim=clim, # ind=int(ncz / 2 - 4), pcolorOpts={"cmap": "jet"}) # ax[0].plot(rx[:, 0], rx[:, 1], 'or') # mesh.plotSlice(((mtrue)), ax=ax[1], normal='Y', clim=clim, # ind=int(ncy / 2), pcolorOpts={"cmap": "jet"}) # mesh.plotSlice(((mtrue)), ax=ax[2], normal='X', clim=clim, # ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"}) # mesh.plotSlice(((mtrue)), ax=ax[3], normal='X', clim=clim, # ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"}) # cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7]) # cb = plt.colorbar(dat[0], ax=cbar_ax) # fig.subplots_adjust(right=0.85) # cb.set_label('rho') # cbar_ax.axis('off') # plt.show() # print(error.size, survey_ip.obs.size) # error = np.asarray(survey_ip.dobs) * (np.random.randint(-1, 2, survey_ip.dobs) / 20.) # survey_ip.dobs = survey_ip.dobs + error # Use Exponential Map: m = log(rho) actmap = Maps.InjectActiveCells(mesh, indActive=actinds, valInactive=np.log(1e8)) mapping = Maps.ExpMap(mesh) * actmap # Generate mtrue_dc for resistivity mtrue_dc = np.log(rho[actinds]) # Generate 3D DC problem # "CC" means potential is defined at center prb = DC.Problem3D_CC(mesh, rhoMap=mapping, storeJ=False, Solver=Solver) # Pair problem with survey # try: prb.pair(survey_dc) # except: # survey_dc.unpair() # prb.pair(survey_dc) survey_dc.dpred(mtrue_dc) # Make synthetic DC data with 5% Gaussian noise dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True) IO.data_dc = dtrue_dc # Generate mtrue_ip for chargability mtrue_ip = mx[actinds] # Generate 3D DC problem # "CC" means potential is defined at center prb_ip = IP.Problem3D_CC(mesh, etaMap=actmap, storeJ=False, rho=rho, Solver=Solver) survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="3D") survey_ip.survey_type = "pole-dipole" survey_ip.getABMN_locations() prb_ip.pair(survey_ip) survey_ip.dpred(mtrue_ip) dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05) survey_ip.std = np.ones_like(dtrue_ip) * 0.05 survey_ip.eps = np.ones_like(dtrue_ip) * 10**(-4) IO.data_ip = dtrue_ip DC.Utils.writeUBC_DCobs("fmip.obs", survey_ip, 3, 'GENERAL', 'pole-dipole')
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 = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey_dc.getABMN_locations() survey_dc = IO.from_ambn_locations_to_survey( survey_dc.a_locations, survey_dc.b_locations, survey_dc.m_locations, survey_dc.n_locations, survey_type, data_dc_type='volt', data_ip_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_dc.drapeTopo(mesh, actind, option="top") # Build conductivity and chargeability 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 ) blk_inds_charg = Utils.ModelBuilder.getIndicesSphere( np.r_[100., -25], 12.5, mesh.gridCC ) 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 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.Problem2D_N( mesh, rhoMap=mapping, storeJ=True, Solver=Solver ) # Pair problem with survey try: prb.pair(survey_dc) except: survey_dc.unpair() prb.pair(survey_dc) # Make synthetic DC data with 5% Gaussian noise dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True) IO.data_dc = dtrue_dc # Generate mtrue_ip for chargability mtrue_ip = charg[actind] # Generate 2.5D DC problem # "N" means potential is defined at nodes prb_ip = IP.Problem2D_N( mesh, etaMap=actmap, storeJ=True, rho=rho, Solver=Solver ) survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="2.5D") prb_ip.pair(survey_ip) dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05) IO.data_ip = dtrue_ip # 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.) # Set uncertainty # floor eps_dc = 10**(-3.2) # percentage std_dc = 0.05 mopt_dc, pred_dc = DC.run_inversion( m0_dc, survey_dc, actind, mesh, std_dc, eps_dc, 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 uncertainty # floor eps_ip = 10**(-4) # percentage std_ip = 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, survey_ip, actind, mesh, std_ip, eps_ip, upper=np.Inf, lower=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()
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., 90., 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., 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) # 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.ModelBuilder.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 prob = PF.Magnetics.MagneticIntegral(self.mesh, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data data = prob.fields(self.model) # Add noise and uncertainties (1nT) noise = np.random.randn(len(data)) data += noise wd = np.ones(len(data)) * 1. survey.dobs = data survey.std = wd # Create sensitivity weights from our linear forward operator rxLoc = survey.srcField.rxList[0].locs wr = prob.getJtJdiag(self.model)**0.5 wr /= np.max(wr) # Create a regularization reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.cell_weights = wr reg.mref = np.zeros(nC) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1. / survey.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=20, lower=0., upper=10., maxIterLS=20, maxIterCG=20, tolCG=1e-4, stepOffBoundsFact=1e-4) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+6) # 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=20, beta_tol=1e-1, betaSearch=False) update_Jacobi = Directives.UpdatePreconditioner() # saveOuput = Directives.SaveOutputEveryIteration() # saveModel.fileName = work_dir + out_dir + 'ModelSus' self.inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, update_Jacobi])
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 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 ] )
if topo is not None: meshLocal = meshutils.refine_tree_xyz( meshLocal, topo, method='surface', octree_levels=octree_levels_topo, finalize=False ) meshLocal = meshutils.refine_tree_xyz( meshLocal, topo_elevations_at_data_locs[ind_t, :], method='surface', max_distance=max_distance, octree_levels=octree_levels_obs, octree_levels_padding=octree_levels_padding, finalize=True, ) tileLayer = Utils.surface2ind_topo(meshLocal, topo) # Calculate approximate problem size nDt, nCt = ind_t.sum()*1. * len(survey.components), tileLayer.sum()*1. nChunks = n_cpu # Number of chunks cSa, cSb = int(nDt/nChunks), int(nCt/nChunks) # Chunk sizes usedRAM = nDt * nCt * 8. * 1e-9 count += 1 print(nDt, nCt, usedRAM, binCount.min()) del meshLocal nTiles = X1.shape[0] # Loop through the tiles and generate all sensitivities print("Number of tiles:" + str(nTiles))
if topo is not None: mesh = meshutils.refine_tree_xyz(mesh, topo, method='surface', octree_levels=octreeTopo, finalize=False) mesh = meshutils.refine_tree_xyz(mesh, newTopo, method='surface', octree_levels=octreeObs, octree_levels_padding=octree_levels_padding, finalize=True) # Compute active cells activeCells = Utils.surface2ind_topo(mesh, topo, gridLoc='CC') # activeCells = meshutils.activeTopoLayer(mesh, topo) Mesh.TreeMesh.writeUBC( mesh, workDir + dsep + outDir + 'OctreeMeshGlobal.msh', models={workDir + dsep + outDir + 'ActiveSurface.act': activeCells}) # Get the layer of cells directly below topo #activeCells = Utils.actIndFull2layer(mesh, active) nC = int(activeCells.sum()) # Number of active cells print(nC) # Create active map to go from reduce set to full activeCellsMap = Maps.InjectActiveCells(mesh, activeCells, ndv)
def run( plotIt=True, survey_type="dipole-dipole", rho_background=1e3, rho_block=1e2, block_x0=100, block_dx=10, block_y0=-10, block_dy=5 ): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations xmin, xmax = 0., 200. ymin, ymax = 0., 0. zmin, zmax = 0, 0 endl = np.array([[xmin, ymin, zmin], [xmax, ymax, zmax]]) # Generate DC survey object survey = DC.Utils.gen_DCIPsurvey(endl, survey_type=survey_type, dim=2, a=10, b=10, n=10) survey.getABMN_locations() survey = IO.from_ambn_locations_to_survey( survey.a_locations, survey.b_locations, survey.m_locations, survey.n_locations, survey_type, data_dc_type='volt' ) # Obtain 2D TensorMesh mesh, actind = IO.set_mesh() # Flat topography actind = Utils.surface2ind_topo( mesh, np.c_[mesh.vectorCCx, mesh.vectorCCx*0.] ) survey.drapeTopo(mesh, actind, option="top") # Use Exponential Map: m = log(rho) actmap = Maps.InjectActiveCells( mesh, indActive=actind, valInactive=np.log(1e8) ) parametric_block = Maps.ParametricBlock(mesh, slopeFact=1e2) mapping = Maps.ExpMap(mesh) * parametric_block # Set true model # val_background,val_block, block_x0, block_dx, block_y0, block_dy mtrue = np.r_[np.log(1e3), np.log(10), 100, 10, -20, 10] # Set initial model m0 = np.r_[ np.log(rho_background), np.log(rho_block), block_x0, block_dx, block_y0, block_dy ] rho = mapping * mtrue rho0 = mapping * m0 # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={'alpha': 0.2}, clim=(10, 1000), pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()} ) ax.plot( survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], 'k.' ) ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect('equal') ax.set_title("True resistivity model") plt.show() # Show the true conductivity model fig = plt.figure(figsize=(12, 3)) ax = plt.subplot(111) temp = rho0.copy() temp[~actind] = np.nan out = mesh.plotImage( temp, grid=False, ax=ax, gridOpts={'alpha': 0.2}, clim=(10, 1000), pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()} ) ax.plot( survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], 'k.' ) ax.set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax.set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[0]) cb.set_label("Resistivity (ohm-m)") ax.set_aspect('equal') ax.set_title("Initial resistivity model") plt.show() # Generate 2.5D DC problem # "N" means potential is defined at nodes prb = DC.Problem2D_N( mesh, rhoMap=mapping, storeJ=True, Solver=Solver ) # Pair problem with survey try: prb.pair(survey) except: survey.unpair() prb.pair(survey) # Make synthetic DC data with 5% Gaussian noise dtrue = survey.makeSyntheticData(mtrue, std=0.05, force=True) # Show apparent resisitivty pseudo-section IO.plotPseudoSection( data=survey.dobs/IO.G, data_type='apparent_resistivity' ) # Show apparent resisitivty histogram fig = plt.figure() out = hist(survey.dobs/IO.G, bins=20) plt.show() # Set uncertainty # floor eps = 10**(-3.2) # percentage std = 0.05 dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = abs(survey.dobs) * std + eps dmisfit.W = 1./uncert # Map for a regularization mesh_1d = Mesh.TensorMesh([parametric_block.nP]) # Related to inversion reg = Regularization.Simple(mesh_1d, alpha_x=0.) opt = Optimization.InexactGaussNewton(maxIter=10) invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2) betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) target = Directives.TargetMisfit() updateSensW = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner() invProb.beta = 0. inv = Inversion.BaseInversion( invProb, directiveList=[ target ] ) prb.counter = opt.counter = Utils.Counter() opt.LSshorten = 0.5 opt.remember('xc') # Run inversion mopt = inv.run(m0) # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping*mopt rho_true = rho.copy() # show recovered conductivity vmin, vmax = rho.min(), rho.max() fig, ax = plt.subplots(2, 1, figsize=(20, 6)) out1 = mesh.plotImage( rho_true, clim=(10, 1000), pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()}, ax=ax[0] ) out2 = mesh.plotImage( rho_est, clim=(10, 1000), pcolorOpts={"cmap": "viridis", "norm": colors.LogNorm()}, ax=ax[1] ) out = [out1, out2] for i in range(2): ax[i].plot( survey.electrode_locations[:, 0], survey.electrode_locations[:, 1], 'kv' ) ax[i].set_xlim(IO.grids[:, 0].min(), IO.grids[:, 0].max()) ax[i].set_ylim(-IO.grids[:, 1].max(), IO.grids[:, 1].min()) cb = plt.colorbar(out[i][0], ax=ax[i]) cb.set_label("Resistivity ($\Omega$m)") ax[i].set_xlabel("Northing (m)") ax[i].set_ylabel("Elevation (m)") ax[i].set_aspect('equal') ax[0].set_title("True resistivity model") ax[1].set_title("Recovered resistivity model") plt.tight_layout() plt.show()
def set_mesh(self, topo=None, dx=None, dy=None, dz=None, n_spacing=None, corezlength=None, npad_x=7, npad_y=7, npad_z=7, pad_rate_x=1.3, pad_rate_y=1.3, pad_rate_z=1.3, ncell_per_dipole=4, mesh_type='TensorMesh', dimension=2, method='nearest' ): """ Set up a mesh for a given DC survey """ if mesh_type == 'TreeMesh': raise NotImplementedError() # 2D or 3D mesh if dimension in [2, 3]: if dimension == 2: z_ind = 1 else: z_ind = 2 a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min() lineLength = abs( self.electrode_locations[:, 0].max() - self.electrode_locations[:, 0].min() ) dx_ideal = a/ncell_per_dipole if dx is None: dx = dx_ideal warnings.warn( "dx is set to {} m (samllest electrode spacing ({}) / {})".format(dx, a, ncell_per_dipole) ) if dz is None: dz = dx*0.5 warnings.warn( "dz ({} m) is set to dx ({} m) / {}".format(dz, dx, 2) ) x0 = self.electrode_locations[:, 0].min() if topo is None: locs = self.electrode_locations else: locs = np.vstack((topo, self.electrode_locations)) if dx > dx_ideal: # warnings.warn( # "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a) # ) pass self.dx = dx self.dz = dz self.npad_x = npad_x self.npad_z = npad_z self.pad_rate_x = pad_rate_x self.pad_rate_z = pad_rate_z self.ncell_per_dipole = ncell_per_dipole zmax = locs[:, z_ind].max() zmin = locs[:, z_ind].min() # 3 cells each for buffer corexlength = lineLength + dx * 6 if corezlength is None: corezlength = self.grids[:, z_ind].max() ncx = np.round(corexlength/dx) ncz = np.round(corezlength/dz) hx = [ (dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x) ] hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)] x0_mesh = -( (dx * pad_rate_x ** (np.arange(npad_x)+1)).sum() + dx * 3 - x0 ) z0_mesh = -((dz * pad_rate_z ** (np.arange(npad_z)+1)).sum() + dz * ncz) + zmax # For 2D mesh if dimension == 2: h = [hx, hz] x0_for_mesh = [x0_mesh, z0_mesh] self.xyzlim = np.vstack(( np.r_[x0, x0+lineLength], np.r_[zmax-corezlength, zmax] )) # For 3D mesh else: if dy is None: raise Exception("You must input dy (m)") self.dy = dy self.npad_y = npad_y self.pad_rate_y = pad_rate_y ylocs = np.unique(self.electrode_locations[:, 1]) ymin, ymax = ylocs.min(), ylocs.max() # 3 cells each for buffer in y-direction coreylength = ymax-ymin+dy*6 ncy = np.round(coreylength/dy) hy = [ (dy, npad_y, -pad_rate_y), (dy, ncy), (dy, npad_y, pad_rate_y) ] y0 = ylocs.min()-dy/2. y0_mesh = -( (dy * pad_rate_y ** (np.arange(npad_y)+1)).sum() + dy*3 - y0 ) h = [hx, hy, hz] x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh] self.xyzlim = np.vstack(( np.r_[x0, x0+lineLength], np.r_[ymin-dy*3, ymax+dy*3], np.r_[zmax-corezlength, zmax] )) mesh = Mesh.TensorMesh(h, x0=x0_for_mesh) actind = Utils.surface2ind_topo(mesh, locs, method=method) else: raise NotImplementedError() return mesh, actind
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 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(-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) # 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(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.norms = [0, 1, 1, 1] 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 # Use pick a treshold parameter empirically based on the distribution of # model parameters IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=3) update_Jacobi = Directives.Update_lin_PreCond() 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 = -5 m_l2 = actvMap * IRLS.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 PF.Magnetics.plot_obs_2D(rxLoc, d=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')
### make a mesh mesh = Mesh.TensorMesh([hx_ind, hy_ind, hz_ind], 'CCC') # Get index of the center mid_x = int(mesh.nCx/2) mid_y = 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 active_cells = Utils.surface2ind_topo(mesh, topo, 'N') active_cells = np.where(active_cells)[0] num_cells = len(active_cells) ### Create and array of observation points x_receiver = np.linspace(-30., 30., 20) y_receiver = np.linspace(-30., 30., 20) X_r, Y_r = np.meshgrid(x_receiver, y_receiver) ### Move the observation points 5m (?) above the topo Z_r = -np.exp((X_r**2 + Y_r**2) / 75**2) + mesh.vectorNz[-1] + 0.001 ### Create a GRAVsurvey ### make an array of station locations rx_loc = np.c_[Utils.mkvc(X_r.T), Utils.mkvc(Y_r.T), Utils.mkvc(Z_r.T)]
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 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(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 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., 90., 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., 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) # 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) # nCy = 2**(int(np.log2(extent/h[1]))+1) # nCz = 2**(int(np.log2(extent/h[2]))+1) # Define the mesh and origin # For now cubic cells self.mesh = Mesh.TreeMesh([np.ones(nCx)*h[0], np.ones(nCx)*h[1], np.ones(nCx)*h[2]]) # Set origin self.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 = self.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 _ in range(int(nCpad[ii])): self.mesh.insert_cells( np.c_[mkvc(CCx), mkvc(CCy), z-zOffset], np.ones_like(z)*maxLevel-ii, finalize=False ) zOffset += dx self.mesh.finalize() # 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.ModelBuilder.addBlock( self.mesh.gridCC, np.zeros(self.mesh.nC), np.r_[-20, -20, -5], np.r_[20, 20, 30], 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 prob = PF.Magnetics.MagneticIntegral( self.mesh, chiMap=idenMap, actInd=actv ) # Pair the survey and problem survey.pair(prob) # Compute linear forward operator and compute some data data = prob.fields(self.model) # Add noise and uncertainties (1nT) noise = np.random.randn(len(data)) data += noise wd = np.ones(len(data))*1. survey.dobs = data survey.std = wd # Create sensitivity weights from our linear forward operator rxLoc = survey.srcField.rxList[0].locs wr = np.zeros(prob.G.shape[1]) for ii in range(survey.nD): wr += (prob.G[ii, :]/survey.std[ii])**2. # wr = (wr/np.max(wr)) wr = wr**0.5 # Create a regularization reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.cell_weights = wr reg.mref = np.zeros(nC) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1./survey.std # Add directives to the inversion opt = Optimization.ProjectedGNCG( maxIter=20, lower=0., upper=10., maxIterLS=20, maxIterCG=20, tolCG=1e-4, stepOffBoundsFact=1e-4 ) invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e+4) # 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=20, beta_tol=5e-1 ) update_Jacobi = Directives.UpdatePreconditioner() # saveOuput = Directives.SaveOutputEveryIteration() # saveModel.fileName = work_dir + out_dir + 'ModelSus' self.inv = Inversion.BaseInversion( invProb, directiveList=[IRLS, update_Jacobi] )
(mesh.gridCC[:, 2] - z0)**2.)) < r0 # indicies of sphere # sphere done ================================================================= print("Starting forward modeling") start = clock() # Define model Background ln_sigback = 0.023 # chargeability rx = getRxData() # rx locations tx = getTxData() # tx locations survey = generateSurvey(rx, tx, 45, 65) # create survey object survey.getABMN_locations() # get locations uniq = Utils.uniqueRows( np.vstack((survey.a_locations, survey.b_locations, survey.m_locations, survey.n_locations))) # row the locations electrode_locations = uniq[0] # assign actinds = Utils.surface2ind_topo(mesh, electrode_locations, method='cubic') # active indicies survey.drapeTopo(mesh, actinds) # drape topo # ============================================================================ # Create model mx = np.ones(mesh.nC) * 0.015 # chargeability sigma = np.ones(mesh.nC) * 1. / 33000. # create dipping structure parameters theta = 45. * np.pi / 180. # dipping angle x0_d = 374700. x1_d = 375000. y0_d = 6275850. y0_1d = 500. * np.sin(theta) + y0_d y1_d = 6275900. y1_1d = 500. * np.sin(theta) + y1_d z0_d = 1860.
def run(plotIt=True, survey_type="pole-dipole"): np.random.seed(1) # Initiate I/O class for DC IO = DC.IO() # Obtain ABMN locations fileName1 = "C:/Users/johnk/Projects/Seabridge/fmdataDC.con" # output mod fileName1_ = "C:/Users/johnk/Projects/Seabridge/fmdataIP.chg" # output mod fileName2 = "C:/Users/johnk/Projects/Seabridge/forwardmodel.msh" # in mesh mesh = Mesh.TensorMesh._readUBC_3DMesh(fileName2) # Read in/create mesh print("Starting forward modeling") start = clock() # Define model Background rx = getRxData() # rx locations tx = getTxData() # tx locations survey_dc = generateSurvey(rx, tx, 45, 65) # create survey object survey_dc.getABMN_locations() # get locations # survey_dc = IO.from_ambn_locations_to_survey( # survey_dc.a_locations, survey_dc.b_locations, # survey_dc.m_locations, survey_dc.n_locations, # survey_type, data_dc_type='volt', data_ip_type='volt' # ) uniq = Utils.uniqueRows(np.vstack((survey_dc.a_locations, survey_dc.b_locations, survey_dc.m_locations, survey_dc.n_locations))) electrode_locations = uniq[0] # assign actinds = Utils.surface2ind_topo(mesh, electrode_locations, method='cubic') # active indicies survey_dc.drapeTopo(mesh, actinds) # drape topo # ============================================================================= # create sphere for ice representation x0 = (np.max(mesh.gridCC[:, 0]) + np.min(mesh.gridCC[:, 0])) / 2. + 50 # x0 center point of sphere y0 = (np.max(mesh.gridCC[:, 1]) + np.min(mesh.gridCC[:, 1])) / 2. - 50 # y0 center point of sphere z0 = 2350 # x0 center point of sphere # (np.max(mesh.gridCC[:, 2]) + np.min(mesh.gridCC[:, 2])) / 2. r0 = 500 # radius of sphere print(x0, y0, z0) csph = (np.sqrt((mesh.gridCC[:, 0] - x0)**2. + (mesh.gridCC[:, 1] - y0)**2. + (mesh.gridCC[:, 2] - z0)**2.)) < r0 # indicies of sphere # sphere done ================================================================= # ============================================================================ # Create model mx = np.ones(mesh.nC) * 0.020 # chargeability sigma = np.ones(mesh.nC) * 1. / 15000. # create dipping structure parameters theta = 45. * np.pi / 180. # dipping angle x0_d = 374700. x1_d = 375000. y0_d = 6275850. y0_1d = 500. * np.sin(theta) + y0_d y1_d = 6275900. y1_1d = 500. * np.sin(theta) + y1_d z0_d = 1860. z1_d = z0_d - (500. * np.cos(theta)) m_ = (z0_d - z1_d) / (y0_1d - y0_d) # slope of dip # loop through mesh and assign dipping structure conductivity for idx in range(mesh.nC): if z1_d <= mesh.gridCC[idx, 2] <= z0_d: if (x0_d <= mesh.gridCC[idx, 0] <= x1_d): yslope1 = y0_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d) yslope2 = y1_d + (1. / m_) * (mesh.gridCC[idx, 2] - z0_d) if yslope1 <= mesh.gridCC[idx, 1] <= yslope2: mx[idx] = 0.03 sigma[idx] = 1. / 300. # mx[csph] = ((0.025) * # np.ones_like(mx[csph])) # set sphere values mx[~actinds] = 1. / 1e8 # flag air values # sigma[csph] = ((5000.) * # np.ones_like(sigma[csph])) # set sphere values sigma[~actinds] = 1. / 1e8 # flag air values rho = 1. / sigma stop = clock() print(stop) # plot results # Show the true conductivity model if plotIt: ncy = mesh.nCy ncz = mesh.nCz ncx = mesh.nCx mtrue = mx print(mtrue.min(), mtrue.max()) clim = [0, 0.04] fig, ax = plt.subplots(2, 2, figsize=(12, 6)) ax = Utils.mkvc(ax) dat = mesh.plotSlice(((mx)), ax=ax[0], normal='Z', clim=clim, ind=int(ncz / 2), pcolorOpts={"cmap": "jet"}) ax[0].plot(rx[:, 0], rx[:, 1], 'or') ax[0].plot(tx[:, 0], tx[:, 1], 'dk') mesh.plotSlice(((mx)), ax=ax[1], normal='Y', clim=clim, ind=int(ncy / 2 + 2), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mx)), ax=ax[2], normal='X', clim=clim, ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mx)), ax=ax[3], normal='X', clim=clim, ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"}) cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7]) cb = plt.colorbar(dat[0], ax=cbar_ax) fig.subplots_adjust(right=0.85) cb.set_label('V/V') cbar_ax.axis('off') plt.show() mtrue = 1. / sigma print(mtrue.min(), mtrue.max()) clim = [0, 20000] fig, ax = plt.subplots(2, 2, figsize=(12, 6)) ax = Utils.mkvc(ax) dat = mesh.plotSlice(((mtrue)), ax=ax[0], normal='Z', clim=clim, ind=int(ncz / 2 - 4), pcolorOpts={"cmap": "jet"}) ax[0].plot(rx[:, 0], rx[:, 1], 'or') ax[0].plot(tx[:, 0], tx[:, 1], 'dk') mesh.plotSlice(((mtrue)), ax=ax[1], normal='Y', clim=clim, ind=int(ncy / 2), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mtrue)), ax=ax[2], normal='X', clim=clim, ind=int(ncx / 2 + 4), pcolorOpts={"cmap": "jet"}) mesh.plotSlice(((mtrue)), ax=ax[3], normal='X', clim=clim, ind=int(ncx / 2 + 8), pcolorOpts={"cmap": "jet"}) cbar_ax = fig.add_axes([0.82, 0.15, 0.05, 0.7]) cb = plt.colorbar(dat[0], ax=cbar_ax) fig.subplots_adjust(right=0.85) cb.set_label('rho') cbar_ax.axis('off') plt.show() # Use Exponential Map: m = log(rho) actmap = Maps.InjectActiveCells( mesh, indActive=actinds, valInactive=np.log(1e8) ) mapping = Maps.ExpMap(mesh) * actmap # Generate mtrue_dc for resistivity mtrue_dc = np.log(rho[actinds]) # Generate 3D DC problem # "CC" means potential is defined at center prb = DC.Problem3D_CC( mesh, rhoMap=mapping, storeJ=False, Solver=Solver ) # Pair problem with survey try: prb.pair(survey_dc) except: survey_dc.unpair() prb.pair(survey_dc) # Make synthetic DC data with 5% Gaussian noise dtrue_dc = survey_dc.makeSyntheticData(mtrue_dc, std=0.05, force=True) IO.data_dc = dtrue_dc # Generate mtrue_ip for chargability mtrue_ip = mx[actinds] # Generate 3D DC problem # "CC" means potential is defined at center prb_ip = IP.Problem3D_CC( mesh, etaMap=actmap, storeJ=False, rho=rho, Solver=Solver ) survey_ip = IP.from_dc_to_ip_survey(survey_dc, dim="3D") prb_ip.pair(survey_ip) dtrue_ip = survey_ip.makeSyntheticData(mtrue_ip, std=0.05) IO.data_ip = dtrue_ip # 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(10000.) # Set uncertainty # floor eps_dc = 10**(-3.2) # percentage std_dc = 0.05 mopt_dc, pred_dc = DC.run_inversion( m0_dc, survey_dc, actinds, mesh, std_dc, eps_dc, use_sensitivity_weight=False) # Convert obtained inversion model to resistivity # rho = M(m), where M(.) is a mapping rho_est = mapping * mopt_dc # rho_est[~actinds] = np.nan rho_true = rho.copy() rho_true[~actinds] = np.nan # write data to file out_file = open(fileName1, "w") for i in range(rho_est.size): out_file.write("%0.5e\n" % rho_est[i]) # Set initial model based upon histogram m0_ip = np.ones(actmap.nP) * 1e-10 # Set uncertainty # floor eps_ip = 10**(-4) # percentage std_ip = 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, survey_ip, actinds, mesh, std_ip, eps_ip, upper=np.Inf, lower=0., use_sensitivity_weight=False) # 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[~actinds] = np.nan charg_true = charg.copy() charg_true[~actinds] = np.nan # write IP data to file out_file = open(fileName1_, "w") for i in range(charg_est.size): out_file.write("%0.5e\n" % charg_est[i])
def setUp(self): ndv = -100 # 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 locXYZ = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] rxLoc = PF.BaseGrav.RxObs(locXYZ) srcField = PF.BaseGrav.SrcField([rxLoc]) survey = PF.BaseGrav.LinearSurvey(srcField) # We can now create a density 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.5 model = Utils.mkvc(model) self.model = model[actv] # Create active map to go from reduce set to full actvMap = Maps.InjectActiveCells(mesh, actv, ndv) # 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(self.model) # Add noise and uncertainties (1nT) data = d + np.random.randn(len(d))*0.001 wd = np.ones(len(data))*.001 survey.dobs = data survey.std = wd # PF.Gravity.plot_obs_2D(survey.srcField.rxList[0].locs, d=data) # Create sensitivity weights from our linear forward operator wr = PF.Magnetics.get_dist_wgt(mesh, locXYZ, actv, 2., 2.) wr = wr**2. # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wr reg.norms = [0, 1, 1, 1] reg.eps_p, reg.eps_q = 5e-2, 1e-2 # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 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, beta=1e+8) # Here is where the norms are applied IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=3) update_Jacobi = Directives.Update_lin_PreCond(mapping=idenMap) self.inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, update_Jacobi])
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 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
rxLoc[:, 1] > ylim[0], rxLoc[:, 1] < ylim[1]], axis=0) if np.sum(ind_t) < 20: continue rxLoc_t = PF.BaseMag.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseMag.SrcField([rxLoc_t], param=survey.srcField.param) survey_t = PF.BaseMag.LinearSurvey(srcField) survey_t.dobs = survey.dobs[ind_t] survey_t.std = survey.std[ind_t] # Extract model from global to local mesh if driver.topofile is not None: topo = np.genfromtxt(work_dir + driver.topofile, skip_header=1) actv = Utils.surface2ind_topo(mesh_t, topo, 'N') actv = np.asarray(np.where(mkvc(actv))[0], dtype=int) else: actv = np.ones(mesh_t.nC, dtype='bool') nC = len(actv) # print("Tile "+str(tt)) print(nC, np.sum(ind_t)) # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(mesh_t, actv, -100) # Create identity map idenMap = Maps.IdentityMap(nP=nC) mstart = np.ones(nC)*1e-4
def createLocalProb(rxLoc, wrGlobal, lims): # Grab the data for current tile ind_t = np.all([ rxLoc[:, 0] >= lims[0], rxLoc[:, 0] <= lims[1], rxLoc[:, 1] >= lims[2], rxLoc[:, 1] <= lims[3], surveyMask ], axis=0) # Remember selected data in case of tile overlap surveyMask[ind_t] = False # Create new survey rxLoc_t = PF.BaseGrav.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseGrav.SrcField([rxLoc_t]) survey_t = PF.BaseGrav.LinearSurvey(srcField) survey_t.dobs = survey.dobs[ind_t] survey_t.std = survey.std[ind_t] survey_t.ind = ind_t # mesh_t = meshTree.copy() mesh_t = Utils.modelutils.meshBuilder(rxLoc[ind_t, :], h, padDist, meshGlobal=meshInput, meshType='TREE', gridLoc='CC') mesh_t = Utils.modelutils.refineTree(mesh_t, topo, dtype='surface', nCpad=[0, 3, 2], finalize=False) mesh_t = Utils.modelutils.refineTree(mesh_t, rxLoc[ind_t, :], dtype='surface', nCpad=[10, 5, 5], finalize=False) center = np.mean(rxLoc[ind_t, :], axis=0) tileCenter = np.r_[np.mean(lims[0:2]), np.mean(lims[2:]), center[2]] ind = closestPoints(mesh, tileCenter, gridLoc='CC') shift = np.squeeze(mesh.gridCC[ind, :]) - center mesh_t.x0 += shift mesh_t.finalize() print(mesh_t.nC) actv_t = Utils.surface2ind_topo(mesh_t, topo) # Create reduced identity map tileMap = Maps.Tile((mesh, actv), (mesh_t, actv_t)) tileMap.nCell = 40 tileMap.nBlock = 1 # Create the forward model operator prob = PF.Gravity.GravityIntegral(mesh_t, rhoMap=tileMap, actInd=actv_t, memory_saving_mode=True, parallelized=True) survey_t.pair(prob) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey_t) dmis.W = 1. / survey_t.std wrGlobal += prob.getJtJdiag(np.ones(tileMap.P.shape[1])) # Create combo misfit function return dmis, wrGlobal
ind = Utils.ModelBuilder.getIndicesSphere(loc, radi, mesh.gridCC) model[ind] = sig[1] # Create quick topo xtopo, ytopo = np.meshgrid(mesh.vectorNx, mesh.vectorNy) ztopo = np.zeros_like(xtopo) topo = np.c_[mkvc(xtopo), mkvc(ytopo), mkvc(ztopo)] # Write out topo file fid = open('Topo.topo', 'w') fid.write(str(topo.shape[0]) + '\n') np.savetxt(fid, topo, fmt='%f', delimiter=' ', newline='\n') fid.close() ind = Utils.surface2ind_topo(mesh, topo, gridLoc='N') # Change aircells model[ind == 0] = air # Write out model Mesh.TensorMesh.writeUBC(mesh, 'Mesh.msh') Mesh.TensorMesh.writeModelUBC(mesh, mfile, model) # Create survey locs centered about origin and write to file locx, locy = np.meshgrid(np.linspace(-xlim, xlim, nstn), np.linspace(-xlim, xlim, nstn)) locz = np.ones_like(locx) * rx_height rxLoc = np.c_[mkvc(locx), mkvc(locy), mkvc(locz)]
def setUp(self): np.random.seed(0) # Define the inducing field parameter H0 = (50000, 90, 0) # Create a 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)] 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.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 = 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, mapping=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.0 survey.dobs = data survey.std = wd # Create sensitivity weights from our linear forward operator wr = np.sum(prob.G ** 2.0, axis=0) ** 0.5 wr = wr / np.max(wr) # Create a regularization reg = Regularization.Sparse(mesh, indActive=actv, mapping=idenMap) reg.cell_weights = wr # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey) dmis.Wd = 1 / wd # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=100, lower=0.0, upper=1.0, 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(norms=([0, 1, 1, 1]), eps=(1e-3, 1e-3), f_min_change=1e-3, minGNiter=3) update_Jacobi = Directives.Update_lin_PreCond() self.inv = Inversion.BaseInversion(invProb, directiveList=[IRLS, betaest, update_Jacobi])
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() # Put all together self.inv = Inversion.BaseInversion( invProb, directiveList=[ betaest, IRLS, update_SensWeight, update_Jacobi ] ) self.mesh = mesh
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()) ########################################################################### # A simple function to plot vectors in TreeMesh # # Should eventually end up on discretize # def plotVectorSectionsOctree(mesh, m, normal='X', ind=0, vmin=None, vmax=None,
def set_mesh(self, topo=None, dx=None, dy=None, dz=None, n_spacing=None, corezlength=None, npad_x=7, npad_y=7, npad_z=7, pad_rate_x=1.3, pad_rate_y=1.3, pad_rate_z=1.3, ncell_per_dipole=4, mesh_type='TensorMesh', dimension=2, method='linear'): """ Set up a mesh for a given DC survey """ if mesh_type == 'TreeMesh': raise NotImplementedError() # 2D or 3D mesh if dimension in [2, 3]: if dimension == 2: z_ind = 1 else: z_ind = 2 a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min() lineLength = abs(self.electrode_locations[:, 0].max() - self.electrode_locations[:, 0].min()) dx_ideal = a / ncell_per_dipole if dx is None: dx = dx_ideal warnings.warn( "dx is set to {} m (samllest electrode spacing ({}) / {})". format(dx, a, ncell_per_dipole)) if dz is None: dz = dx * 0.5 warnings.warn("dz ({} m) is set to dx ({} m) / {}".format( dz, dx, 2)) x0 = self.electrode_locations[:, 0].min() if topo is None: locs = self.electrode_locations else: locs = np.vstack((topo, self.electrode_locations)) if dx > dx_ideal: # warnings.warn( # "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a) # ) pass self.dx = dx self.dz = dz self.npad_x = npad_x self.npad_z = npad_z self.pad_rate_x = pad_rate_x self.pad_rate_z = pad_rate_z self.ncell_per_dipole = ncell_per_dipole zmax = locs[:, z_ind].max() zmin = locs[:, z_ind].min() # 3 cells each for buffer corexlength = lineLength + dx * 6 if corezlength is None: corezlength = self.grids[:, z_ind].max() ncx = np.round(corexlength / dx) ncz = np.round(corezlength / dz) hx = [(dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x)] hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)] x0_mesh = -( (dx * pad_rate_x**(np.arange(npad_x) + 1)).sum() + dx * 3 - x0) z0_mesh = -((dz * pad_rate_z** (np.arange(npad_z) + 1)).sum() + dz * ncz) + zmax # For 2D mesh if dimension == 2: h = [hx, hz] x0_for_mesh = [x0_mesh, z0_mesh] self.xyzlim = np.vstack( (np.r_[x0, x0 + lineLength], np.r_[zmax - corezlength, zmax])) # For 3D mesh else: if dy is None: raise Exception("You must input dy (m)") self.dy = dy self.npad_y = npad_y self.pad_rate_y = pad_rate_y ylocs = np.unique(self.electrode_locations[:, 1]) ymin, ymax = ylocs.min(), ylocs.max() # 3 cells each for buffer in y-direction coreylength = ymax - ymin + dy * 6 ncy = np.round(coreylength / dy) hy = [(dy, npad_y, -pad_rate_y), (dy, ncy), (dy, npad_y, pad_rate_y)] y0 = ylocs.min() - dy / 2. y0_mesh = -((dy * pad_rate_y**(np.arange(npad_y) + 1)).sum() + dy * 3 - y0) h = [hx, hy, hz] x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh] self.xyzlim = np.vstack( (np.r_[x0, x0 + lineLength], np.r_[ymin, ymax], np.r_[zmax - corezlength, zmax])) mesh = Mesh.TensorMesh(h, x0=x0_for_mesh) actind = Utils.surface2ind_topo(mesh, locs, method=method) else: raise NotImplementedError() return mesh, actind