我第一次尝试用 FiPy 写几个扩散反应方程。
我的方程式适用于三种不同的浓度 c_i,仅包含扩散部分和来源(LateX 输入):
\partial_t c_1 = \nabla \cdot (D_1 \nabla c_1) + A_1 c_{1} + B_1 c_2^4 + W_1 \\
\partial_t c_2 = \nabla \cdot (D_2 \nabla c_2) + c_{1}(A_2 + 2c_1) + c_2^4 + W_2\\
\partial_t c_3 = \nabla \cdot (D_3 \nabla c_3) + A_3 c_{1} - W_3 \\
系数D_i、A_i、B_i、P_i和W_1是常数。我已经用 de Diffusion 项和非线性源项编写了代码。但是对于 100 的范围,我对 c2 有一些奇怪的行为。也许是我写错的非线性源项?我使用 ImplicitSourceTerm 命令,我认为这将线性化该术语。我错过了什么吗?我必须通过 myslef 进行线性化吗?(就像泰勒一样?)
如何将平流扩散反应 PDE 与 FiPy和 https://www.ctcms.nist.gov/fipy/examples/diffusion/generated/examples.diffusion.coupled.html耦合
from fipy import *
from fipy import CellVariable, Variable, Grid1D, TransientTerm, DiffusionTerm, ImplicitSourceTerm, LinearLUSolver, Viewer
import math
from fipy.tools import numerix
# Konstanten
F = 96485.3399 #C /mol
R = 8.314472 # J/(mol*K)
T = 273.18 # K
alpha = 0.5
c_std = 1. # mol/s
c1_sat = 1. # mol/s
eta_Zn = 1. # V
kIc = 6.3 # mol/s Von Reaktion I an der Kathode
kIa = 5. # mol/s Von Reaktion I an der Anode
kII = 0.25 # mol/s von Reaktion II
mu_1I = 1. # Von Zinkat in Reaktion I
mu_1II = -2. # Von Zinkat in Reaktion II
mu_2I = -4. # Von OH in Realtion I
mu_2II = 2. # Von OH in Reaktion II
mu_3II = 1. # Von H2O in Reaktion II
ep1 = 1. # Von Zinkat
ep2 = 1. # Von OH
ep3 = 1. # Von H20
D1 = .5 # Von Zinkat
D2 = 1. # Von OH
D3 = 0.1 # Von H20
## Mesh
L = 10.
nx = 1000
mesh = Grid1D(dx=L/1000, nx=nx)
x = mesh.cellCenters[0]
## Initial Conditions
c1 = CellVariable(name="c1", mesh=mesh, value=1., hasOld=True)
c2 = CellVariable(name="c2", mesh=mesh, value=1., hasOld=True)
c3 = CellVariable(name="c3", mesh=mesh, value=1., hasOld=True)
## Boundary Conditions
c1.constrain(2., mesh.facesLeft)
c1.constrain(0., mesh.facesRight)
c2.constrain(0., mesh.facesLeft)
c2.constrain(2., mesh.facesRight)
c3.constrain(0., mesh.facesLeft)
c3.constrain(2., mesh.facesRight)
c2.faceGrad.constrain(1., where=mesh.facesRight)
# Definition Konstanten fuer SourceTerm
Zn1 = (kIc/c_std)*math.exp(-(1-alpha)*(F/(R*T))*eta_Zn)+kII
Zn2 = (kIa/(c_std)**4)*math.exp(alpha*(F/(R*T))*eta_Zn)
Zn3 = kII*c1_sat
OH1 = 4*(kIc/c_std)*math.exp(-(1-alpha)*(F/(R*T))*eta_Zn)+2*kII
OH2 = 4*(kIa/(c_std)**4)*math.exp(alpha*(F/(R*T))*eta_Zn)
OH3 = 2*kII*c1_sat
H1 = kII
H2 = 0.
H3 = kII*c1_sat
sourceCoeff1 = (Zn1*c1) + (Zn1*c2**4) + Zn3
sourceCoeff2 = c1*(OH1 + 2*c1) + c2**4 + OH3
sourceCoeff3 = c1*H1 - H3
eq1 = (TransientTerm(var=c1) == DiffusionTerm(coeff=D1, var=c1) + ImplicitSourceTerm(coeff=sourceCoeff1, var=c1))
eq2 = (TransientTerm(var=c2) == DiffusionTerm(coeff=D2, var=c2) + ImplicitSourceTerm(coeff=sourceCoeff2, var=c2))
eq3 = (TransientTerm(var=c3) == DiffusionTerm(coeff=D3, var=c3) + ImplicitSourceTerm(coeff=sourceCoeff3, var=c3))
eqn = eq1 & eq2 & eq3
vi = Viewer((c1, c2, c3))
for t in range(50):
c1.updateOld()
c2.updateOld()
c3.updateOld()
eqn.solve(dt=1.e-3)
vi.plot()
我也在尝试添加潜在的术语,但我不明白这是否可能。类似的东西(与上面相同,但有潜在的部分)
\partial_t c_1 = \nabla \cdot (D_1 \nabla c_1) + \nabla \cdot \biggl(P_1c_1\nabla\Phi\biggr) + A_1 c_{1} + B_1 c_2^4 + W_1 \\
\partial_t c_2 = \nabla \cdot (D_2 \nabla c_2) + \nabla \cdot \biggl(P_2c_2\nabla\Phi\biggr) + c_{1}(A_2 + 2c_1) + c_2^4 + W_2\\
\partial_t c_3 = \nabla \cdot (D_3 \nabla c_3) + \nabla \cdot \biggl(P_3c_3\nabla\Phi\biggr) + A_3 c_{1} - W_3 \\
我分析了来自 https://www.ctcms.nist.gov/fipy/examples/phase/generated/examples.phase.binaryCoupled.html的示例, 以尝试添加像 Diffusionterm 这样的潜在术语,但我总是得到错误:
SolutionVariableNumberError:不同数量的解变量和方程。
我所期望的,但也许我错过了一些东西。
继承那部分代码:
eq1 = (TransientTerm(var=c1) == DiffusionTerm(coeff=D1, var=c1) + ImplicitSourceTerm(coeff=sourceCoeff1, var=c1)) + DiffusionTerm(coeff=D1phi, var=phi
eq2 = (TransientTerm(var=c2) == DiffusionTerm(coeff=D2, var=c2) + ImplicitSourceTerm(coeff=sourceCoeff2, var=c2)) + DiffusionTerm(coeff=D2phi, var=phi)
eq3 = (TransientTerm(var=c3) == DiffusionTerm(coeff=D3, var=c3) + DiffusionTerm(coeff=D3phi, var=phi) + ImplicitSourceTerm(coeff=sourceCoeff3, var=c3))
也尝试使用命令扫描做一些数值分析,如残差和范数。我在这里看到了关于扫描命令的一个很好的解释: Solver tolerance and residual error when using sweep function in FiPy
那部分代码(仅用于带有源的扩散术语)
dt = 1.e5
solver = LinearLUSolver(tolerance=1e-10)
c1.updateOld()
c2.updateOld()
c3.updateOld()
res = 1.
initialRes = None
while res > 1e-4:
res = eq.sweep(dt=dt, solver=solver)
if initialRes is None:
initialRes = res
res = res / initialRes
尽管如此,我没有得到任何结果或错误,必须手动停止该过程。
总而言之,我的问题是:有可能使用具有扩散项和潜在项的 FiPy 对 pdes 来解决吗?是否也可以对耦合的 pdes 执行命令扫描?
或者我错过了什么?
我非常感谢任何帮助或建议。我希望,我写的很清楚。十分感谢。