(七)、Fealpy 中的 PDE接口与实例

这一节, 我们来介绍一下 Fealpy 中的PDE接口。 打开 fealpy/fealpy/pde, 你可以看到大量的pde接口:
在这里插入图片描述
fealpy/example 中有很多求解的例子, 基本涵盖了 pde solver 等的东西,如下图:
在这里插入图片描述
因为作者的文档写的很清楚了, 故我这里只举一个例子来简单介绍一下:混合边界条件的poisson 方程求解
混合边界条件的方程如下:
在这里插入图片描述

# 构造一个二维有真解的例子,用 p 次有限元来求解, 画出误差阶, 输出误差表格
# -\Delta u + 3 u = f, in \Omega;
# u = gD  on \Gamma_D
# \partial u / \partial n = gN on  \Gamma_N
# \partial u / \partial n + u = gR on \Gamma_R
# 求解区域为 [0, 1]^2, 其中 $x = 0$ 是 Robin 边界条件;  x=1 是Neumann 边界条件, 其余为Dirichlet 边界条件,
# u(x,y) = x^2 + y^2 + cos(pi*x)cos(pi*y)

import numpy as np
from scipy.sparse.linalg import spsolve
from fealpy.mesh import MeshFactory
from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.boundarycondition import DirichletBC, NeumannBC, RobinBC
from fealpy.decorator import cartesian, barycentric
from fealpy.tools.show import showmultirate, show_error_table
import matplotlib.pyplot as plt
class Model:

    def __init__(self):
        pass

    def domain(self):
        return np.array([0, 1, 0, 1])

    @cartesian
    def solution(self, p):
        """
		The exact solution
        Parameters
        ---------
        p :

        Examples
        -------
        p = np.array([0, 1], dtype=np.float64)
        p = np.array([[0, 1], [0.5, 0.5]], dtype=np.float64)
        """
        x = p[..., 0]
        y = p[..., 1]
        pi = np.pi
        val = np.cos(pi * x) * np.cos(pi * y)
        return val  # val.shape == x.shape

    @cartesian
    def source(self, p):
        """
		The right hand side of convection-diffusion-reaction equation
        INPUT:
            p: array object,
        """
        x = p[..., 0]
        y = p[..., 1]
        pi = np.pi
        val = (2 * pi ** 2 + 3) * np.cos(pi * x) * np.cos(pi * y)
        return val

    @cartesian
    def gradient(self, p):
        """
		The gradient of the exact solution
        """
        x = p[..., 0]
        y = p[..., 1]
        pi = np.pi
        val = np.zeros(p.shape, dtype=np.float64)
        val[..., 0] = -pi * np.sin(pi * x) * np.cos(pi * y)
        val[..., 1] = -pi * np.cos(pi * x) * np.sin(pi * y)
        return val  # val.shape == p.shape

    @cartesian
    def reaction_coefficient(self, p):
        x = p[..., 0]
        y = p[..., 1]
        return 3

    @cartesian
    def dirichlet(self, p):
        return self.solution(p)

    @cartesian
    def neumann(self, p, n):
        """
        Neuman  boundary condition

        Parameters
        ----------

        p: (NQ, NE, 2)
        n: (NE, 2)

        grad*n : (NQ, NE, 2)
        """
        grad = self.gradient(p)  # (NQ, NE, 2)
        val = np.sum(grad*n, axis=-1)  # (NQ, NE)
        return val

    @cartesian
    def robin(self, p, n):
        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

    @cartesian
    def is_dirichlet_boundary(self, p):
        y = p[..., 1]
        return ( y == 1.0) | ( y == 0.0)

    @cartesian
    def is_neumann_boundary(self, p):
        x = p[..., 0]
        return x == 1.0

    @cartesian
    def is_robin_boundary(self, p):
        x = p[..., 0]
        return x == 0.0


# p = int(sys.argv[1])  # Lagrange 有限元多项式次数
# n = int(sys.argv[2])  # 初始网格剖分段数
# maxit = int(sys.argv[3])  # 网格加密最大次数

p = 2
n = 10
maxit = 4
pde = Model()
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()
    M = space.mass_matrix(c=pde.reaction_coefficient)
    F = space.source_vector(pde.source)
    A += M
    bc1 = NeumannBC(space, pde.neumann, threshold=pde.is_neumann_boundary)
    F = bc1.apply(F=F)
    bc2 = RobinBC(space, pde.robin, threshold=pde.is_robin_boundary)
    A, F = bc2.apply(A=A, F=F)
    bc = DirichletBC(space, pde.dirichlet, threshold=pde.is_dirichlet_boundary)
    A, F = bc.apply(A, F, uh)

    uh[:] = spsolve(A, F)

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

    if i < maxit - 1:
        mesh.uniform_refine()

# 函数解图像
uh.add_plot(plt, cmap='rainbow')

# 收敛阶图像
showmultirate(plt, 0, NDof, errorMatrix, errorType, propsize=10)

# 输出误差的 latex 表格
show_error_table(NDof, errorType, errorMatrix)
plt.show()

结果为
在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值