求解平流方程 - 周期性条件 - 使用 roll python 函数

计算科学 有限差分 Python 边界条件
2021-12-12 11:06:52

原来的帖子在 stackoverflow 上:我把它转移到这里。

我必须在数值上求解具有周期性边界条件的平流方程:u(t,0) = u(t,L),其中 L 是要求解的系统长度。

我也开始with u(0,x) = uexacte(0,x) = sin(2*pi*x/L)

这是带有循环时间的代码的主要部分(我们在这里使用FTCS scheme):

V=1
L=1
# analytical solution --------------------------
def uexacte(t,x):
    return sin(2*pi*(x-V*t)/L)

# 1. Centre FTCS (Forward Time Centered Space)
cfl = 0.25
nx = 10
tend = 1

#
dx = L/(nx-1.)
dt = cfl*dx/V
nt = int(tend/dt)+1
print "CFL=%5.2f tend=%4.1f --> %i iterations en temps"%(cfl,tend,nt)

# Arrays
x = linspace(0,L,nx)
# Bounadry condition
u0 = uexacte(0,x)

# Starting solution
t=0.0 ; u=copy(u0)

# Time loop
for i in range(1,nt):
    # FTCS
    #u[1:nx-1] = u[1:nx-1] - cfl/2*(u[2:nx] - u[0:nx-2])
    # Using roll
    u = u + - cfl/2*(roll(u,-1)- roll(u,1))
    # Update time
    t = t+dt

不明白用roll这种方式使用python函数的老师给出的解决方案:

# Using roll
u = u - cfl/2*(roll(u,-1)- roll(u,1))

有人说使用roll,我们肯定会尊重周期性边界条件,但我不明白为什么?

事实上,我的第一种方法是:

u[0] = u[nx-1]
u[1:nx-1] = u[1:nx-1] - cfl/2*(u[2:nx] - u[0:nx-2])

但这不起作用,我不知道如何以这种方式实现这个周期性条件(不使用roll函数)。

如果有人可以用 来解释这件事和诀窍roll function,那就太好了。

更新 1:

我尝试了这样的经典方法(简单的递归公式):

# Time loop
for i in range(1,nt):
    # FTCS
    u[1:nx-1] = u[1:nx-1] - cfl/2*(u[2:nx] - u[0:nx-2])

    # Try to impose periodic boundary conditions but without success
    u[0] = u[0] - cfl/2*(u[0] - u[nx-1])

    # Update time
    t = t+dt

事实上,结果很糟糕(每一边的值都不一样)。我可以在每一步都强加理论值,但在实践中,我们并不总是知道解析解。

在每一步的数值解上施加这种周期性边界条件的技巧是什么?

周期性边界条件的问题被表述为:

在此处输入图像描述

更新 2:

LonelyProf 下面给出的解决方案工作正常。谢谢

1个回答

其他语言中也会出现类似的问题,因此这不是特定于 Python 的。

NumPy 函数roll对作为其第一个参数给出的数组应用循环移位。

  • roll(u,-1)返回一个包含元素的数组u[1],u[2],u[3]...,u[nx-1],u[0]
  • roll(u,1)返回一个包含元素的数组u[nx-1],u[0],u[1]...,u[nx-3],u[nx-2]

这正是您在作业右侧想要的u,使用周期性边界访问 的每个元素两侧的元素。

您可以通过数组切片来做到这一点,但是您需要手动处理最终效果。因此,您可以编写一条语句以u[1:nx-2]根据u[0:nx-3]and更新所有的u[2:nx-1],并编写单独的语句以u[0]根据u[nx-1]and更新,并根据andu[1]更新u[nx-1]u[nx-2]u[0]

目前,您在尝试手动执行此操作时犯了错​​误(nx例如,使用非法索引,或者只是在右侧编写错误的索引)。

另一个问题是,使用诸如roll使您能够同时有效地对u. 在某些应用程序中,也许是您的应用程序,更新任何元素可能是错误的(并且肯定是不同的),然后使用右侧的更新值来更新其他元素。如果您坚持使用“手动”方法,则可以通过定义临时变量来保存更新的值来避免这种情况。或者定义一个数组du来保存根据当前值计算的变化,并在单独的语句中实际执行更新,一次全部完成。使用函数(或类似函数)可以使代码更紧凑、更简单。uu=u+duroll


[在 OP 评论之后编辑]

这是我使用临时变量的意思的示例。

utemp1=u[0] - cfl/2*(u[nx-1] - u[1]) utemp2=u[nx-1] - cfl/2*(u[nx-2] - u[0]) u[1:nx-2] = u[1:nx-2] - cfl/2*(u[0:nx-3] - u[2:nx-1]) u[0] = utemp1 u[nx-1] = utemp2