【问题标题】:FiPy for charged particle flow带电粒子流的 FiPy
【发布时间】:2021-03-30 17:02:42
【问题描述】:

前提

我正在尝试解决一个set of coupled PDEs,它描述了使用 FiPy 具有不同扩散系数的带电粒子的扩散。最终目标是获得物质和电场的浓度分布。

几何是一个半径为 R 的无限长圆柱体。我想使用一个非均匀网格,在畴壁附近有更多点。

带电粒子从域的中心(左边界)扩散到域的壁(右边界)。这转化为左边界处的狄利克雷边界条件 (B.C.),其中物种浓度 = 0,以及 Neumann B.C.在右侧边界,物种通量为 0 以描述径向对称性。因为带电物质以不同的速率扩散,所以存在由空间电荷产生的电场。电场使较慢的物质加速,并使较快的物质减速,与场强成正比。

P 是带正电的物质浓度,N 是带负电的物质浓度。 E为空间电荷电场。

问题

我似乎无法从我的代码中得到一个合理的解决方案,我认为这可能与我如何将梯度/散度项转换为对流项有关:

from fipy import *
import scipy.constants as constant
from fipy.tools import numerix
import numpy as np

## Defining physical constants
pi = constant.pi
m_argon = 6.6335e-26 # kg
k_b = constant.k # J/K
e_0 = constant.epsilon_0 # F/m
q_e = constant.elementary_charge # C
m_e = constant.electron_mass # kg
planck = constant.h

def char_diff_length(L,R):
    """Characteristic diffusion length in a cylinder.
    Used for determining the ambipolar diffusion coefficient.
    ref: https://doi.org/10.6028/jres.095.035"""
    a = (pi/L)**2
    b = (2.405/R)**2
    c = (a+b)**(1/2)
    return c

def L_Debye(ne,Te):
    """Electron Debye screening length given in m.
    ne is in #/m3, Te is in K."""
    if ne < 3.3e-5:
        ne = 3.3e-5
    return (((e_0*k_b*Te)/(ne*q_e**2)))**(1/2)

## Setting system parameters
# Operation parameters
Pressure = 1.e5 # ambient pressure Pa
T_g = 400. # background gas temperature K
n_g = Pressure/k_b/T_g # gas number density #/m3
Q_std = 300. # standard volumetric flowrate in sccm
T_e_0 = 11. # plasma temperature ratio T_e/T_g here assumed to be T_e = 0.5 eV and T_g = 500 K
n_e_0 = 1.e20 # electron density in bulk plasma #/m3

# Geometric parameters
R_b = 1.e-3 # radius cylinder m
L = 1.e-1 # length of cylinder m

# Transport parameters
D_ion = 4.16e-6 #m2/s ion diffusion, obtained from https://doi.org/10.1007/s12127-020-00258-z
mu_ion = D_ion*q_e/k_b/T_g # ion electrical mobility using Einstein relation

D_e = 100.68122*D_ion #m2/s electron diffusion
mu_e = D_e*q_e/k_b/T_g # electron electrical mobility using Einstein relation

Lambda = char_diff_length(L,R_b)
debyelength_e = L_Debye(n_e_0,T_g)
gamma = (Lambda/debyelength_e)**2
delta = D_ion/D_e



def d_j(rb,n): #sets the desired spatial steps for mesh
    dj = np.zeros(n)
    for j in range(n):
        dj[j] = 2*rb*(1 - j/n)/n
    return dj

#Initializing mesh
dj = d_j(1.,100) # 100 points
mesh = CylindricalGrid1D(dr = dj)

#Declaring cell variables
N = CellVariable(mesh=mesh, value = 1., hasOld = True, name = "electron density")
P = CellVariable(mesh=mesh, value = 1., hasOld = True, name = "ion density")
H = CellVariable(mesh=mesh, value = 0., hasOld = True, name = "electric field")

#Setting boundary conditions
N.constrain(0.,mesh.facesRight) # electron density = 0 at walls
P.constrain(0.,mesh.facesRight)# ion density = 0 at walls

H.constrain(0.,mesh.facesLeft) # electric field = 0 in the center
N.faceGrad.constrain([0.],mesh.facesLeft) # flux of electron = 0 in the center
P.faceGrad.constrain([0.],mesh.facesLeft) # flux of ion = 0 in the center

if __name__ == '__main__':
    viewer = Viewer(vars=(P,N))
    viewer.plot()

eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta,var=P) 
                                - ConvectionTerm(coeff=[H.cellVolumeAverage,],var=P) 
                                - ConvectionTerm(coeff=[P.cellVolumeAverage,],var=H))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N) 
                                + (1/delta)*(ConvectionTerm(coeff=[H.cellVolumeAverage,],var=N)
                                            +ConvectionTerm(coeff=[N.cellVolumeAverage,],var=H)))
eqn3 = (TransientTerm(var=H) == gamma*(ConvectionTerm(coeff=[delta**2,],var=P) 
                                       - ConvectionTerm(coeff=[delta,],var=N) 
                                       - H*(delta*P.cellVolumeAverage + N.cellVolumeAverage)))
P.setValue(1.)
N.setValue(1.)
H.setValue(0.)
eqn1d = eqn1 & eqn2 & eqn3



timesteps = 1e-5
steps = 100
for i in range(steps):
    P.updateOld()
    N.updateOld()
    H.updateOld()
    res = 1e10
    sweep = 0
    while res > 1e-3 and sweep < 20:
        res = eqn1d.sweep(dt=timesteps)
        sweep += 1
    if __name__ == '__main__':
        viewer.plot()

【问题讨论】:

  • 欢迎来到Stack Overflow.!您的问题对于这个网站来说似乎太宽泛了。为了帮助您,我们需要一个可重现的数据集、生成错误/问题的最少代码、您得到什么以及您期望什么。阅读Where to StartMinimal Reproducible Example,然后编辑您的帖子。
  • 作为相关软件的作者,我不同意。这个问题提供了一个完整的示例以及对他们正在寻找的内容的充分描述。 @itprorh66:StackOverflow 因不受欢迎而享有当之无愧的声誉;把它关掉。
  • 你得到的错误是什么?什么是不合理的结果?
  • 这不是错误。求解器运行了,但该解决方案没有物理意义。

标签: python-3.x fipy


【解决方案1】:

电场是向量,而不是标量。

H = CellVariable(rank=1, mesh=mesh, value = 0., hasOld = True, name = "electric field")

更正应该可以更清楚地将术语转换为 FiPy:

没有理由在eq1eq2的最后一个任期内运行链式法则;它们已经是 FiPy ConvectionTerm 的规范形式。在链式规则之后,它们变成了,例如,,这两者都不是 FiPy 喜欢的形式。您可以将最后两个术语写为明确的来源,但您不应该这样做。

eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta, var=P) 
                                - ConvectionTerm(coeff=H, var=P))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N) 
                                + (1/delta)*ConvectionTerm(coeff=H, var=N))

我不太明白eq3。它看起来有点像连续性方程的积分?我在快速扫描您引用的Phelps paper 时看不到它。无论如何,它不是 FiPy 可以接受的形式。你可以写它,但它不会很好地解决。右边的术语不是ConvectionTerms,它们只是渐变。

如果您要允许电荷分离并担心德拜长度,我认为您应该求解泊松方程。你能分享这个方程的来源吗?我们也许可以把它做成 FiPy 更喜欢的形式。

【讨论】:

  • 您好乔纳森,感谢您的回复。我会听从您的建议,以保持条款链前规则。
【解决方案2】:

eq3 是修改后的泊松方程。我尝试遵循Freeman 概述的程序,其中对泊松方程执行时间导数以替换物种连续性方程。 Freeman 使用 Gear 包解决了这些方程,我只能假设它是 Fortran 上的一个包。我天真地跟着他的脚步走,因为我对数值方法不了解。

我将尝试使用标准形式的泊松方程再次求解。

编辑:我已将电场 H 更改为 1 阶张量,并修改了 eq3 并稍微更改了 gamma 的定义。其他一切都没有改变。

H = CellVariable(rank = 1, mesh=mesh, value = 0., hasOld = True, name = "electric field")

charlength = char_diff_length(L,R_b)
debyelength_e = L_Debye(n_e_0,T_g)
gamma = (debyelength_e/charlength)**2
delta = D_ion/D_e

eqn1 = (TransientTerm(var=P) == DiffusionTerm(coeff=delta,var=P) 
                                - ConvectionTerm(coeff=H,var=P))
eqn2 = (TransientTerm(var=N) == DiffusionTerm(var=N) 
                                + (1/delta)*ConvectionTerm(coeff=H,var=N))
eqn3 = (ConvectionTerm(coeff = gamma/delta, var=H) == ImplicitSourceTerm(var=P) 
                                - ImplicitSourceTerm(var=N))
P.setValue(1.)
N.setValue(1.)
H.setValue(0.)
eqn1d = eqn1 & eqn2 & eqn3

timesteps = 1e-8
steps = 100
for i in range(steps):
    P.updateOld()
    N.updateOld()
    H.updateOld()
    res = 1e10
    sweep = 0
    while res > 1e-3 and sweep < 20:
        res = eqn1d.sweep(dt=timesteps)
        sweep += 1
    if __name__ == '__main__':
        viewer.plot()

它没有给我与以前相同的错误,这是一些进步的迹象。但是,它正在吐出一个新错误:

ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 1 dimension(s) and the array at index 2 has 2 dimension(s)

【讨论】:

  • 我明白了。我想我在 Freeman 的方法中看到了一些实用性,考虑到将近 50 年前使用 ODE 求解器的愿望。如今,求解泊松方程并不难。此外,泊松方程的任何瞬态版本都以光速运行。除了诸如 GHz 或 THz 半导体器件之类的东西之外,我从不需要使用任何东西,除了准静态版本。
  • 我建议求解泊松方程。我建议求解电势(标量)而不是电场(矢量)。 $\vec{E} = -\nabla V$。这将泊松方程置于二阶 PDE 的形式中,非常适合 FiPy。
  • 如需进一步讨论,我鼓励您使用我们的mailing listGitHub issue tracker。 StackOverflow 不适合来回讨论和故障排除。
  • 我直到现在才注册,因为您的两个参考都是针对等离子的。我对等离子体一无所知,但如果你想捕捉激发场的动力学,瞬态泊松方程可能适合你的情况,但我仍然会从静电版本开始。
  • 谢谢,我会跟进邮件列表的进一步讨论
猜你喜欢
  • 1970-01-01
  • 2011-01-25
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多