Beispiel #1
0
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)
Beispiel #2
0
def cellDataToBoundaryDataMatrix(mesh):
    AMM = pg.RSparseMapMatrix(mesh.boundaryCount(), mesh.cellCount())

    for b in mesh.boundaries():
        cellToFaceArithmetic(b, AMM)

    return AMM
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
    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)
Beispiel #6
0
 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()
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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