def setup_preconditioner(W, which, eps): # This is best on H1 x H1 x L2 spaces where the Discacciati proces # well posedness from block.algebraic.petsc import AMG # The following settings seem not so bad for GMRES # # -ksp_rtol 1E-6 # -ksp_monitor_true_residual none # -ksp_type gmres # -ksp_gmres_restart 30 # -ksp_gmres_modifiedgramschmidt 1 u1, p, p1 = map(TrialFunction, W) v1, q, q1 = map(TestFunction, W) b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx B00 = AMG(ii_assemble(b00)) b11 = inner(grad(p), grad(q)) * dx + inner(p, q) * dx B11 = AMG(ii_assemble(b11)) b22 = inner(p1, q1) * dx B22 = AMG(ii_assemble(b22)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps): ''' This is a block diagonal preconditioner based on H1 x H1 x (H-0.5 \cap \sqrt{eps-1}*L2) or ... ''' # NOTE for eps large the fractional term is expected to dominte from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from hsmg import HsNorm V1, V2, Q = W if which == 0: # H1 print '\tUsing H1 x H1 x (sqrt(1./%g)*L2 \cap H-0.5) preconditioner' % eps u1, v1 = TrialFunction(V1), TestFunction(V1) b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx # Inverted by BoomerAMG B00 = AMG(ii_assemble(b00)) u2, v2 = TrialFunction(V2), TestFunction(V2) b11 = inner(grad(u2), grad(v2)) * dx + inner(u2, v2) * dx # Inverted by BoomerAMG B11 = AMG(ii_assemble(b11)) # The Q norm via spectral, the norm is inverted exactly B22 = inverse((HsNorm(Q, s=-0.5) + (eps**-1) * HsNorm(Q, s=0.0))) else: print '\tUsing (H1 \cap H0.5) x (H1 \cap H0.5) x sqrt(%g)*L2 preconditioner' % eps iface = Q.mesh() dxGamma = dx(domain=iface) # H1 u1, v1 = TrialFunction(V1), TestFunction(V1) Tu1, Tv1 = Trace(u1, iface), Trace(v1, iface) b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx + inner( Tu1, Tv1) * dxGamma # Inverted by BoomerAMG B00 = AMG(ii_convert(ii_assemble(b00))) u2, v2 = TrialFunction(V2), TestFunction(V2) Tu2, Tv2 = Trace(u2, iface), Trace(v2, iface) b11 = inner(grad(u2), grad(v2)) * dx + inner(u2, v2) * dx + inner( Tu2, Tv2) * dxGamma # Inverted by BoomerAMG B11 = AMG(ii_convert(ii_assemble(b11))) # The Q norm via spectral p, q = TrialFunction(Q), TestFunction(Q) b22 = Constant(1. / eps) * inner(p, q) * dxGamma B22 = LumpedInvDiag(ii_assemble(b22)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps): from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag, LU from hsmg import HsNorm u1, ub, p1, u2, p2, lambda_ = map(TrialFunction, W) v1, vb, q1, v2, q2, beta_ = map(TestFunction, W) # Neither is super spectacular # Completely block diagonal preconditioner with H1 on the bubble space if which == 0: b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx B00 = AMG(ii_assemble(b00)) bbb = inner(grad(ub), grad(vb)) * dx + inner(ub, vb) * dx Bbb = LumpedInvDiag(ii_assemble(bbb)) b11 = inner(p1, q1) * dx B11 = AMG(ii_assemble(b11)) b22 = inner(div(u2), div(v2)) * dx + inner(u2, v2) * dx B22 = LU(ii_assemble(b22)) b33 = inner(p2, q2) * dx B33 = LumpedInvDiag(ii_assemble(b33)) B44 = inverse(HsNorm(W[-1], s=0.5)) return block_diag_mat([B00, Bbb, B11, B22, B33, B44]) # Monolithic for MINI velocity b = [[0, 0], [0, 0]] b[0][0] = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx b[0][1] = inner(grad(ub), grad(v1)) * dx + inner(ub, v1) * dx b[1][0] = inner(grad(u1), grad(vb)) * dx + inner(u1, vb) * dx b[1][1] = inner(grad(ub), grad(vb)) * dx + inner(ub, vb) * dx # Make into a monolithic matrix B00 = AMG(ii_convert(ii_assemble(b))) b11 = inner(p1, q1) * dx B11 = AMG(ii_assemble(b11)) b22 = inner(div(u2), div(v2)) * dx + inner(u2, v2) * dx B22 = LU(ii_assemble(b22)) b33 = inner(p2, q2) * dx B33 = LumpedInvDiag(ii_assemble(b33)) B44 = inverse(HsNorm(W[-1], s=0.5)) # So this is a 5x5 matrix BB = block_diag_mat([B00, B11, B22, B33, B44]) # But the preconditioner has to be 6x6; reduce 6 to 6 by comcat # first two, rest stays same R = ReductionOperator([2, 3, 4, 5, 6], W) return (R.T) * BB * R
def cannonical_riesz_map(W, mms, params, AA): '''Riesz map wrt. inner product of alpha*H1 x beta*H1 x H-0.5''' V3, V1, Q = W # Extact Vi norms from system V3_inner = AA[0][0] V1_inner = AA[1][1] Q_inner = HsNorm(Q, s=-0.5) mms.normals.append(Q_inner) B = block_diag_mat([AMG(V3_inner), AMG(V1_inner), Q_inner**-1]) return B
def setup_preconditioner(W, which, eps): '''The preconditioner''' from block.algebraic.petsc import AMG, LumpedInvDiag from block import block_transpose from hsmg import HsNorm u, ub, p, lambda_ = map(TrialFunction, W) v, vb, q, beta_ = map(TestFunction, W) # A block diagonal preconditioner if which == 0: b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx B00 = AMG(ii_assemble(b00)) b11 = inner(grad(ub), grad(vb)) * dx + inner(ub, vb) * dx B11 = LumpedInvDiag(ii_assemble(b11)) b22 = inner(p, q) * dx B22 = AMG(ii_assemble(b22)) M = W[-1] Mi = M.sub(0).collapse() B33 = inverse(VectorizedOperator(HsNorm(Mi, s=-0.5), M)) return block_diag_mat([B00, B11, B22, B33]) # Preconditioner monolithic in Stokes velocity 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 # Make into a monolithic matrix B00 = AMG(ii_convert(ii_assemble(b))) b11 = inner(p, q) * dx B11 = AMG(ii_assemble(b11)) M = W[-1] Mi = M.sub(0).collapse() B22 = inverse(VectorizedOperator(HsNorm(Mi, s=-0.5), M)) # So this is a 3x3 matrix BB = block_diag_mat([B00, B11, B22]) # But the preconditioner has to be 4x4 R = ReductionOperator([2, 3, 4], W) return (R.T) * BB * R
def cannonical_riesz_map_AMG(W, mms, params): '''AMG inverse''' V1, V, Q = W kappa = Constant(params.kappa) # Outer, H1_0 u, v = TrialFunction(V1), TestFunction(V1) outer_mesh = V1.mesh() subdomains = mms.subdomains[0] # facet_f = MeshFunction('size_t', outer_mesh, outer_mesh.topology().dim() - 1, 0) [ subd.mark(facet_f, i) for i, subd in enumerate(map(CompiledSubDomain, subdomains), 1) ] bcs = [ DirichletBC(V1, Constant(0), facet_f, i) for i in range(1, 1 + len(subdomains)) ] V1_norm, _ = assemble_system( inner(grad(u), grad(v)) * dx, inner(Constant(0), v) * dx, bcs) # Inner u, v = TrialFunction(V), TestFunction(V) V_norm = assemble(inner(grad(u), grad(v)) * dx + inner(u, v) * dx) # Multiplier on the boundary # Fractional part Hs = HsNorm(Q, s=[(1, -0.5), (params.eps, 0.0)]) Hs = Hs**-1 # L2 part # epsilon = Constant(params.eps) # p, q = TrialFunction(Q), TestFunction(Q) # m = epsilon*inner(p, q)*dx # M = assemble(m) # Q_norm = mat_add(Hs, M) # return block_diag_mat([V1_norm, V_norm, Q_norm]) return block_diag_mat([AMG(V1_norm), AMG(V_norm), Hs])
def setup_preconditioner(W, p_constant): '''Just an idea H1 x H1 x (Hs \cap p_constant L2)''' from block.algebraic.petsc import AMG from hsmg import HsNorm u3, u, p = map(TrialFunction, W) v3, v, q = map(TestFunction, W) b00 = inner(grad(u3), grad(v3)) * dx + inner(u3, v3) * ds B00 = assemble(b00) b11 = inner(grad(u), grad(v)) * dx + inner(u, v) * ds B11 = assemble(b11) B22 = inverse(HsNorm(W[-1], s=-0.5) + p_constant * HsNorm(W[-1], s=0.0)) return block_diag_mat([AMG(B00), AMG(B11), B22])
def setup_preconditioner(W, AA, bcs): '''H1 x L2''' # I don't want symgrad here because of AMG V, Q, R = W u, v = TrialFunction(V), TestFunction(V) # Seminorm due to bcs aV = inner(grad(u), grad(v))*dx AV, _ = assemble_system(aV, inner(Constant((0, 0)), v)*dx, bcs[0]) p, q = TrialFunction(Q), TestFunction(Q) # Pressure mass matrix is L2 aQ = inner(p, q)*dx AQ = assemble(aQ) AR = AA[2][2] return block_diag_mat([AMG(AV), AMG(AQ), AMG(AR)])
def setup_preconditioner(W, radius, which): '''Wishful thinking using mostly H1 norms on the spaces''' from block.algebraic.petsc import AMG # For radius = 0.1 both preconditioner perform almost the same. # However, they get worse when radius -> 0 so the name of the game # will be to make things robust w.r.t radius. u3, u = list(map(TrialFunction, W)) v3, v = list(map(TestFunction, W)) # There is a 3d/1d/iface/bdry conductiity; made up k3d, k1d, kG, kbdry = list(map(Constant, K_CONSTANTS)) b00 = inner(grad(u3), grad(v3)) * dx + inner(u3, v3) * dx # For H1 norm we are done if which == 'H1': B00 = AMG(assemble(b00)) b11 = Constant(pi * radius**2) * inner(grad(u), grad(v)) * dx + inner( u, v) * dx B11 = AMG(assemble(b11)) return block_diag_mat([B00, B11]) # Add the coupling term if which == 'A': gamma = W[-1].mesh() dxG = Measure('dx', domain=gamma) circle = Circle(radius=radius, degree=10) Pi_u3, Pi_v3 = (Average(x, gamma, circle) for x in (u3, v3)) b00 += inner(Constant(2 * pi * radius) * Pi_u3, Pi_v3) * dxG B00 = AMG(ii_convert(ii_assemble(b00))) b11 = Constant(pi * radius**2) * inner(grad(u), grad(v)) * dx + inner( u, v) * dx B11 = AMG(assemble(b11)) return block_diag_mat([B00, B11]) return None
def setup_preconditioner(W, which, eps): '''The preconditioner''' from block.algebraic.petsc import AMG, LumpedInvDiag from hsmg import HsNorm u, p, lambda_ = map(TrialFunction, W) v, q, beta_ = map(TestFunction, W) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx B00 = AMG(ii_assemble(b00)) b11 = inner(p, q) * dx B11 = AMG(ii_assemble(b11)) M = W[-1] Mi = M.sub(0).collapse() B22 = inverse(VectorizedOperator(HsNorm(Mi, s=-0.5), M)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps): ''' TODO ''' from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from hsmg import HsNorm V1, V2, Q = W gamma_mesh = Q.mesh() dxGamma = Measure('dx', domain=gamma_mesh) u1, u2 = map(TrialFunction, (V1, V2)) v1, v2 = map(TestFunction, (V1, V2)) Tu1, Tu2 = map(lambda x: Trace(x, gamma_mesh), (u1, u2)) Tv1, Tv2 = map(lambda x: Trace(x, gamma_mesh), (v1, v2)) if eps > 1: b00 = Constant(eps) * inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx B00 = ii_assemble(b00) else: b00 = Constant(eps) * inner(grad(u1), grad(v1)) * dx + inner( u1, v1) * dx + inner(Tu1, Tv1) * dxGamma B00 = ii_convert(ii_assemble(b00)) B00 = AMG(B00) b11 = inner(grad(u2), grad(v2)) * dx + inner(u2, v2) * dx # Inverted by BoomerAMG B11 = AMG(ii_assemble(b11)) if eps > 1: B22 = inverse(HsNorm(Q, s=-0.5)) else: B22 = inverse(HsNorm(Q, s=0.5)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps): '''The preconditioner''' from block.algebraic.petsc import AMG from hsmg import HsNorm u, p, lambda_ = map(TrialFunction, W) v, q, beta_ = map(TestFunction, W) b00 = Constant(eps) * inner(grad(u), grad(v)) * dx + inner(u, v) * dx B00 = AMG(ii_assemble(b00)) b11a = Constant(1. / eps) * inner(p, q) * dx b11b = inner(grad(p), grad(q)) * dx bcs = DirichletBC(W[1], Constant(0), 'on_boundary') B11b, _ = assemble_system(b11b, inner(Constant(0), q) * dx, bcs) B11 = AMG(ii_assemble(b11a)) + AMG(B11b) B22 = inverse((1. / eps) * HsNorm(W[-1], s=-0.5)) return block_diag_mat([B00, B11, B22])
def setup_preconditioner(W, which, eps=None): ''' This is a block diagonal preconditioner based on H1 x H-0.5 or (H1 \cap H0.5) x L2 ''' from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from hsmg import HsNorm V, Q = W if which == 0: print 'Using H1 x H-0.5 preconditioner' # H1 u, v = TrialFunction(V), TestFunction(V) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx # Inverted by BoomerAMG B00 = AMG(ii_assemble(b00)) # The Q norm via spectral B11 = inverse(HsNorm(Q, s=-0.5)) # The norm is inverted exactly else: print 'Using (H1 \cap H0.5) x L2 preconditioner' bdry = Q.mesh() dxGamma = dx(domain=bdry) # Cap space u, v = TrialFunction(V), TestFunction(V) Tu, Tv = Trace(u, bdry), Trace(v, bdry) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx + inner( Tu, Tv) * dxGamma # Inverted by BoomrAMG B00 = AMG(ii_convert(ii_assemble(b00))) # We don't have to work so hard for multiplier p, q = TrialFunction(Q), TestFunction(Q) B11 = LumpedInvDiag(ii_assemble(inner(p, q) * dx)) return block_diag_mat([B00, B11])
def setup_preconditioner(W, which, eps): from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag, LU from hsmg import HsNorm u1, p1, u2, p2, lambda_ = map(TrialFunction, W) v1, q1, v2, q2, beta_ = map(TestFunction, W) # This is not spectacular b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx B00 = AMG(ii_assemble(b00)) b11 = inner(p1, q1) * dx B11 = AMG(ii_assemble(b11)) b22 = inner(div(u2), div(v2)) * dx + inner(u2, v2) * dx B22 = LU(ii_assemble(b22)) b33 = inner(p2, q2) * dx B33 = LumpedInvDiag(ii_assemble(b33)) B44 = inverse(HsNorm(W[-1], s=0.5)) return block_diag_mat([B00, B11, B22, B33, B44])
def setup_preconditioner(W, which, eps=None): '''This is a block diagonal preconditioner based on H1 x R^1 norm''' from block.algebraic.petsc import AMG V, Q = W # H1 u, v = TrialFunction(V), TestFunction(V) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx # Inverted by BoomerAMG B00 = AMG(ii_assemble(b00)) # Easy B11 = 1 B22 = 1 return block_diag_mat([B00, B11, B22])
def energy(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 considering a complemented strain energy (for which rigid motions are not tranparent). The system to be solved with CG as P*[A+E]*[u] = P'*b with P a precondtioner. We run on series of meshes to show mesh independence of the solver. ''' if not isinstance(mesh, Mesh): # Precompute the 'symbolic' basis mesh0 = first(mesh) Z = rigid_motions.rm_basis(mesh0) return [energy(lmbda, mu, f, h, mesh_, Z) 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 = A + B * block_transpose(B) # Right hand side L = inner(f, v) * dx + inner(h, v) * ds # Orthogonalize P = rigid_motions.Projector(Zh) b = assemble(L) b0 = block_transpose(P) * b # Preconditioner AM = assemble(a + m) BB = AMG(AM) # Solve, using random initial guess x0 = AA.create_vec() as_backend_type(x0).vec().setRandom() AAinv = ConjGrad(AA, precond=BB, initial_guess=x0, maxiter=100, tolerance=1E-8, show=2, relativeconv=True) x = AAinv * b0 # Functions from coefficients # uh = Function(V, x) # Displacement niters = len(AAinv.residuals) - 1 assert niters < 100 P * x # 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(), niters
def nonlinear_babuska(N, u_exact, p_exact): '''MMS for the problem''' mesh = UnitSquareMesh(N, N) bmesh = BoundaryMesh(mesh, 'exterior') V = FunctionSpace(mesh, 'CG', 1) Q = FunctionSpace(bmesh, 'CG', 1) W = (V, Q) up = ii_Function(W) u, p = up # Split v, q = list(map(TestFunction, W)) Tu, Tv = (Trace(x, bmesh) for x in (u, v)) dxGamma = Measure('dx', domain=bmesh) # Nonlinearity nl = lambda u: (Constant(2) + u)**2 f_exact = -div(nl(u) * grad(u)) g_exact = u f = interpolate(Expression(f_exact, subs={u: u_exact}, degree=1), V) h = interpolate(Expression(g_exact, subs={u: u_exact}, degree=4), Q) # The nonlinear functional F = [ inner(nl(u) * grad(u), grad(v)) * dx + inner(p, Tv) * dxGamma - inner(f, v) * dx, inner(Tu, q) * dxGamma - inner(h, q) * dxGamma ] dF = block_jacobian(F, up) # Setup H1 x H-0.5 preconditioner only once B0 = ii_derivative(inner(grad(u), grad(v)) * dx + inner(u, v) * dx, u) # The Q norm via spectral B1 = inverse(HsNorm(Q, s=-0.5)) # The norm is inverted exactly # Preconditioner B = block_diag_mat([AMG(ii_assemble(B0)), B1]) # Newton eps = 1.0 tol = 1.0E-10 niter = 0. maxiter = 25 OptDB = PETSc.Options() # Since later b gets very small making relative too much work OptDB.setValue('ksp_atol', 1E-6) OptDB.setValue('ksp_monitor_true_residual', None) dup = ii_Function(W) x_vec = as_backend_type(dup.vector()).vec() n_kspiters = [] while eps > tol and niter < maxiter: niter += 1. A, b = (ii_assemble(x) for x in (dF, F)) ksp = PETSc.KSP().create() ksp.setType('minres') ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED) ksp.setOperators(ii_PETScOperator(A)) ksp.setPC(ii_PETScPreconditioner(B, ksp)) ksp.setFromOptions() ksp.solve(as_petsc_nest(b), x_vec) niters = ksp.getIterationNumber() + 1 n_kspiters.append(niters) eps = sqrt(sum(x.norm('l2')**2 for x in dup.vectors())) print('\t%d |du| = %g | niters %d' % (niter, eps, niters)) # FIXME: Update for i in range(len(W)): up[i].vector().axpy(-1, dup[i].vector()) return up, n_kspiters
def setup_preconditioner(W, which, eps=None): ''' Mirror the structure of preconditioner proposed in Robust preconditioners for PDE-constrained optimization with limited observations; Mardal and Nielsen and Nordaas, BIT 2017 or Schoeberl and Zulehner's Symmetric indefinite preconditioners for saddle point problems with applications to PDE constrained optimization problems ''' from block.algebraic.petsc import AMG from block.algebraic.petsc import LumpedInvDiag from xii.linalg.convert import collapse print('WHICH is', which) (Q, V, B) = W p, u, lmbda = list(map(TrialFunction, W)) q, v, beta = list(map(TestFunction, W)) bmesh = BoundaryMesh(Q.mesh(), 'exterior') Tu = Trace(u, bmesh) Tv = Trace(v, bmesh) # The line integral dxGamma = Measure('dx', domain=bmesh) # Nielsen if which == 0: b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) M_bdry = ii_convert(ii_assemble(inner(Tu, Tv) * dxGamma)) # H2 norm with H1 elements A = ii_assemble(inner(grad(v), grad(u)) * dx + inner(v, u) * dx) # From dual to nodal M = LumpedInvDiag(ii_assemble(inner(u, v) * dx)) # The whole matrix to be inverted is then (second term is H2 approx) B11 = collapse(M_bdry + eps * A * M * A) # And the inverse B11 = AMG(B11, parameters={'pc_hypre_boomeramg_cycle_type': 'W'}) b22 = Constant(1. / eps) * inner(lmbda, beta) * dx B22 = LumpedInvDiag(ii_assemble(b22)) # SZ else: print('X') # eps*L2 b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) # L2 \cap eps H1 a = inner(u, v) * ds + Constant(eps) * (inner(grad(v), grad(u)) * dx + inner(v, u) * dx) B11 = AMG(assemble(a)) # (1./eps)*L2 \cap 1./sqrt(eps)H1 a = Constant(1./eps)*inner(beta, lmbda)*dx + \ Constant(1./sqrt(eps))*(inner(grad(beta), grad(lmbda))*dx + inner(beta, lmbda)*dx) B22 = AMG(assemble(a)) return block_diag_mat([B00, B11, B22])
a11 = (dot(u,v) + k*inner(grad(u),grad(v)))*dx a12 = div(v)*p*dx a21 = div(u)*q*dx L1 = dot(f, v)*dx #bcs = block_bc([DirichletBC(V, BoundaryFunction(degree=1), Boundary()), None], True) AA = block_assemble([[a11, a12], [a21, 0 ]]) bb = block_assemble([L1, 0]) # bcs.apply(AA).apply(bb) [[A, B], [C, _]] = AA M = assemble(kinv*p*q*dx) bcsQ = DirichletBC(Q, Constant(0), 'on_boundary') L, _ = assemble_system(dot(grad(p),grad(q))*dx, inner(Constant(0), q)*dx, bcsQ) prec = block_mat([[AMG(A), 0 ], [0, AMG(L)+AMG(M)]]) xx = AA.create_vec() xx.randomize() AAinv = CGN(AA, precond=prec, initial_guess=xx, tolerance=1e-11, show=0) x = AAinv*bb e = AAinv.eigenvalue_estimates() print("N=%d K=%.3g" % (N, sqrt(e[-1]/e[0])))
solve = 'gmres' # If the system is to be solved directly there are some extra steps if solve == 'lu': # Make the system monolithic A, b = map(ii_convert, (A, b)) LUSolver(A).solve(wh.vector(), b) # Iterative else: # Here for simplicity cbc.block from block.iterative import LGMRES from block.algebraic.petsc import AMG # A mock up preconditioner is based on inverse of the diagonal block # using AMG to approx inv B = block_diag_mat([AMG(A[0][0]), AMG(A[1][1])]) Ainv = LGMRES(A, precond=B, tolerance=1E-10, show=1) x = Ainv * b for i in range(len(x)): wh[i].vector()[:] = x[i] # Hope for no NaN print wh[0].vector().norm('l2') print wh[1].vector().norm('l2') # Output File('uh3d.pvd') << wh[0] File('uh1d.pvd') << wh[1]
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 cannonical_riesz_map(W, mms, params, AA, Z): '''Riesz map wrt. inner product of alpha*H1 x beta*H1 x H-0.5''' B = cannonical_inner_product(W, mms, params, AA, Z) B = block_diag_mat([AMG(B[0][0]), AMG(B[1][1]), LU(B[2][2])]) return B
# Define variational forms (one per block) a11 = dot(sigma, tau) * dx a12 = div(tau) * u * dx a21 = div(sigma) * v * dx L2 = -f * v * dx AA = block_assemble([[a11, a12], [a21, 0]]) bb = block_assemble([0, L2]) bcs.apply(AA).apply(bb) # Extract the individual submatrices [[A, B], [C, _]] = AA Ap = AMG(A) # Create an approximate inverse of L=C*B using inner Richardson iterations L = C * B Lp = Richardson(L, precond=0.5, iter=40, name='L^') # Alternative b: Use inner Conjugate Gradient iterations. Not completely safe, # but faster (and does not require damping). # #Lp = ConjGrad(L, maxiter=40, name='L^') # Alternative c: Calculate the matrix product, so that a regular preconditioner # can be used. The "collapse" function collapses a composed operator into a # single matrix. For larger problems, and in particular on parallel computers, # this is a very expensive operation --- but here it works fine. #
def mini_block(n): '''Just check MMS''' mesh = UnitSquareMesh(n, n) # Just approx f_space = VectorFunctionSpace(mesh, 'DG', 1) h_space = TensorFunctionSpace(mesh, 'DG', 1) u_int = interpolate(u_exact, VectorFunctionSpace(mesh, 'CG', 2)) p_int = interpolate(p_exact, FunctionSpace(mesh, 'CG', 2)) f = project(-div(grad(u_int)) + grad(p_int), f_space) h = project(-p_int * Identity(2) + grad(u_int), h_space) # ---------------- V = VectorFunctionSpace(mesh, 'Lagrange', 1) Vb = VectorFunctionSpace(mesh, 'Bubble', 3) Q = FunctionSpace(mesh, 'Lagrange', 1) W = [V, Vb, Q] u, ub, p = list(map(TrialFunction, W)) v, vb, q = list(map(TestFunction, W)) n = FacetNormal(mesh) a = [[0] * len(W) for _ in range(len(W))] a[0][0] = inner(grad(u), grad(v)) * dx a[0][2] = -inner(div(v), p) * dx a[2][0] = -inner(div(u), q) * dx a[1][1] = inner(grad(ub), grad(vb)) * dx a[1][2] = -inner(div(vb), p) * dx a[2][1] = -inner(div(ub), q) * dx a[0][1] = inner(grad(v), grad(ub)) * dx a[1][0] = inner(grad(vb), grad(u)) * dx # NOTE: bubbles don't contribute to surface L = [ inner(dot(h, n), v) * ds + inner(f, v) * dx, inner(f, vb) * dx, inner(Constant(0), q) * dx ] # Bubbles don't have bcs on the surface bcs = [[DirichletBC(W[0], u_exact, 'near(x[0], 0)')], [], []] AA = block_assemble(a) bb = block_assemble(L) block_bc(bcs, True).apply(AA).apply(bb) # Preconditioner B0 = AMG(AA[0][0]) H1_Vb = inner(grad(ub), grad(vb)) * dx + inner(ub, vb) * dx B1 = LumpedInvDiag(assemble(H1_Vb)) L2_Q = assemble(inner(p, q) * dx) B2 = LumpedInvDiag(L2_Q) BB = block_mat([[B0, 0, 0], [0, B1, 0], [0, 0, B2]]) x0 = AA.create_vec() x0.randomize() AAinv = MinRes(AA, precond=BB, tolerance=1e-10, maxiter=500, relativeconv=True, show=2, initial_guess=x0) # Compute solution u, ub, p = AAinv * bb uh_ = Function(V, u) uhb = Function(Vb, ub) ph = Function(Q, p) uh = Sum([uh_, uhb], degree=1) return uh, ph, sum(Wi.dim() for Wi in W)
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
def solve_problem(ncells, eps, solver_params): '''Optim problem on [0, 1]^2''' # Made up f = Expression('x[0] + x[1]', degree=1) mesh = UnitSquareMesh(*(ncells, ) * 2) bmesh = BoundaryMesh(mesh, 'exterior') Q = FunctionSpace(mesh, 'DG', 0) V = FunctionSpace(mesh, 'CG', 1) B = FunctionSpace(mesh, 'CG', 1) W = [Q, V, B] p, u, lmbda = list(map(TrialFunction, W)) q, v, beta = list(map(TestFunction, W)) Tu = Trace(u, bmesh) Tv = Trace(v, bmesh) # The line integral dxGamma = Measure('dx', domain=bmesh) a = [[0] * len(W) for _ in range(len(W))] a[0][0] = Constant(eps) * inner(p, q) * dx a[0][2] = inner(q, lmbda) * dx # We put zero on the diagonal temporarily and then replace by # the fractional laplacian a[1][1] = 0 a[1][2] = inner(grad(v), grad(lmbda)) * dx + inner(v, lmbda) * dx a[2][0] = inner(p, beta) * dx a[2][1] = inner(grad(u), grad(beta)) * dx + inner(u, beta) * dx L = [ inner(Constant(0), q) * dx, inner(Constant(0), v) * dx, # Same replacement idea here inner(Constant(0), beta) * dx ] # All but (1, 1) and 1 are final AA, bb = list(map(ii_assemble, (a, L))) # Now I want and operator which corresponds to (Tv, (-Delta^{0.5} T_u))_bdry TV = FunctionSpace(bmesh, 'CG', 1) T = PETScMatrix(trace_mat_no_restrict(V, TV)) # The fractional laplacian nodal->dual fDelta = HsNorm(TV, s=0.5) # This should be it A11 = block_transpose(T) * fDelta * T # Now, while here we can also comute the rhs contribution # (Tv, (-Delta^{0.5}, f)) f_vec = interpolate(f, V).vector() b1 = A11 * f_vec bb[1] = b1 AA[1][1] = A11 wh = ii_Function(W) # Direct solve if not solver_params: AAm, bbm = list(map(ii_convert, (AA, bb))) LUSolver('umfpack').solve(AAm, wh.vector(), bbm) return wh, -1 # Magne like precond if False: # Preconditioner like in the L2 case but with L2 bdry replaced b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) H1 = ii_assemble(inner(grad(v), grad(u)) * dx + inner(v, u) * dx) # From dual to nodal R = LumpedInvDiag(ii_assemble(inner(u, v) * dx)) # The whole matrix to be inverted is then (second term is H2 approx) B11 = collapse(A11 + eps * H1 * R * H1) # And the inverse B11 = AMG(B11, parameters={'pc_hypre_boomeramg_cycle_type': 'W'}) b22 = Constant(1. / eps) * inner(lmbda, beta) * dx B22 = LumpedInvDiag(ii_assemble(b22)) # A bit like SZ else: b00 = Constant(eps) * inner(p, q) * dx B00 = LumpedInvDiag(ii_assemble(b00)) # L2 \cap eps H1 H1 = assemble( Constant(eps) * (inner(grad(v), grad(u)) * dx + inner(v, u) * dx)) B11 = AMG(collapse(A11 + H1)) # (1./eps)*L2 \cap 1./sqrt(eps)H1 a = Constant(1./eps)*inner(beta, lmbda)*dx + \ Constant(1./sqrt(eps))*(inner(grad(beta), grad(lmbda))*dx + inner(beta, lmbda)*dx) B22 = AMG(assemble(a)) BB = block_diag_mat([B00, B11, B22]) # Want the iterations to start from random (iterative) wh.block_vec().randomize() # Default is minres if '-ksp_type' not in solver_params: solver_params['-ksp_type'] = 'minres' opts = PETSc.Options() for key, value in solver_params.items(): opts.setValue(key, None if value == 'none' else value) ksp = PETSc.KSP().create() ksp.setOperators(ii_PETScOperator(AA)) ksp.setPC(ii_PETScPreconditioner(BB, ksp)) ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED) ksp.setFromOptions() ksp.solve(as_petsc_nest(bb), wh.petsc_vec()) niters = ksp.getIterationNumber() return wh, niters
def dd_solve(n, mms, params, tol): '''Domain decomposition for Laplacian using AMG''' base_mesh = UnitSquareMesh(mpi_comm_self(), *(n, )*2) # Marking inside = ['(0.25-tol<x[0])', '(x[0] < 0.75+tol)', '(0.25-tol<x[1])', '(x[1] < 0.75+tol)'] inside = CompiledSubDomain(' && '.join(inside), tol=1E-10) mesh_f = MeshFunction('size_t', base_mesh, base_mesh.topology().dim(), 0) inside.mark(mesh_f, 1) inner_mesh = SubMesh(base_mesh, mesh_f, 1) # Inside outer_mesh = SubMesh(base_mesh, mesh_f, 0) # Ouside interface_mesh = BoundaryMesh(inner_mesh, 'exterior') subdomains = mms.subdomains[0] # facet_f = MeshFunction('size_t', outer_mesh, outer_mesh.topology().dim()-1, 0) [subd.mark(facet_f, i) for i, subd in enumerate(map(CompiledSubDomain, subdomains), 1)] # Spaces V0 = FunctionSpace(outer_mesh, 'CG', 1) V1 = FunctionSpace(inner_mesh, 'CG', 1) W = [V0, V1] u0, u1 = map(TrialFunction, W) v0, v1 = map(TestFunction, W) Tu0, Tv0 = (Trace(f, interface_mesh) for f in (u0, v0)) Tu1, Tv1 = (Trace(f, interface_mesh) for f in (u1, v1)) u0h, u1h = map(Function, W) # Mark subdomains of the interface mesh (to get source terms therein) subdomains = mms.subdomains[1] # marking_f = MeshFunction('size_t', interface_mesh, interface_mesh.topology().dim(), 0) [subd.mark(marking_f, i) for i, subd in enumerate(map(CompiledSubDomain, subdomains), 1)] # The line integral n = OuterNormal(interface_mesh, [0.5, 0.5]) dx_ = Measure('dx', domain=interface_mesh, subdomain_data=marking_f) # Data kappa, epsilon = map(Constant, (params.kappa, params.eps)) # Source for domains, outer boundary data, source for interface f1, f, gBdry, gGamma, hGamma = mms.rhs Tu0h, Tu1h = Trace(u0h, interface_mesh), Trace(u1h, interface_mesh) # Only it has bcs V0_bcs = [DirichletBC(V0, gi, facet_f, i) for i, gi in enumerate(gBdry, 1)] grad_uh1 = Function(VectorFunctionSpace(inner_mesh, 'DG', 0)) Tgrad_uh1 = Trace(grad_uh1, interface_mesh) a0 = kappa*inner(grad(u0), grad(v0))*dx # + (1./epsilon)*inner(Tu0, Tv0)*dx_ L0 = inner(f1, v0)*dx # L0 += sum((1./epsilon)*inner(gi, Tv0)*dx_(i) for i, gi in enumerate(gGamma, 1)) # L0 += (1./epsilon)*inner(Tu1h, Tv0)*dx_ L0 += -inner(dot(Tgrad_uh1, n), Tv0)*dx_ a1 = inner(grad(u1), grad(v1))*dx + (1./epsilon)*inner(Tu1, Tv1)*dx_ L1 = inner(f, v1)*dx L1 += -sum((1./epsilon)*inner(gi, Tv1)*dx_(i) for i, gi in enumerate(gGamma, 1)) L1 += (1./epsilon)*inner(Tu0h, Tv1)*dx_ parameters = {'pc_hypre_boomeramg_max_iter': 4} A0_inv, A1_inv = None, None u0h_, u1h_ = Function(V0), Function(V1) solve_time, assemble_time = 0., 0. rel = lambda x, x0: sqrt(abs(assemble(inner(x-x0, x-x0)*dx)))/sqrt(abs(assemble(inner(x, x)*dx))) k = 0 converged = False errors = [] Q = FunctionSpace(interface_mesh, 'CG', 1) q, q0 = Function(Q), Function(Q) while not converged: k += 1 u0h_.vector().set_local(u0h.vector().get_local()) # Outer u1h_.vector().set_local(u1h.vector().get_local()) # Inner q0.vector().set_local(q.vector().get_local()) # Solve inner A1, b1 = map(ii_convert, map(ii_assemble, (a1, L1))) now = time() if A1_inv is None: # Proxy because ii_assemble is slover assemble(inner(grad(u1), grad(v1))*dx + inner(u1, v1)*ds) A1_inv = AMG(A1, parameters=parameters) u1h.vector()[:] = A1_inv*b1 #solve(A1, u1h.vector(), b1) dt1 = time() - now Tgrad_uh1.vector()[:] = get_P0_gradient(u1h).vector() # Solve outer A0, b0 = map(ii_convert, map(ii_assemble, (a0, L0))) A0, b0 = apply_bc(A0, b0, V0_bcs) # solve(A0, u0h.vector(), b0) now = time() if A0_inv is None: A0_inv = AMG(A0, parameters=parameters) _, _ = assemble_system(inner(grad(u0), grad(v0))*dx, inner(Constant(0), v0)*dx, V0_bcs) u0h.vector()[:] = A0_inv*b0 dt0 = time() - now solve_time += dt0 + dt1 # This is just approx now = time() assemble_time += 0 #time() - now flux_error = flux_continuity(u1h, u0h, interface_mesh, n, kappa2=kappa) rel0 = rel(u0h, u0h_) rel1 = rel(u1h, u1h_) q.vector()[:] = get_diff(u0h, u1h).vector() rel_v = rel(q, q0) print k, '->', u1h.vector().norm('l2'), u0h.vector().norm('l2'), flux_error, rel0, rel1, tol, rel_v, (dt0, dt1, assemble_time) errors.append(rel_v) converged = errors[-1] < tol or k > 200 return (u0h, u1h), (solve_time, assemble_time), (flux_error, k), errors
def setup_preconditioner(W, which, eps): from block.algebraic.petsc import AMG from xii.linalg.block_utils import ReductionOperator, RegroupOperator # This is best on H1 x H1 x L2 spaces where the Discacciati proces # well posedness if which == 0: # The following settings seem not so bad for GMRES # -ksp_rtol 1E-6 # -ksp_monitor_true_residual none # -ksp_type gmres # -ksp_gmres_restart 30 # -ksp_gmres_modifiedgramschmidt 1 u1, p1, p = map(TrialFunction, W) v1, q1, q = map(TestFunction, W) b00 = inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx B00 = AMG(ii_assemble(b00)) b11 = inner(p1, q1) * dx B11 = AMG(ii_assemble(b11)) b22 = inner(grad(p), grad(q)) * dx + inner(p, q) * dx B22 = AMG(ii_assemble(b22)) return block_diag_mat([B00, B11, B22]) # System without coupling: Solve Poisson and Stokes individually iface_domain = BoundaryMesh(W[-1].mesh(), 'exterior') M = FunctionSpace(iface_domain, 'DG', 0) u1, p1, p = map(TrialFunction, W) v1, q1, q = map(TestFunction, W) dxGamma = Measure('dx', domain=iface_domain) # We will need traces of the functions on the boundary Tu1, Tv1 = map(lambda x: Trace(x, iface_domain), (u1, v1)) Tp, Tq = map(lambda x: Trace(x, iface_domain), (p, q)) n = OuterNormal(iface_domain, [0.5, 0.5]) # Outer of Darcy n1 = -n # Outer of Stokes # Get tangent vector tau1 = Constant(((0, -1), (1, 0))) * n1 stokes = [[0] * 2 for i in range(2)] stokes[0][0] = Constant(2)*inner(sym(grad(u1)), sym(grad(v1)))*dx +\ inner(u1, v1)*dx +\ inner(dot(Tu1, tau1), dot(Tv1, tau1))*dxGamma stokes[0][1] = -inner(p1, div(v1)) * dx stokes[1][0] = -inner(q1, div(u1)) * dx if which == 1: B0 = UMFPACK_LU(ii_convert(ii_assemble(stokes))) poisson = inner(p, q) * dx + inner(grad(p), grad(q)) * dx B1 = AMG(assemble(poisson)) # 2x2 B = block_diag_mat([B0, B1]) # Need an adapter for 3 vectors R = ReductionOperator([2, 3], W) return R.T * B * R from block.iterative import MinRes # Solve stokes with Minres A0 = ii_assemble(stokes) # The preconditioner B = block_diag_mat([ AMG(ii_assemble(inner(grad(u1), grad(v1)) * dx + inner(u1, v1) * dx)), AMG(ii_assemble(inner(p1, q1) * dx)) ]) # Approx A0_inv = MinRes(A0, precond=B, relativeconv=True, tolerance=1E-5) B0 = block_op_from_action(action=lambda b, A0_inv=A0_inv: A0_inv * b, create_vec=lambda i, A0=A0: A0.create_vec(i)) poisson = inner(p, q) * dx + inner(grad(p), grad(q)) * dx B1 = AMG(assemble(poisson)) # 2x2 B = block_diag_mat([B0, B1]) # Need an adapter for 3 vectors R = RegroupOperator([2, 3], W) return R.T * B * R
N = int(N) mesh = UnitSquareMesh(N, N) V = FunctionSpace(mesh, 'CG', 1) u = TrialFunction(V) v = TestFunction(V) bc = DirichletBC(V, Constant(0), 'on_boundary') a = inner(grad(u), grad(v)) * dx m = inner(u, v) * dx L = inner(Constant(1), v) * dx A, b = assemble_system(a, L, bc) timer = Timer('AMG') P = AMG(A) amg_time = timer.stop() timer = Timer('AMG_action') x = P * b amg_action = timer.stop() data.append([V.dim(), amg_time, amg_action]) print data[-1] data = np.array(data) print data np.savetxt('./data/py_%s@%s_%.2f_amg' % (mesh_, cpu_type(), mem_total()), data, header='size(A) time to construct P=AMG(A) and its action')