使用隐式方法求解PDE系统

时间:2018-07-31 12:37:01

标签: python numpy scipy differential-equations pde

我有一个偏微分方程(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似乎是最快的,但是对于较大的问题,我怀疑这是否成立。
尤其是:还有更好的方法吗?

谢谢!

0 个答案:

没有答案