Beispiel #1
0
def construct_dg_element(ref_el, degree):
    """Constructs a discontinuous galerkin element of a given degree
    on a particular reference cell.
    """
    if ref_el.get_shape() in [LINE, TRIANGLE]:
        dg_element = DiscontinuousLagrange(ref_el, degree)

    # Quadrilateral facets could be on a FiredrakeQuadrilateral.
    # In this case, we treat this as an interval x interval cell:
    elif ref_el.get_shape() == QUADRILATERAL:
        dg_a = DiscontinuousLagrange(ufc_simplex(1), degree)
        dg_b = DiscontinuousLagrange(ufc_simplex(1), degree)
        dg_element = TensorProductElement(dg_a, dg_b)

    # This handles the more general case for facets:
    elif ref_el.get_shape() == TENSORPRODUCT:
        assert len(degree) == len(ref_el.cells), (
            "Must provide the same number of degrees as the number "
            "of cells that make up the tensor product cell."
        )
        sub_elements = [construct_dg_element(c, d)
                        for c, d in zip(ref_el.cells, degree)
                        if c.get_shape() != POINT]

        if len(sub_elements) > 1:
            dg_element = TensorProductElement(*sub_elements)
        else:
            dg_element, = sub_elements

    else:
        raise NotImplementedError(
            "Reference cells of type %s not currently supported" % type(ref_el)
        )

    return dg_element
Beispiel #2
0
def construct_dg_element(ref_el, degree):
    """Constructs a discontinuous galerkin element of a given degree
    on a particular reference cell.
    """
    if ref_el.get_shape() in [LINE, TRIANGLE]:
        dg_element = DiscontinuousLagrange(ref_el, degree)

    # Quadrilateral facets could be on a FiredrakeQuadrilateral.
    # In this case, we treat this as an interval x interval cell:
    elif ref_el.get_shape() == QUADRILATERAL:
        dg_a = DiscontinuousLagrange(ufc_simplex(1), degree)
        dg_b = DiscontinuousLagrange(ufc_simplex(1), degree)
        dg_element = TensorProductElement(dg_a, dg_b)

    # This handles the more general case for facets:
    elif ref_el.get_shape() == TENSORPRODUCT:
        assert len(degree) == len(ref_el.cells), (
            "Must provide the same number of degrees as the number "
            "of cells that make up the tensor product cell."
        )
        sub_elements = [construct_dg_element(c, d)
                        for c, d in zip(ref_el.cells, degree)
                        if c.get_shape() != POINT]

        if len(sub_elements) > 1:
            dg_element = TensorProductElement(*sub_elements)
        else:
            dg_element, = sub_elements

    else:
        raise NotImplementedError(
            "Reference cells of type %s not currently supported" % type(ref_el)
        )

    return dg_element
Beispiel #3
0
def map_to_reference_facet(points, vertices, facet):
    """Given a set of points and vertices describing a facet of a simplex in n-dimensional
    coordinates (where the points lie on the facet), map the points to the reference simplex
    of dimension (n-1).

    :arg points: A set of points in n-D.
    :arg vertices: A set of vertices describing a facet of a simplex in n-D.
    :arg facet: Integer representing the facet number.
    """

    # Compute the barycentric coordinates of the points with respect to the
    # full physical simplex
    all_coords = barycentric_coordinates(points, vertices)

    # Extract vertices of the reference facet
    reference_facet_simplex = ufc_simplex(len(vertices) - 2)
    reference_vertices = reference_facet_simplex.get_vertices()

    reference_points = []
    for (i, coords) in enumerate(all_coords):
        # Extract the correct subset of barycentric coordinates since we know
        # which facet we are on
        new_coords = [coords[j] for j in range(len(coords)) if j != facet]

        # Evaluate the reference coordinate of a point in barycentric coordinates
        reference_pt = sum(np.asarray(reference_vertices[j]) * new_coords[j]
                           for j in range(len(new_coords)))

        reference_points += [reference_pt]
    return reference_points
Beispiel #4
0
def map_to_reference_facet(points, vertices, facet):
    """Given a set of points and vertices describing a facet of a simplex in n-dimensional
    coordinates (where the points lie on the facet), map the points to the reference simplex
    of dimension (n-1).

    :arg points: A set of points in n-D.
    :arg vertices: A set of vertices describing a facet of a simplex in n-D.
    :arg facet: Integer representing the facet number.
    """

    # Compute the barycentric coordinates of the points with respect to the
    # full physical simplex
    all_coords = barycentric_coordinates(points, vertices)

    # Extract vertices of the reference facet
    reference_facet_simplex = ufc_simplex(len(vertices) - 2)
    reference_vertices = reference_facet_simplex.get_vertices()

    reference_points = []
    for (i, coords) in enumerate(all_coords):
        # Extract the correct subset of barycentric coordinates since we know
        # which facet we are on
        new_coords = [coords[j] for j in range(len(coords)) if j != facet]

        # Evaluate the reference coordinate of a point in barycentric coordinates
        reference_pt = sum(np.asarray(reference_vertices[j]) * new_coords[j]
                           for j in range(len(new_coords)))

        reference_points += [reference_pt]
    return reference_points
Beispiel #5
0
    def __init__(self, ref_el):
        entity_ids = {}
        nodes = []
        cur = 0

        # make nodes by getting points
        # need to do this dimension-by-dimension, facet-by-facet
        top = ref_el.get_topology()
        verts = ref_el.get_vertices()
        sd = ref_el.get_spatial_dimension()
        if ref_el.get_shape() != TRIANGLE:
            raise ValueError("Bell only defined on triangles")

        pd = functional.PointDerivative

        # get jet at each vertex

        entity_ids[0] = {}
        for v in sorted(top[0]):
            nodes.append(functional.PointEvaluation(ref_el, verts[v]))

            # first derivatives
            for i in range(sd):
                alpha = [0] * sd
                alpha[i] = 1
                nodes.append(pd(ref_el, verts[v], alpha))

            # second derivatives
            alphas = [[2, 0], [1, 1], [0, 2]]
            for alpha in alphas:
                nodes.append(pd(ref_el, verts[v], alpha))

            entity_ids[0][v] = list(range(cur, cur + 6))
            cur += 6

        # we need an edge quadrature rule for the moment
        from FIAT.quadrature_schemes import create_quadrature
        from FIAT.jacobi import eval_jacobi
        rline = ufc_simplex(1)
        q1d = create_quadrature(rline, 8)
        q1dpts = q1d.get_points()
        leg4_at_qpts = eval_jacobi(0, 0, 4, 2.0 * q1dpts - 1)

        imond = functional.IntegralMomentOfNormalDerivative
        entity_ids[1] = {}
        for e in sorted(top[1]):
            entity_ids[1][e] = [18 + e]
            nodes.append(imond(ref_el, e, q1d, leg4_at_qpts))

        entity_ids[2] = {0: []}

        super(BellDualSet, self).__init__(nodes, ref_el, entity_ids)
Beispiel #6
0
    def __init__(self, ref_el):
        entity_ids = {}
        nodes = []
        cur = 0

        # make nodes by getting points
        # need to do this dimension-by-dimension, facet-by-facet
        top = ref_el.get_topology()
        verts = ref_el.get_vertices()
        sd = ref_el.get_spatial_dimension()
        if ref_el.get_shape() != TRIANGLE:
            raise ValueError("Bell only defined on triangles")

        pd = functional.PointDerivative

        # get jet at each vertex

        entity_ids[0] = {}
        for v in sorted(top[0]):
            nodes.append(functional.PointEvaluation(ref_el, verts[v]))

            # first derivatives
            for i in range(sd):
                alpha = [0] * sd
                alpha[i] = 1
                nodes.append(pd(ref_el, verts[v], alpha))

            # second derivatives
            alphas = [[2, 0], [1, 1], [0, 2]]
            for alpha in alphas:
                nodes.append(pd(ref_el, verts[v], alpha))

            entity_ids[0][v] = list(range(cur, cur + 6))
            cur += 6

        # we need an edge quadrature rule for the moment
        from FIAT.quadrature_schemes import create_quadrature
        from FIAT.jacobi import eval_jacobi
        rline = ufc_simplex(1)
        q1d = create_quadrature(rline, 8)
        q1dpts = q1d.get_points()
        leg4_at_qpts = eval_jacobi(0, 0, 4, 2.0*q1dpts - 1)

        imond = functional.IntegralMomentOfNormalDerivative
        entity_ids[1] = {}
        for e in sorted(top[1]):
            entity_ids[1][e] = [18+e]
            nodes.append(imond(ref_el, e, q1d, leg4_at_qpts))

        entity_ids[2] = {0: []}

        super(BellDualSet, self).__init__(nodes, ref_el, entity_ids)
Beispiel #7
0
def test_bernstein_2nd_derivatives():
    ref_el = ufc_simplex(2)
    degree = 3

    elem = Bernstein(ref_el, degree)
    rule = create_quadrature(ref_el, degree)
    points = rule.get_points()

    actual = elem.tabulate(2, points)

    assert numpy.allclose(D02, actual[(0, 2)])
    assert numpy.allclose(D11, actual[(1, 1)])
    assert numpy.allclose(D20, actual[(2, 0)])
def test_bernstein_2nd_derivatives():
    ref_el = ufc_simplex(2)
    degree = 3

    elem = Bernstein(ref_el, degree)
    rule = create_quadrature(ref_el, degree)
    points = rule.get_points()

    actual = elem.tabulate(2, points)

    assert numpy.allclose(D02, actual[(0, 2)])
    assert numpy.allclose(D11, actual[(1, 1)])
    assert numpy.allclose(D20, actual[(2, 0)])
Beispiel #9
0
def map_from_reference_facet(point, vertices):
    """Evaluates the physical coordinate of a point using barycentric
    coordinates.

    :arg point: The reference points to be mapped to the facet.
    :arg vertices: The vertices defining the physical element.
    """

    # Compute the barycentric coordinates of the point relative to the reference facet
    reference_simplex = ufc_simplex(len(vertices) - 1)
    reference_vertices = reference_simplex.get_vertices()
    coords = barycentric_coordinates([point, ], reference_vertices)[0]

    # Evaluates the physical coordinate of the point using barycentric coordinates
    point = sum(vertices[j] * coords[j] for j in range(len(coords)))
    return tuple(point)
Beispiel #10
0
def map_from_reference_facet(point, vertices):
    """Evaluates the physical coordinate of a point using barycentric
    coordinates.

    :arg point: The reference points to be mapped to the facet.
    :arg vertices: The vertices defining the physical element.
    """

    # Compute the barycentric coordinates of the point relative to the reference facet
    reference_simplex = ufc_simplex(len(vertices) - 1)
    reference_vertices = reference_simplex.get_vertices()
    coords = barycentric_coordinates([point, ], reference_vertices)[0]

    # Evaluates the physical coordinate of the point using barycentric coordinates
    point = sum(vertices[j] * coords[j] for j in range(len(coords)))
    return tuple(point)
Beispiel #11
0
    def __init__(self, ref_el, degree):
        sd = ref_el.get_spatial_dimension()
        if sd in (0, 1):
            raise ValueError(
                "Cannot use this trace class on a %d-dimensional cell." % sd)

        # Constructing facet element as a discontinuous Lagrange element
        dglagrange = DiscontinuousLagrange(ufc_simplex(sd - 1), degree)

        # Construct entity ids (assigning top. dim. and initializing as empty)
        entity_dofs = {}

        # Looping over dictionary of cell topology to construct the empty
        # dictionary for entity ids of the trace element
        topology = ref_el.get_topology()
        for top_dim, entities in topology.items():
            entity_dofs[top_dim] = {}
            for entity in entities:
                entity_dofs[top_dim][entity] = []

        # Filling in entity ids and generating points for dual basis
        nf = dglagrange.space_dimension()
        points = []
        num_facets = sd + 1
        for f in range(num_facets):
            entity_dofs[sd - 1][f] = range(f * nf, (f + 1) * nf)

            for dof in dglagrange.dual_basis():
                facet_point = list(dof.get_point_dict().keys())[0]
                transform = ref_el.get_entity_transform(sd - 1, f)
                points.append(tuple(transform(facet_point)))

        # Setting up dual basis - only point evaluations
        nodes = [PointEvaluation(ref_el, pt) for pt in points]
        dual = dual_set.DualSet(nodes, ref_el, entity_dofs)

        super(HDivTrace, self).__init__(ref_el, dual, dglagrange.get_order(),
                                        dglagrange.get_formdegree(),
                                        dglagrange.mapping()[0])
        # Set up facet element
        self.facet_element = dglagrange

        # degree for quadrature rule
        self.polydegree = degree
Beispiel #12
0
def get_affine_reference_simplex_mapping(ambient_dim, firedrake_to_meshmode=True):
    """
    Returns a function which takes a numpy array points
    on one reference cell and maps each
    point to another using a positive affine map.

    :arg ambient_dim: The spatial dimension
    :arg firedrake_to_meshmode: If true, the returned function maps from
        the firedrake reference element to
        meshmode, if false maps from
        meshmode to firedrake. More specifically,
        :mod:`firedrake` uses the standard :mod:`FIAT`
        simplex and :mod:`meshmode` uses
        :mod:`modepy`'s
        `unit coordinates <https://documen.tician.de/modepy/nodes.html>`_.
    :return: A function which takes a numpy array of *n* points with
             shape *(dim, n)* on one reference cell and maps
             each point to another using a positive affine map.
             Note that the returned function performs
             no input validation.
    """
    # validate input
    if not isinstance(ambient_dim, int):
        raise TypeError("'ambient_dim' must be an int, not "
                        f"'{type(ambient_dim)}'")
    if ambient_dim < 0:
        raise ValueError("'ambient_dim' must be non-negative")
    if not isinstance(firedrake_to_meshmode, bool):
        raise TypeError("'firedrake_to_meshmode' must be a bool, not "
                        f"'{type(firedrake_to_meshmode)}'")

    from FIAT.reference_element import ufc_simplex
    from modepy.tools import unit_vertices
    # Get the unit vertices from each system,
    # each stored with shape *(dim, nunit_vertices)*
    firedrake_unit_vertices = np.array(ufc_simplex(ambient_dim).vertices).T
    modepy_unit_vertices = unit_vertices(ambient_dim).T

    if firedrake_to_meshmode:
        from_verts = firedrake_unit_vertices
        to_verts = modepy_unit_vertices
    else:
        from_verts = modepy_unit_vertices
        to_verts = firedrake_unit_vertices

    # Compute matrix A and vector b so that A f_i + b -> t_i
    # for each "from" vertex f_i and corresponding "to" vertex t_i
    assert from_verts.shape == to_verts.shape
    dim, nvects = from_verts.shape

    # If we only have one vertex, have A = I and b = to_vert - from_vert
    if nvects == 1:
        shift = to_verts[:, 0] - from_verts[:, 0]

        def affine_map(points):
            return points + shift[:, np.newaxis]
    # Otherwise, we have to solve for A and b
    else:
        # span verts: v1 - v0, v2 - v0, ...
        from_span_verts = from_verts[:, 1:] - from_verts[:, 0, np.newaxis]
        to_span_verts = to_verts[:, 1:] - to_verts[:, 0, np.newaxis]
        # mat maps (fj - f0) -> (tj - t0), our "A"
        mat = la.solve(from_span_verts, to_span_verts)
        # A f0 + b -> t0 so b = t0 - A f0
        shift = to_verts[:, 0] - np.matmul(mat, from_verts[:, 0])

        # Explicitly ensure A is positive
        if la.det(mat) < 0:
            from meshmode.mesh.processing import get_simplex_element_flip_matrix
            flip_matrix = get_simplex_element_flip_matrix(1, to_verts)
            mat = np.matmul(flip_matrix, mat)

        def affine_map(points):
            return np.matmul(mat, points) + shift[:, np.newaxis]

    return affine_map