Beispiel #1
0
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])
Beispiel #2
0
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])])
Beispiel #3
0
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
Beispiel #4
0
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])
Beispiel #5
0
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])
Beispiel #6
0
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])
Beispiel #7
0
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)])
Beispiel #8
0
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])
Beispiel #11
0
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])])
Beispiel #12
0
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])])
Beispiel #13
0
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
Beispiel #14
0
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