I did some dummy code to learn to open and read file. Let's say I have the following test.dat which reads
1
2
3
4
5
6
7
8
9
10
I wrote the following code to open and read the data file
subroutine readdata
implicit none
integer :: j
double precision :: test
open(unit = 100, file = 'test.dat', status = 'old', action = 'read')
do j = 1, 10
read(100,*) test
print *, 'N1=', test
end do
end subroutine
The output is shown below, as expected
gfortran -g -I/usr/include -o main main.o subroutines.o -L/usr/lib64/liblapack -L/usr/lib64/libblas
test= 1.0000000000000000
test= 2.0000000000000000
test= 3.0000000000000000
test= 4.0000000000000000
test= 5.0000000000000000
test= 6.0000000000000000
test= 7.0000000000000000
test= 8.0000000000000000
test= 9.0000000000000000
test= 10.000000000000000
Main finished.
However, if the data is stored in a single row as follows
1 2 3 4 5 6 7 8 9 10
then the above code does not work as desired. It only reads the first element in the row and then prompt an error
sharwani#linux-h6qd:~/PHD_research/myCodes/data> ./runcase.sh
rm -f *.o *.mod *.MOD *.exe *.stackdump main
gfortran -g -I/usr/include -c main.f90
gfortran -g -I/usr/include -c subroutines.f90
gfortran -g -I/usr/include -o main main.o subroutines.o -L/usr/lib64/liblapack -L/usr/lib64/libblas
test= 1.0000000000000000
At line 9 of file subroutines.f90 (unit = 100, file = 'test.dat')
Fortran runtime error: End of file
So, my question is that I have a data file which contains 2879 (1 x 2879) numbers stored in a single row. How am I going to open and read all those numbers in the data file?
Each Fortran read statement, by default, reads a list of values and then advances to the beginning of the next line. Think of read as moving a cursor through the input file as it works. So your statement
read(100,*) test
does what you expect when the numbers in the input file are on separate lines. When they are all on the same line in the file the first read statement reads one value (i.e. test) then advances to the beginning of the next line to read the next value but there isn't a next line and you get the runtime error you have shown us.
There are 2 straightforward solutions.
One, you could read multiple values from a line in one statement, for example, you might declare
real, dimension(10) :: test
then
read(100,*) test
should get all the values into the array in one go.
Second, you could use non-advancing input, which tells the processor to not skip to the beginning of the next line after each read statement. Something like the following (check the edit descriptor for your circumstances)
read(100,'(f8.2)',advance='no') test
If you choose this latter approach, don't forget that after you have read all the values from a line you do want to skip to the beginning of the next line so you may need to execute a statement such as
read(100,*)
which doesn't read any values but does advance to the next line.
As already pointed out before, you can read your data in a row by adding
advance='no'
and a proper format string (depending on your data; for example 'i2' is working for a data sheet like [1 2 3 4 5 6] ) to your read command.
Another useful trick is to additionally take care for the I/O status by writing it's value on a paramter (i.e. io) and exiting the do loop without the runtime error, even if you don't know the lenght of your data sheet. A complete program could for example look like:
program read
integer::a,io
open(100, file='data')
do
read(100,'(i2)',advance='no',IOSTAT=io)a
if (io<0) exit
if (io>0) stop 'problem reading'
write(*,*)a
end do
end program
Have fun!
Related
This question already has answers here:
Line continuation of strings in Fortran
(4 answers)
Closed 4 years ago.
I have this code in FORTRAN 77 (I have to use this because it is used as a subroutine for my Abaqus program) where I am asking the subroutine to print my stresses and strain results, for each element and after each time increment, in a particular place. Now, my directory path is long (because of several reasons). Therefore, I have to write the path to the directory in two lines since FORTRAN 77 only recognizes anything written between columns 6 to 77 (I believe!).
Now, I have tried many things!
I have put & symbol at column 6 on the next line, a number (like 1) at column 6 on the next line, and even a star symbol (*) at the same place!
However, I keep getting error# 5082!
Here is the part of the code that is not being accepted in ifort compiler:
subroutine uvarm(uvar,direct,t,time,dtime,cmname,orname,
1 nuvarm,noel,npt,layer,kspt,kstep,kinc,ndi,nshr,coord,
2 jmac,jmatyp,matlayo,laccfla)
include 'aba_param.inc'
character*80 cmname, orname
character*3 flgray(15)
character*80 file1, file2
dimension uvar(nuvarm),direct(3,3),t(3,3),time(2)
dimension array(15),jarray(15),jmac(*),jmatyp(*),coord(*)
C integer i
call getvrm('E',array,jarray,flgray,jrcd,jmac,jmatyp,
1 matlayo,laccfla)
uvar(1) = array(1)
uvar(2) = array(2)
uvar(3) = array(4)
call getvrm('S',array,jarray,flgray,jrcd,jmac,jmatyp,
1 matlayo,laccfla)
uvar(4) = array(1)
uvar(5) = array(2)
uvar(6) = array(4)
file1 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'
1 '/fracture_subroutines/frac_in_mid_Mode2_case1_strains.txt'
file2 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'
2 '/fracture_subroutines/frac_in_mid_Mode2_case1_stress.txt'
open(unit=101,file=file1)
open(unit=103,file=file2)
write(101,350) uvar(1),uvar(2),uvar(3),coord(1),coord(2)
write(103,350) uvar(4),uvar(5),uvar(6),coord(1),coord(2)
350 format(e12.5,6x,e12.5,6x,e12.5,6x,e12.5,6x,e12.5)
C close(unit=101)
C close(unit=103)
return
end
What should I do?
I know I can always shorten the path so that the entire directory fits in one line. But for two reasons, I want to know how to continue the string into the next line in Fortran 77:
Reason 1: I just really want to know this.
Reason 2: The files printed are more organized this way! I will be able to name the file exactly what I want to.
Simply use the Fortran string concatenation operator // like this
file1 = '/gpfs/work/m/mfg5310/fracture/ResearchWork'//
& '/fracture_subroutines/frac_in_mid_Mode2_case1_strains.txt'
For example, I have a write command to save an array with 6 fields in a text file like this:
OPEN(UNIT=26,FILE='W:\Partikeltemperaturfeld.txt',
&FORM ='FORMATTED',STATUS='UNKNOWN',
&ACTION='READWRITE')
C
WRITE (26,FMT='(6(F8.3,3X))') TFIELD(1,1:6)
C
REWIND(26)
Now I want to read and save the 6 values of the last line of my text file in another array with 6 fields like:
IOS = 0
DO WHILE (IOS.EQ.0)
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TEST(1:6)
END DO
This could be the content of the last line in my file:
1377.445 1373.171 1363.639 1352.062 1341.476 1334.764
The aim is to save the last line in existing format.
But after doing this I always get values 0.000000E+00. How can I read and save the last line of my 'W:\Partikeltemperaturfeld.txt' file in array TEST(1:6)?
If you do
DO WHILE (IOS.EQ.0)
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TEST(1:6)
END DO
the loop will exit when there was some problem (end of file or an error condition) reading the array in the input list. The value of the variable being read is than undefined. You cannot use it. It can contain anything.
BTW your code is not Fortran 77 conforming (it is Fortran 90 or later) so I will not try to make my suggestion 100% Fortran 77 either. You can do
DO
READ(UNIT=26,FMT='(6(F8.3,3X))',IOSTAT=IOS) TMP
IF (IOS.EQ.0) THEN
TEST = TMP
ELSE
EXIT
END DO
END DO
where TEST and TMP are arrays of size 6
I have been trying to write a program in Fortran77 and am not able to finish it up, so I need a bit help to make it work.
At first I am just trying to open a .txt file read the file and write the file.
the .txt file is of the format shown below.
001,0.02014,3.1217
002,0.09611,3.1203
003,0.23753,3.1128
004,0.45527,3.0884
005,0.75772,3.0285
where the first column is integer and the second column coma separated contains a real number with 5 digits after the decimal point and third column again a real number with four digits after the decimal point.
My program looks as follows:
PROGRAM FIRST
IMPLICIT NONE
REAL,DIMENSION(304,3)::A
OPEN(UNIT =7 , FILE = "Pressure_values.txt",
1 FORM = "FORMATTED", STATUS = "OLD", ACTION = "READ")
READ(*,100) ((A(I,J),J=1,3), I=1,304)
WRITE(*,100) ((A(I,J),J=1,3), I=1,304)
100 FORMAT(I3,F10.5,F10.4)
STOP
END
Where am I going wrong?
You are not reading from the file. You need to read from unit 7.
read(7,100)
your code:
READ(*,100) ((A(I,J),J=1,3), I=1,304)
means "read from STDIN with format No.100", not the file you just opened. STDIN normally means the keyboard input stream. use:
READ(7,100) ((A(I,J),J=1,3), I=1,304)
instead.
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 am using FORTRAN to read in data from an ASCII text file. The file contains multiple data values per line but the number of values per line is not constant.
101.5 201.6 21.4 2145.5
45.6 21.2
478.5
...
Normally after a read statement, Fortran would go to the next line. What I want to be able to do is read one data value at a time. If it hits the end of the line, it should just continue reading on the next line. Is this possible?
As pointed out by IRO-bot in their comment to your question, the answer has already been given by M.S.B. Below I have merely provided some code illustrating that answer (as M.S.B.'s post contained none):
program test
character(len=40) :: line
integer :: success, i, indx, prev, beginning
real :: value
open(1,file='test.txt')
do
read(1,'(A)',iostat=success) line
if (success.ne.0) exit
prev = 1
beginning = 1
do i=1,len(line)
! is the current character one out of the desired set? (if you
! have got negative numbers as well, don't forget to add a '-')
indx = index('0123456789.', line(i:i))
! store value when you have reached a blank (or any other
! non-real number character)
if (indx.eq.0 .and. prev.gt.0) then
read(line(beginning:i-1), *) value
print *, value
else if (indx.gt.0 .and. prev.eq.0) then
beginning = i
end if
prev = indx
end do
end do
close(1)
end program test
When running this program using the sample lines you provided the output is
101.5000
201.6000
21.40000
2145.500
45.60000
21.20000
478.5000
I hope you will find this helpful.