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)
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)
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,
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()
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)
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)
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)
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)
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))
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
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)
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]
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)
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)
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)
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
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
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)
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)
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
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()
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()
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)
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
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()
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()
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)
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)
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()
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)