Format columns extracted from different input files in a single output file in Fortran90 [duplicate] - loops

I have a program in Fortran that saves the results to a file. At the moment I open the file using
OPEN (1, FILE = 'Output.TXT')
However, I now want to run a loop, and save the results of each iteration to the files 'Output1.TXT', 'Output2.TXT', 'Output3.TXT', and so on.
Is there an easy way in Fortran to constuct filenames from the loop counter i?

you can write to a unit, but you can also write to a string
program foo
character(len=1024) :: filename
write (filename, "(A5,I2)") "hello", 10
print *, trim(filename)
end program
Please note (this is the second trick I was talking about) that you can also build a format string programmatically.
program foo
character(len=1024) :: filename
character(len=1024) :: format_string
integer :: i
do i=1, 10
if (i < 10) then
format_string = "(A5,I1)"
else
format_string = "(A5,I2)"
endif
write (filename,format_string) "hello", i
print *, trim(filename)
enddo
end program

A much easier solution IMHO ...................
character(len=8) :: fmt ! format descriptor
fmt = '(I5.5)' ! an integer of width 5 with zeros at the left
i1= 59
write (x1,fmt) i1 ! converting integer to string using a 'internal file'
filename='output'//trim(x1)//'.dat'
! ====> filename: output00059.dat

Well here is a simple function which will return the left justified string version of an integer:
character(len=20) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
And here is a test code:
program x
integer :: i
do i=1, 100
open(11, file='Output'//trim(str(i))//'.txt')
write (11, *) i
close (11)
end do
end program x

I already showed this elsewhere on SO (How to use a variable in the format specifier statement? , not an exact duplicate IMHO), but I think it is worthwhile to place it here. It is possible to use the techniques from other answers for this question to make a simple function
function itoa(i) result(res)
character(:),allocatable :: res
integer,intent(in) :: i
character(range(i)+2) :: tmp
write(tmp,'(i0)') i
res = trim(tmp)
end function
which you can use after without worrying about trimming and left-adjusting and without writing to a temporary variable:
OPEN(1, FILE = 'Output'//itoa(i)//'.TXT')
It requires Fortran 2003 because of the allocatable string.

For a shorten version.
If all the indices are smaller than 10, then use the following:
do i=0,9
fid=100+i
fname='OUTPUT'//NCHAR(i+48) //'.txt'
open(fid, file=fname)
!....
end do
For a general version:
character(len=5) :: charI
do i = 0,100
fid = 100 + i
write(charI,"(A)"), i
fname ='OUTPUT' // trim(charI) // '.txt'
open(fid, file=fname)
end do
That's all.

I've tried #Alejandro and #user2361779 already but it gives me an unsatisfied result such as file 1.txt or file1 .txt instead of file1.txt. However i find the better solution:
...
integer :: i
character(len=5) :: char_i ! use your maximum expected len
character(len=32) :: filename
write(char_i, '(I5)') i ! convert integer to char
write(filename, '("path/to/file/", A, ".dat")') trim(adjustl(char_i))
...
Explanation:
e.g. set i = 10 and write(char_i, '(I5)') i
char_i gives " 10" ! this is original value of char_i
adjustl(char_i) gives "10 " ! adjust char_i to the left
trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right
I think this is a simplest solution that give you a dynamical length filename without any legacy blank spaces from integer to string conversion process.

Try the following:
....
character(len=30) :: filename ! length depends on expected names
integer :: inuit
....
do i=1,n
write(filename,'("output",i0,".txt")') i
open(newunit=iunit,file=filename,...)
....
close(iunit)
enddo
....
Where "..." means other appropriate code for your purpose.

To convert an integer to a string:
integer :: i
character* :: s
if (i.LE.9) then
s=char(48+i)
else if (i.GE.10) then
s=char(48+(i/10))// char(48-10*(i/10)+i)
endif

Here is my subroutine approach to this problem. it transforms an integer in the range 0 : 9999 as a character. For example, the INTEGER 123 is transformed into the character 0123. hope it helps.
P.S. - sorry for the comments; they make sense in Romanian :P
subroutine nume_fisier (i,filename_tot)
implicit none
integer :: i
integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii
character(1) :: filename1,filename2,filename3,filename4
character(4) :: filename_tot
! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar
! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate.
if(i<=9) then
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+0)
filename4=char(48+i)
elseif(i>=10.and.i<=99) then
integer_zeci=int(i/10)
rest_zeci=mod(i,10)
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=100.and.i<=999) then
integer_sute=int(i/100)
rest_sute=mod(i,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+0)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=1000.and.i<=9999) then
integer_mii=int(i/1000)
rest_mii=mod(i,1000)
integer_sute=int(rest_mii/100)
rest_sute=mod(rest_mii,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+integer_mii)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
endif
filename_tot=''//filename1//''//filename2//''//filename3//''//filename4//''
return
end subroutine nume_fisier

Related

Fortran open a '.dat' file where name changable [duplicate]

I have a program in Fortran that saves the results to a file. At the moment I open the file using
OPEN (1, FILE = 'Output.TXT')
However, I now want to run a loop, and save the results of each iteration to the files 'Output1.TXT', 'Output2.TXT', 'Output3.TXT', and so on.
Is there an easy way in Fortran to constuct filenames from the loop counter i?
you can write to a unit, but you can also write to a string
program foo
character(len=1024) :: filename
write (filename, "(A5,I2)") "hello", 10
print *, trim(filename)
end program
Please note (this is the second trick I was talking about) that you can also build a format string programmatically.
program foo
character(len=1024) :: filename
character(len=1024) :: format_string
integer :: i
do i=1, 10
if (i < 10) then
format_string = "(A5,I1)"
else
format_string = "(A5,I2)"
endif
write (filename,format_string) "hello", i
print *, trim(filename)
enddo
end program
A much easier solution IMHO ...................
character(len=8) :: fmt ! format descriptor
fmt = '(I5.5)' ! an integer of width 5 with zeros at the left
i1= 59
write (x1,fmt) i1 ! converting integer to string using a 'internal file'
filename='output'//trim(x1)//'.dat'
! ====> filename: output00059.dat
Well here is a simple function which will return the left justified string version of an integer:
character(len=20) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
And here is a test code:
program x
integer :: i
do i=1, 100
open(11, file='Output'//trim(str(i))//'.txt')
write (11, *) i
close (11)
end do
end program x
I already showed this elsewhere on SO (How to use a variable in the format specifier statement? , not an exact duplicate IMHO), but I think it is worthwhile to place it here. It is possible to use the techniques from other answers for this question to make a simple function
function itoa(i) result(res)
character(:),allocatable :: res
integer,intent(in) :: i
character(range(i)+2) :: tmp
write(tmp,'(i0)') i
res = trim(tmp)
end function
which you can use after without worrying about trimming and left-adjusting and without writing to a temporary variable:
OPEN(1, FILE = 'Output'//itoa(i)//'.TXT')
It requires Fortran 2003 because of the allocatable string.
For a shorten version.
If all the indices are smaller than 10, then use the following:
do i=0,9
fid=100+i
fname='OUTPUT'//NCHAR(i+48) //'.txt'
open(fid, file=fname)
!....
end do
For a general version:
character(len=5) :: charI
do i = 0,100
fid = 100 + i
write(charI,"(A)"), i
fname ='OUTPUT' // trim(charI) // '.txt'
open(fid, file=fname)
end do
That's all.
I've tried #Alejandro and #user2361779 already but it gives me an unsatisfied result such as file 1.txt or file1 .txt instead of file1.txt. However i find the better solution:
...
integer :: i
character(len=5) :: char_i ! use your maximum expected len
character(len=32) :: filename
write(char_i, '(I5)') i ! convert integer to char
write(filename, '("path/to/file/", A, ".dat")') trim(adjustl(char_i))
...
Explanation:
e.g. set i = 10 and write(char_i, '(I5)') i
char_i gives " 10" ! this is original value of char_i
adjustl(char_i) gives "10 " ! adjust char_i to the left
trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right
I think this is a simplest solution that give you a dynamical length filename without any legacy blank spaces from integer to string conversion process.
Try the following:
....
character(len=30) :: filename ! length depends on expected names
integer :: inuit
....
do i=1,n
write(filename,'("output",i0,".txt")') i
open(newunit=iunit,file=filename,...)
....
close(iunit)
enddo
....
Where "..." means other appropriate code for your purpose.
To convert an integer to a string:
integer :: i
character* :: s
if (i.LE.9) then
s=char(48+i)
else if (i.GE.10) then
s=char(48+(i/10))// char(48-10*(i/10)+i)
endif
Here is my subroutine approach to this problem. it transforms an integer in the range 0 : 9999 as a character. For example, the INTEGER 123 is transformed into the character 0123. hope it helps.
P.S. - sorry for the comments; they make sense in Romanian :P
subroutine nume_fisier (i,filename_tot)
implicit none
integer :: i
integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii
character(1) :: filename1,filename2,filename3,filename4
character(4) :: filename_tot
! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar
! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate.
if(i<=9) then
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+0)
filename4=char(48+i)
elseif(i>=10.and.i<=99) then
integer_zeci=int(i/10)
rest_zeci=mod(i,10)
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=100.and.i<=999) then
integer_sute=int(i/100)
rest_sute=mod(i,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+0)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=1000.and.i<=9999) then
integer_mii=int(i/1000)
rest_mii=mod(i,1000)
integer_sute=int(rest_mii/100)
rest_sute=mod(rest_mii,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+integer_mii)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
endif
filename_tot=''//filename1//''//filename2//''//filename3//''//filename4//''
return
end subroutine nume_fisier

Conversion of integer to filename incorrect fore more than one digit [duplicate]

I have a program in Fortran that saves the results to a file. At the moment I open the file using
OPEN (1, FILE = 'Output.TXT')
However, I now want to run a loop, and save the results of each iteration to the files 'Output1.TXT', 'Output2.TXT', 'Output3.TXT', and so on.
Is there an easy way in Fortran to constuct filenames from the loop counter i?
you can write to a unit, but you can also write to a string
program foo
character(len=1024) :: filename
write (filename, "(A5,I2)") "hello", 10
print *, trim(filename)
end program
Please note (this is the second trick I was talking about) that you can also build a format string programmatically.
program foo
character(len=1024) :: filename
character(len=1024) :: format_string
integer :: i
do i=1, 10
if (i < 10) then
format_string = "(A5,I1)"
else
format_string = "(A5,I2)"
endif
write (filename,format_string) "hello", i
print *, trim(filename)
enddo
end program
A much easier solution IMHO ...................
character(len=8) :: fmt ! format descriptor
fmt = '(I5.5)' ! an integer of width 5 with zeros at the left
i1= 59
write (x1,fmt) i1 ! converting integer to string using a 'internal file'
filename='output'//trim(x1)//'.dat'
! ====> filename: output00059.dat
Well here is a simple function which will return the left justified string version of an integer:
character(len=20) function str(k)
! "Convert an integer to string."
integer, intent(in) :: k
write (str, *) k
str = adjustl(str)
end function str
And here is a test code:
program x
integer :: i
do i=1, 100
open(11, file='Output'//trim(str(i))//'.txt')
write (11, *) i
close (11)
end do
end program x
I already showed this elsewhere on SO (How to use a variable in the format specifier statement? , not an exact duplicate IMHO), but I think it is worthwhile to place it here. It is possible to use the techniques from other answers for this question to make a simple function
function itoa(i) result(res)
character(:),allocatable :: res
integer,intent(in) :: i
character(range(i)+2) :: tmp
write(tmp,'(i0)') i
res = trim(tmp)
end function
which you can use after without worrying about trimming and left-adjusting and without writing to a temporary variable:
OPEN(1, FILE = 'Output'//itoa(i)//'.TXT')
It requires Fortran 2003 because of the allocatable string.
For a shorten version.
If all the indices are smaller than 10, then use the following:
do i=0,9
fid=100+i
fname='OUTPUT'//NCHAR(i+48) //'.txt'
open(fid, file=fname)
!....
end do
For a general version:
character(len=5) :: charI
do i = 0,100
fid = 100 + i
write(charI,"(A)"), i
fname ='OUTPUT' // trim(charI) // '.txt'
open(fid, file=fname)
end do
That's all.
I've tried #Alejandro and #user2361779 already but it gives me an unsatisfied result such as file 1.txt or file1 .txt instead of file1.txt. However i find the better solution:
...
integer :: i
character(len=5) :: char_i ! use your maximum expected len
character(len=32) :: filename
write(char_i, '(I5)') i ! convert integer to char
write(filename, '("path/to/file/", A, ".dat")') trim(adjustl(char_i))
...
Explanation:
e.g. set i = 10 and write(char_i, '(I5)') i
char_i gives " 10" ! this is original value of char_i
adjustl(char_i) gives "10 " ! adjust char_i to the left
trim(adjustl(char_i)) gives "10" ! adjust char_i to the left then remove blank space on the right
I think this is a simplest solution that give you a dynamical length filename without any legacy blank spaces from integer to string conversion process.
Try the following:
....
character(len=30) :: filename ! length depends on expected names
integer :: inuit
....
do i=1,n
write(filename,'("output",i0,".txt")') i
open(newunit=iunit,file=filename,...)
....
close(iunit)
enddo
....
Where "..." means other appropriate code for your purpose.
To convert an integer to a string:
integer :: i
character* :: s
if (i.LE.9) then
s=char(48+i)
else if (i.GE.10) then
s=char(48+(i/10))// char(48-10*(i/10)+i)
endif
Here is my subroutine approach to this problem. it transforms an integer in the range 0 : 9999 as a character. For example, the INTEGER 123 is transformed into the character 0123. hope it helps.
P.S. - sorry for the comments; they make sense in Romanian :P
subroutine nume_fisier (i,filename_tot)
implicit none
integer :: i
integer :: integer_zeci,rest_zeci,integer_sute,rest_sute,integer_mii,rest_mii
character(1) :: filename1,filename2,filename3,filename4
character(4) :: filename_tot
! Subrutina ce transforma un INTEGER de la 0 la 9999 in o serie de CARACTERE cu acelasi numar
! pentru a fi folosite in numerotarea si denumirea fisierelor de rezultate.
if(i<=9) then
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+0)
filename4=char(48+i)
elseif(i>=10.and.i<=99) then
integer_zeci=int(i/10)
rest_zeci=mod(i,10)
filename1=char(48+0)
filename2=char(48+0)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=100.and.i<=999) then
integer_sute=int(i/100)
rest_sute=mod(i,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+0)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
elseif(i>=1000.and.i<=9999) then
integer_mii=int(i/1000)
rest_mii=mod(i,1000)
integer_sute=int(rest_mii/100)
rest_sute=mod(rest_mii,100)
integer_zeci=int(rest_sute/10)
rest_zeci=mod(rest_sute,10)
filename1=char(48+integer_mii)
filename2=char(48+integer_sute)
filename3=char(48+integer_zeci)
filename4=char(48+rest_zeci)
endif
filename_tot=''//filename1//''//filename2//''//filename3//''//filename4//''
return
end subroutine nume_fisier

How to read and parse a line from file?

There is a file consisted of lines in the following format:
John, D E 100
Bob, F I 200
Oli, G H 1500
...
in general:
string, char char integer
The file needs to be read and stored in two arrays of which the first should store the string and characters1 and the second should store the integer.
How could this be done?
An initial attempt is made here.
1. Concatenated into single string as they are with the comma and the white spaces.
If the items in the input file are delimited by whitespaces or commas, we can read them using list-directed input (fmt=*), as suggested in the comments in the linked question, such that
read (funit, [fmt =] *, iostat = ios) surname, first_name, second_name, consumption
where the part "fmt =" is optional. The following is a slightly modified version of the original code in the linked page (please see comments in the code for more details):
module MyModule
implicit none !<-- this propagates to all routines in this module
contains
subroutine ReadFileIntoArrays (filename, name_arr, kWh_arr, ndata)
character(*), intent(in) :: filename !<-- an assumed-length string
character(*), intent(out) :: name_arr(:) !<-- an array of assumed-length strings
integer, intent(out) :: kWh_arr(:), ndata
character :: first_name, second_name !<-- a single char
character(50) :: surname !<-- a string of 50 chars
integer :: consumption, funit, ios, idx
funit = 10 ! use >= 10 (or open( newunit=funit, ... ) for recent compilers)
open (funit, file = filename, status = 'old')
idx = 0
do
read (funit, fmt = *, iostat = ios) & !<-- "&" means line continuation
surname, first_name, second_name, consumption
! "fmt = *" (list-directed input) tells the compiler
! to use whitespaces/commas as delimiters.
if (ios > 0) then
print *, "Wrong input format!" ; exit
else if (ios < 0) then
print *, "finished reading data." ; exit
else
idx = idx + 1
if (idx > size( name_arr )) stop "size of name_arr(:) too small"
! trim() chops trailing spaces in a string
name_arr( idx ) = trim(surname)//','//first_name//'.'//second_name//'.'
kWh_arr( idx ) = consumption
end if
end do
ndata = idx
close (funit)
end subroutine
end module
program MyMain
use MyModule
implicit none
integer :: consumption( 10 ), ndata, idx
character(50) :: names( 10 ) !<-- an array of size 10 (each element = 50-char string)
character(200) :: filename !<-- a string of 200 chars
filename = "clients.txt"
names = ""
consumption = 0
call ReadFileIntoArrays (filename, names, consumption, ndata)
print "(2a20)", "name", "consumption"
do idx = 1, ndata
print "(a20,i20)", trim( names( idx ) ), consumption( idx )
enddo
end program
Then, with the input in the question, the output becomes
finished reading data.
name consumption
John,D.E. 100
Bob,F.I. 200
Oli,G.H. 1500

Invalid form of array reference in fortran

AM writing a code in FORTRAN to read a mesh file in STARCD format(has.cel, .vrt and .bnd) am trying to use a counter and a pointer array, to count the number of vertices and the cells the file has so that it would be easy to define the neighbours of the cells later. Can you please take a look at the code and correct me out please and i get an error Invalid form of array reference at (1).
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
1
The error is shown here for all the lines with the icounter. To give u the outline of what is being done, i have just declared the types i have used and the variables, am reading the three files .vrt(nov) .cel(noc) and .bnd(bnd) and defining the datastructure where .vrt has 4 columns, .cel has 5 columns.
program reader
implicit none
type::node
real,allocatable,dimension(:)::point1,icounter,vrt
end type
type::elemtype
integer,allocatable,dimension(:)::quad,refback
integer,allocatable,dimension(:)::tri
end type
type::cel
integer,allocatable,dimension(:)::cell,ishape,reffwd
end type
type::boundnode
integer,allocatable,dimension(:)::bnode
end type
type::boundarycell
integer,allocatable,dimension(:)::bcell
end type
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
type(node),allocatable,dimension(:)::ivrt
type(elemtype),allocatable,dimension(:)::iquad
type(elemtype),allocatable,dimension(:)::itri
type(cel),allocatable,dimension(:)::icell
type(boundnode),allocatable,dimension(:)::ibnode
type(boundarycell),allocatable,dimension(:)::ibcell
integer::nov,noc,bnd,nbnd,i,j,k,count1,count2,numquad,flag,numtri
integer::usercell,tcell,cindex
integer::celltype,n,m
integer,allocatable,dimension(:,:)::qedg1,qedg2,qedg3,qedg4
integer,allocatable,dimension(:,:)::tedg1,tedg2,tedg3,tedg4
integer,allocatable,dimension(:)::ctype
integer,allocatable,dimension(:)::quadvert
integer,allocatable,dimension(:)::trivert
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CALL SYSTEM("wc STAR.vrt > NO_V")
OPEN (UNIT=10,FILE='NO_V',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")nov
close(10)
print *, nov
CALL SYSTEM("wc STAR.cel > NO_C")
OPEN (UNIT=10,FILE='NO_C',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")noc
close(10)
print *, noc
CALL SYSTEM("wc STAR.bnd > NO_B")
OPEN (UNIT=10,FILE='NO_B',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")nbnd
close(10)
print *, nbnd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
allocate(ivrt(nov))
do i=1,nov
allocate(ivrt(i)%vrt(1:4))
allocate(ivrt(i)%icounter(1))
end do
allocate(icell(noc))
do i=1,noc
allocate(ivrt(i)%icounter(1))
allocate(icell(i)%cell(1:5))
allocate(icell(i)%ishape(1))
allocate(icell(i)%reffwd(1))
end do
allocate(ibnode(nbnd))
do i=1,bnd
allocate(ibnode(i)%bnode(1:3))
end do
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(unit=10,file="STAR.vrt",status="old",action="read")
do i = 1,nov
read(10,*)ivrt(i)%vrt(1), ivrt(i)%vrt(2), ivrt(i)%vrt(3), ivrt(i)%vrt(4)
!print *, ivrt(i)%vrt(1), ivrt(i)%vrt(2), ivrt(i)%vrt(3), ivrt(i)%vrt(4)
end do
close (10)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(unit=10,file="STAR.cel",status="old",action="read")
do i=1,noc
read(10,*)icell(i)%cell(1),icell(i)%cell(2),icell(i)%cell(3),icell(i)%cell(4),icell(i)%cell(5)
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(3)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(4)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
if (icell(i)%cell(4).ne.icell(i)%cell(5))then
ivrt(icell(i)%cell(5)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
end if
end do
close(10)
do i=1,nov
allocate(ivrt(i)%point1(ivrt(i)%icounter(1)))
end do
ivrt(:)%icounter(:)=0
open(unit=10,file="STAR.cel",status="old",action="read")
do i=1,noc
read(10,*)icell(i)%cell(1),icell(i)%cell(2),icell(i)%cell(3),icell(i)%cell(4),icell(i)%cell(5)
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(3)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(4)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(2))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(3))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(4))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
if (icell(i)%cell(4).ne.icell(i)%cell(5))then
ivrt(icell(i)%cell(5))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(5))%icounter(1)=ivrt(icell(i)%cell(2))%icounter(1)+1
end if
end do
close(10)
There are two brackets missing... Do you mean:
ivrt( icell(i)%cell(2)%icounter(1) ) = ivrt( icell(i)%cell(2)%icounter(1)+1 )
^ ^
or:
ivrt( icell(i)%cell(2)%icounter(1) ) = ivrt( icell(i)%cell(2)%icounter(1) ) + 1
^ ^
That error is repeated several times throughout your code!
Like Alexander Vogt I agree that there are brackets missing. However, there is another problem.
In the defintion of the type cel the component cell is an integer array:
type :: cel
integer, allocatable, dimension(:) :: cell, ishape, reffwd
end type
type(cel), allocatable, dimension(:) :: icell
so one cannot have a reference icell(i)%cell(2)%...
Perhaps, then, the declaration of cel should be
type :: cel
type(node), allocatable, dimension(:) :: cell
! Also components ishape, reffwd of some type.
end type
end type
And then the bracket corrections additionally.

Fortran subroutines with arrays

I am having an issue with the subroutine in this program, which is at the end of the program. I am getting an error for the division of the arrays in the subroutine, which says "unclassifiable statement." Hope someone can help!
PROGRAM subroutine1
IMPLICIT NONE
INTEGER:: err, ierr, counter, y ,i ,j
!INTEGER, ALLOCATABLE:: gamenum(:)
CHARACTER(30):: fname
REAL, ALLOCATABLE:: AB(:), H(:), TB(:), BA (:), SP(:)
100 Format (A)
200 Format (I2)
300 Format (F9.3)
! 1.Open file
WRITE(*,100)"Please enter a filename:"
READ(*,*) fname
OPEN (UNIT=10, FILE=fname, STATUS="OLD", ACTION="READ", IOSTAT=err)
IF(err.NE.0) STOP "An error occured when opening the file."
! 2.Count Lines
READ(10,*)
counter=0
DO
READ(10,*,IOSTAT=ierr)
IF(ierr .NE. 0) EXIT
counter=counter+1
END DO
!WRITE(*,200) counter
! 3. allocate array
ALLOCATE(AB(counter))
ALLOCATE(H(counter))
ALLOCATE(TB(counter))
ALLOCATE(BA (counter))
ALLOCATE(SP(counter))
! 4. read in data
REWIND(10)
READ(10,*)
DO i=1,counter
READ(10,*) AB(i), H(i), TB(i)
END DO
REWIND(10)
! 5. Call subroutine
CALL arraycalc(counter,AB,H,TB,BA,SP)
! 6. Write out
WRITE(*,100)"Game AB H TB BA SP"
DO i=1,counter
WRITE(*,200,ADVANCE="NO") i
WRITE(*,'(5F9.3)') AB(i), H(i), TB(i), BA(i), SP(i)
END DO
END PROGRAM subroutine1
!HERE IS THE PART WHERE I'M HAVING TROUBLE
SUBROUTINE arraycalc(counter,AB,H,TB,BA,SP)
IMPLICIT NONE
INTEGER, INTENT(IN)::counter
INTEGER::i
REAL,INTENT(INOUT)::AB,H,TB
REAL,INTENT(INOUT):: BA,SP
DO i=1,counter
BA(i)=H(i)/AB(i)
END DO
DO i=1,counter
SP(i)=TB(i)/AB(i)
END DO
END SUBROUTINE
Inside the subroutine, AB, H, TB, BA, and SP are not declared as arrays, so the statement that gives the error indeed makes no sense. They are scalars, so can not be indexed.

Resources