I am trying to read an ASCII file and am getting errors when compiling such as:
Error: Syntax error in READ statement at (1)
And
Error: Allocatable array 'pos' at (1) must have a deferred shape or assumed rank
My code:
subroutine read_file(pos,mass,rho,vel,n)
integer :: i, n
real, allocatable, intent(out) :: pos(3,n), mass(n), rho(n), vel(3,n)
open(unit=11,file="star.ascii",status="old",action="read")
n = 0
do
read(unit=11,*)
n = n+1
enddo
allocate(pos(3,n), mass(n), rho(n), vel(3,n))
do i = 1,n
read(unit=11,*) pos(:,i), mass(i), rho(i), vel(:,i)
enddo
close(unit=11)
end subroutine read_file
The first 8 columns in my ascii file are the x, y, z components of position, mass, density, and the x, y, z components of velocity which I am reading into arrays, with (1,n), (2,n), (3,n) being the x, y, and z components correspondingly and n is supposed to be the number of particles.
What am I doing wrong and how can I make this code compile?
Update: first error solved, but still getting the same syntax error with the READ statement.
subroutine read_file(pos,mass,rho,vel,n)
integer :: i, n, ios
real, allocatable, intent(out) :: pos(:,:),mass(:),rho(:),vel(:,:)
open(unit=11,file="star.ascii",status="old",action="read")
n = 0
do
read(unit=11,*,iostat=ios) pos,mass,rho,vel
if (ios /= 0) exit
n = n+1
enddo
allocate(pos(3,n), mass(n), rho(n), vel(3,n))
rewind(11)
do i = 1,n
read(unit=11,*)pos(:,i),mass(i),rho(i),vel(:,i)
enddo
close(unit=11)
end subroutine read_file
The read
syntax error comes from the fact that you use a named dummy argument (unit=11
) but then you do not continue to use named dummy arguments.
Say you have a subroutine with a this interface:
subroutine mysub(a, b, c)
implicit none
integer, intent(in), optional :: a, b, c
end subroutine mysub
There are two ways to call such a subroutine:
Without named dummy arguments:
call mysub(1, 2, 3) ! a->1, b->2, c->3
call mysub(4711, 2) ! a->4711, b->2, c unset
Using so-called keyword arguments:
call mysub(a=4, c=2) ! b unset
call mysub(b=14) ! a and c unset
In case 1. the compiler interprets the inputs according to the order in which the arguments are defined in the interface. In case 2. it sets them by the keyword argument. To some extend, you can mix a bit:
call mysub(1, c=5) ! b unset
But, and this is important, after the first keyword argument, you can't go back:
call mysub(b=4, 2) ! DOES NOT WORK
The compiler doesn't know whether a or c is supposed to be 2 in this case. You might say, "What if I use mysub(a=1, 2, 3)
, that's clear, isn't it?" It might be, but in order to avert the pitfalls, the Fortran Guidelines state that
... once a keyword argument appears in the list, all of the remaining arguments must also be keyword arguments1
The interface for read
has the unit
as the first, and the fmt
as the second parameter. So you can either one of these:
read(unit=11, fmt=*, iostat=ios) ...
read(11, *, iostat=ios) ...
But you can't use unit=
without also declaring fmt=
If you declare an allocatable array, you need to tell it the number of dimensions you want to reserve for allocation. This is not done with n
, but with the colon :
:
real, allocatable :: pos(:, :), mass(:), rho(:), vel(:, :)
1 from Chapman: Fortran 95/2003 For Scientists and Engineers