示例#1
0
def isequal(op1, op2, eps=1e-3):
    from block import block_vec
    v = op1.create_vec()
    block_vec([v]).randomize()
    xv = op1 * v
    err = (xv - op2 * v).norm('l2') / (xv).norm('l2')
    return err < eps
示例#2
0
文件: matrix.py 项目: MiroK/cbc.block
def collapse(x):
    """Compute an explicit matrix representation of an operator. For example,
    given a block_ mul object M=A*B, collapse(M) performs the actual matrix
    multiplication.
    """
    # Since _collapse works recursively, this method is a user-visible wrapper
    # to print timing, and to check input/output arguments.
    from time import time
    from dolfin import PETScMatrix, info, warning
    T = time()
    res = _collapse(x)
    if getattr(res, 'transposed', False):
        # transposed matrices will normally be converted to a non-transposed
        # one by matrix multiplication or addition, but if the transpose is the
        # outermost operation then this doesn't work.
        res.M.transpose()
    info('computed explicit matrix representation %s in %.2f s' %
         (str(res), time() - T))

    result = PETScMatrix(res.M)

    # Sanity check. Cannot trust EpetraExt.Multiply always, it seems.
    from block import block_vec
    v = x.create_vec()
    block_vec([v]).randomize()
    xv = x * v
    err = (xv - result * v).norm('l2') / (xv).norm('l2')
    if (err > 1e-3):
        raise RuntimeError(
            'collapse computed wrong result; ||(a-a\')x||/||ax|| = %g' % err)

    return result
示例#3
0
 def matvec(self, b):
     '''Reduce'''
     reshaped = []
     for indices in self.mapping:
         if len(indices) == 1:
             reshaped.append(b.blocks[indices[0]])
         else:
             reshaped.append(PETScVector(as_petsc_nest(block_vec([b.blocks[idx] for idx in indices]))))
     return block_vec(reshaped) if len(reshaped) > 1 else reshaped[0]
示例#4
0
def issymmetric(op):
    x = op.create_vec()
    if hasattr(x, 'randomize'):
        x.randomize()
    else:
        from block import block_vec
        block_vec([x]).randomize()
    opx = op * x
    err = (opx - op.T * x).norm('l2') / opx.norm('l2')
    return (err < 1e-6)
示例#5
0
    def matvec(self, b):
        '''Reduce'''

        reduced = []
        for f, l in zip(self.offsets[:-1], self.offsets[1:]):
            if (l - f) == 1:
                reduced.append(b[f])
            else:
                reduced.append(block_vec(b.blocks[f:l]))
        return block_vec(reduced) if len(reduced) > 1 else reduced[0]
示例#6
0
    def matmat(self, other):

        from PyTrilinos import Epetra
        from block.block_util import isscalar
        try:
            if isscalar(other):
                C = type(self.M)(self.M)
                if other != 1:
                    C.Scale(other)
                return matrix_op(C, self.transposed)
            other = other.down_cast()
            if hasattr(other, 'mat'):
                from PyTrilinos import EpetraExt

                # Create result matrix C. This is done in a contorted way, to
                # ensure all diagonals are present.
                A = type(self.M)(self.M)
                A.PutScalar(1.0)
                B = type(other.mat())(other.mat())
                B.PutScalar(1.0)
                C = Epetra.FECrsMatrix(Epetra.Copy, self.rowmap(), 100)
                EpetraExt.Multiply(A, self.transposed, B, other.transposed, C)
                C.OptimizeStorage()
                # C is now finalised, we can use it to store the real mat-mat product.

                assert (0 == EpetraExt.Multiply(self.M, self.transposed,
                                                other.mat(), other.transposed,
                                                C))

                result = matrix_op(C)

                # Sanity check. Cannot trust EpetraExt.Multiply always, it seems.
                from block import block_vec
                v = result.create_vec()
                block_vec([v]).randomize()
                xv = self * other * v
                err = (xv - result * v).norm('l2') / (xv).norm('l2')
                if (err > 1e-3):
                    print('++ a :', self * other)
                    print('++ a\':', result)
                    print(
                        '++ EpetraExt.Multiply computed wrong result; ||(a-a\')x||/||ax|| = %g'
                        % err)

                return result
            else:
                C = type(self.M)(self.M)
                if self.transposed:
                    C.LeftScale(other.vec())
                else:
                    C.RightScale(other.vec())
                return matrix_op(C, self.transposed)
        except AttributeError:
            raise TypeError("can't extract matrix data from type '%s'" %
                            str(type(other)))
示例#7
0
    def matvec(self, b):
        '''Reduce'''
        # print type(b), b.size(), self.offsets
        # assert b.size() == self.offsets[-1]

        reduced = []
        for f, l in zip(self.offsets[:-1], self.offsets[1:]):
            if (l - f) == 1:
                reduced.append(b[f])
            else:
                reduced.append(PETScVector(as_petsc_nest(block_vec(b.blocks[f:l]))))
        return block_vec(reduced) if len(reduced) > 1 else reduced[0]
示例#8
0
def as_block(monolithic, blocks):
    '''Turn monolithic operator into block-structured one with indices specified in blocks'''
    comm = mpi_comm_world()

    # We want list of PETSc.IS-es
    elm_type, = element_types(blocks)
    if elm_type is FunctionSpace:
        offsets = np.cumsum(np.r_[0, [Wi.dim() for Wi in blocks]])

        idx = []
        for first, last in zip(offsets[:-1], offsets[1:]):
            idx.append(PETSc.IS().createStride(last - first, first, 1))
        return as_block(monolithic, idx)

    elif elm_type in (list, np.ndarray):
        return as_block(monolithic, [
            PETSc.IS().createGeneral(np.asarray(block, dtype='int32'))
            for block in blocks
        ])

    assert elm_type is PETSc.IS

    # Break up Vector to block-vec
    if isinstance(monolithic, (GenericVector, Vector)):
        return as_block(as_backend_type(monolithic).vec(), blocks)

    if isinstance(monolithic, (GenericMatrix, Matrix)):
        return as_block(as_backend_type(monolithic).mat(), blocks)

    if isinstance(monolithic, PETSc.Vec):
        b = [
            PETSc.Vec().createWithArray(monolithic.getValues(block), comm=comm)
            for block in blocks
        ]
        for bi in b:
            bi.assemblyBegin()
            bi.assemblyEnd()
        return block_vec(list(map(PETScVector, b)))

    # Otherwise we have a Matrix
    try:
        monolithic.getSubMatrix
        A = [[
            PETScMatrix(monolithic.getSubMatrix(block_row, block_col))
            for block_col in blocks
        ] for block_row in blocks]
    # NOTE: 3.8+ does not ahve getSubMatrix, there is getLocalSubMatrix
    # but cannot get that to work - petsc error 73. So for now everything
    # is done with scipy
    except AttributeError:
        monolithic = csr_matrix(monolithic.getValuesCSR()[::-1],
                                shape=monolithic.size)

        A = [[
            numpy_to_petsc(monolithic[block_row.array, :][:, block_col.array])
            for block_col in blocks
        ] for block_row in blocks]
    # Done
    return block_mat(A)
示例#9
0
 def mult(self, mat, x, y):
     '''y = A*x'''
     y *= 0
     # Now x shall be comming as a nested vector
     # Convert
     x_bvec = block_vec(map(PETScVector, x.getNestSubVecs()))
     # Apply
     y_bvec = self.A * x_bvec
     # Convert back
     y.axpy(1., as_petsc_nest(y_bvec))
示例#10
0
    def transpmult(self, b):
        '''Unpack'''
        b_block = []
        for bi in b:
            if isinstance(bi, (Vector, GenericVector)):
                b_block.append(bi)
            else:
                b_block.extend(bi.blocks)

        return block_vec(b_block)
示例#11
0
 def multTranspose(self, mat, x, y):
     '''y = A.T*x'''
     AT = block_transpose(self.A)
 
     y *= 0
     # Now x shall be comming as a nested vector
     # Convert
     x_bvec = block_vec(list(map(PETScVector, x.getNestSubVecs())))
     # Apply
     y_bvec = AT*x_bvec
     # Convert back
     y.axpy(1., as_petsc_nest(y_bvec))
示例#12
0
def randomize(y):
    '''Fill the vector with random values'''
    if isinstance(y, (Vector, GenericVector, PETScVector)):
        values = np.random.rand(y.local_size())
        values -= np.mean(values)
        
        y_vec = as_backend_type(y).vec()
        y_vec.array_w = values

        return y

    return block_vec(map(randomize, y))
示例#13
0
def block_tensor(obj):
    """Return either a block_vec or a block_mat, depending on the shape of the object"""
    from block import block_mat, block_vec
    import numpy
    if isinstance(obj, (block_mat, block_vec)):
        return obj

    from ufl import Form
    if isinstance(obj, Form):
        from .splitting import split_form
        obj = split_form(obj)
    blocks = numpy.array(obj)
    if len(blocks.shape) == 2:
        return block_mat(blocks)
    elif len(blocks.shape) == 1:
        return block_vec(blocks)
    else:
        raise RuntimeError("Not able to create block container of rank %d" %
                           len(blocks.shape))
示例#14
0
    def transpmult(self, b):
        '''Unpack'''
        if isinstance(b, (Vector, GenericVector)):
            b = [b]
        else:
            b = b.blocks
            
        n = sum(map(len, self.index_sets))
        unpacked = [0]*n
        for bi, block_dofs, blocks in zip(b, self.index_sets, self.mapping):
            if len(blocks) == 1:
                unpacked[blocks[0]] = bi
            else:
                x_petsc = as_backend_type(bi).vec()
                subvecs = [PETScVector(x_petsc.getSubVector(dofs)) for dofs in block_dofs]
                for j, subvec in zip(blocks, subvecs):
                    unpacked[j] = subvec

                    
        return block_vec(unpacked)
示例#15
0
    def transpmult(self, b):
        '''Unpack'''
        if isinstance(b, (Vector, GenericVector)):
            b = [b]
        else:
            b = b.blocks
        n = len(b)
        assert n == len(self.index_sets), self.index_sets

        unpacked = []
        for bi, iset in zip(b, self.index_sets):
            if len(iset) == 0:
                unpacked.append(bi)
            else:
                x_petsc = as_backend_type(bi).vec()

                subvecs = map(lambda indices, x=x_petsc: PETScVector(x.getSubVector(indices)),
                              iset)

                unpacked.extend(subvecs)
        return block_vec(unpacked)
示例#16
0
def setup_problem(n, mms, params):
    '''Poisson solver'''
    mesh = UnitCubeMesh(n, n, n)
    
    V = FunctionSpace(mesh, 'CG', 1)

    # Just one
    boundaries = MeshFunction('size_t', mesh, 2, 0)
    for tag, subd in enumerate(mms.subdomains, 1):
        CompiledSubDomain(subd, tol=1E-10).mark(boundaries, tag)

    u_true,  = mms.solution
    bc = DirichletBC(V, u_true, boundaries, 1)

    f, = mms.rhs
    
    u, v = TrialFunction(V), TestFunction(V)
    a = inner(grad(u), grad(v))*dx
    L = inner(f, v)*dx

    A, b = assemble_system(a, L, bc)

    return block_mat([[A]]), block_vec([b]), [V]
示例#17
0
    u, v = TrialFunction(V), TestFunction(V)
    ub, vb = TrialFunction(Vb), TestFunction(Vb)

    b = [[0, 0], [0, 0]]
    b[0][0] = inner(grad(u), grad(v)) * dx + inner(u, v) * dx
    b[0][1] = inner(grad(ub), grad(v)) * dx + inner(ub, v) * dx
    b[1][0] = inner(grad(u), grad(vb)) * dx + inner(u, vb) * dx
    b[1][1] = inner(grad(ub), grad(vb)) * dx + inner(ub, vb) * dx

    BB = ii_assemble(b)

    x = Function(V).vector()
    x.set_local(np.random.rand(x.local_size()))
    y = Function(Vb).vector()
    y.set_local(np.random.rand(y.local_size()))
    bb = block_vec([x, y])

    z_block = BB * bb

    # Make into a monolithic matrix
    BB_m = ii_convert(BB)

    R = ReductionOperator([2], W=[V, Vb])

    z = (R.T) * BB_m * (R * bb)

    print(z - z_block).norm()

    y = BB_m * (R * bb)
    print np.linalg.norm(
        np.hstack([bi.get_local() for bi in z_block]) - y.get_local())
示例#18
0
def apply_bc(A, b, bcs, diag_val=1., return_apply_b=False):
    '''
    Apply block boundary conditions to block system A, b    
    '''
    # Specs of do nothing
    if bcs is None or not bcs or (not any(bc for bc in bcs)
                                  and isinstance(bcs, list)):
        return A, b

    # Allow for A, b be simple matrices. To proceed we wrap them as
    # block objects
    has_wrapped_A = False
    if not isinstance(A, block_mat):
        A = block_mat([[A]])
        has_wrapped_A = True

    if b is None:
        b = A.create_vec()

    if not isinstance(b, block_vec):
        assert has_wrapped_A
        b = block_vec([b])

    if isinstance(bcs, dict):
        assert all(0 <= k < len(A) for k in list(bcs.keys()))
        assert all(isinstance(v, list) for v in list(bcs.values()))
        bcs = [bcs.get(i, []) for i in range(len(A))]
    else:
        if has_wrapped_A:
            bcs = [bcs]

    # block boundary conditions is a list with bcs for each block of A, b
    assert len(A) == len(b) == len(bcs), (len(A), len(b), len(bcs))

    bcs_ = []
    for bc in bcs:
        assert isinstance(bc, (DirichletBC, list))
        if isinstance(bc, DirichletBC):
            bcs_.append([bc])
        else:
            bcs_.append(bc)
    bcs = bcs_

    if not bcs or not any(bcs): return A, b

    # Obtain a monolithic matrix
    AA, bb = list(map(convert, (A, b)))

    # PETSc guys
    AA, bb = as_backend_type(AA).mat(), as_backend_type(bb).vec()

    # We want to make a monotlithic matrix corresponding to function sp ace
    # where the spaces are serialized

    # Break apart for block
    offsets = [0]
    for bi in b:
        offsets.append(offsets[-1] + bi.size())

    assert AA.size[0] == AA.size[1] == offsets[-1], (AA.size[0], AA.size[1],
                                                     offsets)

    rows = []
    x_values = []
    # Each bc in the group has dofs numbered only wrt to its space.
    # We're after global numbering
    for shift, bcs_sub in zip(offsets, bcs):
        for bc in bcs_sub:
            # NOTE: bcs can be a dict or DirichletBC in which case we extract
            # the dict
            if isinstance(bc, DirichletBC): bc = bc.get_boundary_values()
            # Dofs and values for rhs
            rows.extend(shift + np.array(list(bc.keys()), dtype='int32'))
            x_values.extend(list(bc.values()))

    rows = np.hstack(rows)
    x_values = np.array(x_values)

    x = bb.copy()
    x.zeroEntries()
    x.setValues(rows, x_values)
    x.assemble()

    blocks = []
    for first, last in zip(offsets[:-1], offsets[1:]):
        blocks.append(PETSc.IS().createStride(last - first, first, 1))

    if return_apply_b:
        # We don't want to reassemble system and apply bcs (when they are
        # updated) to the (new) matrix and the rhs. Matrix is expensive
        # AND the change of bcs only effects the rhs. So what we build
        # here is a function which applies updated bcs only to rhs as
        # if by assemble_system (i.e. in a symmetric way)
        def apply_b(bb, AA=AA.copy(), dofs=rows, bcs=bcs, blocks=blocks):
            # Pick up the updated values
            values = np.array(
                sum((list(bc.get_boundary_values().values()) if isinstance(
                    bc, DirichletBC) else [] for bcs_sub in bcs
                     for bc in bcs_sub), []))
            # Taken from cbc.block
            c, Ac = AA.createVecs()

            c.zeroEntries()
            c.setValues(dofs, values)  # Forward
            c.assemble()

            AA.mult(c, Ac)  # Note: we work with the deep copy of A

            b = convert(bb)  # We cond't get view here ...
            b_vec = as_backend_type(b).vec()
            b_vec.axpy(-1, Ac)  # Elliminate
            b_vec.setValues(dofs, values)
            b_vec.assemble()

            bb *= 0  # ... so copy
            bb += as_block(b, blocks)

            return bb

    # Apply to monolithic
    len(rows) and AA.zeroRowsColumns(rows, diag=diag_val, x=x, b=bb)

    # Reasamble into block shape
    b = as_block(bb, blocks)
    A = as_block(AA, blocks)

    if has_wrapped_A: return A[0][0], b[0]

    if return_apply_b:
        return A, b, apply_b

    return A, b
示例#19
0
u = TrialFunction(V)
M = assemble(inner(u, v)*dx)

# With cbc.block
Q = FunctionSpace(mesh, 'CG', 1)
p, q = TrialFunction(Q), TestFunction(Q)
block = assemble(inner(p, q)*dx)
Mb = block_mat([[block, 0],
                [0, block]])

# The equivalence: let's see how the two operators act on representation of the same
# function. For cbc block the dofs of subspaces are serialized.
x_array = np.random.rand(V.dim())
x = Function(V).vector(); x.set_local(x_array); x.apply('insert')
# Reorder for cbc.block
xx_array = x_array[dofs_x]
xy_array = x_array[dofs_y]
xx = Function(Q).vector(); xx.set_local(xx_array); xx.apply('insert')
xy = Function(Q).vector(); xy.set_local(xy_array); xy.apply('insert')
xb = block_vec([xx, xy])

# Action
y = x.copy()
M.mult(x, y)
yx, yy = y.array()[dofs_x], y.array()[dofs_y]

yb = Mb*xb
ybx, yby = yb[0].array(), yb[1].array()

print np.linalg.norm(yx-ybx), np.linalg.norm(yy-yby)
示例#20
0
def lagrange_mixed(lmbda, mu, f, h, mesh, Z=None):
    '''
    Solves 

        -div(sigma) = f in  Omega
            sigma.n = h on  boundary

    where sigma(u) = 2*mu*eps(u) + lambda*div(u)*I. The problem is reformulated by
    Lagrange multiplier nu to inforce orthogonality with the space of rigid
    motions. To get robustnes in lmbda solid pressure p = lambda*div u is introduced. 
    The system to be solved with MinRes is 

        P*[A C  B; *[u, = P*[L,
           C' D 0;   p,      0,
           B' 0 0]   nu]     0]

    with P a precondtioner. We run on series of meshes to show mesh independence
    of the solver.
    '''
    if not isinstance(mesh, Mesh):
        # NOTE: You can precompute the 'symbolic' basis and pass it here
        return [lagrange_mixed(lmbda, mu, f, h, mesh_) for mesh_ in mesh]
    
    # For cube
    V = VectorFunctionSpace(mesh, 'CG', 2)
    Q = FunctionSpace(mesh, 'CG', 1)

    u, v = TrialFunction(V), TestFunction(V)
    p, q = TrialFunction(Q), TestFunction(Q)

    # Strain
    epsilon = lambda u: sym(grad(u))
    # Stress
    gdim = mesh.geometry().dim()
    sigma = lambda u: 2*mu*epsilon(u) + lmbda*tr(epsilon(u))*Identity(gdim)
    a = 2*mu*inner(sym(grad(u)), sym(grad(v)))*dx

    A = assemble(a)

    c = inner(div(v), p)*dx
    C = assemble(c)

    d = -(inner(p, q)/Constant(lmbda))*dx
    D = assemble(d)

    m = inner(u, v)*dx
    M = assemble(m)

    # NOTE: Avoiding use of Q space in the assembly - dense blocks!
    X = VectorFunctionSpace(mesh, 'R', 0, dim=6)
    Zh = rigid_motions.RMBasis(V, X, Z)  # L^2 orthogonal
    B = M*Zh

    # System operator
    AA = block_mat([[A,                  C, B], 
                    [block_transpose(C), D, 0],
                    [block_transpose(B), 0, 0]])

    # Right hand side
    L = inner(f, v)*dx + inner(h, v)*ds
    b0 = assemble(L)
    b1 = assemble(inner(Constant(0), q)*dx)
    # Equivalent to assemble(inner(Constant((0, )*6), q)*dx) but cheaper
    b2 = Function(X).vector()
    bb = block_vec([b0, b1, b2])

    # Block diagonal preconditioner
    IV = assemble(a + m)
    IQ = assemble(inner(p, q)*dx)
    IX = rigid_motions.identity_matrix(X)
    BB = block_mat([[AMG(IV), 0,              0], 
                    [0,       AMG(IQ),        0],
                    [0,       0,            IX]])

    # Solve, using random initial guess
    x0 = AA.create_vec()
    [as_backend_type(xi).vec().setRandom() for xi in x0]

    AAinv = MinRes(AA, precond=BB, initial_guess=x0, maxiter=120, tolerance=1E-8,
                   show=2, relativeconv=True)

    x = AAinv*bb

    # # Functions from coefficients
    # # uh = Function(V, x[0])     # Displacement
    # # ph = Function(Q, x[1])     # Solid pressure
    # # nuh = Zh.rigid_motion(x[2])  # Function in V

    niters = len(AAinv.residuals) - 1
    assert niters < 120

    P = rigid_motions.Projector(Zh)

    P*x0[0]  # to get orthogonality

    if MPI.rank(mesh.mpi_comm()) == 0:
        print '\033[1;37;31m%s\033[0m' % ('Orthogonality %g' % max(P.alphas))
        pass

    return V.dim() + Q.dim() + 6, niters
示例#21
0
 def block_vec(self):
     '''A block vec that is the coefficients of the function'''
     return block_vec(self.vectors())
示例#22
0
    def create_vec(self, dim=1):
        if dim == 1:
            return block_vec([Function(Wi).vector() for Wi in self.W])

        x = self.create_vec(dim=1)
        return self*x
示例#23
0
def apply_bc(A, b, bcs, diag_val=1.):
    '''
    Apply block boundary conditions to block system A, b    
    '''
    if not any(bcs): return A, b
    
    # Allow for A, b be simple matrices. To proceed we wrap them as
    # block objects
    has_wrapped_A = False
    if not isinstance(A, block_mat):
        A = block_mat([[A]])
        has_wrapped_A = True

    if b is None:
        b = A.create_vec()
    
    if not isinstance(b, block_vec):
        assert has_wrapped_A
        b = block_vec([b])
        bcs = [bcs]

    # block boundary conditions is a list with bcs for each block of A, b
    assert len(A) == len(b) == len(bcs)

    bcs_ = []
    for bc in bcs:
        assert isinstance(bc, (DirichletBC, list))
        if isinstance(bc, DirichletBC):
            bcs_.append([bc])
        else:
            bcs_.append(bc)
    bcs = bcs_

    if not bcs or not any(bcs): return A, b

    # Obtain a monolithic matrix
    AA, bb = map(convert, (A, b))
    # PETSc guys
    AA, bb = as_backend_type(AA).mat(), as_backend_type(bb).vec()

    # We want to make a monotlithic matrix corresponding to function sp ace
    # where the spaces are serialized
    
    # Break apart for block
    offsets = [0]
    for bi in b:
        offsets.append(offsets[-1] + bi.size())

    rows = []
    x_values = []
    # Each bc in the group has dofs numbered only wrt to its space.
    # We're after global numbering
    for shift, bcs_sub in zip(offsets, bcs): 
        for bc in bcs_sub:
            # NOTE: bcs can be a dict or DirichletBC in which case we extract
            # the dict
            if isinstance(bc, DirichletBC): bc = bc.get_boundary_values()
            # Dofs and values for rhs
            rows.extend(shift + np.array(bc.keys(), dtype='int32'))
            x_values.extend(bc.values())
            
    rows = np.hstack(rows)
    x_values = np.array(x_values)

    x = bb.copy()
    x.zeroEntries()
    x.setValues(rows, x_values)

    # Apply to monolithic
    len(rows) and AA.zeroRowsColumns(rows, diag=diag_val, x=x, b=bb)

    blocks = []
    for first, last in zip(offsets[:-1], offsets[1:]):
        blocks.append(PETSc.IS().createStride(last-first, first, 1))

    # Reasamble
    comm = mpi_comm_world()
    b = [PETSc.Vec().createWithArray(bb.getValues(block), comm=comm) for block in blocks]
    for bi in b:
        bi.assemblyBegin()
        bi.assemblyEnd()
    b = block_vec(map(PETScVector, b))

    # PETSc 3.7.x
    try:
        AA.getSubMatrix
        A = [[PETScMatrix(AA.getSubMatrix(block_row, block_col)) for block_col in blocks]
             for block_row in blocks]
    # NOTE: 3.8+ does not ahve getSubMatrix, there is getLocalSubMatrix
    # but cannot get that to work - petsc error 73. So for now everything
    # is done with scipy    
    except AttributeError:
        AA = csr_matrix(AA.getValuesCSR()[::-1], shape=AA.size)

        A = [[numpy_to_petsc(AA[block_row.array, :][:, block_col.array]) for block_col in blocks]
             for block_row in blocks]
    # Block mat
    A = block_mat(A)

    if has_wrapped_A: return A[0][0], b[0]
    
    return A, b
示例#24
0
 def block_vec(self):
     '''A block vec that is the coefficients of the function'''
     return block_vec(self.vectors())
示例#25
0
# With cbc.block
Q = FunctionSpace(mesh, 'CG', 1)
p, q = TrialFunction(Q), TestFunction(Q)
block00 = assemble(inner(p.dx(0), q.dx(0))*dx)
block01 = assemble(inner(p.dx(1), q.dx(0))*dx)
block10 = assemble(inner(p.dx(0), q.dx(1))*dx)
block11 = assemble(inner(p.dx(1), q.dx(1))*dx)
Mb = block_mat([[block00, block01],
                [block10, block11]])

# The equivalence: let's see how the two operators act on representation of the same
# function. For cbc block the dofs of subspaces are serialized.
x_array = np.random.rand(V.dim())
x = Function(V).vector(); x.set_local(x_array); x.apply('insert')
# Reorder for cbc.block
xx_array = x_array[dofs_x]
xy_array = x_array[dofs_y]
xx = Function(Q).vector(); xx.set_local(xx_array); xx.apply('insert')
xy = Function(Q).vector(); xy.set_local(xy_array); xy.apply('insert')
xb = block_vec([xx, xy])

# Action
y = x.copy()
M.mult(x, y)
yx, yy = y.array()[dofs_x], y.array()[dofs_y]

yb = Mb*xb
ybx, yby = yb[0].array(), yb[1].array()

print np.linalg.norm(yx-ybx), np.linalg.norm(yy-yby)
示例#26
0
def lagrange_primal(lmbda, mu, f, h, mesh, Z=None):
    '''
    Solves 

        -div(sigma) = f in  Omega
            sigma.n = h on  boundary

    where sigma(u) = 2*mu*eps(u) + lambda*div(u)*I. The problem is reformulated by
    Lagrange multiplier p to inforce orthogonality with the space of rigid
    motions. The system to be solved with MinRes is 

        P*[A  B;*[u; = P*[L,
           B'  ]  p]      0]

    with P a precondtioner. We run on series of meshes to show mesh independence
    of the solver.
    '''
    if not isinstance(mesh, Mesh):
        # NOTE: You can precompute the 'symbolic' basis and pass it here
        return [lagrange_primal(lmbda, mu, f, h, mesh_) for mesh_ in mesh]

    # For cube
    V = VectorFunctionSpace(mesh, 'CG', 1)
    u, v = TrialFunction(V), TestFunction(V)
    # Strain
    epsilon = lambda u: sym(grad(u))
    # Stress
    gdim = mesh.geometry().dim()
    sigma = lambda u: 2 * mu * epsilon(u) + lmbda * tr(epsilon(u)) * Identity(
        gdim)
    # Energy of elastic deformation
    a = inner(sigma(u), epsilon(v)) * dx
    A = assemble(a)
    # Mass matrix for B
    m = inner(u, v) * dx
    M = assemble(m)

    # NOTE: Avoiding use of Q space in the assembly - dense blocks!
    Q = VectorFunctionSpace(mesh, 'R', 0, dim=6)
    Zh = rigid_motions.RMBasis(V, Q, Z)  # L^2 orthogonal
    B = M * Zh

    # System operator
    AA = block_mat([[A, B], [block_transpose(B), 0]])

    # Right hand side
    L = inner(f, v) * dx + inner(h, v) * ds
    b0 = assemble(L)
    # Equivalent to assemble(inner(Constant((0, )*6), q)*dx) but cheaper
    b1 = Function(Q).vector()
    bb = block_vec([b0, b1])

    # Block diagonal preconditioner
    AM = assemble(a + m)
    I = rigid_motions.identity_matrix(Q)
    BB = block_mat([[AMG(AM), 0], [0, I]])

    # Solve, using random initial guess
    x0 = AA.create_vec()
    [as_backend_type(xi).vec().setRandom() for xi in x0]

    AAinv = MinRes(AA,
                   precond=BB,
                   initial_guess=x0,
                   maxiter=100,
                   tolerance=1E-8,
                   show=2,
                   relativeconv=True)

    x = AAinv * bb

    # Functions from coefficients
    # uh = Function(V, x[0])     # Displacement
    # zh = Zh.rigid_motion(x[1])  # Function in V

    niters = len(AAinv.residuals) - 1
    assert niters < 100

    P = rigid_motions.Projector(Zh)
    P * x[0]  # to get orthogonality
    if MPI.rank(mesh.mpi_comm()) == 0:
        print '\033[1;37;31m%s\033[0m' % ('Orthogonality %g' % max(P.alphas))

    return V.dim() + 6, niters
示例#27
0
        return [vec.inner(v) for v in self]


# --------------------------------------------------------------------

if __name__ == '__main__':
    from dolfin import *
    from block import block_vec
    import numpy as np

    mesh = UnitSquareMesh(32, 32)
    V = FunctionSpace(mesh, 'CG', 1)
    W = [V, FunctionSpace(mesh, 'CG', 2)]

    x = block_vec([
        interpolate(Constant(1), V).vector(),
        interpolate(Constant(2), V).vector()
    ])

    Z = BlockNullspace(W)
    Z.add_vector(x)
    assert len(Z) == 1

    x = block_vec([0, interpolate(Constant(3), V).vector()])
    Z.add_vector(x)
    assert len(Z) == 2

    y = block_vec([
        interpolate(Constant(1), V).vector(),
        interpolate(Constant(1), V).vector()
    ])
    y = Z.orthogonalize(y)
示例#28
0
 def matvec(self, b):
     '''Extract'''
     return block_vec([b[index] for index in self.indices])