Пример #1
0
def test_normals(cube, square):
    """ Test cell normals for a subset of facets """
    def left_side(x):
        return numpy.isclose(x[0], 0)

    fdim = cube.topology.dim - 1
    facets = locate_entities_boundary(cube, fdim, left_side)
    normals = cell_normals(cube, fdim, facets)
    assert (numpy.allclose(normals, [-1, 0, 0]))

    fdim = square.topology.dim - 1
    facets = locate_entities_boundary(square, fdim, left_side)
    normals = cell_normals(square, fdim, facets)
    assert (numpy.allclose(normals, [-1, 0, 0]))
Пример #2
0
def test_mixed_constant_bc(mesh_factory):
    """Test that setting a dirichletbc with on a component of a mixed
    function yields the same result as setting it with a function"""
    func, args = mesh_factory
    mesh = func(*args)
    tdim, gdim = mesh.topology.dim, mesh.geometry.dim
    boundary_facets = locate_entities_boundary(
        mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool))
    TH = ufl.MixedElement([
        ufl.VectorElement("Lagrange", mesh.ufl_cell(), 2),
        ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 1)
    ])
    W = FunctionSpace(mesh, TH)
    U = Function(W)

    # Apply BC to component of a mixed space using a Constant
    c = Constant(mesh, (PETSc.ScalarType(2), PETSc.ScalarType(2)))
    dofs0 = locate_dofs_topological(W.sub(0), tdim - 1, boundary_facets)
    bc0 = dirichletbc(c, dofs0, W.sub(0))
    u = U.sub(0)
    set_bc(u.vector, [bc0])

    # Apply BC to component of a mixed space using a Function
    ubc1 = u.collapse()
    ubc1.interpolate(lambda x: np.full((gdim, x.shape[1]), 2.0))
    dofs1 = locate_dofs_topological((W.sub(0), ubc1.function_space), tdim - 1,
                                    boundary_facets)
    bc1 = dirichletbc(ubc1, dofs1, W.sub(0))
    U1 = Function(W)
    u1 = U1.sub(0)
    set_bc(u1.vector, [bc1])

    # Check that both approaches yield the same vector
    assert np.allclose(u.x.array, u1.x.array)
Пример #3
0
def test_sub_constant_bc(mesh_factory):
    """Test that setting a dirichletbc with on a component of a vector
    valued function yields the same result as setting it with a
    function"""
    func, args = mesh_factory
    mesh = func(*args)
    tdim = mesh.topology.dim
    V = VectorFunctionSpace(mesh, ("Lagrange", 1))
    c = Constant(mesh, PETSc.ScalarType(3.14))
    boundary_facets = locate_entities_boundary(
        mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool))

    for i in range(V.num_sub_spaces):
        Vi = V.sub(i).collapse()[0]
        u_bci = Function(Vi)
        u_bci.x.array[:] = PETSc.ScalarType(c.value)

        boundary_dofsi = locate_dofs_topological((V.sub(i), Vi), tdim - 1,
                                                 boundary_facets)
        bc_fi = dirichletbc(u_bci, boundary_dofsi, V.sub(i))
        boundary_dofs = locate_dofs_topological(V.sub(i), tdim - 1,
                                                boundary_facets)
        bc_c = dirichletbc(c, boundary_dofs, V.sub(i))

        u_f = Function(V)
        set_bc(u_f.vector, [bc_fi])
        u_c = Function(V)
        set_bc(u_c.vector, [bc_c])
        assert np.allclose(u_f.vector.array, u_c.vector.array)
Пример #4
0
def test_vector_constant_bc(mesh_factory):
    """Test that setting a dirichletbc with a vector valued constant
    yields the same result as setting it with a function"""
    func, args = mesh_factory
    mesh = func(*args)
    tdim = mesh.topology.dim
    V = VectorFunctionSpace(mesh, ("Lagrange", 1))
    assert V.num_sub_spaces == mesh.geometry.dim
    c = np.arange(1, mesh.geometry.dim + 1, dtype=PETSc.ScalarType)
    boundary_facets = locate_entities_boundary(
        mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool))

    # Set using sub-functions
    Vs = [V.sub(i).collapse()[0] for i in range(V.num_sub_spaces)]
    boundary_dofs = [
        locate_dofs_topological((V.sub(i), Vs[i]), tdim - 1, boundary_facets)
        for i in range(len(Vs))
    ]
    u_bcs = [Function(Vs[i]) for i in range(len(Vs))]
    bcs_f = []
    for i, u in enumerate(u_bcs):
        u_bcs[i].x.array[:] = c[i]
        bcs_f.append(dirichletbc(u_bcs[i], boundary_dofs[i], V.sub(i)))
    u_f = Function(V)
    set_bc(u_f.vector, bcs_f)

    # Set using constant
    boundary_dofs = locate_dofs_topological(V, tdim - 1, boundary_facets)
    bc_c = dirichletbc(c, boundary_dofs, V)
    u_c = Function(V)
    u_c.x.array[:] = 0.0
    set_bc(u_c.vector, [bc_c])

    assert np.allclose(u_f.x.array, u_c.x.array)
Пример #5
0
def test_constant_bc(mesh_factory):
    """Test that setting a dirichletbc with a constant yields the same
    result as setting it with a function"""
    func, args = mesh_factory
    mesh = func(*args)
    V = FunctionSpace(mesh, ("Lagrange", 1))
    c = PETSc.ScalarType(2)
    tdim = mesh.topology.dim
    boundary_facets = locate_entities_boundary(
        mesh, tdim - 1, lambda x: np.ones(x.shape[1], dtype=bool))

    boundary_dofs = locate_dofs_topological(V, tdim - 1, boundary_facets)

    u_bc = Function(V)
    u_bc.x.array[:] = c

    bc_f = dirichletbc(u_bc, boundary_dofs)
    bc_c = dirichletbc(c, boundary_dofs, V)

    u_f = Function(V)
    set_bc(u_f.vector, [bc_f])

    u_c = Function(V)
    set_bc(u_c.vector, [bc_c])
    assert np.allclose(u_f.vector.array, u_c.vector.array)
Пример #6
0
def test_sub_bbtree():
    """
    Testing point collision with a BoundingBoxTree of sub entitites
    """
    mesh = UnitCubeMesh(MPI.COMM_WORLD, 4, 4, 4, cell_type=cpp.mesh.CellType.hexahedron)
    tdim = mesh.topology.dim
    fdim = tdim - 1

    def top_surface(x):
        return numpy.isclose(x[2], 1)

    top_facets = locate_entities_boundary(mesh, fdim, top_surface)
    f_to_c = mesh.topology.connectivity(tdim - 1, tdim)
    cells = [f_to_c.links(f)[0] for f in top_facets]
    bbtree = BoundingBoxTree(mesh, tdim, cells)

    # Compute a BBtree for all processes
    process_bbtree = bbtree.compute_global_tree(mesh.mpi_comm())
    # Find possible ranks for this point
    point = numpy.array([0.2, 0.2, 1.0])
    ranks = compute_collisions_point(process_bbtree, point)

    # Compute local collisions
    cells = compute_collisions_point(bbtree, point)
    if MPI.COMM_WORLD.rank in ranks:
        assert(len(cells) > 0)
    else:
        assert(len(cells) == 0)
Пример #7
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 = create_unit_square(MPI.COMM_WORLD, N, N)
        V = VectorFunctionSpace(mesh, 'Lagrange', 1)
        u = TrialFunction(V)
        v = TestFunction(V)

        facetdim = mesh.topology.dim - 1
        bndry_facets = locate_entities_boundary(
            mesh, facetdim, lambda x: np.full(x.shape[1], True))
        bdofs = locate_dofs_topological(V.sub(0), V, facetdim, bndry_facets)
        bc = dirichletbc(PETSc.ScalarType(0), bdofs, V.sub(0))

        # 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.comm)
        solver.setType("cg")

        # Set matrix operator
        solver.setOperators(A)

        # Compute solution and return number of iterations
        return solver.solve(b, u.vector)
Пример #8
0
def solve_system(N):
    fenics_mesh = dolfinx.UnitCubeMesh(fenicsx_comm, N, N, N)
    fenics_space = dolfinx.FunctionSpace(fenics_mesh, ("CG", 1))
    u = ufl.TrialFunction(fenics_space)
    v = ufl.TestFunction(fenics_space)
    k = 2
    # print(u*v*ufl.ds)
    form = (ufl.inner(ufl.grad(u), ufl.grad(v)) -
            k**2 * ufl.inner(u, v)) * ufl.dx

    # locate facets on the cube boundary
    facets = locate_entities_boundary(
        fenics_mesh, 2, lambda x: np.logical_or(
            np.logical_or(
                np.logical_or(np.isclose(x[2], 0.0), np.isclose(x[2], 1.0)),
                np.logical_or(np.isclose(x[1], 0.0), np.isclose(x[1], 1.0))),
            np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0))))

    facets.sort()

    # alternative - more general approach
    boundary = entities_to_geometry(
        fenics_mesh,
        fenics_mesh.topology.dim - 1,
        exterior_facet_indices(fenics_mesh),
        True,
    )
    # print(len(facets)
    assert len(facets) == len(exterior_facet_indices(fenics_mesh))

    u0 = fem.Function(fenics_space)

    with u0.vector.localForm() as u0_loc:
        u0_loc.set(0)
    # solution vector
    bc = DirichletBC(u0, locate_dofs_topological(fenics_space, 2, facets))

    A = 1 + 1j
    f = Function(fenics_space)
    f.interpolate(lambda x: A * k**2 * np.cos(k * x[0]) * np.cos(k * x[1]))

    L = ufl.inner(f, v) * ufl.dx
    u0.name = "u"
    problem = fem.LinearProblem(form,
                                L,
                                u=u0,
                                petsc_options={
                                    "ksp_type": "preonly",
                                    "pc_type": "lu"
                                })
    # problem = fem.LinearProblem(form, L, bcs=[bc], u=u0, petsc_options={"ksp_type": "preonly", "pc_type": "lu"})

    start_time = time.time()
    soln = problem.solve()
    if world_rank == 0:
        print("--- fenics solve done in %s seconds ---" %
              (time.time() - start_time))
Пример #9
0
def test_submesh_boundary(d, n, boundary, ghost_mode):
    if d == 2:
        mesh = create_unit_square(MPI.COMM_WORLD, n, n, ghost_mode=ghost_mode)
    else:
        mesh = create_unit_cube(MPI.COMM_WORLD, n, n, n, ghost_mode=ghost_mode)
    edim = mesh.topology.dim - 1
    entities = locate_entities_boundary(mesh, edim, boundary)
    submesh, vertex_map, geom_map = create_submesh(mesh, edim, entities)
    submesh_topology_test(mesh, submesh, vertex_map, edim, entities)
    submesh_geometry_test(mesh, submesh, geom_map, edim, entities)
Пример #10
0
def test_sub_refine():
    """Test that refinement of a subset of edges works"""
    mesh = create_unit_square(MPI.COMM_WORLD, 3, 4, diagonal=DiagonalType.left,
                              ghost_mode=GhostMode.none)
    mesh.topology.create_entities(1)

    def left_corner_edge(x, tol=1e-16):
        return logical_and(isclose(x[0], 0), x[1] < 1 / 4 + tol)

    edges = locate_entities_boundary(mesh, 1, left_corner_edge)
    if MPI.COMM_WORLD.size == 0:
        assert edges == 1

    mesh2 = refine(mesh, edges, redistribute=False)
    assert mesh.topology.index_map(2).size_global + 3 == mesh2.topology.index_map(2).size_global
Пример #11
0
def test_sub_bbtree_box(ct, N):
    """Test that the bounding box of the stem of the bounding box tree is what we expect"""
    mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, cell_type=ct)
    tdim = mesh.topology.dim
    fdim = tdim - 1

    facets = locate_entities_boundary(mesh, fdim, lambda x: np.isclose(x[1], 1.0))
    f_to_c = mesh.topology.connectivity(fdim, tdim)
    cells = np.int32(np.unique([f_to_c.links(f)[0] for f in facets]))
    bbtree = BoundingBoxTree(mesh, tdim, cells)
    num_boxes = bbtree.num_bboxes
    if num_boxes > 0:
        bbox = bbtree.get_bbox(num_boxes - 1)
        assert np.isclose(bbox[0][1], (N - 1) / N)

    tree = BoundingBoxTree(mesh, tdim)
    assert num_boxes < tree.num_bboxes
Пример #12
0
def test_sub_bbtree_box(ct, N):
    """
    Test that the bounding box of the stem of the bounding box tree is what we expect
    """
    mesh = UnitCubeMesh(MPI.COMM_WORLD, N, N, N, cell_type=ct)
    tdim = mesh.topology.dim
    fdim = tdim - 1

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

    facets = locate_entities_boundary(mesh, fdim, marker)
    f_to_c = mesh.topology.connectivity(fdim, tdim)
    cells = numpy.unique([f_to_c.links(f)[0] for f in facets])
    bbtree = BoundingBoxTree(mesh, tdim, cells)
    num_boxes = bbtree.num_bboxes
    if num_boxes > 0:
        bbox = bbtree.get_bbox(num_boxes - 1)
        assert numpy.isclose(bbox[0][1], (N - 1) / N)

    tree = BoundingBoxTree(mesh, tdim)
    assert num_boxes < tree.num_bboxes
Пример #13
0
def test_sub_bbtree():
    """Testing point collision with a BoundingBoxTree of sub entitites"""
    mesh = create_unit_cube(MPI.COMM_WORLD, 4, 4, 4, cell_type=CellType.hexahedron)
    tdim = mesh.topology.dim
    fdim = tdim - 1

    top_facets = locate_entities_boundary(mesh, fdim, lambda x: np.isclose(x[2], 1))
    f_to_c = mesh.topology.connectivity(tdim - 1, tdim)
    cells = [f_to_c.links(f)[0] for f in top_facets]
    bbtree = BoundingBoxTree(mesh, tdim, cells)

    # Compute a BBtree for all processes
    process_bbtree = bbtree.create_global_tree(mesh.comm)

    # Find possible ranks for this point
    point = np.array([0.2, 0.2, 1.0])
    ranks = compute_collisions(process_bbtree, point)

    # Compute local collisions
    cells = compute_collisions(bbtree, point)
    if MPI.COMM_WORLD.rank in ranks.array:
        assert len(cells.links(0)) > 0
    else:
        assert len(cells.links(0)) == 0
Пример #14
0
def test_assembly_solve_taylor_hood_nl(mesh):
    """Assemble Stokes problem with Taylor-Hood elements and solve."""
    gdim = mesh.geometry.dim
    P2 = VectorFunctionSpace(mesh, ("Lagrange", 2))
    P1 = FunctionSpace(mesh, ("Lagrange", 1))

    def boundary0(x):
        """Define boundary x = 0"""
        return np.isclose(x[0], 0.0)

    def boundary1(x):
        """Define boundary x = 1"""
        return np.isclose(x[0], 1.0)

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

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

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

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

    facetdim = mesh.topology.dim - 1
    bndry_facets0 = locate_entities_boundary(mesh, facetdim, boundary0)
    bndry_facets1 = locate_entities_boundary(mesh, facetdim, boundary1)

    bdofs0 = locate_dofs_topological(P2, facetdim, bndry_facets0)
    bdofs1 = locate_dofs_topological(P2, facetdim, bndry_facets1)

    bcs = [dirichletbc(u_bc_0, bdofs0), dirichletbc(u_bc_1, bdofs1)]

    u, p = Function(P2), 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]]

    F, J, P = form(F), form(J), form(P)

    # -- Blocked and monolithic

    Jmat0 = create_matrix_block(J)
    Pmat0 = create_matrix_block(P)
    Fvec0 = 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")

    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 = create_vector_block(F)
    with u.vector.localForm() as _u, p.vector.localForm() as _p:
        scatter_local_vectors(x0, [_u.array_r, _p.array_r],
                              [(u.function_space.dofmap.index_map,
                                u.function_space.dofmap.index_map_bs),
                               (p.function_space.dofmap.index_map,
                                p.function_space.dofmap.index_map_bs)])
    x0.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                   mode=PETSc.ScatterMode.FORWARD)

    snes.solve(None, x0)

    assert snes.getConvergedReason() > 0

    # -- Blocked and nested

    Jmat1 = create_matrix_nest(J)
    Pmat1 = create_matrix_nest(P)
    Fvec1 = 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_p.setType("preonly")
    ksp_p.getPC().setType('lu')

    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 = 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 = FunctionSpace(mesh, TH)
    U = 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

    F, J, P = form(F), form(J), form(P)

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

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

    Jmat2 = create_matrix(J)
    Pmat2 = create_matrix(P)
    Fvec2 = 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")

    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.sub(0).interpolate(initial_guess_u)
    U.sub(1).interpolate(initial_guess_p)

    x2 = 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)
Пример #15
0
def test_matrix_assembly_block_nl():
    """Test assembly of block matrices and vectors into (a) monolithic
    blocked structures, PETSc Nest structures, and monolithic structures
    in the nonlinear setting
    """
    mesh = create_unit_square(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 = FunctionSpace(mesh, P0)
    V1 = FunctionSpace(mesh, P1)

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

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

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

    facetdim = mesh.topology.dim - 1
    bndry_facets = locate_entities_boundary(
        mesh, facetdim,
        lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0)))

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

    # Define variational problem
    du, dp = ufl.TrialFunction(V0), ufl.TrialFunction(V1)
    u, p = Function(V0), 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 = form([[derivative(F0, u, du),
                     derivative(F0, p, dp)],
                    [derivative(F1, u, du),
                     derivative(F1, p, dp)]])
    L_block = form([F0, F1])

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

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

    # Nested (MatNest)
    x1 = 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 = assemble_matrix_nest(a_block, bcs=[bc])
    b1 = assemble_vector_nest(L_block)
    apply_lifting_nest(b1, a_block, bcs=[bc], x0=x1, scale=-1.0)
    for b_sub in b1.getNestSubVecs():
        b_sub.ghostUpdate(addv=PETSc.InsertMode.ADD,
                          mode=PETSc.ScatterMode.REVERSE)
    bcs0 = bcs_by_block([L.function_spaces[0] for L in L_block], [bc])

    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 = FunctionSpace(mesh, E)
    dU = ufl.TrialFunction(W)
    U = Function(W)
    u0, u1 = ufl.split(U)
    v0, v1 = ufl.TestFunctions(W)

    U.sub(0).interpolate(initial_guess_u)
    U.sub(1).interpolate(initial_guess_p)

    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)
    F, J = form(F), form(J)

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

    bc = dirichletbc(u_bc, bdofsW_V1, W.sub(1))
    A2 = assemble_matrix(J, bcs=[bc])
    A2.assemble()
    b2 = assemble_vector(F)
    apply_lifting(b2, [J], bcs=[[bc]], x0=[U.vector], scale=-1.0)
    b2.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    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)
Пример #16
0
def test_assembly_solve_block_nl():
    """Solve a two-field nonlinear diffusion like problem with block matrix
    approaches and test that solution is the same.
    """
    mesh = create_unit_square(MPI.COMM_WORLD, 12, 11)
    p = 1
    P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), p)
    V0 = FunctionSpace(mesh, P)
    V1 = V0.clone()

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

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

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

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

    facetdim = mesh.topology.dim - 1
    bndry_facets = locate_entities_boundary(
        mesh, facetdim,
        lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0)))

    u_bc0 = Function(V0)
    u_bc0.interpolate(bc_val_0)
    u_bc1 = Function(V1)
    u_bc1.interpolate(bc_val_1)
    bdofs0 = locate_dofs_topological(V0, facetdim, bndry_facets)
    bdofs1 = locate_dofs_topological(V1, facetdim, bndry_facets)
    bcs = [dirichletbc(u_bc0, bdofs0), dirichletbc(u_bc1, bdofs1)]

    # Block and Nest variational problem
    u, p = Function(V0), 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)]]

    F, J = form(F), form(J)

    def blocked_solve():
        """Blocked version"""
        Jmat = create_matrix_block(J)
        Fvec = 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")

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

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

        x = create_vector_block(F)
        scatter_local_vectors(x, [u.vector.array_r, p.vector.array_r],
                              [(u.function_space.dofmap.index_map,
                                u.function_space.dofmap.index_map_bs),
                               (p.function_space.dofmap.index_map,
                                p.function_space.dofmap.index_map_bs)])
        x.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                      mode=PETSc.ScatterMode.FORWARD)

        snes.solve(None, x)
        assert snes.getKSP().getConvergedReason() > 0
        assert snes.getConvergedReason() > 0
        return x.norm()

    def nested_solve():
        """Nested version"""
        Jmat = create_matrix_nest(J)
        assert Jmat.getType() == "nest"
        Fvec = create_vector_nest(F)
        assert Fvec.getType() == "nest"

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

        nested_IS = Jmat.getNestISs()

        snes.getKSP().setType("gmres")
        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_p.setType("preonly")
        ksp_p.getPC().setType('lu')

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

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

        x = create_vector_nest(F)
        assert x.getType() == "nest"
        for x_soln_pair in zip(x.getNestSubVecs(), (u, p)):
            x_sub, soln_sub = x_soln_pair
            soln_sub.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                                        mode=PETSc.ScatterMode.FORWARD)
            soln_sub.vector.copy(result=x_sub)
            x_sub.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                              mode=PETSc.ScatterMode.FORWARD)

        snes.solve(None, x)
        assert snes.getKSP().getConvergedReason() > 0
        assert snes.getConvergedReason() > 0
        return x.norm()

    def monolithic_solve():
        """Monolithic version"""
        E = P * P
        W = FunctionSpace(mesh, E)
        U = 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)

        F, J = form(F), form(J)

        u0_bc = Function(V0)
        u0_bc.interpolate(bc_val_0)
        u1_bc = Function(V1)
        u1_bc.interpolate(bc_val_1)
        bdofsW0_V0 = locate_dofs_topological((W.sub(0), V0), facetdim,
                                             bndry_facets)
        bdofsW1_V1 = locate_dofs_topological((W.sub(1), V1), facetdim,
                                             bndry_facets)
        bcs = [
            dirichletbc(u0_bc, bdofsW0_V0, W.sub(0)),
            dirichletbc(u1_bc, bdofsW1_V1, W.sub(1))
        ]

        Jmat = create_matrix(J)
        Fvec = 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")

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

        U.sub(0).interpolate(initial_guess_u)
        U.sub(1).interpolate(initial_guess_p)

        x = create_vector(F)
        x.array = U.vector.array_r

        snes.solve(None, x)
        assert snes.getKSP().getConvergedReason() > 0
        assert snes.getConvergedReason() > 0
        return x.norm()

    norm0 = blocked_solve()
    norm1 = nested_solve()
    norm2 = monolithic_solve()
    assert norm1 == pytest.approx(norm0, 1.0e-12)
    assert norm2 == pytest.approx(norm0, 1.0e-12)
Пример #17
0
dl_interp(CC, Cn)

my_identity = grad(SpatialCoordinate(mesh))

dl_interp(my_identity, CCv)
dl_interp(my_identity, Cvn)
dl_interp(my_identity, C_quart)
dl_interp(my_identity, C_thr_quart)
dl_interp(my_identity, C_half)

a_uv = (derivative(freeEnergy(CC, CCv), u, v) * dx +
        qvals / h_avg * dot(jump(u), jump(v)) * dS)
jac = derivative(a_uv, u, du)

# assign DirichletBC
left_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, left)
right_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, right)
bottom_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, bottom)
back_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, back)

left_dofs = fem.locate_dofs_topological(V.sub(0), mesh.topology.dim - 1,
                                        left_facets)
right_dofs = fem.locate_dofs_topological(V.sub(0), mesh.topology.dim - 1,
                                         right_facets)
back_dofs = fem.locate_dofs_topological(V.sub(2), mesh.topology.dim - 1,
                                        back_facets)
bottom_dofs = fem.locate_dofs_topological(V.sub(1), mesh.topology.dim - 1,
                                          bottom_facets)

right_disp = fem.Constant(mesh, 0.0)
ul = fem.dirichletbc(st(0), left_dofs, V.sub(0))
Пример #18
0
def mesh_2D_dolfin(celltype: str, theta: float = 0):
    """
    Create two 2D cubes stacked on top of each other,
    and the corresponding mesh markers using dolfin built-in meshes
    """
    def find_line_function(p0, p1):
        """
        Find line y=ax+b for each of the lines in the mesh
        https://mathworld.wolfram.com/Two-PointForm.html
        """
        # Line aligned with y axis
        if np.isclose(p1[0], p0[0]):
            return lambda x: np.isclose(x[0], p0[0])
        return lambda x: np.isclose(
            x[1], p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[0] - p0[0]))

    def over_line(p0, p1):
        """
        Check if a point is over or under y=ax+b for each of the
        lines in the mesh https://mathworld.wolfram.com/Two-PointForm.html
        """
        return lambda x: x[1] > p0[1] + (p1[1] - p0[1]) / (p1[0] - p0[0]) * (x[
            0] - p0[0])

    # Using built in meshes, stacking cubes on top of each other
    N = 15
    if celltype == "quadrilateral":
        ct = _mesh.CellType.quadrilateral
    elif celltype == "triangle":
        ct = _mesh.CellType.triangle
    else:
        raise ValueError("celltype has to be tri or quad")
    if MPI.COMM_WORLD.rank == 0:
        mesh0 = _mesh.create_unit_square(MPI.COMM_SELF, N, N, ct)
        mesh1 = _mesh.create_unit_square(MPI.COMM_SELF, 2 * N, 2 * N, ct)
        mesh0.geometry.x[:, 1] += 1

        # Stack the two meshes in one mesh
        r_matrix = _utils.rotation_matrix([0, 0, 1], theta)
        points = np.vstack([mesh0.geometry.x, mesh1.geometry.x])
        points = np.dot(r_matrix, points.T)
        points = points[:2, :].T

        # Transform topology info into geometry info
        tdim0 = mesh0.topology.dim
        num_cells0 = mesh0.topology.index_map(tdim0).size_local
        cells0 = _cpp.mesh.entities_to_geometry(
            mesh0, tdim0,
            np.arange(num_cells0, dtype=np.int32).reshape((-1, 1)), False)
        tdim1 = mesh1.topology.dim
        num_cells1 = mesh1.topology.index_map(tdim1).size_local
        cells1 = _cpp.mesh.entities_to_geometry(
            mesh1, tdim1,
            np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False)
        cells1 += mesh0.geometry.x.shape[0]

        cells = np.vstack([cells0, cells1])
        cell = ufl.Cell(celltype, geometric_dimension=points.shape[1])
        domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1))
        mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain)
        tdim = mesh.topology.dim
        fdim = tdim - 1

        # Find information about facets to be used in meshtags
        bottom_points = np.dot(
            r_matrix,
            np.array([[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]]).T)
        bottom = find_line_function(bottom_points[:, 0], bottom_points[:, 1])
        bottom_facets = _mesh.locate_entities_boundary(mesh, fdim, bottom)

        top_points = np.dot(
            r_matrix,
            np.array([[0, 1, 0], [1, 1, 0], [1, 2, 0], [0, 2, 0]]).T)
        top = find_line_function(top_points[:, 2], top_points[:, 3])
        top_facets = _mesh.locate_entities_boundary(mesh, fdim, top)

        left_side = find_line_function(top_points[:, 0], top_points[:, 3])
        left_facets = _mesh.locate_entities_boundary(mesh, fdim, left_side)

        right_side = find_line_function(top_points[:, 1], top_points[:, 2])
        right_facets = _mesh.locate_entities_boundary(mesh, fdim, right_side)

        top_cube = over_line(bottom_points[:, 2], bottom_points[:, 3])

        num_cells = mesh.topology.index_map(tdim).size_local
        cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim,
                                                     range(num_cells))
        interface = find_line_function(bottom_points[:, 2], bottom_points[:,
                                                                          3])
        i_facets = _mesh.locate_entities_boundary(mesh, fdim, interface)
        bottom_interface = []
        top_interface = []
        mesh.topology.create_connectivity(fdim, tdim)
        facet_to_cell = mesh.topology.connectivity(fdim, tdim)
        for facet in i_facets:
            i_cells = facet_to_cell.links(facet)
            assert (len(i_cells == 1))
            i_cell = i_cells[0]
            if top_cube(cell_midpoints[i_cell]):
                top_interface.append(facet)
            else:
                bottom_interface.append(facet)

        top_cube_marker = 2
        cell_indices = []
        cell_values = []
        for cell_index in range(num_cells):
            if top_cube(cell_midpoints[cell_index]):
                cell_indices.append(cell_index)
                cell_values.append(top_cube_marker)
        ct = _mesh.meshtags(mesh, tdim, np.array(cell_indices, dtype=np.intc),
                            np.array(cell_values, dtype=np.intc))

        # Create meshtags for facet data
        markers: Dict[int, np.ndarray] = {
            3: top_facets,
            4: np.hstack(bottom_interface),
            9: np.hstack(top_interface),
            5: bottom_facets,
            6: left_facets,
            7: right_facets
        }
        all_indices = []
        all_values = []

        for key in markers.keys():
            all_indices.append(markers[key])
            all_values.append(np.full(len(markers[key]), key, dtype=np.intc))
        arg_sort = np.argsort(np.hstack(all_indices))
        mt = _mesh.meshtags(mesh, fdim,
                            np.hstack(all_indices)[arg_sort],
                            np.hstack(all_values)[arg_sort])
        mt.name = "facet_tags"  # type: ignore
        with _io.XDMFFile(MPI.COMM_SELF,
                          f"meshes/mesh_{celltype}_{theta:.2f}.xdmf",
                          "w") as o_f:
            o_f.write_mesh(mesh)
            o_f.write_meshtags(ct)
            o_f.write_meshtags(mt)
    MPI.COMM_WORLD.barrier()
Пример #19
0
def mesh_3D_dolfin(theta: float = 0,
                   ct: _mesh.CellType = _mesh.CellType.tetrahedron,
                   ext: str = "tetrahedron",
                   res: float = 0.1):
    timer = _common.Timer("~~Contact: Create mesh")

    def find_plane_function(p0, p1, p2):
        """
        Find plane function given three points:
        http://www.nabla.hr/CG-LinesPlanesIn3DA3.htm
        """
        v1 = np.array(p1) - np.array(p0)
        v2 = np.array(p2) - np.array(p0)

        n = np.cross(v1, v2)
        D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2])
        return lambda x: np.isclose(0, np.dot(n, x) + D)

    def over_plane(p0, p1, p2):
        """
        Returns function that checks if a point is over a plane defined
        by the points p0, p1 and p2.
        """
        v1 = np.array(p1) - np.array(p0)
        v2 = np.array(p2) - np.array(p0)

        n = np.cross(v1, v2)
        D = -(n[0] * p0[0] + n[1] * p0[1] + n[2] * p0[2])
        return lambda x: n[0] * x[0] + n[1] * x[1] + D > -n[2] * x[2]

    N = int(1 / res)
    if MPI.COMM_WORLD.rank == 0:
        mesh0 = _mesh.create_unit_cube(MPI.COMM_SELF, N, N, N, ct)
        mesh1 = _mesh.create_unit_cube(MPI.COMM_SELF, 2 * N, 2 * N, 2 * N, ct)
        mesh0.geometry.x[:, 2] += 1

        # Stack the two meshes in one mesh
        r_matrix = _utils.rotation_matrix([1 / np.sqrt(2), 1 / np.sqrt(2), 0],
                                          -theta)
        points = np.vstack([mesh0.geometry.x, mesh1.geometry.x])
        points = np.dot(r_matrix, points.T).T

        # Transform topology info into geometry info
        tdim0 = mesh0.topology.dim
        num_cells0 = mesh0.topology.index_map(tdim0).size_local
        cells0 = _cpp.mesh.entities_to_geometry(
            mesh0, tdim0,
            np.arange(num_cells0, dtype=np.int32).reshape((-1, 1)), False)
        tdim1 = mesh1.topology.dim
        num_cells1 = mesh1.topology.index_map(tdim1).size_local
        cells1 = _cpp.mesh.entities_to_geometry(
            mesh1, tdim1,
            np.arange(num_cells1, dtype=np.int32).reshape((-1, 1)), False)
        cells1 += mesh0.geometry.x.shape[0]

        cells = np.vstack([cells0, cells1])
        cell = ufl.Cell(ext, geometric_dimension=points.shape[1])
        domain = ufl.Mesh(ufl.VectorElement("Lagrange", cell, 1))
        mesh = _mesh.create_mesh(MPI.COMM_SELF, cells, points, domain)
        tdim = mesh.topology.dim
        fdim = tdim - 1
        # Find information about facets to be used in meshtags
        bottom_points = np.dot(
            r_matrix,
            np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0]]).T)
        bottom = find_plane_function(bottom_points[:, 0], bottom_points[:, 1],
                                     bottom_points[:, 2])
        bottom_facets = _mesh.locate_entities_boundary(mesh, fdim, bottom)

        top_points = np.dot(
            r_matrix,
            np.array([[0, 0, 2], [1, 0, 2], [0, 1, 2], [1, 1, 2]]).T)
        top = find_plane_function(top_points[:, 0], top_points[:, 1],
                                  top_points[:, 2])
        top_facets = _mesh.locate_entities_boundary(mesh, fdim, top)

        # left_side = find_line_function(top_points[:, 0], top_points[:, 3])
        # left_facets = _mesh.locate_entities_boundary(
        #     mesh, fdim, left_side)

        # right_side = find_line_function(top_points[:, 1], top_points[:, 2])
        # right_facets = _mesh.locate_entities_boundary(
        #     mesh, fdim, right_side)
        if_points = np.dot(
            r_matrix,
            np.array([[0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]).T)

        interface = find_plane_function(if_points[:, 0], if_points[:, 1],
                                        if_points[:, 2])
        i_facets = _mesh.locate_entities_boundary(mesh, fdim, interface)
        mesh.topology.create_connectivity(fdim, tdim)
        top_interface = []
        bottom_interface = []
        facet_to_cell = mesh.topology.connectivity(fdim, tdim)
        num_cells = mesh.topology.index_map(tdim).size_local
        cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim,
                                                     range(num_cells))
        top_cube = over_plane(if_points[:, 0], if_points[:, 1], if_points[:,
                                                                          2])
        for facet in i_facets:
            i_cells = facet_to_cell.links(facet)
            assert (len(i_cells == 1))
            i_cell = i_cells[0]
            if top_cube(cell_midpoints[i_cell]):
                top_interface.append(facet)
            else:
                bottom_interface.append(facet)

        num_cells = mesh.topology.index_map(tdim).size_local
        cell_midpoints = _cpp.mesh.compute_midpoints(mesh, tdim,
                                                     range(num_cells))
        top_cube_marker = 2
        indices = []
        values = []
        for cell_index in range(num_cells):
            if top_cube(cell_midpoints[cell_index]):
                indices.append(cell_index)
                values.append(top_cube_marker)
        ct = _mesh.meshtags(mesh, tdim, np.array(indices, dtype=np.int32),
                            np.array(values, dtype=np.int32))

        # Create meshtags for facet data
        markers: Dict[int, np.ndarray] = {
            3: top_facets,
            4: np.hstack(bottom_interface),
            9: np.hstack(top_interface),
            5: bottom_facets
        }  # , 6: left_facets, 7: right_facets}
        all_indices = []
        all_values = []

        for key in markers.keys():
            all_indices.append(np.asarray(markers[key], dtype=np.int32))
            all_values.append(np.full(len(markers[key]), key, dtype=np.int32))
        arg_sort = np.argsort(np.hstack(all_indices))
        sorted_vals = np.asarray(np.hstack(all_values)[arg_sort],
                                 dtype=np.int32)
        sorted_indices = np.asarray(np.hstack(all_indices)[arg_sort],
                                    dtype=np.int32)
        mt = _mesh.meshtags(mesh, fdim, sorted_indices, sorted_vals)
        mt.name = "facet_tags"  # type: ignore
        fname = f"meshes/mesh_{ext}_{theta:.2f}.xdmf"

        with _io.XDMFFile(MPI.COMM_SELF, fname, "w") as o_f:
            o_f.write_mesh(mesh)
            o_f.write_meshtags(ct)
            o_f.write_meshtags(mt)
    timer.stop()
Пример #20
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_boundary(mesh, 1, noslip_boundary)
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_boundary(mesh, 1, lid)
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::

# Define variational problem
Пример #21
0
    def __init__(self, mesh, k, omega, c, wx, wy, amp):
        P = FiniteElement("Lagrange", mesh.ufl_cell(), k)
        self.V = FunctionSpace(mesh, P)
        self.u, self.v = Function(self.V), Function(self.V)
        self.g = Function(self.V)
        self.g_deriv = Function(self.V)
        self.omega = omega
        self.c = c
        self.a = amp

        # GEOMETRY: rectangular domain with 5mm radius piston on left wall
        #  |------------------------------------------------------------|
        #  |                                                            |
        #  |                                                            |
        #  ||                                                           |
        #  ||                                                           |
        #  || <-- 5mm radius piston                                     |
        #  ||                                                           |
        #  ||                                                           |
        #  |                                                            |
        #  |                                                            |
        #  |----------------------------------------------------------- |
        # Locate boundary facets
        tdim = mesh.topology.dim
        # facets0 belong to 5mm radius piston at x=0
        facets0 = locate_entities_boundary(mesh, tdim - 1,
                                           lambda x: (x[0] < 1.0e-6) *
                                           (np.abs(x[1]) < 5e-3))
        # facets1 belong to right hand wall, at x=wx
        facets1 = locate_entities_boundary(mesh, tdim - 1,
                                           lambda x: x[0] > (wx - 1.0e-6))
        # facets2 belong to top and bottom walls, at y=+wy/2 and y=-wy/2
        facets2 = locate_entities_boundary(mesh, tdim - 1,
                                           lambda x:
                                           np.abs(x[1]) > (wy / 2 - 1.0e-6))

        indices, pos = np.unique(np.hstack((facets0, facets1, facets2)),
                                 return_index=True)
        values = np.hstack((np.full(facets0.shape, 1, np.intc),
                            np.full(facets1.shape, 2, np.intc),
                            np.full(facets2.shape, 3, np.intc)))
        marker = dolfinx.mesh.MeshTags(mesh, tdim - 1, indices, values[pos])
        ds = ufl.Measure('ds', subdomain_data=marker, domain=mesh)

        # dv, p = TrialFunction(self.V), TestFunction(self.V)
        p = TestFunction(self.V)
        beta = 3.5
        delta0 = 3.0e-6
        delta = delta0

        # # EXPERIMENT: add absorbing layers to top and bottom ("PMLs")
        # def delta_fun(x):
        #     lam = 2 * np.pi / k
        #     depth = 2 * lam
        #     dist = np.abs(x[1]) - (wy/2 - depth)
        #     inside = (dist >= 0)
        #     # outside = (dist < 0)
        #     return delta0 + inside * (dist**2) * 1e3

        # delta = Function(self.V)
        # delta.interpolate(delta_fun)
        # delta.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
        #                          mode=PETSc.ScatterMode.FORWARD)

        # with XDMFFile(mesh.mpi_comm(), "delta.xdmf", "w",
        #               encoding=XDMFFile.Encoding.HDF5) as file:
        #     file.write_mesh(mesh)
        #     file.write_function(delta)

        # Westervelt equation
        self.L1 = - inner(grad(self.u), grad(p)) * dx \
            - (delta / c**2) * inner(grad(self.v), grad(p)) * dx \
            + (2 * beta / (rho * c**4)) * inner(self.v * self.v, p) * dx \
            - (1 / c) * inner(self.v, p) * ds \
            + inner(self.g, p) * ds(1) \
            + (delta / c**2) * inner(self.g_deriv, p) * ds(1)

        self.lumped = True
        # Vector to be re-used for assembly
        self.b = None

        # TODO: precompile/pre-process Form L

        if self.lumped:
            # Westervelt equation
            a = (1 / c**2) * \
                (1 - 2 * beta * self.u / (rho * c**2)) * p * dx(degree=k) \
                + (delta / c**3) * p * ds

            self.M = dolfinx.fem.assemble_vector(a)
            self.M.ghostUpdate(addv=PETSc.InsertMode.ADD,
                               mode=PETSc.ScatterMode.REVERSE)
        else:
            # TODO: non-lumped version of Westervelt
            # a = (1 / self.c**2) * inner(dv, p) * dx(degree=k * k)
            M = dolfinx.fem.assemble_matrix(a)
            M.assemble()
            self.solver = PETSc.KSP().create(mesh.mpi_comm())
            opts = PETSc.Options()
            opts["ksp_type"] = "cg"
            opts["ksp_rtol"] = 1.0e-8
            self.solver.setFromOptions()
            self.solver.setOperators(M)
Пример #22
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_boundary(
    mesh, 1, lambda x: np.logical_or(x[0] < np.finfo(float).eps, x[0] > 1.0 -
                                     np.finfo(float).eps))
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.
#
Пример #23
0
def test_pipeline(u_from_mpc):

    # Create mesh and function space
    mesh = create_unit_square(MPI.COMM_WORLD, 5, 5)
    V = fem.FunctionSpace(mesh, ("Lagrange", 1))

    # Solve Problem without MPC for reference
    u = ufl.TrialFunction(V)
    v = ufl.TestFunction(V)
    d = fem.Constant(mesh, PETSc.ScalarType(0.01))
    x = ufl.SpatialCoordinate(mesh)
    f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1])
    a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx - d * ufl.inner(u, v) * ufl.dx
    rhs = ufl.inner(f, v) * ufl.dx
    bilinear_form = fem.form(a)
    linear_form = fem.form(rhs)

    # Generate reference matrices
    A_org = fem.petsc.assemble_matrix(bilinear_form)
    A_org.assemble()
    L_org = fem.petsc.assemble_vector(linear_form)
    L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE)

    # Create multipoint constraint
    def periodic_relation(x):
        out_x = np.copy(x)
        out_x[0] = 1 - x[0]
        return out_x

    def PeriodicBoundary(x):
        return np.isclose(x[0], 1)

    facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary)
    arg_sort = np.argsort(facets)
    mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32))

    mpc = dolfinx_mpc.MultiPointConstraint(V)
    mpc.create_periodic_constraint_topological(V, mt, 2, periodic_relation, [], 1)
    mpc.finalize()

    if u_from_mpc:
        uh = fem.Function(mpc.function_space)
        problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh,
                                            petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
        problem.solve()

        root = 0
        dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root)
        dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root)

        # Gather LHS, RHS and solution on one process
        A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root)
        K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root)
        L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root)
        u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh.vector, root=root)

        if MPI.COMM_WORLD.rank == root:
            KTAK = K.T * A_csr * K
            reduced_L = K.T @ L_np
            # Solve linear system
            d = scipy.sparse.linalg.spsolve(KTAK, reduced_L)
            # Back substitution to full solution vector
            uh_numpy = K @ d
            assert np.allclose(uh_numpy, u_mpc)

    else:
        uh = fem.Function(V)
        with pytest.raises(ValueError):
            problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh,
                                                petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
            problem.solve()
def demo_periodic3D(celltype: CellType):
    # Create mesh and finite element
    if celltype == CellType.tetrahedron:
        # Tet setup
        N = 10
        mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N)
        V = fem.VectorFunctionSpace(mesh, ("CG", 1))
    else:
        # Hex setup
        N = 10
        mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron)
        V = fem.VectorFunctionSpace(mesh, ("CG", 2))

    def dirichletboundary(x: NDArray[np.float64]) -> NDArray[np.bool_]:
        return np.logical_or(
            np.logical_or(np.isclose(x[1], 0), np.isclose(x[1], 1)),
            np.logical_or(np.isclose(x[2], 0), np.isclose(x[2], 1)))

    # Create Dirichlet boundary condition
    zero = PETSc.ScalarType([0, 0, 0])
    geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary)
    bc = fem.dirichletbc(zero, geometrical_dofs, V)
    bcs = [bc]

    def PeriodicBoundary(x):
        return np.isclose(x[0], 1)

    facets = locate_entities_boundary(mesh, mesh.topology.dim - 1,
                                      PeriodicBoundary)
    arg_sort = np.argsort(facets)
    mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort],
                  np.full(len(facets), 2, dtype=np.int32))

    def periodic_relation(x):
        out_x = np.zeros(x.shape)
        out_x[0] = 1 - x[0]
        out_x[1] = x[1]
        out_x[2] = x[2]
        return out_x

    with Timer("~~Periodic: Compute mpc condition"):
        mpc = dolfinx_mpc.MultiPointConstraint(V)
        mpc.create_periodic_constraint_topological(V.sub(0), mt, 2,
                                                   periodic_relation, bcs, 1)
        mpc.finalize()
    # Define variational problem
    u = TrialFunction(V)
    v = TestFunction(V)
    a = inner(grad(u), grad(v)) * dx

    x = SpatialCoordinate(mesh)
    dx_ = x[0] - 0.9
    dy_ = x[1] - 0.5
    dz_ = x[2] - 0.1
    f = as_vector((x[0] * sin(5.0 * pi * x[1]) +
                   1.0 * exp(-(dx_ * dx_ + dy_ * dy_ + dz_ * dz_) / 0.02),
                   0.1 * dx_ * dz_, 0.1 * dx_ * dy_))

    rhs = inner(f, v) * dx

    petsc_options: Dict[str, Union[str, float, int]]
    if complex_mode:
        rtol = 1e-16
        petsc_options = {"ksp_type": "preonly", "pc_type": "lu"}
    else:
        rtol = 1e-8
        petsc_options = {
            "ksp_type": "cg",
            "ksp_rtol": rtol,
            "pc_type": "hypre",
            "pc_hypre_typ": "boomeramg",
            "pc_hypre_boomeramg_max_iter": 1,
            "pc_hypre_boomeramg_cycle_type": "v",
            "pc_hypre_boomeramg_print_statistics": 1
        }
    problem = LinearProblem(a, rhs, mpc, bcs, petsc_options=petsc_options)
    u_h = problem.solve()

    # --------------------VERIFICATION-------------------------
    print("----Verification----")
    u_ = fem.Function(V)
    u_.x.array[:] = 0
    org_problem = fem.petsc.LinearProblem(a,
                                          rhs,
                                          u=u_,
                                          bcs=bcs,
                                          petsc_options=petsc_options)
    with Timer("~Periodic: Unconstrained solve"):
        org_problem.solve()
        it = org_problem.solver.getIterationNumber()
    print(f"Unconstrained solver iterations: {it}")

    # Write solutions to file
    ext = "tet" if celltype == CellType.tetrahedron else "hex"
    u_.name = "u_" + ext + "_unconstrained"

    # NOTE: Workaround as tabulate dof coordinates does not like extra ghosts
    u_out = fem.Function(V)
    old_local = u_out.x.map.size_local * u_out.x.bs
    old_ghosts = u_out.x.map.num_ghosts * u_out.x.bs
    mpc_local = u_h.x.map.size_local * u_h.x.bs
    assert (old_local == mpc_local)
    u_out.x.array[:old_local + old_ghosts] = u_h.x.array[:mpc_local +
                                                         old_ghosts]
    u_out.name = "u_" + ext
    fname = f"results/demo_periodic3d_{ext}.bp"
    out_periodic = VTXWriter(MPI.COMM_WORLD, fname, u_out)
    out_periodic.write(0)
    out_periodic.close()

    root = 0
    with Timer("~Demo: Verification"):
        dolfinx_mpc.utils.compare_mpc_lhs(org_problem.A,
                                          problem.A,
                                          mpc,
                                          root=root)
        dolfinx_mpc.utils.compare_mpc_rhs(org_problem.b,
                                          problem.b,
                                          mpc,
                                          root=root)

        # Gather LHS, RHS and solution on one process
        A_csr = dolfinx_mpc.utils.gather_PETScMatrix(org_problem.A, root=root)
        K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root)
        L_np = dolfinx_mpc.utils.gather_PETScVector(org_problem.b, root=root)
        u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root)

        if MPI.COMM_WORLD.rank == root:
            KTAK = K.T * A_csr * K
            reduced_L = K.T @ L_np
            # Solve linear system
            d = scipy.sparse.linalg.spsolve(KTAK, reduced_L)
            # Back substitution to full solution vector
            uh_numpy = K @ d
            assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
Пример #25
0
Ny = 20

mesh = BoxMesh(MPI.COMM_WORLD,
               [np.array([0.0, 0.0, 0.0]),
                np.array([xdim, ydim, zdim])], [Nx, Ny, Nz])


def right_side(x):
    return np.isclose(x[1], ydim)


def left_side(x):
    return np.isclose(x[1], 0.0)


left_side_facets = locate_entities_boundary(mesh, 2, left_side)
right_side_facets = locate_entities_boundary(mesh, 2, right_side)

mt = MeshTags(mesh, 2, right_side_facets, 1)

# External boundary facets
ds = ufl.Measure("ds", domain=mesh, subdomain_data=mt)
dx = ufl.Measure("dx", domain=mesh)

load_area = mesh.mpi_comm().allreduce(
    assemble_scalar(1.0 * ds(1, domain=mesh)), MPI.SUM)

if rank == 0:
    logger.info("Mesh hmin={} hmax={}".format(mesh.hmin(), mesh.hmax()))
    logger.info(f"Load area = {load_area}")
Пример #26
0
def test_assembly_ds_domains(mode):
    mesh = dolfinx.generation.UnitSquareMesh(MPI.COMM_WORLD, 10, 10, ghost_mode=mode)
    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_boundary(mesh, mesh.topology.dim - 1, bottom)
    bottom_vals = numpy.full(bottom_facets.shape, 1, numpy.intc)

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

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

    right_facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, right)
    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)

    bc = dolfinx.fem.DirichletBC(dolfinx.Function(V), range(30))

    # 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)

    dolfinx.fem.apply_lifting(b, [a], [[bc]])
    b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES,
                  mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.set_bc(b, [bc])

    L2 = ufl.inner(w, v) * ds
    b2 = dolfinx.fem.assemble_vector(L2)
    dolfinx.fem.apply_lifting(b2, [a2], [[bc]])
    b2.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES,
                   mode=PETSc.ScatterMode.REVERSE)
    dolfinx.fem.set_bc(b2, [bc])

    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))
Пример #27
0
def demo_elasticity():
    mesh = create_unit_square(MPI.COMM_WORLD, 10, 10)

    V = fem.VectorFunctionSpace(mesh, ("Lagrange", 1))

    # Generate Dirichlet BC on lower boundary (Fixed)

    def boundaries(x):
        return np.isclose(x[0], np.finfo(float).eps)

    facets = locate_entities_boundary(mesh, 1, boundaries)
    topological_dofs = fem.locate_dofs_topological(V, 1, facets)
    bc = fem.dirichletbc(np.array([0, 0], dtype=PETSc.ScalarType),
                         topological_dofs, V)
    bcs = [bc]

    # Define variational problem
    u = TrialFunction(V)
    v = TestFunction(V)

    # Elasticity parameters
    E = PETSc.ScalarType(1.0e4)
    nu = 0.0
    mu = fem.Constant(mesh, E / (2.0 * (1.0 + nu)))
    lmbda = fem.Constant(mesh, 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(len(v)))

    x = SpatialCoordinate(mesh)
    # Define variational problem
    u = TrialFunction(V)
    v = TestFunction(V)
    a = inner(sigma(u), grad(v)) * dx
    rhs = inner(as_vector((0, (x[0] - 0.5) * 10**4 * x[1])), v) * dx

    # Create MPC
    def l2b(li):
        return np.array(li, dtype=np.float64).tobytes()

    s_m_c = {l2b([1, 0]): {l2b([1, 1]): 0.9}}
    mpc = MultiPointConstraint(V)
    mpc.create_general_constraint(s_m_c, 1, 1)
    mpc.finalize()

    # Solve Linear problem
    petsc_options = {"ksp_type": "preonly", "pc_type": "lu"}
    problem = LinearProblem(a, rhs, mpc, bcs=bcs, petsc_options=petsc_options)
    u_h = problem.solve()
    u_h.name = "u_mpc"
    with XDMFFile(MPI.COMM_WORLD, "results/demo_elasticity.xdmf",
                  "w") as outfile:
        outfile.write_mesh(mesh)
        outfile.write_function(u_h)

    # Solve the MPC problem using a global transformation matrix
    # and numpy solvers to get reference values
    bilinear_form = fem.form(a)
    A_org = fem.petsc.assemble_matrix(bilinear_form, bcs)
    A_org.assemble()
    linear_form = fem.form(rhs)
    L_org = fem.petsc.assemble_vector(linear_form)
    fem.petsc.apply_lifting(L_org, [bilinear_form], [bcs])
    L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES,
                      mode=PETSc.ScatterMode.REVERSE)
    fem.petsc.set_bc(L_org, bcs)
    solver = PETSc.KSP().create(MPI.COMM_WORLD)
    solver.setType(PETSc.KSP.Type.PREONLY)
    solver.getPC().setType(PETSc.PC.Type.LU)
    solver.setOperators(A_org)
    u_ = fem.Function(V)
    solver.solve(L_org, u_.vector)
    u_.x.scatter_forward()
    u_.name = "u_unconstrained"

    with XDMFFile(MPI.COMM_WORLD, "results/demo_elasticity.xdmf",
                  "a") as outfile:
        outfile.write_function(u_)
        outfile.close()

    root = 0
    with Timer("~Demo: Verification"):
        dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root)
        dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root)

        # Gather LHS, RHS and solution on one process
        A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root)
        K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root)
        L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root)
        u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root)

        if MPI.COMM_WORLD.rank == root:
            KTAK = K.T * A_csr * K
            reduced_L = K.T @ L_np
            # Solve linear system
            d = scipy.sparse.linalg.spsolve(KTAK, reduced_L)
            # Back substitution to full solution vector
            uh_numpy = K @ d
            assert np.allclose(uh_numpy, u_mpc)

    # Print out master-slave connectivity for the first slave
    master_owner = None
    master_data = None
    slave_owner = None
    if mpc.num_local_slaves > 0:
        slave_owner = MPI.COMM_WORLD.rank
        bs = mpc.function_space.dofmap.index_map_bs
        slave = mpc.slaves[0]
        print("Constrained: {0:.5e}\n Unconstrained: {1:.5e}".format(
            u_h.x.array[slave], u_.vector.array[slave]))
        master_owner = mpc._cpp_object.owners.links(slave)[0]
        _masters = mpc.masters
        master = _masters.links(slave)[0]
        glob_master = mpc.function_space.dofmap.index_map.local_to_global(
            [master // bs])[0]
        coeffs, offs = mpc.coefficients()
        master_data = [
            glob_master * bs + master % bs,
            coeffs[offs[slave]:offs[slave + 1]][0]
        ]
        # If master not on proc send info to this processor
        if MPI.COMM_WORLD.rank != master_owner:
            MPI.COMM_WORLD.send(master_data, dest=master_owner, tag=1)
        else:
            print("Master*Coeff: {0:.5e}".format(
                coeffs[offs[slave]:offs[slave + 1]][0] *
                u_h.x.array[_masters.links(slave)[0]]))
    # As a processor with a master is not aware that it has a master,
    # Determine this so that it can receive the global dof and coefficient
    master_recv = MPI.COMM_WORLD.allgather(master_owner)
    for master in master_recv:
        if master is not None:
            master_owner = master
            break
    if slave_owner != master_owner and MPI.COMM_WORLD.rank == master_owner:
        dofmap = mpc.function_space.dofmap
        bs = dofmap.index_map_bs
        in_data = MPI.COMM_WORLD.recv(source=MPI.ANY_SOURCE, tag=1)
        num_local = dofmap.index_map.size_local + dofmap.index_map.num_ghosts
        l2g = dofmap.index_map.local_to_global(
            np.arange(num_local, dtype=np.int32))
        l_index = np.flatnonzero(l2g == in_data[0] // bs)[0]
        print("Master*Coeff (on other proc): {0:.5e}".format(
            u_h.x.array[l_index * bs + in_data[0] % bs] * in_data[1]))
Пример #28
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_boundary(mesh, facetdim, boundary)

    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)
sigma, tau = ufl.TrialFunction(S), ufl.TestFunction(S)
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_boundary(mesh, 1, free_end)
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_boundary(mesh, 1, left)
bdofs = locate_dofs_topological(U, 1, left_facets)
bc = dolfinx.fem.DirichletBC(u_bc, bdofs)

# Elastic stiffness tensor and Poisson ratio
Пример #30
0
# The second argument to {py:class}`FunctionSpace
# <dolfinx.fem.FunctionSpace>` is a tuple consisting of `(family,
# degree)`, where `family` is the finite element family, and `degree`
# specifies the polynomial degree. in this case `V` consists of
# first-order, continuous Lagrange finite element functions.
#
# Next, we locate the mesh facets that lie on the boundary $\Gamma_D$.
# We do this using using {py:func}`locate_entities_boundary
# <dolfinx.mesh.locate_entities_boundary>` and providing  a marker
# function that returns `True` for points `x` on the boundary and
# `False` otherwise.

facets = mesh.locate_entities_boundary(
    msh,
    dim=1,
    marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(
        x[0], 2.0)))

# We now find the degrees-of-freedom that are associated with the
# boundary facets using {py:func}`locate_dofs_topological
# <dolfinx.fem.locate_dofs_topological>`

dofs = fem.locate_dofs_topological(V=V, entity_dim=1, entities=facets)

# and use {py:func}`dirichletbc <dolfinx.fem.dirichletbc>` to create a
# {py:class}`DirichletBCMetaClass <dolfinx.fem.DirichletBCMetaClass>`
# class that represents the boundary condition

bc = fem.dirichletbc(value=ScalarType(0), dofs=dofs, V=V)