Hi I am a really novice coder and I am trying to read a file of positions in Fortran, but I keep getting severe 59 when I try to run the program. There are 343 rows in the file I am trying to read and 4 columns. I have read many questions that are similar on Stack Overflow but none of them have helped.
I tried the code below, and I expected it to work/let me read the file without errors.
PROGRAM force
implicit none
integer :: i, j
real, dimension(343,4) :: a
open(1, file='parameters.txt', Status='old', action='read')
do i = 1,343
read(1,*)(a(i,j),j=2,4)
end do
close(1)
END PROGRAM force
This is the file that I'm trying to read (the first 5 rows of it)
Ar 5.00000000000000 5.00000000000000 1.00000000000000
Ar 5.00000000000000 5.00000000000000 2.00000000000000
Ar 5.00000000000000 5.00000000000000 3.00000000000000
Ar 5.00000000000000 5.00000000000000 4.00000000000000
Ar 5.00000000000000 5.00000000000000 5.00000000000000
You need to skip the 'Ar' item before reading the numbers on each record (line). In list-directed add to the declarations
character(len=2) :: col1
and change
read(1,*) col1,(a(i,j),j=2,4)
You can also simplify that to
read(1,*) col1,a(i,2:4)
(the implicit do was needed in older FORTRAN, but not F90+).
You are reading three numbers in each read statement. However, the first item on each line is a string. If you know that the numbers start at particular columns, you can use the edit descriptors to read from these columns.
E.g.
read(1,'(tr4,3f22.0)') ...
where the actual widths of the columns must be inserted instead of the 22.
tr4 means move right by 6 columns and then 3f22.0 means read 3 floating point numbers, each from 22 columns.
By the way, using unit numbers, like your 1 lower than than 10 is risky. They may be pre-connected to something else. The most risky are 0,5 and 6, but you never know.
Related
I have a matrix A(3,4) in Fortran , I want to write it on a text file like this:
A(1,1) A(2,1) A(3,1)
A(1,2) A(2,2) A(3,2)
A(1,3) A(2,3) A(3,3)
A(1,4) A(2,4) A(3,4)
I use below code. It has two problems at first it is overwritten for each i and it is written in rows. I would be gratful to guide me to solve it. Thanks
do i=1,4
open (unit=10,file="out.txt",action="write")
write (10,*) A(1,i) , A(2,i) , A(3,i)
close (10)
As mentioned by Ian, your file is overwritten for each i because your open statement is inside the loop. Fortran is reopening the file fresh for each i. Move the open statement to before the loop so it is only opened once.
Of course it is written in rows because the first index in a 2-D array is the row index. You can switch the indices if you wish. On the other hand, according to your first box, it appears as though you want the rows across the columns.
You say you need to write just some elements. As long as they are in a contiguous block, you will want to use an implied do loop in the write statement. It is much more concise and you can write large blocks without typing out a lot of variables specifically. It would look like this:
open (unit=10,file="out.txt",action="write")
do i=1,4
write (10,*) (A(j,i), j=1,3)
end do
close (10)
Again, this reverses rows and columns, if you want traditional representation, switch the i and j.
I need a help about implicit do loop in Fortran.
This is my simple code:
Program Simple
Implicit none
Integer::i,j
Integer,parameter::N=2,M=3
Real,dimension(N,M)::Pot
Open(1,File='First.txt',Status='old')
Read(1,'(M(f3.1,1x))') ((Pot(i,j),j=1,M),i=1,N)
Close(1)
Open(2,File='Second.txt',Status='Unknown')
Write(2,'(M(i0,1x,i0,1x,f3.1,1x))') ((i,j,Pot(i,j),j=1,M),i=1,N)
Close(2)
Stop
End program Simple
This is the file First.txt:
1.1 1.2 1.3
2.1 2.2 2.3
When I try to execute this program I got a this message:
Unexpected element 'N' in format string
Unexpected element 'M' in format string
I want to keep the name of integer variables N and M in write statement.
Is there any way to also keep their values from declaration part?
You are using M and N in the string (as characters), not as variables. In order to use the variables you need to write their values into the format string:
character(len=128) :: fmtString
!...
write(fmtString,*) M
fmtString = '('//trim(adjustl(fmtString))//'(f3.1,1x))'
Read(1,fmtString) ((Pot(i,j),j=1,M),i=1,N)
And similarly for the write statement.
However, you can probably use list-directed input (Read(1,*)) for the input, and let Fortran figure out the exact format.
Instead of this string manipulation you can use (*(f3.1,1x)) in modern compilers, or if you have an old one just specify a very large number, e.g. (99999(f3.1,1x)). In both cases, the correct number of values will be printed. However, this will result into writing all m*n values in one single line [thanks #agentp for pointing this out].
I am new to Fortran 77. I need to read the data from a given text file into two arrays, but there are some lines that either are blank or contain descriptive information on the data set before the lines containing the data I need to read. How do I skip those lines?
Also, is there a way my code can count the number of lines containing the data I'm interested in in that file? Or do I necessarily have to count them by hand to build my do-loops for reading the data?
I have tried to find examples online and in Schaum's Programming with Fortran 77, but couldn't find anything too specific on that.
Part of the file I need to read data from follows below. I need to build an array with the entries under each column.
Data from fig. 3 in Klapdor et al., MPLA_17(2002)2409
E(keV) counts_in_bin
2031.5 5.4
2032.5 0
2033.5 0
I am assuming this question is very basic, but I've been fighting with this for a while now, so I thought I would ask.
If you know where the lines are that you don't need/want to read, you can advance the IO with a call to read with no input items.
You can use:
read(input-unit,*)
to read a line from your input file, discard its contents and advance IO to the next line.
It has been a long time since I have looked at F77 code, but in general if your read statement in a DO loop can deal with finding empty lines, or even a record that contains only blanks, then you could write logic to trap that condition and go to a break or continue statement. I just don't recall if read can deal with the situation intelligently.
Alternatively, if you are using a UNIX shell and coreutils, you can use sed to remove empty line, /^$/
or /^ *$/ to preprocess the file before you send it onto F77
Something like
$ sed infile -e 'd/^$/;d/^ *$/' > outfile
It should look something like this:-
C Initialise
integer i
character*80 t1,t2,t3
real*8 x,y
open(unit=1,file='qdata.txt')
C Read headers
read(1,100)t1
100 format(A80)
write(6,*) t1
read(1,100)t2
write(6,*) t2
read(1,100)t3
write(6,*) t3
write(6,*)
C Read data
do 10 i=1,10
read(1,*,end=99) x,y
write(6,*) x,y
10 continue
99 continue
end
So I've used a classic formatted read to read in the header lines, then free-format to read the numbers. The free-format read with the asterisk skips white space including blank lines so it does what you want, and when there is no more data it will go to statement 99 and finish.
The output looks like this:-
Data from fig. 3 in Klapdor et al., MPLA_17(2002)2409
E(keV) counts_in_bin
2031.5000000000000 5.4000000000000004
2032.5000000000000 0.0000000000000000
2033.5000000000000 0.0000000000000000
The following data is given in a file:
1 7 5 4 11 0 1 -13 -7
I want to form a 3x3 matrix from these columns. I have tried advance=no but receive a runtime error.
program form_matrix
implicit none
integer:: col,A(9)
open(unit=12,file='q10.txt')
do col=1,9
read(12,*,advance='no')(A(col))
end do
7 format(3i4)
write(*,7)(A(col),col=1,9)
close(12)
end program
Well, a couple of things:
To read into a variable, you need to specify that variable and not a statement containing the variable. A(col) instead of (A(col)).
Then, you are not allowed to use the list directed format (*) with an advance specifier, you need a format (which would be difficult in your case, because of the different widths of the columns).
It will probably be easier to read the whole line into the array in one go, without the loop and using the list directed format:
program form_matrix
implicit none
integer:: col,A(9)
open(unit=12,file='q10.txt')
read(12,*) A
7 format(3i4)
write(*,7)(A(col),col=1,9)
close(12)
end program
* enables list-directed formatting, where individual values are separated by commas or blanks. The type is determined by the RHS of the statement. So you read in a list of nine (because A is nine elements long) integers (because A is integer). For more details on this I suggest the Fortran 2008 Standard, Cl. 10.10 "List-directed formatting"
I am trying to read a list of real numbers from an external file into an array. I do not know how many records fields, separated by spaces, there are per record in a file, and I was therefore planning to use non-advancing I/O to first count the number of records fields, then allocate a real array of sufficient size, and to finally read the file into that same array.
Here is an example input file (where the edit descriptor should be f3.1 for every record field, i.e. a float 3 characters wide with one decimal, and counting the dot; although if I read Metcalf et al. correctly, the decimal is ignored):
1.0 2.0 3.0 4.0 5.0
And a MWE of my program looks like this
program testread
use iso_fortran_env
implicit none
character(len=255) :: filename
filename = 'read.dat'
print *, count_entries(filename)
contains
integer function count_entries(coefficient_file) result(n)
character(len=*), intent(in) :: coefficient_file
!real, dimension(:), allocatable :: coefficients
integer :: fileunit, stat
real :: temp
n=0
open(newunit=fileunit, file=coefficient_file, iostat=stat)
do
read(fileunit,'(f3.1)',advance='no',iostat=stat) temp
if (stat == iostat_end) then
exit
else
n = n + 1
end if
print *, stat, temp
end do
close(fileunit)
! What should happen in the future...
!allocate(coefficients(n))
!read(fileunit,*,iostat=stat) coefficients
end function count_entries
end program testread
If you save the sample input above as read.dat, compile the program with gfortran -o testread{,.f90} and execute it, you will get the following result:
0 1.00000000
0 2.00000000
0 0.300000012
0 0.00000000
0 4.00000000
0 5.00000000
-2 0.00000000
7
In other words, instead of counting 5 entries, it counts 7. And this is not surprising as it, for some reason, sees 7 numbers. But I wonder: why does it see 7 numbers? How can I extend my function to a) be able to also read larger reals and b) read reals of non-uniform width? For example, I would like to be able to read 1.01 1.003 2.1, etc.
It sees six numbers (the last one is an end of record condition) because your format specification specifies that three characters be read each time, but your data is spaced every four columns (three for the data, one for the separating blank).
If your input isn't fixed format (number of columns may vary), then read the whole record (line) into a character(:), allocatable variable and then manually chop that string up.
(Never use a format specification with a specified number of decimal places for input unless you know that your input will always suit that.)
You forgot to account for the spaces. Just use '(f3.1,1x)'.