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
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
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]
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)
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]
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)))
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]
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)
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))
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)
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))
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))
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))
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)
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)
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]
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())
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
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)
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
def block_vec(self): '''A block vec that is the coefficients of the function''' return block_vec(self.vectors())
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
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
# 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)
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
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)
def matvec(self, b): '''Extract''' return block_vec([b[index] for index in self.indices])