使用周期性网格时,并行和顺序运行在 FiPy 中给出不同的结果
Parallel and sequential runs give different results in FiPy when using periodic mesh
我有运行以下代码来模拟二维网格中围绕圆柱体的流动:
from fipy import CellVariable, FaceVariable, Grid2D, DiffusionTerm, ImplicitSourceTerm, PeriodicGrid2DTopBottom, DistanceVariable, Viewer
from fipy.tools import numerix
L = 1.0
N = 50
dL = L / N
viscosity = 1
U = 1.
#0.8 for pressure and 0.5 for velocity are typical relaxation values for SIMPLE
pressureRelaxation = 0.8
velocityRelaxation = 0.5
if __name__ == '__main__':
sweeps = 500
else:
sweeps = 5
mesh = PeriodicGrid2DTopBottom(nx=N, ny=N, dx=dL, dy=dL)
pressure = CellVariable(mesh=mesh, name='pressure')
pressureCorrection = CellVariable(mesh=mesh)
xVelocity = CellVariable(mesh=mesh, name='X velocity')
yVelocity = CellVariable(mesh=mesh, name='Y velocity')
velocity = FaceVariable(mesh=mesh, rank=1)
pfi=3000.
lfi=0.01
x, y = mesh.cellCenters
var1 = DistanceVariable(name='distance to center', mesh=mesh, value=numerix.sqrt((x-N*dL/2.)**2+(y-N*dL/2.)**2))
rad=0.1
pi_fi= CellVariable(mesh=mesh, value=0.,name='Fluid-interface energy map')
pi_fi.setValue(pfi*numerix.exp(-1.*(var1-rad)/lfi), where=(var1 > rad) )
pi_fi.setValue(pfi, where=(var1 <= rad))
xVelocityEq = DiffusionTerm(coeff=viscosity) - pressure.grad.dot([1., 0.]) - ImplicitSourceTerm(pi_fi)
yVelocityEq = DiffusionTerm(coeff=viscosity) - pressure.grad.dot([0., 1.]) - ImplicitSourceTerm(pi_fi)
ap = CellVariable(mesh=mesh, value=1.)
coeff = 1./ ap.arithmeticFaceValue*mesh._faceAreas * mesh._cellDistances
pressureCorrectionEq = DiffusionTerm(coeff=coeff) - velocity.divergence
from fipy.variables.faceGradVariable import _FaceGradVariable
volume = CellVariable(mesh=mesh, value=mesh.cellVolumes, name='Volume')
contrvolume=volume.arithmeticFaceValue
xVelocity.constrain(U, mesh.facesLeft | mesh.facesRight)
yVelocity.constrain(0., mesh.facesLeft | mesh.facesRight)
X, Y = mesh.faceCenters
pressureCorrection.constrain(0., mesh.facesLeft & (Y < dL))
if __name__ == '__main__':
viewer = Viewer(vars=(pressure, xVelocity, yVelocity, velocity),
xmin=0., xmax=1., ymin=0., ymax=1., colorbar=True)
from builtins import range
for sweep in range(sweeps):
## solve the Stokes equations to get starred values
xVelocityEq.cacheMatrix()
xres = xVelocityEq.sweep(var=xVelocity,
underRelaxation=velocityRelaxation)
xmat = xVelocityEq.matrix
yres = yVelocityEq.sweep(var=yVelocity,
underRelaxation=velocityRelaxation)
## update the ap coefficient from the matrix diagonal
ap[:] = -numerix.asarray(xmat.takeDiagonal())
## update the face velocities based on starred values with the
## Rhie-Chow correction.
## cell pressure gradient
presgrad = pressure.grad
## face pressure gradient
facepresgrad = _FaceGradVariable(pressure)
velocity[0] = xVelocity.arithmeticFaceValue \
+ contrvolume / ap.arithmeticFaceValue * \
(presgrad[0].arithmeticFaceValue-facepresgrad[0])
velocity[1] = yVelocity.arithmeticFaceValue \
+ contrvolume / ap.arithmeticFaceValue * \
(presgrad[1].arithmeticFaceValue-facepresgrad[1])
velocity[..., mesh.exteriorFaces.value] = 0.
velocity[0, mesh.facesLeft.value] = U
velocity[0, mesh.facesRight.value] = U
## solve the pressure correction equation
pressureCorrectionEq.cacheRHSvector()
## left bottom point must remain at pressure 0, so no correction
pres = pressureCorrectionEq.sweep(var=pressureCorrection)
rhs = pressureCorrectionEq.RHSvector
## update the pressure using the corrected value
pressure.setValue(pressure + pressureRelaxation * pressureCorrection )
## update the velocity using the corrected pressure
xVelocity.setValue(xVelocity - pressureCorrection.grad[0] / \
ap * mesh.cellVolumes)
yVelocity.setValue(yVelocity - pressureCorrection.grad[1] / \
ap * mesh.cellVolumes)
if __name__ == '__main__':
if sweep%10 == 0:
print('sweep:', sweep, ', x residual:', xres, \
', y residual', yres, \
', p residual:', pres, \
', continuity:', max(abs(rhs)))
viewer.plot()
print(pressure.globalValue[..., 510])
print(xVelocity.globalValue[..., 510])
print(yVelocity.globalValue[..., 510])
这应该用 top/bottom 周期条件和网格中心的圆柱体求解 Navier-stokes 方程(这就是我的方程中有隐式源项的原因)。速度在左边界和右边界处等于 1,并且平行于 x 轴。这个例子大致对应于通过许多等距圆柱形障碍物的流动。当我 运行 它 没有并行计算 时,压力和速度曲线看起来没问题。为单元格 510 打印的值为 2.788(压力)、1.104(xvelocity)和 -0.289(yvelocity).
但是,当我 运行 它处于并行模式时(比如使用 2 个处理器),配置文件看起来很奇怪。对于速度剖面,y= 0.2 和 y= 0.8 之间的绘图与 y=0 和 y=1 之间的顺序计算的绘图或多或少相似。但压力曲线却大不相同。为单元格 510 打印的值为 -3.163(压力)、1.209(xvelocity)和 -0.044(yvelocity).
为了使用 Grid2D 而不是 PeriodicGrid2DTopBottom,我加入了额外的边界条件,我认为这等同于在此示例中使用周期性网格。那么新的 BC 是:
xVelocity.constrain(U, mesh.facesLeft | mesh.facesRight)
xVelocity.faceGrad.constrain(mesh.faceNormals * 0., where=mesh.facesBottom | mesh.facesTop)
yVelocity.constrain(0., mesh.exteriorFaces)
通过这样做,我通过 运行ning 与两个处理器顺序或并行获得相同的输出:2.784(压力)、1.104(xvelocity)和 -0.290(yvelocity) .
当我使用周期性网格时,我的边界条件是否未指定? (我想这可以解释同一问题的两种不同解决方案)或者并行计算和周期性网格由于某种原因不能相处?
不幸的是,周期性网格目前 broken for parallel runs。
我有运行以下代码来模拟二维网格中围绕圆柱体的流动:
from fipy import CellVariable, FaceVariable, Grid2D, DiffusionTerm, ImplicitSourceTerm, PeriodicGrid2DTopBottom, DistanceVariable, Viewer
from fipy.tools import numerix
L = 1.0
N = 50
dL = L / N
viscosity = 1
U = 1.
#0.8 for pressure and 0.5 for velocity are typical relaxation values for SIMPLE
pressureRelaxation = 0.8
velocityRelaxation = 0.5
if __name__ == '__main__':
sweeps = 500
else:
sweeps = 5
mesh = PeriodicGrid2DTopBottom(nx=N, ny=N, dx=dL, dy=dL)
pressure = CellVariable(mesh=mesh, name='pressure')
pressureCorrection = CellVariable(mesh=mesh)
xVelocity = CellVariable(mesh=mesh, name='X velocity')
yVelocity = CellVariable(mesh=mesh, name='Y velocity')
velocity = FaceVariable(mesh=mesh, rank=1)
pfi=3000.
lfi=0.01
x, y = mesh.cellCenters
var1 = DistanceVariable(name='distance to center', mesh=mesh, value=numerix.sqrt((x-N*dL/2.)**2+(y-N*dL/2.)**2))
rad=0.1
pi_fi= CellVariable(mesh=mesh, value=0.,name='Fluid-interface energy map')
pi_fi.setValue(pfi*numerix.exp(-1.*(var1-rad)/lfi), where=(var1 > rad) )
pi_fi.setValue(pfi, where=(var1 <= rad))
xVelocityEq = DiffusionTerm(coeff=viscosity) - pressure.grad.dot([1., 0.]) - ImplicitSourceTerm(pi_fi)
yVelocityEq = DiffusionTerm(coeff=viscosity) - pressure.grad.dot([0., 1.]) - ImplicitSourceTerm(pi_fi)
ap = CellVariable(mesh=mesh, value=1.)
coeff = 1./ ap.arithmeticFaceValue*mesh._faceAreas * mesh._cellDistances
pressureCorrectionEq = DiffusionTerm(coeff=coeff) - velocity.divergence
from fipy.variables.faceGradVariable import _FaceGradVariable
volume = CellVariable(mesh=mesh, value=mesh.cellVolumes, name='Volume')
contrvolume=volume.arithmeticFaceValue
xVelocity.constrain(U, mesh.facesLeft | mesh.facesRight)
yVelocity.constrain(0., mesh.facesLeft | mesh.facesRight)
X, Y = mesh.faceCenters
pressureCorrection.constrain(0., mesh.facesLeft & (Y < dL))
if __name__ == '__main__':
viewer = Viewer(vars=(pressure, xVelocity, yVelocity, velocity),
xmin=0., xmax=1., ymin=0., ymax=1., colorbar=True)
from builtins import range
for sweep in range(sweeps):
## solve the Stokes equations to get starred values
xVelocityEq.cacheMatrix()
xres = xVelocityEq.sweep(var=xVelocity,
underRelaxation=velocityRelaxation)
xmat = xVelocityEq.matrix
yres = yVelocityEq.sweep(var=yVelocity,
underRelaxation=velocityRelaxation)
## update the ap coefficient from the matrix diagonal
ap[:] = -numerix.asarray(xmat.takeDiagonal())
## update the face velocities based on starred values with the
## Rhie-Chow correction.
## cell pressure gradient
presgrad = pressure.grad
## face pressure gradient
facepresgrad = _FaceGradVariable(pressure)
velocity[0] = xVelocity.arithmeticFaceValue \
+ contrvolume / ap.arithmeticFaceValue * \
(presgrad[0].arithmeticFaceValue-facepresgrad[0])
velocity[1] = yVelocity.arithmeticFaceValue \
+ contrvolume / ap.arithmeticFaceValue * \
(presgrad[1].arithmeticFaceValue-facepresgrad[1])
velocity[..., mesh.exteriorFaces.value] = 0.
velocity[0, mesh.facesLeft.value] = U
velocity[0, mesh.facesRight.value] = U
## solve the pressure correction equation
pressureCorrectionEq.cacheRHSvector()
## left bottom point must remain at pressure 0, so no correction
pres = pressureCorrectionEq.sweep(var=pressureCorrection)
rhs = pressureCorrectionEq.RHSvector
## update the pressure using the corrected value
pressure.setValue(pressure + pressureRelaxation * pressureCorrection )
## update the velocity using the corrected pressure
xVelocity.setValue(xVelocity - pressureCorrection.grad[0] / \
ap * mesh.cellVolumes)
yVelocity.setValue(yVelocity - pressureCorrection.grad[1] / \
ap * mesh.cellVolumes)
if __name__ == '__main__':
if sweep%10 == 0:
print('sweep:', sweep, ', x residual:', xres, \
', y residual', yres, \
', p residual:', pres, \
', continuity:', max(abs(rhs)))
viewer.plot()
print(pressure.globalValue[..., 510])
print(xVelocity.globalValue[..., 510])
print(yVelocity.globalValue[..., 510])
这应该用 top/bottom 周期条件和网格中心的圆柱体求解 Navier-stokes 方程(这就是我的方程中有隐式源项的原因)。速度在左边界和右边界处等于 1,并且平行于 x 轴。这个例子大致对应于通过许多等距圆柱形障碍物的流动。当我 运行 它 没有并行计算 时,压力和速度曲线看起来没问题。为单元格 510 打印的值为 2.788(压力)、1.104(xvelocity)和 -0.289(yvelocity).
但是,当我 运行 它处于并行模式时(比如使用 2 个处理器),配置文件看起来很奇怪。对于速度剖面,y= 0.2 和 y= 0.8 之间的绘图与 y=0 和 y=1 之间的顺序计算的绘图或多或少相似。但压力曲线却大不相同。为单元格 510 打印的值为 -3.163(压力)、1.209(xvelocity)和 -0.044(yvelocity).
为了使用 Grid2D 而不是 PeriodicGrid2DTopBottom,我加入了额外的边界条件,我认为这等同于在此示例中使用周期性网格。那么新的 BC 是:
xVelocity.constrain(U, mesh.facesLeft | mesh.facesRight)
xVelocity.faceGrad.constrain(mesh.faceNormals * 0., where=mesh.facesBottom | mesh.facesTop)
yVelocity.constrain(0., mesh.exteriorFaces)
通过这样做,我通过 运行ning 与两个处理器顺序或并行获得相同的输出:2.784(压力)、1.104(xvelocity)和 -0.290(yvelocity) .
当我使用周期性网格时,我的边界条件是否未指定? (我想这可以解释同一问题的两种不同解决方案)或者并行计算和周期性网格由于某种原因不能相处?
不幸的是,周期性网格目前 broken for parallel runs。