def test_dual0(): space = create_element("dual polygon(4)", "dual", 0) q = sympy.Rational(1, 4) assert symequal( space.tabulate_basis([[q, q], [-q, q], [-q, -q], [q, -q]]), ((1, ), (1, ), (1, ), (1, )) )
def test_element(elements_to_test, cells_to_test, cell_type, element_type, order, kwargs, speed): """Run tests for each element.""" if elements_to_test != "ALL" and element_type not in elements_to_test: pytest.skip() if cells_to_test != "ALL" and cell_type not in cells_to_test: pytest.skip() if speed == "fast": if order > 2: pytest.skip() if order == 2 and cell_type in [ "tetrahedron", "hexahedron", "prism", "pyramid" ]: pytest.skip() element = create_element(cell_type, element_type, order, **kwargs) try: factorised_basis = element._get_basis_functions_tensor() except symfem.finite_element.NoTensorProduct: pytest.skip( "This element does not have a tensor product representation.") basis = element.get_basis_functions() for i, j in zip(basis, factorised_basis): assert symequal(i, j)
def test_equispaced(order): points, weights = quadrature.equispaced(order + 1) x = sympy.Symbol("x") poly = x assert symequal(poly.integrate((x, 0, 1)), sum(i * poly.subs(x, j) for i, j in zip(weights, points)))
def test_legendre(order): points, weights = quadrature.legendre(order) x = sympy.Symbol("x") poly = x**(2 * order - 1) assert symequal(poly.integrate((x, 0, 1)), sum(i * poly.subs(x, j) for i, j in zip(weights, points)))
def test_lagrange_pyramid(): space = create_element("pyramid", "Lagrange", 1) x_i = x[0] / (1 - x[2]) y_i = x[1] / (1 - x[2]) z_i = x[2] / (1 - x[2]) basis = [(1 - x_i) * (1 - y_i) / (1 + z_i), x_i * (1 - y_i) / (1 + z_i), (1 - x_i) * y_i / (1 + z_i), x_i * y_i / (1 + z_i), z_i / (1 + z_i)] assert symequal(basis, space.get_basis_functions()) basis = [(1 - x[0] - x[2]) * (1 - x[1] - x[2]) / (1 - x[2]), x[0] * (1 - x[1] - x[2]) / (1 - x[2]), (1 - x[0] - x[2]) * x[1] / (1 - x[2]), x[0] * x[1] / (1 - x[2]), x[2]] assert symequal(basis, space.get_basis_functions())
def test_dual1(): space = create_element("dual polygon(4)", "dual", 1) h = sympy.Rational(1, 2) q = sympy.Rational(1, 4) e = sympy.Rational(1, 8) assert symequal( space.tabulate_basis([[0, 0], [q, q], [h, 0]]), ((q, q, q, q), (sympy.Rational(5, 8), e, e, e), (sympy.Rational(3, 8), e, e, sympy.Rational(3, 8))) )
def test_hct(): e = symfem.create_element("triangle", "HCT", 3) for f in e.get_polynomial_basis(): # edge from (1,0) to (1/3,1/3) f1 = f.get_piece((half, 0)) f2 = f.get_piece((half, half)) line = ((1 - 2 * t[0], t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2)) # edge from (0,1) to (1/3,1/3) f1 = f.get_piece((half, half)) f2 = f.get_piece((0, half)) line = ((t[0], 1 - 2 * t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2)) # edge from (0,0) to (1/3,1/3) f1 = f.get_piece((0, half)) f2 = f.get_piece((half, 0)) line = ((t[0], t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2))
def test_dual_elements(elements_to_test, cells_to_test, n_tri, order): if elements_to_test != "ALL" and "dual" not in elements_to_test: pytest.skip() if cells_to_test != "ALL" and "dual polygon" not in cells_to_test: pytest.skip() space = create_element(f"dual polygon({n_tri})", "dual", order) sub_e = create_element("triangle", space.fine_space, space.order) for f, coeff_list in zip(space.get_basis_functions(), space.dual_coefficients): for piece, coeffs in zip(f.pieces, coeff_list): map = sub_e.reference.get_map_to(piece[0]) for dof, value in zip(sub_e.dofs, coeffs): point = subs(map, x, dof.point) assert symequal(value, subs(piece[1], x, point))
def test_rhct(): e = symfem.create_element("triangle", "rHCT", 3) for f in e.get_polynomial_basis(): # edge from (1,0) to (1/3,1/3) f1 = f.get_piece((half, 0)) f2 = f.get_piece((half, half)) line = ((1 - 2 * t[0], t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2)) # edge from (0,1) to (1/3,1/3) f1 = f.get_piece((half, half)) f2 = f.get_piece((0, half)) line = ((t[0], 1 - 2 * t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2)) # edge from (0,0) to (1/3,1/3) f1 = f.get_piece((0, half)) f2 = f.get_piece((half, 0)) line = ((t[0], t[0])) f1 = subs(f1, x[:2], line) f2 = subs(f2, x[:2], line) assert symequal(f1, f2) assert symequal(grad(f1, 2), grad(f2, 2)) # Check that normal derivatives are linear f1 = diff(f.get_piece((half, 0)), x[1]).subs(x[1], 0) f2 = f.get_piece((half, half)) f2 = (diff(f2, x[0]) + diff(f2, x[1])).subs(x[1], 1 - x[0]) f3 = diff(f.get_piece((0, half)), x[0]).subs(x[0], 0) assert diff(f1, x[0], x[0]) == 0 assert diff(f2, x[0], x[0]) == 0 assert diff(f3, x[1], x[1]) == 0
def test_lagrange(): space = create_element("triangle", "Lagrange", 1) assert symequal( space.tabulate_basis([[0, 0], [0, 1], [1, 0]]), ((1, 0, 0), (0, 0, 1), (0, 1, 0)), )
def test_Q(): space = create_element("quadrilateral", "Q", 1) assert symequal( space.tabulate_basis([[0, 0], [1, 0], [0, 1], [1, 1]]), ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), )
def test_rt(): space = create_element("triangle", "Raviart-Thomas", 1) assert symequal( space.tabulate_basis([[0, 0], [1, 0], [0, 1]], "xxyyzz"), ((0, -1, 0, 0, 0, 1), (-1, 0, -1, 0, 0, 1), (0, -1, 0, -1, 1, 0)), )
def test_nedelec(): space = create_element("triangle", "Nedelec", 1) assert symequal( space.tabulate_basis([[0, 0], [1, 0], [0, 1]], "xxyyzz"), ((0, 0, 1, 0, 1, 0), (0, 0, 1, 1, 0, 1), (-1, 1, 0, 0, 1, 0)), )
# In this demo, we use the function vdot to compute the dot product of two vectors. # The module symfem.vectors contains many functions that can be used to manipulate # vectors. from symfem.vectors import vdot element = symfem.create_element("triangle", "Nedelec1", 4) polys = element.get_polynomial_basis() # Check that the first 20 polynomials in the polynomial basis are # the polynomials of degree 3 p3 = polynomial_set(2, 2, 3) assert len(p3) == 20 for i, j in zip(p3, polys[:20]): assert i == j # Check that the rest of the polynomials in the polynomial basis # satisfy p DOT x = 0 for p in polys[20:]: assert vdot(p, x) == 0 # Get the basis functions associated with the interior of the triangle basis = element.get_basis_functions() functions = [basis[d] for d in element.entity_dofs(2, 0)] # Check that these functions have 0 tangential component on each edge # symequal will simplify the expressions then check that they are equal for f in functions: assert symequal(vdot(subs(f, x[0], 1 - x[1]), (1, -1)), 0) assert symequal(vdot(subs(f, x[0], 0), (0, 1)), 0) assert symequal(vdot(subs(f, x[1], 0), (1, 0)), 0)
edge_element = symfem.create_element("interval", "Lagrange", 5) # Define a parameter that will go from 0 to 1 on the chosen edge a = sympy.Symbol("a") # Get the basis functions of the Lagrange space and substitute the parameter into the # functions on the edge basis = element.get_basis_functions() edge_basis = [subs(f, x[0], a) for f in edge_element.get_basis_functions()] # Get the DOFs on edge 0 (from vertex 1 (1,0) to vertex 2 (0,1)) # (1 - a, a) is a parametrisation of this edge dofs = element.entity_dofs(0, 1) + element.entity_dofs( 0, 2) + element.entity_dofs(1, 0) # Check that the basis functions on this edge are equal for d, edge_f in zip(dofs, edge_basis): # symequal will simplify the expressions then check that they are equal assert symequal(subs(basis[d], x[:2], (1 - a, a)), edge_f) # Get the DOFs on edge 1 (from vertex 0 (0,0) to vertex 2 (0,1), parametrised (0, a)) dofs = element.entity_dofs(0, 0) + element.entity_dofs( 0, 2) + element.entity_dofs(1, 1) for d, edge_f in zip(dofs, edge_basis): assert symequal(subs(basis[d], x[:2], (0, a)), edge_f) # Get the DOFs on edge 2 (from vertex 0 (0,0) to vertex 1 (1,0), parametrised (a, 0)) dofs = element.entity_dofs(0, 0) + element.entity_dofs( 0, 1) + element.entity_dofs(1, 2) for d, edge_f in zip(dofs, edge_basis): assert symequal(subs(basis[d], x[:2], (a, 0)), edge_f)