def simulate(mesh, res, scheme, verbose=False, **kwargs): """Forward calculation vor given mesh, data and resistivity.""" fop = ERTModelling(verbose=verbose) # fop = ERTManager.createFOP(verbose=verbose) fop.setData(scheme) fop.setMesh(mesh, ignoreRegionManager=True) if not scheme.allNonZero('k'): if min(pg.y(scheme)) != max(pg.y(scheme)) or min(pg.z(scheme)) != max(pg.z(scheme)): pg.info("Non flat earth topography found. " "We will set geometric factors to -1 to emulate " "electrical impedance tomography (EIT). If you want to " "use ERT will full topography support. " "Please consider the use of pyBERT.") scheme.set('k', pg.RVector(scheme.size(), -1)) else: scheme.set('k', fop.calcGeometricFactors(scheme)) rhoa = None isArrayData = None if hasattr(res[0], '__iter__'): isArrayData = True rhoa = np.zeros((len(res), scheme.size())) for i, r in enumerate(res): rhoa[i] = fop.response(r) else: rhoa = fop.response(res) pg.renameKwarg('noisify', 'noiseLevel', kwargs) noiseLevel = kwargs.pop('noiseLevel', 0.0) if noiseLevel > 0: noiseAbs = kwargs.pop('noiseAbs', 1e-4) err = noiseLevel + noiseAbs / rhoa scheme.set('err', err) if verbose: pg.info("Set noise (" + str(noiseLevel*100) + "% + " + str(noiseAbs) + " V) min:", min(err), "max:", max(err)) rhoa *= 1. + pg.randn(scheme.size()) * err if isArrayData is None: scheme.set('rhoa', rhoa) if kwargs.pop('returnArray', False): return rhoa return scheme
def create_mesh_and_data(n): nc = np.linspace(-2.0, 0.0, n) mesh = pg.createMesh2D(nc, nc) mcx = pg.x(mesh.cellCenter()) mcy = pg.y(mesh.cellCenter()) data = np.cos(1.5 * mcx) * np.sin(1.5 * mcy) return mesh, data
def checkData(self): """Check data w.r.t. shot/geophone identity and zero/negative traveltimes, plus check y/z sensor positions """ oldsize = self.dataContainer.size() self.dataContainer.markInvalid(pg.abs(self.dataContainer('s') - self.dataContainer('g')) < 1) self.dataContainer.markInvalid(self.dataContainer('t') <= 0.) self.dataContainer.removeInvalid() newsize = self.dataContainer.size() if newsize < oldsize: if self.verbose: print('Removed ' + str(oldsize - newsize) + ' values.') maxyabs = max(pg.abs(pg.y(self.dataContainer.sensorPositions()))) maxzabs = max(pg.abs(pg.z(self.dataContainer.sensorPositions()))) if maxzabs > 0 and maxyabs == 0: for i in range(self.dataContainer.sensorCount()): pos = self.dataContainer.sensorPosition(i).rotateX(-pi / 2) self.dataContainer.setSensorPosition(i, pos) if self.verbose: print(self.dataContainer)
def cellDataToCellGrad(mesh, v, CtB): if len(v) != mesh.cellCount(): print(len(v), mesh.cellCount()) raise div = mesh.boundaryDataToCellGradient(CtB * v) return np.vstack([pg.x(div), pg.y(div), pg.z(div)]).T vF = cellDataToBoundaryData(mesh, v) gC = np.zeros((mesh.cellCount(), 3)) for b in mesh.boundaries(): leftCell = b.leftCell() rightCell = b.rightCell() vec = b.norm() * vF[b.id()] * b.size() if leftCell: gC[leftCell.id(), 0] += vec[0] gC[leftCell.id(), 1] += vec[1] gC[leftCell.id(), 2] += vec[2] if rightCell: gC[rightCell.id(), 0] -= vec[0] gC[rightCell.id(), 1] -= vec[1] gC[rightCell.id(), 2] -= vec[2] gC[:, 0] /= mesh.cellSizes() gC[:, 1] /= mesh.cellSizes() gC[:, 2] /= mesh.cellSizes() return gC
def cellDataToBoundaryGrad(mesh, v, vGrad): """ """ if len(v) != mesh.cellCount() or len(vGrad) != mesh.cellCount(): raise gB = mesh.cellDataToBoundaryGradient(v, vGrad) return np.vstack([pg.x(gB), pg.y(gB), pg.z(gB)]).T gB = np.zeros((mesh.boundaryCount(), 3)) for b in mesh.boundaries(): leftCell = b.leftCell() rightCell = b.rightCell() gr = pg.RVector3(0.0, 0.0, 0.0) t = (b.node(1).pos() - b.node(0).pos()).norm() if leftCell and rightCell: df1 = b.center().distance(leftCell.center()) df2 = b.center().distance(rightCell.center()) gr = b.norm() * \ (v[rightCell.id()] - v[leftCell.id()]) / (df1 + df2) grL = t * t.dot(vGrad[leftCell.id()]) grR = t * t.dot(vGrad[rightCell.id()]) gr += (grL + grR) * 0.5 elif leftCell: gr = t * t.dot(vGrad[leftCell.id()]) gB[b.id(), 0] = gr[0] gB[b.id(), 1] = gr[1] gB[b.id(), 2] = gr[2] return gB
def showVAold(self, vals=None, ax=None, usepos=True, name='va'): """show apparent velocity as image plot (old style)""" va = self.getVA(t=vals) data = self.dataContainer A = np.ones((data.sensorCount(), data.sensorCount())) * np.nan for i in range(data.size()): A[int(data('s')[i]), int(data('g')[i])] = va[i] if ax is None: fig, ax = plt.subplots() self.figs[name] = fig gci = ax.imshow(A, interpolation='nearest') ax.grid(True) if usepos: xt = np.linspace(0, data.sensorCount()-1, 7) xt.round() px = pg.abs(pg.y(self.dataContainer.sensorPositions())) ax.set_xticks(xt) ax.set_xticklabels([str(int(px[int(xti)])) for xti in xt]) ax.set_yticks(xt) ax.set_yticklabels([str(int(px[int(xti)])) for xti in xt]) plt.colorbar(gci, ax=ax) return va
def transform2DMeshTo3D(mesh, x, y, z=None): """ Transform a 2D mesh into 3D coordinates using a point list (e.g. from GPS) Parameters ---------- mesh: GIMLi::Mesh x,y: array of x/y positions along 2d profile z: optional height to add (topographical correction if computed flat earth) See Also -------- References ---------- """ # get mesh node positions mt, mz = pg.x( mesh.positions() ), pg.y( mesh.positions() ) # mesh tape and z # compute length of reference points along tape pt = np.hstack( (0., np.cumsum( np.sqrt( np.diff( x )**2 + np.diff( y )**2 ) ) ) ) # interpolate node positions from tape to x/y using tape positions mx = np.interp( mt, pt, x ) my = np.interp( mt, pt, y ) # compute z offset by interpolating z if z is None: oz = np.zeros( len(mt) ) else: oz = np.interp( mt, pt, z ) # set the positions in the mesh for i, node in enumerate( mesh.nodes() ): node.setPos( pg.RVector3( mx[i], my[i], mz[i]+oz[i] ) )
def createCoarsePoly( coarseData ): boundary = 1250.0 mesh = g.Mesh() x = g.x( coarseData ) y = g.y( coarseData ) z = g.z( coarseData ) xMin = min( x ); xMax = max( x ) yMin = min( y ); yMax = max( y ) zMin = min( z ); zMax = max( z ) print(xMin, xMax, yMin, yMax) border = max( (xMax - xMin) * boundary / 100.0, (yMax - yMin) * boundary / 100.0); n1 = mesh.createNode( xMin - border, yMin - border, zMin, 1 ) n2 = mesh.createNode( xMax + border, yMin - border, zMin, 2 ) n3 = mesh.createNode( xMax + border, yMax + border, zMin, 3 ) n4 = mesh.createNode( xMin - border, yMax + border, zMin, 4 ) mesh.createEdge( n1, n2, 12 ); mesh.createEdge( n2, n3, 23 ); mesh.createEdge( n3, n4, 34 ); mesh.createEdge( n4, n1, 41 ); for p in coarseData: mesh.createNode( p ) return mesh
def cellDataToBoundaryGrad(mesh, v, vGrad): """TODO Documentme.""" if len(v) != mesh.cellCount() or len(vGrad) != mesh.cellCount(): raise BaseException("len(v) dismatch mesh.cellCount()") gB = mesh.cellDataToBoundaryGradient(v, vGrad) return np.vstack([pg.x(gB), pg.y(gB), pg.z(gB)]).T
def cellDataToCellGrad(mesh, v, CtB): """TODO Documentme.""" if len(v) != mesh.cellCount(): print(len(v), mesh.cellCount()) raise BaseException("len of v missmatch mesh.cellCount()") div = mesh.boundaryDataToCellGradient(CtB * v) return np.vstack([pg.x(div), pg.y(div), pg.z(div)]).T
def showVA(self, t=None, ax=None, usepos=True, name='va', squeeze=True): """show apparent velocity as image plot""" # va = self.getVA(vals=vals) xvec = self.dataContainer('g') yvec = self.dataContainer('s') if usepos: pz = pg.y(self.dataContainer.sensorPositions()) if squeeze: xvec = pz[xvec] yvec = pz[yvec] else: pz = pg.y(self.dataContainer.sensorPositions()) raise Exception('Implement ME') # xvec = px[xvec]*1000 + pz[xvec] # xvec = px[yvec]*1000 + pz[yvec] plotVecMatrix(xvec, yvec, vals=t, squeeze=squeeze, ax=ax, name=name)
def ani(i): axGra.clear() axGra.plot(pg.x(gravPoints), dz[i]) axGra.plot(pg.x(gravPoints), pg.y(gravPoints), 'v', color='black') axGra.set_ylabel('Grav in mGal') axGra.set_xlim((-20, 20)) axGra.set_ylim((0, 0.001)) axGra.grid() pg.mplviewer.setMappableData(gciDDe, abs(dDens[i]), cMin=0, cMax=20, logScale=False)
def createGradientModel2D(data, mesh, VTop, VBot): """ Create 2D velocity gradient model. Creates a smooth, linear, starting model that takes the slope of the topography into account. This is done by fitting a straight line and using the distance to that as the depth value. Known as "The Marcus method" Parameters ---------- data : pygimli DataContainer The topography list is in here. mesh : pygimli.Mesh The parametric mesh used for the inversion VTop : float The velocity at the surface of the mesh VBot : float The velocity at the bottom of the mesh Returns ------- model : pygimli Vector, length M A numpy array with slowness values that can be used to start the inversion. """ p = np.polyfit(pg.x(data.sensorPositions()), pg.y(data.sensorPositions()), deg=1) # slope-intercept form n = np.asarray([-p[0], 1.0]) # normal vector nLen = np.sqrt(np.dot(n, n)) x = pg.x(mesh.cellCenters()) z = pg.y(mesh.cellCenters()) pos = np.column_stack((x, z)) d = np.array([np.abs(np.dot(pos[i, :], n) - p[1]) / nLen for i in range(pos.shape[0])]) return np.interp(d, [min(d), max(d)], [1.0 / VTop, 1.0 / VBot])
def createGradientModel2D(data, mesh, vTop, vBot): """Create 2D velocity gradient model. Creates a smooth, linear, starting model that takes the slope of the topography into account. This is done by fitting a straight line and using the distance to that as the depth value. Known as "The Marcus method" Parameters ---------- data : pygimli DataContainer The topography list is in here. mesh : pygimli.Mesh The parametric mesh used for the inversion vTop : float The velocity at the surface of the mesh vBot : float The velocity at the bottom of the mesh Returns ------- model : pygimli Vector, length M A numpy array with slowness values that can be used to start the inversion. """ p = np.polyfit(pg.x(data.sensorPositions()), pg.y(data.sensorPositions()), deg=1) # slope-intercept form n = np.asarray([-p[0], 1.0]) # normal vector nLen = np.sqrt(np.dot(n, n)) x = pg.x(mesh.cellCenters()) z = pg.y(mesh.cellCenters()) pos = np.column_stack((x, z)) d = np.array([np.abs(np.dot(pos[i, :], n) - p[1]) / nLen for i in range(pos.shape[0])]) return 1. / np.interp(d, [min(d), max(d)], [vTop, vBot])
def createTriangles(mesh, data=None): """ What is this? """ x = pg.x(mesh.positions()) # x.round(1e-1) y = pg.y(mesh.positions()) # y.round(1e-1) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triCount = triCount + 2 else: triCount = triCount + 1 triangles = np.zeros((triCount, 3)) dataIdx = list(range(triCount)) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(2).id() triangles[triCount, 2] = c.node(3).id() dataIdx[triCount] = c.id() triCount = triCount + 1 else: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 z = None if data is not None: if len(data) == mesh.cellCount(): # strange behavior if we just use these slice z = np.array(data[dataIdx]) else: z = np.array(data) return x, y, triangles, z, dataIdx
def cellDataToBoundaryData(mesh, vec): """ DOCUMENT_ME """ if len(data) != mesh.cellCount(): raise BaseException("Dimension mismatch, expecting cellCount(): " + str(mesh.cellCount()) + "got: " + str(len(vec)), str(len(vec[0]))) CtB = mesh.cellToBoundaryInterpolation() if type(vec) == pg.R3Vector(): return np.array([CtB*pg.x(vec), CtB*pg.y(vec), CtB*pg.z(vec)]).T else: return CtB*vec
def calcGeometricFactor(self, data): """Calculate geometry factors for a given dataset.""" if pg.y(data.sensorPositions()) == pg.z(data.sensorPositions()): k = np.zeros(data.size()) for i in range(data.size()): a = data.sensorPosition(data('a')[i]) b = data.sensorPosition(data('b')[i]) m = data.sensorPosition(data('m')[i]) n = data.sensorPosition(data('n')[i]) k[i] = 1. / (2. * np.pi) * (1. / a.dist(m) - 1. / a.dist(n) - 1. / b.dist(m) + 1. / b.dist(n)) return k else: raise BaseException("Please use BERT for non-standard " "data sets" + str(data))
def cellDataToBoundaryData(mesh, data): """ TODO DOCUMENT_ME """ if len(data) != mesh.cellCount(): raise BaseException( "Dimension mismatch, expecting cellCount(): " + str(mesh.cellCount()) + "got: " + str(len(data)), str(len(data[0]))) CtB = mesh.cellToBoundaryInterpolation() if isinstance(data, pg.R3Vector()): return np.array([CtB * pg.x(data), CtB * pg.y(data), CtB * pg.z(data)]).T else: return CtB * data
def cellDataToBoundaryData(mesh, data): """ TODO DOCUMENT_ME """ if len(data) != mesh.cellCount(): raise BaseException("Dimension mismatch, expecting cellCount(): " + str(mesh.cellCount()) + "got: " + str(len(data)), str(len(data[0]))) CtB = mesh.cellToBoundaryInterpolation() if isinstance(data, pg.R3Vector()): return np.array([CtB * pg.x(data), CtB * pg.y(data), CtB * pg.z(data)]).T else: return CtB * data
def createTriangles(mesh, data=None): """TODO Documentme.""" x = pg.x(mesh.positions()) # x.round(1e-1) y = pg.y(mesh.positions()) # y.round(1e-1) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triCount = triCount + 2 else: triCount = triCount + 1 triangles = np.zeros((triCount, 3)) dataIdx = list(range(triCount)) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(2).id() triangles[triCount, 2] = c.node(3).id() dataIdx[triCount] = c.id() triCount = triCount + 1 else: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 z = None if data is not None: if len(data) == mesh.cellCount(): # strange behavior if we just use these slice z = np.array(data[dataIdx]) else: z = np.array(data) return x, y, triangles, z, dataIdx
def calcGeometricFactors(self, data): """Calculate geometry factors for a given dataset.""" if pg.y(data) == pg.z(data): k = np.zeros(data.size()) for i in range(data.size()): a = data.sensorPosition(data('a')[i]) b = data.sensorPosition(data('b')[i]) m = data.sensorPosition(data('m')[i]) n = data.sensorPosition(data('n')[i]) k[i] = 2.*np.pi * 1./(1./a.dist(m) - 1./a.dist(n) - 1./b.dist(m) + 1./b.dist(n)) return k else: raise BaseException("Please use BERT for non-standard " "data sets" + str(data))
def exportHDF5Mesh(mesh, exportname, group='mesh', indices='cell_indices', pos='coordinates', cells='topology', marker='values'): """Writes given :gimliapi:`GIMLI::Mesh` in a hdf5 format file. 3D tetrahedron meshes only! Boundary markers are ignored. Keywords are explained in :py:mod:`pygimli.meshtools.readHDFS` """ h5py = pg.optImport('h5py', requiredFor='export mesh in .h5 data format') if not isinstance(mesh, pg.Mesh): mesh = pg.Mesh(mesh) # prepare output for writing in hdf data container pg_pos = mesh.positions() mesh_pos = np.array((np.array(pg.x(pg_pos)), np.array(pg.y(pg_pos)), np.array(pg.z(pg_pos)))).T mesh_cells = np.zeros((mesh.cellCount(), 4)) # hard coded for tetrahedrons for i, cell in enumerate(mesh.cells()): mesh_cells[i] = cell.ids() mesh_indices = np.arange(0, mesh.cellCount() + 1, 1, dtype=np.int64) mesh_markers = np.array(mesh.cellMarkers()) with h5py.File(exportname, 'w') as out: for grp in np.atleast_1d(group): # can use more than one group # writing indices idx_name = '{}/{}'.format(grp, indices) out.create_dataset(idx_name, data=mesh_indices, dtype=int) # writing node positions pos_name = '{}/{}'.format(grp, pos) out.create_dataset(pos_name, data=mesh_pos, dtype=float) # writing cells via indices cells_name = '{}/{}'.format(grp, cells) out.create_dataset(cells_name, data=mesh_cells, dtype=int) # writing marker marker_name = '{}/{}'.format(grp, marker) out.create_dataset(marker_name, data=mesh_markers, dtype=int) out[grp][cells].attrs['celltype'] = np.string_('tetrahedron') out[grp][cells].attrs.create('partition', [0]) return True
def solveDarcy(mesh, k=None, p0=1, verbose=False): """Darcy flow.""" if verbose: print("Solve Darcy equation ...") uDir = [[2, p0], # left aquiver [3, p0], # left bedrock # [4, 0], # bottom (paper) [5, 0], # right bedrock [6, 0], # right aquiver [7, 0], # right top ] p = pg.solver.solve(mesh, a=k, bc={'Dirichlet': uDir}, verbose=True) vel = -pg.solver.grad(mesh, p) * np.asarray([k, k, k]).T mvel = mt.cellDataToNodeData(mesh, vel) return mesh, mvel, p, k, np.asarray([pg.x(vel), pg.y(vel)])
def createFinePoly( coarseMesh, ePos ): paraBoundary = 10 mesh = g.Mesh() n1 = None; n2 = None; n3 = None; n4 = None for n in coarseMesh.nodes(): if n.marker() == 1: n1 = mesh.createNode( n.pos(), 1 ) elif n.marker() == 2: n2 = mesh.createNode( n.pos(), 2 ) elif n.marker() == 3: n3 = mesh.createNode( n.pos(), 3 ) elif n.marker() == 4: n4 = mesh.createNode( n.pos(), 4 ) mesh.createEdge( n1, n2, 12 ); mesh.createEdge( n2, n3, 23 ); mesh.createEdge( n3, n4, 34 ); mesh.createEdge( n4, n1, 41 ); x = g.x( ePos ) y = g.y( ePos ) z = g.z( ePos ) xMin = min( x ); xMax = max( x ) yMin = min( y ); yMax = max( y ) zMin = min( z ); zMax = max( z ) maxSpan = max( xMax - xMin, yMax - yMin ); borderPara = maxSpan * paraBoundary / 100.0; n5 = mesh.createNode( xMin - borderPara, yMin - borderPara , 0.0, 5 ); n6 = mesh.createNode( xMax + borderPara, yMin - borderPara , 0.0, 6 ); n7 = mesh.createNode( xMax + borderPara, yMax + borderPara , 0.0, 7 ); n8 = mesh.createNode( xMin - borderPara, yMax + borderPara , 0.0, 8 ); mesh.createEdge( n5, n6, 56 ); mesh.createEdge( n6, n7, 67 ); mesh.createEdge( n7, n8, 78 ); mesh.createEdge( n8, n5, 85 ); for p in ePos: mesh.createNode( p ) return mesh;
def exportHDF5Mesh(mesh, exportname, group='mesh', indices='cell_indices', pos='coordinates', cells='topology', marker='values'): ''' 3D tetrahedron meshes only! Boundary markers are ignored. Keywords are explained in "readH5" ''' h5py = pg.io.opt_import('h5py', requiredTo='export mesh in .h5 data format') if not isinstance(mesh, pg.Mesh): mesh = pg.Mesh(mesh) # prepare output for writing in hdf data container pg_pos = mesh.positions() mesh_pos = np.array((np.array(pg.x(pg_pos)), np.array(pg.y(pg_pos)), np.array(pg.z(pg_pos)))).T mesh_cells = np.zeros((mesh.cellCount(), 4)) # hard coded for tetrahedrons for i, cell in enumerate(mesh.cells()): mesh_cells[i] = cell.ids() mesh_indices = np.arange(0, mesh.cellCount() + 1, 1, dtype=np.int64) mesh_markers = np.array(mesh.cellMarkers()) with h5py.File(exportname, 'w') as out: # writing indices idx_name = '{}/{}'.format(group, indices) out.create_dataset(idx_name, data=mesh_indices, dtype=np.int64) # writing node positions pos_name = '{}/{}'.format(group, pos) out.create_dataset(pos_name, data=mesh_pos, dtype=float) # writing cells via indices cells_name = '{}/{}'.format(group, cells) out.create_dataset(cells_name, data=mesh_cells, dtype=np.int64) # writing marker marker_name = '{}/{}'.format(group, marker) out.create_dataset(marker_name, data=mesh_markers, dtype=np.uint64) out[group][cells].attrs['celltype'] = np.array(('tetrahedron')) out[group][cells].attrs['partition'] = np.array([0], dtype=np.uint64) return True
def rst_cov(mesh, cov): """ Simplify refraction coverage with convex hull. """ points_all = np.column_stack(( pg.x(mesh.cellCenters()), pg.y(mesh.cellCenters()), )) points = points_all[np.nonzero(cov)[0]] hull = ConvexHull(points) hull_path = Path(points[hull.vertices]) covs = [] for cell in mesh.cells(): if hull_path.contains_point(points_all[cell.id()]): covs.append(1) else: covs.append(0) return np.array(covs)
def checkData(self): """ check data w.r.t. shot/geophone identity and zero/negative traveltimes, plus check y/z sensor positions """ oldsize = self.data.size() self.data.markInvalid(pg.abs(self.data("s") - self.data("g")) < 1) self.data.markInvalid(self.data("t") <= 0.0) self.data.removeInvalid() newsize = self.data.size() if newsize < oldsize: print("Removed " + str(oldsize - newsize) + " values.") maxyabs = max(pg.abs(pg.y(self.data.sensorPositions()))) maxzabs = max(pg.abs(pg.z(self.data.sensorPositions()))) if maxzabs > 0 and maxyabs == 0: for i in range(self.data.sensorCount()): pos = self.data.sensorPosition(i).rotateX(-pi / 2) self.data.setSensorPosition(i, pos) print(self.data)
def solveDarcy(mesh, k=None, p0=1, verbose=False): """Darcy flow.""" if verbose: print("Solve Darcy equation ...") uDir = [ [2, p0], # left aquiver [3, p0], # left bedrock # [4, 0], # bottom (paper) [5, 0], # right bedrock [6, 0], # right aquiver [7, 0], # right top ] p = pg.solver.solve(mesh, a=k, uB=uDir) vel = -pg.solver.grad(mesh, p) * np.asarray([k, k, k]).T mvel = mt.cellDataToNodeData(mesh, vel) return mesh, mvel, p, k, np.asarray([pg.x(vel), pg.y(vel)])
def drawRayPaths(self, ax, model=None, **kwargs): """Draw the the ray paths for model or last model. If model is not specifies, the last calculated Jacobian is used. Parameters ---------- model : array Velocity model for which to calculate and visualize ray paths (the default is model for last Jacobian calculation in self.velocity). ax : matplotlib.axes object To draw the model and the path into. **kwargs : type Additional arguments passed to LineCollection (alpha, linewidths, color, linestyles). Returns ------- lc : matplotlib.LineCollection """ if model is not None: if self.fop.jacobian().size() == 0 or model != self.model: self.fop.createJacobian(1/model) else: model = self.model _ = kwargs.setdefault("color", "w") _ = kwargs.setdefault("alpha", 0.5) _ = kwargs.setdefault("linewidths", 0.8) shots = self.fop.data.id("s") recei = self.fop.data.id("g") segs = [] for s, g in zip(shots, recei): wi = self.fop.way(s, g) points = self.fop._core.mesh().positions(withSecNodes=True)[wi] segs.append(np.column_stack((pg.x(points), pg.y(points)))) lc = LineCollection(segs, **kwargs) ax.add_collection(lc) return lc
def createMesh(self, quality=34.6, maxarea=0.1, addpoints=None): """Create (inversion) mesh by circumventing PLC""" data = self.dataContainer sx = list(pg.x(data.sensorPositions())) sz = list(pg.y(data.sensorPositions())) if addpoints is not None: for po in addpoints: sx.append(po[0]) sz.append(po[1]) iS = np.argsort(np.arctan2(sx-np.mean(sx), sz-np.mean(sz))) plc = pg.Mesh(2) nodes = [plc.createNode(sx[i], sz[i], 0) for i in iS] for i in range(len(nodes)-1): plc.createEdge(nodes[i], nodes[i+1]) plc.createEdge(nodes[-1], nodes[0]) tri = pg.TriangleWrapper(plc) tri.setSwitches("-pzFq"+str(quality)+"a"+str(maxarea)) self.setMesh(tri.generate())
def createMesh(self, quality=34.6, maxarea=0.1, addpoints=None): """Create (inversion) mesh by circumventing PLC""" data = self.dataContainer sx = list(pg.x(data.sensorPositions())) sz = list(pg.y(data.sensorPositions())) if addpoints is not None: for po in addpoints: sx.append(po[0]) sz.append(po[1]) iS = np.argsort(np.arctan2(sx - np.mean(sx), sz - np.mean(sz))) plc = pg.Mesh(2) nodes = [plc.createNode(sx[i], sz[i], 0) for i in iS] for i in range(len(nodes) - 1): plc.createEdge(nodes[i], nodes[i + 1]) plc.createEdge(nodes[-1], nodes[0]) tri = pg.TriangleWrapper(plc) tri.setSwitches("-pzFq" + str(quality) + "a" + str(maxarea)) self.setMesh(tri.generate())
def showVA(self, data=None, t=None, name='va', pseudosection=False, squeeze=True, full=True, ax=None, cmap=None, **kwargs): """Show apparent velocity as image plot. TODO showXXX commands need to return ax and cbar .. if there is one """ if data is None: data = self.dataContainer if ax is None: fig, ax = plt.subplots() self.figs[name] = fig self.axs[name] = ax if t is None: t = data('t') px = pg.x(data.sensorPositions()) py = pg.y(data.sensorPositions()) if len(np.unique(py)) > len(np.unique(px)): # probably crosshole px = py gx = np.array([px[int(g)] for g in data("g")]) sx = np.array([px[int(s)] for s in data("s")]) offset = self.getOffset(data=data, full=full) kwargs.setdefault('vals', offset / t) if pseudosection: midpoint = (gx + sx) / 2 _, cb = showVecMatrix(midpoint, offset, squeeze=True, ax=ax, label='Apparent slowness [s/m]', cmap=cmap, **kwargs) else: _, cb = showVecMatrix(gx, sx, squeeze=squeeze, ax=ax, label='Apparent velocity [m/s]', cmap=cmap, **kwargs) ax.figure.show() return ax, cb
def transform2DMeshTo3D(mesh, x, y, z=None): """2D mesh into 3D coordinates. Transform a 2D mesh into 3D coordinates using a point list (e.g. from GPS) Parameters ---------- mesh: :gimliapi:`GIMLI::Mesh` x,y: [float] array of x/y positions along 2d profile z: [float] optional height to add (topographical correction on top of flat earth) See Also -------- References ---------- """ # get mesh node positions mt, mz = pg.x(mesh.positions()), pg.y(mesh.positions()) # mesh tape and z # compute length of reference points along tape pt = np.hstack((0., np.cumsum(np.sqrt(np.diff(x)**2 + np.diff(y)**2)))) # interpolate node positions from tape to x/y using tape positions mx = np.interp(mt, pt, x) my = np.interp(mt, pt, y) # compute z offset by interpolating z if z is None: oz = np.zeros(len(mt)) else: oz = np.interp(mt, pt, z) # set the positions in the mesh for i, node in enumerate(mesh.nodes()): node.setPos(pg.RVector3(mx[i], my[i], mz[i] + oz[i]))
def checkData(self): """check data w.r.t. shot/geophone identity and zero/negative traveltimes, plus check y/z sensor positions """ oldsize = self.dataContainer.size() self.dataContainer.markInvalid( pg.abs(self.dataContainer('s') - self.dataContainer('g')) < 1) self.dataContainer.markInvalid(self.dataContainer('t') <= 0.) self.dataContainer.removeInvalid() newsize = self.dataContainer.size() if newsize < oldsize: if self.verbose: print('Removed ' + str(oldsize - newsize) + ' values.') maxyabs = max(pg.abs(pg.y(self.dataContainer.sensorPositions()))) maxzabs = max(pg.abs(pg.z(self.dataContainer.sensorPositions()))) if maxzabs > 0 and maxyabs == 0: for i in range(self.dataContainer.sensorCount()): pos = self.dataContainer.sensorPosition(i).rotateX(-pi / 2) self.dataContainer.setSensorPosition(i, pos) if self.verbose: print(self.dataContainer)
def testShowVariants(): # Create geometry definition for the modelling domain world = mt.createWorld(start=[-10, 0], end=[10, -16], layers=[-8], worldMarker=False) # Create a heterogeneous block block = mt.createRectangle(start=[-6, -3.5], end=[6, -6.0], marker=4, boundaryMarker=10, area=0.1) circ = mt.createCircle(pos=[0, -11], radius=2, boundaryMarker=11, isHole=True) # Merge geometrical entities geom = world + block + circ mesh = mt.createMesh(geom) fig, axs = plt.subplots(3, 5) pg.show(geom, ax=axs[0][0]) axs[0][0].set_title('plc, (default)') pg.show(geom, fillRegion=False, ax=axs[0][1]) axs[0][1].set_title('plc, fillRegion=False') pg.show(geom, showBoundary=False, ax=axs[0][2]) axs[0][2].set_title('plc, showBoundary=False') pg.show(geom, markers=True, ax=axs[0][3]) axs[0][3].set_title('plc, markers=True') pg.show(mesh, ax=axs[0][4], showBoundary=False) axs[0][4].set_title('mesh, showBoundary=False') pg.show(mesh, ax=axs[1][0]) axs[1][0].set_title('mesh, (default)') pg.show(mesh, mesh.cellMarkers(), label='Cell markers', ax=axs[1][1]) axs[1][1].set_title('mesh, cells, (default)') pg.show(mesh, markers=True, ax=axs[1][2]) axs[1][2].set_title('mesh, cells, markers=True') pg.show(mesh, mesh.cellMarkers(), label='Cell markers', showMesh=True, ax=axs[1][3]) axs[1][3].set_title('mesh, cells, showMesh=True') pg.show(mesh, mesh.cellMarkers(), label='Cell markers', showBoundary=False, ax=axs[1][4]) axs[1][4].set_title('mesh, cells, showBoundary=False') pg.show(mesh, pg.x(mesh), label='Nodes (x)', ax=axs[2][0]) axs[2][0].set_title('mesh, nodes, (default)') pg.show(mesh, pg.x(mesh), label='Nodes (x)', showMesh=True, ax=axs[2][1]) axs[2][1].set_title('mesh, nodes, showMesh=True') pg.show(mesh, pg.x(mesh), label='Nodes (x)', showBoundary=True, ax=axs[2][2]) axs[2][2].set_title('mesh, nodes, showBoundary=True') pg.show(mesh, pg.y(mesh.cellCenters()), label='Cell center (y)', tri=True, shading='flat', ax=axs[2][3]) axs[2][3].set_title('mesh, cells, tri=True, shading=flat') pg.show(mesh, pg.y(mesh.cellCenters()), label='Cell center (y)', tri=True, shading='gouraud', ax=axs[2][4]) axs[2][4].set_title('mesh, cells, tri=True, shading=gouraud') ##pg.show(mesh, mesh.cellMarker(), label(markers), axs[1][1]) axs[2][4].figure.tight_layout() fig.tight_layout()
def testCoverage(): grid = pg.createGrid(10, 10) cov = pg.y(grid.cellCenters()).array() cov[-9:] = 0 # remove first row data = pg.Vector(grid.cellCount(), 1.0) pg.show(grid, data, coverage=cov)
def createTriangles(mesh, data=None): """Generate triangle objects for later drawing. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` pyGimli mesh to plot data : iterable [None] cell-based values to plot Returns ------- x : numpy array x position of nodes y : numpy array x position of nodes triangles : numpy array Cx3 cell indices for each triangle z : numpy array data for given indices dataIdx : list of int list of indices into array to plot """ x = pg.x(mesh.positions()) # x.round(1e-1) y = pg.y(mesh.positions()) # y.round(1e-1) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triCount = triCount + 2 else: triCount = triCount + 1 triangles = np.zeros((triCount, 3)) dataIdx = list(range(triCount)) triCount = 0 for c in mesh.cells(): if c.shape().nodeCount() == 4: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(2).id() triangles[triCount, 2] = c.node(3).id() dataIdx[triCount] = c.id() triCount = triCount + 1 else: triangles[triCount, 0] = c.node(0).id() triangles[triCount, 1] = c.node(1).id() triangles[triCount, 2] = c.node(2).id() dataIdx[triCount] = c.id() triCount = triCount + 1 z = None if data is not None: if len(data) == mesh.cellCount(): # strange behavior if we just use these slice z = np.array(data[dataIdx]) else: z = np.array(data) return x, y, triangles, z, dataIdx
axs[1][3].set_title('mesh, cells, showMesh=True') pg.show(mesh, mesh.cellMarkers(), label='Cell markers', showBoundary=False, ax=axs[1][4]) axs[1][4].set_title('mesh, cells, showBoundary=False') pg.show(mesh, pg.x(mesh), label='Nodes (x)', ax=axs[2][0]) axs[2][0].set_title('mesh, nodes, (default)') pg.show(mesh, pg.x(mesh), label='Nodes (x)', showMesh=True, ax=axs[2][1]) axs[2][1].set_title('mesh, nodes, showMesh=True') pg.show(mesh, pg.x(mesh), label='Nodes (x)', showBoundary=True, ax=axs[2][2]) axs[2][2].set_title('mesh, nodes, showBoundary=True') pg.show(mesh, pg.y(mesh.cellCenters()), label='Cell center (y)', tri=True, shading='flat', ax=axs[2][3]) axs[2][3].set_title('mesh, cells, tri=True, shading=flat') pg.show(mesh, pg.y(mesh.cellCenters()), label='Cell center (y)', tri=True, shading='gouraud', ax=axs[2][4]) axs[2][4].set_title('mesh, cells, tri=True, shading=gouraud') ##pg.show(mesh, mesh.cellMarker(), label(markers), axs[1][1]) pg.wait()
def covarianceMatrixPos(pos, **kwargs): """Position (R3Vector) based covariance matrix""" return covarianceMatrixVec(np.array(pg.x(pos)), np.array(pg.y(pos)), np.array(pg.z(pos)), **kwargs)
def test2d(): mesh = pg.Mesh("mesh/world2d.bms") print (mesh) xMin = mesh.boundingBox().min()[0] yMax = mesh.boundingBox().max()[0] x = np.arange(xMin, yMax, 1.0) mesh.createNeighbourInfos() rho = pg.RVector(len(mesh.cellAttributes()), 1.0) * 2000.0 rho.setVal(0.0, pg.find(mesh.cellAttributes() == 1.0)) swatch = pg.Stopwatch(True) pnts = [] spnts = pg.stdVectorRVector3() for i in x: pnts.append(pg.RVector3(i, 0.0001)) spnts.append(pg.RVector3(i, 0.0001)) # gzC, GC = calcGCells(pnts, mesh, rho, 1) gzC = pg.calcGCells(spnts, mesh, rho, 1) print ("calcGCells", swatch.duration(True)) # gzB, GB = calcGBounds(pnts, mesh, rho) # gzB = pg.calcGBounds(spnts, mesh, rho) # print("calcGBounds", swatch.duration(True)) gZ_Mesh = gzC ax1, ax2 = getaxes() # sphere analytical solution gAna = analyticalCircle2D(spnts, radius=2.0, pos=pg.RVector3(0.0, -5.0), dDensity=2000) gAna2 = analyticalCircle2D(spnts, radius=2.0, pos=pg.RVector3(5.0, -5.0), dDensity=2000) gAna = gAna + gAna2 ax1.plot(x, gAna, "-x", label="analytical") ax1.plot(x, gZ_Mesh, label="WonBevis1987-mesh") print (gAna / gZ_Mesh) # rho=GB[0]/mesh.cellSizes() drawModel(ax2, mesh, rho) for i in (0, 1): drawSelectedMeshBoundaries(ax2, mesh.findBoundaryByMarker(i), color=(1.0, 1.0, 1.0, 1.0), linewidth=0.3) # sphere polygone radius = 2.0 depth = 5.0 poly1 = pg.stdVectorRVector3() poly2 = pg.stdVectorRVector3() nSegment = 124 for i in range(nSegment): xp = np.sin((i + 1) * (2.0 * np.pi) / nSegment) yp = np.cos((i + 1) * (2.0 * np.pi) / nSegment) poly1.append(pg.RVector3(xp * radius, yp * radius - depth)) poly2.append(pg.RVector3(xp * radius + 5.0, yp * radius - depth)) gZ_Poly = calcPolydgdz(spnts, poly1, 2000) gZ_Poly += calcPolydgdz(spnts, poly2, 2000) ax1.plot(x, gZ_Poly, label="WonBevis1987-Poly") ax2.plot(pg.x(poly1), pg.y(poly1), color="red") ax2.plot(pg.x(poly2), pg.y(poly2), color="red") ax2.plot(pg.x(spnts), pg.y(spnts), marker="x", color="black") # test some special case for i, p in enumerate(poly1): poly1[i] = pg.RVector3(poly1[i] - pg.RVector3(5.0, -6.0)) ax2.plot(pg.x(poly1), pg.y(poly1), color="green") gz = calcPolydgdz(spnts, poly1, 2000) ax1.plot(x, gz, label="Special Case", color="green") ax1.set_ylabel("dg/dz [mGal]") ax2.set_ylabel("Tiefe [m]") ax1.legend() ax2.set_xlim([x[0], x[-1]]) ax2.grid()
def drawStreams(ax, mesh, data, startStream=3, **kwargs): """Draw streamlines based on an unstructured mesh. Every cell contains only one streamline and every new stream line starts in the center of a cell. You can alternatively provide a second mesh with coarser mesh to draw streams for. Parameters ---------- ax : matplotlib.ax ax to draw into mesh : :gimliapi:`GIMLI::Mesh` 2d Mesh to draw the streamline data : iterable float | [float, float] | pg.R3Vector If data is an array (per cell or node) gradients are calculated otherwise the data will be interpreted as vector field. startStream : int variate the start stream drawing, try values from 1 to 3 what every you like more. **kwargs: forward to drawStreamLine_ * coarseMesh Instead of draw a stream for every cell in mesh, draw a streamline segment for each cell in coarseMesh. * quiver: bool Draw arrows instead of streamlines. Examples -------- >>> import numpy as np >>> import matplotlib.pyplot as plt >>> import pygimli as pg >>> from pygimli.mplviewer import drawStreams >>> n = np.linspace(0, 1, 10) >>> mesh = pg.createGrid(x=n, y=n) >>> nx = pg.x(mesh.positions()) >>> ny = pg.y(mesh.positions()) >>> data = np.cos(1.5 * nx) * np.sin(1.5 * ny) >>> fig, ax = plt.subplots() >>> drawStreams(ax, mesh, data, color='red') >>> drawStreams(ax, mesh, data, dropTol=0.9) >>> drawStreams(ax, mesh, pg.solver.grad(mesh, data), ... color='green', quiver=True) >>> ax.set_aspect('equal') >>> pg.wait() """ viewMesh = None dataMesh = None quiver = kwargs.pop('quiver', False) if quiver: x = None y = None u = None v = None if len(data) == mesh.nodeCount(): x = pg.x(mesh.positions()) y = pg.y(mesh.positions()) elif len(data) == mesh.cellCount(): x = pg.x(mesh.cellCenters()) y = pg.y(mesh.cellCenters()) elif len(data) == mesh.boundaryCount(): x = pg.x(mesh.boundaryCenters()) y = pg.y(mesh.boundaryCenters()) if isinstance(data, pg.R3Vector): u = pg.x(data) v = pg.y(data) else: u = data[:, 0] v = data[:, 1] ax.quiver(x, y, u, v, **kwargs) updateAxes_(ax) return if 'coarseMesh' in kwargs: viewMesh = kwargs['coarseMesh'] dataMesh = mesh dataMesh.createNeighbourInfos() del kwargs['coarseMesh'] else: viewMesh = mesh viewMesh.createNeighbourInfos() for c in viewMesh.cells(): c.setValid(True) if startStream == 1: # start a stream from each boundary cell for y in np.linspace(viewMesh.ymin(), viewMesh.ymax(), 100): c = viewMesh.findCell( [(viewMesh.xmax() - viewMesh.xmax()) / 2.0, y]) if c is not None: if c.valid(): drawStreamLine_(ax, viewMesh, c, data, dataMesh, **kwargs) elif startStream == 2: # start a stream from each boundary cell for x in np.linspace(viewMesh.xmin(), viewMesh.xmax(), 100): c = viewMesh.findCell( [x, (viewMesh.ymax() - viewMesh.ymax()) / 2.0]) if c is not None: if c.valid(): drawStreamLine_(ax, viewMesh, c, data, dataMesh, **kwargs) elif startStream == 3: # start a stream from each boundary cell for b in viewMesh.findBoundaryByMarker(1, 99): c = b.leftCell() if c is None: c = b.rightCell() if c.valid(): drawStreamLine_(ax, viewMesh, c, data, dataMesh, **kwargs) # start a stream from each unused cell for c in viewMesh.cells(): if c.valid(): drawStreamLine_(ax, viewMesh, c, data, dataMesh, **kwargs) for c in viewMesh.cells(): c.setValid(True) updateAxes_(ax)
def show(obj=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a obj with data. Forwards to a known visualization for obj. Typical is :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call creates an empty ax window. Parameters ---------- obj: obj obj can be so far. * :gimliapi:`GIMLI::Mesh` or list of meshes * DataContainer * pg.core.Sparse[Map]Matrix data: iterable Optionally data to visualize. See appropriate show function. Keyword Arguments ----------------- **kwargs Additional kwargs forward to appropriate show functions. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * fitView : bool [True] Scale x and y limits to match the view. Returns ------- Return the results from the showMesh* functions. Usually the axe object and a colorbar. See Also -------- showMesh """ if "axes" in kwargs: # remove me in 1.2 #20200515 print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) ### Empty call just to create a axes if obj is None and not 'mesh' in kwargs.keys(): ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots(figsize=kwargs.pop('figsize', None))[1] return ax, None ### try to interprete obj containes a mesh if hasattr(obj, 'mesh'): return pg.show(obj.mesh, obj, **kwargs) ### try to interprete obj as ERT Data if isinstance(obj, pg.DataContainerERT): from pygimli.physics.ert import showERTData return showERTData(obj, vals=kwargs.pop('vals', data), **kwargs) ### try to interprete obj as matrices if isinstance(obj, pg.core.MatrixBase) or \ (isinstance(obj, np.ndarray) and obj.ndim == 2): return showMatrix(obj, **kwargs) try: from scipy.sparse import spmatrix if isinstance(obj, spmatrix): return showMatrix(obj, **kwargs) except ImportError: pass ### try to interprete obj as mesh or list of meshes mesh = kwargs.pop('mesh', obj) fitView = kwargs.get('fitView', True) if isinstance(mesh, list): ax = kwargs.pop('ax', None) ax, cBar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) for m in mesh[1:]: ax, cBar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) if fitView is not False: ax.autoscale(enable=True, axis='both', tight=True) ax.set_aspect('equal') return ax, cBar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .vistaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) pg.error("Can't interprete obj: {0} to show.".format(obj)) return None, None
def interpolateAlongCurve(curve, t, **kwargs): """Interpolate along curve. Return curve coordinates for a piecewise linear curve :math:`C(t) = {x_i,y_i,z_i}` at positions :math:`t`. Curve and :math:`t` values are expected to be sorted along distance from the origin of the curve. Parameters ---------- curve : [[x,z]] | [[x,y,z]] | [:gimliapi:`GIMLI::RVector3`] | :gimliapi:`GIMLI::R3Vector` Discrete curve for 2D :math:`x,z` curve=[[x,z]], 3D :math:`x,y,z` t : 1D iterable Query positions along the curve in absolute distance kwargs : If kwargs are given an additional curve smoothing is applied using :py:mod:`pygimli.meshtools.interpolate`. The kwargs will be delegated. Returns ------- p : np.array Curve positions at query points :math:`t`. Dimension of p match the size of curve the coordinates. Examples -------- >>> # no need to import matplotlib. pygimli's show does >>> import numpy as np >>> import pygimli as pg >>> import pygimli.meshtools as mt >>> fig, axs = pg.plt.subplots(2,2) >>> topo = np.array([[-2., 0.], [-1., 0.], [0.5, 0.], [3., 2.], [4., 2.], [6., 1.], [10., 1.], [12., 1.]]) >>> t = np.arange(15.0) >>> p = mt.interpolateAlongCurve(topo, t) >>> _= axs[0,0].plot(topo[:,0], topo[:,1], '-x', mew=2) >>> _= axs[0,1].plot(p[:,0], p[:,1], 'o', color='red') #doctest: +ELLIPSIS >>> >>> p = mt.interpolateAlongCurve(topo, t, method='spline') >>> _= axs[1,0].plot(p[:,0], p[:,1], '-o', color='black') #doctest: +ELLIPSIS >>> >>> p = mt.interpolateAlongCurve(topo, t, method='harmonic', nc=3) >>> _= axs[1,1].plot(p[:,0], p[:,1], '-o', color='green') #doctest: +ELLIPSIS >>> >>> pg.plt.show() >>> pg.wait() """ xC = np.zeros(len(curve)) yC = np.zeros(len(curve)) zC = np.zeros(len(curve)) tCurve = kwargs.pop('tCurve', None) if tCurve is None: tCurve = pg.utils.cumDist(curve) dim = 3 ## extrapolate starting overlaps if min(t) < min(tCurve): d = pg.RVector3(curve[1]) - pg.RVector3(curve[0]) #d[2] = 0.0 d.normalise() curve = np.insert(curve, [0], [ curve[0] - np.array(d * (min(tCurve) - min(t)))[0:curve.shape[1]] ], axis=0) tCurve = np.insert(tCurve, 0, min(t), axis=0) ## extrapolate ending overlaps if max(t) > max(tCurve): d = pg.RVector3(curve[-2]) - pg.RVector3(curve[-1]) #d[2] = 0.0 d.normalise() curve = np.append(curve, [ curve[-1] - np.array(d * (max(t) - max(tCurve)))[0:curve.shape[1]] ], axis=0) tCurve = np.append(tCurve, max(t)) if isinstance(curve, pg.R3Vector) or isinstance(curve, pg.stdVectorRVector3): xC = pg.x(curve) yC = pg.y(curve) zC = pg.z(curve) else: if curve.shape[1] == 2: xC = curve[:, 0] zC = curve[:, 1] dim = 2 else: xC = curve[:, 0] yC = curve[:, 1] zC = curve[:, 2] if len(kwargs.keys()) > 0: #interpolate more curve points to get a smooth line dTi = min(pg.utils.dist(pg.utils.diff(curve))) / 10. ti = np.arange(min(tCurve), max(tCurve) + dTi, dTi) xC = pg.interpolate(ti, tCurve, xC, **kwargs) zC = pg.interpolate(ti, tCurve, zC, **kwargs) if dim == 3: yC = pg.interpolate(ti, tCurve, yC, **kwargs) tCurve = ti xt = interpolate(t, tCurve, xC) zt = interpolate(t, tCurve, zC) if dim == 2: return np.vstack([xt, zt]).T yt = interpolate(t, tCurve, yC) return np.vstack([xt, yt, zt]).T
#ax, _ = pg.show(mesh, data=K, label='Hydraulic conductivity $K$ in m$/$s', #cMin=1e-5, cMax=1e-2, nLevs=4, cmap='viridis') #ax, _ = pg.show(mesh, data=pg.abs(vel), logScale=0, label='Velocity $v$ in m$/$s') #ax, _ = pg.show(mesh, data=vel, ax=ax, color='black', linewidth=0.5, dropTol=1e-6) print('Solve Advection-diffusion equation ...') S = pg.RVector(mesh.cellCount(), 0.0) # Fill injection source vector for a fixed injection position sourceCell = mesh.findCell([-19.1, -4.6]) S[sourceCell.id()] = 1.0 / sourceCell.size() #g/(l s) # Choose 800 time steps for 6 days in seconds t = pg.utils.grange(0, 6 * 24 * 3600, n=800) # Create dispersitivity, depending on the absolute velocity dispersion = pg.abs(vel) * 1e-2 # Solve for injection time, but we need velocities on cell nodes vel = mt.cellDataToNodeData(mesh, np.asarray([pg.x(vel), pg.y(vel)]).T).T c1 = pg.solver.solveFiniteVolume(mesh, a=dispersion, f=S, vel=vel, times=t, uB=[1, 0], scheme='PS', verbose=0) # Solve without injection starting with last result c2 = pg.solver.solveFiniteVolume(mesh, a=dispersion, f=0, vel=vel, u0=c1[-1], times=t,
drawField(ax, mesh, times, cmap='Spectral', fillContour=True) drawStreamLines(ax, mesh, -times, nx=50, ny=50) ############################################################################### # We compare the result with the analytical solution along the x axis x = np.arange(0., 140., 0.5) tFMM = pg.interpolate(mesh, times, x, x * 0., x * 0.) tAna = analyticalSolution2Layer(x) print("min(dt)={} ms max(dt)={} ms".format( min(tFMM - tAna) * 1000, max(tFMM - tAna) * 1000)) ############################################################################### # In order to use the Dijkstra, we extract the surface positions >0 mx = pg.x(mesh.positions()) my = pg.y(mesh.positions()) fi = pg.find((my == 0.0) & (mx >= 0)) px = np.sort(mx(fi)) ############################################################################### # A data container with index arrays named s (shot) and g (geophones) is # created and filled with the positions and shot/geophone indices. data = pg.DataContainer() data.registerSensorIndex('s') data.registerSensorIndex('g') for pxi in px: data.createSensor(pg.RVector3(pxi, 0.0)) ndata = len(px) - 1 data.resize(ndata) data.set('s', pg.RVector(ndata, 0)) # only one shot at first sensor
pg.show(mesh, axes=a, data=l[0]) cells = fwd.mesh().cells() active_cells = [cells[i] for i in range(mesh.cellCount()) if l[0][i]] # active_cells.append(cells[2044]) for c in active_cells: pos = c.center() gradient = 2000 * c.grad(pos, fwd.timefields[0]) dx, dy = gradient.x(), gradient.y() a.text(pos.x(), pos.y(), str(c.id())) a.arrow(pos.x(), pos.y(), dx, dy) ray = fwd.poslist a.plot( pg.x(ray), pg.y(ray), 'm-*', ) plt.show() # look at if next gradient contradicts the previous # if so, then follow the interface instead (line segment to next node) # this will stop when the gradients are more aligned. # drawMesh(a, mesh) # drawField(a, mesh, fwd.timefields[0], True, 'Spectral') # drawStreamLines(a, mesh, fwd.timefields[0], nx=50, ny=50) # some stats: delta_t = np.array(data("t")) - t_fmm diff_rms = np.sqrt(np.sum(delta_t**2) / len(delta_t))
def show(mesh=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a mesh with data. Forwards to :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call create an empty ax window. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` or list of meshes 2D or 3D GIMLi mesh **kwargs : * fitView : bool [True] Scale x and y limits to match the view. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * Will be forwarded to the appropriate show functions. Returns ------- Return the results from the showMesh* functions. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', True) ax, cbar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xmin = mesh[0].xmin() xmax = mesh[0].xmax() ymin = mesh[0].ymin() ymax = mesh[0].ymax() for m in mesh[1:]: ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xmin = min(xmin, m.xmin()) xmax = max(xmax, m.xmax()) ymin = min(ymin, m.ymin()) ymax = max(ymax, m.ymax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) # print(ax.get_data_interval()) return ax, cbar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .mayaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def maillage_SWMS2D(geometry): """Définition du maillage triangulaire pour SWMS_2D""" xmin=geometry.xmin xmax=geometry.xmax emin=geometry.emin emax=geometry.emax dtrou=geometry.dtrou etrou=geometry.etrou r=geometry.r dx=geometry.dx zaff=geometry.zaff eaff=geometry.eaff #waff=geometry.waff assert dtrou + zaff < emax xtrou_reg = np.arange(xmin, r + dx, dx, 'float') # xtrou_reg = np.arange(xmin, r + zaff, dx, 'float') etrou_reg = np.arange(etrou, emax +dx, dx, 'float') efin_reg = np.arange(eaff, etrou+dx, dx, 'float') #A présent on crée une zone grâce à un polygone poly = pg.Mesh(2) # empty 2d mesh nStart = poly.createNode(0.0, 0.0, 0.0) # On crée un noeud de départ, on travaille en 2D donc le dernier terme vaut 0.0 nA = nStart # noeud de départ for e in efin_reg[0:len(efin_reg)]: # On démarre de 1 et on se balade sur l'axe des x en créant un noeud à chaque fois nB = poly.createNode(0, e, 0.0) poly.createEdge(nA, nB) # On définit un côté entre le noeud précédemment créé et le nouveau nA = nB # On remplace le noeud de départ par le noeud nouvellement créé #Définir les noeuds au fond du trou for x in xtrou_reg[1:len(xtrou_reg)]: nB = poly.createNode(x, etrou, 0.0) poly.createEdge(nA, nB) #On définit un côté entre le noeud précédemment crée et le nouveau nA = nB #On remplace le noeud de départ par le noeud nouvellement crée #Définir les noeuds le long du trou for f in etrou_reg[1:len(etrou_reg)]: # On démarre du haut et on se balade sur l'axe des z en créant un noeud à chaque fois nB = poly.createNode(r, f, 0.0) poly.createEdge(nA, nB) # On définit un côté entre le noeud précédemment créé et le nouveau nA = nB # On remplace le noeud de départ par le noeud nouvellement crée nC=nB nD = poly.createNode(xmax, emax, 0.0) poly.createEdge(nC, nD) nE = poly.createNode(xmax, emin, 0.0) poly.createEdge(nD, nE) poly.createEdge(nE, nStart) #On ferme le polygone! mesh=pg.meshtools.createMesh(poly, quality=geometry.quality, area=geometry.area, smooth=geometry.smooth) pg_pos = mesh.positions() mesh_pos = np.array((np.array(pg.x(pg_pos)), np.array(pg.y(pg_pos)), np.array(pg.z(pg_pos)))).T #On crée une matrice contenant la position des noeuds mesh_cells = np.zeros((mesh.cellCount(), 3)) #Matrice vide de la taille du nombre de cellules for i, cell in enumerate(mesh.cells()): #On rentre les cellules das une matrice mesh_cells[i] = cell.ids() return mesh, pg_pos, mesh_pos, mesh_cells
def show(mesh=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a mesh with data. Forwards to :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call creates an empty ax window. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` or list of meshes 2D or 3D GIMLi mesh **kwargs : * fitView : bool [True] Scale x and y limits to match the view. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * Will be forwarded to the appropriate show functions. Returns ------- Return the results from the showMesh* functions. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', True) ax, cbar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xmin = mesh[0].xmin() xmax = mesh[0].xmax() ymin = mesh[0].ymin() ymax = mesh[0].ymax() for m in mesh[1:]: ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xmin = min(xmin, m.xmin()) xmax = max(xmax, m.xmax()) ymin = min(ymin, m.ymin()) ymax = max(ymax, m.ymax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xmin, xmax]) ax.set_ylim([ymin, ymax]) # print(ax.get_data_interval()) return ax, cbar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .mayaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def test2d(): mesh = g.Mesh( 'mesh/world2d.bms' ) print mesh xMin = mesh.boundingBox( ).min()[0] yMax = mesh.boundingBox( ).max()[0] x = P.arange( xMin, yMax, 1. ); mesh.createNeighbourInfos() rho = g.RVector( len( mesh.cellAttributes() ), 1. ) * 2000.0 rho.setVal( 0.0, g.find( mesh.cellAttributes() == 1.0 ) ) swatch = g.Stopwatch( True ) pnts = [] spnts = g.stdVectorRVector3() for i in x: pnts.append( g.RVector3( i, 0.0001 ) ) spnts.append( g.RVector3( i, 0.0001 ) ) #gzC, GC = calcGCells( pnts, mesh, rho, 1 ) gzC = g.calcGCells( spnts , mesh, rho, 1 ) print "calcGCells", swatch.duration( True ) #gzB, GB = calcGBounds( pnts, mesh, rho ) gzB = g.calcGBounds( spnts , mesh, rho ) print "calcGBounds", swatch.duration( True ) gZ_Mesh = gzC ax1, ax2 = getaxes() # sphere analytical solution gAna = analyticalCircle2D( spnts, radius = 2.0, pos = g.RVector3( 0.0, -5.0 ), dDensity = 2000 ) gAna2 = analyticalCircle2D( spnts, radius = 2.0, pos = g.RVector3( 5.0, -5.0 ), dDensity = 2000 ) gAna = gAna + gAna2 ax1.plot( x, gAna, '-x', label= 'Analytisch' ) ax1.plot( x, gZ_Mesh, label= 'WonBevis1987-mesh' ) print gAna / gZ_Mesh #rho=GB[0]/mesh.cellSizes() gci = drawModel( ax2, mesh, rho ) drawSelectedMeshBoundaries( ax2, mesh.findBoundaryByMarker( 0 ) , color = ( 1.0, 1.0, 1.0, 1.0 ) , linewidth = 0.3 ) drawSelectedMeshBoundaries( ax2, mesh.findBoundaryByMarker( 1 ) , color = ( 1.0, 1.0, 1.0, 1.0 ) , linewidth = 0.3 ) # sphere polygone radius = 2. depth = 5. poly1 = g.stdVectorRVector3() poly2 = g.stdVectorRVector3() nSegment=124 for i in range( nSegment ): xp = np.sin( (i+1) * ( 2. * np.pi ) / nSegment ) yp = np.cos( (i+1) * ( 2. * np.pi ) / nSegment ) poly1.append( g.RVector3( xp * radius, yp * radius - depth ) ) poly2.append( g.RVector3( xp * radius + 5., yp * radius - depth ) ) gZ_Poly = calcPolydgdz( spnts, poly1, 2000 ) gZ_Poly += calcPolydgdz( spnts, poly2, 2000 ) ax1.plot( x, gZ_Poly, label= 'WonBevis1987-Poly' ) ax2.plot( g.x( poly1 ), g.y( poly1 ), color = 'red' ) ax2.plot( g.x( poly2 ), g.y( poly2 ), color = 'red' ) ax2.plot( g.x( spnts ), g.y( spnts ), marker = 'x', color = 'black' ) # test some special case for i, p in enumerate( poly1 ): poly1[i] = g.RVector3( poly1[i] - g.RVector3( 5.0, -6. ) ) ax2.plot( g.x( poly1 ), g.y( poly1 ), color = 'green' ) gz = calcPolydgdz( spnts, poly1, 2000 ) ax1.plot( x, gz, label= 'Special Case', color = 'green' ) ax1.set_ylabel( 'dg/dz [mGal]' ) ax2.set_ylabel( 'Tiefe [m]' ) ax1.legend() ax2.set_xlim( [ x[0], x[-1] ] ) ax2.grid()
def show(obj=None, data=None, **kwargs): """Mesh and model visualization. Syntactic sugar to show a obj with data. Forwards to a known visualization for obj. Typical is :py:mod:`pygimli.viewer.showMesh` or :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D and 3D content. See tutorials and examples for usage hints. An empty show call creates an empty ax window. Parameters ---------- obj: obj obj can be so far. * :gimliapi:`GIMLI::Mesh` or list of meshes * DataContainer * pg.core.Sparse[Map]Matrix data: iterable Optionally data to visualize. See appropriate show function. Keyword Arguments ----------------- **kwargs Additional kwargs forward to appropriate show functions. * ax : axe [None] Matplotlib axes object. Create a new if necessary. * fitView : bool [True] Scale x and y limits to match the view. Returns ------- Return the results from the showMesh* functions. Usually the axe object and a colorbar. See Also -------- showMesh """ if "axes" in kwargs: print("Deprecation Warning: Please use keyword `ax` instead of `axes`") kwargs['ax'] = kwargs.pop('axes', None) if isinstance(obj, pg.DataContainerERT): from pygimli.physics.ert import showERTData return showERTData(obj, vals=kwargs.pop('vals', data), **kwargs) if isinstance(obj, pg.core.MatrixBase): ax, _ = pg.show() return drawMatrix(ax, obj, **kwargs) mesh = kwargs.pop('mesh', obj) if isinstance(mesh, list): ax = kwargs.pop('ax', None) fitView = kwargs.pop('fitView', ax is None) ax, cBar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs) xMin = mesh[0].xMin() xMax = mesh[0].xMax() yMin = mesh[0].yMin() yMax = mesh[0].yMax() for m in mesh[1:]: ax, cBar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs) xMin = min(xMin, m.xMin()) xMax = max(xMax, m.xMax()) yMin = min(yMin, m.yMin()) yMax = max(yMax, m.yMax()) # ax.relim() # ax.autoscale_view(tight=True) if fitView is not False: ax.set_xlim([xMin, xMax]) ax.set_ylim([yMin, yMax]) # print(ax.get_data_interval()) return ax, cBar if isinstance(mesh, pg.Mesh): if mesh.dim() == 2: if pg.zero(pg.y(mesh)): pg.info("swap z<->y coordinates for visualization.") meshSwap = pg.Mesh(mesh) for n in meshSwap.nodes(): n.pos()[1] = n.pos()[2] return showMesh(meshSwap, data, **kwargs) return showMesh(mesh, data, **kwargs) elif mesh.dim() == 3: from .vistaview import showMesh3D return showMesh3D(mesh, data, **kwargs) else: pg.error("ERROR: Mesh not valid.", mesh) ax = kwargs.pop('ax', None) if ax is None: ax = plt.subplots()[1] return ax, None
def interpolate(*args, **kwargs): r"""Interpolation convinience function. Convenience function to interpolate different kind of data. Currently supported interpolation schemes are: * Interpolate mesh based data from one mesh to another (syntactic sugar for the core based interpolate (see below)) Parameters: args: :gimliapi:`GIMLI::Mesh`, :gimliapi:`GIMLI::Mesh`, iterable `outData = interpolate(outMesh, inMesh, vals)` Interpolate values based on inMesh to outMesh. Values can be of length inMesh.cellCount() interpolated to outMesh.cellCenters() or inMesh.nodeCount() which are interpolated tp outMesh.positions(). Returns: Interpolated values. * Mesh based values to arbitrary points, based on finite element interpolation (from gimli core). Parameters: args: :gimliapi:`GIMLI::Mesh`, ... Arguments forwarded to :gimliapi:`GIMLI::interpolate` kwargs: Arguments forwarded to :gimliapi:`GIMLI::interpolate` `interpolate(srcMesh, destMesh)` All data from inMesh are interpolated to outMesh Returns: Interpolated values * Interpolate along curve. Forwarded to :py:mod:`pygimli.meshtools.interpolateAlongCurve` Parameters: args: curve, t kwargs: Arguments forwarded to :py:mod:`pygimli.meshtools.interpolateAlongCurve` * 1D point set :math:`u(x)` for ascending :math:`x`. Find interpolation function :math:`I = u(x)` and returns :math:`u_{\text{i}} = I(x_{\text{i}})` (interpolation methods are [**linear** via matplotlib, cubic **spline** via scipy, fit with **harmonic** functions' via pygimli]) Note, for 'linear' and 'spline' the interpolate contains all original coordinates while 'harmonic' returns an approximate best fit. The amount of harmonic coefficients can be specfied with the 'nc' keyword. Parameters: args: xi, x, u * :math:`x_{\text{i}}` - target sample points * :math:`x` - function sample points * :math:`u` - function values kwargs: * method : string Specify interpolation method 'linear, 'spline', 'harmonic' * nc : int Number of harmonic coefficients for the 'harmonic' method. Returns: ui: array of length xi :math:`u_{\text{i}} = I(x_{\text{i}})`, with :math:`I = u(x)` To use the core functions :gimliapi:`GIMLI::interpolate` start with a mesh instance as first argument or use the appropriate keyword arguments. TODO * 2D parametric to points (method=['linear, 'spline', 'harmonic']) * 2D/3D point cloud to points/grids ('Delauney', 'linear, 'spline', 'harmonic') * Mesh to points based on nearest neighbour values (pg.core) Examples -------- >>> # no need to import matplotlib. pygimli's show does >>> import numpy as np >>> import pygimli as pg >>> fig, ax = pg.plt.subplots(1, 1, figsize=(10, 5)) >>> u = np.array([1.0, 12.0, 3.0, -4.0, 5.0, 6.0, -1.0]) >>> xu = np.array(range(len(u))) >>> xi = np.linspace(xu[0], xu[-1], 1000) >>> _= ax.plot(xu, u, 'o') >>> _= ax.plot(xi, pg.interpolate(xi, xu, u, method='linear'), ... color='blue', label='linear') >>> _= ax.plot(xi, pg.interpolate(xi, xu, u, method='spline'), ... color='red', label='spline') >>> _= ax.plot(xi, pg.interpolate(xi, xu, u, method='harmonic'), ... color='green', label='harmonic') >>> _= ax.legend() """ pgcore = False if 'srcMesh' in kwargs: pgcore = True elif len(args) > 0: if isinstance(args[0], pg.Mesh): if len(args) == 2 and isinstance(args[1], pg.Mesh): return pg.core._pygimli_.interpolate(args[0], args[1], **kwargs) if len(args) == 3 and isinstance(args[1], pg.Mesh): pgcore = False # (outMesh, inMesh, vals) else: pgcore = True if pgcore: if len(args) == 3: # args: outData = (inMesh, inData, outPos) if args[1].ndim == 2: # outData = (inMesh, mat, vR3) outMat = pg.Matrix() pg.core._pygimli_.interpolate(args[0], inMat=np.array(args[1]), destPos=args[2], outMat=outMat, **kwargs) return np.array(outMat) if len(args) == 4: # args: (inMesh, inData, outPos, outData) if args[1].ndim == 1 and args[2].ndim == 1 and args[3].ndim == 1: return pg.core._pygimli_.interpolate(args[0], inVec=args[1], x=args[2], y=args[3], **kwargs) if isinstance(args[1], pg.RMatrix) and \ isinstance(args[3], pg.RMatrix): return pg.core._pygimli_.interpolate(args[0], inMat=args[1], destPos=args[2], outMat=args[3], **kwargs) if isinstance(args[1], pg.RVector) and \ isinstance(args[3], pg.RVector): return pg.core._pygimli_.interpolate(args[0], inVec=args[1], destPos=args[2], outVec=args[3], **kwargs) if len(args) == 5: if args[1].ndim == 1 and args[2].ndim == 1 and \ args[3].ndim == 1 and args[4].ndim == 1: return pg.core._pygimli_.interpolate(args[0], inVec=args[1], x=args[2], y=args[3], z=args[4], **kwargs) return pg.core._pygimli_.interpolate(*args, **kwargs) # end if pg.core: if len(args) == 3: if isinstance(args[0], pg.Mesh): # args: (outMesh, inMesh, data) outMesh = args[0] inMesh = args[1] data = args[2] if isinstance(data, pg.R3Vector) or isinstance( data, pg.stdVectorRVector3): x = pg.interpolate(outMesh, inMesh, pg.x(data)) y = pg.interpolate(outMesh, inMesh, pg.y(data)) z = pg.interpolate(outMesh, inMesh, pg.z(data)) return np.vstack([x, y, z]).T if isinstance(data, np.ndarray): if data.ndim == 2 and data.shape[1] == 3: x = pg.interpolate(outMesh, inMesh, data[:, 0]) y = pg.interpolate(outMesh, inMesh, data[:, 1]) z = pg.interpolate(outMesh, inMesh, data[:, 2]) return np.vstack([x, y, z]).T if len(data) == inMesh.cellCount(): return pg.interpolate(srcMesh=inMesh, inVec=data, destPos=outMesh.cellCenters()) elif len(data) == inMesh.nodeCount(): return pg.interpolate(srcMesh=inMesh, inVec=data, destPos=outMesh.positions()) else: print(inMesh) print(outMesh) raise Exception("Don't know how to interpolate data of size", str(len(data))) print("data: ", data) raise Exception("Cannot interpret data: ", str(len(data))) else: #args: xi, x, u xi = args[0] x = args[1] u = args[2] method = kwargs.pop('method', 'linear') if 'linear' in method: return np.interp(xi, x, u) if 'harmonic' in method: coeff = kwargs.pop('nc', int(np.ceil(np.sqrt(len(x))))) from pygimli.frameworks import harmfitNative return harmfitNative(u, x=x, nc=coeff, xc=xi, err=None)[0] if 'spline' in method: if pg.optImport("scipy", requiredFor="use interpolate splines."): from scipy import interpolate tck = interpolate.splrep(x, u, s=0) return interpolate.splev(xi, tck, der=0) else: return xi * 0. if len(args) == 2: # args curve, t curve = args[0] t = args[1] return interpolateAlongCurve(curve, t, **kwargs)
def midconfERT(data, ind=None, rnum=1, circular=False): """Return the midpoint and configuration key for ERT data. Return the midpoint and configuration key for ERT data. Parameters ---------- data : DataContainerERT data container with sensorPositions and a/b/m/n fields ind : [] Documentme rnum : [] Documentme circular : bool Return midpoint in degree (rad) instead if meter. Returns ------- mid : np.array of float representative midpoint (middle of MN, AM depending on array) conf : np.array of float configuration/array key consisting of 1) array type (Wenner-alpha/beta, Schlumberger, PP, PD, DD, MG) 00000: pole-pole 10000: pole-dipole or dipole-pole 30000: Wenner-alpha 40000: Schlumberger or Gradient 50000: dipole-dipole or Wenner-beta 2) potential dipole length (in electrode spacings) .XX..: dipole length 3) separation factor (current dipole length or (di)pole separation) ...XX: pole/dipole separation (PP,PD,DD,GR) or separation """ # xe = np.hstack((pg.x(data.sensorPositions()), np.nan)) # not used anymore x0 = data.sensorPosition(0).x() xe = pg.x(data.sensorPositions()) - x0 ux = pg.unique(xe) if len(ux) * 2 > data.sensorCount(): # 2D with topography case dx = np.array(pg.utils.diff(pg.utils.cumDist(data.sensorPositions()))) dxM = pg.mean(dx) if min(pg.y(data)) != max(pg.y(data)) or \ min(pg.z(data)) != max(pg.z(data)): # Topography case if (max(abs(dx - dxM)) < dxM * 0.9): # if the maximum spacing < meanSpacing/2 we assume equidistant # spacing and no missing electrodes dx = np.ones(len(dx)) * dxM else: # topography with probably missing electrodes dx = np.floor(dx / np.round(dxM)) * dxM pass if max(dx) < 0.5: print("Detecting small distances, using mm accuracy") rnum = 3 xe = np.hstack((0., np.cumsum(np.round(dx, rnum)), np.nan)) de = np.median(np.diff(xe[:-1])).round(rnum) ne = np.round(xe / de) else: # 3D (without topo) case => take positions directly de = np.median(np.diff(ux)).round(1) ne = np.array(xe / de, dtype=int) # a, b, m, n = data('a'), data('b'), data('m'), data('n') # check if xe[a]/a is better suited (has similar size) if circular: # for circle geometry center = np.mean(data.sensorPositions(), axis=0) r = data.sensors()[0].distance(center) s0 = data.sensors()[0] - center s1 = data.sensors()[1] - center p0 = np.arctan2(s0[1], s0[0]) p1 = np.arctan2(s1[1], s1[0]) if p1 > p0: # rotate left x = np.cos(np.linspace(0, 2 * pi, data.sensorCount() + 1) + p0)[:-1] * r y = np.sin(np.linspace(0, 2 * pi, data.sensorCount() + 1) + p0)[:-1] * r else: x = np.cos(np.linspace(2 * pi, 0, data.sensorCount() + 1) + p0)[:-1] * r y = np.sin(np.linspace(2 * pi, 0, data.sensorCount() + 1) + p0)[:-1] * r a = np.array([np.arctan2(y[i], x[i]) for i in data['a']]) b = np.array([np.arctan2(y[i], x[i]) for i in data['b']]) m = np.array([np.arctan2(y[i], x[i]) for i in data['m']]) n = np.array([np.arctan2(y[i], x[i]) for i in data['n']]) a = np.unwrap(a) % (np.pi * 2) b = np.unwrap(b) % (np.pi * 2) m = np.unwrap(m) % (np.pi * 2) n = np.unwrap(n) % (np.pi * 2) else: a = np.array([ne[int(i)] for i in data('a')]) b = np.array([ne[int(i)] for i in data('b')]) m = np.array([ne[int(i)] for i in data('m')]) n = np.array([ne[int(i)] for i in data('n')]) if ind is not None: a = a[ind] b = b[ind] m = m[ind] n = n[ind] anan = np.isnan(a) a[anan] = b[anan] b[anan] = np.nan ab, am, an = np.abs(a - b), np.abs(a - m), np.abs(a - n) bm, bn, mn = np.abs(b - m), np.abs(b - n), np.abs(m - n) if circular: for v in [ab, mn, bm, an]: v[v > pi] = 2 * pi - v[v > pi] # 2-point (default) 00000 sep = np.abs(a - m) mid = (a + m) / 2 # 3-point (PD, DP) (now only b==-1 or n==-<1, check also for a and m) imn = np.isfinite(n) * np.isnan(b) mid[imn] = (m[imn] + n[imn]) / 2 sep[imn] = np.minimum(am[imn], an[imn]) + 10000 + 100 * (mn[imn]-1) + \ (np.sign(a[imn]-m[imn])/2+0.5) * 10000 iab = np.isfinite(b) * np.isnan(n) mid[iab] = (a[iab] + b[iab]) / 2 # better 20000 or -10000? sep[iab] = np.minimum(am[iab], bm[iab]) + 10000 + 100 * (ab[iab]-1) + \ (np.sign(a[iab]-n[iab])/2+0.5) * 10000 # + 10000*(a-m) # 4-point alpha: 30000 (WE) or 4000 (SL) iabmn = np.isfinite(a) & np.isfinite(b) & np.isfinite(m) & np.isfinite(n) ialfa = np.copy(iabmn) ialfa[iabmn] = (ab[iabmn] >= mn[iabmn] + 2) # old mnmid = (m[iabmn] + n[iabmn]) / 2 ialfa[iabmn] = np.sign((a[iabmn] - mnmid) * (b[iabmn] - mnmid)) < 0 mid[ialfa] = (m[ialfa] + n[ialfa]) / 2 spac = np.minimum(bn[ialfa], bm[ialfa]) abmn3 = np.round((3 * mn[ialfa] - ab[ialfa]) * 10000) / 10000 sep[ialfa] = spac + (mn[ialfa]-1)*100*(abmn3 != 0) + \ 30000 + (abmn3 < 0)*10000 # gradient # %% 4-point beta ibeta = np.copy(iabmn) ibeta[iabmn] = (bm[iabmn] >= mn[iabmn]) & (~ialfa[iabmn]) if circular: # print(ab[ibeta]) ibeta = np.copy(iabmn) def _averageAngle(vs): sumsin = 0 sumcos = 0 for v in vs: sumsin += np.sin(v) sumcos += np.cos(v) return np.arctan2(sumsin, sumcos) abC = _averageAngle([a[ibeta], b[ibeta]]) mnC = _averageAngle([m[ibeta], n[ibeta]]) mid[ibeta] = _averageAngle([abC, mnC]) # special case when dipoles are completely opposite iOpp = abs(abs((mnC - abC)) - np.pi) < 1e-3 mid[iOpp] = _averageAngle([b[iOpp], m[iOpp]]) minAb = min(ab[ibeta]) sep[ibeta] = 50000 + (np.round(ab[ibeta]/minAb)) * 100 + \ np.round(np.minimum(np.minimum(am[ibeta], an[ibeta]), np.minimum(bm[ibeta], bn[ibeta])) / minAb) else: mid[ibeta] = (a[ibeta] + b[ibeta] + m[ibeta] + n[ibeta]) / 4 sep[ibeta] = 50000 + (ab[ibeta] - 1) * 100 + np.minimum( np.minimum(am[ibeta], an[ibeta]), np.minimum(bm[ibeta], bn[ibeta])) # %% 4-point gamma # multiply with electrode distance and add first position if not circular: mid *= de mid += x0 return mid, sep
def showRayPaths(self, model=None, ax=None, **kwargs): """Show ray paths for `model` or last model for which the Jacobian was calculated. Parameters ---------- model : array Velocity model for which to calculate and visualize ray paths (the default is model for last Jacobian calculation in self.velocity). ax : matplotlib.axes Axes for the plot (the default is None). **kwargs : type Additional arguments passed to LineCollection (alpha, linewidths, color, linestyles). Returns ------- ax : matplotlib.axes object cb : matplotlib.colorbar object (only if model is provided) Examples -------- >>> # No reason to import matplotlib >>> import pygimli as pg >>> from pygimli.physics import Refraction >>> from pygimli.physics.traveltime import createRAData >>> >>> x, y = 8, 6 >>> mesh = pg.createGrid(x, y) >>> data = createRAData([(0,0)] + [(x, i) for i in range(y)], shotdistance=y+1) >>> data.set("t", pg.RVector(data.size(), 1.0)) >>> rst = Refraction() >>> rst.setDataContainer(data) Data: Sensors: 7 data: 6 >>> rst.setMesh(mesh, 5) >>> ax, cb = rst.showRayPaths() """ cbar = None if model is None and self.velocity is None: pg.info("No previous inversion result found and no model given.", "Using homogeneous slowness model.") self.velocity = pg.RVector(self.mesh.cellCount(), 1.0) self.fop.createJacobian(1. / self.velocity) if model is not None: if self.velocity is not None: if not np.allclose(model, self.velocity): self.fop.createJacobian(1 / model) ax, cbar = self.showResult(ax=ax, val=model) _ = kwargs.setdefault("color", "w") _ = kwargs.setdefault("alpha", 0.5) _ = kwargs.setdefault("linewidths", 0.8) else: ax = self.showMesh(ax=ax) # Due to different numbering scheme of way matrix _, shots = np.unique(self.dataContainer("s"), return_inverse=True) _, receivers = np.unique(self.dataContainer("g"), return_inverse=True) # Collecting way segments for all shot/receiver combinations segs = [] for s, g in zip(shots, receivers): wi = self.fop.way(s, g) points = self.fop.mesh().positions(withSecNodes=True)[wi] segs.append(np.column_stack((pg.x(points), pg.y(points)))) line_segments = LineCollection(segs, **kwargs) ax.add_collection(line_segments) return ax, cbar
fig, a = plt.subplots() drawMesh(a, mesh) pg.show(mesh, axes=a, data=l[0]) cells = fwd.mesh().cells() active_cells = [cells[i] for i in range(mesh.cellCount()) if l[0][i]] # active_cells.append(cells[2044]) for c in active_cells: pos = c.center() gradient = 2000*c.grad(pos, fwd.timefields[0]) dx, dy = gradient.x(), gradient.y() a.text(pos.x(), pos.y(), str(c.id())) a.arrow(pos.x(), pos.y(), dx, dy) ray = fwd.poslist a.plot(pg.x(ray), pg.y(ray), 'm-*', ) plt.show() # look at if next gradient contradicts the previous # if so, then follow the interface instead (line segment to next node) # this will stop when the gradients are more aligned. # drawMesh(a, mesh) # drawField(a, mesh, fwd.timefields[0], True, 'Spectral') # drawStreamLines(a, mesh, fwd.timefields[0], nx=50, ny=50) # some stats: diff_rms = np.sqrt(np.sum(delta_t**2)/len(delta_t)) print("RMS of difference: {}".format(diff_rms)) print("Mean of difference: {}".format(np.mean(delta_t))) print("Standard dev of difference: {}".format(np.std(delta_t)))