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)
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)