是否可以在 Fortran IF 语句中使用向量参数而不是标量参数

Is it possible to use vector arguments in Fortran IF statements rather than scalar arguments

如果可能的话,我不想使用三个连续的标量 IF 语句,而是使用一个带有向量参数的 IF 语句。我不知道怎么办。

想要这个的原因是为了测试它的速度。我的代码可以 运行 几天调用此部分数十亿次。即使是一点点加速也会产生很大的不同。

以下是用于虚拟场景的包含三个 IF 语句的工作代码。

program main

!==============================================
!               Define variables
!==============================================

real, dimension(10,3)         :: r                              ! 10 atoms     each with x,y,z coordinates
real, dimension(3)            :: rij                            ! x,y,z vector of difference between two atoms
real                          :: Box_Length                     ! length of simulation box
real                          :: time, timer_start, timer_end   
integer                       :: timer

!=======================================================
!                   Begin Program body
!=======================================================
Box_Length = 1.0    ! based on a box of length = 1 since coords are randomly generated between 0 and 1

!=================================
! Generate random atom coordinates
!=================================

r = 0.0
CALL RANDOM_NUMBER (r) 

!=================================
!         Begin algorithm
!=================================

call cpu_time(timer_start)

do timer = 1,30000

do i = 1,size(r)

    do j = 1, size(r)

        if(i == j) cycle

        rij(:) = abs(r(i,:) - r(j,:))

        !==============================
        ! Apply mirror image convention
        !==============================
        if(rij(1) > Box_Length - rij(1) ) rij(1) = rij(1) - Box_Length 
        if(rij(2) > Box_Length - rij(2) ) rij(2) = rij(2) - Box_Length 
        if(rij(3) > Box_Length - rij(3) ) rij(3) = rij(3) - Box_Length

        !*******************************************************************************
        !   Question: Can I make it into a single if statement i.e.                    *
        !                                                                              *
        ! if(rij(:) > Box_Length(:) - rij(:) ) rij(:) = rij(:) - Box_Length(:)         *
        !                                                                              *
        ! Where Box_Length is now a vector and only the coordinate that triggers      *
        ! the if statement is modified. Meaning that if { rij(2) >  Box_Length - rij(2) } *
        ! only rij(2) is modified, not all three.                                      *
        ! I have tried making Box_Length a vector, but that failed.                    *
        !*******************************************************************************

        ! insert rest of algorithm

    enddo ! j-loop

enddo  ! i loop

enddo   ! timer loop

call cpu_time(timer_end)

time = timer_end - timer_start

print*, 'Time taken was: ', time

end program main

感谢您帮助将其转换为矢量化 IF 语句。另外,我在列向量和行向量之间来回翻转。目前列向量对我来说工作得更快。这不是关于列向量与行向量的问题。我自己计时并使用更快的方法。我根本无法获得一个有效的矢量方法来尝试计时。

"if(rij(:) > Box_Length(:) - rij(:) ) rij(:) = rij(:) - Box_Length(:)"

可以

where (rij > Box_Length - rij) rij = rij - Box_Length

并不是说它不会比显式 DO 循环更快,它只是一种更短的编写方式。它甚至可以使其变慢,因为可能会使用临时数组,或者编译器可能很难对其进行矢量化 - 在 SIMD 矢量化意义上。

我建议不要使用单词 "vectorization" 来谈论 Fortran 中的 shorthand 数组表示法。在 Fortran 中,矢量化通常意味着使用 SIMD CPU 指令。编译器调用该矢量化。您的矢量化概念来自 Python 但未在 Fortran 中使用,这会误导其他读者。

另请阅读 https://software.intel.com/en-us/blogs/2008/03/31/doctor-it-hurts-when-i-do-this 以了解为什么您应该只使用 rij 而不是 rij(:)


TLDR:可以将它写在一行中,但在 Fortran 数组符号中并不是使程序更快的方法。往往适得其反。