コード例 #1
0
ファイル: IPDGModel_poly.py プロジェクト: mfkiwl/fealpy
 def penalty_matrix(self):
     p = self.p
     mesh = self.mesh
     space = self.space
     edge2cell = mesh.ds.edge_to_cell()
     isBdEdge = (edge2cell[:, 0] == edge2cell[:, 1])
     qf = GaussLegendreQuadrature(p + 4)
     bcs, ws = qf.quadpts, qf.weights
     ps = mesh.edge_bc_to_point(bcs)
     
     phi0 = space.basis(ps, index=edge2cell[:, 0]) # (NQ, NE, ldof)
     phi1 = space.basis(ps, index=edge2cell[:, 1]) # (NQ, NE, ldof)
     phi1[:,isBdEdge] = 0*phi1[:,isBdEdge]
     jump = np.append(phi0,-phi1,axis = 2)
     P = np.einsum('i, ijk, ijm->jkm', ws, jump, jump, optimize=True)
     ldof = space.number_of_local_dofs(p=p, doftype='cell')
     cell2dof = space.cell_to_dof()
     dof1  = cell2dof[edge2cell[:,0]]
     dof2  = cell2dof[edge2cell[:,1]]
     dof = np.append(dof1,dof2,axis = 1)
     I = np.einsum('k, ij->ijk', np.ones(2*ldof), dof)
     J = I.swapaxes(-1, -2)
     gdof = space.number_of_global_dofs(p=p)
     # Construct the flux matrix
     P = csr_matrix((P.flat, (I.flat, J.flat)), shape=(gdof, gdof))
     return P
コード例 #2
0
    def edge_cell_mass_matrix(self, p=None):
        p = self.p if p is None else p
        mesh = self.mesh
        mtype = mesh.meshtype
        if mtype == 'tri':
            edge = mesh.entity('edge')
            edge2cell = mesh.ds.edge_to_cell()
            measure = mesh.entity_measure('edge')
            qf = GaussLegendreQuadrature(p + 3)
            bcs, ws = qf.quadpts, qf.weights
            ps = self.mesh.edge_bc_to_point(bcs)
            phi0 = self.edge_basis(ps, p=p - 1)
            phi1 = self.basis(ps, index=edge2cell[:, 0], p=p)
            phi2 = self.basis(ps, index=edge2cell[:, 1], p=p)

            LM = np.einsum('i, ijk, ijm, j->jkm',
                           ws,
                           phi0,
                           phi1,
                           measure,
                           optimize=True)
            RM = np.einsum('i, ijk, ijm, j->jkm',
                           ws,
                           phi0,
                           phi2,
                           measure,
                           optimize=True)
            return LM, RM
        else:
            print("Here has not been implement!")
コード例 #3
0
 def edge_mass_matrix_1(self, p=None):
     p = self.p if p is None else p
     mesh = self.mesh
     edge = mesh.entity('edge')
     measure = mesh.entity_measure('edge')
     qf = GaussLegendreQuadrature(p + 3)
     bcs, ws = qf.quadpts, qf.weights
     ps = self.mesh.edge_bc_to_point(bcs)
     phi = self.edge_basis(ps, p=p)
     H = np.einsum('i, ijk, ijm, j->jkm',
                   ws,
                   phi,
                   phi,
                   measure,
                   optimize=True)
     return H
コード例 #4
0
    def matrix_H(self, p=None):
        p = self.p if p is None else p
        mesh = self.mesh
        node = mesh.entity('node')

        edge = mesh.entity('edge')
        edge2cell = mesh.ds.edge_to_cell()

        isInEdge = (edge2cell[:, 0] != edge2cell[:, 1])

        NC = mesh.number_of_cells()

        qf = GaussLegendreQuadrature(p + 1)
        bcs, ws = qf.quadpts, qf.weights
        ps = np.einsum('ij, kjm->ikm', bcs, node[edge])
        phi0 = self.basis(ps, index=edge2cell[:, 0], p=p)
        phi1 = self.basis(ps[:, isInEdge, :],
                          index=edge2cell[isInEdge, 1],
                          p=p)
        H0 = np.einsum('i, ijk, ijm->jkm', ws, phi0, phi0)
        H1 = np.einsum('i, ijk, ijm->jkm', ws, phi1, phi1)

        nm = mesh.edge_normal()
        b = node[edge[:, 0]] - self.cellbarycenter[edge2cell[:, 0]]
        H0 = np.einsum('ij, ij, ikm->ikm', b, nm, H0)
        b = node[edge[isInEdge, 0]] - self.cellbarycenter[edge2cell[isInEdge,
                                                                    1]]
        H1 = np.einsum('ij, ij, ikm->ikm', b, -nm[isInEdge], H1)

        ldof = self.number_of_local_dofs(p=p)
        H = np.zeros((NC, ldof, ldof), dtype=np.float)
        np.add.at(H, edge2cell[:, 0], H0)
        np.add.at(H, edge2cell[isInEdge, 1], H1)

        multiIndex = self.dof.multi_index_matrix(p=p)
        q = np.sum(multiIndex, axis=1)
        H /= q + q.reshape(-1, 1) + 2
        return H
コード例 #5
0
ファイル: IPDGModel_poly.py プロジェクト: mfkiwl/fealpy
 def flux_matrix(self):
     p =self.p
     mesh = self.mesh
     space = self.space
     edge2cell = mesh.ds.edge_to_cell()
     isBdEdge = (edge2cell[:, 0] == edge2cell[:, 1])
     qf = GaussLegendreQuadrature(p + 4)
     bcs, ws = qf.quadpts, qf.weights
     ps = mesh.edge_bc_to_point(bcs)
     eh = mesh.entity_measure('edge')
     
     phi0 = space.basis(ps, index=edge2cell[:, 0]) # (NQ, NE, ldof)
     phi1 = space.basis(ps, index=edge2cell[:, 1]) # (NQ, NE, ldof)
     phi1[:,isBdEdge] = 0*phi1[:,isBdEdge]
     jump = np.append(phi0,-phi1,axis = 2)
     
     gphi0 = space.grad_basis(ps, edge2cell[:, 0])
     gphi1 = space.grad_basis(ps,edge2cell[:, 1])
     gphi0[:,isBdEdge] = 2*gphi0[:,isBdEdge]
     gphi1[:,isBdEdge] = 0*gphi1[:,isBdEdge]
     gphi = np.append(gphi0,gphi1,axis = 2)
     n = mesh.edge_unit_normal()
     S = 1/2*np.einsum('i, ijk, ijmp, jp, j->jkm', ws, jump, gphi, n, eh)
     
     ldof = space.number_of_local_dofs(p=p, doftype='cell')
     cell2dof = space.cell_to_dof()
     dof1  = cell2dof[edge2cell[:,0]]
     dof2  = cell2dof[edge2cell[:,1]]
     dof = np.append(dof1,dof2,axis = 1)
     I = np.einsum('k, ij->ijk', np.ones(2*ldof), dof)
     J = I.swapaxes(-1, -2)
     gdof = space.number_of_global_dofs(p=p)
     # Construct the flux matrix
     S = csr_matrix((S.flat, (I.flat, J.flat)), shape=(gdof, gdof))
     #print(S.toarray())
     return S
コード例 #6
0
    def DirichletEdge_vector(self, uD, isDirEdge):
        smspace = self.smspace
        p = self.p
        mesh = self.mesh
        node = mesh.entity('node')

        edge = mesh.entity('edge')
        edge2cell = mesh.ds.edge_to_cell()
        edgeArea = mesh.edge_length()
        nm = mesh.edge_normal()
        # # (NE,2). The length of the normal-vector isn't 1, is the length of corresponding edge.

        # isDirEdge = (edge2cell[:, 0] == edge2cell[:, 1])  # the bool vars, to get the boundary edges

        qf = GaussLegendreQuadrature(p +
                                     1)  # the integral points on edges (1D)
        bcs, ws = qf.quadpts, qf.weights  # bcs.shape: (NQ,2); ws.shape: (NQ,)
        ps = np.einsum(
            'ij, kjm->ikm', bcs,
            node[edge])  # ps.shape: (NQ,NE,2), NE is the number of edges

        phi0 = smspace.basis(ps[:, isDirEdge, :],
                             index=edge2cell[isDirEdge, 0])
        # # phi0.shape: (NQ,NDirE,ldof), NDirE is the number of Dirichlet edges, lodf is the number of local DOFs
        # # phi0 is the value of the cell basis functions on the one-side of the corresponding edges.

        gphi0 = smspace.grad_basis(ps[:, isDirEdge, :],
                                   index=edge2cell[isDirEdge, 0])
        # # gphi0.shape: (NQ,NDirE,ldof,2), NDirE is the number of Dirichlet edges, lodf is the number of local DOFs
        # # gphi0 is the grad-value of the cell basis functions on the one-side of the corresponding edges.

        uDh = uD(ps[:, isDirEdge, :])
        # # (NQ,NE), get the Dirichlet values at physical integral points

        # --- get the jump-average, jump-jump vector at the Dirichlet bds --- #
        penalty = 1.0 / (edgeArea[isDirEdge])
        JADir_temp = np.einsum('i, ij, ijpm, jm->jp',
                               ws,
                               uDh,
                               gphi0,
                               nm[isDirEdge],
                               optimize=True)  # (NDirE,ldof)
        JJDir_temp = np.einsum('i, ij, ijp, j, j->jp',
                               ws,
                               uDh,
                               phi0,
                               edgeArea[isDirEdge],
                               penalty,
                               optimize=True)  # (NDirE,ldof)

        # --- construct the final vector --- #
        NC = mesh.number_of_cells()
        ldof = smspace.number_of_local_dofs()
        shape = (NC, ldof)  # shape.shape: (NC,ldof)
        JADir = np.zeros(shape, dtype=np.float)
        JJDir = np.zeros(shape, dtype=np.float)

        np.add.at(JADir, edge2cell[isDirEdge, 0], JADir_temp)
        np.add.at(JJDir, edge2cell[isDirEdge, 0], JJDir_temp)

        gdof = smspace.number_of_global_dofs()

        return JADir.reshape(gdof, ), JJDir.reshape(gdof, )
コード例 #7
0
    def stiff_matrix(self):
        """
        Get the stiff matrix on ScaledMonomialSpace2d.

        -------
        The mass matrix on ScaledMonomialSpace2d can be found in class ScaledMonomialSpace2d(): mass_matrix()

        """

        smspace = self.smspace
        p = self.p
        assert p >= 1, 'the polynomial-order should have p >= 1 '

        mesh = self.mesh
        node = mesh.entity('node')

        NC = mesh.number_of_cells()
        edge = mesh.entity('edge')
        edge2cell = mesh.ds.edge_to_cell()
        nm = mesh.edge_normal()
        # # (NE,2). The length of the normal-vector isn't 1, is the length of corresponding edge.

        isInEdge = (edge2cell[:, 0] != edge2cell[:, 1]
                    )  # the bool vars, to get the inner edges

        qf = GaussLegendreQuadrature(p +
                                     1)  # the integral points on edges (1D)
        bcs, ws = qf.quadpts, qf.weights  # bcs.shape: (NQ,2); ws.shape: (NQ,)
        ps = np.einsum(
            'ij, kjm->ikm', bcs,
            node[edge])  # ps.shape: (NQ,NE,2), NE is the number of edges

        gphi0 = smspace.grad_basis(ps, index=edge2cell[:, 0])
        # # gphi0.shape: (NQ,NInE,ldof,2), NInE is the number of interior edges, lodf is the number of local DOFs
        # # gphi0 is the grad-value of the cell basis functions on the one-side of the corresponding edges.
        gphi1 = smspace.grad_basis(ps[:, isInEdge, :],
                                   index=edge2cell[isInEdge, 1])

        # # using the divergence-theorem to get the
        S0 = np.einsum('i, ijkm, ijpm->jpk', ws, gphi0,
                       gphi0)  # (NE,ldof,ldof)
        b = node[edge[:, 0]] - smspace.cellbarycenter[edge2cell[:,
                                                                0]]  # (NE,2)
        S0 = np.einsum('ij, ij, ikm->ikm', b, nm, S0)  # (NE,ldof,ldof)

        S1 = np.einsum('i, ijkm, ijpm->jpk', ws, gphi1,
                       gphi1)  # (NInE,ldof,ldof)
        b = node[edge[isInEdge,
                      0]] - smspace.cellbarycenter[edge2cell[isInEdge,
                                                             1]]  # (NInE,2)
        S1 = np.einsum('ij, ij, ikm->ikm', b, -nm[isInEdge],
                       S1)  # (NInE,ldof,ldof)

        ldof = smspace.number_of_local_dofs()
        S = np.zeros((NC, ldof, ldof), dtype=np.float)
        np.add.at(S, edge2cell[:, 0], S0)
        np.add.at(S, edge2cell[isInEdge, 1], S1)

        multiIndex = smspace.dof.multiIndex
        q = np.sum(
            multiIndex, axis=1
        ) - 1  # here, we used the grad-basis to get stiff-matrix, so we need to -1
        qq = q + q.reshape(-1, 1) + 2
        qq[0, 0] = 1
        # # note that this is the special case, since we want to compute the \int_T \nabla u\cdot \nabla v,
        # # this needs to minus 1 in the 'q', so qq[0,0] is 0, moreover, S[:, 0, :] == S[:, :, 0] is 0-values,
        # # so we set qq[0, 0] = 1 which doesn't affect the result of S /= qq.

        S /= qq

        # --- get row and col --- #
        row, col = self.global_dof_location(np.arange(NC), np.arange(NC))

        gdof = smspace.number_of_global_dofs()
        S = csr_matrix((S.flat, (row.flat, col.flat)), shape=(gdof, gdof))

        return S
コード例 #8
0
    def DirichletEdge_matrix(self, isDirEdge):
        """
        Get the average-jump, jump-average and jump-jump matrix at Dirichlet edges.

        -------
        The explanations see interiorEdge_matrix().

        """

        smspace = self.smspace
        p = self.p
        mesh = self.mesh
        node = mesh.entity('node')

        edge = mesh.entity('edge')
        edge2cell = mesh.ds.edge_to_cell()
        edgeArea = mesh.edge_length()
        nm = mesh.edge_normal()
        # # (NE,2). The length of the normal-vector isn't 1, is the length of corresponding edge.

        # isDirEdge = (edge2cell[:, 0] == edge2cell[:, 1])  # the bool vars, to get the boundary edges

        qf = GaussLegendreQuadrature(p +
                                     1)  # the integral points on edges (1D)
        bcs, ws = qf.quadpts, qf.weights  # bcs.shape: (NQ,2); ws.shape: (NQ,)
        ps = np.einsum(
            'ij, kjm->ikm', bcs,
            node[edge])  # ps.shape: (NQ,NE,2), NE is the number of edges

        phi0 = smspace.basis(ps[:, isDirEdge, :],
                             index=edge2cell[isDirEdge, 0])
        # # phi0.shape: (NQ,NDirE,ldof), NDirE is the number of Dirichlet edges, lodf is the number of local DOFs
        # # phi0 is the value of the cell basis functions on the one-side of the corresponding edges.

        gphi0 = smspace.grad_basis(ps[:, isDirEdge, :],
                                   index=edge2cell[isDirEdge, 0])
        # # gphi0.shape: (NQ,NDirE,ldof,2), NDirE is the number of Dirichlet edges, lodf is the number of local DOFs
        # # gphi0 is the grad-value of the cell basis functions on the one-side of the corresponding edges.

        # --- get the average-jump matrix --- #
        AJmm = np.einsum('i, ijkm, ijp, jm->jpk',
                         ws,
                         gphi0,
                         phi0,
                         nm[isDirEdge],
                         optimize=True)  # (NDirE,ldof,ldof)

        # --- get the jump-average matrix --- #
        JAmm = np.einsum('i, ijk, ijpm, jm->jpk',
                         ws,
                         phi0,
                         gphi0,
                         nm[isDirEdge],
                         optimize=True)  # (NDirE,ldof,ldof)

        # --- get the jump-jump matrix --- #
        penalty = 1.0 / (edgeArea[isDirEdge])
        JJmm = np.einsum('i, ijk, ijm, j, j->jmk', ws, phi0, phi0,
                         edgeArea[isDirEdge],
                         penalty)  # Jmm.shape: (NDirE,ldof,ldof)

        # --- get the global dofs location --- #
        rowmm, colmm = self.global_dof_location(edge2cell[isDirEdge, 0],
                                                edge2cell[isDirEdge, 0])

        # --- construct the global matrix --- #
        gdof = smspace.number_of_global_dofs()
        AJmm = csr_matrix((AJmm.flat, (rowmm.flat, colmm.flat)),
                          shape=(gdof, gdof))
        JAmm = csr_matrix((JAmm.flat, (rowmm.flat, colmm.flat)),
                          shape=(gdof, gdof))
        JJmm = csr_matrix((JJmm.flat, (rowmm.flat, colmm.flat)),
                          shape=(gdof, gdof))

        return AJmm, JAmm, JJmm
コード例 #9
0
    def interiorEdge_matrix(self):
        """
        Get the average-jump, jump-average and jump-jump matrix at interior edges.


        -------
        In the following, the subscript 'm'(-) stands for the smaller-index of the cell,
        and the subscript 'p'(+) stands for the bigger-index of the cell.

        What's more, let v, w be the trial and test function, respectively.

        Define
        (1) {{\nabla w}} := 1/2*(\nabla w^+ + \nabla w^-),
        (2) [[w]] := (w^- - w^+).
        (3) E_h: all the interior edges.
        (4) n_e: the unit-normal-vector of edge 'e'.
            In FEALPy, n_e is given by nm=mesh.edge_normal() (NE,2).
            Note that, the length of the normal-vector 'nm' isn't 1, is the length of corresponding edge.
            And the The direction of normal vector is from edge2cell[i,0] to edge2cell[i,1]
            (that is, from the cell with smaller-index to the cell with larger-index).


        -------
        The matrix
        AJ-matrix: \int_{E_h} {{\nabla v}}\cdot n_e [[w]],

        JA-matrix: \int_{E_h} [[v]]{{\nabla w}}\cdot n_e,

        JJ-matrix: \int_{E_h} [[v]][[w]].


        -------
        The DG scheme can be found in
        (Béatrice Rivière, Page:29) Discontinuous Galerkin Methods for Solving Elliptic and Parabolic Equations

        """

        smspace = self.smspace
        p = self.p
        mesh = self.mesh
        node = mesh.entity('node')

        edge = mesh.entity('edge')
        edge2cell = mesh.ds.edge_to_cell()
        edgeArea = mesh.edge_length()
        nm = mesh.edge_normal()
        # # (NE,2). The length of the normal-vector isn't 1, is the length of corresponding edge.

        isInEdge = (edge2cell[:, 0] != edge2cell[:, 1]
                    )  # the bool vars, to get the inner edges

        qf = GaussLegendreQuadrature(p +
                                     1)  # the integral points on edges (1D)
        bcs, ws = qf.quadpts, qf.weights  # bcs.shape: (NQ,2); ws.shape: (NQ,)
        ps = np.einsum(
            'ij, kjm->ikm', bcs,
            node[edge])  # ps.shape: (NQ,NE,2), NE is the number of edges

        phi0 = smspace.basis(ps[:, isInEdge, :], index=edge2cell[isInEdge, 0])
        # # phi0.shape: (NQ,NInE,ldof), NInE is the number of interior edges, lodf is the number of local DOFs
        # # phi0 is the value of the cell basis functions on the one-side of the corresponding edges.
        phi1 = smspace.basis(ps[:, isInEdge, :], index=edge2cell[isInEdge, 1])
        # # phi1 is the value of the cell basis functions on the other-side of the corresponding edges.

        gphi0 = smspace.grad_basis(ps[:, isInEdge, :],
                                   index=edge2cell[isInEdge, 0])
        # # gphi0.shape: (NQ,NInE,ldof,2), NInE is the number of interior edges, lodf is the number of local DOFs
        # # gphi0 is the grad-value of the cell basis functions on the one-side of the corresponding edges.
        gphi1 = smspace.grad_basis(ps[:, isInEdge, :],
                                   index=edge2cell[isInEdge, 1])

        # --- get the average-jump matrix --- #
        AJmm = np.einsum('i, ijkm, ijp, jm->jpk',
                         ws,
                         gphi0,
                         phi0,
                         nm[isInEdge],
                         optimize=True)  # (NInE,ldof,ldof)
        AJmp = np.einsum('i, ijkm, ijp, jm->jpk',
                         ws,
                         gphi0,
                         phi1,
                         nm[isInEdge],
                         optimize=True)
        AJpm = np.einsum('i, ijkm, ijp, jm->jpk',
                         ws,
                         gphi1,
                         phi0,
                         nm[isInEdge],
                         optimize=True)
        AJpp = np.einsum('i, ijkm, ijp, jm->jpk',
                         ws,
                         gphi1,
                         phi1,
                         nm[isInEdge],
                         optimize=True)
        AJ_matrix = 0.5 * np.array([AJmm, -AJmp, AJpm, -AJpp
                                    ])  # AJ_matrix.shape: (4,NInE,ldof,lodf)

        # --- get the jump-average matrix --- #
        JAmm = np.einsum('i, ijk, ijpm, jm->jpk',
                         ws,
                         phi0,
                         gphi0,
                         nm[isInEdge],
                         optimize=True)  # (NInE,ldof,ldof)
        JAmp = np.einsum('i, ijk, ijpm, jm->jpk',
                         ws,
                         phi0,
                         gphi1,
                         nm[isInEdge],
                         optimize=True)
        JApm = np.einsum('i, ijk, ijpm, jm->jpk',
                         ws,
                         phi1,
                         gphi0,
                         nm[isInEdge],
                         optimize=True)
        JApp = np.einsum('i, ijk, ijpm, jm->jpk',
                         ws,
                         phi1,
                         gphi1,
                         nm[isInEdge],
                         optimize=True)
        JA_matrix = 0.5 * np.array([JAmm, JAmp, -JApm, -JApp
                                    ])  # JA_matrix.shape: (4,NInE,ldof,lodf)

        # --- get the jump-jump matrix --- #
        penalty = 1.0 / (edgeArea[isInEdge])
        JJmm = np.einsum('i, ijk, ijm, j, j->jmk', ws, phi0, phi0,
                         edgeArea[isInEdge],
                         penalty)  # Jmm.shape: (NInE,ldof,ldof)
        JJmp = np.einsum('i, ijk, ijm, j, j->jmk', ws, phi0, phi1,
                         edgeArea[isInEdge],
                         penalty)  # Jmp.shape: (NInE,ldof,ldof)
        JJpm = np.einsum('i, ijk, ijm, j, j->jmk', ws, phi1, phi0,
                         edgeArea[isInEdge],
                         penalty)  # Jpm.shape: (NInE,ldof,ldof)
        JJpp = np.einsum('i, ijk, ijm, j, j->jmk', ws, phi1, phi1,
                         edgeArea[isInEdge],
                         penalty)  # Jpp.shape: (NInE,ldof,ldof)
        JJ_matrix = np.array([JJmm, -JJmp, -JJpm,
                              JJpp])  # JJ_matrix.shape: (4,NInE,ldof,lodf)

        # --- get the global dofs location --- #
        rowmm, colmm = self.global_dof_location(edge2cell[isInEdge, 0],
                                                edge2cell[isInEdge, 0])
        rowmp, colmp = self.global_dof_location(edge2cell[isInEdge, 0],
                                                edge2cell[isInEdge, 1])
        rowpm, colpm = self.global_dof_location(edge2cell[isInEdge, 1],
                                                edge2cell[isInEdge, 0])
        rowpp, colpp = self.global_dof_location(edge2cell[isInEdge, 1],
                                                edge2cell[isInEdge, 1])
        row = np.array([rowmm, rowmp, rowpm, rowpp])
        col = np.array([colmm, colmp, colpm, colpp])

        # --- construct the global matrix --- #
        gdof = smspace.number_of_global_dofs()
        AJ_matrix = csr_matrix((AJ_matrix.flat, (row.flat, col.flat)),
                               shape=(gdof, gdof))
        JA_matrix = csr_matrix((JA_matrix.flat, (row.flat, col.flat)),
                               shape=(gdof, gdof))
        JJ_matrix = csr_matrix((JJ_matrix.flat, (row.flat, col.flat)),
                               shape=(gdof, gdof))

        return AJ_matrix, JA_matrix, JJ_matrix
コード例 #10
0
# R0 = np.zeros((smldof, len(cell2dof)), dtype=np.float)
# R1 = np.zeros((smldof, len(cell2dof)), dtype=np.float)
#
# edge2cell = pmesh.ds.edge2cell
# idx = cell2dofLocation[edge2cell[:, [0]]] + edge2cell[:, [2]] * (p + 1) + np.arange(p + 1)

# --- test begin --- #
node = pmesh.entity('node')
edge = pmesh.entity('edge')
edge2cell = pmesh.ds.edge_to_cell()
isInEdge = (edge2cell[:, 0] != edge2cell[:, 1])

h = integralalg.edgemeasure
n = pmesh.edge_unit_normal()

qf = GaussLegendreQuadrature(p + 3)
bcs, ws = qf.quadpts, qf.weights
ps = np.einsum('ij, kjm->ikm', bcs, node[edge])
phi0 = smspace.basis(ps, index=edge2cell[:, 0])  # (NQ,NE,smldof)
phi1 = smspace.basis(ps[:, isInEdge, :],
                     index=edge2cell[isInEdge, 1])  # (NQ,NInE,smldof)
phi = smspace.edge_basis(ps)  # (NQ,NE,ldof1d)

F0 = np.einsum('i, ijm, ijn, j->mjn', ws, phi0, phi, h)  # (smldof,NE,ldof1d)
F1 = np.einsum('i, ijm, ijn, j->mjn', ws, phi1, phi[:, isInEdge, :],
               h[isInEdge])

smldof = smspace.number_of_local_dofs()
cell2dof, cell2dofLocation = wgdof.cell2dof, wgdof.cell2dofLocation
R0 = np.zeros((smldof, len(cell2dof)), dtype=np.float)
# # R0.shape: (smldof,NC*CNldof), CNldof is the number of all dofs in one cell