我有一个偏微分方程(PDE)系统,特别是应用于传热和对流的扩散-对流-反应方程式,我使用有限差分法求解。
在我的仿真环境中,我有许多不同的零件,例如管道,储能器,热交换器等。根据零件的不同,每个零件的PDE可以是1D(在大多数情况下)或2D(大约5%)。零件)或3D(很少)。由于这些不同的形状,为整个系统构造一个三对角线(或五边形,隔片...)太复杂了。
这个问题是在SO而不是在计算科学上发布的,因为它是关于如何对PDE使用求解算法,而不是关于PDE的求解方法。
因此,当前每个部件都有一个diff
函数,该函数返回给定输入温度下的差分。由于材料特性等与温度(和流量)有关,因此PDE是非线性的,但是通过滞后系数(在每个步骤和对于隐式方法,请在每次迭代时重新计算它们)。由diff
函数返回的微分的形状与零件的值数组形状相同,例如,对于具有10个网格点的一维管道,其结果是形状为{ {1}}。 扩散系数和其他系数被视为(10, )
函数的内部函数,将不能用于求解器。因此,求解器将只知道差值,当前零件温度和步长。
有什么方法可以使用专用于解决PDE的算法在python中仅一次一步地解决这些PDE吗? (还有一种算法,最好是diff
的一部分,甚至更优选已经由scipy/numpy
支持。)
到目前为止,我已经考虑过的事情:
numba
:仅适用于ODE,而PDE可能不包括在内。那是对的吗?至少对于PDE,我无法获得很好的结果。除此之外,scipy.integrate
并非仅用于计算单个步骤。scipy.integrate
:如果您有带有线性方程的三对角矩阵,这似乎是最好的选择。但是由于我既没有三对角矩阵,也没有线性方程式(线性化,但是滞后系数意味着必须在迭代过程中更新它们)。有什么方法可以在没有太多计算成本的情况下仍然使用此功能?np.linalg.solve
:可行且易于使用。我下面的最小工作示例将使用此方法集成解决方案。但这对于PDE来说总是是否有效?这通常是隐式解决PDE的正确方法吗?还是仅在本示例中有效?我走错了路? scipy.optimize
相同:这只是在这个简单示例中起作用,还是对一般的PDE起作用?scipy.optimize
问题的TL,DR摘要
所有结果似乎都可以,但是这种方法通常对 real PDE是否可行?
推荐使用哪种方法?
对于从import time
from scipy import optimize
def diff(T): # simply example differential function
time.sleep(0.0001) # dummy timer to slow down the calculation
return np.sqrt(T)
def euler_bdf(y, yprev, h):
return (y - yprev - h*diff(y))
def crank_nicolson(y, yprev, h): # diff(yprev) will be outsourced for performance
return (y - yprev - h / 2 * (diff(y) + diff(yprev)))
def iterate_eulerbdf(y0, h, rtol, diff):
y = y0
f = np.ones_like(y)
i = 0
while np.any(f > rtol):
y_old = y
y = y0 + h * diff(y)
f = (y / y_old - 1) # this will be replaced by least mean squares
i += 1
return y, i
def iterate_cranknicolson(y0, h, rtol, diff):
y = y0
diff_old = diff(y)
f = np.ones_like(y)
i = 0
while np.any(f > rtol):
y_old = y
y = y0 + h / 2 * (diff_old + diff(y))
f = (y / y_old - 1)
i += 1
return y, i
T0 = np.arange(10, 20).astype(float) # starting temperature
eulerbdf_hybr = optimize.root(euler_bdf, T0, args=(T0, 1.), method='hybr', tol=1e-6)
eulerbdf_dfsane = optimize.root(euler_bdf, T0, args=(T0, 1.), method='df-sane', tol=1e-6)
eulerbdf_it = iterate_eulerbdf(T0, 1., 1e-6, diff)
cn_hybr = optimize.root(crank_nicolson, T0, args=(T0, 1.), method='hybr', tol=1e-6)
cn_dfsane = optimize.root(crank_nicolson, T0, args=(T0, 1.), method='df-sane', tol=1e-6)
cn_it = iterate_cranknicolson(T0, 1., 1e-6, diff)
到超过(5,)
的各种形状和大小的PDE,哪种方法最有效?对于(100, 100, 100)
来说,目前scipy.integrate
似乎是最快的,但是对于较大的问题,我怀疑这是否成立。
尤其是:还有更好的方法吗?
谢谢!