不可压缩库艾特流的隐式求解(附完整代码)

入门CFD,主要参考书目《计算流体力学基础及其应用》(John D.Anderson 著,吴颂平等 译)

实现了 第 9.3 节 数值方法:隐式Crank-Nicolson  的代码,问题比较简单,主要是托马斯算法的实现,原书中没有提到对角占优的问题,该算法具体可参考10分钟理解托马斯算法(tridiagonal matrix algorithm,Thomas algorithm)。代码运行结果如下:

                                           

不足之处,欢迎指正!

完整代码如下:

# -*- coding: utf-8 -*-
"""
Created on Wed Aug 12 16:02:41 2020

@author: PANSONG
"""

###################################
######## 不可压库艾特流动 ##########
###################################

import numpy as np
import matplotlib.pyplot as plt;plt.close('all')


### 流动条件: 采用无量纲形式,只有一个参数雷诺数,最后的定常解固定: u=y
ReD = 5000 

### 计算参数
E_list = [1,5,10] # 表征时间间隔
N = 21 # 网格点数
y = np.linspace(0,1,N)
max_iteration = 500

### 计算:隐式 Crank-Nicolson 方法
### 托马斯算法(追赶法)解三对角方程
def Thomas_algo(b,d,a,c):
    ## 输入 b,d, a 为三条对角线上的系数,c 为方程右边的值;ndarray(),行向量
    ## 增加一个方程组有唯一解的判断 ?    
    b = np.insert(b,obj=0,values=0) ## 在开头插入 0
    a = np.append(a,values=0) ## 在末尾插入 0
    ## 可以使用托马斯算法判断,对角占优
    if (abs(d)-abs(b)-abs(a)).all()>0: 
        
        d_prime = np.zeros(shape=d.shape)
        c_prime = np.zeros(shape=c.shape)
        
        for i in range(len(d_prime)):
            if i == 0:
                d_prime[i] = d[i]
                c_prime[i] = c[i]
            else:        
                d_prime[i] = d[i] - b[i]*a[i-1]/d_prime[i-1]
                c_prime[i] = c[i] - c_prime[i-1]*b[i]/d_prime[i-1]
                
        u = np.zeros(shape=c.shape)
        u[-1] = c_prime[-1]/d_prime[-1]
        
        for i in range(len(u)-1):
            u[-(i+2)] = (c_prime[-(i+2)]-a[-(i+2)]*u[-(i+1)])/d_prime[-(i+2)]
            
        return u
    
    else:
        print('该方程组不适用托马斯算法 !')
    
dic_list = []
for E in E_list:
    
    u = np.zeros(N)
    u[-1] = 1
    u_history = np.vstack([0.01*np.ones(u.shape),u]) ## 增加一行辅助值,由于计算相对误差
    
    A = -E/2.0*np.ones(shape=u.shape[0]-3)
    B = (E+1.0)*np.ones(shape=u.shape[0]-2)
    
    for i in range(max_iteration):
    
        if  (abs(u_history[-1]-u_history[-2])/(u_history[-2]+1e-10)<1e-04).all():
            
            break
        
        K = (1.0-E)*u[1:-1]+E/2.0*(u[2:]+u[:-2])
        K[-1] = K[-1]-A[-1]
        u[1:-1] = Thomas_algo(A,B,A,K)
        u_history = np.vstack([u_history,u])
    
    u_history = np.delete(u_history,0,axis=0) # 删除添加的辅助行
    
    dic = {'E':E,'u_history':u_history}
    dic_list.append(dic)

######## 结果可视化 #############################################
def find_E(E,dic_list):
    u_history_target = []
    for i in range(len(dic_list)):
        if dic_list[i]['E']==E:
            u_history_target = dic_list[i]['u_history']
            break
    if u_history_target.any():
        return u_history_target
    else:      
        print('Not Found !')

### 瞬态发展过程 ####
E_target = 1
u_history_target = find_E(E_target,dic_list)
time_target = [0,2,12,36,60,240]## 根据需要设置,注意不要超出 u_history 的范围
legend_list = ['0$\Delta$t','2$\Delta$t','12$\Delta$t','36$\Delta$t','60$\Delta$t','240$\Delta$t']

for i in time_target:
    plt.plot(u_history_target[i,:],y)

plt.xlabel('u/${u_e}$')
plt.ylabel('y/D')
plt.title('Evolution of u/${u_e}$')
plt.legend(legend_list)

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值