コード例 #1
0
    def alg_3_3(self, maxit=None):
        """
        1. 最粗网格上求解最小特征特征值问题,得到最小特征值 d_H 和特征向量 u_H
        2. 自适应求解  - \Delta u_h = u_H
            *  u_H 插值到下一层网格上做为新 u_H
        3. 在最细网格上求解一次最小特征值问题

        自适应 maxit, picard:2
        """
        print("算法 3.3")

        if maxit is None:
            maxit = self.maxit

        start = timer()

        if self.step == 0:
            idx = []
        else:
            idx = list(range(0, self.maxit, self.step))

        mesh = self.pde.init_mesh(n=self.numrefine)
        # 1. 粗网格上求解最小特征值问题
        space = LagrangeFiniteElementSpace(mesh, 1)
        AH = self.get_stiff_matrix(space)
        MH = self.get_mass_matrix(space)
        isFreeHDof = ~(space.boundary_dof())

        gdof = space.number_of_global_dofs()
        uH = np.zeros(gdof, dtype=mesh.ftype)
        print("initial mesh :", gdof)

        A = AH[isFreeHDof, :][:, isFreeHDof].tocsr()
        M = MH[isFreeHDof, :][:, isFreeHDof].tocsr()
        if self.matlab is False:
            uH[isFreeHDof], d = self.eig(A, M)
        else:
            uH[isFreeHDof], d = self.meigs(A, M)

        uh = space.function()
        uh[:] = uH

        GD = mesh.geo_dimension()
        if (self.step > 0) and (0 in idx):
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_3_0_' + str(NN) + '.pdf')
            plt.close()
            self.savemesh(mesh,
                          self.resultdir + 'mesh_3_3_0_' + str(NN) + '.mat')

        # 2. 以 u_H 为右端项自适应求解 -\Deta u = u_H
        I = eye(gdof)
        final = 0
        for i in range(maxit - 1):
            eta = self.residual_estimate(uh)
            markedCell = mark(eta, self.theta)
            IM = mesh.bisect(markedCell, returnim=True)
            NN = mesh.number_of_nodes()
            print(i + 1, "refine : ", NN)
            if (self.step > 0) and (i in idx):
                NN = mesh.number_of_nodes()
                fig = plt.figure()
                fig.set_facecolor('white')
                if GD == 2:
                    axes = fig.gca()
                else:
                    axes = Axes3D(fig)
                mesh.add_plot(axes, cellcolor='w')
                fig.savefig(self.resultdir + 'mesh_3_3_' + str(i + 1) + '_' +
                            str(NN) + '.pdf')
                plt.close()
                self.savemesh(
                    mesh, self.resultdir + 'mesh_3_3_' + str(i + 1) + '_' +
                    str(NN) + '.mat')
            final = i + 1
            if NN > self.maxdof:
                break

            I = IM @ I
            uH = IM @ uH

            space = LagrangeFiniteElementSpace(mesh, 1)
            gdof = space.number_of_global_dofs()

            A = self.get_stiff_matrix(space)
            M = self.get_mass_matrix(space)
            isFreeDof = ~(space.boundary_dof())
            b = M @ uH

            uh = space.function()
            if self.matlab is False:
                uh[isFreeDof] = self.psolve(
                    A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof],
                    M[isFreeDof, :][:, isFreeDof].tocsr())
            else:
                uh[isFreeDof] = self.msolve(
                    A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof])

        # 3. 在最细网格上求解一次最小特征值问题

        if self.step > 0:
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_3_' + str(final) + '_' +
                        str(NN) + '.pdf')
            plt.close()
            self.savemesh(
                mesh, self.resultdir + 'mesh_3_3_' + str(final) + '_' +
                str(NN) + '.mat')

        space = LagrangeFiniteElementSpace(mesh, 1)
        gdof = space.number_of_global_dofs()
        A = self.get_stiff_matrix(space)
        M = self.get_mass_matrix(space)
        isFreeDof = ~(space.boundary_dof())
        uh = space.function(array=uh)
        A = A[isFreeDof, :][:, isFreeDof].tocsr()
        M = M[isFreeDof, :][:, isFreeDof].tocsr()
        uh = space.function()

        if self.multieigs is True:
            self.A = A
            self.M = M
            self.ml = pyamg.ruge_stuben_solver(self.A)
            self.eigs()
        else:
            if self.matlab is False:
                uh[isFreeDof], d = self.eig(A, M)
            else:
                uh[isFreeDof], d = self.meigs(A, M)
            print("smallest eigns:", d)
            return uh
        end = timer()
        print("with time: ", end - start)
コード例 #2
0
        grad = self.gradient(p)#(NQ,NE,2)
        val = np.sum(grad*n, axis=-1)
        shape = len(val.shape)*(1, )
        kappa = np.array([1,0], dtype=np.float64).reshape(shape)
        val += self.solution(p)
        return val, kappa



pde = MyPde()

# print(pde.solution.coordtype)
mf = MeshFactory()
box = [0,1,0,1]
mesh = mf.boxmesh2d(box, nx=40, ny=40, meshtype='tri')
space = LagrangeFiniteElementSpace(mesh,p=1)
#space提供一个插值函数  uI
uI = space.interpolation(pde.solution)#空间中的有限元函数,也是一个数组
# print('uI[0:10]:',uI[0:10])#打印前面10个自由度的值
bc = np.array([1/3,1/3,1/3],dtype=mesh.ftype)
val = uI(bc)#(1, NC)有限元函数在每个单元的重心处的函数值
# print('val[0:10]:',val[1:10])

val0 = uI(bc)#(NC,)
val1 = uI.grad_value(bc)#(NC,2)
# print('val0[0:10]:',val0[1:10])
# print('val1[0:10]:',val1[1:10])

#插值误差
error0 = space.integralalg.L2_error(pde.solution, uI)
error1 = space.integralalg.L2_error(pde.gradient, uI.grad_value)
コード例 #3
0
p = 1  # Lagrange 有限元多项式次数
n = 2  # 初始网格剖分段数
maxit = 3  # 网格加密最大次数

pde = CDRMODEL()
domain = pde.domain()

mf = MeshFactory()
mesh = mf.boxmesh2d(domain, nx=n, ny=n, meshtype='tri')

NDof = np.zeros(maxit, dtype=mesh.itype)
errorMatrix = np.zeros((2, maxit), dtype=mesh.ftype)
errorType = ['$|| u  - u_h ||_0$', '$|| \\nabla u - \\nabla u_h||_0$']
for i in range(maxit):
    print('Step:', i)
    space = LagrangeFiniteElementSpace(mesh, p=p)
    NDof[i] = space.number_of_global_dofs()
    uh = space.function()  # 返回一个有限元函数,初始自由度值全为 0
    A = space.stiff_matrix(c=pde.diffusion_coefficient)
    B = space.convection_matrix(c=pde.convection_coefficient)
    M = space.mass_matrix(c=pde.reaction_coefficient)
    F = space.source_vector(pde.source)
    A += B
    A += M

    bc = DirichletBC(space, pde.dirichlet)
    A, F = bc.apply(A, F, uh)

    uh[:] = spsolve(A, F)

    errorMatrix[0, i] = space.integralalg.error(pde.solution,
コード例 #4
0
    def test_interpolation_plane(self):
        def u(p):
            x = p[..., 0]
            y = p[..., 1]
            return x * y

        node = np.array([(0, 0), (1, 0), (1, 1), (0, 1)], dtype=np.float)
        cell = np.array([(1, 2, 0), (3, 0, 2)], dtype=np.int)
        mesh = TriangleMesh(node, cell)

        node = mesh.entity('node')
        cell = mesh.entity('cell')
        tritree = Tritree(node, cell)
        mesh = tritree.to_conformmesh()

        space = LagrangeFiniteElementSpace(mesh, p=2)
        uI = space.interpolation(u)
        error0 = space.integralalg.L2_error(u, uI)

        fig = plt.figure()
        axes = fig.gca()
        mesh.add_plot(axes)
        mesh.find_node(axes, node=space.interpolation_points(), showindex=True)

        data = tritree.interpolation(uI)
        options = tritree.adaptive_options(method='numrefine',
                                           data={"q": data},
                                           maxrefine=1,
                                           p=2)
        if 1:
            #eta = space.integralalg.integral(lambda x : uI.grad_value(x)**2, celltype=True, barycenter=True)
            #eta = eta.sum(axis=-1)
            eta = np.array([1, 0], dtype=np.int)
            tritree.adaptive(eta, options)
        else:
            tritree.uniform_refine(options=options)

        fig = plt.figure()
        axes = fig.gca()
        tritree.add_plot(axes)
        tritree.find_node(axes, showindex=True)

        mesh = tritree.to_conformmesh(options)
        space = LagrangeFiniteElementSpace(mesh, p=2)
        data = options['data']['q']
        uh = space.to_function(data)

        error1 = space.integralalg.L2_error(u, uh)

        data = tritree.interpolation(uh)
        isLeafCell = tritree.is_leaf_cell()

        fig = plt.figure()
        axes = fig.gca()
        tritree.add_plot(axes)
        tritree.find_node(axes,
                          node=space.interpolation_points(),
                          showindex=True)
        tritree.find_cell(axes, index=isLeafCell, showindex=True)

        options = tritree.adaptive_options(method='numrefine',
                                           data={"q": data},
                                           maxrefine=1,
                                           maxcoarsen=1,
                                           p=2)
        if 1:
            #eta = space.integralalg.integral(lambda x : uI.grad_value(x)**2, celltype=True, barycenter=True)
            #eta = eta.sum(axis=-1)
            eta = np.array([-1, -1, -1, -1, 0, 1], dtype=np.int)
            tritree.adaptive(eta, options)
        else:
            tritree.uniform_refine(options=options)

        mesh = tritree.to_conformmesh(options)
        space = LagrangeFiniteElementSpace(mesh, p=2)
        data = options['data']['q']
        uh = space.to_function(data)

        fig = plt.figure()
        axes = fig.gca()
        mesh.add_plot(axes)
        mesh.find_node(axes, node=space.interpolation_points(), showindex=True)
        mesh.find_cell(axes, showindex=True)

        error2 = space.integralalg.L2_error(u, uh)
        print(error0)
        print(error1)
        print(error2)
        plt.show()
コード例 #5
0
from fealpy.boundarycondition import BoundaryCondition

n = int(sys.argv[1])
p = int(sys.argv[2])
scale = float(sys.argv[3])

E = 1e+5
nu = 0.3
pde = LShapeDomainData2d(E=E, nu=nu)

mu = pde.mu
lam = pde.lam

mesh = pde.init_mesh(n=n)

space = LagrangeFiniteElementSpace(mesh, p=p)
bc = BoundaryCondition(space, dirichlet=pde.dirichlet, neuman=pde.neuman)
uh = space.function(dim=2)
A = space.linear_elasticity_matrix(mu, lam)
F = space.source_vector(pde.source, dim=2)

bc.apply_neuman_bc(F, is_neuman_boundary=pde.is_neuman_boundary)
A, F = bc.apply_dirichlet_bc(A,
                             F,
                             uh,
                             is_dirichlet_boundary=pde.is_dirichlet_boundary)

uh.T.flat[:] = spsolve(A, F)

error = space.integralalg.L2_error(pde.displacement, uh)
コード例 #6
0
class HuZhangFiniteElementSpace():
    """
    Hu-Zhang Mixed Finite Element Space.
    """
    def __init__(self, mesh, p):
        self.space = LagrangeFiniteElementSpace(mesh, p)  # the scalar space
        self.mesh = mesh
        self.p = p
        self.dof = self.space.dof
        self.dim = self.space.GD
        self.init_orth_matrices()
        self.init_cell_to_dof()

    def init_orth_matrices(self):
        """
        Initialize the othogonal symetric matrix basis.
        """
        mesh = self.mesh
        gdim = self.geo_dimension()

        NE = mesh.number_of_edges()
        if gdim == 2:
            idx = np.array([(0, 0), (1, 1), (0, 1)])
            self.TE = np.zeros((NE, 3, 3), dtype=np.float)
            self.T = np.array([[(1, 0), (0, 0)], [(0, 0), (0, 1)],
                               [(0, 1), (1, 0)]])
        elif gdim == 3:
            idx = np.array([(0, 0), (1, 1), (2, 2), (1, 2), (0, 2), (0, 1)])
            self.TE = np.zeros((NE, 6, 6), dtype=np.float)
            self.T = np.array([[(1, 0, 0), (0, 0, 0), (0, 0, 0)],
                               [(0, 0, 0), (0, 1, 0), (0, 0, 0)],
                               [(0, 0, 0), (0, 0, 0), (0, 0, 1)],
                               [(0, 0, 0), (0, 0, 1), (0, 1, 0)],
                               [(0, 0, 1), (0, 0, 0), (1, 0, 0)],
                               [(0, 1, 0), (1, 0, 0), (0, 0, 0)]])

        t = mesh.edge_unit_tagent()
        _, _, frame = np.linalg.svd(
            t[:, np.newaxis, :])  # get the axis frame on the edge by svd
        frame[:, 0, :] = t
        for i, (j, k) in enumerate(idx):
            self.TE[:,
                    i] = (frame[:, j, idx[:, 0]] * frame[:, k, idx[:, 1]] +
                          frame[:, j, idx[:, 1]] * frame[:, k, idx[:, 0]]) / 2
        self.TE[:, gdim:] *= np.sqrt(2)

        if gdim == 3:
            NF = mesh.number_of_faces()
            self.TF = np.zeros((NF, 6, 6), dtype=np.float)
            n = mesh.face_unit_normal()
            _, _, frame = np.linalg.svd(
                n[:, np.newaxis, :])  # get the axis frame on the edge by svd
            frame[:, 0, :] = n
            for i, (j, k) in enumerate(idx):
                self.TF[:, i] = (
                    frame[:, j, idx[:, 0]] * frame[:, k, idx[:, 1]] +
                    frame[:, j, idx[:, 1]] * frame[:, k, idx[:, 0]]) / 2

            self.TF[:, gdim:] *= np.sqrt(2)

    def __str__(self):
        return "Hu-Zhang mixed finite element space!"

    def number_of_global_dofs(self):
        """
        """
        p = self.p
        gdim = self.geo_dimension()
        tdim = self.tensor_dimension()

        mesh = self.mesh

        NC = mesh.number_of_cells()
        NN = mesh.number_of_nodes()
        gdof = tdim * NN

        if p > 1:
            edof = p - 1
            NE = mesh.number_of_edges()
            gdof += (tdim - 1) * edof * NE  # 边内部连续自由度的个数
            E = mesh.number_of_edges_of_cells()  # 单元边的个数
            gdof += NC * E * edof  # 边内部不连续自由度的个数

        if p > 2:
            fdof = (p + 1) * (p + 2) // 2 - 3 * p  # 面内部自由度的个数
            if gdim == 2:
                gdof += tdim * fdof * NC
            elif gdim == 3:
                NF = mesh.number_of_faces()
                gdof += 3 * fdof * NF  # 面内部连续自由度的个数
                F = mesh.number_of_faces_of_cells()  # 每个单元面的个数
                gdof += 3 * F * fdof * NC  # 面内部不连续自由度的个数

        if (p > 3) and (gdim == 3):
            ldof = self.dof.number_of_local_dofs()
            V = mesh.number_of_nodes_of_cells()  # 单元顶点的个数
            cdof = ldof - E * edof - F * fdof - V
            gdof += tdim * cdof * NC
        return gdof

    def number_of_local_dofs(self):
        tdim = self.tensor_dimension()
        ldof = self.dof.number_of_local_dofs()
        return tdim * ldof

    def cell_to_dof(self):
        return self.cell2dof

    def init_cell_to_dof(self):
        """
        构建局部自由度到全局自由度的映射矩阵

        Returns
        -------
        cell2dof : ndarray with shape (NC, ldof*tdim)
            NC: 单元个数
            ldof: p 次标量空间局部自由度的个数
            tdim: 对称张量的维数
        """
        mesh = self.mesh
        NN = mesh.number_of_nodes()
        NE = mesh.number_of_edges()
        NC = mesh.number_of_cells()

        gdim = self.geo_dimension()
        tdim = self.tensor_dimension()  # 张量维数
        p = self.p
        dof = self.dof  # 标量空间自由度管理对象

        c2d = dof.cell2dof[..., np.newaxis]
        ldof = dof.number_of_local_dofs()  # ldof : 标量空间单元上自由度个数
        cell2dof = np.zeros((NC, ldof, tdim),
                            dtype=np.int)  # 每个标量自由度变成 tdim 个自由度

        dofFlags = self.dof_flags_1()  # 把不同类型的自由度区分开来
        idx, = np.nonzero(dofFlags[0])  # 局部顶点自由度的编号
        cell2dof[:, idx, :] = tdim * c2d[:, idx] + np.arange(tdim)

        base0 = 0
        base1 = 0
        idx, = np.nonzero(dofFlags[1])  # 边内部自由度的编号
        if len(idx) > 0:
            base0 += NN  # 这是标量编号的新起点
            base1 += tdim * NN  # 这是张量自由度编号的新起点
            #  0号局部自由度对应的是切向不连续的自由度, 留到后面重新编号
            cell2dof[:, idx,
                     1:] = base1 + (tdim - 1) * (c2d[:, idx] -
                                                 base0) + np.arange(tdim - 1)

        idx, = np.nonzero(dofFlags[2])
        if len(idx) > 0:
            edof = p - 1
            base0 += edof * NE
            base1 += (tdim - 1) * edof * NE
            if gdim == 2:
                cell2dof[:, idx, :] = base1 + tdim * (c2d[:, idx] -
                                                      base0) + np.arange(tdim)
            elif gdim == 3:
                # 1, 2, 3 号局部自由度对应切向不连续的张量自由度, 留到后面重新编号
                # TODO: check it is right
                cell2dof[:, idx.reshape(-1, 1),
                         np.array([0, 4, 5])] = base1 + (tdim - 3) * (
                             c2d[:, idx] - base0) + np.arange(tdim - 3)

        fdof = (p + 1) * (p + 2) // 2 - 3 * p  # 边内部自由度
        if gdim == 3:
            idx, = np.nonzero(dofFlags[3])
            if len(idx) > 0:
                NF = mesh.number_of_faces()
                base0 += fdof * NF
                base1 += (tdim - 3) * fdof * NF
                cell2dof[:, idx, :] = base1 + tdim * (c2d[:, idx] -
                                                      base0) + np.arange(tdim)
            cdof = ldof - 4 * fdof - 6 * edof - 4  # 单元内部自由度
        else:
            cdof = fdof

        idx, = np.nonzero(dofFlags[1])
        if len(idx) > 0:
            base1 += tdim * cdof * NC
            cell2dof[:, idx, 0] = base1 + np.arange(NC * len(idx)).reshape(
                NC, len(idx))

        if gdim == 3:
            base1 += NC * len(idx)
            idx, = np.nonzero(dofFlags[2])
            print(idx)
            if len(idx) > 0:
                cell2dof[:, idx.reshape(-1, 1),
                         np.array([1, 2, 3])] = base1 + np.arange(
                             NC * len(idx) * 3).reshape(NC, len(idx), 3)

        self.cell2dof = cell2dof.reshape(NC, -1)

    def geo_dimension(self):
        return self.dim

    def tensor_dimension(self):
        dim = self.dim
        return dim * (dim - 1) // 2 + dim

    def interpolation_points(self):
        return self.dof.interpolation_points()

    def dof_flags(self):
        """ 对标量空间中的自由度进行分类, 分为边内部自由度, 面内部自由度(如果是三维空间的话)及其它自由度 

        Returns
        -------

        isOtherDof : ndarray, (ldof,)
            除了边内部和面内部自由度的其它自由度
        isEdgeDof : ndarray, (ldof, 3) or (ldof, 6) 
            每个边内部的自由度
        isFaceDof : ndarray, (ldof, 4)
            每个面内部的自由度
        -------

        """
        dim = self.geo_dimension()
        dof = self.dof

        isPointDof = dof.is_on_node_local_dof()
        isEdgeDof = dof.is_on_edge_local_dof()
        isEdgeDof[isPointDof] = False

        isEdgeDof0 = np.sum(isEdgeDof, axis=-1) > 0  #
        isOtherDof = (~isEdgeDof0)  # 除了边内部自由度之外的其它自由度
        # dim = 2: 包括点和面内部自由度
        # dim = 3: 包括点, 面内部和体内部自由度
        if dim == 2:
            return isOtherDof, isEdgeDof
        elif dim == 3:
            isFaceDof = dof.is_on_face_local_dof()
            isFaceDof[isPointDof, :] = False
            isFaceDof[isEdgeDof0, :] = False

            isFaceDof0 = np.sum(isFaceDof, axis=-1) > 0
            isOtherDof = isOtherDof & (~isFaceDof0)  # 三维情形下, 从其它自由度中除去面内部自由度

            return isOtherDof, isEdgeDof, isFaceDof
        else:
            raise ValueError('`dim` should be 2 or 3!')

    def dof_flags_1(self):
        """ 
        对标量空间中的自由度进行分类, 分为:
            点上的自由由度
            边内部的自由度
            面内部的自由度
            体内部的自由度

        Returns
        -------

        """
        gdim = self.geo_dimension()  # the geometry space dimension
        dof = self.dof
        isPointDof = dof.is_on_node_local_dof()
        isEdgeDof = dof.is_on_edge_local_dof()
        isEdgeDof[isPointDof] = False
        isEdgeDof0 = np.sum(isEdgeDof, axis=-1) > 0
        if gdim == 2:
            return isPointDof, isEdgeDof0, ~(isPointDof | isEdgeDof0)
        elif gdim == 3:
            isFaceDof = dof.is_on_face_local_dof()
            isFaceDof[isPointDof, :] = False
            isFaceDof[isEdgeDof0, :] = False

            isFaceDof0 = np.sum(isFaceDof, axis=-1) > 0
            return isPointDof, isEdgeDof0, isFaceDof0, ~(
                isPointDof | isEdgeDof0 | isFaceDof0)
        else:
            raise ValueError('`dim` should be 2 or 3!')

    def basis(self, bc, cellidx=None):
        """

        Parameters
        ----------
        bc : ndarray with shape (NQ, dim+1)
            bc[i, :] is i-th quad point
        cellidx : ndarray
            有时我我们只需要计算部分单元上的基函数
        Returns
        -------
        phi : ndarray with shape (NQ, NC, ldof*tdim, 3 or 6)
            NQ: 积分点个数
            NC: 单元个数
            ldof: 标量空间的单元自由度个数
            tdim: 对称张量的维数
        """
        mesh = self.mesh

        gdim = self.geo_dimension()
        tdim = self.tensor_dimension()

        if cellidx is None:
            NC = mesh.number_of_cells()
            cell2edge = mesh.ds.cell_to_edge()
        else:
            NC = len(cellidx)
            cell2edge = mesh.ds.cell_to_edge()[cellidx]

        phi0 = self.space.basis(bc)  # the shape of phi0 is (NQ, ldof)
        shape = list(phi0.shape)
        shape.insert(-1, NC)
        shape += [tdim, tdim]
        # The shape of `phi` is (NQ, NC, ldof, tdim, tdim), where
        #   NQ : the number of quadrature points
        #   NC : the number of cells
        #   ldof : the number of dofs in each cell
        #   tdim : the dimension of symmetric tensor matrix
        phi = np.zeros(shape, dtype=np.float)

        dofFlag = self.dof_flags()
        # the dof on the vertex and the interior of the cell
        isOtherDof = dofFlag[0]
        idx, = np.nonzero(isOtherDof)
        if len(idx) > 0:
            phi[..., idx[..., np.newaxis],
                range(tdim),
                range(tdim)] = phi0[..., np.newaxis, idx, np.newaxis]

        isEdgeDof = dofFlag[1]
        for i, isDof in enumerate(isEdgeDof.T):
            phi[..., isDof, :, :] = np.einsum('...j, imn->...ijmn',
                                              phi0[..., isDof],
                                              self.TE[cell2edge[:, i]])

        if gdim == 3:
            if cellidx is None:
                cell2face = mesh.ds.cell_to_face()
            else:
                cell2face = mesh.ds.cell_to_face()[cellidx]
            isFaceDof = dofFlag[2]
            for i, isDof in enumerate(isFaceDof.T):
                phi[..., isDof, :, :] = np.einsum('...j, imn->...ijmn',
                                                  phi0[..., isDof],
                                                  self.TF[cell2face[:, i]])
        # The shape of `phi` should be (NQ, NC, ldof*tdim, tdim)?
        shape = phi.shape[:-3] + (-1, tdim)
        return phi.reshape(shape)

    def div_basis(self, bc, cellidx=None):
        mesh = self.mesh

        gdim = self.geo_dimension()
        tdim = self.tensor_dimension()

        # the shape of `gphi` is (NQ, NC, ldof, gdim)
        gphi = self.space.grad_basis(bc, cellidx=cellidx)
        shape = list(gphi.shape)
        shape.insert(-1, tdim)
        # the shape of `dphi` is (NQ, NC, ldof, tdim, gdim)
        dphi = np.zeros(shape, dtype=np.float)

        dofFlag = self.dof_flags()
        # the dof on the vertex and the interior of the cell
        isOtherDof = dofFlag[0]
        dphi[..., isOtherDof, :, :] = np.einsum('...ijm, kmn->...ijkn',
                                                gphi[...,
                                                     isOtherDof, :], self.T)

        if cellidx is None:
            cell2edge = mesh.ds.cell_to_edge()
        else:
            cell2edge = mesh.ds.cell_to_edge()[cellidx]
        isEdgeDof = dofFlag[1]
        for i, isDof in enumerate(isEdgeDof.T):
            VAL = np.einsum('ijk, kmn->ijmn', self.TE[cell2edge[:, i]], self.T)
            dphi[..., isDof, :, :] = np.einsum('...ikm, ijmn->...ikjn',
                                               gphi[..., isDof, :], VAL)

        if gdim == 3:
            if cellidx is None:
                cell2face = mesh.ds.cell_to_face()
            else:
                cell2face = mesh.ds.cell_to_face()[cellidx]
            isFaceDof = dofFlag[2]
            for i, isDof in enumerate(isFaceDof.T):
                VAL = np.einsum('ijk, kmn->ijmn', self.TF[cell2face[:, i]],
                                self.T)
                dphi[..., isDof, :, :] = np.einsum('...ikm, ijmn->...ikjn',
                                                   gphi[..., isDof, :], VAL)

        # The new shape of `dphi` is `(NQ, NC, ldof*tdim, gdim)`, where
        shape = dphi.shape[:-3] + (-1, gdim)
        return dphi.reshape(shape)

    def value(self, uh, bc, cellidx=None):
        phi = self.basis(bc, cellidx=cellidx)
        cell2dof = self.cell_to_dof()
        tdim = self.tensor_dimension()
        if cellidx is None:
            uh = uh[cell2dof]
        else:
            uh = uh[cell2dof[cellidx]]
        phi = np.einsum('...jk, kmn->...jmn', phi, self.T)
        val = np.einsum('...ijmn, ij->...imn', phi, uh)
        return val

    def div_value(self, uh, bc, cellidx=None):
        dphi = self.div_basis(bc, cellidx=cellidx)
        cell2dof = self.cell_to_dof()
        tdim = self.tensor_dimension()
        if cellidx is None:
            uh = uh[cell2dof]
        else:
            uh = uh[cell2dof[cellidx]]
        val = np.einsum('...ijm, ij->...im', dphi, uh)
        return val

    def interpolation(self, u):

        mesh = self.mesh
        gdim = self.geo_dimension()
        tdim = self.tensor_dimension()

        if gdim == 2:
            idx = np.array([(0, 0), (1, 1), (0, 1)])
        elif gdim == 3:
            idx = np.array([(0, 0), (1, 1), (2, 2), (1, 2), (0, 2), (0, 1)])

        ipoint = self.dof.interpolation_points()
        c2d = self.dof.cell2dof
        val = u(ipoint)[c2d]

        ldof = self.dof.number_of_local_dofs()
        cell2dof = self.cell2dof.reshape(-1, ldof, tdim)

        uI = Function(self)
        dofFlag = self.dof_flags()
        isOtherDof = dofFlag[0]
        idx0, = np.nonzero(isOtherDof)
        uI[cell2dof[:, idx0, :]] = val[:, idx0][..., idx[:, 0], idx[:, 1]]

        isEdgeDof = dofFlag[1]
        cell2edge = self.mesh.ds.cell_to_edge()
        for i, isDof in enumerate(isEdgeDof.T):
            TE = np.einsum('ijk, kmn->ijmn', self.TE[cell2edge[:, i]], self.T)
            uI[cell2dof[:, isDof, :]] = np.einsum('ikmn, ijmn->ikj',
                                                  val[:, isDof, :, :], TE)

        if gdim == 3:
            cell2face = mesh.ds.cell_to_face()
            isFaceDof = dofFlag[2]
            for i, isDof in enumerate(isFaceDof.T):
                TF = np.einsum('ijk, kmn->ijmn', self.TF[cell2face[:, i]],
                               self.T)
                uI[cell2dof[:, isDof, :]] = np.einsum('ikmn, ijmn->ikj',
                                                      val[...,
                                                          isDof, :, :], TF)
        return uI

        def function(self, dim=None):
            f = Function(self)

        return f

    def array(self, dim=None):
        gdof = self.number_of_global_dofs()
        return np.zeros(gdof, dtype=np.float)
コード例 #7
0
mesh = pde.init_mesh(n=n)

errorType = [
    '$|| u - u_h||_{\Omega,0}$',  # L2 误差
    '$||\\nabla u - \\nabla u_h||_{\Omega, 0}$'  # H1 误差
]
errorMatrix = np.zeros((2, maxit), dtype=np.float)
NDof = np.zeros(maxit, dtype=np.float)

# 初始网格
fig = plt.figure()
axes = fig.gca()
mesh.add_plot(axes)

for i in range(maxit):
    space = LagrangeFiniteElementSpace(mesh, p=p)  # 建立有限元空间

    NDof[i] = space.number_of_global_dofs()  # 有限元空间自由度的个数
    bc = DirichletBC(space, pde.dirichlet)  # DirichletBC 条件

    uh = space.function()  # 有限元函数
    A = space.stiff_matrix()  # 刚度矩阵
    F = space.source_vector(pde.source)  # 载荷向量

    A, F = bc.apply(A, F, uh)  # 处理边界条件

    uh[:] = spsolve(A, F).reshape(-1)  # 稀疏矩阵直接解法器

    #ml = pyamg.ruge_stuben_solver(A)  # 代数多重网格解法器
    #uh[:] = ml.solve(F, tol=1e-12, accel='cg').reshape(-1)
コード例 #8
0
ファイル: debug_09022020.py プロジェクト: ymjyxw/fealpy
from fealpy.pde.poisson_2d import CosCosData

from fealpy.solver import HighOrderLagrangeFEMFastSolver


p = int(sys.argv[1])
n = int(sys.argv[2])

box = [0, 1, 0, 1]
mf = MeshFactory()
mesh = mf.boxmesh2d(box, nx=n, ny=n, meshtype='tri')

pde = CosCosData()

space = LagrangeFiniteElementSpace(mesh, p=p)

uh = space.function()
isBdDof = space.set_dirichlet_bc(uh, pde.dirichlet)

A = space.stiff_matrix()
F = space.source_vector(pde.source)
P = mesh.linear_stiff_matrix()
I = space.linear_interpolation_matrix()

solver = HighOrderLagrangeFEMFastSolver(A, F, P, I, isBdDof)

uh = solver.solve(uh, F)

error = space.integralalg.error(pde.solution, uh)
print(error)
コード例 #9
0
        return x0


from fealpy.mesh import IntervalMesh
from scipy.sparse.linalg import spsolve
from fealpy.functionspace import LagrangeFiniteElementSpace


def u(x):
    return np.cos(x)


p = int(input('p='))
n = int(input('n='))
node = np.array([0, 1], dtype=np.float)
cell = np.array([[0, 1]], dtype=np.int)
mesh = IntervalMesh(node, cell)
mesh.uniform_refine(n)
space = LagrangeFiniteElementSpace(mesh, p=p)
M = space.mass_matrix().toarray()
F = space.source_vector(u)
start1 = time.time()
print(CG(M, F))
start2 = time.time()
print(spsolve(M, F))
start3 = time.time()
print('CG用时', start2 - start1)
print('spsolve用时', start3 - start2)

print(spsolve(M, F) - CG(M, F))
コード例 #10
0
        return flag

    @cartesian
    def is_fracture_boundary(self, p):
        pass


n = int(sys.argv[1])
p = int(sys.argv[2])
scale = float(sys.argv[3])

pde = BoxDomain2DData()

mesh = pde.init_mesh(n=n)

space = LagrangeFiniteElementSpace(mesh, p=p)

bc0 = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary)
bc1 = NeumannBC(space, pde.neumann, threshold=pde.is_neumann_boundary)

uh = space.function(dim=2)  # (gdof, 2) and vector fem function uh[i, j]
A = space.linear_elasticity_matrix(pde.mu, pde.lam)  # (2*gdof, 2*gdof)
F = space.source_vector(pde.source, dim=2)
F = bc1.apply(F)
A, F = bc0.apply(A, F, uh)

if False:
    uh.T.flat[:] = spsolve(A, F)  # (2, gdof ).flat
else:
    ml = pyamg.rootnode_solver(A)  # AMG solver
    M = ml.aspreconditioner(cycle='V')  # preconditioner
コード例 #11
0
from scipy.sparse.linalg import cg, LinearOperator
from scipy.sparse import coo_matrix, csr_matrix, csc_matrix, spdiags, bmat

from fealpy.pde.linear_elasticity_model import PolyModel3d as PDE
from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.boundarycondition import DirichletBC
from fealpy.solver.LinearElasticityRLFEMFastSolver import LinearElasticityRLFEMFastSolver as FastSovler

n = int(sys.argv[1])

pde = PDE(lam=10000.0, mu=1.0)
mu = pde.mu
lam = pde.lam
mesh = pde.init_mesh(n=n)

space = LagrangeFiniteElementSpace(mesh, p=1, q=1)
M, G = space.recovery_linear_elasticity_matrix(lam, mu, format=None)
F = space.source_vector(pde.source, dim=3)

uh = space.function(dim=3)
isBdDof = space.set_dirichlet_bc(uh, pde.dirichlet)

solver = FastSovler(lam, mu, M, G, isBdDof)

solver.solve(uh, F, tol=1e-12)

uI = space.interpolation(pde.displacement, dim=3)

e = uh - uI
error = np.sqrt(np.mean(e**2))
print(error)
コード例 #12
0
    def __init__(self, mesh, args, ctx):
        self.ctx = ctx
        self.args = args # 模拟相关参数

        NT = int((args.T1 - args.T0)/args.DT)
        self.timeline = UniformTimeLine(args.T0, args.T1, NT)
        self.mesh = mesh 

        if self.ctx.myid == 0:
            self.GD = mesh.geo_dimension()
            if self.GD == 2:
                self.vspace = RaviartThomasFiniteElementSpace2d(self.mesh, p=0) # 速度空间
            elif self.GD == 3:
                self.vspace = RaviartThomasFiniteElementSpace3d(self.mesh, p=0)

            self.pspace = self.vspace.smspace # 压力和饱和度所属的空间, 分片常数
            self.cspace = LagrangeFiniteElementSpace(self.mesh, p=1) # 位移空间

            # 上一时刻物理量的值
            self.v = self.vspace.function() # 速度函数
            self.p = self.pspace.function() # 压力函数
            self.s = self.pspace.function() # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
            self.u = self.cspace.function(dim=self.GD) # 位移函数
            self.phi = self.pspace.function() # 孔隙度函数, 分片常数

            # 当前时刻物理量的值, 用于保存临时计算出的值, 模型中系数的计算由当前时刻
            # 的物理量的值决定
            self.cv = self.vspace.function() # 速度函数
            self.cp = self.pspace.function() # 压力函数
            self.cs = self.pspace.function() # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
            self.cu = self.cspace.function(dim=self.GD) # 位移函数
            self.cphi = self.pspace.function() # 孔隙度函数, 分片常数

            # 初值
            self.s[:] = self.mesh.celldata['fluid_0']
            self.p[:] = self.mesh.celldata['pressure_0']  # MPa
            self.phi[:] = self.mesh.celldata['porosity_0'] # 初始孔隙度 

            self.s[:] = self.mesh.celldata['fluid_0']
            self.cp[:] = self.p # 初始地层压力
            self.cphi[:] = self.phi # 当前孔隙度系数

            # 源汇项 
            self.f0 = self.cspace.function()
            self.f1 = self.cspace.function()

            self.f0[:] = self.mesh.nodedata['source_0'] # 流体 0 的源汇项
            self.f1[:] = self.mesh.nodedata['source_1'] # 流体 1 的源汇项

            # 一些常数矩阵和向量

            # 速度散度矩阵, 速度方程对应的散度矩阵, (\nabla\cdot v, w) 
            self.B = self.vspace.div_matrix()

            # 压力方程对应的位移散度矩阵, (\nabla\cdot u, w) 位移散度矩阵
            # * 注意这里利用了压力空间分片常数, 线性函数导数也是分片常数的事实
            c = self.mesh.entity_measure('cell')
            c *= self.mesh.celldata['biot']

            val = self.mesh.grad_lambda() # (NC, TD+1, GD)
            val *= c[:, None, None]
            pc2d = self.pspace.cell_to_dof()
            cc2d = self.cspace.cell_to_dof()
            pgdof = self.pspace.number_of_global_dofs()
            cgdof = self.cspace.number_of_global_dofs()
            I = np.broadcast_to(pc2d, shape=cc2d.shape)
            J = cc2d 
            self.PU0 = csr_matrix(
                    (val[..., 0].flat, (I.flat, J.flat)), 
                    shape=(pgdof, cgdof)
                    )
            self.PU1 = csr_matrix(
                    (val[..., 1].flat, (I.flat, J.flat)),
                    shape=(pgdof, cgdof)
                    )

            if self.GD == 3:
                self.PU2 = csr_matrix(
                        (val[..., 2].flat, (I.flat, J.flat)),
                        shape=(pgdof, cgdof)
                        )

            # 线弹性矩阵的右端向量
            self.FU = np.zeros(self.GD*cgdof, dtype=np.float64)
            self.FU[0*cgdof:1*cgdof] -= [email protected]
            self.FU[1*cgdof:2*cgdof] -= [email protected]

            if self.GD == 3:
                self.FU[2*cgdof:3*cgdof] -= [email protected]

            # 初始应力和等效应力项
            sigma = self.mesh.celldata['stress_0'] + self.mesh.celldata['stress_eff']# 初始应力和等效应力之和
            self.FU[0*cgdof:1*cgdof] -= [email protected]
            self.FU[1*cgdof:2*cgdof] -= [email protected]
            if self.GD == 3:
                self.FU[2*cgdof:3*cgdof] -= [email protected]
コード例 #13
0
class ParallelTwoFluidsWithGeostressSimulator():
    """

    Notes
    -----
    这是一个并行模拟两种流体和地质力学耦合的程序, 这里只是线性系统是并行的  

    * S_0: 流体 0 的饱和度,一般是水
    * S_1: 流体 1 的饱和度,可以为气或油
    * v: 总速度
    * p: 压力
    * u: 岩石位移  

    饱和度 P0 间断元,单元边界用迎风格式
    速度 RT0 元
    压强 P0 元
    岩石位移 P1 连续元离散

    目前, 模型
    * 忽略了毛细管压强和重力作用
    * 饱和度用分片线性间断元求解, 非线性的迎风格式

    渐近解决方案:
    1. Picard 迭代
    2. 气的可压性随着压强的变化而变化
    3. 考虑渗透率随着孔隙度的变化而变化 
    4. 考虑裂缝,裂缝用自适应网格加密,设设置更大的渗透率实现

    体积模量:  K = E/3/(1 - 2*nu) = lambda + 2/3* mu

    Develop
    ------

    """
    def __init__(self, mesh, args, ctx):
        self.ctx = ctx
        self.args = args # 模拟相关参数

        NT = int((args.T1 - args.T0)/args.DT)
        self.timeline = UniformTimeLine(args.T0, args.T1, NT)
        self.mesh = mesh 

        if self.ctx.myid == 0:
            self.GD = mesh.geo_dimension()
            if self.GD == 2:
                self.vspace = RaviartThomasFiniteElementSpace2d(self.mesh, p=0) # 速度空间
            elif self.GD == 3:
                self.vspace = RaviartThomasFiniteElementSpace3d(self.mesh, p=0)

            self.pspace = self.vspace.smspace # 压力和饱和度所属的空间, 分片常数
            self.cspace = LagrangeFiniteElementSpace(self.mesh, p=1) # 位移空间

            # 上一时刻物理量的值
            self.v = self.vspace.function() # 速度函数
            self.p = self.pspace.function() # 压力函数
            self.s = self.pspace.function() # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
            self.u = self.cspace.function(dim=self.GD) # 位移函数
            self.phi = self.pspace.function() # 孔隙度函数, 分片常数

            # 当前时刻物理量的值, 用于保存临时计算出的值, 模型中系数的计算由当前时刻
            # 的物理量的值决定
            self.cv = self.vspace.function() # 速度函数
            self.cp = self.pspace.function() # 压力函数
            self.cs = self.pspace.function() # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
            self.cu = self.cspace.function(dim=self.GD) # 位移函数
            self.cphi = self.pspace.function() # 孔隙度函数, 分片常数

            # 初值
            self.s[:] = self.mesh.celldata['fluid_0']
            self.p[:] = self.mesh.celldata['pressure_0']  # MPa
            self.phi[:] = self.mesh.celldata['porosity_0'] # 初始孔隙度 

            self.s[:] = self.mesh.celldata['fluid_0']
            self.cp[:] = self.p # 初始地层压力
            self.cphi[:] = self.phi # 当前孔隙度系数

            # 源汇项 
            self.f0 = self.cspace.function()
            self.f1 = self.cspace.function()

            self.f0[:] = self.mesh.nodedata['source_0'] # 流体 0 的源汇项
            self.f1[:] = self.mesh.nodedata['source_1'] # 流体 1 的源汇项

            # 一些常数矩阵和向量

            # 速度散度矩阵, 速度方程对应的散度矩阵, (\nabla\cdot v, w) 
            self.B = self.vspace.div_matrix()

            # 压力方程对应的位移散度矩阵, (\nabla\cdot u, w) 位移散度矩阵
            # * 注意这里利用了压力空间分片常数, 线性函数导数也是分片常数的事实
            c = self.mesh.entity_measure('cell')
            c *= self.mesh.celldata['biot']

            val = self.mesh.grad_lambda() # (NC, TD+1, GD)
            val *= c[:, None, None]
            pc2d = self.pspace.cell_to_dof()
            cc2d = self.cspace.cell_to_dof()
            pgdof = self.pspace.number_of_global_dofs()
            cgdof = self.cspace.number_of_global_dofs()
            I = np.broadcast_to(pc2d, shape=cc2d.shape)
            J = cc2d 
            self.PU0 = csr_matrix(
                    (val[..., 0].flat, (I.flat, J.flat)), 
                    shape=(pgdof, cgdof)
                    )
            self.PU1 = csr_matrix(
                    (val[..., 1].flat, (I.flat, J.flat)),
                    shape=(pgdof, cgdof)
                    )

            if self.GD == 3:
                self.PU2 = csr_matrix(
                        (val[..., 2].flat, (I.flat, J.flat)),
                        shape=(pgdof, cgdof)
                        )

            # 线弹性矩阵的右端向量
            self.FU = np.zeros(self.GD*cgdof, dtype=np.float64)
            self.FU[0*cgdof:1*cgdof] -= [email protected]
            self.FU[1*cgdof:2*cgdof] -= [email protected]

            if self.GD == 3:
                self.FU[2*cgdof:3*cgdof] -= [email protected]

            # 初始应力和等效应力项
            sigma = self.mesh.celldata['stress_0'] + self.mesh.celldata['stress_eff']# 初始应力和等效应力之和
            self.FU[0*cgdof:1*cgdof] -= [email protected]
            self.FU[1*cgdof:2*cgdof] -= [email protected]
            if self.GD == 3:
                self.FU[2*cgdof:3*cgdof] -= [email protected]

    def recover(self, val):
        """

        Notes
        -----
        给定一个分片常数的量, 恢复为分片连续的量
        """

        mesh = self.mesh
        cell = self.mesh.entity('cell')
        NC = mesh.number_of_cells()
        NN = mesh.number_of_nodes()

        w = 1/self.mesh.entity_measure('cell') # 恢复权重
        w = np.broadcast_to(w[:, None], shape=cell.shape)

        r = np.zeros(NN, dtype=np.float64)
        d = np.zeros(NN, dtype=np.float64)

        np.add.at(d, cell, w)
        np.add.at(r, cell, val[:, None]*w)

        return r/d

    def add_time(self, n):
        """

        Notes
        ----

        增加 n 步的计算时间 
        """

        if self.ctx.myid == 0:
            self.timeline.add_time(n)


    def pressure_coefficient(self):

        """

        Notes
        -----
        计算当前物理量下的压强质量矩阵系数
        """

        b = self.mesh.celldata['biot'] 
        K = self.mesh.celldata['K']
        c0 = self.mesh.meshdata['fluid_0']['compressibility']
        c1 = self.mesh.meshdata['fluid_1']['compressibility']

        s = self.cs # 流体 0 当前的饱和度 (NQ, NC)
        phi = self.cphi # 当前的孔隙度

        val = phi*s*c0  
        val += phi*(1 - s)*c1 # 注意这里的 co 是常数, 但在水气混合物条件下应该依赖于压力
        val += (b - phi)/K
        return val

    def saturation_pressure_coefficient(self):
        """

        Notes
        -----
        计算当前物理量下, 饱和度方程中, 压强项对应的系数
        """

        b = self.mesh.celldata['biot'] 
        K = self.mesh.celldata['K']
        c0 = self.mesh.meshdata['fluid_0']['compressibility']

        s = self.cs # 当前流体 0 的饱和度
        phi = self.cphi # 当前孔隙度

        val  = (b - phi)/K
        val += phi*c0
        val *= s 
        return val

    def flux_coefficient(self):
        """
        Notes
        -----

        计算**当前**物理量下, 速度方程对应的系数

        计算通量的系数, 流体的相对渗透率除以粘性系数得到流动性系数 
        k_0/mu_0 是气体的流动性系数 
        k_1/mu_1 是油的流动性系数

        这里假设压强的单位是 MPa 

        1 d = 9.869 233e-13 m^2 = 1000 md
        1 cp = 1 mPa s = 1e-9 MPa*s = 1e-3 Pa*s

        """

        mu0 = self.mesh.meshdata['fluid_0']['viscosity'] # 单位是 1 cp = 1 mPa.s
        mu1 = self.mesh.meshdata['fluid_1']['viscosity'] # 单位是 1 cp = 1 mPa.s 

        # 岩石的绝对渗透率, 这里考虑了量纲的一致性, 压强单位是 Pa
        k = self.mesh.celldata['permeability']*9.869233e-4 

        s = self.cs # 流体 0 当前的饱和度系数

        lam0 = self.mesh.fluid_relative_permeability_0(s) # TODO: 考虑更复杂的饱和度和渗透的关系 
        lam0 /= mu0

        lam1 = self.mesh.fluid_relative_permeability_1(s) # TODO: 考虑更复杂的饱和度和渗透的关系 
        lam1 /= mu1

        val = 1/(lam0 + lam1)
        val /=k 

        return val

    def fluid_fractional_flow_coefficient_0(self):
        """

        Notes
        -----

        计算**当前**物理量下, 饱和度方程中, 主流体的的流动性系数
        """


        s = self.cs # 流体 0 当前的饱和度系数

        mu0 = self.mesh.meshdata['fluid_0']['viscosity'] # 单位是 1 cp = 1 mPa.s
        lam0 = self.mesh.fluid_relative_permeability_0(s) 
        lam0 /= mu0

        lam1 = self.mesh.fluid_relative_permeability_1(s) 
        mu1 = self.mesh.meshdata['fluid_1']['viscosity'] # 单位是 1 cp = 1 mPa.s 
        lam1 /= mu1 

        val = lam0/(lam0 + lam1)
        return val


    def get_total_system(self):
        """
        Notes
        -----
        构造整个系统

        二维情形:
        x = [s, v, p, u0, u1]

        A = [[   S, None,   SP,  SU0,  SU1]
             [None,    V,   VP, None, None]
             [None,   PV,    P,  PU0,  PU1]
             [None, None,  UP0,  U00,  U01]
             [None, None,  UP1,  U10,  U11]]
        F = [FS, FV, FP, FU0, FU1]

        三维情形:

        x = [s, v, p, u0, u1, u2]
        A = [[   S, None,   SP,  SU0,  SU1,  SU2]
             [None,    V,   VP, None, None, None]
             [None,   PV,    P,  PU0,  PU1,  PU2]
             [None, None,  UP0,  U00,  U01,  U02]
             [None, None,  UP1,  U10,  U11,  U12]
             [None, None,  UP2,  U20,  U21,  U22]]
        F = [FS, FV, FP, FU0, FU1, FU2]

        """

        GD = self.GD
        A0, FS, isBdDof0 = self.get_saturation_system(q=2)
        A1, FV, isBdDof1 = self.get_velocity_system(q=2)
        A2, FP, isBdDof2 = self.get_pressure_system(q=2)

        if GD == 2:
            A3, A4, FU, isBdDof3 = self.get_dispacement_system(q=2)
            A = bmat([A0, A1, A2, A3, A4], format='csr')
            F = np.r_['0', FS, FV, FP, FU]
        elif GD == 3:
            A3, A4, A5, FU, isBdDof3 = self.get_dispacement_system(q=2)
            A = bmat([A0, A1, A2, A3, A4, A5], format='csr')
            F = np.r_['0', FS, FV, FP, FU]
        isBdDof = np.r_['0', isBdDof0, isBdDof1, isBdDof2, isBdDof3]
        return A, F, isBdDof

    def get_saturation_system(self, q=2):
        """
        Notes
        ----
        计算饱和度方程对应的离散系统

        [   S, None,   SP,  SU0,  SU1]

        [   S, None,   SP,  SU0,  SU1, SU2]
        """

        GD = self.GD
        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()
        cellmeasure = self.mesh.entity_measure('cell')

        # SP 是对角矩阵 
        c = self.saturation_pressure_coefficient() # (NC, )
        c *= cellmeasure 
        SP = diags(c, 0)

        # S 质量矩阵组装, 对角矩阵
        c = self.cphi[:]*cellmeasure
        S = diags(c, 0)

        # SU0, SU1, 饱和度方程中的位移散度对应的矩阵
        b = self.mesh.celldata['biot']
        val = self.mesh.grad_lambda() # (NC, TD+1, GD)
        c = self.cs[:]*b # (NC, ), 注意用当前的水饱和度
        c *= cellmeasure 
        val *= c[:, None, None]

        pgdof = self.pspace.number_of_global_dofs() # 压力空间自由度个数
        cgdof = self.cspace.number_of_global_dofs() # 连续空间自由度个数

        pc2d = self.pspace.cell_to_dof()
        cc2d = self.cspace.cell_to_dof()

        I = np.broadcast_to(pc2d, shape=cc2d.shape)
        J = cc2d 

        SU0 = csr_matrix(
                (val[..., 0].flat, (I.flat, J.flat)),
                shape=(pgdof, cgdof)
                )
        SU1 = csr_matrix(
                (val[..., 1].flat, (I.flat, J.flat)),
                shape=(pgdof, cgdof)
                )

        if GD == 3:
            SU2 = csr_matrix(
                    (val[..., 2].flat, (I.flat, J.flat)),
                    shape=(pgdof, cgdof)
                    )



        # 右端矩阵
        dt = self.timeline.current_time_step_length()
        FS = self.f0.value(bcs) # (NQ, NC)
        FS *= ws[:, None]
        FS = np.sum(FS, axis=0)
        FS *= cellmeasure
        FS *= dt

        FS += [email protected] # 上一时间步的压强 
        FS += [email protected] # 上一时间步的饱和度
        FS += [email protected][:, 0] # 上一时间步的位移 x 分量
        FS += [email protected][:, 1] # 上一个时间步的位移 y 分量 
        if GD == 3:
            FS += [email protected][:, 2] # 上一个时间步的位移 z 分量 


        # 用当前时刻的速度场, 构造迎风格式
        face2cell = self.mesh.ds.face_to_cell()
        isBdFace = face2cell[:, 0] == face2cell[:, 1]

        qf = self.mesh.integrator(2, 'face') # 边或面上的积分公式
        bcs, ws = qf.get_quadrature_points_and_weights()
        facemeasure = self.mesh.entity_measure('face') 

        # 边的定向法线,它是左边单元的外法线,右边单元内法线。
        fn = self.mesh.face_unit_normal() 
        val0 = np.einsum('qfm, fm->qf', self.cv.face_value(bcs), fn) # 当前速度和法线的内积

        # 流体 0 的流动分数, 与水的饱和度有关, 如果饱和度为0, 则为 0
        F0 = self.fluid_fractional_flow_coefficient_0()
        val1 = F0[face2cell[:, 0]] # 边的左边单元的水流动分数
        val2 = F0[face2cell[:, 1]] # 边的右边单元的水流动分数 
        val2[isBdFace] = 0.0 # 边界的贡献是 0,没有流入和流出

        flag = val0 < 0.0 # 对于左边单元来说,是流入项
                           # 对于右边单元来说,是流出项

        # 左右单元流入流出的绝对量是一样的
        val = val0*val1[None, :] # val0 >= 0.0, 左边单元是流出
                                 # val0 < 0.0, 左边单元是流入
        val[flag] = (val0*val2[None, :])[flag] # val0 >= 0, 右边单元是流入
                                               # val0 < 0, 右边单元是流出

        b = np.einsum('q, qf, f->f', ws, val, facemeasure)
        b *= dt
        np.subtract.at(FS, face2cell[:, 0], b)  

        isInFace = ~isBdFace # 只处理内部边
        np.add.at(FS, face2cell[isInFace, 1], b[isInFace])  

        isBdDof = np.zeros(pgdof, dtype=np.bool_) 

        if GD == 2:
            return [   S, None,   SP,  SU0,  SU1], FS, isBdDof
        elif GD == 3:
            return [   S, None,   SP,  SU0,  SU1, SU2], FS, isBdDof

    def get_velocity_system(self, q=2):
        """
        Notes
        -----
        计算速度方程对应的离散系统.


         [None,    V,   VP, None, None]

         [None,    V,   VP, None, None, None]
        """

        GD = self.GD
        dt = self.timeline.current_time_step_length()
        cellmeasure = self.mesh.entity_measure('cell')
        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()

        # 速度对应的矩阵  V
        c = self.flux_coefficient()
        c *= cellmeasure
        phi = self.vspace.basis(bcs)
        V = np.einsum('q, qcin, qcjn, c->cij', ws, phi, phi, c, optimize=True)

        c2d = self.vspace.cell_to_dof()
        I = np.broadcast_to(c2d[:, :, None], shape=V.shape)
        J = np.broadcast_to(c2d[:, None, :], shape=V.shape)

        gdof = self.vspace.number_of_global_dofs()
        V = csr_matrix(
                (V.flat, (I.flat, J.flat)), 
                shape=(gdof, gdof)
                )

        # 压强矩阵
        VP = -self.B

        # 右端向量, 0 向量
        FV = np.zeros(gdof, dtype=np.float64)
        isBdDof = self.vspace.dof.is_boundary_dof()

        if GD == 2:
            return [None, V, VP, None, None], FV, isBdDof 
        elif GD == 3:
            return [None, V, VP, None, None, None], FV, isBdDof 

    def get_pressure_system(self, q=2):
        """
        Notes
        -----
        计算压强方程对应的离散系统

        这里组装矩阵时, 利用了压强是分片常数的特殊性 

        [  Noe,  PV,   P, PU0,   PU1]

        [  None, PV,   P, PU0,   PU1, PU2]
        """

        GD = self.GD
        dt = self.timeline.current_time_step_length()
        cellmeasure = self.mesh.entity_measure('cell')
        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()

        PV = dt*self.B.T

        # P 是对角矩阵, 利用分片常数的
        c = self.pressure_coefficient() # (NQ, NC)
        c *= cellmeasure 
        P = diags(c, 0)

        # 组装压力方程的右端向量
        # * 这里利用了压力空间基是分片常数
        FP = self.f1.value(bcs) + self.f0.value(bcs) # (NQ, NC)
        FP *= ws[:, None]

        FP = np.sum(FP, axis=0)
        FP *= cellmeasure
        FP *= dt

        FP += [email protected] # 上一步的压力向量
        FP += [email protected][:, 0] 
        FP += [email protected][:, 1]

        if GD == 3:
            FP += [email protected][:, 2]

        gdof = self.pspace.number_of_global_dofs()
        isBdDof = np.zeros(gdof, dtype=np.bool_)

        if GD == 2:
            return [None, PV, P, self.PU0, self.PU1], FP, isBdDof
        elif GD == 3:
            return [None, PV, P, self.PU0, self.PU1, self.PU2], FP, isBdDof


    def get_dispacement_system(self, q=2):
        """
        Notes
        -----
        计算位移方程对应的离散系统, 即线弹性方程系统.
        
        GD == 2:
         [None, None, UP0, U00,   U01]
         [None, None, UP1, U10,   U11]

        GD == 3:
         [None, None, UP0, U00, U01, U02]
         [None, None, UP1, U10, U11, U12]
         [None, None, UP2, U20, U21, U22]

        """


        GD = self.GD
        # 拉梅参数 (lambda, mu)
        lam = self.mesh.celldata['lambda']
        mu = self.mesh.celldata['mu']
        U = self.linear_elasticity_matrix(lam, mu, format='list')

        isBdDof = self.cspace.dof.is_boundary_dof()

        if GD == 2:
            return (
                    [None, None, -self.PU0.T, U[0][0], U[0][1]], 
                    [None, None, -self.PU1.T, U[1][0], U[1][1]], 
                    self.FU, np.r_['0', isBdDof, isBdDof]
                    )
        elif GD == 3:
            return (
                    [None, None, -self.PU0.T, U[0][0], U[0][1], U[0][2]], 
                    [None, None, -self.PU1.T, U[1][0], U[1][1], U[1][2]], 
                    [None, None, -self.PU2.T, U[2][0], U[2][1], U[2][2]], 
                    self.FU, np.r_['0', isBdDof, isBdDof, isBdDof]
                    )

    def linear_elasticity_matrix(self, lam, mu, format='csr', q=None):
        """
        Notes
        -----
        注意这里的拉梅常数是单元分片常数
        lam.shape == (NC, ) # MPa
        mu.shape == (NC, ) # MPa
        """

        GD = self.GD
        if GD == 2:
            idx = [(0, 0), (0, 1),  (1, 1)]
            imap = {(0, 0):0, (0, 1):1, (1, 1):2}
        elif GD == 3:
            idx = [(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)]
            imap = {(0, 0):0, (0, 1):1, (0, 2):2, (1, 1):3, (1, 2):4, (2, 2):5}
        A = []

        qf = self.cspace.integrator if q is None else self.mesh.integrator(q, 'cell')
        bcs, ws = qf.get_quadrature_points_and_weights()
        grad = self.cspace.grad_basis(bcs) # (NQ, NC, ldof, GD)


        # 分块组装矩阵
        gdof = self.cspace.number_of_global_dofs()
        cellmeasure = self.cspace.cellmeasure
        for k, (i, j) in enumerate(idx):
            Aij = np.einsum('i, ijm, ijn, j->jmn', ws, grad[..., i], grad[..., j], cellmeasure)
            A.append(Aij)

        if GD == 2:
            C = [[None, None], [None, None]]
            D = mu[:, None, None]*(A[0] + A[2]) 
        elif GD == 3:
            C = [[None, None, None], [None, None, None], [None, None, None]]
            D = mu[:, None, None]*(A[0] + A[3] + A[5])

        
        cell2dof = self.cspace.cell_to_dof() # (NC, ldof)
        ldof = self.cspace.number_of_local_dofs()
        NC = self.mesh.number_of_cells()
        shape = (NC, ldof, ldof)
        I = np.broadcast_to(cell2dof[:, :, None], shape=shape)
        J = np.broadcast_to(cell2dof[:, None, :], shape=shape)

        for i in range(GD):
            Aii = D + (mu + lam)[:, None, None]*A[imap[(i, i)]] 
            C[i][i] = csr_matrix((Aii.flat, (I.flat, J.flat)), shape=(gdof, gdof))
            for j in range(i+1, GD):
                Aij = lam[:, None, None]*A[imap[(i, j)]] + mu[:, None, None]*A[imap[(i, j)]].swapaxes(-1, -2)
                C[i][j] = csr_matrix((Aij.flat, (I.flat, J.flat)), shape=(gdof, gdof)) 
                C[j][i] = C[i][j].T 

        if format == 'csr':
            return bmat(C, format='csr') # format = bsr ??
        elif format == 'bsr':
            return bmat(C, format='bsr')
        elif format == 'list':
            return C

    def solve_linear_system_0(self):
        # 构建总系统

        if self.ctx.myid == 0:
            A, F, isBdDof = self.get_total_system()

            # 处理边界条件, 这里是 0 边界
            gdof = len(isBdDof)
            bdIdx = np.zeros(gdof, dtype=np.int_)
            bdIdx[isBdDof] = 1 
            Tbd = diags(bdIdx)
            T = diags(1-bdIdx)
            A = T@A@T + Tbd
            F[isBdDof] = 0.0

            # 求解
            self.ctx.set_centralized_sparse(A)
            x = F.copy()
            self.ctx.set_rhs(x) # Modified in place

        self.ctx.run(job=6) # Analysis + Factorization + Solve

        if self.ctx.myid == 0:
            vgdof = self.vspace.number_of_global_dofs()
            pgdof = self.pspace.number_of_global_dofs()
            cgdof = self.cspace.number_of_global_dofs()
            
            start = 0
            end = pgdof
            s = x[start:end]

            start = end
            end += vgdof
            v = x[start:end]

            start = end
            end += pgdof
            p = x[start:end]

            start = end
            u = x[start:]

            return s, v, p, u



    def solve_linear_system_1(self):
        """
        Notes
        -----
        构造整个系统

        二维情形:
        x = [s, v, p, u0, u1]

        A = [[   S, None,   SP,  SU0,  SU1]
             [None,    V,   VP, None, None]
             [None,   PV,    P,  PU0,  PU1]
             [None, None,  UP0,  U00,  U01]
             [None, None,  UP1,  U10,  U11]]
        F = [FS, FV, FP, FU0, FU1]

        三维情形:

        x = [s, v, p, u0, u1, u2]
        A = [[   S, None,   SP,  SU0,  SU1,  SU2]
             [None,    V,   VP, None, None, None]
             [None,   PV,    P,  PU0,  PU1,  PU2]
             [None, None,  UP0,  U00,  U01,  U02]
             [None, None,  UP1,  U10,  U11,  U12]
             [None, None,  UP2,  U20,  U21,  U22]]
        F = [FS, FV, FP, FU0, FU1, FU2]

        """
        if self.ctx.myid == 0:
            vgdof = self.vspace.number_of_global_dofs()
            pgdof = self.pspace.number_of_global_dofs()
            cgdof = self.cspace.number_of_global_dofs()

            GD = self.GD
            A0, FS, isBdDof0 = self.get_saturation_system(q=2)
            A1, FV, isBdDof1 = self.get_velocity_system(q=2)
            A2, FP, isBdDof2 = self.get_pressure_system(q=2)

            if GD == 2:
                A3, A4, FU, isBdDof3 = self.get_dispacement_system(q=2)
                A = bmat([A1[1:], A2[1:], A3[1:], A4[1:]], format='csr')
                F = np.r_['0', FV, FP, FU]
            elif GD == 3:
                A3, A4, A5, FU, isBdDof3 = self.get_dispacement_system(q=2)
                A = bmat([A1[1:], A2[1:], A3[1:], A4[1:], A5[1:]], format='csr')
                F = np.r_['0', FV, FP, FU]

            isBdDof = np.r_['0', isBdDof1, isBdDof2, isBdDof3]

            gdof = len(isBdDof)
            bdIdx = np.zeros(gdof, dtype=np.int_)
            bdIdx[isBdDof] = 1 
            Tbd = diags(bdIdx)
            T = diags(1-bdIdx)
            A = T@A@T + Tbd
            F[isBdDof] = 0.0

        #[   S, None,   SP,  SU0,  SU1, SU2]
            self.ctx.set_centralized_sparse(A)
            x = F.copy()
            self.ctx.set_rhs(x) # Modified in place

        self.ctx.run(job=6) # Analysis + Factorization + Solve

        if self.ctx.myid == 0:

            v = x[0:vgdof]
            p = x[vgdof:vgdof+pgdof]
            u = x[vgdof+pgdof:]

            s = FS
            s -= A0[2]@p 
            s -= A0[3]@u[0*cgdof:1*cgdof] 
            s -= A0[4]@u[1*cgdof:2*cgdof] 
            if GD == 3:
                s -= A0[5]@u[2*cgdof:3*cgdof]
            s /= A0[0].diagonal()

            return s, v, p, u
        else:
            return None, None, None, None


    def picard_iteration(self):
        """
        """

        e0 = 1.0
        k = 0
        while e0 > 1e-10: 

            s, v, p, u = self.solve_linear_system_1()

            if self.ctx.myid == 0:
                e0 = 0.0
                e0 += np.sum((self.cs - s)**2)
                self.cs[:] = s 

                e0 += np.sum((self.cp - p)**2)
                self.cp[:] = p 

                self.cv[:] = v 
                self.cu.T.flat[:] = u

                e0 = np.sqrt(e0) # 误差的 l2 norm
                print(e0)

            e0 = self.ctx.comm.bcast(e0, root=0)
            k += 1
            if k >= self.args.npicard: 
                if self.ctx.myid == 0:
                    print('picard iteration arrive max iteration with error:', e0)
                break

        if self.ctx.myid == 0:
            # 更新解
            self.s[:] = self.cs
            self.v[:] = self.cv
            self.p[:] = self.cp
            self.u[:] = self.cu

    def update_mesh_data(self):
        """

        Notes
        -----
        更新 mesh 中的数据
        """
        GD = self.GD
        bc = np.array((GD+1)*[1/(GD+1)], dtype=np.float64)

        mesh = self.mesh

        v = self.v 
        p = self.p
        s = self.s
        u = self.u


        # 单元中心的流体速度
        val = v.value(bc)
        if GD == 2:
            val = np.concatenate((val, np.zeros((val.shape[0], 1), dtype=val.dtype)), axis=1)
        mesh.celldata['velocity'] = val 

        # 分片常数的压强
        val = self.recover(p[:])
        mesh.nodedata['pressure'] = val

        # 分片常数的饱和度
        val = self.recover(s[:])
        mesh.nodedata['fluid_0'] = val

        val = self.recover(1 - s)
        mesh.nodedata['fluid_1'] = val 

        # 节点处的位移
        if GD == 2:
            u = np.concatenate((u[:], np.zeros((u.shape[0], 1), dtype=u.dtype)), axis=1)
        mesh.nodedata['displacement'] = u[:] 

        # 增加应变和应力的计算

        NC = self.mesh.number_of_cells()
        s0 = np.zeros((NC, 3, 3), dtype=np.float64)
        s1 = np.zeros((NC, 3, 3), dtype=np.float64)

        s = u.grad_value(bc) # (NC, GD, GD)
        s0[:, 0:GD, 0:GD] = s + s.swapaxes(-1, -2)
        s0[:, 0:GD, 0:GD] /= 2

        lam = self.mesh.celldata['lambda']
        mu = self.mesh.celldata['mu']

        s1[:, 0:GD, 0:GD] = s0[:, 0:GD, 0:GD]
        s1[:, 0:GD, 0:GD] *= mu[:, None, None]
        s1[:, 0:GD, 0:GD] *= 2 

        s1[:, range(GD), range(GD)] += (lam*s0.trace(axis1=-1, axis2=-2))[:, None]

        s1[:, range(GD), range(GD)] += mesh.celldata['stress_0'][:, None]

        s1[:, range(GD), range(GD)] -= (mesh.celldata['biot']*(p - mesh.celldata['pressure_0']))[:, None]

        mesh.celldata['strain'] = s0.reshape(NC, -1)
        mesh.celldata['stress'] = s1.reshape(NC, -1)



    def run(self, writer=None):
        """

        Notes
        -----

        计算所有时间层物理量。
        """

        args = self.args

        timeline = self.timeline
        dt = timeline.current_time_step_length()

        if (self.ctx.myid == 0) and (writer is not None):
            n = timeline.current
            fname = args.output + str(n).zfill(10) + '.vtu'
            self.update_mesh_data()
            writer(fname, self.mesh)

        while not timeline.stop():
            if self.ctx.myid == 0:
                ct = timeline.current_time_level()/3600/24 # 天为单位
                print('当前时刻为第', ct, '天')

            self.picard_iteration()
            timeline.current += 1
            if timeline.current%args.step == 0:
                if (self.ctx.myid == 0) and (writer is not None):
                    n = timeline.current
                    fname = args.output + str(n).zfill(10) + '.vtu'
                    self.update_mesh_data()
                    writer(fname, self.mesh)

        if (self.ctx.myid == 0) and (writer is not None):
            n = timeline.current
            fname = args.output + str(n).zfill(10) + '.vtu'
            self.update_mesh_data()
            writer(fname, self.mesh)
コード例 #14
0
    def alg_3_4(self, maxit=None):
        """
        1. 最粗网格上求解最小特征特征值问题,得到最小特征值 d_H 和特征向量 u_H
        2. 自适应求解  - \Delta u_h = u_H
            *  u_H 插值到下一层网格上做为新 u_H
        3. 最新网格层上求出的 uh 做为一个基函数,加入到最粗网格的有限元空间中,
           求解最小特征值问题。

        自适应 maxit, picard:2
        """
        print("算法 3.4")
        if maxit is None:
            maxit = self.maxit

        start = timer()
        if self.step == 0:
            idx = []
        else:
            idx = list(range(0, self.maxit, self.step)) + [self.maxit - 1]

        mesh = self.pde.init_mesh(n=self.numrefine)
        integrator = mesh.integrator(self.q)

        # 1. 粗网格上求解最小特征值问题
        space = LagrangeFiniteElementSpace(mesh, 1)
        AH = self.get_stiff_matrix(space)
        MH = self.get_mass_matrix(space)
        isFreeHDof = ~(space.boundary_dof())

        gdof = space.number_of_global_dofs()
        print("initial mesh :", gdof)

        uH = np.zeros(gdof, dtype=np.float)

        A = AH[isFreeHDof, :][:, isFreeHDof].tocsr()
        M = MH[isFreeHDof, :][:, isFreeHDof].tocsr()

        if self.matlab is False:
            uH[isFreeHDof], d = self.eig(A, M)
        else:
            uH[isFreeHDof], d = self.meigs(A, M)

        uh = space.function()
        uh[:] = uH

        GD = mesh.geo_dimension()
        if (self.step > 0) and (0 in idx):
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_4_0_' + str(NN) + '.pdf')
            plt.close()
            self.savemesh(mesh,
                          self.resultdir + 'mesh_3_4_0_' + str(NN) + '.mat')

        # 2. 以 u_H 为右端项自适应求解 -\Deta u = u_H
        I = eye(gdof)
        final = 0
        for i in range(maxit):
            eta = self.residual_estimate(uh)
            markedCell = mark(eta, self.theta)
            IM = mesh.bisect(markedCell, returnim=True)
            print(i + 1, "refine :", mesh.number_of_nodes())
            if (self.step > 0) and (i in idx):
                NN = mesh.number_of_nodes()
                fig = plt.figure()
                fig.set_facecolor('white')
                if GD == 2:
                    axes = fig.gca()
                else:
                    axes = Axes3D(fig)
                mesh.add_plot(axes, cellcolor='w')
                fig.savefig(self.resultdir + 'mesh_3_4_' + str(i + 1) + '_' +
                            str(NN) + '.pdf')
                plt.close()
                self.savemesh(
                    mesh, self.resultdir + 'mesh_3_4_' + str(i + 1) + '_' +
                    str(NN) + '.mat')

            I = IM @ I
            uH = IM @ uH

            space = LagrangeFiniteElementSpace(mesh, 1)
            gdof = space.number_of_global_dofs()

            A = self.get_stiff_matrix(space)
            M = self.get_mass_matrix(space)
            isFreeDof = ~(space.boundary_dof())
            b = M @ uH

            uh = space.function()
            if self.matlab is False:
                uh[isFreeDof] = self.psolve(
                    A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof],
                    M[isFreeDof, :][:, isFreeDof].tocsr())
            else:
                uh[isFreeDof] = self.msolve(
                    A[isFreeDof, :][:, isFreeDof].tocsr(), b[isFreeDof])
            final = i + 1
            if gdof > self.maxdof:
                break

        if self.step > 0:
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_4_' + str(final) + '_' +
                        str(NN) + '.pdf')
            plt.close()
            self.savemesh(
                mesh, self.resultdir + 'mesh_3_4_' + str(final) + '_' +
                str(NN) + '.mat')

        # 3. 把 uh 加入粗网格空间, 组装刚度和质量矩阵
        w0 = uh @ A
        w1 = w0 @ uh
        w2 = w0 @ I
        AA = bmat([[AH, w2.reshape(-1, 1)], [w2, w1]], format='csr')

        w0 = uh @ M
        w1 = w0 @ uh
        w2 = w0 @ I
        MM = bmat([[MH, w2.reshape(-1, 1)], [w2, w1]], format='csr')

        isFreeDof = np.r_[isFreeHDof, True]

        u = np.zeros(len(isFreeDof))

        ## 求解特征值
        A = AA[isFreeDof, :][:, isFreeDof].tocsr()
        M = MM[isFreeDof, :][:, isFreeDof].tocsr()

        if self.multieigs is True:
            self.A = A
            self.M = M
            self.ml = pyamg.ruge_stuben_solver(self.A)
            self.eigs()
        else:
            if self.matlab is False:
                u[isFreeDof], d = self.eig(A, M)
            else:
                u[isFreeDof], d = self.meigs(A, M)
            print("smallest eigns:", d)
            uh *= u[-1]
            uh += I @ u[:-1]

            uh /= np.max(np.abs(uh))
            uh = space.function(array=uh)
            return uh

        end = timer()
        print("with time: ", end - start)
コード例 #15
0
import numpy as np

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from fealpy.pde.navier_stokes_equation_2d import SinCosData
from fealpy.mesh import MeshFactory as MF
from fealpy.functionspace import LagrangeFiniteElementSpace

pde = SinCosData()
mesh = MF.boxmesh2d(pde.box, nx=10, ny=10, meshtype='tri')

uspace = LagrangeFiniteElementSpace(mesh, p=2)
pspace = LagrangeFiniteElementSpace(mesh, p=1)

pI = pspace.interpolation(pde.pressure)
uI = uspace.interpolation(pde.velocity)

#  [[phi, 0], [0, phi]]
#  [[phi_x, phi_y], [0, 0]] [[0, 0], [phi_x, phi_y]]

A = uspace.stiff_matrix()
B = uspace.div_matrix(pspace)

fig = plt.figure()
axes = fig.gca()
bc = np.array([1 / 3] * 3)
point = mesh.bc_to_point(bc)
p = pI.value(bc)
u = uI.value(bc)
mesh.add_plot(axes, cellcolor=p)
コード例 #16
0
    space = FirstKindNedelecFiniteElementSpace2d(mesh, p=args.order)
    bc = DirichletBC(space, pde.dirichlet)

    gdof = space.number_of_global_dofs()
    NDof[i] = gdof

    uh = space.function()
    A = space.curl_matrix() - space.mass_matrix()
    F = space.source_vector(pde.source)

    A, F = bc.apply(A, F, uh)

    uh[:] = spsolve(A, F)

    #ruh = curl_recover(uh)
    space = LagrangeFiniteElementSpace(mesh, p=1)
    rcuh = space.function(dim=1)
    rcuh[:] = spr(uh, edge_curl_value)  # curl

    ruh = space.function(dim=2)
    ruh[:, 0] = spr(uh, edge_value_0)  #
    ruh[:, 1] = spr(uh, edge_value_1)

    errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh)
    errorMatrix[1, i] = space.integralalg.L2_error(pde.curl, uh.curl_value)
    errorMatrix[2, i] = space.integralalg.L2_error(pde.solution, ruh)
    errorMatrix[3, i] = space.integralalg.L2_error(pde.curl, rcuh)

    # 计算单元上的恢复型误差
    eta0 = space.integralalg.error(uh.curl_value, rcuh, power=2,
                                   celltype=True)  # eta_K
コード例 #17
0
axes = fig.gca(projection='3d')
axes.set_aspect('equal')
axes.set_axis_off()
edge0 = np.array([(0, 1), (0, 3), (1, 2), (1, 3), (2, 3)], dtype=np.int)
lines = a3.art3d.Line3DCollection(point[edge0], color='k', linewidths=2)
axes.add_collection3d(lines)
edge1 = np.array([(0, 2)], dtype=np.int)
lines = a3.art3d.Line3DCollection(point[edge1],
                                  color='gray',
                                  linewidths=2,
                                  alpha=0.5)
axes.add_collection3d(lines)
#mesh.add_plot(axes,  alpha=0.3)
mesh.find_point(axes, showindex=True, color='k', fontsize=20, markersize=100)

V = LagrangeFiniteElementSpace(mesh, degree)
ldof = V.number_of_local_dofs()
ipoints = V.interpolation_points()
cell2dof = V.dof.cell2dof[0]

ipoints = ipoints[cell2dof]

idx = np.arange(1, degree + 2)
idx = np.cumsum(np.cumsum(idx))

d = Delaunay(ipoints)
mesh2 = TetrahedronMesh(ipoints, d.simplices)
face = mesh2.ds.face
isFace = np.zeros(len(face), dtype=np.bool)
for i in range(len(idx) - 1):
    flag = np.sum((face >= idx[i]) & (face < idx[i + 1]), axis=-1) == 3
コード例 #18
0
errorType = [
    '$|| u - u_h||_{0}$', '$||\\nabla u - \\nabla u_h||_{0}$',
    '$||\\nabla u - G(\\nabla u_h)||_{0}$',
    '$||\\nabla u_h - G(\\nabla u_h)||_{0}$'
]

NDof = np.zeros((maxit, ), dtype=np.int_)
errorMatrix = np.zeros((len(errorType), maxit), dtype=np.float64)

mesh.add_plot(plt)
plt.savefig('./test-0.png')
plt.close()

for i in range(maxit):
    print('step:', i)
    space = LagrangeFiniteElementSpace(mesh, p=p)
    A = space.stiff_matrix(q=1)
    F = space.source_vector(pde.source)

    NDof[i] = space.number_of_global_dofs()
    bc = DirichletBC(space, pde.dirichlet)

    uh = space.function()
    A, F = bc.apply(A, F, uh)
    uh[:] = spsolve(A, F)

    rguh = space.grad_recovery(uh)

    errorMatrix[0, i] = space.integralalg.error(pde.solution, uh.value)
    errorMatrix[1, i] = space.integralalg.error(pde.gradient, uh.grad_value)
    errorMatrix[2, i] = space.integralalg.error(pde.gradient, rguh.value)
コード例 #19
0
from mpl_toolkits.mplot3d import Axes3D

from fealpy.pde.linear_elasticity_model import BoxDomainData3d
from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.functionspace import CrouzeixRaviartFiniteElementSpace
from fealpy.boundarycondition import DirichletBC

import pyamg
from timeit import default_timer as timer

n = int(sys.argv[1])

pde = BoxDomainData3d()
mesh = pde.init_mesh(n=n)

space = LagrangeFiniteElementSpace(mesh, p=1)
bc = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary)
uh = space.function(dim=3)
A = space.linear_elasticity_matrix(pde.lam, pde.mu, q=1)
F = space.source_vector(pde.source, dim=3)
A, F = bc.apply(A, F, uh)

if False:
    uh.T.flat[:] = spsolve(A, F)
elif False:
    N = len(F)
    print(N)
    start = timer()
    ilu = spilu(A.tocsc(), drop_tol=1e-6, fill_factor=40)
    end = timer()
    print('time:', end - start)
コード例 #20
0
        print("Number of iteration of pcg:", counter.niter)

        return uh


n = int(sys.argv[1])
p = int(sys.argv[2])
scale = float(sys.argv[3])

pde = BoxDomain2DData()

mesh = pde.init_mesh(n=n)

area = mesh.entity_measure('cell')

space = LagrangeFiniteElementSpace(mesh, p=p)

bc0 = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary)
bc1 = NeumannBC(space, pde.neumann, threshold=pde.is_neumann_boundary)

uh = space.function(dim=2)  # (gdof, 2) and vector fem function uh[i, j]
P = space.stiff_matrix(c=2 * pde.mu)
A = space.linear_elasticity_matrix(pde.mu, pde.lam)  # (2*gdof, 2*gdof)
F = space.source_vector(pde.source, dim=2)
F = bc1.apply(F)
A, F = bc0.apply(A, F, uh)

print(A.shape)

if False:
    uh.T.flat[:] = spsolve(A, F)  # (2, gdof ).flat
コード例 #21
0
ファイル: plot_lagrange_basis.py プロジェクト: zweien/fealpy
import numpy as np
import matplotlib.pyplot as plt

from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.pde.poisson_1d import CosData

n = 100
p = 4

pde = CosData()
mesh = pde.init_mesh(n=0)

bc = np.zeros((n, 2), dtype=np.float)
bc[:, 1] = np.linspace(0, 1, n)
bc[:, 0] = 1 - bc[:, 1]

space = LagrangeFiniteElementSpace(mesh, p=p)

val = space.basis(bc)
print(val.shape)

fig = plt.figure()
axes = fig.gca()
mesh.add_plot(axes)
axes.plot(bc[:, 1], val)
axes.set_axis_on()
plt.show()
コード例 #22
0
ファイル: Model4.py プロジェクト: ymjyxw/fealpy
class WaterFloodingModelSolver():
    """

    Notes
    -----

    """
    def __init__(self, model, T=30 * 3600 * 24, NS=32, NT=3 * 60 * 24):
        self.model = model
        self.mesh = model.space_mesh(n=NS)
        self.timeline = model.time_mesh(T=T, n=NT)

        self.vspace = RaviartThomasFiniteElementSpace2d(self.mesh, p=0)  # 速度空间
        self.pspace = self.vspace.smspace  # 压强和饱和度所属的空间, 分片常数
        self.cspace = LagrangeFiniteElementSpace(self.mesh, p=1)  # 位移空间

        # 上一时刻物理量的值
        self.v = self.vspace.function()  # 速度函数
        self.p = self.pspace.function()  # 压强函数
        self.s = self.pspace.function()  # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
        self.u = self.cspace.function(dim=2)  # 位移函数
        self.phi = self.pspace.function()  # 孔隙度函数, 分片常数

        # 当前时刻物理量的值, 用于保存临时计算出的值, 模型中系数的计算由当前时刻
        # 的物理量的值决定
        self.cv = self.vspace.function()  # 速度函数
        self.cp = self.pspace.function()  # 压强函数
        self.cs = self.pspace.function()  # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
        self.cu = self.cspace.function(dim=2)  # 位移函数
        self.cphi = self.pspace.function()  # 孔隙度函数, 分片常数

        # 初值
        self.p[:] = model.rock['initial pressure']  # MPa
        self.phi[:] = model.rock['porosity']
        self.cp[:] = model.rock['initial pressure']
        self.cphi[:] = model.rock['porosity']

        # 源项,  TODO: 注意这里假设用的是结构网格, 换其它的网格需要修改代码
        self.fo = self.cspace.function()
        self.fo[-1] = -self.model.oil['production rate']  # 产出

        self.fw = self.cspace.function()
        self.fw[0] = self.model.water['injection rate']  # 注入

        # 一些常数矩阵和向量

        # 速度散度矩阵, 速度方程对应的散度矩阵, (\nabla\cdot v, w)
        self.B = self.vspace.div_matrix()

        # 压强方程对应的位移散度矩阵, (\nabla\cdot u, w) 位移散度矩阵
        # * 注意这里利用了压强空间分片常数, 线性函数导数也是分片常数的事实
        c = self.mesh.entity_measure('cell')
        c *= self.model.rock['biot']

        val = self.mesh.grad_lambda()  # (NC, TD+1, GD)
        val *= c[:, None, None]
        pc2d = self.pspace.cell_to_dof()
        cc2d = self.cspace.cell_to_dof()
        pgdof = self.pspace.number_of_global_dofs()
        cgdof = self.cspace.number_of_global_dofs()
        I = np.broadcast_to(pc2d, shape=cc2d.shape)
        J = cc2d
        self.PU0 = csr_matrix((val[..., 0].flat, (I.flat, J.flat)),
                              shape=(pgdof, cgdof))
        self.PU1 = csr_matrix((val[..., 1].flat, (I.flat, J.flat)),
                              shape=(pgdof, cgdof))

        # 线弹性矩阵的右端向量
        sigma0 = self.pspace.function()
        sigma0[:] = self.model.rock['initial stress']
        self.FU = np.zeros(2 * cgdof, dtype=np.float64)
        self.FU[:cgdof] -= self.p @ self.PU0
        self.FU[cgdof:] -= self.p @ self.PU1

        # 初始应力和等效应力项
        self.FU[:cgdof] -= sigma0 @ self.PU0
        self.FU[cgdof:] -= sigma0 @ self.PU1

        # vtk 文件输出
        node, cell, cellType, NC = self.mesh.to_vtk()
        self.points = vtk.vtkPoints()
        self.points.SetData(vnp.numpy_to_vtk(node))
        self.cells = vtk.vtkCellArray()
        self.cells.SetCells(NC, vnp.numpy_to_vtkIdTypeArray(cell))
        self.cellType = cellType

    def recover(self, val):
        """

        Notes
        -----
        给定一个分片常数的量, 恢复为分片连续的量
        """

        mesh = self.mesh
        cell = self.mesh.entity('cell')
        NC = mesh.number_of_cells()
        NN = mesh.number_of_nodes()

        w = 1 / self.mesh.entity_measure('cell')  # 恢复权重
        w = np.broadcast_to(w[:, None], shape=(NC, 3))

        r = np.zeros(NN, dtype=np.float64)
        d = np.zeros(NN, dtype=np.float64)

        np.add.at(d, cell, w)
        np.add.at(r, cell, val[:, None] * w)

        return r / d

    def pressure_coefficient(self):
        """

        Notes
        -----
        计算当前物理量下的压强质量矩阵系数
        """

        b = self.model.rock['biot']
        Ks = self.model.rock['solid grain stiffness']
        cw = self.model.water['compressibility']
        co = self.model.oil['compressibility']

        Sw = self.cs[:].copy()  # 当前的水饱和度 (NQ, NC)

        phi = self.cphi[:].copy()  # 当前的孔隙度

        val = phi * Sw * cw
        val += phi * (1 - Sw) * co  # 注意这里的 co 是常数, 但在水气混合物条件下应该依赖于压力
        val += (b - phi) / Ks
        return val

    def saturation_pressure_coefficient(self):
        """

        Notes
        -----
        计算当前物理量下, 饱和度方程中, 压强项对应的系数
        """

        b = self.model.rock['biot']
        Ks = self.model.rock['solid grain stiffness']
        cw = self.model.water['compressibility']

        val = self.cs[:].copy()  # 当前水饱和度
        phi = self.cphi[:].copy()  # 当前孔隙度

        val *= (b - phi) / Ks + phi * cw

        return val

    def flux_coefficient(self):
        """
        Notes
        -----

        计算**当前**物理量下, 速度方程对应的系数

        计算通量的系数, 流体的相对渗透率除以粘性系数得到流动性系数 
        krg/mu_g 是气体的流动性系数 
        kro/mu_o 是油的流动性系数
        krw/mu_w 是水的流动性系数

        这里假设压强的单位是 MPa 

        1 d = 9.869 233e-13 m^2 = 1000 md
        1 cp = 1 mPa s = 1e-9 MPa.s

        """

        muw = self.model.water['viscosity']  # 单位是 1 cp = 1 mPa.s
        muo = self.model.oil['viscosity']  # 单位是 1 cp = 1 mPa.s

        # 岩石的绝对渗透率, 这里考虑了量纲的一致性, 压强是 MPa
        k = self.model.rock['permeability'] * 9.869233e-4

        Sw = self.cs[:].copy()  # 当前水的饱和度系数

        lamw = self.model.water_relative_permeability(Sw)
        lamw /= muw
        lamo = self.model.oil_relative_permeability(Sw)
        lamo /= muo

        val = 1 / (lamw + lamo) / k  #

        return val

    def water_fractional_flow_coefficient(self):
        """

        Notes
        -----

        计算**当前**物理量下, 饱和度方程中, 水的流动性系数
        """

        Sw = self.cs[:].copy()  # 当前水的饱和度系数
        lamw = self.model.water_relative_permeability(Sw)
        lamw /= self.model.water['viscosity']
        lamo = self.model.oil_relative_permeability(Sw)
        lamo /= self.model.oil['viscosity']
        val = lamw / (lamw + lamo)
        return val

    def get_total_system(self):
        """
        Notes
        -----
        构造整个系统

        x = [v, p, s, u0, u1]

        A = [[   V,  VP, None, None,  None]
             [  PV,   P, None,  PU0,   PU1]
             [None,  SP,    S,  SU0,   SU1] 
             [None, UP0, None,  U00,   U01]
             [None, UP1, None,  U10,   U11]

        F = [FV, FP, FS, FU0, FU1]

        FS 中考虑的迎风格式
        """
        A0, FV, isBdDof0 = self.get_velocity_system(q=2)
        A1, FP, isBdDof1 = self.get_pressure_system(q=2)
        A2, FS, isBdDof2 = self.get_saturation_system(q=2)
        A3, A4, FU, isBdDof3 = self.get_dispacement_system(q=2)

        A = bmat([A0, A1, A2, A3, A4], format='csr')
        F = np.r_['0', FV, FP, FS, FU]
        isBdDof = np.r_['0', isBdDof0, isBdDof1, isBdDof2, isBdDof3]

        return A, F, isBdDof

    def get_velocity_system(self, q=2):
        """
        Notes
        -----
        计算速度方程对应的离散系统.

        [   V,  VP, None, None,  None]

        """

        dt = self.timeline.current_time_step_length()
        cellmeasure = self.mesh.entity_measure('cell')
        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()

        # 速度对应的矩阵  V
        c = self.flux_coefficient()
        c *= cellmeasure
        phi = self.vspace.basis(bcs)
        V = np.einsum('q, qcin, qcjn, c->cij', ws, phi, phi, c, optimize=True)

        c2d = self.vspace.cell_to_dof()
        I = np.broadcast_to(c2d[:, :, None], shape=V.shape)
        J = np.broadcast_to(c2d[:, None, :], shape=V.shape)

        gdof = self.vspace.number_of_global_dofs()
        V = csr_matrix((V.flat, (I.flat, J.flat)), shape=(gdof, gdof))

        # 压强矩阵
        VP = -self.B

        # 右端向量, 0 向量
        FV = np.zeros(gdof, dtype=np.float64)
        isBdDof = self.vspace.dof.is_boundary_dof()
        return [V, VP, None, None, None], FV, isBdDof

    def get_pressure_system(self, q=2):
        """
        Notes
        -----
        计算压强方程对应的离散系统

        这里组装矩阵时, 利用了压强是分片常数的特殊性 

        [  PV,   P, None,  PU0,   PU1]
        """

        dt = self.timeline.current_time_step_length()
        cellmeasure = self.mesh.entity_measure('cell')
        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()

        PV = dt * self.B.T

        # P 是对角矩阵, 利用分片常数的
        c = self.pressure_coefficient()  # (NQ, NC)
        c *= cellmeasure
        P = diags(c, 0)

        # 组装压强方程的右端向量
        # * 这里利用了压强空间基是分片常数
        FP = self.fo.value(bcs) + self.fw.value(bcs)  # (NQ, NC)
        FP *= ws[:, None]

        FP = np.sum(FP, axis=0)
        FP *= cellmeasure
        FP *= dt

        FP += P @ self.p  # 上一步的压强向量
        FP += self.PU0 @ self.u[:, 0]
        FP += self.PU1 @ self.u[:, 1]

        gdof = self.pspace.number_of_global_dofs()
        isBdDof = np.zeros(gdof, dtype=np.bool_)

        return [PV, P, None, self.PU0, self.PU1], FP, isBdDof

    def get_saturation_system(self, q=2):
        """
        Notes
        ----
        计算饱和度方程对应的离散系统

        [ None,  SP,    S, SU0,  SU1] 

        """

        qf = self.mesh.integrator(q, etype='cell')
        bcs, ws = qf.get_quadrature_points_and_weights()
        cellmeasure = self.mesh.entity_measure('cell')

        # SP 是对角矩阵
        c = self.saturation_pressure_coefficient()  # (NC, )
        c *= cellmeasure
        SP = diags(c, 0)

        # S 质量矩阵组装, 对角矩阵
        c = self.cphi[:] * cellmeasure
        S = diags(c, 0)

        # SU0, SU1, 饱和度方程中的位移散度对应的矩阵
        val = self.mesh.grad_lambda()  # (NC, TD+1, GD)
        c = self.cs[:] * self.model.rock['biot']  # (NC, ), 注意用当前的水饱和度
        c *= cellmeasure
        val *= c[:, None, None]

        pgdof = self.pspace.number_of_global_dofs()  # 压力空间自由度个数
        cgdof = self.cspace.number_of_global_dofs()  # 连续空间自由度个数

        pc2d = self.pspace.cell_to_dof()
        cc2d = self.cspace.cell_to_dof()

        I = np.broadcast_to(pc2d, shape=cc2d.shape)
        J = cc2d

        SU0 = csr_matrix((val[..., 0].flat, (I.flat, J.flat)),
                         shape=(pgdof, cgdof))
        SU1 = csr_matrix((val[..., 1].flat, (I.flat, J.flat)),
                         shape=(pgdof, cgdof))

        # 右端矩阵
        dt = self.timeline.current_time_step_length()
        FS = self.fw.value(bcs)  # (NQ, NC)
        FS *= ws[:, None]
        FS = np.sum(FS, axis=0)
        FS *= cellmeasure
        FS *= dt

        FS += SP @ self.p  # 上一时间步的压强
        FS += S @ self.s  # 上一时间步的饱和度
        FS += SU0 @ self.u[:, 0]  # 上一时间步的位移 x 分量
        FS += SU1 @ self.u[:, 1]  # 上一个时间步的位移 y 分量

        # 用当前时刻的速度场, 构造非线性迎风格式
        edge2cell = self.mesh.ds.edge_to_cell()
        isBdEdge = edge2cell[:, 0] == edge2cell[:, 1]

        qf = self.mesh.integrator(2, 'edge')  # 边上的积分公式
        bcs, ws = qf.get_quadrature_points_and_weights()
        edgemeasure = self.mesh.entity_measure('edge')  # 所有网格边的长度

        # 边的定向法线,它是左边单元的外法线,右边单元内法线。
        en = self.mesh.edge_unit_normal()
        val0 = np.einsum('qem, em->qe', self.cv.edge_value(bcs),
                         en)  # 当前速度和法线的内积

        # 水的流动分数, 与水的饱和度有关, 如果饱和度为0, 则为 0
        Fw = self.water_fractional_flow_coefficient()
        val1 = Fw[edge2cell[:, 0]]  # 边的左边单元的水流动分数
        val2 = Fw[edge2cell[:, 1]]  # 边的右边单元的水流动分数
        val2[isBdEdge] = 0.0  # 边界的贡献是 0

        flag = val0 < 0.0  # 对于左边单元来说,是流出项
        # 对于右边单元来说,是流入项

        # 左右单元流入流出的绝对量是一样的
        val = val0 * val1[None, :]  # val0 >= 0.0, 左边单元是流出
        # val0 < 0.0, 左边单元是流入
        val[flag] = (val0 * val2[None, :])[flag]  # val0 >= 0, 右边单元是流入
        # val0 < 0, 右边单元是流出

        b = np.einsum('q, qe, e->e', ws, val, edgemeasure)
        b *= dt
        np.subtract.at(FS, edge2cell[:, 0], b)

        isInEdge = ~isBdEdge  # 只处理内部边
        np.add.at(FS, edge2cell[isInEdge, 1], b[isInEdge])

        isBdDof = np.zeros(pgdof, dtype=np.bool_)

        return [None, SP, S, SU0, SU1], FS, isBdDof

    def get_dispacement_system(self, q=2):
        """
        Notes
        -----
        计算位移方程对应的离散系统, 即线弹性方程系统.

         [None, UP0, None,  U00,   U01]
         [None, UP1, None,  U10,   U11]

        A = [[U00, U01], [U10, U11]]
        """

        # 拉梅参数 (lambda, mu)
        lam, mu = self.model.rock['lame']
        U = self.cspace.linear_elasticity_matrix(lam, mu, format='list')

        UP = bmat([[self.PU0.T], [self.PU1.T]])

        isBdDof = self.cspace.dof.is_boundary_dof()

        return [None, -self.PU0.T, None, U[0][0],
                U[0][1]], [None, -self.PU1.T, None, U[1][0],
                           U[1][1]], self.FU, np.r_['0', isBdDof, isBdDof]

    def picard_iteration(self, maxit=10):

        e0 = 1.0
        k = 0
        while e0 > 1e-10:
            # 构建总系统
            A, F, isBdDof = self.get_total_system()

            # 处理边界条件, 这里是 0 边界
            gdof = len(isBdDof)
            bdIdx = np.zeros(gdof, dtype=np.int_)
            bdIdx[isBdDof] = 1
            Tbd = diags(bdIdx)
            T = diags(1 - bdIdx)
            A = T @ A @ T + Tbd
            F[isBdDof] = 0.0

            # 求解
            x = spsolve(A, F)

            vgdof = self.vspace.number_of_global_dofs()
            pgdof = self.pspace.number_of_global_dofs()
            cgdof = self.cspace.number_of_global_dofs()

            e0 = 0.0
            start = 0
            end = vgdof
            self.cv[:] = x[start:end]

            start = end
            end += pgdof
            e0 += np.sum((self.cp - x[start:end])**2)
            self.cp[:] = x[start:end]

            start = end
            end += pgdof

            e0 += np.sum((self.cs - x[start:end])**2)
            self.cs[:] = x[start:end]
            e0 = np.sqrt(e0)  # 误差的 l2 norm
            k += 1

            start = end
            end += cgdof
            self.cu[:, 0] = x[start:end]

            start = end
            end += cgdof
            self.cu[:, 1] = x[start:end]
            print(e0)

            if k >= maxit:
                print('picard iteration arrive max iteration with error:', e0)
                break

    def update_solution(self):
        self.v[:] = self.cv
        self.p[:] = self.cp
        self.s[:] = self.cs
        flag = self.s < 0.0
        self.s[flag] = 0.0
        self.u[:] = self.cu

    def solve(self, step=30):
        """

        Notes
        -----

        计算所有的时间层。
        """

        timeline = self.timeline
        dt = timeline.current_time_step_length()
        timeline.reset()  # 时间置零

        n = timeline.current
        fname = 'test_' + str(n).zfill(10) + '.vtu'
        self.write_to_vtk(fname)
        while not timeline.stop():
            ct = timeline.current_time_level() / 3600 / 24  # 天为单位
            print('当前时刻为第', ct, '天')
            self.picard_iteration()
            self.update_solution()
            timeline.current += 1
            if timeline.current % step == 0:
                n = timeline.current
                fname = 'test_' + str(n).zfill(10) + '.vtu'
                self.write_to_vtk(fname)
        timeline.reset()

    def write_to_vtk(self, fname):
        # 重心处的值
        mesh = self.mesh
        bc = np.array([1 / 3, 1 / 3, 1 / 3], dtype=np.float64)
        ps = self.mesh.bc_to_point(bc)
        vmesh = vtk.vtkUnstructuredGrid()
        vmesh.SetPoints(self.points)
        vmesh.SetCells(self.cellType, self.cells)
        cdata = vmesh.GetCellData()
        pdata = vmesh.GetPointData()

        v = self.v
        p = self.p
        s = self.s
        u = self.u

        val = v.value(bc)
        val = np.concatenate((val, np.zeros(
            (val.shape[0], 1), dtype=val.dtype)),
                             axis=1)
        val = vnp.numpy_to_vtk(val)
        val.SetName('velocity')
        cdata.AddArray(val)

        val = self.recover(p[:])
        val = vnp.numpy_to_vtk(val)
        val.SetName('pressure')
        pdata.AddArray(val)

        val = self.recover(s[:])
        val = vnp.numpy_to_vtk(val)
        val.SetName('saturation')
        pdata.AddArray(val)

        val = np.concatenate((u[:], np.zeros((u.shape[0], 1), dtype=u.dtype)),
                             axis=1)
        val = vnp.numpy_to_vtk(val)
        val.SetName('displacement')
        pdata.AddArray(val)

        writer = vtk.vtkXMLUnstructuredGridWriter()
        writer.SetFileName(fname)
        writer.SetInputData(vmesh)
        writer.Write()
コード例 #23
0
p = int(sys.argv[2])
maxit = int(sys.argv[3])

if m == 1:
    pde = Model2d()
if m == 2:
    pde = Hole2d(lam=10, mu=1.0)

errorType = ['$||u - u_h||_{0}$']
Ndof = np.zeros((maxit, ))
errorMatrix = np.zeros((len(errorType), maxit), dtype=np.float)

mesh = pde.init_mesh()

mesh.uniform_refine(4)
space = LagrangeFiniteElementSpace(mesh, p=p)

GD = space.geo_dimension()
bc = BoundaryCondition(space, dirichlet=pde.dirichlet)

A = space.linear_elasticity_matrix(pde.mu, pde.lam)
F = space.source_vector(pde.source, dim=GD)

for i in range(maxit):
    space = LagrangeFiniteElementSpace(mesh, p=p)
    Ndof[i] = space.number_of_global_dofs()
    GD = space.geo_dimension()
    bc = BoundaryCondition(space, dirichlet=pde.dirichlet)

    uh = space.function(dim=GD)
コード例 #24
0
ファイル: Model4.py プロジェクト: ymjyxw/fealpy
    def __init__(self, model, T=30 * 3600 * 24, NS=32, NT=3 * 60 * 24):
        self.model = model
        self.mesh = model.space_mesh(n=NS)
        self.timeline = model.time_mesh(T=T, n=NT)

        self.vspace = RaviartThomasFiniteElementSpace2d(self.mesh, p=0)  # 速度空间
        self.pspace = self.vspace.smspace  # 压强和饱和度所属的空间, 分片常数
        self.cspace = LagrangeFiniteElementSpace(self.mesh, p=1)  # 位移空间

        # 上一时刻物理量的值
        self.v = self.vspace.function()  # 速度函数
        self.p = self.pspace.function()  # 压强函数
        self.s = self.pspace.function()  # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
        self.u = self.cspace.function(dim=2)  # 位移函数
        self.phi = self.pspace.function()  # 孔隙度函数, 分片常数

        # 当前时刻物理量的值, 用于保存临时计算出的值, 模型中系数的计算由当前时刻
        # 的物理量的值决定
        self.cv = self.vspace.function()  # 速度函数
        self.cp = self.pspace.function()  # 压强函数
        self.cs = self.pspace.function()  # 水的饱和度函数 默认为0, 初始时刻区域内水的饱和度为0
        self.cu = self.cspace.function(dim=2)  # 位移函数
        self.cphi = self.pspace.function()  # 孔隙度函数, 分片常数

        # 初值
        self.p[:] = model.rock['initial pressure']  # MPa
        self.phi[:] = model.rock['porosity']
        self.cp[:] = model.rock['initial pressure']
        self.cphi[:] = model.rock['porosity']

        # 源项,  TODO: 注意这里假设用的是结构网格, 换其它的网格需要修改代码
        self.fo = self.cspace.function()
        self.fo[-1] = -self.model.oil['production rate']  # 产出

        self.fw = self.cspace.function()
        self.fw[0] = self.model.water['injection rate']  # 注入

        # 一些常数矩阵和向量

        # 速度散度矩阵, 速度方程对应的散度矩阵, (\nabla\cdot v, w)
        self.B = self.vspace.div_matrix()

        # 压强方程对应的位移散度矩阵, (\nabla\cdot u, w) 位移散度矩阵
        # * 注意这里利用了压强空间分片常数, 线性函数导数也是分片常数的事实
        c = self.mesh.entity_measure('cell')
        c *= self.model.rock['biot']

        val = self.mesh.grad_lambda()  # (NC, TD+1, GD)
        val *= c[:, None, None]
        pc2d = self.pspace.cell_to_dof()
        cc2d = self.cspace.cell_to_dof()
        pgdof = self.pspace.number_of_global_dofs()
        cgdof = self.cspace.number_of_global_dofs()
        I = np.broadcast_to(pc2d, shape=cc2d.shape)
        J = cc2d
        self.PU0 = csr_matrix((val[..., 0].flat, (I.flat, J.flat)),
                              shape=(pgdof, cgdof))
        self.PU1 = csr_matrix((val[..., 1].flat, (I.flat, J.flat)),
                              shape=(pgdof, cgdof))

        # 线弹性矩阵的右端向量
        sigma0 = self.pspace.function()
        sigma0[:] = self.model.rock['initial stress']
        self.FU = np.zeros(2 * cgdof, dtype=np.float64)
        self.FU[:cgdof] -= self.p @ self.PU0
        self.FU[cgdof:] -= self.p @ self.PU1

        # 初始应力和等效应力项
        self.FU[:cgdof] -= sigma0 @ self.PU0
        self.FU[cgdof:] -= sigma0 @ self.PU1

        # vtk 文件输出
        node, cell, cellType, NC = self.mesh.to_vtk()
        self.points = vtk.vtkPoints()
        self.points.SetData(vnp.numpy_to_vtk(node))
        self.cells = vtk.vtkCellArray()
        self.cells.SetCells(NC, vnp.numpy_to_vtkIdTypeArray(cell))
        self.cellType = cellType
コード例 #25
0
import numpy as np
from scipy.sparse.linalg import spsolve
import matplotlib.pyplot as plt

from fealpy.pde.poisson_2d import CosCosData
from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.boundarycondition import BoundaryCondition


pde = CosCosData()

print('test')
mesh = pde.init_mesh(n=7, meshtype='tri')
print('test')
space = LagrangeFiniteElementSpace(mesh, p=1)
print('test')

A = space.stiff_matrix()
print('test')
b = space.source_vector(pde.source)
print('test')
uh = space.function()
bc = BoundaryCondition(space, robin=pde.robin)
bc.apply_robin_bc(A, b)
uh[:] = spsolve(A, b).reshape(-1)
error = space.integralalg.L2_error(pde.solution, uh)
print(error)

fig = plt.figure()
axes = fig.gca()
コード例 #26
0
ファイル: pde solve.py プロジェクト: Firepkwater/ANN_relu
from fealpy.boundarycondition import DirichletBC
from fealpy.tools.show import showmultirate, show_error_table

p = 1
n = 10
pde = MyPde()
domain = pde.domain()
mf = MeshFactory()
mesh = mf.boxmesh2d(domain, nx=n, ny=n, meshtype='tri')
NDof = np.zeros(4)
Ndof = np.zeros(4, dtype=mesh.itype)
errorMatrix = np.zeros((2, 4), dtype=mesh.ftype)
errorType = ['$||u - u_h||_0$', '$||\\nabla u - \\nabla u_h||_0$']
for i in range(4):
    print('Step:', i)
    space = LagrangeFiniteElementSpace(mesh, p=p, q=4)
    NDof[i] = space.number_of_global_dofs()
    uh = space.function()  #返回一个有限元函数,初始自由度值是 0
    A = space.stiff_matrix()
    M = space.mass_matrix()
    F = space.source_vector(pde.source)

    bc = DirichletBC(space, pde.dirichlet, threshold=pde)
    A, F = bc.apply(A, F, uh)
    uh[:] = spsolve(A, F)

    errorMatrix[0, i] = space.integralalg.L2_error(pde.solution, uh.value)
    errorMatrix[1, i] = space.integralalg.L2_error(pde.gradient, uh.grad_value)

    if i < 3:
        mesh.uniform_refine()
コード例 #27
0
if d == 2:
    from fealpy.pde.poisson_2d import CosCosData as PDE
elif d == 3:
    from fealpy.pde.poisson_3d import CosCosCosData as PDE

pde = PDE()
mesh = pde.init_mesh(n=3)

errorType = [
    '$|| u - u_h||_{\Omega,0}$', '$||\\nabla u - \\nabla u_h||_{\Omega, 0}$'
]
errorMatrix = np.zeros((2, maxit), dtype=np.float)
NDof = np.zeros(maxit, dtype=np.float)

for i in range(maxit):
    space = LagrangeFiniteElementSpace(mesh, p=p)

    NDof[i] = space.number_of_global_dofs()
    bc = DirichletBC(space, pde.dirichlet)

    uh = space.function()
    A = space.stiff_matrix()
    F = space.source_vector(pde.source)

    A, F = bc.apply(A, F, uh)

    #uh[:] = spsolve(A, F).reshape(-1)

    ml = pyamg.ruge_stuben_solver(A)
    uh[:] = ml.solve(F, tol=1e-12, accel='cg').reshape(-1)
コード例 #28
0
from fealpy.solver.fast_solver import LinearElasticityLFEMFastSolver_1

n = int(sys.argv[1])
lam = float(sys.argv[2])
mu = float(sys.argv[3])
stype = sys.argv[4]

pde = PolyModel3d(lam=lam, mu=mu) 

mesh = pde.init_mesh(n=n)

NN = mesh.number_of_nodes()
print("NN:", 3*NN)

space = LagrangeFiniteElementSpace(mesh, p=1)

bc = DirichletBC(space, pde.dirichlet)

uh = space.function(dim=3)
A = space.linear_elasticity_matrix(pde.lam, pde.mu, q=1)
F = space.source_vector(pde.source, dim=3)
A, F = bc.apply(A, F, uh)

I = space.rigid_motion_matrix()
S = space.stiff_matrix(2*pde.mu)
S = bc.apply_on_matrix(S)

solver = LinearElasticityLFEMFastSolver_1(A, S, I, stype=stype, drop_tol=1e-6,
        fill_factor=40) 
コード例 #29
0
ファイル: pde_example.py プロジェクト: mfkiwl/fealpy
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from fealpy.pde.poisson_2d import CosCosData as PDE
from fealpy.functionspace import LagrangeFiniteElementSpace

pde = PDE()

mesh = pde.init_mesh(n=4, meshtype='tri')

space = LagrangeFiniteElementSpace(mesh, 2)

uI = space.interpolation(pde.solution)  # 有限元空间的函数,同地它也是一个数组

bc = np.array([1 / 3, 1 / 3, 1 / 3], dtype=np.float64)
val = uI(bc)  # (NC, )
val = uI.value(bc)  # (NC, )
gval = uI.grad_value(bc)  #(NC, GD)

L2error = space.integralalg.error(pde.solution, uI, q=5, power=2)
H1error = space.integralalg.error(pde.gradient, uI.grad_value, q=5, power=2)
print(H1error)

fig = plt.figure()
axes = fig.add_subplot(projection='3d')
uI.add_plot(axes, cmap='rainbow')
plt.show()
コード例 #30
0
    def alg_3_2(self, maxit=None):
        """
        1. 自适应求解 -\Delta u = 1。
        1. 在最细网格上求最小特征值和特征向量。

        refine maxit, picard: 1
        """
        print("算法 3.2")
        if maxit is None:
            maxit = self.maxit

        start = timer()
        if self.step == 0:
            idx = []
        else:
            idx = list(range(0, self.maxit, self.step)) + [self.maxit - 1]

        mesh = self.pde.init_mesh(n=self.numrefine)
        GD = mesh.geo_dimension()
        if (self.step > 0) and (0 in idx):
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_2_0_' + str(NN) + '.pdf')
            plt.close()
            self.savemesh(mesh,
                          self.resultdir + 'mesh_3_2_0_' + str(NN) + '.mat')

        final = 0
        integrator = mesh.integrator(self.q)
        for i in range(maxit):
            space = LagrangeFiniteElementSpace(mesh, 1)
            gdof = space.number_of_global_dofs()

            A = self.get_stiff_matrix(space)
            M = self.get_mass_matrix(space)
            b = M @ np.ones(gdof)

            isFreeDof = ~(space.boundary_dof())
            A = A[isFreeDof, :][:, isFreeDof].tocsr()
            M = M[isFreeDof, :][:, isFreeDof].tocsr()

            uh = space.function()
            if self.matlab is False:
                uh[isFreeDof] = self.psolve(A, b[isFreeDof], M)
            else:
                uh[isFreeDof] = self.msolve(A, b[isFreeDof])

            eta = self.residual_estimate(uh)
            markedCell = mark(eta, self.theta)
            IM = mesh.bisect(markedCell, returnim=True)
            NN = mesh.number_of_nodes()
            print(i + 1, "refine :", NN)
            if (self.step > 0) and (i in idx):
                fig = plt.figure()
                fig.set_facecolor('white')
                if GD == 2:
                    axes = fig.gca()
                else:
                    axes = Axes3D(fig)
                mesh.add_plot(axes, cellcolor='w')
                fig.savefig(self.resultdir + 'mesh_3_2_' + str(i + 1) + '_' +
                            str(NN) + '.pdf')
                plt.close()
                self.savemesh(
                    mesh, self.resultdir + 'mesh_3_2_' + str(i + 1) + '_' +
                    str(NN) + '.mat')
            final = i + 1
            if NN > self.maxdof:
                break

        if self.step > 0:
            NN = mesh.number_of_nodes()
            fig = plt.figure()
            fig.set_facecolor('white')
            if GD == 2:
                axes = fig.gca()
            else:
                axes = Axes3D(fig)
            mesh.add_plot(axes, cellcolor='w')
            fig.savefig(self.resultdir + 'mesh_3_2_' + str(final) + '_' +
                        str(NN) + '.pdf')
            plt.close()
            self.savemesh(
                mesh, self.resultdir + 'mesh_3_2_' + str(final) + '_' +
                str(NN) + '.mat')

        space = LagrangeFiniteElementSpace(mesh, 1)
        gdof = space.number_of_global_dofs()

        A = self.get_stiff_matrix(space)
        M = self.get_mass_matrix(space)
        isFreeDof = ~(space.boundary_dof())
        A = A[isFreeDof, :][:, isFreeDof].tocsr()
        M = M[isFreeDof, :][:, isFreeDof].tocsr()

        if self.multieigs is True:
            self.A = A
            self.M = M
            self.ml = pyamg.ruge_stuben_solver(self.A)
            self.eigs()
        else:
            uh = IM @ uh
            if self.matlab is False:
                uh[isFreeDof], d = self.eig(A, M)
            else:
                uh[isFreeDof], d = self.meigs(A, M)
            print("smallest eigns:", d)
            return space.function(array=uh)
        end = timer()
        print("with time: ", end - start)