def setup_preconditioner(W, which, eps): ''' This is a block diagonal preconditioner based on Hdiv x L2 x (H0.5 \cap sqrt(eps)*L2) or ? ''' from block.algebraic.petsc import LU from block.algebraic.petsc import LumpedInvDiag from hsmg import HsNorm S, V, Q = W # Hdiv sigma, tau = TrialFunction(S), TestFunction(S) b00 = inner(div(sigma), div(tau))*dx + inner(sigma, tau)*dx # Inverted exactly B00 = LU(ii_assemble(b00)) # L2 u, v = TrialFunction(V), TestFunction(V) b11 = inner(u, v)*dx # Inverted by BoomerAMG B11 = LumpedInvDiag(ii_assemble(b11)) # The Q norm via spectral B22 = inverse(HsNorm(Q, s=0.5) + eps*HsNorm(Q, s=0.0))# The norm is inverted exactly 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 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): '''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 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, 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=None): ''' This is a block diagonal preconditioner based on H1 x H^{-0.5} ''' from xii.linalg.matrix_utils import as_petsc from numpy import hstack from petsc4py import PETSc from hsmg import HsNorm assert len(eps) == 2 mu_value, lmbda_value = eps V, Q = W # H1 u, v = TrialFunction(V), TestFunction(V) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx A = as_backend_type(assemble(b00)) # Attach rigid deformations to A # Functions Z = [ interpolate(Constant((1, 0)), V), interpolate(Constant((0, 1)), V), interpolate(Expression(('x[1]', '-x[0]'), degree=1), V) ] # The basis Z = VectorSpaceBasis([z.vector() for z in Z]) Z.orthonormalize() A.set_nullspace(Z) A.set_near_nullspace(Z) A = as_petsc(A) # Setup the preconditioner in petsc pc = PETSc.PC().create() pc.setType(PETSc.PC.Type.HYPRE) pc.setOperators(A) # Other options opts = PETSc.Options() opts.setValue('pc_hypre_boomeramg_cycle_type', 'V') opts.setValue('pc_hypre_boomeramg_relax_type_all', 'symmetric-SOR/Jacobi') opts.setValue('pc_hypre_boomeramg_coarsen_type', 'Falgout') pc.setFromOptions() # Wrap for cbc.block B00 = BlockPC(pc) # The Q norm via spectral Qi = Q.sub(0).collapse() B11 = inverse(VectorizedOperator(HsNorm(Qi, s=-0.5), Q)) return block_diag_mat([B00, B11])
def setup_preconditioner(W, which, eps=None): ''' This is a block diagonal preconditioner based on Hdiv x H0.5''' from block.algebraic.petsc import LU from hsmg import HsNorm S, Q = W sigma, tau = TrialFunction(S), TestFunction(S) # Hdiv b00 = inner(div(sigma), div(tau)) * dx + inner(sigma, tau) * dx B00 = LU(ii_assemble(b00)) # Exact # H0.5 B11 = HsNorm(Q, s=0.5)**-1 # The norm is inverted exactly return block_diag_mat([B00, B11])
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=None): ''' This is a block diagonal preconditioner based on H1 x L2 x H^{-0.5} ''' from block.algebraic.petsc import LumpedInvDiag from xii.linalg.matrix_utils import as_petsc from numpy import hstack from petsc4py import PETSc from hsmg import HsNorm V, Q, Y = W # H1 u, v = TrialFunction(V), TestFunction(V) b00 = inner(grad(u), grad(v)) * dx + inner(u, v) * dx # NOTE: since interpolation is broken with MINI I don't interpolate # here the RM basis to attach the vectros to matrix A = assemble(b00) A = as_petsc(A) # Setup the preconditioner in petsc pc = PETSc.PC().create() pc.setType(PETSc.PC.Type.HYPRE) pc.setOperators(A) # Other options opts = PETSc.Options() opts.setValue('pc_hypre_boomeramg_cycle_type', 'V') opts.setValue('pc_hypre_boomeramg_relax_type_all', 'symmetric-SOR/Jacobi') opts.setValue('pc_hypre_boomeramg_coarsen_type', 'Falgout') pc.setFromOptions() # Wrap for cbc.block B00 = BlockPC(pc) p, q = TrialFunction(Q), TestFunction(Q) B11 = LumpedInvDiag(assemble(inner(p, q) * dx)) # The Y norm via spectral Yi = Y.sub(0).collapse() B22 = inverse(VectorizedOperator(HsNorm(Yi, s=-0.5), Y)) 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])
from hsmg import HsNorm import numpy as np mesh = UnitSquareMesh(10, 10) VV = FunctionSpace(mesh, MixedElement([FiniteElement('Lagrange', triangle, 1)] * 3)) u, v = TrialFunction(VV), TestFunction(VV) M = assemble(inner(u, v) * dx) x = M.create_vec() x.set_local(np.random.rand(x.local_size())) y = M * x V = FunctionSpace(mesh, 'CG', 1) u, v = TrialFunction(V), TestFunction(V) Mj = assemble(inner(u, v) * dx) # Should match M X = VectorizedOperator(Mj, VV) y0 = X * x print(x.norm('l2'), (y - y0).norm('linf')) I = HsNorm(V, s=0.5) II = VectorizedOperator(I, VV) foo = II * x x0 = inverse(II) * foo print((x - x0).norm('linf'))
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