def test_create_quadrature_extr_quadrilateral(extr_quadrilateral, basedeg, extrdeg, scheme): q = FIAT.create_quadrature(extr_quadrilateral, (basedeg, extrdeg), scheme) assert numpy.allclose( q.integrate(lambda x: (x[0] + x[1])**basedeg * x[2]**extrdeg), (2**(basedeg + 2) - 2) / ((basedeg + 1) * (basedeg + 2)) * 1 / (extrdeg + 1))
def convert_finiteelement(element, vector_is_mixed): if element.family() == "Real": # Real element is just DG0 cell = element.cell() return create_element(ufl.FiniteElement("DG", cell, 0), vector_is_mixed) cell = as_fiat_cell(element.cell()) if element.family() == "Quadrature": degree = element.degree() scheme = element.quadrature_scheme() if degree is None or scheme is None: raise ValueError("Quadrature scheme and degree must be specified!") quad_rule = FIAT.create_quadrature(cell, degree, scheme) return FIAT.QuadratureElement(cell, quad_rule.get_points()) lmbda = supported_elements[element.family()] if lmbda is None: if element.cell().cellname() == "quadrilateral": # Handle quadrilateral short names like RTCF and RTCE. element = element.reconstruct(cell=quadrilateral_tpc) elif element.cell().cellname() == "hexahedron": # Handle hexahedron short names like NCF and NCE. element = element.reconstruct(cell=hexahedron_tpc) else: raise ValueError("%s is supported, but handled incorrectly" % element.family()) return FlattenedDimensions(create_element(element, vector_is_mixed)) kind = element.variant() if kind is None: kind = 'spectral' if element.cell().cellname( ) == 'interval' else 'equispaced' # default variant if element.family() == "Lagrange": if kind == 'equispaced': lmbda = FIAT.Lagrange elif kind == 'spectral' and element.cell().cellname() == 'interval': lmbda = FIAT.GaussLobattoLegendre else: raise ValueError("Variant %r not supported on %s" % (kind, element.cell())) elif element.family() in [ "Discontinuous Lagrange", "Discontinuous Lagrange L2" ]: if kind == 'equispaced': lmbda = FIAT.DiscontinuousLagrange elif kind == 'spectral' and element.cell().cellname() == 'interval': lmbda = FIAT.GaussLegendre else: raise ValueError("Variant %r not supported on %s" % (kind, element.cell())) return lmbda(cell, element.degree())
def create_quadrature(shape, degree, scheme="default"): """ Generate quadrature rule (points, weights) for given shape that will integrate an polynomial of order 'degree' exactly. """ if isinstance(shape, int) and shape == 0: return (numpy.zeros((1, 0)), numpy.ones((1,))) if shape in cellname2dim and cellname2dim[shape] == 0: return (numpy.zeros((1, 0)), numpy.ones((1,))) if scheme == "vertex": # The vertex scheme, i.e., averaging the function value in the vertices # and multiplying with the simplex volume, is only of order 1 and # inferior to other generic schemes in terms of error reduction. # Equation systems generated with the vertex scheme have some # properties that other schemes lack, e.g., the mass matrix is # a simple diagonal matrix. This may be prescribed in certain cases. if degree > 1: from warnings import warn warn(("Explicitly selected vertex quadrature (degree 1), " + "but requested degree is %d.") % degree) if shape == "tetrahedron": return (array([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), array([1.0 / 24.0, 1.0 / 24.0, 1.0 / 24.0, 1.0 / 24.0]) ) elif shape == "triangle": return (array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]), array([1.0 / 6.0, 1.0 / 6.0, 1.0 / 6.0]) ) elif shape == "interval": # Trapezoidal rule. return (array([[0.0], [1.0]]), array([1.0 / 2.0, 1.0 / 2.0]) ) quad_rule = FIAT.create_quadrature(reference_cell(shape), degree, scheme) points = numpy.asarray(quad_rule.get_points()) weights = numpy.asarray(quad_rule.get_weights()) return points, weights
def create_quadrature(shape, degree: int, scheme: str = "default"): """Generate quadrature rule. Quadrature rule(points, weights) for given shape that will integrate an polynomial of order 'degree' exactly. """ if isinstance(shape, int) and shape == 0: return (numpy.zeros((1, 0)), numpy.ones((1, ))) if shape in ufl.cell.cellname2dim and ufl.cell.cellname2dim[shape] == 0: return (numpy.zeros((1, 0)), numpy.ones((1, ))) quad_rule = FIAT.create_quadrature(FIAT.ufc_cell(shape), degree, scheme) points = numpy.asarray(quad_rule.get_points()) weights = numpy.asarray(quad_rule.get_weights()) return points, weights
def _(element, vector_is_mixed): if element.family() == "Real": # Real element is just DG0 cell = element.cell() return create_element(ufl.FiniteElement("DG", cell, 0), vector_is_mixed) cell = as_fiat_cell(element.cell()) if element.family() == "Quadrature": degree = element.degree() scheme = element.quadrature_scheme() if degree is None or scheme is None: raise ValueError("Quadrature scheme and degree must be specified!") quad_rule = FIAT.create_quadrature(cell, degree, scheme) return FIAT.QuadratureElement(cell, quad_rule.get_points()) lmbda = supported_elements[element.family()] if lmbda is None: if element.cell().cellname() != "quadrilateral": raise ValueError("%s is supported, but handled incorrectly" % element.family()) # Handle quadrilateral short names like RTCF and RTCE. element = element.reconstruct(cell=quad_tpc) return FlattenedDimensions(create_element(element, vector_is_mixed)) kind = element.variant() if kind is None: kind = 'equispaced' # default variant if element.family() == "Lagrange": if kind == 'equispaced': lmbda = FIAT.Lagrange elif kind == 'spectral' and element.cell().cellname() == 'interval': lmbda = FIAT.GaussLobattoLegendre else: raise ValueError("Variant %r not supported on %s" % (kind, element.cell())) elif element.family() == "Discontinuous Lagrange": if kind == 'equispaced': lmbda = FIAT.DiscontinuousLagrange elif kind == 'spectral' and element.cell().cellname() == 'interval': lmbda = FIAT.GaussLegendre else: raise ValueError("Variant %r not supported on %s" % (kind, element.cell())) return lmbda(cell, element.degree())
def create_quadrature(cell, degree, scheme="default"): """Create a quadrature rule. :arg cell: The FIAT cell. :arg degree: The degree of polynomial that should be integrated exactly by the rule. :kwarg scheme: optional scheme to use (either ``"default"``, or ``"canonical"``). .. note :: If the cell is a tensor product cell, the degree should be a tuple, indicating the degree in each direction of the tensor product. """ if scheme not in ("default", "canonical"): raise ValueError("Unknown quadrature scheme '%s'" % scheme) rule = FIAT.create_quadrature(cell, degree, scheme) if len(rule.get_points()) > 900: raise RuntimeError("Requested a quadrature rule with %d points" % len(rule.get_points())) return rule
def test_create_quadrature_tetrahedron(tetrahedron, degree, scheme): q = FIAT.create_quadrature(tetrahedron, degree, scheme) assert numpy.allclose(q.integrate(lambda x: sum(x)**degree), 1/(2*degree + 6))
def test_create_quadrature_quadrilateral(quadrilateral, degree, scheme): q = FIAT.create_quadrature(quadrilateral, degree, scheme) assert numpy.allclose(q.integrate(lambda x: sum(x)**degree), (2**(degree + 2) - 2) / ((degree + 1)*(degree + 2)))
def test_high_degree_runtime_error(cell): with pytest.raises(RuntimeError): FIAT.create_quadrature(cell, 60)
def test_create_quadrature_triangle(triangle, degree, scheme): q = FIAT.create_quadrature(triangle, degree, scheme) assert numpy.allclose(q.integrate(lambda x: sum(x)**degree), 1/(degree + 2))
def test_create_quadrature_interval(interval, degree, scheme): q = FIAT.create_quadrature(interval, degree, scheme) assert numpy.allclose(q.integrate(lambda x: x[0]**degree), 1/(degree + 1))
def test_create_quadrature_hexahedron(hexahedron, degree, scheme): q = FIAT.create_quadrature(hexahedron, degree, scheme) assert numpy.allclose(q.integrate(lambda x: sum(x)**degree), -3 * (2**(degree + 3) - 3**(degree + 2) - 1) / ((degree + 1)*(degree + 2)*(degree + 3)))
def test_invalid_quadrature_degree_tensor_prod(cell): with pytest.raises(ValueError): FIAT.create_quadrature(cell, (-1, -1))
def test_create_quadrature_extr_triangle(extr_triangle, basedeg, extrdeg, scheme): q = FIAT.create_quadrature(extr_triangle, (basedeg, extrdeg), scheme) assert numpy.allclose(q.integrate(lambda x: (x[0] + x[1])**basedeg * x[2]**extrdeg), 1/(basedeg + 2) * 1/(extrdeg + 1))
def test_high_degree_runtime_error_tensor_prod(cell): with pytest.raises(RuntimeError): FIAT.create_quadrature(cell, (60, 60))
def test_create_quadrature_extr_interval(extr_interval, basedeg, extrdeg, scheme): q = FIAT.create_quadrature(extr_interval, (basedeg, extrdeg), scheme) assert numpy.allclose(q.integrate(lambda x: x[0]**basedeg * x[1]**extrdeg), 1/(basedeg + 1) * 1/(extrdeg + 1))
def test_assembly_into_quadrature_function(): """Test assembly into a Quadrature function. This test evaluates a UFL Expression into a Quadrature function space by evaluating the Expression on all cells of the mesh, and then inserting the evaluated values into a PETSc Vector constructed from a matching Quadrature function space. Concretely, we consider the evaluation of: e = B*(K(T)))**2 * grad(T) where K = 1/(A + B*T) where A and B are Constants and T is a Coefficient on a P2 finite element space with T = x + 2*y. The result is compared with interpolating the analytical expression of e directly into the Quadrature space. In parallel, each process evaluates the Expression on both local cells and ghost cells so that no parallel communication is required after insertion into the vector. """ mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 3, 6) quadrature_degree = 2 quadrature_points = FIAT.create_quadrature(FIAT.ufc_simplex( mesh.topology.dim), quadrature_degree, scheme="default").get_points() Q_element = ufl.VectorElement("Quadrature", ufl.triangle, quadrature_degree, quad_scheme="default") Q = dolfinx.FunctionSpace(mesh, Q_element) def T_exact(x): return x[0] + 2.0 * x[1] P2 = dolfinx.FunctionSpace(mesh, ("P", 2)) T = dolfinx.Function(P2) T.interpolate(T_exact) A = dolfinx.Constant(mesh, 1.0) B = dolfinx.Constant(mesh, 2.0) K = 1.0 / (A + B * T) e = B * K**2 * ufl.grad(T) e_expr = dolfinx.Expression(e, quadrature_points) map_c = mesh.topology.index_map(mesh.topology.dim) num_cells = map_c.size_local + map_c.num_ghosts cells = np.arange(0, num_cells, dtype=np.int32) e_eval = e_expr.eval(cells) # Assemble into Function e_Q = dolfinx.Function(Q) with e_Q.vector.localForm() as e_Q_local: e_Q_local.setValues(Q.dofmap.list.array, e_eval, addv=PETSc.InsertMode.INSERT) def e_exact(x): T = x[0] + 2.0 * x[1] K = 1.0 / (A.value + B.value * T) grad_T = np.zeros((2, x.shape[1])) grad_T[0, :] = 1.0 grad_T[1, :] = 2.0 e = B.value * K**2 * grad_T return e e_exact_Q = dolfinx.Function(Q) e_exact_Q.interpolate(e_exact) assert (np.isclose((e_exact_Q.vector - e_Q.vector).norm(), 0.0))
def test_create_quadrature_extr_quadrilateral(extr_quadrilateral, basedeg, extrdeg, scheme): q = FIAT.create_quadrature(extr_quadrilateral, (basedeg, extrdeg), scheme) assert numpy.allclose(q.integrate(lambda x: (x[0] + x[1])**basedeg * x[2]**extrdeg), (2**(basedeg + 2) - 2) / ((basedeg + 1)*(basedeg + 2)) * 1/(extrdeg + 1))
def test_invalid_quadrature_degree(cell, scheme): with pytest.raises(ValueError): FIAT.create_quadrature(cell, -1, scheme)
def test_tensor_product_composition(interval, triangle, extr_triangle, scheme): degree = (4, 4) qa = FIAT.create_quadrature(triangle, degree[0], scheme) qb = FIAT.create_quadrature(interval, degree[1], scheme) q = FIAT.create_quadrature(extr_triangle, degree, scheme) assert len(q.get_points()) == len(qa.get_points())*len(qb.get_points())
V = dolfinx.FunctionSpace(mesh, ("Lagrange", 1)) u = ufl.TrialFunction(V) v = ufl.TestFunction(V) f = dolfinx.Function(V) def rhs(x): return sin(pi*x[0])*sin(pi*x[1]) f.interpolate(rhs) a_eqn = inner(grad(u), grad(v)) L_eqn = inner(f, v) a = a_eqn*ufl.dx(metadata={"quadrature_rule": "runtime"}) L = L_eqn*ufl.dx(metadata={"quadrature_rule": "runtime"}) degree = 2 q = FIAT.create_quadrature(FIAT.reference_element.UFCQuadrilateral(), degree) qr_pts = q.get_points().flatten() qr_w = q.get_weights().flatten() A = libcutfemx.custom_assemble_matrix(a, [(cells, [qr_pts], [qr_w])]) A.assemble() b = libcutfemx.custom_assemble_vector(L, [(cells, [qr_pts], [qr_w])]) print(A.norm()) print(numpy.linalg.norm(b.array)) vec = ksp_solve(A, b) u = vec_to_function(vec, V, "u") write("poisson.xdmf", mesh, u) # Reference