网格中的填充点-前向Euler算法-错误的输出

时间:2018-10-20 16:38:53

标签: python math numerical-methods differential-equations

我将非常简要地尝试向那些对数学经验不足的人解释我的做法,这确实很简单。

我们正在尝试填充网格,如下所示:

enter image description here

我们在橙色点U(j,n+1)下连续使用三个点U(j-1,n), U(j,n), U(j,n+1)

给出整个底部行中U的值,并且该值是周期性的。因此,从理论上讲,我们可以填充整个网格。

计算橙点的公式为:

U(j,n+1) = U(j,n) + (delta_t / (2 * delta_x)) * (U(j+1,n) - U(j-1,n))

我们可以很容易地将其写为线性方程组,如下所示:

enter image description here

现在,我们只需要重复这个乘以该矩阵的过程(迭代时间变量)即可。这是一种对偏微分方程的解进行数值近似的简单方法。

我编写了执行此操作的代码,然后将最后一行与微分方程的已知解进行比较。

这是代码

import math
import numpy

def f(x):
    return math.cos(2 * math.pi * x)


def solution(x, t):
    return math.cos(2 * math.pi * (x + t))


# setting everything up
N = 16

Lambda = 10 ** (-20)
Delta_x = 1/(N+1)
Delta_t = Lambda * Delta_x * Delta_x
t_f = 5
v_0 = numpy.zeros((N, 1))

# Filling first row, initial condition was given
for i in range(N):
    v_0[i, 0] = f(i * Delta_x)

# Create coefficient matrix
M = numpy.zeros((N, N))
for i in range(N):
    M[i, i - 1] = -Delta_t / (2 * Delta_x)
    M[i, i] = 1
    M[i, (i + 1) % N] = Delta_t / (2 * Delta_x)

# start iterating through time
v_i = v_0
for i in range(math.floor(t_f / Delta_t) - 1):
    v_i = numpy.dot(M, v_i)

v_final = v_i
if (Delta_t * math.ceil(t_f / Delta_t) != t_f): #we don't reach t_f exactly using Delta_t
    v_final = (1/2) * (v_i + numpy.dot(M, v_i))

u = numpy.zeros(v_final.shape)
for i in range(N):
    u[i, 0] = solution(i * Delta_x, t_f)

for x in range(v_final.shape[0]):
    print (v_final[x], u[x])

从理论上讲,我应该能够找到足够小的lambda,以使v_final和已知的解决方案u非常相似。

但是我不能。不管我做多λ,如何做网格,我似乎都会收敛到不正确的地方。他们没有关闭。

我一生无法解决问题。 有人知道什么地方可能出问题吗?

1 个答案:

答案 0 :(得分:1)

在将间隔分为Delta_x = 1.0/N个单元格时,您应该拥有N

您在N+1u[0]的网格上获得u[N]个点,但是根据边界条件u[N]=u[0],您还只使用了长度为{{1 }}来保存所有节点值。

根据给定的公式,您有N,因此反向计算应为gamma = dt/(2*dx)或您的变量名

dt = gamma*2*dx

或者您针对的是Delta_t = Lambda * 2 * Delta_x 方法的错误,因此拥有O(dt, dx²)是有意义的,但是如果您使用dt = c*dx^2这样的荒谬因素,则不会希望时间离散化误差小于空间离散化误差,c=1e-20c=0.1就足够了。


c=0.01

欧拉方法也不是最精确的方法,对于import numpy as np def f(x): return np.cos(2 * np.pi * x) def solution(x, t): return f(x + t) # setting everything up N_x = 16 Lambda = 1e-2 Delta_x = 1./N_x Delta_t = Lambda * Delta_x * Delta_x t_f = 5 N_t = int(t_f/Delta_t+0.5); t_f = N_t*Delta_t # Filling first row, initial condition was given x = np.arange(0,N_x,1) * Delta_x v_0 = f(x) # Create coefficient matrix M = np.zeros((N_x, N_x)) for i in range(N_x): M[i, i - 1] = -Delta_t / (2 * Delta_x) M[i, i] = 1 M[i, (i + 1) % N_x] = Delta_t / (2 * Delta_x) # start iterating through time v_i = v_0[:] for i in range(N_t): v_i = np.dot(M, v_i) v_final = v_i u = solution(x, t_f) for vx, ux in zip(v_final, u): print (vx, ux) ,预期误差在exp(L*t_f)*dx^2 = e^5/N_x^2=0.58范围内,其中N_x=16被视为近似Lipschitz常数。现在,如果您增加到L=1,则此错误估计值将减少到N_x=50,这在结果中也将可见。


0.06离散问题的t精确解是x,其中cos(2*pi*(x+c*t))。如果与该公式进行比较,则误差应该很小c=sin(2*pi*dx)/(2*pi*dx)