我正在尝试编写用于解决极其困难的微分方程的代码: X' = 1 用有限元法。 据我所知,我可以获得解决方案u
用基函数phi_i(x),而我可以得到u_i作为线性方程组的解:
使用微分算子D(这里只是一阶导数)。作为我使用帐篷功能的基础:
def tent(l, r, x):
m = (l + r) / 2
if x >= l and x <= m:
return (x - l) / (m - l)
elif x < r and x > m:
return (r - x) / (r - m)
else:
return 0
def tent_half_down(l,r,x):
if x >= l and x <= r:
return (r - x) / (r - l)
else:
return 0
def tent_half_up(l,r,x):
if x >= l and x <= r:
return (x - l) / (r - l)
else:
return 0
def tent_prime(l, r, x):
m = (l + r) / 2
if x >= l and x <= m:
return 1 / (m - l)
elif x < r and x > m:
return 1 / (m - r)
else:
return 0
def tent_half_prime_down(l,r,x):
if x >= l and x <= r:
return - 1 / (r - l)
else:
return 0
def tent_half_prime_up(l, r, x):
if x >= l and x <= r:
return 1 / (r - l)
else:
return 0
def sources(x):
return 1
明确我的空间:
n_vertex = 30
n_points = (n_vertex-1) * 40
space = (0,5)
x_space = np.linspace(space[0],space[1],n_points)
vertx_list = np.linspace(space[0],space[1], n_vertex)
tent_list = np.zeros((n_vertex, n_points))
tent_prime_list = np.zeros((n_vertex, n_points))
tent_list[0,:] = [tent_half_down(vertx_list[0],vertx_list[1],x) for x in x_space]
tent_list[-1,:] = [tent_half_up(vertx_list[-2],vertx_list[-1],x) for x in x_space]
tent_prime_list[0,:] = [tent_half_prime_down(vertx_list[0],vertx_list[1],x) for x in x_space]
tent_prime_list[-1,:] = [tent_half_prime_up(vertx_list[-2],vertx_list[-1],x) for x in x_space]
for i in range(1,n_vertex-1):
tent_list[i, :] = [tent(vertx_list[i-1],vertx_list[i+1],x) for x in x_space]
tent_prime_list[i, :] = [tent_prime(vertx_list[i-1],vertx_list[i+1],x) for x in x_space]
计算线性方程组:
b = np.zeros((n_vertex))
A = np.zeros((n_vertex,n_vertex))
for i in range(n_vertex):
b[i] = np.trapz(tent_list[i,:]*sources(x_space))
for j in range(n_vertex):
A[j, i] = np.trapz(tent_prime_list[j] * tent_list[i])
然后解决并重建它
u = np.linalg.solve(A,b)
sol = tent_list.T.dot(u)
但它不起作用,我只是得到一些上下模式。我究竟做错了什么?
答案 0 :(得分:4)
首先,关于术语和符号的几点评论:
1)你 使用弱配方,尽管你已经隐含地这样做了。一种“弱”的配方&#34;与所涉及的衍生物的顺序无关。它很弱,因为你并不完全满足每个位置的微分方程。 FE最小化在域上集成的解决方案的加权残差。函数phi_j实际上使加权函数离散化。只有一阶导数的区别在于你不必应用高斯散度定理(简化为一维的零件积分)来消除二阶导数。你可以说这还没有完成,因为在LHS中没有区分phi_j。
2)我建议不要使用&#34; A&#34;作为微分算子。您还将此符号用于全局系统矩阵,因此您的符号不一致。人们经常使用&#34; D&#34;,因为这更适合用于区分的想法。
其次,关于你的实施:
3)您正在使用比必要更多的集成点。您的元素使用线性插值函数,这意味着您只需要一个位于元素中心的积分点来精确地评估积分。查看高斯求积的细节,看看为什么。此外,您已将积分点数指定为节点数的倍数。这应该是元素数量的倍数(在您的情况下,n_vertex-1),因为元素是您正在整合的域。
4)您只需从配方中删除两个末端节点即可构建系统。这不是指定边界条件的正确方法。我建议首先构建完整的系统,并使用一种典型的方法来应用Dirichlet边界条件。另外,考虑一下约束两个节点对你试图解决的微分方程有什么意义。满足x&#39; = 1,x(0)= 0,x(5)= 0?您通过尝试将2个边界条件应用于一阶微分方程来过度约束系统。
不幸的是,没有一个小的调整可以让代码工作,但我希望上面的评论可以帮助你重新思考你的方法。
编辑以解决您的更改:
1)假设矩阵A用A [row,col]寻址,那么你的指数是向后的。你应该与A [i,j] = ...
整合2)应用约束的一种简单方法是用所需的约束替换一行。如果你想要x(0)= 0,例如,为所有j设置A [0,j] = 0,则设置A [0,0] = 1并设置b [0] = 0.这将替换其中一个u_0 = 0的方程式。积分后执行此操作。