Пример #1
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
Пример #2
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])
Пример #3
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
Пример #4
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])
Пример #5
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, 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 = LumpedInvDiag(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])
Пример #6
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
Пример #7
0
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])
Пример #8
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])
Пример #9
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
Пример #10
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)
Пример #11
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])
Пример #12
0
    def calculate_v(self, state, dt):
        """
    Calculate :math:`\\vec{v}` according to the algorithm introduced above.

    *Arguments*
      state (:class:`State`)
        The simulation state containing the magnetization configuration.
      dt (:class:`float`)
        The time-step size.
    """

        with Timer("Calculate v"):
            # Initialize mesh and function spaces
            VV = state.VectorFunctionSpace()
            VS = state.FunctionSpace()

            v = TrialFunction(VV)
            w = TestFunction(VV)

            #######################################################
            # Forms
            #######################################################
            f_ex  =  Constant(-2.0 / state.scale**2 * Constants.gamma / Constants.mu0) \
                     * state.material.Aex / state.material.ms

            # Bilinear form for LLG
            a = state.material.alpha * dot(v, w) * state.dx('magnetic')
            a += dot(cross(state.m, v), w) * state.dx('magnetic')
            L = zero()

            # Effective field contributions
            for term in self.terms:
                L += term.form_rhs(state, w) * state.dx('magnetic')
                a += term.form_lhs(
                    state, w,
                    Constant(0.5 * dt) * v) * state.dx('magnetic')

            #######################################################
            # Assembly
            #######################################################

            # assemble llg
            A = assemble(a, keep_diagonal=True)
            A.ident_zeros()
            b = assemble(L)

            # assemble constraint
            #B  = DofAssembler.assemble(ScalarProductMatrix(VS, VV, state.m))
            #BT = DofAssembler.assemble(TransScalarProductMatrix(VS, VV, state.m))

            v = TestFunction(state.FunctionSpace())
            u = TrialFunction(state.VectorFunctionSpace())
            B = assemble(v * dot(state.m, u) * dP)

            v = TestFunction(state.VectorFunctionSpace())
            u = TrialFunction(state.FunctionSpace())
            BT = assemble(u * dot(state.m, v) * dP)

            # assemble block matrix
            AA = block_mat([[A, BT], [B, 0]])
            bb = block_vec([b, BT.create_vec()])

            Ap = ILU(A)
            Bp = InvDiag(collapse(B * LumpedInvDiag(A) * BT))
            AAp = block_mat([[Ap, BT], [0, -Bp]]).scheme('sgs')

            #######################################################
            # Solve the system
            #######################################################
            AAinv = BiCGStab(AA, precond=AAp, tolerance=1e-8 / dt)
            u, foo = AAinv * bb

            v = Function(VV)
            v.vector()[:] = u

            return v
  def calculate_v(self, state, dt):
    """
    Calculate :math:`\\vec{v}` according to the algorithm introduced above.

    *Arguments*
        state (:class:`State`)
            The simulation state containing the magnetization configuration.
        dt (:class:`float`)
            The time-step size.
    """


    with Timer("Calculate v"):
      cache = self._assemble_cache
      if cache.requires_update(state):

        if isinstance(state.mesh, WrappedMesh):
          raise Exception("Use simple mesh with shell instead of WrappedMesh.")

        # setup function spaces
        cache.VV = VectorFunctionSpace(state.mesh, "CG", 1)
        cache.VD = FunctionSpace(state.mesh, "CG", self.demag_order)
        cache.VL = FunctionSpace(state.mesh, "CG", 1)

        # setup some stuff for the demag field
        transformation_order = 2 if (self.demag_order == 1) else 2
        shell_width = state.mesh.coordinates().max(axis=0).min() / 2.0
        sample_size = state.mesh.coordinates().max(axis=0) - shell_width
        cache.gx = MetricMatrix.create_for_cube(sample_size, 0, transformation_order)
        cache.gy = MetricMatrix.create_for_cube(sample_size, 1, transformation_order)
        cache.gz = MetricMatrix.create_for_cube(sample_size, 2, transformation_order)

      # Test and Trial Functions
      u     = TrialFunction(cache.VD)
      v     = TrialFunction(cache.VV)
      sigma = TrialFunction(cache.VL)

      w1    = TestFunction(cache.VD)
      w2    = TestFunction(cache.VV)
      w3    = TestFunction(cache.VL)

      #######################################################
      # Define weak forms
      #######################################################
      f_ex = (- 2.0 * state.material.Aex * Constants.gamma) / \
             (Constants.mu0 * state.material.ms * state.scale**2)

      # Bilinear form
      a12  = - 0.5 * Constant(dt) * inner(v, grad(w1)) * state.dx('magnetic')                            # Demag Field, Implicit RHS
      a11  = inner(grad(w1), grad(u))            * state.dx('all') \
           + inner(grad(w1), grad(u))            * state.dx(1000)  \
           + inner(grad(w1), cache.gx * grad(u)) * state.dx(1001)  \
           + inner(grad(w1), cache.gy * grad(u)) * state.dx(1002)  \
           + inner(grad(w1), cache.gz * grad(u)) * state.dx(1003)
      a21  = - Constant(state.material.ms * Constants.gamma) * inner(grad(u), w2) * state.dx('magnetic') # Demag
      a22  = Constant(state.material.alpha) * dot(v, w2) * state.dx('magnetic')                          # LLG
      a22 += dot(cross(state.m, v), w2) * state.dx('magnetic')
      a22 += - 0.5 * Constant(dt * f_ex) * Dx(v[i],j) * Dx(w2[i],j) * state.dx('magnetic')               # Exchange

      # Linear form
      L1 = inner(state.m, grad(w1)) * state.dx('magnetic')                                               # Demag Field
      L2 = Constant(f_ex) * Dx(state.m[i],j) * Dx(w2[i],j) * state.dx('magnetic')                        # Exchange

      for term in self.terms:                                                                            # Additional Terms
        L2  += term.form_rhs(state, w2) * state.dx('magnetic')
        #a22 += term.form_lhs(state, w2, Constant(0.5 * dt) * v) * state.dx('magnetic')

      #######################################################
      # Define boundary conditions
      #######################################################
      bc1 = DirichletBC(cache.VD, Constant(0.0), DomainBoundary())

      #######################################################
      # Assemble the system
      #######################################################
      A11, b1 = assemble_system(a11, L1, bc1)
      A12 = assemble(a12)
      A21 = assemble(a21)
      A22 = assemble(a22, keep_diagonal=True); A22.ident_zeros()

      v23 = TestFunction(state.VectorFunctionSpace())
      u23 = TrialFunction(state.FunctionSpace())
      A23 = assemble(u23 * dot(state.m, v23) * dP)

      v32 = TestFunction(state.FunctionSpace())
      u32 = TrialFunction(state.VectorFunctionSpace())
      A32 = assemble(v32 * dot(state.m, u32) * dP)

      #A23 = DofAssembler.assemble(TransScalarProductMatrix(cache.VL, cache.VV, state.m))
      #A32 = DofAssembler.assemble(ScalarProductMatrix(cache.VL, cache.VV, state.m))

      b2  = assemble(L2)

      #######################################################
      # Schur Ansatz
      #######################################################
      A11p   = ILU(A11)
      A11inv = ConjGrad(A11, precond=A11p)
      z1     = A11inv * b1

      S11    = A22 - A21 * A11inv * A12
      S      = block_mat([[S11, A23],
                          [A32,   0]])

      Sp11   = ILU(A22)
      Sp22   = InvDiag(collapse(A32 * LumpedInvDiag(A22) * A23))
      Sp     = block_mat([[Sp11, A23],
                          [0, -Sp22]]).scheme('sgs')

      Sinv   = BiCGStab(S, precond=Sp, tolerance=1e-8/dt)

      b      = block_vec([b2 - A21*z1, 0])
      v, _   = Sinv * b

      return Function(cache.VV, v)