def createJacobian(self, slowness): """Generate Jacobian matrix using fat-ray after Jordi et al. (2016).""" self.J = pg.Matrix(self.data().size(), self.mesh().cellCount()) self.sensorNodes = [self.mesh().findNearestNode(pos) for pos in self.data().sensorPositions()] if (self.iMat.cols() != self.mesh().nodeCount() or self.iMat.rows() != self.mesh().cellCount()): self.iMat = self.mesh().interpolationMatrix( self.mesh().cellCenters()) Di = self.dijkstra() slowPerCell = self.createMappedModel(slowness, 1e16) Di.setGraph(self.createGraph(slowPerCell)) numN = self.mesh().nodeCount() data = self.data() numS = data.sensorCount() Tmat = pg.Matrix(numS, numN) Dmat = pg.Matrix(numS, numS) for i, node in enumerate(self.sensorNodes): Di.setStartNode(node) Tmat[i] = Di.distances() # (0, numN) Dmat[i] = Tmat[i][self.sensorNodes] for i in range(data.size()): iS = int(data("s")[i]) iG = int(data("g")[i]) tsr = Dmat[iS][iG] # shot-receiver travel time dt = self.iMat * (Tmat[iS] + Tmat[iG]) - tsr weight = np.maximum(1 - 2 * self.frequency * dt, 0.0) # 1 on ray wa = weight # * np.sqrt(self.mesh().cellSizes()) if np.sum(wa) > 0: # not if all values are zero wa /= np.sum(wa) self.J[i] = wa * tsr / slowness self.setJacobian(self.J)
def resistivityArchie(rBrine, porosity, a=1.0, m=2.0, S=1.0, n=2.0, mesh=None, meshI=None): """ .. math:: \rho = a\rho_{\text{Brine}}\phi^{-m}\S_w^{-n} * :math:`\rho` - the electrical conductivity of the fluid saturated rock * :math:`\rho_{\text{Brine}}` - electrical conductivity of the brine * :math:`\phi` - porosity 0.0 --1.0 * :math:`a` - tortuosity factor. (common 1) * :math:`m` - cementation exponent of the rock (usually in the range 1.3 -- 2.5 for sandstones) * :math:`n` - is the saturation exponent (usually close to 2) """ rB = None if rBrine.ndim == 1: rB = pg.Matrix(1, len(rBrine)) rB[0] = parseArgToArray(rBrine, mesh.cellCount(), mesh) elif rBrine.ndim == 2: rB = pg.Matrix(len(rBrine), len(rBrine[0])) for i in range(len(rBrine)): rB[i] = rBrine[i] porosity = parseArgToArray(porosity, mesh.cellCount(), mesh) a = parseArgToArray(a, mesh.cellCount(), mesh) m = parseArgToArray(m, mesh.cellCount(), mesh) S = parseArgToArray(S, mesh.cellCount(), mesh) n = parseArgToArray(n, mesh.cellCount(), mesh) r = pg.Matrix(len(rBrine), len(rBrine[0])) for i in range(len(r)): r[i] = rB[i] * a * porosity**(-m) * S**(-n) rI = pg.Matrix(len(r), meshI.cellCount()) if meshI: pg.interpolate(mesh, r, meshI.cellCenters(), rI) for i in range(len(rI)): rI[i] = pg.solver.fillEmptyToCellArray(meshI, rI[i]) return rI
def loadKernel(self, name=''): """Load kernel matrix from mrsk or two bmat files.""" from scipy.io import loadmat # loading Matlab mat files if name[-5:].lower() == '.mrsk': kdata = loadmat(name, struct_as_record=False, squeeze_me=True)['kdata'] self.K = kdata.K self.z = np.hstack((0., kdata.model.z)) else: # try load real/imag parts (backward compat.) KR = pg.Matrix(name + 'KR.bmat') KI = pg.Matrix(name + 'KI.bmat') self.K = np.zeros((KR.rows(), KR.cols()), dtype='complex') for i in range(KR.rows()): self.K[i] = np.array(KR[i]) + np.array(KI[i]) * 1j
def __init__(self, verbose=True): """Constructor.""" super(GravimetryModelling, self).__init__(verbose) self._J = pg.Matrix() # unless doing reference counting we need to hold the reference here self.sensorPositions = None self.setJacobian(self._J)
def calcERT(ertScheme, rhoa): ert = ERT(verbose=False) solutionName = createCacheName('ERT') + "-" + str(ertScheme.size()) + \ "-" + str(len(rhoa)) try: ertModels = pg.load(solutionName + '.bmat') ertMesh = pg.load(solutionName + '.bms') except Exception as e: print(e) print("Building .... ") ertModels = ert.invert(ertScheme, values=rhoa, maxiter=10, lambd=50, paraDX=0.5, paraDZ=0.5, nLayers=20, paraDepth=15, verbose=1) ertMesh = ert.fop.regionManager().paraDomain() ertModels.save(solutionName + '.bmat') ertMesh.save(solutionName) ertRatioModels = pg.Matrix(ertModels) for i in range(len(ertModels)): ertRatioModels[i] /= ertModels[0] return ertMesh, ertModels, ertRatioModels
def test_RMatrixToNumpy(self): """Implemented through automatic iterator """ M = np.arange(20.).reshape((5, 4)) A = pg.Matrix(M) N = np.array(A) self.assertEqual(A.rows(), N.shape[0]) self.assertEqual(A.cols(), N.shape[1]) self.assertEqual(sum(A[0]), sum(N[0])) self.assertEqual(sum(A[1]), sum(N[1])) self.assertEqual(sum(A[2]), sum(N[2])) self.assertEqual(sum(A[3]), sum(N[3])) M = np.arange(16.).reshape((4, 4)) A = pg.Matrix(M) M2 = np.array(A) np.testing.assert_equal(M, M2) A = np.array(pg.Matrix(4, 4))
def testRMatrixIndex(self): A = pg.Matrix(4, 4) A[0] = pg.Vector(4, 1) np.testing.assert_equal(sum(A[0]), 4) A[1, 2] = 2.0 # np.testing.assert_equal(sum(A[1]), 2) np.testing.assert_equal(A[1, 2], 2)
def numpy2gmat(nmat): """Convert numpy.array into pygimli RMatrix. TODO implement correct rval """ gmat = pg.Matrix() for arr in nmat: gmat.push_back(arr) # pg.asvector(arr)) return gmat
def invert(self, sensorPositions, gz, errAbs, verbose=0, **kwargs): """ """ self.fop.setVerbose(verbose) self.inv.setMaxIter(kwargs.pop('maxiter', 10)) self.inv.setLambda(kwargs.pop('lambd', 10)) self.fop.setSensorPositions(sensorPositions) mesh = kwargs.pop('mesh', None) if mesh is None: raise ('implement me') self.setParaMesh(mesh) startModel = pg.Vector(self.fop.regionManager().parameterCount(), 0.0) self.inv.setForwardOperator(self.fop) self.fop.regionManager().setConstraintType(10) # check err here self.inv.setData(gz) self.inv.setAbsoluteError(errAbs) self.inv.setModel(startModel) model = self.inv.run() return model # tl can start here values = model if values is not None: if isinstance(values, pg.Vector): values = [values] elif isinstance(values, np.ndarray): if values.ndim == 1: values = [values] allModel = pg.Matrix(len(values) + 1, len(model)) allModel[0] = model self.inv.setVerbose(False) for i in range(1, len(values)): tic = time.time() self.inv.setModel(model) self.inv.setReferenceModel(model) dData = pg.abs(values[i] - data) # relModel = self.inv.invSubStep(pg.log(dData)) # allModel[i] = model * pg.exp(relModel) relModel = self.inv.invSubStep(dData) allModel[i] = model + relModel print(i, "/", len(values), " : ", time.time() - tic, "s") return allModel return model
def loadSIPallData(filename, outnumpy=False): """load SIP data with the columns ab/2,mn/2,rhoa and PHI with the corresponding frequencies in the first row.""" if outnumpy: A = N.loadtxt(filename) fr = A[0, 3:] ab2 = A[1:, 0] mn2 = A[1:, 1] rhoa = A[1:, 2] PHI = A[1:, 3:] else: A = pg.Matrix() pg.loadMatrixCol(A, 'sch/dc.ves') ndata = A.cols() ab2 = A[0](1, ndata) mn2 = A[1](1, ndata) rhoa = A[2](1, ndata) PHI = pg.Matrix() fr = [] for i in range(3, A.rows()): fr.append(A[i][0]) PHI.push_back(A[i](1, ndata)) return ab2, mn2, rhoa, PHI, fr
def loadmrsproject(mydir): """ load mrs project from given directory (zkernel.ve) (datacube.dat, KR/KI.bmat, zkernel.vec) """ if mydir is None: mydir = '.' if mydir[-1] != '/': mydir = mydir + '/' # load files from directory zvec = pg.Vector(mydir + 'zkernel.vec') KR = pg.Matrix(mydir + 'KR.bmat') KI = pg.Matrix(mydir + 'KI.bmat') A = pg.Matrix() pg.loadMatrixCol(A, mydir + 'datacube.dat') t = np.array(A[0]) # data datvec = pg.Vector() for i in range(1, len(A)): datvec = pg.cat(datvec, A[i]) # print len(A), len(t) return KR, KI, zvec, t, datvec
def createJacobian(self, slowness): """Generate Jacobian matrix using fat-ray after Jordi et al. (2016).""" self.J = pg.Matrix(self.data().size(), self.mesh().cellCount()) self.sensorNodes = [self.mesh().findNearestNode(pos) for pos in self.data().sensorPositions()] Di = self.dijkstra() slowPerCell = self.createMappedModel(slowness, 1e16) Di.setGraph(self.createGraph(slowPerCell)) numN = self.mesh().nodeCount() data = self.data() numS = data.sensorCount() Tmat = pg.Matrix(numS, numN) Dmat = pg.Matrix(numS, numS) print(self.mesh()) print(self.nnodes, max(self.mids)) for i, node in enumerate(self.sensorNodes): Di.setStartNode(node) dist0 = Di.distances() dist = Di.distances(withSecNodes=True) print("dist len ", len(dist0), len(dist)) Tmat[i] = dist[self.mids] # Tmat[i] = (self.nnodes, len(dist)) Dmat[i] = Tmat[i][self.sensorNodes] for i in range(data.size()): iS = int(data("s")[i]) iG = int(data("g")[i]) tsr = Dmat[iS][iG] # shot-receiver travel time dt = Tmat[iS] + Tmat[iG] - tsr weight = np.maximum(1 - 2 * self.frequency * dt, 0.0) # 1 on ray wa = weight # * np.sqrt(self.mesh().cellSizes()) if np.sum(wa) > 0: # not if all values are zero wa /= np.sum(wa) self.J[i] = wa * tsr / slowness self.setJacobian(self.J)
def test_NumpyToRMatrix(self): """Implemented in custom_rvalue.cpp.""" M = np.ndarray((5, 4)) A = pg.Matrix(M) self.assertEqual(A.rows(), M.shape[0]) self.assertEqual(A.cols(), M.shape[1]) M = np.arange(20.).reshape((5, 4)) A = pg.Matrix(M) self.assertEqual(sum(A[0]), sum(M[0])) self.assertEqual(sum(A[1]), sum(M[1])) self.assertEqual(sum(A[2]), sum(M[2])) self.assertEqual(sum(A[3]), sum(M[3])) M = np.zeros((6, 2), dtype=float) M[0:3, 0] = 1 M[3:, 1] = 1 A = pg.Matrix(M) self.assertEqual(A.col(0), M[:, 0]) self.assertEqual(A.col(1), M[:, 1]) A = pg.Matrix(M.T) self.assertEqual(A.row(0), M[:, 0]) self.assertEqual(A.row(1), M[:, 1])
def init(self, mesh, tMax, satSteps, ertSteps): """Initialize some settings.""" if mesh is not None: self.parMesh = pg.Mesh(mesh) self.setMesh(mesh) self.createRefinedForwardMesh(refine=False, pRefine=False) self.tMax = tMax self.satSteps = satSteps self.ertSteps = ertSteps self.timesAdvection = np.linspace(1, tMax, satSteps) self.timesERT = pg.IndexArray( np.floor( np.linspace(0, len(self.timesAdvection) - 1, self.ertSteps))) self._J = pg.Matrix() self.setJacobian(self._J) self.ws = WorkSpace()
def __init__(self, fvec, tvec, verbose=False): # save reference in class """constructor with frequecy and tau vector""" self.f = fvec self.nf = len(fvec) self.t = tvec self.nt = len(tvec) mesh = pg.meshtools.createMesh1D(len(tvec)) # standard 1d mesh super(DebyeComplex, self).__init__(mesh, verbose) T, W = np.meshgrid(tvec, fvec * 2. * pi) WT = W*T self.A = WT**2 / (WT**2 + 1) self.B = WT / (WT**2+1) self.J = pg.Matrix() self.J.resize(len(fvec)*2, len(tvec)) for i in range(self.nf): wt = fvec[i] * 2.0 * pi * tvec wt2 = wt**2 self.J[i] = wt2 / (wt2 + 1.0) self.J[i+self.nf] = wt / (wt2 + 1.0) self.setJacobian(self.J)
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 createJacobian(self, model): print('=' * 100) if self.complex(): modelRe = model[0:int(len(model)/2)] modelIm = model[int(len(model)/2):len(model)] modelC = pg.math.toComplex(modelRe, modelIm) print("Real", min(modelRe), max(modelRe)) print("Imag", min(modelIm), max(modelIm)) u = self.prepareJacobian_(modelC) if self._J.rows() == 0: #re(data)/re(mod) = im(data)/im(mod) # we need a local copy until we have a gimli internal reference counter FIXTHIS M1 = pg.Matrix() M2 = pg.Matrix() self.matrixHeap.append(M1) self.matrixHeap.append(M2) JRe = self._J.addMatrix(M1) JIm = self._J.addMatrix(M2) self._J.addMatrixEntry(JRe, 0, 0) self._J.addMatrixEntry(JIm, 0, len(modelRe), -1.0) self._J.addMatrixEntry(JIm, self.data().size(), 0, 1.0) self._J.addMatrixEntry(JRe, self.data().size(), len(modelRe)) else: self._J.clean() k = pg.Vector(self.data()('k')) self.data().set('k', k*0.0 + 1.0) dMapResponse = pb.DataMap() dMapResponse.collect(self.electrodes(), self.solution()) respRe = dMapResponse.data(self.data(), False, False) respIm = dMapResponse.data(self.data(), False, True) #CVector resp(toComplex(respRe, respIm)); #RVector am(abs(resp) * dataContainer_->get("k")); #RVector ph(-phase(resp)); print("respRe", pg.math.median(respRe), min(respRe), max(respRe)) print("respIm", pg.math.median(respIm), min(respIm), max(respIm)) JC = pg.matrix.CMatrix() self.createJacobian_(modelC, u, JC) for i in range(JC.rows()): #JC[i] *= 1.0/(modelC*modelC) * k[i] JC[i] /= (modelC * modelC) / k[i] self._J.mat(0).copy(pg.math.real(JC)) self._J.mat(1).copy(pg.math.imag(JC)) #self.createJacobian_(modelRe*0.0+1.0, pg.math.real(u), self._J.mat(1)) #self.createJacobian_(modelRe*0.0+1.0, pg.math.imag(u), self._J.mat(2)) #self.createJacobian_(modelRe*0.0+1.0, pg.math.imag(u), self._J.mat(3)) sumsens0 = pg.Vector(self._J.mat(0).rows()) sumsens1 = pg.Vector(self._J.mat(0).rows()) sumsens2 = pg.Vector(self._J.mat(0).rows()) for i in range(self._J.mat(0).rows()): #self._J.mat(0)[i] *= 1./modelRe / respRe[i] #self._J.mat(1)[i] *= 1./modelIm / respRe[i] #self._J.mat(2)[i] *= 1./modelRe / respIm[i] #self._J.mat(3)[i] *= 1./modelIm / respIm[i] #self._J.mat(0)[i] *= 1./(modelRe * modelRe) * k[i] #self._J.mat(1)[i] *= 1./(modelRe * modelIm) * k[i] #self._J.mat(2)[i] *= 1./(modelIm * modelRe) * k[i] #self._J.mat(3)[i] *= 1./(modelIm * modelIm) * k[i] sumsens0[i] = sum(self._J.mat(0)[i]) sumsens1[i] = sum(self._J.mat(1)[i]) sumsens2[i] = abs(sum(JC[i])) print(pg.math.median(sumsens0), min(sumsens0), max(sumsens0)) print(pg.math.median(sumsens1), min(sumsens1), max(sumsens1)) print(pg.math.median(sumsens2), min(sumsens2), max(sumsens2)) self.data().set('k', k) self._J.recalcMatrixSize() else: # self.setVerbose(True) u = self.prepareJacobian_(model) #J = pg.Matrix() if self._J.rows() == 0: print('#' * 100) M1 = pg.Matrix() Jid = self._J.addMatrix(M1) self._J.addMatrixEntry(Jid, 0, 0) else: self._J.clean() self.createJacobian_(model, u, self._J.mat(0)) self._J.recalcMatrixSize()
def calc(out, mesh, density, viscosity): print(mesh) velBoundary = [[1, [0.0, 'nan']], [2, [0.0, 'nan']], [3, ['nan', 0.0]], [4, ['nan', 0.0]]] preBoundary = [ [1, 0.0], [2, 0.0], [3, 0.0], [4, 0.0], ] densMatrix = pg.Matrix() vels = [] swatch = pg.core.Stopwatch(True) class WS(): pass wsfv = WS() ax, _ = pg.show(mesh, density) v = 1 nSteps = 3000 dt = 0.1 * v dtSteps = 20 meshC = pg.createGrid(x=np.linspace(-10, 10, 21), y=np.linspace(0, 20, 21)) vel = None pre = None for i in range(nSteps): print(i, 'dens', min(density), max(density), "t:", dt * i) densMatrix.push_back(density) if v > 1: viscosity = 1.0 * density #v3 elif v < 1: viscosity = 1.0 / density #v3 else: viscosity = 1.0 vel, pre, pCNorm, divVNorm = solver.solveStokes( mesh, velBoundary=velBoundary, preBoundary=preBoundary, viscosity=viscosity, density=density, pre0=pre, vel0=vel, f=[density * 0, (density - 1.0) * -9.81], maxIter=1000, tol=1e-6, verbose=1, vRelax=0.1, pRelax=0.1, ws=wsfv) vels.append(vel) print("stokes:", swatch.duration(True), "div V: ", divVNorm[-1]) dens2 = solver.solveFiniteVolume( mesh, a=1. / 500, b=0.0, u0=density, vel=vel, times=np.linspace(0, dt, dtSteps), #uBoundary=[4, 0], scheme='PS', verbose=0) print("Convekt:", swatch.duration(True)) density = dens2[-1] ax.clear() pg.show(mesh, density, axes=ax) pg.show(mesh, vel, coarseMesh=meshC, axes=ax, color='white') mesh.save(out) meshC.save(out + 'C') densMatrix.save(out + 'density.bmat') np.save(out + 'velo.bmat', vels)
def invert(self, data, values=None, verbose=0, **kwargs): """ Invert the given data. A parametric mesh for the inversion will be created if non is given before. Parameters ---------- """ self.fop.setVerbose(verbose) self.inv.setVerbose(verbose) self.inv.setMaxIter(kwargs.pop('maxiter', 10)) self.inv.setLambda(kwargs.pop('lambd', 10)) if self.paraMesh is None: self.paraMesh = createParaMesh2dGrid(data.sensorPositions(), **kwargs) self.setParaMesh(self.paraMesh) if verbose: print(self.paraMesh) # pg.show(self.paraMesh) err = data('err') rhoa = data('rhoa') startModel = pg.Vector(self.fop.regionManager().parameterCount(), pg.math.median(rhoa)) self.fop.setData(data) self.inv.setForwardOperator(self.fop) # check err here self.inv.setData(rhoa) self.inv.setError(err) self.inv.setModel(startModel) model = self.inv.run() if values is not None: if isinstance(values, pg.Vector): values = [values] elif isinstance(values, np.ndarray): if values.ndim == 1: values = [values] allModel = pg.Matrix(len(values), len(model)) self.inv.setVerbose(False) for i in range(len(values)): print(i) tic = time.time() self.inv.setModel(model) self.inv.setReferenceModel(model) dData = pg.abs(values[i] / rhoa) relModel = self.inv.invSubStep(pg.log(dData)) allModel[i] = model * pg.exp(relModel) print(i, "/", len(values), " : ", time.time() - tic, "s min/max: ", min(allModel[i]), max(allModel[i])) return allModel return model
def simulate(self, mesh, scheme, res, **kwargs): """Simulate an ERT measurement. Perform the forward task for a given mesh, a resistivity distribution (per cell), a measurement scheme and will return data (apparent resistivity) or potential fields. This function can also operate on complex resistivity models, thereby computing complex apparent resistivities. The forward operator itself only calculate potential values for the given scheme file. To calculate apparent resistivities, geometric factors (k) are needed. If there are no values k in the DataContainerERT scheme, then we will try to calculate them, either analytic or by using a p2-refined version of the given mesh. TODO ---- * 2D + Complex + SR Args ---- mesh : :gimliapi:`GIMLI::Mesh` 2D or 3D Mesh to calculate for. res : float, array(mesh.cellCount()) | array(N, mesh.cellCount()) | list Resistivity distribution for the given mesh cells can be: . float for homogeneous resistivity . single array of length mesh.cellCount() . matrix of N resistivity distributions of length mesh.cellCount() . resistivity map as [[regionMarker0, res0], [regionMarker0, res1], ...] scheme : :gimliapi:`GIMLI::DataContainerERT` Data measurement scheme. Keyword Args ------------ verbose: bool[False] Be verbose. Will override class settings. calcOnly: bool [False] Use fop.calculate instead of fop.response. Useful if you want to force the calculation of impedances for homogeneous models. No noise handling. Solution is put as token 'u' in the returned DataContainerERT. noiseLevel: float [0.0] add normally distributed noise based on scheme('err') or on noiseLevel if scheme did not contain 'err' noiseAbs: float [0.0] Absolute voltage error in V returnArray: bool [False] Returns an array of apparent resistivities instead of a DataContainerERT returnFields: bool [False] Returns a matrix of all potential values (per mesh nodes) for each injection electrodes. Returns ------- DataContainerERT | array(N, data.size()) | array(N, data.size()) | array(N, data.size()): Data container with resulting apparent resistivity data and errors (if noiseLevel or noiseAbs is set). Optional returns a Matrix of rhoa values (for returnArray==True forces noiseLevel=0). In case of a complex valued resistivity model, phase values will be returned in the DataContainerERT (see example below), or as an additional returned array. Examples -------- # TODO: Remove pybert dependencies # >>> import pybert as pb # >>> import pygimli as pg # >>> import pygimli.meshtools as mt # >>> world = mt.createWorld(start=[-50, 0], end=[50, -50], # ... layers=[-1, -5], worldMarker=True) # >>> scheme = pb.createData( # ... elecs=pg.utils.grange(start=-10, end=10, n=21), # ... schemeName='dd') # >>> for pos in scheme.sensorPositions(): # ... _= world.createNode(pos) # ... _= world.createNode(pos + [0.0, -0.1]) # >>> mesh = mt.createMesh(world, quality=34) # >>> rhomap = [ # ... [1, 100. + 0j], # ... [2, 50. + 0j], # ... [3, 10.+ 0j], # ... ] # >>> ert = pb.ERTManager() # >>> data = ert.simulate(mesh, res=rhomap, scheme=scheme, verbose=True) # >>> rhoa = data.get('rhoa').array() # >>> phia = data.get('phia').array() """ verbose = kwargs.pop('verbose', self.verbose) calcOnly = kwargs.pop('calcOnly', False) returnFields = kwargs.pop("returnFields", False) returnArray = kwargs.pop('returnArray', False) noiseLevel = kwargs.pop('noiseLevel', 0.0) noiseAbs = kwargs.pop('noiseAbs', 1e-4) seed = kwargs.pop('seed', None) #segfaults with self.fop (test & fix) fop = self.createForwardOperator(useBert=self.useBert, sr=self.sr) fop.data = scheme fop.setMesh(mesh, ignoreRegionManager=True) fop.verbose = verbose rhoa = None phia = None isArrayData = False # parse the given res into mesh-cell-sized array if isinstance(res, int) or isinstance(res, float): res = np.ones(mesh.cellCount()) * float(res) elif isinstance(res, complex): res = np.ones(mesh.cellCount()) * res elif hasattr(res[0], '__iter__'): # ndim == 2 if len(res[0]) == 2: # res seems to be a res map # check if there are markers in the mesh that are not defined in # the rhomap. better signal here before it results in some error meshMarkers = list(set(mesh.cellMarkers())) mapMarkers = [m[0] for m in res] if any([mark not in mapMarkers for mark in meshMarkers]): left = [m for m in meshMarkers if m not in mapMarkers] pg.critical( "Mesh contains markers without assigned resistivities {}. Please fix given rhomap." .format(left)) res = pg.solver.parseArgToArray(res, mesh.cellCount(), mesh) else: # probably nData x nCells array # better check for array data here isArrayData = True if isinstance(res[0], np.complex) or isinstance(res, pg.CVector): pg.info("Complex resistivity values found.") fop.setComplex(True) else: fop.setComplex(False) if not scheme.allNonZero('k') and not calcOnly: if verbose: pg.info('Calculate geometric factors.') scheme.set('k', fop.calcGeometricFactor(scheme)) ret = pg.DataContainerERT(scheme) ## just be sure that we don't work with artifacts ret['u'] *= 0.0 ret['i'] *= 0.0 ret['r'] *= 0.0 if isArrayData: rhoa = np.zeros((len(res), scheme.size())) for i, r in enumerate(res): rhoa[i] = fop.response(r) if verbose: print(i, "/", len(res), " : ", pg.dur(), "s", "min r:", min(r), "max r:", max(r), "min r_a:", min(rhoa[i]), "max r_a:", max(rhoa[i])) else: # res is single resistivity array if len(res) == mesh.cellCount(): if calcOnly: fop.mapERTModel(res, 0) dMap = pg.core.DataMap() fop.calculate(dMap) if fop.complex(): pg.critical('Implement me') else: ret["u"] = dMap.data(scheme) ret["i"] = np.ones(ret.size()) if returnFields: return pg.Matrix(fop.solution()) return ret else: if fop.complex(): res = pg.utils.squeezeComplex(res) resp = fop.response(res) if fop.complex(): rhoa, phia = pg.utils.toPolar(resp) else: rhoa = resp else: print(mesh) print("res: ", res) raise BaseException( "Simulate called with wrong resistivity array.") if not isArrayData: ret['rhoa'] = rhoa if phia is not None: ret.set('phia', phia) else: ret.set('rhoa', rhoa[0]) if phia is not None: ret.set('phia', phia[0]) if returnFields: return pg.Matrix(fop.solution()) if noiseLevel > 0: # if errors in data noiseLevel=1 just triggers if not ret.allNonZero('err'): # 1A and #100µV ret.set( 'err', self.estimateError(ret, relativeError=noiseLevel, absoluteUError=noiseAbs, absoluteCurrent=1)) print("Data error estimate (min:max) ", min(ret('err')), ":", max(ret('err'))) rhoa *= 1. + pg.randn(ret.size(), seed=seed) * ret('err') ret.set('rhoa', rhoa) ipError = None if phia is not None: if scheme.allNonZero('iperr'): ipError = scheme('iperr') else: # np.abs(self.data("phia") +TOLERANCE) * 1e-4absoluteError if noiseLevel > 0.5: noiseLevel /= 100. if 'phiErr' in kwargs: ipError = np.ones( ret.size()) * kwargs.pop('phiErr') / 1000 else: ipError = abs(ret["phia"]) * noiseLevel if verbose: print("Data IP abs error estimate (min:max) ", min(ipError), ":", max(ipError)) phia += np.randn(ret.size(), seed=seed) * ipError ret['iperr'] = ipError ret['phia'] = phia # check what needs to be setup and returned if returnArray: if phia is not None: return rhoa, phia else: return rhoa return ret
def _createParameterContraintsLines(mesh, cMat, cWeights=None): """Create line segments representing constrains. """ C = None if isinstance(cMat, pg.matrix.SparseMapMatrix): tmp = pg.optImport('tempfile') _, tmpFile = tmp.mkstemp(suffix='.matrix') C = pg.Matrix() cMat.save(tmpFile) pg.loadMatrixCol(C, tmpFile) try: import os os.remove(tmpFile) except Exception as e: pg.error(e) print("can't remove:", tmpFile) else: C = cMat cellList = dict() for c in mesh.cells(): pID = c.marker() if pID not in cellList: cellList[pID] = [] cellList[pID].append(c) paraCenter = dict() for pID, vals in list(cellList.items()): p = pg.RVector3(0.0, 0.0, 0.0) for c in vals: p += c.center() p /= float(len(vals)) paraCenter[pID] = p nConstraints = cMat.rows() start = [] end = [] # swatch = pg.core.Stopwatch(True) # not used i = -1 while i < C[0].size(): cID = C[0][i] a = C[1][i] b = None if i < C[0].size() - 1: if C[0][i + 1] == cID: b = C[1][i + 1] i += 1 if b is not None: if cWeights[cID] > 0: p1 = paraCenter[a] p2 = paraCenter[b] if cWeights is not None: pa = pg.RVector3(p1 + (p2 - p1) / 2.0 * (1.0 - cWeights[cID])) pb = pg.RVector3(p2 + (p1 - p2) / 2.0 * (1.0 - cWeights[cID])) else: pa = p1 pb = p2 start.append(pa) end.append(pb) else: start.append(paraCenter[a]) end.append(paraCenter[a]) i += 1 return start, end
def response(self, model): """Solve forward task. Create apparent resistivity values for a given resistivity distribution for self.mesh. """ ### NOTE TODO can't be MT until mixed boundary condition depends on ### self.resistivity pg.tic() if not self.data.allNonZero('k'): pg.error('Need valid geometric factors: "k".') pg.warn('Fallback "k" values to -sign("rhoa")') self.data.set('k', -pg.math.sign(self.data('rhoa'))) mesh = self.mesh() nDof = mesh.nodeCount() elecs = self.data.sensorPositions() nEle = len(elecs) nData = self.data.size() self.resistivity = res = self.createMappedModel(model, -1.0) if self.verbose: print("Calculate response for model:", min(res), max(res)) rMin = elecs[0].dist(elecs[1]) / 2.0 rMax = elecs[0].dist(elecs[-1]) * 2.0 k, w = self.getIntegrationWeights(rMin, rMax) self.k = k self.w = w # pg.show(mesh, res, label='res') # pg.wait() rhs = self.createRHS(mesh, elecs) # store all potential fields u = np.zeros((nEle, nDof)) self.subPotentials = [pg.Matrix(nEle, nDof) for i in range(len(k))] for i, ki in enumerate(k): ws = dict() uE = pg.solve(mesh, a=1. / res, b=-(ki * ki) / res, f=rhs, bc={'Robin': ['*', self.mixedBC]}, userData={ 'sourcePos': elecs, 'k': ki }, verbose=False, stats=0, debug=False) self.subPotentials[i] = uE u += w[i] * uE # collect potential matrix, # i.e., potential for all electrodes and all injections pM = np.zeros((nEle, nEle)) for i in range(nEle): pM[i] = pg.interpolate(mesh, u[i, :], destPos=elecs) # collect resistivity values for all 4 pole measurements r = np.zeros(nData) for i in range(nData): iA = int(self.data('a')[i]) iB = int(self.data('b')[i]) iM = int(self.data('m')[i]) iN = int(self.data('n')[i]) uAB = pM[iA] - pM[iB] r[i] = uAB[iM] - uAB[iN] self.lastResponse = r * self.data('k') if self.verbose: print("Resp min/max: {0} {1} {2}s".format(min(self.lastResponse), max(self.lastResponse), pg.dur())) return self.lastResponse
def createJacobian(self, model): """TODO WRITEME.""" if self.subPotentials is None: self.response(model) J = self.jacobian() J.resize(self.data.size(), self.regionManager().parameterCount()) cells = self.mesh().findCellByMarker(0, -1) Si = pg.matrix.ElementMatrix() St = pg.matrix.ElementMatrix() u = self.subPotentials pg.tic() if self.verbose: print("Calculate sensitivity matrix for model: ", min(model), max(model)) Jt = pg.Matrix(self.data.size(), self.regionManager().parameterCount()) for kIdx, w in enumerate(self.w): k = self.k[kIdx] w = self.w[kIdx] Jt *= 0. A = pg.matrix.ElementMatrixMap() for i, c in enumerate(cells): modelIdx = c.marker() # 2.5D Si.u2(c) Si *= k * k Si += St.ux2uy2uz2(c) # 3D # Si.ux2uy2uz2(c); w = w* 2 A.add(modelIdx, Si) for dataIdx in range(self.data.size()): a = int(self.data('a')[dataIdx]) b = int(self.data('b')[dataIdx]) m = int(self.data('m')[dataIdx]) n = int(self.data('n')[dataIdx]) Jt[dataIdx] = A.mult(u[kIdx][a] - u[kIdx][b], u[kIdx][m] - u[kIdx][n]) J += w * Jt m2 = model * model k = self.data('k') for i in range(J.rows()): J[i] /= (m2 / k[i]) if self.verbose: sumsens = np.zeros(J.rows()) for i in range(J.rows()): sumsens[i] = pg.sum(J[i]) print("sens sum: median = ", pg.math.median(sumsens), " min = ", pg.min(sumsens), " max = ", pg.max(sumsens))
def solveERT(mesh, concentration, verbose=0): """Simulate resistivity distribution for given nonsteady concentration.""" if verbose: print("Solve for ERT ...") ertScheme = pg.physics.ert.createERTData(pg.utils.grange(-20, 20, dx=1.0), schemeName='dd') meshERT = mt.createParaMesh(ertScheme, quality=33, paraMaxCellSize=0.2, boundaryMaxCellSize=50, smooth=[1, 2]) scale = 0.001 concentration *= scale # mg/m² # apply saturation model to simulate unsaturated topsoil sat = np.zeros(mesh.cellCount()) for c in mesh.cells(): if c.center()[1] < -8: sat[c.id()] = 1. elif c.center()[1] < -2: sat[c.id()] = 1. else: sat[c.id()] = .5 cWater = 1. / 100. conductivity = concentration * 0.1 + cWater rArchie = resistivityArchie(rFluid=1. / conductivity, porosity=0.3, sat=sat, m=1.3, mesh=mesh, meshI=meshERT, fill=1) # apply background resistivity model rho0 = np.zeros(meshERT.cellCount()) for c in meshERT.cells(): if c.center()[1] < -8: rho0[c.id()] = 150. elif c.center()[1] < -2: rho0[c.id()] = 500. else: rho0[c.id()] = 1000. resis = pg.Matrix(rArchie) for i, rbI in enumerate(rArchie): resis[i] = 1. / ((1. / rbI) + 1. / rho0) ert = pg.physics.ert.ERTManager(verbose=False) ertScheme.set('k', ert.fop.calcGeometricFactor(ertScheme)) errPerc = 0.01 errVolt = 1e-5 rhoa = ert.simulate(meshERT, resis, ertScheme, verbose=0, returnArray=True) voltage = rhoa / ertScheme('k') err = np.abs(errVolt / voltage) + errPerc dRhoa = rhoa[1:] / rhoa[0] dErr = err[1:] return meshERT, ertScheme, resis, rhoa, dRhoa, dErr
sigmaFluid = c[timesERT] * 0.1 + 0.01 # Calculate bulk resistivity based on Archie's Law resBulk = petro.resistivityArchie(rFluid=1. / sigmaFluid, porosity=0.3, m=1.3, mesh=mesh, meshI=meshERT, fill=1) # apply background resistivity model rho0 = np.zeros(meshERT.cellCount()) + 1000. for c in meshERT.cells(): if c.center()[1] < -8: rho0[c.id()] = 150. elif c.center()[1] < -2: rho0[c.id()] = 500. resis = pg.Matrix(resBulk) for i, rbI in enumerate(resBulk): resis[i] = 1. / ((1. / rbI) + 1. / rho0) # Initialize ert method manager ERT = ERTManager(verbose=False) # Run simulation for the apparent resistivities rhoa = ERT.simulate(meshERT, resis, ertScheme, verbose=0, returnArray=True) # Solve the electrical forward problem using the ERT method manager axs = pg.plt.subplots(3, 2, sharex=True, sharey=True)[1].flatten() for i in range(6): ERT.showData(ertScheme, vals=rhoa[i] / rhoa[0], ax=axs[i]) # just hold figure windows open if run outside from spyder, ipython or similar pg.wait()
def solvePressureWave(mesh, velocities, times, sourcePos, uSource, verbose=False): r""" Solve pressure wave equation. Solve pressure wave for a given source function .. math:: \frac{\partial^2 u}{\partial t^2} & = \diverg(a\grad u) + f\\ finalize equation Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Mesh to solve on velocities : array velocities for each cell of the mesh time : array Time base definition sourcePos : RVector3 Source position uSource : array u(t, sourcePos) source movement of length(times) Usually a Ricker wavelet of the desired seismic signal frequency. Returns ------- u : RMatrix Return Examples -------- See TODO write example """ A = pg.matrix.SparseMatrix() M = pg.matrix.SparseMatrix() # F = pg.Vector(mesh.nodeCount(), 0.0) rhs = pg.Vector(mesh.nodeCount(), 0.0) u = pg.Matrix(len(times), mesh.nodeCount()) v = pg.Matrix(len(times), mesh.nodeCount()) sourceID = mesh.findNearestNode(sourcePos) if len(uSource) != len(times): raise Exception("length of uSource does not fit length of times: " + str(uSource) + " != " + len(times)) A.fillStiffnessMatrix(mesh, velocities * velocities) M.fillMassMatrix(mesh) # M.fillMassMatrix(mesh, velocities) FV = 0 if FV: A, rhs = pygimli.solver.diffusionConvectionKernel(mesh, velocities * velocities, sparse=1) M = pygimli.solver.identity(len(rhs)) u = pg.Matrix(len(times), mesh.cellCount()) v = pg.Matrix(len(times), mesh.cellCount()) sourceID = mesh.findCell(sourcePos).id() dt = times[1] - times[0] theta = 0.51 #theta = 1. S1 = M + dt * dt * theta * theta * A S2 = M solver1 = pg.core.LinSolver(S1, verbose=False) solver2 = pg.core.LinSolver(S2, verbose=False) swatch = pg.core.Stopwatch(True) # ut = pg.Vector(mesh.nodeCount(), .0) # vt = pg.Vector(mesh.nodeCount(), .0) timeIter1 = np.zeros(len(times)) timeIter2 = np.zeros(len(times)) timeIter3 = np.zeros(len(times)) timeIter4 = np.zeros(len(times)) progress = pg.utils.ProgressBar(its=len(times), width=40, sign='+') for n in range(1, len(times)): u[n - 1, sourceID] = uSource[n - 1] # solve for u tic = time.time() # + * dt*dt * F rhs = dt * M * v[n - 1] + (M - dt * dt * theta * (1. - theta) * A) * u[n - 1] timeIter1[n - 1] = time.time() - tic tic = time.time() u[n] = solver1.solve(rhs) timeIter2[n - 1] = time.time() - tic # solve for v tic = time.time() rhs = M * v[n - 1] - dt * \ ((1. - theta) * A * u[n - 1] + theta * A * u[n]) # + dt * F timeIter3[n - 1] = time.time() - tic tic = time.time() v[n] = solver2.solve(rhs) timeIter4[n - 1] = time.time() - tic # same as above # rhs = M * v[n-1] - dt * A * u[n-1] + dt * F # v[n] = solver1.solve(rhs) t1 = swatch.duration(True) if verbose: progress(n) return u
def calcSeismics(meshIn, vP): """Do seismic computations.""" meshSeis = meshIn.createH2() meshSeis = mt.appendTriangleBoundary(meshSeis, xbound=25, ybound=22.0, marker=1, quality=32.0, area=0.3, smooth=True, markerBoundary=1, isSubSurface=False, verbose=False) print(meshSeis) meshSeis = meshSeis.createH2() meshSeis = meshSeis.createH2() # meshSeis = meshSeis.createP2() meshSeis.smooth(1, 1, 1, 4) vP = pg.interpolate(meshIn, vP, meshSeis.cellCenters()) mesh = meshSeis vP = pg.solver.fillEmptyToCellArray(mesh, vP) print(mesh) # ax, cbar = pg.show(mesh, data=vP) # pg.show(mesh, axes=ax) geophPointsX = np.arange(-19, 19.1, 1) geophPoints = np.vstack((geophPointsX, np.zeros(len(geophPointsX)))).T sourcePos = geophPoints[4] c = mesh.findCell(sourcePos) h1 = pg.findBoundary(c.boundaryNodes(0)).size() h2 = pg.findBoundary(c.boundaryNodes(1)).size() h3 = pg.findBoundary(c.boundaryNodes(2)).size() print([h1, h2, h3]) h = pg.math.median([h1, h2, h3]) # h = pg.math.median(mesh.boundarySizes()) f0scale = 0.25 cfl = 0.5 dt = cfl * h / max(vP) print("Courant-Friedrich-Lewy number:", cfl) tmax = 40. / min(vP) times = np.arange(0.0, tmax, dt) solutionName = createCacheName('seis', mesh, times) + "cfl-" + str(cfl) try: # u = pg.load(solutionName + '.bmat') uI = pg.load(solutionName + 'I.bmat') except Exception as e: print(e) f0 = f0scale * 1. / dt print("h:", round(h, 2), "dt:", round(dt, 5), "1/dt:", round(1 / dt, 1), "f0", round(f0, 2), "Wavelength: ", round(max(vP) / f0, 2), " m") uSource = ricker(times, f0, t0=1. / f0) plt.figure() plt.plot(times, uSource, '-*') plt.show(block=0) plt.pause(0.01) u = solvePressureWave(mesh, vP, times, sourcePos=sourcePos, uSource=uSource, verbose=10) u.save(solutionName) uI = pg.Matrix() print("interpolate node to cell data ... ") pg.interpolate(mesh, u, mesh.cellCenters(), uI) print("... done") uI.save(solutionName + 'I') # nodes = [mesh.findNearestNode(p) for p in geophPoints] # fig = plt.figure() # axs = fig.add_subplot(1,1,1) # drawSeismogramm(axs, mesh, u, nodes, dt, i=None) # plt.show() dpi = 92 scale = 1 fig = plt.figure(facecolor='white', figsize=(scale * 800 / dpi, scale * 490 / dpi), dpi=dpi) ax = fig.add_subplot(1, 1, 1) gci = pg.viewer.mpl.drawModel(ax, mesh, data=uI[0], cMin=-1, cMax=1, cmap='bwr') pg.viewer.mpl.drawMeshBoundaries(ax, meshIn, hideMesh=1) ax.set_xlim((-20, 20)) ax.set_ylim((-15, 0)) ax.set_ylabel('Depth [m]') ax.set_xlabel('$x$ [m]') ticks = ax.yaxis.get_majorticklocs() tickLabels = [] for t in ticks: tickLabels.append(str(int(abs(t)))) ax.set_yticklabels(tickLabels) plt.tight_layout() # ax, cbar = pg.show(mesh, data=vP) # pg.showNow() # ax = fig.add_subplot(1,1,1) def animate(i): i = i * 5 if i > len(uI) - 1: return print("Frame:", i, "/", len(uI)) ui = uI[i] ui = ui / max(pg.abs(ui)) ui = pg.logDropTol(ui, 1e-2) cMax = max(pg.abs(ui)) pg.viewer.mpl.setMappableData(gci, ui, cMin=-cMax, cMax=cMax, logScale=False) # plt.pause(0.001) anim = animation.FuncAnimation(fig, animate, frames=int(len(uI) / 5), interval=0.001, repeat=0) # , blit=True) out = 'seis' + str(f0scale) + "cfl-" + str(cfl) anim.save(out + ".mp4", writer=None, fps=20, dpi=dpi, codec=None, bitrate=24 * 1024, extra_args=None, metadata=None, extra_anim=None, savefig_kwargs=None) try: print("create frames ... ") os.system('mkdir -p anim-' + out) os.system('ffmpeg -i ' + out + '.mp4 anim-' + out + '/movie%d.jpg') except: pass
def resistivityArchie(rFluid, porosity, a=1.0, m=2.0, sat=1.0, n=2.0, mesh=None, meshI=None, fill=None, show=False): r"""Resistivity of rock for the petrophysical model from Archies law. Calculates resistivity of rock for the petrophysical model from Archie's law. :cite:`Archie1942` .. math:: \rho = a\rho_{\text{fl}}\phi^{-m} S^{-n} * :math:`\rho` - the electrical resistivity of the fluid saturated rock in :math:`\Omega\text{m}` * :math:`\rho_{\text{fl}}` - rFluid: electrical resistivity of the fluid in :math:`\Omega\text{m}` * :math:`\phi` - porosity 0.0 --1.0 * :math:`S` - fluid saturation 0.0 --1.0 [sat] * :math:`a` - Tortuosity factor. (common 1) * :math:`m` - Cementation exponent of the rock (usually in the range 1.3 -- 2.5 for sandstones) * :math:`n` - is the saturation exponent (usually close to 2) If mesh is not None the resulting values are calculated for each cell of the mesh. All parameter can be scalar, array of length mesh.cellCount() or callable(pg.cell). If rFluid is non-steady n-step distribution than rFluid can be a matrix of size(n, mesh.cellCount()) If meshI is not None the result is interpolated to meshI.cellCenters() and prolonged (if fill ==1). Notes ----- We experience some unstable nonlinear behavior. Until this is clarified all results are rounded to the precision 1e-6. Examples -------- >>> # WRITEME """ phi = porosity if isinstance(porosity, list): phi = np.array(porosity) if mesh is None: return rFluid * a * phi**(-m) * sat**(-n) rB = None if isinstance(rFluid, float): rB = pg.Matrix(1, mesh.cellCount()) rB[0] = pg.solver.parseArgToArray(rFluid, mesh.cellCount(), mesh) elif isinstance(rFluid, pg.Vector): rB = pg.Matrix(1, len(rFluid)) rB[0] = pg.solver.parseArgToArray(rFluid, mesh.cellCount(), mesh) elif hasattr(rFluid, 'ndim') and rFluid.ndim == 1: rB = pg.Matrix(1, len(rFluid)) rB[0] = pg.solver.parseArgToArray(rFluid, mesh.cellCount(), mesh) elif hasattr(rFluid, 'ndim') and rFluid.ndim == 2: rB = pg.Matrix(len(rFluid), len(rFluid[0])) for i, rFi in enumerate(rFluid): rB[i] = rFi phi = pg.solver.parseArgToArray(phi, mesh.cellCount(), mesh) a = pg.solver.parseArgToArray(a, mesh.cellCount(), mesh) m = pg.solver.parseArgToArray(m, mesh.cellCount(), mesh) S = pg.solver.parseArgToArray(sat, mesh.cellCount(), mesh) n = pg.solver.parseArgToArray(n, mesh.cellCount(), mesh) if show: pg.show(mesh, S, label='S') pg.show(mesh, phi, label='p') pg.wait() r = pg.Matrix(len(rB), len(rB[0])) for i, _ in enumerate(r): r[i] = rB[i] * a * phi**(-m) * S**(-n) r.round(1e-6) if meshI is None: if len(r) == 1: return r[0].copy() return r rI = pg.Matrix(len(r), meshI.cellCount()) if meshI: pg.interpolate(mesh, r, meshI.cellCenters(), rI) if fill: for i, ri_ in enumerate(rI): # slope == True produce unstable behavior .. check!!!!!! rI[i] = mt.fillEmptyToCellArray(meshI, ri_, slope=False) rI.round(1e-6) if len(rI) == 1: # copy here because of missing refcounter TODO return rI[0].array() return rI