使用Python解决PDE源代码问题

时间:2016-04-03 12:25:01

标签: python fipy

我使用FiPy来解决受生物学启发的问题。

基本上,我想表示一个2D平面,在不同的点我有源和汇。源以固定速率发射基板(不同的源可以具有不同的速率)并且吸收器以固定速率消耗基板(不同的接收器可以具有不同的速率)。我的代码:

import numpy.matlib
from fipy import CellVariable, Grid2D, Viewer, TransientTerm, DiffusionTerm, ImplicitSourceTerm, ExplicitDiffusionTerm
from fipy.tools import numerix
from time import *

nx = 10
ny = nx
dx = 1.
dy = dx
L = dx*nx
mesh = Grid2D(dx=dx, dy=dy, nx=nx, ny=ny)

arr_grid = numerix.array((
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,),'d')

arr_source = numerix.array((
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0.5,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,),'d')

arr_sink = numerix.array((
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0.5,),'d')

source = CellVariable(mesh=mesh, value = arr_source)
sink = CellVariable(mesh=mesh, value = arr_sink)
phi = CellVariable(name = "solution variable", mesh = mesh, value = arr_grid)
X,Y = mesh.cellCenters
phi.setValue(3.0, where=(X < 2.0) & (X > 1.0))
phi.setValue(-1.0, where=(X < 6.0) & (X > 5.0))
D = 1.
eq = TransientTerm() == DiffusionTerm(coeff=D)



viewer = Viewer(vars=phi, datamin=0., datamax=1.)

steadyState = False

if(steadyState):
    print("SteadyState")
    DiffusionTerm().solve(var=phi)
    viewer.plot()
    sleep(20)
else:
    print("ByStep")
    timeStepDuration = 10 * 0.9 * dx**2 / (2 * D)
    steps = 500
    for step in range(steps):
        print(step)
        eq.solve(var=phi,
        dt=timeStepDuration)
        if __name__ == '__main__':
            viewer.plot()

这很有效,但FiPy将来源视为&#34;不可再生的&#34;并且最终我会在整个空间内获得均匀的浓度。另一种方法是删除:

X,Y = mesh.cellCenters
phi.setValue(3.0, where=(X < 2.0) & (X > 1.0))
phi.setValue(-1.0, where=(X < 6.0) & (X > 5.0))

将等式更改为:

eq = TransientTerm() == DiffusionTerm(coeff=D) + source - sink

鉴于源和接收器从未改变,这提供了&#34;无限&#34;来源和汇。但是,当我尝试使用

求解稳态时
eq = TransientTerm() == DiffusionTerm(coeff=D) + source - sink

我明白了:

C:\Python27\python.exe C:/Users/dario_000/PycharmProjects/mesa-test/mesher.py
SteadyState
C:\Python27\lib\site-packages\fipy-3.1.dev134+g64f7866-py2.7.egg\fipy\solvers\scipy\linearLUSolver.py:71: RuntimeWarning: invalid value encountered in double_scalars
  if (numerix.sqrt(numerix.sum(errorVector**2)) / error0)  <= self.tolerance:

方程式尚未解决。但是,如果我通过步骤&#34;解决它。再次使用:

eq = TransientTerm() == DiffusionTerm(coeff=D) + source - sink

我得到了一张与我期待的相似的好照片:

enter image description here

关于如何在不同的空间位置指定源/汇的初始设置的任何建议,每个空间位置具有不同的发射/消耗率,以便我能够获得稳态解决方案?

谢谢!

1 个答案:

答案 0 :(得分:4)

请注意,正如评论中wd15所述,邮件列表中有更深入的讨论和跟进。

首先,初始条件和源都可以使用where逻辑。

source = CellVariable(mesh=mesh, value = arr_source, where=(2 < X) & (X < 3))

这避免了数组的显式构造。

其次,初始条件和来源之间存在关键差异。在原始公式中,您在字段变量SetValue上使用phi方法,您将为瞬态解决方案(或直接稳态求解的初始猜测)提供初始条件,而不是实际来源。因此,正确的方法是您实际将第二个方法直接添加到方程中的方法:

eq = TransientTerm() == DiffusionTerm(coeff=D) + source - sink

另外,要尝试直接稳定求解,您可以在没有TransientTerm的情况下编写等式,

eq = 0 == DiffusionTerm(coeff=D) + source - sink

然后使用eq.solve()解决,这将解决合并的DiffusionTerm和来源/接收器。

然而,直接到稳定的方法值得注意。首先,对于一般系统,没有真正好的直接计算稳态解的数值方法。通常,您最好的选择是通过从某个初始条件到达稳定状态的时间步长来解决瞬态方程,因为这实际上可能是解决稳态分布的最稳健算法。在某些情况下,您甚至可以通过一个大的时间步骤来执行此操作,如“完全隐式解决方案并非没有陷阱”一节中所述here。其次,您确定您的系统允许稳定状态吗?您有无通量边界条件(隐含,因为您没有指定任何其他边界条件),但您有内部源/接收器。除非这些源/接收器以完全相同的速率产生/消耗字段变量,否则系统中将有净累积。 R =常量,均匀和非零的简单示例:

dc/dt = R

没有通量边界条件的

是一个不允许任何稳态的方程。增加扩散项不会改变这一点。如果要添加任何dirichlet(指定值)边界条件,则可以实现稳定的解决方案,因为系统内的净生产/消耗可以通过系统边界离开/进入。可以找到关于边界条件以及如何应用它们的讨论here

最后,另一件需要注意的事情。所写的源/汇项是“零阶”,这将导致例如如果下沉项足够大和/或远离源,则浓度变为负值。如果发生这种情况,模型显然需要通过例如使接收器成为一阶来修改,

eq = TransientTerm() == DiffusionTerm(coeff=D) + source - sink*phi

当phi变为零时,这将确保接收器“关闭”,但这也可以通过修改以耦合到其他字段变量,如本地单元密度。