如何构造具有变量赋值的多维数组

时间:2018-03-29 00:24:19

标签: arrays fortran physics

所以我遇到了数组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 

....等等

但是从现在开始我有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个距离点,以便它们像D(j,i)一样存储,其中j表示数字1-976中的原子,变量i是2197由公式计算的不同点。我的想法是拥有967个原子,其中每个原子有2197个点我可以用来计算其他的东西。然后将电荷除以距离以找到电压电位,所以基本上我需要能够像D(atom#,charge.)那样调用距离

我的逻辑是正确的,还是应该使用其他数组组合来解决这个问题?

1 个答案:

答案 0 :(得分:1)

你的问题很难理解,至少对我而言,但假设这不是一个家庭作业问题而且你只是一个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规范。 Fortran已经有多种计算L2范数的方法,其中一种方法是norm2 (x [ , dim ] ),它返回一个实数x的L2范数;结果是与x相同类型的真实标量。 请注意,您需要一个Fortran 2008编译器来编译此代码。这是一个在线2008编译器,您可以使用它编写代码https://www.tutorialspoint.com/compile_fortran_online.php

请记住,为了让编译器为您自动并行化并发循环,您很可能需要使用O2或更好的编译代码,O3优化标志以及自动并行化标志(用于例如英特尔的ifort)。我不确定GNU gfortran中do concurrent的状态。但是,在使用Intel ifort编译器时,我发现它与它有明显的性能差异。以下是关于此主题的相关但旧的主题:https://stackoverflow.com/a/25860047/2088694