I try to read a lot of data from a file. The structure of the file is consistent, but the number of times it repeats is not. The first line in input file tells how many times the file repeats. I would like to allocate many vectors with the same length as input file repeats.
Is there a elegant way to solve this, without allocating every single variable? My current subroutine does not work (I am a Fortran Novice).
subroutine geometry(N, Aw, Vp, Vtot,Ds, Spos, DIR)
implicit none
integer, intent(out) :: N
real, dimension(:), allocatable, intent(out):: Aw, Vp, Vtot, Ym, Zm, Zt, Ds
real, dimension(:), allocatable, intent(out) :: Spos
integer, dimension(:), allocatable, intent(out) :: Ns, DIR
real, dimension(:), allocatable :: Hp
real, parameter :: pi = 4.0*atan(1.0)
real :: Vs, Ds, Ns
integer :: i
open(unit = 11, file = "semisub.dat")
read(11,*) N
allocate(Aw(N))
allocate(Vp(N))
allocate(Vtot(N))
allocate(Ym(N))
allocate(Zm(N))
allocate(Zt(N))
allocate(Ds(N))
allocate(Spos(N,4))
allocate(Ns(N))
allocate(DIR(N))
allocate(Hp(N))
do i = 1,N
read(11,*) Bp, Hp, Lp, Ym(i), Zm(i), DIR(i)
read(11,*) Ns(i), Ds(i)
read(11,*) Spos(i,1:Ns(i))
end do
Aw(:) = 2 * Ds(:) * Ns(:)
Vp(:) = 2 * Lp(:) * Bp(:) * Hp(:)
Vs(:) = 2 * Ns(:) * pi * (Ds/2)**2 * (-Zt(:))
Vtot(:) = Vp(:) + Vs(:)
end subroutine geometry
Error log:
geometry.f03:7.54:
integer, dimension(:),allocatable, intent(out) :: Ns, DIR
1
Error: Symbol at (1) is not a DUMMY variable
geometry.f03:5.65:
real, dimension(:), allocatable, intent(out):: Aw, Vp, Vtot, Ym, Zm, Zt, Ds
1
Error: Symbol at (1) is not a DUMMY variable
geometry.f03:5.69:
real, dimension(:), allocatable, intent(out):: Aw, Vp, Vtot, Ym, Zm, Zt, Ds
1
Error: Symbol at (1) is not a DUMMY variable
geometry.f03:5.73:
real, dimension(:), allocatable, intent(out):: Aw, Vp, Vtot, Ym, Zm, Zt, Ds
1
Error: Symbol at (1) is not a DUMMY variable
geometry.f03:23.15:
allocate(Spos(N,4))
1
Error: Rank mismatch in array reference at (1) (2/1)
geometry.f03:32.20:
read(11,*) Spos(i,1:Ns(i))
1
Error: Rank mismatch in array reference at (1) (2/1)
You have to allocate every array you are filling when reading before. Your approach is OK, with some mistakes not affecting the logic.
The only other option would be to use reallocation by assignment:
do...
...
read(11,*) Ns_tmp, Ds_tmp
Ns = [Ns, Ns_tmp]
Ds = [Ds, Ds_tmp]
...
end do...
but I wouldn't do that if you know the number of the sections at the start of the file. It is slower and too much complicated.
Your error is, that the argument list (N, Aw, Vp, Vtot,Ds, Spos, DIR)
is not consistent with your declarations of dummy-arguments:
integer, intent(out) :: N
real, dimension(:), allocatable, intent(out):: Aw, Vp, Vtot, Ym, Zm, Zt, Ds
real, dimension(:), allocatable, intent(out) :: Spos
integer, dimension(:), allocatable, intent(out) :: Ns, DIR
Just sort that out and it should work. Just add all arguments in the argument list and do not use intent
for non-arguments.
The other error is that you declared Spos
as on-dimensional and you are using it as 2 dimensional.