使用 WENO 和 ENO 方案在 Python 中实现 1D Advection

计算科学 pde Python 抛物线pde 平流 数值建模
2021-12-11 00:37:40

我正在尝试使用 WENO 和 ENO 方案实现一维平流求解器。

\begin{方程} \frac{\partial u}{\partial t} + \frac{\partial f(u)}{\partial x} =0 \end{equation}

其中:

\begin{方程} f(u) = C\,u \end{方程}

离散为:

\begin{方程} \frac{u^{n+1}_j-u^{n}_j}{\Delta t} + \frac{F_{j+1/2}-F_{j-1/2} }{\Delta x} =0 \end{方程}

我已经将Jan S Hesthaven Matlab 实现翻译成 Python。

这就是我们如何调用ENOWENO例程

from numpy import *
nx = 81
dx = 2./(nx-1)
x = linspace(0,2,nx)
nt = 25    
dt = .02  
c = 1.      #assume wavespeed of c = 1
u = zeros(nx)      #numpy function ones()
u[.5/dx : 1/dx+1]=2  #setting u = 2 between 0.5 and 1 as per our I.C.s
k = 3 # number of weights Order= 2*k-1
gc = k-1 #number of ghost cells 
#adding ghost cells 
gcr=x[-1]+linspace(1,gc,gc)*dx
gcl=x[0]+linspace(-gc,-1,gc)*dx
xc = append(x,gcr)
xc = append(gcl,xc)
uc = append(u,u[-gc:])
uc = append(u[0:gc],uc)

for n in range(1,nt):  
    un = uc.copy() 
    for i in range(1,nx): 
        xloc = xc[i-(k-1):i+k]
        floc = c*uc[i-(k-1):i+k]
        #f_left,f_right = ENO(xloc,floc,k)
        f_left,f_right = WENO(xloc,floc,k)        
        uc[i] = un[i]-dt/dx*(f_right-f_left)

最后,对于 WENO 或 ENO,我得到相同的初始条件

我知道了

这就是我们应该使用朴素的欧拉积分得到的结果。

for n in range(1,nt):  
    un = u.copy() 
    for i in range(1,nx): 
        u[i] = un[i]-c*dt/dx*(un[i]-un[i-1]) 

由于 Δx=(ntΔt)C=(250.02)1=0.5,波向右位移 0.5 个单位。

朴素的欧拉

我应该如何使用从 WENO 和 ENO 获得的通量进行一维平流方程的简单一阶欧拉积分?或者您是否使用 WENO 或 ENO 方案实现了 1D Advection?

这就是我这样做的方式,但是通量($F_{j+1/2}=$和 $F_{j-1/2}=$ )太小而无法产生任何更新。看来我需要对助焊剂使用逆风。Fj+1/2= f_rightFj1/2=f_left

ujn+1=ujnΔtΔx(Fj+1/2Fj1/2)

ps:仅供参考,这些是我正在使用的ENO和WENO例程:

def ENOweights(k,r):
    #Purpose: compute weights c_rk in ENO expansion 
    # v_[i+1/2] = \sum_[j=0]^[k-1] c_[rj] v_[i-r+j]
    #where k = order and r = shift 

    c = zeros(k)

    for j in range(0,k):
            de3 = 0.
            for m in range(j+1,k+1):
                #compute denominator 
                de2 = 0.
                for l in range(0,k+1):
                    #print 'de2:',de2
                    if l is not m:
                        de1 = 1.
                        for q in range(0,k+1):
                            #print 'de1:',de1
                            if (q is not m) and (q is not l):
                                de1 = de1*(r-q+1)


                        de2 = de2 + de1


                #compute numerator 
                de1 = 1.
                for l in range(0,k+1):
                    if (l is not m):
                        de1 = de1*(m-l)

                de3 = de3 + de2/de1


            c[j] = de3


    return c

def nddp(X,Y):
    #Newton's divided difference table 
    #the input are two vectors X and Y that represent points 

    n = len(X)

    DD = zeros((n,n+1))

    #inserting x into 1st column of DD-table 
    DD[:,0]=X

    #inserting y into 2nd column of DD-table
    DD[:,1]=Y

    #creates divided difference coefficients 
    #e.g: D[0,0] = (Y[1]-Y[0])/(X[1]-X[0])

    for j in range(0,n-1):
        for k in range(0,n-j-1): #j goes from 0 to n-2
            DD[k,j+2]= (DD[k+1,j+1]-DD[k,j+1])/(DD[k+j+1,0]-DD[k,0])

    return DD

def ENO(xloc, uloc, k):
    #Purpose: compute the left and right cell interface values using an ENO 
    #Approach based on 2k-1 long vectors uloc with cell k 

    #treat special case of k=1 - no stencil to select 
    if (k==1):
        ul = uloc[0]
        ur = uloc[0]

    #Apply ENO procedure 
    S = zeros(k,dtype=int)
    S[0] = k
    for kk in range (0,k-1):
        #print 'S:',S
        #left stencil
        xvec = zeros(k)
        uvec = zeros(k)
        Sindxl = append(S[0]-1, S[0:kk+1])-1
        xvec = xloc[Sindxl]
        uvec = uloc[Sindxl]
        DDl = nddp(xvec,uvec)
        Vl = abs(DDl[0,kk+2])

        #right stencil 
        xvec = zeros(k)
        uvec = zeros(k)
        Sindxr = append(S[0:kk+1], S[kk]+1)-1
        xvec = xloc[Sindxr]
        uvec = uloc[Sindxr]
        DDr = nddp(xvec,uvec)
        Vr = abs(DDr[0,kk+2])

        #choose stencil through divided differences 
        if (Vr>Vl):
            #print 'Vr>Vl'
            S[0:kk+2] = Sindxl+1
        else:
            S[0:kk+2] = Sindxr+1

    #Compute stencil shift 'r'
    r = k - S[0]

    #Compute weights for stencil 
    cr = ENOweights(k,r)
    cl = ENOweights(k,r-1)

    #Compute cell interface values 
    ur = 0 
    ul = 0 
    for i in range(0,k):
        ur = ur + cr[i]*uloc[S[i]-1]
        ul = ul + cl[i]*uloc[S[i]-1]

    return (ul,ur)

def WENO(xloc, uloc, k):
    #Purpose: compute the left and right cell interface values using ENO 
    #approach based on 2k-1 long vectors uloc with cell k 

    #treat special case of k = 1 no stencil to select 
    if (k==1):
        ul = uloc[0]
        ur = uloc[1]

    #Apply WENO procedure 
    alphal = zeros(k)
    alphar = zeros(k)
    omegal = zeros(k)
    omegar = zeros(k)
    beta = zeros(k)
    d = zeros(k)
    vareps= 1e-6

    #Compute k values of xl and xr based on different stencils 
    ulr = zeros(k)
    urr = zeros(k)

    for r in  range(0,k):
        cr = ENOweights(k,r)
        cl = ENOweights(k,r-1)

        for i in range(0,k):
            urr[r] = urr[r] + cr[i]*uloc[k-r+i-1] 
            ulr[r] = ulr[r] + cl[i]*uloc[k-r+i-1] 


    #setup WENO coefficients for different orders -2k-1
    if (k==2):
        d[0]=2/3.
        d[1]=1/3.
        beta[0] = (uloc[2]-uloc[1])**2
        beta[1] = (uloc[1]-uloc[0])**2


    if(k==3):
        d[0] = 3/10. 
        d[1] = 3/5.
        d[2] = 1/10.
        beta[0] = 13/12.*(uloc[2]-2*uloc[3]+uloc[4])**2 + 1/4.*(3*uloc[2]-4*uloc[3]+uloc[4])**2
        beta[1] = 13/12.*(uloc[1]-2*uloc[2]+uloc[3])**2 + 1/4.*(uloc[1]-uloc[3])**2
        beta[2] = 13/12.*(uloc[0]-2*uloc[1]+uloc[2])**2 + 1/4.*(3*uloc[2]-4*uloc[1]+uloc[0])**2

    #compute alpha parameters
    for r in range(0,k):
        alphar[r] = d[r]/(vareps+beta[r])**2
        alphal[r] = d[k-r-1]/(vareps+beta[r])**2

    #Compute WENO weights parameters
    for r in range(0,k):
        omegal[r] = alphal[r]/alphal.sum()
        omegar[r] = alphar[r]/alphar.sum()

    #Compute cell interface values
    ul = 0 
    ur = 0 
    for r in range(0,k):
        ul = ul + omegal[r]*ulr[r]
        ur = ur + omegar[r]*urr[r]

    return (ul,ur)
1个回答

混淆是误导变量 $F_{j-1/2}$ 和 $F_{j+1/2}$ with and ,它们是完全不同的。Fj1/2 and Fj+1/2 with f_leftf_right

f_leftf_right是一个面的插值通量。然后它们必须使用平流速度逆风来计算特定单元面的通量。这意味着如果 $C>0$ 我们采取,否则我们采取C>0 we take f_leftf_right

gs = zeros((nx+2*gc,nt))
flux = zeros(nx+2*gc)

for n in range(1,nt):  
    un = uc.copy() 
    for i in range(gc,nx-1+gc): #i=2
        xloc = xc[i-(k-1):i+k] #i+k-1-(i-(k-1)-1) = 2k -1 
        uloc = uc[i-(k-1):i+k]
        f_left,f_right = ENO(xloc,uloc,k)
        #f_left,f_right = WENO(xloc,uloc,k)
        #upwind flux
        flux[i]=0.5*(c+fabs(c))*f_left + 0.5*(c-fabs(c))*f_right

    for i in range(gc,nx-gc):
        if c>0:
            uc[i] = un[i]-dt/dx*(flux[i]-flux[i-1])
        else:
            uc[i] = un[i]-dt/dx*(flux[i+1]-flux[i])

最后这是平流标量

在此处输入图像描述