data entrance error Fortran - fortran

I'm learning how to programming with fortran90 and i need receive data from a txt file by the command prompt (something like that:
program.exe"<"data.txt).
at the Input txt file I'll always have a single line with at least 6 numbers till infinity.
if the data was wrote line by line it runs fine but as single line I'm receiving the error: "traceback:not available,compile with - ftrace=frame or - ftrace=full fortran runtime error:end file"
*note: i'm using Force fortran 2.0
here is example of data:
0 1 0.001 5 3 1 0 -9 3
edit: just clarifying: the code is working fine itself except for the read statement, which is a simple "read*,". I want know how To read a entire line from a txt once the entrance will be made by the promt command with stream direction.
( you can see more about that here: https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true).
there is no need to read the code, i've posted it just for knowledge.
I'm sorry about the whole inconvenience.
here is the code so far:
program bissecao
implicit none
integer::cont,int,e,k,intc,t1,t2,t3
doubleprecision::ii,is,pre,prec,erro,somaa,somab,xn
doubleprecision,dimension(:),allocatable::co
t1=0
t2=0
t3=0
! print*,"insira um limite inf da funcao"
read*,ii
!print*,"insira o limite superior da func"
read*,is
! print*,"insira a precisÆo admissivel"
read*,pre
if (erro<=0) then !elimina criterio de parada negativo ou zero
Print*,"erro"
go to 100
end if
!print*,"insira a qtd iteracoes admissiveis"
read*,int
!print*,"insira o grau da f(x)"
read*,e
if (e<=0) then ! elimina expoente negativo
e=(e**2)**(0.5)
end if
allocate(co(e+1))
!print*, "insira os coeficientes na ordem:&
! &c1x^n+...+(cn-1)x^1+cnx^0"
read(*,*)(co(k),k=e+1,1,-1)
somab=2*pre
intc=0
do while (intc<int.and.(somab**2)**0.5>pre.and.((is-ii)**2)**0.5>pre)
somab=0
somaa=0
xn =(ii+is)/2
do k=1,e+1,1
if (ii /=0) then
somaa=ii**(k-1)*co(k)+somaa
else
somaa=co(1)
end if
! print*,"somaa",k,"=",somaa
end do
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
!print*,"somab",k,"=",somab
end do
if ((somaa*somab)<0) then
is=xn
else if((somaa*somab)>0)then
ii=xn
else if ((somaa*somab)==0) then
xn=(ii+is)/2
go to 100
end if
intc =intc+1
prec=is-ii
if ((((is-ii)**2)**.5)< pre) then
t3=1
end if
if (((somab**2)**.5)< pre) then
t2=1.
end if
if (intc>=int) then
t1=1
end if
end do
somab=0
xn=(ii+is)/2
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
end do
100 write(*,'(A,F20.15,A,F20.15,A,A,F20.15,A,F20.15,A,I2)'),"I:[",ii,",",is,"]","raiz:",xn,"Fraiz:",somab,"Iteracoes:",intc
end program !----------------------------------------------------------------------------

In your program, you are using the "list-directed input" (i.e., read *, or read(*,*))
read *, ii
read *, is
read *, pre
read *, int
read *, e
read *, ( co( k ), k = e+1, 1, -1 )
which means that the program goes to the next line of the data file after each read statement (by neglecting any remaining data in the same line). So, the program works if the data file (say "multi.dat") consists of separate lines (as suggested by OP):
0
1
0.001
5
3
1 0 -9 3
But now you are trying to read an input file containing only a single line (say "single.dat")
0 1 0.001 5 3 1 0 -9 3
In this case, we need to read all the values with a single read statement (if list-directed input is to be used).
A subtle point here is that the range of array co depends on e, which also needs to be read by the same read statement. A workaround might be to just pre-allocate co with a sufficiently large number of elements (say 100) and read the data in a single line, e.g.,
integer :: k
allocate( co( 100 ) )
read *, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
For completeness, here is a test program where you can choose method = 1 or 2 to read "multi.dat" or "single.dat".
program main
implicit none
integer :: int, e, k, method
double precision :: ii, is, pre
double precision, allocatable :: co(:)
allocate( co( 1000 ) )
method = 1 !! 1:multi-line-data, 2:single-line-data
if ( method == 1 ) then
call system( "cat multi.dat" )
read*, ii
read*, is
read*, pre
read*, int
read*, e
read*, ( co( k ), k = e+1, 1, -1 )
else
call system( "cat single.dat" )
read*, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
endif
print *, "Input data obtained:"
print *, "ii = ", ii
print *, "is = ", is
print *, "pre = ", pre
print *, "int = ", int
print *, "e = ", e
do k = 1, e+1
print *, "co(", k, ") = ", co( k )
enddo
end program
You can pass the input file from standard input as
./a.out < multi.dat (for method=1)
./a.out < single.dat (for method=2)
Please note that "multi.dat" can also be read directly by using "<".

Related

Reading three specific numbers in a text file and writing them out

I have a problem how to print only specific three numbers, which are in a file with no format. I have no idea how to read it and print because if I use read from higher i, it does not start reading e.g. for i = 4, the line 4. I need only numbers 88.98, 65.50, and 30.
text
678 people
450 girls
22 old people
0 cats
0 dogs
4 girls blond
1 boy blond
1 old man
0 88.9814 xo xi
0 65.508 yo yi
0 30 zo zi
I tried this, but this is not working at all.
program souradnice
implicit none
integer :: i, k
character*100 :: yo, zo, line, name, text
real :: xo
open(10,file="text.dat", status='old')
do i=20,20
read(10,fmt='(a)') line
read(unit=line, fmt='(a100)') text
if(name=="xo") then
print *, trim(text)
endif
enddo
close(10)
end program souradnice
You need to read the whole file line by line, and check each line to see if it's the one you want, e.g. by using the index intrinsic. For example,
program souradnice
implicit none
character(100) :: line
character(5) :: matches(3)
real :: numbers(3)
character(10) :: dummy
integer :: i, ierr
! Substrings to match to find the relevant lines
matches = ["xo xi", "yo yi", "zo zi"]
open(10,file="text.dat", status='old')
do
! Read a line from the file, and exit the loop if the file end is reached.
read(10,fmt='(a)',iostat=ierr) line
if (ierr<0) then
exit
endif
do i=1,3
! Check if `line` matches any of the i'th line we want.
if (index(line, matches(i))>0) then
! If it matches, read the relevant number into `numbers`.
read(line,*) dummy, numbers(i)
endif
enddo
enddo
write(*,*) numbers
end program

Fortran: Reading and printing 2D array from text file

I am trying to read a 3x3 array and print it out but I am getting an end of line error:
The text file contains the following array:
1 2 3
4 5 6
7 8 9
Here is my code:
program myfile
implicit none
! Declare Variables
integer i,j
!real, dimension(1:3,1:3) :: A
integer, parameter :: M = 3, N =3
real, dimension(1:M,1:N) :: A
! Open and read data
open(unit=10, file = 'test_file_cols.txt', status = 'old')
do i =1,M
do j =1,N
read(unit=10,FMT=*) A(i,j)
print *,A(i,j)
end do
end do
end program myfile
The error I am getting is below:
1.000000
4.000000
7.000000
forrtl: severe (24): end-of-file during read, unit 10, file C:\Users\M42141\Documents\mean_flow_file\test_file_cols.txt
As discussed briefly in the comments by default all I/O in Fortran is record based. This is true for both formatted and unformatted files. What happens is the file is viewed as a set of records - and you can think of a record as a line in the file. Now these lines may be very, very long, especially in an unformatted files, but the default Fortran I/O methodology still views it as a set of lines.
Now the important thing is that by default every time you perform an I/O statement (read, write, print) the last thing it does is move from the record it is on to the next record - a write statement will write an end of record marker. This is why you automatically get a newline after a write statement, but it also means that for a read statement any remaining data in the record (on the line) will get skipped over. This is what is happening to you. The first read reads record 1, and so you get 1.0, and then moves to record 2. Your program then reads record 2 and so you get 4.0, and it automatically moves to record 3. this is then read (9.0) and the file pointer moves onto record 4. You then try to read this, but there isn't a record 4, so you get an end of file error.
Record structure is a bit strange when you first encounter it, but when you get used to it it is very powerful and convenient - I'll show an example below, and another one might be that you could leave a comment at the end of each line saying what it does, the end of the read statement will mean you move to the next record, so skipping the comment and needing to take no special action in you code to deal with such a case.
Anyway how to solve your case. Three possible ways
Read a whole record at a time - the comment suggests an implied do loop but I think in this case an array section is much easier and more intuitive
You can simply read the whole array in one go. This works because when a read statement finishes a record and finds it still "needs" more data it will carry onto the next record and keep reading. But note the end of line comment idea won't work here - can you work out why?
Non-Advancing I/O. I don't recommend this at all in this case, but for completeness this allows you to perform a read or write without moving onto the next record
There may be others, you could probably use so called stream I/O but personally I prefer record based whenever possible, I find it more convenient and powerful. Anyway here is a program illustrating the 3 methods. Note I have also changed your input file, getting the original to work with non-advancing I/O is a pain, but not the other 2 - another reason not to use it here.
ian#eris:~/work/stack$ cat readit.f90
Program readit
Implicit None
Real, Dimension( 1:3, 1:3 ) :: a
Integer :: i, j
! one line per read
Write( *, * ) 'Line at a time'
Open( 10, file = 'in' )
Do i = 1, 3
Read ( 10, * ) a( i, : )
Write( *, * ) a( i, : )
End Do
Close( 10 )
! All in one go
Write( *, * ) 'All in one go'
Open( 10, file = 'in' )
Read ( 10, * ) a
Write( *, * ) a
Close( 10 )
! Non advancing I/O
Write( *, * ) 'Non-advancing'
Open( 10, file = 'in' )
Do i = 1, 3
Do j = 1, 3
! Non advancing I/O requires a 'proper' format
Read ( 10, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
Write( *, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
End Do
! Move to next records (lines)
Read ( 10, * )
Write( *, * )
End Do
Close( 10 )
End Program readit
ian#eris:~/work/stack$ gfortran-8 -Wall -Wextra -pedantic -std=f2008 -fcheck=all -O readit.f90
ian#eris:~/work/stack$ cat in
1.0 2.0 3.00
4.0 5.0 6.00
7.0 8.0 9.00
ian#eris:~/work/stack$ ./a.out
Line at a time
1.00000000 2.00000000 3.00000000
4.00000000 5.00000000 6.00000000
7.00000000 8.00000000 9.00000000
All in one go
1.00000000 2.00000000 3.00000000 4.00000000 5.00000000 6.00000000 7.00000000 8.00000000 9.00000000
Non-advancing
1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0

Trouble reading reals from unknown length character string in Fortran

This is a small portion of the data I am trying to read:
01/06/2009,Tom Sanders,,264,220,73,260
01/08/2009,Adam Apple,158,,260,,208
01/13/2009,Lori Freeman,230,288,218,282,234
01/15/2009,Diane Greenberg,170,,250,321,197
01/20/2009,Adam Apple,257,,263,256,190
01/21/2009,Diane Greenberg,201,,160,195,142
01/27/2009,Tom Sanders,267,,143,140,206
01/29/2009,Tina Workman,153,,124,155,140
02/03/2009,Tina Workman,233,,115,,163
02/03/2009,Adam Apple,266,130,310,,310
the numbers between each comma are from a different location
Where two commas would represent missing data and a trailing comma would mean the fifth data point is missing
My goal is to organize the data into a table after calculating the average of each site and person, hence my two dim arrays
I want my output to look something like the following:
(obviously neater formatting but a table nonetheless)
Average Observed TDS (mg/l)
Name Site 1 Site 2 Site 3 Site 4 Site 5
------------------------------------------------------
Tom Sanders 251.0 172.5 251.7 160.0 229.0
Adam Apple 227.0 130.0 277.7 256.0 236.0
Lori Freeman 194.0 288.0 216.7 279.0 202.7
Diane Greenberg 185.5 190.0 205.0 258.0 169.5
Tina Workman 193.0 140.0 119.5 155.0 163.0
This is my program so far:
program name_finder
implicit none
integer, parameter :: wp = selected_real_kind(15)
real(wp) :: m, tds
real(wp), dimension(20,5) :: avg_site, site_sum
integer, dimension(20) :: nobs
integer, dimension(5) :: x
integer :: ierror, i, nemp, cp, non, ni, n
character(len=40), dimension(20) :: names
character(len=200) :: line, aname
character(len=20) :: output, filename
character(len=3), parameter :: a = "(A)"
do
write(*,*) "Enter file to open."
read(*,*) filename
open(unit=10,file = filename, status = "old", iostat = ierror)
if (ierror==0) exit
end do
write(*,*) "File, ",trim(filename)," has been opened."
non = 0
outer: do
read(10,a, iostat = ierror) line
if (ierror/=0) exit
cp = index(line(12:),",") + 11
aname = line(12:cp-1)
n=0
middle: do
read(line,'(Tcp,f4.2)') tds
write(*,*) "tds=", tds
n=n+1
if (n>10) exit
i = 1
inner: do
if (i > non) then
non = non +1
names(non) = trim(aname)
!ni = non
exit
end if
if (aname == names(i)) then
!ni = i
!cycle outer
exit inner
end if
i = i + 1
end do inner
end do middle
end do outer
write(*,*)
write(*,*) "Names:"
do i = 1,non
write(*,*) i, names(i)
end do
close(10)
close(20)
STOP
end program name_finder
TLDR; I am having trouble reading the data from the file shown at the top of each site after the names.
Suggestions? Thanks!
I hope the following is helpful. I have omitted any easily assumed declarations or any further data manipulation or writing to another file. The code is used just to read the data line by line.
character(150) :: word
read(fileunit, '(A)') word ! read the entire line
comma_ind = index(word,',') ! find the position of first comma
! Find the position of next comma
data_begin = index(word(comma_ind+1:),',')
! Save the name
thename = word(comma_ind+1:comma_ind+data_begin-1)
! Define next starting point
data_begin = comma_ind+data_begin
! Read the rest of the data
outer: do
if (word(data_begin+1:data_begin+1) == ',') then
! decide what to do when missing an entry
data_begin = data_begin + 1
cycle outer
else if (word(data_begin+1:data_begin+1) == ' ') then
! Missing last entry
exit outer
else
! Use it to find the length of current entry
st_ind = index(word(data_begin+1:),',')
if (st_ind == 0) then
! You reached the last entry, read it and exit
read(word(data_begin+1:), *) realData
exit outer
else
! Read current entry
read(word(data_begin+1: data_begin+st_ind-1),*) realData
end if
! Update starting point
data_begin = data_begin + st_ind
end if
end do outer
There could be a more elegant way to do it but I cannot think of any at the moment.

checking input type in fortran read statement

I have put a check in error made in the input as:
integer :: lsp
chksp:do
write(*,*) "#Enter Number"
read(*,*,iostat=istat)lsp
if (istat==0) then
exit chksp
else
write(*,*)"Number can only be integer. Re-enter!"
end if
end do chksp
The problem is, it can detect error if a character value in enteres, instead of a numeric value; but it cannot detect error, if a real value is entered, instead of a integer.
Any way to force it detect integer only?
NB: May be problem with ifort; gfortran is happy with the code.
You can specify the format to request an integer:
program enter_int
implicit none
integer :: ierror, intVal
do
write(*,*) "Enter an integer number"
read(*,'(i10)',iostat=ierror) intval
if ( ierror == 0 ) then
exit
endif
write(*,*) 'An error occured - please try again'
enddo
write(*,*) 'I got: ', intVal
end program
Then, providing a float fails.
Something like the following?
ian#ian-pc:~/test/stackoverflow$ cat read.f90
Program readit
Integer :: val
Integer :: iostat
val = -9999
Do
Read( *, '( i20 )', iostat = iostat ) val
If( iostat == 0 ) Then
Write( *, * ) 'val = ', val
Else
Write( *, * ) 'oh dear!!'
End If
End Do
End Program readit
ian#ian-pc:~/test/stackoverflow$ nagfor -o read read.f90
NAG Fortran Compiler Release 5.3.1(907)
[NAG Fortran Compiler normal termination]
ian#ian-pc:~/test/stackoverflow$ ./read
10
val = 10
10.0
oh dear!!
safs
oh dear!!
123dfs23
oh dear!!
^C
ian#ian-pc:~/test/stackoverflow$ gfortran -o read read.f90
ian#ian-pc:~/test/stackoverflow$ ./read
10
val = 10
10.0
oh dear!!
dsfs
oh dear!!
^C
ian#ian-pc:~/test/stackoverflow$

How to get FORTRAN 77 to read input?

I am using some old fortran code for a biology project I am doing. I am posting the relevant snippets here. Here is a subroutine called "READCN". Earllier in the program MAXN was set to 108.
OPEN ( UNIT = CNUNIT, FILE = CNFILE,
: STATUS = 'OLD', FORM = 'UNFORMATTED' )
READ ( CNUNIT ) N, BOX
IF ( N .GT. MAXN ) STOP ' N TOO LARGE '
READ ( CNUNIT ) ( RX(I), I = 1, N ), ( RY(I), I = 1, N )
CLOSE ( UNIT = CNUNIT )
RETURN
END
I am inputting a file called "data.dat" to the program. Here is the file:
10, 4
0.8147, 0.1576
0.9058, 0.9706
0.1270, 0.9572
0.9134, 0.4854
0.6324, 0.8003
0.0975, 0.1419
0.2785, 0.4218
0.5469, 0.9157
0.9575, 0.7922
0.9649, 0.9595
Nevertheless, I always get the message "N TOO LARGE". Any advice? Thanks!
Don't open as unformatted, it will read your file as if it were binary data. Open as formatted instead, and use "*" format. Also, don't read in one line, as you would not read your data in the expected order.
program bob
implicit none
integer cnunit, n, maxn, box, i
parameter(maxn=108, cnunit=10)
real rx(maxn), ry(maxn)
open(unit=cnunit, file='bob.txt', status='old', form='formatted')
read(cnunit, *) n, box
print *, 'n=', n, 'box=', box
if(n .gt. maxn) stop 'n too large'
do i=1, n
read(cnunit, *) rx(i), ry(i)
print *, rx(i), ry(i)
end do
close(unit=cnunit)
end
Alternately, if you can't change the code, then change your input file to fit the needs of your program. The input file you give simply won't work: you need binary data, in the format expected by your compiler (there is the usual, non portable "record size"), and data must be given column-wise, not row-wise.