Performance 通过重新构造if语句/do循环避免重复代码

Performance 通过重新构造if语句/do循环避免重复代码,performance,if-statement,fortran,Performance,If Statement,Fortran,嗨,我试图在我的网格中的许多不同的空间点上对我的函数施加一个特定的条件。然而,我复制了很多代码,而且效率越来越低 我如何通过简单地使用do循环来完成我需要做的事情?我试图对我的函数施加的具体条件在所有不同的空间点上都是相同的,所以我想有一种方法可以在一个循环中完成所有这些。或者如何将所有这些If/else If语句组合成一个语句?一定有比我现在做的更有效的方法 我在下面提供了一个示例代码 FUNCTION grad(psi) IMPLICIT NONE INTEGER :: i,j,kk,ll

嗨,我试图在我的网格中的许多不同的空间点上对我的函数施加一个特定的条件。然而,我复制了很多代码,而且效率越来越低

我如何通过简单地使用do循环来完成我需要做的事情?我试图对我的函数施加的具体条件在所有不同的空间点上都是相同的,所以我想有一种方法可以在一个循环中完成所有这些。或者如何将所有这些If/else If语句组合成一个语句?一定有比我现在做的更有效的方法

我在下面提供了一个示例代码

FUNCTION grad(psi)
IMPLICIT NONE
INTEGER :: i,j,kk,ll
INTEGER, PARAMETER :: nx = 24, ny = 24
COMPLEX,DIMENSION(3,3,-nx:nx, -ny:ny) :: psi, grad
REAL :: pi
REAL :: f0
INTEGER :: nxx, nyy

nxx = nx/2
nyy = ny/2

pi = 4*atan(1.0)
f0 = pi**2*1.3

DO i=-nx+1,nx-1 !spatial points
DO j=-ny+1,ny-1 !spatial points

   IF ( i == 0 .AND. j == 0 .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE IF ( i == nxx .AND. j == nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == -nyy .AND. i == j) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nxx .AND. j == -nyy) THEN ! I have lots of statements like this

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == -nxx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

  ELSE IF ( i == -nxx .AND. j == ny) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == -nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

   ELSE IF ( i == nx .AND. j == nyy) THEN

    DO kk=1,3

         grad(kk,1,i,j)  = psi(kk,1,i+1,j) - f0*psi(kk,1,i,j)

         grad(kk,2,i,j)  = psi(kk,2,i+1,j) - f0*psi(kk,2,i,j)

         grad(kk,3,i,j)  = psi(kk,3,i+1,j) - f0*psi(kk,3,i,j)

    END DO

    ELSE 

        DO kk=1,3

        grad(kk,1,i,j)  = psi(kk,1,i+1,j) 

        grad(kk,2,i,j)  = psi(kk,2,i+1,j)

        grad(kk,3,i,j)  = psi(kk,3,i+1,j)

    END DO

   END IF

END DO
END DO

END FUNCTION grad
如果你想要简洁,我会说你可以比现在简洁得多。您提供的整个功能可以像这样重写:

function grad(psi)
  implicit none
  integer, parameter :: nx = 24, ny = 24, nxx = nx / 2, nyy = ny / 2
  real, parameter :: pi = 4 * atan(1.0), f0 = pi ** 2 * 1.3
  complex, dimension(3,3,-nx:nx,-ny:ny) :: psi, grad

  grad(:,:,-nx+1:nx-1,-ny+1:ny-1) = psi(:,:,-nx+2:nx,-ny+1:ny-1)
  grad(:,:,0,0) = psi(:,:,1,0)
  grad(:,:,[-nxx,nxx],[-nyy,nyy,ny]) = psi(:,:,[-nxx+1,nxx+1],[-nyy,nyy,ny]) - f0 * psi(:,:,[-nxx,nxx],[-nyy,nyy,ny])
  !grad(:,:,nx,[-nyy,nyy]) = psi(:,:,nx+1,[-nyy,nyy]) - f0 * psi(:,:,nx,[-nyy,nyy])
end
正如@IanBush所说,分配默认值然后修改特殊情况似乎是一种很好的方法。此外,它是Fortran语言的一个独特而强大的功能,可用于提高表达能力而不影响清晰度

纯冒号表示此维度中的所有值,值之间的冒号仅表示此维度中此范围内的值

所以,当我写
grad(:,:,-nx+1:nx-1,-ny+1:ny-1)=psi(:,:,-nx+2:nx,-ny+1:ny-1)
时,我的意思是:我将数组
psi
中的值赋值给
grad
;我包括第一个维度的所有值,但仅包括最后两个维度的子集(我不包括每个维度中的第一个维度和最后一个维度);此外,它们直接映射到除第三维之外的其他三维,该三维映射到
psi
中的下一个等效位置

当我写
grad(:,:,[-nxx,nxx],-nyy,ny])
时,我指定的是索引列表,而不是第三和第四维度的范围。这将包括两个列表的总组合:
-nxx,-nyy
-nxx,nyy
-nxx,ny
nxx,-nyy

这种表示法的一个优点是,因为它更明显,更接近数学表示法,所以更容易发现不一致。这就是为什么最后一行被注释掉的原因:索引
nx+1
,正如您在编写的代码的第8和第9条条件中所做的那样,将超出范围。我不知道您提供的示例代码是否是官方代码;如果是的话,你应该纠正你的算法(好吧,因为你只是从第二个索引循环到最后一个索引,你实际上永远不会碰到那些条件…)


另一个建议是,您可以将自定义函数放在模块中,以便将所有这些参数声明传递给模块范围。此外,您可以考虑假设的形状数组参数。

三个简单的想法是使用。或者,使用一个包含文件或调用(一个可能的内部)子程序。数组语法也可以简化它。但我可能不会从这里开始——我会设置整个网格的“默认”值,然后使用单独的循环来修改异常值,而不是一个if-in-sight。@IanBush谢谢您的评论!这正是我想要的。正如你所注意到的,我对冒号符号不太熟悉,也不太熟悉。我需要考虑一下你的答案并实施它,在我完成所有这些的时候,我可能会有一些问题。非常感谢你简洁明了的回答。我刚刚发布了一个新问题,它是这个问题的延伸。我现在正试图修改我的代码,因为我的索引列表比这个例子要大得多。如果您有任何解决方案,非常感谢!这个解决方案极大地帮助了我,而您确实在帮助我提高代码的效率。