I have the following write statement in a fortran code:
write(4,'(7f20.4)'),x(i,1), x(i,2),x(i,3),x(i,4),x(i,5),x(i,6),x(i,7),x(i,8),x(i,9)
I'd like to have the complete set of values printed in a single line, however I'm getting the two last values in a second.
I've tried advance=no already and the issue persists.
Fortran 2008 introduced the unlimited-format-item, which is *(format-items) (in other words, '*' is like a repeat count).
Your compiler (you didn't say which you are using) may support this.
In the (621-page) Working Document,
Note 10.7 explains further:
"The effect of an unlimited-format-item is as if its enclosed list were preceded by a very large repeat count. There is no file positioning implied by unlimited-format-item reversion. This may be used to write what is commonly called a comma separated value record.
For example,
WRITE( 10, ’( "IARRAY =", *( I0, :, ","))’) IARRAY
produces a single record with a header and a comma separated list of integer values."
Here's another example - a full program - using the line you gave us above
Program test
Implicit None
Integer, Parameter :: i = 1
Real, Parameter :: x(i, 9) = reshape( [1,2,3,4,5,6,7,8,9], [1,9] )
Write (4, '(*(f20.4))') x(i, 1), x(i, 2), x(i, 3), x(i, 4), x(i, 5), &
x(i, 6), x(i, 7), x(i, 8), x(i, 9)
End Program
Related
I am trying to make characters with an output as such in Fortran but I don't know how to. I made one with columns of asterisks but now I need it to change to the image linked.
I am a novice at Fortran.
Here's my code for the columns:
program chardesign
integer complete
do complete = 1, 5
write (*, 10, advance='no')
10 format (' * ')
enddo
!Newline to complete
write (*, 10)
stop
end program chardesign
How can I go about this?
Since we can no longer restrain ourselves from offering solutions...
Suppose we had a file called diamond.txt that had the picture already drawn:
*
***
*****
*******
*********
*******
*****
***
*
I know it's not visible here, but each line in diamond.txt has sufficient trailing spaces to make it 9 characters long. Now we just need a program that copies diamond.txt to its output:
program diamond
implicit none
character(9) line
open(10,file='diamond.txt',status='old')
do
read(10,'(a)',end=20) line
write(*,'(a)') line
end do
20 continue
end program diamond
The program has a couple of new features: first off it has implicit none which forces the programmer to declare all variables, thus avoiding a common source of hard-to-trace programming errors. Then it declares a character variable character(9) line which creates a variable which always contains 9 characters. There are rules that govern what happens if you try to assign it to a string of lesser or greater length, but we won't do that here.
Then it opens the file diamond.txt. The unit number, 10, will be used to reference the file in subsequent I/O statements. The status='old' part will cause the program to abort if it can't find diamond.txt.
Then we have a do statement which means do forever. Of course we don't really want to 'do forever', so there should be some way to exit the loop from its body.
Now we have a read statement that reads from unit 10, which, due to our previous open statement, is our file diamond.txt. The end=20 part means that when the read statement tries to read past end-of-file execution jumps to statement number 20, which gets us out of the loop. The format (a) does character I/O. It is the same as (a9) because the program knows that the length of the character variable to be read, line, is 9, so it will try to read the next 9 characters from diamond.txt and put them in variable line. After the read statement is complete, the file pointer advances to the next line of diamond.txt.
Then the write statement just writes variable line to standard output, thus copying the current line of diamond.txt to the screen.
When it's done, the end=20 branch is taken getting us to the 20 continue statement after which the end line is encountered and execution terminates.
So how could we do this without an external file? We could just convert the picture into a format statement and then print according to the format:
1 format(' * '/ &
' *** '/ &
' ***** '/ &
' ******* '/ &
'*********'/ &
' ******* '/ &
' ***** '/ &
' *** '/ &
' * ')
print 1
end
So we have encountered a new format specifier, /, the 'slash', which advances I/O to the next record (or line). Also the free-format continuation character &, the 'ampersand', which means that the current line continues to the next noncomment line. Also the print statement where here print 1 has the same effect as write(*,1).
OK, but what if we wanted to carry out some kind of calculation to produce the picture? If we considered the picture to lie on a raster array where row i ran from 1 at the top to 9 at the bottom and column j ran from column 1 at the left to column 9 at the right, we might observe that the image is symmetric about i=5 and about j=5. If we considered i and j to run from -4 to 4 instead we might be able to see some patterns that enable us to take advantage of the symmetry now about the y-axis and x-axis. Accordingly we write a program that will print out the coordinates...
print"(9(1x:'(',i2,',',i2,')'))",[((i,j,j=-4,4),i=-4,4)];end
Now we have a couple of new program elements: there is an array constructor [stuff] which will create an array of the elements listed within the square brackets.
[(more_stuff,i=-4,4)] is an ac-implied-do which effectively creates a list by evaluating more_stuff sequentially for each value of i from -4 to 4, thus a list of 9 things.
[((still_more_stuff,j=-4,4),i=-4,4)] is a nested ac-impied-do which for each value of i makes a list by evaluating still_more_stuff sequentially for each value of j from -4 to 4, thus there is a list of 9*9=81 things.
Since still_more_stuff is i,j, i.e. 2 things, the array constructor creates an array of 162 things, each (i,j) pair with j varying faster than I.
The print statement has a format string surrounded by " double quotes rather than ' apostrophes so that we can use apostrophe-delimited strings in the format.
The 9(stuff) part is a repeat count that means to do the formats specified in stuff 9 times over.
The 1x format says just skip one space and the following colon just separates it from the next format item. We can use , (comma), : (colon), or / (slash) to separate format items. As the reader will recall, slash skips to the next record; for the purposes or the current discussion let's ignore the distinction between comma and colon.
The i2 format prints out an integer in a field of width 2. If it takes more than 2 characters to print out the integer it will print out two asterisks ** instead.
So the format with the repeat count will print out 2*9=18 integers. When the format is exhausted there are rules called format reversion that in this case will result in output advancing to the next line and the format being reused.
Finally, in free format code one can write the next line of code on the current one if the current statement is followed by a semicolon ;. Thus ;end puts the required end statement at the end of the program. Note that the introductory program statement, although good style, is optional.
The output of the program is as follows:
(-4,-4) (-4,-3) (-4,-2) (-4,-1) (-4, 0) (-4, 1) (-4, 2) (-4, 3) (-4, 4)
(-3,-4) (-3,-3) (-3,-2) (-3,-1) (-3, 0) (-3, 1) (-3, 2) (-3, 3) (-3, 4)
(-2,-4) (-2,-3) (-2,-2) (-2,-1) (-2, 0) (-2, 1) (-2, 2) (-2, 3) (-2, 4)
(-1,-4) (-1,-3) (-1,-2) (-1,-1) (-1, 0) (-1, 1) (-1, 2) (-1, 3) (-1, 4)
( 0,-4) ( 0,-3) ( 0,-2) ( 0,-1) ( 0, 0) ( 0, 1) ( 0, 2) ( 0, 3) ( 0, 4)
( 1,-4) ( 1,-3) ( 1,-2) ( 1,-1) ( 1, 0) ( 1, 1) ( 1, 2) ( 1, 3) ( 1, 4)
( 2,-4) ( 2,-3) ( 2,-2) ( 2,-1) ( 2, 0) ( 2, 1) ( 2, 2) ( 2, 3) ( 2, 4)
( 3,-4) ( 3,-3) ( 3,-2) ( 3,-1) ( 3, 0) ( 3, 1) ( 3, 2) ( 3, 3) ( 3, 4)
( 4,-4) ( 4,-3) ( 4,-2) ( 4,-1) ( 4, 0) ( 4, 1) ( 4, 2) ( 4, 3) ( 4, 4)
Looking at these results we might observe that within the diamond, |i|+|j|<=4 while outside, |i|+|j|>=5. Let's create a program to check this:
print'(9(L1))',[((abs(j)+abs(i)<5,j=-4,4),i=-4,4)];end
Similar to the last program, but now the still_more_stuff in the inner ac-implied-do, abs(j)+abs(i)<5 is a logical expression which asks 'is |j|+|i| less than 5?' The value of the expression will be .TRUE. or .FALSE., depending on the outcome of this test.
The L1 format is a logical I/O specifier that outputs T for .TRUE. or F for .FALSE..
Output of the program is as follows:
FFFFTFFFF
FFFTTTFFF
FFTTTTTFF
FTTTTTTTF
TTTTTTTTT
FTTTTTTTF
FFTTTTTFF
FFFTTTFFF
FFFFTFFFF
We can see the diamond but we need to convert to (spaces) and * (asterisks):
print'(9a)',merge('*',' ',[((abs(j)+abs(i)<5,j=-4,4),i=-4,4)]);end
And this does it! The merge function processes our logical array (the third argument) and everywhere a .TRUE. element is encountered, replaces it with an asterisk * (the first argument) while every .FALSE. element is replaced by a space (the second argument).
The resulting 81-element character array is printed out 9 elements at a time by the (9a) format string, resulting in the desired output. The whole program, although complex to write, was only 66 characters long :)
I propose this approach on implementation, because it gives you flexibility on the character string length to be printed.
program chardesign
implicit none
call print_diamond('*', 5, 1)
call print_diamond('()', 3, 3)
call print_diamond('.', 1, 4)
call print_diamond('0', 0, 3)
contains
subroutine print_diamond(str, depth, start)
character(*), intent(in) :: str
integer, intent(in) :: depth, start
character(len(str)) :: spc
integer :: i, span
spc = ''
span = start + (depth - 1) * 2
print '(a)', (repeat(spc, (span - i) / 2) // repeat(str, i), i = start, span, 2)
print '(a)', (repeat(spc, (span - i) / 2) // repeat(str, i), i = span - 2, start, -2)
end
end
This yields the following output:
*
***
*****
*******
*********
*******
*****
***
*
()()()
()()()()()
()()()()()()()
()()()()()
()()()
....
I need to read from a txt file into three arrays in order to calculate distances between coordinates. I have looked through other answers and pieced together the script bellow. The columns of the input file need to be come my x, y and z arrays respectively. There are 64 rows and 16 decimal places for each entry. Pointers would be greatly appreciated.
the data format:
0.8607595188703266 0.9252035918116585 0.4094258340665792
0.5246038490998378 0.9804633529144733 0.5325820695466118
0.6955271184611949 0.3304908806613460 0.7154502550542654
and my script so far:
PROGRAM readtest
use, intrinsic :: iso_fortran_env
implicit none
integer, parameter :: ArrayLen = 64
real(real64), DIMENSION(ArrayLen) :: x
real(real64), DIMENSION(ArrayLen) :: y
real(real64), DIMENSION(ArrayLen) :: z
integer :: i, ReadCode, num
OPEN(1, FILE='contcar.txt', STATUS='old', ACTION='read')
OPEN(2, FILE='xyz.txt', STATUS='replace', ACTION='write')
num = 0
ReadLoop: do i=1, ArrayLen
read (1, '(A,F18.16)', iostat=ReadCode ) x(i), y(i), z(i)
if ( ReadCode /= 0 ) then
if ( ReadCode == iostat_end ) then
exit ReadLoop
else
write ( *, '( / "Error on read: ", I0 )' ) ReadCode
stop
end if
end if
num = num + 1
end do ReadLoop
WRITE(3, 100) x, y, z
100 format (A,F18.16)
END PROGRAM readtest
The xyz.txt is appearing blank and I am not getting any errors at this stage, what is wrong here that is stopping the array filling and writing to the file?
Sorry, if this is too much of mess to approach, any help would be appreciated.
Thanks
You have two problems with you approach:
Your format specifications are wrong
Your write won't do what you want
First off, the format A,F18.16 reads two items, a character and a floating point number. What you want is to read 3 floating point numbers. With the file provided, there are two spaces before each number so you could use
read (1, '(3(2X,F18.16))', iostat=ReadCode ) x(i), y(i), z(i)
but this is not very flexible if your input format changes and it is easier to just do list-directed input:
read (1, *, iostat=ReadCode ) x(i), y(i), z(i)
which will do what you want and is not sensitive to the exact positioning of the numbers within the file and how many intervening spaces exist.
This will load your data into the arrays. Now for output you want the same thing. You want to duplicate the output so we can use the first format about to stipulate that output (3(2X,F18.16)). This will output 3 numbers per line with 2 spaces before each number. The next problem is that you are attempting
WRITE(3, 100) x, y, z
which will transpose your array. It will write all of the x, then all of the y and lastly all of the z. If you want the same output, put it in a loop. Putting the above together, use:
do i=1, ArrayLen
WRITE(2, 100) x(i), y(i), z(i)
end do
100 format (3(2X,F18.16))
As a note, don't use single digit unit numbers, particularly the first few which conflict with system defined standard input/output/error units on most compilers.
I imagine this is something silly I've missed but I've asked my whole class and noone can seem to work it out. Making a simple program calling in a subroutine and I'm having trouble with the do loop reading in the entries of the matrix.
program Householder_Program
use QR_Factorisation
use numeric_kinds
complex(dp), dimension(:,:), allocatable :: A, Q, R, V
integer :: i, j, n, m
print *, 'Enter how many rows in the matrix A'
read *, m
print *, 'Enter how many columns in the matrix A'
read *, n
allocate(A(m,n), Q(m,n), R(n,n), V(n,n))
do i = 1,m
do j = 1,n
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, A(i,j)
end do
end do
call Householder_Triangularization(A,V,R,n,m)
print *, R
end program
It will ask me for A(1,1) but when I type in a number it will not ask me for A(1,2), it will leave a blank line. When I try to put in a 2nd number it will error and say :
Enter row 1 and column 1 of matrix A
1
2
At line 22 of file HouseholderProgram.f90 (unit = 5, file = 'stdin')
Fortran runtime error: Bad repeat count in item 1 of list input
Your variable A is (an array) of type complex. This means that when you attempt to do the list-directed input of the element values you cannot just specify a single number. So, in your case the problem is not with the program but with the input.
From the Fortran 2008 standard, 10.10.3
When the next effective item is of type complex, the input form consists of a left parenthesis followed by an ordered pair of numeric input fields separated by a comma (if the decimal edit mode is POINT) or semicolon (if the decimal edit mode is COMMA), and followed by a right parenthesis.
Input, then, must be something like (1., 12.).
You are trying to read in complex numbers (A is complex)! As such, you should specify complex numbers to the code... Since you are providing just one integer, the program does not know what to do.
Providing (1,0) and (2,0) instead of 1 and 2 will do the trick.
In case the user input is always real, and you want to read it into a complex type array you can do something like this:
Print *, 'Enter row', i, 'and column', j, 'of matrix A'
read *, dummy
A(i,j)=dummy
where dummy is declared real. This will save the user from the need to key in the parenthesis required for complex numbers. ( The conversion to complex is automatic )
I have the following write statement in a fortran code:
write(4,'(7f20.4)'),x(i,1), x(i,2),x(i,3),x(i,4),x(i,5),x(i,6),x(i,7),x(i,8),x(i,9)
I'd like to have the complete set of values printed in a single line, however I'm getting the two last values in a second.
I've tried advance=no already and the issue persists.
Fortran 2008 introduced the unlimited-format-item, which is *(format-items) (in other words, '*' is like a repeat count).
Your compiler (you didn't say which you are using) may support this.
In the (621-page) Working Document,
Note 10.7 explains further:
"The effect of an unlimited-format-item is as if its enclosed list were preceded by a very large repeat count. There is no file positioning implied by unlimited-format-item reversion. This may be used to write what is commonly called a comma separated value record.
For example,
WRITE( 10, ’( "IARRAY =", *( I0, :, ","))’) IARRAY
produces a single record with a header and a comma separated list of integer values."
Here's another example - a full program - using the line you gave us above
Program test
Implicit None
Integer, Parameter :: i = 1
Real, Parameter :: x(i, 9) = reshape( [1,2,3,4,5,6,7,8,9], [1,9] )
Write (4, '(*(f20.4))') x(i, 1), x(i, 2), x(i, 3), x(i, 4), x(i, 5), &
x(i, 6), x(i, 7), x(i, 8), x(i, 9)
End Program
I am new to FORTRAN, and must write a FORTRAN 77 program to read the following format from a file redirection or standard input:
[CHARACTER] [REAL] [REAL] [REAL] ... (can have any number of these)
D [INTEGER] (only one of these)
[REAL] [REAL] [REAL] ... (can have any number of these)
example input could be:
T 1.0 2.0 3.0
S 1.0 2.0 4.0
Y 3.0 4.0 5.0
D 2
3.0 5.0 6.0
4.5 4.6 5.6
My native language is C++, so I'm new to this whole idea of a read statement going to the next line automatically.
So far, I have the following code:
c234567
character*1 D
character*1 LETTER
real X, Y, Z
integer lines
real point1, point2, point3
85 format (3F10.6)
100 format (A1, 5X, F10.6, 5X, F10.6, 4X, F10.6)
990 format (A, I10)
MAX = 6
LETTER = 'Z'
D = 'D'
read *, LETTER, X, Y, Z
10 if(LETTER .ne. D) then
write (6, 100) LETTER, X, Y, Z
read *, LETTER, X, Y, Z
goto 10
else
goto 20
endif
C =====================================================
20 lines = aint(X)
write (*,990) 'LINES: ', lines
write (6, 85) X, Y, Z
read *, Z
write (6, 85) X, Y, Z
end
As you can see, I get the first portion of the input fine, but after that it kind of all goes to mush because of the read statement: read*, Z going to the next line. In my specific input file provided above, I get the 2 after the D, and the next two values (3.0, 5.0) but I skip the 6.0
Any help would be great. Thanks.
If you know that your lines will never exceed a maximum length, I suggest to read the whole line and then to parse the line according to your rules.
An example using a maximum line length of 1024 characters:
CHARACTER*1024 line
CHARACTER letter
100 FORMAT (A)
READ(*,100) line
READ(line, *) letter
IF (letter .eq. 'T') THEN
...
END IF
Maybe this technique works for you.
I haven't even looked at you code but I would suggest a strategy like this
(1) read the initial character of the line
if not "D" then
read reals
store the line
loop to (1)
else
read one integer
store the line
break
endif
read lines of reals until end-of-file
My fortran is very rusty, but I believe that there are constructs that will help you with this. Certainly the END modifier to READ is going to be helpful with the last bit.
After a little experimenting, I find that gfortran seems to support the old trailing $ for non-advancing input convention and advance='no'. However, g77 does not. I can't speak to any other compiler--as far as I know this was never standardized until fortran 90 where advance='no' was introduced.
Demo code that works in gfortran, but not in g77
program temp
c234567
character a
integer i
real x, y, z, w(50)
c This or with (*,'(A1 $)')
read (*,'(A1)',advance='no') a
if (a .eq. 'D') then
read (*,*) i
write (*,*) a, i
endif
end
This should be enough to make the incremental strategy work if you compiler supports non-advancing input somehow.
The alternative is to read the letter plus the rest of the line into a large character buffer, then parse the buffer separately along the lines of
character a, buf(1024)
read (*,'(a1, a1024)') a, buf
if (a .eq. d) then
read (buf,*) i
endif