数值数学导论
这就是“你好,世界!” PDE(偏微分方程)。拉普拉斯方程或扩散方程经常出现在物理学中,例如热方程,变形,流体动力学等。由于现实生活是3D,但我们要说的是“世界,你好!” 而不是唱“ 99瓶啤酒,...”,此任务以1D形式给出。您可以将其解释为两端都绑在墙上的橡胶长袍。
在一个[0,1]
域中找到一个函数u
在给定源功能f
和边界值u_L
和u_R
这样的:
-u'' = f
u(0) = u_L
u(1) = u_R
u''
表示的二阶导数 u
这是可以解决的纯粹theoritical但你的任务是它数值求解一个离散域X的N
要点:
- x =
{i/(N-1) | i=0..N-1}
或从1开始:{(i-1)/(N-1) | i=1..N}
h = 1/(N-1)
是间距
输入值
f
作为函数或表达式或字符串u_L
,u_R
作为浮点值N
作为整数> = 2
输出量
- 阵列,列表,某种形式的分离式串
u
这样的u_i == u(x_i)
例子
例子1
输入:f = -2
,u_L = u_R = 0
,N = 10
(不要拿f=-2
错了,它不是一个值,而是一个常数函数,返回-2
所有x
它就像我们的绳子恒定的重力。)
输出: [-0.0, -0.09876543209876543, -0.1728395061728395, -0.22222222222222224, -0.24691358024691357, -0.24691358024691357, -0.22222222222222224, -0.1728395061728395, -0.09876543209876547, -0.0]
有一个简单的精确解决方案: u = -x*(1-x)
例子2
输入:f = 10*x
,u_L = 0
u_R = 1
,N = 15
(这里有右侧很多上风的)
输出: [ 0., 0.1898688, 0.37609329, 0.55502915, 0.72303207, 0.87645773, 1.01166181, 1.125, 1.21282799, 1.27150146, 1.29737609, 1.28680758, 1.2361516, 1.14176385, 1.]
确切的解决方案指出: u = 1/3*(8*x-5*x^3)
例子3
输入:f = sin(2*pi*x)
,u_L = u_R = 1
,N = 20
(有人打破了重力或有一种向上和顺风)
输出: [ 1., 1.0083001, 1.01570075, 1.02139999, 1.0247802, 1.0254751, 1.02340937, 1.01880687, 1.01216636, 1.00420743, 0.99579257, 0.98783364, 0.98119313, 0.97659063, 0.9745249, 0.9752198, 0.97860001, 0.98429925, 0.9916999, 1.]
这里的确切解决方案是 u = (sin(2*π*x))/(4*π^2)+1
例子4
输入:f = exp(x^2)
,u_L = u_R = 0
,N=30
输出:
[ 0. 0.02021032 0.03923016 0.05705528 0.07367854 0.0890899
0.10327633 0.11622169 0.12790665 0.13830853 0.14740113 0.15515453
0.16153488 0.1665041 0.17001962 0.172034 0.17249459 0.17134303
0.16851482 0.1639387 0.15753606 0.1492202 0.13889553 0.12645668
0.11178744 0.09475961 0.07523169 0.05304738 0.02803389 0. ]
注意轻微的不对称
FDM
解决此问题的一种可能方法是有限差分法:
- 改写
-u_i'' = f_i
为 (-u_{i-1} + 2u_i - u{i+1})/h² = f_i
等于-u_{i-1} + 2u_i - u{i+1} = h²f_i
- 设置方程式:
- 等于矩阵向量方程式:
- 求解此方程并输出
u_i
一个用Python演示的实现:
import matplotlib.pyplot as plt
import numpy as np
def laplace(f, uL, uR, N):
h = 1./(N-1)
x = [i*h for i in range(N)]
A = np.zeros((N,N))
b = np.zeros((N,))
A[0,0] = 1
b[0] = uL
for i in range(1,N-1):
A[i,i-1] = -1
A[i,i] = 2
A[i,i+1] = -1
b[i] = h**2*f(x[i])
A[N-1,N-1] = 1
b[N-1] = uR
u = np.linalg.solve(A,b)
plt.plot(x,u,'*-')
plt.show()
return u
print laplace(lambda x:-2, 0, 0, 10)
print laplace(lambda x:10*x, 0, 1, 15)
print laplace(lambda x:np.sin(2*np.pi*x), 1, 1, 20)
没有矩阵代数的替代实现(使用Jacobi方法)
def laplace(f, uL, uR, N):
h=1./(N-1)
b=[f(i*h)*h*h for i in range(N)]
b[0],b[-1]=uL,uR
u = [0]*N
def residual():
return np.sqrt(sum(r*r for r in[b[i] + u[i-1] - 2*u[i] + u[i+1] for i in range(1,N-1)]))
def jacobi():
return [uL] + [0.5*(b[i] + u[i-1] + u[i+1]) for i in range(1,N-1)] + [uR]
while residual() > 1e-6:
u = jacobi()
return u
但是,您可以使用任何其他方法来求解拉普拉斯方程。如果您使用的迭代方法,你应该迭代,直到残留|b-Au|<1e-6
,与b
被右手边矢量u_L,f_1h²,f_2h²,...
笔记
根据您的解决方案方法,您可能无法完全根据给定的解决方案来解决示例。至少对于N->infinity
误差应该接近零。
不允许出现标准漏洞,允许内置PDE。
奖金
显示解决方案(图形或ASCII艺术形式)的奖励为-30%。
获奖
这是codegolf,因此以字节为单位的最短代码胜出!
log(log(x))
或sqrt(1-x^4)
确实具有积分的函数,但是在基本函数中无法表达。
u(x) = 1/2 (-sqrt(π) x erfi(x)+sqrt(π) erfi(1) x+e^(x^2)-e x+x-1)
无法精确计算。
f(x) = exp(x^2)
。