def createLocalMesh(rxLoc, ind_t): """ Function to generate a mesh based on receiver locations """ # Create new survey if input_dict["inversion_type"] == 'grav': rxLoc_t = PF.BaseGrav.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseGrav.SrcField([rxLoc_t]) local_survey = PF.BaseGrav.LinearSurvey(srcField) local_survey.dobs = survey.dobs[ind_t] local_survey.std = survey.std[ind_t] local_survey.ind = ind_t elif input_dict["inversion_type"] in ['mag', 'mvi', 'mvis']: rxLoc_t = PF.BaseMag.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseMag.SrcField([rxLoc_t], param=survey.srcField.param) local_survey = PF.BaseMag.LinearSurvey( srcField, components=survey.components ) dataInd = np.kron(ind_t, np.ones(len(survey.components))).astype('bool') local_survey.dobs = survey.dobs[dataInd] local_survey.std = survey.std[dataInd] local_survey.ind = ind_t meshLocal = meshutils.mesh_builder_xyz( topo_elevations_at_data_locs, core_cell_size, padding_distance=padding_distance, mesh_type=inversion_mesh_type, base_mesh=input_mesh, depth_core=depth_core ) if shift_mesh_z0 is not None: print("In mesh z0") meshLocal.x0 = np.r_[meshLocal.x0[0], meshLocal.x0[1], shift_mesh_z0] if inversion_mesh_type.upper() == 'TREE': 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, ) # Create combo misfit function return meshLocal, local_survey
def createLocalMesh(rxLoc, ind_t): """ Function to generate a mesh based on receiver locations """ # Create new survey if input_dict["inversion_type"].lower() == 'grav': rxLoc_t = PF.BaseGrav.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseGrav.SrcField([rxLoc_t]) local_survey = PF.BaseGrav.LinearSurvey(srcField) local_survey.dobs = survey.dobs[ind_t] local_survey.std = survey.std[ind_t] local_survey.ind = ind_t # Utils.io_utils.writeUBCgravityObservations(outDir + "Tile" + str(ind) + '.dat', local_survey, local_survey.dobs) elif input_dict["inversion_type"].lower() in ['mag', 'mvi', 'mvis']: rxLoc_t = PF.BaseMag.RxObs(rxLoc[ind_t, :]) srcField = PF.BaseMag.SrcField([rxLoc_t], param=survey.srcField.param) local_survey = PF.BaseMag.LinearSurvey(srcField, components=survey.components) dataInd = np.kron(ind_t, np.ones(len(survey.components))).astype('bool') local_survey.dobs = survey.dobs[dataInd] local_survey.std = survey.std[dataInd] local_survey.ind = ind_t # Utils.io_utils.writeUBCmagneticsObservations(outDir + "Tile" + str(ind) + '.dat', local_survey, local_survey.dobs) meshLocal = meshutils.mesh_builder_xyz(newTopo, core_cell_size, padding_distance=padding_distance, mesh_type='TREE', base_mesh=meshInput, depth_core=depth_core) 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, rxLoc[ind_t, :], method='surface', max_distance=max_distance, octree_levels=octree_levels_obs, octree_levels_padding=octree_levels_padding, finalize=True, ) # Create combo misfit function return meshLocal, local_survey
def test_box(self): dx = 0.25 dl = 10 # Create a box 2*dl in width X, Y, Z = np.meshgrid(np.c_[-dl, dl], np.c_[-dl, dl], np.c_[-dl, dl]) xyz = np.c_[np.ravel(X), np.ravel(Y), np.ravel(Z)] mesh = meshutils.mesh_builder_xyz( np.c_[0.01, 0.01, 0.01], [dx, dx, dx], depth_core=0, padding_distance=[[0, 20], [0, 20], [0, 20]], mesh_type='TREE', ) mesh = meshutils.refine_tree_xyz( mesh, xyz, octree_levels=[1], method='box', finalize=True ) # Volume of box vol = (2*dl)**3 residual = np.abs( vol - mesh.vol[ mesh._cell_levels_by_indexes(range(mesh.nC)) == mesh.max_level ].sum() )/vol * 100 self.assertTrue(residual < 0.5)
def test_surface(self): dx = 0.1 dl = 20 # Define triangle xyz = np.r_[ np.c_[-dl/2, -dl/2, 0], np.c_[dl/2, -dl/2, 0], np.c_[dl/2, dl/2, 0] ] mesh = meshutils.mesh_builder_xyz( np.c_[0.01, 0.01, 0.01], [dx, dx, dx], depth_core=0, padding_distance=[[0, 20], [0, 20], [0, 20]], mesh_type='TREE', ) mesh = meshutils.refine_tree_xyz( mesh, xyz, octree_levels=[1], method='surface', finalize=True ) # Volume of triangle vol = dl*dl*dx/2 residual = np.abs( vol - mesh.vol[ mesh._cell_levels_by_indexes(range(mesh.nC)) == mesh.max_level ].sum()/2 )/vol * 100 self.assertTrue(residual < 5)
def test_radial(self): dx = 0.25 rad = 10 mesh = meshutils.mesh_builder_xyz( np.c_[0.01, 0.01, 0.01], [dx, dx, dx], depth_core=0, padding_distance=[[0, 20], [0, 20], [0, 20]], mesh_type='TREE', ) radCell = int(np.ceil(rad/dx)) mesh = meshutils.refine_tree_xyz( mesh, np.c_[0, 0, 0], octree_levels=[radCell], method='radial', finalize=True ) # Volume of sphere vol = 4.*np.pi/3.*rad**3. residual = np.abs( vol - mesh.vol[ mesh._cell_levels_by_indexes(range(mesh.nC)) == mesh.max_level ].sum() )/vol * 100 self.assertTrue(residual < 3)
def refine_box(mesh): # Refine for sphere xp, yp, zp = np.meshgrid([-55.0, 50.0], [-50.0, 50.0], [-40.0, 20.0]) xyz = np.c_[mkvc(xp), mkvc(yp), mkvc(zp)] mesh = refine_tree_xyz(mesh, xyz, octree_levels=[2], method="box", finalize=False) return mesh
def refine_topography(mesh): # Define topography and refine [xx, yy] = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = -3 * np.exp((xx**2 + yy**2) / 60**2) + 45.0 topo = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)] mesh = refine_tree_xyz(mesh, topo, octree_levels=[3, 2], method="surface", finalize=False) return mesh
def refine_octree_surface(mesh, f): """ Refine an octree mesh around the given surface :param mesh: TreeMesh instance to refine :param f: function giving z(x,y) in physical units :return: TreeMesh instance """ xx, yy = np.meshgrid(mesh.vectorNx, mesh.vectorNy) zz = f(xx, yy) idx_valid = ~np.isnan(zz) xx, yy, zz = xx[idx_valid], yy[idx_valid], zz[idx_valid] surf = np.c_[mkvc(xx), mkvc(yy), mkvc(zz)] # Play with different octree_levels=[lx,ly,lz] settings below return refine_tree_xyz( mesh, surf, octree_levels=[1,1,1], method="surface", finalize=False )
# Compute number of base mesh cells required in x and y nbcx = 2**int(np.round(np.log(x_length / dx) / np.log(2.))) nbcy = 2**int(np.round(np.log(y_length / dy) / np.log(2.))) # Define the base mesh hx = [(dx, nbcx)] hy = [(dy, nbcy)] M = TreeMesh([hx, hy], x0=['C', -15000]) # definir camada xx = M.vectorNx yy = np.zeros(nbcx + 1) #vetor linha(poderia ser uma função ou pontos) pts = np.c_[matutils.mkvc(xx), matutils.mkvc(yy)] M = meshutils.refine_tree_xyz(M, pts, octree_levels=[1, 1], method='box', finalize=False) #definir um ponto(xc,yc) a ser refinado. Raio_length = 500 xc = -5000 yc = 2200 xx = M.vectorNx yy = np.zeros(nbcx + 1) #vetor linha(poderia ser uma função ou pontos) pts = np.c_[matutils.mkvc(xx), matutils.mkvc(yy)] def refine(cell): if np.sqrt(((np.r_[cell.center] + [xc, yc])**2).sum()) < Raio_length:
ind_t = tileIDs == tile_numbers[indMax] # Create the mesh and refine the same as the global mesh meshLocal = meshutils.mesh_builder_xyz( newTopo, core_cell_size, padding_distance=padding_distance, mesh_type='TREE', base_mesh=meshInput, depth_core=depth_core) 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, rxLoc[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)
def run(plotIt=True): nFreq = 13 freqs = np.logspace(2, -2, nFreq) # x and y grid parameters # dh = 10 # minimum cell width (base mesh cell width) dx = 15 # minimum cell width (base mesh cell width) in x dy = 15 dz = 10 x_length = 10000. # domain width in x y_length = 10000. z_length = 40000. # Compute number of base mesh cells required in x and y nbcx = 2**int(np.round(np.log(x_length / dx) / np.log(2.))) nbcy = 2**int(np.round(np.log(y_length / dy) / np.log(2.))) nbcz = 2**int(np.round(np.log(z_length / dz) / np.log(2.))) # Define the base mesh hx = [(dx, nbcx)] hy = [(dy, nbcy)] hz = [(dz, nbcz)] M = Mesh.TreeMesh([hx, hy, hz], x0=['C', 'C', -15000]) # camadas xx = M.vectorNx yy = M.vectorNy zz = np.zeros(nbcx + 1) #vetor linha(poderia ser uma função ou pontos) pts = np.c_[matutils.mkvc(xx), matutils.mkvc(yy), matutils.mkvc(zz)] M = meshutils.refine_tree_xyz(M, pts, octree_levels=[1, 1, 1], method='surface', finalize=False) xx = M.vectorNx yy = M.vectorNy zz = np.zeros(nbcx + 1) - 150 #vetor linha(poderia ser uma função ou pontos) pts = np.c_[matutils.mkvc(xx), matutils.mkvc(yy), matutils.mkvc(zz)] M = meshutils.refine_tree_xyz(M, pts, octree_levels=[1, 1, 1], method='surface', finalize=False) xx = M.vectorNx yy = M.vectorNy zz = np.zeros(nbcx + 1) - 350 #vetor linha(poderia ser uma função ou pontos) pts = np.c_[matutils.mkvc(xx), matutils.mkvc(yy), matutils.mkvc(zz)] M = meshutils.refine_tree_xyz(M, pts, octree_levels=[1, 1, 1], method='surface', finalize=False) # M.finalize() print("\n the mesh has {} cells".format(M)) ccMesh = M.gridCC print('indices:', np.size(ccMesh)) ### conds = [1e-2, 1] sig = simpeg.Utils.ModelBuilder.defineBlock(M.gridCC, [-15000, 15000, -350], [15000, 1500, -150], conds) sig[M.gridCC[:, 2] > 0] = 1e-8 sigBG = np.zeros(M.nC) + conds[1] sigBG[M.gridCC[:, 2] > 0] = 1e-8 fig = plt.figure('slice: malha + modelo') ax = fig.add_subplot() collect_obj, = M.plotSlice(np.log(sig), normal='x', ax=ax, grid=True)
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 createLocalProb(rxLoc, wrGlobal, ind_t, ind): # createLocalProb(rxLoc, wrGlobal, lims, ind) # Generate a problem, calculate/store sensitivities for # given data points # 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 if input_dict["inversion_type"].lower() == 'grav': 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 Utils.io_utils.writeUBCgravityObservations(outDir + "Tile" + str(ind) + '.dat', survey_t, survey_t.dobs) elif input_dict["inversion_type"].lower() in ['mag', 'mvi']: 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] survey_t.ind = ind_t Utils.io_utils.writeUBCmagneticsObservations(outDir + "Tile" + str(ind) + '.dat', survey_t, survey_t.dobs) meshLocal = meshutils.mesh_builder_xyz( newTopo, core_cell_size, padding_distance=padding_distance, mesh_type='TREE', base_mesh=meshInput, depth_core=depth_core ) 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, rxLoc[ind_t, :], method='surface', max_distance=max_distance, octree_levels=octree_levels_obs, octree_levels_padding=octree_levels_padding, finalize=True, ) # Need to find a way to compute sensitivities only for intersecting cells activeCells_t = np.ones(meshLocal.nC, dtype='bool') # meshUtils.modelutils.activeTopoLayer(meshLocal, topo) # Create reduced identity map if input_dict["inversion_type"].lower() == 'mvi': nBlock = 3 else: nBlock = 1 tileMap = Maps.Tile((mesh, activeCells), (meshLocal, activeCells_t), nBlock=nBlock) activeCells_t = tileMap.activeLocal print(activeCells_t.sum(), meshLocal.nC) if input_dict["inversion_type"].lower() == 'grav': prob = PF.Gravity.GravityIntegral( meshLocal, rhoMap=tileMap, actInd=activeCells_t, parallelized=parallelized, Jpath=outDir + "Tile" + str(ind) + ".zarr", maxRAM=max_ram, n_cpu=n_cpu, ) elif input_dict["inversion_type"].lower() == 'mag': prob = PF.Magnetics.MagneticIntegral( meshLocal, chiMap=tileMap, actInd=activeCells_t, parallelized=parallelized, Jpath=outDir + "Tile" + str(ind) + ".zarr", maxRAM=max_ram, n_cpu=n_cpu, ) elif input_dict["inversion_type"].lower() == 'mvi': prob = PF.Magnetics.MagneticIntegral( meshLocal, chiMap=tileMap, actInd=activeCells_t, parallelized=parallelized, Jpath=outDir + "Tile" + str(ind) + ".zarr", maxRAM=max_ram, modelType='vector', n_cpu=n_cpu ) survey_t.pair(prob) # Write out local active and obs for validation Mesh.TreeMesh.writeUBC( meshLocal, outDir + 'Octree_Tile' + str(ind) + '.msh', models={outDir + 'ActiveGlobal_Tile' + str(ind) + ' .act': activeCells_t} ) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey_t) dmis.W = 1./survey_t.std wr = prob.getJtJdiag(np.ones(tileMap.shape[1]), W=dmis.W) wrGlobal += wr del meshLocal # Create combo misfit function return dmis
h = [40, 40, 20] pads = [[0, 0], [0, 0],[2000, 0]] octreeTopo = [0,5,10,10] octreeObs = [5, 5] maxDist = 100 depth_core = 2500 mesh = meshutils.mesh_builder_xyz( topo, h, padding_distance=pads, mesh_type='TREE', depth_core=depth_core, ) mesh = meshutils.refine_tree_xyz(mesh, topo, octree_levels=octreeTopo, method='surface', finalize=False) mesh = meshutils.refine_tree_xyz(mesh, xyz, octree_levels=octreeObs, method='surface', max_distance=maxDist, finalize=True) actv = modelutils.surface2ind_topo(mesh, topo, gridLoc='N') ############################################################################### def plot_pyvista(mesh, model, actv, interactive=False, use_panel=True, clim=None): # Convert TreeMesh to VTK dataset = mesh.toVTK()
def createLocalProb(rxLoc, wrGlobal, lims, ind): # createLocalProb(rxLoc, wrGlobal, lims, ind) # Generate a problem, calculate/store sensitivities for # given data points # 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 if driver["dataFile"][0] == 'GRAV': 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 Utils.io_utils.writeUBCgravityObservations( workDir + dsep + outDir + "Tile" + str(ind) + '.dat', survey_t, survey_t.dobs) elif driver["dataFile"][0] == 'MAG': 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] survey_t.ind = ind_t Utils.io_utils.writeUBCmagneticsObservations( workDir + dsep + outDir + "Tile" + str(ind) + '.dat', survey_t, survey_t.dobs) meshLocal = meshutils.mesh_builder_xyz( newTopo, h, padDist, mesh_type='TREE', depth_core=depth_core, base_mesh=meshInput, ) if topo is not None: meshLocal = meshutils.refine_tree_xyz(meshLocal, topo, method='surface', octree_levels=octreeTopo, finalize=False) # Refine the mesh around loc meshLocal = meshutils.refine_tree_xyz( meshLocal, newTopo[ind_t, :], method='surface', octree_levels=octreeObs, octree_levels_padding=octree_levels_padding, finalize=True) # Need to find a way to compute sensitivities only for intersecting cells activeCells_t = np.ones( meshLocal.nC, dtype='bool') # meshmeshutils.activeTopoLayer(meshLocal, topo) # Create reduced identity map tileMap = Maps.Tile((mesh, activeCells), (meshLocal, activeCells_t)) activeCells_t = tileMap.activeLocal print(activeCells_t.sum(), meshLocal.nC) if driver["dataFile"][0] == 'GRAV': prob = PF.Gravity.GravityIntegral(meshLocal, rhoMap=tileMap, actInd=activeCells_t, parallelized=parallelized, Jpath=workDir + dsep + outDir + "Tile" + str(ind) + ".zarr", maxRAM=maxRAM / n_cpu, n_cpu=n_cpu, n_chunks=n_chunks) elif driver["dataFile"][0] == 'MAG': prob = PF.Magnetics.MagneticIntegral( meshLocal, chiMap=tileMap, actInd=activeCells_t, parallelized=parallelized, Jpath=workDir + dsep + outDir + "Tile" + str(ind) + ".zarr", maxRAM=maxRAM / n_cpu, n_cpu=n_cpu, n_chunks=n_chunks) survey_t.pair(prob) # Write out local active and obs for validation Mesh.TreeMesh.writeUBC( meshLocal, workDir + dsep + outDir + dsep + 'Octree_Tile' + str(ind) + '.msh', models={ workDir + dsep + outDir + dsep + 'ActiveGlobal_Tile' + str(ind) + ' .act': activeCells_t }) if driver["dataFile"][0] == 'GRAV': Utils.io_utils.writeUBCgravityObservations( workDir + dsep + outDir + dsep + 'Tile' + str(ind) + '.dat', survey_t, survey_t.dobs) elif driver["dataFile"][0] == 'MAG': Utils.io_utils.writeUBCmagneticsObservations( workDir + dsep + outDir + dsep + 'Tile' + str(ind) + '.dat', survey_t, survey_t.dobs) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey_t) dmis.W = 1. / survey_t.std wr = prob.getJtJdiag(np.ones(tileMap.P.shape[1]), W=dmis.W) wrGlobal += wr del meshLocal # Create combo misfit function return dmis
padDist = np.r_[np.c_[padLen, padLen], np.c_[padLen, padLen], np.c_[padLen, 0]] print("Creating Global Octree") mesh = meshutils.mesh_builder_xyz( newTopo, h, padDist, mesh_type='TREE', depth_core=depth_core, base_mesh=meshInput, ) 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)
def setUp(self): np.random.seed(0) # First we need to define the direction of the inducing field # As a simple case, we pick a vertical inducing field of magnitude # 50,000nT. # From old convention, field orientation is given as an # azimuth from North (positive clockwise) # and dip from the horizontal (positive downward). H0 = (50000.0, 90.0, 0.0) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [2, 4, 2] # Create grid of points for topography # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(np.linspace(-200.0, 200.0, 50), np.linspace(-200.0, 200.0, 50)) b = 100 A = 50 zz = A * np.exp(-0.5 * ((xx / b)**2.0 + (yy / b)**2.0)) # We would usually load a topofile topo = np.c_[utils.mkvc(xx), utils.mkvc(yy), utils.mkvc(zz)] # Create and array of observation points xr = np.linspace(-100.0, 100.0, 20) yr = np.linspace(-100.0, 100.0, 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2.0 + (Y / b)**2.0)) + 5 # Create a MAGsurvey xyzLoc = np.c_[utils.mkvc(X.T), utils.mkvc(Y.T), utils.mkvc(Z.T)] rxLoc = mag.Point(xyzLoc) srcField = mag.SourceField([rxLoc], parameters=H0) survey = mag.Survey(srcField) # self.mesh.finalize() self.mesh = meshutils.mesh_builder_xyz( xyzLoc, h, padding_distance=padDist, mesh_type="TREE", ) self.mesh = meshutils.refine_tree_xyz( self.mesh, topo, method="surface", octree_levels=nCpad, octree_levels_padding=nCpad, finalize=True, ) # Define an active cells from topo actv = utils.surface2ind_topo(self.mesh, topo) nC = int(actv.sum()) # We can now create a susceptibility model and generate data # Lets start with a simple block in half-space self.model = utils.model_builder.addBlock( self.mesh.gridCC, np.zeros(self.mesh.nC), np.r_[-20, -20, -15], np.r_[20, 20, 20], 0.05, )[actv] # Create active map to go from reduce set to full self.actvMap = maps.InjectActiveCells(self.mesh, actv, np.nan) # Creat reduced identity map idenMap = maps.IdentityMap(nP=nC) # Create the forward model operator sim = mag.Simulation3DIntegral( self.mesh, survey=survey, chiMap=idenMap, actInd=actv, store_sensitivities="ram", ) self.sim = sim data = sim.make_synthetic_data(self.model, relative_error=0.0, noise_floor=1.0, add_noise=True) # Create a regularization reg = regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.mref = np.zeros(nC) # Data misfit function dmis = data_misfit.L2DataMisfit(simulation=sim, data=data) # Add directives to the inversion opt = optimization.ProjectedGNCG( maxIter=10, lower=0.0, upper=10.0, maxIterLS=5, maxIterCG=5, tolCG=1e-4, stepOffBoundsFact=1e-4, ) invProb = inverse_problem.BaseInvProblem(dmis, reg, opt, beta=1e6) # Here is where the norms are applied # Use pick a treshold parameter empirically based on the distribution of # model parameters IRLS = directives.Update_IRLS(f_min_change=1e-3, max_irls_iterations=20, beta_tol=1e-1, beta_search=False) update_Jacobi = directives.UpdatePreconditioner() sensitivity_weights = directives.UpdateSensitivityWeights() self.inv = inversion.BaseInversion( invProb, directiveList=[IRLS, sensitivity_weights, update_Jacobi])
if add_data_padding or decimate_to_mesh: # Scipy.interpolate flags divide-by-zero and invalid value errors when making # the mesh. They don't affect the result, so we suppress them temporarily. old_settings = np.seterr(divide='ignore', invalid='ignore') # Create a quadtree mesh using the same params as the full mesh decimate_mesh = meshutils.mesh_builder_xyz( survey.rxLoc[:, :2], core_cell_size[:2], padding_distance=padding_distance[:2], mesh_type='tree' ) decimate_mesh = meshutils.refine_tree_xyz( decimate_mesh, survey.rxLoc[:, :2], method='surface', max_distance=max_distance, octree_levels=octree_levels_obs, octree_levels_padding=octree_levels_padding, finalize=True, ) np.seterr(**old_settings) if decimate_to_mesh: print("Decimating the whole survey to the mesh") survey, data_trend = decimate_survey_to_mesh(decimate_mesh, data_trend, survey) elif add_data_padding: print("Decimating the padding points to the mesh") survey, data_trend = decimate_survey_to_mesh(decimate_mesh, data_trend, survey, survey)
def setUp(self): # We will assume a vertical inducing field H0 = (50000., 90., 0.) # The magnetization is set along a different direction (induced + remanence) M = np.array([90., 0.]) # Block with an effective susceptibility chi_e = 0.05 # Create grid of points for topography # Lets create a simple Gaussian topo and set the active cells [xx, yy] = np.meshgrid(np.linspace(-200, 200, 50), np.linspace(-200, 200, 50)) b = 100 A = 50 zz = A * np.exp(-0.5 * ((xx / b)**2. + (yy / b)**2.)) topo = np.c_[Utils.mkvc(xx), Utils.mkvc(yy), Utils.mkvc(zz)] # Create and array of observation points xr = np.linspace(-100., 100., 20) yr = np.linspace(-100., 100., 20) X, Y = np.meshgrid(xr, yr) Z = A * np.exp(-0.5 * ((X / b)**2. + (Y / b)**2.)) + 5 # Create a MAGsurvey xyzLoc = np.c_[Utils.mkvc(X.T), Utils.mkvc(Y.T), Utils.mkvc(Z.T)] Rx = PF.BaseMag.RxObs(xyzLoc) srcField = PF.BaseMag.SrcField([Rx], param=H0) survey = PF.BaseMag.LinearSurvey(srcField) # Create a mesh h = [5, 5, 5] padDist = np.ones((3, 2)) * 100 nCpad = [4, 4, 2] self.mesh = meshutils.mesh_builder_xyz( xyzLoc, h, padding_distance=padDist, mesh_type='TREE', ) self.mesh = meshutils.refine_tree_xyz( self.mesh, topo, method='surface', octree_levels=nCpad, octree_levels_padding=nCpad, finalize=True, ) # Define an active cells from topo actv = Utils.surface2ind_topo(self.mesh, topo) nC = int(actv.sum()) # Convert the inclination declination to vector in Cartesian M_xyz = Utils.matutils.dip_azimuth2cartesian( np.ones(nC) * M[0], np.ones(nC) * M[1]) # Get the indicies of the magnetized block ind = Utils.ModelBuilder.getIndicesBlock( np.r_[-20, -20, -15], np.r_[20, 20, 20], self.mesh.gridCC, )[0] # Assign magnetization value, inducing field strength will # be applied in by the :class:`SimPEG.PF.Magnetics` problem model = np.zeros(self.mesh.nC) model[ind] = chi_e # Remove air cells self.model = model[actv] # Create active map to go from reduce set to full self.actvPlot = Maps.InjectActiveCells(self.mesh, actv, np.nan) # Creat reduced identity map idenMap = Maps.IdentityMap(nP=nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(self.mesh, M=M_xyz, chiMap=idenMap, actInd=actv) # Pair the survey and problem survey.pair(prob) # Compute some data and add some random noise data = prob.fields(self.model) # Split the data in components nD = xyzLoc.shape[0] std = 5 # nT data += np.random.randn(nD) * std wd = np.ones(nD) * std # Assigne data and uncertainties to the survey survey.dobs = data survey.std = wd ###################################################################### # Equivalent Source # Get the active cells for equivalent source is the top only surf = Utils.modelutils.surface_layer_index(self.mesh, topo) # Get the layer of cells directyl below topo nC = np.count_nonzero(surf) # Number of active cells # Create active map to go from reduce set to full surfMap = Maps.InjectActiveCells(self.mesh, surf, np.nan) # Create identity map idenMap = Maps.IdentityMap(nP=nC) # Create static map prob = PF.Magnetics.MagneticIntegral(self.mesh, chiMap=idenMap, actInd=surf, parallelized=False, equiSourceLayer=True) prob.solverOpts['accuracyTol'] = 1e-4 # Pair the survey and problem if survey.ispaired: survey.unpair() survey.pair(prob) # Create a regularization function, in this case l2l2 reg = Regularization.Sparse(self.mesh, indActive=surf, mapping=Maps.IdentityMap(nP=nC), scaledIRLS=False) reg.mref = np.zeros(nC) # Specify how the optimization will proceed, # set susceptibility bounds to inf opt = Optimization.ProjectedGNCG(maxIter=20, lower=-np.inf, upper=np.inf, maxIterLS=20, maxIterCG=20, tolCG=1e-3) # Define misfit function (obs-calc) dmis = DataMisfit.l2_DataMisfit(survey) dmis.W = 1. / survey.std # Create the default L2 inverse problem from the above objects invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # Specify how the initial beta is found betaest = Directives.BetaEstimate_ByEig() # Target misfit to stop the inversion, # try to fit as much as possible of the signal, # we don't want to lose anything IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, beta_tol=1e-1) update_Jacobi = Directives.UpdatePreconditioner() # Put all the parts together inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_Jacobi]) # Run the equivalent source inversion mstart = np.ones(nC) * 1e-4 mrec = inv.run(mstart) # Won't store the sensitivity and output 'xyz' data. prob.forwardOnly = True prob.rx_type = 'xyz' prob._G = None prob.modelType = 'amplitude' prob.model = mrec pred = prob.fields(mrec) bx = pred[:nD] by = pred[nD:2 * nD] bz = pred[2 * nD:] bAmp = (bx**2. + by**2. + bz**2.)**0.5 # AMPLITUDE INVERSION # Create active map to go from reduce space to full actvMap = Maps.InjectActiveCells(self.mesh, actv, -100) nC = int(actv.sum()) # Create identity map idenMap = Maps.IdentityMap(nP=nC) self.mstart = np.ones(nC) * 1e-4 # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(self.mesh, chiMap=idenMap, actInd=actv, modelType='amplitude', rx_type='xyz') prob.model = self.mstart # Change the survey to xyz components surveyAmp = PF.BaseMag.LinearSurvey(survey.srcField) # Pair the survey and problem surveyAmp.pair(prob) # Create a regularization function, in this case l2l2 wr = np.sum(prob.G**2., axis=0)**0.5 wr /= np.max(wr) # Re-set the observations to |B| surveyAmp.dobs = bAmp surveyAmp.std = wd # Create a sparse regularization reg = Regularization.Sparse(self.mesh, indActive=actv, mapping=idenMap) reg.norms = np.c_[0, 0, 0, 0] reg.mref = np.zeros(nC) reg.cell_weights = wr # Data misfit function dmis = DataMisfit.l2_DataMisfit(surveyAmp) dmis.W = 1. / surveyAmp.std # Add directives to the inversion opt = Optimization.ProjectedGNCG(maxIter=30, lower=0., upper=1., maxIterLS=20, maxIterCG=20, tolCG=1e-3) invProb = InvProblem.BaseInvProblem(dmis, reg, opt) # Here is the list of directives betaest = Directives.BetaEstimate_ByEig() # Specify the sparse norms IRLS = Directives.Update_IRLS(f_min_change=1e-3, minGNiter=1, coolingRate=1, betaSearch=False) # The sensitivity weights are update between each iteration. update_SensWeight = Directives.UpdateSensitivityWeights() update_Jacobi = Directives.UpdatePreconditioner() # Put all together self.inv = Inversion.BaseInversion( invProb, directiveList=[betaest, IRLS, update_SensWeight, update_Jacobi])
def createLocalProb(rxLoc, wrGlobal, lims, ind): # 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.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] survey_t.ind = ind_t meshLocal = meshutils.mesh_builder_xyz(topo, h, padding_distance=padDist, mesh_type='TREE', base_mesh=meshInput, depth_core=depth_core) if topo is not None: meshLocal = meshutils.refine_tree_xyz(meshLocal, topo, method='surface', octree_levels=octreeTopo, finalize=False) meshLocal = meshutils.refine_tree_xyz( meshLocal, rxLoc[ind_t, :], method='surface', max_distance=maxDist, octree_levels=octreeObs, octree_levels_padding=octreeObs_XY, finalize=True, ) actv_t = np.ones(meshLocal.nC, dtype='bool') # Create reduced identity map tileMap = Maps.Tile((mesh, actv), (meshLocal, actv_t)) actv_t = tileMap.activeLocal print(actv_t.sum(), meshLocal.nC) # Create the forward model operator prob = PF.Magnetics.MagneticIntegral(meshLocal, chiMap=tileMap, actInd=actv_t, parallelized='dask', Jpath=work_dir + out_dir + "Tile" + str(ind) + ".zarr", store_zarr=True) survey_t.pair(prob) # Data misfit function dmis = DataMisfit.l2_DataMisfit(survey_t) dmis.W = 1. / survey_t.std wr = prob.getJtJdiag(np.ones(tileMap.P.shape[1]), W=dmis.W) localMap = Maps.InjectActiveCells(meshLocal, actv_t, 1e-8) Mesh.TreeMesh.writeUBC( mesh, work_dir + out_dir + 'OctreeMesh' + str(tt) + '.msh', models={ work_dir + out_dir + 'Wr_' + str(tt) + '.act': actvMap * wr }) Mesh.TreeMesh.writeUBC( meshLocal, work_dir + out_dir + 'OctreeMesh' + str(tt) + '.msh', models={ work_dir + out_dir + 'Wr_' + str(tt) + '.act': localMap * tileMap * wr }) # localMap = Maps.InjectActiveCells(meshLocal, actv_t, 1e-8) # Mesh.TreeMesh.writeUBC( # meshLocal, work_dir + out_dir + 'OctreeMesh' + str(tt) + '.msh', # models={work_dir + out_dir + 'Wr_' + str(tt) + '.act': localMap*wr} # ) # wrGlobal += wr del meshLocal # Create combo misfit function return dmis, wrGlobal