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 = 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 = ONPolynomialSet(ref_el, k + 1) PkH = Pkp1.take(list(range(dimPkm1, dimPk))) Q = quadrature.make_quadrature(ref_el, 2 * k + 2) Qpts = np.array(Q.get_points()) Qwts = np.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 = np.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 = PolynomialSet(ref_el, k + 1, k + 1, vec_Pkp1.get_expansion_set(), PkH_crossx_coeffs, vec_Pkp1.get_dmats()) return polynomial_set_union_normalized(vec_Pk_from_Pkp1, PkHcrossx)
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 = 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 = 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 = np.array(Q.get_points()) Qwts = np.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 = np.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, :] = np.dot(Pkp1_at_Qpts, fooij) PkHx = PolynomialSet(ref_el, deg, deg + 1, vec_Pkp1.get_expansion_set(), PkHx_coeffs, vec_Pkp1.get_dmats()) return polynomial_set_union_normalized(vec_Pk_from_Pkp1, PkHx)
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 = 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 = np.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 = np.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, :, :] = np.outer(tangent, tangent_polys.coeffs[i, :]) bubble_set = PolynomialSet(ref_el, order, order, vec_poly_set.get_expansion_set(), new_coeffs, vec_poly_set.get_dmats()) element_set = polynomial_set_union_normalized(bubble_set, vec_poly_set) return element_set
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 = 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 = ONPolynomialSet(ref_el, k + 1) Q = quadrature.make_quadrature(ref_el, 2 * (k + 1)) Qpts = np.array(Q.get_points()) Qwts = np.array(Q.get_weights()) zero_index = tuple([0 for i in range(sd)]) PkCrossXcoeffs = np.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, :] = np.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 = PolynomialSet(ref_el, k + 1, k + 1, vec_Pkp1.get_expansion_set(), PkCrossXcoeffs, vec_Pkp1.get_dmats()) return polynomial_set_union_normalized(vec_Pk, PkCrossX)