具有反应性边界条件的FiPY中的一维耦合瞬态扩散

问题描述 投票:0回答:1

我想解决两个化合物A和B的瞬态扩散方程,如图所示。我认为图像是显示我的问题的更好方法。Diffusion equations and boundary conditions.

您可以看到,反应仅在表面发生,并且A的通量等于B的通量。因此,这两个方程仅在表面处耦合。边界条件类似于ROBIN边界条件,在Fipy手册中进行了说明。但是,主要区别在于边界条件中第二个变量的存在。有人知道如何在Fipy中制定此边界条件吗?我想我需要在ROBIN边界条件上添加一些额外的术语,但我无法弄清楚。

非常感谢您的帮助。

这是用x = 0的ROBIN边界条件求解上述方程的代码。

-D(dC_A / dx)= -kC_A

-D(dC_B / dx)= -kC_B

在这种情况下,我可以轻松地使用ROBIN边界条件来求解方程。对于该边界条件,结果似乎是合理的。

"""
Question for StackOverflow
"""
#%%
from fipy import Variable, FaceVariable, CellVariable, Grid1D, TransientTerm, DiffusionTerm, Viewer, ImplicitSourceTerm
from fipy.tools import numerix



#%%
##### Model parameters

L= 8.4853e-4 # m boundary layer thickness
dx= 1e-8 # mesh size 
nx = int(L/dx)+1 # number of meshes
D = 1e-9 # m^2/s diffusion coefficient
k = 1e-4 # m/s reaction coefficient R = k [c_A],
c_inf =  0. # ROBIN general condition, once can think R = k ([c_A]-[c_inf])
c_init = 1. # Initial concentration of compound A, mol/m^3


#%%
###### Meshing and variable definition

mesh = Grid1D(nx=nx, dx=dx)
c_A = CellVariable(name="c_A", hasOld = True,
                    mesh=mesh,
                    value=c_init)
c_B = CellVariable(name="c_B", hasOld = True,
                    mesh=mesh,
                    value=0.)

#%%
##### Right boundary condition 

valueRight = c_init
c_A.constrain(valueRight, mesh.facesRight)
c_B.constrain(0., mesh.facesRight)

#%%
### ROBIN BC requirements, defining cellDistanceVectors
## This code is for fixing celldistance via this link:
## https://stackoverflow.com/questions/60073399/fipy-problem-with-grid2d-celltofacedistancevectors-gives-error-uniformgrid2d
MA = numerix.MA
tmp = MA.repeat(mesh._faceCenters[..., numerix.NewAxis,:], 2, 1)
cellToFaceDistanceVectors = tmp - numerix.take(mesh._cellCenters, mesh.faceCellIDs, axis=1)
tmp = numerix.take(mesh._cellCenters, mesh.faceCellIDs, axis=1)
tmp = tmp[..., 1,:] - tmp[..., 0,:]
cellDistanceVectors = MA.filled(MA.where(MA.getmaskarray(tmp), cellToFaceDistanceVectors[:, 0], tmp))

#%%
##### Defining mask and Robin BC at left boundary 
mask = mesh.facesLeft
Gamma0 = D
Gamma = FaceVariable(mesh=mesh, value=Gamma0)
Gamma.setValue(0., where=mask)
dPf = FaceVariable(mesh=mesh,
                   value=mesh._faceToCellDistanceRatio * cellDistanceVectors)
n = mesh.faceNormals
a = FaceVariable(mesh=mesh, value=k, rank=1)
b = FaceVariable(mesh=mesh, value=D, rank=0)
g = FaceVariable(mesh=mesh, value= k * c_inf, rank=0)
RobinCoeff = (mask * Gamma0 * n / (-dPf.dot(a)+b))

#%%
#### Making a plot
viewer = Viewer(vars=(c_A, c_B),
                     datamin=-0.2, datamax=c_init * 1.4)
viewer.plot()

#%% Time step and simulation time definition
time = Variable()
t_simulation = 4 # seconds
timeStepDuration = .05
steps = int(t_simulation/timeStepDuration)

#%% PDE Equations
eqcA = (TransientTerm(var=c_A) == DiffusionTerm(var=c_A, coeff=Gamma) + 
            (RobinCoeff * g).divergence 
            - ImplicitSourceTerm(var=c_A, coeff=(RobinCoeff * a.dot(-n)).divergence))

eqcB = (TransientTerm(var=c_B) == DiffusionTerm(var=c_B, coeff=Gamma) -
                (RobinCoeff * g).divergence 
            + ImplicitSourceTerm(var=c_B, coeff=(RobinCoeff * a.dot(-n)).divergence))


#%% A loop for solving PDE equations
while time() <= (t_simulation):
    time.setValue(time() + timeStepDuration)
    c_B.updateOld()
    c_A.updateOld()
    res1=res2 = 1e10
    viewer.plot()
    while (res1 > 1e-6) & (res2 > 1e-6):
        res1 = eqcA.sweep(var=c_A, dt=timeStepDuration)
        res2 = eqcB.sweep(var=c_B, dt=timeStepDuration)
pde fipy
1个回答
0
投票

可以将其解决为完全隐式的系统。下面的代码将问题简化为具有统一的域大小和扩散系数。 k设置为0.2。它带有一些警告,很好地捕获了分析解决方案(请参阅下文)。

from fipy import (
    CellVariable,
    TransientTerm,
    DiffusionTerm,
    ImplicitSourceTerm,
    Grid1D,
    Viewer,
)

L = 1.0
nx = 1000
dx = L / nx
konstant = 0.2
coeff = 1.0

mesh = Grid1D(nx=nx, dx=dx)

var_a = CellVariable(mesh=mesh, value=1.0, hasOld=True)
var_b = CellVariable(mesh=mesh, value=0.0, hasOld=True)

var_a.constrain(1.0, mesh.facesRight)
var_b.constrain(0.0, mesh.facesRight)

coeff_mask = ~mesh.facesLeft * coeff
boundary_coeff = konstant * (mesh.facesLeft * mesh.faceNormals).divergence

eqn_a = TransientTerm(var=var_a) == DiffusionTerm(
    coeff_mask, var=var_a
) - ImplicitSourceTerm(boundary_coeff, var=var_a) + ImplicitSourceTerm(
    boundary_coeff, var=var_b
)

eqn_b = TransientTerm(var=var_b) == DiffusionTerm(
    coeff_mask, var=var_b
) - ImplicitSourceTerm(boundary_coeff, var=var_b) + ImplicitSourceTerm(
    boundary_coeff, var=var_a
)

eqn = eqn_a & eqn_b

for _ in range(5):
    var_a.updateOld()
    var_b.updateOld()
    eqn.sweep(dt=1e10)

Viewer((var_a, var_b)).plot()

print("var_a[0] (expected):", (1 + konstant) / (1 + 2 * konstant))
print("var_b[0] (expected):", konstant / (1 + 2 * konstant))
print("var_a[0] (actual):", var_a[0])
print("var_b[0] (actual):", var_b[0])

input("wait")

注意以下内容:

  • 正如所写,边界条件仅是一阶精确的,这对于这个问题并不重要,但是可能会在较高维度上对您造成伤害。可能有一些方法可以解决此问题,例如在边界附近有一个小单元格或为边界条件添加显式的二阶校正。

  • 等式在此处耦合。如果解耦,则可能需要迭代负载才能达到平衡。

  • 它确实需要进行几次迭代才能达到平衡,但不是必须的。这可能是由于求解器没有几次尝试就无法充分收敛。耦合方程可能存在一些不良条件。

© www.soinside.com 2019 - 2024. All rights reserved.