示例#1
0
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])
示例#2
0
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])
示例#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
示例#4
0
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
示例#5
0
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
示例#6
0
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])
示例#7
0
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])
示例#8
0
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)])
示例#9
0
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])
示例#11
0
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])
示例#12
0
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])
示例#13
0
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])
示例#15
0
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])
示例#16
0
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
示例#18
0
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])
示例#19
0
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])))
示例#20
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]
示例#21
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
示例#22
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
示例#23
0
# 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.
#
示例#24
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)
示例#25
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
示例#26
0
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
示例#27
0
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
示例#28
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
示例#29
0
        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')