Esempio n. 1
0
def test_submesh_cell_assembly(d, n, k, space, ghost_mode):
    """Check that assembling a form over a unit square gives the same
    result as assembling over half of a 2x1 rectangle with the same
    triangulation."""
    if d == 2:
        mesh_0 = create_unit_square(
            MPI.COMM_WORLD, n, n, ghost_mode=ghost_mode)
        mesh_1 = create_rectangle(
            MPI.COMM_WORLD, ((0.0, 0.0), (2.0, 1.0)), (2 * n, n),
            ghost_mode=ghost_mode)
    else:
        mesh_0 = create_unit_cube(
            MPI.COMM_WORLD, n, n, n, ghost_mode=ghost_mode)
        mesh_1 = create_box(
            MPI.COMM_WORLD, ((0.0, 0.0, 0.0), (2.0, 1.0, 1.0)),
            (2 * n, n, n), ghost_mode=ghost_mode)

    A_mesh_0 = assemble(mesh_0, space, k)

    edim = mesh_1.topology.dim
    entities = locate_entities(mesh_1, edim, lambda x: x[0] <= 1.0)
    submesh = create_submesh(mesh_1, edim, entities)[0]
    A_submesh = assemble(submesh, space, k)

    # FIXME Would probably be better to compare entries rather than just
    # norms
    assert(np.isclose(A_mesh_0.norm(), A_submesh.norm()))
Esempio n. 2
0
def mesh2d():
    """Create 2D mesh with one equilateral triangle"""
    mesh2d = create_rectangle(
        MPI.COMM_WORLD,
        [np.array([0.0, 0.0]), np.array([1., 1.])], [1, 1], CellType.triangle,
        GhostMode.none, create_cell_partitioner(), DiagonalType.left)
    i1 = np.where((mesh2d.geometry.x == (1, 1, 0)).all(axis=1))[0][0]
    mesh2d.geometry.x[i1, :2] += 0.5 * (math.sqrt(3.0) - 1.0)
    return mesh2d
Esempio n. 3
0
def test_basic_interior_facet_assembly():
    mesh = create_rectangle(MPI.COMM_WORLD, [np.array([0.0, 0.0]), np.array([1.0, 1.0])],
                            [5, 5], cell_type=CellType.triangle,
                            ghost_mode=GhostMode.shared_facet)
    V = FunctionSpace(mesh, ("DG", 1))
    u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    a = ufl.inner(ufl.avg(u), ufl.avg(v)) * ufl.dS
    a = form(a)
    A = assemble_matrix(a)
    A.assemble()
    assert isinstance(A, PETSc.Mat)

    L = ufl.conj(ufl.avg(v)) * ufl.dS
    L = form(L)
    b = assemble_vector(L)
    b.assemble()
    assert isinstance(b, PETSc.Vec)
Esempio n. 4
0
from ufl import ds, dx, grad, inner

from mpi4py import MPI
from petsc4py.PETSc import ScalarType
# -

# We begin by using {py:func}`create_rectangle
# <dolfinx.mesh.create_rectangle>` to create a rectangular
# {py:class}`Mesh <dolfinx.mesh.Mesh>` of the domain, and creating a
# finite element {py:class}`FunctionSpace <dolfinx.fem.FunctionSpace>`
# $V$ on the mesh.

# +
msh = mesh.create_rectangle(
    comm=MPI.COMM_WORLD,
    points=((0.0, 0.0), (2.0, 1.0)),
    n=(32, 16),
    cell_type=mesh.CellType.triangle,
)
V = fem.FunctionSpace(msh, ("Lagrange", 1))
# -

# 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
Esempio n. 5
0
from dolfinx import common, fem, mesh, plot

from mpi4py import MPI

# -

# SciPy solvers do no support MPI, so all computations are performed on
# a single MPI rank

# +
comm = MPI.COMM_SELF
# -

# Create a mesh and function space

msh = mesh.create_rectangle(comm=comm, points=((0.0, 0.0), (2.0, 1.0)), n=(32, 16),
                            cell_type=mesh.CellType.triangle)
V = fem.FunctionSpace(msh, ("Lagrange", 1))

# Define a variartional problem
u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
x = ufl.SpatialCoordinate(msh)
fr = 10 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02)
fc = ufl.sin(2 * np.pi * x[0]) + 10 * ufl.sin(4 * np.pi * x[1]) * 1j
gr = ufl.sin(5 * x[0])
gc = ufl.sin(5 * x[0]) * 1j
a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
L = ufl.inner(fr + fc, v) * ufl.dx + ufl.inner(gr + gc, v) * ufl.ds


# In preparation for constructing Dirichlet boundary conditions, locate
# facets on the constrained boundary and the corresponding
Esempio n. 6
0
from dolfinx.mesh import CellType, create_rectangle, locate_entities_boundary
from ufl import ds, dx, grad, inner

from mpi4py import MPI
from petsc4py.PETSc import ScalarType

# We begin by defining a mesh of the domain and a finite element
# function space :math:`V` relative to this mesh. As the unit square is
# a very standard domain, we can use a built-in mesh provided by the
# class :py:class:`create_unit_square_mesh
# <dolfinx.mesh.create_unit_square_mesh>`. In order to create a mesh
# consisting of 32 x 32 squares with each square divided into two
# triangles, we do as follows ::

# Create mesh and define function space
mesh = create_rectangle(MPI.COMM_WORLD, ((0.0, 0.0), (2.0, 1.0)), (32, 16),
                        CellType.triangle)
V = FunctionSpace(mesh, ("Lagrange", 1))

# The second argument to :py:class:`FunctionSpace
# <dolfinx.fem.FunctionSpace>` is the finite element family, while the
# third argument specifies the polynomial degree. Thus, in this case,
# our space ``V`` consists of first-order, continuous Lagrange finite
# element functions (or in order words, continuous piecewise linear
# polynomials).
#
# Next, we want to consider the Dirichlet boundary condition. A simple
# Python function, returning a boolean, can be used to define the
# boundary for the Dirichlet boundary condition (:math:`\Gamma_D`). The
# function should return ``True`` for those points inside the boundary
# and ``False`` for the points outside. In our case, we want to say that
# the points :math:`(x, y)` such that :math:`x = 0` or :math:`x = 1` are
Esempio n. 7
0
def test_biharmonic():
    """Manufactured biharmonic problem.

    Solved using rotated Regge mixed finite element method. This is equivalent
    to the Hellan-Herrmann-Johnson (HHJ) finite element method in
    two-dimensions."""
    mesh = create_rectangle(
        MPI.COMM_WORLD,
        [np.array([0.0, 0.0]), np.array([1.0, 1.0])], [32, 32],
        CellType.triangle)

    element = ufl.MixedElement([
        ufl.FiniteElement("Regge", ufl.triangle, 1),
        ufl.FiniteElement("Lagrange", ufl.triangle, 2)
    ])

    V = FunctionSpace(mesh, element)
    sigma, u = ufl.TrialFunctions(V)
    tau, v = ufl.TestFunctions(V)

    x = ufl.SpatialCoordinate(mesh)
    u_exact = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[0]) * ufl.sin(
        ufl.pi * x[1]) * ufl.sin(ufl.pi * x[1])
    f_exact = div(grad(div(grad(u_exact))))
    sigma_exact = grad(grad(u_exact))

    # sigma and tau are tangential-tangential continuous according to the
    # H(curl curl) continuity of the Regge space. However, for the biharmonic
    # problem we require normal-normal continuity H (div div). Theorem 4.2 of
    # Lizao Li's PhD thesis shows that the latter space can be constructed by
    # the former through the action of the operator S:
    def S(tau):
        return tau - ufl.Identity(2) * ufl.tr(tau)

    sigma_S = S(sigma)
    tau_S = S(tau)

    # Discrete duality inner product eq. 4.5 Lizao Li's PhD thesis
    def b(tau_S, v):
        n = FacetNormal(mesh)
        return inner(tau_S, grad(grad(v))) * dx \
            - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \
            - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds

    # Non-symmetric formulation
    a = form(inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v))
    L = form(inner(f_exact, v) * dx)

    V_1 = V.sub(1).collapse()[0]
    zero_u = Function(V_1)
    zero_u.x.array[:] = 0.0

    # Strong (Dirichlet) boundary condition
    boundary_facets = locate_entities_boundary(
        mesh, mesh.topology.dim - 1,
        lambda x: np.full(x.shape[1], True, dtype=bool))
    boundary_dofs = locate_dofs_topological(
        (V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets)

    bcs = [dirichletbc(zero_u, boundary_dofs, V.sub(1))]

    A = assemble_matrix(a, bcs=bcs)
    A.assemble()
    b = assemble_vector(L)
    apply_lifting(b, [a], bcs=[bcs])
    b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE)
    set_bc(b, bcs)

    # Solve
    solver = PETSc.KSP().create(MPI.COMM_WORLD)
    PETSc.Options()["ksp_type"] = "preonly"
    PETSc.Options()["pc_type"] = "lu"
    # PETSc.Options()["pc_factor_mat_solver_type"] = "mumps"
    solver.setFromOptions()
    solver.setOperators(A)

    x_h = Function(V)
    solver.solve(b, x_h.vector)
    x_h.x.scatter_forward()

    # Recall that x_h has flattened indices.
    u_error_numerator = np.sqrt(
        mesh.comm.allreduce(assemble_scalar(
            form(
                inner(u_exact - x_h[4], u_exact - x_h[4]) *
                dx(mesh, metadata={"quadrature_degree": 5}))),
                            op=MPI.SUM))
    u_error_denominator = np.sqrt(
        mesh.comm.allreduce(assemble_scalar(
            form(
                inner(u_exact, u_exact) *
                dx(mesh, metadata={"quadrature_degree": 5}))),
                            op=MPI.SUM))

    assert np.absolute(u_error_numerator / u_error_denominator) < 0.05

    # Reconstruct tensor from flattened indices.
    # Apply inverse transform. In 2D we have S^{-1} = S.
    sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]]))
    sigma_error_numerator = np.sqrt(
        mesh.comm.allreduce(assemble_scalar(
            form(
                inner(sigma_exact - sigma_h, sigma_exact - sigma_h) *
                dx(mesh, metadata={"quadrature_degree": 5}))),
                            op=MPI.SUM))
    sigma_error_denominator = np.sqrt(
        mesh.comm.allreduce(assemble_scalar(
            form(
                inner(sigma_exact, sigma_exact) *
                dx(mesh, metadata={"quadrature_degree": 5}))),
                            op=MPI.SUM))

    assert np.absolute(sigma_error_numerator / sigma_error_denominator) < 0.005
Esempio n. 8
0
def test_curl_curl_eigenvalue(family, order):
    """curl curl eigenvalue problem.

    Solved using H(curl)-conforming finite element method.
    See https://www-users.cse.umn.edu/~arnold/papers/icm2002.pdf for details.
    """
    slepc4py = pytest.importorskip("slepc4py")  # noqa: F841
    from slepc4py import SLEPc

    mesh = create_rectangle(
        MPI.COMM_WORLD,
        [np.array([0.0, 0.0]), np.array([np.pi, np.pi])], [24, 24],
        CellType.triangle)

    element = ufl.FiniteElement(family, ufl.triangle, order)
    V = FunctionSpace(mesh, element)

    u = ufl.TrialFunction(V)
    v = ufl.TestFunction(V)

    a = inner(ufl.curl(u), ufl.curl(v)) * dx
    b = inner(u, v) * dx

    boundary_facets = locate_entities_boundary(
        mesh, mesh.topology.dim - 1,
        lambda x: np.full(x.shape[1], True, dtype=bool))
    boundary_dofs = locate_dofs_topological(V, mesh.topology.dim - 1,
                                            boundary_facets)

    zero_u = Function(V)
    zero_u.x.array[:] = 0.0
    bcs = [dirichletbc(zero_u, boundary_dofs)]

    a, b = form(a), form(b)

    A = assemble_matrix(a, bcs=bcs)
    A.assemble()

    B = assemble_matrix(b, bcs=bcs, diagonal=0.01)
    B.assemble()

    eps = SLEPc.EPS().create()
    eps.setOperators(A, B)
    PETSc.Options()["eps_type"] = "krylovschur"
    PETSc.Options()["eps_gen_hermitian"] = ""
    PETSc.Options()["eps_target_magnitude"] = ""
    PETSc.Options()["eps_target"] = 5.0
    PETSc.Options()["eps_view"] = ""
    PETSc.Options()["eps_nev"] = 12
    eps.setFromOptions()
    eps.solve()

    num_converged = eps.getConverged()
    eigenvalues_unsorted = np.zeros(num_converged, dtype=np.complex128)

    for i in range(0, num_converged):
        eigenvalues_unsorted[i] = eps.getEigenvalue(i)

    assert np.isclose(np.imag(eigenvalues_unsorted), 0.0).all()
    eigenvalues_sorted = np.sort(np.real(eigenvalues_unsorted))[:-1]
    eigenvalues_sorted = eigenvalues_sorted[np.logical_not(
        eigenvalues_sorted < 1E-8)]

    eigenvalues_exact = np.array([1.0, 1.0, 2.0, 4.0, 4.0, 5.0, 5.0, 8.0, 9.0])
    assert np.isclose(eigenvalues_sorted[0:eigenvalues_exact.shape[0]],
                      eigenvalues_exact,
                      rtol=1E-2).all()
Esempio n. 9
0
                         locate_dofs_geometrical, locate_dofs_topological)
from dolfinx.io import XDMFFile
from dolfinx.mesh import (CellType, GhostMode, create_rectangle,
                          locate_entities_boundary)
from ufl import div, dx, grad, inner

from mpi4py import MPI
from petsc4py import PETSc
# -

# We create a Mesh and attach a coordinate map to the mesh:

# +
# Create mesh
msh = create_rectangle(MPI.COMM_WORLD,
                       [np.array([0, 0]), np.array([1, 1])], [32, 32],
                       CellType.triangle, GhostMode.none)


# Function to mark x = 0, x = 1 and y = 0
def noslip_boundary(x):
    return np.logical_or(
        np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 1.0)),
        np.isclose(x[1], 0.0))


# Function to mark the lid (y = 1)
def lid(x):
    return np.isclose(x[1], 1.0)

def test_div_grad_then_integrate_over_cells_and_boundary():

    # Define 2D geometry
    n = 10
    mesh = create_rectangle(
        [np.array([0.0, 0.0]), np.array([2.0, 3.0])], 2 * n, 3 * n)

    x, y = SpatialCoordinate(mesh)
    xs = 0.1 + 0.8 * x / 2  # scaled to be within [0.1,0.9]
    # ys = 0.1 + 0.8 * y / 3  # scaled to be within [0.1,0.9]
    n = FacetNormal(mesh)

    # Define list of expressions to test, and configure accuracies
    # these expressions are known to pass with.  The reason some
    # functions are less accurately integrated is likely that the
    # default choice of quadrature rule is not perfect
    F_list = []

    def reg(exprs, acc=10):
        for expr in exprs:
            F_list.append((expr, acc))

    # FIXME: 0*dx and 1*dx fails in the ufl-ffcx-jit framework somewhere
    # reg([Constant(0.0, cell=cell)])
    # reg([Constant(1.0, cell=cell)])
    monomial_list = [x**q for q in range(2, 6)]
    reg(monomial_list)
    reg([2.3 * p + 4.5 * q for p in monomial_list for q in monomial_list])
    reg([xs**xs])
    reg(
        [xs**(xs**2)], 8
    )  # Note: Accuracies here are from 1D case, not checked against 2D results.
    reg([xs**(xs**3)], 6)
    reg([xs**(xs**4)], 2)
    # Special functions:
    reg([atan(xs)], 8)
    reg([sin(x), cos(x), exp(x)], 5)
    reg([ln(xs), pow(x, 2.7), pow(2.7, x)], 3)
    reg([asin(xs), acos(xs)], 1)
    reg([tan(xs)], 7)

    # To handle tensor algebra, make an x dependent input tensor
    # xx and square all expressions
    def reg2(exprs, acc=10):
        for expr in exprs:
            F_list.append((inner(expr, expr), acc))

    xx = as_matrix([[2 * x**2, 3 * x**3], [11 * x**5, 7 * x**4]])
    xxs = as_matrix([[2 * xs**2, 3 * xs**3], [11 * xs**5, 7 * xs**4]])
    x3v = as_vector([3 * x**2, 5 * x**3, 7 * x**4])
    cc = as_matrix([[2, 3], [4, 5]])
    reg2(
        [xx]
    )  # TODO: Make unit test for UFL from this, results in listtensor with free indices
    reg2([x3v])
    reg2([cross(3 * x3v, as_vector([-x3v[1], x3v[0], x3v[2]]))])
    reg2([xx.T])
    reg2([tr(xx)])
    reg2([det(xx)])
    reg2([dot(xx, 0.1 * xx)])
    reg2([outer(xx, xx.T)])
    reg2([dev(xx)])
    reg2([sym(xx)])
    reg2([skew(xx)])
    reg2([elem_mult(7 * xx, cc)])
    reg2([elem_div(7 * xx, xx + cc)])
    reg2([elem_pow(1e-3 * xxs, 1e-3 * cc)])
    reg2([elem_pow(1e-3 * cc, 1e-3 * xx)])
    reg2([elem_op(lambda z: sin(z) + 2, 0.03 * xx)], 2)  # pretty inaccurate...

    # FIXME: Add tests for all UFL operators:
    # These cause discontinuities and may be harder to test in the
    # above fashion:
    # 'inv', 'cofac',
    # 'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not',
    # 'conditional', 'sign',
    # 'jump', 'avg',
    # 'LiftingFunction', 'LiftingOperator',

    # FIXME: Test other derivatives: (but algorithms for operator
    # derivatives are the same!):
    # 'variable', 'diff',
    # 'Dx', 'grad', 'div', 'curl', 'rot', 'Dn', 'exterior_derivative',

    # Run through all operators defined above and compare integrals
    debug = 0
    if debug:
        F_list = F_list[1:]

    for F, acc in F_list:
        if debug:
            print('\n', "F:", str(F))

        # Integrate over domain and its boundary
        int_dx = assemble(div(grad(F)) * dx(mesh))  # noqa
        int_ds = assemble(dot(grad(F), n) * ds(mesh))  # noqa

        if debug:
            print(int_dx, int_ds)

        # Compare results. Using custom relative delta instead of
        # decimal digits here because some numbers are >> 1.
        delta = min(abs(int_dx), abs(int_ds)) * 10**-acc
        assert int_dx - int_ds <= delta
Esempio n. 11
0
def rectangle():
    return create_rectangle(
        MPI.COMM_WORLD,
        [np.array([0.0, 0.0]), np.array([2.0, 2.0])], [5, 5],
        CellType.triangle, GhostMode.none)