欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Python中的fealpy包求解泊松方程

程序员文章站 2022-03-27 20:42:22
针对特定的温度场模型利用fealpy进行泊松方程求解问题重述:在10*10的网格中:泊松方程:△u=∂2u∂x2+∂2u∂y2=f\bigtriangleup u = \frac{\partial^2u}{\partial x^2} +\frac{\partial^2u}{\partial y^2} =f△u=∂x2∂2u​+∂y2∂2u​=f边界条件:恒温条件(散热口):u=T0=298Ku = T_{0} =298Ku=T0​=298K绝热条件(另外三边):∂u∂n=0\frac{\...

针对特定的温度场模型利用 f e a l p y fealpy fealpy包求解泊松方程

问题重述:

在10*10的网格中:
泊松方程:
△ u = ∂ 2 u ∂ x 2 + ∂ 2 u ∂ y 2 = f \bigtriangleup u = \frac{\partial^2u}{\partial x^2} +\frac{\partial^2u}{\partial y^2} =f u=x22u+y22u=f

边界条件:

  • 恒温条件(散热口): u = T 0 = 298 K u = T_{0} =298K u=T0=298K
  • 绝热条件(其余边): ∂ u ∂ n = 0 \frac{\partial u}{\partial n}=0 nu=0

已知 f = 2 × 1 0 6 [ ( x − 0.1 2 ) 2 + ( y − 0.1 2 ) 2 ] − 10000 f = 2\times 10^6[(x-\frac{0.1}{2})^2 +(y-\frac{0.1}{2})^2 ]-10000 f=2×106[(x20.1)2+(y20.1)2]10000

简化问题:将散热口所在的 y = 0 y=0 y=0边定义为 D i r i c h l e t Dirichlet Dirichlet边界条件

  • 定义问题:
    { △ u = f i n Ω u = g D o n Γ D ∂ u ∂ n = 0 o n Γ N \left\{\begin{matrix} \triangle \begin{matrix} u=f & in\Omega \end{matrix} \\ \begin{matrix} u=g_{D} & on\Gamma _{D} \end{matrix} \\ \begin{matrix} \frac{\partial u}{\partial n} =0 & on\Gamma _{N} \end{matrix} \end{matrix}\right. u=finΩu=gDonΓDnu=0onΓN
    求解区域:
    Ω = [ 0 , 0.1 ] × [ 0 , 0.1 ] \Omega = \left [ 0,0.1 \right ] \times \left [ 0,0.1 \right ] Ω=[0,0.1]×[0,0.1]
    边界条件:
  1. 在y=0上: D i r i c h l e t Dirichlet Dirichlet边界条件
  2. 在y=0.1,x=0,x=0.1: N e u m a n n Neumann Neumann边界条件
  • 积分弱形式:
    在方程两边同时乘以测试函数
    v ∈ H 1 ( Ω ) , v ∣ Γ D = 0 \begin{matrix} v\in H^{1}(\Omega ), &v|_{\Gamma _{D} }=0 \end{matrix} vH1(Ω),vΓD=0
    并在 Ω \Omega Ω上积分:
    ∫ Ω f v d x d y = ∫ Ω △ u v \int\limits_{\Omega } fvdxdy=\int\limits_{\Omega }\bigtriangleup uv Ωfvdxdy=Ωuv

  • 分部积分:
    使用分部积分公式(格林公式)可得
    ∫ Ω ∇ u ⋅ ∇ v d x d y = ∫ Ω △ u ⋅ n v d x d y + ∫ Ω f v d x d y \int\limits_{\Omega } \nabla u ·\nabla vdxdy= \int\limits_{\Omega }\bigtriangleup u·nvdxdy + \int\limits_{\Omega }fvdxdy Ωuvdxdy=Ωunvdxdy+Ωfvdxdy

    将其在 Ω \Omega Ω的边界上表示就有:
    ∫ Ω ∇ u ⋅ ∇ v d x d y = ∫ Ω f v d x d y + ∫ Γ D △ u ⋅ n v d l + ∫ Γ N △ u ⋅ n v d l \int\limits_{\Omega } \nabla u· \nabla vdxdy= \int\limits_{\Omega } fvdxdy + \int\limits_{\Gamma _{D}}\bigtriangleup u·nvdl + \int\limits_{\Gamma _{N}}\bigtriangleup u·nvdl Ωuvdxdy=Ωfvdxdy+ΓDunvdl+ΓNunvdl

    利用边界条件:

  • v ∣ Γ D = 0 v|_{\Gamma_{D}}=0 vΓD=0

  • ∂ u ∂ n ∣ Γ N = 0 \frac{\partial u}{\partial n}\mid _{\Gamma_{N} } =0 nuΓN=0

    可以得到:
    ∫ Ω ∇ u ⋅ ∇ v d x d y = ∫ Ω f v d x d y + ∫ Γ N g N v d l \int\limits_{\Omega } \nabla u· \nabla vdxdy= \int\limits_{\Omega } fvdxdy +\int\limits_{\Gamma _{N}}g_{N} vdl Ωuvdxdy=Ωfvdxdy+ΓNgNvdl

  • 代数系统:
    离散后用代数系统表达可得:
    A ⋅ u = b + b N A·u=b+b_{N} Au=b+bN
    其中:
    A = ∫ Ω ∇ u h ⋅ ∇ v h d x d y = Σ e ∈ Γ ∫ e ∇ u h ⋅ ∇ v h d x d y A = \int\limits_{\Omega } \nabla u^{h} ·\nabla v^{h} dxdy= \underset{e\in \Gamma }{\Sigma } \int\limits_{e} \nabla u^{h} ·\nabla v^{h} dxdy A=Ωuhvhdxdy=eΓΣeuhvhdxdy
    b = ∫ Ω f ⋅ v h d x d y = Σ e ∈ Γ ∫ e f ⋅ v h d x d y b = \int\limits_{\Omega } f· v^{h} dxdy= \underset{e\in \Gamma }{\Sigma } \int\limits_{e} f· v^{h} dxdy b=Ωfvhdxdy=eΓΣefvhdxdy
    b N = ∫ Γ N g N ⋅ v h d x d y = Σ e ∈ Γ ∫ e d g e g N ⋅ v h d x d y b_{N} = \int\limits_{\Gamma _{N} } g_{N}· v^{h} dxdy= \underset{e\in \Gamma }{\Sigma } \int\limits_{edge} g_{N}· v^{h} dxdy bN=ΓNgNvhdxdy=eΓΣedgegNvhdxdy

下面是上述方程的程序求解过程,使用 fealpy 有限元程序包.

导入必要的包

from fealpy.functionspace import LagrangeFiniteElementSpace
from fealpy.mesh import MeshFactory
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from scipy.sparse.linalg import spsolve
from fealpy.boundarycondition import DirichletBC, NeumannBC

from fealpy.tools.show import showmultirate, show_error_table 

使用python中的类来定义PDE

import numpy as np
from fealpy.decorator import cartesian,barycentric
class possion_solution:
    
    def __init__(self):
        pass
    
    # 定义网格区域大小
    @property
    def domain(self):   
        return np.array([0, 0.1, 0, 0.1])
        
    # 原项 f(x,y),泊松方程的右边
    @cartesian
    def source(self, p):  
        x = p[..., 0]
        y = p[..., 1]
        pi = np.pi
        val = 2*pi*pi*np.cos(pi*x)*np.cos(pi*y)
        return val
    
    # 精确解u(x,y),泊松方程的左边
    @cartesian
    def exact_solution(self, p):
        x = p[..., 0]
        y = p[..., 1]
        pi = np.pi
        val = np.cos(pi*x)*np.cos(pi*y)
        return val
        
    # 真解的梯度 
    @cartesian
    def gradient(self, p):  
        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
        
    # 梯度的负方向
    @cartesian 
    def flux(self, p):
        return -self.gradient(p)
        
    #定义边界条件
    @cartesian
    def is_dirichlet_boundary(self, p):
        y = p[..., 1]
        return (y == 0.0) 
    
    @cartesian
    def dirichlet(self, p):
        return self.exact_solution(p)
    
    @cartesian
    def is_neumann_boundary(self, p):
        x = p[..., 0]
        y = p[..., 1]
        return (x == 0.0)|(x == 0.1)|(y == 0.1)
        
    @cartesian
    def neumann(self, p, n):
        grad = self.gradient(p)
        val = np.sum(grad * n, axis = -1)
        return val 

网格生成并可视化

import numpy as np
from fealpy.mesh import MeshFactory
import matplotlib.pyplot as plt
%matplotlib inline

# 加载pde模型
pde = possion_solution()

# 加载网格
mf = MeshFactory()
box = pde.domain
mesh = mf.boxmesh2d(box, nx = 10, ny = 10, meshtype = 'quad')

# 画图
figure = plt.figure()
axes = figure.gca()
mesh.add_plot(axes)
#mesh.find_node(axes, showindex = True)
#mesh.find_edge(axes, showindex = True)
mesh.find_cell(axes, showindex = True)

#获取单元,网格,节点信息
nodes = mesh.entity('node')
cells = mesh.entity('cell')
edges = mesh.entity('edge') 

形成有限元空间

import sys
def possion_solution_solver(pde, n, refine, order): 
    """
    Input:
        @pde: 定义偏微分方程
        @n: 初始网格剖分段数
        @refine: 网格加密的最大次数(迭代求解次数)
        @order: 有限元多项式次数
    Output: None
    """
    mf = MeshFactory()
    mesh = mf.boxmesh2d(pde.domain, nx = n, ny = n, meshtype = 'tri')
    
    number_of_dofs = np.zeros(refine, dtype = mesh.itype)
    # 建立空数组,目的把每组的*度个数存下来
    error_matrix = np.zeros((2, refine), dtype = mesh.ftype)
    error_type = ['$||u - u^{h}||_{0}$', '$||\\nabla u - \\nabla u^{h}||_{0}$']
    
    for i in range(refine):
        femspace = LagrangeFiniteElementSpace(mesh, p = order)
        number_of_dofs[i] = femspace.number_of_global_dofs()
        uh = femspace.function() 
        # 返回一个有限元函数,初始*度值全为 0
        
        # A·u = b + b_n
        
        A = femspace.stiff_matrix()
        F = femspace.source_vector(pde.source)
        # 先计算纽曼
        bc = NeumannBC(femspace, pde.neumann, threshold = pde.is_neumann_boundary)
        F = bc.apply(F)
        
        #最后计算Dirichlet
        bc = DirichletBC(femspace, pde.dirichlet, threshold = pde.is_dirichlet_boundary)
        A, F = bc.apply(A, F, uh)
        
        uh[:] = spsolve(A, F)
        
        #计算误差
        error_matrix[0, i] = femspace.integralalg.L2_error(pde.exact_solution, uh.value)
        error_matrix[1, i] = femspace.integralalg.L2_error(pde.gradient, uh.grad_value)
        
        print('插值点: ', femspace.interpolation_points().shape)
        print('*度数(NDof): ', number_of_dofs[i])
        nodes = mesh.entity('node')
        print('节点数: ', nodes.shape)
        if i < refine - 1:
            mesh.uniform_refine()
    
    fig = plt.figure()
    axes = fig.gca(projection = '3d')
    uh.add_plot(axes, cmap = 'rainbow')
    showmultirate(plt, 0, number_of_dofs, error_matrix, error_type, propsize = 20)
    show_error_table(number_of_dofs, error_type, error_matrix, f='e', pre=4, sep=' & ', out=sys.stdout, end='\n')
    plt.show() 

使用线性元求解

possion_solution_solver(possion_solution(), 10, 5, 1) 

使用二次元求解

possion_solution_solver(possion_solution(), 10, 5, 2) 

本文地址:https://blog.csdn.net/cium123/article/details/109004730