一维热方程的 Python 有限差分方案:如何使用 numpy 表达式表示 for 循环

计算科学 有限差分 Python 流体动力学 麻木的 传播热量
2021-12-21 16:02:21

大家好,

我最近被介绍到 Python 和 Numpy,并且仍然是将其应用于数值方法的初学者。我一直在执行简单的一维扩散计算。我想我的问题更多是关于将 python 应用于差分方法。我在这里问它是因为可能需要一些 diff eq 背景才能理解我的问题。

我的总体问题: 非常初学者的问题,我在下面有一张具体示例的图片。

在数值计算方法(CFD 和 FEA)中使用内置 numpy 函数与使用 for 循环有什么好处/缺点,有时是否绝对有必要为时间步长编写显式 for 循环?(没有双关语)

我在下面附上了我一直在练习的简短练习的链接。谢谢你的时间!


离散化方案

*

离散化

* 离散一维扩散方程、FWD 时间、中心空间


我的具体代码示例:您如何摆脱下面的 for 循环?


for 循环


练习链接:

http://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_01_Heat_Equation_1D_Explicit.ipynb

1个回答

numpy 数组和方法非常有用。它们通常经过优化,比在 python 中循环要快得多。始终寻找一种方法来为您的应用程序使用现有的 numpy 方法。

np.roll()将允许您转移,然后您只需添加。

convolve()从关于如何更快地 np.roll() 的评论中学会了使用?. 我没有检查这是否更快,但这可能取决于维度的数量。请参阅此答案以了解拉普拉斯方程的 2D 松弛(静电,另一个问题)

对于这种放松,你需要一个边界框,所以布尔值do_meFalse边界上。

我知道对于拉普拉斯方程的雅可比松弛解,有两种加速方法。我不知道它们是否可以扩展到求解热扩散方程,但我确信可以做一些事情:

  • 多重网格在粗(快速)网格上求解,然后插值到细网格并迭代更长的时间

  • 连续过度松弛通过将值更改为大于简单平均时所具有的值的 100% 的量来“超调”平均值。尝试像 110% 到 150% 这样的值,如果它们太大,它可能会变得不稳定。

在此处输入图像描述

import numpy as np
import matplotlib.pyplot as plt
from scipy.ndimage import convolve

T0             = np.zeros(50, dtype=float)
T0[17:25]      = 1.

T1             = T0.copy()  # method 1  np.roll()
T2             = T0.copy()  # method 2  convolve()

do_me          = np.ones_like(T0, dtype=bool)
do_me[[0, -1]] = False    #  keep the boundaries of your bounding box fixed

a              = 0.01

hold_1         = [T0.copy()]
for i in range(10001):
    Ttemp      = T1 + a*(np.roll(T1, +1) + np.roll(T1, -1) - 2*T1)
    T1[do_me]  = Ttemp[do_me]
    if not i%1000:
        hold_1.append(T1.copy())

hold_2         = [T0.copy()]
kernel         = np.array([a, (1 - 2.*a), a])

for i in range(10001):
    Ttemp      = convolve(T2, kernel)
    T2[do_me]  = Ttemp[do_me]
    if not i%1000:
        hold_2.append(T2.copy())

if True:
    plt.figure()
    plt.subplot(1, 2, 1)
    for thing in hold_1:
        plt.plot(thing)

    plt.subplot(1, 2, 2)
    for thing in hold_2:
        plt.plot(thing)

    plt.show()