getfem++ 热弹性-电耦合算例 Python 实现

网上似乎没有好的译文,自己翻译了一下。原文戳这里

问题设定

考虑一个厚度为 ε \varepsilon ε 的二维平板,受到外力、电势和加热作用。令 Ω ⊂ I R 2 \Omega \subset \rm I\hspace{-0.15em}R^2 ΩIR2为平板计算域,记 θ : Ω → I R \theta : \Omega \rightarrow \rm I\hspace{-0.15em}R θ:ΩIR 为温度场(摄氏度), V : Ω → I R V : \Omega \rightarrow \rm I\hspace{-0.15em}R V:ΩIR 为电势场, u : Ω → I R u : \Omega \rightarrow \rm I\hspace{-0.15em}R u:ΩIR 为薄板的位移场。

在这里插入图片描述

热问题

假设板的侧面(上下左右)是绝热的,前后表面与空气存在热交换,热传导系数为 D D D。温度方程和边界条件为
{ − div ( ε κ ( ∇ θ ) ) + 2 D ( θ − T 0 ) − ε σ ∣ ∇ V ∣ 2 = 0    in  Ω , κ ∇ θ ⋅ n = 0    on  ∂ Ω , \left\{\begin{array}{l} -\text{div}(\varepsilon\kappa(\nabla \theta)) + 2D(\theta - T_0) - \varepsilon\sigma|\nabla V|^2 = 0 ~~ \text{ in } \Omega, \\ \kappa\nabla \theta \cdot n = 0 ~~ \text{ on } \partial \Omega, \end{array} \right. {div(εκ(θ))+2D(θT0)εσV2=0   in Ω,κθn=0   on Ω,
其中热导率由 κ \kappa κ 设定, T 0 T_0 T0 是空气温度, n n n 是外法向量。 σ ∣ ∇ V ∣ 2 \sigma|\nabla V|^2 σV2 是与焦耳热对应的非线性耦合项, σ \sigma σ 是电导率。

电势问题

假设右侧面和左侧面之间存在一个电势差 0.1 V 0.1V 0.1V。其他表面为电绝缘。电势方程为
{ − div ( ε σ ( ∇ V ) ) = 0    in  Ω , σ ∇ V ⋅ n = 0    on the top an bottom lateral faces , V = 0    on the right lateral face , V = 0.1    on the left lateral face , \left\{\begin{array}{l} -\text{div}(\varepsilon\sigma(\nabla V)) = 0 ~~ \text{ in } \Omega, \\ \sigma\nabla V \cdot n = 0 ~~ \text{ on the top an bottom lateral faces}, \\ V = 0 ~~ \text{ on the right lateral face}, \\ V = 0.1 ~~ \text{ on the left lateral face}, \\ \end{array} \right. div(εσ(V))=0   in Ω,σVn=0   on the top an bottom lateral faces,V=0   on the right lateral face,V=0.1   on the left lateral face,
其中电导率依赖于温度,即
σ = 1 ρ 0 ( 1 + α ( θ − T 0 ) ) , \sigma = \dfrac{1}{\rho_0(1+\alpha(\theta - T_0))}, σ=ρ0(1+α(θT0))1,
其中 ρ 0 \rho_0 ρ0 α \alpha α 均为电阻温度系数。

变形问题

考虑平板在右侧面力和热的影响下发生薄壁小变形。线弹性位移方程为
{ − div ( σ ˉ ( u ) ) = 0    in  Ω , σ ˉ   n = 0    on the top an bottom lateral faces , σ ˉ   n = F    on the right lateral face , u = 0    on the left lateral face , \left\{\begin{array}{l} -\text{div}(\bar{\sigma}(u)) = 0 ~~ \text{ in } \Omega, \\ \bar{\sigma}\ n = 0 ~~ \text{ on the top an bottom lateral faces}, \\ \bar{\sigma}\ n = F ~~ \text{ on the right lateral face}, \\ u = 0 ~~ \text{ on the left lateral face}, \end{array} \right. div(σˉ(u))=0   in Ω,σˉ n=0   on the top an bottom lateral faces,σˉ n=F   on the right lateral face,u=0   on the left lateral face,
其中 F F F 是右侧面上的表面力, σ ˉ \bar{\sigma} σˉ 是柯西应力张量,定义为
σ ˉ ( u ) = λ ∗ div ( u ) I + 2 μ ε ˉ ( u ) + β ( T 0 − θ ) I , \bar{\sigma}(u) = \lambda^* \text{div}(u) I + 2\mu \bar{\varepsilon}(u) + \beta(T_0-\theta) I, σˉ(u)=λdiv(u)I+2μεˉ(u)+β(T0θ)I,
线性应变张量为
ε ˉ ( u ) = ( ∇ u + ( ∇ u ) T ) / 2 \bar{\varepsilon}(u) = (\nabla u + (\nabla u)^T)/2 εˉ(u)=(u+(u)T)/2
λ ∗ \lambda^* λ μ \mu μ 为拉梅系数。 β ( T 0 − θ ) I \beta(T_0-\theta) I β(T0θ)I 对应于热膨胀, β = α t h E / ( 1 − 2 ν ) \beta = \alpha_{th} E/(1-2\nu) β=αthE/(12ν), 其中 α t h \alpha_{th} αth 为热膨胀系数。

弱形式

基于伽辽金法的弱形式决定了我们要在代码中添加哪些项。该问题的弱形式为
Find  θ , V , u  with  V = 0.1 , u = 0  on the left face , V = 0  on the right face , ∫ Ω ε κ ∇ θ ⋅ ∇ δ θ + 2 D θ δ θ d Ω = ∫ Ω ( 2 D T 0 + ε σ ∣ ∇ V ∣ 2 ) δ θ d Ω     for all  δ θ , ∫ Ω ε σ ∇ V ⋅ ∇ δ V = 0 d Ω     for all  δ V  satisfying  δ V = 0  on the left and right faces , ∫ Ω σ ˉ ( u ) : ε ˉ ( δ u ) d Ω = ∫ Γ N F ⋅ δ u d Γ     for all  δ u  satisfying  δ u = 0  on the left face , \text{Find } \theta, V, u \text{ with } V = 0.1, u = 0 \text{ on the left face}, V = 0 \text{ on the right face}, \\ \int_{\Omega} \varepsilon\kappa\nabla\theta\cdot\nabla\delta_{\theta} + 2D\theta\delta_{\theta}d\Omega = \int_{\Omega} (2DT_0 + \varepsilon\sigma|\nabla V|^2)\delta_{\theta} d\Omega ~~~\text{ for all } \delta_{\theta}, \\ \int_{\Omega} \varepsilon\sigma\nabla V\cdot\nabla\delta_V = 0 d\Omega ~~~ \text{ for all } \delta_V \text{ satisfying } \delta_V = 0 \text{ on the left and right faces}, \\ \int_{\Omega} \bar{\sigma}(u):\bar{\varepsilon}(\delta_u)d\Omega = \int_{\Gamma_N} F\cdot \delta_u d\Gamma ~~~ \text{ for all } \delta_{u} \text{ satisfying } \delta_u = 0 \text{ on the left face}, Find θ,V,u with V=0.1,u=0 on the left face,V=0 on the right face,Ωεκθδθ+2DθδθdΩ=Ω(2DT0+εσV2)δθdΩ    for all δθ,ΩεσVδV=0dΩ    for all δV satisfying δV=0 on the left and right faces,Ωσˉ(u):εˉ(δu)dΩ=ΓNFδudΓ    for all δu satisfying δu=0 on the left face,
其中 δ θ , δ V , δ u \delta_{\theta}, \delta_V, \delta_u δθ,δV,δu 分别代表 θ , V , u \theta, V, u θ,V,u 的试函数。 Γ N \Gamma_N ΓN 表示施加表面力的右侧边界。

Python 实现

  1. 导入

    import getfem as gf
    import numpy as np
    
  2. 模型参数

    epsilon = 1.; E = 21E6; nu = 0.3;
    clambda = E*nu/((1+nu)*(1-2*nu));
    cmu = E/(2*(1+nu));
    clambdastar = 2*clambda*cmu/(clambda+2*cmu);
    F = 100E2; kappa = 4.; D = 10;
    air_temp = 20; alpha_th = 16.6E-6;
    T0 = 20; rho_0 = 1.754E-8;
    alpha = 0.0039;
    
    h = 2; elements_degree = 2;
    
  3. 网格生成
    getfem++ 提供较弱的网格工具,因此此处采用自带工具。一般建议借助更专业的外部软件导入网格。以下代码中 h 代表网格尺寸,网格的 degree 等于2(代表单元的插值多项式次数)。

    mo1 = gf.MesherObject('rectangle', [0., 0.], [100., 25.])
    mo2 = gf.MesherObject('ball', [25., 12.5], 8.)
    mo3 = gf.MesherObject('ball', [50., 12.5], 8.)
    mo4 = gf.MesherObject('ball', [75., 12.5], 8.)
    mo5 = gf.MesherObject('union', mo2, mo3, mo4)
    mo  = gf.MesherObject('set minus', mo1, mo5)
    
    mesh = gf.Mesh('generate', mo, h, 2)
    
  4. 边界选择

    由于边界的不同部分具有不同的边界条件,我们需要将边界的不同部分进行编号(孔洞边界上假设为绝热绝缘且应力自由)。我们要选择一些网格单元的面(face)并定义为 region,编号为1,2,3,4,依次对应右、左、上、下边界。这些边界编号将用于构建模型的块 (brick)。

    fb1 = mesh.outer_faces_in_box([1., 1.], [99., 24.])
    fb2 = mesh.outer_faces_with_direction([ 1., 0.], 0.01)
    fb3 = mesh.outer_faces_with_direction([-1., 0.], 0.01)
    fb4 = mesh.outer_faces_with_direction([0.,  1.], 0.01)
    fb5 = mesh.outer_faces_with_direction([0., -1.], 0.01)
    
    RIGHT_BOUND=1; LEFT_BOUND=2; TOP_BOUND=3; BOTTOM_BOUND=4; HOLE_BOUND=5;
    
    mesh.set_region( RIGHT_BOUND, fb2)
    mesh.set_region(  LEFT_BOUND, fb3)
    mesh.set_region(   TOP_BOUND, fb4)
    mesh.set_region(BOTTOM_BOUND, fb5)
    mesh.set_region(  HOLE_BOUND, fb1)
    mesh.region_subtract( RIGHT_BOUND, HOLE_BOUND)
    mesh.region_subtract(  LEFT_BOUND, HOLE_BOUND)
    mesh.region_subtract(   TOP_BOUND, HOLE_BOUND)
    mesh.region_subtract(BOTTOM_BOUND, HOLE_BOUND)
    

    注意:上面这段代码相比于 demo 代码,少了孔洞边界的定义。但demo 代码中的 outer_faces_in_ball 函数会报错称不存在(文档里可查到,原因不明)。可以把那部分代码改为:

    rh = 8 + 0.01*h
    fb6 = mesh.outer_faces_in_box([25-rh, 12.5-rh], [25+rh, 12.5+rh]) # Left hole boundary
    fb7 = mesh.outer_faces_in_box([50-rh, 12.5-rh], [50+rh, 12.5+rh]) # Center hole boundary
    fb8 = mesh.outer_faces_in_box([75-rh, 12.5-rh], [75+rh, 12.5+rh]) # Right hole boundary

    或者干脆把孔洞边界都注释掉。

  5. 网格绘制

    mesh.export_to_vtk('mesh.vtk');
    
  6. 有限元和积分方法定义
    getfem++的所谓“Fem (finite element method)”其实是指单元类型,而所谓“MeshFem (mesh of finite element method)”则是指由指定类型的单元组成的离散网格。以下将采取后一种表述以防混淆。现在我们选择经典单元(即连续拉格朗日单元),且单元阶数(degree)等于2(代表二阶等参元)。(这里有一份可选择的有限元列表。最常用的就是经典有限元。)我们定义三个离散网格。第一个向量离散网格mfu用于近似位移场。第二个标量离散网格mft用于近似温度场和电势场。原则上一个离散网格允许被用于近似任意个变量。第三个是经典不连续标量离散网格(即间断标量拉格朗日离散网格),可被用于插值某个变量的导数,例如插值Mises应力。最后定义一个积分方法。getfem++没有默认积分方法,所以这一步是必须的。积分阶数必须足够高以保证积分的方便。这里令阶数等于单元阶数平方就够了。

    mfu = gf.MeshFem(mesh, 2)
    mfu.set_classical_fem(elements_degree)
    mft = gf.MeshFem(mesh, 1)
    mft.set_classical_fem(elements_degree)
    mfvm = gf.MeshFem(mesh, 1)
    mfvm.set_classical_discontinuous_fem(elements_degree)
    mim = gf.MeshIm(mesh, elements_degree*2)
    
  7. 模型定义
    model 对象包含了模型的变量(unknowns)、数据 (data) 和所谓的块(model bricks)。块是弱形式中的一个项,可以是线性或非线性(注意这个线性与线弹性概念不是一回事,是指微分方程的线性。),用于一个或多个变量。real表示模型变量都是实数。

    md=gf.Model('real');
    md.add_fem_variable('u', mfu)
    md.add_fem_variable('theta', mft)
    md.add_fem_variable('V', mft)
    

    7.1 薄壁弹性变形问题

    我们使用预定义的add_isotropic_linearized_elasticity_brick构建一个块,它代表以下的项:
    ∫ Ω ( λ ∗ div ( u ) I + 2 μ ε ˉ ( u ) ) : ε ˉ ( δ u ) d x , \int_{\Omega} (\lambda^* \text{div}(u) I + 2\mu \bar{\varepsilon}(u)):\bar{\varepsilon}(\delta_u)dx, Ω(λdiv(u)I+2μεˉ(u)):εˉ(δu)dx,
    除了预定义方法,也可以用“通用弱形式语言(GWFL, generic weak form language)”自己定义每个块。 add_isotropic_linearized_elasticity_brick需要拉梅系数对应的数据(数据在 getfem++ 里称为 data,是定义在一个离散网格上的长度等于单元数量的数组,数组元素的形状与 MeshFem 变量一致。)。拉梅系数的数据可以是常数或非常数的数组。

    然后构建耦合项
    ∫ Ω ( β θ I ) : ε ˉ ( δ u ) d x , \int_{\Omega} (\beta\theta I) :\bar{\varepsilon}(\delta_u)dx, Ω(βθI):εˉ(δu)dx,
    由于没有预定义的块,所以我们用 GWFL 构建。该项为线性项,GWFL 构建方法为add_linear_term。GWFL 定义的表达式将会在高斯点上执行,并组装到总体矩阵中。

    最后用预定义方法add_Dirichlet_condition_with_multipliersadd_source_term_brick构建了狄利克雷边界条件块。关于狄利克雷边界条件的预定义方法有很多,详见这里add_initialized_data里的 initialized 代表该数据属于当前时间步(静力学只有一步)的起点,在该步的迭代中保持不变。

    md.add_initialized_data('cmu', [cmu])
    md.add_initialized_data('clambdastar', [clambdastar])
    md.add_initialized_data('T0', [T0])
    md.add_isotropic_linearized_elasticity_brick(mim, 'u', 'clambdastar', 'cmu')
    
    md.add_Dirichlet_condition_with_multipliers(mim, 'u', elements_degree-1, LEFT_BOUND)
    md.add_initialized_data('Fdata', [F*epsilon, 0])
    md.add_source_term_brick(mim, 'u', 'Fdata', RIGHT_BOUND)
    
    md.add_initialized_data('beta', [alpha_th*E/(1-2*nu)])
    md.add_linear_term(mim, 'beta*(T0-theta)*Div_Test_u')
    

    7.2 电势问题

    方法同上。

    sigmaeps = '(eps/(rho_0*(1+alpha*(theta-T0))))'
    md.add_initialized_data('eps', [epsilon])
    md.add_initialized_data('rho_0', [rho_0])
    md.add_initialized_data('alpha', [alpha])
    md.add_nonlinear_term(mim, sigmaeps+'*(Grad_V.Grad_Test_V)')
    md.add_Dirichlet_condition_with_multipliers(mim, 'V', elements_degree-1, RIGHT_BOUND)
    md.add_initialized_data('DdataV', [0.1])
    md.add_Dirichlet_condition_with_multipliers(mim, 'V', elements_degree-1, LEFT_BOUND, 'DdataV')
    

    7.3 热问题

    方法同上。

    md.add_initialized_data('kaeps', [kappa*epsilon])
    md.add_generic_elliptic_brick(mim, 'theta', 'kaeps')
    md.add_initialized_data('D2', [D*2])
    md.add_initialized_data('D2airt', [air_temp*D*2])
    md.add_mass_brick(mim, 'theta', 'D2')
    md.add_source_term_brick(mim, 'theta', 'D2airt')
    
    md.add_nonlinear_term(mim, '-'+sigmaeps+'*Norm_sqr(Grad_V)*Test_theta')
    
  8. model 求解

    8.1. 强耦合求解

    md.solve('max_res', 1E-9, 'max_iter', 100, 'noisy')
    

    由于耦合是非线性的,所以求解器用了牛顿迭代法,迭代了4次。

    8.2. 弱耦合求解

    也可以先求解热电问题再求解变形问题,这样就使得温度和电势与变形不同步了,所以称为弱耦合。这通过 disable_variableenable_variable 来实现。

    md.disable_variable('u')
    md.solve('max_res', 1E-9, 'max_iter', 100, 'noisy')
    md.enable_variable('u')
    md.disable_variable('theta')
    md.disable_variable('V')
    md.solve('max_res', 1E-9, 'max_iter', 100, 'noisy')
    
  9. 导出

    数据切片和导出详见这里

    U = md.variable('u')
    V = md.variable('V')
    THETA = md.variable('theta')
    VM = md.compute_isotropic_linearized_Von_Mises_or_Tresca('u', 'clambdastar', 'cmu', mfvm)
    CO = np.reshape(md.interpolation('-'+sigmaeps+'*Grad_V', mfvm), (2, mfvm.nbdof()), 'F')
    
    mfvm.export_to_vtk('displacement_with_von_mises.vtk', mfvm,
                      VM, 'Von Mises Stresses', mfu, U, 'Displacements')
    print ('You can view solutions with for instance:')
    print ('mayavi2 -d displacement_with_von_mises.vtk -f WarpVector -m Surface')
    mft.export_to_vtk('temperature.vtk', mft, THETA, 'Temperature')
    print ('mayavi2 -d temperature.vtk -f WarpScalar -m Surface')
    mft.export_to_vtk('electric_potential.vtk', mft, V, 'Electric potential')
    print ('mayavi2 -d electric_potential.vtk -f WarpScalar -m Surface')
    

    在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值