def sparseMatrix2coo(A): """Convert SparseMatrix to scipy.coo_matrix. Parameters ---------- A: pg.SparseMapMatrix | pg.SparseMatrix Matrix to convert from. Returns ------- mat: scipy.coo_matrix Matrix to convert into. """ from scipy.sparse import coo_matrix vals = pg.RVector() rows = pg.IndexArray([0]) cols = pg.IndexArray([0]) if isinstance(A, pg.SparseMatrix): C = pg.RSparseMapMatrix(A) C.fillArrays(vals=vals, rows=rows, cols=cols) return coo_matrix(vals, (rows, cols)) elif isinstance(A, pg.SparseMapMatrix): A.fillArrays(vals, rows, cols) return coo_matrix(vals, (rows, cols)) return coo_matrix(A)
def cellDataToBoundaryDataMatrix(mesh): AMM = pg.RSparseMapMatrix(mesh.boundaryCount(), mesh.cellCount()) for b in mesh.boundaries(): cellToFaceArithmetic(b, AMM) return AMM
def test_Interpolate(self): grid = pg.createGrid(x=[0.0, 1.0], y=[0.0, 1.0]) u = pg.RVector(grid.nodeCount(), 1.) # test with pg.interpolate queryPos = [0.2, 0.2] uI = pg.interpolate(srcMesh=grid, inVec=u, destPos=[queryPos, queryPos]) np.testing.assert_allclose(uI[0], 1.) # test manual interpolation c = grid.findCell(queryPos) uI = c.pot(queryPos, u) np.testing.assert_allclose(uI, 1.) # test with manual interpolationMatrix generation I = pg.RSparseMapMatrix(1, grid.nodeCount()) cI = c.N(c.shape().rst(queryPos)) for i in range(c.nodeCount()): I.addVal(0, c.node(i).id(), cI[i]) uI = I.mult(u) np.testing.assert_allclose(uI[0], 1) # test with automatic interpolationMatrix generation I = grid.interpolationMatrix([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) uI = I * u np.testing.assert_allclose(uI, u) # api test https://github.com/gimli-org/gimli/issues/131 x = np.linspace(grid.xmin(), grid.xmax(), 11) np.testing.assert_allclose(pg.interpolate(grid, pg.x(grid), x), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x, x * 0.), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x, y=x * 0), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x, x * 0, x * 0), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x, y=x * 0, z=x * 0), x) x = pg.Vector(x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x, x * 0.), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x, y=x * 0), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x, x * 0, x * 0), x) np.testing.assert_allclose( pg.interpolate(grid, pg.x(grid.positions()), x=x, y=x * 0, z=x * 0), x)
def test_Interpolate(self): grid = pg.createGrid(x=[0.0, 1.0], y=[0.0, 1.0]) u = pg.RVector(grid.nodeCount(), 1.) # test with pg.interpolate queryPos = [0.2, 0.2] uI = pg.interpolate(srcMesh=grid, inVec=u, destPos=[queryPos, queryPos]) np.testing.assert_allclose(uI[0], 1.) # test manual interpolation c = grid.findCell(queryPos) uI = c.pot(queryPos, u) np.testing.assert_allclose(uI, 1.) # test with manual interpolationMatrix generation I = pg.RSparseMapMatrix(1, grid.nodeCount()) cI = c.N(c.shape().rst(queryPos)) for i in range(c.nodeCount()): I.addVal(0, c.node(i).id(), cI[i]) uI = I.mult(u) np.testing.assert_allclose(uI[0], 1) # test with automatic interpolationMatrix generation I = grid.interpolationMatrix([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]) uI = I * u np.testing.assert_allclose(uI, u)
def createConstraints(self): # First order smoothness matrix self._Ctmp = pg.RSparseMapMatrix() if self.corr_l is None: pg.info("Using smoothing with zWeight = %.2f." % self.zWeight) rm = self.RST.fop.regionManager() rm.fillConstraints(self._Ctmp) # Set zWeight rm.setZWeight(self.zWeight) self.cWeight = pg.RVector() rm.fillConstraintsWeight(self.cWeight) self._CW = pg.LMultRMatrix(self._Ctmp, self.cWeight) else: pg.info("Using geostatistical constraints with " + str(self.corr_l)) # Geostatistical constraints by Jordi et al., GJI, 2018 CM = pg.utils.geostatistics.covarianceMatrix(self.mesh, I=self.corr_l) self._Ctmp = pg.matrix.Cm05Matrix(CM) self._CW = self._Ctmp # Putting together in block matrix self._C = pg.RBlockMatrix() cid = self._C.addMatrix(self._CW) self._C.addMatrixEntry(cid, 0, 0) self._C.addMatrixEntry(cid, self._Ctmp.rows(), self.cellCount) self._C.addMatrixEntry(cid, self._Ctmp.rows() * 2, self.cellCount * 2) self._C.addMatrixEntry(cid, self._Ctmp.rows() * 3, self.cellCount * 3) self.setConstraints(self._C) # Identity matrix for interparameter regularization self._I = pg.IdentityMatrix(self.cellCount) self._G = pg.RBlockMatrix() iid = self._G.addMatrix(self._I) self._G.addMatrixEntry(iid, 0, 0) self._G.addMatrixEntry(iid, 0, self.cellCount) self._G.addMatrixEntry(iid, 0, self.cellCount * 2) self._G.addMatrixEntry(iid, 0, self.cellCount * 3) self.fix_val_matrices = {} # Optionally fix phases to starting model globally or in selected cells phases = ["water", "ice", "air", "rock matrix"] for i, phase in enumerate( [self.fix_water, self.fix_ice, self.fix_air, self.fix_poro]): name = phases[i] vec = pg.RVector(self.cellCount) if phase is True: pg.info("Fixing %s content globally." % name) vec += 1.0 elif hasattr(phase, "__len__"): pg.info("Fixing %s content at selected cells." % name) phase = np.asarray(phase, dtype="int") vec[phase] = 1.0 self.fix_val_matrices[name] = pg.matrix.DiagonalMatrix(vec) self._G.addMatrix(self.fix_val_matrices[name], self._G.rows(), self.cellCount * i)
def createConstraints(self): """ """ print("createConstrains(self, model):") Ctmp = pg.RSparseMapMatrix() self.matrixHeap.append(Ctmp) self.regionManager().fillConstraints(Ctmp) CiD = self._C.addMatrix(Ctmp) self._C.addMatrixEntry(CiD, 0, 0) self._C.addMatrixEntry(CiD, Ctmp.rows(), Ctmp.cols()) self._C.recalcMatrixSize()
def identity(dom, start=0, end=-1, scale=1): """Create identity matrix.""" A = pg.RSparseMapMatrix(dom, dom) if end == -1: end = dom for i in range(start, end): if hasattr(scale, '__len__'): A.addVal(i, i, scale[i]) else: A.addVal(i, i, scale) return A
def triDiagToeplitz(dom, a, l, r, start=0, end=-1): """Create tri-diagonal Toeplitz matrix.""" A = pg.RSparseMapMatrix(dom, dom) if end == -1: end = dom for i in range(start, end): A.addVal(i, i, a) if i > start: A.addVal(i, i - 1, l) if i < end - 1: A.addVal(i, i + 1, r) return A
def computeInverseRootMatrix(CM, thrsh=0.001, verbose=False): """Compute inverse square root (C^{-0.5} of matrix.""" spl = opt_import('scipy.linalg', 'scipy linear algebra') if spl is None: return None t = time.time() e_vals, e_vecs = spl.eigh(CM) if verbose: print('(C) Calculation time for eigenvalue decomposition:\n%s sec' % (time.time() - t)) t = time.time() A = spl.inv(np.diag(np.sqrt(np.real(e_vals)))) if verbose: print('(C) Calculation time for inv(diag(sqrt)):\n%s sec' % (time.time() - t)) t = time.time() gemm = spl.get_blas_funcs("gemm", [e_vecs, A]) B = gemm(1, e_vecs, A) if verbose: print('(C) Calculation time for dot 1:\n%s sec' % (time.time() - t)) t = time.time() gemm2 = spl.get_blas_funcs("gemm", [B, np.transpose(e_vecs)]) if verbose: print('gemm test:\n%s sec' % (time.time() - t)) CM05 = gemm2(1, B, np.transpose(e_vecs)) if verbose: print('(C) Calculation time for dot 2:\n%s sec' % (time.time() - t)) if thrsh: nModel = len(CM) RCM05 = pg.RSparseMapMatrix(nModel, nModel) for i in range(nModel): for j in range(nModel): if np.abs(CM05[i][j]) > thrsh: RCM05.setVal(i, j, CM05[i][j]) return RCM05 else: return CM05 # not making sense as constraints matrix
def diffusionConvectionKernel( mesh, a=None, b=0.0, uB=None, duB=None, vel=0, # u0=0, fn=None, scheme='CDS', sparse=False, time=0.0, userData=None): """ Generate system matrix for diffusion and convection in a velocity field. Particle concentration u inside a velocity field. Peclet Number - ratio between convection/diffusion = F/D F = velocity flow trough volume boundary, D = diffusion coefficient Parameters ---------- mesh : :gimliapi:`GIMLI::Mesh` Mesh represents spatial discretization of the calculation domain a : value | array | callable(cell, userData) Diffusion coefficient per cell b : value | array | callable(cell, userData) TODO What is b fn : iterable(cell) TODO What is fn vel : ndarray (N,dim) | RMatrix(N,dim) velocity field [[v_i,]_j,] with i=[1..3] for the mesh dimension and j = [0 .. N-1] per Cell or per Node so N is either mesh.cellCount() or mesh.nodeCount() scheme : str [CDS] Finite volume scheme * CDS -- Central Difference Scheme. maybe irregular for Peclet no. |F/D| > 2 Diffusion dominant. Error of order 2 * UDS -- Upwind Scheme. Convection dominant. Error of order 1 * HS -- Hybrid Scheme. Diffusion dominant for Peclet-number |(F/D)| < 2 Convection dominant else. * PS -- Power Law Scheme. Identical to HS for Peclet-number |(F/D)| > 10 and near to ES else Convection dominant. * ES -- Exponential scheme Only stationary one-dimensional but exact solution Returns ------- S : :gimliapi:`GIMLI::SparseMatrix` | numpy.ndarray(nCells, nCells) Kernel matrix, depends on vel, a, b, scheme, uB, duB .. if some of this has been changed you cannot cache these matrix rhsBoundaryScales : ndarray(nCells) RHS offset vector """ if a is None: a = pg.RVector(mesh.boundaryCount(), 1.0) AScheme = None if scheme == 'CDS': AScheme = lambda peclet_: 1.0 - 0.5 * abs(peclet_) elif scheme == 'UDS': AScheme = lambda peclet_: 1.0 elif scheme == 'HS': AScheme = lambda peclet_: max(0.0, 1.0 - 0.5 * abs(peclet_)) elif scheme == 'PS': AScheme = lambda peclet_: max(0.0, (1.0 - 0.1 * abs(peclet_))**5.0) elif scheme == 'ES': AScheme = lambda peclet_: (peclet_) / (np.exp(abs(peclet_)) - 1.0) \ if peclet_ != 0.0 else 1 else: raise BaseException("Scheme unknwon:" + scheme) useHalfBoundaries = False dof = mesh.cellCount() if not uB: uB = [] if not duB: duB = [] if useHalfBoundaries: dof = mesh.cellCount() + len(uB) S = None if sparse: S = pg.RSparseMapMatrix(dof, dof, stype=0) + identity(dof, scale=b) else: S = np.zeros((dof, dof)) rhsBoundaryScales = np.zeros(dof) # swatch = pg.Stopwatch(True) # we need this to fast identify uBoundary and value by boundary uBoundaryID = [] uBoundaryVals = [None] * mesh.boundaryCount() for [boundary, val] in uB: if not isinstance(boundary, pg.Boundary): raise BaseException("Please give boundary, value list") uBoundaryID.append(boundary.id()) uBoundaryVals[boundary.id()] = val duBoundaryID = [] duBoundaryVals = [None] * mesh.boundaryCount() for [boundary, val] in duB: if not isinstance(boundary, pg.Boundary): raise BaseException("Please give boundary, value list") duBoundaryID.append(boundary.id()) duBoundaryVals[boundary.id()] = val # iterate over all cells for cell in mesh.cells(): cID = cell.id() for bi in range(cell.boundaryCount()): boundary = pg.findBoundary(cell.boundaryNodes(bi)) ncell = boundary.leftCell() if ncell == cell: ncell = boundary.rightCell() v = findVelocity(mesh, vel, boundary, cell, ncell) # Convection part F = boundary.norm(cell).dot(v) * boundary.size() # print(F, boundary.size(), v, vel) # Diffusion part D = findDiffusion(mesh, a, boundary, cell, ncell) # print(F, D, F/D) # print((1.0 - 0.1 * abs(F/D))**5.0) aB = D * AScheme(F / D) + max(-F, 0.0) aB /= cell.size() # print(cell.center(), boundary.center(), boundary.norm(cell), aB) if ncell: # no boundary if sparse: S.addVal(cID, ncell.id(), -aB) S.addVal(cID, cID, +aB) else: S[cID, ncell.id()] -= aB S[cID, cID] += aB elif not useHalfBoundaries: if boundary.id() in uBoundaryID: val = pg.solver.generateBoundaryValue( boundary, uBoundaryVals[boundary.id()], time=time, userData=userData) if sparse: S.addVal(cID, cID, aB) else: S[cID, cID] += aB rhsBoundaryScales[cID] += aB * val if boundary.id() in duBoundaryID: # Neumann boundary condition val = pg.solver.generateBoundaryValue( boundary, duBoundaryVals[boundary.id()], time=time, userData=userData) # amount of flow through the boundary outflow = val * boundary.size() / cell.size() if sparse: S.addVal(cID, cID, outflow) else: S[cID, cID] += outflow if fn is not None: if sparse: # * cell.shape().domainSize()) S.addVal(cell.id(), cell.id(), -fn[cell.id()]) else: # * cell.shape().domainSize() S[cell.id(), cell.id()] -= fn[cell.id()] return S, rhsBoundaryScales
def diffusionConvectionKernel(mesh, a=None, f=None, uBoundaries=None, duBoundaries=None, fn=None, vel=0, u0=0, scheme='CDS', sparse=False, time=0.0, userData=None): """ Peclet Number - ratio between convection/diffusion * Length Advection .. forced convection """ if a is None: a = pg.RVector(mesh.boundaryCount(), 1.0) AScheme = None if scheme == 'CDS': # CDS - central differences scheme .. # .. maybe irregular for Peclet-number |F/D| > 2 # diffusion dominant # Error of order 2 AScheme = lambda peclet_: 1.0 - 0.5 * abs(peclet_) elif scheme == 'UDS': # UDS - upwind scheme # Convection dominant # Error of order 1 AScheme = lambda peclet_: 1.0 elif scheme == 'HS': # HS - hybrid scheme. # Diffusion dominant for Peclet-number |(F/D)| < 2 # Convection dominant else AScheme = lambda peclet_: max(0.0, 1.0 - 0.5 * abs(peclet_)) elif scheme == 'PS': # PS - power-law scheme. # Identical to HS for Peclet-number |(F/D)| > 10 and near to ES else AScheme = lambda peclet_: max(0.0, (1.0 - 0.1 * abs(peclet_))**5.0) elif scheme == 'ES': # ES - exponential scheme # Only stationary one-dimensional but exact solution AScheme = lambda peclet_: (peclet_) / (np.exp(abs(peclet_))-1.0) \ if peclet_ != 0.0 else 1 else: raise useHalfBoundaries = False dof = mesh.cellCount() if not uBoundaries: uBoundaries = [] if not duBoundaries: duBoundaries = [] if useHalfBoundaries: dof = mesh.cellCount() + len(uBoundaries) S = None if sparse: S = pg.RSparseMapMatrix(dof, dof, 0) else: S = np.zeros((dof, dof)) rhsBoundaryScales = np.zeros(dof) # we need this to fast identify uBoundary and value by boundary uBoundaryID = [] uBoundaryVals = [None] * mesh.boundaryCount() for i, [boundary, val] in enumerate(uBoundaries): if not isinstance(boundary, pg.Boundary): raise BaseException("Please give boundary, value list") uBoundaryID.append(boundary.id()) uBoundaryVals[boundary.id()] = val duBoundaryID = [] duBoundaryVals = [None] * mesh.boundaryCount() for i, [boundary, val] in enumerate(duBoundaries): if not isinstance(boundary, pg.Boundary): raise BaseException("Please give boundary, value list") duBoundaryID.append(boundary.id()) duBoundaryVals[boundary.id()] = val for cell in mesh.cells(): for bi in range(cell.boundaryCount()): boundary = pg.findBoundary(cell.boundaryNodes(bi)) ncell = boundary.leftCell() if ncell == cell: ncell = boundary.rightCell() v = findVelocity(mesh, vel, boundary, cell, ncell) # Convection part F = boundary.norm(cell).dot(v) * boundary.size() # Diffusion part D = findDiffusion(mesh, a, boundary, cell, ncell) aB = D * AScheme(F / D) + max(-F, 0.0) aB /= cell.size() # print(cell.center(), boundary.center(), boundary.norm(cell), aB) if ncell: # no boundary if sparse: S.addVal(cell.id(), ncell.id(), -aB) S.addVal(cell.id(), cell.id(), +aB) else: S[cell.id(), ncell.id()] -= aB S[cell.id(), cell.id()] += aB elif not useHalfBoundaries: if boundary.id() in uBoundaryID: val = pg.solver.generateBoundaryValue( boundary, uBoundaryVals[boundary.id()], time=time, userData=userData) if sparse: S.addVal(cell.id(), cell.id(), aB) else: S[cell.id(), cell.id()] += aB rhsBoundaryScales[cell.id()] += aB * val if boundary.id() in duBoundaryID: # Neumann boundary condition val = pg.solver.generateBoundaryValue( boundary, duBoundaryVals[boundary.id()], time=time, userData=userData) if sparse: # amount of flow through the boundary S.addVal(cell.id(), cell.id(), val * boundary.size()/cell.size()) else: S[cell.id(), cell.id()] += val * boundary.size() / \ cell.size() if fn is not None: if sparse: S.addVal(cell.id(), cell.id(), -fn[cell.id()]) # * cell.shape().domainSize()) else: S[cell.id(), cell.id()] -= fn[cell.id()] # * cell.shape().domainSize() if useHalfBoundaries: for i, [b, val] in enumerate(uDirBounds): # not defined! bIdx = mesh.cellCount() + i c = b.leftCell() if not c: c = b.rightCell() if c: n = b.norm(c) v = findVelocity(mesh, vel, b, c, nc=None) F = n.dot(v) * b.size() D = findDiffusion(mesh, a, b, c) aB = D * AScheme(F / D) + max(-F, 0.0) if useHalfBoundaries: if sparse: S.setVal(c.id(), c.id(), 1.) S.addVal(c.id(), bIdx, -aB) else: S[bIdx, bIdx] = 1. S[c.id(), bIdx] -= aB rhsBoundaryScales[bIdx] = aB return S, rhsBoundaryScales