def __init__(self, ref_el, degree): nodes = [] dim = ref_el.get_spatial_dimension() Q = quadrature.make_quadrature(ref_el, 2 * (degree + 1)) f_at_qpts = numpy.ones(len(Q.wts)) nodes.append(functional.IntegralMoment(ref_el, Q, f_at_qpts)) vertices = ref_el.get_vertices() midpoint = tuple(sum(numpy.array(vertices)) / len(vertices)) for k in range(1, degree + 1): # Loop over all multi-indices of degree k. for alpha in mis(dim, k): nodes.append( functional.PointDerivative(ref_el, midpoint, alpha)) entity_ids = { d: {e: [] for e in ref_el.sub_entities[d]} for d in range(dim + 1) } entity_ids[dim][0] = list(range(len(nodes))) super(DiscontinuousTaylorDualSet, self).__init__(nodes, ref_el, entity_ids)
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)
def __init__(self, ref_el, degree, order=1): bc_nodes = [] for x in ref_el.get_vertices(): bc_nodes.append([functional.PointEvaluation(ref_el, x), *[functional.PointDerivative(ref_el, x, [alpha]) for alpha in range(1, order)]]) bc_nodes[1].reverse() k = len(bc_nodes[0]) idof = slice(k, -k) bdof = list(range(-k, k)) bdof = bdof[k:] + bdof[:k] # Define the generalized eigenproblem on a GLL element gll = GaussLobattoLegendre(ref_el, degree) xhat = numpy.array([list(x.get_point_dict().keys())[0][0] for x in gll.dual_basis()]) # Tabulate the BC nodes constraints = gll.tabulate(order-1, ref_el.get_vertices()) C = numpy.column_stack(list(constraints.values())) perm = list(range(len(bdof))) perm = perm[::2] + perm[-1::-2] C = C[:, perm].T # Tabulate the basis that splits the DOFs into interior and bcs E = numpy.eye(gll.space_dimension()) E[bdof, idof] = -C[:, idof] E[bdof, :] = numpy.dot(numpy.linalg.inv(C[:, bdof]), E[bdof, :]) # Assemble the constrained Galerkin matrices on the reference cell rule = quadrature.GaussLegendreQuadratureLineRule(ref_el, degree+1) phi = gll.tabulate(order, rule.get_points()) E0 = numpy.dot(phi[(0, )].T, E) Ek = numpy.dot(phi[(order, )].T, E) B = numpy.dot(numpy.multiply(E0.T, rule.get_weights()), E0) A = numpy.dot(numpy.multiply(Ek.T, rule.get_weights()), Ek) # Eigenfunctions in the constrained basis S = numpy.eye(A.shape[0]) if S.shape[0] > len(bdof): _, Sii = sym_eig(A[idof, idof], B[idof, idof]) S[idof, idof] = Sii S[idof, bdof] = numpy.dot(Sii, numpy.dot(Sii.T, -B[idof, bdof])) # Eigenfunctions in the Lagrange basis S = numpy.dot(E, S) self.gll_points = xhat self.gll_tabulation = S.T # Interpolate eigenfunctions onto the quadrature points basis = numpy.dot(S.T, phi[(0, )]) nodes = bc_nodes[0] + [functional.IntegralMoment(ref_el, rule, f) for f in basis[idof]] + bc_nodes[1] entity_ids = {0: {0: [0], 1: [degree]}, 1: {0: list(range(1, degree))}} entity_permutations = {} entity_permutations[0] = {0: {0: [0]}, 1: {0: [0]}} entity_permutations[1] = {0: make_entity_permutations(1, degree - 1)} super(FDMDual, self).__init__(nodes, ref_el, entity_ids, entity_permutations)
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)
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)
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)
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)