繁体   English   中英

如何在 Fortran 代码中将二维数组转换为一维数组?

[英]How to convert 2D array to 1D array in Fortran code?

如何将 r(i,j) 转换为一维数组,以便我可以轻松地对数字进行排序?

program sort
  implicit none
  character CN*8,O*7
  integer j,iconf,nconf
  integer i,nbins,t
  integer n,nmax,ind,num,b
  parameter (n=216)
  double precision xbox,rq
  parameter (nmax=3091,nconf=1)
  double precision atom(nmax),id(nmax),ox(nmax),oy(nmax),oz(nmax)
  double precision xij,yij,zij,rij
  double precision r(n,n),A(n)
  open(unit=10,status='unknown',file='1000.gro')
   do iconf= 1,nconf
    write(*,*)iconf
     read(10,*)
     read(10,*)
   do i=1,n
     read(10,'(A8,A7,1i5,3f8.3)')CN,O,num,ox(i),oy(i),oz(i)
   enddo
     read(10,*)xbox        ! read the xbox for PBC

  open(unit=3,file='dist.txt')

   do i=1,n
    do j=1,n
   if(i .ne. j) then
   xij=ox(i)-ox(j)
   yij=oy(i)-oy(j)
   zij=oz(i)-oz(j)
   r(i,j)=dsqrt(xij**2 + yij**2 + zij**2)
      write(3,'(i3,2x,i3,4x,f17.15)') i,j, r(i,j)
    endif 
    enddo
    enddo
    enddo
    END

我必须计算距离并将其保存在数组中作为r (i,j) 我想将r(i,j)转换为一维数组,以便我可以轻松地对r(i,j)进行排序。

之前的两个答案已经研究了如何将rank-2数组“转换”为rank-1数组的字面问题。 他们使用不同的方法:

  • 将值复制到新的rank-1数组中;
  • 在最终子例程中,具有与rank-2实际参数相关联的rank-1伪参数。

我们可以扩展这两种方法。

以最简单的形式reshape形成返回所需的rank-1数组。 作为替代方案,我们可以说形式[x]的数组构造函数也是这样做的:

real r1d(6), r2d(3,2)
r2d=5.
r1d = [r2d]

当实际参数是数组元素时 ,数组伪参数和包含并遵循实际参数的数组元素是顺序关联的。

通过序列关联,虚拟阵列将呈现大小或显式形状。 在这种情况下,我们对整个数组感兴趣,我们可以传递整个数组:

real r2d(3,2)
call sub(r2d)

哪里

subroutine sub(r1d)
  real r1d(*) ! or r1d(6), etc.
end subroutine

这里重要的是,对于显式形状和假定大小的伪参数,秩不需要与实际参数的匹配。

如前所述,第一组方法涉及创建新阵列。 序列关联的使用不会。 第三种方法也是可用的:具有指向秩-2目标的秩-1指针。 当然,创建副本也意味着任何更改都不会反映在原始的rank-2数组中。 序列关联和指针将看到传递的更改。

关于这些事情中的任何一个的更多细节可以在其他问题和答案中找到。

对于排序来说,将rank-2数组视为rank-1数组是否有意义是一个不同的考虑因素。

这似乎是为重塑功能量身定制的: https//gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html在这个微小的例子中,首先使用重塑来制作二维数组A,然后再次调用重塑形状制作一维数组C.

Program reshape_demo
    use, intrinsic :: iso_c_binding

    implicit none
    real(kind=c_float),allocatable :: A(:,:),C(:)
    integer(kind=c_int) :: krow
    allocate(A(3,3))
    A=reshape((/1,2,3,4,5,6,7,8,9/),(/3,3/))
    do krow=1,3
       write(*,fmt="(1p3e10.3)")A(krow,:)
    end do
    C=reshape(A,(/9/))
    write(*,fmt="(9(1x,f4.1))")C
End Program reshape_demo

您可以将r(1,1)传递给子例程,该子例程将参数声明为一维数组。 这在Fortran中是合法的(有一些限制不适用于您的代码)并使用称为“序列关联”的功能。

现在FORTRAN的用户已经不多了,所以问题也不是那么频繁了。 接受的答案很好,可以形成一个简单的函数作为解决方案 1。但是还有另一种选择使用 C_F_POINTER 而不复制源数组(可以通过巨大的数组获得更高的效率)。

解决方案1:

function downsize(A)result(C)
 real::A(:,:)
 real,allocatable::C(:)
 C=reshape(A,[size(A)])
end function downsize

使用该功能

real,allocatable::C(:); C=downsize(A);

解决方案2:
ISO Binding 中的 C_F_POINTER 可用于像 C 中一样传输内存地址。

USE, INTRINSIC :: ISO_C_BINDING
integer::i,i1d(9)=reshape((real([(i,i=1,9)])),[9])
integer,dimension(:,:),pointer::p2d
! Here has to be "Deferred-shape" but it only defined a pointer to an array, not an array of pointers as is always misleading...
real::r2d(3,3)=reshape((real([(i,i=1,9)])),[3,3])
real, pointer ::pr1d(:)
!Let's Grow the size from I1D to I2D by the pointer pI2D...
call c_f_pointer(c_loc(i1d),pi2d,[3,3])
!The pointer pi2d is a 2d array with the contents of i1d. Note you cannot deallocate the pointer pi2d - any deallocation has to be of pointee i1d.
!Let's Down the size from R2D to R1D by the pointer pR1D ...
call c_f_pointer(c_loc(r2d), pr1d,[size(r2d)])

通过这样做,您将丢失有关距离对应的对的所有信息,但如果这只是您想要的距离,那么我不会得到所有令人费解的答案。 为什么不这样做:

[....]

    implicit none
    real(8), dimension(:), allocatable:: dist_arr

    allocate(dist_arr(n**2))

    k=0
    do i=1,n
        do j=1,n
            k=k+1
            dist_arr(k)=r(i,j)
        enddo
    enddo

[....]

    

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM