最近在等师兄数据,偶然发现github上有一个很有意思的项目,用python(其实是jupyter)学习CFD,借此机会来摸摸鱼,顺便记录一下做点笔记
ipywidgets==7.2.1
jupyter==1.0.0
numpy==1.14.3
matplotlib==2.2.2
scipy==1.1.0
sympy==1.1.1
from xxx import *
# np.linspace
myarray = numpy.linspace(0, 5, 10)
# 0-5之间产生10个点
# array([ 0. , 0.55555556, 1.11111111, 1.66666667, 2.22222222,
# 2.77777778, 3.33333333, 3.88888889, 4.44444444, 5. ])
int/int=float
)a = 5 #a is an integer 5
b = 'five' #b is a string of the word 'five'
c = 5.0 #c is a floating point 5
#%%
type(a) # int
#%%
type(b) # str
#%%
type(c) # float
缩进
来控制的,而不是像c一样的中括号myvals = numpy.array([1, 2, 3, 4, 5])
myvals[0], myvals[4] # output:1,5
myvals[5] # output: error
myvals[0:3] # output:1 2 3
copy
来解决a1 = numpy.linspace(1,5,5) # a1=1 2 3 4 5
b = a1
b[3] = 17 # b = a1 = 1 2 3 17 5
a2 = numpy.linspace(1,5,5) # a1=1 2 3 4 5
c = a2.copy()
c[3] = 17 # a2=1 2 3 4 5; c=1 2 3 17 5
这一节学到个新东西,原来jupyter里面还可以展示youtube,下次试试能不能展示bilibili
from IPython.display import YouTubeVideo
# a short video about using NumPy arrays, from Enthought
YouTubeVideo('...')
向后一阶差分
,对空间域采用向前一阶差分
,通过有限差分法对方程进行离散:# Remember: comments in python are denoted by the pound sign
import numpy #here we load numpy
from matplotlib import pyplot #here we load matplotlib
import time, sys #and load some utilities
#this makes matplotlib plots appear in the notebook (instead of a separate window)
%matplotlib inline
# 绘制网格:空间节点有41个,时间节点为25个,可以理解为解域是一个41*25的均匀网格
nx = 41 # 加大这个值,会让结果更为精确(即加密网格,但不是所有方程都会精确)
dx = 2 / (nx-1)
nt = 25 #nt is the number of timesteps we want to calculate
dt = .025 #dt is the amount of time each timestep covers (delta t)
c = 1 #assume wavespeed of c = 1
# 设置初始条件:在x属于0.5-1的时候是2,其余时刻是1
u = numpy.ones(nx) #numpy function ones()
u[int(.5 / dx):int(1 / dx + 1)] = 2 #setting u = 2 between 0.5 and 1 as per our I.C.s
pyplot.plot(numpy.linspace(0, 2, nx), u);
# 设置temp变量,用来表示上一时刻的值,即n时刻,最终计算n+1时刻的值
un = numpy.ones(nx) #initialize a temporary array
# 开始求解方程:原作者说,这种方式比较浪费资源,之后课程有更好的方式
for n in range(nt): #loop for values of n from 0 to nt, so it will run nt times
un = u.copy() ##copy the existing values of u into un
for i in range(1, nx):
u[i] = un[i] - c * dt / dx * (un[i] - un[i-1])
pyplot.plot(numpy.linspace(0, 2, nx), u);
xx=numpy.linspace(0,2,nx)
tt=numpy.linspace(0,dt*nt,nt)
x,y=numpy.meshgrid(xx,tt,indexing='xy')
pyplot.scatter(x,y)
for n in range(nt):
un = u.copy()
for i in range(1, nx):
u[i] = un[i] - un[i] * dt / dx * (un[i] - un[i-1])
数值振荡
,因为markdown的原因就不贴图了强烈推荐
去看原jupyter notebook,作者用不同的网格数x来显示一维对流方程的结果,发现在nx=85的时候出现了数值振荡import numpy
from matplotlib import pyplot
def linearconv(nx):
dx = 2 / (nx - 1)
nt = 20 #nt is the number of timesteps we want to calculate
c = 1
sigma = .5
dt = sigma * dx
u = numpy.ones(nx)
u[int(.5/dx):int(1 / dx + 1)] = 2
un = numpy.ones(nx)
for n in range(nt): #iterate through time
un = u.copy() ##copy the existing values of u into un
for i in range(1, nx):
u[i] = un[i] - c * dt / dx * (un[i] - un[i-1])
pyplot.plot(numpy.linspace(0, 2, nx), u)
二阶中心差分
:现在扩散项进行泰勒展开,然后两者相加即可。u i + 1 = u i + Δ x ∂ u ∂ x ∣ i + Δ x 2 2 ∂ 2 u ∂ x 2 ∣ i + Δ x 3 3 ! ∂ 3 u ∂ x 3 ∣ i + O ( Δ x 4 ) u_{i+1} = u_i + \Delta x \frac{\partial u}{\partial x}\bigg|_i + \frac{\Delta x^2}{2} \frac{\partial ^2 u}{\partial x^2}\bigg|_i + \frac{\Delta x^3}{3!} \frac{\partial ^3 u}{\partial x^3}\bigg|_i + O(\Delta x^4) ui+1=ui+Δx∂x∂u i+2Δx2∂x2∂2u i+3!Δx3∂x3∂3u i+O(Δx4)
u i − 1 = u i − Δ x ∂ u ∂ x ∣ i + Δ x 2 2 ∂ 2 u ∂ x 2 ∣ i − Δ x 3 3 ! ∂ 3 u ∂ x 3 ∣ i + O ( Δ x 4 ) u_{i-1} = u_i - \Delta x \frac{\partial u}{\partial x}\bigg|_i + \frac{\Delta x^2}{2} \frac{\partial ^2 u}{\partial x^2}\bigg|_i - \frac{\Delta x^3}{3!} \frac{\partial ^3 u}{\partial x^3}\bigg|_i + O(\Delta x^4) ui−1=ui−Δx∂x∂u i+2Δx2∂x2∂2u i−3!Δx3∂x3∂3u i+O(Δx4)
u i + 1 + u i − 1 = 2 u i + Δ x 2 ∂ 2 u ∂ x 2 ∣ i + O ( Δ x 4 ) u_{i+1} + u_{i-1} = 2u_i+\Delta x^2 \frac{\partial ^2 u}{\partial x^2}\bigg|_i + O(\Delta x^4) ui+1+ui−1=2ui+Δx2∂x2∂2u i+O(Δx4)
∂ 2 u ∂ x 2 = u i + 1 − 2 u i + u i − 1 Δ x 2 + O ( Δ x 2 ) \frac{\partial ^2 u}{\partial x^2}=\frac{u_{i+1}-2u_{i}+u_{i-1}}{\Delta x^2} + O(\Delta x^2) ∂x2∂2u=Δx2ui+1−2ui+ui−1+O(Δx2)
3. 同理,非稳态项采用一阶向前差分,扩散项采用二阶中心差分,最终得到:
u i n + 1 − u i n Δ t = ν u i + 1 n − 2 u i n + u i − 1 n Δ x 2 \frac{u_{i}^{n+1}-u_{i}^{n}}{\Delta t}=\nu\frac{u_{i+1}^{n}-2u_{i}^{n}+u_{i-1}^{n}}{\Delta x^2} Δtuin+1−uin=νΔx2ui+1n−2uin+ui−1n
u i n + 1 = u i n + ν Δ t Δ x 2 ( u i + 1 n − 2 u i n + u i − 1 n ) u_{i}^{n+1}=u_{i}^{n}+\frac{\nu\Delta t}{\Delta x^2}(u_{i+1}^{n}-2u_{i}^{n}+u_{i-1}^{n}) uin+1=uin+Δx2νΔt(ui+1n−2uin+ui−1n)
4. 全部代码如下:
import numpy
from matplotlib import pyplot
%matplotlib inline
nx = 41
dx = 2 / (nx - 1)
nt = 20 #the number of timesteps we want to calculate
nu = 0.3 #the value of viscosity,粘性系数
sigma = .2 #sigma is a parameter, we'll learn more about it later
dt = sigma * dx**2 / nu # 这个时候库朗数变了,多了粘性项,具体看最终形式(v*dt/dx**2)
# 设置初始条件,同之前的step
u = numpy.ones(nx)
u[int(.5 / dx):int(1 / dx + 1)] = 2
# 存放前一时刻-n-时刻的速度值
un = numpy.ones(nx)
# 开始迭代
for n in range(nt):
un = u.copy()
for i in range(1, nx - 1):
u[i] = un[i] + nu * dt / dx**2 * (un[i+1] - 2 * un[i] + un[i-1])
# 这里nu * dt / dx**2===sigma
pyplot.plot(numpy.linspace(0, 2, nx), u);
非稳态项
采用一阶向前差分,对对流项
采用一阶向后差分,对扩散项
采用二阶中心差分,离散后得到如下结果:symbolic
,是一种符号表示的库import numpy
import sympy
from sympy import init_printing # 用于输出打印
init_printing(use_latex=True)
# 用symbols来表示\phi
x, nu, t=sympy.symbols('x nu t')
phi = (sympy.exp(-(x - 4 * t)**2 / (4 * nu * (t + 1))) +
sympy.exp(-(x - 4 * t - 2 * sympy.pi)**2 / (4 * nu * (t + 1))))
# 对x进行求导
phiprime = phi.diff(x)
print(phiprime)
# output
# -(-8*t + 2*x)*exp(-(-4*t + x)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)) - (-8*t + 2*x - 4*pi)*exp(-(-4*t + x - 2*pi)**2/(4*nu*(t + 1)))/(4*nu*(t + 1))
from sympy.utilities.lambdify import lambdify
u = -2 * nu * (phiprime / phi) + 4
ufunc = lambdify((t, x, nu), u)
print(ufunc(1, 4, 3))
# output: 3.49170664206
复杂初始条件+周期性边界条件
的一维Burgers方程from matplotlib import pyplot
%matplotlib inline
###variable declarations
nx = 101
nt = 100
dx = 2 * numpy.pi / (nx - 1)
nu = .07
dt = dx * nu
x = numpy.linspace(0, 2 * numpy.pi, nx)
un = numpy.empty(nx)
t = 0
# 计算u
u = numpy.asarray([ufunc(t, x0, nu) for x0 in x])
u
# 画图
pyplot.figure(figsize=(11, 7), dpi=100)
pyplot.plot(x, u, marker='o', lw=2)
pyplot.xlim([0, 2 * numpy.pi])
pyplot.ylim([0, 10]);
for n in range(nt):
un = u.copy()
# 计算1-N-1的结果
for i in range(1, nx-1):
u[i] = un[i] - un[i] * dt / dx *(un[i] - un[i-1]) + nu * dt / dx**2 *(un[i+1] - 2 * un[i] + un[i-1])
# 计算边界结果
# 对于i=0的计算结果,取u[-1]=u[0],即最后一个点的结果=第一个点的结果
u[0] = un[0] - un[0] * dt / dx * (un[0] - un[-2]) + nu * dt / dx**2 *(un[1] - 2 * un[0] + un[-2])
u[-1] = u[0]
u_analytical = numpy.asarray([ufunc(nt * dt, xi, nu) for xi in x])
# 画图
pyplot.figure(figsize=(11, 7), dpi=100)
pyplot.plot(x,u, marker='o', lw=2, label='Computational')
pyplot.plot(x, u_analytical, label='Analytical')
pyplot.xlim([0, 2 * numpy.pi])
pyplot.ylim([0, 10])
pyplot.legend();