所以我遇到了一个数组do循环的问题。
我有一个976个原子的X,Y,Z坐标数组列表。在另一个文本文件中,我有一个数组,每个原子有976个电荷。此外,我还有Xo,Yo,Zo的2,971个点(13x13,x13)的数组。我需要计算的是原子的实际X,Y,Z坐标和2,197个网格点之间的距离。最初,我用33个原子做的计算是这样的。
do i=1,2197
D1(i) = (((X(1)-Xi(i))**2 + (Y(1)-Yi(i))**2 + (Z(1)-Zi(i))**2)**0.5)*10E-10
D2(i) = (((X(2)-Xi(i))**2 + (Y(2)-Yi(i))**2 + (Z(2)-Zi(i))**2)**0.5)*10E-10
D3(i) = (((X(3)-Xi(i))**2 + (Y(3)-Yi(i))**2 + (Z(3) Zi(i))**2)**0.5)*10E-10
D4(i) = (((X(4)-Xi(i))**2 + (Y(4)-Yi(i))**2 + (Z(4)-
Zi(i))**2)**0.5)*10E-10 ....etc等
但由于我现在有976个原子,手动做这件事将是一场噩梦。我的问题是:由于我需要为每个原子创建一个包含2197个点的数组,有没有一种方法可以在不手动写出的情况下生成这个数组?
我尝试了下面这样的方法:
do i=1,2197
Do n=1,976
DO j=1,976
D(j,i) = (((X(n)-Xi(i))**2 + (Y(n)-Yi(i))**2 + (Z(n)-
Zi(i))**2)**0.5)*10E-10
End do
End Do
Enddo我的逻辑基本上是计算每个原子的2,197个距离点,这样它们将像这样存储,其中j将表示它是数字1-976中的哪个原子,变量i将是通过公式计算的2197个不同的点。我们的想法是拥有967个原子,其中每个原子都有2197个点,我可以在以后使用它来计算其他东西。然后将电荷除以距离,得到电压电位,因此基本上我需要能够将距离称为D(atom#,charge.)
我对此的逻辑是否正确,或者我是否应该使用其他数组组合以不同的方式处理此问题?
发布于 2018-03-29 10:44:45
你的问题很难理解,至少对我来说是这样,但假设这不是一个家庭作业问题,假设你只是一名Fortran爱好者或新开发人员,下面是一个非面向对象但现代高效的解决方案:
program confusingQuestion
use, intrinsic :: iso_fortran_env, only: int32,real64
implicit none
integer(int32), parameter :: nAtom = 976
integer(int32), parameter :: nGrid = 2197
real(real64) :: AtomCrd(3,nAtom), AtomCharge(nAtom)
real(real64) :: GridCrd(3,nGrid), Atom2GridDistance(nGrid,nAtom)
integer(int32) :: iAtom,iGrid
! for demonstration purposes, I assign random values to variables
call random_number(AtomCrd)
call random_number(GridCrd)
call random_number(AtomCharge)
do concurrent (iAtom = 1:nAtom,iGrid=1:nGrid)
Atom2GridDistance(iGrid,iAtom) = norm2( AtomCrd(:,iAtom)-GridCrd(:,iGrid) )
end do
! print a sample:
write(*,'(*(g0.4,","))') Atom2GridDistance(:,1) ! print distances for the first atom
end program confusingQuestion注意,我在这里有目的地使用了do concurrent构造。与一个接一个地串行执行常规do循环不同,do concurrent告诉编译器循环中的所有元素级计算都是相互独立的,并且可以并行计算。因此,根据您的编译器,此代码可以并行执行,这将提高代码的速度。
此外,也不需要在代码中手动实现L2-norm。Fortran已经有多个计算L2范数的方法,其中之一是norm2 (x [ , dim ] ),它返回实数组x的L2范数;结果是与x相同的实标量。请注意,您需要使用Fortran 2008编译器来编译此代码。这是一个在线2008编译器,您可以使用它来尝试代码https://www.tutorialspoint.com/compile_fortran_online.php
请记住,为了让编译器自动并行化并发循环,您很可能需要使用O2或更好的O3优化标志以及自动并行化标志(例如在英特尔的ifort中)来编译代码。我不确定do concurrent在GNU gfortran中的状态。但是,在使用英特尔ifort编译器时,我发现它的性能有明显的差异。下面是关于这个主题的一个相关但古老的主题:https://stackoverflow.com/a/25860047/2088694
https://stackoverflow.com/questions/49546198
复制相似问题