I have a sub routine file as follows
subroutine grids(Ngrids,gridsize,boundx,boundy,boundz,occmatrix,myid)
implicit NONE
integer i,j,k,Ngrids, occmatrix(14,14,10)
integer locx,locy,locz,myid
double precision gridsize,boundx,boundy,boundz
do i = 1, 14
do j = 1, 14
do k = 1, 10
occmatrix(i,j,k) = 0
enddo
enddo
enddo
open (13, file = 'grid_data.9deg')
write(*,'(A,i2)'),' READING GRID FILE ON PROC.....',myid
read(13,*) Ngrids,gridsize
read(13,*) boundx,boundy,boundz
do i = 1, Ngrids
read(13,*) locx, locy, locz
occmatrix(locx,locy,locz) = 1
enddo
close(13)
return
end
It gives the following syntax error in compiling
subroutine grids(Ngrids,gridsize,boundx,boundy,boundz,occmatrix,my
1
Error: Unexpected junk in formal argument list at (1)
It used to run well before
I would believe, your line is to long. Did you add a new argument? Your code looks like free form, but it might be the compiler tried to apply fixed form due to a .f suffix in the filename or something like that. Convince the compiler to assume free formatted source code (by compiler options or usually a .f90 suffix).
Even in free formatted files your line width is limited and you should break longer lines, which would for example look like:
subroutine grids( Ngrids,gridsize,boundx,boundy,boundz, &
& occmatrix,myid )
If you are stuck with fixed format you need to indicate a continuation line by a non blank character in column 6.
Here is how it looks like in fixed form:
subroutine grids(Ngrids,gridsize,boundx,boundy,boundz,
& occmatrix,myid)
Please do not use fixed form anymore! Instead, change your files to end with .f90, most compilers recognize this for free formatted code.
Related
I would like to read the same line of a file many time in Fortran. The concerned data are real values. I tried to build this code as test but I am always getting it wrong.
program advance
implicit none
integer , parameter :: ut = 20
character(len=7) :: fname = 'dat.dat'
integer :: n, idx
character(len=100) :: lnumber
open(unit = ut, file =fname, status='old', action='read')
n = 10
do idx = 1, n
read(ut, '(a)', advance = 'no') lnumber
print *, lnumber
end do
end program advance
The dat.dat file contains one line with 25.325654515464564564
The code return the following error.
At line 13 of file advance.f90 (unit = 20, file = 'dat.dat')
Fortran runtime error: End of record
How do I fix this bug?
Such non-advancing input (using advance='no') doesn't mean that the file position is not advanced at all. It means that the file position isn't advanced beyond what is needed to satisfy the requirements of the input list.
So, in this case, the file position is advanced by reading the single "real number" into the character variable lnumber. The next read will continue from this later point. This later point happens to be the end of the file.
With advancing input more generally, the file position is advanced to the start of the next record even if the record is not required in entirety.
As High Performance Mark comments, reading the same line over and over again likely isn't what you should be doing. You could read the line into a character variable (such as is done here) and repeatedly use that variable as an internal file. However, if you really want to read a line again, consider backspace.
I am trying to read a file called "syerasg.txt" in Fortran90. This text file includes panel data on 91 variables (columns) for 8984 individuals for 16 years (143 744 rows). This variables are divided in 7 groups and this groups are divided in 13 subgroups. I am trying to read this file with the following code:
PROGRAM main
IMPLICIT NONE
INTEGER, PARAMETER :: p=8984, tf=16, sem=53, emp=7, gap=13
INTEGER :: r, t, j, m, g, x, i, IOstatus
INTEGER, DIMENSION (p,tf,emp) :: yemp
INTEGER, DIMENSION (p,tf,emp,gap) :: gaps
OPEN(UNIT=4, FILE='syearsg.txt',STATUS='old') !start gap years
DO i=1,p
DO t=1,tf
DO j=1,emp
IF (j==1) THEN
READ(4,*)(gaps(i,t,j,g),g=1,13)
ELSE IF (j==2) THEN
READ(4,*)(gaps(i,t,j,g-13),g=14,26)
ELSE IF (j==3) THEN
READ(4,*)(gaps(i,t,j,g-26),g=27,39)
ELSE IF (j==4) THEN
READ(4,*)(gaps(i,t,j,g-39),g=40,52)
ELSE IF (j==5) THEN
READ(4,*)(gaps(i,t,j,g-52),g=53,65)
ELSE IF (j==6) THEN
READ(4,*)(gaps(i,t,j,g-65),g=66,78)
ELSE IF (j==7) THEN
READ(4,*)(gaps(i,t,j,g-78),g=79,91)
END IF
END DO
END DO
END DO
CLOSE(4)
END PROGRAM main
When, running the code I get the following message:
Fortran runtime error: End of file
Any ideas on how to solve this?
Your loop nest issues 1,006,208 (that is p*tf*emp) read statements. It's no surprise that the program runs past the end of a file with only 143,744 lines. read reads the values it is asked to read, then skips to the start of the next line ready for the next read.
You might be able to fix your program by fiddling around with non-advancing input, ie telling the read statements not to skip to the start of the next line. But it would be easier not to.
From what you write you should only be issuing p*tf read statements, then reading a single line containing 91 elements, then distributing those elements into gaps as your logic demands.
You might revise your code to something like this (untested and not very carefully checked)
INTEGER, DIMENSION(91) :: workvec
...
DO i=1,p
DO t=1,tf
READ(4,*) workvec
gaps(i,t,1,1:13) = workvec( 1:13)
gaps(i,t,2,1:13) = workvec(14:26)
...
END DO
END DO
Suppose I have the matrix c(i,j). I want to write it on the screen on oldest Fortran77 language with three signs after comma. I write
do i=1,N
write(*,"(F8.3)") ( c(i,j), j=1,N )
end do
but the output is in the form
c(1,1)
c(1,2)
...
c(1,10) c(2,1)
c(2,2)
...
Finally, I may simply write
do i=1,N
write(*,*) ( c(i,j), j=1,N )
end do
and then the output is like the matrix, but, of course, it is not formatted.
How to get the correct output in Fortran77?
An edit. It seems that one of solutions is to write
do i=1, N
do j=1, N
write(*,'(F9.3,A,$)') c(i,j), ' '
end do
write(*,*) ' '
end do
Your format only specifies a single float but you actually want to write N per line.
A fairly general solution for this simple case would be something like
program temp
implicit none
integer, parameter :: N=3
real, dimension(N,N) :: c
integer :: i,j
character(len=20) :: exFmt
c = 1.0
write(exFmt,'("(",I0,"(F8.3))")') N
do i=1,N
write(*,exFmt) (c(i,j), j=1,N)
end do
end program
This will make exFmt be '(3(F8.3))', which specifies printing three floats (note you probably really want '(3(F8.3," "))' to explicitly include some spacing).
Note some compilers will allow for exFmt to be just '(*(F8.3))'. This is part of the fortran 2008 specification so may not be provided by all compilers you have access to. See here for a summary of compiler support (see Unlimited format item, thanks to HighPerformanceMark for this)
Finally an easy bodge is to use a format statment like '(1000(F8.3))' where 1000 is larger than you will ever need.
I have some issues about opening and reading multiple files. I have to write a code which reads two columns in n files formatted in the same way (they are different only for the values...). Before this, I open another input file and an output file in which I will write my results. I read other questions in this forum (such as this one) and tried to do the same thing, but I receive these errors:
read(fileinp,'(I5)') i-49
1
devstan.f90:20.24:
fileLoop : do i = 50,52
2
Error: Variable 'i' at (1) cannot be redefined inside loop beginning at (2)
and
read(fileinp,'(I5)') i-49
1
Error: Invalid character in name at (1)
My files are numbered from 1 to n and are named 'lin*27-n.dat' (where n is the index starts from 1) and the code is:
program deviation
implicit none
character(len=15) :: filein,fileout,fileinp
integer :: row,i,h
real :: usv,usf,tsv,tsf,diff
write(*,'(2x,''Input file .......''/)')
read(*,'(a12)') filein
write(*,'(2x,''Output file........''/)')
read(*,'(a12)') fileout
open(unit = 30,File=filein)
open(unit = 20,File=fileout)
fileLoop : do i = 50,52
fileinp = 'lin*27-'
read(fileinp,'(I5)') i-49
open(unit = i,File=fileinp)
do row = 1,24
read(30,*) h,usv,tsv
read(i,*) h,usf,tsf
diff = usf - usv
write(20,*) diff
enddo
close(i)
enddo fileLoop
end program deviation
How can I solve it? I am not pro in Fortran, so please don't use difficult language, thanks.
The troublesome line is
read(fileinp,'(I5)') i-49
You surely mean to do a write (as in the example linked): this read statement attempts to read from the variable fileinp rather than writing to it.
That said, simply replacing with write is probably not what you need either. This will ignore the previous line
fileinp = 'lin*27-'
merely setting to, in turn, "1", "2", "3" (with leading blanks). Something like (assuming you intend that * to be there)
write(fileinp, '("lin*27-",I1)') i-49
Note also the use of I1 in the format, rather than I5: one may want to avoid blanks in the filename. [This is suitable when there is exactly one digit; look up Iw.m and I0 when generalizing.]
I have opened a file to write a number. I have to write the number at the end of the file so
how to go to the last line to write on it?
You should open the file with
open(..., position="append",...)
Alternatively, you can inquire for the size of the file
inquire(...,size=some_integer_variable,...)
then if the file is a direct access file, you can use this size to calculate the record number of the final record. Alternatively, if the access mode is "stream", you can use
write(..., pos=some_integer_variable)
to write starting at the end of the file.
I've been using the same trick for years, and would be interested in a more elegant way but I can propose you the following method. Note that it is less and less efficient as the file increases in number of lines. Note also that this part of code could endup in an elegant module dedicated to playing with input/output.
Open your file
open(11, file='monfichier')
Compute how many lines there are in your file
nbline = 0 ! should have been declared as an integer
do while(.true.)
read(11,*,iostat=ios) ! ios should have been declared as an integer
if( ios > 0 ) then
stop 'problem somewhere'
else if( ios < 0 ) then ! end of file is reached
exit
else
nbline = nbline + 1
end if
end do
close(11)
at this step, you have the total number of lines stored in variable nbline.
If you want to print something at the Nth line before the last line, then
open(11, file='monfichier')
do i = 1, nbline - N ! see my nota bene at the end of my answer; i and N are integers
read(11,*)
end do
write(11,*)'hello world'
Et voilĂ !
N.B. : Please be carefull in the way you count for nbline-N or nbline-(N-1), depending on exactly what you want.
subroutine to_last_rec (luout)
! purpose: position to last record of file
implicit none
integer :: luout
logical :: ende
! first executable statement
ende = .FALSE.
do while ( .NOT. ende)
read (luout,*,end=100)
enddo
100 return
end subroutine to_last_rec
PROGRAM example
IMPLICIT NONE
INTEGER :: ierr
OPEN(UNIT=13,FILE="ex.dat")
CALL FSEEK(13, 0, 2, ierr)
! DO WHATEVER YOU WANT THEN
CLOSE(13)
END PROGRAM example
the call to fseek goes to the end of the file ( used like that, check the usage http://docs.oracle.com/cd/E19957-01/805-4942/6j4m3r8ti/index.html)