In a given file record, I need to read the first two integer elements at first, and then the rest of the line (a large number of real elements), because the assignment depend on the first 2. Suppose the format of the first two integer elements is not really well defined.
The best way to solve the problem could be something:
read(unitfile, "(I0,I0)", advance='no') ii, jj
read(unitfile,*) aa(ii,jj,:)
But it seems to me the "(I0)" specification is not allowed in gfortran.
Basically the file read in unitfile could be something like:
0 0 <floats>
0 10 <floats>
10 0 <floats>
100 0 <floats>
100 100 <floats>
which is hard to be read with any fortran-like fixed field format specification.
Is there any other way to get around this, apparently trivial, problem?
This applies string manipulations to get the individual components, separated by blanks ' ' and/or tabs (char(9)):
program test
implicit none
character(len=256) :: string, substring
integer :: ii, jj, unitfile, stat, posBT(2), pos
real, allocatable :: a(:)
open(file='in.txt', newunit=unitfile, status='old' )
read(unitfile,'(a)') string
! Crop whitespaces
string = adjustl(trim(string))
! Get first part:
posBT(1) = index(string,' ') ! Blank
posBT(2) = index(string,char(9)) ! Tab
pos = minval( posBT, posBT > 0 )
substring = string(1:pos)
string = adjustl(string(pos+1:))
read(substring,*) ii
! Get second part:
posBT(1) = index(string,' ') ! Blank
posBT(2) = index(string,char(9)) ! Tab
pos = minval( posBT, posBT > 0 )
substring = string(1:pos)
string = adjustl(string(pos+1:))
read(substring,*) jj
! Do stuff
allocate( a(ii+jj), stat=stat )
if (stat/=0) stop 'Cannot allocate memory'
read(string,*) a
print *,a
! Clean-up
close(unitfile)
deallocate(a)
end program
For a file in.txt like:
1 2 3.0 4.0 5.0
This results in
./a.out
3.00000000 4.00000000 5.00000000
NOTE: This is just a quick&dirty example, adjust it to your needs.
[This answer has been significantly revised: the original was unsafe. Thanks to IanH for pointing that out.]
I generally try to avoid doing formatted input which isn't list-directed, when I can afford it. There's already an answer with string parsing for great generality, but I'll offer some suggestions for a simpler setting.
When you are relaxed about trusting the input, such as when it's just the formatting that's a bit tricky (or you 're happy leaving it to your compiler's bounds checking), you can approach your example case with
read(unitfile, *) ii, jj, aa(ii, jj, :)
Alternatively, if the array section is more complicated than given directly by the first two columns, it can be by an expression, or even by functions
read(unitfile, *) ii, jj, aa(fi(ii,jj), fj(ii,jj), :fn(ii,jj))
with pure integer function fi(ii,jj) etc. There is even some possibility of having range validation in those functions (returning a size 0 section, for example).
In a more general case, but staying list-directed, one could use a buffer for the real variables
read(unitfile, *) ii, jj, buffer(:) ! Or ... buffer(:fn(ii,jj))
! Validate ii and jj before attempting to access aa with them
aa(.., .., :) = buffer
where buffer is of suitable size.
Your first considered approach suggests you have some reasonable idea of the structure of the lines, including length, but when the number of reals is unknown from ii and jj, or when the type (and polymorphism reading isn't allowed) is not known, then things do indeed get tricky. Also, if one is very sensitive about validating input, or even providing meaningful detailed user feedback on error, this is not optimal.
Finally, iostat helps.
Related
I'm trying to write a subroutine in a module that I can include in various codes to read data from a given file. I have several codes (numerical algorithms) which will be reading the data from the file.
The file has the following format:
First entry: No. of rows and columns of my array of data (e.g. 720)
First n(=720) entries: entire first row of the matrix A
Second n(=720) entries: entire 2nd row of the matrix A
etc.
Last n(=720) entries: all n entries of vector b
Each entry has two columns, one for the REAL part of the number, the other for the COMPLEX part.
In summary, an example basic input file:
2
-0.734192049E+00 0.711486186E+01
0.274492957E+00 0.378855374E+01
0.248391205E-01 0.412154039E+01
-0.632557864E+00 0.195397735E+01
0.289619736E+00 0.895562183E+00
-0.284756160E+00 -0.892163111E+00
where the first entry says its a 2x2 matrix and 2x1 vector
The first 4 lines are the four entries of the matrix A (left column Real, right column Imag.)
The last 2 lines are the two entries of the vector b (left column Real, right column Imag.)
I have written the following code to try and implement this but it simply outputs the wrong results:
n= 2
A= ( 0.0000000 , 1.08420217E-19) (-9.15983229E-16, 3.69024734E+19) ( 1.26116862E-43, 0.0000000 ) ( 0.0000000 , 0.0000000 )
b= ( 0.0000000 , 1.08420217E-19) ( 0.0000000 , 1.08420217E-19)
With the code:
SUBROUTINE matrix_input(n,A,b)
IMPLICIT NONE
!
INTEGER, INTENT(OUT) ::n !size of matrix to be read
COMPLEX, DIMENSION(:,:), INTENT(OUT), ALLOCATABLE ::A !system matrix to be read
COMPLEX, DIMENSION(:), INTENT(OUT), ALLOCATABLE ::b !RHS b vector to be read
DOUBLE PRECISION ::A_Re,A_Im,b_Re,b_Im !
INTEGER ::i,j
!----------------------------------------------------------
! Subroutine outputs 'n'=size of matrix, 'A'=system matrix
! 'b'= RHS vector
!matrix194.txt
OPEN (UNIT = 24, FILE = "matrix_input_test.txt", STATUS="OLD", FORM="FORMATTED", ACTION="READ")
!Read in size of matrix
READ(24,*) n
ALLOCATE(A(n,n))
ALLOCATE(b(n))
!Read matrix A:
DO i=1,n
DO j=1,n
READ(24,*) A_Re, A_Im
A(i,j)=CMPLX(A_Re,A_Im)
END DO
END DO
!Read RHS vector b:
DO i=((n*n)+1),((n*n)+n)
READ(24,*) b_Re, b_Im
b(i)=CMPLX(b_Re,b_Im)
END DO
CLOSE(UNIT=24)
DEALLOCATE(A,b)
END SUBROUTINE matrix_input
EDIT: Following HPC Mark's insights, I have edited my code, and this yields the correct result, however if there are any commands which could lead to issues later on down the line (e.g. with very large arrays that I will be using) I would very grateful to hear about them!
SUBROUTINE matrix_input(n,A,b)
IMPLICIT NONE
!
INTEGER, INTENT(OUT) ::n !size of matrix to be read
COMPLEX, DIMENSION(:,:), INTENT(OUT), ALLOCATABLE ::A !system matrix to be read
COMPLEX, DIMENSION(:), INTENT(OUT), ALLOCATABLE ::b !RHS b vector to be read
!
COMPLEX, DIMENSION(:), ALLOCATABLE ::temp,A_temp !temp vector of matrix A
DOUBLE PRECISION ::A_Re,A_Im,b_Re,b_Im
INTEGER ::i,j,k
!----------------------------------------------------------
! Subroutine outputs 'n'=size of matrix, 'A'=system matrix
! 'b'= RHS vector
!matrix194.txt
OPEN (UNIT = 24, FILE = "matrix_input_test.txt", STATUS="OLD", FORM="FORMATTED", ACTION="READ")
!Read in size of matrix
READ(24,*) n
!Allocate arrays/vectors
ALLOCATE(A(n,n))
ALLOCATE(b(n))
ALLOCATE(temp(n*n+n))
ALLOCATE(A_temp(n*n))
!Read matrix A & vector b:
!16 characters, 9 decimal places, exponent notation, 2 spaces
DO i=1,(n*n)+n
READ(24, FMT="(E16.9, 2X, E16.9)") A_Re, A_Im
temp(i)=CMPLX(A_Re,A_Im)
END DO
!Select A:
DO i=1,n*n
A_temp(i)=temp(i)
END DO
!Reshape
A=RESHAPE(A_temp, (/n,n/))
!Select b:
k=0
DO i=n*n+1,n*n+n
k=k+1
b(k)=temp(i)
END DO
CLOSE(UNIT=24)
!Do not deallocate A & b otherwise won't return anything properly
DEALLOCATE(temp, A_temp)
END SUBROUTINE matrix_input
RESULTS FROM THE EDITED CODE:
n= 2
A= (-0.73419207 , 7.1148620 ) ( 0.27449295 , 3.7885537 ) ( 0.24839121 , 4.1215405 ) (-0.63255787 , 1.9539773 )
b= ( 0.28961974 , 0.89556217 ) (-0.28475615 ,-0.89216310 )
High Performance Mark has already identified the significant issue, some other notes...
Your format specification in your updated code suggests two spaces in between numbers. Your example input suggests one - be mindful of the (optional) leading sign on the second number!
A and b are allocatable dummy arguments. That's a widely supported and very useful Fortran 2003 feature. You are well beyond Fortran 90! If that is unintentional then you will need to seriously redesign things, otherwise...
Being beyond Fortran 90 is a good thing - Fortran 95 (which is the minimum level of standard support offered by all current mainstream Fortran compilers - Fortran 90 is practically obsolete) and Fortran 2003 by extension fixed a serious deficiency in Fortran 90 - as of Fortran 95 local allocatable objects are deallocated automatically when the return or end statement of a procedure is executed. Your deallocate statement at the end is therefore harmless but redundant.
You read in the components of each complex number into double precision (note a common source code style used for modern Fortran tends to avoid the DOUBLE PRECISION type specifier - it is just a synonym for REAL(KIND(0.0D0))). You then store them into default (single precision) complex. Is that intentional? If so, its harmless but a little pointless/inconsistent, otherwise if you intended for the real and imaginary components in the output arrays to be stored at higher precision, then you need to change the declaration of the complex arrays appropriately. All kinds available for REAL must be available for COMPLEX, so your declaration could be COMPLEX(KIND(0.0D0)) (typically you would have the kind as a named constant).
In an input-output list, a complex scalar variable represents two effective items - the real part followed by the imaginary part. Consequently your double precision variables A_Re and A_Im, etc., are somewhat superfluous... READ(24, FMT="(E16.9, 2X, E16.9)") temp(i) is all that is required.
Personally I wouldn't bother with the other temporary arrays - once you know the size of the input data (the first line) allocate your A and B arrays to the necessary size and read directly into them. In an io list an array is expanded into its elements in array element order (first subscript varies fastest) - which appears to be the way your file is arranged. You can combine this with what's known as format reversion to eliminate the need for loops.
Upon return from your subroutine the allocatable arrays "know" their shape - there's no need to return that information separately. Again, harmless but redundant.
Consequently - I think your entire subroutine could look something like:
! Read A and B in from a file that has... etc, etc...
! Assuming a module procedure, where the module already has IMPLICIT NONE.
SUBROUTINE matrix_input(A, b)
! Number of rows and columns of A, elements of B.
INTEGER :: n
! Our output data.
COMPLEX(KIND(0.0D0)), INTENT(OUT), ALLOCATABLE :: A(:,:), b(:)
! Number of the logical unit for IO. In F2008 this becomes a variable
! and you use the NEWUNIT specifier.
INTEGER, PARAMETER :: unit = 24
! The name of the file to read the data from.
CHARACTER(*), PARAMETER :: filename = "matrix_input_test.txt"
! Format for the array and vector component of the data.
CHARACTER(*), PARAMETER :: fmt = "(E16.9, 1X, E16.9)"
!*****************************************************************************
! Connect to the file for sequential formatted reading.
OPEN(unit, FILE=filename, STATUS='OLD', ACTION='READ')
READ (unit, *) n ! Get array dimension.
ALLOCATE(A(n,n), b(n)) ! Allocate result arrays.
READ (unit, fmt) A ! Read in A.
READ (unit, fmt) b ! Read in B.
CLOSE (unit) ! Clean up.
END SUBROUTINE matrix_input
Your code confuses me. SUBROUTINE matrix_input declares arrays A and b to be allocatable with intent(out). Just before the END SUBROUTINE statement you go right ahead and deallocate them. What do you expect the subroutine to return to the calling routine ?
This should be an easy one.. I can't figure out why my read statement has a syntax error. I have a file 7477 lines long and I want each of those variables to correspond in each line like my format specifies. Any help here would be great. Thanks!
implicit none
integer :: spe, flen = 7477, i
real, dimension (7477):: wnum,s,A,abh
character :: other
integer :: lun = 11
write(*,*) 'Opening File!'
open(lun,file ='h2o_allbands',status = 'old',action ='read')
write(*,*) 'Success!'
17 format (1x,i2,3x,F9.6,1x,E9.3,1x,E9.3,F5.5,A120)
do i = 1, 7477
read(lun,17) spe(i),wnum(i),s(i),A(i),abh(i),other
write(*,*) wnum(i)
end do
The read has spe(i) as an input list item. spe is not declared as an array, so the compiler probably thinks spe(i) is a reference to an integer function. You cannot read "into" the result of a plain integer function.
Perhaps spe should be declared as an array?
Without seeing a line from your input file, it is difficult to say what the exact problem is: However:
First of all, you should not use a format statement when reading entities (unless in special cases), as this can lead to all sort of different errors, if your line is not well formatted for whatever reasons. So just replace the read line with:
read(lun,*) spe(i), wnum(i), s(i), A(i), abh(i), other
If all the lines are read in well apart the last one, then make sure, that you have a newline at the end of the last line.
I have made a program which takes a 1000 digit number as input.
It is fixed, so I put this input into the code file itself.
I would obviously be storing it as Integer type, but how do I do it?
I have tried the program by having 1000 digits in the same line. I know this is the worst possible code format! But it works.
How can assign the variable this number, and split its lines. I read somewhere something about eos? Ruby, end of what?
I was thinking that something similar to comments could be used here.
Help will be appreciated.
the basic idea is to make this work:
a=3847981438917489137897491412341234
983745893289572395725258923745897232
instead of something like this:
a=3847981438917489137897491412341234983745893289572395725258923745897232
Haskell doesn't have a way to split (non-String) literals across multiple lines. Since Strings are an exception, we can shoehorn in other literals by parsing a multiline String:
v = read
"32456\
\23857\
\23545" :: Integer
Alternately, you can use list syntax if you think it's prettier:
v = read . concat $
["32456"
,"24357"
,"23476"
] :: Integer
The price you pay for this is that some work will be done (once) at runtime, namely, the parsing (e.g. read).
does fortran have a maximum 'string' length?
i am going to be reading lines from a file which could have very long lines. the one i am looking at now has around 1.3k characters per line, but it is possible that they may have much more. i am reading each line from the file to a character*5000 variable, but if i get more in the future, is it bad to make it a character*5000000 variable? is there a max? is there a better way to solve this problem than making a very large character variables?
Since the usual Fortran IO is record based, reading lines into strings implies knowing the maximum string length. Another possible design: use stream IO and Fortran will ignore the record boundaries. Read the file in fixed-length chunks that are shorter than the longest lines. The complication is handling items split across chunk boundaries. The practicality depends on details not given in the question.
P.S. From "The Fortran 2003 Handbook" by Adams et al.: "The maximum length permitted for character strings is processor-dependent." -- meaning compiler dependent.
Maximum wil be implementation dependant. For your case, I can think of something along these lines:
character(:),allocatable :: ch
l = 5
do
allocate(character(l) :: ch)
read(unit,'(a)',iostat=io) ch
if (ch(l-4:l) = ' ' .or. io/=0) exit
deallocate(ch)
l = l * 2
end do
Obviously will not work for pad='no' and if you expect long regions with spacec in your records.
this is my first time trying to program in Fortran. I'm trying to write a program that prints the first 1476 terms of the Fibonacci sequence, then examines the first digit of each term and stores the number of 1s, 2s, 3s, ..., 9s that occur in an array.
The problem that I can't seem to figure out is how to read the first digit of each term. I've tried several things but am having difficulty with my limited knowledge of Fortran techniques. I write the terms to a text file and the idea is to read the first digit of each line and accumulate the respective number in the array. Does anyone have any suggestions of how to do this?
Here is my code so far:
(edit: I included the code I have for reading the file. Right now it just prints out 3.60772951994415996E-313,
which seems like an address of some sort, because it's not one of the Fibonacci numbers. Also, it is the only thing printed, I expected that it would print out every line of the file...)
(edit edit: After considering this, perhaps there's a way to format the writing to the text file to just the first digit. Is there a way to set the number of significant digits of a real number to one? :P)
subroutine writeFib(n)
integer :: i
real*8 :: prev, current, newFib
prev = 0
current = 1
do i = 1, n
newFib = prev + current
prev = current
current = newFib
write(7,*) newFib
end do
return
end subroutine
subroutine recordFirstDigits(a)
integer :: openStat, inputStat
real*8 :: fibNum
open(7, file = "fort.7", iostat = openStat)
if (openStat > 0) stop "*** Cannot open the file ***"
do
read(7, *, iostat = inputStat) fibNum
print *,fibNum
if (inputStat > 0) stop "*** input error ***"
if (inputStat < 0) exit ! end of file
end do
close(7)
end subroutine
program test
integer :: k, a(9)
k = 1476
call writeFib(k)
call recordFirstDigits(a)
end program
Although the suggestions were in place, there were also several things that were forgotten. Range of the REAL kind, and some formatting problems.
Anyways, here's one patched up solution, compiled and working, so try to see if this will work for you. I've took the liberty of choosing my own method for fibonacci numbers calculation.
program SO1658805
implicit none
integer, parameter :: iwp = selected_real_kind(15,310)
real(iwp) :: fi, fib
integer :: i
character(60) :: line
character(1) :: digit
integer :: n0=0, n1=0, n2=0, n3=0, n4=0, n5=0, n6=0, n7=0, n8=0, n9=0
open(unit=1, file='temp.txt', status='replace')
rewind(1)
!-------- calculating fibonacci numbers -------
fi = (1+5**0.5)/2.
do i=0,1477
fib = (fi**i - (1-fi)**i)/5**0.5
write(1,*)fib,i
end do
!----------------------------------------------
rewind(1)
do i=0,1477
read(1,'(a)')line
line = adjustl(line)
write(*,'(a)')line
read(line,'(a1)')digit
if(digit.eq.' ') n0=n0+1
if(digit.eq.'1') n1=n1+1
if(digit.eq.'2') n2=n2+1
if(digit.eq.'3') n3=n3+1
if(digit.eq.'4') n4=n4+1
if(digit.eq.'5') n5=n5+1
if(digit.eq.'6') n6=n6+1
if(digit.eq.'7') n7=n7+1
if(digit.eq.'8') n8=n8+1
if(digit.eq.'9') n9=n9+1
end do
close(1)
write(*,'("Total number of different digits")')
write(*,'("Number of digits 0: ",i5)')n0
write(*,'("Number of digits 1: ",i5)')n1
write(*,'("Number of digits 2: ",i5)')n2
write(*,'("Number of digits 3: ",i5)')n3
write(*,'("Number of digits 4: ",i5)')n4
write(*,'("Number of digits 5: ",i5)')n5
write(*,'("Number of digits 6: ",i5)')n6
write(*,'("Number of digits 7: ",i5)')n7
write(*,'("Number of digits 8: ",i5)')n8
write(*,'("Number of digits 9: ",i5)')n9
read(*,*)
end program SO1658805
Aw, ... I just read you need the number of digits stored in to an array. While I just counted them.
Oh well, ... "left as an exercise for the reader ..." :-)
Can you read with a FORMAT(A1)? It's been 20 years so I don't remember the exact syntax.
I wonder why the open statement succeeds when file 7 hasn't been closed. I think you need an endfile statement and/or a rewind statement in between writing and reading.
Paul Tomblin posted what you have to do after you solve your problem in getting reads to work in the first place.
I am getting an 'end of line' runtime error
You don't show the ! code to read here... which makes it kind of difficult to guess what you are doing wrong :-)
Perhaps you need a loop to read each line and then jump out of the loop to a continue statement when there are no more lines.
Something like this:
do
read(7,*,end=10) fibNumber
end do
10 continue
Better still - look at the more modern style used in this revcomp program.
here are some hints:
You don't need to use characters,
much less file i/o for this problem
(unless you forgot to state that a
file must be created).
Therefore, use math to find your statistics. There are lots of resources on Fibonacci numbers that might provide a simplifying insight or at least a way to independently spot check your answers.
Here is a complicated hint in non-Fortran lingo:
floor(10^(frac(log_10(7214989861293412))))
(Put this in Wolfram Alpha to see what it does.)
A simpler hint (for a different approach) is that you can do very
well in Fortran with simple
arithmetic inside of looping
constructs--at least for a first pass at the solution.
Accumulate your statistics as you
go. This advice would even apply to your character-driven approach. (This problem is ideally suited
for coming up with a cute indexing
scheme for your statistics, but some
people hate cute schemes in
programming. If you don't fear
cuteness ... then you can have associative
arrays in Fortran as long as your
keys are integers ;-)
The most important aspect of this
problem is the data type you will
use to calculate your answers. For
example, here's the last number you
will have to print.
Cheers, --Jared