def createGeometricFactors(scheme, numerical=None, mesh=None, verbose=False): """Create geometric factors for a data scheme. Create geometric factors for a data scheme with and without topography. Calculation will be done analytical (only for half space geometry) or numerical. This function caches the result depending on scheme, mesh and pg.version() Parameters ---------- scheme: :gimliapi:`GIMLI::DataContainerERT` Datacontainer of the scheme. numerical: bool | None [False] If numerical is None, False is assumed, we try to guess topography and warn if we think we found them. If set to True or False, numerical calculation will used respectively. mesh: :gimliapi:`GIMLI::Mesh` | str Mesh for numerical calculation. If not given, analytical geometric factors for halfspace earth are guessed or a default mesh will be created. The mesh will be h and p refined. If given topo is set to True. If the numerical effort is to high or the accuracy to low you should consider to calculate the factors manual. verbose: bool Give some output. """ if numerical is None: numerical = False if (min(pg.z(scheme)) != max(pg.z(scheme))): verbose = True pg.warn('Sensor z-coordinates not equal. Is there topography?') if numerical is False and mesh is None: if verbose: pg.info('Calculate analytical flat earth geometric factors.') return pg.core.geometricFactors(scheme, forceFlatEarth=True) if mesh is None: mesh = createInversionMesh(scheme) if verbose: pg.info('mesh', mesh) m = mesh.createH2() if verbose: pg.info('mesh-h2', m) m = m.createP2() if verbose: pg.info('mesh-p2', m) pg.info('Calculate numerical geometric factors.') d = simulate(m, res=1.0, scheme=scheme, sr=False, useBert=True, calcOnly=True, verbose=True) return 1. / d['u']
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 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 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 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 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 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 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 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 showMesh3DFallback(mesh, data, **kwargs): """ Plot the 3D object sketchy. """ ax = kwargs.pop('ax', None) from mpl_toolkits.mplot3d import Axes3D if ax is None or not isinstance(ax, Axes3D): fig = plt.figure() ax = fig.gca(projection='3d', proj_type='persp') #ax = fig.gca(projection='3d', proj_type='ortho') if mesh.boundaryCount() > 0: x, y, tri, z, dataIndex = pg.viewer.mpl.createTriangles(mesh) ax.plot_trisurf(x, y, tri, z) else: if mesh.nodeCount() < 1e4: x = pg.x(mesh.positions()) y = pg.y(mesh.positions()) z = pg.z(mesh.positions()) ax.scatter(x, y, z, 'ko') ax.set_title('Fallback, install pyvista for proper 3D visualization') return ax, None
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 createTriangles(mesh): """Generate triangle objects for later drawing. Creates triangle for each 2D triangle cell or 3D boundary. Quads will be split into two triangles. Result will be cached into mesh._triData. Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` 2D mesh or 3D mesh Returns ------- x : numpy array x position of nodes y : numpy array x position of nodes triangles : numpy array Cx3 cell indices for each triangle, quad or boundary face z : numpy array z position for given indices dataIdx : list of int List of indices for a data array """ if hasattr(mesh, '_triData'): if hash(mesh) == mesh._triData[0]: return mesh._triData[1:] x = pg.x(mesh) y = pg.y(mesh) z = pg.z(mesh) # x.round(1e-1) # y.round(1e-1) if mesh.dim() == 2: ents = mesh.cells() else: ents = mesh.boundaries(mesh.boundaryMarkers() != 0) if len(ents) == 0: for b in mesh.boundaries(): if b.leftCell() is None or b.rightCell() is None: ents.append(b) triangles = [] dataIdx = [] for c in ents: triangles.append([c.node(0).id(), c.node(1).id(), c.node(2).id()]) dataIdx.append(c.id()) if c.shape().nodeCount() == 4: triangles.append([c.node(0).id(), c.node(2).id(), c.node(3).id()]) dataIdx.append(c.id()) mesh._triData = [hash(mesh), x, y, triangles, z, dataIdx] return x, y, triangles, z, dataIdx
def tapeMeasureToCoordinates(tape, pos): """Interpolate 2D tape measured topography to 2D Cartesian coordinates. Tape and pos value are expected to be sorted along distance to the orign. TODO optional smooth curve with harmfit Parameters ---------- tape : [[x,z]] | [RVector3] | R3Vector List of tape measured topography points with measured distance (x) from origin and height (z) pos : iterable Query positions along the tape measured profile Returns ------- res : ndarray(N, 2) Same as pos but with interpolated height values. The Distance between pos points and res (along curve) points remains. Examples -------- >>> # no need to import matplotlib. pygimli's show does >>> import numpy as np >>> import pygimli as pg >>> import pygimli.meshtools as mt >>> elec = np.arange(11.) >>> topo = np.array([[0., 0.], [3., 2.], [4., 2.], [6., 1.], [10., 1.]]) >>> _= pg.plt.plot(topo[:,0], topo[:,1]) >>> p = mt.tapeMeasureToCoordinates(topo, elec) >>> pg.plt.gca().plot(p[:,0], p[:,1], 'o') #doctest: +ELLIPSIS [...] >>> pg.plt.gca().set_aspect(1) >>> pg.wait() """ if isinstance(tape, pg.R3Vector) or isinstance(tape, pg.stdVectorRVector3): xTape = pg.x(tape) zTape = pg.z(tape) else: xTape = tape[:, 0] zTape = tape[:, 1] t = pg.utils.cumDist(pos) # print(t) tTape = pg.utils.cumDist(tape) xt = np.interp(t, tTape, xTape) zt = np.interp(t, tTape, zTape) pg.plt.plot(xTape, zTape) pg.plt.plot(xt, zt, 'o') pg.wait() return np.vstack([xt, zt]).T
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, 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 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 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 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 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" TODO ---- * Cite "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. """ yVals = pg.y(data) if abs(min(yVals)) < 1e-8 and abs(max(yVals)) < 1e-8: yVals = pg.z(data) p = np.polyfit(pg.x(data), yVals, 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.0 / np.interp(d, [min(d), max(d)], [vTop, vBot])
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 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 drawTravelTimeData(a, data): ''' Draw first arrival traveltime data into mpl axes a. data of type \ref DataContainer must contain sensorIdx 's' and 'g' and thus numbered internal from [0..n) ''' x = pg.x(data.sensorPositions()) z = pg.z(data.sensorPositions()) shots = pg.unique(pg.sort(data('s'))) geoph = pg.unique(pg.sort(data('g'))) startOffsetIDX = 0 if min(min(shots), min(geoph) == 1): startOffsetIDX = 1 a.set_xlim([ min(x), max(x) ]) a.set_ylim([ max(data('t')), -0.002 ]) a.figure.show() for shot in shots: gIdx = pg.find(data('s') == shot) sensorIdx = [int(i__ - startOffsetIDX) for i__ in data('g')[ gIdx ]] a.plot(x[ sensorIdx ], data('t')[ gIdx ], 'x-') yPixel = a.transData.inverted().transform_point((1, 1))[1]-a.transData.inverted().transform_point((0, 0))[1] xPixel = a.transData.inverted().transform_point((1, 1))[0]-a.transData.inverted().transform_point((0, 0))[0] # draw shot points a.plot(x[ [int(i__ - startOffsetIDX) for i__ in shots] ], np.zeros(len(shots)) + 8.*yPixel, 'gv', markersize = 8) # draw geophone points a.plot(x[ [int(i__ - startOffsetIDX) for i__ in geoph] ], np.zeros(len(geoph)) + 3.*yPixel, 'r^', markersize = 8) a.grid() a.set_ylim([ max(data('t')), +16.*yPixel]) a.set_xlim([ min(x)-5.*xPixel, max(x)+5.*xPixel ]) a.set_xlabel('x-Coordinate [m]') a.set_ylabel('Traveltime [ms]') # def drawTravelTimeData(...)
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
def div(mesh, v): """ Return the discrete interpolated divergence field :math:`\mathbf{u}` at each cell for a given vector field :math:`\mathbf{v}`. First order integration via boundary center. .. math:: d(cells) & = \nabla\cdot\vec{v} \\ d(c_i) & = \sum_{j=0}^{N_B}\vec{v}_{B_j} \cdot \vec{n}_{B_j} Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Discretization base, interpolation will be performed via finite element base shape functions. V : array(N,3) | R3Vector Vector field at cell centers or boundary centers Returns ------- d : array(M) Array of divergence values for each cell in the given mesh. Examples -------- >>> import pygimli as pg >>> import numpy as np >>> v = lambda p: p >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4)) >>> print(pg.round(pg.solver.div(mesh, v(mesh.boundaryCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 3 [1.0, 1.0, 1.0] >>> print(pg.round(pg.solver.div(mesh, v(mesh.cellCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 3 [0.5, 1.0, 0.5] >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4), ... y=np.linspace(0, 1, 4)) >>> print(pg.round(pg.solver.div(mesh, v(mesh.boundaryCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 9 [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0] >>> divCells = pg.solver.div(mesh, v(mesh.cellCenters())) >>> #divergence from boundary values are exact where the divergence from >>> #interpolated cell center values are wrong due to boundary interpolation >>> print(sum(divCells)) 12.0 >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4), ... y=np.linspace(0, 1, 4), ... z=np.linspace(0, 1, 4)) >>> print(sum(pg.solver.div(mesh, v(mesh.boundaryCenters())))) 81.0 >>> divCells = pg.solver.div(mesh, v(mesh.cellCenters())) >>> print(sum(divCells)) 54.0 """ d = None if hasattr(v, '__len__'): if len(v) == mesh.boundaryCount(): d = mesh.divergence(v) elif len(v) == mesh.nodeCount(): d = mesh.divergence(pointDataToBoundaryData(mesh, v)) elif len(v) == mesh.cellCount(): CtB = mesh.cellToBoundaryInterpolation() d = mesh.divergence(np.array([CtB*pg.x(v), CtB*pg.y(v), CtB*pg.z(v)]).T) else: raise BaseException("implement me") elif callable(v): raise BaseException("implement me") return d
def main( argv ): from optparse import OptionParser parser = OptionParser( "usage: %prog [options] data|topo-xyz-list" ) parser.add_option("-v", "--verbose", dest="verbose", action="store_true" , help="be verbose", default=False ) (options, args) = parser.parse_args() print(options, args) if len( args ) == 0: parser.print_help() print("Please add a mesh or model name.") sys.exit( 2 ) else: datafile = args[ 0 ]; topoList = None try: data = g.DataContainer( datafile ) print(data) topoList = data.electrodePositions() except: topoList = g.loadRVector3( datafile ) #topoList[ 0 ] localiseOffset = g.RVector3( 308354.26737118, 6008130.1579486, 91.23 ) for i, p in enumerate( topoList ): topoList[ i ] = p - localiseOffset coarsePoly = createCoarsePoly( topoList ); coarseTopoZ = g.z( coarsePoly.positions() ) tri = g.TriangleWrapper( coarsePoly ); tri.setSwitches( "-pzeAfaq0" ); coarseMesh = g.Mesh() tri.generate( coarseMesh ); if coarseMesh.nodeCount() == len( coarseTopoZ ): for n in coarseMesh.nodes(): n.pos().setZ( coarseTopoZ[ n.id() ] ); else: print(" this should not happen. " + str( coarseMesh.nodeCount() ) + "/=" + str( len( coarseTopoZ ) )) coarsePoly.exportVTK('meshCoarsePoly.vtk') coarseMesh.exportVTK('meshCoarseMesh.vtk') finePoly = createFinePoly( coarseMesh, topoList) tri = g.TriangleWrapper( finePoly ); tri.setSwitches( "-pzeAfaq34" ); fineMesh = g.Mesh() tri.generate( fineMesh ); finePoly.exportVTK('meshFinePoly.vtk') fineMesh.exportVTK('meshFineMesh.vtk') g.interpolateSurface( coarseMesh, fineMesh ) fineMesh.exportVTK('meshFine.vtk') fineMesh.exportAsTetgenPolyFile( "meshFine.poly" ); system('closeSurface -v -z 40.0 -a 1000 -o mesh meshFine.poly') # system( 'polyAddVIP -f ../../para/all.vip mesh.poly') translate = 'polyTranslate -x ' + str( localiseOffset[0] ) \ + ' -y ' + str( localiseOffset[1] ) \ + ' -z ' + str( localiseOffset[2] ) + ' mesh.poly' system( translate)
def appendBoundaryGrid(grid, xbound=None, ybound=None, zbound=None, marker=1, isSubSurface=True, **kwargs): """ Return a copy of grid surrounded by boundary grid. Note that the input grid needs to be a 2d or 3d grid with quad/hex cells. TODO ---- * preserve inner boundaries * add subsurface setting Args ---- grid: :gimliapi:`GIMLI::Mesh` 2D or 3D Mesh that must contain structured quads or hex cells xbound: iterable of type float [None] Needed for 2D or 3D grid prolongation and will be added on the left side in opposit order and on the right side in normal order. ybound: iterable of type float [None] Needed for 2D or 3D grid prolongation and will be added (2D bottom, 3D fron) in opposit order and (2D top, 3D back) in normal order. zbound: iterable of type float [None] Needed for 3D grid prolongation and will be added the bottom side in opposit order on the top side in normal order. marker: int [1] Cellmarker for the cells in the boundary region isSubSurface : boolean, optional Apply boundary conditions suitable for geo-simulaion and prolongate mesh to the surface if necessary, e.i., no boundary on top of the grid. Examples -------- >>> import pygimli as pg >>> import pygimli.meshtools as mt >>> grid = mt.createGrid(5,5) ... >>> g1 = mt.appendBoundaryGrid(grid, ... xbound=[1, 3, 6], ... ybound=[1, 3, 6], ... marker=2, ... isSubSurface=False) >>> ax,_ = pg.show(g1, markers=True, showMesh=True) >>> grid = mt.createGrid(5,5,5) ... >>> g2 = mt.appendBoundaryGrid(grid, ... xbound=[1, 3, 6], ... ybound=[1, 3, 6], ... zbound=[1, 3, 6], ... marker=2, ... isSubSurface=False) >>> ax, _ = pg.show(g2, g2.cellMarkers(), hold=True, opacity=0.5); """ if isSubSurface: pg.critical('Implement me') def _concat(v, vBound): if (not pg.isArray(vBound)): pg.critical("please give bound array") v = np.append(-np.array(vBound)[::-1] + v[0], v) v = np.append(v, v[-1] + np.array(vBound)) return v x = None y = None z = None if grid.dim() > 1: if grid.dim() == 2: if any([c.nodeCount() != 4 for c in grid.cells()]): pg.critical("Grid have other cells than quads. " "Can't refine it with a grid") x = pg.utils.unique(pg.x(grid)) y = pg.utils.unique(pg.y(grid)) x = _concat(x, xbound) y = _concat(y, ybound) if grid.dim() == 3: if any([c.nodeCount() != 8 for c in grid.cells()]): pg.critical("Grid have other cells than hex's. " "Can't refine it with a grid") z = pg.utils.unique(pg.z(grid)) z = _concat(z, zbound) mesh = pg.meshtools.createGrid(x=x, y=y, z=z, marker=marker) mesh.setCellMarkers( pg.interpolate(grid, grid.cellMarkers(), mesh.cellCenters(), fallback=marker)) return mesh
def loadProjectFile( projectfile, ContainerTyp, verbose = False ): """ A project file defines how multiple data files are imported and merged. The currently supported formats are:\n\n A list of multiple row entries with the following formats: fileName fileName interpolationfile fileName startx starty endx endy You can comment out a row by adding '#'. interpolationfile is a 3-column-ascii-file (dx x y) """ dataList = [] fi = open( projectfile, "r" ) content = fi.readlines( ) fi.close(); for c in content: row = c.split( '\n' )[0].split() d = None if len( row ) > 0 and row[ 0 ] != '#' : if len( row ) == 1: ### filename only d = ContainerTyp( row[0] ) elif len( row ) == 2: ### Thomas?? ist das von dir?? was macht das d = ContainerTyp( row[0] ) xn = g.x( d.sensorPositions() ) zn = g.z( d.sensorPositions() ) A = np.loadtxt( row[1] ).T x3n = np.interp( xn, A[0], A[1] ) y3n = np.interp( xn, A[0], A[2] ) for i in range( d.sensorCount() ): d.setSensorPosition( i, g.RVector3( x3n[i], y3n[i], zn[i] ) ) elif len( row ) == 3: ### filename xstart xend d = ContainerTyp( row[0] ) start = g.RVector3( float( row[1] ), 0.0 ) end = g.RVector3( float( row[2] ), 0.0 ) for i in range( d.sensorCount() ): d.setSensorPosition( i, start + float(i)*(end-start)/(d.sensorCount() - 1.) ) elif len( row ) == 5: ### filename xstart ystart xend yend d = ContainerTyp( row[0] ) start = g.RVector3( float( row[1] ), float( row[2] ) ) end = g.RVector3( float( row[3] ), float( row[4] ) ) for i in range( d.sensorCount() ): d.setSensorPosition( i, start + float(i)*(end-start)/(d.sensorCount() - 1.) ) elif len( row ) == 7: ### filename xstart ystart zstart xend yend zend d = ContainerTyp( row[0] ) start = g.RVector3( float( row[1] ), float( row[2] ), float( row[3] ) ) end = g.RVector3( float( row[4] ), float( row[5] ), float( row[6] ) ) for i in range( d.sensorCount() ): d.setSensorPosition( i, start + float(i)*(end-start)/(d.sensorCount() - 1.) ) else: print(("cannot interprete project format: len(row) = ", len( row ))) return dataList dataList.append( d ) if verbose: print(("append: ", d)) print(("from:" , d.sensorPositions()[ 0 ], "to:", d.sensorPositions()[ -1 ])) return dataList
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 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
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 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)
return False combinedSensors = pg.DataContainer() for pos in ertData.sensorPositions(): combinedSensors.createSensor(pos) for pos in rstData.sensorPositions(): if is_close(pos, ertData): print("Not adding", pos) else: combinedSensors.createSensor(pos) combinedSensors.sortSensorsX() x = pg.x(combinedSensors.sensorPositions()).array() z = pg.z(combinedSensors.sensorPositions()).array() np.savetxt("sensors.npy", np.column_stack((x, z))) print("Number of combined positions:", combinedSensors.sensorCount()) print(combinedSensors) # %% for case in 1, 2: if case == 2: p1 = [8., 0, -0.03] p2 = [12., 0, -0.23] p3 = [24., 0, -0.37] p4 = [28., 0, -0.69] for p in p1, p2, p3, p4: combinedSensors.createSensor(p)
def showERTData(data, vals=None, **kwargs): """Plot ERT data as pseudosection matrix (position over separation). Creates figure, axis and draw a pseudosection. Parameters ---------- data : :gimliapi:`BERT::DataContainerERT` **kwargs : * axes : matplotlib.axes Axes to plot into. Default is None and a new figure and axes are created. * vals : Array[nData] Values to be plotted. Default is data('rhoa'). """ var = kwargs.pop('var', 0) if var > 0: import pybert as pb pg._g(kwargs) return pb.showData(data, vals, var=var, **kwargs) # remove ax keyword global ax = kwargs.pop('ax', None) if ax is None: fig = pg.plt.figure() ax = None axTopo = None if 'showTopo' in kwargs: ax = fig.add_subplot(1, 1, 1) # axs = fig.subplots(2, 1, sharex=True) # # Remove horizontal space between axes # fig.subplots_adjust(hspace=0) # ax = axs[1] # axTopo = axs[0] else: ax = fig.add_subplot(1, 1, 1) pg.checkAndFixLocaleDecimal_point(verbose=False) if vals is None: vals = 'rhoa' if isinstance(vals, str): if data.haveData(vals): vals = data(vals) else: pg.critical('field not in data container: ', vals) kwargs['cMap'] = kwargs.pop('cMap', pg.utils.cMap('rhoa')) kwargs['label'] = kwargs.pop('label', pg.utils.unit('rhoa')) kwargs['logScale'] = kwargs.pop('logScale', min(vals) > 0.0) ax, cbar = drawERTData(ax, data, vals=vals, **kwargs) # TODO here cbar handling like pg.show if 'xlabel' in kwargs: ax.set_xlabel(kwargs['xlabel']) if 'ylabel' in kwargs: ax.set_ylabel(kwargs['ylabel']) if 'showTopo' in kwargs: # if axTopo is not None: print(ax.get_position()) axTopo = pg.plt.axes([ ax.get_position().x0, ax.get_position().y0, ax.get_position().x0 + 0.2, ax.get_position().y0 + 0.2 ]) x = pg.x(data) x *= (ax.get_xlim()[1] - ax.get_xlim()[0]) / (max(x) - min(x)) x += ax.get_xlim()[0] axTopo.plot(x, pg.z(data), '-o', markersize=4) axTopo.set_ylim(min(pg.z(data)), max(pg.z(data))) axTopo.set_aspect(1) # ax.set_aspect('equal') # plt.pause(0.1) pg.viewer.mpl.updateAxes(ax) return ax, cbar
def maillage_GPRMAX(paramGPRMAX, paramMVG, mesh, mesh_pos, f_thetas, nT): xmin = paramGPRMAX.xmin xmax = paramGPRMAX.xmax zmin = paramGPRMAX.zmin zmax = paramGPRMAX.zmax dx = paramGPRMAX.dx xreg = np.arange(xmin, xmax + dx, dx, 'float') zreg = np.arange(zmin, zmax + dx, dx, 'float') mesh2 = pg.Mesh(3) mesh2.createGrid(xreg, zreg) #fig, axe = plt.subplots(1,1, figsize=(20, 100)) #pg.show(mesh2,ax=axe) for c in mesh2.cells(): c.setMarker(3) pg_pos2 = mesh2.positions() #On crée une matrice contenant la position des noeuds mesh2_pos2 = np.array((np.array(pg.x(pg_pos2)), np.array(pg.y(pg_pos2)), np.array(pg.z(pg_pos2)))).T #Matrice vide de la taille du nombre de cellules mesh2_cells2 = np.zeros((mesh2.cellCount(), 4)) #On rentre les cellules dans une matrice for i, cell in enumerate(mesh2.cells()): mesh2_cells2[i] = cell.ids() mx = pg.x(mesh2.cellCenter()) my = pg.y(mesh2.cellCenter()) mesh_pos2 = mesh2_pos2[:, 0:2] xv, yv = np.meshgrid(xreg, zreg, sparse=False, indexing='ij') #maillage triangulaire que l'on a défini pour SWMS_2D maillage = mesh_pos (x, z) = np.shape(maillage) theta = np.loadtxt(f_thetas) #Ouvrir le fichier min_theta = min(theta) eps = np.zeros(len(theta)) for i in range(0, len(theta)): eps[i] = CRIM(theta[i], paramMVG, paramGPRMAX) eps_mat = np.zeros([x, int((len(eps) / x))]) for i in range(0, nT + 1): # xi = i * x eps_mat[:, i] = eps[xi:(xi + x)] #grid_lin=np.zeros([len(mx),nT+1]) grid_mat = {} #plt.close('all') #fig, axe = plt.subplots(1,1, figsize=(20, 100)) #pg.show(mesh,ax=axe) #fig, ax = plt.subplots(nT+1, figsize=(20, 100)) for i in range(0, nT + 1): # grid = np.zeros([len(xv[:, 0]), len(xv[0, :])]) outdata = interpolate(mesh2, mesh, eps_mat[:, i], fill_value=eps[0]) outdata2 = nodeDataToCellData(mesh2, outdata) for j in range(0, len(xv[0, :])): k = j * len(xv[:, 0]) kk = len(xv[:, 0]) grid[:, j] = np.around(outdata[k:(k + kk)], decimals=2) grid_mat[i] = grid.T a = np.where(grid_mat[i] == 0.0) grid_mat[i][a] = min(eps) b = np.where(grid_mat[i] <= eps[0]) grid_mat[i][b] = eps[0] #drawModel(ax[i], mesh2 , outdata2) #Même interpolation pour les sigma si nécessaire sigma = np.zeros(len(theta)) for i in range(0, len(theta)): #if theta[i]==min_theta: # sigma[i]=0.0 sigma[i] = Rhoades(theta[i]) sigma_mat = np.zeros([x, int((len(eps) / x))]) for i in range(0, nT + 1): xi = i * x sigma_mat[:, i] = sigma[xi:(xi + x)] sigma_grid_mat = {} for i in range(0, nT + 1): # grid = np.zeros([len(xv[:, 0]), len(xv[0, :])]) outdata = interpolate(mesh2, mesh, sigma_mat[:, i], fill_value=min(sigma)) outdata2 = nodeDataToCellData(mesh2, outdata) for j in range(0, len(xv[0, :])): k = j * len(xv[:, 0]) kk = len(xv[:, 0]) grid[:, j] = np.around(outdata[k:(k + kk)], decimals=1) sigma_grid_mat[i] = grid.T a = np.where(sigma_grid_mat[i] == sigma[0]) sigma_grid_mat[i][a] = 0.0 return xv, yv, mx, my, mesh2, grid, grid_mat, eps_mat, sigma_grid_mat
def div(mesh, v): r"""Return the discrete interpolated divergence field. Return the discrete interpolated divergence field. :math:`\mathbf{u}` for each cell for a given vector field :math:`\mathbf{v}`. First order integration via boundary center. .. math:: d(cells) & = \nabla\cdot\vec{v} \\ d(c_i) & = \sum_{j=0}^{N_B}\vec{v}_{B_j} \cdot \vec{n}_{B_j} Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Discretization base, interpolation will be performed via finite element base shape functions. V : array(N,3) | R3Vector Vector field at cell centers or boundary centers Returns ------- d : array(M) Array of divergence values for each cell in the given mesh. Examples -------- >>> import pygimli as pg >>> import numpy as np >>> v = lambda p: p >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4)) >>> print(pg.round(pg.solver.div(mesh, v(mesh.boundaryCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 3 [1.0, 1.0, 1.0] >>> print(pg.round(pg.solver.div(mesh, v(mesh.cellCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 3 [0.5, 1.0, 0.5] >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4), ... y=np.linspace(0, 1, 4)) >>> print(pg.round(pg.solver.div(mesh, v(mesh.boundaryCenters())), 1e-5)) <class 'pygimli.core._pygimli_.RVector'> 9 [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0] >>> divCells = pg.solver.div(mesh, v(mesh.cellCenters())) >>> # divergence from boundary values are exact where the divergence from >>> # interpolated cell center values are wrong due to boundary interp >>> print(sum(divCells)) 12.0 >>> mesh = pg.createGrid(x=np.linspace(0, 1, 4), ... y=np.linspace(0, 1, 4), ... z=np.linspace(0, 1, 4)) >>> print(sum(pg.solver.div(mesh, v(mesh.boundaryCenters())))) 81.0 >>> divCells = pg.solver.div(mesh, v(mesh.cellCenters())) >>> print(sum(divCells)) 54.0 """ d = None if hasattr(v, '__len__'): if len(v) == mesh.boundaryCount(): d = mesh.divergence(v) elif len(v) == mesh.nodeCount(): d = mesh.divergence(pg.meshtools.nodeDataToBoundaryData(mesh, v)) elif len(v) == mesh.cellCount(): CtB = mesh.cellToBoundaryInterpolation() d = mesh.divergence( np.array([CtB * pg.x(v), CtB * pg.y(v), CtB * pg.z(v)]).T) else: print(len(v), mesh) raise BaseException("implement me") elif callable(v): raise BaseException("implement me") return d
n_sensors = 8 sensors = np.zeros((n_sensors, 3)) sensors[0, 0] = 15 sensors[0, 1] = -10 sensors[1:, 0] = -15 sensors[1:, 1] = np.linspace(-15, 15, n_sensors - 1) for pos in sensors: plc.createNode(pos) mesh = mt.createMesh(plc) mesh.createSecondaryNodes(1) ################################################################################ # Create vertical gradient model. vel = 300 + -pg.z(mesh.cellCenters()) * 100 if pyvista: label = pg.utils.unit("vel") pg.show(mesh, vel, label=label) ################################################################################ # Set-up data container. data = traveltime.createRAData(sensors) data.markInvalid(data("s") > 1) data.set("t", np.zeros(data.size())) data.removeInvalid() ################################################################################ # Do raytracing.
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 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 maillage_SWMS2D_EL(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 xreg = [xmin, xmin, xmin + r, xmin + r, xmax, xmax, xmin + r] zreg = [emin, etrou, etrou, emax, emax, emin, emin] nStart = poly.createNode( xreg[0], zreg[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 xx, zz in zip( xreg[1::], zreg[1::] ): # On démarre de 1 et on se balade sur l'axe des x en créant un noeud à chaque fois nB = poly.createNode(xx, zz, 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éé poly.createEdge(nA, nStart) #============================================================================= c1 = plc.createCircle(pos=[xmin + r / 2, etrou + 1], radius=20, area=geometry.area * 0.3) mesh1 = pg.meshtools.createMesh(c1, quality=geometry.quality, area=geometry.area, smooth=geometry.smooth) #pg.show(mesh1, markers=True, showMesh=True) for ii in range(mesh1.nodeCount()): if (mesh1.node(ii)[1] > etrou): if (mesh1.node(ii)[0] > xmin + r): poly.createNode(mesh1.node(ii)[0], mesh1.node(ii)[1], 0) elif (mesh1.node(ii)[1] < etrou): if (mesh1.node(ii)[0] > xmin): poly.createNode(mesh1.node(ii)[0], mesh1.node(ii)[1], 0) #============================================================================= 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