Esempio n. 1
0
def main(n):
    '''Solves grad-div problem in 2d with HypreAMS preconditioning'''
    # Exact solution
    x, y = sp.symbols('x[0] x[1]')

    u = sp.sin(pi * x * (1 - x) * y * (1 - y))

    sp_div = lambda f: f[0].diff(x, 1) + f[1].diff(y, 1)

    sp_grad = lambda f: sp.Matrix([f.diff(x, 1), f.diff(y, 1)])

    sigma = sp_grad(u)
    f = -sp_div(sigma) + u

    sigma_expr, u_expr, f_expr = list(map(as_expression, (sigma, u, f)))

    # The discrete problem
    mesh = UnitSquareMesh(n, n)

    V = FunctionSpace(mesh, 'RT', 1)
    Q = FunctionSpace(mesh, 'DG', 0)
    W = (V, Q)

    sigma, u = list(map(TrialFunction, W))
    tau, v = list(map(TestFunction, W))

    a00 = inner(sigma, tau) * dx
    a01 = inner(div(tau), u) * dx
    a10 = inner(div(sigma), v) * dx
    a11 = -inner(u, v) * dx

    L0 = inner(Constant((0, 0)), tau) * dx
    L1 = inner(-f_expr, v) * dx

    AA = block_assemble([[a00, a01], [a10, a11]])
    bb = block_assemble([L0, L1])

    # b00 = inner(sigma, tau)*dx + inner(div(sigma), div(tau))*dx
    # B00 = LU(assemble(b00))
    B00 = HypreAMS(V)

    b11 = inner(u, v) * dx
    B11 = LumpedInvDiag(assemble(b11))

    BB = block_mat([[B00, 0], [0, B11]])

    AAinv = MinRes(AA, precond=BB, tolerance=1e-10, maxiter=500, show=2)

    # Compute solution
    sigma_h, u_h = AAinv * bb
    sigma_h, u_h = Function(V, sigma_h), Function(Q, u_h)

    niters = len(AAinv.residuals) - 1
    # error = sqrt(errornorm(sigma_expr, sigma_h, 'Hdiv', degree_rise=1)**2 +
    #              errornorm(u_expr, u_h, 'L2', degree_rise=1)**2)

    hmin = mesh.mpi_comm().tompi4py().allreduce(mesh.hmin(), pyMPI.MIN)
    error = 1.

    return hmin, V.dim() + Q.dim(), niters, error
Esempio n. 2
0
    print(clog.header())
    for i in range(5):
        n = 4*2**i
        mesh = UnitSquareMesh(n, n)
        facet_f = MeshFunction('size_t', mesh, 1, 0)
        [subdomain.mark(facet_f, tag) for tag, subdomain in mms['subdomains'].items()]
        
        a, L, W, bcs = setup_problem(facet_f, mms, flux_deg=args.flux_degree)

        A, b = map(ii_assemble, (a, L))
        A, b = apply_bc(A, b, bcs)

        B = setup_preconditioner(W, facet_f, mms, flux_deg=args.flux_degree, hs_block=args.hs)
        
        wh = ii_Function(W)
        Ainv = MinRes(A, precond=B, tolerance=1E-10, show=0)
        # NOTE: assigning from block_vec
        wh.vector()[:] = ii_convert(Ainv*b)

        sigmah, uh, ph = wh
        niters = len(Ainv.residuals)

        clog.add((sigmah, uh, ph, niters))
        print(clog.report_last(with_name=False))

    eoc = 0.95 if args.flux_degree == 1 else 1.95
    # Match increamental and lstsq rate
    passed = all(clog[var].get_rate()[0] > eoc for var in ('sigma', 'u', 'p'))
    passed = passed and all(clog[var].get_rate()[1] > eoc for var in ('sigma', 'u', 'p'))
    passed = passed and all(count < 40 for count in clog['niters'])
    
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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)
Esempio n. 7
0
L1 = inner(f, c) * dx

from block import block_assemble, block_bc, block_mat
from block.iterative import MinRes
from block.algebraic.petsc import ML, Cholesky

# lhs
AA = block_assemble([[a00, a01, a02], [a10, a11, a12], [a20, a21, 0]])
# rhs
b = block_assemble([L0, L1, 0])

# Collect boundary conditions
bcs = [[bc0, bc1], [], []]
block_bc(bcs, True).apply(AA).apply(b)

b22 = inner(p, q) * dx
B22 = assemble(b22)
# Possible action of preconditioner
BB = block_mat([[ML(AA[0, 0]), 0, 0], [0, Cholesky(AA[1, 1]), 0],
                [0, 0, Cholesky(B22)]])

AAinv = MinRes(AA, precond=BB, tolerance=1E-10, maxiter=500)
U, B, P = AAinv * b

p = Function(Q)
p.vector()[:] = P

# Plot solution
plot(p)
interactive()