def setup_preconditioner(W, facet_f, mms, flux_deg, hs_block): '''Preconditioner will be Riesz map H(div) x L^2 x H^{1/2}''' lm_tags, pressure_tags, flux_tags = (2, 4), (1, ), (3, ) S, V, Q = W sigma, u, p = map(TrialFunction, W) tau, v, q = map(TestFunction, W) # H(div) aS = inner(sigma, tau)*dx + inner(div(sigma), div(tau))*dx S_bcs = [DirichletBC(S, mms['flux'][tag], facet_f, tag) for tag in flux_tags] BS, _ = assemble_system(aS, inner(Constant((0, 0)), tau)*dx, S_bcs) # L^2 aV = inner(u, v)*dx BV = assemble(aV) # H^s norm bmesh = Q.mesh() facet_f = MeshFunction('size_t', bmesh, bmesh.topology().dim()-1, 0) CompiledSubDomain('near(x[0], 1)').mark(facet_f, 1) Q_bcs = [(facet_f, 1)] if hs_block == 'eig': BQ = HsEig(Q, s=0.5, bcs=Q_bcs) else: raise NotImplementedError return block_diag_mat([LU(BS), LU(BV), BQ**-1])
def cannonical_riesz_map(W, mms, params): '''Approx Riesz map w.r.t to H1 x Hdiv x L2''' from block.algebraic.petsc import LU, AMG # from weak_bcs.hypre_ams import HypreAMS B = cannonical_inner_product(W, mms, params) return block_diag_mat([LU(B[0][0]), LU(B[1][1])])
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 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 cannonical_riesz_map(W, mms, params): '''Exact 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([LU(V1_norm), LU(V_norm), Hs])
def cannonical_riesz_map(W, mms, params, AA): '''Exact Riesz map w.r.t to Hdiv x L2 x H^s''' V, Q, Y = W kappa1 = Constant(params.kappa) # Hdiv norm with piecewise conductivities mesh = V.mesh() cell_f = MeshFunction('size_t', mesh, mesh.topology().dim(), 0) # Mark [ CompiledSubDomain(subd, tol=1E-10).mark(cell_f, tag) for tag, subd in enumerate(mms.subdomains[2]) ] # 0 is outside and that is where we have kappa sigma, tau = TrialFunction(V), TestFunction(V) dX = Measure('dx', subdomain_data=cell_f) V_norm = assemble((1. / kappa1) * inner(sigma, tau) * dX(0) + inner(sigma, tau) * dX(1) + inner(div(sigma), div(tau)) * dX) p, q = TrialFunction(Q), TestFunction(Q) Q_norm = assemble(inner(p, q) * dx) # Multiplier on the boundary epsilon = Constant(params.eps) # Fractional part Hs = HsNorm(Y, s=[(1, 0.5), (1. / params.eps, 0.)]) # Weight Hs = Hs**-1 # L2 part #p, q = TrialFunction(Y), TestFunction(Y) #m = (1./epsilon)*inner(p, q)*dx #M = assemble(m) #Y_norm = mat_add(Hs, M) return block_diag_mat([LU(V_norm), LU(Q_norm), Hs])
def setup_preconditioner(W, i, mms, parameters, hs_block): '''Preconditioner is H1 x H1 x H-0.5 cap H-1''' _, facet_f_ = mms['get_geometry'](i) [V, V1, Q] = W # We have different meshIds facet_f = MeshFunction('size_t', V.mesh(), 1, 0) facet_f.array()[:] = facet_f_.array() u, u1, p = map(TrialFunction, W) v, v1, q = map(TestFunction, W) # Material parameters kappa, kappa1 = (Constant(parameters[key]) for key in ('kappa', 'kappa1')) aV = kappa * inner(grad(u), grad(v)) * dx V_bcs = [ DirichletBC(V, Constant(0), facet_f, tag) for tag, value in mms['dirichlet_omega'].items() ] BV, _ = assemble_system(aV, inner(Constant(0), v) * dx, V_bcs) aV1 = kappa1 * inner(grad(u1), grad(v1)) * dx V1_bcs = [DirichletBC(V1, mms['dirichlet_gamma'], 'on_boundary')] BV1, _ = assemble_system(aV1, inner(Constant(0), v1) * dx, V1_bcs) bmesh = Q.mesh() facet_f = MeshFunction('size_t', bmesh, bmesh.topology().dim() - 1, 0) DomainBoundary().mark(facet_f, 1) if hs_block == 'eig': Hs0 = Hs0Eig(Q, s=-0.5, kappa=1 / kappa, bcs=[(facet_f, 1)]).collapse() Hs1 = Hs0Eig(Q, s=-1.0, kappa=1 / kappa1, bcs=[(facet_f, 1)]).collapse() BQ = ii_convert(Hs0 + Hs1) return block_diag_mat([LU(BV), LU(BV1), LU(BQ)])
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, facet_f, mms, bc_setup, hs_block): '''Preconditioner will be a Riesz map wrt H1 x H^{-1/2} inner product''' # See the mms below for how the boundaries are marked # NOTE: which bcs meet LM boundary effects boundary conditions # on the multiplier space if bc_setup == 'dir_neu': lm_tags, dir_tags, neu_tags = (2, 4), (1, ), (3, ) elif bc_setup == 'dir': lm_tags, dir_tags, neu_tags = (2, 4), (1, 3), () else: lm_tags, dir_tags, neu_tags = (2, 4), (), (1, 3) [V, Q] = W u, p = map(TrialFunction, W) v, q = map(TestFunction, W) aV = inner(grad(u), grad(v))*dx if not dir_tags: # For Neumann case we need an invertible block for V aV += inner(u, v)*dx V_bcs = None else: # Boundary conditions; a list for each subspace V_bcs = [DirichletBC(V, mms['dirichlet'][tag], facet_f, tag) for tag in dir_tags] # H1 part BV, _ = assemble_system(aV, inner(Constant(0), v)*dx, V_bcs) # For LM we want Dirichlet where we meet the Dirichlet Boundary bmesh = Q.mesh() facet_f = MeshFunction('size_t', bmesh, bmesh.topology().dim()-1, 0) if bc_setup == 'dir_neu': CompiledSubDomain('near(x[0], 0)').mark(facet_f, 1) Q_bcs = [(facet_f, 1)] elif bc_setup == 'dir': # Both endpoints DomainBoundary().mark(facet_f, 1) Q_bcs = [(facet_f, 1)] else: Q_bcs = None if hs_block == 'eig': BQ = HsEig(Q, s=-0.5, bcs=Q_bcs) else: raise NotImplementedError return block_diag_mat([LU(BV), BQ**-1])
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 cannonical_riesz_map_AMG(W, mms, params): '''Hdiv AMG inverse''' B = cannonical_inner_product(W, mms, params) return block_diag_mat([HypreAMS(A=B[0][0], V=W[0]), LU(B[1][1])])
def wGamma_riesz_map(W, mms, params): '''Exact inverse''' B = wGamma_inner_product(W, mms, params) return block_diag_mat([LU(B[0][0]), LU(B[1][1])])
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
def dd_solve(n, mms, params, tol): '''Domain decomposition for Laplacian using LU''' 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 = LU(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 = LU(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