如何使用fortran代码对2d数组中的距离进行排序?

时间:2018-08-22 18:47:27

标签: sorting fortran

我想对距离进行排序。例如r(1,3)dist.txt的输入文件是这样的

1,2,3.5
1,3,0.5
1,4,4.7
1,5,4,5  

sort.txt的输出文件应该是这样

1, 3, 0.5
1,2, 3.5
1,5, 4.5
1,4,4.7

此处第一列为i,第二列为j,然后第三列为r(i,j)。 所以在这里,我在fortran中写下了一个可以对2D数组进行排序的代码。但是该代码有问题,如果可以解决。我会很高兴。

 program sort
  implicit none
  character CN*8,O*7
  integer i,m,k,j
  integer n,nmax,ind,num
  integer L
  parameter (n=3,m=n**2-n)
  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,t
  double precision a(n,n)
  double precision r(n,n)
  open(unit=10,status='unknown',file='a.gro')

   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

   t=0.0d0
  open(unit=3,file='dist.txt')
  open(unit=4,file='2d_1d_dist.txt')
  open(unit=5,file='sort.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)
   xij=xij - nint(xij/xbox)*xbox
   yij=yij - nint(yij/xbox)*xbox
   zij=zij - nint(zij/xbox)*xbox
   r(i,j)=dsqrt(xij**2 + yij**2 + zij**2) !distance calculation
    write(3,'(i3,2x,i3,4x,f17.15)') i,j, r(i,j)
    endif
    enddo
    enddo


  t=0.0d0
  do i = 1,m-2
  do j = i+1,m-1
  if(i .ne. j) then
  write(4,*) r(i,j),"   ", r(i,j+1)
  if (r(i,j) .gt. r(i,j+1)) then
   t=r(i,j)
  r(i,j)=r(i,j+1)
  r(i,j+1)=t
  endif
   endif
  write(5,*) r(i,j)
  enddo
  enddo
  END program sort

请查看代码。

1 个答案:

答案 0 :(得分:2)

遇到这种情况时,我首先想到的是:是否需要编写自己的程序?

这里没有快速答案:Linux / Unix的sort命令可以正常工作:

sort -t, -k3 -g dist.txt
  • -t,告诉排序字段分隔符是逗号,
  • -k3告诉它根据第三个字段进行排序,
  • -g告诉它使用常规数字排序

如果我需要使用Fortran进行此操作,则可能会将ijr读入单独的一维数组,然后编写一个不仅排序的排序例程r,但也返回订单。然后,您可以轻松地重新排列ij数组以对应相同的顺序。参见以下示例:

program sort_r

    implicit none
    integer :: u
    integer, parameter :: num_of_elements = 4
    integer :: i(num_of_elements), j(num_of_elements)
    real :: r(num_of_elements)
    integer :: order(num_of_elements)
    integer :: ii
    open(newunit=u, file='dist.txt')
    do ii=1, num_of_elements
        read(u, *) i(ii), j(ii), r(ii)
    end do
    close(u)
    order = [(ii, ii=1, num_of_elements)]
    call qsort(r, first=1, last=num_of_elements, order=order)
    i(:) = i(order)
    j(:) = j(order)
    do ii = 1, num_of_elements
        write(*,'(I0,",",I0,",",F3.1)') i(ii), j(ii), r(ii)
    end do

contains
    recursive subroutine qsort(a, first, last, order)
        real, intent(inout) :: a(:)
        integer, intent(in) :: first, last
        integer, intent(inout) :: order(:)
        ! Prerequsits:
        !       first >= lbound(a, 1)
        !       last <= lbound(a, 1)
        !       lbound(a, 1) == lbound(order, 1)
        !       ubound(a, 1) == ubound(order, 1)
        real :: pivot
        integer :: i, j

        if (.not. first < last) return ! less than 2 elements

        ! Get pivot from middle to beginning of subarray.
        call swap(a, first, (first+last)/2, order)
        pivot = a(first)
        i = first + 1
        j = last

        do while (j >= i)
            ! move up from left while elements are smaller than pivot
            do while (a(i) < pivot)
                i = i + 1
            end do
            ! move down from right while elements are larger than pivot
            do while (a(j) > pivot)
                j = j - 1
            end do
            ! If we moved past the other index, exit loop
            if (j < i) exit

            ! We have found a larger than pivot element left of a smaller than
            ! pivot element to the right, swap the two, move the indices to next
            call swap(a,i,j,order)
            i = i + 1
            j = j - 1
        end do

        ! Move pivot back to centre
        call swap(a,first,j, order)

        call qsort(a,first=first,last=j-1,order=order)
        call qsort(a,first=i,last=last,order=order)

    end subroutine qsort

    subroutine swap(a, i, j, order)
        real, intent(inout) :: a(:)
        integer, intent(in) :: i, j
        integer, intent(inout) :: order(:)
        real :: t
        integer :: k
        t = a(i)
        a(i) = a(j)
        a(j) = t
        k = order(i)
        order(i) = order(j)
        order(j) = k
    end subroutine swap

end program sort_r