Пример #1
0
 def __init__(self, ref_el, degree):
     if ref_el.shape != LINE:
         raise ValueError("Gauss-Legendre elements are only defined in one dimension.")
     poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
     dual = GaussLegendreDualSet(ref_el, degree)
     formdegree = ref_el.get_spatial_dimension()  # n-form
     super(GaussLegendre, self).__init__(poly_set, dual, degree, formdegree)
Пример #2
0
    def _generate_edge_dofs(self, cell, degree, offset, variant, quad_deg):
        """Generate degrees of freedoms (dofs) for entities of
        codimension 1 (edges)."""

        # (degree+1) tangential component point evaluation degrees of
        # freedom per entity of codimension 1 (edges)
        dofs = []
        ids = {}

        if variant == "integral":
            edge = cell.construct_subelement(1)
            Q = quadrature.make_quadrature(edge, quad_deg)
            Pq = polynomial_set.ONPolynomialSet(edge, degree)
            Pq_at_qpts = Pq.tabulate(Q.get_points())[tuple([0]*(1))]
            for e in range(len(cell.get_topology()[1])):
                for i in range(Pq_at_qpts.shape[0]):
                    phi = Pq_at_qpts[i, :]
                    dofs.append(functional.IntegralMomentOfEdgeTangentEvaluation(cell, Q, phi, e))
                jj = Pq_at_qpts.shape[0] * e
                ids[e] = list(range(offset + jj, offset + jj + Pq_at_qpts.shape[0]))

        elif variant == "point":
            for edge in range(len(cell.get_topology()[1])):

                # Create points for evaluation of tangential components
                points = cell.make_points(1, edge, degree + 2)

                # A tangential component evaluation for each point
                dofs += [Tangent(cell, edge, point) for point in points]

                # Associate these dofs with this edge
                i = len(points) * edge
                ids[edge] = list(range(offset + i, offset + i + len(points)))

        return (dofs, ids)
Пример #3
0
def RTSpace(ref_el, deg):
    """Constructs a basis for the the Raviart-Thomas space
    (P_k)^d + P_k x"""
    sd = ref_el.get_spatial_dimension()

    vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, deg + 1, (sd,))

    dimPkp1 = expansions.polynomial_dimension(ref_el, deg + 1)
    dimPk = expansions.polynomial_dimension(ref_el, deg)
    dimPkm1 = expansions.polynomial_dimension(ref_el, deg - 1)

    vec_Pk_indices = list(chain(*(range(i * dimPkp1, i * dimPkp1 + dimPk)
                                  for i in range(sd))))
    vec_Pk_from_Pkp1 = vec_Pkp1.take(vec_Pk_indices)

    Pkp1 = polynomial_set.ONPolynomialSet(ref_el, deg + 1)
    PkH = Pkp1.take(list(range(dimPkm1, dimPk)))

    Q = quadrature.make_quadrature(ref_el, 2 * deg + 2)

    # have to work on this through "tabulate" interface
    # first, tabulate PkH at quadrature points
    Qpts = numpy.array(Q.get_points())
    Qwts = numpy.array(Q.get_weights())

    zero_index = tuple([0 for i in range(sd)])

    PkH_at_Qpts = PkH.tabulate(Qpts)[zero_index]
    Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[zero_index]

    PkHx_coeffs = numpy.zeros((PkH.get_num_members(),
                               sd,
                               Pkp1.get_num_members()), "d")

    for i in range(PkH.get_num_members()):
        for j in range(sd):
            fooij = PkH_at_Qpts[i, :] * Qpts[:, j] * Qwts
            PkHx_coeffs[i, j, :] = numpy.dot(Pkp1_at_Qpts, fooij)

    PkHx = polynomial_set.PolynomialSet(ref_el,
                                        deg,
                                        deg + 1,
                                        vec_Pkp1.get_expansion_set(),
                                        PkHx_coeffs,
                                        vec_Pkp1.get_dmats())

    return polynomial_set.polynomial_set_union_normalized(vec_Pk_from_Pkp1, PkHx)
Пример #4
0
    def __init__(self, ref_el, degree):
        sd = ref_el.get_spatial_dimension()
        if sd != 2:
            raise Exception("Nedelec2D only works on triangles")

        nodes = []

        t = ref_el.get_topology()

        num_edges = len(t[1])

        # edge tangents
        for i in range(num_edges):
            pts_cur = ref_el.make_points(1, i, degree + 2)
            for j in range(len(pts_cur)):
                pt_cur = pts_cur[j]
                f = functional.PointEdgeTangentEvaluation(ref_el, i, pt_cur)
                nodes.append(f)

        # internal moments
        if degree > 0:
            Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1))
            qpts = Q.get_points()
            Pkm1 = polynomial_set.ONPolynomialSet(ref_el, degree - 1)
            zero_index = tuple([0 for i in range(sd)])
            Pkm1_at_qpts = Pkm1.tabulate(qpts)[zero_index]

            for d in range(sd):
                for i in range(Pkm1_at_qpts.shape[0]):
                    phi_cur = Pkm1_at_qpts[i, :]
                    l_cur = functional.IntegralMoment(ref_el, Q, phi_cur,
                                                      (d, ))
                    nodes.append(l_cur)

        entity_ids = {}

        # set to empty
        for i in range(sd + 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # edges
        num_edge_pts = len(ref_el.make_points(1, 0, degree + 2))

        for i in range(len(t[1])):
            entity_ids[1][i] = list(range(cur, cur + num_edge_pts))
            cur += num_edge_pts

        # moments against P_{degree-1} internally, if degree > 0
        if degree > 0:
            num_internal_dof = sd * Pkm1_at_qpts.shape[0]
            entity_ids[2][0] = list(range(cur, cur + num_internal_dof))

        super(NedelecDual2D, self).__init__(nodes, ref_el, entity_ids)
Пример #5
0
 def __init__(self, ref_el, degree):
     if ref_el.shape != LINE:
         raise ValueError("FDM elements are only defined in one dimension.")
     poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
     if degree == 0:
         dual = P0Dual(ref_el)
     else:
         dual = FDMDual(ref_el, degree, order=self._order)
     formdegree = 0
     super(FDMLagrange, self).__init__(poly_set, dual, degree, formdegree)
Пример #6
0
 def __init__(self, ref_el, degree):
     flat_el = flatten_reference_cube(ref_el)
     poly_set = polynomial_set.ONPolynomialSet(
         hypercube_simplex_map[flat_el], degree)
     dual = DPCDualSet(ref_el, flat_el, degree)
     formdegree = flat_el.get_spatial_dimension()  # n-form
     super(HigherOrderDPC, self).__init__(poly_set=poly_set,
                                          dual=dual,
                                          order=degree,
                                          ref_el=ref_el,
                                          formdegree=formdegree)
Пример #7
0
    def __init__(self, cell, degree):

        # Crouzeix Raviart is only defined for polynomial degree == 1
        if not (degree == 1):
            raise Exception("Crouzeix-Raviart only defined for degree 1")

        # Construct polynomial spaces, dual basis and initialize
        # FiniteElement
        space = polynomial_set.ONPolynomialSet(cell, 1)
        dual = CrouzeixRaviartDualSet(cell, 1)
        super(CrouzeixRaviart, self).__init__(space, dual, 1)
Пример #8
0
 def __init__(self, ref_el):
     flat_el = flatten_reference_cube(ref_el)
     poly_set = polynomial_set.ONPolynomialSet(
         hypercube_simplex_map[flat_el], 0)
     dual = P0Dual(ref_el)
     degree = 0
     formdegree = ref_el.get_spatial_dimension()  # n-form
     super(DPC0, self).__init__(poly_set=poly_set,
                                dual=dual,
                                order=degree,
                                ref_el=ref_el,
                                formdegree=formdegree)
Пример #9
0
    def __init__(self, ref_el, k, variant=None):

        (variant, quad_deg) = check_format_variant(variant, k, "BDM")

        if k < 1:
            raise Exception("BDM_k elements only valid for k >= 1")

        sd = ref_el.get_spatial_dimension()
        poly_set = polynomial_set.ONPolynomialSet(ref_el, k, (sd, ))
        dual = BDMDualSet(ref_el, k, variant, quad_deg)
        formdegree = sd - 1  # (n-1)-form
        super(BrezziDouglasMarini, self).__init__(poly_set, dual, k, formdegree,
                                                  mapping="contravariant piola")
Пример #10
0
    def __init__(self, family, degree):
        "Create time element with given (polynomial degree)."

        # Only defined in 1D (on an inteval)
        cell = reference_element.UFCInterval()

        # Initialize polynomial space of degree 'degree'
        polynomial_space = polynomial_set.ONPolynomialSet(cell, degree)

        # Create dual (degrees of freedom)
        dual = TimeElementDualSet(family, degree)

        # Initialize super class
        finite_element.FiniteElement.__init__(self, polynomial_space, dual,
                                              degree)
Пример #11
0
    def __init__(self, ref_el, degree):

        if degree < 1:
            raise Exception("BDM_k elements only valid for k >= 1")

        sd = ref_el.get_spatial_dimension()
        poly_set = polynomial_set.ONPolynomialSet(ref_el, degree, (sd, ))
        dual = BDMDualSet(ref_el, degree)
        formdegree = sd - 1  # (n-1)-form
        super(BrezziDouglasMarini,
              self).__init__(poly_set,
                             dual,
                             degree,
                             formdegree,
                             mapping="contravariant piola")
Пример #12
0
def BDFMSpace(ref_el, order):
    sd = ref_el.get_spatial_dimension()
    if sd != 2:
        raise Exception("BDFM_k elements only valid for dim 2")
    # Note that order will be 2.

    # Linear vector valued space. Since the embedding degree of this element
    # is 2, this is implemented by taking the quadratic space and selecting
    # the linear polynomials.
    vec_poly_set = polynomial_set.ONPolynomialSet(ref_el, order, (sd,))
    # Linears are the first three polynomials in each dimension.
    vec_poly_set = vec_poly_set.take([0, 1, 2, 6, 7, 8])

    # Scalar quadratic Lagrange element.
    lagrange_ele = lagrange.Lagrange(ref_el, order)
    # Select the dofs associated with the edges.
    edge_dofs_dict = lagrange_ele.dual.get_entity_ids()[sd - 1]
    edge_dofs = numpy.array([(edge, dof)
                             for edge, dofs in list(edge_dofs_dict.items())
                             for dof in dofs])

    tangent_polys = lagrange_ele.poly_set.take(edge_dofs[:, 1])
    new_coeffs = numpy.zeros((tangent_polys.get_num_members(), sd, tangent_polys.coeffs.shape[-1]))

    # Outer product of the tangent vectors with the quadratic edge polynomials.
    for i, (edge, dof) in enumerate(edge_dofs):
        tangent = ref_el.compute_edge_tangent(edge)

        new_coeffs[i, :, :] = numpy.outer(tangent, tangent_polys.coeffs[i, :])

    bubble_set = polynomial_set.PolynomialSet(ref_el,
                                              order,
                                              order,
                                              vec_poly_set.get_expansion_set(),
                                              new_coeffs,
                                              vec_poly_set.get_dmats())

    element_set = polynomial_set.polynomial_set_union_normalized(bubble_set, vec_poly_set)
    return element_set
Пример #13
0
def test_edge_degree(degree):
    """Verify that the outer edges of a degree KMV element
       are indeed of degree and the interior is of degree+1"""
    # create a degree+1 polynomial
    I = UFCInterval()
    # an exact quad. rule for a degree+1 polynomial on the UFCinterval
    qr = make_quadrature(I, degree + 1)
    W = np.diag(qr.wts)
    sd = I.get_spatial_dimension()
    pset = polynomial_set.ONPolynomialSet(I, degree + 1, (sd, ))
    pset = pset.take([degree + 1])
    # tabulate at the quadrature points
    interval_vals = pset.tabulate(qr.get_points())[(0, )]
    interval_vals = np.squeeze(interval_vals)
    # create degree KMV element (should have degree outer edges and degree+1 edge in center)
    T = UFCTriangle()
    element = KMV(T, degree)
    # tabulate values on an edge of the KMV element
    for e in range(3):
        edge_values = element.tabulate(0, qr.get_points(), (1, e))[(0, 0)]
        # degree edge should be orthogonal to degree+1 ONpoly edge values
        result = edge_values @ W @ interval_vals.T
        assert np.allclose(np.sum(result), 0.0)
Пример #14
0
    def __init__(self, ref_el, degree, variant, quad_deg):
        entity_ids = {}
        nodes = []

        sd = ref_el.get_spatial_dimension()
        t = ref_el.get_topology()

        if variant == "integral":
            facet = ref_el.get_facet_element()
            # Facet nodes are \int_F v\cdot n p ds where p \in P_{q-1}
            # degree is q - 1
            Q = quadrature.make_quadrature(facet, quad_deg)
            Pq = polynomial_set.ONPolynomialSet(facet, degree)
            Pq_at_qpts = Pq.tabulate(Q.get_points())[tuple([0] * (sd - 1))]
            for f in range(len(t[sd - 1])):
                for i in range(Pq_at_qpts.shape[0]):
                    phi = Pq_at_qpts[i, :]
                    nodes.append(
                        functional.IntegralMomentOfScaledNormalEvaluation(
                            ref_el, Q, phi, f))

            # internal nodes. These are \int_T v \cdot p dx where p \in P_{q-2}^d
            if degree > 0:
                Q = quadrature.make_quadrature(ref_el, quad_deg)
                qpts = Q.get_points()
                Pkm1 = polynomial_set.ONPolynomialSet(ref_el, degree - 1)
                zero_index = tuple([0 for i in range(sd)])
                Pkm1_at_qpts = Pkm1.tabulate(qpts)[zero_index]

                for d in range(sd):
                    for i in range(Pkm1_at_qpts.shape[0]):
                        phi_cur = Pkm1_at_qpts[i, :]
                        l_cur = functional.IntegralMoment(
                            ref_el, Q, phi_cur, (d, ), (sd, ))
                        nodes.append(l_cur)

        elif variant == "point":
            # codimension 1 facets
            for i in range(len(t[sd - 1])):
                pts_cur = ref_el.make_points(sd - 1, i, sd + degree)
                for j in range(len(pts_cur)):
                    pt_cur = pts_cur[j]
                    f = functional.PointScaledNormalEvaluation(
                        ref_el, i, pt_cur)
                    nodes.append(f)

            # internal nodes.  Let's just use points at a lattice
            if degree > 0:
                cpe = functional.ComponentPointEvaluation
                pts = ref_el.make_points(sd, 0, degree + sd)
                for d in range(sd):
                    for i in range(len(pts)):
                        l_cur = cpe(ref_el, d, (sd, ), pts[i])
                        nodes.append(l_cur)

        # sets vertices (and in 3d, edges) to have no nodes
        for i in range(sd - 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # set codimension 1 (edges 2d, faces 3d) dof
        pts_facet_0 = ref_el.make_points(sd - 1, 0, sd + degree)
        pts_per_facet = len(pts_facet_0)
        entity_ids[sd - 1] = {}
        for i in range(len(t[sd - 1])):
            entity_ids[sd - 1][i] = list(range(cur, cur + pts_per_facet))
            cur += pts_per_facet

        # internal nodes, if applicable
        entity_ids[sd] = {0: []}
        if degree > 0:
            num_internal_nodes = expansions.polynomial_dimension(
                ref_el, degree - 1)
            entity_ids[sd][0] = list(range(cur, cur + num_internal_nodes * sd))

        super(RTDualSet, self).__init__(nodes, ref_el, entity_ids)
Пример #15
0
def NedelecSpace3D(ref_el, k):
    """Constructs a nodal basis for the 3d first-kind Nedelec space"""
    sd = ref_el.get_spatial_dimension()
    if sd != 3:
        raise Exception("NedelecSpace3D requires 3d reference element")

    vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd, ))

    dimPkp1 = expansions.polynomial_dimension(ref_el, k + 1)
    dimPk = expansions.polynomial_dimension(ref_el, k)
    if k > 0:
        dimPkm1 = expansions.polynomial_dimension(ref_el, k - 1)
    else:
        dimPkm1 = 0

    vec_Pk_indices = list(
        chain(*(range(i * dimPkp1, i * dimPkp1 + dimPk) for i in range(sd))))
    vec_Pk = vec_Pkp1.take(vec_Pk_indices)

    vec_Pke_indices = list(
        chain(*(range(i * dimPkp1 + dimPkm1, i * dimPkp1 + dimPk)
                for i in range(sd))))

    vec_Pke = vec_Pkp1.take(vec_Pke_indices)

    Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1)

    Q = quadrature.make_quadrature(ref_el, 2 * (k + 1))

    Qpts = numpy.array(Q.get_points())
    Qwts = numpy.array(Q.get_weights())

    zero_index = tuple([0 for i in range(sd)])

    PkCrossXcoeffs = numpy.zeros(
        (vec_Pke.get_num_members(), sd, Pkp1.get_num_members()), "d")

    Pke_qpts = vec_Pke.tabulate(Qpts)[zero_index]
    Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[zero_index]

    for i in range(vec_Pke.get_num_members()):
        for j in range(sd):  # vector components
            qwts_cur_bf_val = (
                Qpts[:, (j + 2) % 3] * Pke_qpts[i, (j + 1) % 3, :] -
                Qpts[:, (j + 1) % 3] * Pke_qpts[i, (j + 2) % 3, :]) * Qwts
            PkCrossXcoeffs[i, j, :] = numpy.dot(Pkp1_at_Qpts, qwts_cur_bf_val)


#            for k in range( Pkp1.get_num_members() ):
#                 PkCrossXcoeffs[i,j,k] = sum( Qwts * cur_bf_val * Pkp1_at_Qpts[k,:] )
#                for l in range( len( Qpts ) ):
#                    cur_bf_val = Qpts[l][(j+2)%3] \
#                                 * Pke_qpts[i,(j+1)%3,l] \
#                                 - Qpts[l][(j+1)%3] \
#                                 * Pke_qpts[i,(j+2)%3,l]
#                    PkCrossXcoeffs[i,j,k] += Qwts[l] \
#                                             * cur_bf_val \
#                                             * Pkp1_at_Qpts[k,l]

    PkCrossX = polynomial_set.PolynomialSet(ref_el, k + 1, k + 1,
                                            vec_Pkp1.get_expansion_set(),
                                            PkCrossXcoeffs,
                                            vec_Pkp1.get_dmats())
    return polynomial_set.polynomial_set_union_normalized(vec_Pk, PkCrossX)
Пример #16
0
    def __init__(self, ref_el, degree, variant, quad_deg):
        sd = ref_el.get_spatial_dimension()
        if sd != 3:
            raise Exception("NedelecDual3D only works on tetrahedra")

        nodes = []

        t = ref_el.get_topology()

        if variant == "integral":
            # edge nodes are \int_F v\cdot t p ds where p \in P_{q-1}(edge)
            # degree is q - 1
            edge = ref_el.get_facet_element().get_facet_element()
            Q = quadrature.make_quadrature(edge, quad_deg)
            Pq = polynomial_set.ONPolynomialSet(edge, degree)
            Pq_at_qpts = Pq.tabulate(Q.get_points())[tuple([0] * (1))]
            for e in range(len(t[1])):
                for i in range(Pq_at_qpts.shape[0]):
                    phi = Pq_at_qpts[i, :]
                    nodes.append(
                        functional.IntegralMomentOfEdgeTangentEvaluation(
                            ref_el, Q, phi, e))

            # face nodes are \int_F v\cdot p dA where p \in P_{q-2}(f)^3 with p \cdot n = 0 (cmp. Monk)
            # these are equivalent to dofs from Fenics book defined by
            # \int_F v\times n \cdot p ds where p \in P_{q-2}(f)^2
            if degree > 0:
                facet = ref_el.get_facet_element()
                Q = quadrature.make_quadrature(facet, quad_deg)
                Pq = polynomial_set.ONPolynomialSet(facet, degree - 1, (sd, ))
                Pq_at_qpts = Pq.tabulate(Q.get_points())[(0, 0)]

                for f in range(len(t[2])):
                    # R is used to map [1,0,0] to tangent1 and [0,1,0] to tangent2
                    R = ref_el.compute_face_tangents(f)

                    # Skip last functionals because we only want p with p \cdot n = 0
                    for i in range(2 * Pq.get_num_members() // 3):
                        phi = Pq_at_qpts[i, ...]
                        phi = numpy.matmul(phi[:-1, ...].T, R)
                        nodes.append(
                            functional.MonkIntegralMoment(ref_el, Q, phi, f))

            # internal nodes. These are \int_T v \cdot p dx where p \in P_{q-3}^3(T)
            if degree > 1:
                Q = quadrature.make_quadrature(ref_el, quad_deg)
                qpts = Q.get_points()
                Pkm2 = polynomial_set.ONPolynomialSet(ref_el, degree - 2)
                zero_index = tuple([0 for i in range(sd)])
                Pkm2_at_qpts = Pkm2.tabulate(qpts)[zero_index]

                for d in range(sd):
                    for i in range(Pkm2_at_qpts.shape[0]):
                        phi_cur = Pkm2_at_qpts[i, :]
                        l_cur = functional.IntegralMoment(
                            ref_el, Q, phi_cur, (d, ), (sd, ))
                        nodes.append(l_cur)

        elif variant == "point":
            num_edges = len(t[1])

            for i in range(num_edges):
                # points to specify P_k on each edge
                pts_cur = ref_el.make_points(1, i, degree + 2)
                for j in range(len(pts_cur)):
                    pt_cur = pts_cur[j]
                    f = functional.PointEdgeTangentEvaluation(
                        ref_el, i, pt_cur)
                    nodes.append(f)

            if degree > 0:  # face tangents
                num_faces = len(t[2])
                for i in range(num_faces):  # loop over faces
                    pts_cur = ref_el.make_points(2, i, degree + 2)
                    for j in range(len(pts_cur)):  # loop over points
                        pt_cur = pts_cur[j]
                        for k in range(2):  # loop over tangents
                            f = functional.PointFaceTangentEvaluation(
                                ref_el, i, k, pt_cur)
                            nodes.append(f)

            if degree > 1:  # internal moments
                Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1))
                qpts = Q.get_points()
                Pkm2 = polynomial_set.ONPolynomialSet(ref_el, degree - 2)
                zero_index = tuple([0 for i in range(sd)])
                Pkm2_at_qpts = Pkm2.tabulate(qpts)[zero_index]

                for d in range(sd):
                    for i in range(Pkm2_at_qpts.shape[0]):
                        phi_cur = Pkm2_at_qpts[i, :]
                        f = functional.IntegralMoment(ref_el, Q, phi_cur,
                                                      (d, ), (sd, ))
                        nodes.append(f)

        entity_ids = {}
        # set to empty
        for i in range(sd + 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # edge dof
        num_pts_per_edge = len(ref_el.make_points(1, 0, degree + 2))
        for i in range(len(t[1])):
            entity_ids[1][i] = list(range(cur, cur + num_pts_per_edge))
            cur += num_pts_per_edge

        # face dof
        if degree > 0:
            num_pts_per_face = len(ref_el.make_points(2, 0, degree + 2))
            for i in range(len(t[2])):
                entity_ids[2][i] = list(range(cur, cur + 2 * num_pts_per_face))
                cur += 2 * num_pts_per_face

        if degree > 1:
            num_internal_dof = Pkm2_at_qpts.shape[0] * sd
            entity_ids[3][0] = list(range(cur, cur + num_internal_dof))

        super(NedelecDual3D, self).__init__(nodes, ref_el, entity_ids)
Пример #17
0
    def __init__(self, ref_el, degree, variant, quad_deg):
        sd = ref_el.get_spatial_dimension()
        if sd != 2:
            raise Exception("Nedelec2D only works on triangles")

        nodes = []

        t = ref_el.get_topology()

        if variant == "integral":
            # edge nodes are \int_F v\cdot t p ds where p \in P_{q-1}(edge)
            # degree is q - 1
            edge = ref_el.get_facet_element()
            Q = quadrature.make_quadrature(edge, quad_deg)
            Pq = polynomial_set.ONPolynomialSet(edge, degree)
            Pq_at_qpts = Pq.tabulate(Q.get_points())[tuple([0] * (sd - 1))]
            for e in range(len(t[sd - 1])):
                for i in range(Pq_at_qpts.shape[0]):
                    phi = Pq_at_qpts[i, :]
                    nodes.append(
                        functional.IntegralMomentOfEdgeTangentEvaluation(
                            ref_el, Q, phi, e))

            # internal nodes. These are \int_T v \cdot p dx where p \in P_{q-2}^2
            if degree > 0:
                Q = quadrature.make_quadrature(ref_el, quad_deg)
                qpts = Q.get_points()
                Pkm1 = polynomial_set.ONPolynomialSet(ref_el, degree - 1)
                zero_index = tuple([0 for i in range(sd)])
                Pkm1_at_qpts = Pkm1.tabulate(qpts)[zero_index]

                for d in range(sd):
                    for i in range(Pkm1_at_qpts.shape[0]):
                        phi_cur = Pkm1_at_qpts[i, :]
                        l_cur = functional.IntegralMoment(
                            ref_el, Q, phi_cur, (d, ), (sd, ))
                        nodes.append(l_cur)

        elif variant == "point":
            num_edges = len(t[1])

            # edge tangents
            for i in range(num_edges):
                pts_cur = ref_el.make_points(1, i, degree + 2)
                for j in range(len(pts_cur)):
                    pt_cur = pts_cur[j]
                    f = functional.PointEdgeTangentEvaluation(
                        ref_el, i, pt_cur)
                    nodes.append(f)

            # internal moments
            if degree > 0:
                Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1))
                qpts = Q.get_points()
                Pkm1 = polynomial_set.ONPolynomialSet(ref_el, degree - 1)
                zero_index = tuple([0 for i in range(sd)])
                Pkm1_at_qpts = Pkm1.tabulate(qpts)[zero_index]

                for d in range(sd):
                    for i in range(Pkm1_at_qpts.shape[0]):
                        phi_cur = Pkm1_at_qpts[i, :]
                        l_cur = functional.IntegralMoment(
                            ref_el, Q, phi_cur, (d, ), (sd, ))
                        nodes.append(l_cur)

        entity_ids = {}

        # set to empty
        for i in range(sd + 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # edges
        num_edge_pts = len(ref_el.make_points(1, 0, degree + 2))

        for i in range(len(t[1])):
            entity_ids[1][i] = list(range(cur, cur + num_edge_pts))
            cur += num_edge_pts

        # moments against P_{degree-1} internally, if degree > 0
        if degree > 0:
            num_internal_dof = sd * Pkm1_at_qpts.shape[0]
            entity_ids[2][0] = list(range(cur, cur + num_internal_dof))

        super(NedelecDual2D, self).__init__(nodes, ref_el, entity_ids)
Пример #18
0
 def __init__(self, ref_el):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, 5)
     dual = QuinticArgyrisDualSet(ref_el)
     super(QuinticArgyris, self).__init__(poly_set, dual, 5)
Пример #19
0
    def to_riesz(self, poly_set):
        r"""This method gives the action of the entire dual set
        on each member of the expansion set underlying poly_set.
        Then, applying the linear functionals of the dual set to an
        arbitrary polynomial in poly_set is accomplished by (generalized)
        matrix multiplication.

        For scalar-valued spaces, this produces a matrix
        :\math:`R_{i, j}` such that
        :\math:`\ell_i(f) = \sum_{j} a_j \ell_i(\phi_j)`
        for :\math:`f=\sum_{j} a_j \phi_j`.

        More generally, it will have shape concatenating
        the number of functionals in the dual set, the value shape
        of functions it takes, and the number of members of the
        expansion set.
        """

        # This rather technical code queries the low-level information
        # in pt_dict and deriv_dict
        # for each functional to find out where it evaluates its
        # inputs and/or their derivatives.  Then, it tabulates the
        # expansion set one time for all the function values and
        # another for all of the derivatives.  This circumvents
        # needing to call the to_riesz method of each functional and
        # also limits the number of different calls to tabulate.

        tshape = self.nodes[0].target_shape
        num_nodes = len(self.nodes)
        es = poly_set.get_expansion_set()
        ed = poly_set.get_embedded_degree()
        num_exp = es.get_num_members(poly_set.get_embedded_degree())

        riesz_shape = tuple([num_nodes] + list(tshape) + [num_exp])

        self.mat = numpy.zeros(riesz_shape, "d")

        # Dictionaries mapping pts to which functionals they come from
        pts_to_ells = collections.OrderedDict()
        dpts_to_ells = collections.OrderedDict()

        for i, ell in enumerate(self.nodes):
            for pt in ell.pt_dict:
                if pt in pts_to_ells:
                    pts_to_ells[pt].append(i)
                else:
                    pts_to_ells[pt] = [i]

            for pt in ell.deriv_dict:
                if pt in dpts_to_ells:
                    dpts_to_ells[pt].append(i)
                else:
                    dpts_to_ells[pt] = [i]

        # Now tabulate the function values
        pts = list(pts_to_ells.keys())
        expansion_values = es.tabulate(ed, pts)

        for j, pt in enumerate(pts):
            which_ells = pts_to_ells[pt]

            for k in which_ells:
                pt_dict = self.nodes[k].pt_dict
                wc_list = pt_dict[pt]

                for i in range(num_exp):
                    for (w, c) in wc_list:
                        self.mat[k][c][i] += w*expansion_values[i, j]

        # Tabulate the derivative values that are needed
        max_deriv_order = max([ell.max_deriv_order for ell in self.nodes])
        if max_deriv_order > 0:
            dpts = list(dpts_to_ells.keys())
            # It's easiest/most efficient to get derivatives of the
            # expansion set through the polynomial set interface.
            # This is creating a short-lived set to do just this.
            expansion = polynomial_set.ONPolynomialSet(self.ref_el, ed)
            dexpansion_values = expansion.tabulate(dpts, max_deriv_order)

            for j, pt in enumerate(dpts):
                which_ells = dpts_to_ells[pt]

                for k in which_ells:
                    dpt_dict = self.nodes[k].deriv_dict
                    wac_list = dpt_dict[pt]

                    for i in range(num_exp):
                        for (w, alpha, c) in wac_list:
                            self.mat[k][c][i] += w*dexpansion_values[alpha][i, j]

        return self.mat
Пример #20
0
    def __init__(self, ref_el, degree, variant, quad_deg):

        # Initialize containers for map: mesh_entity -> dof number and
        # dual basis
        entity_ids = {}
        nodes = []

        sd = ref_el.get_spatial_dimension()
        t = ref_el.get_topology()

        if variant == "integral":
            facet = ref_el.get_facet_element()
            # Facet nodes are \int_F v\cdot n p ds where p \in P_{q-1}
            # degree is q - 1
            Q = quadrature.make_quadrature(facet, quad_deg)
            Pq = polynomial_set.ONPolynomialSet(facet, degree)
            Pq_at_qpts = Pq.tabulate(Q.get_points())[tuple([0] * (sd - 1))]
            for f in range(len(t[sd - 1])):
                for i in range(Pq_at_qpts.shape[0]):
                    phi = Pq_at_qpts[i, :]
                    nodes.append(
                        functional.IntegralMomentOfScaledNormalEvaluation(
                            ref_el, Q, phi, f))

            # internal nodes
            if degree > 1:
                Q = quadrature.make_quadrature(ref_el, quad_deg)
                qpts = Q.get_points()
                Nedel = nedelec.Nedelec(ref_el, degree - 1, variant)
                Nedfs = Nedel.get_nodal_basis()
                zero_index = tuple([0 for i in range(sd)])
                Ned_at_qpts = Nedfs.tabulate(qpts)[zero_index]

                for i in range(len(Ned_at_qpts)):
                    phi_cur = Ned_at_qpts[i, :]
                    l_cur = functional.FrobeniusIntegralMoment(
                        ref_el, Q, phi_cur)
                    nodes.append(l_cur)

        elif variant == "point":
            # Define each functional for the dual set
            # codimension 1 facets
            for i in range(len(t[sd - 1])):
                pts_cur = ref_el.make_points(sd - 1, i, sd + degree)
                for j in range(len(pts_cur)):
                    pt_cur = pts_cur[j]
                    f = functional.PointScaledNormalEvaluation(
                        ref_el, i, pt_cur)
                    nodes.append(f)

            # internal nodes
            if degree > 1:
                Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1))
                qpts = Q.get_points()
                Nedel = nedelec.Nedelec(ref_el, degree - 1, variant)
                Nedfs = Nedel.get_nodal_basis()
                zero_index = tuple([0 for i in range(sd)])
                Ned_at_qpts = Nedfs.tabulate(qpts)[zero_index]

                for i in range(len(Ned_at_qpts)):
                    phi_cur = Ned_at_qpts[i, :]
                    l_cur = functional.FrobeniusIntegralMoment(
                        ref_el, Q, phi_cur)
                    nodes.append(l_cur)

        # sets vertices (and in 3d, edges) to have no nodes
        for i in range(sd - 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # set codimension 1 (edges 2d, faces 3d) dof
        pts_facet_0 = ref_el.make_points(sd - 1, 0, sd + degree)
        pts_per_facet = len(pts_facet_0)

        entity_ids[sd - 1] = {}
        for i in range(len(t[sd - 1])):
            entity_ids[sd - 1][i] = list(range(cur, cur + pts_per_facet))
            cur += pts_per_facet

        # internal nodes, if applicable
        entity_ids[sd] = {0: []}

        if degree > 1:
            num_internal_nodes = len(Ned_at_qpts)
            entity_ids[sd][0] = list(range(cur, cur + num_internal_nodes))

        super(BDMDualSet, self).__init__(nodes, ref_el, entity_ids)
Пример #21
0
    def to_riesz(self, poly_set):
        r"""Constructs an array representation of the functional so
        that the functional may be applied to a function expressed in
        in terms of the expansion set underlying  `poly_set` by means
        of contracting coefficients.

        That is, `poly_set` will have members all expressed in the
        form :math:`p = \sum_{i} \alpha^i \phi_i`
        where :math:`\{\phi_i\}_{i}` is some orthonormal expansion set
        and :math:`\alpha^i` are coefficients.  Note: the orthonormal
        expansion set is always scalar-valued but if the members of
        `poly_set` are vector or tensor valued the :math:`\alpha^i`
        will be scalars or vectors.

        This function constructs a tensor :math:`R` such that the
        contraction of :math:`R` with the array of coefficients
        :math:`\alpha` produces the effect of :math:`\ell(f)`

        In the case of scalar-value functions, :math:`R` is just a
        vector of the same length as the expansion set, and
        :math:`R_i = \ell(\phi_i)`.  For vector-valued spaces,
        :math:`R_{ij}` will be :math:`\ell(e^i \phi_j)` where
        :math:`e^i` is the canonical unit vector nonzero only in one
        entry :math:`i`.
        """
        es = poly_set.get_expansion_set()
        ed = poly_set.get_embedded_degree()
        nexp = es.get_num_members(ed)

        pt_dict = self.get_point_dict()

        pts = list(pt_dict.keys())
        npts = len(pts)

        bfs = es.tabulate(ed, pts)
        result = numpy.zeros(poly_set.coeffs.shape[1:], "d")

        # loop over points
        for j in range(npts):
            pt_cur = pts[j]
            wc_list = pt_dict[pt_cur]

            # loop over expansion functions
            for i in range(nexp):
                for (w, c) in wc_list:
                    result[c][i] += w * bfs[i, j]

        if self.deriv_dict:
            dpt_dict = self.deriv_dict

            # this makes things quicker since it uses dmats after
            # instantiation
            es_foo = polynomial_set.ONPolynomialSet(self.ref_el, ed)
            dpts = list(dpt_dict.keys())

            dbfs = es_foo.tabulate(dpts, self.max_deriv_order)

            ndpts = len(dpts)
            for j in range(ndpts):
                dpt_cur = dpts[j]
                wac_list = dpt_dict[dpt_cur]
                for i in range(nexp):
                    for (w, alpha, c) in wac_list:
                        result[c][i] += w * dbfs[tuple(alpha)][i, j]

        return result
Пример #22
0
    def __init__(self, ref_el, degree):
        sd = ref_el.get_spatial_dimension()
        if sd != 3:
            raise Exception("NedelecDual3D only works on tetrahedra")

        nodes = []

        t = ref_el.get_topology()

        # how many edges
        num_edges = len(t[1])

        for i in range(num_edges):
            # points to specify P_k on each edge
            pts_cur = ref_el.make_points(1, i, degree + 2)
            for j in range(len(pts_cur)):
                pt_cur = pts_cur[j]
                f = functional.PointEdgeTangentEvaluation(ref_el, i, pt_cur)
                nodes.append(f)

        if degree > 0:  # face tangents
            num_faces = len(t[2])
            for i in range(num_faces):  # loop over faces
                pts_cur = ref_el.make_points(2, i, degree + 2)
                for j in range(len(pts_cur)):  # loop over points
                    pt_cur = pts_cur[j]
                    for k in range(2):  # loop over tangents
                        f = functional.PointFaceTangentEvaluation(
                            ref_el, i, k, pt_cur)
                        nodes.append(f)

        if degree > 1:  # internal moments
            Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1))
            qpts = Q.get_points()
            Pkm2 = polynomial_set.ONPolynomialSet(ref_el, degree - 2)
            zero_index = tuple([0 for i in range(sd)])
            Pkm2_at_qpts = Pkm2.tabulate(qpts)[zero_index]

            for d in range(sd):
                for i in range(Pkm2_at_qpts.shape[0]):
                    phi_cur = Pkm2_at_qpts[i, :]
                    f = functional.IntegralMoment(ref_el, Q, phi_cur, (d, ))
                    nodes.append(f)

        entity_ids = {}
        # set to empty
        for i in range(sd + 1):
            entity_ids[i] = {}
            for j in range(len(t[i])):
                entity_ids[i][j] = []

        cur = 0

        # edge dof
        num_pts_per_edge = len(ref_el.make_points(1, 0, degree + 2))
        for i in range(len(t[1])):
            entity_ids[1][i] = list(range(cur, cur + num_pts_per_edge))
            cur += num_pts_per_edge

        # face dof
        if degree > 0:
            num_pts_per_face = len(ref_el.make_points(2, 0, degree + 2))
            for i in range(len(t[2])):
                entity_ids[2][i] = list(range(cur, cur + 2 * num_pts_per_face))
                cur += 2 * num_pts_per_face

        if degree > 1:
            num_internal_dof = Pkm2_at_qpts.shape[0] * sd
            entity_ids[3][0] = list(range(cur, cur + num_internal_dof))

        super(NedelecDual3D, self).__init__(nodes, ref_el, entity_ids)
Пример #23
0
 def __init__(self, ref_el):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, 2)
     dual = MorleyDualSet(ref_el)
     super(Morley, self).__init__(poly_set, dual, 2)
Пример #24
0
 def __init__(self, ref_el):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, 0)
     dual = P0Dual(ref_el)
     degree = 0
     formdegree = ref_el.get_spatial_dimension()  # n-form
     super(P0, self).__init__(poly_set, dual, degree, formdegree)
Пример #25
0
 def __init__(self, ref_el, degree):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
     dual = LagrangeDualSet(ref_el, degree)
     formdegree = 0  # 0-form
     super(Lagrange, self).__init__(poly_set, dual, degree, formdegree)
Пример #26
0
 def __init__(self, ref_el):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, 5)
     dual = BellDualSet(ref_el)
     super(Bell, self).__init__(poly_set, dual, 5)
Пример #27
0
def NedelecSpace2D(ref_el, k):
    """Constructs a basis for the 2d H(curl) space of the first kind
    which is (P_k)^2 + P_k rot( x )"""
    sd = ref_el.get_spatial_dimension()
    if sd != 2:
        raise Exception("NedelecSpace2D requires 2d reference element")

    vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd, ))

    dimPkp1 = expansions.polynomial_dimension(ref_el, k + 1)
    dimPk = expansions.polynomial_dimension(ref_el, k)
    dimPkm1 = expansions.polynomial_dimension(ref_el, k - 1)

    vec_Pk_indices = list(
        chain(*(range(i * dimPkp1, i * dimPkp1 + dimPk) for i in range(sd))))
    vec_Pk_from_Pkp1 = vec_Pkp1.take(vec_Pk_indices)

    Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1)
    PkH = Pkp1.take(list(range(dimPkm1, dimPk)))

    Q = quadrature.make_quadrature(ref_el, 2 * k + 2)

    Qpts = numpy.array(Q.get_points())
    Qwts = numpy.array(Q.get_weights())

    zero_index = tuple([0 for i in range(sd)])

    PkH_at_Qpts = PkH.tabulate(Qpts)[zero_index]
    Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[zero_index]

    PkH_crossx_coeffs = numpy.zeros(
        (PkH.get_num_members(), sd, Pkp1.get_num_members()), "d")

    def rot_x_foo(a):
        if a == 0:
            return 1, 1.0
        elif a == 1:
            return 0, -1.0

    for i in range(PkH.get_num_members()):
        for j in range(sd):
            (ind, sign) = rot_x_foo(j)
            for k in range(Pkp1.get_num_members()):
                PkH_crossx_coeffs[i, j, k] = sign * sum(
                    Qwts * PkH_at_Qpts[i, :] * Qpts[:, ind] *
                    Pkp1_at_Qpts[k, :])


#                for l in range( len( Qpts ) ):
#                    PkH_crossx_coeffs[i,j,k] += Qwts[ l ] \
#                                                * PkH_at_Qpts[i,l] \
#                                                * Qpts[l][ind] \
#                                                * Pkp1_at_Qpts[k,l] \
#                                                * sign

    PkHcrossx = polynomial_set.PolynomialSet(ref_el, k + 1, k + 1,
                                             vec_Pkp1.get_expansion_set(),
                                             PkH_crossx_coeffs,
                                             vec_Pkp1.get_dmats())

    return polynomial_set.polynomial_set_union_normalized(
        vec_Pk_from_Pkp1, PkHcrossx)
Пример #28
0
 def __init__(self, ref_el, degree):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
     dual = ArgyrisDualSet(ref_el, degree)
     super(Argyris, self).__init__(poly_set, dual, degree)
Пример #29
0
 def create_data():
     ps = polynomial_set.ONPolynomialSet(
         ref_el=reference_element.DefaultLine(), degree=3)
     return ps.dmats
Пример #30
0
 def __init__(self, ref_el, degree):
     poly_set = polynomial_set.ONPolynomialSet(ref_el, degree)
     dual = DiscontinuousTaylorDualSet(ref_el, degree)
     formdegree = ref_el.get_spatial_dimension()  # n-form
     super(HigherOrderDiscontinuousTaylor,
           self).__init__(poly_set, dual, degree, formdegree)