问题
How do I convert r(i,j) to a 1D array so that I can sort the number easily?
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
I have to calculate the distance and save this in array as r (i,j)
. I want to convert r(i,j)
to a 1 dimensional array, so that I can sort the r(i,j)
easily.
回答1:
This seems tailor made for the reshape function: https://gcc.gnu.org/onlinedocs/gfortran/RESHAPE.html In this tiny example, reshape is used first to make a two-dimensional array A, then reshape is called again to make the one-dimension array 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
回答2:
Two previous answers have looked at the literal question of how to "convert" a rank-2 array in to a rank-1 array. They use different approaches:
- copy the values in to a new rank-1 array;
- in the end subroutine, have a rank-1 dummy argument associated with a rank-2 actual argument.
We can expand on both of these approaches.
reshape in its simplest form returns the desired rank-1 array. As an alternative, we can say that an array constructor, of the form [x]
does that also:
real r1d(6), r2d(3,2)
r2d=5.
r1d = [r2d]
When the actual argument is an array element the array dummy argument and those elements of the array including and following the actual argument are in sequence association.
With sequence association, the dummy array would be assumed-size or explicit shape. As in this case we're interested in the whole array, we could just pass the whole array:
real r2d(3,2)
call sub(r2d)
where
subroutine sub(r1d)
real r1d(*) ! or r1d(6), etc.
end subroutine
The important thing here is that for explicit-shape and assumed-size dummy arguments the rank need not match that of the actual argument.
As noted before, this first group of approaches involves creating a new array. The use of sequence association doesn't. A third approach is also available: having a rank-1 pointer pointing to a rank-2 target. Creating a copy does also mean, of course, that any changes aren't reflected in the original rank-2 array. Sequence association and pointers will see changes passed on.
More detail on any one of these things can be found in other questions and answers.
Whether, for sorting, it makes much sense to treat a rank-2 array as a rank-1 array is a different consideration.
回答3:
You can pass r(1,1) to a subroutine that declares the argument to be a one-dimension array. This is legal in Fortran (with some restrictions that don't apply to your code) and uses a feature called "sequence association".
来源:https://stackoverflow.com/questions/51912396/how-to-convert-2d-array-to-1d-array-in-fortran-code