Reading from a named pipe (and then stopping) - fortran

I am trying to get two fortran programs to communicate through a named pipe but the reading program is hanging. My command look like this:
> mkfifo /tmp/myfifo
> ./app/fortw /tmp/myfifo &
> ./app/fortr /tmp/myfifo
where fortw prints the numbers 1 to 10 and 'fortr' reads them like this
open ( unit = nsave, file = outputfile , form = 'formatted', access = 'stream' )
do while ( .TRUE. )
read ( unit = nsave, fmt = *, end = 10), j
write( 6, *), j
end do
10 continue
It prints the numbers 1 - 6 and then hangs so i have to do fg then C^C to stop it.
If I replace ./app/fortr with cat, or an equivalent c++ program, then I get the numbers 1 to 10 as expected so the problem seems to be with the reading not the writing. But if I read from a normal file rather than a fifo, ./app/fortr gives the expected result.
Should I expect to be able to get this to work, and it so, how?
UPDATE:
A more minimal example. If test contains the numbers 1 to 10, then
./app/fortr test
prints the numbers 1 to 10
but
./app/fortr <( cat test )
prints the numbers 1 to 6 and hangs

Related

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

fortran averaging columns frame by frame in specific format

I would like to average first column and last column shown here(that is my output). My code does several things such as compare specific atoms with the name "CA" for each frame (I have 1000 frames), exclude the nearest neighbours and depending on the cutoff value, and count those contacts and print them separately according to my wish (input file looks like this). I would like to print a file where it gives me the output something like following as an example:
1 0
2 12
3 12
....
100 16
Need guidance to achieve that by helping me form a loop or a condition.
open(unit=11,file="0-1000.gro", status="old", action="read")
do f=1,frames,10
25 format (F10.5,F10.5,F10.5)
do h=1,natoms_frames
read(11,format11)nom(h),resname(h),atmtype(h),num(h),x(h),y(h),z(h)
end do
read(11,25)lasta(f),lastb(f),lastc(f)
count=0
do h=1, natoms_frames
if (atmtype(h).eq.' CA') then
count=count+1
CAx(count)=x(h)
CAy(count)=y(h)
CAz(count)=z(h)
end if
end do
do h=1, count
avg_cal=0
cal=0
do hh=h+3, count
if (h.ne.hh) then
! finding distance formula from the gro file
distance = sqrt((CAx(hh)-CAx(h))**2 + (CAy(hh)-CAy(h))**2 + (CAz(hh)-CAz(h))**2)
if (distance.le.cutoff) then
cal = cal+1
set = set+1
final_set=final_set+1
avg_cal=avg_cal+1
end if
end if
end do
write(*,*)h,cal,final_set
end do
end do ! end of frames
close(11)
end program num_contacts
Writing in a file (in ASCII) is the same as printing on screen, except that you need to specify the file's unit.
So first, open your file:
open(unit = 10, file = "filename.dat", access = "sequential", form = "formatted", status = "new", iostat = ierr)
where 'unit' is a unique integer that will be associated to your file (as an ID). Note that the 'form' is 'formatted' as you want to output something readable by a human. Then you can start your loop:
do h = 1, natoms_frames
! BUNCH OF STUFF TO CALCULATE REQUIRED VARIABLES
write(10, *) h, cal, final_set
end do
Finally, close your file:
close(10)

data entrance error 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 "<".

Adapting a Fortran Code to write a file, run an executable and read in arrays from a file

I am new to Fortran but I am trying to adapt a Fortran code and I am having trouble doing something which I think is probably quite simple.
I want to adapt a Fortran file called original.f so that it makes an input file called input.inp and populates it with 4 integers calculated earlier in original.f so that input.inp looks like, for example:
&input
A = 1
B = 2
C = 3
D = 4
&end
I know how to write this format:
OPEN(UNIT=10,FILE='input.inp')
WRITE (10,00001) 1,2,3,4
...
...
...
00001 Format (/2x,'&input',
& /2x,'A = ',i4,
& /2x,'B = ',i4,
& /2x,'C = ',i4,
& /2x,'D = ',i4,
& /2x,'&end')
(or something like this that I can fiddle with when I get it working) but I am not sure how to create the input.inp file write this into it and then use this input file.
The input file needs to be used to run an executable called "exec". I would run this in bash as:
./exec < input.inp > output.out
Where output.out contains two arrays called eg(11) and ai(11,6,2) (with dimensions given) like:
eg(1)= 1
eg(2)= 2
...
...
...
eg(11)= 11
ai(1,1,1)= 111
ai(1,2,1)= 121
...
...
...
ai(11,6,2)=1162
Finally I need to read these inputs back into original.f so that they can be used further down in file. I have defined these arrays at the beginning of original.f as:
COMMON /DATA / eg(11),ai(11,6,2)
But I am not sure of the Fortran to read data line by linw from output.out to populate these arrays.
Any help for any of the stages in this process would be hugely appreciated.
Thank you very much
James
Since you have shown how you create the input file, I assume the question is how to read it. The code shows how "a" and "b" can be read from successive lines after skipping the first line. On Windows, if the resulting executable is a.exe, the commands a.exe < data.txt or type data.txt | a.exe will read from data.txt.
program xread
implicit none
character (len=10) :: words(3)
integer, parameter :: iu = 5 ! assuming unit 5 is standard input
integer :: a,b
read (iu,*) ! skip line with &input
read (iu,*) words ! read "a", "=", and "1" into 3 strings
read (words(3),*) a ! read integer from 3rd string
read (iu,*) words ! read "b", "=", and "1" into 3 strings
read (words(3),*) b ! read integer from 3rd string
print*,"a =",a," b =",b
end program xread
If I understand the expanded question correctly, you have to work with an output file, produced by some other code you did not write, with lines like eg(1) = ....
For the simplest case where you know the number of elements and their ordering beforehand, you can simply search each line for the equals sign from behind:
program readme
implicit none
character(100) :: buffer
integer :: i, j, k, pos, eg(11), ai(11,6,2)
do i = 1,11
read*, buffer
pos = index(buffer, '=', back = .true.)
read(buffer(pos+1:), *) eg(i)
enddo
! I have assumed an arbitrary ordering here
do k = 1,2
do i = 1,11
do j = 1,6
read*, buffer
pos = index(buffer, '=', back = .true.)
read(buffer(pos+1:), *) ai(i,j,k)
enddo
enddo
enddo
end program
Assuming here for simplicity that the data are provided to standard input.

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.