예제 #1
0
u, v = ufl.TrialFunction(U), ufl.TestFunction(U)


def free_end(x):
    """Marks the leftmost points of the cantilever"""
    return numpy.isclose(x[0], 48.0)


def left(x):
    """Marks left part of boundary, where cantilever is attached to wall"""
    return numpy.isclose(x[0], 0.0)


# Locate all facets at the free end and assign them value 1
free_end_facets = locate_entities_geometrical(mesh,
                                              1,
                                              free_end,
                                              boundary_only=True)
mt = dolfinx.mesh.MeshTags(mesh, 1, free_end_facets, 1)

ds = ufl.Measure("ds", subdomain_data=mt)

# Homogeneous boundary condition in displacement
u_bc = dolfinx.Function(U)
with u_bc.vector.localForm() as loc:
    loc.set(0.0)

# Displacement BC is applied to the left side
left_facets = locate_entities_geometrical(mesh, 1, left, boundary_only=True)
bdofs = locate_dofs_topological(U, 1, left_facets)
bc = dolfinx.fem.DirichletBC(u_bc, bdofs)
예제 #2
0
def test_assembly_ds_domains(mesh):
    V = dolfinx.FunctionSpace(mesh, ("CG", 1))
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)

    def bottom(x):
        return numpy.isclose(x[1], 0.0)

    def top(x):
        return numpy.isclose(x[1], 1.0)

    def left(x):
        return numpy.isclose(x[0], 0.0)

    def right(x):
        return numpy.isclose(x[0], 1.0)

    bottom_facets = locate_entities_geometrical(mesh,
                                                mesh.topology.dim - 1,
                                                bottom,
                                                boundary_only=True)
    bottom_vals = numpy.full(bottom_facets.shape, 1, numpy.intc)

    top_facets = locate_entities_geometrical(mesh,
                                             mesh.topology.dim - 1,
                                             top,
                                             boundary_only=True)
    top_vals = numpy.full(top_facets.shape, 2, numpy.intc)

    left_facets = locate_entities_geometrical(mesh,
                                              mesh.topology.dim - 1,
                                              left,
                                              boundary_only=True)
    left_vals = numpy.full(left_facets.shape, 3, numpy.intc)

    right_facets = locate_entities_geometrical(mesh,
                                               mesh.topology.dim - 1,
                                               right,
                                               boundary_only=True)
    right_vals = numpy.full(right_facets.shape, 6, numpy.intc)

    indices = numpy.hstack(
        (bottom_facets, top_facets, left_facets, right_facets))
    values = numpy.hstack((bottom_vals, top_vals, left_vals, right_vals))

    indices, pos = numpy.unique(indices, return_index=True)
    marker = dolfinx.mesh.MeshTags(mesh, mesh.topology.dim - 1, indices,
                                   values[pos])

    ds = ufl.Measure('ds', subdomain_data=marker, domain=mesh)

    w = dolfinx.Function(V)
    with w.vector.localForm() as w_local:
        w_local.set(0.5)

    # Assemble matrix
    a = w * ufl.inner(u, v) * (ds(1) + ds(2) + ds(3) + ds(6))
    A = dolfinx.fem.assemble_matrix(a)
    A.assemble()
    norm1 = A.norm()
    a2 = w * ufl.inner(u, v) * ds
    A2 = dolfinx.fem.assemble_matrix(a2)
    A2.assemble()
    norm2 = A2.norm()
    assert norm1 == pytest.approx(norm2, 1.0e-12)

    # Assemble vector
    L = ufl.inner(w, v) * (ds(1) + ds(2) + ds(3) + ds(6))
    b = dolfinx.fem.assemble_vector(L)
    b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    L2 = ufl.inner(w, v) * ds
    b2 = dolfinx.fem.assemble_vector(L2)
    b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    assert b.norm() == pytest.approx(b2.norm(), 1.0e-12)

    # Assemble scalar
    L = w * (ds(1) + ds(2) + ds(3) + ds(6))
    s = dolfinx.fem.assemble_scalar(L)
    s = mesh.mpi_comm().allreduce(s, op=MPI.SUM)
    L2 = w * ds
    s2 = dolfinx.fem.assemble_scalar(L2)
    s2 = mesh.mpi_comm().allreduce(s2, op=MPI.SUM)
    assert (s == pytest.approx(s2, 1.0e-12)
            and 2.0 == pytest.approx(s, 1.0e-12))
예제 #3
0
# and the part of the boundary on which the condition applies.
# This boundary part is identified with degrees of
# freedom in the function space to which we apply the boundary conditions.
# A method ``locate_dofs_geometrical`` is provided to extract the boundary
# degrees of freedom using a geometrical criterium.
# In our example, the function space is ``V``,
# the value of the boundary condition (0.0) can represented using a
# :py:class:`Function <dolfinx.functions.Function>` and the Dirichlet
# boundary is defined immediately above. The definition of the Dirichlet
# boundary condition then looks as follows: ::

# Define boundary condition on x = 0 or x = 1
u0 = Function(V)
u0.vector.set(0.0)
facets = locate_entities_geometrical(mesh, 1,
                                     lambda x: np.logical_or(x[0] < np.finfo(float).eps,
                                                             x[0] > 1.0 - np.finfo(float).eps),
                                     boundary_only=True)
bc = DirichletBC(u0, locate_dofs_topological(V, 1, facets))


# Next, we want to express the variational problem.  First, we need to
# specify the trial function :math:`u` and the test function :math:`v`,
# both living in the function space :math:`V`. We do this by defining a
# :py:class:`TrialFunction <dolfinx.functions.function.TrialFunction>`
# and a :py:class:`TestFunction
# <dolfinx.functions.function.TrialFunction>` on the previously defined
# :py:class:`FunctionSpace <dolfinx.functions.FunctionSpace>` ``V``.
#
# Further, the source :math:`f` and the boundary normal derivative
# :math:`g` are involved in the variational forms, and hence we must
# specify these.
예제 #4
0
    def amg_solve(N, method):
        # Elasticity parameters
        E = 1.0e9
        nu = 0.3
        mu = E / (2.0 * (1.0 + nu))
        lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu))

        # Stress computation
        def sigma(v):
            return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym(
                grad(v))) * Identity(2)

        # Define problem
        mesh = UnitSquareMesh(MPI.COMM_WORLD, N, N)
        V = VectorFunctionSpace(mesh, 'Lagrange', 1)
        bc0 = Function(V)
        with bc0.vector.localForm() as bc_local:
            bc_local.set(0.0)

        def boundary(x):
            return np.full(x.shape[1], True)

        facetdim = mesh.topology.dim - 1
        bndry_facets = locate_entities_geometrical(mesh, facetdim, boundary, boundary_only=True)

        bdofs = locate_dofs_topological(V.sub(0), V, facetdim, bndry_facets)
        bc = DirichletBC(bc0, bdofs, V.sub(0))
        u = TrialFunction(V)
        v = TestFunction(V)

        # Forms
        a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector((1.0, 1.0)), v) * dx

        # Assemble linear algebra objects
        A = assemble_matrix(a, [bc])
        A.assemble()
        b = assemble_vector(L)
        apply_lifting(b, [a], [[bc]])
        b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
        set_bc(b, [bc])

        # Create solution function
        u = Function(V)

        # Create near null space basis and orthonormalize
        null_space = build_nullspace(V, u.vector)

        # Attached near-null space to matrix
        A.set_near_nullspace(null_space)

        # Test that basis is orthonormal
        assert null_space.is_orthonormal()

        # Create PETSC smoothed aggregation AMG preconditioner, and
        # create CG solver
        solver = PETSc.KSP().create(mesh.mpi_comm)
        solver.setType("cg")

        # Set matrix operator
        solver.setOperators(A)

        # Compute solution and return number of iterations
        return solver.solve(b, u.vector)
예제 #5
0
def test_3d(tempdir, cell_type, encoding):
    filename = os.path.join(tempdir, "meshtags_3d.xdmf")
    comm = MPI.COMM_WORLD
    mesh = UnitCubeMesh(comm, 4, 4, 4, cell_type)

    bottom_facets = locate_entities_geometrical(
        mesh, 2, lambda x: np.isclose(x[1], 0.0))
    bottom_values = np.full(bottom_facets.shape, 1, dtype=np.intc)
    left_facets = locate_entities_geometrical(mesh, 2,
                                              lambda x: np.isclose(x[0], 0.0))
    left_values = np.full(left_facets.shape, 2, dtype=np.intc)

    indices, pos = np.unique(np.hstack((bottom_facets, left_facets)),
                             return_index=True)
    mt = MeshTags(mesh, 2, indices,
                  np.hstack((bottom_values, left_values))[pos])
    mt.name = "facets"

    top_lines = locate_entities_geometrical(mesh, 1,
                                            lambda x: np.isclose(x[2], 1.0))
    top_values = np.full(top_lines.shape, 3, dtype=np.intc)
    right_lines = locate_entities_geometrical(mesh, 1,
                                              lambda x: np.isclose(x[0], 1.0))
    right_values = np.full(right_lines.shape, 4, dtype=np.intc)

    indices, pos = np.unique(np.hstack((top_lines, right_lines)),
                             return_index=True)
    mt_lines = MeshTags(mesh, 1, indices,
                        np.hstack((top_values, right_values))[pos])
    mt_lines.name = "lines"

    with XDMFFile(comm, filename, "w", encoding=encoding) as file:
        mesh.topology.create_connectivity_all()
        file.write_mesh(mesh)
        file.write_meshtags(mt)
        file.write_meshtags(mt_lines)

    with XDMFFile(comm, filename, "r", encoding=encoding) as file:
        mesh_in = file.read_mesh()
        mesh_in.topology.create_connectivity_all()
        mt_in = file.read_meshtags(mesh_in, "facets")
        mt_lines_in = file.read_meshtags(mesh_in, "lines")
        assert mt_in.name == "facets"
        assert mt_lines_in.name == "lines"

    with XDMFFile(comm,
                  os.path.join(tempdir, "meshtags_3d_out.xdmf"),
                  "w",
                  encoding=encoding) as file:
        file.write_mesh(mesh_in)
        file.write_meshtags(mt_lines_in)
        file.write_meshtags(mt_in)

    # Check number of owned and marked entities
    lines_local = comm.allreduce(
        (mt_lines.indices < mesh.topology.index_map(1).size_local).sum(),
        op=MPI.SUM)
    lines_local_in = comm.allreduce(
        (mt_lines_in.indices < mesh_in.topology.index_map(1).size_local).sum(),
        op=MPI.SUM)

    assert lines_local == lines_local_in
예제 #6
0
def test_assembly_solve_taylor_hood(mesh):
    """Assemble Stokes problem with Taylor-Hood elements and solve."""
    gdim = mesh.geometry.dim
    P2 = dolfinx.function.VectorFunctionSpace(mesh, ("Lagrange", 2))
    P1 = dolfinx.function.FunctionSpace(mesh, ("Lagrange", 1))

    def boundary0(x):
        """Define boundary x = 0"""
        return x[0] < 10 * numpy.finfo(float).eps

    def boundary1(x):
        """Define boundary x = 1"""
        return x[0] > (1.0 - 10 * numpy.finfo(float).eps)

    def initial_guess_u(x):
        u_init = numpy.row_stack((numpy.sin(x[0]) * numpy.sin(x[1]),
                                  numpy.cos(x[0]) * numpy.cos(x[1])))
        if gdim == 3:
            u_init = numpy.row_stack((u_init, numpy.cos(x[2])))
        return u_init

    def initial_guess_p(x):
        return -x[0]**2 - x[1]**3

    u_bc_0 = dolfinx.Function(P2)
    u_bc_0.interpolate(lambda x: numpy.row_stack(tuple(x[j] + float(j) for j in range(gdim))))

    u_bc_1 = dolfinx.Function(P2)
    u_bc_1.interpolate(lambda x: numpy.row_stack(tuple(numpy.sin(x[j]) for j in range(gdim))))

    facetdim = mesh.topology.dim - 1
    bndry_facets0 = locate_entities_geometrical(mesh, facetdim, boundary0, boundary_only=True)
    bndry_facets1 = locate_entities_geometrical(mesh, facetdim, boundary1, boundary_only=True)

    bdofs0 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets0)
    bdofs1 = dolfinx.fem.locate_dofs_topological(P2, facetdim, bndry_facets1)

    bcs = [dolfinx.DirichletBC(u_bc_0, bdofs0),
           dolfinx.DirichletBC(u_bc_1, bdofs1)]

    u, p = dolfinx.Function(P2), dolfinx.Function(P1)
    du, dp = ufl.TrialFunction(P2), ufl.TrialFunction(P1)
    v, q = ufl.TestFunction(P2), ufl.TestFunction(P1)

    F = [inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx,
         inner(ufl.div(u), q) * dx]
    J = [[derivative(F[0], u, du), derivative(F[0], p, dp)],
         [derivative(F[1], u, du), derivative(F[1], p, dp)]]
    P = [[J[0][0], None],
         [None, inner(dp, q) * dx]]

    # -- Blocked and monolithic

    Jmat0 = dolfinx.fem.create_matrix_block(J)
    Pmat0 = dolfinx.fem.create_matrix_block(P)
    Fvec0 = dolfinx.fem.create_vector_block(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    snes.getKSP().setType("minres")
    snes.getKSP().getPC().setType("lu")
    snes.getKSP().getPC().setFactorSolverType("superlu_dist")

    problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P)
    snes.setFunction(problem.F_block, Fvec0)
    snes.setJacobian(problem.J_block, J=Jmat0, P=Pmat0)

    u.interpolate(initial_guess_u)
    p.interpolate(initial_guess_p)

    x0 = dolfinx.fem.create_vector_block(F)
    with u.vector.localForm() as _u, p.vector.localForm() as _p:
        dolfinx.cpp.la.scatter_local_vectors(
            x0, [_u.array_r, _p.array_r],
            [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map])
    x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    snes.solve(None, x0)

    assert snes.getConvergedReason() > 0

    # -- Blocked and nested

    Jmat1 = dolfinx.fem.create_matrix_nest(J)
    Pmat1 = dolfinx.fem.create_matrix_nest(P)
    Fvec1 = dolfinx.fem.create_vector_nest(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    nested_IS = Jmat1.getNestISs()

    snes.getKSP().setType("minres")
    snes.getKSP().setTolerances(rtol=1e-12)
    snes.getKSP().getPC().setType("fieldsplit")
    snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]])

    ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP()
    ksp_u.setType("preonly")
    ksp_u.getPC().setType('lu')
    ksp_u.getPC().setFactorSolverType('superlu_dist')
    ksp_p.setType("preonly")
    ksp_p.getPC().setType('lu')
    ksp_p.getPC().setFactorSolverType('superlu_dist')

    problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs, P=P)
    snes.setFunction(problem.F_nest, Fvec1)
    snes.setJacobian(problem.J_nest, J=Jmat1, P=Pmat1)

    u.interpolate(initial_guess_u)
    p.interpolate(initial_guess_p)

    x1 = dolfinx.fem.create_vector_nest(F)
    for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)):
        x1_sub, soln_sub = x1_soln_pair
        soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
        soln_sub.vector.copy(result=x1_sub)
        x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    x1.set(0.0)
    snes.solve(None, x1)

    assert snes.getConvergedReason() > 0
    assert nest_matrix_norm(Jmat1) == pytest.approx(Jmat0.norm(), 1.0e-12)
    assert Fvec1.norm() == pytest.approx(Fvec0.norm(), 1.0e-12)
    assert x1.norm() == pytest.approx(x0.norm(), 1.0e-12)

    # -- Monolithic

    P2_el = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2)
    P1_el = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    TH = P2_el * P1_el
    W = dolfinx.FunctionSpace(mesh, TH)
    U = dolfinx.Function(W)
    dU = ufl.TrialFunction(W)
    u, p = ufl.split(U)
    du, dp = ufl.split(dU)
    v, q = ufl.TestFunctions(W)

    F = inner(ufl.grad(u), ufl.grad(v)) * dx + inner(p, ufl.div(v)) * dx \
        + inner(ufl.div(u), q) * dx
    J = derivative(F, U, dU)
    P = inner(ufl.grad(du), ufl.grad(v)) * dx + inner(dp, q) * dx

    bdofsW0_P2_0 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets0)
    bdofsW0_P2_1 = dolfinx.fem.locate_dofs_topological((W.sub(0), P2), facetdim, bndry_facets1)

    bcs = [dolfinx.DirichletBC(u_bc_0, bdofsW0_P2_0, W.sub(0)),
           dolfinx.DirichletBC(u_bc_1, bdofsW0_P2_1, W.sub(0))]

    Jmat2 = dolfinx.fem.create_matrix(J)
    Pmat2 = dolfinx.fem.create_matrix(P)
    Fvec2 = dolfinx.fem.create_vector(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    snes.getKSP().setType("minres")
    snes.getKSP().getPC().setType("lu")
    snes.getKSP().getPC().setFactorSolverType("superlu_dist")

    problem = NonlinearPDE_SNESProblem(F, J, U, bcs, P=P)
    snes.setFunction(problem.F_mono, Fvec2)
    snes.setJacobian(problem.J_mono, J=Jmat2, P=Pmat2)

    U.interpolate(lambda x: numpy.row_stack((initial_guess_u(x), initial_guess_p(x))))

    x2 = dolfinx.fem.create_vector(F)
    x2.array = U.vector.array_r

    snes.solve(None, x2)

    assert snes.getConvergedReason() > 0
    assert Jmat2.norm() == pytest.approx(Jmat0.norm(), 1.0e-12)
    assert Fvec2.norm() == pytest.approx(Fvec0.norm(), 1.0e-12)
    assert x2.norm() == pytest.approx(x0.norm(), 1.0e-12)
예제 #7
0
def test_matrix_assembly_block():
    """Test assembly of block matrices and vectors into (a) monolithic
    blocked structures, PETSc Nest structures, and monolithic structures
    in the nonlinear setting
    """
    mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 4, 8)

    p0, p1 = 1, 2
    P0 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p0)
    P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p1)

    V0 = dolfinx.function.FunctionSpace(mesh, P0)
    V1 = dolfinx.function.FunctionSpace(mesh, P1)

    def boundary(x):
        return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6)

    def initial_guess_u(x):
        return numpy.sin(x[0]) * numpy.sin(x[1])

    def initial_guess_p(x):
        return -x[0]**2 - x[1]**3

    def bc_value(x):
        return numpy.cos(x[0]) * numpy.cos(x[1])

    facetdim = mesh.topology.dim - 1
    bndry_facets = locate_entities_geometrical(mesh, facetdim, boundary, boundary_only=True)

    u_bc = dolfinx.function.Function(V1)
    u_bc.interpolate(bc_value)
    bdofs = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets)
    bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofs)

    # Define variational problem
    du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1)
    u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1)
    v, q = ufl.TestFunction(V0), ufl.TestFunction(V1)

    u.interpolate(initial_guess_u)
    p.interpolate(initial_guess_p)

    f = 1.0
    g = -3.0

    F0 = inner(u, v) * dx + inner(p, v) * dx - inner(f, v) * dx
    F1 = inner(u, q) * dx + inner(p, q) * dx - inner(g, q) * dx

    a_block = [[derivative(F0, u, du), derivative(F0, p, dp)],
               [derivative(F1, u, du), derivative(F1, p, dp)]]
    L_block = [F0, F1]

    # Monolithic blocked
    x0 = dolfinx.fem.create_vector_block(L_block)
    dolfinx.cpp.la.scatter_local_vectors(
        x0, [u.vector.array_r, p.vector.array_r],
        [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map])
    x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    # Ghosts are updated inside assemble_vector_block
    A0 = dolfinx.fem.assemble_matrix_block(a_block, [bc])
    b0 = dolfinx.fem.assemble_vector_block(L_block, a_block, [bc], x0=x0, scale=-1.0)
    A0.assemble()
    assert A0.getType() != "nest"
    Anorm0 = A0.norm()
    bnorm0 = b0.norm()

    # Nested (MatNest)
    x1 = dolfinx.fem.create_vector_nest(L_block)
    for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)):
        x1_sub, soln_sub = x1_soln_pair
        soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
        soln_sub.vector.copy(result=x1_sub)
        x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    A1 = dolfinx.fem.assemble_matrix_nest(a_block, [bc])
    b1 = dolfinx.fem.assemble_vector_nest(L_block)
    dolfinx.fem.apply_lifting_nest(b1, a_block, [bc], x1, scale=-1.0)
    for b_sub in b1.getNestSubVecs():
        b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    bcs0 = dolfinx.cpp.fem.bcs_rows(dolfinx.fem.assemble._create_cpp_form(L_block), [bc])
    dolfinx.fem.set_bc_nest(b1, bcs0, x1, scale=-1.0)
    A1.assemble()

    assert A1.getType() == "nest"
    assert nest_matrix_norm(A1) == pytest.approx(Anorm0, 1.0e-12)
    assert b1.norm() == pytest.approx(bnorm0, 1.0e-12)

    # Monolithic version
    E = P0 * P1
    W = dolfinx.function.FunctionSpace(mesh, E)
    dU = ufl.TrialFunction(W)
    U = dolfinx.function.Function(W)
    u0, u1 = ufl.split(U)
    v0, v1 = ufl.TestFunctions(W)

    U.interpolate(lambda x: numpy.row_stack((initial_guess_u(x), initial_guess_p(x))))

    F = inner(u0, v0) * dx + inner(u1, v0) * dx + inner(u0, v1) * dx + inner(u1, v1) * dx \
        - inner(f, v0) * ufl.dx - inner(g, v1) * dx
    J = derivative(F, U, dU)

    bdofsW_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets)

    bc = dolfinx.fem.dirichletbc.DirichletBC(u_bc, bdofsW_V1, W.sub(1))
    A2 = dolfinx.fem.assemble_matrix(J, [bc])
    A2.assemble()
    b2 = dolfinx.fem.assemble_vector(F)
    dolfinx.fem.apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0)
    b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.set_bc(b2, [bc], x0=U.vector, scale=-1.0)
    assert A2.getType() != "nest"
    assert A2.norm() == pytest.approx(Anorm0, 1.0e-12)
    assert b2.norm() == pytest.approx(bnorm0, 1.0e-12)
예제 #8
0
def test_assembly_solve_block():
    """Solve a two-field nonlinear diffusion like problem with block matrix
    approaches and test that solution is the same.
    """
    mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 12, 11)
    p = 1
    P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p)
    V0 = dolfinx.function.FunctionSpace(mesh, P)
    V1 = V0.clone()

    def bc_val_0(x):
        return x[0]**2 + x[1]**2

    def bc_val_1(x):
        return numpy.sin(x[0]) * numpy.cos(x[1])

    def initial_guess_u(x):
        return numpy.sin(x[0]) * numpy.sin(x[1])

    def initial_guess_p(x):
        return -x[0]**2 - x[1]**3

    def boundary(x):
        return numpy.logical_or(x[0] < 1.0e-6, x[0] > 1.0 - 1.0e-6)

    facetdim = mesh.topology.dim - 1
    bndry_facets = locate_entities_geometrical(mesh, facetdim, boundary, boundary_only=True)

    u_bc0 = dolfinx.function.Function(V0)
    u_bc0.interpolate(bc_val_0)
    u_bc1 = dolfinx.function.Function(V1)
    u_bc1.interpolate(bc_val_1)

    bdofs0 = dolfinx.fem.locate_dofs_topological(V0, facetdim, bndry_facets)
    bdofs1 = dolfinx.fem.locate_dofs_topological(V1, facetdim, bndry_facets)

    bcs = [dolfinx.fem.dirichletbc.DirichletBC(u_bc0, bdofs0),
           dolfinx.fem.dirichletbc.DirichletBC(u_bc1, bdofs1)]

    # Block and Nest variational problem
    u, p = dolfinx.function.Function(V0), dolfinx.function.Function(V1)
    du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1)
    v, q = ufl.TestFunction(V0), ufl.TestFunction(V1)

    f = 1.0
    g = -3.0

    F = [inner((u**2 + 1) * ufl.grad(u), ufl.grad(v)) * dx - inner(f, v) * dx,
         inner((p**2 + 1) * ufl.grad(p), ufl.grad(q)) * dx - inner(g, q) * dx]

    J = [[derivative(F[0], u, du), derivative(F[0], p, dp)],
         [derivative(F[1], u, du), derivative(F[1], p, dp)]]

    # -- Blocked version
    Jmat0 = dolfinx.fem.create_matrix_block(J)
    Fvec0 = dolfinx.fem.create_vector_block(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    snes.getKSP().setType("preonly")
    snes.getKSP().getPC().setType("lu")
    snes.getKSP().getPC().setFactorSolverType("superlu_dist")

    problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs)
    snes.setFunction(problem.F_block, Fvec0)
    snes.setJacobian(problem.J_block, J=Jmat0, P=None)

    u.interpolate(initial_guess_u)
    p.interpolate(initial_guess_p)

    x0 = dolfinx.fem.create_vector_block(F)
    dolfinx.cpp.la.scatter_local_vectors(
        x0, [u.vector.array_r, p.vector.array_r],
        [u.function_space.dofmap.index_map, p.function_space.dofmap.index_map])
    x0.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    snes.solve(None, x0)

    assert snes.getKSP().getConvergedReason() > 0
    assert snes.getConvergedReason() > 0

    J0norm = Jmat0.norm()
    F0norm = Fvec0.norm()
    x0norm = x0.norm()

    # -- Nested (MatNest)
    Jmat1 = dolfinx.fem.create_matrix_nest(J)
    Fvec1 = dolfinx.fem.create_vector_nest(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    nested_IS = Jmat1.getNestISs()

    snes.getKSP().setType("fgmres")
    snes.getKSP().setTolerances(rtol=1e-12)
    snes.getKSP().getPC().setType("fieldsplit")
    snes.getKSP().getPC().setFieldSplitIS(["u", nested_IS[0][0]], ["p", nested_IS[1][1]])

    ksp_u, ksp_p = snes.getKSP().getPC().getFieldSplitSubKSP()
    ksp_u.setType("preonly")
    ksp_u.getPC().setType('lu')
    ksp_u.getPC().setFactorSolverType('superlu_dist')
    ksp_p.setType("preonly")
    ksp_p.getPC().setType('lu')
    ksp_p.getPC().setFactorSolverType('superlu_dist')

    problem = NonlinearPDE_SNESProblem(F, J, [u, p], bcs)
    snes.setFunction(problem.F_nest, Fvec1)
    snes.setJacobian(problem.J_nest, J=Jmat1, P=None)

    u.interpolate(initial_guess_u)
    p.interpolate(initial_guess_p)

    x1 = dolfinx.fem.create_vector_nest(F)
    for x1_soln_pair in zip(x1.getNestSubVecs(), (u, p)):
        x1_sub, soln_sub = x1_soln_pair
        soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)
        soln_sub.vector.copy(result=x1_sub)
        x1_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD)

    snes.solve(None, x1)

    assert snes.getKSP().getConvergedReason() > 0
    assert snes.getConvergedReason() > 0
    assert x1.getType() == "nest"
    assert Jmat1.getType() == "nest"
    assert Fvec1.getType() == "nest"

    J1norm = nest_matrix_norm(Jmat1)
    F1norm = Fvec1.norm()
    x1norm = x1.norm()

    assert J1norm == pytest.approx(J0norm, 1.0e-12)
    assert F1norm == pytest.approx(F0norm, 1.0e-12)
    assert x1norm == pytest.approx(x0norm, 1.0e-12)

    # -- Monolithic version
    E = P * P
    W = dolfinx.function.FunctionSpace(mesh, E)
    U = dolfinx.function.Function(W)
    dU = ufl.TrialFunction(W)
    u0, u1 = ufl.split(U)
    v0, v1 = ufl.TestFunctions(W)

    F = inner((u0**2 + 1) * ufl.grad(u0), ufl.grad(v0)) * dx \
        + inner((u1**2 + 1) * ufl.grad(u1), ufl.grad(v1)) * dx \
        - inner(f, v0) * ufl.dx - inner(g, v1) * dx
    J = derivative(F, U, dU)

    u0_bc = dolfinx.function.Function(V0)
    u0_bc.interpolate(bc_val_0)
    u1_bc = dolfinx.function.Function(V1)
    u1_bc.interpolate(bc_val_1)

    bdofsW0_V0 = dolfinx.fem.locate_dofs_topological((W.sub(0), V0), facetdim, bndry_facets)
    bdofsW1_V1 = dolfinx.fem.locate_dofs_topological((W.sub(1), V1), facetdim, bndry_facets)

    bcs = [dolfinx.fem.dirichletbc.DirichletBC(u0_bc, bdofsW0_V0, W.sub(0)),
           dolfinx.fem.dirichletbc.DirichletBC(u1_bc, bdofsW1_V1, W.sub(1))]

    Jmat2 = dolfinx.fem.create_matrix(J)
    Fvec2 = dolfinx.fem.create_vector(F)

    snes = PETSc.SNES().create(MPI.COMM_WORLD)
    snes.setTolerances(rtol=1.0e-15, max_it=10)

    snes.getKSP().setType("preonly")
    snes.getKSP().getPC().setType("lu")
    snes.getKSP().getPC().setFactorSolverType("superlu_dist")

    problem = NonlinearPDE_SNESProblem(F, J, U, bcs)
    snes.setFunction(problem.F_mono, Fvec2)
    snes.setJacobian(problem.J_mono, J=Jmat2, P=None)

    U.interpolate(lambda x: numpy.row_stack((initial_guess_u(x), initial_guess_p(x))))

    x2 = dolfinx.fem.create_vector(F)
    x2.array = U.vector.array_r

    snes.solve(None, x2)

    assert snes.getKSP().getConvergedReason() > 0
    assert snes.getConvergedReason() > 0

    J2norm = Jmat2.norm()
    F2norm = Fvec2.norm()
    x2norm = x2.norm()

    assert J2norm == pytest.approx(J0norm, 1.0e-12)
    assert F2norm == pytest.approx(F0norm, 1.0e-12)
    assert x2norm == pytest.approx(x0norm, 1.0e-12)
예제 #9
0
# field::

P2 = ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2)
P1 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1)
V, Q = FunctionSpace(mesh, P2), FunctionSpace(mesh, P1)

# We can define boundary conditions::

# No-slip boundary condition for velocity field (`V`) on boundaries
# where x = 0, x = 1, and y = 0
noslip = Function(V)
with noslip.vector.localForm() as bc_local:
    bc_local.set(0.0)

facets = locate_entities_geometrical(mesh,
                                     1,
                                     noslip_boundary,
                                     boundary_only=True)
bc0 = DirichletBC(noslip, locate_dofs_topological(V, 1, facets))

# Driving velocity condition u = (1, 0) on top boundary (y = 1)
lid_velocity = Function(V)
lid_velocity.interpolate(lid_velocity_expression)

facets = locate_entities_geometrical(mesh, 1, lid, boundary_only=True)
bc1 = DirichletBC(lid_velocity, locate_dofs_topological(V, 1, facets))

# Collect Dirichlet boundary conditions
bcs = [bc0, bc1]

# We now define the bilinear and linear forms corresponding to the weak
# mixed formulation of the Stokes equations in a blocked structure::