def facet_reference_edge_vectors(L, tablename, cellname): celltype = getattr(basix.CellType, cellname) topology = basix.topology(celltype) geometry = basix.geometry(celltype) triangle_edges = basix.topology(basix.CellType.triangle)[1] quadrilateral_edges = basix.topology(basix.CellType.quadrilateral)[1] if len(topology) != 4: raise ValueError("Can only get facet edges for 3D cells.") edge_vectors = [] for facet in topology[-2]: if len(facet) == 3: edge_vectors += [ geometry[facet[j]] - geometry[facet[i]] for i, j in triangle_edges ] elif len(facet) == 4: edge_vectors += [ geometry[facet[j]] - geometry[facet[i]] for i, j in quadrilateral_edges ] else: raise ValueError( "Only triangular and quadrilateral faces supported.") out = numpy.array(edge_vectors) return L.ArrayDecl("static const double", f"{cellname}_{tablename}", out.shape, out)
def run_map_test(e, J, detJ, K, reference_value_size, physical_value_size): tdim = len(basix.topology(e.cell_type)) - 1 N = 5 if tdim == 1: points = np.array([[i / N] for i in range(N + 1)]) elif tdim == 2: points = np.array([[i / N, j / N] for i in range(N + 1) for j in range(N + 1 - i)]) elif tdim == 3: points = np.array([[i / N, j / N, k / N] for i in range(N + 1) for j in range(N + 1 - i) for k in range(N + 1 - i - j)]) values = e.tabulate(0, points)[0] _J = np.array([J for p in points]) _detJ = np.array([detJ for p in points]) _K = np.array([K for p in points]) assert values.shape[1] == e.dim assert values.shape[2] == reference_value_size mapped = e.push_forward(values, _J, _detJ, _K) assert mapped.shape[0] == values.shape[0] assert mapped.shape[1] == e.dim assert mapped.shape[2] == physical_value_size unmapped = e.pull_back(mapped, _J, _detJ, _K) assert np.allclose(values, unmapped)
def test_interpolation(cell_type, n, element_type): element = basix.create_element(element_type, cell_type, n, basix.LagrangeVariant.gll_warped) assert element.interpolation_matrix.shape[0] == element.dim assert element.interpolation_matrix.shape[1] == element.points.shape[0] assert element.points.shape[1] == len(basix.topology( element.cell_type)) - 1
def test_outward_normals(cell): cell_type = getattr(basix.CellType, cell) normals = basix.cell.facet_outward_normals(cell_type) facets = basix.topology(cell_type)[-2] geometry = basix.geometry(cell_type) midpoint = sum(geometry) / len(geometry) for normal, facet in zip(normals, facets): assert np.dot(geometry[facet[0]] - midpoint, normal) > 0
def reference_edge_vectors(L, tablename, cellname): celltype = getattr(basix.CellType, cellname) topology = basix.topology(celltype) geometry = basix.geometry(celltype) edge_vectors = [geometry[j] - geometry[i] for i, j in topology[1]] out = numpy.array(edge_vectors[cellname]) return L.ArrayDecl("static const double", f"{cellname}_{tablename}", out.shape, out)
def test_normals(cell): cell_type = getattr(basix.CellType, cell) normals = basix.cell.facet_normals(cell_type) facets = basix.topology(cell_type)[-2] geometry = basix.geometry(cell_type) for normal, facet in zip(normals, facets): assert np.isclose(np.linalg.norm(normal), 1) for v in facet[1:]: tangent = geometry[v] - geometry[facet[0]] assert np.isclose(np.dot(tangent, normal), 0)
def map_facet_points(points, facet, cellname): geom = basix.geometry(basix_cells[cellname]) facet_vertices = [ geom[i] for i in basix.topology(basix_cells[cellname])[-2][facet] ] return [ facet_vertices[0] + sum((i - facet_vertices[0]) * j for i, j in zip(facet_vertices[1:], p)) for p in points ]
def map_facet_points(points, facet, cellname): """Map points from a reference facet to a physical facet.""" geom = basix.geometry(basix.cell.string_to_type(cellname)) facet_vertices = [ geom[i] for i in basix.topology(basix.cell.string_to_type(cellname))[-2][facet] ] return [ facet_vertices[0] + sum((i - facet_vertices[0]) * j for i, j in zip(facet_vertices[1:], p)) for p in points ]
def facet_edge_vertices(L, tablename, cellname): celltype = getattr(basix.CellType, cellname) topology = basix.topology(celltype) triangle_edges = basix.topology(basix.CellType.triangle)[1] quadrilateral_edges = basix.topology(basix.CellType.quadrilateral)[1] if len(topology) != 4: raise ValueError("Can only get facet edges for 3D cells.") edge_vertices = [] for facet in topology[-2]: if len(facet) == 3: edge_vertices += [[facet[i] for i in edge] for edge in triangle_edges] elif len(facet) == 4: edge_vertices += [[facet[i] for i in edge] for edge in quadrilateral_edges] else: raise ValueError( "Only triangular and quadrilateral faces supported.") out = numpy.array(edge_vertices, dtype=int) return L.ArrayDecl("static const unsigned int", f"{cellname}_{tablename}", out.shape, out)
def test_closure_dofs(cell_type, degree, element_type, element_args): element = basix.create_element(element_type, cell_type, degree, *element_args) entity_dofs = element.entity_dofs entity_closure_dofs = element.entity_closure_dofs topology = basix.topology(cell_type) connectivity = basix.cell.sub_entity_connectivity(cell_type) for dim, t in enumerate(topology): for e, _ in enumerate(t): for dim2 in range(dim + 1): for e2 in connectivity[dim][e][dim2]: for dof in entity_dofs[dim2][e2]: assert dof in entity_closure_dofs[dim][e]
def test_sub_entity_connectivity(cell): cell_type = getattr(basix.CellType, cell) connectivity = basix.cell.sub_entity_connectivity(cell_type) topology = basix.topology(cell_type) assert len(connectivity) == len(topology) for dim, entities in enumerate(connectivity): assert len(entities) == len(topology[dim]) for n, entity in enumerate(entities): for dim2, connected_entities in enumerate(entity): for n2 in connected_entities: if dim > dim2: for i in topology[dim2][n2]: assert i in topology[dim][n] else: for i in topology[dim][n]: assert i in topology[dim2][n2]
def test_mesh_topology_against_basix(mesh_factory, ghost_mode): """Test that mesh cells have topology matching to Basix reference cell they were created from. """ func, args = mesh_factory xfail_ghosted_quads_hexes(func, ghost_mode) mesh = func(*args) if not is_simplex(mesh.topology.cell_type): return # Create basix cell cell_name = cpp.mesh.to_string(mesh.topology.cell_type) basix_celltype = getattr(basix.CellType, cell_name) # Initialize all mesh entities and connectivities mesh.topology.create_connectivity_all() map = mesh.topology.index_map(mesh.topology.dim) num_cells = map.size_local + map.num_ghosts for i in range(num_cells): # Get indices of cell vertices vertex_global_indices = mesh.topology.connectivity( mesh.topology.dim, 0).links(i) # Loop over all dimensions of reference cell topology for d, d_topology in enumerate(basix.topology(basix_celltype)): # Get entities of dimension d on the cell entities = mesh.topology.connectivity(mesh.topology.dim, d).links(i) if len(entities) == 0: # Fixup for highest dimension entities = (i, ) # Loop over all entities of fixed dimension d for entity_index, entity_topology in enumerate(d_topology): # Check that entity vertices map to cell vertices in correct order vertices = mesh.topology.connectivity(d, 0).links( entities[entity_index]) vertices_dolfin = np.sort(vertices) vertices2 = np.sort( vertex_global_indices[np.array(entity_topology)]) assert all(vertices2 == vertices_dolfin)
def test_tensor_product_factorisation(cell_type, degree, element_type, element_args): element = basix.create_element(element_type, cell_type, degree, *element_args) tdim = len(basix.topology(cell_type)) - 1 # These elements should have a factorisation if cell_type in [basix.CellType.quadrilateral, basix.CellType.hexahedron] and element_type in [ basix.ElementFamily.P ] and basix.LagrangeVariant.equispaced in element_args: assert element.has_tensor_product_factorisation if not element.has_tensor_product_factorisation: with pytest.raises(RuntimeError): element.get_tensor_product_representation() pytest.skip() factors = element.get_tensor_product_representation() lattice = basix.create_lattice(cell_type, 1, basix.LatticeType.equispaced, True) tab1 = element.tabulate(1, lattice) for i, point in enumerate(lattice): for ds in product(range(2), repeat=tdim): if sum(ds) > 1: continue deriv = basix.index(*ds) values1 = tab1[deriv, i, :, :] values2 = np.empty((element.dim, 1)) for fs, perm in factors: evals = [ e.tabulate(d, [p])[d, 0, :, 0] for e, p, d in zip(fs, point, ds) ] tab2 = tensor_product(*evals) for a, b in enumerate(perm): if b != -1: values2[b, 0] = tab2[a] assert np.allclose(values1, values2)
def sympy_rt(celltype, n): x = sympy.Symbol("x") y = sympy.Symbol("y") z = sympy.Symbol("z") from sympy import S topology = basix.topology(celltype) geometry = S(basix.geometry(celltype).astype(int)) dummy = [ sympy.Symbol("DUMMY1"), sympy.Symbol("DUMMY2"), sympy.Symbol("DUMMY3") ] funcs = [] if celltype == basix.CellType.triangle: tdim = 2 for i in range(n): for j in range(n - i): for d in range(2): funcs += [[x**j * y**i if k == d else 0 for k in range(2)]] for i in range(n): funcs.append([x**(n - i) * y**i, x**(n - 1 - i) * y**(i + 1)]) mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # edge normals for i, f in enumerate(funcs): if n == 1: edge_basis = [sympy.Integer(1)] else: edge_basis = sympy_lagrange(basix.CellType.interval, n - 1) edge_basis = [a.subs(x, dummy[0]) for a in edge_basis] j = 0 for edge in topology[1]: edge_geom = [geometry[t, :] for t in edge] tangent = edge_geom[1] - edge_geom[0] norm = sympy.sqrt(sum(i**2 for i in tangent)) tangent = [i / norm for i in tangent] normal = [-tangent[1], tangent[0]] param = [(1 - dummy[0]) * a + dummy[0] * b for a, b in zip(edge_geom[0], edge_geom[1])] for g in edge_basis: integrand = sum((f_i * v_i) for f_i, v_i in zip(f, normal)) integrand = integrand.subs(x, param[0]).subs(y, param[1]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1)) j += 1 # interior dofs if n > 1: for i, f in enumerate(funcs): if n == 2: face_basis = [sympy.Integer(1)] else: face_basis = sympy_lagrange(basix.CellType.triangle, n - 2) j = n * 3 for g in face_basis: for vec in [(1, 0), (0, 1)]: integrand = sum( (f_i * v_i) for f_i, v_i in zip(f, vec)) * g mat[i, j] = integrand.integrate( (x, 0, 1 - y)).integrate((y, 0, 1)) j += 1 elif celltype == basix.CellType.tetrahedron: tdim = 3 for i in range(n): for j in range(n - i): for k in range(n - i - j): for d in range(3): funcs += [[ x**k * y**j * z**i if m == d else 0 for m in range(3) ]] for j in range(n): for k in range(n - j): p = x**(n - 1 - j - k) * y**j * z**k funcs.append((x * p, y * p, z * p)) mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # face normals for i, f in enumerate(funcs): if n == 1: face_basis = [sympy.Integer(1)] else: face_basis = sympy_lagrange(basix.CellType.triangle, n - 1) face_basis = [ a.subs(x, dummy[0]).subs(y, dummy[1]) for a in face_basis ] j = 0 for face in topology[2]: face_geom = [geometry[t, :] for t in face] axes = [ face_geom[1] - face_geom[0], face_geom[2] - face_geom[0] ] normal = [ axes[0][1] * axes[1][2] - axes[0][2] * axes[1][1], axes[0][2] * axes[1][0] - axes[0][0] * axes[1][2], axes[0][0] * axes[1][1] - axes[0][1] * axes[1][0] ] norm = sympy.sqrt(sum(i**2 for i in normal)) normal = [k / norm for k in normal] param = [ a + dummy[0] * b + dummy[1] * c for a, b, c in zip(face_geom[0], *axes) ] for g in face_basis: integrand = sum(f_i * v_i for f_i, v_i in zip(f, normal)) integrand = integrand.subs(x, param[0]).subs( y, param[1]).subs(z, param[2]) integrand *= g * norm mat[i, j] = integrand.integrate( (dummy[0], 0, 1 - dummy[1])).integrate( (dummy[1], 0, 1)) j += 1 assert j == 2 * n * (n + 1) if n > 1: for i, f in enumerate(funcs): if n == 2: interior_basis = [sympy.Integer(1)] else: interior_basis = sympy_lagrange(basix.CellType.tetrahedron, n - 2) j = 2 * n * (n + 1) for g in interior_basis: for vec in [(1, 0, 0), (0, 1, 0), (0, 0, 1)]: integrand = sum(f_i * v_i for f_i, v_i in zip(f, vec)) integrand *= g mat[i, j] = integrand.integrate( (x, 0, 1 - y - z)).integrate( (y, 0, 1 - z)).integrate((z, 0, 1)) j += 1 mat = sympy.Matrix(mat) mat = mat.inv() g = [] for r in range(mat.shape[0]): row = [] for dim in range(tdim): row.append( sum([v * funcs[i][dim] for i, v in enumerate(mat.row(r))])) g.append(row) return g
def sympy_lagrange(celltype, n): x = sympy.Symbol("x") y = sympy.Symbol("y") z = sympy.Symbol("z") from sympy import S topology = basix.topology(celltype) geometry = S(basix.geometry(celltype).astype(int)) pt = [] for dim, entities in enumerate(topology): for ent in entities: entity_geom = [geometry[t, :] for t in ent] if (dim == 0): pt += [entity_geom[0]] elif (dim == 1): for i in range(n - 1): pt += [ entity_geom[0] + sympy.Rational(i + 1, n) * (entity_geom[1] - entity_geom[0]) ] elif (dim == 2): for i in range(n - 2): for j in range(n - 2 - i): pt += [ entity_geom[0] + sympy.Rational(i + 1, n) * (entity_geom[2] - entity_geom[0]) + sympy.Rational(j + 1, n) * (entity_geom[1] - entity_geom[0]) ] elif (dim == 3): for i in range(n - 3): for j in range(n - 3 - i): for k in range(n - 3 - i - j): pt += [ entity_geom[0] + sympy.Rational(i + 1, n) * (entity_geom[3] - entity_geom[0]) + sympy.Rational(j + 1, n) * (entity_geom[2] - entity_geom[0]) + sympy.Rational(k + 1, n) * (entity_geom[1] - entity_geom[0]) ] funcs = [] if celltype == basix.CellType.interval: for i in range(n + 1): funcs += [x**i] mat = numpy.empty((len(pt), len(funcs)), dtype=object) for i, f in enumerate(funcs): for j, p in enumerate(pt): mat[i, j] = f.subs([(x, p[0])]) elif celltype == basix.CellType.triangle: for i in range(n + 1): for j in range(n + 1 - i): funcs += [x**j * y**i] mat = numpy.empty((len(pt), len(funcs)), dtype=object) for i, f in enumerate(funcs): for j, p in enumerate(pt): mat[i, j] = f.subs([(x, p[0]), (y, p[1])]) elif celltype == basix.CellType.tetrahedron: for i in range(n + 1): for j in range(n + 1 - i): for k in range(n + 1 - i - j): funcs += [x**j * y**i * z**k] mat = numpy.empty((len(pt), len(funcs)), dtype=object) for i, f in enumerate(funcs): for j, p in enumerate(pt): mat[i, j] = f.subs([(x, p[0]), (y, p[1]), (z, p[2])]) mat = sympy.Matrix(mat) mat = mat.inv() g = [] for r in range(mat.shape[0]): g += [sum([v * funcs[i] for i, v in enumerate(mat.row(r))])] return g
return 100 * p[0] + 30 * p[1] def to_y(p): if len(p) == 1: return 120 if len(p) == 2: return 120 - 100 * p[1] if len(p) == 3: return 120 - 100 * p[2] - 40 * p[1] for shape in ["interval", "triangle", "tetrahedron", "quadrilateral", "hexahedron", "prism", "pyramid"]: cell_type = getattr(basix.CellType, shape) geometry = basix.geometry(cell_type) topology = basix.topology(cell_type) yadd = 0 width = 100 if shape == "interval": yadd = -100 if shape == "hexahedron": yadd = 40 width = 140 if shape == "pyramid": width = 140 if shape == "prism": yadd = 40 svg = ""
def reference_topology(self): return basix.topology(self.element.cell_type)
def reference_topology(self): """Get the topology of the reference element.""" return basix.topology(self.element.cell_type)
def sympy_nedelec(celltype, n): x = sympy.Symbol("x") y = sympy.Symbol("y") z = sympy.Symbol("z") from sympy import S topology = basix.topology(celltype) geometry = S(basix.geometry(celltype).astype(int)) dummy = [ sympy.Symbol("DUMMY1"), sympy.Symbol("DUMMY2"), sympy.Symbol("DUMMY3") ] funcs = [] if celltype == basix.CellType.triangle: tdim = 2 for i in range(n + 1): for j in range(n + 1 - i): for d in range(2): funcs += [[x**j * y**i if k == d else 0 for k in range(2)]] mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # edge tangents edge_basis = sympy_lagrange(basix.CellType.interval, n) edge_basis = [a.subs(x, dummy[0]) for a in edge_basis] for i, f in enumerate(funcs): j = 0 for edge in topology[1]: edge_geom = [geometry[t, :] for t in edge] tangent = edge_geom[1] - edge_geom[0] norm = sympy.sqrt(sum(i**2 for i in tangent)) tangent = [i / norm for i in tangent] param = [(1 - dummy[0]) * a + dummy[0] * b for a, b in zip(edge_geom[0], edge_geom[1])] for g in edge_basis: integrand = sum( (f_i * v_i) for f_i, v_i in zip(f, tangent)) integrand = integrand.subs(x, param[0]).subs(y, param[1]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1)) j += 1 # interior dofs if n > 1: face_basis = sympy_rt(basix.CellType.triangle, n - 1) for i, f in enumerate(funcs): j = (n + 1) * 3 for g in face_basis: integrand = sum((f_i * v_i) for f_i, v_i in zip(f, g)) mat[i, j] = integrand.integrate((x, 0, 1 - y)).integrate( (y, 0, 1)) j += 1 elif celltype == basix.CellType.tetrahedron: tdim = 3 for i in range(n + 1): for j in range(n + 1 - i): for k in range(n + 1 - i - j): for d in range(3): funcs += [[ x**k * y**j * z**i if m == d else 0 for m in range(3) ]] mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # edge tangents edge_basis = sympy_lagrange(basix.CellType.interval, n) edge_basis = [a.subs(x, dummy[0]) for a in edge_basis] for i, f in enumerate(funcs): j = 0 for edge in topology[1]: edge_geom = [geometry[t, :] for t in edge] tangent = edge_geom[1] - edge_geom[0] norm = sympy.sqrt(sum(i**2 for i in tangent)) tangent = [i / norm for i in tangent] param = [(1 - dummy[0]) * a + dummy[0] * b for a, b in zip(edge_geom[0], edge_geom[1])] for g in edge_basis: integrand = sum( (f_i * v_i) for f_i, v_i in zip(f, tangent)) integrand = integrand.subs(x, param[0]).subs( y, param[1]).subs(z, param[2]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1)) j += 1 # face dofs if n > 1: face_basis = sympy_rt(basix.CellType.triangle, n - 1) face_basis = [[b.subs(x, dummy[0]).subs(y, dummy[1]) for b in a] for a in face_basis] for i, f in enumerate(funcs): j = (n + 1) * 6 for face in topology[2]: face_geom = [geometry[t, :] for t in face] axes = [ face_geom[1] - face_geom[0], face_geom[2] - face_geom[0] ] norm = sympy.sqrt( sum(i**2 for i in [ axes[0][1] * axes[1][2] - axes[0][2] * axes[1][1], axes[0][2] * axes[1][0] - axes[0][0] * axes[1][2], axes[0][0] * axes[1][1] - axes[0][1] * axes[1][0] ])) scaled_axes = [] for a in axes: scaled_axes.append([k / norm for k in a]) param = [ a + dummy[0] * b + dummy[1] * c for a, b, c in zip(face_geom[0], *axes) ] this_face_basis = [[ a[0] * b + a[1] * c for b, c in zip(*scaled_axes) ] for a in face_basis] for g in this_face_basis: integrand = sum(f_i * v_i for f_i, v_i in zip(f, g)) integrand = integrand.subs(x, param[0]).subs( y, param[1]).subs(z, param[2]) integrand *= norm mat[i, j] = integrand.integrate( (dummy[0], 0, 1 - dummy[1])).integrate( (dummy[1], 0, 1)) j += 1 # interior dofs if n > 2: interior_basis = sympy_rt(basix.CellType.tetrahedron, n - 2) for i, f in enumerate(funcs): j = (n + 1) * 6 + 4 * (n - 1) * (n + 1) for g in interior_basis: integrand = sum(f_i * v_i for f_i, v_i in zip(f, g)) mat[i, j] = integrand.integrate( (x, 0, 1 - y - z)).integrate((y, 0, 1 - z)).integrate( (z, 0, 1)) j += 1 mat = sympy.Matrix(mat) mat = mat.inv() g = [] for r in range(mat.shape[0]): row = [] for dim in range(tdim): row.append( sum([v * funcs[i][dim] for i, v in enumerate(mat.row(r))])) g.append(row) return g
def sympy_nedelec(celltype, n): x = sympy.Symbol("x") y = sympy.Symbol("y") z = sympy.Symbol("z") from sympy import S topology = basix.topology(celltype) geometry = S(basix.geometry(celltype).astype(int)) dummy = [sympy.Symbol("DUMMY1"), sympy.Symbol("DUMMY2"), sympy.Symbol("DUMMY3")] funcs = [] if celltype == basix.CellType.triangle: tdim = 2 for i in range(n): for j in range(n - i): for d in range(2): funcs += [[x**j * y**i if k == d else 0 for k in range(2)]] for i in range(n): funcs += [[x ** (n - 1 - i) * y ** (i + 1), -x ** (n - i) * y ** i]] mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # edge tangents if n == 1: edge_basis = [sympy.Integer(1)] else: edge_basis = sympy_lagrange(basix.CellType.interval, n - 1) edge_basis = [a.subs(x, dummy[0]) for a in edge_basis] for i, f in enumerate(funcs): j = 0 for edge in topology[1]: edge_geom = [geometry[t, :] for t in edge] tangent = edge_geom[1] - edge_geom[0] norm = sympy.sqrt(sum(i ** 2 for i in tangent)) tangent = [i / norm for i in tangent] param = [(1 - dummy[0]) * a + dummy[0] * b for a, b in zip(edge_geom[0], edge_geom[1])] for g in edge_basis: integrand = sum((f_i * v_i) for f_i, v_i in zip(f, tangent)) integrand = integrand.subs(x, param[0]).subs(y, param[1]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1)) j += 1 # interior dofs if n > 1: if n == 2: face_basis = [sympy.Integer(1)] else: face_basis = sympy_lagrange(basix.CellType.triangle, n - 2) for i, f in enumerate(funcs): j = n * 3 for g in face_basis: for vec in [(1, 0), (0, 1)]: integrand = sum((f_i * v_i) for f_i, v_i in zip(f, vec)) * g mat[i, j] = integrand.integrate((x, 0, 1 - y)).integrate((y, 0, 1)) j += 1 elif celltype == basix.CellType.tetrahedron: tdim = 3 for i in range(n): for j in range(n - i): for k in range(n - i - j): for d in range(3): funcs += [[x**k * y**j * z**i if m == d else 0 for m in range(3)]] if n == 1: funcs += [[y, -x, sympy.Integer(0)], [z, sympy.Integer(0), -x], [sympy.Integer(0), z, -y]] elif n == 2: funcs += [ [y ** 2, -x * y, sympy.Integer(0)], [x * y, -x ** 2, sympy.Integer(0)], [z * y, -z * x, sympy.Integer(0)], [sympy.Integer(0), y * z, -y ** 2], [sympy.Integer(0), z ** 2, -z * y], [sympy.Integer(0), x * z, -x * y], [x * z, sympy.Integer(0), -x ** 2], [z ** 2, sympy.Integer(0), -z * x], ] elif n == 3: funcs += [ [x ** 2 * y, -x ** 3, sympy.Integer(0)], [x ** 2 * z, sympy.Integer(0), -x ** 3], [sympy.Integer(0), x ** 2 * z, -x ** 2 * y], [x * y ** 2, -x ** 2 * y, sympy.Integer(0)], [2 * x * y * z, -x ** 2 * z, -x ** 2 * y], [sympy.Integer(0), x * y * z, -x * y ** 2], [x * z ** 2, sympy.Integer(0), -x ** 2 * z], [sympy.Integer(0), x * z ** 2, -x * y * z], [y ** 3, -x * y ** 2, sympy.Integer(0)], [9 * y ** 2 * z, -4 * x * y * z, -5 * x * y ** 2], [sympy.Integer(0), y ** 2 * z, -y ** 3], [9 * y * z ** 2, -5 * x * z ** 2, -4 * x * y * z], [sympy.Integer(0), y * z ** 2, -y ** 2 * z], [z ** 3, sympy.Integer(0), -x * z ** 2], [sympy.Integer(0), z ** 3, -y * z ** 2], ] else: raise NotImplementedError mat = numpy.empty((len(funcs), len(funcs)), dtype=object) # edge tangents if n == 1: edge_basis = [sympy.Integer(1)] else: edge_basis = sympy_lagrange(basix.CellType.interval, n - 1) edge_basis = [a.subs(x, dummy[0]) for a in edge_basis] for i, f in enumerate(funcs): j = 0 for edge in topology[1]: edge_geom = [geometry[t, :] for t in edge] tangent = edge_geom[1] - edge_geom[0] norm = sympy.sqrt(sum(i ** 2 for i in tangent)) tangent = [i / norm for i in tangent] param = [(1 - dummy[0]) * a + dummy[0] * b for a, b in zip(edge_geom[0], edge_geom[1])] for g in edge_basis: integrand = sum((f_i * v_i) for f_i, v_i in zip(f, tangent)) integrand = integrand.subs(x, param[0]).subs(y, param[1]).subs(z, param[2]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1)) j += 1 # face dofs if n > 1: def dot(a, b): return sum(i * j for i, j in zip(a, b)) def cross(a, b): assert len(a) == 3 and len(b) == 3 return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]] if n == 2: face_basis = [sympy.Integer(1)] else: face_basis = sympy_lagrange(basix.CellType.triangle, n - 2) face_basis = [a.subs(x, dummy[0]).subs(y, dummy[1]) for a in face_basis] for i, f in enumerate(funcs): j = n * 6 for face in topology[2]: face_geom = [geometry[t, :] for t in face] axes = [face_geom[1] - face_geom[0], face_geom[2] - face_geom[0]] norm = sympy.sqrt(sum(i**2 for i in cross(axes[0], axes[1]))) scaled_axes = [] for a in axes: scaled_axes.append([k / norm for k in a]) param = [a + dummy[0] * b + dummy[1] * c for a, b, c in zip(face_geom[0], *axes)] for g in face_basis: for vec in scaled_axes: integrand = dot(vec, f) integrand = integrand.subs(x, param[0]).subs(y, param[1]).subs(z, param[2]) integrand *= g * norm mat[i, j] = integrand.integrate((dummy[0], 0, 1 - dummy[1])).integrate((dummy[1], 0, 1)) j += 1 # interior dofs if n > 2: if n == 3: interior_basis = [sympy.Integer(1)] else: interior_basis = sympy_lagrange(basix.CellType.tetrahedron, n - 3) for i, f in enumerate(funcs): j = n * 6 + 4 * n * (n - 1) for g in interior_basis: for vec in [(1, 0, 0), (0, 1, 0), (0, 0, 1)]: integrand = sum(f_i * v_i for f_i, v_i in zip(f, vec)) integrand *= g mat[i, j] = integrand.integrate((x, 0, 1 - y - z)).integrate((y, 0, 1 - z)).integrate((z, 0, 1)) j += 1 mat = sympy.Matrix(mat) mat = mat.inv() g = [] for r in range(mat.shape[0]): row = [] for dim in range(tdim): row.append(sum([v * funcs[i][dim] for i, v in enumerate(mat.row(r))])) g.append(row) return g