当我尝试使用-fcheck=all
编译代码时,出现运行时错误,因为似乎我超出了数组维数的范围。它来自下面显示的我的代码部分。我认为这是因为我在i,j上的循环仅从-ny
到ny
,从-nx
到nx
,但是我尝试使用i+1,j+1,i-1,j-1
上的点带我走出了数组的界限。当j
上的循环从-ny
开始时,它需要j-1
,所以由于我要访问-ny-1
,因此它立即使我越界。 j=ny, i=-nx,nx
时类似。
我的问题是,如何使用最少的代码有效地解决此问题?
我需要在边界上正确定义array grad(1,i,j)
,并且需要完全按照下面等式的右侧进行定义,我只是不知道执行此操作的有效方法。我可以分别明确定义grad(1,nx,j), grad(1,-nx,j), etc,
,并且仅循环遍历i=-nx+1,nx-1,j=-ny+1,ny-1
,但这会导致很多重复的代码,而且我有很多这样的数组,因此我认为这不是逻辑/有效的方法。如果这样做,我将得到数百行重复的代码,这使得调试非常困难。谢谢。
integer :: i,j
integer, parameter :: nx = 50, ny = 50
complex, dimension (3,-nx:nx,-ny:ny) :: grad,psi
real, parameter :: h = 0.1
do j = -ny,ny
do i = -nx,nx
psi(1,i,j) = sin(i*h)+sin(j*h)
psi(2,i,j) = sin(i*h)+sin(j*h)
psi(3,i,j) = sin(i*h)+sin(j*h)
end do
end do
do j = -ny,ny
do i = -nx,nx
grad(1,i,j) = (psi(1,i+1,j)+psi(1,i-1,j)+psi(1,i,j+1)+psi(1,i,j-1)-4*psi(1,i,j))/h**2 &
- (psi(2,i+1,j)-psi(2,i,j))*psi(1,i,j)/h &
- (psi(3,i,j+1)-psi(3,i,j))*psi(1,i,j)/h &
- psi(2,i,j)*(psi(1,i+1,j)-psi(1,i,j))/h &
- psi(3,i,j)*(psi(1,i,j+1)-psi(1,i,j))/h
end do
end do
如果我直接为grad(1,nx,j), grad(1,-nx,j)
执行此操作,则将由
do j = -ny+1,ny-1
grad(1,nx,j) = (psi(1,nx,j)+psi(1,nx-2,j)+psi(1,nx,j+1)+psi(1,nx,j-1)-2*psi(1,nx-1,j)-2*psi(1,nx,j))/h**2 &
- (psi(2,nx,j)-psi(2,nx-1,j))*psi(1,nx,j)/h &
- (psi(3,nx,j+1)-psi(3,nx,j))*psi(1,nx,j)/h &
- psi(2,nx,j)*(psi(1,nx,j)-psi(1,nx-1,j))/h &
- psi(3,nx,j)*(psi(1,nx,j+1)-psi(1,nx,j))/h
grad(1,-nx,j) = (psi(1,-nx+2,j)+psi(1,-nx,j)+psi(1,-nx,j+1)+psi(1,-nx,j-1)-2*psi(1,-nx+1,j)-2*psi(1,-nx,j))/h**2 &
- (psi(2,-nx+1,j)-psi(2,-nx,j))*psi(1,-nx,j)/h &
- (psi(3,-nx,j+1)-psi(3,-nx,j))*psi(1,-nx,j)/h &
- psi(2,-nx,j)*(psi(1,-nx+1,j)-psi(1,-nx,j))/h &
- psi(3,-nx,j)*(psi(1,-nx,j+1)-psi(1,-nx,j))/h
end do
答案 0 :(得分:2)
一种可能的方法是对边界使用附加的索引变量,该变量是从原始索引修改而来的,以避免越界。我的意思是这样的:
do j = -ny,ny
jj = max(min(j, ny-1), -ny+1)
do i = -nx,nx
ii = max(min(i, nx-1), -nx+1)
grad(1,i,j) = (psi(1,ii+1,j)+psi(1,ii-1,j)+psi(1,i,jj+1)+psi(1,i,jj-1)-4*psi(1,i,j))/h**2 &
- (psi(2,ii+1,j)-psi(2,ii,j))*psi(1,i,j)/h &
- (psi(3,i,jj+1)-psi(3,i,jj))*psi(1,i,j)/h &
- psi(2,i,j)*(psi(1,ii+1,j)-psi(1,ii,j))/h &
- psi(3,i,j)*(psi(1,i,jj+1)-psi(1,i,jj))/h
end do
end do
我很难编写适当的代码,因为似乎您在问题中提出的代码中修剪了原始表达式的一部分,但我希望您理解该想法并将其正确地应用于您的逻辑。
意见
if
条件或函数调用)。如@evets所建议的那样,使用“幽灵细胞”可能会更有效。您应该进行概要分析和比较。dimension(-nx:nx,-ny:ny,3)
。 Fortran以列优先顺序存储数组,并且当您访问“ x”和“ y”附近的值时,它们将是不连续的存储位置,因为固定的“ other”维是最左侧的,因此意味着更少的缓存命中。答案 1 :(得分:1)
可以用伪代码完成
do j = -ny, ny
if (j == -ny) then
p1jm1 = XXXXX ! Some boundary condition
else
p1jm1 = psi(1,i,j-1)
end if
if (j == ny) then
p1jp1 = YYYYY ! Some other boundary condition
else
p1jp1 = psi(1,i,j+1)
end if
do i = -nx, ny
grad(1,i,j) = ... term involving p1jm1 ... term involving p1jp1 ...
...
end do
end do
j循环还不错,因为您要添加2 * 2 * ny条件。内部i循环为每个j迭代添加2 * 2 * nx个条件(或2 * 2 * ny * 2 * 2 * nx个条件)。请注意,您需要为每个psi临时设置一个三元组索引,这些索引是唯一的,即psi(1,i,j+1)
,psi(1,i,j-1)
和psi(3,i,j+1)
。